python communication MODBUS TCP/IP raspberry pi and HMI - write value - python

I'm French student and i need your help in Python for my program.
I've got a program in my rapsberry in Python which acquire datas from temperature and hygrometry sensors.
I need to communicate these values to an Human Machine Interface supervisor by the MODBUS TCP/IP PROTOCOL to display and made some graphics of these values in my HMI
The IP adress of the raspberry : 172.16.0.2
The IP adress of the HMI : 172.16.0.10
I think I need to use package like pyModbusTCP or things like that but I don't understand how to use it.
Could you help me to understand how I made the communication between my Rpi and my HMI and for example how I could write the integer value 100 at the address index 1?
Thanks for all!
Antoine

MODBUS is a single-master protocol, meaning that there can only be one master, the rest of attached devices are slaves ( http://www.ni.com/white-paper/52134/en/ , similar to USB protocol, called host and device there ). In addition in MODBUS protocol a slave never starts a communications, slaves only answer to requests. Consequentially the machine on that your HMI runs has to be the MODBUS master /client ( this naming convention is a bit senseless )
For a quick general overview read this https://www.reddit.com/r/PLC/comments/7bqppu/using_raspberry_pi_as_modbus_slave_and/ and http://www.simplymodbus.ca/TCP.htm
pymodbus client / master on HMI machine
From this master / client you can send requests to the RPi ( MODBUS slave / server ) with its sensors using the following code ( if one of the sensors stores its data in a register that is presented to the bus as coil 1 by the pymodbus server that runs on the RPi, see below ). This is only an example there are other data blocks in MODBUS, namely Coils, Discrete Inputs, Input Registers, Holding Registers which of them you use depends on how you configure the MODBUS server on the RPi, normally Discrete Inputs and Input Registers are rarely used :
client = ModbusTcpClient('172.16.0.2')
client.write_coil(1, True)
result = client.read_coils(1,1)
print(result.bits[0])
client.close()
https://github.com/riptideio/pymodbus
pymodbus server / slave on Rpi
For this to work on the RPi has to run software ( pymodbus server ) that enables it as MODBUS slave / server and the sensors have to write their values into specific memory locations that are presented to MODBUS as coils / registers. How this can be done is in https://www.youtube.com/watch?v=p3Dgd0PDjnU and https://jacekhryniewicz.wixsite.com/website/raspberry-pi-with-modbus-tcp ( is a bit outdated )
In https://github.com/riptideio/pymodbus/blob/master/examples/common/asynchronous_server.py is a working example of a MODBUS server that has to run onthe RPi ( read the comments, especially the lines following # initialize your data store )
The word coils has its origin in the past of MODBUS protocol which was developed when electromechanical relays with coils were used in automation technology

Related

Multi clients modbus to single modbus server

I have two python scripts which need to get data from the same modbus server.
However they cannot be simultaneously connected to the same modbus server, so I am looking for a "proxy" software.
This proxy will then sequentially transfer the modbus queries to the modbus server.
Solution should run on debian 11 lite.
Thanks!
I have the same challenges before and ended up with Modbus-to-MQTT bridge solution, because each protocol has its limit, Modbus is designed for master-slave poll in nature and MQTT is good for multiple clients/subscribers.
Modbus + MQTT, such a combination is just nice and could be very powerful in modern IoT applications. You can try modpoll, which is a python-based Modbus tool and can run as a Modbus-to-MQTT bridge in your case.
Assuming you are dealing with Modbus TCP you can try modbus-proxy:
Many modbus devices support only one or very few clients. This proxy
acts as a bridge between the client and the modbus device. It can be
seen as a layer 7 reverse proxy. This allows multiple clients to
communicate with the same modbus device.
When multiple clients are connected, cross messages are avoided by
serializing communication on a first come first served REQ/REP basis.
EDIT: According to your comment below:
...it is RTU over a linux file descriptor /dev/ttyS1
That seems to me a not-so-straightforward way of saying that you are dealing with a serial link.
If that's the case I'm afraid you need to go back all the way to the physical layer.
If you have a point-to-point serial connection (no matter the voltage levels you have, they can be TTL 3.3VDC or RS-232) there is no way you can have more than one Modbus client connecting to the same server.
For a serial link to have more than two devices (two or multiple clients sending queries to a Modbus server, for instance) you need a way for the devices to take control of the bus when they communicate and let go of it when they are idle. An RS-485 multipoint serial link is the most frequent solution to this problem.
If you follow the link you will find many resources and documentation. That might be a bit overwhelming but it is actually very easy: instead of connecting RX to TX as you'd do for a normal serial port you will have two cables for each device (they are called A and B or D+ and D-) that you can put together. And you only need to add a TTL to RS-485 transceiver in between each device and the bus (or RS-232 to RS-485, depending on your devices).
There are a couple of nuances:
You might need terminating resistors, but that should only be the case if your devices are far away (more than several meters) from each other.
If you go for the cheapest transceivers you might end up being forced to toggle the bus in your software, which is not a good solution. See my answer here for more details. And better aim for something with automatic TX enable.
The most complete reference on all these topics I know of is Jan Axelson's book Serial Port Complete. It's a bit old (the last edition was released in 2007) but still very relevant. And you can find older editions secondhand for next to nothing. If you need to work with serial ports, this book will be a very valuable companion.
Final note: if you are not able or willing to mess with the phy layer, you might, of course, find other solutions that are more palatable. You might, for instance, implement a software forwarder to take queries from your clients and convert them to Modbus RTU to be sent to your server. Pymodbus includes an example, but since you did not elaborate much I'm not sure it will be useful for your situation.

Using serial ports over bluetooth with micro bit

I have correctly got a microbit working with serial communication via COM port USB.
My aim is to use COM over bluetooth to do the same.
Steps I have taken:
(on windows 10) bluetooth settings -> more bluetooth settings -> COM ports -> add -> incoming
in device manager changed the baud rate to match that of the microbit (115,200)
paired and connected to the microbit
tried to write to both the serial and uart bluetooth connection from the microbit to the PC (using a flashed python script)
using Tera Term, setup -> serial port... -> COM(number - in my case 4), with all necessary values (including 115,200 baud rate)
After doing all of these, I see no incoming message on Tera Term. Have I missed anything?
This is not directly possible via BLE UART communication because it uses different protocols (as mentioned above by ukBaz).
You are able to, however, communicate via custom BLE libraries such as bleak.
Bleak has some good examples on its github repo of how to scan GATT characteristics and services to find the TX and RX characteristics of your BLE device.
From there you're able to connect to the microbit directly over bluetooth and read and write to it's GATT table and not using the proprietary BLE protocols etc.
I'll make a tutorial at some point and link it back here when it's done.

Python read modbus over TCP

I have a modbus device and have connected a modbus RTU to ethernet converter ( and not modbus RTU to modbus TCP converter ).
All modules I have come across can read normal Modbus RTU, Modbus TCP, Modbus ASCII. But I haven't seen any module to read modbus through ethernet port.
When I tested using ModScan, I can see the data when I select Remote TELNET Server.
Is there a way I can read this data using python ??
That's a common case, the devices are remote serial/tcp converters. MOXA has tons of then.
You should understand that:
'modbus rtu' - this is serial modbus, contains data+crc16
'modbus tcp' - this is TcpHeader[6 bytes] + data.
'modbus rtu over tcp' - this is YOUR case.
Standard modbus tcp/rtu converting devices change not only physics (ethernet/rs485 eg) but also protocol itself, removing tcp header and adding crc.
Simple serial/tcp converters (like you have) do not modify protocol.
You can use your lovely PyModbus after you manually specify rtu-framer for tcp-client.
client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer)
https://pymodbus.readthedocs.io/en/latest/source/example/synchronous_client.html

