Python WebSocket client for mWebSocket Server - python

I am trying to build a WebSocket client in python that connects to an Arduino Uno every second via an Ethernet cable, that has a WebSocket server on it, based on the mWebSocket library. The working Arduino code is shown below:
#include <WebSocketServer.h>
using namespace net;
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[]{0xA8, 0x61, 0x0A, 0xAE, 0x69, 0x13};
IPAddress ip(198, 162, 1, 177);
IPAddress gateway(0,0,0,0);
IPAddress DNSserver(0,0,0,0);
IPAddress subnet(255,255,255,0);
constexpr uint16_t port = 80;
WebSocketServer wss{port};
void setup() {
// You can use Ethernet.init(pin) to configure the CS pin
Ethernet.init(10); // Most Arduino shields
//Ethernet.init(5); // MKR ETH shield
//Ethernet.init(0); // Teensy 2.0
//Ethernet.init(20); // Teensy++ 2.0
//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("Ethernet WebServer Example");
// start the Ethernet connection and the server:
Ethernet.begin(mac,ip,DNSserver,gateway,subnet);
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
}
// start the server
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
wss.onConnection([](WebSocket & ws) {
const auto protocol = ws.getProtocol();
if (protocol) {
Serial.print(F("Client protocol: "));
Serial.println(protocol);
}
ws.onMessage([](WebSocket & ws, const WebSocket::DataType dataType,
const char *message, uint16_t length) {
switch (dataType) {
case WebSocket::DataType::TEXT:
Serial.print(F("Received: "));
Serial.println(message);
break;
case WebSocket::DataType::BINARY:
Serial.println(F("Received binary data"));
break;
}
ws.send(dataType, message, length);
});
ws.onClose([](WebSocket &, const WebSocket::CloseCode, const char *,
uint16_t) {
Serial.println(F("Disconnected"));
});
Serial.print(F("New client: "));
Serial.println(ws.getRemoteIP());
const char message[] {"Hello from Arduino server!"};
ws.send(WebSocket::DataType::TEXT, message, strlen(message));
});
wss.begin();
Serial.println(Ethernet.localIP());
}
void loop() {
wss.listen();
}
I have constructed a python socket client to interact with this Arduino and hopefully print the message "Hello from Arduino server!" to the client with every connection.
#!/usr/bin/python3
import asyncio
import websockets
import socket
import time
import datetime
import struct
starttime = time.time() # start value for timed data acquisition
# setup socket 1
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.connect(("198.162.1.177",80))
s1.sendall(b'GET / HTTP/1.1 400')
if True:
print('Connected')
def acquire():
data = s1.recv(10000)
print(data)
while True:
acquire()
time.sleep(1.0 - ((time.time() - starttime) % 1.0)) # continue every (2.0 seconds)
s1.close()
However, when I run the above code. I obtain:
Connected
b'H'
b'TTP/1.1 400 Bad Request\r\n'
b''
b''
b''
b''
b''
What am I missing here, I presume that the connection is not being fully made, even though I can ping the Arduino from my PC. Do I need to account for a HTTP header in a different way for a WebSocket client?

Websocket connection is made by a HTTP request with upgrade headers which specifies that the connecting client want's to upgrade to a websocket protocol. When the server receives this message and finding the upgrade headers in the request it validates if the upgrade it supported on it's end and upgrades the underlying connection to a websocket connection. This is the thing that seems to be missing from your end.
Also, as you are importing websockets in your client code. You can use the library functions which does this work for you and you just make a GET request with "ws/wss" specified in your request URL.

Related

Arduino RP2040 (client) - Python (server) through WiFi

