I was working on a custom firmware for ESP8266 using the famous Arduino library and I wanted to create a websocket server. I also wanted the EPS to serve the web page that acts as a websocket server (having the ESP in AP mode).
The awesome library ArduinoWebSockets is very easy to set up and make the ESP serve websockets connections on port 81. The thing is that when I was opening a browser at http://192.168.4.1:81 I had this message: "This is a Websocket server only!". Wow! This means that ESP is capable of returning a http message to the browser! This also means that the message could be tweaked to include the actual html page with the websocket JS client!
I looked at the library file WebSocketsServer.h and found that the method handleNonWebsocketConnection
was the one sending this message.
Also, this comment retained my atention: /* Note: can be override */
So I started to learn how I could override a C++ class inside the Arduino environment.
There are multiple examples of it on the Internet but none of them were showing how to override the constructor of a class!
Without further discussion, here is the magic.
In your Arduino IDE create a new tab named overrides.h
containing the following code:
#ifndef _OVERRIDES_H
#define _OVERRIDES_H
class MyWebSocketsServer: public WebSocketsServer {
public:
MyWebSocketsServer(uint16_t port); // Declaration of the new constructor of my overriding class
virtual void handleNonWebsocketConnection(WSclient_t * client); // Declaration of the override of the virtual method
};
// This is how you override a virtual method:
void MyWebSocketsServer::handleNonWebsocketConnection(WSclient_t * client) {
client->tcp->write("HTTP/1.1 200 OK\r\n"
"Server: arduino-WebSocket-Server\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 1099\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE html><html><head><script>function sendRGB(){var n=parseInt(document.getElementById('r').value).toString(16),e=parseInt(document.getElementById('g').value).toString(16),o=parseInt(document.getElementById('b').value).toString(16);n.length<2&&(n='0'+n),e.length<2&&(e='0'+e),o.length<2&&(o='0'+o);var t='#'+n+e+o;console.log('RGB: '+t),connection.send(t)}var connection=new WebSocket('ws://192.168.4.1:81/',['arduino']);connection.onopen=function(){connection.send('Message from Browser to ESP8266 yay its Working!! '+new Date),connection.send('ping'),connection.send('Time: '+new Date)},connection.onerror=function(n){console.log('WebSocket Error ',n)},connection.onmessage=function(n){console.log('Server: ',n.data),connection.send('Time: '+new Date)};</script></head><body>LED Control:<br><br>R: <input id=\"r\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\"><br>G: <input id=\"g\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\"><br>B: <input id=\"b\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" oninput=\"sendRGB();\"><br></body></html>");
}
// This is how you override a constructor, making a call to it's super class' constructor:
MyWebSocketsServer::MyWebSocketsServer(uint16_t port) : WebSocketsServer(port) {}
#endif //_OVERRIDES_H
Easy hu!?
Now in you main sketch, you have to include the ArduinoWebSockets library but also the override.h
you just created. Next you will need to change the way you instaciate the WebSocketsServer
class.
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WebSocketsServer.h>
#include <Hash.h>
#include "overrides.h"
// Instead of instanciating original class:
// WebSocketsServer webSocket = WebSocketsServer(81);
// Instanciate your override:
MyWebSocketsServer _webSocket = MyWebSocketsServer(81);
void setup(void) {
initAP(); // AP initialization
initWebSocket(); // See ArduinoWebSockets' examples on how to initialize the server
}
void loop(void) {
_webSocket.loop();
}
Et voilà!
Thanks for reading.