Browse Source

0.6.1 2020-01-16
* improved uptime evaluation/output
* improved logging function
* added another web console which does not use WebSockets and buffers up to 4k message history
* WS version stays in for now, accessible via _/wsconsole_ - will maybe merge them to a hybrid version in the future
* added EXPERIMENTAL encryption of saved passwords
* Disabled by default
* Enable encryption with command "encrypt"
* Disable again with command "decrypt", which also deletes all stored passwords in order to save them from beeing retrieved easily. If decryption is done intentionally all credentials have to be re-entered.
* Simple XOR encryption, key can only be changed at compile time
Not perfectly safe but better than storing in plain text. Makes it at least a little bit more difficult to retrieve passwords. Still looking for an improved solution, which is not easy as ressources are very limited and the decryption key must be stored somewhere on the device anyway - which would not be different with another encryption technique.
* added compile time options to disable certain features completely
* has weird issues when compiling with PlatformIO and WebSockets function is disabled -> has to be investigated
* added/improved commands, added help command, etc.
* all commands work via serial, MQTT (/cmd topic) and web console now
* see commands list in seperate file
* added sysinfo page at /sysinfo
* many small improvements

FloKra 4 years ago
parent
commit
b470e6565c
75 changed files with 4013 additions and 2463 deletions
  1. 20 0
      CHANGELOG.md
  2. 49 0
      COMMANDS.md
  3. 9 0
      ClearESP-Sketch/ClearESP/ClearESP.ino
  4. BIN
      build/elf/WiFiThermostat.ino.d1_mini.20200113_v0.6.1.elf.zip
  5. BIN
      releases/bin/WiFiThermostat.ino.d1_mini.20200113_v0.6.1.bin
  6. BIN
      releases/src/WiFiThermostat_0.6.1.zip
  7. 0 0
      src/Buttonhandling.ino
  8. 0 0
      src/Display.ino
  9. 217 132
      src/WiFiThermostat.ino
  10. 0 199
      src/WiFiThermostat/commands.ino
  11. 0 20
      src/WiFiThermostat/commonFunctions.ino
  12. 0 1476
      src/WiFiThermostat/httpServer.ino
  13. 0 69
      src/WiFiThermostat/logging.ino
  14. 0 41
      src/WiFiThermostat/miscFunctions.ino
  15. 0 95
      src/WiFiThermostat/time.ino
  16. 303 0
      src/commands.ino
  17. 42 0
      src/commonFunctions.ino
  18. 515 306
      src/config.ino
  19. 9 6
      src/html.h
  20. 7 3
      src/html_conf.h
  21. 0 0
      src/html_confAdd.h
  22. 0 0
      src/html_confAdv.h
  23. 0 0
      src/html_confBas.h
  24. 1 1
      src/html_confDevWiFi.h
  25. 27 5
      src/html_confLog.h
  26. 1 1
      src/html_confMqtt.h
  27. 2 2
      src/html_confTime.h
  28. 8 4
      src/html_confWeb.h
  29. 89 0
      src/html_console.h
  30. 6 2
      src/html_console_ws.h
  31. 6 2
      src/html_main.h
  32. 0 0
      src/html_redTemps.h
  33. 111 0
      src/html_sysinfo.h
  34. 1913 0
      src/httpServer.ino
  35. 187 0
      src/logging.ino
  36. 88 0
      src/miscFunctions.ino
  37. 28 53
      src/mqtt.ino
  38. 7 6
      src/mqtt_out.ino
  39. 0 0
      src/outTempHum.ino
  40. 7 13
      src/scheduler.ino
  41. 0 0
      src/thermostat.ino
  42. 44 0
      src/time.ino
  43. 0 1
      src/webinterface/api
  44. 0 1
      src/webinterface/confDataDevWiFi
  45. 0 1
      src/webinterface/confDataWeb
  46. 4 2
      src/websockets.ino
  47. 1 0
      webinterface/api
  48. 7 5
      webinterface/conf
  49. 0 0
      webinterface/confDataAdd
  50. 0 0
      webinterface/confDataAdv
  51. 0 0
      webinterface/confDataBas
  52. 1 0
      webinterface/confDataDevWiFi
  53. 0 0
      webinterface/confDataLog
  54. 0 0
      webinterface/confDataMqtt
  55. 0 0
      webinterface/confDataTime
  56. 1 0
      webinterface/confDataWeb
  57. 0 0
      webinterface/confadd
  58. 0 0
      webinterface/confadv
  59. 0 0
      webinterface/confbas
  60. 0 0
      webinterface/confdevwifi
  61. 0 0
      webinterface/conflog
  62. 0 0
      webinterface/confmqtt
  63. 5 5
      webinterface/conftime
  64. 11 7
      webinterface/confweb
  65. 27 0
      webinterface/console
  66. 64 0
      webinterface/csapp.js
  67. 3 2
      webinterface/index
  68. 0 0
      webinterface/redTemps
  69. 0 0
      webinterface/style.css
  70. 0 0
      webinterface/style_reduced.css
  71. 117 0
      webinterface/sysinfo
  72. 1 0
      webinterface/sysinfod
  73. 72 0
      webinterface/webcsapi
  74. 0 0
      webinterface/wsapp.js
  75. 3 3
      webinterface/wsconsole

+ 20 - 0
CHANGELOG.md

@@ -1,5 +1,25 @@
 # WiFiThermostat - Changelog
 
+## 0.6.1 2020-01-16
+
+* improved uptime evaluation/output
+* improved logging function
+* added another web console which does not use WebSockets and buffers up to 4k message history
+    * WS version stays in for now, accessible via _/wsconsole_  - will maybe merge them to a hybrid version in the future
+* added EXPERIMENTAL encryption of saved passwords
+    * Disabled by default
+    * Enable encryption with command "encrypt"
+    * Disable again with command "decrypt", which also deletes all stored passwords in order to save them from beeing retrieved easily. If decryption is done intentionally all credentials have to be re-entered.
+    * Simple XOR encryption, key can only be changed at compile time  
+      Not perfectly safe but better than storing in plain text. Makes it at least a little bit more difficult to retrieve passwords. Still looking for an improved solution, which is not easy as ressources are very limited and the decryption key must be stored somewhere on the device anyway - which would not be different with another encryption technique.
+* added compile time options to disable certain features completely
+  * has weird issues when compiling with PlatformIO and WebSockets function is disabled -> has to be investigated
+* added/improved commands, added help command, etc.
+  * all commands work via serial, MQTT (/cmd topic) and web console now
+  * see commands list in seperate file
+* added sysinfo page at /sysinfo
+* many small improvements
+
 ## 0.6.0 2020-01-13
 
 * added NTP time sync + config page

+ 49 - 0
COMMANDS.md

@@ -0,0 +1,49 @@
+# WiFiThermostat - Commands
+
+## Valid Commands
+All commands can be used via Serial, MQTT (/cmd topic) and Web Console. 
+| Command             | Description 
+| ------------------- | ---------------------------------------------------
+| sysinfo             | show uptime, free heap, heap fragmentation...
+| date                | show current date/time
+| syncclock           | perform NTP time sync now
+| debugmode [0/1]     | enable/disable debug mode  <br> currently only prints sysinfo every second but will be enhanced in the near future
+| loadconf            | load saved configuration as it´s done on every startup
+| getconf             | list all conf parameters  <br> Parameters are displayed in format "CATEGORY.PARAM: VALUE", each on one line.  <br> Use PARAM name in set/get commands.  <br> Use CATEGORY in get command to display all related parameters.  
+| get [PARAM]         | show a named conf value  
+| get [CATEGORY]      | lists conf values of one category  
+| get values          | list all current saved values (see table below)
+| set [PARAM] [VALUE] | sets PARAM to VALUE  <br> (add 1 blank after PARAM to clear)
+| saveconf            | save all configurations  <br> mandatory as last step before restarting when configuring via commands
+| savevalues          | save set values
+| clearcreds          | delete all passwords  ***
+| clearwifi           | delete WiFi configurations    ****
+| encrypt             | switch on encrypted stored passwords
+| decrypt             | switch off encrypted stored passwords  <br> WARNING: deletes all currently saved credentials ****
+| ls                  | list files on SPIFFS
+| delconf             | delete ALL configuration  ****
+| restart             | 
+
+*** only affects MQTT and Web passwords, WiFi passwords are not touched.  
+
+**** You will have to enter WiFi credentials again. __BEFORE RESTART__ this can be done via command or Web Interface.  After restarting with cleared configuration you cannot access the device over WiFi any more. Therefore reconfiguration can only be done via AP-Mode/Captive Portal or Serial Console afterwards!  
+
+## Configuration Categories
+
+For use with command "get" only.  
+Case-Insensitive.  
+
+| Category    | Description
+| ----------- | --------------------
+| confDevWiFi | Device and WiFi configuration
+| confDev     | alias for 'confdevwifi'
+| confWiFi    | alias for 'confdevwifi'
+| confWeb     | Web Interface configuration
+| confMqtt    | MQTT configuration
+| confBas     | Thermostat Basic configuration
+| confAdv     | Thermostat Advanced configuration
+| confAdd     | Additional Functions configuration
+| confTime    | configuration regarding Time and NTP
+| confLog     | configuration regarding Logging
+
+

+ 9 - 0
ClearESP-Sketch/ClearESP/ClearESP.ino

@@ -0,0 +1,9 @@
+#include <ESP8266WiFi.h>
+//#include <WiFiClient.h>
+//WiFiClient espClient;
+
+void setup() {
+ESP.eraseConfig();
+ESP.reset();
+}
+void loop() {}

BIN
build/elf/WiFiThermostat.ino.d1_mini.20200113_v0.6.1.elf.zip


BIN
releases/bin/WiFiThermostat.ino.d1_mini.20200113_v0.6.1.bin


BIN
releases/src/WiFiThermostat_0.6.1.zip


+ 0 - 0
src/WiFiThermostat/Buttonhandling.ino → src/Buttonhandling.ino


+ 0 - 0
src/WiFiThermostat/Display.ino → src/Display.ino


+ 217 - 132
src/WiFiThermostat/WiFiThermostat.ino → src/WiFiThermostat.ino

@@ -1,36 +1,41 @@
 //#include <Arduino.h>
 
-//#define WIFI_HTM_PROGMEM
-#include <PersWiFiManagerExt.h>
-
-#include <ArduinoJson.h>
-#include <string.h>
-
+// ESP8266 core libs
 #include <ESP8266HTTPUpdateServer.h>
 #include <ESP8266WebServer.h>
 #include <ESP8266WiFi.h>
 #include <ESP8266mDNS.h>
-#include <WiFiClient.h>
+//#include <WiFiClient.h>
+
+// WiFiManager
+#include <PersWiFiManagerExt.h>
 
+// DNS server used for captive portal in WiFiManager
 #include <DNSServer.h>
+
+// MQTT client
 #include <PubSubClient.h>
 
+// SPIFFS FS support - used for config storage
 #include <FS.h>
 
-#include <LiquidCrystal_I2C.h>
+// Json lib - used for config storage and web api
+#include <ArduinoJson.h>
+//#include <string.h>
+
+// I2C and LCD display
 #include <Wire.h>
+#include <LiquidCrystal_I2C.h>
 
+// DHT22 sensor lib
 #include <DHT.h>
 
+// Button handling
 #include <Bounce2.h>
 #include <Button.h>
 #include <ButtonEventCallback.h>
 #include <PushButton.h>
 
-#include <time.h>
-
-#include <WebSocketsServer.h>
-
 // PRE-COMPILE CONFIGURATION
 
 //#define FORCE_SPIFFS_FORMAT
@@ -38,38 +43,51 @@
 //#define DEBUG_VERBOSE
 //#define DEBUGMODE // WARNING - DEBUGMODE reveals saved passwords on serial connection and shows note in web interface
 
-#define DEBUG_SERIAL true
+//#define DEBUG_SERIAL true
 #define DEBUG_MQTT true
 
-#define SPIFFS_DBG
-#define SPIFFS_USE_MAGIC
+// ENABLE FEATURES
+#define ENABLE_FEATURE_NTP_TIME
+#define ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+#define ENABLE_FEATURE_WEB_CONSOLE_BUFFERED
+#define ENABLE_FEATURE_PW_ENCRYPTION
+#define ENABLE_FEATURE_HTTP_UPDATER
 
+#ifdef ENABLE_FEATURE_NTP_TIME
+#include <time.h>
+#endif
+
+//#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+#include <WebSocketsServer.h>
+//#endif
+
+// DEFINE NAMES
 #define FIRMWARE_NAME "WiFiThermostat"
-#define FIRMWARE_VERSION "0.6.0"
+#define FIRMWARE_VERSION "0.6.1"
 #define FIRMWARE_URL "https://git.flokra.at/flo/WiFiThermostat"
 #define FIRMWARE_COPYRIGHT "FloKra"
 #define FIRMWARE_COPYRIGHT_URL "https://www.flokra.at/"
-
-// used as prefix in AP mode SSID, computed hostname and MQTT cliend ID
 #define FIRMWARE_SHORTNAME "WTherm"
 
+// ENCRYPTION KEY used for passwords - up to 100 chars
+#define PW_ENCRYPTION_KEY "PLhg2i7fPoYSoipq1hTF1KOqyzp3OPWtUzufCDWmD9KgxbaKYOG5WbxoO4QoLDj3F6Iif4R55UbHX1nRo7GKNqT6QXQCTsdFvFem"
+
 // default values, can later be overridden via configuration
 #define MAX_MEASUREMENT_AGE 30000      // in ms, for measured inside Temp/Hum
 #define MAX_MEASUREMENT_AGE_OUT 300000 // in ms, for received outside Temp/Hum
 
-// NTP
-#define TIMEZONE "CET-1CEST,M3.5.0/02,M10.5.0/03"
-#define NTP_TIMEOUT 1500
-#define NTP_TIMEZONE 1
-#define NTP_MINUTES_TZ 0
-#define NTP_SYNC_INTERVAL 7200
-#define NTP_SERVER "pool.ntp.org"
-
-// conf DevWiFi
-//#define DEVICE_NAME "WTherm-1" - created from FIRMWARE_SHORTNAME + last 2
-// octets of MAC address
-#define HOST_NAME ""
-#define WIFI_APMODE_PASSWORD ""
+// NTP defaults
+#ifdef ENABLE_FEATURE_NTP_TIME
+#define DEFAULT_NTP_ENABLED true
+#define DEFAULT_NTP_SERVER "pool.ntp.org"
+#define DEFAULT_NTP_SYNC_INTERVAL 7200
+#define DEFAULT_TIMEZONE "CET-1CEST,M3.5.0/02,M10.5.0/03"
+#endif
+
+// confDevWiFi
+//#define DEVICE_NAME "WTherm-1" // now created from FIRMWARE_SHORTNAME + last 2 octets of MAC address
+//#define DEFAULT_HOST_NAME "" // now created from FIRMWARE_SHORTNAME + last 2 octets of MAC address
+#define DEFAULT_WIFI_APMODE_PASSWORD "nichtsicher" // min 8 chars!
 #define DEFAULT_WIFI_APMODE_TIMEOUT 5      //min
 #define DEFAULT_WIFI_RETRY_INTERVAL 5      //min
 #define DEFAULT_WIFI_CONNCHECK_INTERVAL 20 //s
@@ -80,21 +98,21 @@
 #define DEFAULT_HTTP_USER ""
 #define DEFAULT_HTTP_PASS ""
 #define DEFAULT_HTTP_USER_AUTH false
-#define DEFAULT_ENABLE_WEBCONSOLE false
+#define DEFAULT_ENABLE_WEBCONSOLE true
 
 // confMqtt
-#define MQTT_ENABLE true
-#define MQTT_SERVER "mqtt.lan"
+#define MQTT_ENABLE false
+#define MQTT_SERVER ""
 #define MQTT_PORT 1883
 #define MQTT_USER ""
 #define MQTT_PASS ""
-#define MQTT_TOPIC_IN "Test/Thermostat"
-#define MQTT_TOPIC_OUT "Test/Thermostat/stat"
+#define MQTT_TOPIC_IN "Test/WTherm"
+#define MQTT_TOPIC_OUT "Test/WTherm/stat"
 #define MQTT_OUT_RETAIN false
 #define MQTT_OUT_RETAIN_SENSORS false
 #define MQTT_OUT_PUBLISH_INTERVAL 0         // min, 0=only on change
 #define MQTT_OUT_PUBLISH_INTERVAL_SENSORS 5 // min, 0=only on change
-#define MQTT_WILLTOPIC "Test/Thermostat/availability"
+#define MQTT_WILLTOPIC "Test/WTherm/availability"
 #define MQTT_WILLQOS 2
 #define MQTT_WILLRETAIN false
 #define MQTT_WILLMSG "offline"
@@ -120,19 +138,17 @@
 // interval for display updates (if out-temp is active, display will toggle
 // in this interval)
 #define DEFAULT_DISPLAY_INTERVAL 5
-
 #define DEFAULT_DISPLAY_TIMEOUT 30 // display timeout after keypress (illumination)
 #define DEFAULT_PIR_ENABLES_DISPLAY false
 #define DEFAULT_PIR_ENABLES_DISPLAY_PRESET0_ONLY true
 #define DEFAULT_TOGGLING_I_O_TEMPHUM false
 
 // confAdv
-#define DEFAULT_HYSTERESIS 0.2          // hysteresis, normally 0.1 - 0.5
-#define DEFAULT_HEATING_MIN_OFFTIME 120 // minimal time the heating keeps turned off in s
+#define DEFAULT_HYSTERESIS 0.15         // hysteresis, normally 0.1 - 0.3
+#define DEFAULT_HEATING_MIN_OFFTIME 300 // minimal time the heating must keep turned off until it can start again, in s
 
 // correction value for temperature sensor reading
 #define TEMPSENSOR_CORRECTION_VALUE 0.0
-
 #define HUMSENSOR_CORRECTION_VALUE 0 // correction value for humidity sensor reading
 
 // decreases the set temp to overcome further temperature rise when the
@@ -143,9 +159,9 @@
 #define OUTSIDE_TEMP_LABEL "O"
 #define MODE_NAME_0 "off"
 #define MODE_NAME_1 "heat"
-#define PRESET_NAME_0 "none"
-#define PRESET_NAME_1 "reduction1"
-#define PRESET_NAME_2 "reduction2"
+#define PRESET_NAME_0 "Normal"
+#define PRESET_NAME_1 "Reduction 1"
+#define PRESET_NAME_2 "Reduction 2"
 
 // confAdd
 #define OUTTEMP_TOPIC_IN ""
@@ -154,22 +170,29 @@
 #define MQTT_TOPIC_PIR_ON "ON"
 #define MQTT_TOPIC_PIR_OFF "OFF"
 
-// other (not configurable via WebIF)
-#define DEFAULT_SETTEMP_HEATOFF 5.0 // set temperature in OFF mode (freezing guard > 0)
+// confLog
+#define DEFAULT_LOGLEVEL_SERIAL LOGLEVEL_DEBUG
+#define DEFAULT_LOGLEVEL_WEB LOGLEVEL_INFO
+#define DEFAULT_LOGLEVEL_MQTT LOGLEVEL_INFO
+#define DEFAULT_LOGLEVEL_SYSLOG LOGLEVEL_DEBUG // SYSLOG not implemented yet
+#define LOG_WEB_REQUESTS false
+
+// other (not configurable via commands/WebIF)
+#define DEFAULT_SETTEMP_HEATOFF 5.0 // heating target temperature in OFF mode (freezing guard, therefore > 0)
+#define SETTEMP_LOW_MIN 14.0        // minimal configurable temperature for reduction mode
+#define SETTEMP_LOW_MAX 21.5        // maximal configurable temperature for reduction mode
 
 // default initial values
 #define DEFAULT_SETTEMP 21.5
 #define DEFAULT_HEATINGMODE 1
 #define DEFAULT_PRESET 1
 #define DEFAULT_SETTEMP_LOW 20.0  // set temperature in night/low mode
-#define DEFAULT_SETTEMP_LOW2 18.0 // set temperature in night/low mode
+#define DEFAULT_SETTEMP_LOW2 17.0 // set temperature in night/low mode
 
-// default values that can only be configured at compile time / hardware
-// configuration
+// COMPILE TIME SETTINGS
+// default values that can only be configured at compile time / hardware configuration
 #define BUTTON_DEBOUNCE_TIME 120
 #define BUTTON_HOLD_TIME 750
-#define SETTEMP_LOW_MIN 14.0 // minimal configurable temperature for reduction mode
-#define SETTEMP_LOW_MAX 21.5 // maximal configurable temperature for reduction mode
 
 // pin assignments and I2C addresses
 #define PIN_DHTSENSOR 13
@@ -180,13 +203,17 @@
 #define PIN_PIRSENSOR 12
 #define DHTTYPE DHT22 // DHT sensor type
 #define LCDADDR 0x27  // I2C address LCD
-#define LCDCOLS 16
-#define LCDLINES 2
+#define LCDCOLS 16    // LCD cols
+#define LCDLINES 2    // LCD lines
 
 // default logic levels
 #define RELAISONSTATE HIGH
 #define BUTTONONSTATE LOW
 
+// SPIFFS settings
+#define SPIFFS_DBG
+#define SPIFFS_USE_MAGIC
+
 // LOG LEVELS
 #define LOGLEVEL_OFF 0
 #define LOGLEVEL_ERROR 1
@@ -195,13 +222,15 @@
 #define LOGLEVEL_DEBUG 4
 #define LOGLEVEL_VERBOSE 5
 
-#define DEFAULT_LOGLEVEL_SERIAL LOGLEVEL_DEBUG
-#define DEFAULT_LOGLEVEL_WEB LOGLEVEL_DEBUG
-#define DEFAULT_LOGLEVEL_MQTT LOGLEVEL_DEBUG
-#define DEFAULT_LOGLEVEL_SYSLOG LOGLEVEL_DEBUG
-
 // END PRE-COMPILE CONFIGURATION
 
+PROGMEM const char PGMStr_FIRMWARE_NAME[] = FIRMWARE_NAME;
+PROGMEM const char PGMStr_FIRMWARE_VERSION[] = FIRMWARE_VERSION;
+PROGMEM const char PGMStr_FIRMWARE_URL[] = FIRMWARE_URL;
+PROGMEM const char PGMStr_FIRMWARE_COPYRIGHT[] = FIRMWARE_COPYRIGHT;
+PROGMEM const char PGMStr_FIRMWARE_COPYRIGHT_URL[] = FIRMWARE_COPYRIGHT_URL;
+PROGMEM const char PGMStr_FIRMWARE_SHORTNAME[] = FIRMWARE_SHORTNAME;
+
 PROGMEM const char PGMStr_changedTo[] = "changed to";
 PROGMEM const char PGMStr_preset[] = "preset";
 PROGMEM const char PGMStr_heatingMode[] = "heatingMode";
@@ -214,38 +243,49 @@ PROGMEM const char PGMStr_mqttRetainedSave[] = "MQTT retained save";
 PROGMEM const char PGMStr_heating[] = "heating";
 PROGMEM const char PGMStr_thermostat[] = "TSTAT";
 PROGMEM const char PGMStr_WiFi[] = "WiFi";
-PROGMEM const char PGMStr_connectedTo[] = "connected to";
-PROGMEM const char PGMStr_withIP[] = "with IP";
+//PROGMEM const char PGMStr_connectedTo[] = "connected to";
+//PROGMEM const char PGMStr_withIP[] = "with IP";
 PROGMEM const char PGMStr_MQTT[] = "MQTT";
 PROGMEM const char PGMStr_connectedReconnects[] = "connected, reconnects";
 PROGMEM const char PGMStr_connectedFailed[] = "connect FAILED";
 
-const char PGMStr_MQTTStateM4[] PROGMEM = "CONNECTION_TIMEOUT";
-const char PGMStr_MQTTStateM3[] PROGMEM = "CONNECTION_LOST";
-const char PGMStr_MQTTStateM2[] PROGMEM = "CONNECT_FAILED";
-const char PGMStr_MQTTStateM1[] PROGMEM = "DISCONNECTED";
-const char PGMStr_MQTTState0[] PROGMEM = "CONNECTED";
-const char PGMStr_MQTTState1[] PROGMEM = "CONNECT_BAD_PROTOCOL";
-const char PGMStr_MQTTState2[] PROGMEM = "CONNECT_BAD_CLIENT_ID";
-const char PGMStr_MQTTState3[] PROGMEM = "CONNECT_UNAVAILABLE";
-const char PGMStr_MQTTState4[] PROGMEM = "CONNECT_BAD_CREDENTIALS";
-const char PGMStr_MQTTState5[] PROGMEM = "CONNECT_UNAUTHORIZED";
-
-char mqttCurrentStateName[25];
-
+PROGMEM const char compile_date[] = __DATE__ " " __TIME__;
+
+const char PGMStr_confDevWiFi[] PROGMEM = "confDevWiFi";
+const char PGMStr_confWeb[] PROGMEM = "confWeb";
+const char PGMStr_confMqtt[] PROGMEM = "confMqtt";
+const char PGMStr_confBas[] PROGMEM = "confBas";
+const char PGMStr_confAdv[] PROGMEM = "confAdv";
+const char PGMStr_confAdd[] PROGMEM = "confAdd";
+const char PGMStr_confTime[] PROGMEM = "confTime";
+const char PGMStr_confLog[] PROGMEM = "confLog";
+
+//const char PGMStr_delimiter[] PROGMEM = "--------";
+const char PGMStr_MQTTState_DIS[] PROGMEM = "DISABLED";
+const char PGMStr_MQTTState_M4[] PROGMEM = "CONNECTION_TIMEOUT";
+const char PGMStr_MQTTState_M3[] PROGMEM = "CONNECTION_LOST";
+const char PGMStr_MQTTState_M2[] PROGMEM = "CONNECT_FAILED";
+const char PGMStr_MQTTState_M1[] PROGMEM = "DISCONNECTED";
+const char PGMStr_MQTTState_0[] PROGMEM = "CONNECTED";
+const char PGMStr_MQTTState_1[] PROGMEM = "CONNECT_BAD_PROTOCOL";
+const char PGMStr_MQTTState_2[] PROGMEM = "CONNECT_BAD_CLIENT_ID";
+const char PGMStr_MQTTState_3[] PROGMEM = "CONNECT_UNAVAILABLE";
+const char PGMStr_MQTTState_4[] PROGMEM = "CONNECT_BAD_CREDENTIALS";
+const char PGMStr_MQTTState_5[] PROGMEM = "CONNECT_UNAUTHORIZED";
 const char *const PGMStr_MQTTStates[] PROGMEM =
     {
-        PGMStr_MQTTStateM4,
-        PGMStr_MQTTStateM3,
-        PGMStr_MQTTStateM2,
-        PGMStr_MQTTStateM1,
-        PGMStr_MQTTState0,
-        PGMStr_MQTTState1,
-        PGMStr_MQTTState2,
-        PGMStr_MQTTState3,
-        PGMStr_MQTTState4,
-        PGMStr_MQTTState5,
+        PGMStr_MQTTState_M4,
+        PGMStr_MQTTState_M3,
+        PGMStr_MQTTState_M2,
+        PGMStr_MQTTState_M1,
+        PGMStr_MQTTState_0,
+        PGMStr_MQTTState_1,
+        PGMStr_MQTTState_2,
+        PGMStr_MQTTState_3,
+        PGMStr_MQTTState_4,
+        PGMStr_MQTTState_5,
 };
+char mqttCurrentStateName[25];
 
 //---------------------------------------------------------------------------------------------------------------------------------------------
 
@@ -254,18 +294,21 @@ PushButton buttonMinus = PushButton(PIN_BUTTON_MINUS, ENABLE_INTERNAL_PULLUP);
 PushButton buttonMode = PushButton(PIN_BUTTON_MODE, ENABLE_INTERNAL_PULLUP);
 PushButton pirSensor = PushButton(PIN_PIRSENSOR, PRESSED_WHEN_HIGH);
 
-bool serialdebug = DEBUG_SERIAL;
-bool mqttdebug = DEBUG_MQTT;
-
 bool WifiInApMode = false;
 unsigned long WifiApModeStartedAt;
 
-// time
+#ifdef ENABLE_FEATURE_PW_ENCRYPTION
+char encKey[] = PW_ENCRYPTION_KEY;
+#endif
+bool confEncryptionEnabled = false;
+
+#ifdef ENABLE_FEATURE_NTP_TIME
 struct tm lt; // http://www.cplusplus.com/reference/ctime/tm/
-const char *const PROGMEM dayNames[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
-const char *const PROGMEM dayShortNames[] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"};
-const char *const PROGMEM monthNames[] = {"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
-const char *const PROGMEM monthShortNames[] = {"Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"};
+//const char *const PROGMEM dayNames[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
+//const char *const PROGMEM dayShortNames[] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"};
+//const char *const PROGMEM monthNames[] = {"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
+//const char *const PROGMEM monthShortNames[] = {"Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"};
+#endif
 
 // config variables - do not change here!
 
@@ -297,7 +340,8 @@ struct confDataWeb
   char http_pass1[31];
   char http_user2[31];
   char http_pass2[31];
-  bool enableConsole;
+  bool wConsole;
+  bool wsConsole;
 } confWeb;
 
 // confMqtt
@@ -390,8 +434,21 @@ struct confDataLog
   uint8_t logLevelWeb;
   uint8_t logLevelMqtt;
   uint8_t logLevelSyslog;
+  bool logWebRequests;
 } confLog;
 