Pyserial reads data but does not write

I have a Digi Transport WR41 cellular router that runs a it's own proprietary operating system and a Python 2.6 interpreter. The router has a serial port (RJ45) that I've connected to a serial port (DB9) on a Windows 7 PC. The cable wiring is a straight through configuration.
On the PC, I've installed RealTerm Serial Capture program and connected it to COM1.
I want to be able to read/write data through the serial connection using python (and pyserial).
My python script is very very basic:
import serial
ser = serial.Serial(port=0, baudrate=9600, parity=serial.PARITY_EVEN, timeout=1)
ser.write(‘hello world’)
#ser.read(1000)
When I send data from RealTerm, I can read it just fine in python via ser.read(1000). This works all day long.
However, when I try to send data from python via ser.write('hello world'), I am unable to see it in RealTerm.
Thinking it might be a RealTerm issue, I tried other emulator/capture programs on the PC: TeraTerm and Serial Port Monitor 6 (by Eltima), but I never saw the data show up.
Serial Port Monitor 6 was the only program to show some sort activity, but I still never saw my data. I don't know enough about serial communication to make any sense of the output, but here is an excerpt:
[19/02/2015 07:58:21]
435 IRP_MJ_DEVICE_CONTROL - Request operates a serial port (COM1)
STATUS_SUCCESS
IOCTL_SERIAL_WAIT_ON_MASK - Request is used to wait for the occurrence of any wait event specified by using an IOCTL_SERIAL_SET_WAIT_MASK request
Mask - 0x00000010 (EV_DSR)
----------------------------------------------------------------------------------
[19/02/2015 07:58:21]
437 IRP_MJ_DEVICE_CONTROL - Request operates a serial port (COM1)
STATUS_SUCCESS
IOCTL_SERIAL_GET_WAIT_MASK - Request returns the event wait mask that is currently set on a COM port
Mask - 0x00000119 (EV_CTS | EV_DSR | EV_RING | EV_RXCHAR)
----------------------------------------------------------------------------------
[19/02/2015 07:58:21]
439 IRP_MJ_DEVICE_CONTROL - Request operates a serial port (COM1)
STATUS_SUCCESS
IOCTL_SERIAL_GET_MODEMSTATUS - Request updates the modem status, and returns the value of the modem status register before the update
Modem Status - 0x00000080 (MS_RLSD_ON)
----------------------------------------------------------------------------------
The router has a counter for Bytes Sent. Every time I call ser.write('hello world'), I see it increment by the correct number of bytes.
I've looked at two similar issues on SO:
pySerial sends ASCII data but recieving device does not respond to it
PySerial can read but not write
I've verified that the device, RealTerm and the python code have consistent settings for the baudrate, parity, stopbits, control flow, etc.
Any other ideas why serial communication with pyserial would only work one way? Why would reads be allowed but not writes?
When I send data from RealTerm, I can read it just fine in python via ser.read(1000). This works all day long.
However, when I try to send data from python via ser.write('hello world'), I am unable to see it in RealTerm.
Are you sure that you can send 'hello world' maybe this is just filtered ?
Did you try with another command or at least another encoding format?

