Button vs Websocket: Round 1
Posted: Sat Nov 11, 2017 4:20 am
Bashing my head against another wall here. The below code is my current relayswitch implementation by using the websockets example from this thread. It works rather well, except that the handlePhysicalButton() in the main loop is causing problems by continuously firing at the websocket server no matter if it's running or not. Or, just to make it complicated for giggles, sometimes it refuses to fire at all until i reload the page. That's what i want eventually, but i don't know why and when it happens.
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) .
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) .
Code: Select all
#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();
}