#define WM_MDNS #include #include #include #include #include #ifdef ARDUINO_ARCH_ESP8266 extern "C" { #include "lwip/etharp.h" } #endif WiFiManager wm; WiFiManagerParameter* wmHostname; WiFiManagerParameter* wmMqttServer; UnsignedShortParameter* wmMqttPort; WiFiManagerParameter* wmMqttUser; WiFiManagerParameter* wmMqttPassword; WiFiManagerParameter* wmMqttPrefix; UnsignedIntParameter* wmMqttPublishInterval; UnsignedIntParameter* wmOtInPin; UnsignedIntParameter* wmOtOutPin; UnsignedIntParameter* wmOtMemberIdCode; CheckboxParameter* wmOtDhwPresent; CheckboxParameter* wmOtSummerWinterMode; CheckboxParameter* wmOtHeatingCh2Enabled; CheckboxParameter* wmOtHeatingCh1ToCh2; CheckboxParameter* wmOtDhwToCh2; CheckboxParameter* wmOtDhwBlocking; CheckboxParameter* wmOtModSyncWithHeating; UnsignedIntParameter* wmOutdoorSensorPin; UnsignedIntParameter* wmIndoorSensorPin; #if USE_BLE WiFiManagerParameter* wmOutdoorSensorBleAddress; #endif CheckboxParameter* wmExtPumpUse; UnsignedIntParameter* wmExtPumpPin; UnsignedShortParameter* wmExtPumpPostCirculationTime; UnsignedIntParameter* wmExtPumpAntiStuckInterval; UnsignedShortParameter* wmExtPumpAntiStuckTime; HeaderParameter* wmMqttHeader; HeaderParameter* wmOtHeader; HeaderParameter* wmOtFlagsHeader; HeaderParameter* wmSensorsHeader; HeaderParameter* wmExtPumpHeader; extern EEManager eeSettings; #if USE_TELNET extern ESPTelnetStream TelnetStream; #endif const char S_WIFI[] PROGMEM = "WIFI"; const char S_WIFI_SETTINGS[] PROGMEM = "WIFI.SETTINGS"; class WifiManagerTask : public LeanTask { public: WifiManagerTask(bool _enabled = false, unsigned long _interval = 0) : LeanTask(_enabled, _interval) { wmHostname = new WiFiManagerParameter("hostname", "Hostname", settings.hostname, 80); wm.addParameter(wmHostname); wmMqttHeader = new HeaderParameter("MQTT"); wm.addParameter(wmMqttHeader); wmMqttServer = new WiFiManagerParameter("mqtt_server", "Server", settings.mqtt.server, 80); wm.addParameter(wmMqttServer); wmMqttPort = new UnsignedShortParameter("mqtt_port", "Port", settings.mqtt.port, 6); wm.addParameter(wmMqttPort); wmMqttUser = new WiFiManagerParameter("mqtt_user", "Username", settings.mqtt.user, 32); wm.addParameter(wmMqttUser); wmMqttPassword = new WiFiManagerParameter("mqtt_password", "Password", settings.mqtt.password, 32, "type=\"password\""); wm.addParameter(wmMqttPassword); wmMqttPrefix = new WiFiManagerParameter("mqtt_prefix", "Prefix", settings.mqtt.prefix, 32); wm.addParameter(wmMqttPrefix); wmMqttPublishInterval = new UnsignedIntParameter("mqtt_publish_interval", "Publish interval (sec)", settings.mqtt.interval, 3); wm.addParameter(wmMqttPublishInterval); wmOtHeader = new HeaderParameter("OpenTherm"); wm.addParameter(wmOtHeader); wmOtInPin = new UnsignedIntParameter("ot_in_pin", "GPIO IN", settings.opentherm.inPin, 2); wm.addParameter(wmOtInPin); wmOtOutPin = new UnsignedIntParameter("ot_out_pin", "GPIO OUT", settings.opentherm.outPin, 2); wm.addParameter(wmOtOutPin); wmOtMemberIdCode = new UnsignedIntParameter("ot_member_id_code", "Master Member ID", settings.opentherm.memberIdCode, 5); wm.addParameter(wmOtMemberIdCode); wmOtFlagsHeader = new HeaderParameter("OpenTherm flags"); wm.addParameter(wmOtFlagsHeader); wmOtDhwPresent = new CheckboxParameter("ot_dhw_present", "DHW present", settings.opentherm.dhwPresent); wm.addParameter(wmOtDhwPresent); wmOtSummerWinterMode = new CheckboxParameter("ot_summer_winter_mode", "Summer/winter mode", settings.opentherm.summerWinterMode); wm.addParameter(wmOtSummerWinterMode); wmOtHeatingCh2Enabled = new CheckboxParameter("ot_heating_ch2_enabled", "CH2 enabled", settings.opentherm.heatingCh2Enabled); wm.addParameter(wmOtHeatingCh2Enabled); wmOtHeatingCh1ToCh2 = new CheckboxParameter("ot_heating_ch1_to_ch2", "Heating CH1 to CH2", settings.opentherm.heatingCh1ToCh2); wm.addParameter(wmOtHeatingCh1ToCh2); wmOtDhwToCh2 = new CheckboxParameter("ot_dhw_to_ch2", "DHW to CH2", settings.opentherm.dhwToCh2); wm.addParameter(wmOtDhwToCh2); wmOtDhwBlocking = new CheckboxParameter("ot_dhw_blocking", "DHW blocking", settings.opentherm.dhwBlocking); wm.addParameter(wmOtDhwBlocking); wmOtModSyncWithHeating = new CheckboxParameter("ot_mod_sync_with_heating", "Modulation sync with heating", settings.opentherm.modulationSyncWithHeating); wm.addParameter(wmOtModSyncWithHeating); wmSensorsHeader = new HeaderParameter("Sensors"); wm.addParameter(wmSensorsHeader); wmOutdoorSensorPin = new UnsignedIntParameter("outdoor_sensor_pin", "Outdoor sensor GPIO", settings.sensors.outdoor.pin, 2); wm.addParameter(wmOutdoorSensorPin); wmIndoorSensorPin = new UnsignedIntParameter("indoor_sensor_pin", "Indoor sensor GPIO", settings.sensors.indoor.pin, 2); wm.addParameter(wmIndoorSensorPin); #if USE_BLE wmOutdoorSensorBleAddress = new WiFiManagerParameter("ble_address", "BLE sensor address", settings.sensors.indoor.bleAddresss, 17); wm.addParameter(wmOutdoorSensorBleAddress); #endif wmExtPumpHeader = new HeaderParameter("External pump"); wm.addParameter(wmExtPumpHeader); wmExtPumpUse = new CheckboxParameter("ext_pump_use", "Use external pump
", settings.externalPump.use); wm.addParameter(wmExtPumpUse); wmExtPumpPin = new UnsignedIntParameter("ext_pump_pin", "Relay GPIO", settings.externalPump.pin, 2); wm.addParameter(wmExtPumpPin); wmExtPumpPostCirculationTime = new UnsignedShortParameter("ext_pump_ps_time", "Post circulation time (min)", (settings.externalPump.postCirculationTime / 60), 5); wm.addParameter(wmExtPumpPostCirculationTime); wmExtPumpAntiStuckInterval = new UnsignedIntParameter("ext_pump_as_interval", "Anti stuck interval (days)", (settings.externalPump.antiStuckInterval / 86400), 7); wm.addParameter(wmExtPumpAntiStuckInterval); wmExtPumpAntiStuckTime = new UnsignedShortParameter("ext_pump_as_time", "Anti stuck time (min)", (settings.externalPump.antiStuckTime / 60), 5); wm.addParameter(wmExtPumpAntiStuckTime); } WifiManagerTask* addTaskForDisable(AbstractTask* task) { this->tasksForDisable.push_back(task); return this; } protected: bool connected = false; unsigned long lastArpGratuitous = 0; unsigned long lastReconnecting = 0; std::vector tasksForDisable; const char* getTaskName() { return "WifiManager"; } /*int getTaskCore() { return 1; }*/ int getTaskPriority() { return 0; } void setup() { #ifdef WOKWI WiFi.begin("Wokwi-GUEST", "", 6); #endif wm.setDebugOutput(settings.debug, (wm_debuglevel_t) WM_DEBUG_MODE); wm.setTitle(PROJECT_NAME); wm.setCustomHeadElement(PSTR( "" )); wm.setCustomMenuHTML(PSTR( "" "
" "
" PROJECT_NAME "
" "
Repo | Issues | Releases | v" PROJECT_VERSION " (" __DATE__ ")
" "
" )); std::vector menu = {"custom", "wifi", "param", "sep", "info", "update", "restart"}; wm.setMenu(menu); //wm.setCleanConnect(true); wm.setRestorePersistent(false); wm.setHostname(settings.hostname); wm.setWiFiAutoReconnect(false); wm.setAPClientCheck(true); wm.setConfigPortalBlocking(false); wm.setSaveParamsCallback(saveParamsCallback); wm.setPreOtaUpdateCallback([this] { for (AbstractTask* task : this->tasksForDisable) { if (task->isEnabled()) { task->disable(); } } }); wm.setConfigPortalTimeout(wm.getWiFiIsSaved() ? 180 : 0); wm.setDisableConfigPortal(false); wm.autoConnect(AP_SSID, AP_PASSWORD); } void loop() { if (connected && WiFi.status() != WL_CONNECTED) { connected = false; if (wm.getWebPortalActive()) { wm.stopWebPortal(); #ifdef ARDUINO_ARCH_ESP8266 ::yield(); #endif } /*wm.setCaptivePortalEnable(true); if (!wm.getConfigPortalActive()) { wm.startConfigPortal(AP_SSID, AP_PASSWORD); }*/ #if USE_TELNET TelnetStream.stop(); #ifdef ARDUINO_ARCH_ESP8266 ::yield(); #endif #endif Log.sinfoln(FPSTR(S_WIFI), F("Disconnected")); } if (WiFi.status() != WL_CONNECTED && !wm.getConfigPortalActive()) { if (millis() - this->lastReconnecting > 5000) { Log.sinfoln(FPSTR(S_WIFI), F("Reconnecting...")); WiFi.reconnect(); this->lastReconnecting = millis(); } } if (!connected && WiFi.status() == WL_CONNECTED) { connected = true; wm.setConfigPortalTimeout(180); if (wm.getConfigPortalActive()) { wm.stopConfigPortal(); #ifdef ARDUINO_ARCH_ESP8266 ::yield(); #endif } wm.setCaptivePortalEnable(false); if (!wm.getWebPortalActive()) { wm.startWebPortal(); #ifdef ARDUINO_ARCH_ESP8266 ::yield(); #endif } #if USE_TELNET TelnetStream.begin(23, false); #ifdef ARDUINO_ARCH_ESP8266 ::yield(); #endif #endif Log.sinfoln(FPSTR(S_WIFI), F("Connected. IP: %s, RSSI: %hhd"), WiFi.localIP().toString().c_str(), WiFi.RSSI()); } #ifdef ARDUINO_ARCH_ESP8266 if (connected && millis() - lastArpGratuitous > 60000) { stationKeepAliveNow(); lastArpGratuitous = millis(); ::yield(); } #endif wm.process(); } static void saveParamsCallback() { bool changed = false; bool needRestart = false; if (strcmp(wmHostname->getValue(), settings.hostname) != 0) { changed = true; needRestart = true; strcpy(settings.hostname, wmHostname->getValue()); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New hostname: %s"), settings.hostname); } if (strcmp(wmMqttServer->getValue(), settings.mqtt.server) != 0) { changed = true; strcpy(settings.mqtt.server, wmMqttServer->getValue()); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New mqtt.server: %s"), settings.mqtt.server); } if (wmMqttPort->getValue() != settings.mqtt.port) { changed = true; settings.mqtt.port = wmMqttPort->getValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New mqtt.port: %hu"), settings.mqtt.port); } if (strcmp(wmMqttUser->getValue(), settings.mqtt.user) != 0) { changed = true; strcpy(settings.mqtt.user, wmMqttUser->getValue()); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New mqtt.user: %s"), settings.mqtt.user); } if (strcmp(wmMqttPassword->getValue(), settings.mqtt.password) != 0) { changed = true; strcpy(settings.mqtt.password, wmMqttPassword->getValue()); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New mqtt.password: %s"), settings.mqtt.password); } if (strcmp(wmMqttPrefix->getValue(), settings.mqtt.prefix) != 0) { changed = true; strcpy(settings.mqtt.prefix, wmMqttPrefix->getValue()); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New mqtt.prefix: %s"), settings.mqtt.prefix); } if (wmMqttPublishInterval->getValue() != settings.mqtt.interval) { changed = true; settings.mqtt.interval = wmMqttPublishInterval->getValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New mqtt.interval: %du"), settings.mqtt.interval); } if (wmOtInPin->getValue() != settings.opentherm.inPin) { changed = true; needRestart = true; settings.opentherm.inPin = wmOtInPin->getValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.inPin: %hhu"), settings.opentherm.inPin); } if (wmOtOutPin->getValue() != settings.opentherm.outPin) { changed = true; needRestart = true; settings.opentherm.outPin = wmOtOutPin->getValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.outPin: %hhu"), settings.opentherm.outPin); } if (wmOtMemberIdCode->getValue() != settings.opentherm.memberIdCode) { changed = true; settings.opentherm.memberIdCode = wmOtMemberIdCode->getValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.memberIdCode: %du"), settings.opentherm.memberIdCode); } if (wmOtDhwPresent->getCheckboxValue() != settings.opentherm.dhwPresent) { changed = true; settings.opentherm.dhwPresent = wmOtDhwPresent->getCheckboxValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.dhwPresent: %s"), settings.opentherm.dhwPresent ? "on" : "off"); } if (wmOtSummerWinterMode->getCheckboxValue() != settings.opentherm.summerWinterMode) { changed = true; settings.opentherm.summerWinterMode = wmOtSummerWinterMode->getCheckboxValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.summerWinterMode: %s"), settings.opentherm.summerWinterMode ? "on" : "off"); } if (wmOtHeatingCh2Enabled->getCheckboxValue() != settings.opentherm.heatingCh2Enabled) { changed = true; settings.opentherm.heatingCh2Enabled = wmOtHeatingCh2Enabled->getCheckboxValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.heatingCh2Enabled: %s"), settings.opentherm.heatingCh2Enabled ? "on" : "off"); if (settings.opentherm.heatingCh1ToCh2) { settings.opentherm.heatingCh1ToCh2 = false; wmOtHeatingCh1ToCh2->setValue(false); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.heatingCh1ToCh2: %s"), settings.opentherm.heatingCh1ToCh2 ? "on" : "off"); } if (settings.opentherm.dhwToCh2) { settings.opentherm.dhwToCh2 = false; wmOtDhwToCh2->setValue(false); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.dhwToCh2: %s"), settings.opentherm.dhwToCh2 ? "on" : "off"); } } if (wmOtHeatingCh1ToCh2->getCheckboxValue() != settings.opentherm.heatingCh1ToCh2) { changed = true; settings.opentherm.heatingCh1ToCh2 = wmOtHeatingCh1ToCh2->getCheckboxValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.heatingCh1ToCh2: %s"), settings.opentherm.heatingCh1ToCh2 ? "on" : "off"); if (settings.opentherm.heatingCh2Enabled) { settings.opentherm.heatingCh2Enabled = false; wmOtHeatingCh2Enabled->setValue(false); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.heatingCh2Enabled: %s"), settings.opentherm.heatingCh2Enabled ? "on" : "off"); } if (settings.opentherm.dhwToCh2) { settings.opentherm.dhwToCh2 = false; wmOtDhwToCh2->setValue(false); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.dhwToCh2: %s"), settings.opentherm.dhwToCh2 ? "on" : "off"); } } if (wmOtDhwToCh2->getCheckboxValue() != settings.opentherm.dhwToCh2) { changed = true; settings.opentherm.dhwToCh2 = wmOtDhwToCh2->getCheckboxValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.dhwToCh2: %s"), settings.opentherm.dhwToCh2 ? "on" : "off"); if (settings.opentherm.heatingCh2Enabled) { settings.opentherm.heatingCh2Enabled = false; wmOtHeatingCh2Enabled->setValue(false); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.heatingCh2Enabled: %s"), settings.opentherm.heatingCh2Enabled ? "on" : "off"); } if (settings.opentherm.heatingCh1ToCh2) { settings.opentherm.heatingCh1ToCh2 = false; wmOtHeatingCh1ToCh2->setValue(false); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.heatingCh1ToCh2: %s"), settings.opentherm.heatingCh1ToCh2 ? "on" : "off"); } } if (wmOtDhwBlocking->getCheckboxValue() != settings.opentherm.dhwBlocking) { changed = true; settings.opentherm.dhwBlocking = wmOtDhwBlocking->getCheckboxValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.dhwBlocking: %s"), settings.opentherm.dhwBlocking ? "on" : "off"); } if (wmOtModSyncWithHeating->getCheckboxValue() != settings.opentherm.modulationSyncWithHeating) { changed = true; settings.opentherm.modulationSyncWithHeating = wmOtModSyncWithHeating->getCheckboxValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New opentherm.modulationSyncWithHeating: %s"), settings.opentherm.modulationSyncWithHeating ? "on" : "off"); } if (wmOutdoorSensorPin->getValue() != settings.sensors.outdoor.pin) { changed = true; needRestart = true; settings.sensors.outdoor.pin = wmOutdoorSensorPin->getValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New sensors.outdoor.pin: %hhu"), settings.sensors.outdoor.pin); } if (wmIndoorSensorPin->getValue() != settings.sensors.indoor.pin) { changed = true; needRestart = true; settings.sensors.indoor.pin = wmIndoorSensorPin->getValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New sensors.indoor.pin: %hhu"), settings.sensors.indoor.pin); } #if USE_BLE if (strcmp(wmOutdoorSensorBleAddress->getValue(), settings.sensors.indoor.bleAddresss) != 0) { changed = true; strcpy(settings.sensors.indoor.bleAddresss, wmOutdoorSensorBleAddress->getValue()); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New sensors.indoor.bleAddresss: %s"), settings.sensors.indoor.bleAddresss); } #endif if (wmExtPumpUse->getCheckboxValue() != settings.externalPump.use) { changed = true; settings.externalPump.use = wmExtPumpUse->getCheckboxValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New externalPump.use: %s"), settings.externalPump.use ? "on" : "off"); } if (wmExtPumpPin->getValue() != settings.externalPump.pin) { changed = true; needRestart = true; settings.externalPump.pin = wmExtPumpPin->getValue(); Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New externalPump.pin: %hhu"), settings.externalPump.pin); } if ((wmExtPumpPostCirculationTime->getValue() * 60) != settings.externalPump.postCirculationTime) { changed = true; settings.externalPump.postCirculationTime = wmExtPumpPostCirculationTime->getValue() * 60; Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New externalPump.postCirculationTime: %hu"), settings.externalPump.postCirculationTime); } if ((wmExtPumpAntiStuckInterval->getValue() * 86400) != settings.externalPump.antiStuckInterval) { changed = true; settings.externalPump.antiStuckInterval = wmExtPumpAntiStuckInterval->getValue() * 86400; Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New externalPump.antiStuckInterval: %du"), settings.externalPump.antiStuckInterval); } if ((wmExtPumpAntiStuckTime->getValue() * 60) != settings.externalPump.antiStuckTime) { changed = true; settings.externalPump.antiStuckTime = wmExtPumpAntiStuckTime->getValue() * 60; Log.sinfoln(FPSTR(S_WIFI_SETTINGS), F("New externalPump.antiStuckTime: %hu"), settings.externalPump.antiStuckTime); } if (!changed) { return; } else if (needRestart) { vars.actions.restart = true; } eeSettings.update(); } #ifdef ARDUINO_ARCH_ESP8266 /** * @brief * https://github.com/arendst/Tasmota/blob/e6515883f0ee5451931b6280ff847b117de5a231/tasmota/tasmota_support/support_wifi.ino#L1196 */ static void stationKeepAliveNow(void) { for (netif* interface = netif_list; interface != nullptr; interface = interface->next) { if ( (interface->flags & NETIF_FLAG_LINK_UP) && (interface->flags & NETIF_FLAG_UP) && interface->num == STATION_IF && (!ip4_addr_isany_val(*netif_ip4_addr(interface))) ) { etharp_gratuitous(interface); break; } } } #endif };