HOWTO Read Device Identification

1,887 views
Skip to first unread message

Justin Findlay

unread,
May 30, 2012, 8:30:33 PM5/30/12
to pymo...@googlegroups.com
Read Device Identification is described in section 6.21 of the MODBUS Application Protocol Specification V1.1b

http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf

and I believe I've found the relevant pymodbus code here:

http://readthedocs.org/docs/pymodbus/en/latest/library/mei-message.html#pymodbus.mei_message.ReadDeviceInformationRequest

I have instantiated a pymodbus ModbusSerialClient like this:

client = ModbusSerialClient(
    method='rtu',
    port='/dev/tts/1',
    baudrate=9600,
    bytesize=8,
    parity='N',
    stopbits=2,
    timeout=1.5,
    writeTimeout=1.5)

but I don't know how to execute the request.  I've tried the following:

>>> from pymodbus.client.sync import ModbusSerialClient as ModbusClient
>>> from pymodbus.mei_message import ReadDeviceInformationRequest
>>> c = ModbusClient(method='rtu',port='/dev/tts/1',baudrate=9600,bytesize=8,parity='N',stopbits=2,timeout=1.5,writeTimeout=1.5)
>>> req = ReadDeviceInformationRequest(01,0x00)
>>> c.execute(req)
>>>

but there is no return value like the read_* functions in modbus/client/common.py.  Am I doing this correctly?  Is there a simpler way to do this?  I feel as though I need to implement a read_device_information() in the manner of ModbusClientMixin.read_coils(), but I am unsure if this is how this should be done.


Justin

Bashwork

unread,
Jun 18, 2012, 10:59:33 AM6/18/12
to pymo...@googlegroups.com
Justin,

Sorry your message never made it to my inbox.  What device are you sending your requests to (and does it support the device information request).  Also, are you using the latest code from github?

Sorry again for the late reply,

Galen

Bashwork

unread,
Jun 18, 2012, 4:29:48 PM6/18/12
to pymo...@googlegroups.com
I just tested the latest code on two reference implementations and it does indeed work as expected.  Can you tell me what version of the code you are using and what device you are hitting against?

Justin Findlay

unread,
Jun 25, 2012, 2:14:46 PM6/25/12
to pymo...@googlegroups.com
On Monday, June 18, 2012 2:29:48 PM UTC-6, Bashwork wrote:
I just tested the latest code on two reference implementations and it does indeed work as expected.  Can you tell me what version of the code you are using and what device you are hitting against?

Sorry for not replying sooner.  I'm communicating from a debian single board computer to a Morningstar charge controller.  ReadDeviceIdentification should work on this device since it's advertized in the manual.  I have been using a recent github snapshot taken a few days before I posted this topic.

Currently I have portions of my system in a darkbox so that I can do some radiometer and laser calibrations, but I will try this again when I have a chance.


Justin

jvr

unread,
Jul 12, 2012, 11:16:00 AM7/12/12
to pymo...@googlegroups.com
Hi

I think you would need to set unit_id in the request:


>>> from pymodbus.client.sync import ModbusSerialClient as ModbusClient
>>> from pymodbus.mei_message import ReadDeviceInformationRequest
>>> c = ModbusClient(method='rtu',port='/dev/tts/1',baudrate=9600,bytesize=8,parity='N',stopbits=2,timeout=1.5,writeTimeout=1.5)
>>> req = ReadDeviceInformationRequest(01,0x00)
c.unit_id = 4   # or whatever
>>> c.execute(req)
>>>

At least I got it to communicate with that modification.

Still not complete working though... I just get a None response from the c.execute(reg). The problem seems to be related to IndexError raised in checkFrame (transaction.py) due to incorrectly calculated frame length. I don't get what calculateRtuFrameSize (mei_message.py) is supposed to be doing; at least the reported frame size seems to have little to do with buffer length. For example, in my test run has the following RTU frames:

TX: 04 2b 0e 01 00 bc 77
RX: 04 2b 0e 01 81 00 01 01 00 06 66 6f 6f 62 61 72 d7 3b

(Note: I assume the response from the embedded server I'm implementing is OK, but I don't have any tool for verifying this. The response is just hand-crafted according to the MODBUS specification. Any pointers to tools or test vectors would be appreciated).

RX frame has length of 18, yet the return value of calculateRtuFrameSize() is 113. This causes checkFrame() to set crc to an empty string and indexing that in assignment to crc_val raises IndexError.

It seems that I can get the checkFrame to work by just changing this:

frame_size = len(self.__buffer)  #self.__header['len']

Even then, the result has an empty information field for some reason, but at least the first field is decoded correctly.

>>> print c.information
{0: 'foobar', 215: ''}

Using newest pymodbus available from github and Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32 for what it's worth.

Almost working...

Cheers
JVR

jvr

unread,
Jul 12, 2012, 4:18:42 PM7/12/12
to pymo...@googlegroups.com
Correction:


On Thursday, July 12, 2012 6:16:00 PM UTC+3, jvr wrote:

>>> from pymodbus.client.sync import ModbusSerialClient as ModbusClient
>>> from pymodbus.mei_message import ReadDeviceInformationRequest
>>> c = ModbusClient(method='rtu',port='/dev/tts/1',baudrate=9600,bytesize=8,parity='N',stopbits=2,timeout=1.5,writeTimeout=1.5)
>>> req = ReadDeviceInformationRequest(01,0x00)
req.unit_id = 4   # or whatever
>>> c.execute(req)
>>>

JVR

Bashwork

unread,
Jul 12, 2012, 6:26:29 PM7/12/12
to pymo...@googlegroups.com
Justin,

I am sorry, I was testing with the TCP framer.  You are right, there was a bug in calculating the length of the device information response.  I have fixed the bug and you can pull latest from github for the following commit: 29ae36a7fe9a3fe157ac60758d70ef35a63cb1ef

As for testing to see if a message is valid, I have written a helper utility that can do just that (it is included in the examples code).  I have added your response to the messages file and you can run the decoder as follows:

./message-parser.py -p rtu -b -f messages
-p use the rtu parser
-b convert the message to binary
-f convert all the messages from the supplied file

This results in the following output:

================================================================================
Decoding Message 042b0e01810001010006666f6f626172d73b
================================================================================
ServerDecoder
--------------------------------------------------------------------------------
ClientDecoder
--------------------------------------------------------------------------------
name            = ReadDeviceInformationResponse
read_code       = 0x1
information     =
  0            => foobar
more_follows    = 0x0
protocol_id     = 0x0
unit_id         = 0x4
sub_function_code = 0xe
next_object_id  = 0x1
number_of_objects = 0x1
conformity      = 0x81
check           = 0x0
transaction_id  = 0x0
documentation   = 


On Wednesday, May 30, 2012 7:30:33 PM UTC-5, Justin Findlay wrote:

jvr

unread,
Jul 13, 2012, 3:13:22 AM7/13/12
to pymo...@googlegroups.com
Hi

Thanks mate, seems to be working now. Also the decoder tool looks quite usedful.

Juho

(Sorry for hijacking the thread :P)

Mesias

unread,
Sep 4, 2012, 10:58:18 AM9/4/12
to pymo...@googlegroups.com
Is it possible to discover a whole serial network with this feature ? reading device to device to find out the devices connected on the serial ?

Bashwork

unread,
Sep 4, 2012, 12:09:21 PM9/4/12
to pymo...@googlegroups.com
I would imagine so if you just brute forced a python script to do so.  Just loop around creating a client, see if you can connect, and then issue a the request.
Reply all
Reply to author
Forward
0 new messages