I am trying to connect my Arduino Nano Connect RP2040 with my machine using Python (3.8.8). I want to use WiFi communication protocol and I am currently working on a client-server socket.
Since I am not so familiar with this communication protocol I am following this thread which looks to perform good results. Of course, this thread talks about Ethernet and I am readapting using WiFiNina library which has been developed by Arduino in order to use the module.
Here the code I am running on Arduino:
#include <SPI.h>
#include <WiFiNINA.h>
#include <ArduinoJson.h>
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0x08, 0x3A, 0xF2, 0xB1, 0x9D, 0xE0 };
IPAddress ip(192,168,43,98);
// Enter the IP address of the server you're connecting to:
IPAddress server(192,168,0,4);
// Initialize the WiFi client library
// with the IP address and port of the server
WiFiClient client;
char ssid[] = "xxxxx"; // the name of your network
char username[] = "xxxxxxx";
char pass[] = "xxxxxxx";
void setup() {
// start the Wifi connection:
WiFi.beginEnterprise(ssid, username, pass);
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
// give the Ethernet shield a second to initialize:
delay(1000);
Serial.println("connecting...");
// if you get a connection, report back via serial:
if (client.connect(server, 13380)) {
Serial.println("connected");
}
else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
void loop()
{
//JSON stuff
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "gps";
root["time"] = 42;
JsonArray& data = root.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);
char json[100];
root.printTo(json);
Serial.print(json);
// if there are incoming bytes available
// from the server, read them and print them:
if (client.available()) {
char c = client.read();
Serial.print(c);
}
// as long as there are bytes in the serial queue,
// read them and send them out the socket if it's open:
if (client.connected()) {
client.print(json);
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
// do nothing:
while(true);
}
}
I have used some functions from WiFiNina (for example .beginEnterprise() in order to connect Arduino to the network).
For what server concerns, here the code in Python:
import socket
import sys
import json
# host = '127.0.0.1'
host = '192.168.0.4'
port = 13380
address = (host, port)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(address)
server_socket.listen(5)
# server_socket.connect(address)
print ("waiting for a connection . . .")
conn, address = server_socket.accept()
print ("Connection established: "), address
while True:
output = conn.recv(84048);
if output.strip() == "disconnect":
conn.close()
sys.exit("Disconnect message received - terminate the connection")
conn.send("dack")
elif output:
print(output)
data = json.load(output)
print(data)
I am not interested in sending JSON data, like I have already mentioned I am just readapt the code in thread. I actually need to send data in real-time, but step-by-step :-)
The problem is that I cannot establish the connection between Arduino (client) and Python (server).
From server part, I actually got this error:
Traceback (most recent call last):
File "server_arduino.py", line 18, in <module>
server_socket.bind(address)
OSError: [WinError 10049] The requested address is not valid in its context
For some reasons which I actually did not understand yet, if I would change host in 127.0.0.1 (following suggestions here) the server part starts to work, and it stucks in waiting for a connection . . . printed in my console, because it needs a client to connect.
At this stage, running my Arduino code I got this:
connecting...
connection failed
{"sensor":"gps","time":42,"data":[48.75608,2.302038]}
disconnecting.
So, it does mean to me that I was able to connect to WiFi, but not to server.
Does anyone give me any suggestions?
I know I am really beginner and any suggestions would be really appreciated.

Socket server between Unity and Raspberry doesn't connect

