1

I am working on a slave computer and want to save the data transmitted from the master via Modbus RS485, into a text file. The master computer constantly send writing and reading request to the slave computer I am working on, below is a picture captured by serial port monitor.

enter image description here

I just found with minimalmodbus you can read registers. But it seems to only work if you are a master device. Can I do something similar but on a slave computer? http://minimalmodbus.readthedocs.io/en/master/usage.html

#!/usr/bin/env python
import minimalmodbus

instrument = minimalmodbus.Instrument('/dev/ttyUSB1', 1) # port name, slave 
#address (in decimal)

## Read temperature (PV = ProcessValue) ##
temperature = instrument.read_register(289, 1) # Registernumber, number of 
#decimals
print temperature

## Change temperature setpoint (SP) ##
NEW_TEMPERATURE = 95
instrument.write_register(24, NEW_TEMPERATURE, 1) # Registernumber, value, 
#number of decimals for storage
Yang
  • 177
  • 4
  • 20
  • You can use PyModbus to create a server on your slave device, I am not sure if your slave device is already running a modbus slave or not in any case Refer these examples https://github.com/riptideio/pymodbus/blob/master/examples/common/updating-server.py , https://github.com/riptideio/pymodbus/blob/master/examples/contrib/serial-forwarder.py, https://github.com/riptideio/pymodbus/blob/master/examples/common/synchronous-server.py. – Sanju Dec 23 '17 at 16:28

2 Answers2

2

modbus-tk makes possible to write your own modbus slave.

Here is an example running a RTU server with 100 holding registers starting at adress 0 :

import sys

import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
import serial


PORT = 0
#PORT = '/dev/ptyp5'

def main():
    """main"""
    logger = modbus_tk.utils.create_logger(name="console", record_format="%(message)s")

    #Create the server
    server = modbus_rtu.RtuServer(serial.Serial(PORT))

    try:
        logger.info("running...")
        logger.info("enter 'quit' for closing the server")

        server.start()

        slave_1 = server.add_slave(1)
        slave_1.add_block('0', cst.HOLDING_REGISTERS, 0, 100)
        while True:
            cmd = sys.stdin.readline()
            args = cmd.split(' ')

            if cmd.find('quit') == 0:
                sys.stdout.write('bye-bye\r\n')
                break

    finally:
        server.stop()

if __name__ == "__main__":
    main()

I hope it helps

luc
  • 41,928
  • 25
  • 127
  • 172
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/18631668) – The fourth bird Jan 26 '18 at 09:24
  • OK, i replaced the link with some code. However, the link was pointing to the library documentation which should stay up to date. – luc Jan 26 '18 at 09:33
  • Thanks! It seems to be able to open a port. But how can I read the message from the master? Can I read it as a text? Where are the registers exactly on my computer? – Yang Jan 26 '18 at 16:04
  • the master is in charge of sending a query to the salve to get register value. registers are just numbers that can be read / write by a modbus query. – luc Jan 26 '18 at 17:03
  • Do you mean that only the master can I pull out the values in the registers? If I'm running python on a slave, I can't access the registers? – Yang Jan 27 '18 at 09:10
  • The slave (in most cases a PLC) is responding to queries sent by the master. The master can send queries to write the values of registers. but the communication is initiated by the master – luc Jan 27 '18 at 13:33
  • That's correct. But in this case, our master is a Siemens master PLC, which keeps sending the readings of other slaves (sensors) to this slave (my PC). Is it possible to extract the queries with modbus_tk.modbus.Slave.get_values? – Yang Jan 29 '18 at 09:20
  • Yes, it is possible with modbus_tk.modbus.Slave.get_values – luc Jan 29 '18 at 09:49
  • Thanks! But it seems to be working only I take out the cmd = sys.stdin.readline() part. Are the queries from the master read by sys.stdin.readline() ? – Yang Jan 29 '18 at 10:49
  • Hi @luc thanks for the help. Another question is how to set the slave to represent a signed integer instead of an unsigned. For example, now I use 16 bits data, (FC19) HEX should represent -999 decimal , but now it reads as 64537. Thanks! – Yang Feb 09 '18 at 14:14
  • Hello @Yang, it could be another question on SO :-) You can pass a data_format flag to convert the values : See https://github.com/ljean/modbus-tk/blob/master/examples/tcpmaster_example.py For signed values, it should be ">b" See struct module for details https://docs.python.org/2/library/struct.html – luc Feb 09 '18 at 14:34
  • Hi @luc, I created a new question, can you please have a look: https://stackoverflow.com/questions/48708648/modbus-tk-rtu-slave-holding-register-read-signed-integer. – Yang Feb 09 '18 at 15:05
  • Hi @Yang, Sorry I misunderstood your question. I'll answer on the other one. – luc Feb 09 '18 at 15:10
  • Hi @luc, is it possible to capture the master query message with Modbus-tk? for example, 01 10 00 64 00 02 04 00 63 00 0A? Ideally, I would like to have something like: http://www.modbustools.com/poll_traffic.html. Thanks! – Yang Feb 14 '18 at 10:57
  • @Yang There is a "hook" mechanism that should allow to do something like this. – luc Feb 14 '18 at 13:04
  • Hi @luc thanks. Could you guide me a little about how can I use this function? Are there any examples available? – Yang Feb 14 '18 at 13:06
  • Hello @Yang, I suggest that you ask the question to the modus_tk mailing list or on the hither repo. It is easier to answer than in comments. – luc Feb 16 '18 at 17:30
  • Hi @luc, I have posted the question in the mailing list. Could you please take a look? Thanks. https://groups.google.com/forum/#!topic/modbus-tk/rEvAIvCTsUI – Yang Feb 20 '18 at 14:22
0

You may want to manage serial port directly.

For doing this, you can use the pyserial module and you must know how Modbus Protocol works.

A base configuration could be:

import serial

port = '/dev/ttyUSB1'
serial_comunication = serial.Serial(port, baudrate=4800, timeout=0.75)
serial_comunication.write(b'frame')
answer = serial_comunication.read(255)
serial_comunication.close()
print answer.decode()
Gsk
  • 2,929
  • 5
  • 22
  • 29