Modbus协议下MQTT发送含0x00十六进制数据的问题
问题描述
现有一段用于通过MQTT发送Modbus RTU十六进制帧的Python代码,功能是将Modbus指令以字节数组形式发送到指定MQTT主题。但当前代码存在问题:当Modbus帧中间包含0x00时,0x00之后的字节无法被发送,且必须在帧末尾添加0x00才能终止查询。需要解决在指令中间使用0x00且不导致数据提前终止的问题。
原代码
import paho.mqtt.client as mqtt # MQTT broker details broker = "test.mosquitto.org" port = 1883 topic = "M66_Rx" # Modbus RTU Frame as a list of hex values modbus_hex = [0x11, 0x03, 0x01, 0x02, 0x01, 0x04, 0xe7, 0x59] # Convert the list of hex values to a byte array modbus_bytes = bytes(modbus_hex) # MQTT client setup client = mqtt.Client() def on_connect(client, userdata, flags, rc): if rc == 0: print("Connected to MQTT broker") else: print(f"Failed to connect to MQTT broker, return code {rc}") def on_publish(client, userdata, mid): print(f"Message published with mid={mid}") client.on_connect = on_connect client.on_publish = on_publish # Connect to MQTT broker client.connect(broker, port) # Start the MQTT client loop in a non-blocking manner client.loop_start() # Send the Modbus RTU frame as a single byte array try: client.publish(topic, modbus_bytes) print("Payload being sent:", modbus_bytes.hex()) print("Modbus RTU frame sent") except KeyboardInterrupt: # Handle the user interrupt to stop the script gracefully print("Interrupted by user") # Disconnect from MQTT broker client.disconnect() client.loop_stop() print("Script finished")
问题根源与解决方案
核心问题
原代码存在回调函数缩进错误:on_publish被嵌套在on_connect函数内部,导致MQTT客户端无法正确注册on_publish回调,进而引发二进制数据发送逻辑异常;同时若接收端错误将payload按字符串解析,0x00会被当作字符串终止符截断数据。
修复后的代码
import paho.mqtt.client as mqtt # MQTT broker details broker = "test.mosquitto.org" port = 1883 topic = "M66_Rx" # Modbus RTU Frame with 0x00 in the middle modbus_hex = [0x11, 0x03, 0x00, 0x02, 0x01, 0x04, 0xe7, 0x59] # Convert to byte array to ensure binary transmission modbus_bytes = bytes(modbus_hex) # MQTT client setup client = mqtt.Client() def on_connect(client, userdata, flags, rc): if rc == 0: print("Connected to MQTT broker") else: print(f"Failed to connect to MQTT broker, return code {rc}") def on_publish(client, userdata, mid): print(f"Message published with mid={mid}") # Correctly register callbacks (fixed indentation issue) client.on_connect = on_connect client.on_publish = on_publish # Connect to MQTT broker client.connect(broker, port) # Start non-blocking loop client.loop_start() try: # Publish binary payload directly (bytes type avoids truncation at 0x00) publish_result = client.publish(topic, payload=modbus_bytes, qos=0) # Wait for publish completion to ensure full data delivery publish_result.wait_for_publish() print("Payload being sent:", modbus_bytes.hex()) print("Modbus RTU frame sent completely") except KeyboardInterrupt: print("Interrupted by user") finally: # Clean up connection properly client.disconnect() client.loop_stop() print("Script finished")
关键修复点
- 修正回调缩进:将
on_publish从on_connect内部移出,确保客户端正确注册回调,避免发送逻辑异常。 - 强制二进制发送:使用
bytes类型作为payload,paho.mqtt客户端会直接发送原始二进制数据,不会将0x00视为字符串终止符截断。 - 添加发布确认:通过
publish_result.wait_for_publish()确保消息完全发送,避免异步发送导致的数据遗漏。
额外注意
若接收端仍出现数据截断,需确认接收端是否以二进制模式解析MQTT消息,而非按字符串解码——只有接收端同样处理二进制数据,才能完整接收包含0x00的Modbus帧。
内容的提问来源于stack exchange,提问作者Bhavik Patel
相关产品推荐
相关产品推荐

