Pymodbus:Modbus RTU的使用反应器 - 回调从来没有所谓的

问题描述 投票:0回答:2

我想创建Modbus串行/ RTU客户端,它会读取使用Pymodbus库从串口数据。

Python的:3.6 Pymodbus:2.1.0 平台:Linux / Windows的

我的示例代码碱下面给出:

def readDevices(modbusRTUDevice):
    deviceIP = modbusRTUDevice["ip"]
    devicePort = modbusRTUDevice["port"]
    logger.info("Connecting to Modbus RTU device at address {0}".format(deviceIP + ":" + str(devicePort)))
    modbusClientFactory = CustomModbusClientFactory()
    modbusClientFactory.address = deviceIP
    modbusClientFactory.modbusDevice = modbusRTUDevice
    SerialModbusClient(modbusClientFactory, devicePort, reactor)
    Thread(target=reactor.run, args=(False,)).start() 

class SerialModbusClient(serialport.SerialPort):
    def __init__(self, factory, *args, **kwargs):
        serialport.SerialPort.__init__(self, factory.buildProtocol(), *args, **kwargs)

class CustomModbusClientFactory(protocol.ClientFactory, ModbusClientMixin):
    modbusDevice = {} 

    def buildProtocol(self, addr=None):
        modbusClientProtocol = CustomModbusClientProtocol()
        modbusClientProtocol.factory = self
        modbusClientProtocol.modbusDevice = self.modbusDevice
        return modbusClientProtocol

class CustomModbusClientProtocol(ModbusClientProtocol):
    def connectionMade(self):
        framer = ModbusRtuFramer.__init__(self, ClientDecoder(), client=None)
        ModbusClientProtocol.__init__(self, framer, baudrate=9600, parity='E', bytesize=8, stopbits=1, timeout=0.2, retryOnEmpty=True, retries=3)
        ModbusClientProtocol.connectionMade(self)
        deviceIP = self.modbusDevice["ip"]
        devicePort = self.modbusDevice["port"]
        logger.info("Modbus RTU device connected at address {0}".format(deviceIP + ":" + str(devicePort)))
        self.read()

    def read(self):
        deviceIP = self.modbusDevice["ip"]
        devicePort = self.modbusDevice["port"]
        slaveAddress = self.modbusDevice["slaveAddress"]
        logger.info("Reading holding registers of Modbus RTU device at address {0}...".format(deviceIP + ":" + str(devicePort)))
        deferred = self.read_holding_registers(self.startingAddress, self.registerCount, unit=slaveAddress)
        deferred.addCallbacks(self.requestFetched, self.requestNotFetched)

    def requestNotFetched(self, error):
        logger.info("Error reading registers of Modbus RTU device : {0}".format(error))
        sleep(0.5)

    def requestFetched(self, response):
        logger.info("Inside request fetched...")
        #Do some other stuff here
        reactor.callLater(0, self.read) 

调试完毕后,read()方法的selfCustomModbusClientProtocol: Null Transport。在此之后,我按F8&线程去堵递延从来没有所谓的状态和回调。

输出:

INFO:__main__: (2019-01-30 15:42:53; Test.py:200 Connecting to Modbus RTU device at address 127.0.0.1:/dev/ttyUSB0)
INFO:__main__: (2019-01-30 15:42:53; Test.py:70 Modbus RTU device connected at address 127.0.0.1:/dev/ttyUSB0)
INFO:__main__: (2019-01-30 15:46:18; Test.py:87 Reading holding registers of Modbus RTU device at address 127.0.0.1:/dev/ttyUSB0...)

Serial + Async + RTU: Callback is never fired #160,要求延期回调的问题是固定的。但是,在我的情况下,它仍然存在。

我试图在这两个,树莓PI和Windows的代码,让在这两种情况下相同的反应。

搞不明白为什么会这样。我需要在我的代码添加一些东西,或者我应该做错了什么,同时连接到Modbus设备的串行端口上?

任何帮助,将不胜感激。

python-3.x raspberry-pi modbus pymodbus
2个回答
0
投票

