I'm looking for
a) an quick assessment if the concept of how i coded this makes sense
b) a way to have the physical button routine only send a message when pressed and checking if the websocket connection is up. I was able to do within the javascript with if (websock.readyState === WebSocket.OPEN) .
#include <Arduino.h>
#include <Hash.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsServer.h>
#include <ESP8266mDNS.h>
const char *website =
R"0(
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width = device-width, initial-scale = 1.0, maximum-scale = 1.0, user-scalable=0">
<title>Switcheroo</title>
<body>
<script>
var websock;
function start() {
websock = new WebSocket('ws://' + window.location.hostname + ':81/');
websock.onopen = function(evt) {
console.log('websock open');
};
websock.onclose = function(evt) {
console.log('websock close');
};
websock.onerror = function(evt) {
console.log(evt);
};
websock.onmessage = function(evt) {
console.log(evt);
var a = document.getElementById('cbStyle');
var e = document.getElementById('ledstatus');
if (evt.data === 'ledon') {
e.style.color = 'red';
a.checked = true;
} else if (evt.data === 'ledoff') {
e.style.color = 'black';
a.checked = false;
} else {
console.log('unknown event');
}
};
}
function checkboxClick(e) {
if (e.checked) {
if (websock.readyState === WebSocket.OPEN) {
websock.send('ledon');
}
} else {
if (websock.readyState === WebSocket.OPEN) {
websock.send('ledoff');
}
}
e.checked = !e.checked;
}
function buttonClick(e) {
if (websock.readyState === WebSocket.OPEN) {
websock.send(e.id);
}
}
window.addEventListener("load", start, false);
</script>
</head>
<body>
<h1>Switcheroo111</h1>
<div id="ledstatus"><b>LED</b></div>
<button id="ledon" type="button" onclick="buttonClick(this);">On</button>
<button id="ledoff" type="button" onclick="buttonClick(this);">Off</button>
<div id="switchCB" class="switch">
<input id="cbStyle" class="cbStyle cbStyle-round" type="checkbox" onclick="checkboxClick(this)">
<label for="cbStyle"></label>
</div>
</body>
</html>
)0";
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, unsigned int length), handleRoot(), handleNotFound(), handlePhysicalButton();
static void writeLED(bool LEDon);
#define RELAY 5 //D1
#define BUTTON 4 //D2
MDNSResponder mdns;
ESP8266WiFiMulti WiFiMulti;
ESP8266WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);
const char* ssid = "xxxxxxxxxxx";
const char* password = "xxxxxxxxxxx";
// Commands sent through Web Socket
const char LEDON[] = "ledon";
const char LEDOFF[] = "ledoff";
bool LEDStatus = false;
bool currentState = false;
bool lastButtonState = false;
bool pressedState = false;
//----------------------------------------------------------------------
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, unsigned int length)
{
Serial.printf("webSocketEvent(%d, %d, ...)\r\n", num, type);
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\r\n", num);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\r\n", num, ip[0], ip[1], ip[2], ip[3], payload);
// Send the current LED status
if (LEDStatus) { webSocket.sendTXT(num, LEDON, strlen(LEDON)); }
else { webSocket.sendTXT(num, LEDOFF, strlen(LEDOFF)); }
}
break;
case WStype_TEXT:
Serial.printf("[%u] get Text: %s\r\n", num, payload);
if (strcmp(LEDON, (const char *)payload) == 0) {
writeLED(true);
} else if (strcmp(LEDOFF, (const char *)payload) == 0) {
writeLED(false);
}
else { Serial.println("Unknown command"); }
// send data to all connected clients
webSocket.broadcastTXT(payload, length);
break;
case WStype_BIN:
Serial.printf("[%u] get binary length: %u\r\n", num, length);
hexdump(payload, length);
// echo data back to browser
webSocket.sendBIN(num, payload, length);
break;
default:
Serial.printf("Invalid WStype [%d]\r\n", type);
break;
}
}
void handleRoot() {
server.send ( 200, "text/html", website );
}
void handleNotFound()
{
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i=0; i<server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
server.send(404, "text/plain", message);
}
void handlePhysicalButton() {
delay(100); //just slow down a bit
currentState = digitalRead(BUTTON);
if (currentState != lastButtonState) {
lastButtonState = currentState;
if (currentState == pressedState) {
LEDStatus = !LEDStatus;
}
digitalWrite(RELAY, LEDStatus);
}
delay(50); //poor mans debounce
if (LEDStatus) { webSocket.sendTXT(0, LEDON, strlen(LEDON)); }
else { webSocket.sendTXT(0, LEDOFF, strlen(LEDOFF)); }
}
static void writeLED(bool LEDon)
{
LEDStatus = LEDon;
if (LEDon) { digitalWrite(RELAY, 1); }
else { digitalWrite(RELAY, 0); }
}
//----------------------------------------------------------------------
void setup() {
pinMode(BUTTON, INPUT_PULLUP);
pinMode(RELAY, OUTPUT);
writeLED(false);
char HostName[32];
sprintf(HostName, "Narfel-%06X", ESP.getChipId()); //create hostname name+chip-id
WiFi.mode(WIFI_STA);
WiFi.hostname(HostName);
Serial.begin(115200);
//Serial.setDebugOutput(true);
Serial.println();
for(uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] BOOT WAIT %d...\r\n", t);
Serial.flush();
delay(1000);
}
Serial.printf("%s, ChipID: ", HostName);
Serial.println(ESP.getChipId());
WiFiMulti.addAP(ssid, password);
while(WiFiMulti.run() != WL_CONNECTED) {
Serial.print(".");
delay(100);
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print(WiFi.SSID());
Serial.print(" (");
Serial.print(WiFi.RSSI());
Serial.println(")");
if (mdns.begin("esprelay", WiFi.localIP())) {
Serial.println("MDNS responder started");
mdns.addService("http", "tcp", 80);
mdns.addService("ws", "tcp", 81);
} else { Serial.println("MDNS.begin failed"); }
Serial.print("Connect to http://esprelay.local or http://");
Serial.println(WiFi.localIP());
// webserver
server.on("/", handleRoot);
server.onNotFound(handleNotFound);
server.begin();
webSocket.begin();
webSocket.onEvent(webSocketEvent);
}
void loop() {
handlePhysicalButton();
webSocket.loop();
server.handleClient();
}