Skip to content

Commit 223096e

Browse files
committed
Updated the Readme.md files in this fork (used Mark Text editor)
Cookie auth with Xtea encrypting, see SmartSwitch.ino example Tested on ESP8266 and ESP32 with better built-in LED handling Minor updates and improvements of js / html packed files.
1 parent 9dfa595 commit 223096e

16 files changed

+378
-109
lines changed

README.md

+105-11
Large diffs are not rendered by default.

examples/SmartSwitch/PinOut_Notes.txt

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
This application:
22
D2 = 4; // DHT DATA I/O
3-
D3 = 0; // BUTTON - most modules have it populated on PCB
4-
D4 = 2; // LED (RELAY) - most modules have it populated on PCB
3+
D3 = 0; // BUTTON - most modules have it populated on PCB
4+
D4 = 2; // LED (RELAY) - most modules have it populated, on ESP32 is with reversed logic levels
55

66

77

88
Pinout ESP12 (8266)
9-
D GPIO In Out Notes
9+
D GPIO In Out Notes
1010

1111
D0 16 no interrupt no PWM or I2C support HIGH at boot used to wake up from deep sleep
1212
D1 5 OK OK often used as SCL (I2C)
@@ -23,16 +23,16 @@ A0 ADC0 Analog Input
2323

2424

2525
Pinout ESP32
26-
IO In Out Notes
26+
IO In Out Notes
2727

2828
0 PU OK pulled-up input, outputs PWM signal at boot
29-
1 TX OK debug output at boot
29+
1 TX OK debug output at boot
3030
2 OK OK connected to on-board LED
31-
3 OK RX pin HIGH at boot
31+
3 OK RX HIGH at boot
3232
4 OK OK
3333
5 OK OK outputs PWM signal at boot
3434

35-
6-11 x x connected to the integrated SPI flash
35+
6-11 x x connected to the integrated SPI flash
3636

3737
12 OK OK boot fail if pulled high
3838
13 OK OK

examples/SmartSwitch/README.md

+29-13
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
1-
![](1.PNG) ![](2.PNG)
2-
##
3-
![](3.PNG) ![](4.PNG)
1+
<img title="" src="1.PNG" alt="" width="137"> <img title="" src="2.PNG" alt="" width="138"> <img title="" src="3.PNG" alt="" width="150"> <img title="" src="4.PNG" alt="" width="150">
42

