//#include #include "version.h" #include "firmware_definitions.h" #include "settings.h" #include "settings_secrets.h" // ESP8266 core libs #include #include #include #include #include #ifdef ENABLE_I2C_INTERFACE #include #endif #ifdef ENABLE_FEATURE_ARDUINO_OTA #include #include #endif #ifdef ENABLE_FEATURE_NTP_TIME #include #endif // cannot be excluded if unused, throws error even if all // references are inactive by preprocessor #include #ifdef USE_MQTT_TLS #include #else #include #endif // WiFiManager #include // DNS server used for captive portal in WiFiManager #include // MQTT client #include // File System support - used for config storage (switched from SPIFFS to LittleFS in 12/2021) #include "LittleFS.h" // LittleFS is declared FSInfo fs_info; // struct for file system infos // Json lib - used for web api #include // I2C LCD display #ifdef ENABLE_LCD_I2C #include #endif // DHT22 sensor lib #ifdef ENABLE_SENSOR_DHT22 //#include // not needed for used version of DHT library v1.3.8 #include #endif // Dallas OneWire Temperature Sensors #ifdef ENABLE_SENSORS_ONEWIRE #include #include // Setup a oneWire instance to communicate with any OneWire devices OneWire oneWire(ONE_WIRE_BUS); // Pass our oneWire reference to Dallas Temperature sensor DallasTemperature oneWireSensors(&oneWire); // arrays to hold device addresses //DeviceAddress oneWireSensor0, oneWireSensor1, oneWireSensor2; DeviceAddress oneWireSensors_IndexToAddress[ONEWIRE_SENSORS_COUNT]; //DeviceAddress oneWireDevAddress_outside = { 0x28, 0xd7, 0xbd, 0x16, 0x00, 0x00, 0x00, 0xcd }; //DeviceAddress oneWireDevAddress_feed = { 0x28, 0x75, 0xb2, 0x16, 0x00, 0x00, 0x00, 0x90 }; //DeviceAddress oneWireDevAddress_return = { 0x28, 0x1f, 0x7a, 0x17, 0x00, 0x00, 0x00, 0x0f }; //uint8_t oneWireDevAddress_tempFeed[0] = {0x28, 0x75, 0xb2, 0x16, 0x00, 0x00, 0x00, 0x90}; // temp feed //uint8_t oneWireDevAddress_tempReturn[] = {0x28, 0x1f, 0x7a, 0x17, 0x00, 0x00, 0x00, 0x0f}; // temp return //uint8_t oneWireDevAddress_tempOutside[] = {0x28, 0xd7, 0xbd, 0x16, 0x00, 0x00, 0x00, 0xcd}; // temp outside //uint8_t confSens.oneWireDevAddress[ONEWIRE_SENSORS_COUNT][8]; //= { // {0x28, 0x75, 0xb2, 0x16, 0x00, 0x00, 0x00, 0x90}, // temp feed // {0x28, 0x1f, 0x7a, 0x17, 0x00, 0x00, 0x00, 0x0f}, // temp return // {0x28, 0xd7, 0xbd, 0x16, 0x00, 0x00, 0x00, 0xcd} // temp outside //}; // -> moved to struct confSens uint8_t oneWireSensor_assignedDevToIndex[ONEWIRE_SENSORS_COUNT] = {255, 255, 255}; //uint8_t oneWireDevAddressToSensor[ONEWIRE_SENSORS_COUNT]; //float tempFeed, tempReturn, tempOutside; #endif #ifdef ENABLE_I2C_PORTEXPANDER #include PCF8574 pcf8574(PCF8574_I2C_ADDRESS, PIN_I2C_SDA, PIN_I2C_SCL); #endif //#ifdef ENABLE_INPUT_BUTTONS // can not be excluded if unused, throws compile error // even when all references are also deactivated by preprocessor #include #include #include #include //#endif #ifdef LANG_DE #include "strings_progmem_DE.h" #else #include "strings_progmem.h" #endif //--------------------------------------------------------------------------------------------------------------------------------------------- #include "globalVars_conf.h" #include "globalVars.h" #ifdef FIRMWARE_VARIANT_THERMOSTAT #include "globalVars_conf_thermostat.h" #include "globalVars_thermostat.h" #endif #ifdef FIRMWARE_VARIANT_HEATCONTROL #include "globalVars_heatcontrol.h" #include "globalVars_conf_heatcontrol.h" #ifdef LANG_DE #include "heatcontrol_strings_DE.h" #else #include "heatcontrol_strings.h" #endif #endif #ifdef ENABLE_INPUT_BUTTONS PushButton buttonMode = PushButton(PIN_BUTTON_MODE, ENABLE_INTERNAL_PULLUP); #ifdef FIRMWARE_VARIANT_THERMOSTAT PushButton buttonPlus = PushButton(PIN_BUTTON_PLUS, ENABLE_INTERNAL_PULLUP); PushButton buttonMinus = PushButton(PIN_BUTTON_MINUS, ENABLE_INTERNAL_PULLUP); #endif #ifdef ENABLE_SENSOR_PIR PushButton pirSensor = PushButton(PIN_PIRSENSOR, PRESSED_WHEN_HIGH); #endif #endif #ifdef ENABLE_SENSOR_DHT22 DHT dht(PIN_DHTSENSOR, DHTTYPE); #endif #ifdef ENABLE_LCD_I2C LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDLINES); #ifdef LANG_DE #include "strings_display_DE.h" #else #include "strings_display.h" #endif #endif #ifdef USE_MQTT_TLS //WiFiClientSecure wifiClient; BearSSL::WiFiClientSecure wifiClient; #else WiFiClient wifiClient; #endif PubSubClient mqttclient(wifiClient); ESP8266WebServer httpServer(80); // WebSockets Console #ifdef ENABLE_FEATURE_WSCONSOLE 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); #ifdef FIRMWARE_VARIANT_THERMOSTAT void thermostat_publishCurrentValues(bool force = false); #endif // END - FUNCTION PROTOTYPES // MAIN FUNCTIONS void setup() { conf_restoreDebugMode(); Serial.begin(SERIAL_BAUDRATE); delay(50); if(debug) { Serial.println(); Serial.print(PGMStr_FIRMWARE_NAME); Serial.print(F(" v")); Serial.print(PGMStr_FIRMWARE_VERSION); Serial.println(F(" starting...")); Serial.print("DEBUG="); Serial.println(debug); } #ifdef ENABLE_I2C_INTERFACE Wire.begin(PIN_I2C_SDA, PIN_I2C_SCL); #endif #ifdef FIRMWARE_VARIANT_THERMOSTAT thermostat_setup(); #endif #ifdef ENABLE_INPUT_BUTTONS setupInputsButtons(); #endif // set conf default values loadConf_defaults(); if(debug) { snprintf_P(logBuf, LOG_BUFFER_SIZE, PGMStr_conf_defaultsLoaded); sendLog(logBuf); } #ifdef ENABLE_LCD_I2C display_init(); #endif // LittleFS if(debug) { snprintf_P(logBuf, LOG_BUFFER_SIZE, PGMStr_filesystem_mounting); sendLog(logBuf, LOGLEVEL_ERROR); } if (!LittleFS.begin()) { snprintf_P(logBuf, LOG_BUFFER_SIZE, PGMStr_filesystem_mounting_error); sendLog(logBuf, LOGLEVEL_ERROR); return; } #ifdef FORCE_FILESYSTEM_FORMAT FS_format(); #endif FS_formatIfIsnt(); if(debug) { FS_listFiles(); } #ifdef ENABLE_FEATURE_SECRETS_ENCRYPTION confCheckEncrypted(); #endif loadConf_all(); // if configuration returned empty strings - use the defaults where a values // is necessary if (strlen(deviceName) < 4) strlcpy(deviceName, DEVICE_NAME, // 31); loadConf_restoreDefaultWhenMissing(); #ifdef FIRMWARE_VARIANT_THERMOSTAT thermostat_loadSavedValues(); thermostat_updateCurrentHeatingModeName(); thermostat_updateCurrentPresetName(); #endif // initialize DHT11/22 temp/hum sensor #ifdef ENABLE_SENSOR_DHT22 dht.begin(); #endif // Start the DS18B20 sensor #ifdef ENABLE_SENSORS_ONEWIRE oneWireSensors_setup(); oneWireSensors_loadAssignments(); #endif #ifdef ENABLE_I2C_PORTEXPANDER portexpander_setup(); #endif 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 #ifdef ENABLE_LCD_I2C display_showWifiConnected(); #endif }); //...or AP mode is started persWM.onAp([]() { snprintf_P(logBuf, LOG_BUFFER_SIZE, PGMStr_setup_APmode_started, PGMStr_WiFi, persWM.getApSsid().c_str(), confSecrets.WiFiAPModePassword); sendLog(logBuf, LOGLEVEL_INFO); WifiInApMode = true; WifiApModeStartedAt = millis(); #ifdef ENABLE_LCD_I2C display_showWifiConnectionError(); #endif }); persWM.onApOff([]() { snprintf_P(logBuf, LOG_BUFFER_SIZE, PGMStr_setup_APmode_stopped, PGMStr_WiFi); sendLog(logBuf, LOGLEVEL_INFO); }); // sets network name and password for AP mode 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]); } if (strlen(confSecrets.WiFiAPModePassword) < 5) { persWM.setApCredentials(confDevWiFi.WiFiAPModeSSID); if(debug>0) { snprintf_P(logBuf, LOG_BUFFER_SIZE, PGMStr_setup_APmode_openNet, PGMStr_WiFi, confDevWiFi.WiFiAPModeSSID); sendLog(logBuf); } } else { persWM.setApCredentials(confDevWiFi.WiFiAPModeSSID, confSecrets.WiFiAPModePassword); if(debug>0) { snprintf_P(logBuf, LOG_BUFFER_SIZE, PGMStr_setup_APmode_withPassword, PGMStr_WiFi, confDevWiFi.WiFiAPModeSSID, confSecrets.WiFiAPModePassword); sendLog(logBuf, LOGLEVEL_INFO); } } persWM.setWifi1Credentials(confDevWiFi.WiFiSSID1, confSecrets.WiFiPW1); persWM.setWifi2Credentials(confDevWiFi.WiFiSSID2, confSecrets.WiFiPW2); persWM.setHttpCredentials(confSecrets.http_user, confSecrets.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(); #ifdef USE_MQTT_TLS //randomSeed(micros()); //wifiClient.setFingerprint(MQTT_TLS_fingerprint); wifiClient.setInsecure(); wifiClient.allowSelfSignedCerts(); wifiClient.setCiphersLessSecure(); #endif httpServerInit(); #ifdef ENABLE_FEATURE_ARDUINO_OTA if(confDevWiFi.enableArduinoOTA) { ArduinoOTA.setPort(ARDUINO_OTA_PORT); ArduinoOTA.begin(); } #endif #ifdef ENABLE_FEATURE_WSCONSOLE if (confWeb.wsConsole) { startWebSocketServer(); } #endif if (confMqtt.mqtt_enable) { mqttPrepareSubscribeTopics(); mqttClientInit(); } snprintf_P(logBuf, LOG_BUFFER_SIZE, PGMStr_system_setupComplete); sendLog(logBuf, LOGLEVEL_INFO); // get sensor data and do things right on system start #ifdef ENABLE_SENSORS_ONEWIRE oneWireSensors_getData(); #endif #ifdef ENABLE_SENSOR_DHT22 if (confSens.DHT_enable) DHT_measureTempHum(); #endif #ifdef FIRMWARE_VARIANT_THERMOSTAT thermostat_mainFunction(); #endif #ifdef FIRMWARE_VARIANT_HEATCONTROL heatcontrol_mainFunction(); portexpander_readInputs(); #endif } // void setup void loop() { scheduler_checkMillis(); persWM.handleWiFi(); // in non-blocking mode, handleWiFi must be called in the main loop yield(); mqttHandleConnection(); yield(); #ifdef ENABLE_FEATURE_ARDUINO_OTA if(confDevWiFi.enableArduinoOTA) { ArduinoOTA.handle(); yield(); } #endif outTempHum_updateOnNewValue(); yield(); dnsServer.processNextRequest(); httpServer.handleClient(); #ifdef ENABLE_INPUT_BUTTONS buttonMode.update(); #ifdef FIRMWARE_VARIANT_THERMOSTAT buttonPlus.update(); buttonMinus.update(); #endif #ifdef ENABLE_SENSOR_PIR pirSensor.update(); #endif #endif yield(); evalCmd(); yield(); if (Serial.available()) { serialEvent(); yield(); } #ifdef ENABLE_LCD_I2C if (display_updateImmediately) { display_updateImmediately = false; display_update(); } #endif #ifdef ENABLE_FEATURE_WSCONSOLE if (confWeb.wsConsole) { if (WiFi.status() == WL_CONNECTED) { webSocket.loop(); } else { webSocket.disconnect(); } } #endif } // void loop //#ifdef USE_MQTT_TLS //void verifytls() { // // Use WiFiClientSecure class to create TLS connection // Serial.print(F("MQTT: trying TLS connection to ")); // Serial.println(confMqtt.mqtt_server); // if (!wifiClient.connect(confMqtt.mqtt_server, confMqtt.mqtt_port)) { // Serial.println("connection failed"); // return; // } // // if (wifiClient.verify(MQTT_TLS_fingerprint, confMqtt.mqtt_server)) { // Serial.println("certificate matches"); // } else { // Serial.println("certificate doesn't match"); // } //} //#endif