#include #include #include #include #include #include #include #ifndef CONFIG_TARGET_ESP01 #include #endif #include #include "mqtt.h" #include "leds.h" #include "temphum.h" using namespace homekit; #ifndef CONFIG_TARGET_ESP01 enum class WorkingMode { RECOVERY, // AP mode, http server with configuration NORMAL, // MQTT client }; static enum WorkingMode working_mode = WorkingMode::NORMAL; static const uint16_t recovery_boot_detection_ms = 2000; static const uint8_t recovery_boot_delay_ms = 100; #endif enum class WiFiConnectionState { WAITING = 0, JUST_CONNECTED = 1, CONNECTED = 2 }; static volatile enum WiFiConnectionState wifi_state = WiFiConnectionState::WAITING; static void* service = nullptr; static WiFiEventHandler wifiConnectHandler, wifiDisconnectHandler; static Ticker wifiTimer; #if MQTT_BLINK static StopWatch blinkStopWatch; #endif #ifndef CONFIG_TARGET_ESP01 static DNSServer* dnsServer = nullptr; #endif static void onWifiConnected(const WiFiEventStationModeGotIP& event); static void onWifiDisconnected(const WiFiEventStationModeDisconnected& event); static void wifiConnect() { const char *ssid, *psk, *hostname; auto cfg = config::read(); wifi::getConfig(cfg, &ssid, &psk, &hostname); PRINTF("Wi-Fi STA creds: ssid=%s, psk=%s, hostname=%s\n", ssid, psk, hostname); wifi_state = WiFiConnectionState::WAITING; WiFi.mode(WIFI_STA); WiFi.hostname(hostname); WiFi.begin(ssid, psk); PRINT("connecting to wifi.."); } #ifndef CONFIG_TARGET_ESP01 static void wifiHotspot() { mcu_led->on(); auto scanResults = wifi::scan(); WiFi.mode(WIFI_AP); WiFi.softAP(wifi::AP_SSID); dnsServer = new DNSServer(); dnsServer->start(53, "*", WiFi.softAPIP()); service = new HttpServer(scanResults); ((HttpServer*)service)->start(); } static void waitForRecoveryPress() { pinMode(CONFIG_FLASH_GPIO, INPUT_PULLUP); for (uint16_t i = 0; i < recovery_boot_detection_ms; i += recovery_boot_delay_ms) { delay(recovery_boot_delay_ms); if (digitalRead(CONFIG_FLASH_GPIO) == LOW) { working_mode = WorkingMode::RECOVERY; break; } } } #endif void setup() { WiFi.disconnect(); #ifndef CONFIG_TARGET_ESP01 waitForRecoveryPress(); #endif #ifdef DEBUG Serial.begin(115200); #endif temphum::setup(); auto cfg = config::read(); if (config::isDirty(cfg)) { PRINTLN("config is dirty, erasing..."); config::erase(cfg); #ifdef CONFIG_TARGET_NODEMCU board_led->blink(10, 50); #else mcu_led->blink(10, 50); #endif } #ifndef CONFIG_TARGET_ESP01 switch (working_mode) { case WorkingMode::RECOVERY: wifiHotspot(); break; case WorkingMode::NORMAL: #endif wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnected); wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnected); wifiConnect(); #ifndef CONFIG_TARGET_ESP01 break; } #endif } void loop() { #ifndef CONFIG_TARGET_ESP01 if (working_mode == WorkingMode::NORMAL) { #endif if (wifi_state == WiFiConnectionState::WAITING) { PRINT("."); mcu_led->blink(2, 50); delay(1000); return; } if (wifi_state == WiFiConnectionState::JUST_CONNECTED) { #ifdef CONFIG_TARGET_NODEMCU board_led->blink(3, 300); #endif wifi_state = WiFiConnectionState::CONNECTED; if (service == nullptr) service = new mqtt::MQTT(); ((mqtt::MQTT*)service)->connect(); #if MQTT_BLINK blinkStopWatch.save(); #endif } auto mqtt = (mqtt::MQTT*)service; if (static_cast(wifi_state) >= 1 && mqtt != nullptr) { mqtt->loop(); if (mqtt->ota.readyToRestart) { mqtt->disconnect(); } else if (mqtt->diagnosticsStopWatch.elapsed(10000)) { mqtt->sendDiagnostics(); auto data = temphum::read(); PRINT("temp:"); PRINT(data.temp); PRINT(", rh: "); PRINTLN(data.rh); mqtt->sendTempHumData(data.temp, data.rh); } #if MQTT_BLINK // periodically blink board led if (blinkStopWatch.elapsed(5000)) { #ifdef CONFIG_TARGET_NODEMCU board_led->blink(1, 10); #endif blinkStopWatch.save(); } #endif } #ifndef CONFIG_TARGET_ESP01 } else { if (dnsServer != nullptr) dnsServer->processNextRequest(); auto httpServer = (HttpServer*)service; if (httpServer != nullptr) httpServer->loop(); } #endif } static void onWifiConnected(const WiFiEventStationModeGotIP& event) { PRINTF("connected (%s)\n", WiFi.localIP().toString().c_str()); wifi_state = WiFiConnectionState::JUST_CONNECTED; } static void onWifiDisconnected(const WiFiEventStationModeDisconnected& event) { PRINTLN("disconnected from wi-fi"); wifi_state = WiFiConnectionState::WAITING; if (service != nullptr) ((mqtt::MQTT*)service)->disconnect(); wifiTimer.once(2, wifiConnect); }