+// Uptime
+struct sysUptimeStruct
+{
+  unsigned int day = 0;
+  unsigned int hour = 0;
+  unsigned int min = 0;
+  unsigned int sec = 0;
+  unsigned int highMillis = 0;
+  unsigned int rollover = 0;
+  char uptimeStr[16];
+} sysUptime;
+
 bool mqtt_tempDisabled_credentialError = false;
 
 char mqtt_topic_in_cmd[61];
@@ -450,11 +507,11 @@ unsigned long lastMeasure = 0;       // millis of last temp/hum measurement
 unsigned long lastDisplayUpdate = 0; // millis of last display update
 unsigned long lastDisplayToggle = 0; // millis of last display toggle
 unsigned long lastTempUpdate = 0;    // last update time of DHT reading
-char msg[50];                        // buffer MQTT in payload
-char topic[50];                      // buffer MQTT in topic
-bool displayActive = false;          // gets true when button is pressed. display light
-                                     // gets switched on until timeout. button actions
-                                     // are only performed while display is active
+//char msg[101];                       // buffer MQTT in payload
+//char topic[70];                      // buffer MQTT in topic
+bool displayActive = false; // gets true when button is pressed. display light
+                            // gets switched on until timeout. button actions
+                            // are only performed while display is active
 bool PIRSensorOn = false;
 unsigned long heatingOnTime, heatingOffTime;
 bool config_was_changed = false;
@@ -465,10 +522,13 @@ unsigned long lastUpdate_setTempLow2 = 0; // set to millis() every time setTemp
 unsigned long lastUpdate_heatingMode = 0; // set to millis() every time heatingMode value is changed
 unsigned long lastUpdate_preset = 0;      // set to millis() every time preset value is changed
 
-char cmdPayload[101];            // buffer for commands
-bool cmdInQueue = false;         // command is queued and will be processed next loop() run
-bool saveConfigToFlash = false;  // conf is saved in next loop() run
-bool saveConfig2ToFlash = false; // conf2 is saved in next loop() run
+char cmdPayload[101];    // buffer for commands
+bool cmdInQueue = false; // command is queued and will be processed next loop() run
+
+// not used any more, now triggered directly
+//bool saveConfigToFlash = false;  // conf is saved in next loop() run
+//bool saveConfig2ToFlash = false; // conf2 is saved in next loop() run
+// ----
 
 uint16_t saveValuesTimeout = 5000;
 unsigned long lastValueChange;       // is set to millis() whenever setTemp value
@@ -505,51 +565,64 @@ bool pendingPresetToggle = false;
 bool updateDisplayImmediately = false;
 uint8_t pendingPreset;
 char pendingPresetName[15];
-// unsigned long pendingPreset_millis = 0;
-// int pendingPreset_timeout = 2000;
 
 bool displayShowLine2OverlayMsg = false;
 
-// build Uptime String (unnecessary, i know ;) )
-uint16_t sysUptime_days = 0;
-uint16_t sysUptime_hours = 0;
-uint16_t sysUptime_mins = 0;
-char uptimeStr[15];
+// if command "debugmode 1" is called...
+bool sysInfoEverySecond = false;
+
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_BUFFERED
+char webLogBuffer[4096];
+unsigned int webLogBuffer_index = 0;
+#endif
+
+// END global variables
 
 DHT dht(PIN_DHTSENSOR, DHTTYPE);
 LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDLINES);
 
 WiFiClient espClient;
 
-void mqttCallback(char *topic, byte *payload, uint16_t length);
 PubSubClient mqttclient(espClient);
 
 ESP8266WebServer httpServer(80);
+
+// WebSocketsServer
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
 WebSocketsServer webSocket(81);
+unsigned long int wsValidSessionId = 0;
+#endif
+
 DNSServer dnsServer;
 PersWiFiManager persWM(httpServer, dnsServer);
 
+#ifdef ENABLE_FEATURE_HTTP_UPDATER
 ESP8266HTTPUpdateServer httpUpdater;
+#endif
 
-// WebSocketsServer
-unsigned long int wsValidSessionId = 0;
-
+// FUNCTION PROTOTYPES
+#ifdef ENABLE_FEATURE_NTP_TIME
 void updateTime();
 bool setupTime();
-void updateTimeFromNTP();
-
+void syncClock(bool force = false);
+#endif
+char *getUptimeStr(bool includeSeconds = false);
 void sendLog(const char *msg, uint8_t loglevel = 1);
 void sendLog(const __FlashStringHelper *msg, uint8_t loglevel = 1);
+void mqttCallback(char *topic, byte *payload, uint16_t length);
+char *getTimeStringFromSeconds(unsigned int inSeconds);
+// END - FUNCTION PROTOTYPES
 
+// MAIN FUNCTIONS
 void setup()
 {
   Serial.begin(115200);
   delay(50);
   Serial.println();
-  Serial.print(FIRMWARE_NAME);
-  Serial.print(" v");
-  Serial.print(FIRMWARE_VERSION);
-  Serial.println(" starting...");
+  Serial.print(PGMStr_FIRMWARE_NAME);
+  Serial.print(F(" v"));
+  Serial.print(PGMStr_FIRMWARE_VERSION);
+  Serial.println(F(" starting..."));
 
   pinMode(PIN_RELAIS, OUTPUT);
   digitalWrite(PIN_RELAIS, !RELAISONSTATE);
@@ -557,16 +630,12 @@ void setup()
   setupInputsButtons();
 
   // set conf default values
-
-  // set initial deviceName
-  createDeviceName();
-
   loadConf_defaults();
 
   //if (serialdebug)
   //  Serial.println("default config values loaded..");
 
-  sendLog(F("DEV: default config values loaded."), LOGLEVEL_INFO);
+  sendLog(F("CONF: default config loaded."), LOGLEVEL_INFO);
 
   initDisplay();
 
@@ -583,7 +652,11 @@ void setup()
 
   SPIFFS_formatIfIsnt();
 
-  SPIFFS_listFiles();
+  //SPIFFS_listFiles();
+
+#ifdef ENABLE_FEATURE_PW_ENCRYPTION
+  confCheckEncrypted();
+#endif
 
   loadConf_all();
   loadSavedValues();
@@ -611,13 +684,18 @@ void setup()
     //Serial.print(WiFi.SSID());
     //Serial.print(F("' with IP: "));
     //Serial.println(WiFi.localIP());
-    char buf[60];
-    sprintf(buf, "%s: %s '%s' %s: '%s'", PGMStr_WiFi, PGMStr_connectedTo, WiFi.SSID().c_str(), PGMStr_withIP, WiFi.localIP().toString().c_str());
-    sendLog(buf, LOGLEVEL_INFO);
+    //char buf[60];
+    //sprintf(buf, "%s: %s '%s' %s: '%s'", PGMStr_WiFi, PGMStr_connectedTo, WiFi.SSID().c_str(), PGMStr_withIP, WiFi.localIP().toString().c_str());
+    //sendLog(buf, LOGLEVEL_INFO);
+    printIpcfg();
 
     WifiInApMode = false;
+
+#ifdef ENABLE_FEATURE_NTP_TIME
     if (confTime.ntpEnable)
       setupTime();
+#endif
+
     displayShowWifiConnected();
   });
   //...or AP mode is started
@@ -659,9 +737,15 @@ void setup()
   //Serial.println(confDevWiFi.WiFiAPModeSSID);
 
   if (strlen(confDevWiFi.WiFiAPModePassword) < 5)
+  {
     persWM.setApCredentials(confDevWiFi.WiFiAPModeSSID);
+    //sendLog("WIFI-AP: open network");
+  }
   else
+  {
     persWM.setApCredentials(confDevWiFi.WiFiAPModeSSID, confDevWiFi.WiFiAPModePassword);
+    //sendLog("WIFI-AP: with password");
+  }
 
   //Serial.print(F("WiFi: SSID 1: ")); Serial.println(confDevWiFi.WiFiSSID1); //Serial.print("', PW: '"); Serial.print(confDevWiFi.WiFiPW1); Serial.println("'");
   //Serial.print(F("WiFi: SSID 2: ")); Serial.println(confDevWiFi.WiFiSSID2); //Serial.print("', PW: '"); Serial.print(confDevWiFi.WiFiPW2); Serial.println("'");
@@ -683,17 +767,16 @@ void setup()
 
   httpServerInit();
 
-  if (confWeb.enableConsole)
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+  if (confWeb.wsConsole)
     startWebSocketServer();
+#endif
 
   if (confMqtt.mqtt_enable)
   {
     mqttPrepareSubscribeTopics();
     mqttClientInit();
   }
-
-  buildUptimeString();
-
   sendLog(F("DEV: setup complete."), LOGLEVEL_INFO);
 } // void setup
 
@@ -737,7 +820,8 @@ void loop()
     updateDisplay();
   }
 
-  if (confWeb.enableConsole)
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+  if (confWeb.wsConsole)
   {
     if (WiFi.status() == WL_CONNECTED)
     {
@@ -748,5 +832,6 @@ void loop()
       webSocket.disconnect();
     }
   }
+#endif
 
 } // void loop

+ 0 - 199
src/WiFiThermostat/commands.ino

@@ -1,199 +0,0 @@
-
-#define SER_INPUT_SIZE 70
-char serBuffer[SER_INPUT_SIZE + 1];
-int serBufferCount;
-
-void serialEvent() {
-  char ch = Serial.read();
-  serBuffer[serBufferCount] = ch;
-  serBufferCount++;
-  if (ch == 13 || ch == 10) { // ASCII code 13 = "CR",  10 = "LF"
-    serBuffer[serBufferCount - 1] = '\0';
-#ifdef DEBUG_VERBOSE
-    Serial.print("serial cmd: '");
-    Serial.print(serBuffer);
-    Serial.println("'");
-#endif
-    strlcpy(cmdPayload, serBuffer, sizeof(cmdPayload));
-    cmdInQueue = true;
-    evalCmd();
-    serBufferCount = 0;
-  }
-}
-
-void evalCmd() {
-  if (cmdInQueue) {
-    //Serial.print("cmdPayload: ");
-    //Serial.println(cmdPayload);
-
-    if (strncmp(cmdPayload, "loadconf", 8) == 0) {
-      loadConf_all();
-    }
-
-
-
-    else if (strncmp(cmdPayload, "set ", 4) == 0) {
-      char buf[81];
-      char setconfCmd[16];
-
-      uint8_t len = strlen(cmdPayload) - 4;
-      for (unsigned char i = 0; i < len; i++) {
-        if (i < (sizeof(buf)-1)) buf[i] = cmdPayload[i + 4];
-      }
-      if (len <= (sizeof(buf)-1)) buf[len] = '\0';
-      else buf[(sizeof(buf)-1)] = '\0';
-
-#ifdef DEBUG_VERBOSE
-      Serial.print("Buf: ");
-      Serial.println(buf);
-#endif
-
-      bool cmdNoPayload = false;
-      uint8_t setconfCmdLen = 0;
-      for (unsigned char i = 0; i < len; i++) {
-        //if (buf[i] == 32 || buf[i] == '\0') break; // if SPACE command name is finished, if \0 command parameter is missing
-        if (buf[i] == 32 || buf[i] == 61 || buf[i] == 58) break; // if SPACE(32) or =(61) or :(58) command name is finished
-        else if (buf[i] == 0 || buf[i] == 10 || buf[i] == 13) { // if \0, LF (10) or CR (13) command parameter is missing
-          cmdNoPayload = true;
-          break;
-        }
-        setconfCmd[i] = buf[i];
-        setconfCmdLen++;
-      }
-      setconfCmd[setconfCmdLen] = '\0';
-      yield();
-
-      if (setconfCmdLen == len) cmdNoPayload = true;
-
-#ifdef DEBUG_VERBOSE
-      Serial.print("setconfCmd: '");
-      Serial.print(setconfCmd);
-      Serial.print("'");
-#endif
-
-      if ( cmdNoPayload ) {
-#ifdef DEBUG_VERBOSE
-        Serial.println(", no payload, displaying current value");
-#endif
-        //getConfig(setconfCmd);
-      }
-      else {
-        char setconfPayload[62];
-#ifdef DEBUG_VERBOSE
-        Serial.println();
-#endif
-        int setconfPayloadLen = 0;
-        for (int i = 0; i < len; i++) {
-          char c = buf[i + setconfCmdLen + 1];
-          if (c == 0 || c == 10 || c == 13) break; // if \0, LF (10) or CR (13) command parameter is finished
-          setconfPayload[i] = c;
-          setconfPayloadLen++;
-        }
-        setconfPayload[setconfPayloadLen] = '\0';
-
-#ifdef DEBUG_VERBOSE
-        Serial.print("setconfPayload: '");
-        Serial.print(setconfPayload);
-        Serial.println("'");
-#endif
-        setConfig(setconfCmd, setconfPayload);
-      }
-    }
-
-
-
-    else if (strncmp(cmdPayload, "get ", 4) == 0) {
-      char buf[81];
-      char setconfCmd[16];
-
-      uint8_t len = strlen(cmdPayload) - 4;
-      for (int i = 0; i < len; i++) {
-        if (i < 81) buf[i] = cmdPayload[i + 4];
-      }
-      if (len <= (sizeof(buf)-1)) buf[len] = '\0';
-      else buf[(sizeof(buf)-1)] = '\0';
-
-#ifdef DEBUG_VERBOSE
-      Serial.print("Buf: ");
-      Serial.println(buf);
-#endif
-      
-      uint8_t setconfCmdLen = 0;
-      for (int i = 0; i < len; i++) {
-        //if (buf[i] == 32 || buf[i] == '\0') break; // if SPACE command name is finished, if \0 command parameter is missing
-        if (buf[i] == 32 || buf[i] == 61 || buf[i] == 58) break; // if SPACE(32) or =(61) or :(58) command name is finished
-        else if (buf[i] == 0 || buf[i] == 10 || buf[i] == 13) { // if \0, LF (10) or CR (13) command parameter is missing
-          break;
-        }
-        setconfCmd[i] = buf[i];
-        setconfCmdLen++;
-      }
-      setconfCmd[setconfCmdLen] = '\0';
-      yield();
-#ifdef DEBUG_VERBOSE
-      Serial.print("setconfCmd: '");
-      Serial.print(setconfCmd);
-      Serial.println("'");
-#endif
-      //getConfig(setconfCmd);
-    }
-
-
-
-    else if (strncmp(cmdPayload, "restart", 7) == 0) {
-      Serial.print("restarting...");
-      delay(100);
-      ESP.restart();
-    }
-
-
-
-    else if (strncmp(cmdPayload, "save", 4) == 0) {
-      //saveConfig();
-      
-      //saveConfig2();
-      saveConfigDevWiFi();
-      yield();
-      saveConfigWeb();
-      yield();
-      saveConfigMqtt();
-      yield();
-      saveConfigBas();
-      yield();
-      saveConfigAdv();
-      yield();
-      saveConfigAdd();
-      yield();
-      
-
-      saveSetTemp();
-      yield();
-      saveSetTempLow();
-      yield();
-      saveSetTempLow2();
-      yield();
-      saveHeatingMode();
-      yield();
-            
-      //Serial.println("saved config to SPIFFS");
-      sendLog("saved config to SPIFFS");
-      //Serial.println("reloading config to check...");
-      //loadConfig();
-      //yield();
-      //loadConfig2();
-      //yield();
-    }
-    else if (strncmp(cmdPayload, "getconf", 7) == 0) {
-      //printConfig();
-      //printConfig2();
-      printConfigWeb();
-      printConfigMqtt();
-    }
-    else if (strncmp(cmdPayload, "delconf", 7) == 0) {
-      deleteConfig();
-    }
-
-
-    cmdInQueue = false;
-  }
-}

+ 0 - 20
src/WiFiThermostat/commonFunctions.ino

@@ -1,20 +0,0 @@
-/*#include <string.h>
-#include <ctype.h>*/
-char *strlwr(char *str)
-{
-  unsigned char *p = (unsigned char *)str;
-  while (*p)
-  {
-    *p = tolower((unsigned char)*p);
-    p++;
-  }
-  return str;
-}
-
-double round2(double value) {
-   return round(value * 100) / 100.0;
-}
-
-double round1(double value) {
-   return round(value * 10) / 10.0;
-}

+ 0 - 1476
src/WiFiThermostat/httpServer.ino

