A library for writing modern websockets applications with Arduino (see prerequisites for supported platforms). This project is based on my project TinyWebsockets.
The library provides simple and easy interface for websockets work (Client and Server). See the basic-usage guide and the examples.
This section should help you get started with the library. If you have any questions feel free to open an issue.
Currently (version 0.5.*) the library only works with ESP8266
, ESP32
and Teensy 4.1
.
You can install the library from the Arduino IDE or using a release ZIP file from the Github release page. Detailed instructions can be found here.
Creating a client and connecting to a server:
WebsocketsClient client;
client.connect("ws://your-server-ip:port/uri");
Sending a message:
client.send("Hello Server!");
Waiting for messages:
client.onMessage([](WebsocketsMessage msg){
Serial.println("Got Message: " + msg.data());
});
In order to keep receiving messages, you should:
void loop() {
client.poll();
}
Creating a server and listening for connections:
WebsocketsServer server;
server.listen(8080);
Accepting connections:
WebsocketsClient client = server.accept();
// handle client as described before :)
#include <ArduinoWebsockets.h>
#include <ESP8266WiFi.h>
const char* ssid = "ssid"; //Enter SSID
const char* password = "password"; //Enter Password
const char* websockets_server = "www.myserver.com:8080"; //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!");
}
}
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.print(".");
delay(1000);
}
// Setup Callbacks
client.onMessage(onMessageCallback);
client.onEvent(onEventsCallback);
// Connect to server
client.connect(websockets_server);
// Send a message
client.send("Hi Server!");
// Send a ping
client.ping();
}
void loop() {
client.poll();
}
Note: for ESP32 you only need to change to code that connects to WiFi (replace #include <ESP8266WiFi.h>
with #include <WiFi.h>
), everything else stays the same.
#include <ArduinoWebsockets.h>
#include <ESP8266WiFi.h>
const char* ssid = "ssid"; //Enter SSID
const char* password = "password"; //Enter Password
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
server.listen(80);
Serial.print("Is server live? ");
Serial.println(server.available());
}
void loop() {
auto client = server.accept();
if(client.available()) {
auto msg = client.readBlocking();
// log
Serial.print("Got Message: ");
Serial.println(msg.data());
// return echo
client.send("Echo: " + msg.data());
// close the connection
client.close();
}
delay(1000);
}
Note: for ESP32 you only need to change to code that connects to WiFi (replace #include <ESP8266WiFi.h>
with #include <WiFi.h>
), everything else stays the same.
For binary data it is recommended to use msg.rawData()
which returns a std::string
, or msg.c_str()
which returns a const char*
.
The reason is that msg.data()
returns an Arduino String
, which is great for Serial printing and very basic memory handling but bad for most binary usages.
See issue #32 for further information.
No matter what board you are using, in order to use WSS (websockets over SSL) you need to use
client.connect("wss://your-secured-server-ip:port/uri");
The next sections describe board-specific code for using WSS with the library.
With the esp8266 there are multiple ways for using WSS. By default, ArduinoWebsockets
does not validate the certificate chain. This can be set explicitly using:
client.setInsecure();
You can also use a SSL Fingerprint
to validate the SSL connection, for example:
const char ssl_fingerprint[] PROGMEM = "D5 07 4D 79 B2 D2 53 D7 74 E6 1B 46 C5 86 4E FE AD 00 F1 98";
client.setFingerprint(ssl_fingerprint);
or you could use the setKnownKey()
method to specify the public key of a certificate in order to validate the server you are connecting to.
PublicKey *publicKey = new PublicKey(public_key);
client.setKnownKey(publicKey);
or you can specify the Certificate Authority (CA) using setTrustAnchors
method, as follows:
X509List *serverTrustedCA = new X509List(ca_cert);
client.setTrustAnchors(serverTrustedCA);
For client-side certificate validation, you can use RSA or EC certificates, using the method setClientRSACert
or setClientECCert
.
With the esp32 you could either provide the full certificate, or provide no certificate. An example for setting CA Certificate:
const char ssl_ca_cert[] PROGMEM = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n" \
"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n" \
"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\n" \
"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\n" \
"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\n" \
"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\n" \
"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\n" \
"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\n" \
"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\n" \
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\n" \
"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\n" \
"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\n" \
"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\n" \
"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\n" \
"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\n" \
"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\n" \
"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\n" \
"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\n" \
"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\n" \
"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\n" \
"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\n" \
"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\n" \
"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n" \
"-----END CERTIFICATE-----\n";
client.setCACert(ssl_ca_cert);
Currently WSS is not implemented.
Contributions are welcomed! Please open issues if you have troubles while using the library or any queshtions on how to get started. Pull requests are welcomed, please open an issue first.
Thanks for everyone who reported a bug, suggested a feature and contributed to the development of this library.
⭐️ arnoson |
⭐️ ramdor |
⭐️ xgarb |
matsujirushi |
bastienvans |
johneakin |
lalten |
⭐️ adelin-mcbsoft |
⭐️ Jonty |
Nufflee |
mmcArg |
JohnInWI |
logdog2709 |
elC0mpa |
⭐️ oofnik |
⭐️ zastrixarundell |
elielmarcos |
String
class. Merged more changes (mainly optimizations) from TinyWebsockets.setNoDelay(true)
instead of sync communication. This makes communication faster and more relaiable than default. Thank you @ramdor for pointing out these methods.client.setInsecure()
(does not validate certificate chain) or client.setFingerprint(fingerprint)
in order to use WSS. With ESP32 there is client.setCACert(certificate)
that can be used. (Usage is same as the built in WiFiClientSecure
).close
event callback not called in some cases (sudden disconnect, for example). Thank you @adelin-mcbsoft for pointing out the issue (related issue)setInsecure
method. Thank you adelin-mcbsoft!addHeader
method as suggested in issue #22). Thank you mmcArg!WiFiClient
library itself). Added some missing keywords. Thank you Nufflee for pointing out the issue!WebsocketClient
instances. Also handshake validation is now case insensitive. Thank you logdog2709 for pointing out the issue.yield
calls in order to prevent software-watchdog resets on esp8266 (on long messages). Thank you elC0mpa for documenting and helping with the issue.rawData
and c_str
as acccessors in WebsocketsMessage
so now the raw data can be acccessed which should solve issue #32 and not break any existing sketch.Origin
and User-Agent
headers to requests sent by the library, this seems to be required by some servers. Thank you imesut for pointing out the issue.addHeader
method. Thank you zastrixarundell for the contribution.connectSecure
method to support WSS connection with the classic interface (host, port, path). Thank you!