VWED_server/tests/test_modbus_client.py

294 lines
12 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Modbus TCP 客户端测试脚本
测试VWED在线脚本中的Modbus通信功能
"""
import sys
import os
import time
import threading
# 添加项目根目录到路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from services.online_script.built_in_modules.modbus_module import VWEDModbusModule
from tests.test_modbus_server import ModbusTestServer
class ModbusClientTester:
"""Modbus客户端测试器"""
def __init__(self):
self.server = None
self.modbus_module = VWEDModbusModule("test_script")
self.host = 'localhost'
self.port = 5020
self.slave_id = 1
def start_test_server(self):
"""启动测试服务器"""
print("启动Modbus测试服务器...")
self.server = ModbusTestServer(self.host, self.port)
self.server.start_server()
time.sleep(2) # 等待服务器启动
print(f"测试服务器已启动: {self.host}:{self.port}")
def stop_test_server(self):
"""停止测试服务器"""
if self.server:
self.server.stop_server()
print("测试服务器已停止")
def test_basic_read_operations(self):
"""测试基础读取操作"""
print("\n" + "="*50)
print("测试基础读取操作")
print("="*50)
# 测试读取线圈
print("\n1. 测试读取线圈 (功能码01)")
result = self.modbus_module.read_coil_status(self.host, self.port, self.slave_id, 0)
print(f" read_coil_status(0): {result}")
# 测试读取离散输入
print("\n2. 测试读取离散输入 (功能码02)")
result = self.modbus_module.read_input_status(self.host, self.port, self.slave_id, 0)
print(f" read_input_status(0): {result}")
# 测试读取保持寄存器
print("\n3. 测试读取保持寄存器 (功能码03)")
result = self.modbus_module.read_holding_register(self.host, self.port, self.slave_id, 0, 2)
print(f" read_holding_register(0, 无符号): {result}")
# 测试读取输入寄存器
print("\n4. 测试读取输入寄存器 (功能码04)")
result = self.modbus_module.read_input_register(self.host, self.port, self.slave_id, 0, 2)
print(f" read_input_register(0, 无符号): {result}")
def test_batch_read_operations(self):
"""测试批量读取操作"""
print("\n" + "="*50)
print("测试批量读取操作")
print("="*50)
# 批量读取线圈
print("\n1. 批量读取线圈")
result = self.modbus_module.batch_read_coil_status(self.host, self.port, self.slave_id, 0, 5)
print(f" batch_read_coil_status(0-4): {result}")
# 批量读取离散输入
print("\n2. 批量读取离散输入")
result = self.modbus_module.batch_read_input_status(self.host, self.port, self.slave_id, 0, 5)
print(f" batch_read_input_status(0-4): {result}")
# 批量读取保持寄存器
print("\n3. 批量读取保持寄存器")
result = self.modbus_module.batch_read_holding_registers(self.host, self.port, self.slave_id, 0, 5)
print(f" batch_read_holding_registers(0-4): {result}")
# 批量读取输入寄存器
print("\n4. 批量读取输入寄存器")
result = self.modbus_module.batch_read_input_registers(self.host, self.port, self.slave_id, 0, 5)
print(f" batch_read_input_registers(0-4): {result}")
def test_write_operations(self):
"""测试写入操作"""
print("\n" + "="*50)
print("测试写入操作")
print("="*50)
# 测试写入线圈
print("\n1. 测试写入线圈 (功能码05)")
result = self.modbus_module.write_coil_status(self.host, self.port, self.slave_id, 0, True)
print(f" write_coil_status(0, True): {result}")
# 验证写入结果
read_result = self.modbus_module.read_coil_status(self.host, self.port, self.slave_id, 0)
print(f" 验证结果 read_coil_status(0): {read_result}")
# 测试写入保持寄存器
print("\n2. 测试写入保持寄存器 (功能码06)")
result = self.modbus_module.write_holding_register(self.host, self.port, self.slave_id, 0, 2, 12345)
print(f" write_holding_register(0, 12345): {result}")
# 验证写入结果
read_result = self.modbus_module.read_holding_register(self.host, self.port, self.slave_id, 0, 2)
print(f" 验证结果 read_holding_register(0): {read_result}")
def test_batch_write_operations(self):
"""测试批量写入操作"""
print("\n" + "="*50)
print("测试批量写入操作")
print("="*50)
# 批量写入线圈
print("\n1. 批量写入线圈 (功能码0F)")
values = [True, False, True, False, True]
result = self.modbus_module.batch_write_coil_status(self.host, self.port, self.slave_id, 0, values)
print(f" batch_write_coil_status(0-4, {values}): {result}")
# 验证结果
read_result = self.modbus_module.batch_read_coil_status(self.host, self.port, self.slave_id, 0, 5)
print(f" 验证结果: {read_result}")
# 批量写入保持寄存器
print("\n2. 批量写入保持寄存器 (功能码10)")
values = [1111, 2222, 3333, 4444, 5555]
result = self.modbus_module.batch_write_holding_register(self.host, self.port, self.slave_id, 0, values)
print(f" batch_write_holding_register(0-4, {values}): {result}")
# 验证结果
read_result = self.modbus_module.batch_read_holding_registers(self.host, self.port, self.slave_id, 0, 5)
print(f" 验证结果: {read_result}")
def test_generic_operations(self):
"""测试通用读写操作"""
print("\n" + "="*50)
print("测试通用读写操作")
print("="*50)
# 测试通用读取
print("\n1. 通用读取测试")
for type_str in ['0x', '1x', '3x', '4x']:
result = self.modbus_module.read_single_modbus_value(self.host, self.port, self.slave_id, type_str, 0)
print(f" read_single_modbus_value(type={type_str}, addr=0): {result}")
# 测试通用批量读取
print("\n2. 通用批量读取测试")
for type_str in ['0x', '1x', '3x', '4x']:
result = self.modbus_module.read_batch_modbus_value(self.host, self.port, self.slave_id, type_str, 0, 3)
print(f" read_batch_modbus_value(type={type_str}, addr=0-2): {result}")
# 测试通用写入(只测试可写的类型)
print("\n3. 通用写入测试")
for type_str, value in [('0x', 1), ('4x', 9999)]:
result = self.modbus_module.write_single_modbus_value(self.host, self.port, self.slave_id, type_str, 0, value)
print(f" write_single_modbus_value(type={type_str}, addr=0, value={value}): {result}")
# 测试不可写类型
print("\n4. 测试只读类型写入(应该失败)")
for type_str in ['1x', '3x']:
result = self.modbus_module.write_single_modbus_value(self.host, self.port, self.slave_id, type_str, 0, 1)
print(f" write_single_modbus_value(type={type_str}, 只读): {result}")
def test_instance_operations(self):
"""测试实例化操作"""
print("\n" + "="*50)
print("测试实例化操作")
print("="*50)
# 配置实例
print("\n1. 配置Modbus实例")
self.modbus_module.configure_modbus_instance("test_plc", self.host, self.port, self.slave_id, "4x")
print(" 已配置实例: test_plc")
# 通过实例名称读取
print("\n2. 通过实例名称读取")
result = self.modbus_module.read_single_modbus_value_by_instance_name("test_plc", 0)
print(f" read_single_modbus_value_by_instance_name(test_plc, 0): {result}")
result = self.modbus_module.read_batch_modbus_value_by_instance_name("test_plc", 0, 3)
print(f" read_batch_modbus_value_by_instance_name(test_plc, 0-2): {result}")
# 通过实例名称写入
print("\n3. 通过实例名称写入")
result = self.modbus_module.write_single_modbus_value_by_instance_name("test_plc", 0, 8888)
print(f" write_single_modbus_value_by_instance_name(test_plc, 0, 8888): {result}")
# 验证结果
read_result = self.modbus_module.read_single_modbus_value_by_instance_name("test_plc", 0)
print(f" 验证结果: {read_result}")
# 批量写入
result = self.modbus_module.write_batch_modbus_value_by_instance_name("test_plc", 1, [7777, 6666, 5555])
print(f" write_batch_modbus_value_by_instance_name(test_plc, 1-3): {result}")
# 验证结果
read_result = self.modbus_module.read_batch_modbus_value_by_instance_name("test_plc", 1, 3)
print(f" 验证结果: {read_result}")
# 测试未配置实例(应该抛出异常)
print("\n4. 测试未配置实例(应该抛出异常)")
try:
self.modbus_module.read_single_modbus_value_by_instance_name("non_exist", 0)
except Exception as e:
print(f" 预期异常: {e}")
def test_data_type_conversion(self):
"""测试数据类型转换"""
print("\n" + "="*50)
print("测试数据类型转换")
print("="*50)
# 测试有符号和无符号整数
print("\n1. 测试有符号/无符号整数转换")
# 写入一个大数值(可能被解释为负数)
test_value = 65535 # 最大16位无符号数
result = self.modbus_module.write_holding_register(self.host, self.port, self.slave_id, 10, 2, test_value)
print(f" 写入无符号整数 {test_value}: {result}")
# 以无符号方式读取
result_unsigned = self.modbus_module.read_holding_register(self.host, self.port, self.slave_id, 10, 2)
print(f" 无符号读取结果: {result_unsigned}")
# 以有符号方式读取
result_signed = self.modbus_module.read_holding_register(self.host, self.port, self.slave_id, 10, 3)
print(f" 有符号读取结果: {result_signed}")
# 写入负数(有符号)
test_value = -1
result = self.modbus_module.write_holding_register(self.host, self.port, self.slave_id, 11, 3, test_value)
print(f" 写入有符号整数 {test_value}: {result}")
# 以有符号方式读取
result_signed = self.modbus_module.read_holding_register(self.host, self.port, self.slave_id, 11, 3)
print(f" 有符号读取结果: {result_signed}")
# 以无符号方式读取
result_unsigned = self.modbus_module.read_holding_register(self.host, self.port, self.slave_id, 11, 2)
print(f" 无符号读取结果: {result_unsigned}")
def run_all_tests(self):
"""运行所有测试"""
print("VWED Modbus TCP 功能测试")
print("="*60)
try:
# 启动测试服务器
self.start_test_server()
# 运行各项测试
self.test_basic_read_operations()
self.test_batch_read_operations()
self.test_write_operations()
self.test_batch_write_operations()
self.test_generic_operations()
self.test_instance_operations()
self.test_data_type_conversion()
print("\n" + "="*60)
print("所有测试完成!")
print("="*60)
except Exception as e:
print(f"\n测试过程中发生错误: {e}")
import traceback
traceback.print_exc()
finally:
# 停止测试服务器
self.stop_test_server()
def main():
"""主函数"""
tester = ModbusClientTester()
tester.run_all_tests()
if __name__ == "__main__":
main()