53
## SmartSwitch
6-
* Remote Temperature Control application with schedule (example car block heater or battery charger)
7-
* Based on ESP_AsyncFSBrowser example with ACE editor
4+
5+
* Remote Temperature Control application with schedule
6+
7+
(example: car block heater or car battery charger for winter)
8+
9+
* Based on [ESP_AsyncFSBrowser](https://github.com/lorol/ESPAsyncWebServer/tree/master/examples/ESP_AsyncFSBrowser) example that uses embedded ACE editor
10+
811
* Wide browser compatibility, no extra server-side needed
9-
* HTTP server and WebSocket, single port
10-
* Standalone, no JS dependencies for the browser from Internet (I hope), ace editor included
11-
* Added ESPAsyncWiFiManager
12-
* Real Time (NTP) w/ Time Zones
12+
13+
* HTTP server and WebSocket on same port
14+
15+
* Standalone, no JS dependencies for the browser from Internet
16+
17+
* [Ace Editor](https://github.com/ajaxorg/ace) embedded to source but also - editable, upgradeable see [extras folder](https://github.com/lorol/ESPAsyncWebServer/tree/master/extras)
18+
19+
* Added [ESPAsyncWiFiManager](https://github.com/alanswx/ESPAsyncWiFiManager) and fallback AP mode after timeout
20+
21+
* Real Time (NTP) w/ Time Zones. Sync from browser time if in AP mode
22+
1323
* Memorized settings to EEPROM
24+
1425
* Multiple clients can be connected at same time, they see each other' requests
15-
* Base Authentication of the editor, static content, WS
16-
* Or Cookie Authentication including WS part, need lib src changes taken from https://github.com/me-no-dev/ESPAsyncWebServer/pull/684
17-
* Default credentials <b>smart:switch</b>
18-
* Use latest ESP8266 ESP32 cores from GitHub
1926

27+
* Authentication variants including [Cookie-based](https://github.com/me-no-dev/ESPAsyncWebServer/pull/684) idea
28+
29+
* Used [this Xtea implementation](https://github.com/franksmicro/Arduino/tree/master/libraries/Xtea) for getting a fancier Cookie token
30+
31+
* Default credentials **smart : switch** or only **switch** as password
32+
33+
* OTA included
34+
35+
* Use the latest ESP8266 ESP32 cores from GitHub

examples/SmartSwitch/SmartSwitch.ino

+96-29
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@ Use latest ESP core lib (from Github)
1717
//#define DEL_WFM // delete Wifi credentials stored
1818
//(use once then comment and flash again), also HTTP /erase-wifi can do the same live
1919

20-
// AUTH COOKIE uses only the password, Base uses both
20+
// AUTH COOKIE uses only the password and unsigned long MY_SECRET_NUMBER
21+
2122
#define http_username "smart"
2223
#define http_password "switch"
2324

25+
#define MY_SECRET_NUMBER 0xA217B02F
26+
2427
//See https://github.com/me-no-dev/ESPAsyncWebServer/pull/684
28+
//SSWI or other 4 chars
2529
#define USE_AUTH_COOKIE
26-
// 1 year age, path helps Safari to unset
27-
#define MY_COOKIE_FULL "LLKQ=3; Max-Age=31536000; Path=/;"
28-
#define MY_COOKIE_DEL "LLKQ=; Max-Age=-1; Path=/;"
29-
#define MY_COOKIE "LLKQ=3"
30+
#define MY_COOKIE_DEL "SSWI=;Max-Age=-1;Path=/;"
31+
#define MY_COOKIE_PREF "SSWI="
32+
#define MY_COOKIE_SUFF ";Max-Age=31536000;Path=/;"
3033

3134
#ifndef USE_AUTH_COOKIE
3235
#define USE_AUTH_STAT //Base Auth for stat, /commands and SPIFFSEditor
33-
//#define USE_AUTH_WS //Base Auth also for WS, not very supported
36+
//#define USE_AUTH_WS //Base Auth also for WS, not very supported
3437
#endif
3538

3639
#include <ArduinoOTA.h>
@@ -54,6 +57,11 @@ Use latest ESP core lib (from Github)
5457
#include <Ticker.h>
5558
#include <DHT.h>
5659

60+
#ifdef USE_AUTH_COOKIE
61+
#include <stdint.h>
62+
#include "Xtea.h"
63+
#endif
64+
5765
#define RTC_UTC_TEST 1577836800 // Some Date
5866
#define MYTZ PSTR("EST5EDT,M3.2.0,M11.1.0")
5967

@@ -70,12 +78,13 @@ Use latest ESP core lib (from Github)
7078
#define DHTTYPE DHT22 // DHT 11 // DHT 22, AM2302, AM2321 // DHT 21, AM2301
7179
#define DHTPIN 4 //D2
7280

73-
#define DHT_T_CORR -0.5 //Temperature offset compensation of the sensor (can be -)
74-
#define DHT_H_CORR 1.5 //Humidity offset compensation of the sensor
81+
#define DHT_T_CORR -0.3 //Temperature offset compensation of the sensor (can be -)
82+
#define DHT_H_CORR -2.2 //Humidity offset compensation of the sensor
83+
84+
// SKETCH BEGIN MAIN DECLARATIONS
7585

7686
DHT dht(DHTPIN, DHTTYPE);
7787

78-
// SKETCH BEGIN MAIN DECLARATIONS
7988
Ticker tim;
8089
AsyncWebServer server(80); //single port - easy for forwarding
8190
AsyncWebSocket ws("/ws");
@@ -86,7 +95,7 @@ AsyncWebSocket ws("/ws");
8695
#else
8796
DNSServer dns;
8897
#endif
89-
98+
9099
//Fallback timeout in seconds allowed to config or it creates an own AP, then serves 192.168.4.1
91100
#define FBTO 120
92101
const char* fbssid = "FBSSW";
@@ -96,7 +105,8 @@ AsyncWebSocket ws("/ws");
96105
const char* ssid = "MYROUTERSSD";
97106
const char* password = "MYROUTERPASSWD";
98107
#endif
99-
const char* hostName = "smartsw32";
108+
109+
const char* hostName = "smartsw";
100110

101111
// RTC
102112
static timeval tv;
@@ -222,7 +232,7 @@ void updateDHT(){
222232
float h1 = dht.readHumidity();
223233
float t1 = dht.readTemperature(); //Celsius or dht.readTemperature(true) for Fahrenheit
224234
if (isnan(h1) || isnan(t1)) {
225-
Serial.print(F("Failed to read from DHT sensor!"));
235+
Serial.println(F("Failed to read from DHT sensor!"));
226236
} else {
227237
h = h1 + DHT_H_CORR;
228238
t = t1 + DHT_T_CORR;
@@ -241,8 +251,13 @@ void checkPhysicalButton()
241251
if (btnState != LOW) { // btnState is used to avoid sequential toggles
242252
ledState = !ledState;
243253
digitalWrite(ledPin, ledState);
244-
if (ledState == LED_OFF) ws.textAll("led,ledoff");
245-
else ws.textAll("led,ledon");
254+
if (ledState == LED_OFF) {
255+
ws.textAll("led,ledoff");
256+
Serial.println(F("LED-OFF"));
257+
} else {
258+
ws.textAll("led,ledon");
259+
Serial.println(F("LED-ON"));
260+
}
246261
}
247262
btnState = LOW;
248263
} else {
@@ -267,12 +282,41 @@ void mytimer() {
267282
}
268283

269284
#ifdef USE_AUTH_COOKIE
285+
unsigned long key[4] = {0x01F20304,0x05060708,0x090a0b0c,0x0d0e0f00};
286+
Xtea x(key);
287+
288+
void encip(String &mtk, unsigned long token){
289+
unsigned long res[2] = {random(0xFFFFFFFF),token};
290+
x.encrypt(res);
291+
char buf1[18];
292+
sprintf(buf1, "%08X_%08X",res[0],res[1]); //8 bytes for encryping the IP cookie
293+
mtk = (String)buf1;
294+
}
295+
296+
unsigned long decip(const char *pch){
297+
unsigned long res[2] = {0,0};
298+
res[0] = strtoul(pch, NULL, 16);
299+
res[1] = strtoul(&pch[9], NULL, 16);
300+
x.decrypt(res);
301+
return res[1];
302+
}
303+
270304
bool myHandshake(AsyncWebServerRequest *request){ // false will 401
305+
bool rslt = false;
271306
if (request->hasHeader("Cookie")){
272307
String cookie = request->header("Cookie");
273-
if (cookie.indexOf(MY_COOKIE) != -1) return true;
274-
else return false;
275-
} else return false;
308+
Serial.println(cookie);
309+
310+
uint8_t pos = cookie.indexOf(MY_COOKIE_PREF);
311+
if (pos != -1){
312+
unsigned long ix = decip(cookie.substring(pos+5, pos+22).c_str());
313+
Serial.printf("Ask:%08X Got:%08X\n", MY_SECRET_NUMBER, ix);
314+
if (MY_SECRET_NUMBER == ix)
315+
rslt=true;
316+
} else rslt=false;
317+
} else rslt=false;
318+
Serial.printf(rslt ? "C-YES\n" : "C-NO\n");
319+
return rslt;
276320
}
277321
#endif
278322

@@ -322,8 +366,7 @@ void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventT
322366
ws.textAll("led,ledoff");
323367
}
324368
digitalWrite(ledPin, ledState); // apply change
325-
326-
369+
327370
} else if(data[0] == 'T') { // timeset
328371
if (len > 11) {
329372
data[3] = data[6] = data[9] = data[12] = 0; // cut strings
@@ -444,7 +487,8 @@ void setup(){
444487
}
445488
#endif
446489

447-
Serial.print(F("*CONNECTED*\n"));
490+
Serial.print(F("*CONNECTED* OWN IP:"));
491+
Serial.println(WiFi.localIP());
448492

449493
//DHT
450494
dht.begin();
@@ -492,25 +536,41 @@ void setup(){
492536
server.addHandler(new SPIFFSEditor(SPIFFS, http_username,http_password));
493537
#elif defined(USE_AUTH_COOKIE)
494538
server.addHandler(new SPIFFSEditor(SPIFFS)).setFilter(myHandshake);
539+
#else
540+
server.addHandler(new SPIFFSEditor(SPIFFS));
495541
#endif
496542
#elif defined(ESP8266)
497543
#ifdef USE_AUTH_STAT
498544
server.addHandler(new SPIFFSEditor(http_username,http_password));
499545
#elif defined(USE_AUTH_COOKIE)
500546
server.addHandler(new SPIFFSEditor()).setFilter(myHandshake);
547+
#else
548+
server.addHandler(new SPIFFSEditor());
501549
#endif
502550
#endif
503551

504552
#ifdef USE_AUTH_COOKIE
505-
server.on("/lg2n", HTTP_POST, [](AsyncWebServerRequest *request){ // cookie test
506-
if((request->hasParam("pa2w",true) && (String(request->getParam("pa2w",true)->value().c_str()) == String(http_password)))||(request->hasParam("lg0f",true))){
507-
AsyncWebServerResponse *response = request->beginResponse(301);
553+
server.on("/lg2n", HTTP_POST, [](AsyncWebServerRequest *request){
554+
555+
String ckx;
556+
encip(ckx, MY_SECRET_NUMBER);
557+
558+
AsyncWebServerResponse *response;
559+
560+
if(request->hasParam("lg0f",true)){
561+
response = request->beginResponse(200, "text/html;charset=utf-8", "<h1>Logged Out! <a href='/'>Back</a></h1>");
562+
response->addHeader("Cache-Control", "no-cache");
563+
response->addHeader("Set-Cookie", MY_COOKIE_DEL);
564+
565+
} else if(request->hasParam("pa2w",true) && (String(request->getParam("pa2w",true)->value().c_str()) == String(http_password))){
566+
response = request->beginResponse(301);
508567
response->addHeader("Location", "/");
509568
response->addHeader("Cache-Control", "no-cache");
510-
if(request->hasParam("lg0f",true)) response->addHeader("Set-Cookie", MY_COOKIE_DEL);
511-
else response->addHeader("Set-Cookie", MY_COOKIE_FULL);
512-
request->send(response);
513-
} else request->send(200, "text/plain","Wrong Password!");
569+
response->addHeader("Set-Cookie", MY_COOKIE_PREF + ckx + MY_COOKIE_SUFF);
570+
571+
} else response = request->beginResponse(200, "text/html;charset=utf-8", "<h1>Wrong password! <a href='/'>Back</a></h1>");
572+
573+
request->send(response);
514574
});
515575
#endif
516576

@@ -520,7 +580,14 @@ void setup(){
520580
#ifdef USE_AUTH_STAT
521581
if(!request->authenticate(http_username, http_password)) return request->requestAuthentication();
522582
#endif
523-
request->send(200, "text/plain", String(ESP.getFreeHeap()));
583+
584+
#ifdef ESP32
585+
request->send(200, "text/plain", String(ESP.getMinFreeHeap()) + ':' + String(ESP.getFreeHeap()) + ':'+ String(ESP.getHeapSize()));
586+
#else
587+
request->send(200, "text/plain", String(ESP.getFreeHeap()));
588+
#endif
589+
590+
524591
#ifdef USE_AUTH COOKIE
525592
}).setFilter(myHandshake);
526593
#else
@@ -584,7 +651,7 @@ void setup(){
584651

585652
#ifdef USE_AUTH_COOKIE
586653
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm").setFilter(myHandshake);
587-
server.serveStatic("/", SPIFFS, "/login/").setDefaultFile("index.htm").setFilter(!myHandshake);
654+
server.serveStatic("/", SPIFFS, "/login/").setDefaultFile("index.htm");
588655
#else
589656
#ifdef USE_AUTH_STAT
590657
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm").setAuthentication(http_username,http_password);

examples/SmartSwitch/Xtea.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
Xtea.cpp - Xtea encryption/decryption
3+
Written by Frank Kienast in November, 2010
4+
https://github.com/franksmicro/Arduino/tree/master/libraries/Xtea
5+
*/
6+
#include <stdint.h>
7+
#include "Xtea.h"
8+
9+
#define NUM_ROUNDS 32
10+
11+
Xtea::Xtea(unsigned long key[4])
12+
{
13+
_key[0] = key[0];
14+
_key[1] = key[1];
15+
_key[2] = key[2];
16+
_key[3] = key[3];
17+
}
18+
19+
void Xtea::encrypt(unsigned long v[2])
20+
{
21+
unsigned int i;
22+
unsigned long v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
23+
24+
for (i=0; i < NUM_ROUNDS; i++)
25+
{
26+
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + _key[sum & 3]);
27+
sum += delta;
28+
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + _key[(sum>>11) & 3]);
29+
}
30+
31+
v[0]=v0; v[1]=v1;
32+
}
33+
34+
void Xtea::decrypt(unsigned long v[2])
35+
{
36+
unsigned int i;
37+
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*NUM_ROUNDS;
38+
39+
for (i=0; i < NUM_ROUNDS; i++)
40+
{
41+
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + _key[(sum>>11) & 3]);
42+
sum -= delta;
43+
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + _key[sum & 3]);
44+
}
45+
46+
v[0]=v0; v[1]=v1;
47+
}
48+

examples/SmartSwitch/Xtea.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
Xtea.h - Crypto library
3+
Written by Frank Kienast in November, 2010
4+
https://github.com/franksmicro/Arduino/tree/master/libraries/Xtea
5+
*/
6+
#ifndef Xtea_h
7+
#define Xtea_h
8+
9+
10+
class Xtea
11+
{
12+
public:
13+
Xtea(unsigned long key[4]);
14+
void encrypt(unsigned long data[2]);
15+
void decrypt(unsigned long data[2]);
16+
private:
17+
unsigned long _key[4];
18+
};
19+
20+
#endif
0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)