//#include // ESP8266 core libs #include #include #include #include //#include // WiFiManager #include // DNS server used for captive portal in WiFiManager #include // MQTT client #include // SPIFFS FS support - used for config storage #include // Json lib - used for config storage and web api #include //#include // I2C and LCD display #include #include // DHT22 sensor lib #include // Button handling #include #include #include #include // PRE-COMPILE CONFIGURATION //#define FORCE_SPIFFS_FORMAT //#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_MQTT true // 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 #endif //#ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS #include //#endif // DEFINE NAMES #define FIRMWARE_NAME "WiFiThermostat" #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/" #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 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 #define DEFAULT_WIFI_REBOOT_ONNOCONNECT 60 //min // confWeb #define HTTP_SET_TOKEN "" #define DEFAULT_HTTP_USER "" #define DEFAULT_HTTP_PASS "" #define DEFAULT_HTTP_USER_AUTH false #define DEFAULT_ENABLE_WEBCONSOLE true // confMqtt #define MQTT_ENABLE false #define MQTT_SERVER "" #define MQTT_PORT 1883 #define MQTT_USER "" #define MQTT_PASS "" #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/WTherm/availability" #define MQTT_WILLQOS 2 #define MQTT_WILLRETAIN false #define MQTT_WILLMSG "offline" #define MQTT_CONNMSG "online" #define MQTT_ENABLE_HEARTBEAT true // max interval for MQTT heartbeat message. only applicable if MQTT // IN-topic is defined. after this timeout MQTT reconnect is forced #define MQTT_HEARTBEAT_MAXAGE 180000 // max interval for MQTT heartbeat message. only applicable if MQTT // IN-topic is defined. after this timeout the ESP will reboot #define MQTT_HEARTBEAT_MAXAGE_REBOOT 1800000 // confBas #define DEFAULT_SETTEMP_MIN 16.0 // minimal temperature that can be set #define DEFAULT_SETTEMP_MAX 26.0 // maximal temperature that can be set #define AUTOSAVE_SETTEMP true #define AUTOSAVE_SETMODE false #define SAVE_TO_MQTT_RETAINED false #define DEFAULT_MEASURE_INTERVAL 15 // interval for temp/hum measurement // 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.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 // heating is already switched off #define SETTEMP_DECREASE_VALUE 0.0 #define OFF_MESSAGE "HEATING OFF" #define INSIDE_TEMP_LABEL "I" #define OUTSIDE_TEMP_LABEL "O" #define MODE_NAME_0 "off" #define MODE_NAME_1 "heat" #define PRESET_NAME_0 "Normal" #define PRESET_NAME_1 "Reduction 1" #define PRESET_NAME_2 "Reduction 2" // confAdd #define OUTTEMP_TOPIC_IN "" #define OUTHUM_TOPIC_IN "" #define MQTT_TOPIC_PIR "" // extra publish topic for PIR sensor #define MQTT_TOPIC_PIR_ON "ON" #define MQTT_TOPIC_PIR_OFF "OFF" // 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 17.0 // set temperature in night/low mode // 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 // pin assignments and I2C addresses #define PIN_DHTSENSOR 13 #define PIN_RELAIS 15 // 16 #define PIN_BUTTON_PLUS 2 #define PIN_BUTTON_MINUS 0 #define PIN_BUTTON_MODE 14 #define PIN_PIRSENSOR 12 #define DHTTYPE DHT22 // DHT sensor type #define LCDADDR 0x27 // I2C address LCD #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 #define LOGLEVEL_WARN 2 #define LOGLEVEL_INFO 3 #define LOGLEVEL_DEBUG 4 #define LOGLEVEL_VERBOSE 5 // 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"; PROGMEM const char PGMStr_setTemp[] = "setTemp"; PROGMEM const char PGMStr_currentSetTemp[] = "currSetTemp"; PROGMEM const char PGMStr_setTempLow[] = "setTempLow"; PROGMEM const char PGMStr_setTempLow2[] = "setTempLow2"; PROGMEM const char PGMStr_switchHeating[] = "switch heating"; 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_MQTT[] = "MQTT"; PROGMEM const char PGMStr_connectedReconnects[] = "connected, reconnects"; PROGMEM const char PGMStr_connectedFailed[] = "connect FAILED"; 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_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]; //--------------------------------------------------------------------------------------------------------------------------------------------- PushButton buttonPlus = PushButton(PIN_BUTTON_PLUS, ENABLE_INTERNAL_PULLUP); 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 WifiInApMode = false; unsigned long WifiApModeStartedAt; #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"}; #endif // config variables - do not change here! // confDevWiFi struct confDataDevWiFi { char deviceName[33]; // device name - for web interface and AP-Mode SSID char hostName[33]; // announced hostname on WiFi connection char WiFiSSID1[33]; char WiFiPW1[64]; char WiFiSSID2[33]; char WiFiPW2[64]; char WiFiAPModeSSID[33]; // generated, not set via config char WiFiAPModePassword[64]; uint16_t WiFiAPModeTimeout; uint16_t WiFiRetryInterval; uint16_t WiFiConnCheckInterval; uint16_t WiFiRebootOnNoConnect; } confDevWiFi; // confWeb struct confDataWeb { char http_token[31]; char http_user[31]; char http_pass[31]; bool http_user_auth; char http_user1[31]; char http_pass1[31]; char http_user2[31]; char http_pass2[31]; bool wConsole; bool wsConsole; } confWeb; // confMqtt struct confDataMqtt { bool mqtt_enable; char mqtt_server[41]; uint16_t mqtt_port; char mqtt_user[31]; char mqtt_pass[31]; char mqtt_topic_in[51]; // MQTT in topic for commands char mqtt_topic_out[51]; // MQTT out base topic, will be extended by various value names char mqtt_willTopic[51]; // MQTT Last Will topic uint8_t mqtt_willQos; // MQTT Last Will topic QOS bool mqtt_willRetain; // MQTT Last Will retain char mqtt_willMsg[31]; // MQTT Last Will payload char mqtt_connMsg[31]; bool mqtt_outRetain; // send MQTT out with retain flag bool mqtt_outRetain_sensors; // send MQTT out with retain flag uint8_t mqtt_outPubInterval; uint8_t mqtt_outPubInterval_sensors; bool mqtt_enable_heartbeat; unsigned long mqtt_heartbeat_maxage_reconnect; unsigned long mqtt_heartbeat_maxage_reboot; } confMqtt; // confBas struct confDataBas { float setTempMin; // minimal temperature that can be set float setTempMax; // maximal temperature that can be set bool autoSaveSetTemp; bool autoSaveHeatingMode; bool saveToMqttRetained; uint16_t measureInterval; // interval for temp/hum measurement uint16_t displayInterval; // interval for display updates (if out-temp is // active, display will toggle in this interval) uint16_t displayTimeout; // display timeout after keypress (illumination) bool PIR_enablesDisplay; // PIR sensor enables display illumination bool PIR_enablesDisplay_preset0only; bool togglingTempHumAIDisplay; } confBas; // confAdv struct confDataAdv { float hysteresis; // hysteresis, normally 0.1 - 0.5 uint16_t heatingMinOffTime; // minimal time the heating keeps turned off in // s float tempCorrVal; // correction value for // temperature sensor reading int humCorrVal; // correction value for humidity sensor reading float setTempDecreaseVal; // decreases the set temp to overcome further // temperature rise when the heating is already // switched off char offMessage[15]; char iTempLabel[2]; char oTempLabel[2]; char modeName0[15]; char modeName1[15]; char psetName0[15]; char psetName1[15]; char psetName2[15]; } confAdv; // confAdd struct confDataAdd { char mqtt_topic_pir[51]; char mqtt_payload_pir_on[10]; char mqtt_payload_pir_off[10]; char outTemp_topic_in[51]; char outHum_topic_in[51]; } confAdd; // confTime struct confDataTime { bool ntpEnable; char timeZoneStr[50]; char ntpServer1[31]; char ntpServer2[31]; unsigned long ntpSyncInterval; } confTime; // confLog struct confDataLog { uint8_t logLevelSerial; 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]; char mqtt_topic_in_setTemp[61]; char mqtt_topic_in_setMode[61]; char mqtt_topic_in_setPreset[61]; // set values float setTemp = DEFAULT_SETTEMP; float setTempLow = DEFAULT_SETTEMP_LOW; // set temperature in night/low mode float setTempLow2 = DEFAULT_SETTEMP_LOW2; // set temperature in night/low mode float currSetTemp = DEFAULT_SETTEMP; uint8_t heatingMode = DEFAULT_HEATINGMODE; // 0 = off, 1 = heat uint8_t preset = DEFAULT_PRESET; // 0 = normal/day, 1 = night/reduction 1, 2 = // reduction 2 (long term leave) // saved set values (same as above, held in memory additionally to prevent // saving unchanged values) float setTempSaved; float setTempLowSaved; float setTempLow2Saved; uint8_t heatingModeSaved; uint8_t presetSaved; // global pre set conf variables - not changeable via configuration float setTempLowMin = SETTEMP_LOW_MIN; float setTempLowMax = SETTEMP_LOW_MAX; uint16_t debounceTime = BUTTON_DEBOUNCE_TIME; uint16_t buttonHoldTime = BUTTON_HOLD_TIME; unsigned long maxMeasurementAge = MAX_MEASUREMENT_AGE; unsigned long maxMeasurementAgeOut = MAX_MEASUREMENT_AGE_OUT; // global variables for program flow float currTemp; // last reading from DHT sensor with smoothing float currTemp_raw; // last reading from DHT sensor (raw) uint16_t currHum; // last reading from DHT sensor with smoothing uint16_t currHum_raw; // last reading from DHT sensor (raw) bool turnHeatingOn = false; // true if heating is active (relais switched on) unsigned long heatingLastOnMillis; // last time heating was switched on unsigned long heatingLastOffMillis; // last time heating was switched off float outTemp; // outside temp (via MQTT if enabled and in-topic configured) uint16_t outHum; // outside temp (via MQTT if enabled and in-topic configured) unsigned long outTempHumLastUpdate; // last reading from out temp/hum source char outTemp_newValue[6]; bool outTemp_parseNewValue; char outHum_newValue[4]; bool outHum_parseNewValue; char currentModeName[15]; char currentPresetName[15]; uint16_t displayInterval; uint8_t whichTempToDisplay; // 1=temp inside (from DHT sensor), 2= temp outside // (via MQTT) - if out temp/hum available this value // and the displayed value pair toggles with every // displayInterval 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[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; unsigned long lastUpdate_setTemp = 0; // set to millis() every time setTemp value is changed unsigned long lastUpdate_setTempLow = 0; // set to millis() every time setTemp value is changed unsigned long lastUpdate_setTempLow2 = 0; // set to millis() every time setTemp value is changed 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 // 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 // and/or heatingMode value is changed. used for // autoSave function with hardcoded 5s timeout bool setTempAlreadySaved = true; // only save if not yet done bool setTempLowAlreadySaved = true; // only save if not yet done bool setTempLow2AlreadySaved = true; // only save if not yet done bool heatingModeAlreadySaved = true; // only save if not yet done bool presetAlreadySaved = true; // only save if not yet done unsigned long lastRun = 0; uint16_t count100ms = 0; uint16_t countSeconds = 0; uint16_t countMeasureInterval = 0; uint16_t countDisplayInterval = 0; uint16_t displayOverlayMsgTimeout = 2; unsigned long mqttLastReconnectAttempt = 0; uint16_t mqttReconnectAttempts = 0; uint16_t mqttReconnects = 0; bool mqttConnected = false; unsigned long mqttLastHeartbeat; bool mqttInTopicSubscribed = false; bool pendingRestart = false; bool doRestart = false; unsigned long pendingRestart_lastMillis = 0; bool displayShowFullscreenMsg = false; // unsigned long displayShowFullscreenMsg_lastMillis = 0; bool pendingPresetToggle = false; bool updateDisplayImmediately = false; uint8_t pendingPreset; char pendingPresetName[15]; bool displayShowLine2OverlayMsg = false; // 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; 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 // FUNCTION PROTOTYPES #ifdef ENABLE_FEATURE_NTP_TIME void updateTime(); bool setupTime(); 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(PGMStr_FIRMWARE_NAME); Serial.print(F(" v")); Serial.print(PGMStr_FIRMWARE_VERSION); Serial.println(F(" starting...")); pinMode(PIN_RELAIS, OUTPUT); digitalWrite(PIN_RELAIS, !RELAISONSTATE); setupInputsButtons(); // set conf default values loadConf_defaults(); //if (serialdebug) // Serial.println("default config values loaded.."); sendLog(F("CONF: default config loaded."), LOGLEVEL_INFO); initDisplay(); sendLog(F("Mounting SPIFFS..."), LOGLEVEL_INFO); if (!SPIFFS.begin()) { sendLog(F("Failed to mount SPIFFS"), LOGLEVEL_ERROR); return; } #ifdef FORCE_SPIFFS_FORMAT SPIFFS_format(); #endif SPIFFS_formatIfIsnt(); //SPIFFS_listFiles(); #ifdef ENABLE_FEATURE_PW_ENCRYPTION confCheckEncrypted(); #endif loadConf_all(); loadSavedValues(); // if configuration returned empty strings - use the defaults where a values // is necessary if (strlen(deviceName) < 4) strlcpy(deviceName, DEVICE_NAME, // 31); loadConf_restoreDefaultWhenMissing(); updateCurrentHeatingModeName(); updateCurrentPresetName(); // initialize DHT11/22 temp/hum sensor dht.begin(); if (strlen(confDevWiFi.hostName) >= 4) { // if no hostname is set WiFi manager will create a unique one automatically // based on MAC address WiFi.hostname(confDevWiFi.hostName); } // optional code handlers to run everytime wifi is connected... persWM.onConnect([]() { //Serial.print(F("WiFi: connected to '")); //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); printIpcfg(); WifiInApMode = false; #ifdef ENABLE_FEATURE_NTP_TIME if (confTime.ntpEnable) setupTime(); #endif displayShowWifiConnected(); }); //...or AP mode is started persWM.onAp([]() { //Serial.print(F("WiFi: AP mode, SSID: '")); //Serial.print(persWM.getApSsid()); //if (strlen(confDevWiFi.WiFiAPModePassword) >= 4) //{ // Serial.print("', PW: '"); // Serial.print(confDevWiFi.WiFiAPModePassword); //} //Serial.println("'"); char buf[60]; sprintf(buf, "%s: AP-MODE started, SSID '%s', PW: '%s'", PGMStr_WiFi, persWM.getApSsid().c_str(), confDevWiFi.WiFiAPModePassword); sendLog(buf, LOGLEVEL_INFO); WifiInApMode = true; WifiApModeStartedAt = millis(); displayShowWifiConnectionError(); }); persWM.onApOff([]() { //Serial.println(F("WiFi: AP mode stopped")); sendLog(F("WiFi: AP-MODE stopped"), LOGLEVEL_INFO); }); // sets network name and password for AP mode // sprintf(WiFiAPModeSSID, "%s-%s", FIRMWARE_SHORTNAME, deviceName); if (strlen(confDevWiFi.deviceName) >= 8) strlcpy(confDevWiFi.WiFiAPModeSSID, confDevWiFi.deviceName, sizeof(confDevWiFi.WiFiAPModeSSID)); else { byte mac[6]; WiFi.macAddress(mac); sprintf(confDevWiFi.WiFiAPModeSSID, "%s-%02X%02X", FIRMWARE_SHORTNAME, (uint8_t)mac[4], (uint8_t)mac[5]); } //Serial.print(F("WiFi: AP-SSID name: ")); //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("'"); persWM.setWifi1Credentials(confDevWiFi.WiFiSSID1, confDevWiFi.WiFiPW1); persWM.setWifi2Credentials(confDevWiFi.WiFiSSID2, confDevWiFi.WiFiPW2); persWM.setHttpCredentials(confWeb.http_user, confWeb.http_pass); persWM.setApTimeout(confDevWiFi.WiFiAPModeTimeout); persWM.setConnCheckInterval(confDevWiFi.WiFiConnCheckInterval); persWM.setForceRetryWifi1Interval(confDevWiFi.WiFiRetryInterval); persWM.setRebootOnNoConnect(confDevWiFi.WiFiRebootOnNoConnect); // make connecting/disconnecting non-blocking persWM.setConnectNonBlock(true); // in non-blocking mode, program will continue past this point without waiting persWM.begin(); delay(500); httpServerInit(); #ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS if (confWeb.wsConsole) startWebSocketServer(); #endif if (confMqtt.mqtt_enable) { mqttPrepareSubscribeTopics(); mqttClientInit(); } sendLog(F("DEV: setup complete."), LOGLEVEL_INFO); } // void setup void loop() { checkMillis(); persWM.handleWiFi(); // in non-blocking mode, handleWiFi must be called in the // main loop yield(); mqttHandleConnection(); yield(); outTempHum_updateOnNewValue(); yield(); dnsServer.processNextRequest(); httpServer.handleClient(); buttonPlus.update(); buttonMinus.update(); buttonMode.update(); pirSensor.update(); yield(); evalCmd(); yield(); if (Serial.available()) { serialEvent(); yield(); } if (updateDisplayImmediately) { updateDisplayImmediately = false; updateDisplay(); } #ifdef ENABLE_FEATURE_WEB_CONSOLE_WEBSOCKETS if (confWeb.wsConsole) { if (WiFi.status() == WL_CONNECTED) { webSocket.loop(); } else { webSocket.disconnect(); } } #endif } // void loop