Описание
В настоящее время у меня есть шина RS-485 с 3 Raspberry Pi, на каждой из которых работает pymodbus (синхронизация - 1 мастер / клиент и 2 подчиненных устройства / сервера). Отправка команд на индивидуальный адрес каждого сервера работает должным образом. Однако широковещательные сообщения на адрес 0 дают неверное сообщение отладки идентификатора устройства на серверах, поэтому каждый сервер отклоняет команду от мастера. Прочитав предыдущие выпуски и документацию, я попытался добавить константу enable_broadcast в каждую конфигурацию, но безуспешно. Что-то не так с моей конфигурацией?
Версии
- Python: 2.7.16
- Pymodbus: 2.3.0
Код и журналы
Код
Раб 1
#!/usr/bin/env python
import serial
from pymodbus.server.sync import StartSerialServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusBinaryFramer
# --------------------------------------------------------------------------- #
# Logging
# --------------------------------------------------------------------------- #
import logging
FORMAT = (' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def run_server():
block = ModbusSequentialDataBlock(0, [17]*100)
slave = {
0x01: ModbusSlaveContext(di=block, co=block, hr=block, ir=block),
}
context = ModbusServerContext(slaves=slave, single=False)
identity = ModbusDeviceIdentification()
identity.VendorName = 'Pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'URL'
identity.ProductName = '#1 Test Slave'
identity.ModelName = 'Research Testbed'
identity.MajorMinorRevision = '2.3.0'
StartSerialServer(context, framer=ModbusRtuFramer, identity=identity,
port='/dev/ttySC0', timeout=1, baudrate=115200, enable_broadcast=True)
if __name__ == "__main__":
run_server()
Раб 2:
#!/usr/bin/env python
import serial
from pymodbus.server.sync import StartSerialServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusBinaryFramer
# --------------------------------------------------------------------------- #
# Logging
# --------------------------------------------------------------------------- #
import logging
FORMAT = (' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def run_server():
block = ModbusSequentialDataBlock(0, [17]*100)
slave = {
0x0A: ModbusSlaveContext(di=block, co=block, hr=block, ir=block, zero_mode=True),
}
context = ModbusServerContext(slaves=slave, single=False)
identity = ModbusDeviceIdentification()
identity.VendorName = 'Pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'URL'
identity.ProductName = '#3 Test Slave'
identity.ModelName = 'Research Testbed'
identity.MajorMinorRevision = '2.3.0'
StartSerialServer(context, framer=ModbusRtuFramer, identity=identity,
port='/dev/ttySC0', timeout=1, baudrate=115200, enable_broadcast = True)
if __name__ == "__main__":
run_server()
Мастер:
#!/usr/bin/env python
import serial
from pymodbus.repl.client import ModbusSerialClient as ModbusClient
import logging
#-------------------------------------------#
# Logging
#-------------------------------------------#
FORMAT = ('%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
#-------------------------------------------#
# Client Initialization
#-------------------------------------------#
client = ModbusClient(method='rtu', port='/dev/ttySC0', timeout=2,
baudrate=115200, broadcast_enable=True)
#-------------------------------------------#
# Command Interface
#-------------------------------------------#
def command_switch(UNIT , command):
#Command Switch
if command == 1:
print(client.read_device_information(read_code=0x02, object_id=4, unit = UNIT))
elif command == 2:
print(client.read_coils(0,8, unit=UNIT))
elif command == 3:
response = client.read_holding_registers(0,4,unit=UNIT)
print(response)
elif command == 4:
start = input("Enter starting address of coil (0-7 available): ")
number = input("Select number of coils to write: ")
value = input("Enter value to write (0-False, 1-True): ")
write_coil(UNIT, start, number, value)
elif command == 5:
rq = client.write_registers(1, [2, 3, 4], unit = 0)
assert(not rq.isError())
def write_coil(UNIT, start, number, value):
#Verify coil address is valid
if (start + number) >= 8:
number = start + number % 8;
#Write intended value
holder = False
if value:
holder = True
#if multiple use write_coils else write_coil
if number > 1:
rq = client.write_coils(start, [holder]*number, unit=UNIT)
else:
rq = client.write_coil(start, holder, unit=UNIT)
if __name__ == "__main__":
client.connect()
command = 0
while command != 8:
command = input("Enter Command to run:\n1. Device ID\n2. Read Coils\n3. Read Register\n4. Write Coils\n8. Exit\n")
if command != 8:
UNIT = input("Enter Device Address:")
command_switch(UNIT, command)
client.close()
Журналы:
Подчиненный 1 - адрес-1
DEBUG sync :46 Client Connected [/dev/ttySC0:/dev/ttySC0]
DEBUG sync :580 Started thread to serve client
DEBUG rtu_framer :180 Getting Frame - 0x5 0x0 0x0 0xff 0x0
DEBUG factory :137 Factory Request[WriteSingleCoilRequest: 5]
DEBUG rtu_framer :115 Frame advanced, resetting header!!
DEBUG context :64 validate: fc-[5] address-1: count-1
DEBUG context :90 setValues[5] 1:1
DEBUG context :78 getValues fc-[5] address-1: count-1
DEBUG sync :144 send: [WriteCoilResponse(0) => 1]- 01050000ff008c3a
DEBUG rtu_framer :229 Not a valid unit id - 10, ignoring!!
DEBUG rtu_framer :128 Resetting frame - Current Frame in buffer - 0xa 0x1 0x0 0x0 0x0 0x8 0x3c 0xb7
DEBUG rtu_framer :232 Frame check failed, ignoring!!
DEBUG rtu_framer :128 Resetting frame - Current Frame in buffer - 0xa 0x1 0x1 0xff 0x13 0xec
DEBUG rtu_framer :229 Not a valid unit id - 0, ignoring!!
DEBUG rtu_framer :128 Resetting frame - Current Frame in buffer - 0x0 0x5 0x0 0x0 0xff 0x0 0x8d 0xeb
Подчиненный 2: адрес-10
DEBUG sync :46 Client Connected [/dev/ttySC0:/dev/ttySC0]
DEBUG sync :580 Started thread to serve client
DEBUG rtu_framer :229 Not a valid unit id - 1, ignoring!!
DEBUG rtu_framer :128 Resetting frame - Current Frame in buffer - 0x1 0x5 0x0 0x0 0xff 0x0 0x8c 0x3a 0x1 0x5 0x0 0x0 0xff 0x0 0x8c 0x3a
DEBUG rtu_framer :180 Getting Frame - 0x1 0x0 0x0 0x0 0x8
DEBUG factory :137 Factory Request[ReadCoilsRequest: 1]
DEBUG rtu_framer :115 Frame advanced, resetting header!!
DEBUG context :64 validate: fc-[1] address-0: count-8
DEBUG context :78 getValues fc-[1] address-0: count-8
DEBUG sync :144 send: [ReadBitResponse(8)]- 0a0101ff13ec
DEBUG rtu_framer :229 Not a valid unit id - 0, ignoring!!
DEBUG rtu_framer :128 Resetting frame - Current Frame in buffer - 0x0 0x5 0x0 0x0 0xff 0x0 0x8d 0xeb
Мастер:
Enter Command to run:
1. Device ID
2. Read Coils
3. Read Register
4. Write Coils
8. Exit
4
Enter Device Address:1
Enter starting address of coil (0-7 available): 0
Select number of coils to write: 1
Enter value to write (0-False, 1-True: 1
DEBUG transaction :115 Current transaction state - IDLE
DEBUG transaction :120 Running transaction 1
DEBUG transaction :219 SEND: 0x1 0x5 0x0 0x0 0xff 0x0 0x8c 0x3a
DEBUG sync :75 New Transaction state 'SENDING'
DEBUG transaction :228 Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG transaction :304 Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG transaction :233 RECV: 0x1 0x5 0x0 0x0 0xff 0x0 0x8c 0x3a
DEBUG rtu_framer :180 Getting Frame - 0x5 0x0 0x0 0xff 0x0
DEBUG factory :266 Factory Response[WriteSingleCoilResponse: 5]
DEBUG rtu_framer :115 Frame advanced, resetting header!!
DEBUG transaction :383 Adding transaction 1
DEBUG transaction :394 Getting transaction 1
DEBUG transaction :193 Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
Enter Command to run:
1. Device ID
2. Read Coils
3. Read Register
4. Write Coils
8. Exit
2
Enter Device Address:10
DEBUG transaction :115 Current transaction state - TRANSACTION_COMPLETE
DEBUG transaction :120 Running transaction 2
DEBUG transaction :219 SEND: 0xa 0x1 0x0 0x0 0x0 0x8 0x3c 0xb7
DEBUG rtu_framer :264 Changing state to IDLE - Last Frame End - 1595270440.95, Current Time stamp - 1595270458.87
DEBUG sync :75 New Transaction state 'SENDING'
DEBUG transaction :228 Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG transaction :304 Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG transaction :233 RECV: 0xa 0x1 0x1 0xff 0x13 0xec
DEBUG rtu_framer :180 Getting Frame - 0x1 0x1 0xff
DEBUG factory :266 Factory Response[ReadCoilsResponse: 1]
DEBUG rtu_framer :115 Frame advanced, resetting header!!
DEBUG transaction :383 Adding transaction 10
DEBUG transaction :394 Getting transaction 10
DEBUG transaction :193 Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
{u'function_code': 1, u'bits': [True, True, True, True, True, True, True, True]}
Enter Command to run:
1. Device ID
2. Read Coils
3. Read Register
4. Write Coils
8. Exit
4
Enter Device Address:0
Enter starting address of coil (0-7 available): 0
Select number of coils to write: 1
Enter value to write (0-False, 1-True: 1
DEBUG transaction :115 Current transaction state - TRANSACTION_COMPLETE
DEBUG transaction :120 Running transaction 3
DEBUG transaction :219 SEND: 0x0 0x5 0x0 0x0 0xff 0x0 0x8d 0xeb
DEBUG rtu_framer :264 Changing state to IDLE - Last Frame End - 1595270459.16, Current Time stamp - 1595270469.71
DEBUG sync :75 New Transaction state 'SENDING'
DEBUG transaction :223 Changing transaction state from 'SENDING' to 'TRANSACTION_COMPLETE'
Traceback (most recent call last):
File "modbus-client-rtu.py", line 62, in <module>
command_switch(UNIT, command)
File "modbus-client-rtu.py", line 36, in command_switch
write_coil(UNIT, start, number, value)
File "modbus-client-rtu.py", line 52, in write_coil
rq = client.write_coil(start, holder, unit=UNIT)
File "/home/pi/.local/lib/python2.7/site-packages/pymodbus/repl/client.py", line 112, in write_coil
if not resp.isError():
AttributeError: 'str' object has no attribute 'isError'