Pymodbus (Serial) over a tcp serial connection

I will be creating a connection between my Linux server and a cellular modem where the modem will act as a server for serial over TCP.
The modem itself is connected to a modbus device (industrial protocol) via an RS232 connection.
I would like to use pymodbus to facilitate talking to the end modbus device. However, I cannot use the TCP modbus option in PyModbus as the end device speaks serial modbus (Modbus RTU). And I cannot use the serial modbus option in Pymodbus as it expects to open an actual local serial port (tty device) on the linux server.
How can I bridge the serial connection such that the pymodbus library will see the connection as a local serial device?
There is no straightforward solution to trick your linux server into thinking that a MODBUS RTU is actually of MODBUS TCP connection.
In all cases, your modem will have to transfer data from TCP to serial (and the other way around). So I assume that:
1) somehow you can program your modem and instruct it to do whatever you want
2) the manufacturer of the modem has provided a built-in mechanism to do that.
If 1): you should program your modem so that it can replace TCP ADUs by RTU ADUs (and the other way around) when copying data from the TCP connection to the RS link.
If 2): simply provide your RTU frame to whatever API the manufacturer devised.
I actually was working on something similar and decided to make my own Serial/TCP bridge. Using virtual serial ports to handle the communication with each of the modems.
I used the minimalmodbus library although I had to modify it a little in order to handle the virtual serial ports.
I hope you solved your problem and if you didn't I can try to help you out.

Categories

Resources