You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 19:59:58