294 lines
12 KiB
Python
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() |