Using: python3, pyModbusTCP, Linux, Raspberry pi 4, ViewMarq by Automation Direct
I have a digital display board that can receive ModBusTCP ascii packets. The information below is similar to what I am trying to send as a test message.
<ID 30><CLR><WIN 0 0 287 31><POS 0 0><LJ><BL N><CS 0><GRN><T>Test</T>
I am new to python Modbus and am trying to use a pyModbus client to send data to its holding register of 411000 via port 502 which I believe is just 11000 by dropping the 4. I have set up a simple client script that can communicate with the board but I have to encode the message to send it to the register. In the world of PLCs this is much simpler but that isnt an option here.
Using the windows application to populate the board, my Wireshark modbus data was detected as follows:
Ethernet II, Src: Dell_63:da:e2 (34:48:ed:63:da:e2), Dst: FACTSEng_06:6c:fc (60:52:d0:06:6c:fc) Internet Protocol Version 4, Src: 169.254.108.210, Dst: 169.254.108.223 Transmission Control Protocol, Src Port: 55053, Dst Port: 502, Seq: 1, Ack: 1, Len: 85 Modbus/TCP Transaction Identifier: 256 Protocol Identifier: 0 Length: 79 Unit Identifier: 1 Modbus .001 0000 = Function Code: Write Multiple Registers (16)<nl> Reference Number: 10999 Word Count: 36 Byte Count: 72 Register 10999 (UINT16): 18748 Register 11000 (UINT16): 8260 Register 11001 (UINT16): 12339 Register 11002 (UINT16): 15422 Register 11003 (UINT16): 19523 Register 11004 (UINT16): 15954 Register 11005 (UINT16): 22332 Register 11006 (UINT16): 20041 Register 11007 (UINT16): 12320 Register 11008 (UINT16): 12320 Register 11009 (UINT16): 12832 Register 11010 (UINT16): 14136 Register 11011 (UINT16): 13088 Register 11012 (UINT16): 15921 Register 11013 (UINT16): 20540 Register 11014 (UINT16): 21327 Register 11015 (UINT16): 12320 Register 11016 (UINT16): 12320 Register 11017 (UINT16): 15422 Register 11018 (UINT16): 19020 Register 11019 (UINT16): 15422 Register 11020 (UINT16): 19522 Register 11021 (UINT16): 20000 Register 11022 (UINT16): 15422 Register 11023 (UINT16): 21315 Register 11024 (UINT16): 12320 Register 11025 (UINT16): 15422 Register 11026 (UINT16): 21063 Register 11027 (UINT16): 15950 Register 11028 (UINT16): 21564 Register 11029 (UINT16): 21566 Register 11030 (UINT16): 29541 Register 11031 (UINT16): 15476 Register 11032 (UINT16): 21551 Register 11033 (UINT16): 3390 Register 11034 (UINT16): 52237
From here, I am a bit confused as to what to do next. I tried reading those register addresses but saw nothing there.
from pyModbusTCP.client import ModbusClient client = ModbusClient('169.254.108.223', port=502) client.open() print(client.read_holding_registers(10999,100))
and received…
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,..... <all 100 zeros>]
Can someone help me understand if I’m moving in the right direction and what should I be doing next? I’m trying to keep this as simple as possible and I appreciate the help.
Thank you in advance.
Update:
After a suggestion I looked deeper into the documentation. The documentation of the display does these registers immediately go back to 0 when the execution is complete. From the docs *
c) Word Swap and Byte Swap should be checked assuming the selections are Off (default) in the ViewMarq display. d) Slave Modbus Memory Starting Address is the location of the Command Block within the ViewMarq display (400000+11000 = 411000). e) The Function Code should be set to 16 – Write Multiple Registers.
I have to admit. I have no idea how to write a payload. I rewrote the code and tried a payload construction approach.
from pymodbus.constants import Endian from pymodbus.payload import BinaryPayloadDecoder from pymodbus.payload import BinaryPayloadBuilder from pymodbus.client.sync import ModbusTcpClient as ModbusClient from pymodbus.compat import iteritems from collections import OrderedDict client = ModbusClient('169.254.108.223', port=502) client.connect() builder = BinaryPayloadBuilder(byteorder=Endian.Little, wordorder=Endian.Little) builder.add_string("<ID 30><CLR>""$0D") #$0D is the termination code in the docs payload = builder.build() client.write_registers(10999, payload, skip_encode=True, unit=1)
This didnt work. It ran but the board didn’t update. Suggestions are very welcome.
Advertisement
Answer
This is not a complete solution for your problem, but only a suggestion what to do next.
Read the documentation of the display.
- Maybe the command buffer registers are write only?
- Or maybe you will read all 0 when the display has processed the command?
Try to read the response buffer registers.
Convert the data from your Wireshark log to hex:
18748
=0x493c
->0x49
='I'
0x3c
='<'
-> little endian"<I"
8260
=0x2044
->0x20
=' '
0x44
='D'
-> little endian"D "
12339
=0x3033
->0x30
='0'
0x33
='3'
-> little endian"30"
These 3 values written to registers correspond to "<ID 30"
etc.
So every Modbus register seems to correspond to 2 bytes of the buffer in little-endian byte order.
Most probably it is the same for the response buffer.
Edit after question has been edited:
If your program does not work, compare the data sent from your program with the data sent from the Windows application, e.g. using Wireshark.