I have a project where I want to use websockets to communicate between a web page running in a browser and a stepper motor controlled by the Arduino.
I can get a simple web page served up by the Arduino to work.
I can get the stepper motor controlled by the Arduino to work.
What I'm having trouble with is getting both a simple web server and web socket server running simultaneously on the Arduino.
To simplify things I tried running the code for a web chat application which serves up a page using static html from port 80 and then has a web socket listening on port 81.
This uses the ArduinoCore-renesas WiFiS3 web server running on port 80 to serve the web page. This page has some javascript embedded to interact with the page and send commands back to the Arduino over port 81, which is the websocket server, using the mWebSockets library.
I can get it compiled and uploaded to the R4 Uno Wifi, the Arduino gets a DHCP assigned IP address from my router and I can then use a browser on my desktop to load the web page.
From that web page I can Connect to the web socket server and see the connection succeed - both in the serial monitor and from the feedback on the web page.
However if I then type in a message such as "Hi from firefox" and click Send, the serial monitor shows
<< ⸮⸮;⸮q⸮s⸮Q⸮I⸮⸮}⸮⸮]⸮ ⸮
Clicking Disconnect shows
<< ⸮⸮⸮5⸮b
From the formatting of those lines with the "<<" prefix it appears this is being handled by the web server running on port 80, not the websocket server running on port 81.
Thanks, I've followed the code exactly as in the online tutorial. I get readable feedback in the serial monitor until the web socket stuff starts (and this is what fails to do what it says on the tin).
/*
* Created by ArduinoGetStarted.com
* This example code is in the public domain
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-websocket
*/
#include <WiFiS3.h>
#include <WebSocketServer.h>
#include "index.h"
using namespace net;
WebSocketServer wss(81);
WiFiServer server(80);
const char ssid[] = "****"; // change your network SSID
const char pass[] = "****"; // change your network password
int status = WL_IDLE_STATUS;
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
String fv = WiFi.firmwareVersion();
// version is 0.2.1
if (fv < WIFI_FIRMWARE_LATEST_VERSION)
Serial.println("Please upgrade the firmware");
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 4 seconds for connection:
delay(4000);
}
// print your board's IP address:
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
server.begin();
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;
}
String reply = "Received: " + String((char *)message);
ws.send(dataType, reply.c_str(), reply.length());
});
ws.onClose([](WebSocket &, const WebSocket::CloseCode, const char *,
uint16_t) {
Serial.println(F("Disconnected"));
});
Serial.print(F("New WebSocket Connnection from client: "));
Serial.println(ws.getRemoteIP());
const char message[]{ "Hello from Arduino server!" };
ws.send(WebSocket::DataType::TEXT, message, strlen(message));
});
wss.begin();
}
void loop() {
wss.listen();
// listen for incoming clients
WiFiClient client = server.available();
if (client) {
// read the HTTP request header line by line
while (client.connected()) {
if (client.available()) {
String HTTP_header = client.readStringUntil('\n'); // read the header line of HTTP request
if (HTTP_header.equals("\r")) // the end of HTTP request
break;
Serial.print("<< ");
Serial.println(HTTP_header); // print HTTP request to Serial Monitor
}
}
// send the HTTP response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println(); // the separator between HTTP header and body
String html = String(HTML_CONTENT);
client.println(html);
client.flush();
// give the web browser time to receive the data
delay(50);
// close the connection:
client.stop();
}
}
When you open the serial monitor, what does it say at the bottom right? Select Carriage return. Here are the choices in that drop down window:
No line ending
Newline
Carriage return
Both NL & CR
Thanks for your help. It is not the character encoding, or baud rate etc.
The serial monitor correctly displays the Serial.println commands from when the initial wifi connection is made, the web page served out to the browser etc.
The problem is that in the loop function, the web server on port 80 is receiving commands for the web socket server (port 81), you see this as the folowing two lines of logging code is putting the jibberish onto the monitor
Serial.print("<< ");
Serial.println(HTTP_header); // print HTTP request to Serial Monitor
Just to clarify, here is a copy of the Serial Monitor output. You can see the initial request on port 80 to output the web page to the browser is fine. It is the subsequent request on port 81 (the web socket port) that is getting processed by the code bound to port 80 (the last line)
IP Address: 192.168.0.194
<< GET / HTTP/1.1
<< Host: 192.168.0.194
<< User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:127.0) Gecko/20100101 Firefox/127.0
<< Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
<< Accept-Language: en-GB,en;q=0.5
<< Accept-Encoding: gzip, deflate
<< Connection: keep-alive
<< Upgrade-Insecure-Requests: 1
<< Priority: u=1
New WebSocket Connnection from client: 192.168.0.237
<< ��e���h��
The second to last line is the initial establishment of the web socket connection
Even though this is a board I only purchased last month, the ESP32 radio link firmware was way out of date. So it has been sitting on the shelf at Farnell / Element 14 I'm guessing.
The version reported by
WiFi.firmwareVersion();
was 0.2.1
The current version is 0.4.1
The process to upgrade was not straightforward, probably because the version was out of date and so not compatible with the IDE ?