'[输入/输出] Modbus错误:[无效的消息]接收到的消息不完整,预期至少8个字节(接收到0个字符''

问题描述 投票:1回答:1

我正在尝试将树莓派用作modbus从站,并从常规Windows计算机(代表modbus主站)中获取数据。现在,从属服务器和主服务器都在同一台(Windows)计算机上运行,​​以便事先进行尝试。

这是我从pymodbus updating server example适应我的需要的modbus从站:

    #!/usr/bin/env python
# --------------------------------------------------------------------------- #
# import the modbus libraries we need
# --------------------------------------------------------------------------- #
from pymodbus.server.asynchronous import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer

# --------------------------------------------------------------------------- #
# import the twisted libraries we need
# --------------------------------------------------------------------------- #
from twisted.internet.task import LoopingCall

# --------------------------------------------------------------------------- #
# configure the service logging
# --------------------------------------------------------------------------- #
import logging, random
logging.basicConfig(format="%(message)s")
log = logging.getLogger()
log.setLevel(logging.INFO)

# --------------------------------------------------------------------------- #
# define your callback process
# --------------------------------------------------------------------------- #
def update_temperature(kw):
    context = kw["context"]
    slave = kw["slave_info"] 
    functionCode_read = 3
    functionCode_write = 6

    # coils     :   0x0000  : fc=01 (read) fc=05 (write)
    # inputs    :   0x2710  : fc=02 (read)
    # inp.reg.  :   0x7530  : fc=04 (read)  
    # hold.reg. :   0x9C40  : fc=03 (read) fc=06 (write)

    values = context[slave["id"]].getValues(functionCode_read, slave["holding_registers"])
    log.info("old temperature values: " + str(values))

    for i in range(len(values)): # 
        if values[i] <= 16:
            values[i] = values[i]+1 if (random.random() >= 0.3) else values[i]-1
        elif values[i] >= 26:
            values[i] = values[i]+1 if (random.random() >= 0.7) else values[i]-1
        else:
            values[i] = values[i]+1 if (random.random() >= 0.5) else values[i]-1

    log.info("new temperature values: " + str(values))
    context[slave["id"]].setValues(functionCode_write, slave["holding_registers"], values)

def update_window_contact(kw):
    context = kw["context"]
    slave = kw["slave_info"] 
    functionCode_read = 1
    functionCode_write = 5

    # coils     :   0x0000  : fc=01 (read) fc=05 (write)
    # inputs    :   0x2710  : fc=02 (read)
    # inp.reg.  :   0x7530  : fc=04 (read)  
    # hold.reg. :   0x9C40  : fc=03 (read) fc=06 (write)

    values = context[slave["id"]].getValues(functionCode_read, slave["coils"])
    log.info("old contact values: " + str(values))

    for i in range(len(values)):
        if values[i] == 0:
            values[i] = 1 if (random.random() >= 0.95) else 0
        else: # value is 1
            values[i] = 0 if (random.random() >= 0.95) else 1

    log.info("new contact values: " + str(values))
    context[slave["id"]].setValues(functionCode_write, slave["coils"], values)


