-
Notifications
You must be signed in to change notification settings - Fork 0
/
ESP8266_homie_unified.ino
811 lines (641 loc) · 26 KB
/
ESP8266_homie_unified.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
#include <FS.h> // this needs to be first, or it all crashes and burns...
/*
FWTYPE:
1 esp8266-temperature-sensor
2 esp8266-flow-counter
3 esp8266-switch
4 esp8266-depth-sensor
5 esp8266-pressure-sensors
6 esp8266-loadcell
7 esp8266-watermeter
8 esp8266-bme280
9 esp8266-sht31
10 esp8266-air
11 esp8266-weathervane
12 esp8266-mq135
13 esp8266-timer
14 esp8266-pump-controller
15 esp8266-tli4970
16 esp8266-pressure-depth
17 esp8266-relay
*/
/******************** IMPORTANT NOTE for ADS1115 ********************
Note: change ADS1115_CONVERSIONDELAY from 8 to 9 in libraries/Adafruit_ADS1X15/Adafruit_ADS1015.h
If this isn't done the value is read before it's converted and you will get the previous pin's reading
#define ADS1115_CONVERSIONDELAY (9)
**********************************************************************/
// Much of the HTTP authentication code is based on brzi's work published at https://www.hackster.io/brzi/esp8266-advanced-login-security-748560
#define FWTYPE 14
#define FWVERSION "0.9.19v"
#define FWPASSWORD "esp8266."
#define USESSD1306 // SSD1306 OLED display
//#define USETLI4970 // Does the sensor board include a TLi4970 current sensor
//#define DEBUG
#define SERIALSPEED 115200
#include <ESP8266WiFi.h> // ESP8266 Core WiFi Library
#include <ESP8266WebServer.h> // Local WebServer used to serve the configuration portal
//#include <ESP8266WebServerSecure.h> // At this stage loading the key and cert from a file doesn't work, it's too memory intensive and one page handler can't server both HTTP and HTTPS (this can be handled to some degree except for file uploads).
#include "StreamString.h" // Need for web server firmware update
#include <ESP8266mDNS.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson
#include <PubSubClient.h> // http://pubsubclient.knolleary.net/
// ########### String constants ############
#include "String_Consts.h"
// Local DNS Server used for redirecting all requests to the configuration portal
#include <DNSServer.h>
DNSServer dnsServer;
const byte DNS_PORT = 53;
bool inConfigAP = false;
bool connectNewWifi = false;
const uint16_t configPortalTimeout = 300; // 5 minute timeout on config portal before giving up and rebooting
// Accurate time is needed to be able to verify security certificates
#include <time.h>
char ntp_server1[41];
char ntp_server2[41];
float tzoffset = 10; // Default timezone offset in minutes (AEST)
#include <WiFiClientSecure.h>
bool tlsOkay = false;
WiFiClientSecure espSecureClient;
WiFiClient espClient;
#include <Syslog.h> // https://github.com/arcao/Syslog
#include <WiFiUdp.h>
bool use_syslog = false;
char host_name[21] = "";
char syslog_server[41];
uint16_t loglevel = LOG_NOTICE;
WiFiUDP udpClient;
Syslog syslog(udpClient, SYSLOG_PROTO_BSD);
#ifdef USESSD1306
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);
#define COLS 20
#define ROWS 8
uint32_t prevDisplay = 0;
char displayArray[ROWS][COLS+1]; // y postion first in array as we are dealing with lines of text then position on line
uint8_t displayLine = 0;
uint16_t displaySleep = 30; // Seconds before the display goes to sleep
bool displayActive = true;
#endif
// ########### Sensor Variables ############
#include "SensorVariables.h"
#ifndef CONFIG_PIN
#define CONFIG_PIN 13 // WeMos D1 Mini D7
#endif
//define the default MQTT values here, if there are different values in config.json, they are overwritten.
char mqtt_server[41];
bool mqtt_tls = false;
bool mqtt_auth = false;
uint16_t mqtt_port = 1883;
char mqtt_name[21];
char mqtt_topicbase[21];
char mqtt_user[21];
char mqtt_passwd[33];
int mqtt_interval = 5; // interval in seconds between updates
int mqtt_watchdog = 60; // seconds with mqtt data before watchdog reboots device
unsigned long watchdog = millis(); // timer to keep last watchdog packet
int error_count_log = 2; // How many errors need to be encountered for a sensor before it's logged, if it's more or less don't log
/// Max size for the MQTT data output string
#define OUT_STR_MAX 120
char output[OUT_STR_MAX];
String baseTopic;
char pubTopic[50];
char subTopic[50];
/// The MQTT client
PubSubClient mqttClient;
/// The HTTP server
ESP8266WebServer httpServer(80);
//ESP8266WebServerSecure httpsServer(443);
bool lock = false; // This bool is used to control device lockout
String httpUser;
String httpPasswd;
bool httpLoggedin = false;
unsigned long logincld = millis(), reqmillis = millis(), tempign = millis(); // First 2 timers are for lockout and last one is inactivity timer
uint8_t trycount = 0; // trycount will be our buffer for remembering how many failed login attempts there have been
bool rebootRequired = false;
bool use_staticip = false;
IPAddress local_ip(192, 168, 0, 99);
IPAddress dns1(192, 168, 0, 1);
IPAddress dns2(0, 0, 0, 0);
IPAddress subnet(255, 255, 255, 0);
IPAddress gateway(192, 168, 0, 1);
String ssid = "";
String psk = "";
String _ssid = ""; // Used for when we are trying to connect to a new WiFi network
String _psk = ""; // Used for when we are trying to connect to a new WiFi network
unsigned long currentTime = 0;
unsigned long cloopTime = 0;
unsigned long mqttTime = 0;
unsigned long mqttConnectTime = 0;
String tmpString;
String logString; // This can be used by MQTT logging as well
bool configured = false;
bool configLoaded = false;
String configfilename = "/config.json";
String CAcertfilename = "/cacert.der";
String HTTPScertfilename = "/httpscert.der";
String HTTPSkeyfilename = "/httpskey.der";
bool ca_cert_okay = false;
//bool https_okay = false;
int buttonState; // the current reading from the config button
int lastButtonState = LOW; // the previous reading from the config button
uint32_t lastDebounceTime = 0; // the last time the output pin was toggled
uint32_t debounceDelay = 50; // the debounce time; increase as needed for your button
bool buttonStateChanged = false; //
////////////////////////////////////// setup ///////////////////////////////////////
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
digitalWrite(LED_BUILTIN, LOW); // Turn the LED on (Note that LOW is the voltage level
// but actually the LED is on; this is because
// it is acive low on the ESP-01)
#ifdef DEBUG
tmpString = String(fwname);
tmpString = String(tmpString + "-DEBUG");
tmpString.toCharArray(fwname, 40);
#endif
Serial.begin(SERIALSPEED); // Open serial monitor at SERIALSPEED baud to see results.
delay(200); // Give the serial port time to setup
pinMode(CONFIG_PIN, INPUT_PULLUP);
// Load all the defaults into memory
strncpy_P( ntp_server1, default_ntp_server1, 41);
strncpy_P( ntp_server2, default_ntp_server2, 41);
strncpy_P( syslog_server, default_syslog_server, 41);
strncpy_P( mqtt_server, default_mqtt_server, 41);
strncpy_P( mqtt_topicbase, default_mqtt_topicbase, 21);
strncpy_P( mqtt_name, fwname, 21);
strcpy(host_name, mqtt_name);
httpUser = String(FPSTR(default_httpUser));
httpPasswd = String(FPSTR(default_httpPasswd));
#ifdef USESSD1306
Serial.print( F("Configuring OLED..."));
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64)
display.setTextSize(1);
display.clearDisplay();
display.setTextColor(WHITE);
display.setCursor(0, 0);
for (byte y=0; y<ROWS; y++) {
for (byte x=0; x<COLS; x++) {
displayArray[y][x] = ' ';
}
}
printDone();
#endif
Serial.println();
logString = String(fwname) + " v" + FWVERSION + F(" booting.");
printMessage(app_name_sys, logString, true);
logString = String(F("Connecting to '")) + String(WiFi.SSID()) + "'";
printMessage(app_name_wifi, logString, true);
uint32_t realSize = ESP.getFlashChipRealSize();
uint32_t ideSize = ESP.getFlashChipSize();
if (ideSize != realSize) {
logString = String(F("Flash size config wrong. IDE: ")) + String(ideSize/1048576.0) + F(" MB, real: ") + String(realSize/1048576.0) + " MB";
printMessage(app_name_sys, logString, true);
if (ideSize >= realSize) {
logString = F("\nFlash too small!\nCANNOT BOOT\n");
printMessage(app_name_sys, logString, true);
bool ledState = 0;
while (1) {
digitalWrite(LED_BUILTIN, ledState);
ledState = 1 - ledState;
delay(1000);
}
}
}
loadConfig();
logString = String(F("MAC address: ")) + String(WiFi.macAddress());
printMessage(app_name_wifi, logString, true);
#ifdef DEBUG
dmesg();
Serial.println("Saved WiFi credentials");
dmesg();
Serial.printf("SSID: %s\n", WiFi.SSID().c_str());
dmesg();
Serial.printf("PSK: %s\n", WiFi.psk().c_str());
#endif
if ( digitalRead(CONFIG_PIN) == HIGH ) { // If the config pin is NOT pressed then skip this
// Back off for between 0 and 1 seconds before starting Wifi
// This reduces the sudden current draw when too many sensors start at once or lots of data packets at exactly the same time
long startupDelay = random(1000);
logString = String(F("Startup random delay: ")) + String(startupDelay);
printMessage(app_name_sys, logString, true);
delay( startupDelay );
}
// This will be available in the setup AP as well
logString = F("Starting web server");
printMessage(app_name_http, logString, true);
httpSetup();
// These 3 lines tell esp to collect User-Agent and Cookie in http header when request is made
const char * headerkeys[] = {"User-Agent","Cookie"} ;
size_t headerkeyssize = sizeof(headerkeys)/sizeof(char*);
httpServer.collectHeaders(headerkeys, headerkeyssize );
httpServer.begin();
// is configuration portal requested?
if ( ( digitalRead(CONFIG_PIN) == LOW ) || (WiFi.SSID() == "") || (! configLoaded) ) {
if ( digitalRead(CONFIG_PIN) == LOW ) // if it's the config pin that's put us here
logString = F("Config PIN pressed.");
if (WiFi.SSID() == "")
logString = F("No saved SSID.");
if (! configLoaded)
logString = F("Config file failed to load.");
logString += F(" Resetting configuration.");
printMessage(app_name_cfg, logString, true);
while ( digitalRead(CONFIG_PIN) == LOW )
yield();
if (millis() >= 10000) {
logString = F("Config pin pressed for more than 10 seconds. Performing factory default reset.");
printMessage(app_name_cfg, logString, true);
if (SPIFFS.begin()) {
SPIFFS.format();
}
WiFi.persistent(true); // Discard old WiFi credentials, i.e. erase the WiFi credentials
WiFi.disconnect(); // Disconnect
logString = F("Done.");
printMessage(app_name_cfg, logString, true);
bool ledState = 0;
for (byte i=0;i<20;i++) {
digitalWrite(LED_BUILTIN, ledState);
ledState = 1 - ledState;
delay(500);
}
delay(1000);
logString = F("Rebooting.");
printMessage(app_name_cfg, logString, true);
//reboot and try again, or maybe put it to deep sleep
ESP.restart();
delay(5000);
}
// Without this disconnect() setting mode to WIFI_AP_STA with corrupted or incorrect credentials can sometimes cause
// the ESP8266 to get stuck and have the wdt constantly reboot before you can correct the problem. The persitant(false)
// tells it to retain the saved credentials (i.e. don't erase anything)
WiFi.persistent(false); // KEEP old WiFi credentials
WiFi.disconnect(); // but disconnect
delay(100);
WiFi.mode(WIFI_AP_STA);
logString = F("Starting AP as ");
logString += String(fwname);
printMessage(app_name_wifi, logString, true);
WiFi.softAP(fwname, FWPASSWORD);
connectNewWifi = false;
delay(500); // Without delay the IP address may be blank
#ifdef DEBUG
dmesg();
Serial.print(F("AP "));
Serial.print(str_cfg_ip_address);
Serial.print(F(": "));
Serial.println(WiFi.softAPIP());
#endif
/* Setup the DNS server redirecting all the domains to the apIP */
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(DNS_PORT, "*", WiFi.softAPIP());
inConfigAP = true; // We don't need to ask for a password on the webpage and shouldn't act on anything yet
connectNewWifi = false;
unsigned long configPortalStart = millis();
while (true) {
if ( millis() >= (configPortalStart + (1000 * configPortalTimeout ) ) ) {
logString = String(F("Config portal timeout reached. ")) + str_rebooting;
printMessage(app_name_sys, logString, true);
delay(500);
//reboot and try again, or maybe put it to deep sleep
ESP.restart();
delay(5000);
}
dnsServer.processNextRequest();
httpServer.handleClient();
if (connectNewWifi) {
saveConfig(); // Save a config file, with the defaults if nothing else has been set.
delay(100);
if (newWiFiCredentials()) {
break;
}
}
yield();
}
inConfigAP = false;
} else {
logString = String(F("Connecting to '")) + String(WiFi.SSID()) + "'";
printMessage(app_name_wifi, logString, true);
WiFi.begin();
}
WiFi.hostname(host_name);
WiFi.mode(WIFI_STA);
ssid = WiFi.SSID();
psk = WiFi.psk();
if (use_staticip) {
bool configstatus = WiFi.config(local_ip, gateway, subnet, dns1, dns2);
logString = str_static + str_space + str_ipv4 + str_space;
if (configstatus) {
logString += str_succeeded;
} else {
logString += str_failed;
}
printMessage(app_name_net, logString, false);
}
if (use_syslog) {
setupSyslog();
}
logString = str_ipv4 + str_space + cfg_configured;
logMessage(app_name_net, logString, true);
/*
* If the serial speed is greater than 57600 baud sometimes the IP address will not be applied
* https://github.com/esp8266/Arduino/issues/128
* It appears to set the IP but then it uses a DHCP address instead. Putting enough data through the connection,
* such as a syslog message and a DNS lookup, seems to be enough to trigger the behaviour after which setting
* the IP a second time works properly.
*/
if (use_staticip) {
IPAddress tmpip;
tmpString = IPtoString(dns1);
WiFi.hostByName(tmpString.c_str(), tmpip);
while (IPtoString(WiFi.localIP()) != IPtoString(local_ip) ) {
Serial.println(str_dot);
bool configstatus = WiFi.config(local_ip, gateway, subnet, dns1, dns2);
logString = str_static + str_space + str_ipv4 + str_space;
if (configstatus) {
logString += str_succeeded;
} else {
logString += str_failed;
}
printMessage(app_name_net, logString, false);
}
}
//if you get here you have connected to the WiFi
logString = str_connected;
logMessage(app_name_wifi, logString, true);
logString = String(fwname) + " v" + FWVERSION;
logMessage(app_name_sys, logString, false);
if (use_staticip) {
logString = str_static;
} else {
waitForDHCPLease();
logString = str_dhcp;
}
logString += str_space + str_cfg_ip_address + str_colon + IPtoString(WiFi.localIP());
logMessage(app_name_net, logString, true);
logString = str_cfg_subnet + str_colon + IPtoString(WiFi.subnetMask());
logMessage(app_name_net, logString, false);
logString = str_cfg_gateway + str_colon + IPtoString(WiFi.gatewayIP());
logMessage(app_name_net, logString, false);
if (use_staticip) {
logString = str_cfg_dns_server1 + str_colon + IPtoString(dns1);
logMessage(app_name_net, logString, false);
logString = str_cfg_dns_server2 + str_colon + IPtoString(dns2);
logMessage(app_name_net, logString, false);
}
/*
bool https_files_okay = true;
File certfile, keyfile;
if ( SPIFFS.exists(HTTPScertfilename) ) {
certfile = SPIFFS.open(HTTPScertfilename, "r");
if (certfile) {
logString = F("Opened HTTPS certificate file.");
logMessage(app_name_http, logString, false);
} else {
logString = F("Failed to open HTTPS certificate! HTTPS disabled.");
logMessage(app_name_http, logString, false);
https_files_okay = false;
}
} else {
logString = F("HTTPS certificate doesn't exist! HTTPS disabled.");
logMessage(app_name_http, logString, false);
https_files_okay = false;
}
if ( SPIFFS.exists(HTTPSkeyfilename) ) {
keyfile = SPIFFS.open(HTTPSkeyfilename, "r");
if (keyfile) {
logString = F("Opened HTTPS key file.");
logMessage(app_name_http, logString, false);
} else {
logString = F("Failed to open HTTPS key! HTTPS disabled.");
logMessage(app_name_http, logString, false);
https_files_okay = false;
}
} else {
logString = F("HTTPS key doesn't exist! HTTPS disabled.");
logMessage(app_name_http, logString, false);
https_files_okay = false;
}
if (https_files_okay) {
uint8_t x509[certfile.size()];
uint8_t rsakey[keyfile.size()];
certfile.read((uint8_t *)x509, certfile.size());
keyfile.read((uint8_t *)rsakey, keyfile.size());
httpsServer.setServerKeyAndCert(rsakey, sizeof(rsakey), x509, sizeof(x509));
httpsServer.collectHeaders(headerkeys, headerkeyssize );
httpsServer.begin();
MDNS.addService("https", "tcp", 443);
logString = String(F("HTTPS server available by https://")) + String(host_name) + F(".local/");
logMessage(app_name_http, logString, false);
https_okay = true;
} else {
logString = F("Failed to start HTTPS server using supplied certificate and key files! HTTPS disabled.");
logMessage(app_name_http, logString, false);
}
if (certfile)
certfile.close();
if (keyfile)
keyfile.close();
*/
MDNS.begin(host_name);
MDNS.addService("http", "tcp", 80);
logString = String(F("Web server available by http://")) + String(host_name) + F(".local/");
logMessage(app_name_http, logString, true);
if (mqtt_tls) {
mqttClient.setClient(espSecureClient);
// Synchronize time useing SNTP. This is necessary to verify that
// the TLS certificates offered by the server are currently valid.
logString = F("Setting time using SNTP. Time zone: ");
logString += String(tzoffset);
logMessage(app_name_sys, logString, false);
configTime(tzoffset * 3600, 0, ntp_server1, ntp_server2);
time_t now = time(nullptr);
while (now < tzoffset * 3600 * 2) {
delay(500);
Serial.print(str_dot);
now = time(nullptr);
}
struct tm timeinfo;
localtime_r(&now, &timeinfo);
logString = String(asctime(&timeinfo));
logString.trim();
logMessage(app_name_sys, logString, true);
if ( SPIFFS.exists(CAcertfilename) ) {
File CAcertfile = SPIFFS.open(CAcertfilename, "r");
if (CAcertfile) {
logString = F("Opened CA certificate file.");
logMessage(app_name_mqtt, logString, false);
if (espSecureClient.loadCACert(CAcertfile, CAcertfile.size()) ) {
ca_cert_okay = true;
} else {
logString = F("Failed to load root CA certificate! MQTT disabled.");
logMessage(app_name_mqtt, logString, false);
}
CAcertfile.close();
} else {
logString = F("Failed to open CA certificate! MQTT disabled.");
logMessage(app_name_mqtt, logString, false);
}
} else {
logString = F("CA certificate doesn't exist! MQTT disabled.");
logMessage(app_name_mqtt, logString, false);
}
} else {
mqttClient.setClient(espClient);
}
/// The MQTT baseTopic
baseTopic = String(mqtt_topicbase) + String('/') + String(mqtt_name) + String('/');
logString = "server: " + String(mqtt_server) + ':' + String(mqtt_port);
logMessage(app_name_mqtt, logString, false);
logString = String("topic: " + baseTopic);
logMessage(app_name_mqtt, logString, false);
tmpString = String(baseTopic) + String(FPSTR(mqttstr_ota)) + String(FPSTR(str_command));
tmpString.toCharArray(subTopic, 50);
mqttClient.setServer(mqtt_server, mqtt_port);
mqttClient.setCallback(mqttCallback);
mqttConnect();
mqttClient.loop(); // Check for incoming messages
currentTime = millis();
cloopTime = currentTime;
// #################### sensorSetup() is defined in each sensor file as appropriate
sensorSetup();
// mqtt_send_systeminfo(); // Send this whenever MQTT connects so that if an IP address changes it gets sent again.
logString = F("Startup complete.");
logMessage(app_name_sys, logString, true);
#ifdef DEBUG
logString = String(F("Flash size: ")) + String(realSize/1048576.0) + " MB";
logMessage(app_name_sys, logString, false);
logString = String(F("Flash size config: ")) + String(ideSize/1048576.0) + " MB";
logMessage(app_name_sys, logString, false);
logString = String(F("Program Size: ")) + String(ESP.getSketchSize() / 1024) + " kB";
logMessage(app_name_sys, logString, false);
logString = String(F("Free Program Space: ")) + String(ESP.getFreeSketchSpace() / 1024) + " kB";
logMessage(app_name_sys, logString, false);
logString = String(F("Free Memory: ")) + String(ESP.getFreeHeap() / 1024) + " kB";
logMessage(app_name_sys, logString, false);
FSInfo fs_info;
SPIFFS.info(fs_info);
logString = String(F("Filesystem size:")) + String(fs_info.totalBytes / 1024) + " kB";
logMessage(app_name_sys, logString, false);
logString = String(F("Filesystem free:")) + String((fs_info.totalBytes - fs_info.usedBytes) / 1024) + " kB";
logMessage(app_name_sys, logString, false);
logString = String(F("ESP Chip Id: ")) + String(ESP.getChipId());
logMessage(app_name_sys, logString, false);
logString = String(F("Flash Chip Id: ")) + String(ESP.getFlashChipId());
logMessage(app_name_sys, logString, false);
#endif
#ifdef DEBUG
digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH
#endif
}
////////////////////////////////////// main loop ///////////////////////////////////////
void loop() {
buttonStateChanged = false;
// Check the button first
int reading = digitalRead(CONFIG_PIN);
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
buttonStateChanged = true;
// if (buttonState == LOW) {
// oled_offtime = (millis()/1000) + cfg.oled_timeout; // Set
// }
}
}
lastButtonState = reading;
// buttonState can now be used elsewhere
httpServer.handleClient();
// if (https_okay)
// httpsServer.handleClient();
if (connectNewWifi) {
newWiFiCredentials(); // Attempt to connect to new WiFi network
}
if (lock && abs(millis() - logincld) > 300000) {
lock = false;
trycount = 0;
logincld = millis(); // After 5 minutes is passed unlock the system
}
if (!lock && abs(millis() - logincld) > 60000) {
trycount = 0;
logincld = millis();
// After minute is passed without bad entries, reset trycount
}
if (abs(millis() - tempign) > 120000) {
httpLoggedin = false;
gencookie();
tempign = millis();
// if there is no activity from loged on user, generate a new cookie. This is more secure than adding expiry to the cookie header
}
bool reconnected = false;
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(250);
checkWatchdog(); // Let the watchdog reboot if we've been disconnected too long
reconnected = true; // Records that we have reconnected
}
if (reconnected == true) {
logString = str_connected;
logMessage(app_name_wifi, logString, true);
if (!use_staticip) {
waitForDHCPLease();
}
logString = str_connected;
logMessage(app_name_net, logString, true);
}
currentTime = millis();
if (!mqttClient.connected()) {
if ( currentTime >= (mqttConnectTime + 1000 ) ) {
mqttConnectTime = currentTime; // Updates mqttConnectTime
mqttConnect();
}
}
mqttClient.loop(); // Check for incoming messages
////////////////////////////////////// calculate data ///////////////////////////////////////
currentTime = millis();
calcData();
////////////////////////////////////// send data ///////////////////////////////////////
// Every mqtt_interval seconds send the current data to the MQTT broker
currentTime = millis();
if ( currentTime >= (mqttTime + (1000 * mqtt_interval ) ) ) {
mqttTime = currentTime; // Updates mqttTime
sendData();
/// send uptime and signal
unsigned long uptime = millis();
uptime = uptime / 1000;
mqttSend(String("$uptime"), String(uptime), true);
int signal = WiFi.RSSI();
mqttSend(String("$signal"), String(signal), true);
}
#ifdef USESSD1306
if (buttonStateChanged && buttonState == LOW) {
if ( millis() > (prevDisplay + (displaySleep * 1000) ) ) { // if the display is sleeping redraw it.
display.setTextSize(1);
display.clearDisplay();
for (byte y=0; y<(ROWS-1); y++) {
display.setCursor(0, y*8);
display.print(displayArray[y]);
}
display.display();
}
prevDisplay = millis();
displayActive = true;
}
if ( displayActive && millis() > (prevDisplay + (displaySleep * 1000) ) ) {
display.clearDisplay();
display.display();
displayActive = false;
}
#endif
////////////////////////////////////// check the watchdog ///////////////////////////////////////
checkWatchdog();
}