Is it possible to use pyModbusTCP as modbus slave? - python

I'm perusing the pyModbusTCP with the intent of writing a Modbus slave running on Linux.
[begin rant]: pyModbusTCP uses the terms "client" and "server" instead of "slave/master", so the docs are a bit confusing. [end rant]
It seems all they do in the demos is use the library as a Master, either reading or writing from remote slave devices.
Is it possible to set up pyModbusTCP to act as a Modbus slave, listening to a port and allowing Modbus devices (PLCs, etc) to connect and read/write values from/to this slave?
As a bonus, is it possible to automatically execute a Python function (like an event) when a remote master reads or writes to/from this slave?
Thanks!

pyModbusTCP can work as Modbus slave. They call it “server”, you can find a simple example here http://pymodbustcp.readthedocs.io/en/latest/examples/server.html
Regarding your last question it looks like it’s not possible out of the box, but the source code looks relatively simple, maybe you can modify it. Specifically look at the DataBank class here https://github.com/sourceperl/pyModbusTCP/blob/master/pyModbusTCP/server.py

Related

Debugging a TCP client/server pair of applications on Windows?

I have a server application in .NET 6/VS2022 which creates a TCP listener, and a python 3 application which creates a socket to connect to the server application.
Rather than hopping back and forth between VS2022 and PyCharm with breakpoints in each, is there any way I can view the network communication, including contents with bytes and ASCII decode, source and remote endpoint, and source and remote process names and ids?
Solution
A simple way is to use the Wireshark GUI application. On devices that do not allow the installation of the GUI, the network data can be recorded using tshark to a file, transferred to a PC with GUI Wireshark and viewed in detail.
https://www.wireshark.org/
(On windows, the tshark is part of the Wireshark installation. In Linux, it is installed separately from the SW repository.)
Wireshark allows you to view everything you want from the captured data. It is necessary to correctly choose the interface from which the data is recorded. If the server and client are on the same PC, you must choose the localhost interface (the loopback i/f with the address 127.0.0.1).
Addition
The problem arises if the network communication is encrypted (SSL, e.g. HTTPS). Wireshark then displays the packets, but the payload is unreadable. Even this case has a solution, but significantly more complex. It is necessary to use keys/certificates from communicating peers in Wireshark.

modbus error failing to connect to ModbusTcpClient when reading/writing

Recently I have been tasked with a project involving reading Modbus data, specifically with the pymodbus package. before diving into this project I wanted to simulate some reading and writing of Modbus data (without having to use a machine) with python. Using the sample data they have on their homepage, I try to write using the client but encounter a Modbus error
Ive tried looking into the matter to see what I could dig up wonder if I need a server to write or read. However I am unsure as with my experiences with socket and serial I just needed an established connection with the correct port to simply write (however I understand that Modbus is different).
Here is the code
client = ModbusTcpClient('localhost')
client.write_coil(1, True)
result = client.read_coils(1,1)
print(result.bits[0])
client.close()
and here is my error "pymodbus.exceptions.ConnectionException: Modbus Error: [Connection] Failed to connect[ModbusTcpClient(localhost:502)]"
I expect the output to simply write Modbus without needing anything no necessarily listen on the other end, but instead I keep getting an error when trying to connect/write. (sorry if this is hard to comprehend, my brain is all over the place and I am extremely new to Modbus in general).
If you want to send Modbus queries and you don't have any Modbus hardware yet you need to run a dummy Modbus server on your computer.
You can take a look at the examples.
You might also need to add a rule to your firewall for port 502. If you are on Linux you can just switch ports to a higher number like 5020 on both ends to avoid this problem.

Serial Communication one to one