@@ -1,1476 +0,0 @@
-
-#include "html.h"
-#include "html_conf.h"
-#include "html_confAdd.h"
-#include "html_confAdv.h"
-#include "html_confBas.h"
-#include "html_confDevWiFi.h"
-#include "html_confMqtt.h"
-#include "html_confWeb.h"
-#include "html_confTime.h"
-#include "html_confLog.h"
-#include "html_main.h"
-#include "html_redTemps.h"
-#include "html_console.h"
-
-void httpServerHandleMainPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_main_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_main_body);
-  if (httpIsAuthenticatedAdmin()) {
-    httpServer.sendContent_P(html_main_body_adminonly);
-    if(confWeb.enableConsole) httpServer.sendContent_P(html_main_body_adminonly_console);
-  }
-  httpServer.sendContent_P(html_main_body2);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleRedTempsPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_redTemps_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_redTemps_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_conf_body);
-  if(confWeb.enableConsole) httpServer.sendContent_P(html_conf_body_console);
-  httpServer.sendContent_P(html_conf_body_end);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfWebPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_confweb_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_confweb_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfMqttPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_confmqtt_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_confmqtt_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfDevWiFiPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_confDevWiFi_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_confDevWiFi_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfBasPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_confbas_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_confbas_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfAdvPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_confadv_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_confadv_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfAddPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_confadd_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_confadd_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfTimePage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_conftime_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_conftime_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfLogPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_conflog_script);
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag_jsinit);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_conflog_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConsolePage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_console_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfSavedPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_confsaved_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleConfSavedRestartPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_confsavedrestart_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleRestartPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_restarting_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerHandleClearconfPage() {
-  httpServerSendHtmlHeadChunked();
-  httpServer.sendContent_P(html_head_end);
-  httpServer.sendContent_P(html_bodytag);
-  httpServerSendHtmlBodyPageheadChunked();
-  httpServer.sendContent_P(html_clearconf_body);
-  httpServerSendHtmlFooterChunked();
-}
-
-void httpServerSendHtmlHeadChunked() {
-  httpServer.setContentLength(CONTENT_LENGTH_UNKNOWN);   //Enable Chunked Transfer
-  httpServer.send(200, "text/html", html_head_part1);
-  httpServer.sendContent(FIRMWARE_NAME);
-  httpServer.sendContent(" - ");
-  httpServer.sendContent(confDevWiFi.deviceName);
-  httpServer.sendContent_P(html_head_part2);
-}
-
-void httpServerSendHtmlBodyPageheadChunked() {
-  httpServer.sendContent_P(html_body_pagehead_part1);
-  httpServer.sendContent(FIRMWARE_NAME);
-  httpServer.sendContent(" - ");
-  httpServer.sendContent(confDevWiFi.deviceName);
-  httpServer.sendContent_P(html_body_pagehead_part2);
-  if(config_was_changed) httpServer.sendContent_P(html_body_pagehead_confchangednote);
-}
-
-void httpServerSendHtmlFooterChunked() {
-  httpServer.sendContent_P(html_footer1);
-  httpServer.sendContent("<a href='");
-  httpServer.sendContent(FIRMWARE_URL);
-  httpServer.sendContent("' target='_blank' style='color:#AAA;'>");
-  httpServer.sendContent(FIRMWARE_NAME);
-  httpServer.sendContent("</a> v");
-  httpServer.sendContent(FIRMWARE_VERSION);
-#ifdef DEBUGMODE
-  httpServer.sendContent("&nbsp;<span style='color:red;font-weight:bold;'>DEBUG</span>");
-#endif
-  httpServer.sendContent(" by <a href='");
-  httpServer.sendContent(FIRMWARE_COPYRIGHT_URL);
-  httpServer.sendContent("' target='_blank' style='color:#AAA;'>");
-  httpServer.sendContent(FIRMWARE_COPYRIGHT);
-  httpServer.sendContent("</a>");
-  httpServer.sendContent_P(html_footer2);
-  httpServer.sendContent("");
-  httpServer.client().stop();
-}
-
-boolean httpIsAuthenticated() {
-  if (confWeb.http_user_auth) {
-    boolean useAuth = false;
-    boolean isAuthenticated = false;
-    // user authentication enabled - only allow access without authentication if no admin credentials are set
-    // or if user1 credentials are empty
-    if ((strlen(confWeb.http_user) > 0 && strlen(confWeb.http_pass) > 0) || (strlen(confWeb.http_user1) > 0 && strlen(confWeb.http_pass1) > 0) || (strlen(confWeb.http_user2) > 0 && strlen(confWeb.http_pass2) > 0)) useAuth = true;
-    if (useAuth) {
-      // allow access if one set of valid credentials are given
-      if ((strlen(confWeb.http_user) > 0 && strlen(confWeb.http_pass) > 0)) {
-        if (httpServer.authenticate(confWeb.http_user, confWeb.http_pass)) isAuthenticated = true;
-      }
-      if ((strlen(confWeb.http_user1) > 0 && strlen(confWeb.http_pass1) > 0)) {
-        if (httpServer.authenticate(confWeb.http_user1, confWeb.http_pass1)) isAuthenticated = true;
-      }
-      if ((strlen(confWeb.http_user2) > 0 && strlen(confWeb.http_pass2) > 0)) {
-        if (httpServer.authenticate(confWeb.http_user2, confWeb.http_pass2)) isAuthenticated = true;
-      }
-      // also allow access if admin credentials are set but user1 credentials are empty and user-authentication is enabled
-      if ((strlen(confWeb.http_user1) == 0 && strlen(confWeb.http_pass1) == 0)) { 
-        isAuthenticated = true;
-      }
-      return isAuthenticated;
-    }
-    // allow access if all credentials are empty
-    else return true;
-  }
-  // user authentication disabled - only allow access without password if no admin credentials are set
-  else {  
-    if ((strlen(confWeb.http_user) > 0 && strlen(confWeb.http_pass) > 0)) {
-      if (httpServer.authenticate(confWeb.http_user, confWeb.http_pass)) return true;
-      else return false;
-    }
-    else return true;
-  }
-}
-
-boolean httpIsAuthenticatedAdmin() {
-  boolean auth = false;
-  if ((strlen(confWeb.http_user) > 0 && strlen(confWeb.http_pass) > 0)) auth = true;
-  if (auth) {
-    if (!httpServer.authenticate(confWeb.http_user, confWeb.http_pass)) return false;
-    else return true;
-  }
-  else return true;
-}
-
-void httpServerHandleNotFound() {
-  httpServer.send(404, "text/plain", "404 NOT FOUND");
-}
-
-void httpSendUnauthorized() {
-  httpServer.send (401, "text/plain", "UNAUTHORIZED");
-}
-
-void httpSend200OK() {
-  httpServer.send (200, "text/plain", "OK");
-}
-
-boolean httpCheckToken() {
-  if (confWeb.http_token[0] != '\0') { // dont accept empty token
-    if (httpServer.hasArg("token")) {
-      char buf[20];
-      httpServer.arg("token").toCharArray(buf, 20);
-      if (strcmp(buf, confWeb.http_token) == 0) return true;
-      else return false;
-    }
-    else return false;
-  }
-  else return false;
-}
-
-void httpServerInit() {
-  httpServer.on("/style.css", []() {
-    httpServer.sendHeader("cache-control", "max-age=86400", false);
-    httpServer.send_P(200, "text/css", html_stylesheet);
-  });
-
-  httpServer.on("/wsapp.js", []() {
-    httpServer.sendHeader("cache-control", "max-age=86400", false);
-    httpServer.send_P(200, "text/javascript", js_wsapp);
-  });
-
-  httpServer.on("/api", []() {
-    if (!httpIsAuthenticated()) return httpServer.requestAuthentication();
-    else {
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /api (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-      //sendLog("WEB: /api", LOGLEVEL_INFO);
-      if (httpServer.hasArg("BtnPlus")) {
-        setTempStepUp();
-        sendLog(F("WEB: Btn +"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnMinus")) {
-        setTempStepDown();
-        sendLog(F("WEB: Btn -"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnPset0")) {
-        setPresetTo(0);
-        sendLog(F("WEB: Btn PSet0"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnPset1")) {
-        setPresetTo(1);
-        sendLog(F("WEB: Btn PSet1"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnPset2")) {
-        setPresetTo(2);
-        sendLog(F("WEB: Btn PSet2"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnOn")) {
-        setHeatingmodeTo(1);
-        sendLog(F("WEB: Btn ON"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnOff")) {
-        setHeatingmodeTo(0);
-        sendLog(F("WEB: Btn OFF"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnL1Plus")) {
-        setTempLowStepUp();
-        sendLog(F("WEB: Btn L1+"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnL1Minus")) {
-        setTempLowStepDown();
-        sendLog(F("WEB: Btn L1-"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnL2Plus")) {
-        setTempLow2StepUp();
-        sendLog(F("WEB: Btn L2+"), LOGLEVEL_INFO);
-      } //if
-      if (httpServer.hasArg("BtnL2Minus")) {
-        setTempLow2StepDown();
-        sendLog(F("WEB: Btn L2-"), LOGLEVEL_INFO);
-      } //if
-
-      if (httpServer.hasArg("setTemp")) {
-        sendLog(F("WEB: api?setTemp"), LOGLEVEL_INFO);
-        char bufVal[20];
-        httpServer.arg("setTemp").toCharArray(bufVal, 20);
-        float valueFloat = round(atof(bufVal) * 2.0) / 2.0;
-        setTempTo(valueFloat);
-      }
-
-      if (httpServer.hasArg("setMode")) {
-        sendLog(F("WEB: api?setMode"), LOGLEVEL_INFO);
-        char bufVal[20];
-        httpServer.arg("setMode").toCharArray(bufVal, 20);
-        int valueInt = atoi(bufVal);
-        if (valueInt >= 0 && valueInt <= 1) setHeatingmodeTo(valueInt);
-      }
-
-      if (httpServer.hasArg("setPreset")) {
-        sendLog(F("WEB: api?setPreset"), LOGLEVEL_INFO);
-        char bufVal[20];
-        httpServer.arg("setPreset").toCharArray(bufVal, 20);
-        int valueInt = atoi(bufVal);
-        if (valueInt >= 0 && valueInt <= 2) setPresetTo(valueInt);
-      }
-
-      //char ch_currTemp[6];
-      //char ch_currSetTemp[6];
-      //dtostrf(currTemp, 1, 1, ch_currTemp );
-      //dtostrf(setTemp, 1, 1, ch_currSetTemp );
-
-      //build json object of program data
-      StaticJsonDocument<700> json;
-
-      json["devname"] = confDevWiFi.deviceName;
-      json["ssid"] = WiFi.SSID();
-      json["WiFiNum"] = persWM.getActiveWiFiNum();
-      json["uptime"] = uptimeStr;
-      //json["uptime"] = NTP.getUptimeString();
-
-      if(confTime.ntpEnable) {
-        char buf[13];
-        updateTime();
-        strftime(buf, sizeof(buf), "%H:%M", &lt);
-        json["time"] = buf;
-        strftime(buf, sizeof(buf), "%d.%m.%Y", &lt);
-        json["date"] = buf;
-      }
-      json["freeheap"] = ESP.getFreeHeap();
-
-      mqtt_updateCurrentStateName();
-      json["mqttstate"] = mqttCurrentStateName;
-      //if (mqttclient.state() == -4) json["mqttstate"] = "CONNECTION_TIMEOUT";
-      //else if (mqttclient.state() == -3) json["mqttstate"] = "CONNECTION_LOST";
-      //else if (mqttclient.state() == -2) json["mqttstate"] = "CONNECT_FAILED";
-      //else if (mqttclient.state() == -1) json["mqttstate"] = "DISCONNECTED";
-      //else if (mqttclient.state() == 0) json["mqttstate"] = "CONNECTED";
-      //else if (mqttclient.state() == 1) json["mqttstate"] = "CONNECT_BAD_PROTOCOL";
-      //else if (mqttclient.state() == 2) json["mqttstate"] = "CONNECT_BAD_CLIENT_ID";
-      //else if (mqttclient.state() == 3) json["mqttstate"] = "CONNECT_UNAVAILABLE";
-      //else if (mqttclient.state() == 4) json["mqttstate"] = "CONNECT_BAD_CREDENTIALS";
-      //else if (mqttclient.state() == 5) json["mqttstate"] = "CONNECT_UNAUTHORIZED";
-      //if (mqttclient.state() == -4) json["mqttstate"] = PGMStr_MQTTStateM4;
-      //else if (mqttclient.state() == -3) json["mqttstate"] = PGMStr_MQTTStateM3;
-      //else if (mqttclient.state() == -2) json["mqttstate"] = PGMStr_MQTTStateM2;
-      //else if (mqttclient.state() == -1) json["mqttstate"] = PGMStr_MQTTStateM1;
-      //else if (mqttclient.state() == 0) json["mqttstate"] = PGMStr_MQTTState0;
-      //else if (mqttclient.state() == 1) json["mqttstate"] = PGMStr_MQTTState1;
-      //else if (mqttclient.state() == 2) json["mqttstate"] = PGMStr_MQTTState2;
-      //else if (mqttclient.state() == 3) json["mqttstate"] = PGMStr_MQTTState3;
-      //else if (mqttclient.state() == 4) json["mqttstate"] = PGMStr_MQTTState4;
-      //else if (mqttclient.state() == 5) json["mqttstate"] = PGMStr_MQTTState5;
-
-      json["mqtthost"] = confMqtt.mqtt_server;
-
-      if (mqttReconnects < 1) json["mqttreconn"] = mqttReconnects;
-      else json["mqttreconn"] = mqttReconnects - 1;
-
-      json["setTemp"] = setTemp;
-      json["currSetTemp"] = currSetTemp;
-      json["temp"] = round1(currTemp);
-      json["hum"] = int(currHum);
-      json["heating"] = turnHeatingOn;
-      json["mode"] = heatingMode;
-      json["modeName"] = currentModeName;
-      json["pset"] = preset;
-      json["psetName"] = currentPresetName;
-      json["psetName0"] = confAdv.psetName0;
-      json["psetName1"] = confAdv.psetName1;
-      json["psetName2"] = confAdv.psetName2;
-      json["tempLow"] = setTempLow;
-      json["tempLow2"] = setTempLow2;
-      json["outTemp"] = round1(outTemp);
-      json["outHum"] = outHum;
-
-      char jsonchar[500];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /api
-
-  //httpServer.on("/setTemp", []() {
-  //  if ( httpIsAuthenticated() || (!httpIsAuthenticated() && httpCheckToken()) ) {
-  //    //Serial.println("web triggered setTemp");
-  //    sendLog(F("WEB: /setTemp"), LOGLEVEL_INFO);
-  //    if (httpServer.hasArg("value")) {
-  //      char bufVal[20];
-  //      httpServer.arg("value").toCharArray(bufVal, 20);
-  //      float valueFloat = round(atof(bufVal) * 2.0) / 2.0;
-  //      setTempTo(valueFloat);
-  //      httpSend200OK();
-  //    }
-  //  } //if
-  //  else httpSendUnauthorized();
-  //});
-
-  //httpServer.on("/setMode", []() {
-  //  if ( httpIsAuthenticated() || (!httpIsAuthenticated() && httpCheckToken()) ) {
-  //    //Serial.println("web triggered setMode");
-  //    sendLog(F("WEB: /setMode"), LOGLEVEL_INFO);
-  //    if (httpServer.hasArg("value")) {
-  //      char bufVal[20];
-  //      httpServer.arg("value").toCharArray(bufVal, 20);
-  //      int valueInt = atoi(bufVal);
-  //      if (valueInt >= 0 && valueInt <= 1) setHeatingmodeTo(valueInt);
-  //      httpSend200OK();
-  //    }
-  //  } //if
-  //  else httpSendUnauthorized();
-  //});
-
-  //httpServer.on("/setPreset", []() {
-  //  if ( httpIsAuthenticated() || (!httpIsAuthenticated() && httpCheckToken()) ) {
-  //    //Serial.println("web triggered setPreset");
-  //    sendLog(F("WEB: /setPreset"), LOGLEVEL_INFO);
-  //    if (httpServer.hasArg("value")) {
-  //      char bufVal[20];
-  //      httpServer.arg("value").toCharArray(bufVal, 20);
-  //      int valueInt = atoi(bufVal);
-  //      if (valueInt >= 0 && valueInt <= 2) setPresetTo(valueInt);
-  //      httpSend200OK();
-  //    }
-  //  } //if
-  //  else httpSendUnauthorized();
-  //});
-
-  httpServer.on("/confDataWeb", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //Serial.println("httpServer.on /confdata");
-      //sendLog("WEB: /confDataWeb", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confDataWeb (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      StaticJsonDocument<1000> json;
-
-      json["apiToken"] = confWeb.http_token;
-      json["httpUA"] =  confWeb.http_user;
-      //json["httpPA"] =  confWeb.http_pass;
-      if(strlen(confWeb.http_pass) > 0) json["httpPA"] = "****";
-      else json["httpPA"] = "";
-
-      if (confWeb.http_user_auth) json["httpAuth"] = 1;
-      else json["httpAuth"] = 0;
-
-      json["httpU1"] =  confWeb.http_user1;
-      //json["httpP1"] =  confWeb.http_pass1;
-      if(strlen(confWeb.http_pass1) > 0) json["httpP1"] = "****";
-      else json["httpP1"] = "";
-      json["httpU2"] =  confWeb.http_user2;
-      //json["httpP2"] =  confWeb.http_pass2;
-      if(strlen(confWeb.http_pass2) > 0) json["httpP2"] = "****";
-      else json["httpP2"] = "";
-
-      if (confWeb.enableConsole) json["enableConsole"] = 1;
-      else json["enableConsole"] = 0;
-
-      yield();
-
-      char jsonchar[1000];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /confdweb
-
-
-
-  httpServer.on("/confDataMqtt", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //sendLog("WEB: /confDataMqtt", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confDataMqtt (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      StaticJsonDocument<1000> json;
-
-      if (confMqtt.mqtt_enable) json["mqttEnable"] = 1;
-      else json["mqttEnable"] = 0;
-
-      json["mqttHost"] = confMqtt.mqtt_server;
-      json["mqttPort"] = confMqtt.mqtt_port;
-      json["mqttUser"] =  confMqtt.mqtt_user;
-      
-      //json["mqttPass"] =  confMqtt.mqtt_pass;
-      if(strlen(confMqtt.mqtt_pass) > 0) json["mqttPass"] = "****";
-      else json["mqttPass"] = "";
-
-      json["inTop"] = confMqtt.mqtt_topic_in;
-      json["outTop"] = confMqtt.mqtt_topic_out;
-
-      if (confMqtt.mqtt_outRetain) json["outRet"] = 1;
-      else json["outRet"] = 0;
-      if (confMqtt.mqtt_outRetain_sensors) json["outRetSens"] = 1;
-      else json["outRetSens"] = 0;
-
-      json["outPubInt"] = confMqtt.mqtt_outPubInterval;
-      json["outPubIntSens"] = confMqtt.mqtt_outPubInterval_sensors;
-
-      json["willTop"] = confMqtt.mqtt_willTopic;
-      json["willQos"] = confMqtt.mqtt_willQos;
-
-      if (confMqtt.mqtt_willRetain) json["willRet"] = 1;
-      else json["willRet"] = 0;
-
-      json["willMsg"] = confMqtt.mqtt_willMsg;
-      json["connMsg"] = confMqtt.mqtt_connMsg;
-
-      if (confMqtt.mqtt_enable_heartbeat) json["hbEnable"] = 1;
-      else json["hbEnable"] = 0;
-
-      json["hbReconn"] = confMqtt.mqtt_heartbeat_maxage_reconnect / 60000;
-      json["hbReboot"] = confMqtt.mqtt_heartbeat_maxage_reboot / 60000;
-
-      yield();
-
-      char jsonchar[1000];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /confdmqtt
-
-  httpServer.on("/setConfWeb", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //sendLog("WEB: /setConfWeb", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /setConfWeb (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      bool httpPASet, httpP1Set, httpP2Set;
-      httpPASet = false;
-      httpP1Set = false;
-      httpP2Set = false;
-      if (httpServer.hasArg("httpPASet")) httpPASet = true;
-      if (httpServer.hasArg("httpP1Set")) httpP1Set = true;
-      if (httpServer.hasArg("httpP2Set")) httpP2Set = true;
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          Serial.print("web update ");
-          Serial.print(bufName);
-          Serial.print(" = ");
-          Serial.println(bufValue);
-
-          if (strcmp(bufName, "httpUA") == 0 || strcmp(bufName, "httpPA") == 0) {
-            if (httpPASet) setConfig(bufName, bufValue);
-          }
-          else if (strcmp(bufName, "httpU1") == 0 || strcmp(bufName, "httpP1") == 0) {
-            if (httpP1Set) setConfig(bufName, bufValue);
-          }
-          else if (strcmp(bufName, "httpU2") == 0 || strcmp(bufName, "httpP2") == 0) {
-            if (httpP2Set) setConfig(bufName, bufValue);
-          }
-          else if (strcmp(bufName, "httpPASet") != 0 && strcmp(bufName, "httpP1Set") != 0 && strcmp(bufName, "httpP2Set") != 0) setConfig(bufName, bufValue);
-          //else setConfig(bufName, bufValue);
-        }
-        //saveConfigWebToFlash = true; // will be saved in next loop()
-        //Serial.println("web triggered saveConfigWebToFlash");
-      }
-      yield();
-      saveConfigWeb();
-
-      httpServerHandleConfSavedPage();
-      config_was_changed = true;
-      // yield();
-      // ESP.restart();
-    }
-  }); //httpServer.on /setConfWeb
-
-  httpServer.on("/setConfMqtt", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //Serial.println("httpServer.on /setConfMqtt");
-      //sendLog("WEB: /setConfMqtt", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /setConfMqtt (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      bool mqttPassSet;
-      mqttPassSet = false;
-      if (httpServer.hasArg("mqttPassSet")) mqttPassSet = true;
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          Serial.print("web update ");
-          Serial.print(bufName);
-          Serial.print(" = ");
-          Serial.println(bufValue);
-
-          if (strcmp(bufName, "mqttUser") == 0 || strcmp(bufName, "mqttPass") == 0) {
-            if (mqttPassSet) setConfig(bufName, bufValue);
-          }
-          else setConfig(bufName, bufValue);
-        }
-        //saveConfigMqttToFlash = true; // will be saved in next loop()
-        //Serial.println("web triggered saveConfigMqttToFlash");
-      }
-      yield();
-      saveConfigMqtt();
-
-      httpServerHandleConfSavedRestartPage();
-      config_was_changed = true;
-      restart();
-    }
-  }); //httpServer.on /setConfMqtt
-
-  httpServer.on("/confDataDevWiFi", []() {
-    if (!httpIsAuthenticated()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confDataDevWiFi", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confDataDevWiFi (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          //Serial.print("web update ");
-          //Serial.print(bufName);
-          //Serial.print(" = ");
-          //Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-        saveConfigToFlash = true; // will be saved in next loop()
-        //Serial.println("web triggered saveConfigToFlash");
-      }
-      yield();
-
-      //build json object of program data
-      StaticJsonDocument<800> json;
-
-      json["devName"] = confDevWiFi.deviceName;
-      json["hostName"] = confDevWiFi.hostName;
-      json["SSID1"] = confDevWiFi.WiFiSSID1;
-      //json["WPW1"] = confDevWiFi.WiFiPW1;
-      if(strlen(confDevWiFi.WiFiPW1) > 0) json["WPW1"] = "****";
-      else json["WPW1"] = "";
-      json["SSID2"] = confDevWiFi.WiFiSSID2;
-      //json["WPW2"] = confDevWiFi.WiFiPW2;
-      if(strlen(confDevWiFi.WiFiPW2) > 0) json["WPW2"] = "****";
-      else json["WPW2"] = "";
-      json["SSIDAP"] = confDevWiFi.WiFiAPModeSSID;
-      json["WPWAP"] = confDevWiFi.WiFiAPModePassword;
-      json["WAPtout"] = confDevWiFi.WiFiAPModeTimeout;
-      json["WConnCheck"] = confDevWiFi.WiFiConnCheckInterval;
-      json["Wretry"] = confDevWiFi.WiFiRetryInterval;
-      json["Wreboot"] = confDevWiFi.WiFiRebootOnNoConnect;
-
-      yield();
-
-      char jsonchar[1000];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /getConf/DevWiFi
-
-  httpServer.on("/setConfDevWiFi", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //sendLog("WEB: /setConfDevWiFi", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /setConfDevWiFi (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-      
-      bool WPW1Set, WPW2Set, WPWAPSet;
-      WPW1Set = false;
-      WPW2Set = false;
-      WPWAPSet = false;
-      if (httpServer.hasArg("WPW1Set")) WPW1Set = true;
-      if (httpServer.hasArg("WPW2Set")) WPW2Set = true;
-      if (httpServer.hasArg("WPWAPSet")) WPWAPSet = true;
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          Serial.print("web update ");
-          Serial.print(bufName);
-          Serial.print(" = ");
-          Serial.println(bufValue);
-
-          if (strcmp(bufName, "SSID1") == 0 || strcmp(bufName, "WPW1") == 0) {
-            if (WPW1Set) setConfig(bufName, bufValue);
-          }
-          else if (strcmp(bufName, "SSID2") == 0 || strcmp(bufName, "WPW2") == 0) {
-            if (WPW2Set) setConfig(bufName, bufValue);
-          }
-          else if (strcmp(bufName, "WPWAP") == 0) {
-            if (WPWAPSet) setConfig(bufName, bufValue);
-          }
-          else setConfig(bufName, bufValue);
-        }
-      }
-      yield();
-      saveConfigDevWiFi();
-
-      httpServerHandleConfSavedRestartPage();
-      
-      config_was_changed = true;
-      restart();
-    }
-  }); //httpServer.on /setConfDev
-
-  httpServer.on("/setConfBas", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //sendLog("WEB: /setConfBas", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /setConfBas (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          Serial.print("web update ");
-          Serial.print(bufName);
-          Serial.print(" = ");
-          Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-      }
-      yield();
-      saveConfigBas();
-
-      httpServerHandleConfSavedPage();
-      config_was_changed = true;
-      // delay(10);
-      // yield();
-      // ESP.restart();
-    }
-  }); //httpServer.on /setConfBas
-
-  httpServer.on("/setConfAdv", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //sendLog("WEB: /setConfAdv", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /setConfAdv (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          Serial.print("web update ");
-          Serial.print(bufName);
-          Serial.print(" = ");
-          Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-      }
-      yield();
-      saveConfigAdv();
-
-      httpServerHandleConfSavedPage();
-      config_was_changed = true;
-      // delay(10);
-      // yield();
-      // ESP.restart();
-    }
-  }); //httpServer.on /setConfAdv
-
-  httpServer.on("/setConfAdd", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //sendLog("WEB: /setConfAdd", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /setConfAdd (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          Serial.print("web update ");
-          Serial.print(bufName);
-          Serial.print(" = ");
-          Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-      }
-      yield();
-      saveConfigAdd();
-
-      httpServerHandleConfSavedPage();
-      config_was_changed = true;
-      // delay(10);
-      // yield();
-      // ESP.restart();
-    }
-  }); //httpServer.on /setConfAdd
-
-  httpServer.on("/setConfTime", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //sendLog("WEB: /setConfTime", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /setConfTime (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          Serial.print("web update ");
-          Serial.print(bufName);
-          Serial.print(" = ");
-          Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-      }
-      yield();
-      saveConfigTime();
-
-      httpServerHandleConfSavedPage();
-      config_was_changed = true;
-      // delay(10);
-      // yield();
-      // ESP.restart();
-    }
-  }); //httpServer.on /setConfTime
-
-  httpServer.on("/setConfLog", []() {
-    if (!httpIsAuthenticatedAdmin()) httpSendUnauthorized();
-    else {
-      //sendLog("WEB: /setConfLog", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /setConfLog (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          Serial.print("web update ");
-          Serial.print(bufName);
-          Serial.print(" = ");
-          Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-      }
-      yield();
-      saveConfigLog();
-
-      httpServerHandleConfSavedPage();
-      config_was_changed = true;
-      // delay(10);
-      // yield();
-      // ESP.restart();
-    }
-  }); //httpServer.on /setConfLog
-
-  httpServer.on("/confDataBas", []() {
-    if (!httpIsAuthenticated()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confDataBas", LOGLEVEL_INFO);
-      //Serial.println("httpServer.on /confdata2");
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confDataBas (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          //Serial.print("web update ");
-          //Serial.print(bufName);
-          //Serial.print(" = ");
-          //Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-        saveConfig2ToFlash = true;
-        //Serial.println("web triggered saveConfig2ToFlash");
-      }
-      yield();
-
-      //build json object of program data
-      StaticJsonDocument<500> json;
-
-      if (confBas.autoSaveSetTemp) json["autoSaveTemp"] = 1;
-      else json["autoSaveTemp"] = 0;
-
-      if (confBas.autoSaveHeatingMode) json["autoSaveMode"] = 1;
-      else json["autoSaveMode"] = 0;
-
-      if (confBas.saveToMqttRetained) json["saveToMqttRet"] = 1;
-      else json["saveToMqttRet"] = 0;
-
-      json["tempMin"] = confBas.setTempMin;
-      json["tempMax"] = confBas.setTempMax;
-      json["measInt"] = confBas.measureInterval;
-      json["dispInt"] = confBas.displayInterval;
-      json["dispTout"] = confBas.displayTimeout;
-
-      if (confBas.PIR_enablesDisplay) json["PIRenDisp"] = 1;
-      else json["PIRenDisp"] = 0;
-
-      if (confBas.PIR_enablesDisplay_preset0only) json["PIRenDispPs0"] = 1;
-      else json["PIRenDispPs0"] = 0;
-
-      if (confBas.togglingTempHumAIDisplay) json["togTHdisp"] = 1;
-      else json["togTHdisp"] = 0;
-
-      yield();
-
-      char jsonchar[1000];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /confdbas
-
-
-  httpServer.on("/confDataAdv", []() {
-    if (!httpIsAuthenticated()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confDataAdv", LOGLEVEL_INFO);
-      //Serial.println("httpServer.on /confdata2");
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confDataAdv (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          //Serial.print("web update ");
-          //Serial.print(bufName);
-          //Serial.print(" = ");
-          //Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-        saveConfig2ToFlash = true;
-        //Serial.println("web triggered saveConfig2ToFlash");
-      }
-      yield();
-
-      //build json object of program data
-      StaticJsonDocument<600> json;
-      json["minOffTime"] = confAdv.heatingMinOffTime;
-      json["tempDec"] = confAdv.setTempDecreaseVal;
-      json["hyst"] = confAdv.hysteresis;
-      json["tempCorr"] = confAdv.tempCorrVal;
-      json["humCorr"] = confAdv.humCorrVal;
-      json["offMsg"] = confAdv.offMessage;
-      json["modeName0"] = confAdv.modeName0;
-      json["modeName1"] = confAdv.modeName1;
-      json["psetName0"] = confAdv.psetName0;
-      json["psetName1"] = confAdv.psetName1;
-      json["psetName2"] = confAdv.psetName2;
-      json["iTempLab"] = confAdv.iTempLabel;
-      json["oTempLab"] = confAdv.oTempLabel;
-
-      yield();
-
-      char jsonchar[1000];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /confdadv
-
-  httpServer.on("/confDataAdd", []() {
-    if (!httpIsAuthenticated()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confDataAdd", LOGLEVEL_INFO);
-      //Serial.println("httpServer.on /confdata2");
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confDataAdd (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          //Serial.print("web update ");
-          //Serial.print(bufName);
-          //Serial.print(" = ");
-          //Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-        saveConfig2ToFlash = true;
-        //Serial.println("web triggered saveConfig2ToFlash");
-      }
-      yield();
-
-      //build json object of program data
-      StaticJsonDocument<1000> json;
-
-      json["outTempTop"] = confAdd.outTemp_topic_in;
-      json["outHumTop"] = confAdd.outHum_topic_in;
-      json["PIRTop"] = confAdd.mqtt_topic_pir;
-      json["PIROnPld"] = confAdd.mqtt_payload_pir_on;
-      json["PIROffPld"] = confAdd.mqtt_payload_pir_off;
-
-      yield();
-
-      char jsonchar[1000];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /confdadd
-
-  httpServer.on("/confDataTime", []() {
-    if (!httpIsAuthenticated()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confDataTime", LOGLEVEL_INFO);
-      //Serial.println("httpServer.on /confdata2");
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confDataTime (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          //Serial.print("web update ");
-          //Serial.print(bufName);
-          //Serial.print(" = ");
-          //Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-        saveConfig2ToFlash = true;
-        //Serial.println("web triggered saveConfig2ToFlash");
-      }
-      yield();
-
-      //build json object of program data
-      StaticJsonDocument<1000> json;
-
-      if(confTime.ntpEnable) json["NTPEnable"] = 1;
-      else json["NTPEnable"] = 0;
-
-      json["NTPServer1"] = confTime.ntpServer1;
-      json["NTPServer2"] = confTime.ntpServer2;
-      json["TZStr"] = confTime.timeZoneStr;
-      json["NTPSyncInt"] = confTime.ntpSyncInterval;
-
-      yield();
-
-      char jsonchar[1000];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /confDataTime
-
-  httpServer.on("/confDataLog", []() {
-    if (!httpIsAuthenticated()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confDataLog", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confDataLog (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      for (int i = 0; i < httpServer.args(); i++) {
-        char bufName[20];
-        char bufValue[101];
-        httpServer.argName(i).toCharArray(bufName, 20);
-        httpServer.arg(i).toCharArray(bufValue, 101);
-
-        if (strlen(bufName) > 0) {
-          //Serial.print("web update ");
-          //Serial.print(bufName);
-          //Serial.print(" = ");
-          //Serial.println(bufValue);
-          setConfig(bufName, bufValue);
-        }
-        saveConfig2ToFlash = true;
-        //Serial.println("web triggered saveConfig2ToFlash");
-      }
-      yield();
-
-      //build json object of program data
-      StaticJsonDocument<1000> json;
-
-      //if(confTime.ntpEnable) json["NTPEnable"] = 1;
-      //else json["NTPEnable"] = 0;
-
-      json["logLevSer"] = confLog.logLevelSerial;
-      json["logLevWeb"] = confLog.logLevelWeb;
-      json["logLevMqtt"] = confLog.logLevelMqtt;
-
-      yield();
-
-      char jsonchar[1000];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /confDataLog
-
-  //get heap status, analog input value and all GPIO statuses in one json call
-  httpServer.on("/sysinfo", HTTP_GET, []() {
-    if (!httpIsAuthenticated()) return httpServer.requestAuthentication();
-    else {
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /sysinfo (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      StaticJsonDocument<600> json;
-      json["Devname"] = confDevWiFi.deviceName;
-      json["Ssid"] = WiFi.SSID();
-      json["WiFiNum"] = persWM.getActiveWiFiNum();
-      json["Uptime"] = uptimeStr;
-      json["HeapFree"] = ESP.getFreeHeap();
-      json["HeapFragment"] = ESP.getHeapFragmentation();
-      json["HeapMaxBlock"] = ESP.getMaxFreeBlockSize();
-      json["ResetReason"] = ESP.getResetReason();
-      json["CoreVersion"] = ESP.getCoreVersion();
-      json["SDKVersion"] = ESP.getSdkVersion();
-      json["CPUfreq"] = ESP.getCpuFreqMHz();
-      json["SketchSize"] = ESP.getSketchSize();
-      json["FlashSize"] = ESP.getFlashChipRealSize();
-
-      if(confTime.ntpEnable) {
-        char buf[13];
-        updateTime();
-        strftime(buf, sizeof(buf), "%H:%M", &lt);
-        json["time"] = buf;
-        strftime(buf, sizeof(buf), "%d.%m.%Y", &lt);
-        json["date"] = buf;
-      }
-      
-      yield();
-
-      char jsonchar[1000];
-      serializeJson(json, jsonchar);
-      httpServer.send(200, "application/json", jsonchar);
-    }
-  }); //httpServer.on /sysinfo
-
-  /*httpServer.on("/", []() {
-    if ( WifiInApMode ) {
-      httpServer.sendHeader("Location", "/wifi.htm", true);
-      httpServer.send(302);
-    }
-    else {
-      httpServer.sendHeader("Location", "/main", true);
-      httpServer.send(302);
-    }
-    });*/
-
-  httpServer.on("/", []() {
-    String addr = httpServer.client().remoteIP().toString();
-    char buf[40];
-    sprintf(buf, "WEB: / (from %s)", addr.c_str());
-    sendLog(buf, LOGLEVEL_INFO);
-
-    if (httpServer.hasArg("restart")) {
-      if (httpIsAuthenticated() || (!httpIsAuthenticated() && httpCheckToken()) ) {
-        sendLog("WEB: /?restart", LOGLEVEL_INFO);
-        httpServerHandleRestartPage();
-        restart();
-      }
-      else httpSendUnauthorized();
-    }
-    else if (httpServer.hasArg("mqttreconnect")) {
-      if ( httpIsAuthenticated() || (!httpIsAuthenticated() && httpCheckToken()) ) {
-        //Serial.println("web triggered mqttreconnect");
-        sendLog("WEB: /?mqttreconnect", LOGLEVEL_INFO);
-        mqttReconnect();
-        httpServer.sendHeader("Location", "/", true);
-        httpServer.send(303);
-      }
-      else httpSendUnauthorized();
-    }
-    else if (httpServer.hasArg("clearconf")) {
-      if (httpIsAuthenticatedAdmin() || (!httpIsAuthenticatedAdmin() && httpCheckToken()) ) {
-        sendLog("WEB: /?clearconf", LOGLEVEL_INFO);
-        httpServerHandleClearconfPage();
-
-        yield();
-        delay(5);
-        deleteConfig();
-      }
-      else httpSendUnauthorized();
-    }
-    else if (!httpIsAuthenticated()) return httpServer.requestAuthentication();
-    else {
-      sendLog("WEB: /", LOGLEVEL_INFO);
-      httpServerHandleMainPage();
-    }
-  });
-
-  httpServer.on("/conf", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /conf", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /conf (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleConfPage();
-    }
-  });
-
-  httpServer.on("/confweb", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confweb", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confweb (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleConfWebPage();
-    }
-  });
-
-  httpServer.on("/confmqtt", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confmqtt", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confmqtt (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleConfMqttPage();
-    }
-  });
-
-  httpServer.on("/confdevwifi", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confdevwifi", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confdevwifi (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleConfDevWiFiPage();
-    }
-  });
-
-  httpServer.on("/confbas", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confbas", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confbas (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleConfBasPage();
-    }
-  });
-
-  httpServer.on("/confadv", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confadv", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confadv (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleConfAdvPage();
-    }
-  });
-
-  httpServer.on("/confadd", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /confadd", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /confadd (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleConfAddPage();
-    }
-  });
-
-  httpServer.on("/conftime", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /conftime", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /conftime (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleConfTimePage();
-    }
-  });
-
-  httpServer.on("/conflog", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /conflog", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /conflog (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleConfLogPage();
-    }
-  });
-
-  httpServer.on("/redTemps", []() {
-    if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-    else {
-      //sendLog("WEB: /redTemps", LOGLEVEL_INFO);
-      String addr = httpServer.client().remoteIP().toString();
-      char buf[40];
-      sprintf(buf, "WEB: /redTemps (from %s)", addr.c_str());
-      sendLog(buf, LOGLEVEL_INFO);
-
-      httpServerHandleRedTempsPage();
-    }
-  });
-
-  if(confWeb.enableConsole) {
-    httpServer.on("/console", []() {
-      if (!httpIsAuthenticatedAdmin()) return httpServer.requestAuthentication();
-      else {
-        //sendLog("WEB: /console", LOGLEVEL_INFO);
-        String addr = httpServer.client().remoteIP().toString();
-        char buf[40];
-        sprintf(buf, "WEB: /console (from %s)", addr.c_str());
-        sendLog(buf, LOGLEVEL_INFO);
-
-        wsValidSessionId = millis();
-        char sidbuf[20];
-        sprintf(sidbuf, "sessionId=%lu|", wsValidSessionId);
-        httpServer.sendHeader("Set-Cookie",sidbuf);
-        httpServerHandleConsolePage();
-      }
-    });
-  }
-
-  httpServer.onNotFound([]() {
-    String addr = httpServer.client().remoteIP().toString();
-    char buf[40];
-    sprintf(buf, "WEB: 404 (from %s)", addr.c_str());
-    sendLog(buf, LOGLEVEL_INFO);
-    httpServerHandleNotFound();
-  }); //httpServer.onNotFound
-
-  // HTTP Updater at /update
-  httpUpdater.setup(&httpServer, "/update", confWeb.http_user, confWeb.http_pass);
-
-  httpServer.begin();
-}

+ 0 - 69
src/WiFiThermostat/logging.ino