编辑

更新的代码和日志


问题是你直接在self.read()connectionMade调用CustomModbusClientProtocol,反应器实际上是开始前。你将不得不等待反应器启动,并在与schedule以后readreactor.callLater(<time-to-wait-in-seconds>, self.read)。修改后的CustomModbusClientProtocol代码会是这个样子

from twisted.internet import serialport, reactor
from twisted.internet import protocol
from pymodbus.factory import ClientDecoder
from pymodbus.client.async.twisted import ModbusClientProtocol

from pymodbus.transaction import ModbusRtuFramer
from threading import Thread
from time import sleep
import logging
FORMAT = ('%(asctime)-15s %(threadName)-15s '
          '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)


def readDevices(modbusRTUDevice):
    deviceIP = modbusRTUDevice["ip"]
    devicePort = modbusRTUDevice["port"]
    logger.info("Connecting to Modbus RTU device at address {0}".format(deviceIP + ":" + str(devicePort)))
    modbusClientFactory = CustomModbusClientFactory()
    modbusClientFactory.address = deviceIP
    modbusClientFactory.modbusDevice = modbusRTUDevice
    SerialModbusClient(modbusClientFactory, devicePort, reactor)
    Thread(target=reactor.run, args=(False,)).start()

class SerialModbusClient(serialport.SerialPort):
    def __init__(self, factory, *args, **kwargs):
        serialport.SerialPort.__init__(self, factory.buildProtocol(), *args, **kwargs)

class CustomModbusClientFactory(protocol.ClientFactory):
    modbusDevice = {}

    def buildProtocol(self, addr=None):
        modbusClientProtocol = CustomModbusClientProtocol()
        modbusClientProtocol.factory = self
        modbusClientProtocol.modbusDevice = self.modbusDevice
        return modbusClientProtocol

class CustomModbusClientProtocol(ModbusClientProtocol):
    def connectionMade(self):
        framer = ModbusRtuFramer(ClientDecoder(), client=None)
        ModbusClientProtocol.__init__(self, framer, baudrate=9600, parity='E', bytesize=8, stopbits=1, timeout=0.2, retryOnEmpty=True, retries=3)
        ModbusClientProtocol.connectionMade(self)
        deviceIP = self.modbusDevice["ip"]
        devicePort = self.modbusDevice["port"]
        logger.info("Modbus RTU device connected at address logger{0}".format(deviceIP + ":" + str(devicePort)))
        reactor.callLater(5, self.read)

    def read(self):
        deviceIP = self.modbusDevice["ip"]
        devicePort = self.modbusDevice["port"]
        slaveAddress = self.modbusDevice["slaveAddress"]
        logger.info("Reading holding registers of Modbus RTU device at address {0}...".format(deviceIP + ":" + str(devicePort)))
        deferred = self.read_holding_registers(0, 10, unit=slaveAddress)
        deferred.addCallbacks(self.requestFetched, self.requestNotFetched)

    def requestNotFetched(self, error):
        logger.info("Error reading registers of Modbus RTU device : {0}".format(error))
        sleep(0.5)

    def requestFetched(self, response):
        logger.info("Inside request fetched...")
        #Do some other stuff here
        reactor.callLater(0, self.read)


readDevices({"ip": "127.0.0.1", "port": "/dev/ptyp0", "slaveAddress": 1})

日志:

$ python scratch_118.py
2019-01-31 12:34:56,734 MainThread      INFO     scratch_118    :21       Connecting to Modbus RTU device at address 127.0.0.1:/dev/ptyp0
2019-01-31 12:34:56,735 MainThread      DEBUG    __init__       :80       Client connected to modbus server
2019-01-31 12:34:56,735 MainThread      INFO     scratch_118    :48       Modbus RTU device connected at address logger127.0.0.1:/dev/ptyp0
2019-01-31 12:35:01,737 Thread-1        INFO     scratch_118    :55       Reading holding registers of Modbus RTU device at address 127.0.0.1:/dev/ptyp0...
2019-01-31 12:35:01,738 Thread-1        DEBUG    __init__       :112      send: 0x1 0x3 0x0 0x0 0x0 0xa 0xc5 0xcd
2019-01-31 12:35:01,738 Thread-1        DEBUG    transaction    :418      Adding transaction 1
2019-01-31 12:35:02,196 Thread-1        DEBUG    rtu_framer     :175      Getting Frame - 0x3 0x14 0x0 0x2d 0x0 0x2c 0x0 0x2e 0x0 0x2d 0x0 0x2d 0x0 0x2e 0x0 0x29 0x0 0x2d 0x0 0x2d 0x0 0x2c
2019-01-31 12:35:02,197 Thread-1        DEBUG    factory        :246      Factory Response[ReadHoldingRegistersResponse: 3]
2019-01-31 12:35:02,197 Thread-1        DEBUG    rtu_framer     :110      Frame advanced, resetting header!!
2019-01-31 12:35:02,197 Thread-1        INFO     scratch_118    :64       Inside request fetched...
2019-01-31 12:35:02,197 Thread-1        INFO     scratch_118    :55       Reading holding registers of Modbus RTU device at address 127.0.0.1:/dev/ptyp0...
2019-01-31 12:35:02,198 Thread-1        DEBUG    __init__       :112      send: 0x1 0x3 0x0 0x0 0x0 0xa 0xc5 0xcd
2019-01-31 12:35:02,198 Thread-1        DEBUG    transaction    :418      Adding transaction 2
2019-01-31 12:35:03,202 Thread-1        DEBUG    rtu_framer     :175      Getting Frame - 0x3 0x14 0x0 0x2d 0x0 0x2c 0x0 0x2e 0x0 0x2d 0x0 0x2d 0x0 0x2e 0x0 0x29 0x0 0x2d 0x0 0x2d 0x0 0x2c
2019-01-31 12:35:03,202 Thread-1        DEBUG    factory        :246      Factory Response[ReadHoldingRegistersResponse: 3]
2019-01-31 12:35:03,202 Thread-1        DEBUG    rtu_framer     :110      Frame advanced, resetting header!!
2019-01-31 12:35:03,202 Thread-1        INFO     scratch_118    :64       Inside request fetched...
2019-01-31 12:35:03,203 Thread-1        INFO     scratch_118    :55       Reading holding registers of Modbus RTU device at address 127.0.0.1:/dev/ptyp0...
2019-01-31 12:35:03,203 Thread-1        DEBUG    __init__       :112      send: 0x1 0x3 0x0 0x0 0x0 0xa 0xc5 0xcd
2019-01-31 12:35:03,203 Thread-1        DEBUG    transaction    :418      Adding transaction 3
2019-01-31 12:35:04,207 Thread-1        DEBUG    rtu_framer     :175      Getting Frame - 0x3 0x14 0x0 0x2d 0x0 0x2c 0x0 0x2e 0x0 0x2d 0x0 0x2d 0x0 0x2e 0x0 0x29 0x0 0x2d 0x0 0x2d 0x0 0x2c
2019-01-31 12:35:04,207 Thread-1        DEBUG    factory        :246      Factory Response[ReadHoldingRegistersResponse: 3]
2019-01-31 12:35:04,208 Thread-1        DEBUG    rtu_framer     :110      Frame advanced, resetting header!!
2019-01-31 12:35:04,208 Thread-1        INFO     scratch_118    :64       Inside request fetched...
2019-01-31 12:35:04,208 Thread-1        INFO     scratch_118    :55       Reading holding registers of Modbus RTU device at address 127.0.0.1:/dev/ptyp0...
2019-01-31 12:35:04,208 Thread-1        DEBUG    __init__       :112      send: 0x1 0x3 0x0 0x0 0x0 0xa 0xc5 0xcd
2019-01-31 12:35:04,209 Thread-1        DEBUG    transaction    :418      Adding transaction 4
2019-01-31 12:35:05,213 Thread-1        DEBUG    rtu_framer     :175      Getting Frame - 0x3 0x14 0x0 0x2d 0x0 0x2c 0x0 0x2e 0x0 0x2d 0x0 0x2d 0x0 0x2e 0x0 0x29 0x0 0x2d 0x0 0x2d 0x0 0x2c
2019-01-31 12:35:05,213 Thread-1        DEBUG    factory        :246      Factory Response[ReadHoldingRegistersResponse: 3]
2019-01-31 12:35:05,214 Thread-1        DEBUG    rtu_framer     :110      Frame advanced, resetting header!!
2019-01-31 12:35:05,214 Thread-1        INFO     scratch_118    :64       Inside request fetched...
2019-01-31 12:35:05,214 Thread-1        INFO     scratch_118    :55       Reading holding registers of Modbus RTU device at address 127.0.0.1:/dev/ptyp0...
2019-01-31 12:35:05,214 Thread-1        DEBUG    __init__       :112      send: 0x1 0x3 0x0 0x0 0x0 0xa 0xc5 0xcd
2019-01-31 12:35:05,215 Thread-1        DEBUG    transaction    :418      Adding transaction 5
2019-01-31 12:35:06,218 Thread-1        DEBUG    rtu_framer     :175      Getting Frame - 0x3 0x14 0x0 0x2d 0x0 0x2c 0x0 0x2e 0x0 0x2d 0x0 0x2d 0x0 0x2e 0x0 0x29 0x0 0x2d 0x0 0x2d 0x0 0x2c
2019-01-31 12:35:06,218 Thread-1        DEBUG    factory        :246      Factory Response[ReadHoldingRegistersResponse: 3]
2019-01-31 12:35:06,219 Thread-1        DEBUG    rtu_framer     :110      Frame advanced, resetting header!!
2019-01-31 12:35:06,219 Thread-1        INFO     scratch_118    :64       Inside request fetched...
2019-01-31 12:35:06,219 Thread-1        INFO     scratch_118    :55       Reading holding registers of Modbus RTU device at address 127.0.0.1:/dev/ptyp0...

0
投票

下面的解决方案对我的作品。我的设备配置给出如下:

设备配置: 波特率= 9600,奇偶校验= 'E',Bytesize = 8超时= 0.2 协议:RTU PLC使用串行到USB转换器连接到树莓派。

工作守则:

import logging
from threading import Thread
from time import sleep

from pymodbus.client.async.twisted import ModbusClientProtocol
from pymodbus.constants import Endian
from pymodbus.factory import ClientDecoder
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.transaction import ModbusRtuFramer
from serial import EIGHTBITS
from serial import PARITY_EVEN
from serial import STOPBITS_ONE
from twisted.internet import protocol
from twisted.internet import serialport, reactor

FORMAT = ('%(asctime)-15s %(threadName)-15s '
      '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
logger = logging.getLogger()
logger.setLevel(logging.INFO)


def readDevices(modbusRTUDevice):
    deviceIP = modbusRTUDevice["ip"]
    devicePort = modbusRTUDevice["port"]
    logger.info("Connecting to Modbus RTU device at address {0}".format(deviceIP +    ":" + str(devicePort)))
    modbusClientFactory = CustomModbusClientFactory()
    modbusClientFactory.address = deviceIP
    modbusClientFactory.modbusDevice = modbusRTUDevice
    SerialModbusClient(modbusClientFactory, devicePort, reactor, baudrate=9600, bytesize=EIGHTBITS,
                   parity=PARITY_EVEN, stopbits=STOPBITS_ONE, timeout=0.2, xonxoff=0, rtscts=0)
    Thread(target=reactor.run, args=(False,)).start()  # @UndefinedVariable


class SerialModbusClient(serialport.SerialPort):

    def __init__(self, factory, *args, **kwargs):
        serialport.SerialPort.__init__(self, factory.buildProtocol(), *args, **kwargs)


class CustomModbusClientFactory(protocol.ClientFactory):
    modbusDevice = {}

    def buildProtocol(self, addr=None):
        modbusClientProtocol = CustomModbusClientProtocol()
        modbusClientProtocol.factory = self
        modbusClientProtocol.modbusDevice = self.modbusDevice
        return modbusClientProtocol

    def clientConnectionLost(self, connector, reason):
        modbusTcpDeviceIP = self.modbusDevice["ip"]
        modbusTcpDevicePort = self.modbusDevice["port"]
        logger.critical("Connection lost with device running on {0}:{1}.".format(modbusTcpDeviceIP, modbusTcpDevicePort))
        logger.critical("Root Cause : {0}".format(reason))
        connector.connect()

    def clientConnectionFailed(self, connector, reason):
        modbusTcpDeviceIP = self.modbusDevice["ip"]
        modbusTcpDevicePort = self.modbusDevice["port"]
        logger.critical("Connection failed with device running on {0}:{1}.".format(modbusTcpDeviceIP, modbusTcpDevicePort))
        logger.critical("Root Cause : {0}".format(reason))
        connector.connect()


class CustomModbusClientProtocol(ModbusClientProtocol):

    def connectionMade(self):
        framer = ModbusRtuFramer(ClientDecoder(), client=None)
        ModbusClientProtocol.__init__(self, framer)
        ModbusClientProtocol.connectionMade(self)
        deviceIP = self.modbusDevice["ip"]
        devicePort = self.modbusDevice["port"]
        logger.info("Modbus RTU device connected at address logger{0}".format(deviceIP + ":" + str(devicePort)))
        reactor.callLater(5, self.read)  # @UndefinedVariable

    def read(self):
        deviceIP = self.modbusDevice["ip"]
        devicePort = self.modbusDevice["port"]
        slaveAddress = self.modbusDevice["slaveAddress"]
        logger.info("Reading holding registers of Modbus RTU device at address {0}...".format(deviceIP + ":" + str(devicePort)))
        deferred = self.read_holding_registers(0, 1, unit=slaveAddress)
        deferred.addCallbacks(self.requestFetched, self.requestNotFetched)

    def requestNotFetched(self, error):
        logger.info("Error reading registers of Modbus RTU device : {0}".format(error))
        sleep(0.5)

    def requestFetched(self, response):
        logger.info("Inside request fetched...")
        decoder = BinaryPayloadDecoder.fromRegisters(response.registers, byteorder=Endian.Big, wordorder=Endian.Big)
        skipBytesCount = 0
        decoder.skip_bytes(skipBytesCount)
        registerValue = decoder.decode_16bit_int()
        skipBytesCount += 2
        logger.info("Sensor updated to value '{0}'.".format(registerValue))
        reactor.callLater(5, self.read)  # @UndefinedVariable


readDevices({"ip": "127.0.0.1", "port": "/dev/ttyUSB0", "slaveAddress": 1})

输出:

2019-02-03 00:39:00,623 MainThread      INFO     TestRTU:26       Connecting to Modbus RTU device at address 127.0.0.1:/dev/ttyUSB0
2019-02-03 00:39:00,628 MainThread      INFO     TestRTU:73       Modbus RTU device connected at address logger127.0.0.1:/dev/ttyUSB0
2019-02-03 00:39:05,634 Thread-1        INFO     TestRTU:80       Reading holding registers of Modbus RTU device at address 127.0.0.1:/dev/ttyUSB0...
2019-02-03 00:39:05,676 Thread-1        INFO     TestRTU:89       Inside request fetched...
2019-02-03 00:39:05,677 Thread-1        INFO     TestRTU:95       Sensor updated to value '26'.

serialport.SerialPort.init(...)构造负责初始化所有必需的参数用于与设备的串行通信。你只需要更新您的设备设置在这里和运行代码。 SerialModbusClient(modbusClientFactory, devicePort, reactor, baudrate=9600, bytesize=EIGHTBITS, parity=PARITY_EVEN, stopbits=STOPBITS_ONE, timeout=0.2, xonxoff=0, rtscts=0)

© www.soinside.com 2019 - 2024. All rights reserved.