Ricordi il progetto creato nella guida “How to create a web server with esp8266 and esp32”? E’ arrivato il momento di porlo nell’era moderna, quindi rimuoveremo il polling e aggiungeremo il push per la modifica dei dati in tempo reale.
Questa modalità è la strada migliore, le normali applicazione recuperano i dati iniziali dalle chiamate REST e poi vengono aggiornati tramite WebSocket.
Per prima cosa aggiungeremo il server WebSocket.
#include <WebSocketsServer.h>
[...]
const uint8_t wsPort = 81;
WebSocketsServer webSocket = WebSocketsServer(wsPort);
[...]
// In the setup
Serial.print("Starting WebSocket..");
webSocket.begin();
webSocket.onEvent(webSocketEvent);
Serial.println("OK");
[...]
// In the loop
webSocket.loop();
Quindi nel ciclo andremo ad aggiungere un messaggio di broadcast (per tutti i client) ogni 2 secondi che aggiorna la temperatura e l’umidità
if (connectionNumber>0 && lastUpdate+messageInterval<millis()){
Serial.println("[WSc] SENT: Broadcast message!!");
const size_t capacity = 1024;
DynamicJsonDocument doc(capacity);
doc["humidity"] = dht12.readHumidity();
doc["temp"] = dht12.readTemperature();
// If you don't have a DHT12 put only the library
// comment upper line and decomment this line
doc["humidity"] = random(10,80);
doc["temp"] = random(1000,3500)/100.;
String buf;
serializeJson(doc, buf);
webSocket.broadcastTXT(buf);
lastUpdate = millis();
}
Il codice è abbastanza semplice, ma presta attenzione alla condizione connectionNumber>0 la quale impedisce l’invio messaggi di WebSocket se non ci sono client connessi.
È una semplice variabile, che aggiorno ad ogni connessione/disconnessione, con il numero di client connessi.
Quindi tutta la gestione si può dire completata
Qui nel webSocketEvent puoi vedere la gestione del numero di client connessi.
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\n", num);
webSocket.sendTXT(num, "{\"connected\":false}");
connectionNumber = webSocket.connectedClients();
Serial.print("Connected devices ");
Serial.println(connectionNumber);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
// send message to client
webSocket.sendTXT(num, "{\"connected\":true}");
connectionNumber = webSocket.connectedClients();
Serial.print("Connected devices ");
Serial.println(connectionNumber);
}
break;
case WStype_TEXT:
Serial.printf("[%u] RECEIVE TXT: %s\n", num, payload);
// send message to client
webSocket.sendTXT(num, "(ECHO MESSAGE) "+String((char *)payload));
// send data to all connected clients
// webSocket.broadcastTXT("message here");
break;
case WStype_BIN:
Serial.printf("[%u] get binary length: %u\n", num, length);
hexdump(payload, length);
// send message to client
// webSocket.sendBIN(num, payload, length);
break;
}
}
Quindi dobbiamo aggiungere il listener degli eventi al front-end per gestire il messaggio
function onOpen(evt) {
console.log("CONNECTED");
}
function onClose(evt) {
console.log("DISCONNECTED");
}
function onMessage(evt) {
var res = JSON.parse(evt.data);
hw.setHumidity(res.humidity);
tw.setTemperature(res.temp);
}
function onError(evt) {
alert(evt.data);
}
function initWebSocket() {
var uri = 'ws://'+location.hostname+':81/';
websocket = new WebSocket(uri);
websocket.onopen = function (evt) {
onOpen(evt)
};
websocket.onclose = function (evt) {
onClose(evt)
};
websocket.onmessage = function (evt) {
onMessage(evt)
};
websocket.onerror = function (evt) {
onError(evt)
};
}
initWebSocket();
Il codice è molto semplice e funziona correttamente.
Autenticazione
Semplice work workaround per l’autenticazione
Questa non è una soluzione così bella, ma è abbastanza semplice da implementare senza l’uso di conoscenze extra (come header, cookie ecc.), Ed è abbastanza potente.
Puoi aggiungere un token come authorization, in questo modo il token viene passato come per il login.
// Simple way to invalidate session every restart
// ws_auth_code = sha1(String(www_username) + ":" + String(www_password) + ":" + String(random(1000)))+":";
ws_auth_code = sha1(String(www_username) + ":" + String(www_password))+":";
Serial.println(base64::encode(ws_auth_code).c_str());
webSocket.setAuthorization(base64::encode(ws_auth_code).c_str());
Poi aggiungo un nuovo token in fase di autenticazione (senza clientIP)
httpServer.sendHeader("Set-Cookie", "ESPWSSESSIONID=" + String(ws_auth_code));
ed inserisco il token nell’URI di ws, come descritto nel precedente articolo.
Qui recupero il cookie
var getCookie = function (name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
};
if (ENABLE_WS_AUTHORIZATION) {
// Example
var cookieVal = getCookie('ESPWSSESSIONID');
initWebSocket(cookieVal);
}else{
initWebSocket();
}
e verrà passato nell’uri in questa maniera
ws://937c7478aaa380b87242dd7aba8ff9304e5cf089@192.168.1.136:81/
if (authToken){
var newUri = uri.substring(0,uri.indexOf("//")+2)+authToken+'@'+uri.substring(uri.indexOf("//")+2);
websocket = new WebSocket(newUri,'arduino');
}else {
websocket = new WebSocket(uri);
}
Controlla il codice completo su GitHub
Autenticazione basata su token
L’ultima volta abbiamo eseguito un’autenticazione basata su token, ora possiamo recuperare quell’implementazione e integrare il WebSoket.
Come vedi nell’articolo “Web Server con esp8266 e esp32: gestione sicurezza ed autenticazione” aggiungo il token nel cookie ESPSESSIONID,
void handleLogin() {
Serial.println("Handle login");
String msg;
if (httpServer.hasHeader("Cookie")) {
// Print cookies
Serial.print("Found cookie: ");
String cookie = httpServer.header("Cookie");
Serial.println(cookie);
}
if (httpServer.hasArg("username") && httpServer.hasArg("password")) {
Serial.print("Found parameter: ");
if (httpServer.arg("username") == String(www_username) && httpServer.arg("password") == String(www_password)) {
httpServer.sendHeader("Location", "/");
httpServer.sendHeader("Cache-Control", "no-cache");
String token = sha1(String(www_username) + ":" + String(www_password) + ":" + httpServer.client().remoteIP().toString());
httpServer.sendHeader("Set-Cookie", "ESPSESSIONID=" + token);
httpServer.sendHeader("Set-Cookie", "CLIENTIP=" + httpServer.client().remoteIP().toString());
httpServer.send(301);
Serial.println("Log in Successful");
return;
}
msg = "Wrong username/password! try again.";
Serial.println("Log in Failed");
httpServer.sendHeader("Location", "/login.html?msg=" + msg);
httpServer.sendHeader("Cache-Control", "no-cache");
httpServer.send(301);
return;
}
}
di ogni chiamata REST controllo se è presente.
//Check if header is present and correct
bool is_authenticated() {
Serial.println("Enter is_authenticated");
if (httpServer.hasHeader("Cookie")) {
Serial.print("Found cookie: ");
String cookie = httpServer.header("Cookie");
Serial.println(cookie);
String token = sha1(String(www_username) + ":" +
String(www_password) + ":" +
httpServer.client().remoteIP().toString());
// token = sha1(token);
if (cookie.indexOf("ESPSESSIONID=" + token) != -1) {
Serial.println("Authentication Successful");
return true;
}
}
Serial.println("Authentication Failed");
return false;
}
Come puoi vedere utilizzo il client IP anche per generare un token specifico per il dispositivo, quindi per risolvere questo problema aggiungo l’IP del client al cookie.
String token = sha1(String(www_username) + ":" + String(www_password) + ":" + httpServer.client().remoteIP().toString());
httpServer.sendHeader("Set-Cookie", "ESPSESSIONID=" + token);
httpServer.sendHeader("Set-Cookie", "CLIENTIP=" + httpServer.client().remoteIP().toString());
Quindi dobbiamo aggiungere il validatore personalizzato al WebSoket
const char * headerkeys[] = { "Cookie" };
size_t headerKeyCount = sizeof(headerkeys) / sizeof(char*);
webSocket.onValidateHttpHeader(validateHttpHeader, headerkeys, headerKeyCount);
L’onValidateHttpHeader
richiede 3 parametri:
- validateHttpHeader : è la funzione che fa la validazione;
- headerkeys : è l’elenco degli headers obbligatori;
- headerKeyCount : è la dimensione degli headers.
La funzione bool validateHttpHeader(String headerName, String headerValue)
prevede 2 parametri
- headerName : il nome del cookie;
- headerValue : il valore del cookie.
Ora abbiamo un’header specifico per convalidare il cookie , perciò anche l’header obbligatorio è il cookie,
/*
* The WebSocketServerHttpHeaderValFunc delegate passed to webSocket.onValidateHttpHeader
*/
bool validateHttpHeader(String headerName, String headerValue) {
//assume a true response for any headers not handled by this validator
bool valid = true;
if(headerName.equalsIgnoreCase("Cookie")) {
//if the header passed is the Cookie header, validate it according to the rules in 'isCookieValid' function
valid = isCookieValid(headerValue);
}
return valid;
}
e quando troviamo questa intestazione dobbiamo controllarne il valore
bool isCookieValid(String rawCookieHeaderValue) {
Serial.print("Cookie validation ");
Serial.println(rawCookieHeaderValue);
String clientIP = "";
if (rawCookieHeaderValue.indexOf("CLIENTIP") != -1) {
clientIP = rawCookieHeaderValue.substring(rawCookieHeaderValue.indexOf("CLIENTIP=") + 9, rawCookieHeaderValue.indexOf("|"));
Serial.print("clientIP ");
Serial.println(clientIP);
}
if (rawCookieHeaderValue.indexOf("ESPSESSIONID") != -1) {
String tokenStr = rawCookieHeaderValue.substring(rawCookieHeaderValue.indexOf("ESPSESSIONID=") + 13, rawCookieHeaderValue.indexOf(";"));
Serial.print("ESPSESSIONID ");
Serial.println(tokenStr);
String token = sha1(String(www_username) + ":" + String(www_password) + ":" + clientIP);
Serial.print("token ");
Serial.println(token);
return tokenStr == token;
}
return false;
}
Al front-end non servono altre modifiche, per sfruttare il cookie esistente.
Ed ecco il codice del server completo
/*
* WeMos D1 mini (esp8266)
* Simple web server that read from SPIFFS and
* stream on browser various type of file
* and manage gzip format also.
* Here I add a management of a token authentication
* with a custom login form, and relative logout.
* Add WebSocket data update with the
* integration with token authentication handshake
*
* DHT12 library https://mischianti.org/dht12-library-en/
*
* DHT12 ----- Esp8266
* SDL ----- D1
* SDA ----- D2
*
* by Mischianti Renzo <https://mischianti.org>
*
* https://mischianti.org/it/websocket-su-arduino-esp8266-e-esp32-aggiornamento-temperatura-e-umidita-realtime-3/
*
*/
#define ENABLE_WS_AUTHORIZATION
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WebSocketsServer.h>
#include <base64.h>
#include <FS.h>
#include "Hash.h"
#include <DHT12.h>
#include <ArduinoJson.h>
const char* ssid = "<YOUR-SSID>";
const char* password = "<YOUR-PASSWD>";
const char* www_username = "admin";
const char* www_password = "esp8266";
String ws_auth_code;
const uint8_t wsPort = 81;
int8_t connectionNumber = 0;
unsigned long messageInterval = 2000;
// Set dht12 i2c comunication on default Wire pin
DHT12 dht12;
ESP8266WebServer httpServer(80);
WebSocketsServer webSocket = WebSocketsServer(wsPort);
void serverRouting();
void manageSecurity();
#ifdef ENABLE_WS_AUTHORIZATION
bool validateHttpHeader(String headerName, String headerValue);
#endif
void setup(void) {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Start sensor
dht12.begin();
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print(F("Inizializing FS..."));
if (SPIFFS.begin()) {
Serial.println(F("done."));
} else {
Serial.println(F("fail."));
}
Serial.println("Set routing for http server!");
serverRouting();
httpServer.begin();
Serial.println("HTTP server started");
Serial.print("Starting WebSocket..");
#ifdef ENABLE_WS_AUTHORIZATION
// Simple way to invalidate session every restart
// ws_auth_code = sha1(String(www_username) + ":" + String(www_password) + ":" + String(random(1000)))+":";
// ws_auth_code = sha1(String(www_username) + ":" + String(www_password))+":";
//
// Serial.println(base64::encode(ws_auth_code).c_str());
//
// webSocket.setAuthorization(base64::encode(ws_auth_code).c_str());
const char * headerkeys[] = { "Cookie" };
size_t headerKeyCount = sizeof(headerkeys) / sizeof(char*);
webSocket.onValidateHttpHeader(validateHttpHeader, headerkeys, headerKeyCount);
#endif
webSocket.begin();
webSocket.onEvent(webSocketEvent);
Serial.println("OK");
}
unsigned long lastUpdate = millis()+messageInterval;
void loop(void) {
httpServer.handleClient();
webSocket.loop();
if (connectionNumber>0 && lastUpdate+messageInterval<millis()){
Serial.println("[WSc] SENT: Broadcast message!!");
const size_t capacity = 1024;
DynamicJsonDocument doc(capacity);
doc["humidity"] = dht12.readHumidity();
doc["temp"] = dht12.readTemperature();
// If you don't have a DHT12 put only the library
// comment upper line and decomment this line
doc["humidity"] = random(10,80);
doc["temp"] = random(1000,3500)/100.;
String buf;
serializeJson(doc, buf);
webSocket.broadcastTXT(buf);
lastUpdate = millis();
}
}
String getContentType(String filename) {
if (filename.endsWith(F(".htm"))) return F("text/html");
else if (filename.endsWith(F(".html"))) return F("text/html");
else if (filename.endsWith(F(".css"))) return F("text/css");
else if (filename.endsWith(F(".js"))) return F("application/javascript");
else if (filename.endsWith(F(".json"))) return F("application/json");
else if (filename.endsWith(F(".png"))) return F("image/png");
else if (filename.endsWith(F(".gif"))) return F("image/gif");
else if (filename.endsWith(F(".jpg"))) return F("image/jpeg");
else if (filename.endsWith(F(".jpeg"))) return F("image/jpeg");
else if (filename.endsWith(F(".ico"))) return F("image/x-icon");
else if (filename.endsWith(F(".xml"))) return F("text/xml");
else if (filename.endsWith(F(".pdf"))) return F("application/x-pdf");
else if (filename.endsWith(F(".zip"))) return F("application/x-zip");
else if (filename.endsWith(F(".gz"))) return F("application/x-gzip");
return F("text/plain");
}
bool handleFileRead(String path) {
Serial.print(F("handleFileRead: "));
Serial.println(path);
if (!is_authenticated()) {
Serial.println(F("Go on not login!"));
path = F("/login.html");
handleLogout();
return true;
} else {
if (path.endsWith("/")) path += F("index.html"); // If a folder is requested, send the index file
}
String contentType = getContentType(path); // Get the MIME type
String pathWithGz = path + F(".gz");
if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { // If the file exists, either as a compressed archive, or normal
if (SPIFFS.exists(pathWithGz)) { // If there's a compressed version available
path += F(".gz"); // Use the compressed version
}
fs::File file = SPIFFS.open(path, "r"); // Open the file
size_t sent = httpServer.streamFile(file, contentType); // Send it to the client
file.close(); // Close the file again
Serial.println(
String(F("\tSent file: ")) + path + String(F(" of size "))
+ sent);
return true;
}
Serial.println(String(F("\tFile Not Found: ")) + path);
return false; // If the file doesn't exist, return false
}
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += httpServer.uri();
message += "\nMethod: ";
message += (httpServer.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += httpServer.args();
message += "\n";
for (uint8_t i = 0; i < httpServer.args(); i++) {
message += " " + httpServer.argName(i) + ": " + httpServer.arg(i)
+ "\n";
}
httpServer.send(404, "text/plain", message);
}
void handleLogin() {
Serial.println("Handle login");
String msg;
if (httpServer.hasHeader("Cookie")) {
// Print cookies
Serial.print("Found cookie: ");
String cookie = httpServer.header("Cookie");
Serial.println(cookie);
}
if (httpServer.hasArg("username") && httpServer.hasArg("password")) {
Serial.print("Found parameter: ");
if (httpServer.arg("username") == String(www_username) && httpServer.arg("password") == String(www_password)) {
httpServer.sendHeader("Location", "/");
httpServer.sendHeader("Cache-Control", "no-cache");
String token = sha1(String(www_username) + ":" + String(www_password) + ":" + httpServer.client().remoteIP().toString());
httpServer.sendHeader("Set-Cookie", "ESPSESSIONID=" + token);
httpServer.sendHeader("Set-Cookie", "CLIENTIP=" + httpServer.client().remoteIP().toString());
httpServer.send(301);
Serial.println("Log in Successful");
return;
}
msg = "Wrong username/password! try again.";
Serial.println("Log in Failed");
httpServer.sendHeader("Location", "/login.html?msg=" + msg);
httpServer.sendHeader("Cache-Control", "no-cache");
httpServer.send(301);
return;
}
}
/**
* Manage logout (simply remove correct token and redirect to login form)
*/
void handleLogout() {
Serial.println("Disconnection");
httpServer.sendHeader("Location", "/login.html?msg=User disconnected");
httpServer.sendHeader("Cache-Control", "no-cache");
httpServer.sendHeader("Set-Cookie", "ESPSESSIONID=0");
// httpServer.sendHeader("Set-Cookie", "ESPWSSESSIONID=0");
httpServer.send(301);
return;
}
/**
* Retrieve temperature humidity realtime data
*/
void handleTemperatureHumidity(){
Serial.println("handleTemperatureHumidity");
manageSecurity();
Serial.println("handleTemperatureHumidity security pass!");
const size_t capacity = 1024;
DynamicJsonDocument doc(capacity);
doc["humidity"] = dht12.readHumidity();
doc["temp"] = dht12.readTemperature();
// If you don't have a DHT12 put only the library
// comment upper line and decomment this line
doc["humidity"] = random(10,80);
doc["temp"] = random(1000,3500)/100.;
String buf;
serializeJson(doc, buf);
httpServer.send(200, F("application/json"), buf);
}
//Check if header is present and correct
bool is_authenticated() {
Serial.println("Enter is_authenticated");
if (httpServer.hasHeader("Cookie")) {
Serial.print("Found cookie: ");
String cookie = httpServer.header("Cookie");
Serial.println(cookie);
String token = sha1(String(www_username) + ":" +
String(www_password) + ":" +
httpServer.client().remoteIP().toString());
if (cookie.indexOf("ESPSESSIONID=" + token) != -1) {
Serial.println("Authentication Successful");
return true;
}
}
Serial.println("Authentication Failed");
return false;
}
void manageSecurity(){
if (!is_authenticated()) {
httpServer.send(401, F("application/json"), "{\"msg\": \"You must authenticate!\"}");
return;
}
}
void restEndPoint(){
// External rest end point (out of authentication)
httpServer.on("/login", HTTP_POST, handleLogin);
httpServer.on("/logout", HTTP_GET, handleLogout);
httpServer.on("/temperatureHumidity", HTTP_GET, handleTemperatureHumidity);
}
void serverRouting() {
restEndPoint();
// Manage Web Server
Serial.println(F("Go on not found!"));
httpServer.onNotFound([]() { // If the client requests any URI
Serial.println(F("On not found"));
if (!handleFileRead(httpServer.uri())) { // send it if it exists
handleNotFound();// otherwise, respond with a 404 (Not Found) error
}
});
Serial.println(F("Set cache!"));
// Serve a file with no cache so every tile It's downloaded
httpServer.serveStatic("/configuration.json", SPIFFS, "/configuration.json", "no-cache, no-store, must-revalidate");
// Server all other page with long cache so browser chaching they
httpServer.serveStatic("/", SPIFFS, "/", "max-age=31536000");
//here the list of headers to be recorded
const char * headerkeys[] = { "User-Agent", "Cookie" };
size_t headerkeyssize = sizeof(headerkeys) / sizeof(char*);
//ask server to track these headers
httpServer.collectHeaders(headerkeys, headerkeyssize);
}
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\n", num);
webSocket.sendTXT(num, "{\"connected\":false}");
connectionNumber = webSocket.connectedClients();
Serial.print("Connected devices ");
Serial.println(connectionNumber);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
// send message to client
webSocket.sendTXT(num, "{\"connected\":true}");
connectionNumber = webSocket.connectedClients();
Serial.print("Connected devices ");
Serial.println(connectionNumber);
}
break;
case WStype_TEXT:
Serial.printf("[%u] RECEIVE TXT: %s\n", num, payload);
// send message to client
webSocket.sendTXT(num, "(ECHO MESSAGE) "+String((char *)payload));
// send data to all connected clients
// webSocket.broadcastTXT("message here");
break;
case WStype_BIN:
Serial.printf("[%u] get binary length: %u\n", num, length);
hexdump(payload, length);
// send message to client
// webSocket.sendBIN(num, payload, length);
break;
}
}
#ifdef ENABLE_WS_AUTHORIZATION
bool isCookieValid(String rawCookieHeaderValue) {
Serial.print("Cookie validation ");
Serial.println(rawCookieHeaderValue);
String clientIP = "";
if (rawCookieHeaderValue.indexOf("CLIENTIP") != -1) {
clientIP = rawCookieHeaderValue.substring(rawCookieHeaderValue.indexOf("CLIENTIP=") + 9, rawCookieHeaderValue.indexOf("|"));
Serial.print("clientIP ");
Serial.println(clientIP);
}
if (rawCookieHeaderValue.indexOf("ESPSESSIONID") != -1) {
String tokenStr = rawCookieHeaderValue.substring(rawCookieHeaderValue.indexOf("ESPSESSIONID=") + 13, rawCookieHeaderValue.indexOf("ESPSESSIONID=") + 13+40);
Serial.print("ESPSESSIONID ");
Serial.println(tokenStr);
String token = sha1(String(www_username) + ":" + String(www_password) + ":" + clientIP);
Serial.print("token ");
Serial.println(token);
return tokenStr == token;
}
return false;
}
/*
* The WebSocketServerHttpHeaderValFunc delegate passed to webSocket.onValidateHttpHeader
*/
bool validateHttpHeader(String headerName, String headerValue) {
//assume a true response for any headers not handled by this validator
bool valid = true;
if(headerName.equalsIgnoreCase("Cookie")) {
//if the header passed is the Cookie header, validate it according to the rules in 'isCookieValid' function
valid = isCookieValid(headerValue);
}
return valid;
}
#endif
Anche la gestione della pagina html varia di un poco.
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" type="text/css" href="./sldierElement.css">
<link rel="stylesheet" type="text/css" href="./floatButton.css">
<script src="iot-widget.min.js"></script>
<script src="sliderManager.js"></script>
<meta charset="UTF-8">
<title>Temperature humidity www.mischianti.org</title>
<style>
html {
height: 100%;
}
body {
height: 100%;
background: #76b852; /* fallback for old browsers */
background: -webkit-linear-gradient(right, #76b852, #8DC26F);
background: -moz-linear-gradient(right, #76b852, #8DC26F);
background: -o-linear-gradient(right, #76b852, #8DC26F);
background: linear-gradient(to left, #76b852, #8DC26F);
}
.titleContainer {
font-size: 6vw;;
text-align: center;
width: 100%;
height: 16%;
/*padding: 10px;*/
}
.sliderContainer {
height: 84%;
position: relative;
}
.humidity-container,
.termometer-container{
width: 768px;
height: 100%;
}
.humidity-container{
height: 70%;
}
</style>
</head>
<body>
<div class="titleContainer">Temperature humidity</div>
<div class="sliderContainer">
<div class="slider-wrap">
<div class="slider" id="slider">
<div class="holder">
<div class="slide-wrapper">
<div class="humidity-container" id="humidity-container"></div>
</div>
<div class="slide-wrapper">
<div class="termometer-container" id="termomter-container" ></div>
</div>
</div>
</div>
</div>
</div>
<script>
var ENABLE_WS_AUTHORIZATION = true;
var sliderElement = document.getElementById('slider');
var sliderImageElements = document.querySelectorAll(".slide-wrapper");
var holderElement = document.querySelector(".holder");
var animateElements = document.querySelectorAll('.animate');
sliderInitialization( sliderElement,
sliderImageElements,
holderElement,
animateElements,
2);
var container = document.getElementById('humidity-container');
var hw = new Widget.Humidity(container, 50, 'auto', 80);
hw.draw();
var container2 = document.getElementById('termomter-container');
var tw = new Widget.Termometer(container2, 0);
tw.draw();
</script>
<script>
// debugger
function debounce(fn, threshold) {
threshold = threshold || 300;
var timer;
return function() {
if (!timer) {
fn.apply(this, arguments);
}
clearTimeout(timer);
timer = setTimeout(function() {
timer = null;
}, threshold);
};
};
var requestTempHum = function(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
var res = JSON.parse(xhttp.responseText);
hw.setHumidity(res.humidity);
tw.setTemperature(res.temp);
}
};
xhttp.onerror = function () {
alert("Status code is " + this.status + " click F12 and check what is the problem on console");
};
xhttp.open("GET", "/temperatureHumidity", true);
xhttp.send();
}
var debouncedRequestTempHum = debounce(requestTempHum, 400);
var refresh = function(){
debouncedRequestTempHum();
}
debouncedRequestTempHum();
function onOpen(evt) {
console.log("CONNECTED");
// doSend("Hi, I'm simple JS client!!");
}
function onClose(evt) {
console.log("DISCONNECTED");
}
function onMessage(evt) {
var res = JSON.parse(evt.data);
hw.setHumidity(res.humidity);
tw.setTemperature(res.temp);
}
function onError(evt) {
// alert(evt.data);
console.error(evt);
}
// function doSend(message) {
// writeToScreen("SENT: " + message);
// websocket.send(message);
// }
function initWebSocket(authToken) {
var uri = 'ws://'+location.hostname+':81/';
if (authToken){
var newUri = uri.substring(0,uri.indexOf("//")+2)+authToken+'@'+uri.substring(uri.indexOf("//")+2);
console.log(newUri);
try {
websocket = new WebSocket(newUri, 'arduino');
}catch (e) {
console.error(e);
alert(e);
}
}else {
websocket = new WebSocket(uri);
}
websocket.onopen = function (evt) {
onOpen(evt)
};
websocket.onclose = function (evt) {
onClose(evt)
};
websocket.onmessage = function (evt) {
onMessage(evt)
};
websocket.onerror = function (evt) {
onError(evt)
};
}
var getCookie = function (name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
};
if (ENABLE_WS_AUTHORIZATION) {
// Example
var cookieVal = getCookie('ESPSESSIONID'); // returns "turkey"
if (cookieVal && cookieVal!=="0") {
initWebSocket(cookieVal);
}else{
// alert("No cookie found!");
window.location.href = '/login.html?msg=User not logged in!';
}
}else{
initWebSocket();
}
// function polling() {
// setTimeout(function () {
// debouncedRequestTempHum();
// polling();
// }, 2500);
// }
// polling();
</script>
<div style="position: absolute">
<a href="#" onclick="refresh();" class="floatRefresh">
<div style="font-size: xx-large">R</div>
</a>
</div>
<div style="position: absolute">
<a href="/logout" class="floatLogout">
<div style="font-size: xx-large">L</div>
</a>
</div>
</body>
</html>
Grazie
- WebSocket su Arduino, esp8266 ed esp32: client
- WebSocket su Arduino, esp8266 ed esp32: server e autenticazione
- WebSocket su Arduino, esp8266 ed esp32: aggiornamento temperatura e umidità realtime
Codice completo su GitHub