@@ -1,69 +0,0 @@
-void sendLog(const char *msg, uint8_t loglevel)
-{
-    char buf[101];
-    char buf2[121];
-    static char tbuf[20];
-    bool timeIsValid=false;
-    strlcpy(buf, msg, sizeof(buf));
-
-    if (confTime.ntpEnable)
-    {
-        updateTime();
-        if(lt.tm_year > 70) { // lt.tm_year = years since 1900, before NTP is synced = 70
-            //strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", &lt);
-            strftime(tbuf, sizeof(tbuf), "%H:%M:%S", &lt);
-            sprintf(buf2, "[%s] %s\r\n", tbuf, buf);
-            timeIsValid = true;
-        }
-    }
-
-    if(!timeIsValid)
-    {
-        //unsigned long tmpMillis;
-        unsigned long tmpSecs;
-        //unsigned int restMillis;
-        //tmpMillis = millis();
-        //tmpSecs = tmpMillis / 1000;
-        //restMillis = tmpMillis - (tmpSecs * 1000);
-        tmpSecs = millis() / 1000;
-        
-        //sprintf(buf2, "[%u.%u] %s\r\n", tmpSecs, restMillis, buf);
-        sprintf(buf2, "[%07lu] %s\r\n", tmpSecs, buf);
-    }
-
-    if(loglevel <= confLog.logLevelSerial) Serial.print(buf2);
-
-    if (confMqtt.mqtt_enable && mqttclient.state() == 0)
-    {
-        if(loglevel <= confLog.logLevelMqtt) mqttclient.publish(confMqtt.mqtt_topic_out, buf, confMqtt.mqtt_outRetain);
-    }
-    yield();
-
-    if (confWeb.enableConsole && webSocket.connectedClients() > 0)
-    {
-        if(loglevel <= confLog.logLevelWeb) webSocket.broadcastTXT(buf2);
-    }
-}
-
-void sendLog(const __FlashStringHelper *msg, uint8_t loglevel)
-{
-    char buf[501];
-    PGM_P p = reinterpret_cast<PGM_P>(msg);
-    size_t n = 0;
-    while (1)
-    {
-        unsigned char c = pgm_read_byte(p++);
-        if (c == 0) {
-            buf[n] = c;
-            break;
-        }
-        else if (n >= sizeof(buf)-1) {
-            break;
-        }
-        else {
-            buf[n] = c;
-            n++;
-        }
-    }
-    sendLog(buf, loglevel);
-}

+ 0 - 41
src/WiFiThermostat/miscFunctions.ino

@@ -1,41 +0,0 @@
-void updateUptime() {
-  sysUptime_mins++;
-  if(sysUptime_mins == 60) {
-    sysUptime_mins=0;
-    sysUptime_hours++;
-  }
-  if(sysUptime_hours == 24) {
-    sysUptime_hours=0;
-    sysUptime_days++;
-  }
-}
-void buildUptimeString() {
-  if(sysUptime_days > 0) sprintf(uptimeStr, "%dd %02d:%02d", sysUptime_days, sysUptime_hours, sysUptime_mins);
-  else sprintf(uptimeStr, "%02d:%02d", sysUptime_hours, sysUptime_mins);
-}
-void createDeviceName() {
-  byte mac[6];
-  WiFi.macAddress(mac);
-  sprintf(confDevWiFi.deviceName, "%s-%02X%02X", FIRMWARE_SHORTNAME, (uint8_t)mac[4], (uint8_t)mac[5]);
-  }
-
-void restart() {
-  delay(100);
-  //ESP.restart();
-  // Adding Safer Restart method
-  ESP.wdtDisable();
-	ESP.reset();
-  delay(2000);
-}
-
-void logSysdata() {
-    // Serial.print (NTP.getDateStr_YMD()); Serial.print (" "); Serial.print (NTP.getTimeStr ());
-    // Serial.print (" "); Serial.print (NTP.isSummerTime () ? "Summer Time. " : "Winter Time. "); Serial.println();
-    // Serial.print ("Uptime: ");
-    // Serial.print (NTP.getUptimeString ()); Serial.print (" since ");
-    // Serial.println (NTP.getDateTimeString (NTP.getFirstSync ()).c_str ());
-    // Serial.printf ("Free heap: %u", ESP.getFreeHeap ()); Serial.println();
-    char logBuf[101];
-    sprintf_P(logBuf, "SYS: uptime=%s, freeHeap=%u, heapFragm=%u%%", uptimeStr, ESP.getFreeHeap(), ESP.getHeapFragmentation());
-    sendLog(logBuf, LOGLEVEL_INFO);
-}

+ 0 - 95
src/WiFiThermostat/time.ino

@@ -1,95 +0,0 @@
-bool setupTime()
-{
-    if (strlen(confTime.ntpServer1) > 4 && strlen(confTime.ntpServer2) > 4)
-    {
-        //configTime(gmtOffset_sec, daylightOffset_sec, ntpServer [, ntpServer2[, ntpServer3]]);
-        configTime(0, 0, confTime.ntpServer1, confTime.ntpServer2);
-    }
-    else if (strlen(confTime.ntpServer1) > 4)
-    {
-        configTime(0, 0, confTime.ntpServer1);
-    }
-    else return false;
-    setenv("TZ", confTime.timeZoneStr, 1); // Zeitzone einstellen https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
-    return true;
-}
-
-void updateTimeFromNTP()
-{
-    time_t now = time(&now);
-    static time_t lastsek{0};
-    if (lt.tm_sec != lastsek)
-    {
-        lastsek = lt.tm_sec;
-        if (!(time(&now) % confTime.ntpSyncInterval))
-        {
-            //Serial.println("updating time from NTP server");
-            sendLog(F("NTP: updating time"), LOGLEVEL_INFO);
-            setupTime();
-        }
-    }
-}
-
-void updateTime() {
-    time_t now = time(&now);
-    localtime_r(&now, &lt);
-}
-
-// char getDateTime() {
-//     char* buf[30]; // je nach Format von "strftime" eventuell anpassen
-//     time_t now = time(&now);
-//     localtime_r(&now, &lt);
-//     strftime(&buf, sizeof(buf), "%Y-%m-%d %T", &lt); // http://www.cplusplus.com/reference/ctime/strftime/
-//     return buf;
-// }
-
-
-// char getDate() {
-//     char buf[13];
-//     updateTime();
-//     strftime(buf, sizeof(buf), "%d.%m.%Y", &lt); // http://www.cplusplus.com/reference/ctime/strftime/
-//     //return buf;
-// }
-
-// char getDate_YMD() {
-//     char* buf[13];
-//     time_t now = time(&now);
-//     localtime_r(&now, &lt);
-    
-//     strftime(&buf, sizeof(buf), "%Y-%m-%d", &lt); // http://www.cplusplus.com/reference/ctime/strftime/
-//     return buf;
-// }
-
-// char getTime() {
-//     char* buf[6];
-//     time_t now = time(&now);
-//     localtime_r(&now, &lt);
-    
-//     strftime(&buf, sizeof(buf), "%H:%M", &lt); // http://www.cplusplus.com/reference/ctime/strftime/
-//     return buf;
-// }
-
-// char getTime_HMS() {
-//     char* buf[9];
-//     time_t now = time(&now);
-//     localtime_r(&now, &lt);
-    
-//     strftime(&buf, sizeof(buf), "%H:%M:%S", &lt); // http://www.cplusplus.com/reference/ctime/strftime/
-//     return buf;
-// }
-
-/*void printTimeToSerial()
-{
-    static char buf[30]; // je nach Format von "strftime" eventuell anpassen
-    time_t now = time(&now);
-    localtime_r(&now, &lt);
-    //gmtime_r(&now, &utc);
-
-    strftime(buf, sizeof(buf), "%Y-%m-%d %T", &lt); // http://www.cplusplus.com/reference/ctime/strftime/
-    //Serial.printf("%s %s", buf, dayShortNames[lt.tm_wday]);
-    Serial.printf("%s", buf);
-    Serial.println();
-
-    //Serial.printf("UTC: %.2d:%.2d:%.2d\n", utc.tm_hour, utc.tm_min, utc.tm_sec);
-    //Serial.printf("%s: %.2d:%.2d:%.2d %s\n\n", *tzname, lt.tm_hour, lt.tm_min, lt.tm_sec, lt.tm_isdst ? "Sommerzeit" : "Normalzeit");
-}*/

+ 303 - 0
src/commands.ino

@@ -0,0 +1,303 @@
+
+#define SER_INPUT_SIZE 70
+char serBuffer[SER_INPUT_SIZE + 1];
+int serBufferCount;
+
+void serialEvent() {
+  char ch = Serial.read();
+  serBuffer[serBufferCount] = ch;
+  serBufferCount++;
+  if (ch == 13 || ch == 10) { // ASCII code 13 = "CR",  10 = "LF"
+    serBuffer[serBufferCount - 1] = '\0';
+#ifdef DEBUG_VERBOSE
+    Serial.print("serial cmd: '");
+    Serial.print(serBuffer);
+    Serial.println("'");
+#endif
+    strlcpy(cmdPayload, serBuffer, sizeof(cmdPayload));
+    cmdInQueue = true;
+    evalCmd();
+    serBufferCount = 0;
+  }
+}
+
+void evalCmd() {
+  if (cmdInQueue) {
+    //Serial.print("cmdPayload: ");
+    //Serial.println(cmdPayload);
+
+    char cmdPayload_lower[sizeof(cmdPayload)];
+    strlcpy(cmdPayload_lower, cmdPayload, sizeof(cmdPayload_lower));
+    strlwr(cmdPayload_lower);
+
+    if (strncmp(cmdPayload_lower, "loadconf", 8) == 0) {
+      sendLog(F("loading config..."));
+      loadConf_all();
+    }
+
+    else if (strncmp(cmdPayload_lower, "set ", 4) == 0) {
+      char buf[81];
+      char setconfCmd[16];
+
+      uint8_t len = strlen(cmdPayload) - 4;
+      for (unsigned char i = 0; i < len; i++) {
+        if (i < (sizeof(buf)-1)) buf[i] = cmdPayload[i + 4];
+      }
+      if (len <= (sizeof(buf)-1)) buf[len] = '\0';
+      else buf[(sizeof(buf)-1)] = '\0';
+
+#ifdef DEBUG_VERBOSE
+      Serial.print("Buf: ");
+      Serial.println(buf);
+#endif
+
+      bool cmdNoPayload = false;
+      uint8_t setconfCmdLen = 0;
+      for (unsigned char i = 0; i < len; i++) {
+        //if (buf[i] == 32 || buf[i] == '\0') break; // if SPACE command name is finished, if \0 command parameter is missing
+        if (buf[i] == 32 || buf[i] == 61 || buf[i] == 58) break; // if SPACE(32) or =(61) or :(58) command name is finished
+        else if (buf[i] == 0 || buf[i] == 10 || buf[i] == 13) { // if \0, LF (10) or CR (13) command parameter is missing
+          cmdNoPayload = true;
+          break;
+        }
+        setconfCmd[i] = buf[i];
+        setconfCmdLen++;
+      }
+      setconfCmd[setconfCmdLen] = '\0';
+      yield();
+
+      if (setconfCmdLen == len) cmdNoPayload = true;
+
+#ifdef DEBUG_VERBOSE
+      Serial.print("setconfCmd: '");
+      Serial.print(setconfCmd);
+      Serial.print("'");
+#endif
+
+      if ( cmdNoPayload ) {
+#ifdef DEBUG_VERBOSE
+        Serial.println(", no payload, displaying current value");
+#endif
+        //getConfig(setconfCmd);
+        cmdPrintHelp();
+        
+      }
+      else {
+        char setconfPayload[62];
+#ifdef DEBUG_VERBOSE
+        Serial.println();
+#endif
+        int setconfPayloadLen = 0;
+        for (int i = 0; i < len; i++) {
+          char c = buf[i + setconfCmdLen + 1];
+          if (c == 0 || c == 10 || c == 13) break; // if \0, LF (10) or CR (13) command parameter is finished
+          setconfPayload[i] = c;
+          setconfPayloadLen++;
+        }
+        setconfPayload[setconfPayloadLen] = '\0';
+
+#ifdef DEBUG_VERBOSE
+        Serial.print("setconfPayload: '");
+        Serial.print(setconfPayload);
+        Serial.println("'");
+#endif
+        char bufg[100];
+        sprintf(bufg, "set '%s'->'%s'", setconfCmd, setconfPayload);
+        sendLog(bufg);
+        setConfig(setconfCmd, setconfPayload);
+      }
+    }
+
+
+
+    else if (strncmp(cmdPayload_lower, "get ", 4) == 0) {
+      char buf[81];
+      char setconfCmd[16];
+
+      uint8_t len = strlen(cmdPayload) - 4;
+      for (int i = 0; i < len; i++) {
+        if (i < 81) buf[i] = cmdPayload[i + 4];
+      }
+      if (len <= (sizeof(buf)-1)) buf[len] = '\0';
+      else buf[(sizeof(buf)-1)] = '\0';
+
+#ifdef DEBUG_VERBOSE
+      Serial.print("Buf: ");
+      Serial.println(buf);
+#endif
+      
+      uint8_t setconfCmdLen = 0;
+      for (int i = 0; i < len; i++) {
+        //if (buf[i] == 32 || buf[i] == '\0') break; // if SPACE command name is finished, if \0 command parameter is missing
+        if (buf[i] == 32 || buf[i] == 61 || buf[i] == 58) break; // if SPACE(32) or =(61) or :(58) command name is finished
+        else if (buf[i] == 0 || buf[i] == 10 || buf[i] == 13) { // if \0, LF (10) or CR (13) command parameter is missing
+          break;
+        }
+        setconfCmd[i] = buf[i];
+        setconfCmdLen++;
+      }
+      setconfCmd[setconfCmdLen] = '\0';
+      yield();
+#ifdef DEBUG_VERBOSE
+      Serial.print("setconfCmd: '");
+      Serial.print(setconfCmd);
+      Serial.println("'");
+#endif
+      char bufg[50];
+      sprintf(bufg, "get '%s'", setconfCmd);
+      sendLog(bufg);
+      getConfig(setconfCmd);
+    }
+
+    /*else if (strncmp(cmdPayload, "enc ", 4) == 0) {
+      char buf[81];
+      char setconfCmd[16];
+
+      uint8_t len = strlen(cmdPayload) - 4;
+      for (int i = 0; i < len; i++) {
+        if (i < 81) buf[i] = cmdPayload[i + 4];
+      }
+      if (len <= (sizeof(buf)-1)) buf[len] = '\0';
+      else buf[(sizeof(buf)-1)] = '\0';
+
+#ifdef DEBUG_VERBOSE
+      Serial.print("Buf: ");
+      Serial.println(buf);
+#endif
+      
+      uint8_t setconfCmdLen = 0;
+      for (int i = 0; i < len; i++) {
+        //if (buf[i] == 32 || buf[i] == '\0') break; // if SPACE command name is finished, if \0 command parameter is missing
+        if (buf[i] == 32 || buf[i] == 61 || buf[i] == 58) break; // if SPACE(32) or =(61) or :(58) command name is finished
+        else if (buf[i] == 0 || buf[i] == 10 || buf[i] == 13) { // if \0, LF (10) or CR (13) command parameter is missing
+          break;
+        }
+        setconfCmd[i] = buf[i];
+        setconfCmdLen++;
+      }
+      setconfCmd[setconfCmdLen] = '\0';
+      yield();
+#ifdef DEBUG_VERBOSE
+      Serial.print("setconfCmd: '");
+      Serial.print(setconfCmd);
+      Serial.println("'");
+#endif
+      char bufg[50];
+      sprintf(bufg, "enc '%s'", setconfCmd);
+      sendLog(bufg);
+
+      sprintf(bufg, "%s", XORENC(setconfCmd, encKey));
+      sendLog(bufg);
+      //getConfig(setconfCmd);
+    }*/
+
+    else if (strncmp(cmdPayload_lower, "restart", 7) == 0) {
+      sendLog(F("restarting..."));
+      restart();
+    }
+
+    else if (strncmp(cmdPayload_lower, "sysinfo", 7) == 0) {
+      logSysdata();
+    }
+
+    else if (strncmp(cmdPayload_lower, "debugmode 1", 11) == 0) {
+      sendLog(F("debugmode on"));
+      sysInfoEverySecond = true;
+    }
+
+    else if (strncmp(cmdPayload_lower, "debugmode 0", 11) == 0) {
+      sendLog(F("debugmode off"));
+      sysInfoEverySecond = false;
+    }
+
+#ifdef ENABLE_FEATURE_NTP_TIME
+    else if (strncmp(cmdPayload_lower, "date", 7) == 0) {
+      printDate();
+    }
+#endif
+
+#ifdef ENABLE_FEATURE_NTP_TIME
+    else if (strncmp(cmdPayload_lower, "syncclock", 7) == 0) {
+      syncClock(true);
+    }
+#endif
+
+    else if (strncmp(cmdPayload_lower, "clearcreds", 10) == 0) {
+      confClearCredentials();
+    }
+
+    else if (strncmp(cmdPayload_lower, "clearwifi", 10) == 0) {
+      confClearWiFiCredentials();
+    }
+
+    else if (strncmp(cmdPayload_lower, "saveconf", 8) == 0) {
+      saveConfig_all();
+    }
+    
+    else if (strncmp(cmdPayload_lower, "savevalues", 10) == 0) {
+      saveValues();
+    }
+
+    else if (strncmp(cmdPayload_lower, "encrypt", 10) == 0) {
+      confEncrypt();
+    }
+
+    else if (strncmp(cmdPayload_lower, "decrypt", 10) == 0) {
+      confDecrypt();
+    }
+
+    else if (strncmp(cmdPayload_lower, "ls", 2) == 0) {
+      SPIFFS_listFiles();
+    }
+
+    else if (strncmp(cmdPayload_lower, "ipcfg", 5) == 0) {
+      printIpcfg();
+    }
+    
+
+    else if (strncmp(cmdPayload_lower, "help", 4) == 0) {
+      cmdPrintHelp();
+    }
+    else if (strncmp(cmdPayload_lower, "getconf", 7) == 0) {
+      sendLog(F("CONF: listing all conf parameters:"));
+      getConfig((char*)"confDevWiFi");
+      getConfig((char*)"confWeb");
+      getConfig((char*)"confMqtt");
+      getConfig((char*)"confBas");
+      getConfig((char*)"confAdv");
+      getConfig((char*)"confAdd");
+      getConfig((char*)"confTime");
+      getConfig((char*)"confLog");
+      sendLog(F("------"));
+    }
+    else if (strncmp(cmdPayload_lower, "delconf", 7) == 0) {
+      sendLog(F("deleting configuration..."));
+      deleteConfig();
+    }
+    
+    cmdInQueue = false;
+  }
+}
+
+void cmdPrintHelp() {
+  sendLog(F("valid commands:"));
+  sendLog(F("   sysinfo       show uptime, heap usage..."));
+  sendLog(F("   date          show current date/time"));
+  sendLog(F("   syncclock     perform NTP time sync now"));
+  sendLog(F("   debugmode [0/1]"));
+  sendLog(F("   loadconf      load saved configuration"));
+  sendLog(F("   getconf       list all conf parameters"));
+  sendLog(F("   get [PARAM]   show conf value"));
+  sendLog(F("   get values    list current saved values"));
+  sendLog(F("   set [PARAM] [VALUE] (1 blank after PARAM to clear)"));
+  sendLog(F("   saveconf      save all configurations"));
+  sendLog(F("   savevalues    save set values"));
+  sendLog(F("   clearcreds    delete all passwords"));
+  sendLog(F("   clearwifi     delete WiFi configurations"));
+  sendLog(F("   encrypt       switch on encrypted stored passwords"));
+  sendLog(F("   decrypt       switch off encrypted stored passwords"));
+  sendLog(F("                 WARNING: deletes all currently saved credentials"));
+  sendLog(F("   ls            list files on SPIFFS"));
+  sendLog(F("   delconf       delete ALL configuration"));
+  sendLog(F("   restart"));
+}

+ 42 - 0
src/commonFunctions.ino

@@ -0,0 +1,42 @@
+/*#include <string.h>
+#include <ctype.h>*/
+char *strlwr(char *str)
+{
+  unsigned char *p = (unsigned char *)str;
+  while (*p)
+  {
+    *p = tolower((unsigned char)*p);
+    p++;
+  }
+  return str;
+}
+
+double round2(double value) {
+   return round(value * 100) / 100.0;
+}
+
+double round1(double value) {
+   return round(value * 10) / 10.0;
+}
+
+char* XORENC(char* in, char* key){
+  // Brad @ pingturtle.com
+  int insize = strlen(in);
+  int keysize = strlen(key);
+  for(int x=0; x<insize; x++){
+    for(int i=0; i<keysize;i++){
+      in[x]=(in[x]^key[i])^(x*i);
+    }
+  }
+  return in;
+}
+
+char timeStringFromSeconds[10];
+char* getTimeStringFromSeconds(unsigned int inSeconds) {
+  unsigned int minutes, hours, seconds;
+  minutes = inSeconds/60;
+  hours = minutes/60;
+  seconds = inSeconds - (hours*3600 + minutes*60);
+  sprintf(timeStringFromSeconds, "%02u:%02u:%02u", hours, minutes, seconds);
+  return timeStringFromSeconds;
+}

File diff suppressed because it is too large
+ 515 - 306
src/config.ino


+ 9 - 6
src/WiFiThermostat/html.h → src/html.h

@@ -38,12 +38,12 @@ static const char html_confsaved_body[] PROGMEM = R"=====(
 <td><form action='.' method='get'><button class='bgrey'>Main Menu</button></form></td></tr></table>
 )====="; // html_confsaved_body
 
-static const char html_confsavedrestart_body[] PROGMEM = R"=====(
-<script>setTimeout(function(){window.location.href = 'conf';}, 10000);</script>
-<div>Configuration saved. Restarting...</div>
-<table style='width:100%'><tr><td style='width:50%'><form action='conf' method='get'><button class='bgrey'>Config</button></form></td>
-<td><form action='.' method='get'><button class='bgrey'>Main Menu</button></form></td></tr></table>
-)====="; // html_confsavedreboot_body
+//static const char html_confsavedrestart_body[] PROGMEM = R"=====(
+//<script>setTimeout(function(){window.location.href = 'conf';}, 10000);</script>
+//<div>Configuration saved. Restarting...</div>
+//<table style='width:100%'><tr><td style='width:50%'><form action='conf' method='get'><button class='bgrey'>Config</button></form></td>
+//<td><form action='.' method='get'><button class='bgrey'>Main Menu</button></form></td></tr></table>
+//)====="; // html_confsavedreboot_body
 
 static const char html_restarting_body[] PROGMEM = R"=====(
 <script>setTimeout(function(){window.location.href = '.';}, 10000);</script>
@@ -59,6 +59,9 @@ static const char html_clearconf_body[] PROGMEM = R"=====(
 
 static const char html_footer1[] PROGMEM = R"=====(
 <div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/>)=====";
+static const char html_footer_a1[] PROGMEM = R"=====(<a href=')=====";
+static const char html_footer_a2[] PROGMEM = R"=====(' target='_blank' style='color:#AAA;'>)=====";
+static const char html_footer_ae[] PROGMEM = R"=====(</a>)=====";
 static const char html_footer2[] PROGMEM = R"=====(</div>
 </div></body></html>
 )=====";

+ 7 - 3
src/WiFiThermostat/html_conf.h → src/html_conf.h

@@ -12,12 +12,16 @@ static const char html_conf_body[] PROGMEM = R"=====(
 <tr><td><form action='confadv' method='get'><button>Thermostat Advanced</button></form></td></tr>
 <tr><td><form action='confadd' method='get'><button>Additional Functions</button></form></td></tr>
 <tr><td><form action='update' method='get'><button>OTA Firmware Update</button></form></td></tr>
+<tr><td>&nbsp;</td></tr>
 )====="; // html_conf_body
 
 static const char html_conf_body_console[] PROGMEM = R"=====(
-<tr><td>&nbsp;</td></tr>
-<tr><td><form action='console' method='get'><button>Console</button></form></td></tr>
-)====="; // html_conf_body
+<tr><td><form action='console' method='get'><button>Web Console</button></form></td></tr>
+)====="; // html_conf_body_console
+
+static const char html_conf_body_wsconsole[] PROGMEM = R"=====(
+<tr><td><form action='wsconsole' method='get'><button>WebSockets Console</button></form></td></tr>
+)====="; // html_conf_body_wsconsole
 
 static const char html_conf_body_end[] PROGMEM = R"=====(
 </table>

+ 0 - 0
src/WiFiThermostat/html_confAdd.h → src/html_confAdd.h


+ 0 - 0
src/WiFiThermostat/html_confAdv.h → src/html_confAdv.h


+ 0 - 0
src/WiFiThermostat/html_confBas.h → src/html_confBas.h


+ 1 - 1
src/WiFiThermostat/html_confDevWiFi.h → src/html_confDevWiFi.h

@@ -131,7 +131,7 @@ Reconnect always tries Main-AP first, then Fallback-AP.</p>
 <div></div>
 <table style='width:100%'>
   <td style='width:50%'><button onclick='location="conf";' class='bgrey'>Cancel</button></td>
-  <td style='width:50%'><button onclick='return saveConf()' class='bred'>Save &amp; Restart</button></td>
+  <td style='width:50%'><button onclick='return saveConf()' class='bred'>Save</button></td>
 </tr></table>
 </div>
 )====="; // html_confDevWiFi_body

+ 27 - 5
src/WiFiThermostat/html_confLog.h → src/html_confLog.h

@@ -7,12 +7,31 @@ static const char html_conflog_script[] PROGMEM = R"=====(
   var xhttp, reqTime, reqFin;
   function selectElement(el, val) {    
     el.value = val;
-}
-  
+  }
+  function setCbx(el, da) {
+    if(da == '1') {
+      el.checked = true;
+      el.style.visibility = 'visible';
+    }
+    else {
+      el.checked = false;
+      el.style.visibility = 'visible';
+    }
+  }
+  function updCbxVal(el) {
+    if (el.checked) el.value = '1';
+    else {
+      el.checked = true;
+    el.value = '0';
+      el.style.visibility = 'hidden';
+    }
+  }
+   
   function transmit(f) {
     if (!xhttp) {   
     reqTime = 0;
     reqFin = false;
+    updCbxVal(g('logWebRequests'));
     xhttp = new XMLHttpRequest();
     xhttp.timeout = 1000;
     xhttp.overrideMimeType('application/json');
@@ -21,9 +40,10 @@ static const char html_conflog_script[] PROGMEM = R"=====(
     xhttp.onreadystatechange = function () {
       if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
         var data = JSON.parse(xhttp.responseText);
-		selectElement(g('logLevSer'), data.logLevSer);
-		selectElement(g('logLevWeb'), data.logLevWeb);
-		selectElement(g('logLevMqtt'), data.logLevMqtt);
+		    selectElement(g('logLevSer'), data.logLevSer);
+		    selectElement(g('logLevWeb'), data.logLevWeb);
+		    selectElement(g('logLevMqtt'), data.logLevMqtt);
+        setCbx(g('logWebRequests'), data.logWebRequests);
         xhttp = null;
         reqFin = true;
        }
@@ -38,6 +58,7 @@ static const char html_conflog_script[] PROGMEM = R"=====(
     return false;
   }
   function saveConf() {
+    updCbxVal(g('logWebRequests'));
     g('frmConf').submit();
   }
   function init() {
@@ -81,6 +102,7 @@ static const char html_conflog_body[] PROGMEM = R"=====(
   <option value="5">Verbose</option>
 </select></p>
 <br>
+<p><b>Log Web Requests</b>&nbsp;<input type='checkbox' name='logWebRequests' id='logWebRequests'></p>
 </fieldset>
 </form>
 <div></div>

+ 1 - 1
src/WiFiThermostat/html_confMqtt.h → src/html_confMqtt.h

@@ -144,7 +144,7 @@ Just set them to 0 to disable.</p>
 <div></div>
 <table style='width:100%'>
 <td style='width:50%'><button onclick='location="conf";' class='bgrey'>Cancel</button></td>
-<td style='width:50%'><button onclick='return saveConf()' class='bred'>Save &amp; Restart</button></td>
+<td style='width:50%'><button onclick='return saveConf()' class='bred'>Save</button></td>
 </tr></table>
 </div>
 )====="; // html_confmqtt_body

+ 2 - 2
src/WiFiThermostat/html_confTime.h → src/html_confTime.h

@@ -78,8 +78,8 @@ static const char html_conftime_body[] PROGMEM = R"=====(
 <p><b>NTP Server 1</b><br><input type='text' name='NTPServer1' id='NTPServer1'></p>
 <p><b>NTP Server 2</b><br><input type='text' name='NTPServer2' id='NTPServer2'></p>
 <p><b>Timezone String</b><br><input type='text' name='TZStr' id='TZStr'></p>
-<p class='n'>a valid TZ string (right column) from here: <br><a href='https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv'>zones.csv</a></p>
-<p><b>NTP Sync Interval [s]</b><br><input type='text' name='NTPSyncInt' id='NTPSyncInt'></p>
+<p class='n'>a valid TZ string (right column) from here: <br><a target='_blank' href='https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv'>zones.csv</a></p>
+<p><b>NTP Sync Interval [m]</b><br><input type='text' name='NTPSyncInt' id='NTPSyncInt'></p>
 </fieldset>
 <div></div><br>
 </form>

+ 8 - 4
src/WiFiThermostat/html_confWeb.h → src/html_confWeb.h

@@ -29,7 +29,8 @@ static const char html_confweb_script[] PROGMEM = R"=====(
     reqTime = 0;
     reqFin = false;
     updCbxVal(g('httpAuth'));
-    updCbxVal(g('enableConsole'));
+    updCbxVal(g('wConsole'));
+    updCbxVal(g('wsConsole'));
     xhttp = new XMLHttpRequest();
     xhttp.timeout = 1000;
     xhttp.overrideMimeType('application/json');
@@ -46,7 +47,8 @@ static const char html_confweb_script[] PROGMEM = R"=====(
         g('httpP1').value = data.httpP1;
         g('httpU2').value = data.httpU2;
         g('httpP2').value = data.httpP2;
-        setCbx(g('enableConsole'), data.enableConsole);
+        setCbx(g('wConsole'), data.wConsole);
+        setCbx(g('wsConsole'), data.wsConsole);
         xhttp = null;
         reqFin = true;
        }