def run_updating_server():
    # ----------------------------------------------------------------------- # 
    # initializing devices
    # ----------------------------------------------------------------------- # 
    temperature_slave = { # temperature sensor
        "id": 0x01, 
        "coils": 0x0000,
        "inputs": 0x2710,
        "input_registers": 0x7530,
        "holding_registers": 0x9C40
    }
    contact_slave = { # window sensor
        "id": 0x02,
        "coils": 0x0000,
        "inputs": 0x2710,
        "input_registers": 0x7530,
        "holding_registers": 0x9C40
    } 

    store = {
        temperature_slave["id"]: ModbusSlaveContext( 
            co=ModbusSequentialDataBlock(address=temperature_slave["coils"], values=[None]),                  # coils  / discrete outp. (adress=0)
            di=ModbusSequentialDataBlock(address=temperature_slave["inputs"], values=[None]),              # inputs / discrete input (adress=10000)
            ir=ModbusSequentialDataBlock(address=temperature_slave["input_registers"], values=[None]),     # input register / analog input (adress=30000)
            hr=ModbusSequentialDataBlock(address=temperature_slave["holding_registers"], values=[16]),   # hold. register / analog outp. (adress=40000)
            zero_mode=True),
        contact_slave["id"]: ModbusSlaveContext( 
            co=ModbusSequentialDataBlock(address=temperature_slave["coils"], values=[1]),               # coils  / discrete outp. (adress=0)
            di=ModbusSequentialDataBlock(address=temperature_slave["inputs"], values=[None]),              # inputs / discrete input (adress=10000)
            ir=ModbusSequentialDataBlock(address=temperature_slave["input_registers"], values=[None]),     # input register / analog input (adress=30000)
            hr=ModbusSequentialDataBlock(address=temperature_slave["holding_registers"], values=[None]),     # hold. register / analog outp. (adress=40000)
            zero_mode=True)
    } 
    context = ModbusServerContext(slaves=store, single=False)

    # ----------------------------------------------------------------------- # 
    # initialize the server information
    # ----------------------------------------------------------------------- # 
    identity = ModbusDeviceIdentification()
    identity.VendorName = 'raspi2b'
    identity.ProductCode = 'r2b'
    identity.VendorUrl = 'http://hs-mannheim.de'
    identity.ProductName = 'Pymodbus Slave-Server'
    identity.ModelName = '2b'
    identity.MajorMinorRevision = '1.0.0'

    # ----------------------------------------------------------------------- # 
    # run the server you want
    # ----------------------------------------------------------------------- # 
    loop_temperature = LoopingCall(f=update_temperature, kw={"context":context, "slave_info": temperature_slave}) 
    loop_temperature.start(20, now=False) # initially delay by 1 sec

    loop_contact = LoopingCall(f=update_window_contact, kw={"context":context, "slave_info": contact_slave}) 
    loop_contact.start(20, now=False) # initially delay by 1 sec

    StartTcpServer(context, identity=identity, address=("localhost", 5020))

if __name__ == "__main__":
    run_updating_server()

它基本上只是更新温度值和窗户传感器的开/关值。现在,当我尝试通过modbus主站获取数据时,又一次从pymodbus synchronous client example改编而成,我看到一条错误消息:

'[输入/输出] Modbus错误:[无效的消息]接收到的消息不完整,预期至少8个字节(接收到0个字节)' 从第48和52行的断言声明

这是我的客户端实现:

#!/usr/bin/env python
# --------------------------------------------------------------------------- #
# import the various server implementations
# --------------------------------------------------------------------------- #
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
from influxdb import InfluxDBClient
# --------------------------------------------------------------------------- #
# configure the client logging
# --------------------------------------------------------------------------- #
import logging, json, time
FORMAT = ('%(asctime)-15s %(threadName)-15s '
          '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.INFO)


def run_sync_client():
    # ------------------------------------------------------------------------#
    # choose the client you want
    # ------------------------------------------------------------------------#
    client = ModbusClient("localhost", port=5020) #'192.168.0.10'
    client.connect()

    # ------------------------------------------------------------------------#
    # specify slave to query
    # ------------------------------------------------------------------------#
    temperature_slave = { # temperature sensor
        "id": 0x01, 
        "coils": 0x0000,
        "inputs": 0x2710,
        "input_registers": 0x7530,
        "holding_registers": 0x9C40
    }
    contact_slave = { # window sensor
        "id": 0x02,
        "coils": 0x0000,
        "inputs": 0x2710,
        "input_registers": 0x7530,
        "holding_registers": 0x9C41
    } 

    # ----------------------------------------------------------------------- #
    # example requests
    # ----------------------------------------------------------------------- #
    log.debug("Read from a Coil")
    co_data = client.read_coils(address=contact_slave["coils"], count=1, SLAVE=contact_slave["id"])
    assert(not co_data.isError())     # test that we are not an error

    log.debug("Read holding registers")
    hr_data = client.read_holding_registers(address=temperature_slave["holding_registers"], count=1, SLAVE=temperature_slave["id"])
    assert(not hr_data.isError())     # test that we are not an error

    # ----------------------------------------------------------------------- #
    # close the client
    # ----------------------------------------------------------------------- #
    client.close()

if __name__ == "__main__":
    run_sync_client()

我想我完全不了解modbus协议,因此我很难弄清为什么会发生此错误。如果有人可以帮助我更好地理解它并理想地解决此问题,我将非常高兴。

python modbus pymodbus
1个回答
0
投票

读取寄存器/线圈时使用unit关键字参数而不是SLAVE解决了此问题

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