'[Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 8 bytes (0 received)'
'[Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 8 bytes (0 received)'
我正在尝试将我的 raspberry pi 用作 modbus 从站,并从我的常规 windows 机器(代表 modbus 主站)获取数据。现在从机和主机都在同一台 (windows) 机器上 运行,以预先尝试。
这是我根据pymodbus的需要改编的modbus slave updating server example:
#!/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()
它基本上只是更新温度值和 window 传感器的 on/off-values。
现在,当我尝试通过 modbus master 获取数据时,我再次从 pymodbus synchronous client example 改编而来,我收到一条错误消息:
'[Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 8 bytes (0 received)'
from the assert-statement in line 48 and 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 协议,所以我很难弄清楚为什么会出现这个错误。如果有人能帮助我更好地理解它并理想地解决这个问题,我会非常高兴。
在阅读 register/coil 时使用 unit
关键字参数而不是 SLAVE
解决了这个问题:
所以而不是
co_data = client.read_coils(address=contact_slave["coils"], count=1, SLAVE=contact_slave["id"])
assert(not co_data.isError())
log.debug("Read holding registers")
hr_data = client.read_holding_registers(address=temperature_slave["holding_registers"], count=1, SLAVE=temperature_slave["id"])
写
co_data = client.read_coils(address=contact_slave["coils"], count=1, UNIT=contact_slave["id"])
assert(not co_data.isError())
log.debug("Read holding registers")
hr_data = client.read_holding_registers(address=temperature_slave["holding_registers"], count=1, UNIT=temperature_slave["id"])
我正在尝试将我的 raspberry pi 用作 modbus 从站,并从我的常规 windows 机器(代表 modbus 主站)获取数据。现在从机和主机都在同一台 (windows) 机器上 运行,以预先尝试。
这是我根据pymodbus的需要改编的modbus slave updating server example:
#!/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()
它基本上只是更新温度值和 window 传感器的 on/off-values。 现在,当我尝试通过 modbus master 获取数据时,我再次从 pymodbus synchronous client example 改编而来,我收到一条错误消息:
'[Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 8 bytes (0 received)' from the assert-statement in line 48 and 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 协议,所以我很难弄清楚为什么会出现这个错误。如果有人能帮助我更好地理解它并理想地解决这个问题,我会非常高兴。
在阅读 register/coil 时使用 unit
关键字参数而不是 SLAVE
解决了这个问题:
所以而不是
co_data = client.read_coils(address=contact_slave["coils"], count=1, SLAVE=contact_slave["id"])
assert(not co_data.isError())
log.debug("Read holding registers")
hr_data = client.read_holding_registers(address=temperature_slave["holding_registers"], count=1, SLAVE=temperature_slave["id"])
写
co_data = client.read_coils(address=contact_slave["coils"], count=1, UNIT=contact_slave["id"])
assert(not co_data.isError())
log.debug("Read holding registers")
hr_data = client.read_holding_registers(address=temperature_slave["holding_registers"], count=1, UNIT=temperature_slave["id"])