gilmaimon / arduinowebsockets Goto Github PK
View Code? Open in Web Editor NEWA library for writing modern websockets applications with Arduino (ESP8266 and ESP32)
License: GNU General Public License v3.0
A library for writing modern websockets applications with Arduino (ESP8266 and ESP32)
License: GNU General Public License v3.0
Nice library & easy to use.
I have a websocket "bridge" (node-red) set up on a remote server, so I'm using the example client sketch on a ESP8266.
The ESP connects to the remote socket and works well, but after a period of time and inactivity, disconnects. If I re-boot the ESP it connects again. The remote server is not the cause, as other sockets remain connected indefinitely.
I'm new to the websocket world, so perhaps I'm overlooking the obvious? or, is there a built-in timeout in the library i might be able to change?
My ESP32 panics when ArduinoWebsockets initiates a websocket connection.
Code running on ESP32:
#include <Arduino.h>
#include <WiFiManager.h>
#include <ArduinoWebsockets.h>
WiFiManager wifiManager;
using namespace websockets;
WebsocketsClient client;
static const char SERVER[] = "ws://192.168.1.149"; // my laptop's IP
void onMessageCallback(WebsocketsMessage message) {
Serial.print("Got Message: ");
Serial.println(message.data());
}
void onEventsCallback(WebsocketsEvent event, String data) {
if(event == WebsocketsEvent::ConnectionOpened) {
Serial.println("Connnection Opened");
} else if(event == WebsocketsEvent::ConnectionClosed) {
Serial.println("Connnection Closed");
} else if(event == WebsocketsEvent::GotPing) {
Serial.println("Got a Ping!");
} else if(event == WebsocketsEvent::GotPong) {
Serial.println("Got a Pong!");
}
}
void setup()
{
Serial.begin(115200);
wifiManager.autoConnect();
// Setup Callbacks
client.onMessage(onMessageCallback);
client.onEvent(onEventsCallback);
client.connect(SERVER);
client.send("Hello");
client.ping();
}
void loop()
{
client.send(String(millis()));
client.poll();
delay(500);
}
On my laptop, I can see an incoming connection:
$ sudo nc -l 80 -vvvv
Listening on [0.0.0.0] (family 0, port 80)
Connection from espressif 62507 received!
GET / HTTP/1.1
Host: 192.168.1.149
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: MDEyMzQ1Njc4OWFiY2RlZg==
Sec-WebSocket-Version: 13
But when I use websocat
's server:
sudo websocat -s 80 -vvvv
Listening on ws://127.0.0.1:80/
[INFO websocat::lints] Auto-inserting the line mode
[DEBUG websocat] Done third phase of interpreting options.
[DEBUG websocat] Done fourth phase of interpreting options.
[DEBUG websocat] Preparation done. Now actually starting.
[INFO websocat::sessionserve] Serving Message2Line(WsServer(TcpListen(V4(127.0.0.1:80)))) to BroadcastReuser(Line2Message(Stdio)) with Options { websocket_text_mode: true, websocket_protocol: None, websocket_reply_protocol: None, udp_oneshot_mode: false, unidirectional: false, unidirectional_reverse: false, exit_on_eof: true, oneshot: false, unlink_unix_socket: false, exec_args: [], ws_c_uri: "ws://0.0.0.0/", linemode_strip_newlines: false, linemode_strict: false, origin: None, custom_headers: [], custom_reply_headers: [], websocket_version: None, websocket_dont_close: false, one_message: false, no_auto_linemode: false, buffer_size: 65536, broadcast_queue_len: 16, read_debt_handling: Warn, linemode_zero_terminated: false, restrict_uri: None, serve_static_files: [], exec_set_env: false, reuser_send_zero_msg_on_disconnect: false, process_zero_sighup: false, process_exit_sighup: false, socks_destination: None, auto_socks5: None, socks5_bind_script: None, tls_domain: None, tls_insecure: false, max_parallel_conns: None, ws_ping_interval: None, ws_ping_timeout: None }
The ESP32 will die:
*WM: [1] AutoConnect
*WM: [2] ESP32 event handler enabled
*WM: [2] Connecting as wifi client...
*WM: [1] STA static IP:
*WM: [2] setSTAConfig static ip not set
*WM: [3] WIFI station disconnect
*WM: [1] Connecting to saved AP: XXXXXXXX
*WM: [3] Using Password: XXXXXXXX
*WM: [3] WiFi station enable
*WM: [1] connectTimeout not set, ESP waitForConnectResult...
*WM: [2] Connection result: WL_CONNECTED
*WM: [3] lastconxresult: WL_CONNECTED
*WM: [1] AutoConnect: SUCCESS
*WM: [1] STA IP Address: 192.168.1.29
[E][WiFiClient.cpp:282] setOption(): fail on fd 54, errno: 22, "Invalid argument"
[E][WiFiClient.cpp:365] write(): fail on fd 54, errno: 104, "Connection reset by peer"
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x4012d2c0 PS : 0x00060830 A0 : 0x8012d721 A1 : 0x3ffb1b90
A2 : 0x00000000 A3 : 0x3ffb1bef A4 : 0x00000001 A5 : 0x00000001
A6 : 0x00000000 A7 : 0xffffffa7 A8 : 0x00000000 A9 : 0x00000000
A10 : 0x00000000 A11 : 0x3ffc8dcc A12 : 0x00000000 A13 : 0x00000001
A14 : 0x00060e20 A15 : 0x00000000 SAR : 0x00000004 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000008 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff
Backtrace: 0x4012d2c0:0x3ffb1b90 0x4012d71e:0x3ffb1bb0 0x40173692:0x3ffb1be0 0x400dc65b:0x3ffb1c10 0x400dc2e6:0x3ffb1c30 0x400dcefa:0x3ffb1d70 0x400d20ad:0x3ffb1f60 0x400e0abf:0x3ffb1fb0 0x4008b015:0x3ffb1fd0
Rebooting...
What is the best way to reconnect after a disconnect or some error?
I tried the following but doesn't appear to be working.
void onEventsCallback(WebsocketsEvent event, String data) {
if(event == WebsocketsEvent::ConnectionClosed) {
client.connect("wss://ws-feed.pro.coinbase.com");
client.send("{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker"]}");
}
Instead is there any way to check if the connection is active in the loop() and reconnect from there?
I think the letter I
might have accidentally got into the mamon
surname.
Beside that, cool job
First described in this issue #2.
When continusly sending and receiving messages (with no/very-short delays) on esp8266 a message with bad values is read (opcode and fin makes no sense).
Does the issue occurs on ESP32?
Hi Gil,
Me again.
I want to bring to your attention the following situation:
Messages that go through client.send()
are sent in plain-text, unmasked (see more about websocket masking).
However, it seems that the library understands and successfully decodes the received masked messages.
How I tested:
send()
method to send a message, the messages are automatically masked by the browser and sent to the server./**
* @method unmask
* @param $text string
* @return string
* @desc Unmask incoming framed message
*/
private function unmaskReceivedData($text) {
$length = ord($text[1]) & 127;
if($length == 126) {
$masks = substr($text, 4, 4);
$data = substr($text, 8);
} elseif($length == 127) {
$masks = substr($text, 10, 4);
$data = substr($text, 14);
} else {
$masks = substr($text, 2, 4);
$data = substr($text, 6);
}
$text = '';
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i%4];
}
return $text;
}
AFAIK, this method is being written according to the RFC standards.
From there, on my server I decode (unmask) the message, process it, then mask it again to broadcast to all the connected clients.
For masking I'm using the following code:
private function maskSentData($text) {
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($text);
$header = '';
if($length <= 125)
$header = pack('CC', $b1, $length);
elseif($length > 125 && $length < 65536)
$header = pack('CCn', $b1, 126, $length);
elseif($length >= 65536)
$header = pack('CCNN', $b1, 127, $length);
return $header . $text;
}
When I broadcast it, the browser and the ESP32 receive it successfully.
However, when I try to send a message through libraries client.send(text)
method, all the messages received on the server are plain, not masked in any way (and of course, the servers unmask method fails).
Just a note to this: Something might had happen recently (through an update or so) because few weeks ago (when we had issue #14 ), this bug didn't happen (though I cannot identify where the change could come from...).
You know the library as better as anyone, so I'm pretty sure you can shed some light here.
If you need any more info from me, just let me know.
Hope it helps,
Thanks,
Best,
A.
Hi.
This library looks like exactly what I need but I cannot compile.
Initially I had a syntax error in "ws_common.hpp" with the "#include <string" I changed it to -> "#include <string.h>" and it was fixed.
But the next one I cannot fix it and it is related to "#include <memory.h>" inside the file "websockets_endpoint.hpp".
COMPILER ERROR ------->
In file included from ...Documents/Arduino/libraries/ArduinoWebsockets-0.4.9/src/tiny_websockets/client.hpp:6:0,
from ... Documents/Arduino/libraries/ArduinoWebsockets-0.4.9/src/ArduinoWebsockets.h:5,
from ...Documents/Arduino/libraries/ArduinoWebsockets-0.4.9/src/tiny_websockets/internals/websockets_endpoint.hpp:7:10: fatal error: memory.h: No such file or directory
#include <memory.h>
^~~~~~~~~~
compilation terminated.
exit status 1
Error compiling for board Arduino/Genuino Mega or Mega 2560.
<-------END OF COMPILER ERROR
Please help !
Hi Gil...
This library is GREAT!!! Much needed. All the previous ones seemed very complex, especially for noobs like me. ;)
How would I use your library to create a server that just sends out the contents of an INT variable to connected clients every second, and doesn't disconnect the client?
Thanks!
--
Jim
Hi Gil, I am using your Arduino webSockets library with both the client and server running on an ESP32 Wroom-32 dev board in a similar manner to denden4444 described in issue #35. I have found the library really easy to use – it seems to have all the features I shall ever need. You have done a good job in writing this library. I am using the library to interface to my own local cloud server running on a Linux system where the code there is node.js. Initially I developed the Arduino code using inline code and it works perfectly.
In simple terms, the ESP board send a simple message to my local cloud to register itself and thereafter commands are sent from the cloud server to the ESP board to carry out various functions. All of this works. Your library is excellent.
I then wanted to use the same code in another application so I put the same client + server code in a library. The client component works perfectly but the server code does not work. When calling socket_server. available () function from within the library I always get a response that that server is not running. I have developed a test application which has the combined inline code and the library code and you can switch between the inline code and the library code by setting an integer to an appropriate value. Can you advise how I can try and determine the source of the problem?
I am happy to let you have the test code to illustrate the problem.
The board I am using is an ESP32 Wroom-32 dev board.
The library version I am using is 0.4.12 – the latest as of 17 October 2019.
I have a simple test harness in node.js for the local cloud function which I can also provide but I have also done some testing using netcat in Linux (i.e. the nc command).
Your library looks great. It seems to be more updated than
https://github.com/PaulStoffregen/ArduinoWebsocketClient
I am hoping to use Websocket through the wizen module on a teensy 3.2 (Arduino compatible micro controller).
But the library I am currently using does not support SEC-Key but it looks yours does.
Do you think it would be possible to add support for the wiznet ethernet module?
Your wifi solution is great but I find a wired solution more secure for long term installations.
Thanks for any advice.
For versions above 0.4.0 sending binary (video frames) is crashing in my script:
Cut down code on ESP32 (Arduino IDE)
void loop() {
auto client = socket_server.accept();
client.onMessage(handle_message);
while (client.available()) {
client.poll();
fb = esp_camera_fb_get();
client.sendBinary((const char *)fb->buf, fb->len);
esp_camera_fb_return(fb);
fb = NULL;
}
}
JS in browser:
document.addEventListener("DOMContentLoaded", function(event) {
var baseHost = document.location.origin;
const WS_URL = "ws://" + window.location.host + ":82";
const ws = new WebSocket(WS_URL);
ws.onmessage = message => {
if (message.data instanceof Blob) {
var urlObject = URL.createObjectURL(message.data);
view.src = urlObject;
}
};
});
It works great in 0.4.0 so I don't know if some code was changed for send.binary in later versions?
Crash report....
[D][WiFiClient.cpp:482] connected(): Disconnected: RES: 0, ERR: 128
[E][WiFiClient.cpp:365] write(): fail on fd 63, errno: 11, "No more processes"
[E][WiFiClient.cpp:365] write(): fail on fd 63, errno: 11, "No more processes"
[E][WiFiClient.cpp:365] write(): fail on fd 63, errno: 11, "No more processes"
[E][WiFiClient.cpp:365] write(): fail on fd 63, errno: 11, "No more processes"
[E][WiFiClient.cpp:365] write(): fail on fd 63, errno: 11, "No more processes"
abort() was called at PC 0x40136eeb on core 1Backtrace: 0x40091408:0x3ffb1d20 0x40091639:0x3ffb1d40 0x40136eeb:0x3ffb1d60 0x40136f32:0x3ffb1d80 0x401362bf:0x3ffb1da0 0x401363ae:0x3ffb1dc0 0x40136365:0x3ffb1de0 0x400d575b:0x3ffb1e00 0x400d57b6:0x3ffb1e30 0x400d4b8a:0x3ffb1e60 0x400d3339:0x3ffb1e80 0x400d9be9:0x3ffb1fb0 0x4008d3a5:0x3ffb1fd0
Rebooting...
Decoding stack results
0x40091408: invoke_abort at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/panic.c line 155
0x40091639: abort at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/panic.c line 170
0x40136eeb: __cxxabiv1::__terminate(void ()()) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_terminate.cc line 47
0x40136f32: std::terminate() at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_terminate.cc line 57
0x401362bf: __cxxabiv1::__cxa_throw(void, std::type_info*, void ()(void)) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_throw.cc line 87
0x401363ae: operator new(unsigned int) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/new_op.cc line 54
0x40136365: operator new[](unsigned int) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/new_opv.cc line 32
0x400d575b: websockets::internals::WebsocketsEndpoint::send(char const*, unsigned int, unsigned char, bool, bool, char const*) at C:\Users\Dude\Documents\Arduino\libraries\ArduinoWebsockets\src\websockets_endpoint.cpp line 367
0x400d57b6: websockets::internals::WebsocketsEndpoint::send(char const*, unsigned int, unsigned char, bool) at C:\Users\Dude\Documents\Arduino\libraries\ArduinoWebsockets\src\websockets_endpoint.cpp line 321
0x400d4b8a: websockets::WebsocketsClient::sendBinary(char const*, unsigned int) at C:\Users\Dude\Documents\Arduino\libraries\ArduinoWebsockets\src\websockets_client.cpp line 396
0x400d3339: loop() at C:\Users\Dude\Documents\Arduino\CameraWebServerWeChatWebSockets/CameraWebServerWeChatWebSockets.ino line 358
0x400d9be9: loopTask(void*) at C:\Users\Dude\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.3-rc1\cores\esp32\main.cpp line 19
0x4008d3a5: vPortTaskWrapper at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/port.c line 143
Hi Gil
Both server and client are working great so far.
I would like to replace the existing websockets library I have been using with your one.
For this I need to know how to use message.data() and what it is .. array struct etc and what format the data is in ?
In the previous library I was working with a payload array and am doing comparisons like :
if (payload[0] == '#') {
If you would be so kind as to expand on this a little it would save me oodles of time in switching my code over to start using and and use your awesome library.
I love the way it has very granular control.
I'm about to start on creating a client and server in one sketch for testing.Will update you on progress too.
I look forward to your reply.
Den
I'm not sure I'm doing this right. I'm want to send a stream of co-ordinates from the browser and drive a servo based on them, I get one though and then the browser error shown in the subject line above. Code pasted below.
Maybe auto client = server.accept(); should be outside the loop?
#include <ArduinoWebsockets.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
AsyncWebServer webserver(80);
using namespace websockets;
WebsocketsServer server;
void setup() {
Serial.begin(115200);
// Connect to wifi
WiFi.begin(ssid, password);
// Wait some time to connect to wifi
for(int i = 0; i < 15 && WiFi.status() != WL_CONNECTED; i++) {
Serial.print(".");
delay(1000);
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP()); //You can get IP address assigned to ESP
webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html_gz, sizeof(index_html_gz));
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
webserver.begin();
server.listen(83);
Serial.print("Is server live? ");
Serial.println(server.available());
}
void loop() {
auto client = server.accept();
if(client.available()) {
Serial.println("client.available");
auto msg = client.readBlocking();
// log
Serial.print("Got Message: ");
Serial.println(msg.data());
}
}
Hello, I'm using an esp32 (olimex esp32 gateway) as a websocket serve which a local html5 page connects to. Its wired via ethernet.
If the webpage crahes, I want it to reconnect on relaunch.
I'm using a flag to store the connection state of the websocket,
which is updated in the websocket event callback.
However these are not called on connection.
Serial.println("TEMP: connected"); is printing fine and javascript ws.onopen returns true.
Whats wrong?
How can I detect the websocket state here?
#include <ArduinoWebsockets.h>
#include <ETH.h>
bool eth_connected = false;
IPAddress local_IP(192, 168, 0, 50);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 0, 0);
IPAddress primaryDNS(9, 9, 9, 9);
IPAddress secondaryDNS(8, 8, 8, 8);
bool ws_connected = false;
using namespace websockets;
WebsocketsServer server;
WebsocketsClient client;
// Ethernet callbacks
void WiFiEvent(WiFiEvent_t event)
{
switch (event) {
case SYSTEM_EVENT_ETH_START:
Serial.println("ETH Started");
//set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case SYSTEM_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
}
void onMessageCallback(WebsocketsMessage message) {
Serial.print("Got Message: ");
Serial.println(message.data());
}
void onEventsCallback(WebsocketsEvent event, String data) {
if (event == WebsocketsEvent::ConnectionOpened) {
Serial.println("Connnection Opened");
ws_connected = true;
} else if (event == WebsocketsEvent::ConnectionClosed) {
Serial.println("Connnection Closed");
ws_connected = false;
} else if (event == WebsocketsEvent::GotPing) {
Serial.println("Got a Ping!");
} else if (event == WebsocketsEvent::GotPong) {
Serial.println("Got a Pong!");
}
}
void setup() {
Serial.begin(115200);
// Connect ethernet
WiFi.onEvent(WiFiEvent);
ETH.begin();
ETH.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
server.listen(80);
Serial.print("Is server live? ");
Serial.println(server.available());
}
void loop() {
if (eth_connected) {
// ethernet connected, wait for websocket
if (ws_connected == true) {
if (client.available()) {
WebsocketsMessage msg = client.readBlocking();
Serial.print("Got Message: ");
Serial.println(msg.data());
}
}
else {
Serial.println("no websocket client, waiting for connection ...");
// Setup Callbacks
client.onMessage(onMessageCallback);
client.onEvent(onEventsCallback);
// wait for client (blocking ...)
client = server.accept();
Serial.println("TEMP: connected");
}
// polling also needed to detect close state ?
client.poll();
}
else {
ETH.begin();
ETH.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
delay(3000);
}
}
Using your example, I can connect to wss://echo.websocket.org but not wss://ws-feed.pro.coinbase.com, nor wss://api.bitfinex.com/ws/2.
I've tried with fingerprint and with client.setInsecure(), no luck.
Some logs:
14:19:08.149 -> connect ws...
14:19:08.149 -> [hostByName] request IP for: api.bitfinex.com
14:19:08.184 -> pm open,type:2 0
14:19:08.184 -> [hostByName] Host: api.bitfinex.com IP: 104.16.171.181
14:19:08.252 -> :ref 1
14:19:08.287 -> BSSL:_connectSSL: start connection
14:19:08.321 -> :wr 221 0
14:19:08.321 -> :wrc 221 221 0
14:19:08.356 -> :ack 221
14:19:08.391 -> :rn 536
.......................................
14:19:09.598 -> :rdi 32, 32
14:19:09.598 -> :c0 32, 43
14:19:09.632 -> BSSL:Connected!
14:19:09.632 -> :wr 180 0
14:19:09.632 -> :wrc 180 180 0
14:19:09.737 -> :ack 180
14:19:09.737 -> BSSL:read: failed
14:19:09.737 -> BSSL:read: failed
14:19:09.771 -> BSSL:read: failed
14:19:09.805 -> BSSL:read: failed
14:19:09.805 -> BSSL:read: failed
14:19:09.839 -> BSSL:read: failed
14:19:09.839 -> BSSL:read: failed
14:19:09.874 -> BSSL:read: failed
14:19:09.874 -> BSSL:read: failed
14:19:09.908 -> BSSL:read: failed
14:19:09.908 -> BSSL:read: failed
14:19:09.943 -> BSSL:read: failed
14:19:09.977 -> BSSL:read: failed
14:19:09.977 -> BSSL:read: failed
14:19:10.011 -> BSSL:read: failed
14:19:10.011 -> BSSL:read: failed
14:19:10.046 -> :rn 536
14:19:10.046 -> :rch 536, 173
14:19:10.080 -> :rch 709, 125
If I try connecting to the unsecured ones (ws://api.bitfinex.com/ws/2)
14:23:46.080 -> connect ws...
14:23:46.080 -> [hostByName] request IP for: api.bitfinex.com
14:23:46.115 -> pm open,type:2 0
14:23:46.149 -> [hostByName] Host: api.bitfinex.com IP: 104.16.175.181
14:23:46.183 -> :ref 1
14:23:46.218 -> :wr 159 0
14:23:46.218 -> :wrc 159 159 0
14:23:46.288 -> :ack 159
14:23:46.288 -> :rn 288
14:23:46.288 -> :wr 2 0
14:23:46.288 -> :wrc 2 2 0
14:23:46.323 -> :wr 2 0
14:23:46.323 -> :wrc 2 2 0
14:23:46.358 -> :ack 2
14:23:46.358 -> :rch 288, 332
14:23:46.358 -> :rcl
14:23:46.358 -> :abort
14:23:46.392 -> Connnection Closed
Any ideas?
Thanks a lot
Me again. As part of the same set of projects I'm using face detection and recognition from this library: https://github.com/espressif/esp-who
I want to send images and also a message to the browser (for further actions) when a face is detected. I can do it like this which is working well:
(loop)
//camera and detection stuff here
if(detected==true){
client.send("Face Detected");
}
client.sendBinary((const char *)_jpg_buf, _jpg_buf_len);
(/loop)
ws.onmessage = message => {
if (typeof message.data === 'string'){
console.log("Face Detected")
}
if (message.data instanceof Blob){
var urlObject = URL.createObjectURL(message.data);
ws_img.setAttribute('src', urlObject);
}
I'm not sure this is the best way to separate the two sent items. Also if I can work out how to do it I want to send the mapping of the face instead of just a message which I'm guessing will be another blob.
Is this the best way of sending two different things to the client? I couldn't see a way of identifying messages as they are sent.
I'll get back to you on the other question soon.
Looks like 0 chars in binary package terminats packed.
Or msg.data().length() is not working ...
Hi Gil
I am experiencing a compile error ..
`
In file included from C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/internals/ws_common.hpp:47:0,
from C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/message.hpp:3,
from C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/ArduinoWebsockets.h:4,
from C:\Users\den\Documents\Arduino\libraries\arduino_290866\examples\Esp8266-Client\Esp8266-Client.ino:19:
C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/network/esp8266/esp8266_tcp.hpp: In member function 'void websockets::network::SecuredEsp8266TcpClient::setInsecure()':
C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/network/esp8266/esp8266_tcp.hpp:18:20: error: 'class WiFiClientSecure' has no member named 'setInsecure'
this->client.setInsecure();
^
C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/network/esp8266/esp8266_tcp.hpp: In member function 'void websockets::network::SecuredEsp8266TcpClient::setFingerprint(const char*)':
C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/network/esp8266/esp8266_tcp.hpp:22:20: error: 'class WiFiClientSecure' has no member named 'setFingerprint'
this->client.setFingerprint(fingerprint);
^
exit status 1
Error compiling for board Generic ESP8266 Module.
`
Could you please shed some light ?
Kind regards
Den
Hello, I would like to use this library to develop a websocketclient wich will communicate with a php laravel websocketserver.
This websocket server is currently running and comunicating with other websocket clients written in javascript.
new WebSocket(ws://192.168.1.12:6001);
Above is shown the way in wich javascript objects are being created (these objects can comunicate with the websocket server).
This is my question, when i call the connect method, I would like to pass the host, the port and the path independiently as shown below, in this case its pretty easy to identify the host and the port, but i have some doubts about which will be the correct path.
#define IP_ADDRESS "192.168.1.12"
#define PORT 6001
#define PATH "/"
websocket.connect(IP_ADDRESS, PORT, PATH);
I know this looks like a basic question, but i would like to know which is the correct answer.
Thanks in advance
Describe the bug
Strange warning when connecting to a websocket server:
[E][WiFiClient.cpp:309] setOption(): fail on fd -1, errno: 9, "Bad file number"
To Reproduce
Just connect to a websocket server as shown in the examples.
Expected behavior
This warning is unexpected...
Code
Should be able to reproduce with the given examples.
Additional context
ESP32, framework-arduinoespressif32 2.10004.191002 (1.0.4)
Hi Gil
Part of migrating my existing code to use your code involves handling multiple clients from the server side.
Is this possible and how do you handle this ?
Specifically :
How do you handle multiple clients and replies to each individual client ?
How do you identify each in turn and their specific data back and forth ?
Kind regards
Den
Hello!
I'm trying to use this library on an ESP32 against API's that stream very large messages (~40k).
It works fine for the smaller messages, however as soon as a large message (should be) received a WebsocketsEvent::ConnectionClosed
event is emitted and the connection is dropped.
I did some brief digging and it looks like the TCP connection stops being available()
, but I'm not clear why.
This example code demonstrates the problem:
#include <ArduinoWebsockets.h>
#include <WiFi.h>
const char* ssid = "SSID";
const char* password = "PASSWORD";
const char* websockets_connection_string = "wss://ws.blockchain.info/inv";
using namespace websockets;
void onMessageCallback(WebsocketsMessage message) {
Serial.print("Got Message: ");
Serial.println(message.data());
}
WebsocketsClient client;
void onEventsCallback(WebsocketsEvent event, String data) {
if(event == WebsocketsEvent::ConnectionOpened) {
Serial.println("ConnectionOpened");
} else if(event == WebsocketsEvent::ConnectionClosed) {
Serial.println("ConnectionClosed");
} else if(event == WebsocketsEvent::GotPong) {
Serial.println("GotPong");
}
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
for(int i = 0; i < 10 && WiFi.status() != WL_CONNECTED; i++) {
Serial.print(".");
delay(1000);
}
client.onMessage(onMessageCallback);
client.onEvent(onEventsCallback);
client.setCACert(nullptr);
client.connect(websockets_connection_string);
// Works - results in "GotPong"
client.ping();
// Works - results in "Got Message: {"op":"pong"}"
client.send("{\"op\":\"ping\"}");
// FAILS - results in "ConnectionClosed"
// This will cause ~40k of data to be returned down the websocket
client.send("{\"op\":\"ping_block\"}");
}
void loop() {
client.poll();
}
Any help very much appreciated.
I've found yet another bug while working on receiving extremely large websocket messages, however I'm not entirely convinced it's size related.
The same test program as from the previous large message issue should reproduce the problem:
#include <ArduinoWebsockets.h>
#include <WiFi.h>
const char* ssid = "SSID";
const char* password = "PASSWORD";
const char* websockets_connection_string = "wss://ws.blockchain.info/inv";
using namespace websockets;
void onMessageCallback(WebsocketsMessage message) {
Serial.print("Got Message: ");
Serial.println(message.data());
}
WebsocketsClient client;
void onEventsCallback(WebsocketsEvent event, String data) {
if(event == WebsocketsEvent::ConnectionOpened) {
Serial.println("ConnectionOpened");
}
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
for(int i = 0; i < 10 && WiFi.status() != WL_CONNECTED; i++) {
Serial.print(".");
delay(1000);
}
client.onMessage(onMessageCallback);
client.onEvent(onEventsCallback);
client.setCACert(nullptr);
client.connect(websockets_connection_string);
// Results in total memory exhaustion, regardless of the amount of free memory available
// ESP Panics
client.send("{\"op\":\"ping_block\"}");
}
void loop() {
client.poll();
}
I obtained an ESP32 WROVER module with 8mb of ram, which I know all the messages should easily fit into. At first I thought the allocator was failing to use the external memory as it carried on crashing, but after some digging it's revealed an odd bug.
It seems that the following segment of code in websockets_endpoint.cpp
is the cause of the memory exhaustion:
ArduinoWebsockets/src/websockets_endpoint.cpp
Lines 177 to 181 in a3da335
Inserting a print
statement to show the size of numReceived
reveals normal behaviour right up until the crash, at which point the value of numReceived
is set to the maximum value for uint32_t
(4294967295) and the loop reads garbage data until the device runs out of memory.
Changing uint32_t
to uint64_t
for the return of client.read()
resulted in the max value for uint64_t
being returned instead.
This is a log & backtrace of the above program running, with websockets_endpoint.cpp
patched to print out the size of numReceived
:
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:852
load:0x40078000,len:8424
load:0x40080400,len:5880
entry 0x4008069c
.[E][WiFiClient.cpp:309] setOption(): fail on fd -1, errno: 9, "Bad file number"
ConnectionOpened
size: 512
size: 512
size: 512
size: 512
size: 512
size: 512
size: 512
size: 498
size: 512
size: 512
size: 512
size: 512
size: 512
size: 512
size: 512
size: 498
size: 512
size: 512
size: 512
size: 512
size: 326
size: 512
size: 512
size: 512
size: 172
size: 512
size: 512
size: 373
size: 4294967295
Guru Meditation Error: Core 1 panic'ed (LoadStoreError). Exception was unhandled.
Core 1 register dump:
PC : 0x401421ca PS : 0x00060c30 A0 : 0x8014228c A1 : 0x3ffb1bf0
0x401421ca: websockets::internals::readData[abi:cxx11](websockets::network::TcpClient&, unsigned long long) at /Users/jonty/code/esp/xtensa-esp32-elf/xtensa-esp32-elf/include/c++/5.2.0/bits/shared_ptr_base.h:659
A2 : 0x00000575 A3 : 0x3ffbb9b8 A4 : 0x00000ff2 A5 : 0xffffffff
A6 : 0x3ffb1e44 A7 : 0x00000000 A8 : 0x0001f627 A9 : 0x40000000
A10 : 0x00000000 A11 : 0x000000fe A12 : 0x3ffb1c0c A13 : 0x00000000
A14 : 0x00000ff2 A15 : 0x3ffe636c SAR : 0x00000004 EXCCAUSE: 0x00000003
EXCVADDR: 0x40000000 LBEG : 0x40098705 LEND : 0x40098715 LCOUNT : 0xffffffff
0x40098705: strlen at /home/jeroen/esp8266/esp32/newlib_xtensa-2.2.0-bin/newlib_xtensa-2.2.0/xtensa-esp32-elf/newlib/libc/machine/xtensa/../../../../.././newlib/libc/machine/xtensa/strlen.S:84
0x40098715: strlen at /home/jeroen/esp8266/esp32/newlib_xtensa-2.2.0-bin/newlib_xtensa-2.2.0/xtensa-esp32-elf/newlib/libc/machine/xtensa/../../../../.././newlib/libc/machine/xtensa/strlen.S:96
Backtrace: 0x401421ca:0x3ffb1bf0 0x40142289:0x3ffb1e30 0x401433fd:0x3ffb1e80 0x4013f7e3:0x3ffb1ef0 0x4013bdfa:0x3ffb1f90 0x401207e1:0x3ffb1fb0 0x4008b799:0x3ffb1fd0
0x401421ca: websockets::internals::readData[abi:cxx11](websockets::network::TcpClient&, unsigned long long) at /Users/jonty/code/esp/xtensa-esp32-elf/xtensa-esp32-elf/include/c++/5.2.0/bits/shared_ptr_base.h:659
0x40142289: websockets::internals::WebsocketsEndpoint::_recv() at /Users/jonty/code/esp/xtensa-esp32-elf/xtensa-esp32-elf/include/c++/5.2.0/bits/shared_ptr_base.h:659
0x401433fd: websockets::internals::WebsocketsEndpoint::recv() at /Users/jonty/code/chain/components/arduino/libraries/ArduinoWebsockets/src/websockets_endpoint.cpp:312
0x4013f7e3: websockets::WebsocketsClient::poll() at /Users/jonty/code/chain/components/arduino/libraries/ArduinoWebsockets/src/websockets_client.cpp:499
0x4013bdfa: loop() at /Users/jonty/code/chain/main/main.cpp:93
0x401207e1: loopTask(void*) at /Users/jonty/code/chain/components/arduino/cores/esp32/main.cpp:19
0x4008b799: vPortTaskWrapper at /Users/jonty/code/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
to_read
is always a sane value, so I also tried adding an extra check to the read loop to ensure that i <= to_read
and while this prevented the memory exhaustion it resulted in being disconnected from the server shortly afterward, so clearly the session state is messed up.
This should be easily reproducible on an ESP32 with limited memory as the exhaustion trigger happens before any significant memory usage, although I've not tested this.
Let me know if you need any more information, or want me to test things.
Hi!
First of all, thanks for this lovely library!
I have found something that is similar to #25
I use https://github.com/websockets/wscat for my development. And start up a server.
The first time, client.connect works.
Also, if I never start the server, client.connect does not crash and I can stay in a client.available loop.
However, if I start the board, it successfully connects to the server. Then reboot the board (without wscat noticing) and it tries to connect to wscat that still thinks it's connected to the previous boot. Then the board crashes.
I have extracted the stacktrace:
PC: 0x400d2e18: WiFiClientRxBuffer::read(unsigned char*, unsigned int) at /home/lex/.arduino15/packages/esp32/hardware/esp32/1.0.4-rc1/libraries/WiFi/src/WiFiClient.cpp line 107
EXCVADDR: 0x00000008
Decoding stack results
0x400d2e18: WiFiClientRxBuffer::read(unsigned char*, unsigned int) at /home/lex/.arduino15/packages/esp32/hardware/esp32/1.0.4-rc1/libraries/WiFi/src/WiFiClient.cpp line 107
0x400d2ee9: WiFiClient::read(unsigned char*, unsigned int) at /home/lex/.arduino15/packages/esp32/hardware/esp32/1.0.4-rc1/libraries/WiFi/src/WiFiClient.cpp line 434
0x4015fcea: WiFiClient::read() at /home/lex/.arduino15/packages/esp32/hardware/esp32/1.0.4-rc1/libraries/WiFi/src/WiFiClient.cpp line 345
0x400e32af: websockets::network::GenericEspTcpClient ::readLine() at /home/lex/Arduino/libraries/ArduinoWebsockets/src/tiny_websockets/network/generic_esp/generic_esp_clients.hpp line 46
0x400e2fce: websockets::WebsocketsClient::connect(String, int, String) at /home/lex/Arduino/libraries/ArduinoWebsockets/src/websockets_client.cpp line 279
0x400d1ac5: loop() at /home/lex/Arduino/sketch_oct15a/sketch_oct15a.ino line 95
0x400e870d: loopTask(void*) at /home/lex/.arduino15/packages/esp32/hardware/esp32/1.0.4-rc1/cores/esp32/main.cpp line 19
0x40088dbd: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
Board: Huzzah 32
Websockets: 0.4.11
Wscat: 2.2.1
Don't really know why it behaves differently when trying to connect to a non open port vs a port that I guess "thinks" it's open.
This will probably not cause any issue for me during production when I run with a real server but I would like to contribute to making this library rock-solid in any way I can.
Cheers!
I got 'false' at client.connect().
here
Maybe wss://echo.websocket.org/ is changed fingerprint.
Hi. This might be more of a programming question again but...
Something like this works:
void delete_all_faces() {
delete_face_all_in_flash_with_name(&st_face_list);
}
void handle_message(WebsocketsMessage msg) {
if (msg.data() == "delete_all") {
delete_all_faces();
g_state = DELETE_ALL;
}
}
void loop() {
auto client = socket_server.accept();
client.onMessage(handle_message);
while (client.available()) {
client.poll();
switch (g_state) {
case DELETE_ALL:
client.send("All Faces Deleted");
break;
case ...
}
}
}
But I would prefer to send the message from the delete_all_faces function something like this...
void delete_all_faces() {
delete_face_all_in_flash_with_name(&st_face_list);
client.send("All Faces Deleted");
}
void handle_message(WebsocketsMessage msg) {
if (msg.data() == "delete_all") {
delete_all_faces();
}
}
void loop() {
auto client = socket_server.accept();
client.onMessage(handle_message);
while (client.available()) {
...
}
}
Is it possible to make 'client' accessible outside the loop?
Describe the bug
I have just downloaded the latest version of the library on Arduino IDE.
I am trying to complile the example "Minimal Esp8266 Websockets Client" sketch in a NodeMCU board and I am receiving "Error compiling for board NodeMCU 1.0 (ESP-12E Module)."
Is the library compatible with NodeMCU 1.0 board?
Hey!
This is a question. I'm using this lib together with https://arduinojson.org
My code currently looks like:
void onWsMsg(WebsocketsMessage message) {
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, message.data());
JsonObject obj = doc.as<JsonObject>();
and
void sendJson(JsonObject obj) {
char output[2048];
serializeJson(obj, output);
client.send(output);
}
My question is if it would be possible to hook ArduinoWebsockets up directly with the stream functionality of https://arduinojson.org/v6/api/json/deserializejson/ and https://arduinojson.org/v6/api/json/serializejson/ and if so how I would do that.
Cheers!
In version 0.3.1 and using the following code in a loop, after some random time (sometimes a long time) available() will return false, and bConnected will return true. Yet in the next loop around available is still false. The project in question is constantly sending and receiving websocket data until this problem occurs.
if(m_objWebsocketClient.available()) {
m_objWebsocketClient.poll();
} else {
bConnected = m_objWebsocketClient.connect(m_sTCI_server, port, "/");
}
Consider:
Hi Gil
ESP8266 server example won't compile .. (similar issues to my previous post about the client example not compiling.
`
In file included from C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/internals/ws_common.hpp:47:0,
from C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/message.hpp:3,
from C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/ArduinoWebsockets.h:4,
from C:\Users\den\AppData\Local\Temp\arduino_modified_sketch_512897\Esp8266-Server.ino:20:
C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/network/esp8266/esp8266_tcp.hpp: In member function 'void websockets::network::SecuredEsp8266TcpClient::setInsecure()':
C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/network/esp8266/esp8266_tcp.hpp:18:20: error: 'class WiFiClientSecure' has no member named 'setInsecure'
this->client.setInsecure();
^
C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/network/esp8266/esp8266_tcp.hpp: In member function 'void websockets::network::SecuredEsp8266TcpClient::setFingerprint(const char*)':
C:\Users\den\Documents\Arduino\libraries\arduino_290866\src/tiny_websockets/network/esp8266/esp8266_tcp.hpp:22:20: error: 'class WiFiClientSecure' has no member named 'setFingerprint'
this->client.setFingerprint(fingerprint);
^
exit status 1
Error compiling for board Generic ESP8266 Module.
Hope you can help
Kind regards
Den
`
Describe the bug
Websocketclient is disconnected from websocketserver after client get a ping from server
To Reproduce
Library : 0.4.11
Board : NodeMCU
Steps to reproduce the behavior.
Expected behavior
I just hope the client doesn't disconnect from server
Additional context
When this first happens, I thought it was because of a bug of the library, but i realized that the websocketserver makes a ping to the client when it receives a connection, so I decided to supress this behavior. After doing this, the websocketclient worked as expected, but i have no idea of what am i doing wrong. I suppose that i should modify the code when the client receives a Ping, something like answer with a pong, but i am not sure
Describe the bug
I am using your library to receive a JSON file from a websocketserver. When it receive the file, it starts printing hexadecimal numbers and after two seconds aproximately the esp8266 restarts.
To Reproduce
Version : 0.4.11
Board : NODEMCU
Only using this library
Expected behavior
I expect to receive the json file, wich is received as a string, and later i want to print it By using serial library
Additional context
I supposed that this problem was related to the receive buffer size, so I execute the same code, but receiving a short json file and it worked as expected, so I think the problem is not related to code.
Hi,
I'm using the code from the Client Example for an SSL server.
Most of it works as expected, however - if I shutdown the WebSocket server I'm connected to or even disconnect the network, no event is being triggered.
Surprisingly, even if i call client.available()
it returns true
, even though the server is shut down or there's no network connection to it...
I'm using an ESP-WROOM-32 board if and an NGinx WebSocket server. The socket server works without any issue with any browser client (tested EDGE, Firefox, Chrome) and these browsers successfully report a server disconnect or so.
As told, code is the one from the client example:
#include <ArduinoWebsockets.h>
#include <WiFi.h>
const char* ssid = "WiFi Name"; //Enter SSID
const char* password = "WiFi Password"; //Enter Password
const char* websockets_server = "wss://url.com:443/ws/"; //server adress and port
using namespace websockets;
void onMessageCallback(WebsocketsMessage message) {
Serial.print("Got Message: ");
Serial.println(message.data());
}
void onEventsCallback(WebsocketsEvent event, String data) {
if(event == WebsocketsEvent::ConnectionOpened) {
Serial.println("Connnection Opened");
} else if(event == WebsocketsEvent::ConnectionClosed) {
Serial.println("Connnection Closed");
} else if(event == WebsocketsEvent::GotPing) {
Serial.println("Got a Ping!");
} else if(event == WebsocketsEvent::GotPong) {
Serial.println("Got a Pong!");
}
Serial.println("Event triggered...");
}
WebsocketsClient client;
void setup() {
Serial.begin(115200);
// Connect to wifi
WiFi.begin(ssid, password);
// Wait some time to connect to wifi
for(int i = 0; i < 10 && WiFi.status() != WL_CONNECTED; i++) {
Serial.println(".");
delay(1000);
}
Serial.println("Connected to WiFi... probably.");
// Setup Callbacks
client.onMessage(onMessageCallback);
client.onEvent(onEventsCallback);
// Connect to server
client.connect(websockets_server);
// Send a message
client.send("This is a nice little message sent from ESP32.");
}
void loop() {
if (client.available()) {
client.poll();
} else {
Serial.println("OOPS!! Client Disconnected...");
delay(5000);
}
}
If there's any detail I can help you with to debug this issue, just let me know.
All the best,
A.
I am new to Arduino and have a few questions:
Thank you.
Currently there is a lot of info in the TinyWebsockets Wiki but no one seems to arrive there.
Hi there,
first, thank you for doing this, it seems a solid library to me.
My question: I didn’t see any examples of a secured websocket server for esp32 or any other, did I miss something or isnt there a way yet?
Thank you
Describe the bug
Infinite connection process if wifi is not connected
To Reproduce
The connection process is not timed out if wifi lost the connection or wifi was not connected.
Usually wifi gets DISCONNECTED status after Websocket loses the connection, so the connection process stacks ESP
I'm trying to setup a websocket server on my Arduino UNO wifi rev 2, but as soon as I include ArduinoWebsockets to my script, I get a compilation error:
In file included from /.../Arduino/libraries/ArduinoWebsockets/src/tiny_websockets/message.hpp:3:0,
from /.../Arduino/libraries/ArduinoWebsockets/src/ArduinoWebsockets.h:4,
from /.../Arduino/distancemeterWifi/distancemeterWifi.ino:3:
/.../Arduino/libraries/ArduinoWebsockets/src/tiny_websockets/internals/ws_common.hpp:4:10: fatal error: string: No such file or directory
#include <string>
^~~~~~~~
compilation terminated.
exit status 1
I'm fairly new to the programming language, so I have no clue what is causing this... Why is this importing "string" ?
Hi Gil,
Me again (and again, and again). :D
I just want to bring to your attention and old discussed issue, regarding the SSL Certificate and Handshaking, on ESP32
.
Situation 1: When not using any sort of certificate but using an WSS (secure) server/URL, the debug messages report that the certificate is verified, though I don't provide any CA
resource (as browsers do).
Situation 2: When I provide a good CA along with the client.setCAcert()
method, the verification passes as well.
(messages for both situation 1 and 2):
[V][ssl_client.cpp:53] start_ssl_client(): Free internal heap before TLS 277372
[V][ssl_client.cpp:55] start_ssl_client(): Starting socket
[V][ssl_client.cpp:90] start_ssl_client(): Seeding the random number generator
[V][ssl_client.cpp:99] start_ssl_client(): Setting up the SSL/TLS structure...
[V][ssl_client.cpp:112] start_ssl_client(): Loading CA cert
[V][ssl_client.cpp:177] start_ssl_client(): Setting hostname for TLS session...
[V][ssl_client.cpp:192] start_ssl_client(): Performing the SSL/TLS handshake...
[V][ssl_client.cpp:213] start_ssl_client(): Verifying peer X.509 certificate...
[V][ssl_client.cpp:222] start_ssl_client(): Certificate verified.
[V][ssl_client.cpp:237] start_ssl_client(): Free internal heap after TLS 236048
Situation 3: However, when I provide a wrong CA resource (e.g. an invalid CA root cert.), the handshaking fails (as it should).
The question is: When not providing a CA resource (Situation 1), does the library verifies indeed the certificate in any way or not? Does it connect remotely to the CA Roots and verifies it? I guess this ssl_client
is inherited by Espressifs library...
I tested the above situations with an LetsEncrypt certificate along its roots ( https://letsencrypt.org/certificates/ ).
Many thanks,
Best,
A.
Hi Gil
Hope all's well with you.
As you may recall I have been testing your websockets on the ESP8266 and the tests have been good so far.
I'm hoping you could possibly identify/clarify some strange anomalies.
I am running both client and server on the same ESP8266.
Please refer to this image:
A is a client (web browser) and needs to stay connected all the time until A decides it wants to disconnect
B is the ESP running both client and server.
When B receives a certain message , B fires up the websocket client portion and as w ebsocket client establishes a connection with C (C is running as a websockets server)
The above happen successfully (YAY ;-)) BUT
after B closes the connection (client disconnect) with C , the connection of A to B is lost. :-(
I have tried to set B not to close the connection to C ( no disconnect) but the same behavior occurs between A and B.
So I end up having to refresh the browser at A which re-establishes the connection from A to B.
Could you possibly shed some light as to how or where I could check and fix this ?
I'm not sure if this your software that may be causing the following :
Sometimes base on the problem in point 1. above , I am unable to re-establish a browser and/or websocket connection from A to B .
Its seems like B just stops servicing browser and/or websocket requests and sometimes a ping even though the serial console is still responding quite fine.
Any thoughts ?
Kind regards
Den
Describe the bug
ESP32 is configured as server that accepts multiple clients. When connecting from firefox browser using server.poll(), two clients are registered (in most cases).
When this happens, no more code is executed. (It appears to be trapped in handshake part of server.accept() ).
To Reproduce
Using below code, connect to the esp32 board from firefox browser.
Expected behavior
Only 1 client is added to the list for each new connection (which is what happens in chrome).
Code
#include <WiFi.h>
#include <ArduinoWebsockets.h>
using namespace websockets;
const char *ssid = "xxxx";
const char *password = "xxxx";
const int maxClients = 4; // Accept up to 4 connections
WebsocketsServer server;
WebsocketsClient clients[maxClients];
int nClients = 0;
void setup()
{
Serial.begin(115200);
while (!Serial)
;
// WIFI SETUP
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("WiFi connected, IP: ");
Serial.println(WiFi.localIP());
// WEBSOCKET: Open websocket on port 80
server.listen(80);
Serial.print("Is server live? ");
Serial.println(server.available());
}
void loop()
{
if (server.available())
{
// if there is a client that wants to connect
if (server.poll() && nClients < maxClients)
{
//accept the connection and register callback
Serial.print("Accepting a new client! Number of clients accepted: ");
Serial.println(nClients + 1);
WebsocketsClient client = server.accept();
client.onMessage(onMessage);
// store it for later use
clients[nClients] = client;
nClients++;
delay(10);
}
// check for updates in all clients
pollAllClients();
delay(10);
}
}
// this method goes thrugh every client and polls for new messages and events
void pollAllClients()
{
for (int i = 0; i < nClients; i++)
{
clients[i].poll();
}
}
// this callback is common for all clients, the client that sent that
// message is the one that gets the echo response
void onMessage(WebsocketsClient &client, WebsocketsMessage message)
{
Serial.print("Got Message: ");
Serial.print(message.data());
Serial.println(", Sending Echo.");
client.send("Echo: " + message.data());
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="../css/style.css" />
<script src="../js/websocket.js" defer></script>
<title>Websocket demo</title>
</head>
<body>
<table>
<thead>
<th>Status</th>
<th>Messages received</th>
</thead>
<tbody>
<td id="status">Not connected</td>
<td id="messages"></td>
</tbody>
</table>
<form>
<input type="button" id="msg_button" value="Send a msg" />
<input type="text" placeholder="IP of server" name="IP" id="IP" value="" />
<input type="button" id="IP_button" value="Configure IP" />
</form>
</body>
</html>
let messages = document.querySelector("#messages");
let status = document.querySelector("#status");
let ws;
document.querySelector("#IP_button").onclick = () => {
if(typeof ws !== 'undefined'){
ws.close();
}
ws = new WebSocket("ws://" + document.querySelector("#IP").value);
status.innerHTML = "Websocket " + ws.readyState;
ws.onopen = () => {
status.innerHTML = "Websocket open";
let i = 0;
document.querySelector("#msg_button").onclick = () => {
console.log("click");
ws.send(i++);
};
ws.onmessage = event => {
console.log(event);
let txt = messages.innerHTML;
messages.innerHTML = txt + "<br>" + event.data;
};
};
ws.onclose = () => {
status.innerHTML = "Websocket closed";
};
ws.onerror = event => {
console.log(event);
status.innerHTML = "Cannot connect to " + event.target.url;
};
};
Hello Gil
This looks like an awesome alternative to other libraries, and I'm quite excited to try it ;-)
I just need to know the following please :
I need to have the server and client on the same ESP. is this possible and if so could you kindly explain how or provide an example ?
Please see attached pic for reference.
I would like to enable to disable the connection(client and/or server) when desired/required, independently of eachother.
For example (pseudo code) :
client enable
do something
client disable
and same as above for server
Are you able to call (and control - disable/enable) client and/or server from anywhere other than the main loop ?
Really looking forward to your reply
Kind regards
Den
Connecting to AWS API Gateway Websockets
Without fingerprint
-- Connection Closed ([$disconnect] getting called in Cloudwatch logs)
Reason: 1002
With fingerprint
-- No response on serial (No API is getting called)
I am able to connect to the websocket server from cmd.
What might be the issue here?
Hi,
How can I implement Sec-WebSocket-Protocol transfer when connecting to a server?
How would I do it through JS:
let socket = new WebSocket("ws://xxx.xxx.xxx.x:8080/WebSocket/001", ["protocol1", "protocol2"]);
Hi Gil
How do you set the server to be non-blocking in the main loop , in other words to allow other code/functions to run ?
For example I have the following :
void loop() {
server.handleClient(); // run the web server
//websockets server
WebsocketsClient client = wsserver.accept();
if (client.available()) {
WebsocketsMessage msg = client.readBlocking();
// log
Serial.print("Got Message: ");
Serial.println(msg.data());
}
// return echo
client.send("Echo: " + msg.data());
// close the connection
client.close();
}//endof if client.available
//end of webSocket Server
SOME_OTHER_FUNCTION();
SOME_OTHER_FUNCTION_TWO();
//etc
//start from beginning of loop again
}
Look forward to your reply as always :-)
Den
My ESP32 panics when I try to connect to a WebSocket that is not running. This is not what I'd expect, I would expect it to try connecting and if it fails it just tells me that it failed and doesn't make the ESP32 panic.
Everything works as expected once I start the WebSocket.
This issue is closely related to #10 but the conclusion you've come to in this comment is that it only happens when there's not a working WiFi connection but it also happens if the WebSocket is not running.
This is the full panic message:
[E][WiFiClient.cpp:282] setOption(): fail on fd 54, errno: 22, "Invalid argument"
[E][WiFiClient.cpp:365] write(): fail on fd 54, errno: 104, "Connection reset by peer"
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x40122d4c PS : 0x00060830 A0 : 0x80123129 A1 : 0x3ffb1b70
A2 : 0x00000000 A3 : 0x3ffb1bcf A4 : 0x00000001 A5 : 0x00000001
A6 : 0x00000000 A7 : 0xffffffa7 A8 : 0x00000000 A9 : 0x00000000
A10 : 0x00000000 A11 : 0x3ffc8660 A12 : 0x00000000 A13 : 0x3f4108b2
A14 : 0x00000000 A15 : 0x00000001 SAR : 0x00000004 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000008 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff
Backtrace: 0x40122d4c:0x3ffb1b70 0x40123126:0x3ffb1b90 0x4016250a:0x3ffb1bc0 0x400d3daf:0x3ffb1bf0 0x400d3a36:0x3ffb1c10 0x400d466a:0x3ffb1d50 0x400d1e69:0x3ffb1f40 0x400d7f2b:0x3ffb1fb0 0x40088ea9:0x3ffb1fd0
Rebooting...
Hi!!!, first of all, the library is great!!!!, and sorry for my english.
I am working with a server that requires a token in connection header ("Authorization: JWT [token]") to accept the connection of websocket. Is possible to add a custom header in header request?
223index.html:39 WebSocket is already in CLOSING or CLOSED state.
(anonymous) @ index.html:39
setInterval (async)
ws.onopen @ index.html:38
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.