@@ -63,7 +65,8 @@ static const char html_confweb_script[] PROGMEM = R"=====(
   //transmit();
   function saveConf() {
     updCbxVal(g('httpAuth'));
-    updCbxVal(g('enableConsole'));
+    updCbxVal(g('wConsole'));
+    updCbxVal(g('wsConsole'));
     if(g('httpPASet').checked && g('httpPA').value != g('httpPAC').value) {
       alert("Admin password verification failed!");
     }
@@ -116,7 +119,8 @@ make usaccessible without Auth.</p>
 <br>
 <fieldset>
 <legend>Console</legend>
-<p><b>Enable Web-Console (Experimental)</b>&nbsp;<input type='checkbox' name='enableConsole' id='enableConsole'></p>
+<p><b>Enable Web Console</b>&nbsp;<input type='checkbox' name='wConsole' id='wConsole'></p>
+<p><b>Enable WebSockets Console (Experimental)</b>&nbsp;<input type='checkbox' name='wsConsole' id='wsConsole'></p>
 </fieldset>
 </form>
 <div></div>

+ 89 - 0
src/html_console.h

@@ -0,0 +1,89 @@
+/* clang-format off */
+
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+
+static const char js_csapp[] PROGMEM = R"=====(function g(i) { return document.getElementById(i) };
+var xhttp, updateTime, reqTime, reqFin;
+var msgList = document.getElementById('msgs');
+
+g('cmdInput').addEventListener("keyup", function(event) {
+    event.preventDefault();
+    if (event.keyCode === 13) {
+		sendCmd();
+    }
+});
+
+function sendCmd() {
+  var form = g('cmdForm');
+  msgList.innerHTML += 'Sent: ' + g('cmdInput').value + '\n';
+  g('cmd').value=g('cmdInput').value;
+  g('cmdInput').value='';
+  g('cmdInput').value = '';
+  msgList.scrollTop = msgList.scrollHeight;
+  return transmit(form);
+}
+
+var lastMsgIndex=0;
+
+function transmit(f) {
+  if (!xhttp) { 
+    reqTime = 0;
+    reqFin = false;
+    xhttp = new XMLHttpRequest();
+    xhttp.timeout = 1000;
+    xhttp.overrideMimeType("text/plain");
+    xhttp.open('POST', 'webcsapi');
+    xhttp.send(f ? (new FormData(f)) : '');
+    xhttp.onreadystatechange = function () {
+      if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+        var data = xhttp.responseText.split("\n");
+		    for(i=0; i < data.length; i++) {
+		      var numEnd = data[i].indexOf("}");
+		      var num = parseInt(data[i].substring(1, numEnd));
+		      var msg = data[i].substring(numEnd+1);
+		      if(num > lastMsgIndex || lastMsgIndex == 0) {
+            msgList.innerHTML += msg;
+			      msgList.scrollTop = msgList.scrollHeight;
+			      lastMsgIndex = num;
+		      }
+		    }
+		
+        xhttp = null;
+        updateTime = 0;
+        reqFin = true;
+        }
+      else {
+        if(!reqFin && reqTime > 10) {
+          xhttp = null;
+          reqFin = true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+transmit();
+setInterval(transmit, 2000);
+
+)====="; // js_csapp
+
+static const char html_console_body[] PROGMEM = R"=====(
+<p><b>Console</b></p>
+<table style='width:100%'>
+<tr><td style='width:800px;'><textarea id="msgs" style="width:100%;min-height:400px;resize:both;"></textarea></td></tr>
+<tr><td><input id='cmdInput' type='text'></td></tr>
+<tr><td><button type='submit' id='btnSend' onclick='sendCmd();'>Send</button></td></tr>
+<tr><td><form action='.' method='get'><button class='bgrey'>Close</button></form></td></tr>
+</table>
+
+<form id='cmdForm'>
+<input type='hidden' name='cmd' id='cmd'>
+</form>
+
+<script src="csapp.js"></script>
+
+
+)====="; // html_console_body
+
+#endif

+ 6 - 2
src/WiFiThermostat/html_console.h → src/html_console_ws.h

@@ -1,5 +1,7 @@
 /* clang-format off */
 
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+
 static const char js_wsapp[] PROGMEM = R"=====(var cmd = document.getElementById('cmd');
 var listMsgs = document.getElementById('msgs');
 var socketStatus = document.getElementById('status');
@@ -49,7 +51,7 @@ document.getElementById("cmd")
 });
 )====="; // js_wsapp
 
-static const char html_console_body[] PROGMEM = R"=====(
+static const char html_wsconsole_body[] PROGMEM = R"=====(
 <p><b>Console</b></p>
 <div id="status">Connecting...</div>
 <table style='width:100%'>
@@ -60,4 +62,6 @@ static const char html_console_body[] PROGMEM = R"=====(
 <tr><td style='width:100%'><form action='.' method='get'><button class='bgrey'>Main Menu</button></form></td></tr>
 </table>
 <script src="wsapp.js"></script>
-)====="; // html_console_body
+)====="; // html_wsconsole_body
+
+#endif

+ 6 - 2
src/WiFiThermostat/html_main.h → src/html_main.h

@@ -139,13 +139,17 @@ static const char html_main_body[] PROGMEM = R"=====(
 <tr><td>Time</td><td><span id='time'></span></td></tr>
 </table>
 <br>
-<table style='width:100%'>)====="; // html_main_body2
+<table style='width:100%'>
+<tr><td style='width:100%'><form action='sysinfo' method='get'><button>System Information</button></form></td></tr>)====="; // html_main_body2
 
 static const char html_main_body_adminonly[] PROGMEM = R"=====(
 <tr><td style='width:100%'><form action='conf' method='get'><button>Configuration</button></form></td></tr>)====="; // html_main_body_adminonly
 
 static const char html_main_body_adminonly_console[] PROGMEM = R"=====(
-<tr><td style='width:100%'><form action='console' method='get'><button>Console</button></form></td></tr>)====="; // html_main_body_adminonly_console
+<tr><td style='width:100%'><form action='console' method='get'><button>Web Console</button></form></td></tr>)====="; // html_main_body_adminonly_console
+
+static const char html_main_body_adminonly_wsconsole[] PROGMEM = R"=====(
+<tr><td style='width:100%'><form action='wsconsole' method='get'><button>WebSockets Console</button></form></td></tr>)====="; // html_main_body_adminonly_wsconsole
 
 static const char html_main_body2[] PROGMEM = R"=====(
 <tr><td style='width:100%'><form action='/' method='get' onsubmit='return confirm("Confirm Restart");'><button name='restart' class='bred'>Restart</button></form></td></tr>

+ 0 - 0
src/WiFiThermostat/html_redTemps.h → src/html_redTemps.h


+ 111 - 0
src/html_sysinfo.h