If this is a stupid question, please don't mind me. But I spent some time trying to find the answer but I couldn't get anything solid. Maybe this is a hardware question, but I figured I'd try here first.
Does Serial Communication only work one to one? The reason this came up is because I had an arduino board listening for communication on its serial port. I had a python script feed bytes to the port as well. However, whenever I opened up the arduino's serial monitor, the connection with the python script failed. The serial monitor also connects to the serial port for communication for its little text input field.
So what's the deal? Does serial communication only work between a single client and a single server? Is there a way to get multiple clients writing to the server? I appreciate your suggestions.
Multiple clients (e.g. Arduinos) communicating with one server (e.g. a desktop computer) is commonly done with the serial variant:
RS-485
This is a simple method widely used in industrial settings where you want to have many devices connected to one computer via one serial port. This type of arrangement is also called multi-drop, because one cable strings around a building with Tees that tap in and drop lines to each device.
The hardware for this is widely available. You can buy USB serial adapters that provide the hardware interface for a computer. Programmatically the port looks just like an RS232 port. For the Arduino you would just add a transceiver chip. A sea of serial transceivers exists, e.g.
Example computer USB adapter with 485 interface
Sample RS485 transceiver chip from Element14
All the devices hang on the same bus listening at the same time. A simple communication protocol used is just add a device address before every command. For example:
001SETLIGHT1 <- tells Arduino "001" to turn on the light
013SETLIGHT0 <- tells "013" to turn off the light
Any device hanging on the cable ignores commands that do not start with their address. When a device responds, it prepends its address.
001SETLIGHT1DONE <- response from device "001" that the command has been received and executed
The address in the response lets the receiving party know which device was talking.
Well, your question can be quite wide, so I'm going to layer my answer:
On the hardware side, the same pair of wires can work be shared with many devices. It is mostly a question of electronics (maintaining the signal in the good voltage range), and not having all devices writing to the serial port at the same time (or you'll get wreckage).
On the software side, on the host, yes you can share the same serial connection to a device with multiple processes. But that's not straight forward. I'll assume you're using an unix (macos or linux):
in unix, everything is a file, your serial connection is one too: /dev/ttyACM0 on linux, for example.
When you have a process opening that file, it will block it (using ioctl, iirc) so no other process can mess with that file too.
Then, you can input and output to that file using the process that opened it, that's all.
But hopefully, it is still possible to share the connection between processes. One of them would simply be to use the tee command, that will be able to get input from one process, and give it back output, and copy the output to another process. You can also do it from within python, by duplicating the file descriptor.
To easily output stuff that can be redirected the unix way (using pipes), you can use socat: http://www.dest-unreach.org/socat/
here's an usage example:
socat -,raw,echo=0,escape=0x0f /dev/ttyACM0,raw,echo=0,crnl
you may want to tweak it for your needs.
Edit:
I forgot about RS-485, which 'jdr5ca' was smart enough to recommend. My explanation below is restricted to RS-232, the more "garden variety" serial port. As 'jdr5ca' points out, RS-485 is a much better alternative for the described problem.
Original:
To expand on zmo's answer a bit, it is possible to share serial at the hardware level, and it has been done before, but it is rarely done in practice.
Likewise, at the software driver level, it is again theoretically possible to share, but you run into similar problems as the hardware level, i.e. how to "share" the link to prevent collisions, etc.
A "typical" setup would be two serial (hardware) devices attached to each other 1:1. Each would run a single software process that would manage sending/receiving data on the link.
If it is desired to share the serial link amongst multiple processes (on either side), the software process that manages the link would also need to manage passing the received data to each reading process (keeping track of which data each process had read) and also arbitrate which sending process gets access to the link during "writes".
If there are multiple read/write processes on each end of the link, the handshaking/coordination of all this gets deep as some sort of meta-signaling arrangement may be needed to coordinate the comms between the process on each end.
Either a real mess or a fun challenge, depending on your needs and how you view such things.

Decentralized networking in Python - How?

I want to write a Python script that will check the users local network for other instances of the script currently running.
For the purposes of this question, let's say that I'm writing an application that runs solely via the command line, and will just update the screen when another instance of the application is "found" on the local network. Sample output below:
$ python question.py
Thanks for running ThisApp! You are 192.168.1.101.
Found 192.168.1.102 running this application.
Found 192.168.1.104 running this application.
What libraries/projects exist to help facilitate something like this?
One of the ways to do this would be the Application under question is broadcasting UDP packets and your application is receiving that from different nodes and then displaying it. Twisted Networking Framework provides facilities for doing such a job. The documentation provides some simple examples too.
Well, you could write something using the socket module. You would have to have two programs though, a server on the users local computer, and then a client program that would interface with the server. The server would also use the select module to listen for multiple connections. You would then have a client program that sends something to the server when it is run, or whenever you want it to. The server could then print out which connections it is maintaining, including the details such as IP address.
This is documented extremely well at this link, more so than you need but it will explain it to you as it did to me. http://ilab.cs.byu.edu/python/
You can try broadcast UDP, I found some example here: http://vizible.wordpress.com/2009/01/31/python-broadcast-udp/
You can have a server-based solution: a central server where clients register themselves, and query for other clients being registered. A server framework like Twisted can help here.
In a peer-to-peer setting, push technologies like UDP broadcasts can be used, where each client is putting out a heartbeat packet ever so often on the network, for others to receive. Basic modules like socket would help with that.
Alternatively, you could go for a pull approach, where the interesting peer would need to discover the others actively. This is probably the least straight-forward. For one, you need to scan the network, i.e. find out which IPs belong to the local network and go through them. Then you would need to contact each IP in turn. If your program opens a TCP port, you could try to connect to this and find out your program is running there. If you want your program to be completely ignorant of these queries, you might need to open an ssh connection to the remote IP and scan the process list for your program. All this might involve various modules and libraries. One you might want to look at is execnet.

Python Remote Procedure Call (Without the Remote Part)

I have a Python server which is not running as root, which fronts an application I am developing. However there are some application features which require access to RAW sockets which means root privileges.
Obviously I do not want to run the main server as root, and so my solution is to create a daemon process or command line script which runs as root providing guarded access to said features.
However I want put aside stdin/stdout communication and use an RPC style of interaction such as Pyro. But this exposes the RPC interface to anyone with network access to the machine, whereas I know that the process calling the RPC methods will be another process on the same machine.
Is there not a sort of inter-process procedure call standard which could be used in a similar (local machine only) fashion? I imagine the server doing something like this:
# Server not running as root
pythonically, returned, values = other_process_running_as_root.some_method()
And the process running as root exposing a method:
# Daemon running as root
#expose_this_method
def some_method():
# Play with RAW sockets
return pythonically, returned, values
Is anything like this possible?
Following my comment, I was interested to see if it was possible, so I had a go at putting this together: https://github.com/takowl/ZeroRPC
Bear in mind that this is thrown together in an hour or so, so it's almost certainly inferior to any serious solution (e.g. any errors on the server side will crash it...). But it works as you suggested:
Server:
rpcserver = zerorpc.Server("ipc://myrpc.ipc")
#rpcserver.expose
def product(a, b):
return a * b
rpcserver.run()
Client:
rpcclient = zerorpc.Client("ipc://myrpc.ipc")
print(rpcclient.product(5, 7))
rpcclient._stopserver()
This is an easy problem. You should be able to get what you want from any RPC mechanism that can use Unix sockets, or use regular TCP sockets but only accept connections from the loopback interface (listen on 127.0.0.1).
The multiprocessing library in the Python standard library supports local IPC, too. http://docs.python.org/library/multiprocessing.html#module-multiprocessing.connection
Pyro has a number of security features specifically to limit the access to the RPC interface. Are these too much of a performance burden to use?

Categories

Resources