So I am trying to send data from the raspberry pi to unity.
I trying to create socket server to do so.
I can get the socket server running on the raspberry pi and can also look at the port with netstat -tulpn | grep :5005 in the terminal on the machine where the python script is running.
I also tried it on my mac and it also showed up as a TCP-server.
However when I try to connect to the same port and ip via Unity or on another machine it doesn't work. I also can't seem to find the port when listing all of the ports with netstat.
Unity spits out a "Connection refused" error.
Here is the code in Unity in C#
using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Net.Sockets;
public class ClientSocket : MonoBehaviour
{
bool socketReady = false;
TcpClient mySocket;
public NetworkStream theStream;
StreamWriter theWriter;
StreamReader theReader;
public String Host = "192.168.8.137";
public Int32 Port = 5005;
void Start()
{
setupSocket();
TextMessage("SocketTest");
}
public void setupSocket()
{ // Socket setup here
try
{
mySocket = new TcpClient(Host, Port);
theStream = mySocket.GetStream();
theWriter = new StreamWriter(theStream);
theReader = new StreamReader(theStream);
socketReady = true;
}
catch (Exception e)
{
Debug.Log("Socket error:" + e); // catch any exceptions
}
}
public void TextMessage(string message)
{
if (socketReady == true)
{
theWriter.Write(message);
theWriter.Flush();
}
}
}
here is the code in python, which should be running on the raspberry pi.
import socket
import sys
backlog = 1
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('192.168.8.137', 5005))
s.listen(1)
try:
print ("is waiting")
client, address = s.accept()
while 1:
data = client.recv(size)
if data:
print (data)
finally:
print("closing socket")
cient.close()
s.close()
I'm new to socket servers, but I really trying to accomplish a connection here.
Thanks for reading!
am pretty sure you need to encode the data that you about to send in c# TcpClient
adding an example from my final project:
string data = "Hello Server!"; //the message in string (important it will be string)
byte[] msg = Encoding.Unicode.GetBytes(data); //encoded the message using unicode (utf-16)
NetworkStream stream = client.GetStream(); //get the tcp client stream
stream.Write(msg, 0, msg.Length); //write the message to the stream
and in the server you suppose to have something like that:
msg = clnt.recv(1024) #reciving the data
msg = msg.decode("utf-16") #decoding the data
print(msg) #printing the data
and i think thats it
and i would recommend using port above 10000 because most of the ports can be used

Communicating between Raspberry Pi and Arduino over LAN

I'm doing image processing with a raspberry pi, and I want it to be able to talk to my arduino over LAN to steer a light beam based on the pi's instructions. The only things I've seen a lot are direct connections between the Pi and the Arduino. It may seem naive of me, but I was trying to have them communicate using the Arduino as a server, programmed with the Ethernet library, and the Raspberry Pi as the client through the socket library. I gave them both static IP's on my router, and used the following code to try and get through, but I was met with socket.error: [Errno 113] No route to host when my python line came to the command to connect to the Arduino's IP through a specific port.
Any ideas on how I could more properly do this connection? The main goal for me is to be able to do this over LAN, so the USB connections and the direct I2C connections aren't helpful, though they would definitely get the job done.
Raspberry Pi:
from socket import *
import select
data = None
timeout = 3 # timeout in seconds
msg = "test"
host = "192.168.1.113"
print ("Connecting to " + host)
port = 23
s = socket(AF_INET, SOCK_STREAM)
print "Socket made"
ready = select.select([s],[],[],timeout)
s.connect((host,port))
print("Connection made")
while True:
if data != None:
print("[INFO] Sending message...")
s.sendall(msg)
data = None
print("[INFO] Message sent.")
continue
if ready[0]: #if data is actually available for you
data = s.recv(4096)
print("[INFO] Data received")
print data
continue
Arduino:
//90-a2-da-0f-25-E7
byte mac[] = {0x90, 0xA2, 0xDA, 0x0f, 0x25, 0xE7};
//ip Address for shield
byte ip[] = {192,168,1,113};
//Use port 23
EthernetServer server = EthernetServer(23);
void setup() {
//init device
Ethernet.begin(mac,ip);
//start listening for clients
server.begin();
Serial.begin(9600); //For visual feedback on what's going on
while(!Serial){
; //cause Leonardo
}
delay(1000);
if(server.available()){
Serial.write("Client available");
}
}
void loop() {
// put your main code here, to run repeatedly:
EthernetClient client = server.available();
if (client == true){
Serial.write("Client Connected.");
if(client.read() > 0){
Serial.write(client.read());
}
else{
server.write("ping");
}
}
else{
Serial.println("No one's here yet...");
}
delay(1500);
}
After digging around, I found my solution, and some more details. So both the R-Pi and the Arduino can do TCP, and I found the source of my errors.
1) I believe the delay I set after server.begin() in my Arduino Code was giving me the error, since it pauses the program and so probably pauses the listening process.
2) The while loop in my R-Pi client code was giving me a broken pipe error.
3) The if (client == True) test in my Arduino's loop() was not working. The R-Pi could connect and send messages with no error, but the Arduino didn't seem to be responding properly. Once I pulled everything out of the if statement, the R-Pi started receiving my messages and I saw everything respond. Here's my final code:
R-Pi:
from socket import *
import select
data = None
timeout = 3 # timeout in seconds
msg = "test"
host = "192.168.1.113"
print ("Connecting to " + host)
port = 23
s = socket(AF_INET, SOCK_STREAM)
print "Socket made"
ready = select.select([s],[],[],timeout)
s.connect((host,port))
print("Connection made")
if ready[0]: #if data is actually available for you
print("[INFO] Sending message...")
s.sendall(msg)
print("[INFO] Message sent.")
data = s.recv(4096)
print("[INFO] Data received")
print data
Arduino:
#include <SPI.h>
#include <Ethernet.h>
//90-a2-da-0f-25-E7
byte mac[] = {0x90, 0xA2, 0xDA, 0x0f, 0x25, 0xE7};
//ip Address for shield
byte ip[] = {192,168,1,113};
//Use port 23 for telnet
EthernetServer server = EthernetServer(23);
void setup() {
Serial.begin(9600); //For visual feedback on what's going on
while(!Serial){
; //wait for serial to connect -- needed by Leonardo
}
Ethernet.begin(mac,ip); // init EthernetShield
delay(1000);
server.begin();
if(server.available()){
Serial.println("Client available");
}
}
void loop() {
// put your main code here, to run repeatedly:
EthernetClient client = server.available();
message = client.read();
server.write(message);
server.write("Testu ");
Serial.println(message);
// if (client == true){ <----- This check screwed it up. Not needed.
// Serial.println("Client Connected.");
// server.write(client.read()); //send back to the client whatever the client sent to us.
// }
}