@@ -0,0 +1,111 @@
+/* clang-format off */
+
+static const char html_sysinfo_script[] PROGMEM = R"=====(
+<script>
+  function g(i) { return document.getElementById(i) };
+  var xhttp, updateTime, reqTime, reqFin;
+  function transmit(f) {
+    if (!xhttp) { 
+      reqTime = 0;
+      reqFin = false;
+      xhttp = new XMLHttpRequest();
+      xhttp.timeout = 1000;
+      xhttp.overrideMimeType("application/json");
+      xhttp.open('GET', 'sysinfod');
+      xhttp.send(f ? (new FormData(f)) : '');
+      xhttp.onreadystatechange = function () {
+        if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+          var data = JSON.parse(xhttp.responseText);
+          if(data.DevName !== undefined) g('DevName').innerHTML = data.DevName;
+          if(data.HostName !== undefined) g('HostName').innerHTML = data.HostName;
+          if(data.SSID !== undefined) g('SSID').innerHTML = data.SSID;
+          if(data.WiFiConf !== undefined) {
+            if(data.WiFiConf == 1) g('WiFiConf').innerHTML = 'Default';
+            else if(data.WiFiConf == 2) g('WiFiConf').innerHTML = 'Fallback';
+            else g('WiFiConf').innerHTML = data.WiFiConf;
+            }
+          if(data.MAC !== undefined) g('MAC').innerHTML = data.MAC;
+          if(data.IP !== undefined) g('IP').innerHTML = data.IP;
+          if(data.GW !== undefined) g('GW').innerHTML = data.GW;
+          if(data.DNS !== undefined) g('DNS').innerHTML = data.DNS;
+          if(data.UpTime !== undefined) g('UpTime').innerHTML = data.UpTime;
+          if(data.HeapFree !== undefined) g('HeapFree').innerHTML = data.HeapFree + ' Bytes';
+          if(data.HeapFragment !== undefined) g('HeapFragment').innerHTML = data.HeapFragment + ' %';
+          if(data.HeapMaxBlock !== undefined) g('HeapMaxBlock').innerHTML = data.HeapMaxBlock + ' Bytes';
+          if(data.ResetReason !== undefined) g('ResetReason').innerHTML = data.ResetReason;
+          if(data.FWName !== undefined) g('FWName').innerHTML = data.FWName;
+          if(data.FWVer !== undefined) g('FWVer').innerHTML = data.FWVer;
+          if(data.FWBuilt !== undefined) g('FWBuilt').innerHTML = data.FWBuilt;
+          if(data.FWCr !== undefined) g('FWCr').innerHTML = data.FWCr;
+          if(data.FWDebug !== undefined) g('FWDebug').innerHTML = data.FWDebug;
+          if(data.CoreVersion !== undefined) g('CoreVersion').innerHTML = data.CoreVersion;
+          if(data.SDKVersion !== undefined) g('SDKVersion').innerHTML = data.SDKVersion;
+          if(data.CPUfreq !== undefined) g('CPUfreq').innerHTML = data.CPUfreq + ' MHz';
+          if(data.SketchSize !== undefined) g('SketchSize').innerHTML = data.SketchSize + ' Bytes';
+          if(data.FlashSize !== undefined) g('FlashSize').innerHTML = data.FlashSize + ' Bytes';
+          if(data.Time !== undefined) g('Time').innerHTML = data.Time;
+          if(data.Date !== undefined) g('Date').innerHTML = data.Date;
+          xhttp = null;
+          updateTime = 0;
+          reqFin = true;
+          }
+        else {
+          if(!reqFin && reqTime > 10) {
+            xhttp = null;
+            reqFin = true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+  function init() {
+    transmit();
+  }
+  setInterval(transmit, 2500);
+</script>
+)====="; // html_sysinfo_script
+
+static const char html_sysinfo_body[] PROGMEM = R"=====(
+<p><b>System Information</b></p>
+
+<table style='width:100%'>
+<tr><td>Device Name</td><td><span id='DevName'></td></tr>
+<tr><td colspan='2'>&nbsp;</td></tr>
+<tr><td>Host Name</td><td><span id='HostName'></td></tr>
+<tr><td>SSID</td><td><span id='SSID'></td></tr>
+<tr><td>WiFi-Conf</td><td><span id='WiFiConf'></td></tr>
+<tr><td>MAC</td><td><span id='MAC'></td></tr>
+<tr><td>IP</td><td><span id='IP'></td></tr>
+<tr><td>Gateway</td><td><span id='GW'></td></tr>
+<tr><td>DNS</td><td><span id='DNS'></td></tr>
+<tr><td colspan='2'>&nbsp;</td></tr>
+<tr><td colspan='2'>Heap Memory</td></tr>
+<tr><td>&nbsp;Free</td><td><span id='HeapFree'></td></tr>
+<tr><td>&nbsp;Fragmentation</td><td><span id='HeapFragment'></td></tr>
+<tr><td>&nbsp;Max Blocksize</td><td><span id='HeapMaxBlock'></td></tr>
+<tr><td>CPU Frequency</td><td><span id='CPUfreq'></td></tr>
+<tr><td colspan='2'>&nbsp;</td></tr>
+<tr><td colspan='2'>Firmware</td></tr>
+<tr><td>Name</td><td><span id='FWName'></td></tr>
+<tr><td>Version</td><td><span id='FWVer'></td></tr>
+<tr><td>Built Date</td><td><span id='FWBuilt'></td></tr>
+<tr><td>Created by</td><td><span id='FWCr'></td></tr>
+<tr><td>Debug Version</td><td><span id='FWDebug'></td></tr>
+<tr><td>Core Version</td><td><span id='CoreVersion'></td></tr>
+<tr><td>SDK Version</td><td><span id='SDKVersion'></td></tr>
+<tr><td>Sketch Size</td><td><span id='SketchSize'></td></tr>
+<tr><td>Flash Size</td><td><span id='FlashSize'></td></tr>
+<tr><td colspan='2'>&nbsp;</td></tr>
+<tr><td>Date</td><td><span id='Date'></td></tr>
+<tr><td>Time</td><td><span id='Time'></td></tr>
+<tr><td>Reset Reason</td><td><span id='ResetReason'></td></tr>
+<tr><td>UpTime</td><td><span id='UpTime'></td></tr>
+</table>
+
+<table style='width:100%'>
+<tr>
+<td style='width:100%'><button onclick='location=".";' class='bgrey'>Close</button></td>
+</tr></table>
+<div></div>
+)====="; // html_confweb_body

+ 1913 - 0
src/httpServer.ino

@@ -0,0 +1,1913 @@
+
+#include "html.h"
+#include "html_conf.h"
+#include "html_confAdd.h"
+#include "html_confAdv.h"
+#include "html_confBas.h"
+#include "html_confDevWiFi.h"
+#include "html_confMqtt.h"
+#include "html_confWeb.h"
+#include "html_confTime.h"
+#include "html_confLog.h"
+#include "html_main.h"
+#include "html_redTemps.h"
+#include "html_sysinfo.h"
+
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+#include "html_console_ws.h"
+#endif
+
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_BUFFERED
+#include "html_console.h"
+#endif
+
+void httpServerHandleMainPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_main_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_main_body);
+  if (httpIsAuthenticatedAdmin())
+  {
+    httpServer.sendContent_P(html_main_body_adminonly);
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_BUFFERED
+    if (confWeb.wConsole)
+      httpServer.sendContent_P(html_main_body_adminonly_console);
+#endif
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+if (confWeb.wsConsole)
+      httpServer.sendContent_P(html_main_body_adminonly_wsconsole);
+#endif
+  }
+  httpServer.sendContent_P(html_main_body2);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleRedTempsPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_redTemps_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_redTemps_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_conf_body);
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_BUFFERED
+    if (confWeb.wConsole)
+      httpServer.sendContent_P(html_conf_body_console);
+#endif
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+  if (confWeb.wsConsole)
+    httpServer.sendContent_P(html_conf_body_wsconsole);
+#endif
+  httpServer.sendContent_P(html_conf_body_end);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfWebPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_confweb_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_confweb_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfMqttPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_confmqtt_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_confmqtt_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfDevWiFiPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_confDevWiFi_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_confDevWiFi_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfBasPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_confbas_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_confbas_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfAdvPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_confadv_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_confadv_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfAddPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_confadd_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_confadd_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfTimePage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_conftime_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_conftime_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfLogPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_conflog_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_conflog_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+void httpServerHandleWSConsolePage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_wsconsole_body);
+  httpServerSendHtmlFooterChunked();
+}
+#endif
+
+void httpServerHandleConsolePage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_console_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleConfSavedPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_confsaved_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+//void httpServerHandleConfSavedRestartPage() {
+//  httpServerSendHtmlHeadChunked();
+//  httpServer.sendContent_P(html_head_end);
+//  httpServer.sendContent_P(html_bodytag);
+//  httpServerSendHtmlBodyPageheadChunked();
+//  httpServer.sendContent_P(html_confsavedrestart_body);
+//  httpServerSendHtmlFooterChunked();
+//}
+
+void httpServerHandleRestartPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag);
+  config_was_changed = false;
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_restarting_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleClearconfPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_clearconf_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerHandleSysInfoPage()
+{
+  httpServerSendHtmlHeadChunked();
+  httpServer.sendContent_P(html_sysinfo_script);
+  httpServer.sendContent_P(html_head_end);
+  httpServer.sendContent_P(html_bodytag_jsinit);
+  httpServerSendHtmlBodyPageheadChunked();
+  httpServer.sendContent_P(html_sysinfo_body);
+  httpServerSendHtmlFooterChunked();
+}
+
+void httpServerSendHtmlHeadChunked()
+{
+  httpServer.setContentLength(CONTENT_LENGTH_UNKNOWN); //Enable Chunked Transfer
+  httpServer.send(200, "text/html", html_head_part1);
+  httpServer.sendContent_P(PGMStr_FIRMWARE_NAME);
+  httpServer.sendContent(" - ");
+  httpServer.sendContent(confDevWiFi.deviceName);
+  httpServer.sendContent_P(html_head_part2);
+}
+
+void httpServerSendHtmlBodyPageheadChunked()
+{
+  httpServer.sendContent_P(html_body_pagehead_part1);
+  httpServer.sendContent_P(PGMStr_FIRMWARE_NAME);
+  httpServer.sendContent(" - ");
+  httpServer.sendContent(confDevWiFi.deviceName);
+  httpServer.sendContent_P(html_body_pagehead_part2);
+  if (config_was_changed)
+    httpServer.sendContent_P(html_body_pagehead_confchangednote);
+}
+
+void httpServerSendHtmlFooterChunked()
+{
+  httpServer.sendContent_P(html_footer1);
+  httpServer.sendContent_P(html_footer_a1);
+  httpServer.sendContent_P(PGMStr_FIRMWARE_URL);
+  httpServer.sendContent_P(html_footer_a2);
+  httpServer.sendContent_P(PGMStr_FIRMWARE_NAME);
+  httpServer.sendContent_P(html_footer_ae);
+  httpServer.sendContent(" ");
+  httpServer.sendContent_P(PGMStr_FIRMWARE_VERSION);
+#ifdef DEBUGMODE
+  httpServer.sendContent("&nbsp;<span style='color:red;font-weight:bold;'>DEBUG</span>");
+#endif
+  httpServer.sendContent(" by ");
+  httpServer.sendContent_P(html_footer_a1);
+  httpServer.sendContent_P(PGMStr_FIRMWARE_COPYRIGHT_URL);
+  httpServer.sendContent_P(html_footer_a2);
+  httpServer.sendContent_P(PGMStr_FIRMWARE_COPYRIGHT);
+  httpServer.sendContent_P(html_footer_ae);
+  httpServer.sendContent_P(html_footer2);
+  httpServer.sendContent("");
+  httpServer.client().stop();
+}
+
+boolean httpIsAuthenticated()
+{
+  if (WifiInApMode && strlen(confDevWiFi.WiFiAPModePassword) >= 8)
+    return true;
+  if (confWeb.http_user_auth)
+  {
+    boolean useAuth = false;
+    boolean isAuthenticated = false;
+    // user authentication enabled - only allow access without authentication if no admin password is set
+    // or if user1 credentials are empty (access in "user mode")
+    if (strlen(confWeb.http_pass) > 0 || strlen(confWeb.http_pass1) > 0 || strlen(confWeb.http_pass2) > 0)
+      useAuth = true;
+    if (strlen(confWeb.http_pass) == 0)
+    {
+      return true; // no admin password set - in this case authentication is off
+    }
+    if (useAuth)
+    {
+      // allow access if one set of valid credentials are given
+      if ((strlen(confWeb.http_user) > 0 && strlen(confWeb.http_pass) > 0))
+      {
+        if (httpServer.authenticate(confWeb.http_user, confWeb.http_pass))
+          isAuthenticated = true;
+      }
+      if ((strlen(confWeb.http_user1) > 0 && strlen(confWeb.http_pass1) > 0))
+      {
+        if (httpServer.authenticate(confWeb.http_user1, confWeb.http_pass1))
+          isAuthenticated = true;
+      }
+      if ((strlen(confWeb.http_user2) > 0 && strlen(confWeb.http_pass2) > 0))
+      {
+        if (httpServer.authenticate(confWeb.http_user2, confWeb.http_pass2))
+          isAuthenticated = true;
+      }
+      // also allow access if admin credentials are set but user1 password is empty and user-authentication is enabled
+      if (strlen(confWeb.http_pass1) == 0)
+      {
+        isAuthenticated = true;
+      }
+      return isAuthenticated;
+    }
+    // allow access if all credentials are empty
+    else
+      return true;
+  }
+  // user authentication disabled - only allow access without password if no admin password is set
+  else
+  {
+    if (strlen(confWeb.http_pass) > 0)
+    {
+      if (httpServer.authenticate(confWeb.http_user, confWeb.http_pass))
+        return true;
+      else
+        return false;
+    }
+    else
+      return true;
+  }
+}
+
+boolean httpIsAuthenticatedAdmin()
+{
+  if (WifiInApMode && strlen(confDevWiFi.WiFiAPModePassword) >= 8)
+    return true;
+  boolean auth = false;
+  if ((strlen(confWeb.http_user) > 0 && strlen(confWeb.http_pass) > 0))
+    auth = true;
+  if (auth)
+  {
+    if (!httpServer.authenticate(confWeb.http_user, confWeb.http_pass))
+      return false;
+    else
+      return true;
+  }
+  else
+    return true;
+}
+
+void httpServerHandleNotFound()
+{
+  httpServer.send(404, "text/plain", "404 NOT FOUND");
+}
+
+void httpSendUnauthorized()
+{
+  httpServer.send(401, "text/plain", "UNAUTHORIZED");
+}
+
+void httpSend200OK()
+{
+  httpServer.send(200, "text/plain", "OK");
+}
+
+boolean httpCheckToken()
+{
+  if (confWeb.http_token[0] != '\0')
+  { // dont accept empty token
+    if (httpServer.hasArg("token"))
+    {
+      char buf[20];
+      httpServer.arg("token").toCharArray(buf, 20);
+      if (strcmp(buf, confWeb.http_token) == 0)
+        return true;
+      else
+        return false;
+    }
+    else
+      return false;
+  }
+  else
+    return false;
+}
+
+void httpServerInit()
+{
+  httpServer.on("/style.css", []() {
+    httpServer.sendHeader("cache-control", "max-age=86400", false);
+    httpServer.send_P(200, "text/css", html_stylesheet);
+  });
+
+  httpServer.on("/api", []() {
+    if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      if (confLog.logWebRequests || httpServer.args() > 0)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /api (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+      //sendLog("WEB: /api", LOGLEVEL_INFO);
+      if (httpServer.hasArg("BtnPlus"))
+      {
+        setTempStepUp();
+        sendLog(F("WEB: BtnPlus"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnMinus"))
+      {
+        setTempStepDown();
+        sendLog(F("WEB: BtnMinus"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnPset0"))
+      {
+        setPresetTo(0);
+        sendLog(F("WEB: BtnPset0"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnPset1"))
+      {
+        setPresetTo(1);
+        sendLog(F("WEB: BtnPset1"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnPset2"))
+      {
+        setPresetTo(2);
+        sendLog(F("WEB: BtnPset2"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnOn"))
+      {
+        setHeatingmodeTo(1);
+        sendLog(F("WEB: BtnOn"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnOff"))
+      {
+        setHeatingmodeTo(0);
+        sendLog(F("WEB: BtnOff"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnL1Plus"))
+      {
+        setTempLowStepUp();
+        sendLog(F("WEB: BtnL1Plus"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnL1Minus"))
+      {
+        setTempLowStepDown();
+        sendLog(F("WEB: BtnL1Minus"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnL2Plus"))
+      {
+        setTempLow2StepUp();
+        sendLog(F("WEB: BtnL2Plus"), LOGLEVEL_INFO);
+      } //if
+      if (httpServer.hasArg("BtnL2Minus"))
+      {
+        setTempLow2StepDown();
+        sendLog(F("WEB: BtnL2Minus"), LOGLEVEL_INFO);
+      } //if
+
+      if (httpServer.hasArg("setTemp"))
+      {
+        sendLog(F("WEB: /api?setTemp"), LOGLEVEL_INFO);
+        char bufVal[20];
+        httpServer.arg("setTemp").toCharArray(bufVal, 20);
+        float valueFloat = round(atof(bufVal) * 2.0) / 2.0;
+        setTempTo(valueFloat);
+      }
+
+      if (httpServer.hasArg("setMode"))
+      {
+        sendLog(F("WEB: /api?setMode"), LOGLEVEL_INFO);
+        char bufVal[20];
+        httpServer.arg("setMode").toCharArray(bufVal, 20);
+        int valueInt = atoi(bufVal);
+        if (valueInt >= 0 && valueInt <= 1)
+          setHeatingmodeTo(valueInt);
+      }
+
+      if (httpServer.hasArg("setPreset"))
+      {
+        sendLog(F("WEB: /api?setPreset"), LOGLEVEL_INFO);
+        char bufVal[20];
+        httpServer.arg("setPreset").toCharArray(bufVal, 20);
+        int valueInt = atoi(bufVal);
+        if (valueInt >= 0 && valueInt <= 2)
+          setPresetTo(valueInt);
+      }
+
+      //char ch_currTemp[6];
+      //char ch_currSetTemp[6];
+      //dtostrf(currTemp, 1, 1, ch_currTemp );
+      //dtostrf(setTemp, 1, 1, ch_currSetTemp );
+
+      //build json object of program data
+      StaticJsonDocument<700> json;
+
+      json["devname"] = confDevWiFi.deviceName;
+      json["ssid"] = WiFi.SSID();
+      json["WiFiNum"] = persWM.getActiveWiFiNum();
+      //json["uptime"] = uptimeStr;
+      json["uptime"] = getUptimeStr();
+
+#ifdef ENABLE_FEATURE_NTP_TIME
+      if (confTime.ntpEnable)
+      {
+        char buf[13];
+        updateTime();
+        if (lt.tm_year > 70)
+        {
+          strftime(buf, sizeof(buf), "%H:%M", &lt);
+          json["time"] = buf;
+          strftime(buf, sizeof(buf), "%d.%m.%Y", &lt);
+          json["date"] = buf;
+        }
+      }
+#endif
+
+      json["freeheap"] = ESP.getFreeHeap();
+
+      mqtt_updateCurrentStateName();
+      json["mqttstate"] = mqttCurrentStateName;
+      json["mqtthost"] = confMqtt.mqtt_server;
+
+      if (mqttReconnects < 1)
+        json["mqttreconn"] = mqttReconnects;
+      else
+        json["mqttreconn"] = mqttReconnects - 1;
+
+      json["setTemp"] = setTemp;
+      json["currSetTemp"] = currSetTemp;
+      json["temp"] = round1(currTemp);
+      json["hum"] = int(currHum);
+      json["heating"] = turnHeatingOn;
+      json["mode"] = heatingMode;
+      json["modeName"] = currentModeName;
+      json["pset"] = preset;
+      json["psetName"] = currentPresetName;
+      json["psetName0"] = confAdv.psetName0;
+      json["psetName1"] = confAdv.psetName1;
+      json["psetName2"] = confAdv.psetName2;
+      json["tempLow"] = setTempLow;
+      json["tempLow2"] = setTempLow2;
+      json["outTemp"] = round1(outTemp);
+      json["outHum"] = outHum;
+
+      char jsonchar[500];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /api
+
+  httpServer.on("/confDataWeb", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //Serial.println("httpServer.on /confdata");
+      //sendLog("WEB: /confDataWeb", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confDataWeb (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      StaticJsonDocument<1000> json;
+
+      json["apiToken"] = confWeb.http_token;
+      json["httpUA"] = confWeb.http_user;
+      //json["httpPA"] =  confWeb.http_pass;
+      if (strlen(confWeb.http_pass) > 0)
+        json["httpPA"] = "****";
+      else
+        json["httpPA"] = "";
+
+      if (confWeb.http_user_auth)
+        json["httpAuth"] = 1;
+      else
+        json["httpAuth"] = 0;
+
+      json["httpU1"] = confWeb.http_user1;
+      //json["httpP1"] =  confWeb.http_pass1;
+      if (strlen(confWeb.http_pass1) > 0)
+        json["httpP1"] = "****";
+      else
+        json["httpP1"] = "";
+      json["httpU2"] = confWeb.http_user2;
+      //json["httpP2"] =  confWeb.http_pass2;
+      if (strlen(confWeb.http_pass2) > 0)
+        json["httpP2"] = "****";
+      else
+        json["httpP2"] = "";
+
+      if (confWeb.wConsole)
+        json["wConsole"] = 1;
+      else
+        json["wConsole"] = 0;
+        
+      if (confWeb.wsConsole)
+        json["wsConsole"] = 1;
+      else
+        json["wsConsole"] = 0;
+
+      yield();
+
+      char jsonchar[1000];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /confdweb
+
+  httpServer.on("/confDataMqtt", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //sendLog("WEB: /confDataMqtt", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confDataMqtt (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      StaticJsonDocument<1000> json;
+
+      if (confMqtt.mqtt_enable)
+        json["mqttEnable"] = 1;
+      else
+        json["mqttEnable"] = 0;
+
+      json["mqttHost"] = confMqtt.mqtt_server;
+      json["mqttPort"] = confMqtt.mqtt_port;
+      json["mqttUser"] = confMqtt.mqtt_user;
+
+      //json["mqttPass"] =  confMqtt.mqtt_pass;
+      if (strlen(confMqtt.mqtt_pass) > 0)
+        json["mqttPass"] = "****";
+      else
+        json["mqttPass"] = "";
+
+      json["inTop"] = confMqtt.mqtt_topic_in;
+      json["outTop"] = confMqtt.mqtt_topic_out;
+
+      if (confMqtt.mqtt_outRetain)
+        json["outRet"] = 1;
+      else
+        json["outRet"] = 0;
+      if (confMqtt.mqtt_outRetain_sensors)
+        json["outRetSens"] = 1;
+      else
+        json["outRetSens"] = 0;
+
+      json["outPubInt"] = confMqtt.mqtt_outPubInterval;
+      json["outPubIntSens"] = confMqtt.mqtt_outPubInterval_sensors;
+
+      json["willTop"] = confMqtt.mqtt_willTopic;
+      json["willQos"] = confMqtt.mqtt_willQos;
+
+      if (confMqtt.mqtt_willRetain)
+        json["willRet"] = 1;
+      else
+        json["willRet"] = 0;
+
+      json["willMsg"] = confMqtt.mqtt_willMsg;
+      json["connMsg"] = confMqtt.mqtt_connMsg;
+
+      if (confMqtt.mqtt_enable_heartbeat)
+        json["hbEnable"] = 1;
+      else
+        json["hbEnable"] = 0;
+
+      json["hbReconn"] = confMqtt.mqtt_heartbeat_maxage_reconnect / 60000;
+      json["hbReboot"] = confMqtt.mqtt_heartbeat_maxage_reboot / 60000;
+
+      yield();
+
+      char jsonchar[1000];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /confdmqtt
+
+  httpServer.on("/setConfWeb", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //sendLog("WEB: /setConfWeb", LOGLEVEL_INFO);
+      String addr = httpServer.client().remoteIP().toString();
+      char buf[40];
+      sprintf(buf, "WEB: /setConfWeb (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+
+      bool httpPASet, httpP1Set, httpP2Set;
+      httpPASet = false;
+      httpP1Set = false;
+      httpP2Set = false;
+      if (httpServer.hasArg("httpPASet"))
+        httpPASet = true;
+      if (httpServer.hasArg("httpP1Set"))
+        httpP1Set = true;
+      if (httpServer.hasArg("httpP2Set"))
+        httpP2Set = true;
+
+      for (int i = 0; i < httpServer.args(); i++)
+      {
+        char bufName[20];
+        char bufValue[101];
+        httpServer.argName(i).toCharArray(bufName, 20);
+        httpServer.arg(i).toCharArray(bufValue, 101);
+
+        if (strlen(bufName) > 0)
+        {
+          Serial.print("web update ");
+          Serial.print(bufName);
+          Serial.print(" = ");
+          Serial.println(bufValue);
+
+          if (strcmp(bufName, "httpUA") == 0 || strcmp(bufName, "httpPA") == 0)
+          {
+            if (httpPASet)
+              setConfig(bufName, bufValue);
+          }
+          else if (strcmp(bufName, "httpU1") == 0 || strcmp(bufName, "httpP1") == 0)
+          {
+            if (httpP1Set)
+              setConfig(bufName, bufValue);
+          }
+          else if (strcmp(bufName, "httpU2") == 0 || strcmp(bufName, "httpP2") == 0)
+          {
+            if (httpP2Set)
+              setConfig(bufName, bufValue);
+          }
+          else if (strcmp(bufName, "httpPASet") != 0 && strcmp(bufName, "httpP1Set") != 0 && strcmp(bufName, "httpP2Set") != 0)
+            setConfig(bufName, bufValue);
+          //else setConfig(bufName, bufValue);
+        }
+      }
+      yield();
+
+      saveConfigWeb();
+      yield();
+      loadConfigWeb();
+
+      httpServerHandleConfSavedPage();
+      config_was_changed = true;
+      // yield();
+      // ESP.restart();
+    }
+  }); //httpServer.on /setConfWeb
+
+  httpServer.on("/setConfMqtt", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //Serial.println("httpServer.on /setConfMqtt");
+      //sendLog("WEB: /setConfMqtt", LOGLEVEL_INFO);
+      String addr = httpServer.client().remoteIP().toString();
+      char buf[40];
+      sprintf(buf, "WEB: /setConfMqtt (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+
+      bool mqttPassSet;
+      mqttPassSet = false;
+      if (httpServer.hasArg("mqttPassSet"))
+        mqttPassSet = true;
+
+      for (int i = 0; i < httpServer.args(); i++)
+      {
+        char bufName[20];
+        char bufValue[101];
+        httpServer.argName(i).toCharArray(bufName, 20);
+        httpServer.arg(i).toCharArray(bufValue, 101);
+
+        if (strlen(bufName) > 0)
+        {
+          Serial.print("web update ");
+          Serial.print(bufName);
+          Serial.print(" = ");
+          Serial.println(bufValue);
+
+          if (strcmp(bufName, "mqttUser") == 0 || strcmp(bufName, "mqttPass") == 0)
+          {
+            if (mqttPassSet)
+              setConfig(bufName, bufValue);
+          }
+          else
+            setConfig(bufName, bufValue);
+        }
+        //saveConfigMqttToFlash = true; // will be saved in next loop()
+        //Serial.println("web triggered saveConfigMqttToFlash");
+      }
+      yield();
+      saveConfigMqtt();
+      yield();
+      loadConfigMqtt();
+
+      //httpServerHandleConfSavedRestartPage();
+      httpServerHandleConfSavedPage();
+      config_was_changed = true;
+      //restart();
+    }
+  }); //httpServer.on /setConfMqtt
+
+  httpServer.on("/confDataDevWiFi", []() {
+    if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confDataDevWiFi", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confDataDevWiFi (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      //for (int i = 0; i < httpServer.args(); i++) {
+      //  char bufName[20];
+      //  char bufValue[101];
+      //  httpServer.argName(i).toCharArray(bufName, 20);
+      //  httpServer.arg(i).toCharArray(bufValue, 101);
+      //
+      //  if (strlen(bufName) > 0) {
+      //    //Serial.print("web update ");
+      //    //Serial.print(bufName);
+      //    //Serial.print(" = ");
+      //    //Serial.println(bufValue);
+      //    setConfig(bufName, bufValue);
+      //  }
+      //  saveConfigToFlash = true; // will be saved in next loop()
+      //  //Serial.println("web triggered saveConfigToFlash");
+      //}
+      //yield();
+
+      //build json object of program data
+      StaticJsonDocument<800> json;
+
+      json["devName"] = confDevWiFi.deviceName;
+      json["hostName"] = confDevWiFi.hostName;
+      json["SSID1"] = confDevWiFi.WiFiSSID1;
+      //json["WPW1"] = confDevWiFi.WiFiPW1;
+      if (strlen(confDevWiFi.WiFiPW1) > 0)
+        json["WPW1"] = "****";
+      else
+        json["WPW1"] = "";
+      json["SSID2"] = confDevWiFi.WiFiSSID2;
+      //json["WPW2"] = confDevWiFi.WiFiPW2;
+      if (strlen(confDevWiFi.WiFiPW2) > 0)
+        json["WPW2"] = "****";
+      else
+        json["WPW2"] = "";
+      json["SSIDAP"] = confDevWiFi.WiFiAPModeSSID;
+      json["WPWAP"] = confDevWiFi.WiFiAPModePassword;
+      json["WAPtout"] = confDevWiFi.WiFiAPModeTimeout;
+      json["WConnCheck"] = confDevWiFi.WiFiConnCheckInterval;
+      json["Wretry"] = confDevWiFi.WiFiRetryInterval;
+      json["Wreboot"] = confDevWiFi.WiFiRebootOnNoConnect;
+
+      yield();
+
+      char jsonchar[1000];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /confDataDevWiFi
+
+  httpServer.on("/setConfDevWiFi", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //sendLog("WEB: /setConfDevWiFi", LOGLEVEL_INFO);
+      String addr = httpServer.client().remoteIP().toString();
+      char buf[40];
+      sprintf(buf, "WEB: /setConfDevWiFi (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+
+      bool WPW1Set, WPW2Set, WPWAPSet;
+      WPW1Set = false;
+      WPW2Set = false;
+      WPWAPSet = false;
+      if (httpServer.hasArg("WPW1Set"))
+        WPW1Set = true;
+      if (httpServer.hasArg("WPW2Set"))
+        WPW2Set = true;
+      if (httpServer.hasArg("WPWAPSet"))
+        WPWAPSet = true;
+
+      for (int i = 0; i < httpServer.args(); i++)
+      {
+        char bufName[20];
+        char bufValue[101];
+        httpServer.argName(i).toCharArray(bufName, 20);
+        httpServer.arg(i).toCharArray(bufValue, 101);
+
+        if (strlen(bufName) > 0)
+        {
+          Serial.print("web update ");
+          Serial.print(bufName);
+          Serial.print(" = ");
+          Serial.println(bufValue);
+
+          if (strcmp(bufName, "SSID1") == 0 || strcmp(bufName, "WPW1") == 0)
+          {
+            if (WPW1Set)
+              setConfig(bufName, bufValue);
+          }
+          else if (strcmp(bufName, "SSID2") == 0 || strcmp(bufName, "WPW2") == 0)
+          {
+            if (WPW2Set)
+              setConfig(bufName, bufValue);
+          }
+          else if (strcmp(bufName, "WPWAP") == 0)
+          {
+            if (WPWAPSet)
+              setConfig(bufName, bufValue);
+          }
+          else
+            setConfig(bufName, bufValue);
+        }
+      }
+      yield();
+      saveConfigDevWiFi();
+      yield();
+      loadConfigDevWiFi();
+
+      //httpServerHandleConfSavedRestartPage();
+      httpServerHandleConfSavedPage();
+
+      config_was_changed = true;
+      //restart();
+    }
+  }); //httpServer.on /setConfDev
+
+  httpServer.on("/setConfBas", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //sendLog("WEB: /setConfBas", LOGLEVEL_INFO);
+      String addr = httpServer.client().remoteIP().toString();
+      char buf[40];
+      sprintf(buf, "WEB: /setConfBas (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+
+      for (int i = 0; i < httpServer.args(); i++)
+      {
+        char bufName[20];
+        char bufValue[101];
+        httpServer.argName(i).toCharArray(bufName, 20);
+        httpServer.arg(i).toCharArray(bufValue, 101);
+
+        if (strlen(bufName) > 0)
+        {
+          Serial.print("web update ");
+          Serial.print(bufName);
+          Serial.print(" = ");
+          Serial.println(bufValue);
+          setConfig(bufName, bufValue);
+        }
+      }
+      yield();
+      saveConfigBas();
+      yield();
+      loadConfigBas();
+
+      httpServerHandleConfSavedPage();
+      config_was_changed = true;
+    }
+  }); //httpServer.on /setConfBas
+
+  httpServer.on("/setConfAdv", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //sendLog("WEB: /setConfAdv", LOGLEVEL_INFO);
+      String addr = httpServer.client().remoteIP().toString();
+      char buf[40];
+      sprintf(buf, "WEB: /setConfAdv (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+
+      for (int i = 0; i < httpServer.args(); i++)
+      {
+        char bufName[20];
+        char bufValue[101];
+        httpServer.argName(i).toCharArray(bufName, 20);
+        httpServer.arg(i).toCharArray(bufValue, 101);
+
+        if (strlen(bufName) > 0)
+        {
+          Serial.print("web update ");
+          Serial.print(bufName);
+          Serial.print(" = ");
+          Serial.println(bufValue);
+          setConfig(bufName, bufValue);
+        }
+      }
+      yield();
+      saveConfigAdv();
+      yield();
+      loadConfigAdv();
+
+      httpServerHandleConfSavedPage();
+      config_was_changed = true;
+    }
+  }); //httpServer.on /setConfAdv
+
+  httpServer.on("/setConfAdd", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //sendLog("WEB: /setConfAdd", LOGLEVEL_INFO);
+      String addr = httpServer.client().remoteIP().toString();
+      char buf[40];
+      sprintf(buf, "WEB: /setConfAdd (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+
+      for (int i = 0; i < httpServer.args(); i++)
+      {
+        char bufName[20];
+        char bufValue[101];
+        httpServer.argName(i).toCharArray(bufName, 20);
+        httpServer.arg(i).toCharArray(bufValue, 101);
+
+        if (strlen(bufName) > 0)
+        {
+          Serial.print("web update ");
+          Serial.print(bufName);
+          Serial.print(" = ");
+          Serial.println(bufValue);
+          setConfig(bufName, bufValue);
+        }
+      }
+      yield();
+      saveConfigAdd();
+      yield();
+      loadConfigAdd();
+
+      httpServerHandleConfSavedPage();
+      config_was_changed = true;
+    }
+  }); //httpServer.on /setConfAdd
+
+#ifdef ENABLE_FEATURE_NTP_TIME
+  httpServer.on("/setConfTime", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //sendLog("WEB: /setConfTime", LOGLEVEL_INFO);
+      String addr = httpServer.client().remoteIP().toString();
+      char buf[40];
+      sprintf(buf, "WEB: /setConfTime (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+
+      for (int i = 0; i < httpServer.args(); i++)
+      {
+        char bufName[20];
+        char bufValue[101];
+        httpServer.argName(i).toCharArray(bufName, 20);
+        httpServer.arg(i).toCharArray(bufValue, 101);
+
+        if (strlen(bufName) > 0)
+        {
+          Serial.print("web update ");
+          Serial.print(bufName);
+          Serial.print(" = ");
+          Serial.println(bufValue);
+          setConfig(bufName, bufValue);
+        }
+      }
+      yield();
+      saveConfigTime();
+      yield();
+      loadConfigTime();
+
+      httpServerHandleConfSavedPage();
+      config_was_changed = true;
+    }
+  }); //httpServer.on /setConfTime
+#endif
+
+  httpServer.on("/setConfLog", []() {
+    if (!httpIsAuthenticatedAdmin())
+      httpSendUnauthorized();
+    else
+    {
+      //sendLog("WEB: /setConfLog", LOGLEVEL_INFO);
+      String addr = httpServer.client().remoteIP().toString();
+      char buf[40];
+      sprintf(buf, "WEB: /setConfLog (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+
+      for (int i = 0; i < httpServer.args(); i++)
+      {
+        char bufName[20];
+        char bufValue[101];
+        httpServer.argName(i).toCharArray(bufName, 20);
+        httpServer.arg(i).toCharArray(bufValue, 101);
+
+        if (strlen(bufName) > 0)
+        {
+          Serial.print("web update ");
+          Serial.print(bufName);
+          Serial.print(" = ");
+          Serial.println(bufValue);
+          setConfig(bufName, bufValue);
+        }
+      }
+      yield();
+      saveConfigLog();
+      yield();
+      loadConfigLog();
+
+      httpServerHandleConfSavedPage();
+      config_was_changed = true;
+    }
+  }); //httpServer.on /setConfLog
+
+  httpServer.on("/confDataBas", []() {
+    if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confDataBas", LOGLEVEL_INFO);
+      //Serial.println("httpServer.on /confdata2");
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confDataBas (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      //for (int i = 0; i < httpServer.args(); i++) {
+      //  char bufName[20];
+      //  char bufValue[101];
+      //  httpServer.argName(i).toCharArray(bufName, 20);
+      //  httpServer.arg(i).toCharArray(bufValue, 101);
+      //
+      //  if (strlen(bufName) > 0) {
+      //    //Serial.print("web update ");
+      //    //Serial.print(bufName);
+      //    //Serial.print(" = ");
+      //    //Serial.println(bufValue);
+      //    setConfig(bufName, bufValue);
+      //  }
+      //  saveConfig2ToFlash = true;
+      //  //Serial.println("web triggered saveConfig2ToFlash");
+      //}
+      //yield();
+
+      //build json object of program data
+      StaticJsonDocument<500> json;
+
+      if (confBas.autoSaveSetTemp)
+        json["autoSaveTemp"] = 1;
+      else
+        json["autoSaveTemp"] = 0;
+
+      if (confBas.autoSaveHeatingMode)
+        json["autoSaveMode"] = 1;
+      else
+        json["autoSaveMode"] = 0;
+
+      if (confBas.saveToMqttRetained)
+        json["saveToMqttRet"] = 1;
+      else
+        json["saveToMqttRet"] = 0;
+
+      json["tempMin"] = confBas.setTempMin;
+      json["tempMax"] = confBas.setTempMax;
+      json["measInt"] = confBas.measureInterval;
+      json["dispInt"] = confBas.displayInterval;
+      json["dispTout"] = confBas.displayTimeout;
+
+      if (confBas.PIR_enablesDisplay)
+        json["PIRenDisp"] = 1;
+      else
+        json["PIRenDisp"] = 0;
+
+      if (confBas.PIR_enablesDisplay_preset0only)
+        json["PIRenDispPs0"] = 1;
+      else
+        json["PIRenDispPs0"] = 0;
+
+      if (confBas.togglingTempHumAIDisplay)
+        json["togTHdisp"] = 1;
+      else
+        json["togTHdisp"] = 0;
+
+      yield();
+
+      char jsonchar[1000];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /confdbas
+
+  httpServer.on("/confDataAdv", []() {
+    if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confDataAdv", LOGLEVEL_INFO);
+      //Serial.println("httpServer.on /confdata2");
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confDataAdv (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      //for (int i = 0; i < httpServer.args(); i++) {
+      //  char bufName[20];
+      //  char bufValue[101];
+      //  httpServer.argName(i).toCharArray(bufName, 20);
+      //  httpServer.arg(i).toCharArray(bufValue, 101);
+      //
+      //  if (strlen(bufName) > 0) {
+      //    //Serial.print("web update ");
+      //    //Serial.print(bufName);
+      //    //Serial.print(" = ");
+      //    //Serial.println(bufValue);
+      //    setConfig(bufName, bufValue);
+      //  }
+      //  saveConfig2ToFlash = true;
+      //  //Serial.println("web triggered saveConfig2ToFlash");
+      //}
+      //yield();
+
+      //build json object of program data
+      StaticJsonDocument<600> json;
+      json["minOffTime"] = confAdv.heatingMinOffTime;
+      json["tempDec"] = confAdv.setTempDecreaseVal;
+      json["hyst"] = confAdv.hysteresis;
+      json["tempCorr"] = confAdv.tempCorrVal;
+      json["humCorr"] = confAdv.humCorrVal;
+      json["offMsg"] = confAdv.offMessage;
+      json["modeName0"] = confAdv.modeName0;
+      json["modeName1"] = confAdv.modeName1;
+      json["psetName0"] = confAdv.psetName0;
+      json["psetName1"] = confAdv.psetName1;
+      json["psetName2"] = confAdv.psetName2;
+      json["iTempLab"] = confAdv.iTempLabel;
+      json["oTempLab"] = confAdv.oTempLabel;
+
+      yield();
+
+      char jsonchar[1000];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /confdadv
+
+  httpServer.on("/confDataAdd", []() {
+    if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confDataAdd", LOGLEVEL_INFO);
+      //Serial.println("httpServer.on /confdata2");
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confDataAdd (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      //for (int i = 0; i < httpServer.args(); i++) {
+      //  char bufName[20];
+      //  char bufValue[101];
+      //  httpServer.argName(i).toCharArray(bufName, 20);
+      //  httpServer.arg(i).toCharArray(bufValue, 101);
+      //
+      //  if (strlen(bufName) > 0) {
+      //    //Serial.print("web update ");
+      //    //Serial.print(bufName);
+      //    //Serial.print(" = ");
+      //    //Serial.println(bufValue);
+      //    setConfig(bufName, bufValue);
+      //  }
+      //  saveConfig2ToFlash = true;
+      //  //Serial.println("web triggered saveConfig2ToFlash");
+      //}
+      //yield();
+
+      //build json object of program data
+      StaticJsonDocument<1000> json;
+
+      json["outTempTop"] = confAdd.outTemp_topic_in;
+      json["outHumTop"] = confAdd.outHum_topic_in;
+      json["PIRTop"] = confAdd.mqtt_topic_pir;
+      json["PIROnPld"] = confAdd.mqtt_payload_pir_on;
+      json["PIROffPld"] = confAdd.mqtt_payload_pir_off;
+
+      yield();
+
+      char jsonchar[1000];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /confdadd
+
+  httpServer.on("/confDataTime", []() {
+    if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confDataTime", LOGLEVEL_INFO);
+      //Serial.println("httpServer.on /confdata2");
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confDataTime (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      //for (int i = 0; i < httpServer.args(); i++) {
+      //  char bufName[20];
+      //  char bufValue[101];
+      //  httpServer.argName(i).toCharArray(bufName, 20);
+      //  httpServer.arg(i).toCharArray(bufValue, 101);
+      //
+      //  if (strlen(bufName) > 0) {
+      //    //Serial.print("web update ");
+      //    //Serial.print(bufName);
+      //    //Serial.print(" = ");
+      //    //Serial.println(bufValue);
+      //    setConfig(bufName, bufValue);
+      //  }
+      //  saveConfig2ToFlash = true;
+      //  //Serial.println("web triggered saveConfig2ToFlash");
+      //}
+      //yield();
+
+      //build json object of program data
+      StaticJsonDocument<1000> json;
+
+      if (confTime.ntpEnable)
+        json["NTPEnable"] = 1;
+      else
+        json["NTPEnable"] = 0;
+
+      json["NTPServer1"] = confTime.ntpServer1;
+      json["NTPServer2"] = confTime.ntpServer2;
+      json["TZStr"] = confTime.timeZoneStr;
+      json["NTPSyncInt"] = confTime.ntpSyncInterval / 60;
+
+      yield();
+
+      char jsonchar[1000];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /confDataTime
+
+  httpServer.on("/confDataLog", []() {
+    if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confDataLog", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confDataLog (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      //for (int i = 0; i < httpServer.args(); i++) {
+      //  char bufName[20];
+      //  char bufValue[101];
+      //  httpServer.argName(i).toCharArray(bufName, 20);
+      //  httpServer.arg(i).toCharArray(bufValue, 101);
+      //
+      //  if (strlen(bufName) > 0) {
+      //    //Serial.print("web update ");
+      //    //Serial.print(bufName);
+      //    //Serial.print(" = ");
+      //    //Serial.println(bufValue);
+      //    setConfig(bufName, bufValue);
+      //  }
+      //  saveConfig2ToFlash = true;
+      //  //Serial.println("web triggered saveConfig2ToFlash");
+      //}
+      //yield();
+
+      //build json object of program data
+      StaticJsonDocument<1000> json;
+
+      //if(confTime.ntpEnable) json["NTPEnable"] = 1;
+      //else json["NTPEnable"] = 0;
+
+      json["logLevSer"] = confLog.logLevelSerial;
+      json["logLevWeb"] = confLog.logLevelWeb;
+      json["logLevMqtt"] = confLog.logLevelMqtt;
+
+      if (confLog.logWebRequests)
+        json["logWebRequests"] = 1;
+      else
+        json["logWebRequests"] = 0;
+
+      yield();
+
+      char jsonchar[1000];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /confDataLog
+
+  //get heap status, analog input value and all GPIO statuses in one json call
+  httpServer.on("/sysinfod", HTTP_GET, []() {
+    if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /sysinfod (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      char buf[40];
+      byte mac[6];
+      WiFi.macAddress(mac);
+
+      StaticJsonDocument<1000> json;
+      json["DevName"] = confDevWiFi.deviceName;
+      json["HostName"] = confDevWiFi.hostName;
+
+      sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", (uint8_t)mac[0], (uint8_t)mac[1], (uint8_t)mac[2], (uint8_t)mac[3], (uint8_t)mac[4], (uint8_t)mac[5]);
+      json["MAC"] = buf;
+
+      //sprintf(buf, "%s", WiFi.localIP().toString().c_str());
+      //json["IP"] = buf;
+      
+      //sprintf(buf, "%s", WiFi.gatewayIP().toString().c_str());
+      //json["Gateway"] = buf;
+
+      json["IP"] = WiFi.localIP().toString();
+      json["GW"] = WiFi.gatewayIP().toString();
+      json["DNS"] = WiFi.dnsIP().toString();
+
+      json["SSID"] = WiFi.SSID();
+      json["WiFiConf"] = persWM.getActiveWiFiNum();
+      json["UpTime"] = getUptimeStr();
+      json["HeapFree"] = ESP.getFreeHeap();
+      json["HeapFragment"] = ESP.getHeapFragmentation();
+      json["HeapMaxBlock"] = ESP.getMaxFreeBlockSize();
+      json["ResetReason"] = ESP.getResetReason();
+      json["CoreVersion"] = ESP.getCoreVersion();
+      json["SDKVersion"] = ESP.getSdkVersion();
+      json["CPUfreq"] = ESP.getCpuFreqMHz();
+      json["SketchSize"] = ESP.getSketchSize();
+      json["FlashSize"] = ESP.getFlashChipRealSize();
+
+      sprintf(buf, "%s", PGMStr_FIRMWARE_NAME);
+      json["FWName"] = buf;
+
+      sprintf(buf, "%s", PGMStr_FIRMWARE_VERSION);
+      json["FWVer"] = buf;
+
+      sprintf(buf, "%s", PGMStr_FIRMWARE_COPYRIGHT);
+      json["FWCr"] = buf;
+
+      sprintf(buf, "%s", compile_date);
+      json["FWBuilt"] = buf;
+#ifdef DEBUGMODE
+      json["FWDebug"] = "yes";
+#else
+      json["FWDebug"] = "no";
+#endif
+
+#ifdef ENABLE_FEATURE_NTP_TIME
+      if (confTime.ntpEnable)
+      {
+        char buf[13];
+        updateTime();
+        if(lt.tm_year > 70) {
+          strftime(buf, sizeof(buf), "%H:%M", &lt);
+          json["Time"] = buf;
+          strftime(buf, sizeof(buf), "%d.%m.%Y", &lt);
+          json["Date"] = buf;
+        }
+      }
+#endif
+
+      yield();
+
+      char jsonchar[1000];
+      serializeJson(json, jsonchar);
+      httpServer.send(200, "application/json", jsonchar);
+    }
+  }); //httpServer.on /sysinfod
+
+  httpServer.on("/sysinfo", HTTP_GET, []() {
+    if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /sysinfo (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+      httpServerHandleSysInfoPage();
+    }
+  });
+
+  /*httpServer.on("/", []() {
+    if ( WifiInApMode ) {
+      httpServer.sendHeader("Location", "/wifi.htm", true);
+      httpServer.send(302);
+    }
+    else {
+      httpServer.sendHeader("Location", "/main", true);
+      httpServer.send(302);
+    }
+    });*/
+
+  httpServer.on("/", []() {
+    String addr = httpServer.client().remoteIP().toString();
+    if (confLog.logWebRequests || httpServer.args() > 0)
+    {
+      char buf[40];
+      sprintf(buf, "WEB: / (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+    }
+
+    if (httpServer.hasArg("restart"))
+    {
+      if (httpIsAuthenticated() || (!httpIsAuthenticated() && httpCheckToken()))
+      {
+        sendLog("WEB: /?restart", LOGLEVEL_INFO);
+        httpServerHandleRestartPage();
+        restart();
+      }
+      else
+        httpSendUnauthorized();
+    }
+    else if (httpServer.hasArg("mqttreconnect"))
+    {
+      if (httpIsAuthenticated() || (!httpIsAuthenticated() && httpCheckToken()))
+      {
+        //Serial.println("web triggered mqttreconnect");
+        sendLog("WEB: /?mqttreconnect", LOGLEVEL_INFO);
+        mqttReconnect();
+        httpServer.sendHeader("Location", "/", true);
+        httpServer.send(303);
+      }
+      else
+        httpSendUnauthorized();
+    }
+    else if (httpServer.hasArg("clearconf"))
+    {
+      if (httpIsAuthenticatedAdmin() || (!httpIsAuthenticatedAdmin() && httpCheckToken()))
+      {
+        sendLog("WEB: /?clearconf", LOGLEVEL_INFO);
+        httpServerHandleClearconfPage();
+
+        yield();
+        delay(5);
+        deleteConfig();
+      }
+      else
+        httpSendUnauthorized();
+    }
+    else if (httpServer.hasArg("clearwifi"))
+    {
+      if (httpIsAuthenticatedAdmin() || (!httpIsAuthenticatedAdmin() && httpCheckToken()))
+      {
+        sendLog("WEB: /?clearwifi", LOGLEVEL_INFO);
+        httpServerHandleClearconfPage();
+
+        yield();
+        delay(5);
+        confClearWiFiCredentials();
+      }
+      else
+        httpSendUnauthorized();
+    }
+    else if (httpServer.hasArg("clearcreds"))
+    {
+      if (httpIsAuthenticatedAdmin() || (!httpIsAuthenticatedAdmin() && httpCheckToken()))
+      {
+        sendLog("WEB: /?clearcreds", LOGLEVEL_INFO);
+        httpServerHandleClearconfPage();
+
+        yield();
+        delay(5);
+        confClearCredentials();
+      }
+      else
+        httpSendUnauthorized();
+    }
+    else if (!httpIsAuthenticated())
+      return httpServer.requestAuthentication();
+    else
+    {
+      if (confLog.logWebRequests)
+        sendLog("WEB: /", LOGLEVEL_INFO);
+      httpServerHandleMainPage();
+    }
+  });
+
+  httpServer.on("/conf", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /conf", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /conf (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleConfPage();
+    }
+  });
+
+  httpServer.on("/confweb", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confweb", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confweb (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleConfWebPage();
+    }
+  });
+
+  httpServer.on("/confmqtt", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confmqtt", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confmqtt (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleConfMqttPage();
+    }
+  });
+
+  httpServer.on("/confdevwifi", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confdevwifi", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confdevwifi (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleConfDevWiFiPage();
+    }
+  });
+
+  httpServer.on("/confbas", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confbas", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confbas (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleConfBasPage();
+    }
+  });
+
+  httpServer.on("/confadv", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confadv", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confadv (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleConfAdvPage();
+    }
+  });
+
+  httpServer.on("/confadd", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /confadd", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /confadd (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleConfAddPage();
+    }
+  });
+
+  httpServer.on("/conftime", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /conftime", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /conftime (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleConfTimePage();
+    }
+  });
+
+  httpServer.on("/conflog", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /conflog", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /conflog (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleConfLogPage();
+    }
+  });
+
+  httpServer.on("/redTemps", []() {
+    if (!httpIsAuthenticatedAdmin())
+      return httpServer.requestAuthentication();
+    else
+    {
+      //sendLog("WEB: /redTemps", LOGLEVEL_INFO);
+      if (confLog.logWebRequests)
+      {
+        String addr = httpServer.client().remoteIP().toString();
+        char buf[40];
+        sprintf(buf, "WEB: /redTemps (from %s)", addr.c_str());
+        sendLog(buf, LOGLEVEL_INFO);
+      }
+
+      httpServerHandleRedTempsPage();
+    }
+  });
+
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+  if (confWeb.wsConsole)
+  {
+    httpServer.on("/wsconsole", []() {
+      if (!httpIsAuthenticatedAdmin())
+        return httpServer.requestAuthentication();
+      else
+      {
+        //sendLog("WEB: /wsconsole", LOGLEVEL_INFO);
+        if (confLog.logWebRequests)
+        {
+          String addr = httpServer.client().remoteIP().toString();
+          char buf[40];
+          sprintf(buf, "WEB: /wsconsole (from %s)", addr.c_str());
+          sendLog(buf, LOGLEVEL_INFO);
+        }
+
+        wsValidSessionId = millis();
+        char sidbuf[20];
+        sprintf(sidbuf, "sessionId=%lu|", wsValidSessionId);
+        httpServer.sendHeader("Set-Cookie", sidbuf);
+        httpServerHandleWSConsolePage();
+      }
+    });
+    httpServer.on("/wsapp.js", []() {
+      httpServer.sendHeader("cache-control", "max-age=86400", false);
+      httpServer.send_P(200, "text/javascript", js_wsapp);
+    });
+  }
+#endif
+
+  httpServer.onNotFound([]() {
+    String addr = httpServer.client().remoteIP().toString();
+    if (confLog.logWebRequests)
+    {
+      char buf[40];
+      sprintf(buf, "WEB: 404 (from %s)", addr.c_str());
+      sendLog(buf, LOGLEVEL_INFO);
+    }
+    httpServerHandleNotFound();
+  }); //httpServer.onNotFound
+
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_BUFFERED
+  if (confWeb.wConsole)
+  {
+    httpServer.on("/console", []() {
+      if (!httpIsAuthenticatedAdmin())
+        return httpServer.requestAuthentication();
+      else
+      {
+        //sendLog("WEB: /console", LOGLEVEL_INFO);
+        if (confLog.logWebRequests)
+        {
+          String addr = httpServer.client().remoteIP().toString();
+          char buf[40];
+          sprintf(buf, "WEB: /console (from %s)", addr.c_str());
+          sendLog(buf, LOGLEVEL_INFO);
+        }
+        httpServerHandleConsolePage();
+      }
+    });
+    httpServer.on("/webcsapi", []() {
+      if (!httpIsAuthenticatedAdmin())
+        return httpServer.requestAuthentication();
+      else
+      {
+        if (httpServer.hasArg("cmd"))
+        {
+          char buf[101];
+          httpServer.arg("cmd").toCharArray(buf, 100);
+          strlcpy(cmdPayload, buf, sizeof(cmdPayload));
+          cmdInQueue = true;
+          evalCmd();
+        }
+        if (confLog.logWebRequests)
+        {
+          String addr = httpServer.client().remoteIP().toString();
+          char buf[40];
+          sprintf(buf, "WEB: /conflog (from %s)", addr.c_str());
+          sendLog(buf, LOGLEVEL_INFO);
+        }
+        httpServer.send(200, "text/plain", webLogBuffer);
+      }
+    });
+    httpServer.on("/csapp.js", []() {
+      httpServer.sendHeader("cache-control", "max-age=86400", false);
+      httpServer.send_P(200, "text/javascript", js_csapp);
+    });
+  }
+#endif
+
+// HTTP Updater at /update
+#ifdef ENABLE_FEATURE_HTTP_UPDATER
+  httpUpdater.setup(&httpServer, "/update", confWeb.http_user, confWeb.http_pass);
+#endif
+
+  httpServer.begin();
+}

+ 187 - 0
src/logging.ino

@@ -0,0 +1,187 @@
+void sendLog(const char *msg, uint8_t loglevel)
+{
+    char buf[200];
+    char buf2[221];
+    bool timeIsValid = false;
+    strlcpy(buf, msg, sizeof(buf));
+
+#ifdef ENABLE_FEATURE_NTP_TIME
+    static char tbuf[20];
+    if (confTime.ntpEnable)
+    {
+        updateTime();
+        if (lt.tm_year > 70)
+        { // lt.tm_year = years since 1900, before NTP is synced = 70
+            //strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", &lt);
+            strftime(tbuf, sizeof(tbuf), "%H:%M:%S", &lt);
+            sprintf(buf2, "[%s] %s\r\n", tbuf, buf);
+            timeIsValid = true;
+        }
+    }
+#endif
+
+    if (!timeIsValid)
+    {
+        unsigned long tmpMillis;
+        unsigned long tmpSecs;
+        unsigned int restMillis;
+        tmpMillis = millis();
+        tmpSecs = tmpMillis / 1000;
+        restMillis = tmpMillis - (tmpSecs * 1000);
+        //tmpSecs = millis() / 1000;
+
+        if (tmpSecs < 10000)
+            sprintf(buf2, "[%04lu.%3u] %s\r\n", tmpSecs, restMillis, buf);
+        else
+            sprintf(buf2, "[%08lu] %s\r\n", tmpSecs, buf);
+    }
+
+    if (loglevel <= confLog.logLevelSerial)
+        Serial.print(buf2);
+
+    if (confMqtt.mqtt_enable && mqttclient.state() == 0)
+    {
+        if (loglevel <= confLog.logLevelMqtt)
+            mqttclient.publish(confMqtt.mqtt_topic_out, buf, false);
+    }
+
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
+    yield();
+    if (confWeb.wsConsole && webSocket.connectedClients() > 0)
+    {
+        if (loglevel <= confLog.logLevelWeb)
+            webSocket.broadcastTXT(buf2);
+    }
+#endif
+
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_BUFFERED
+    if (confWeb.wConsole && loglevel <= confLog.logLevelWeb)
+    {
+        char buf3[250];
+        //char webLogBuffer[2000];
+        //unsigned int webLogBuffer_index=0;
+        sprintf(buf3, "{%u}%s", webLogBuffer_index, buf2);
+
+        //Serial.print("DEV: '");
+        //Serial.print(buf3);
+        //Serial.println("'");
+
+        //char * posmsg2 = 0;
+        //posmsg2 = strstr(webLogBuffer,'\n');
+        //Serial.print("POS=");
+        //Serial.println((int)posmsg2);
+
+        bool done = false;
+        while (!done)
+        {
+            int currSize = strlen(webLogBuffer);
+            int addSize = strlen(buf3);
+            int maxSize = sizeof(webLogBuffer) - 10;
+
+            //if(addSize < 100) addSize = 100;
+            //Serial.print("   currSize="); Serial.print(currSize);
+            //Serial.print("   addSize="); Serial.print(addSize);
+            //Serial.print("   maxSize="); Serial.print(maxSize);
+
+            if ((currSize + addSize) >= maxSize)
+            {
+                //Serial.print("   buf FULL, size=");
+                //Serial.print(currSize);
+                //Serial.print("   removing 1.msg...");
+
+                int posMsg2 = 0;
+                while (posMsg2 < currSize)
+                {
+                    if (webLogBuffer[posMsg2] == '\n')
+                    {
+                        posMsg2++;
+                        break;
+                    }
+                    else
+                        posMsg2++;
+                }
+
+                //Serial.print("   posMsg2=");
+                //Serial.print(posMsg2);
+
+                int oldSize = strlen(webLogBuffer);
+                int c = 0;
+                while (c < (oldSize - posMsg2))
+                {
+                    webLogBuffer[c] = webLogBuffer[posMsg2 + c];
+                    //Serial.println();
+                    //Serial.print(webLogBuffer[posMsg2 + c]);
+                    //Serial.print("  [");
+                    //Serial.print(posMsg2 + c);
+                    //Serial.print("] -> [");
+                    //Serial.print(c);
+                    //Serial.print("]");
+                    c++;
+                }
+                webLogBuffer[c] = '\0';
+                //Serial.print("   removed msg 1, new size=");
+                //Serial.print(strlen(webLogBuffer));
+            }
+            else
+            {
+                done = true;
+                //Serial.println("   done");
+            }
+            //Serial.println();
+        }
+
+        if ((strlen(webLogBuffer) + strlen(buf3)) < (sizeof(webLogBuffer) - 10))
+        {
+            //Serial.print("   add msg to buf");
+            int c = 0;
+            int offset = strlen(webLogBuffer);
+            //Serial.print("   offset=");
+            //Serial.print(offset);
+
+            int size = strlen(buf3);
+            while (c < size)
+            {
+                if ((c + offset) < (int)sizeof(webLogBuffer))
+                {
+                    webLogBuffer[c + offset] = buf3[c];
+                    c++;
+                }
+                else
+                    break;
+            }
+            webLogBuffer[c + offset] = '\0';
+
+            //Serial.print("AFTER 2: ");
+            //Serial.println(webLogBuffer);
+
+            webLogBuffer_index++;
+        }
+    }
+#endif
+}
+
+void sendLog(const __FlashStringHelper *msg, uint8_t loglevel)
+{
+    char buf[201];
+    PGM_P p = reinterpret_cast<PGM_P>(msg);
+    size_t n = 0;
+    while (1)
+    {
+        unsigned char c = pgm_read_byte(p++);
+        if (c == 0)
+        {
+            buf[n] = c;
+            break;
+        }
+        else if (n >= sizeof(buf) - 1)
+        {
+            break;
+        }
+        else
+        {
+            buf[n] = c;
+            n++;
+        }
+    }
+    sendLog(buf, loglevel);
+}

+ 88 - 0
src/miscFunctions.ino

@@ -0,0 +1,88 @@
+//void updateUptime()
+//{
+//  sysUptime_mins++;
+//  if (sysUptime_mins == 60)
+//  {
+//    sysUptime_mins = 0;
+//    sysUptime_hours++;
+//  }
+//  if (sysUptime_hours == 24)
+//  {
+//    sysUptime_hours = 0;
+//    sysUptime_days++;
+//  }
+//}
+
+//void buildUptimeString()
+//{
+//  if (sysUptime_days > 0)
+//    sprintf(uptimeStr, "%dd %02d:%02d", sysUptime_days, sysUptime_hours, sysUptime_mins);
+//  else
+//    sprintf(uptimeStr, "%02d:%02d", sysUptime_hours, sysUptime_mins);
+//}
+
+
+void updateUptime()
+{
+  if (millis() >= 3000000000) // save expected rollover
+  {
+    sysUptime.highMillis = 1;
+  }
+  if (millis() <= 100000 && sysUptime.highMillis == 1) // save actual rollover
+  {
+    sysUptime.rollover++;
+    sysUptime.highMillis = 0;
+  }
+
+  unsigned long secsUp = millis() / 1000;
+  sysUptime.sec = secsUp % 60;
+  sysUptime.min = (secsUp / 60) % 60;
+  sysUptime.hour = (secsUp / (60 * 60)) % 24;
+  sysUptime.day = (sysUptime.rollover * 50) + (secsUp / (60 * 60 * 24)); // millis rollover ~50days
+}
+
+char* getUptimeStr(bool includeSeconds) {
+  updateUptime();
+  if(includeSeconds) {
+    if(sysUptime.day == 0) sprintf(sysUptime.uptimeStr, "%02u:%02u:%02u", sysUptime.hour, sysUptime.min, sysUptime.sec);
+    else sprintf(sysUptime.uptimeStr, "%ud %02u:%02u:%02u", sysUptime.day, sysUptime.hour, sysUptime.min, sysUptime.sec);
+  }
+  else {
+    if(sysUptime.day == 0) sprintf(sysUptime.uptimeStr, "%02u:%02u", sysUptime.hour, sysUptime.min);
+    else sprintf(sysUptime.uptimeStr, "%ud %02u:%02u", sysUptime.day, sysUptime.hour, sysUptime.min);
+  }
+  return sysUptime.uptimeStr;
+}
+
+void createDeviceName()
+{
+  byte mac[6];
+  WiFi.macAddress(mac);
+  sprintf(confDevWiFi.deviceName, "%s-%02X%02X", FIRMWARE_SHORTNAME, (uint8_t)mac[4], (uint8_t)mac[5]);
+}
+
+void restart()
+{
+  delay(100);
+  //ESP.restart();
+  // Adding Safer Restart method
+  ESP.wdtDisable();
+  ESP.reset();
+  delay(2000);
+}
+
+void logSysdata()
+{
+  char logBuf[101];
+  sprintf_P(logBuf, "SYS: uptime=%s, freeHeap=%u, heapFragm=%u%%", getUptimeStr(true), ESP.getFreeHeap(), ESP.getHeapFragmentation());
+  //sprintf_P(logBuf, "SYS: uptime=%lu, freeHeap=%u, heapFragm=%u%%", millis(), ESP.getFreeHeap(), ESP.getHeapFragmentation());
+  sendLog(logBuf, LOGLEVEL_INFO);
+}
+
+void printIpcfg() {
+  char buf[100];
+  byte mac[6];
+  WiFi.macAddress(mac);
+  sprintf(buf, "%s: SSID='%s', IP='%s', GW='%s', DNS='%s', MAC='%02X:%02X:%02X:%02X:%02X:%02X'", PGMStr_WiFi, WiFi.SSID().c_str(), WiFi.localIP().toString().c_str(), WiFi.gatewayIP().toString().c_str(), WiFi.dnsIP().toString().c_str(), (uint8_t)mac[0], (uint8_t)mac[1], (uint8_t)mac[2], (uint8_t)mac[3], (uint8_t)mac[4], (uint8_t)mac[5]);
+  sendLog(buf, LOGLEVEL_INFO);
+}

+ 28 - 53
src/WiFiThermostat/mqtt.ino → src/mqtt.ino

@@ -1,5 +1,11 @@
 /*#include <Arduino.h>*/
 
+#define MQTT_RECONNECT_INTERVAL_3_TRIES 15000
+#define MQTT_RECONNECT_INTERVAL_10_TRIES 60000
+#define MQTT_RECONNECT_INTERVAL_LONG 300000
+
+bool mqttHeartbeatReceived = false;
+
 // MQTT callback
 void mqttCallback(char *topic, unsigned char *payload, uint16_t length)
 {
@@ -17,10 +23,10 @@ void mqttCallback(char *topic, unsigned char *payload, uint16_t length)
   if (strcmp(topic, mqtt_topic_in_cmd) == 0)
   { //if topic = mqtt_topic_in_cmd
     int len;
-    if (length < 101)
+    if (length < sizeof(cmdPayload))
       len = length; // if input is bigger than dest buffer, cut
     else
-      len = 100;
+      len = sizeof(cmdPayload)-1;
 
     for (int i = 0; i < len; i++)
     {
@@ -47,8 +53,8 @@ void mqttCallback(char *topic, unsigned char *payload, uint16_t length)
 
     if (strncmp(cmdPayload, "HEARTBEAT", 9) == 0)
     {
-      sendLog(F("MQTT: received HEARTBEAT - resetting timer..."), LOGLEVEL_INFO);
       mqttLastHeartbeat = millis();
+      mqttHeartbeatReceived = true;
       mqttConnected = true;
     }
     else
@@ -60,10 +66,10 @@ void mqttCallback(char *topic, unsigned char *payload, uint16_t length)
   if (strcmp(topic, mqtt_topic_in_setTemp) == 0)
   { //if topic = mqtt_topic_in_setTemp
     int len;
-    if (length < 101)
+    if (length < sizeof(cmdPayload))
       len = length; // if input is bigger than dest buffer, cut
     else
-      len = 100;
+      len = sizeof(cmdPayload)-1;
 
     for (int i = 0; i < len; i++)
     {
@@ -107,10 +113,10 @@ void mqttCallback(char *topic, unsigned char *payload, uint16_t length)
   { //if topic = mqtt_topic_in_setMode
     uint8_t len;
 
-    if (length < 101)
+    if (length < sizeof(cmdPayload))
       len = length; // if input is bigger than dest buffer, cut
     else
-      len = 100;
+      len = sizeof(cmdPayload)-1;
 
     for (int i = 0; i < len; i++)
     {
@@ -190,10 +196,10 @@ void mqttCallback(char *topic, unsigned char *payload, uint16_t length)
     uint16_t len;
     unsigned char tmpPreset = 100;
 
-    if (length < 101)
+    if (length < sizeof(cmdPayload))
       len = length; // if input is bigger than dest buffer, cut
     else
-      len = 100;
+      len = sizeof(cmdPayload)-1;
 
     for (unsigned char i = 0; i < len; i++)
     {
@@ -437,55 +443,16 @@ bool mqttReconnect(void)
   else
   {
     int mqttConnRes = mqttclient.state();
-    //if (serialdebug) {
     char logBuf[70];
     mqtt_updateCurrentStateName();
-    //sprintf_P(logBuf, "%s: %s, rc=%d (%s)", PGMStr_MQTT, PGMStr_connectedFailed, mqttConnRes, PGMStr_MQTTStates[mqttConnRes + 4]);
     sprintf_P(logBuf, "%s: %s, rc=%d (%s)", PGMStr_MQTT, PGMStr_connectedFailed, mqttConnRes, mqttCurrentStateName);
     sendLog(logBuf, LOGLEVEL_INFO);
-    //Serial.print("MQTT connect FAILED, rc=");
-    //Serial.print(mqttConnRes);
-    //Serial.print(" (");
-    //switch (mqttConnRes)
-    //{
-    //case -4:
-    //  sendLog(PGMStr_MQTTStateM4);
-    //  break;
-    //case -3:
-    //  sendLog(PGMStr_MQTTStateM3);
-    //  break;
-    //case -2:
-    //  sendLog(PGMStr_MQTTStateM2);
-    //  break;
-    //case -1:
-    //  sendLog(PGMStr_MQTTStateM1);
-    //  break;
-    //case 0:
-    //  sendLog(PGMStr_MQTTState0);
-    //  break;
-    //case 1:
-    //  sendLog(PGMStr_MQTTState1);
-    //  break;
-    //case 2:
-    //  sendLog(PGMStr_MQTTState2);
-    //  break;
-    //case 3:
-    //  sendLog(PGMStr_MQTTState3);
-    //  break;
-    //case 4:
-    //  sendLog(PGMStr_MQTTState4);
-    //  break;
-    //case 5:
-    //  sendLog(PGMStr_MQTTState5);
-    //  break;
-    //}
-    //}
 
     if (mqttReconnectAttempts >= 3 && (mqttConnRes == 4 || mqttConnRes == 5))
     {
       // MQTT credentials are invalid/rejected from the server - stop trying to reconnect until reboot
       mqtt_tempDisabled_credentialError = true;
-      if (serialdebug)
+      if (confLog.logLevelSerial >= LOGLEVEL_VERBOSE)
       {
         //Serial.println(F("MQTT disabled until reboot due to credential error"));
         sendLog(F("MQTT disabled until reboot due to credential error"), LOGLEVEL_ERROR);
@@ -513,6 +480,11 @@ int lastWifiStatus;
 
 void mqttHandleConnection()
 {
+  if(mqttHeartbeatReceived) {
+    mqttHeartbeatReceived = false;
+    sendLog(F("MQTT: received HEARTBEAT - resetting timer..."), LOGLEVEL_VERBOSE);
+  }
+
   int currWifiStatus = WiFi.status();
   if (currWifiStatus != lastWifiStatus)
   {
@@ -544,11 +516,11 @@ void mqttHandleConnection()
     {
       unsigned long mqttReconnectAttemptDelay;
       if (mqttReconnectAttempts < 3)
-        mqttReconnectAttemptDelay = 15000; // if this is the 1-3rd attempt, try again in 15s
+        mqttReconnectAttemptDelay = MQTT_RECONNECT_INTERVAL_3_TRIES; // if this is the 1-3rd attempt, try again in 15s
       else if (mqttReconnectAttempts < 10)
-        mqttReconnectAttemptDelay = 60000; // if more than 3 attempts failed, try again every min
+        mqttReconnectAttemptDelay = MQTT_RECONNECT_INTERVAL_10_TRIES; // if more than 3 attempts failed, try again every min
       else
-        mqttReconnectAttemptDelay = 300000; // if more than 10 attempts failed, try again every 5 min
+        mqttReconnectAttemptDelay = MQTT_RECONNECT_INTERVAL_LONG; // if more than 10 attempts failed, try again every 5 min
 
       if (confMqtt.mqtt_enable_heartbeat && confMqtt.mqtt_heartbeat_maxage_reboot > 0 && ((millis() - mqttLastHeartbeat) > confMqtt.mqtt_heartbeat_maxage_reboot))
       {
@@ -616,5 +588,8 @@ void mqttPublishHeartbeat()
 }
 
 void mqtt_updateCurrentStateName() {
-  sprintf_P(mqttCurrentStateName, "%s", PGMStr_MQTTStates[mqttclient.state()+4]);
+  if(confMqtt.mqtt_enable) {
+    sprintf_P(mqttCurrentStateName, "%s", PGMStr_MQTTStates[mqttclient.state()+4]);
+  }
+  else sprintf_P(mqttCurrentStateName, "%s", PGMStr_MQTTState_DIS);
 }

+ 7 - 6
src/WiFiThermostat/mqtt_out.ino → src/mqtt_out.ino

@@ -155,21 +155,22 @@ void publishCurrentThermostatValues(bool force = false)
 
   //sendLog(F("heating ON"));
   //char logBuf[40];
-  sprintf_P(logBuf, "%s: %s=%s (%us)", PGMStr_thermostat, PGMStr_heating, ch_turnHeatingOn, currOnOffTime);
+
+  sprintf_P(logBuf, "%s: %s=%s (%s)", PGMStr_thermostat, PGMStr_heating, ch_turnHeatingOn, getTimeStringFromSeconds(currOnOffTime));
   sendLog(logBuf, LOGLEVEL_INFO);
   // END turnHeatingOn
 
   yield();
 
-  char buf[101];
-  sprintf(buf, "%lu", heatingOnTime);
+  //char buf[101];
+  //sprintf(buf, "%lu", heatingOnTime);
   sprintf(tmp_topic_out, "%s/%s", confMqtt.mqtt_topic_out, "heatingOnTime");
-  mqttclient.publish(tmp_topic_out, buf);
+  mqttclient.publish(tmp_topic_out, getTimeStringFromSeconds(heatingOnTime));
   yield();
 
-  sprintf(buf, "%lu", heatingOffTime);
+  //sprintf(buf, "%lu", heatingOffTime);
   sprintf(tmp_topic_out, "%s/%s", confMqtt.mqtt_topic_out, "heatingOffTime");
-  mqttclient.publish(tmp_topic_out, buf);
+  mqttclient.publish(tmp_topic_out, getTimeStringFromSeconds(heatingOffTime));
 
   yield();
 }

+ 0 - 0
src/WiFiThermostat/outTempHum.ino → src/outTempHum.ino


+ 7 - 13
src/WiFiThermostat/scheduler.ino → src/scheduler.ino

@@ -1,6 +1,6 @@
 
 void checkMillis() {
-  if ( (millis() - lastRun) > 100 ) {
+  if ( (millis() - lastRun) >= 100 ) {
     lastRun = millis();
     every100ms();
   }
@@ -31,8 +31,11 @@ void everySecond() {
 
   handleDisplayTimeout();
   checkValuesChanged();
+  if(sysInfoEverySecond) logSysdata();
 
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
   clearValidSessionId();
+#endif
 
   if (countMeasureInterval < confBas.measureInterval) countMeasureInterval++;
   else {
@@ -62,12 +65,11 @@ unsigned int outPubInterval_states_count = 0;
 unsigned int outPubInterval_sensors_count = 0;
 
 void everyMinute() {
-  updateUptime();
-  buildUptimeString();
-
+#ifdef ENABLE_FEATURE_NTP_TIME
   if(confTime.ntpEnable) {
-    updateTimeFromNTP();
+    syncClock();
   }
+#endif
 
   logSysdata();
 
@@ -97,12 +99,4 @@ void everyMinute() {
       publishCurrentSensorValues(false); // false publishes only changed values
     }
   }
-
-//  if(WifiInApMode) {
-//    if( (millis() - WifiApModeStartedAt) > WIFI_AP_MODE_TIMEOUT ) {
-//      
-//    }
-//  }
-  //  Serial.print("WiFi Status: ");
-  //  Serial.println(WiFi.status());
 }

+ 0 - 0
src/WiFiThermostat/thermostat.ino → src/thermostat.ino


+ 44 - 0
src/time.ino

@@ -0,0 +1,44 @@
+#ifdef ENABLE_FEATURE_NTP_TIME
+bool setupTime()
+{
+    if (strlen(confTime.ntpServer1) > 4 && strlen(confTime.ntpServer2) > 4)
+    {
+        //configTime(gmtOffset_sec, daylightOffset_sec, ntpServer [, ntpServer2[, ntpServer3]]);
+        configTime(0, 0, confTime.ntpServer1, confTime.ntpServer2);
+    }
+    else if (strlen(confTime.ntpServer1) > 4)
+    {
+        configTime(0, 0, confTime.ntpServer1);
+    }
+    else return false;
+    setenv("TZ", confTime.timeZoneStr, 1); // Zeitzone einstellen https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
+    sendLog(F("NTP: updating time..."), LOGLEVEL_INFO);
+    return true;
+}
+
+void syncClock(bool force)
+{
+    time_t now = time(&now);
+    static time_t lastsek{0};
+    if (lt.tm_sec != lastsek || force)
+    {
+        lastsek = lt.tm_sec;
+        if (force || !(time(&now) % confTime.ntpSyncInterval))
+        {
+            //sendLog(F("NTP: updating time"), LOGLEVEL_INFO);
+            setupTime();
+        }
+    }
+}
+
+void updateTime() {
+    time_t now = time(&now);
+    localtime_r(&now, &lt);
+}
+
+void printDate() {
+    char buf[30];
+    strftime(buf, sizeof(buf), "DATE: %Y-%m-%d %H:%M:%S", &lt);
+    sendLog(buf);
+}
+#endif

+ 0 - 1
src/webinterface/api

@@ -1 +0,0 @@
-{"devname":"WTherm-3598","ssid":"Kinf","WiFiNum":1,"uptime":"00:01","time":"23:26","date":"13.01.2020","freeheap":29904,"mqttstate":"CONNECTED","mqtthost":"mqtt.lan","mqttreconn":0,"setTemp":23,"currSetTemp":20.5,"temp":25.981,"hum":21,"heating":false,"mode":1,"modeName":"heat","pset":1,"psetName":"Absenkung 1","psetName0":"Normalbetrieb","psetName1":"Absenkung 1","psetName2":"Absenkung 2","tempLow":20.5,"tempLow2":17.5,"outTemp":0,"outHum":88}

+ 0 - 1
src/webinterface/confDataDevWiFi

@@ -1 +0,0 @@
-{"devName":"WTherm-T5WZ","hostName":"WThermT5WZ","SSID1":"Kinf","WPW1":"****","SSID2":"","WPW2":"","SSIDAP":"WTherm-T5WZ","WPWAP":"****","WAPtout":3,"WConnCheck":20,"Wretry":10,"Wreboot":60}

+ 0 - 1
src/webinterface/confDataWeb

@@ -1 +0,0 @@
-{"apiToken":"","httpUA":"admin","httpPA":"****","httpAuth":1,"httpU1":"flo","httpP1":"****","httpU2":"","httpP2":"","enableConsole":1}

+ 4 - 2
src/WiFiThermostat/websockets.ino → src/websockets.ino

@@ -1,3 +1,4 @@
+#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS
 /*
  * Returns a bool value as an indicator to describe whether a user is allowed to initiate a websocket upgrade
  * based on the value of a cookie. This function expects the rawCookieHeaderValue to look like this "sessionId=<someSessionIdNumberValue>|"
@@ -72,7 +73,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length
                 sprintf(buf, "%s", payload);
 
                 // send received text to command handler
-                if(strlen(buf) > 3) strlcpy(cmdPayload, buf, sizeof(cmdPayload));
+                if(strlen(buf) > 0) strlcpy(cmdPayload, buf, sizeof(cmdPayload));
                 cmdInQueue = true; // will be checked in next loop() run
 
                 // send message to client
@@ -95,4 +96,5 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length
             //    break;
         }
     }
-}
+}
+#endif

+ 1 - 0
webinterface/api

@@ -0,0 +1 @@
+{"devname":"WTherm-3598","ssid":"Kinf","WiFiNum":1,"uptime":"00:05","time":"00:44","date":"17.01.2020","freeheap":24944,"mqttstate":"CONNECTED","mqtthost":"mqtt.lan","mqttreconn":0,"setTemp":21.5,"currSetTemp":20,"temp":25.1,"hum":21,"heating":false,"mode":1,"modeName":"heat","pset":1,"psetName":"Reduction 1","psetName0":"Normal","psetName1":"Reduction 1","psetName2":"Reduction 2","tempLow":20,"tempLow2":17,"outTemp":0,"outHum":0}

+ 7 - 5
src/webinterface/conf → webinterface/conf

@@ -1,10 +1,10 @@
 <html><head>
 <meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>
 <link rel='stylesheet' href='style.css'>
-<title>WiFiThermostat - WTherm-T5WZ</title></head>
+<title>WiFiThermostat - WTherm-3598</title></head>
 <body>
 <div id='main'>
-<div id='head'>WiFiThermostat - WTherm-T5WZ
+<div id='head'>WiFiThermostat - WTherm-3598
 </div><hr>
 <div></div>
 <p><b>Configuration</b></p>
@@ -18,9 +18,11 @@
 <tr><td><form action='confadv' method='get'><button>Thermostat Advanced</button></form></td></tr>
 <tr><td><form action='confadd' method='get'><button>Additional Functions</button></form></td></tr>
 <tr><td><form action='update' method='get'><button>OTA Firmware Update</button></form></td></tr>
-
 <tr><td>&nbsp;</td></tr>
-<tr><td><form action='console' method='get'><button>Console</button></form></td></tr>
+
+<tr><td><form action='console' method='get'><button>Web Console</button></form></td></tr>
+
+<tr><td><form action='wsconsole' method='get'><button>WebSockets Console</button></form></td></tr>
 
 </table>
 <div></div>
@@ -29,5 +31,5 @@
 <td><form action='/' method='get' onsubmit='return confirm("Confirm Restart");'><button name='restart' class='bred'>Restart</button></form></td>
 </tr></table>
 
-<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> v0.6.0 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
+<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> 0.6.1 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
 </div></body></html>

+ 0 - 0
src/webinterface/confDataAdd → webinterface/confDataAdd


+ 0 - 0
src/webinterface/confDataAdv → webinterface/confDataAdv


+ 0 - 0
src/webinterface/confDataBas → webinterface/confDataBas


+ 1 - 0
webinterface/confDataDevWiFi

@@ -0,0 +1 @@
+{"devName":"WTherm-3598","hostName":"WTherm-3598","SSID1":"Kinf","WPW1":"****","SSID2":"","WPW2":"","SSIDAP":"WTherm-3598","WPWAP":"****","WAPtout":5,"WConnCheck":20,"Wretry":5,"Wreboot":60}

+ 0 - 0
src/webinterface/confDataLog → webinterface/confDataLog


+ 0 - 0
src/webinterface/confDataMqtt → webinterface/confDataMqtt


+ 0 - 0
src/webinterface/confDataTime → webinterface/confDataTime


+ 1 - 0
webinterface/confDataWeb

@@ -0,0 +1 @@
+{"apiToken":"","httpUA":"admin","httpPA":"****","httpAuth":0,"httpU1":"","httpP1":"","httpU2":"","httpP2":"","wConsole":1,"wsConsole":1}

+ 0 - 0
src/webinterface/confadd → webinterface/confadd


+ 0 - 0
src/webinterface/confadv → webinterface/confadv


+ 0 - 0
src/webinterface/confbas → webinterface/confbas


+ 0 - 0
src/webinterface/confdevwifi → webinterface/confdevwifi


+ 0 - 0
src/webinterface/conflog → webinterface/conflog


+ 0 - 0
src/webinterface/confmqtt → webinterface/confmqtt


+ 5 - 5
src/webinterface/conftime → webinterface/conftime

@@ -1,7 +1,7 @@
 <html><head>
 <meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>
 <link rel='stylesheet' href='style.css'>
-<title>WiFiThermostat - WTherm-T5WZ</title>
+<title>WiFiThermostat - WTherm-3598</title>
 <script>
   function g(i) { return document.getElementById(i) };
   function sp(i){g(i).type=(g(i).type==='text'?'password':'text');}
@@ -69,7 +69,7 @@
 </head>
 <body onload='init()'>
 <div id='main'>
-<div id='head'>WiFiThermostat - WTherm-T5WZ
+<div id='head'>WiFiThermostat - WTherm-3598
 </div><hr>
 <div></div>
 <b>Configuration - Date &amp; Time</b>
@@ -82,8 +82,8 @@
 <p><b>NTP Server 1</b><br><input type='text' name='NTPServer1' id='NTPServer1'></p>
 <p><b>NTP Server 2</b><br><input type='text' name='NTPServer2' id='NTPServer2'></p>
 <p><b>Timezone String</b><br><input type='text' name='TZStr' id='TZStr'></p>
-<p class='n'>a valid TZ string (right column) from here: <br><a href='https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv'>zones.csv</a></p>
-<p><b>NTP Sync Interval [s]</b><br><input type='text' name='NTPSyncInt' id='NTPSyncInt'></p>
+<p class='n'>a valid TZ string (right column) from here: <br><a target='_blank' href='https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv'>zones.csv</a></p>
+<p><b>NTP Sync Interval [m]</b><br><input type='text' name='NTPSyncInt' id='NTPSyncInt'></p>
 </fieldset>
 <div></div><br>
 </form>
@@ -94,5 +94,5 @@
 </tr></table>
 </div>
 
-<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> v0.6.0 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
+<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> 0.6.1 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
 </div></body></html>

+ 11 - 7
src/webinterface/confweb → webinterface/confweb

@@ -1,7 +1,7 @@
 <html><head>
 <meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>
 <link rel='stylesheet' href='style.css'>
-<title>WiFiThermostat - WTherm-T5WZ</title>
+<title>WiFiThermostat - WTherm-3598</title>
 <script>
   function g(i) { return document.getElementById(i) };
   function sp(i){g(i).type=(g(i).type==='text'?'password':'text');}
@@ -30,7 +30,8 @@
     reqTime = 0;
     reqFin = false;
     updCbxVal(g('httpAuth'));
-    updCbxVal(g('enableConsole'));
+    updCbxVal(g('wConsole'));
+    updCbxVal(g('wsConsole'));
     xhttp = new XMLHttpRequest();
     xhttp.timeout = 1000;
     xhttp.overrideMimeType('application/json');
@@ -47,7 +48,8 @@
         g('httpP1').value = data.httpP1;
         g('httpU2').value = data.httpU2;
         g('httpP2').value = data.httpP2;
-        setCbx(g('enableConsole'), data.enableConsole);
+        setCbx(g('wConsole'), data.wConsole);
+        setCbx(g('wsConsole'), data.wsConsole);
         xhttp = null;
         reqFin = true;
        }
@@ -64,7 +66,8 @@
   //transmit();
   function saveConf() {
     updCbxVal(g('httpAuth'));
-    updCbxVal(g('enableConsole'));
+    updCbxVal(g('wConsole'));
+    updCbxVal(g('wsConsole'));
     if(g('httpPASet').checked && g('httpPA').value != g('httpPAC').value) {
       alert("Admin password verification failed!");
     }
@@ -81,7 +84,7 @@
 </head>
 <body onload='init()'>
 <div id='main'>
-<div id='head'>WiFiThermostat - WTherm-T5WZ
+<div id='head'>WiFiThermostat - WTherm-3598
 </div><hr>
 <div></div>
 <p><b>Configuration - Web</b></p>
@@ -120,7 +123,8 @@ make usaccessible without Auth.</p>
 <br>
 <fieldset>
 <legend>Console</legend>
-<p><b>Enable Web-Console (Experimental)</b>&nbsp;<input type='checkbox' name='enableConsole' id='enableConsole'></p>
+<p><b>Enable Web Console</b>&nbsp;<input type='checkbox' name='wConsole' id='wConsole'></p>
+<p><b>Enable WebSockets Console (Experimental)</b>&nbsp;<input type='checkbox' name='wsConsole' id='wsConsole'></p>
 </fieldset>
 </form>
 <div></div>
@@ -131,5 +135,5 @@ make usaccessible without Auth.</p>
 <div></div>
 </div>
 
-<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> v0.6.0 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
+<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> 0.6.1 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
 </div></body></html>

+ 27 - 0
webinterface/console

@@ -0,0 +1,27 @@
+<html><head>
+<meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>
+<link rel='stylesheet' href='style.css'>
+<title>WiFiThermostat - WTherm-3598</title></head>
+<body>
+<div id='main'>
+<div id='head'>WiFiThermostat - WTherm-3598
+</div><hr>
+<div></div>
+<p><b>Console</b></p>
+<table style='width:100%'>
+<tr><td style='width:800px;'><textarea id="msgs" style="width:100%;min-height:400px;resize:both;"></textarea></td></tr>
+<tr><td><input id='cmdInput' type='text'></td></tr>
+<tr><td><button type='submit' id='btnSend' onclick='sendCmd();'>Send</button></td></tr>
+<tr><td><form action='.' method='get'><button class='bgrey'>Close</button></form></td></tr>
+</table>
+
+<form id='cmdForm'>
+<input type='hidden' name='cmd' id='cmd'>
+</form>
+
+<script src="csapp.js"></script>
+
+
+
+<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> 0.6.1 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
+</div></body></html>

+ 64 - 0
webinterface/csapp.js

@@ -0,0 +1,64 @@
+function g(i) { return document.getElementById(i) };
+var xhttp, updateTime, reqTime, reqFin;
+var msgList = document.getElementById('msgs');
+
+g('cmdInput').addEventListener("keyup", function(event) {
+    event.preventDefault();
+    if (event.keyCode === 13) {
+		sendCmd();
+    }
+});
+
+function sendCmd() {
+  var form = g('cmdForm');
+  msgList.innerHTML += 'Sent: ' + g('cmdInput').value + '\n';
+  g('cmd').value=g('cmdInput').value;
+  g('cmdInput').value='';
+  g('cmdInput').value = '';
+  msgList.scrollTop = msgList.scrollHeight;
+  return transmit(form);
+}
+
+var lastMsgIndex=0;
+
+function transmit(f) {
+  if (!xhttp) { 
+    reqTime = 0;
+    reqFin = false;
+    xhttp = new XMLHttpRequest();
+    xhttp.timeout = 1000;
+    xhttp.overrideMimeType("text/plain");
+    xhttp.open('POST', 'webcsapi');
+    xhttp.send(f ? (new FormData(f)) : '');
+    xhttp.onreadystatechange = function () {
+      if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+        var data = xhttp.responseText.split("\n");
+		    for(i=0; i < data.length; i++) {
+		      var numEnd = data[i].indexOf("}");
+		      var num = parseInt(data[i].substring(1, numEnd));
+		      var msg = data[i].substring(numEnd+1);
+		      if(num > lastMsgIndex || lastMsgIndex == 0) {
+            msgList.innerHTML += msg;
+			      msgList.scrollTop = msgList.scrollHeight;
+			      lastMsgIndex = num;
+		      }
+		    }
+		
+        xhttp = null;
+        updateTime = 0;
+        reqFin = true;
+        }
+      else {
+        if(!reqFin && reqTime > 10) {
+          xhttp = null;
+          reqFin = true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+transmit();
+setInterval(transmit, 2000);
+

+ 3 - 2
src/webinterface/index → webinterface/index

@@ -145,9 +145,10 @@
 <br>
 <table style='width:100%'>
 <tr><td style='width:100%'><form action='conf' method='get'><button>Configuration</button></form></td></tr>
-<tr><td style='width:100%'><form action='console' method='get'><button>Console</button></form></td></tr>
+<tr><td style='width:100%'><form action='console' method='get'><button>Web Console</button></form></td></tr>
+<tr><td style='width:100%'><form action='wsconsole' method='get'><button>WebSockets Console</button></form></td></tr>
 <tr><td style='width:100%'><form action='/' method='get' onsubmit='return confirm("Confirm Restart");'><button name='restart' class='bred'>Restart</button></form></td></tr>
 </table>
 
-<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> v0.6.0 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
+<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> 0.6.1 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
 </div></body></html>

+ 0 - 0
src/webinterface/redTemps → webinterface/redTemps


+ 0 - 0
src/webinterface/style.css → webinterface/style.css


+ 0 - 0
src/webinterface/style_reduced.css → webinterface/style_reduced.css


+ 117 - 0
webinterface/sysinfo

@@ -0,0 +1,117 @@
+<html><head>
+<meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>
+<link rel='stylesheet' href='style.css'>
+<title>WiFiThermostat - WTherm-3598</title>
+<script>
+  function g(i) { return document.getElementById(i) };
+  var xhttp, updateTime, reqTime, reqFin;
+  function transmit(f) {
+    if (!xhttp) { 
+      reqTime = 0;
+      reqFin = false;
+      xhttp = new XMLHttpRequest();
+      xhttp.timeout = 1000;
+      xhttp.overrideMimeType("application/json");
+      xhttp.open('GET', 'sysinfod');
+      xhttp.send(f ? (new FormData(f)) : '');
+      xhttp.onreadystatechange = function () {
+        if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+          var data = JSON.parse(xhttp.responseText);
+          if(data.DevName !== undefined) g('DevName').innerHTML = data.DevName;
+          if(data.HostName !== undefined) g('HostName').innerHTML = data.HostName;
+          if(data.SSID !== undefined) g('SSID').innerHTML = data.SSID;
+          if(data.WiFiConf !== undefined) {
+            if(data.WiFiConf == 1) g('WiFiConf').innerHTML = 'Default';
+            else if(data.WiFiConf == 2) g('WiFiConf').innerHTML = 'Fallback';
+            else g('WiFiConf').innerHTML = data.WiFiConf;
+            }
+          if(data.MAC !== undefined) g('MAC').innerHTML = data.MAC;
+          if(data.IP !== undefined) g('IP').innerHTML = data.IP;
+          if(data.GW !== undefined) g('GW').innerHTML = data.GW;
+          if(data.DNS !== undefined) g('DNS').innerHTML = data.DNS;
+          if(data.UpTime !== undefined) g('UpTime').innerHTML = data.UpTime;
+          if(data.HeapFree !== undefined) g('HeapFree').innerHTML = data.HeapFree + ' Bytes';
+          if(data.HeapFragment !== undefined) g('HeapFragment').innerHTML = data.HeapFragment + ' %';
+          if(data.HeapMaxBlock !== undefined) g('HeapMaxBlock').innerHTML = data.HeapMaxBlock + ' Bytes';
+          if(data.ResetReason !== undefined) g('ResetReason').innerHTML = data.ResetReason;
+          if(data.FWName !== undefined) g('FWName').innerHTML = data.FWName;
+          if(data.FWVer !== undefined) g('FWVer').innerHTML = data.FWVer;
+          if(data.FWBuilt !== undefined) g('FWBuilt').innerHTML = data.FWBuilt;
+          if(data.FWCr !== undefined) g('FWCr').innerHTML = data.FWCr;
+          if(data.FWDebug !== undefined) g('FWDebug').innerHTML = data.FWDebug;
+          if(data.CoreVersion !== undefined) g('CoreVersion').innerHTML = data.CoreVersion;
+          if(data.SDKVersion !== undefined) g('SDKVersion').innerHTML = data.SDKVersion;
+          if(data.CPUfreq !== undefined) g('CPUfreq').innerHTML = data.CPUfreq + ' MHz';
+          if(data.SketchSize !== undefined) g('SketchSize').innerHTML = data.SketchSize + ' Bytes';
+          if(data.FlashSize !== undefined) g('FlashSize').innerHTML = data.FlashSize + ' Bytes';
+          if(data.Time !== undefined) g('Time').innerHTML = data.Time;
+          if(data.Date !== undefined) g('Date').innerHTML = data.Date;
+          xhttp = null;
+          updateTime = 0;
+          reqFin = true;
+          }
+        else {
+          if(!reqFin && reqTime > 10) {
+            xhttp = null;
+            reqFin = true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+  function init() {
+    transmit();
+  }
+  setInterval(transmit, 2500);
+</script>
+</head>
+<body onload='init()'>
+<div id='main'>
+<div id='head'>WiFiThermostat - WTherm-3598
+</div><hr>
+<div></div>
+<p><b>System Information</b></p>
+
+<table style='width:100%'>
+<tr><td>Device Name</td><td><span id='DevName'></td></tr>
+<tr><td colspan='2'>&nbsp;</td></tr>
+<tr><td>Host Name</td><td><span id='HostName'></td></tr>
+<tr><td>SSID</td><td><span id='SSID'></td></tr>
+<tr><td>WiFi-Conf</td><td><span id='WiFiConf'></td></tr>
+<tr><td>MAC</td><td><span id='MAC'></td></tr>
+<tr><td>IP</td><td><span id='IP'></td></tr>
+<tr><td>Gateway</td><td><span id='GW'></td></tr>
+<tr><td>DNS</td><td><span id='DNS'></td></tr>
+<tr><td colspan='2'>&nbsp;</td></tr>
+<tr><td colspan='2'>Heap Memory</td></tr>
+<tr><td>&nbsp;Free</td><td><span id='HeapFree'></td></tr>
+<tr><td>&nbsp;Fragmentation</td><td><span id='HeapFragment'></td></tr>
+<tr><td>&nbsp;Max Blocksize</td><td><span id='HeapMaxBlock'></td></tr>
+<tr><td>CPU Frequency</td><td><span id='CPUfreq'></td></tr>
+<tr><td colspan='2'>&nbsp;</td></tr>
+<tr><td colspan='2'>Firmware</td></tr>
+<tr><td>Name</td><td><span id='FWName'></td></tr>
+<tr><td>Version</td><td><span id='FWVer'></td></tr>
+<tr><td>Built Date</td><td><span id='FWBuilt'></td></tr>
+<tr><td>Created by</td><td><span id='FWCr'></td></tr>
+<tr><td>Debug Version</td><td><span id='FWDebug'></td></tr>
+<tr><td>Core Version</td><td><span id='CoreVersion'></td></tr>
+<tr><td>SDK Version</td><td><span id='SDKVersion'></td></tr>
+<tr><td>Sketch Size</td><td><span id='SketchSize'></td></tr>
+<tr><td>Flash Size</td><td><span id='FlashSize'></td></tr>
+<tr><td colspan='2'>&nbsp;</td></tr>
+<tr><td>Date</td><td><span id='Date'></td></tr>
+<tr><td>Time</td><td><span id='Time'></td></tr>
+<tr><td>Reset Reason</td><td><span id='ResetReason'></td></tr>
+<tr><td>UpTime</td><td><span id='UpTime'></td></tr>
+</table>
+
+<table style='width:100%'>
+<tr>
+<td style='width:100%'><button onclick='location=".";' class='bgrey'>Close</button></td>
+</tr></table>
+<div></div>
+
+<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> 0.6.1 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
+</div></body></html>

+ 1 - 0
webinterface/sysinfod

@@ -0,0 +1 @@
+{"DevName":"WTherm-3598","HostName":"WTherm-3598","MAC":"5C:CF:7F:D3:35:98","IP":"10.1.5.196","GW":"10.1.5.1","DNS":"10.1.1.11","SSID":"Kinf","WiFiConf":1,"UpTime":"00:07","HeapFree":24848,"HeapFragment":4,"HeapMaxBlock":24008,"ResetReason":"External System","CoreVersion":"2_6_3","SDKVersion":"2.2.2-dev(38a443e)","CPUfreq":80,"SketchSize":521264,"FlashSize":4194304,"FWName":"WiFiThermostat","FWVer":"0.6.1","FWCr":"FloKra","FWBuilt":"Jan 17 2020 01:46:15","FWDebug":"no","Time":"01:54","Date":"17.01.2020"}

+ 72 - 0
webinterface/webcsapi

@@ -0,0 +1,72 @@
+{201}[19:42:13] TSTAT: heatingMode=1, preset=1, setTemp=22.5, currSetTemp=20.5
+{202}[19:42:13] TSTAT: heating=off (1085s)
+{203}[19:42:13] SENS: temp=26.0, hum=20, tempRaw=26.0, humRaw=20
+{204}[19:42:13] MQTT: received HEARTBEAT - resetting timer...
+{205}[19:42:52] MQTT: received OUTTemp=-1.3
+{206}[19:42:52] MQTT: received OUTHum=88
+{207}[19:43:21] SYS: uptime=00:19:21, freeHeap=25080, heapFragm=4%
+{208}[19:43:21] MQTT: connected, reconnects: 0
+{209}[19:43:21] TSTAT: heatingMode=1, preset=1, setTemp=22.5, currSetTemp=20.5
+{210}[19:43:21] TSTAT: heating=off (1149s)
+{211}[19:43:21] SENS: temp=26.0, hum=20, tempRaw=26.0, humRaw=20
+{212}[19:43:21] MQTT: received HEARTBEAT - resetting timer...
+{213}[19:43:58] MQTT: received OUTTemp=-1.3
+{214}[19:43:58] MQTT: received OUTHum=88
+{215}[19:44:29] SYS: uptime=00:20:29, freeHeap=25080, heapFragm=4%
+{216}[19:44:29] MQTT: connected, reconnects: 0
+{217}[19:44:29] TSTAT: heatingMode=1, preset=1, setTemp=22.5, currSetTemp=20.5
+{218}[19:44:29] TSTAT: heating=off (1212s)
+{219}[19:44:29] SENS: temp=26.0, hum=20, tempRaw=26.0, humRaw=20
+{220}[19:44:29] MQTT: received HEARTBEAT - resetting timer...
+{221}[19:44:59] MQTT: received OUTTemp=-1.3
+{222}[19:44:59] MQTT: received OUTHum=88
+{223}[19:45:36] SYS: uptime=00:21:37, freeHeap=25080, heapFragm=4%
+{224}[19:45:36] MQTT: connected, reconnects: 0
+{225}[19:45:36] TSTAT: heatingMode=1, preset=1, setTemp=22.5, currSetTemp=20.5
+{226}[19:45:36] TSTAT: heating=off (1275s)
+{227}[19:45:36] SENS: temp=26.0, hum=20, tempRaw=26.0, humRaw=20
+{228}[19:45:37] MQTT: received HEARTBEAT - resetting timer...
+{229}[19:45:59] MQTT: received OUTTemp=-1.4
+{230}[19:45:59] MQTT: received OUTHum=85
+{231}[19:46:01] MQTT: received OUTTemp=-1.4
+{232}[19:46:01] MQTT: received OUTHum=88
+{233}[19:46:44] SYS: uptime=00:22:44, freeHeap=25080, heapFragm=4%
+{234}[19:46:44] MQTT: connected, reconnects: 0
+{235}[19:46:44] TSTAT: heatingMode=1, preset=1, setTemp=22.5, currSetTemp=20.5
+{236}[19:46:44] TSTAT: heating=off (1360s)
+{237}[19:46:44] SENS: temp=26.0, hum=20, tempRaw=26.0, humRaw=20
+{238}[19:46:44] MQTT: received HEARTBEAT - resetting timer...
+{239}[19:47:03] MQTT: received OUTTemp=-1.4
+{240}[19:47:03] MQTT: received OUTHum=88
+{241}[19:47:52] SYS: uptime=00:23:52, freeHeap=25080, heapFragm=4%
+{242}[19:47:52] MQTT: connected, reconnects: 0
+{243}[19:47:52] TSTAT: heatingMode=1, preset=1, setTemp=22.5, currSetTemp=20.5
+{244}[19:47:52] TSTAT: heating=off (1423s)
+{245}[19:47:52] SENS: temp=26.0, hum=20, tempRaw=26.0, humRaw=20
+{246}[19:47:52] MQTT: received HEARTBEAT - resetting timer...
+{247}[19:48:09] MQTT: received OUTTemp=-1.4
+{248}[19:48:09] MQTT: received OUTHum=88
+{249}[19:49:00] SYS: uptime=00:25:00, freeHeap=25080, heapFragm=4%
+{250}[19:49:00] MQTT: connected, reconnects: 0
+{251}[19:49:00] TSTAT: heatingMode=1, preset=1, setTemp=22.5, currSetTemp=20.5
+{252}[19:49:00] TSTAT: heating=off (1487s)
+{253}[19:49:00] SENS: temp=26.0, hum=20, tempRaw=26.0, humRaw=20
+{254}[19:49:00] MQTT: received HEARTBEAT - resetting timer...
+{255}[19:49:15] MQTT: received OUTTemp=-1.4
+{256}[19:49:15] MQTT: received OUTHum=88
+{257}[19:50:08] SYS: uptime=00:26:08, freeHeap=25080, heapFragm=4%
+{258}[19:50:08] MQTT: connected, reconnects: 0
+{259}[19:50:08] TSTAT: heatingMode=1, preset=1, setTemp=22.5, currSetTemp=20.5
+{260}[19:50:08] TSTAT: heating=off (1550s)
+{261}[19:50:08] SENS: temp=26.0, hum=20, tempRaw=26.0, humRaw=20
+{262}[19:50:08] MQTT: received HEARTBEAT - resetting timer...
+{263}[19:50:21] MQTT: received OUTTemp=-1.4
+{264}[19:50:21] MQTT: received OUTHum=88
+{265}[19:51:16] SYS: uptime=00:27:16, freeHeap=25080, heapFragm=4%
+{266}[19:51:16] MQTT: connected, reconnects: 0
+{267}[19:51:16] TSTAT: heatingMode=1, preset=1, setTemp=22.5, currSetTemp=20.5
+{268}[19:51:16] TSTAT: heating=off (1635s)
+{269}[19:51:16] SENS: temp=26.0, hum=20, tempRaw=26.1, humRaw=20
+{270}[19:51:16] MQTT: received HEARTBEAT - resetting timer...
+{271}[19:51:27] MQTT: received OUTTemp=-1.4
+{272}[19:51:27] MQTT: received OUTHum=88

+ 0 - 0
src/webinterface/wsapp.js → webinterface/wsapp.js


+ 3 - 3
src/webinterface/console → webinterface/wsconsole

@@ -1,10 +1,10 @@
 <html><head>
 <meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>
 <link rel='stylesheet' href='style.css'>
-<title>WiFiThermostat - WTherm-T5WZ</title></head>
+<title>WiFiThermostat - WTherm-3598</title></head>
 <body>
 <div id='main'>
-<div id='head'>WiFiThermostat - WTherm-T5WZ
+<div id='head'>WiFiThermostat - WTherm-3598
 </div><hr>
 <div></div>
 <p><b>Console</b></p>
@@ -18,5 +18,5 @@
 </table>
 <script src="wsapp.js"></script>
 
-<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> v0.6.0 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
+<div style='text-align:right;font-size:0.7em;color:#AAA;'><hr/><a href='https://git.flokra.at/flo/WiFiThermostat' target='_blank' style='color:#AAA;'>WiFiThermostat</a> 0.6.1 by <a href='https://www.flokra.at/' target='_blank' style='color:#AAA;'>FloKra</a></div>
 </div></body></html>

Some files were not shown because too many files changed in this diff