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

如何用pymodbus捕获原始字节并创建中断处理Modbus请求响应?

Modbus RTU 服务器优化解决方案

一、捕获原始请求字节并解析寄存器信息

要绕过轮询直接获取请求的关键信息,你需要自定义RTU帧处理器,在请求被处理前捕获原始字节并解析:

1. 自定义RTU帧处理器

继承ModbusRtuFramer并重写processIncomingPacket方法,在此阶段获取原始字节流并解析请求参数:

from pymodbus.framer.rtu_framer import ModbusRtuFramer
from pymodbus.pdu import ModbusRequest

class CustomRtuFramer(ModbusRtuFramer):
    def processIncomingPacket(self, data, callback, slave=None):
        # 打印原始请求字节
        print(f"原始请求字节: {data.hex()}")
        
        # 解析请求PDU,提取关键信息
        try:
            request = self._parseRequest(data)
            if isinstance(request, ModbusRequest):
                slave_id = request.slave_id
                func_code = request.function_code
                start_addr = request.address
                reg_count = request.count
                
                # 直接从context获取对应数据
                data_values = self.decoder.context[slave_id].getValues(func_code, start_addr, reg_count)
                print(f"解析请求: 从站ID={slave_id}, 功能码={func_code}, 起始地址={start_addr}, 寄存器数量={reg_count}, 数据={data_values}")
        except Exception as e:
            print(f"解析请求失败: {e}")
        
        # 调用父类方法继续处理请求,保证正常响应客户端
        super().processIncomingPacket(data, callback, slave)

2. 启动服务器时使用自定义帧处理器

修改服务器启动代码,替换framer参数为自定义类:

server = StartSerialServer(
    context, 
    framer=CustomRtuFramer, 
    identity=identity,
    port='/dev/ttyUSB0', 
    timeout=1, 
    baudrate=9600, 
    parity='N',
    bytesize=8,
    stopbits=1
)

二、实现请求/响应触发式通知(替代轮询)

通过自定义服务器类,重写请求处理方法,实现收到请求或发送响应时的触发式操作:

1. 自定义Modbus服务器

继承ModbusSerialServer并重写handle_request方法:

from pymodbus.server.sync import ModbusSerialServer

class CustomModbusServer(ModbusSerialServer):
    def handle_request(self, request):
        # 收到请求时触发打印
        print(f"收到请求: {request}")
        
        # 处理请求获取响应
        response = super().handle_request(request)
        
        # 发送响应时触发打印
        if response:
            print(f"发送响应: {response}")
        return response

2. 启动自定义服务器

替换默认启动方式,直接实例化自定义服务器:

server = CustomModbusServer(
    context, 
    framer=CustomRtuFramer, 
    identity=identity,
    port='/dev/ttyUSB0', 
    timeout=1, 
    baudrate=9600, 
    parity='N',
    bytesize=8,
    stopbits=1
)
server.serve_forever()

三、寄存器变化的触发式检测

如果需要检测寄存器值变化,无需轮询,可重写SlaveContext的setValues方法,在值被修改时触发通知:

from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext

class CustomSlaveContext(ModbusSlaveContext):
    def setValues(self, fc_as_hex, address, values):
        # 记录修改前的值
        old_values = self.getValues(fc_as_hex, address, len(values))
        # 执行修改操作
        super().setValues(fc_as_hex, address, values)
        # 对比值是否变化,变化则触发通知
        if old_values != values:
            print(f"寄存器更新: 功能码={fc_as_hex}, 起始地址={address}, 旧值={old_values}, 新值={values}")

# 创建上下文时使用自定义SlaveContext
slave_context = CustomSlaveContext()
context = ModbusServerContext(slaves=slave_context, single=True)

内容的提问来源于stack exchange,提问作者Umer Farooq

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 14:02:09