Send data from Arduino to a Web Server through Ethenet shield

I have an Arduino with an Ethernet shield, it connected to the same hub with my computer.
I tried to let this Arduino send some HTTP Request Get to my web server written in Python.
I fixed the IP for my computer at 192.168.1.2 and the Arduino will get its IP automatically through a DHCP server or if it fails to get a new IP, it would get a static IP.
Web server part: I tested my Web server and it worked as whenever I called that request, it would save for me the record into the database(I am using mongodb as my database)
Arduino part: I tested and I saw it could connect to my DHCP server, not my web server as it sent a Request and get a Response from the DHCP server.
How to config so my DHCP server can transfer Arduino's request directly to my web server? Or other solution like let my Arduino send data directly to my web server?
Small code of my web server:
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
from bottle import *
from pymongo import *
import datetime
#route('/hello')
def hello():
return "Hello World!"
#get('/receiver', method = 'GET')
def receiver():
# Get data from http request and save it into db
print 'Inserting data'
receiver_id = request.query.getall('id')
broadcaster_id = request.query.getall('bid')
signal_strength = request.query.getall('s')
client = MongoClient('localhost', 27017)
db = client['arduino']
collection = db['arduino']
record = {'receiver_id':receiver_id,
'broadcaster_id':broadcaster_id,
'signal_strength':signal_strength,
'date': datetime.datetime.utcnow()}
print record
collection.insert_one(record)
return template('Record: {{record}}', record = record)
#get('/db')
def db():
# Display all data
client = MongoClient('localhost', 27017)
db = client['arduino']
collection = db['arduino']
for record in collection.find():
return template('<div>{{receiver_id}}</div>',receiver_id = record)
#error(404)
def error404(error):
return 'Something wrong, try again!'
run(host='localhost', port=80, debug=True)
Small code of my Arduino program:
/*
Connect to Ethernet Using DHCP
Author:- Embedded Laboratory
*/
#include <SPI.h>
#include <Ethernet.h>
#define ETH_CS 10
#define SD_CS 4
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {0xCA,0xFE,0x00,0x00,0x00,0x15};
IPAddress ip(192,168,1,15);
IPAddress server(192,168,1,2);
//char server[] = "localhost";
EthernetClient client;
void setup()
{
Serial.begin(9600);
Serial.println("Starting Ethernet Connection");
pinMode(ETH_CS,OUTPUT);
pinMode(SD_CS,OUTPUT);
digitalWrite(ETH_CS,LOW); // Select the Ethernet Module.
digitalWrite(SD_CS,HIGH); // De-Select the internal SD Card
if (Ethernet.begin(mac) == 0) // Start in DHCP Mode
{
Serial.println("Failed to configure Ethernet using DHCP, using Static Mode");
// If DHCP Mode failed, start in Static Mode
Ethernet.begin(mac, ip);
}
Serial.print("My IP address: ");
for (byte thisByte = 0; thisByte < 4; thisByte++)
{
// print the value of each byte of the IP address:
Serial.print(Ethernet.localIP()[thisByte], DEC);
Serial.print(".");
}
Serial.println();
// give the Ethernet shield a second to initialize:
delay(1000);
Serial.println("connecting...");
for(int i =1; i < 6; i++){
Serial.print("Test number ");
Serial.println(i);
// if you get a connection, report back via serial:
if (client.connect(server, 80))
{
Serial.println("connected");
// Make a HTTP request:
//client.println("GET /receiver?id=4&bid=3&s=70 HTTP/1.1");
client.println("GET / HTTP/1.1");
client.println("Host: localhost");
client.println("Connection: close");
client.println();
delay(1000);
}
else
{
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
}
void loop()
{
// if there are incoming bytes available
// from the server, read them and print them:
if (client.available())
{
char c = client.read();
client.write(c);
Serial.print("Read the client:");
Serial.print(c);
}
// as long as there are bytes in the serial queue,
// read them and send them out the socket if it's open:
while (Serial.available() > 0)
{
char inChar = Serial.read();
if (client.connected())
{
client.print(inChar);
}
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
// do nothing:
while(true);
}
}

Dumping data over ethernet with an arduino client / python server

I'm using an arduino ethernet to read data form sensors, and then would like to send data to a computer in another building to drive the logic/control in a piece of python software. I decided to sketch up a simple sketch in python/arduino that just sends text from the arduino to my python program over ethernet:
The arduino client code is mostly taken from the EthernetClient example:
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {0x90, 0xA2, 0xDA, 0x0E, 0x40, 0x9F};
byte ip[] = {192, 168, 0, 172};
byte server[] = {192,168,0,17};
int port = 1700;
EthernetClient client;
void setup() {
Serial.begin(9600);
while (!Serial) {
;
}
Ethernet.begin(mac, ip);
delay(1000);
Serial.println("connecting...");
// if you get a connection, report back via serial:
if (client.connect(server, port)) {
Serial.println("connected.");
//print text to the server
client.println("This is a request from the client.");
}
else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
void loop()
{
// if there are incoming bytes available
// from the server, read them and print them:
if (client.available()) {
char c = client.read();
Serial.print(c);
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
// do nothing forevermore:
while(true);
}
}
And then my python code:
import socket
host = ''
port = 1700
address = (host, port)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((address))
server_socket.listen(5)
print "Listening for client . . ."
conn, address = server_socket.accept()
print "Connected to client at ", address
//pick a large output buffer size because i don't necessarily know how big the incoming packet is
output = conn.recv(2048);
print "Message received from client:"
print output
conn.send("This is a response from the server.")
conn.close()
print "Test message sent and connection closed."
The response from the server is what i expect:
Listening for client . . .
Connected to client at ('192.168.0.172', 1025)
Message received from client:
This is a request from the client.
Test message sent and connection closed.
But the client receives:
connecting...
connected.
This
disconnecting.
And seems to stop receiving the text from my server after the stream. Why is that?
Another question: Why is it that I asked my arduino to connect on port 1700, but python claims that it's receiving a request from port 1025?
thanks!

Categories

Resources