I've been using Twisted for a while to connect a computer with some devices over the net. I wrote a custom Protocol and Factory.
factory = TModBusFactory()
reactor.listenTCP(9007, factory)
Now I'd like to connect the devices to the serial port of the server machine. As long as I know, no change in the protocol is needed but I need to switch from sending bytes over TCP to send them over the serial port.
How hard to do is this change? How can I change the code snippet in order to make it work?
Thanks!
Serial port setup looks like this:
from twisted.internet.serialport import SerialPort
from twisted.internet import reactor
factory = TModBusFactory()
protocol = factory.buildProtocol(None)
deviceName = "ttyS0"
port = SerialPort(protocol, deviceName, reactor)
Related
I need to communicate with several modules and devices using the ModBus Protocol and the Raspberry Pi.
I am using PyModBus on Raspberry Pi to read/write Modbus function codes. (https://pymodbus.readthedocs.io/en/latest/readme.html)
I was able to communicate Modbus RTU over RS485 with the device but now that I am trying to communicate ModbusTCP over a Ethernet cable and keep running into the following error:
import pymodbus
from pymodbus.client.sync import ModbusTcpClient
client = ModbusTcpClient('127.0.0.1')
connection = client.connect()
Output:
ERROR.pymodbus.client.sync: Conection to (127.0.0.1, 502) failed: [Errno 111] connection refused
Any tips or explanation for the error?
127.0.0.1 is a loopback address; this means that ModbusTcpClient('127.0.0.1') will attempt to establish a connection to the Pi iteslf. Unless there is a Modbus server running on the Pi the error you received is to be expected.
"I am trying to communicate ModbusTCP over a Ethernet cable" indicates you are communicating with another device which should have it's own IP address. You need to work out what that address is and use that when attempting to connect (as well as ensuring your network setup is valid). The method used to set/determine a devices address varies from device to device so you would need to check the documentation (you did not specify what the device is).
I looking for clarification on how the WiFiClient and WiFiServer objects in this example ESP8266 sketch starts a TCP connection and allows an Android app to read and write to buffers that's setup in the sketch.
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
WiFiServer server(port);
WiFiClient client;
uint8_t buf1[1024];
server.begin(); // start TCP server
client = server.available(); // wait for it to connect
buf1[i1] = (uint8_t)client.read(); // read char from client (RoboRemo app)
client.write((char*)buf2, i2);
This sketch talks to a closed-source Android app call Roboremo. It uses WiFiServer to create a TCP server, and WiFiClient to read/write to buffers. What is this TCP server, and what mechanism is being used to read/write to the ESP8266? So, if I were having a conversation with an app developer, how do I tell them how to write to this TCP server (other than IP and port number)? Is this a "TCP socket", and does that translate into something that mobile app people would know how to proceed?
Another way to ask this question: I'd like to be able to test read/write to the ESP8266 without the Android app. So if I have a Raspberry Pi on the same network as this ESP8266, what utility (mechanism again) can I use to read/write to those buffers from the Pi?
Checking the Roboremo sketch shows that you will be working with esp8266 on STA mode by providing your ssid and pass into the sketch. That means you need to find the ip address of esp8266 before making a connection. A ridiculous comment from sketch is :
Then somehow find the IP that the ESP got from router
So, if you will continue with STA mode, you may go to your router settings and find the ESP8266 from DHCP clients.
For a raspberry TCP client connection, you need nothing else from a Linux socket client. Here a basic python client to test on raspberry :
import socket
import sys
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
sys.exit();
print 'Socket Created'
host = 'YOUR_ESP8266_IP '
port = 9876
s.connect((remote_ip , port))
print 'Socket Connected to ' + host
#Send some data to remote server
message = "test esp8266 server"
try :
s.sendall(message)
except socket.error:
print 'Send failed'
sys.exit()
print 'Message send successfully'
Is it possible to get sensor output from Arduino via Ethernet connection and to send data to Arduino via Ethernet?
So basically can "replace" serial port with Ethernet port?
The typical way to do this is with an Arduino Ethernet shield, a small hardware module that plugs into your Arduino board:
http://arduino.cc/en/Main/ArduinoEthernetShield
Updated:
One very common approach for client to server communication would be to use HTTP over TCP/IP. See this example on the Ardunio site of a simple client on an Ardunio connecting with a server (in this case google):
http://arduino.cc/en/Tutorial/WebClient
For your use case you can simply create your own server and modify the example to send data to it.
Alternatively you can skip the HTTP part and just use sockets - there is an open source example here:
https://github.com/billroy/socket.io-arduino-client
Arduino: Is it possible to communicate with Arduino through Ethernet, using a Processing (PDE) script?
I've already created a desktop application using Processing, but in this case I communicate with Arduino through the USB.
Yes you can
You could for example create an arduino chat server : http://arduino.cc/en/Tutorial/ChatServer
And create a processing client like this : http://processing.org/reference/libraries/net/Client_write_.html
ofcourse you would need to change the
myClient = new Client(this, "127.0.0.1", 10002);
to
myClient = new Client(this, "IP of Arduino", 23);
If you would then connect with a telnet session to the arduin o you would see output from the prosessing script comming back from the arduino
I am writing a small application in QT that sends a UDP packet broadcast over the local network and waits for a UDP responce packet from one or more devices over the network.
Creating the sockets and sending the broadcast packet.
udpSocketSend = new QUdpSocket(this);
udpSocketGet = new QUdpSocket(this);
bcast = new QHostAddress("192.168.1.255");
udpSocketSend->connectToHost(*bcast,65001,QIODevice::ReadWrite);
udpSocketGet->bind(udpSocketSend->localPort());
connect(udpSocketGet,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
QByteArray *datagram = makeNewDatagram(); // data from external function
udpSocketSend->write(*datagram);
The application sends the packet properly and the response packet arrives but the readPendingDatagrams() function is never called. I have verified the packets are sent and received using Wireshark and that the application is listening on the port indicated in wireshark using Process Explorer.
I solved the problem. Here is the solution.
udpSocketSend = new QUdpSocket(this);
udpSocketGet = new QUdpSocket(this);
host = new QHostAddress("192.168.1.101");
bcast = new QHostAddress("192.168.1.255");
udpSocketSend->connectToHost(*bcast,65001);
udpSocketGet->bind(*host, udpSocketSend->localPort());
connect(udpSocketGet,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
QByteArray *datagram = makeNewDatagram(); // data from external function
udpSocketSend->write(*datagram);
The device on the network listens on port 65001 and responds to packets on the source port of the received packet. It is necessary to use connectToHost(...) in order to know what port to bind for the response packet.
It is also necessary to bind to the correct address and port to receive the packets. This was the problem.
You're binding your udpSocketSend in QIODevice::ReadWrite mode. So that's the object that's going to be receiving the datagrams.
Try one of:
binding the send socket in write only mode, and the receive one in receive only mode
using the same socket for both purposes (remove udpSocketGet entirely).
depending on your constraints.
For me, changing the bind from
udpSocket->bind(QHostAddress::LocalHost, 45454);
to simple
udpSocket->bind(45454);
does the trick!