From f9a5c6961a667bbfd5fc5edc2b3bf2fb9f924bb3 Mon Sep 17 00:00:00 2001 From: Florian Date: Fri, 23 Aug 2024 16:55:04 -0500 Subject: [PATCH] [SYS][BREAKING] Add gateway states, Offline mode and refactor sleep (#2020) Gaterway states to improve LED management Make the sleep function accessible outside BT BREAKING remove sleep for ESP8266 BREAKING lowpowermode API changed to powermode and new mode definition Co-authored-by: Florian <1technophile@users.noreply.github.com> --- .gitignore | 3 +- docs/use/boards.md | 64 +---- docs/use/gateway.md | 4 + environments.ini | 14 +- main/User_config.h | 63 +++-- main/Zblufi.ino | 3 + main/ZboardM5.ino | 36 +-- main/ZgatewayBT.ino | 97 ++----- main/ZmqttDiscovery.ino | 12 +- main/ZsensorC37_YL83_HMRD.ino | 9 +- main/ZsensorDS1820.ino | 6 +- main/config_BT.h | 1 - main/config_M5.h | 2 +- main/config_SSD1306.h | 2 +- main/main.ino | 492 ++++++++++++++++++---------------- prod_env.ini.example | 2 +- 16 files changed, 367 insertions(+), 443 deletions(-) diff --git a/.gitignore b/.gitignore index d734bc3..d460f6a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ CMakeLists.txt dependencies.lock sdkconfig.* !sdkconfig.defaults -__pycache__ \ No newline at end of file +__pycache__ +*.pem \ No newline at end of file diff --git a/docs/use/boards.md b/docs/use/boards.md index 9f226dd..8563786 100644 --- a/docs/use/boards.md +++ b/docs/use/boards.md @@ -21,33 +21,33 @@ This can be achieved with the following macro, `WifiGMode` defined true and `Wif Since the WiFi protocol is persisted in the flash of the ESP you have to run at least once with `WiFiGMode` defined **false** to get Band N back. ### Low power mode for ESP32 -OpenMQTTGateway support a low power mode for ESP32, this mode is available per default on boards with batteries. The other boards needs to have the macro `DEFAULT_LOW_POWER_MODE` defined at 0, 1 or 2 to use it. More information about the modes is available into User_config.h. +OpenMQTTGateway support a low power mode for ESP32, the boards needs to have the macro `DEFAULT_LOW_POWER_MODE` defined at `ALWAYS_ON`, `INTERVAL` or `ACTION` to use it. More information about the modes is available into User_config.h. When available this mode can be set by MQTT: * Normal mode (per default) -`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoBT/config" -m '{"lowpowermode":0}'` +`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"powermode":0, "save":true}'` -* Low Power mode +* Low Power mode wake up from interval defined by DEEP_SLEEP_IN_US and pins defined by ESP32_EXT0_WAKE_PIN and/or ESP32_EXT1_WAKE_PIN -`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoBT/config" -m '{"lowpowermode":2}'` +`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"powermode":1, "save":true}'` -The interval between the ESP32 wake up is defined at build time by the macro `TimeBtwRead`, a change of the `interval` through MQTT will not impact the time between wake up. +* Low Power mode wake up from pins defined by ESP32_EXT0_WAKE_PIN and/or ESP32_EXT1_WAKE_PIN + +`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"powermode":2, "save":true}'` ::: tip -When coming back from mode 2 to mode 0 you may publish the command with a retain flag so as to enable the gateway to retrieve it when reconnecting. A low power mode switch is automatically created by discovery with Home Assistant, you may experience a delay between the command and the state update due to the fact that the update will be received and acknowledged when the device woke up. -In low power mode you should use ESPWifiManualSetup so as to rely on the credentials entered into User_config.h. -So as to do that uncomment the line below in User_config.h -``` c -//# define ESPWifiManualSetup true -``` -For platformio and example of environment is available into [prod_env.ini.example](https://github.com/1technophile/OpenMQTTGateway/blob/development/prod_env.ini.example) +If you are publishing the state change while the device is asleep use the retain flag. This way the device will retrieve the powermode command at wake up. ::: +The default sleep time is defined by the macro `DEEP_SLEEP_IN_US` (default 60s) + +We can also use an external sensor state to wake-up the ESP, this is defined by macro `ESP32_EXT0_WAKE_PIN/ESP32_EXT1_WAKE_PIN`, the level is defined by the macro `ESP32_EXT0_WAKE_PIN_STATE/ESP32_EXT0_WAKE_PIN_STATE` (default to HIGH). + ::: warning -If you change the default low power mode in config_BT.h to 2 and your credential are not set or not correct, the ESP32 will not connect to the broker and the only way to change the low power mode will be a new erase/upload. +If you change the default low power mode to INTERVAL or ACTION and your credential are not set or not correct, the ESP32 will not connect to the broker and the only way to change the low power mode will be a new erase/upload. ::: ## M5StickC, M5StickC Plus or M5Stack @@ -73,41 +73,3 @@ You can also change it by MQTT. For example if you want to set to LCD you can also revert it to the serial monitor: `mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoM5/config -m '{"log-display":false}'` - -### Low power mode for M5 boards -OpenMQTTGateway support a low power mode for ESP32, this mode can be set by MQTT or a button on M5 boards: - -* Normal mode (per default), screen ON - -`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoBT/config" -m '{"lowpowermode":0}'` - -* Low Power mode, screen ON when processing only - -`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoBT/config" -m '{"lowpowermode":1}'` - -* Low Power mode, screen OFF, LED ON when processing on M5StickC or M5stickC Plus - -`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoBT/config" -m '{"lowpowermode":2}'` - -The low power mode can be changed also with a push to button B when the board is processing (top button on M5stickC, M5stickC Plus and middle button of M5stack). -If you are already in low power mode 1 or 2 with M5Stack you can wake up the board by pressing the red button. - -### Low power mode (deepSleep) for ESP8266 & ESP32 boards -In certain use cases where power is severely limited you can use the ESP8266 or ESP32 deep sleep capability. - -* e.g. measuring a pool temperature every 5 minutes using an ESP8266 and DS18B20 probe where the ESP8266 is powered by very limited battery backed solar power. -* e.g. as a water/leak detector which wake-up based on sensor state an ESP32 and C-37 YL-83 HM-RD sensor where the ESP32 is powered by very limited battery power. - -During deep sleep everything is off and (almost) all execution state is lost. - -Consumption is about 20 µA on an ESP8266. - -Use this when you want the device to sleep for minutes, hours woken by external sensor state. - -You only have to define the macro `DEEP_SLEEP_IN_US` with the number of microseconds, this works for both ESP8266 and ESP32. - -For an ESP8266 a hardware jumper is required connecting RST to a GPIO (not to CH_PD) defined by the macro `ESP8266_DEEP_SLEEP_WAKE_PIN` and defaulted to D0. - -On an ESP32 we can also use an external sensor state to wake-up the ESP and this is defined by macro `ESP32_EXT0_WAKE_PIN` and which state it must toggle to by macro `ESP32_EXT0_WAKE_PIN_STATE` defaulted to 1 (high). - -And the sensor code must set variable `ready_to_sleep` to true after publishing the measurement to MQTT and the main loop will then enter deep sleep. diff --git a/docs/use/gateway.md b/docs/use/gateway.md index bdf1db8..4d0238c 100644 --- a/docs/use/gateway.md +++ b/docs/use/gateway.md @@ -47,6 +47,10 @@ If you want the settings to be kept upon gateway restart, you can save the state This command can also be used with other controllers that does not support the is_defined key. ::: +## Activate Offline mode + +`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"offline":true,"save":true}'` + ## Change the WiFi credentials `mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"wifi_ssid":"ssid", "wifi_pass":"password"}'` diff --git a/environments.ini b/environments.ini index a2d4c47..51a27bc 100644 --- a/environments.ini +++ b/environments.ini @@ -387,7 +387,7 @@ build_flags = '-DZgatewayBT="BT"' '-DLED_SEND_RECEIVE=2' '-DLED_SEND_RECEIVE_ON=0' - '-DARDUINO_LOOP_STACK_SIZE=15000' + '-DARDUINO_LOOP_STACK_SIZE=17500' '-DMQTT_SECURE_DEFAULT=true' '-DMQTT_CERT_VALIDATE_DEFAULT=true' '-DMQTT_SECURE_SIGNED_CLIENT=true' @@ -432,7 +432,7 @@ build_flags = '-DLED_SEND_RECEIVE_ON=0' '-DGateway_Name="OMG_LOLIN32LITE_BLE"' ;; Low power parameters, uncomment and fill credentials - '-DDEFAULT_LOW_POWER_MODE=2' + '-DDEFAULT_LOW_POWER_MODE=INTERVAL' ; '-DTimeBtwRead=155000' ; '-DScan_duration=2000' ; '-DAttemptBLEConnect=false' @@ -557,7 +557,7 @@ build_flags = '-DLED_SEND_RECEIVE_ON=1' '-DTRIGGER_GPIO=35' '-DIR_EMITTER_GPIO=17' - '-DDEFAULT_LOW_POWER_MODE=0' + '-DDEFAULT_LOW_POWER_MODE=ALWAYS_ON' '-DGateway_Name="OMG_ESP32_M5STICK_BLE_IR"' board_upload.speed = 921600 custom_description = Expandable module with BLE gateway, display, and little IR emitter @@ -582,7 +582,7 @@ build_flags = '-DTRIGGER_GPIO=37' '-DSLEEP_BUTTON=38' '-DINPUT_GPIO=39' - '-DDEFAULT_LOW_POWER_MODE=0' + '-DDEFAULT_LOW_POWER_MODE=ALWAYS_ON' '-DGateway_Name="OMG_ESP32_M5STACK_BLE"' board_upload.speed = 921600 custom_description = Expandable module with BLE gateway and display @@ -632,7 +632,7 @@ build_flags = '-DTRIGGER_GPIO=39' '-DIR_EMITTER_INVERTED=true' '-DIR_EMITTER_GPIO=9' - '-DDEFAULT_LOW_POWER_MODE=0' + '-DDEFAULT_LOW_POWER_MODE=ALWAYS_ON' '-DGateway_Name="OMG_ESP32_M5STICK_C_BLE_IR"' board_upload.speed = 1500000 custom_description = Expandable module with BLE gateway, display, and little IR emitter @@ -663,7 +663,7 @@ build_flags = '-DTRIGGER_GPIO=39' '-DIR_EMITTER_INVERTED=true' '-DIR_EMITTER_GPIO=9' - '-DDEFAULT_LOW_POWER_MODE=0' + '-DDEFAULT_LOW_POWER_MODE=ALWAYS_ON' '-DGateway_Name="OMG_ESP32_M5STICK_CP_BLE_IR"' board_upload.speed = 1500000 custom_description = Expandable module with BLE gateway, display, and little IR emitter @@ -1797,5 +1797,5 @@ build_flags = '-DLED_SEND_RECEIVE_ON=0' '-DGateway_Name="OMG_ESP32_BLE"' '-DUSE_BLUFI=1' - '-DARDUINO_LOOP_STACK_SIZE=16000' + '-DARDUINO_LOOP_STACK_SIZE=17500' custom_description = Regular BLE gateway based on esp-idf with adaptive scanning activated, automatically adapts the scan parameters depending on your devices diff --git a/main/User_config.h b/main/User_config.h index dfb4bbc..1ef5cb5 100644 --- a/main/User_config.h +++ b/main/User_config.h @@ -163,7 +163,7 @@ #endif #ifndef mqtt_max_payload_size -# define mqtt_max_payload_size JSON_MSG_BUFFER_MAX // maximum size of the MQTT payload +# define mqtt_max_payload_size JSON_MSG_BUFFER_MAX + mqtt_topic_max_size + 10 // maximum size of the MQTT payload #endif #ifndef MQTT_USER @@ -301,16 +301,6 @@ ss_cnt_parameters cnt_parameters_array[cnt_parameters_array_size] = { #define MIN_CERT_LENGTH 200 // Minimum length of a certificate to be considered valid -/** - * Deep-sleep for the ESP8266. - * Set the wake pin. - */ -#if defined(DEEP_SLEEP_IN_US) && defined(ESP8266) -# ifndef ESP8266_DEEP_SLEEP_WAKE_PIN -# define ESP8266_DEEP_SLEEP_WAKE_PIN D0 -# endif -#endif - /** * Ext wake for Deep-sleep for the ESP32. * Set the wake pin state. @@ -321,16 +311,23 @@ ss_cnt_parameters cnt_parameters_array[cnt_parameters_array_size] = { # endif #endif -/*------------------DEEP SLEEP parameters ------------------*/ -//DEFAULT_LOW_POWER_MODE -1 to normal mode, low power mode can't be used on this build -//DEFAULT_LOW_POWER_MODE 0 to normal mode (no power consumption optimisations) -//DEFAULT_LOW_POWER_MODE 1 to activate deep sleep -//DEFAULT_LOW_POWER_MODE 2 to activate deep sleep (LCD is turned OFF) -#ifdef ESP32 -# ifndef DEFAULT_LOW_POWER_MODE -# define DEFAULT_LOW_POWER_MODE -1 +#ifdef ESP32_EXT1_WAKE_PIN +# ifndef ESP32_EXT1_WAKE_PIN_STATE +# define ESP32_EXT1_WAKE_PIN_STATE 1 # endif -int lowpowermode = DEFAULT_LOW_POWER_MODE; +#endif + +#ifndef DEEP_SLEEP_IN_US +# define DEEP_SLEEP_IN_US 60000000 // 1 minute +#endif + +/*------------------DEEP SLEEP parameters ------------------*/ +//DEFAULT_LOW_POWER_MODE DEACTIVATED low power mode can't be used on this build to prevent bricking devices that does not support low power mode +//DEFAULT_LOW_POWER_MODE ALWAYS_ON normal mode (no power consumption optimisations) +//DEFAULT_LOW_POWER_MODE INTERVAL to activate deep sleep with intervals and action wake up +//DEFAULT_LOW_POWER_MODE ACTION to activate deep sleep with action wake up +#ifndef DEFAULT_LOW_POWER_MODE +# define DEFAULT_LOW_POWER_MODE DEACTIVATED #endif /*-------------DEFINE THE MODULES YOU WANT BELOW----------------*/ @@ -715,9 +712,15 @@ Adafruit_NeoPixel leds3(ANEOPIX_IND_NUM_LEDS, ANEOPIX_IND_DATA_GPIO3, ANEOPIX_IN #endif /*--------------MQTT general topics-----------------*/ // global MQTT subject listened by the gateway to execute commands (send RF, IR or others) -#define subjectMQTTtoX "/commands/#" -#define subjectMultiGTWKey "toMQTT" -#define subjectGTWSendKey "MQTTto" +#ifndef subjectMQTTtoX +# define subjectMQTTtoX "/commands/#" +#endif +#ifndef subjectMultiGTWKey +# define subjectMultiGTWKey "toMQTT" +#endif +#ifndef subjectGTWSendKey +# define subjectGTWSendKey "MQTTto" +#endif // key used for launching commands to the gateway #define restartCmd "restart" @@ -735,7 +738,9 @@ Adafruit_NeoPixel leds3(ANEOPIX_IND_NUM_LEDS, ANEOPIX_IND_DATA_GPIO3, ANEOPIX_IN # endif #endif -#define TimeBetweenReadingSYS 120 // time between (s) system readings (like memory) +#ifndef TimeBetweenReadingSYS +# define TimeBetweenReadingSYS 120 // time between (s) system readings (like memory) +#endif #define TimeBetweenCheckingSYS 3600 // time between (s) system checkings (like updates) #define TimeLedON 1 // time LED are ON #define InitialMQTTConnectionTimeout 10 // time estimated (s) before the board is connected to MQTT @@ -807,6 +812,11 @@ unsigned long lastDiscovery = 0; // Time of the last discovery to trigger automa #define isBlack(device) device->isBlkL #define isDiscovered(device) device->isDisc +enum PowerMode { DEACTIVATED = -1, + ALWAYS_ON, + INTERVAL, + ACTION }; + /*--------------------Minimum freeHeap--------------------*/ // Below this parameter we trigger a restart, this avoid stuck boards like seen in https://github.com/1technophile/OpenMQTTGateway/issues/1693 #define MinimumMemory 40000 @@ -814,16 +824,21 @@ unsigned long lastDiscovery = 0; // Time of the last discovery to trigger automa /*----------------CONFIGURABLE PARAMETERS-----------------*/ struct SYSConfig_s { bool XtoMQTT; // if true the gateway will publish the received data on the MQTT broker + bool offline; bool discovery; // HA discovery convention bool ohdiscovery; // OH discovery specificities #ifdef RGB_INDICATORS int rgbbrightness; // brightness of the RGB LED #endif + enum PowerMode powerMode; }; #ifndef DEFAULT_XtoMQTT # define DEFAULT_XtoMQTT true #endif +#ifndef DEFAULT_OFFLINE +# define DEFAULT_OFFLINE false +#endif #if defined(ZgatewayRF) || defined(ZgatewayIR) || defined(ZgatewaySRFB) || defined(ZgatewayWeatherStation) || defined(ZgatewayRTL_433) bool isAduplicateSignal(uint64_t); diff --git a/main/Zblufi.ino b/main/Zblufi.ino index be10e5c..dfa27c0 100644 --- a/main/Zblufi.ino +++ b/main/Zblufi.ino @@ -66,6 +66,7 @@ static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_para break; case ESP_BLUFI_EVENT_BLE_CONNECT: Log.trace(F("BLUFI BLE connect" CR)); + gatewayState = GatewayState::ONBOARDING; omg_blufi_ble_connected = true; esp_blufi_adv_stop(); blufi_security_init(); @@ -75,11 +76,13 @@ static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_para omg_blufi_ble_connected = false; blufi_security_deinit(); if (WiFi.isConnected()) { + gatewayState = GatewayState::NTWK_CONNECTED; esp_blufi_deinit(); # ifndef ESPWifiManualSetup wifiManager.stopConfigPortal(); # endif } else { + gatewayState = GatewayState::WAITING_ONBOARDING; esp_blufi_adv_start(); } break; diff --git a/main/ZboardM5.ino b/main/ZboardM5.ino index 9134b2b..276f717 100644 --- a/main/ZboardM5.ino +++ b/main/ZboardM5.ino @@ -60,28 +60,13 @@ void setupM5() { // M5 stack 320*240 // M5StickC 160*80 // M5Stick LCD not supported - Log.notice(F("Low power set to: %d" CR), lowpowermode); - switch (lowpowermode) // if LOW POWER the intro is bypassed and the brightness set to sleep brightness - { - case 0: - wakeScreen(NORMAL_LCD_BRIGHTNESS); - M5.Lcd.fillScreen(WHITE); - displayIntro(M5.Lcd.width() * 0.25, (M5.Lcd.width() / 2) + M5.Lcd.width() * 0.12, (M5.Lcd.height() / 2) + M5.Lcd.height() * 0.2); + wakeScreen(NORMAL_LCD_BRIGHTNESS); + M5.Lcd.fillScreen(WHITE); + displayIntro(M5.Lcd.width() * 0.25, (M5.Lcd.width() / 2) + M5.Lcd.width() * 0.12, (M5.Lcd.height() / 2) + M5.Lcd.height() * 0.2); # if LOG_TO_LCD - Log.begin(LOG_LEVEL_LCD, &M5.Lcd); // Log on LCD following LOG_LEVEL_LCD + Log.begin(LOG_LEVEL_LCD, &M5.Lcd); // Log on LCD following LOG_LEVEL_LCD # endif - break; - case 1: - wakeScreen(SLEEP_LCD_BRIGHTNESS); - M5.Lcd.fillScreen(WHITE); -# if LOG_TO_LCD - Log.begin(LOG_LEVEL_LCD, &M5.Lcd); // Log on LCD following LOG_LEVEL_LCD -# endif - break; - case 2: - M5.begin(false, false, false); - break; - } + Log.notice(F("Setup M5 end" CR)); } @@ -106,17 +91,9 @@ void wakeScreen(int brightness) { } void loopM5() { - static int previousBtnState; - int currentBtnState = digitalRead(SLEEP_BUTTON); - if (currentBtnState != previousBtnState && currentBtnState == 0) { - int newlowpowermode = lowpowermode; - (lowpowermode == 2) ? newlowpowermode = 0 : newlowpowermode = newlowpowermode + 1; - changelowpowermode(newlowpowermode); - } - previousBtnState = currentBtnState; static int previousLogLevel; int currentLogLevel = Log.getLastMsgLevel(); - if (previousLogLevel != currentLogLevel && lowpowermode != 2) { + if (previousLogLevel != currentLogLevel) { switch (currentLogLevel) { case 1: case 2: @@ -218,7 +195,6 @@ void drawLogo(int logoSize, int circle1X, int circle1Y, bool circle1, bool circl } void M5Print(char* line1, char* line2, char* line3) { - if (lowpowermode == 2) InfoIndicatorON(); wakeScreen(NORMAL_LCD_BRIGHTNESS); M5.Lcd.fillScreen(TFT_WHITE); drawLogo(M5.Lcd.width() * 0.1875, (M5.Lcd.width() / 2) - M5.Lcd.width() * 0.24, M5.Lcd.height() * 0.5, true, true, true, true, true, true); diff --git a/main/ZgatewayBT.ino b/main/ZgatewayBT.ino index 5b01dd8..d1c4414 100644 --- a/main/ZgatewayBT.ino +++ b/main/ZgatewayBT.ino @@ -39,7 +39,6 @@ QueueHandle_t BLEQueue; # include # include # include -# include # include # include @@ -805,32 +804,23 @@ void stopProcessing() { void coreTask(void* pvParameters) { while (true) { if (!BTProcessLock) { - int n = 0; - while (mqtt->connected() && n <= InitialMQTTConnectionTimeout && !BTProcessLock) { - n++; - delay(1000); - } - if (!mqtt->connected()) { - Log.warning(F("MQTT client or Network disconnected no BLE scan" CR)); - } else if (!BTProcessLock) { - if (xSemaphoreTake(semaphoreBLEOperation, pdMS_TO_TICKS(30000)) == pdTRUE) { - BLEscan(); - // Launching a connect every TimeBtwConnect - if (millis() > (timeBetweenConnect + BTConfig.intervalConnect) && BTConfig.bleConnect) { - timeBetweenConnect = millis(); - BLEconnect(); - } - //dumpDevices(); - Log.trace(F("CoreTask stack free: %u" CR), uxTaskGetStackHighWaterMark(xCoreTaskHandle)); - xSemaphoreGive(semaphoreBLEOperation); - } else { - Log.error(F("Failed to start scan - BLE busy" CR)); + if (xSemaphoreTake(semaphoreBLEOperation, pdMS_TO_TICKS(30000)) == pdTRUE) { + BLEscan(); + // Launching a connect every TimeBtwConnect + if (millis() > (timeBetweenConnect + BTConfig.intervalConnect) && BTConfig.bleConnect) { + timeBetweenConnect = millis(); + BLEconnect(); } + //dumpDevices(); + Log.trace(F("CoreTask stack free: %u" CR), uxTaskGetStackHighWaterMark(xCoreTaskHandle)); + xSemaphoreGive(semaphoreBLEOperation); + } else { + Log.error(F("Failed to start scan - BLE busy" CR)); } - if (lowpowermode > 0) { - lowPowerESP32(); + if (SYSConfig.powerMode > 0) { int scan = atomic_exchange_explicit(&forceBTScan, 0, ::memory_order_seq_cst); // is this enough, it will wait the full deepsleep... if (scan == 1) BTforceScan(); + ready_to_sleep = true; } else { for (int interval = BTConfig.BLEinterval, waitms; interval > 0; interval -= waitms) { int scan = atomic_exchange_explicit(&forceBTScan, 0, ::memory_order_seq_cst); @@ -843,64 +833,9 @@ void coreTask(void* pvParameters) { } } -# if DEFAULT_LOW_POWER_MODE != -1 -void lowPowerESP32() { // low power mode - Log.trace(F("Going to deep sleep for: %l s" CR), (TimeBtwRead / 1000)); - deepSleep(TimeBtwRead * 1000); -} - -void deepSleep(uint64_t time_in_us) { -# if defined(ZboardM5STACK) || defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH) - sleepScreen(); - esp_sleep_enable_ext0_wakeup((gpio_num_t)SLEEP_BUTTON, LOW); -# endif - - Log.trace(F("Deactivating ESP32 components" CR)); - stopProcessing(); - ProcessLock = true; - // Ignore the deprecated warning, this call is necessary here. -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" - adc_power_off(); -# pragma GCC diagnostic pop - esp_wifi_stop(); - esp_deep_sleep(time_in_us); -} -# else -void lowPowerESP32() {} -# endif - -void changelowpowermode(int newLowPowerMode) { -# if DEFAULT_LOW_POWER_MODE != -1 - Log.notice(F("Changing LOW POWER mode to: %d" CR), newLowPowerMode); -# if defined(ZboardM5STACK) || defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH) - if (lowpowermode == 2) { -# ifdef ZboardM5STACK - M5.Lcd.wakeup(); -# endif -# if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH) - M5.Axp.SetLDO2(true); - M5.Lcd.begin(); -# endif - } - char lpm[2]; - sprintf(lpm, "%d", newLowPowerMode); - M5Print("Changing LOW POWER mode to:", lpm, ""); -# endif - lowpowermode = newLowPowerMode; - preferences.begin(Gateway_Short_Name, false); - int result = preferences.putUInt("lowpowermode", lowpowermode); - Log.notice(F("BT LPM config save result: %d" CR), result); - preferences.end(); - // Publish the states to update the controller switch status - stateMeasures(); -# endif -} - void setupBTTasksAndBLE() { BLEDevice::setScanDuplicateCacheSize(BLEScanDuplicateCacheSize); BLEDevice::init(""); - xTaskCreatePinnedToCore( procBLETask, /* Function to implement the task */ "procBLETask", /* Name of the task */ @@ -936,7 +871,6 @@ void setupBT() { Log.notice(F("Adaptive BLE scan: %T" CR), BTConfig.adaptiveScan); Log.notice(F("Active BLE scan interval: %d" CR), BTConfig.intervalActiveScan); Log.notice(F("minrssi: %d" CR), -abs(BTConfig.minRssi)); - Log.notice(F("Low Power Mode: %d" CR), lowpowermode); Log.notice(F("Presence Away Timer: %d" CR), BTConfig.presenceAwayTimer); Log.notice(F("Moving Timer: %d" CR), BTConfig.movingTimer); Log.notice(F("Force passive scan: %T" CR), BTConfig.forcePassiveScan); @@ -953,6 +887,8 @@ void setupBT() { BLEQueue = xQueueCreate(QueueSize, sizeof(NimBLEAdvertisedDevice*)); if (BTConfig.enabled) { setupBTTasksAndBLE(); + if (SYSConfig.offline) // We start the BLE scan if we are offline, if not we wait for MQTT connection + BTProcessLock = false; Log.notice(F("ZgatewayBT multicore ESP32 setup done" CR)); } else { Log.notice(F("ZgatewayBT multicore ESP32 setup disabled" CR)); @@ -1541,9 +1477,6 @@ void MQTTtoBT(char* topicOri, JsonObject& BTdata) { // json object decoding // Load config from json if available BTConfig_fromJson(BTdata); - if (BTdata.containsKey("lowpowermode")) { - changelowpowermode((int)BTdata["lowpowermode"]); - } } else if (cmpToMainTopic(topicOri, subjectMQTTtoBT)) { MQTTtoBTAction(BTdata); } diff --git a/main/ZmqttDiscovery.ino b/main/ZmqttDiscovery.ino index d91ff9e..63addc0 100644 --- a/main/ZmqttDiscovery.ino +++ b/main/ZmqttDiscovery.ino @@ -1310,20 +1310,20 @@ void pubMqttDiscovery() { stateClassNone, //State Class "false", "true" //state_off, state_on ); -# if DEFAULT_LOW_POWER_MODE != -1 +# if DEFAULT_LOW_POWER_MODE != DEACTIVATED createDiscovery("switch", //set Type - subjectSYStoMQTT, "SYS: Low Power Mode command", (char*)getUniqueId("lowpowermode", "").c_str(), //set state_topic,name,uniqueId - will_Topic, "", "{{ value_json.lowpowermode | bool }}", //set availability_topic,device_class,value_template, - "{\"lowpowermode\":2}", "{\"lowpowermode\":0}", "", //set,payload_on,payload_off,unit_of_meas, + subjectSYStoMQTT, "SYS: Low Power Mode command", (char*)getUniqueId("powermode", "").c_str(), //set state_topic,name,uniqueId + will_Topic, "", "{{ value_json.powermode | bool }}", //set availability_topic,device_class,value_template, + "{\"powermode\":1,\"save\":true}", "{\"powermode\":0,\"save\":true}", "", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay - Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoBTset, //set,payload_available,payload_not available,is a gateway entity, command topic + Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoSYSset, //set,payload_available,payload_not available,is a gateway entity, command topic "", "", "", "", true, // device name, device manufacturer, device model, device MAC, retain stateClassNone, //State Class "false", "true" //state_off, state_on ); # else // Remove previously created switch for version < 1.4.0 - eraseTopic("switch", (char*)getUniqueId("lowpowermode", "").c_str()); + eraseTopic("switch", (char*)getUniqueId("powermode", "").c_str()); # endif # endif # endif diff --git a/main/ZsensorC37_YL83_HMRD.ino b/main/ZsensorC37_YL83_HMRD.ino index 0e0b637..3e98764 100644 --- a/main/ZsensorC37_YL83_HMRD.ino +++ b/main/ZsensorC37_YL83_HMRD.ino @@ -68,11 +68,10 @@ void MeasureC37_YL83_HMRDWater() { if (C37_YL83_HMRDdata.size() > 0) { C37_YL83_HMRDdata["origin"] = C37_YL83_HMRD_TOPIC; handleJsonEnqueue(C37_YL83_HMRDdata); - delay(10); -# if defined(DEEP_SLEEP_IN_US) || defined(ESP32_EXT0_WAKE_PIN) - if (sensorDigitalValue == 1) //No water detected, all good we can sleep - ready_to_sleep = true; -# endif + if (sensorDigitalValue == 1) { //No water detected, all good we can sleep + if (SYSConfig.powerMode > 0) + ready_to_sleep = true; + } } persistedanalog = sensorAnalogValue; persisteddigital = sensorDigitalValue; diff --git a/main/ZsensorDS1820.ino b/main/ZsensorDS1820.ino index cf5ff0f..0cb8c0a 100644 --- a/main/ZsensorDS1820.ino +++ b/main/ZsensorDS1820.ino @@ -159,10 +159,8 @@ void MeasureDS1820Temp() { String origin = String(OW_TOPIC) + "/" + ds1820_addr[i]; DS1820data["origin"] = origin; handleJsonEnqueue(DS1820data); - delay(10); -# if defined(DEEP_SLEEP_IN_US) || defined(ESP32_EXT0_WAKE_PIN) - ready_to_sleep = true; -# endif + if (SYSConfig.powerMode > 0) + ready_to_sleep = true; } else { Log.trace(F("DS1820: Temperature for device %s didn't change, don't publish it." CR), (char*)ds1820_addr[i].c_str()); } diff --git a/main/config_BT.h b/main/config_BT.h index bf4f918..6ebe994 100644 --- a/main/config_BT.h +++ b/main/config_BT.h @@ -32,7 +32,6 @@ extern void MQTTtoBT(char* topicOri, JsonObject& RFdata); extern void pubMainCore(JsonObject& data); extern void launchBTDiscovery(bool overrideDiscovery); extern void stopProcessing(); -extern void lowPowerESP32(); extern String stateBTMeasures(bool); #ifdef ESP32 diff --git a/main/config_M5.h b/main/config_M5.h index b08ee61..1468c86 100644 --- a/main/config_M5.h +++ b/main/config_M5.h @@ -74,7 +74,7 @@ extern void loopM5(); // Simple construct for displaying message in lcd and oled displays #define displayPrint(...) \ - if (lowpowermode < 2) M5Print(__VA_ARGS__) // only print if not in low power mode + if (SYSConfig.powerMode < 1) M5Print(__VA_ARGS__) // only print if not in low power mode #define lpDisplayPrint(...) M5Print(__VA_ARGS__) // print in low power mode void M5Print(char*, char* = "", char* = ""); diff --git a/main/config_SSD1306.h b/main/config_SSD1306.h index 4e8b797..fea51ea 100644 --- a/main/config_SSD1306.h +++ b/main/config_SSD1306.h @@ -131,7 +131,7 @@ extern String stateSSD1306Display(); // Simple construct for displaying message in lcd and oled displays #define displayPrint(...) \ - if (lowpowermode < 2) ssd1306Print(__VA_ARGS__) // only print if not in low power mode + if (SYSConfig.powerMode < 1) ssd1306Print(__VA_ARGS__) // only print if not in low power mode #define lpDisplayPrint(...) ssd1306Print(__VA_ARGS__) // print in low power mode void ssd1306Print(char*, char*, char*); diff --git a/main/main.ino b/main/main.ino index 062703b..ee5287f 100644 --- a/main/main.ino +++ b/main/main.ino @@ -27,14 +27,20 @@ */ #include "User_config.h" -// States of the gateway -// Wm setup -// Connected to MQTT -// Disconnected from Wifi -// Disconnected from MQTT -// Deep sleep -// Local OTA in progress -// Remote OTA in progress +enum GatewayState { + WAITING_ONBOARDING, + ONBOARDING, + OFFLINE, + NTWK_CONNECTED, + BROKER_CONNECTED, + PROCESSING, + NTWK_DISCONNECTED, + BROKER_DISCONNECTED, + LOCAL_OTA_IN_PROGRESS, + REMOTE_OTA_IN_PROGRESS, + SLEEPING +}; +GatewayState gatewayState = GatewayState::WAITING_ONBOARDING; // Macros and structure to enable the duplicates removing on the following gateways #if defined(ZgatewayRF) || defined(ZgatewayIR) || defined(ZgatewaySRFB) || defined(ZgatewayWeatherStation) || defined(ZgatewayRTL_433) @@ -71,9 +77,7 @@ int maxQueueLength = 0; * Deep-sleep for the ESP8266 & ESP32 we need some form of indicator that we have posted the measurements and am ready to deep sleep. * Set this to true in the sensor code after publishing the measurement. */ -#if defined(DEEP_SLEEP_IN_US) || defined(ESP32_EXT0_WAKE_PIN) bool ready_to_sleep = false; -#endif #include #include @@ -88,6 +92,7 @@ struct JsonBundle { std::queue jsonQueue; #ifdef ESP32 +# include // Mutex to protect the queue SemaphoreHandle_t xQueueMutex; bool blufiConnectAP = false; @@ -709,7 +714,7 @@ void pubMQTT(const char* topic, const char* payload) { * @param retainFlag true if retain the retain Flag */ void pubMQTT(const char* topic, const char* payload, bool retainFlag) { - if (SYSConfig.XtoMQTT) { + if (SYSConfig.XtoMQTT && !SYSConfig.offline) { if (mqtt && mqtt->connected()) { SendReceiveIndicatorON(); Log.trace(F("[ OMG->MQTT ] topic: %s msg: %s " CR), topic, payload); @@ -718,7 +723,7 @@ void pubMQTT(const char* topic, const char* payload, bool retainFlag) { Log.warning(F("MQTT not connected, aborting the publication" CR)); } } else { - Log.notice(F("[ OMG->MQTT CANCELED] topic: %s msg: %s " CR), topic, payload); + Log.notice(F("[ OMG->MQTT deactivated or offline] topic: %s msg: %s " CR), topic, payload); } } @@ -850,6 +855,7 @@ void delayWithOTA(long waitMillis) { void SYSConfig_init() { SYSConfig.XtoMQTT = DEFAULT_XtoMQTT; + SYSConfig.offline = DEFAULT_OFFLINE; #ifdef ZmqttDiscovery SYSConfig.discovery = DEFAULT_DISCOVERY; SYSConfig.ohdiscovery = OpenHABDiscovery; @@ -857,10 +863,12 @@ void SYSConfig_init() { #ifdef RGB_INDICATORS SYSConfig.rgbbrightness = DEFAULT_ADJ_BRIGHTNESS; #endif + SYSConfig.powerMode = DEFAULT_LOW_POWER_MODE; } void SYSConfig_fromJson(JsonObject& SYSdata) { Config_update(SYSdata, "xtomqtt", SYSConfig.XtoMQTT); + Config_update(SYSdata, "offline", SYSConfig.offline); #ifdef ZmqttDiscovery Config_update(SYSdata, "disc", SYSConfig.discovery); Config_update(SYSdata, "ohdisc", SYSConfig.ohdiscovery); @@ -868,8 +876,34 @@ void SYSConfig_fromJson(JsonObject& SYSdata) { #ifdef RGB_INDICATORS Config_update(SYSdata, "rgbb", SYSConfig.rgbbrightness); #endif + Config_update(SYSdata, "powermode", SYSConfig.powerMode); } +#ifdef ESP32 +void SYSConfig_save() { + StaticJsonDocument jsonBuffer; + JsonObject SYSdata = jsonBuffer.to(); + SYSdata["xtomqtt"] = SYSConfig.XtoMQTT; + SYSdata["offline"] = SYSConfig.offline; + SYSdata["powermode"] = SYSConfig.powerMode; +# ifdef ZmqttDiscovery + SYSdata["disc"] = SYSConfig.discovery; + SYSdata["ohdisc"] = SYSConfig.ohdiscovery; +# endif +# ifdef RGB_INDICATORS + SYSdata["rgbb"] = SYSConfig.rgbbrightness; +# endif + String conf = ""; + serializeJson(jsonBuffer, conf); + preferences.begin(Gateway_Short_Name, false); + int result = preferences.putString("SYSConfig", conf); + preferences.end(); + Log.notice(F("SYS Config_save: %s, result: %d" CR), conf.c_str(), result); +} +#else // Function not available for ESP8266 +void SYSConfig_save() {} +#endif + #if defined(ESP32) void SYSConfig_load() { StaticJsonDocument jsonBuffer; @@ -1021,6 +1055,7 @@ void setupMQTT() { displayPrint("MQTT connected"); Log.notice(F("Connected to broker" CR)); + gatewayState = GatewayState::BROKER_CONNECTED; failure_number_mqtt = 0; // Once connected, publish an announcement... pub(will_Topic, Gateway_AnnouncementMsg, will_Retain); @@ -1044,11 +1079,12 @@ void setupMQTT() { }; mqtt->connection_failure_callback = [] { - if (WiFi.status() != WL_CONNECTED && ethConnected == false) { - // No WiFi connection, MQTT couldn't connect, ignore this failure + if (WiFi.status() != WL_CONNECTED || ethConnected == false || SYSConfig.offline) { + // No network connection or offline, ignore this failure return; } failure_number_mqtt++; // we count the failure + gatewayState = GatewayState::BROKER_DISCONNECTED; Log.warning(F("failure_number_mqtt: %d" CR), failure_number_mqtt); const auto& parameters = cnt_parameters_array[cnt_index]; @@ -1227,6 +1263,9 @@ void setup() { SYSConfig_init(); SYSConfig_load(); + if (SYSConfig.offline) + gatewayState = GatewayState::OFFLINE; + //setup LED status SetupIndicatorError(); SetupIndicatorSendReceive(); @@ -1241,15 +1280,6 @@ void setup() { # endif #elif ESP32 xQueueMutex = xSemaphoreCreateMutex(); -# if DEFAULT_LOW_POWER_MODE != -1 // don't check preferences value if low power mode is not activated - preferences.begin(Gateway_Short_Name, false); - if (preferences.isKey("lowpowermode")) { - lowpowermode = preferences.getUInt("lowpowermode", DEFAULT_LOW_POWER_MODE); - } else { - Log.notice(F("No lowpowermode config to load" CR)); - } - preferences.end(); -# endif # if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5STACK) || defined(ZboardM5TOUGH) setupM5(); # endif @@ -1261,33 +1291,21 @@ void setup() { Log.notice(F("OpenMQTTGateway Version: " OMG_VERSION CR)); -/** - * Deep-sleep for the ESP8266 & ESP32 we need some form of indicator that we have posted the measurements and am ready to deep sleep. - * When woken set back to false. - */ -#if defined(DEEP_SLEEP_IN_US) || defined(ESP32_EXT0_WAKE_PIN) - ready_to_sleep = false; -#endif - -#ifdef DEEP_SLEEP_IN_US -# ifdef ESP8266 - Log.notice(F("Setting wake pin for deep sleep." CR)); - pinMode(ESP8266_DEEP_SLEEP_WAKE_PIN, WAKEUP_PULLUP); -# endif -# ifdef ESP32 - Log.notice(F("Setting duration for deep sleep." CR)); - if (esp_sleep_enable_timer_wakeup(DEEP_SLEEP_IN_US) != ESP_OK) { - Log.error(F("Failed to set deep sleep duration." CR)); - } -# endif -#endif - #ifdef ESP32_EXT0_WAKE_PIN Log.notice(F("Setting EXT0 Wakeup for deep sleep." CR)); - if (esp_sleep_enable_ext0_wakeup(ESP32_EXT0_WAKE_PIN, ESP32_EXT0_WAKE_PIN_STATE) != ESP_OK) { + gpio_num_t wake_pin0 = static_cast(ESP32_EXT0_WAKE_PIN); + if (esp_sleep_enable_ext0_wakeup(wake_pin0, ESP32_EXT0_WAKE_PIN_STATE) != ESP_OK) { Log.error(F("Failed to set deep sleep EXT0 Wakeup." CR)); } #endif +#ifdef ESP32_EXT1_WAKE_PIN + Log.notice(F("Setting EXT1 Wakeup for deep sleep." CR)); + uint64_t wake_pin_bitmask = 1ULL << ESP32_EXT1_WAKE_PIN; // Adjust this line if multiple pins are used. + esp_sleep_ext1_wakeup_mode_t wake_state1 = static_cast(ESP32_EXT1_WAKE_PIN_STATE); + if (esp_sleep_enable_ext1_wakeup(wake_pin_bitmask, wake_state1) != ESP_OK) { + Log.error(F("Failed to set deep sleep EXT1 Wakeup." CR)); + } +#endif #ifdef ESP32 //esp_task_wdt_init(GeneralTimeOut, true); //enable panic so ESP32 restarts #endif @@ -1304,6 +1322,10 @@ void setup() { modules.add(ZactuatorONOFF); #endif +#if defined(ESP32) && defined(USE_BLUFI) + startBlufi(); +#endif + #if defined(ESPWifiManualSetup) setup_wifi(); #else @@ -1510,7 +1532,7 @@ void setup() { modules.add(ZgatewayRTL_433); #endif Log.trace(F("mqtt_max_payload_size: %d" CR), mqtt_max_payload_size); - + SYSConfig.offline ? Log.notice(F("Offline enabled" CR)) : Log.notice(F("Offline disabled" CR)); char jsonChar[100]; serializeJson(modules, jsonChar, measureJson(modules) + 1); Log.notice(F("OpenMQTTGateway modules: %s" CR), jsonChar); @@ -1523,6 +1545,7 @@ bool wifi_reconnect_bypass() { extern bool omg_blufi_ble_connected; if (omg_blufi_ble_connected) { Log.notice(F("BLUFI is connected, bypassing wifi reconnect" CR)); + gatewayState = GatewayState::ONBOARDING; return true; } #endif @@ -1581,6 +1604,7 @@ void setOTA() { }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Log.trace(F("Progress: %u%%\r" CR), (progress / (total / 100))); + gatewayState = GatewayState::LOCAL_OTA_IN_PROGRESS; #ifdef ESP32 //esp_task_wdt_reset(); #endif @@ -1738,9 +1762,9 @@ void setup_wifi() { Log.trace(F("." CR)); failure_number_ntwk++; # if defined(ESP32) && defined(ZgatewayBT) - if (lowpowermode) { + if (SYSConfig.powerMode) { if (failure_number_ntwk > maxConnectionRetryNetwork) { - lowPowerESP32(); + sleep(); } } else { if (failure_number_ntwk > maxRetryWatchDog) { @@ -2186,26 +2210,12 @@ void setupwifi(bool reset_settings) { wifiManager.setBreakAfterConfig(true); // If ethernet is used, we don't want to block the connection by keeping the portal up # endif - if (!wifi_reconnect_bypass()) // if we didn't connect with saved credential we start Wifimanager web portal / Blufi + if (!SYSConfig.offline && !wifi_reconnect_bypass()) // if we didn't connect with saved credential we start Wifimanager web portal / Blufi { - -# if defined(ESP32) && defined(USE_BLUFI) - startBlufi(); -# endif -# ifdef ESP32 - if (lowpowermode < 2) { - displayPrint("Connect your phone to WIFI AP:", WifiManager_ssid, ota_pass); - } else { // in case of low power mode we put the ESP to sleep again if we didn't get connected (typical in case the wifi is down) -# ifdef ZgatewayBT - lowPowerESP32(); -# endif - } -# endif - InfoIndicatorON(); ErrorIndicatorON(); Log.notice(F("Connect your phone to WIFI AP: %s with PWD: %s" CR), WifiManager_ssid, ota_pass); - + gatewayState = GatewayState::ONBOARDING; //fetches ssid and pass and tries to connect //if it does not connect it starts an access point with the specified name //and goes into a blocking loop awaiting configuration @@ -2350,6 +2360,48 @@ void WiFiEvent(WiFiEvent_t event) { # endif #endif +#if DEFAULT_LOW_POWER_MODE != DEACTIVATED && defined(ESP32) +/** + * Deep-sleep for the ESP32 - e.g. DEEP_SLEEP_IN_US 30000000 for 30 seconds / wake by ESP32_EXT0_WAKE_PIN/ESP32_EXT1_WAKE_PIN. + * Everything is off and (almost) all execution state is lost. + */ +void sleep() { + if (SYSConfig.powerMode < PowerMode::INTERVAL) + return; + Log.notice(F("Entering deep sleep" CR)); + gatewayState = GatewayState::SLEEPING; + delay(250); // To allow the LEDs to switch off and MQTT message to be sent +# if defined(ZboardM5STACK) || defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5TOUGH) + sleepScreen(); + esp_sleep_enable_ext0_wakeup((gpio_num_t)SLEEP_BUTTON, LOW); +# endif + Log.trace(F("Deactivating ESP32 components" CR)); +# ifdef ZgatewayBT + stopProcessing(); + ProcessLock = true; +# endif +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" + adc_power_off(); +# pragma GCC diagnostic pop + esp_wifi_stop(); +# ifdef ESP32_EXT0_WAKE_PIN + Log.notice(F("Entering deep sleep, EXT0 Wakeup by pin : %l." CR), ESP32_EXT0_WAKE_PIN); +# endif +# ifdef ESP32_EXT1_WAKE_PIN + Log.notice(F("Entering deep sleep, EXT1 Wakeup by pin : %l." CR), ESP32_EXT1_WAKE_PIN); +# endif + if (SYSConfig.powerMode == PowerMode::ACTION) { + esp_deep_sleep_start(); + } else if (SYSConfig.powerMode == PowerMode::INTERVAL) { + Log.notice(F("Entering deep sleep for %l us." CR), DEEP_SLEEP_IN_US); + esp_deep_sleep(DEEP_SLEEP_IN_US); + } +} +#else +void sleep() {} +#endif + void loop() { #ifndef ESPWifiManualSetup checkButton(); // check if a reset of wifi/mqtt settings is asked @@ -2358,10 +2410,11 @@ void loop() { #ifdef ESP32 //esp_task_wdt_reset(); #endif - - if (mqttSetupPending) { - setupMQTT(); - mqttSetupPending = false; + if (!SYSConfig.offline) { + if (mqttSetupPending) { + setupMQTT(); + mqttSetupPending = false; + } } unsigned long now = millis(); @@ -2428,131 +2481,16 @@ void loop() { BTProcessLock = !BTConfig.enabled; // Release BLE processes at start if enabled #endif } - timer_sys_checks = millis(); } emptyQueue(); -#ifdef ZsensorBME280 - MeasureTempHumAndPressure(); //Addon to measure Temperature, Humidity, Pressure and Altitude with a Bosch BME280/BMP280 -#endif -#ifdef ZsensorHTU21 - MeasureTempHum(); //Addon to measure Temperature, Humidity, of a HTU21 sensor -#endif -#ifdef ZsensorLM75 - MeasureTemp(); //Addon to measure Temperature of an LM75 sensor -#endif -#ifdef ZsensorAHTx0 - MeasureAHTTempHum(); //Addon to measure Temperature, Humidity, of an 'AHTx0' sensor -#endif -#ifdef ZsensorHCSR04 - MeasureDistance(); //Addon to measure distance with a HC-SR04 -#endif -#ifdef ZsensorBH1750 - MeasureLightIntensity(); //Addon to measure Light Intensity with a BH1750 -#endif -#ifdef ZsensorMQ2 - MeasureGasMQ2(); -#endif -#ifdef ZsensorTEMT6000 - MeasureLightIntensityTEMT6000(); -#endif -#ifdef ZsensorTSL2561 - MeasureLightIntensityTSL2561(); -#endif -#ifdef ZsensorC37_YL83_HMRD - MeasureC37_YL83_HMRDWater(); //Addon for leak detection with a C-37 YL-83 H-MRD -#endif -#ifdef ZsensorDHT - MeasureTempAndHum(); //Addon to measure the temperature with a DHT -#endif -#ifdef ZsensorSHTC3 - MeasureTempAndHum(); //Addon to measure the temperature with a DHT -#endif -#ifdef ZsensorDS1820 - MeasureDS1820Temp(); //Addon to measure the temperature with DS1820 sensor(s) -#endif -#ifdef ZsensorINA226 - MeasureINA226(); -#endif -#ifdef ZsensorHCSR501 - MeasureHCSR501(); -#endif -#ifdef ZsensorGPIOInput - MeasureGPIOInput(); -#endif -#ifdef ZsensorGPIOKeyCode - MeasureGPIOKeyCode(); -#endif -#ifdef ZsensorADC - MeasureADC(); //Addon to measure the analog value of analog pin -#endif -#ifdef ZsensorTouch - MeasureTouch(); -#endif -#ifdef ZgatewayLORA - LORAtoMQTT(); -# ifdef ZmqttDiscovery - if (SYSConfig.discovery) - launchLORADiscovery(false); -# endif -#endif -#ifdef ZgatewayRF - RFtoMQTT(); -#endif -#ifdef ZgatewayRF2 - RF2toMQTT(); -#endif -#ifdef ZgatewayWeatherStation - ZgatewayWeatherStationtoMQTT(); -#endif -#ifdef ZgatewayGFSunInverter - ZgatewayGFSunInverterMQTT(); -#endif -#ifdef ZgatewayPilight - PilighttoMQTT(); -#endif -#ifdef ZgatewayBT -# ifdef ZmqttDiscovery - if (SYSConfig.discovery) - launchBTDiscovery(false); -# endif -#endif -#ifdef ZgatewaySRFB - SRFBtoMQTT(); -#endif -#ifdef ZgatewayIR - IRtoMQTT(); -#endif -#ifdef Zgateway2G - if (_2GtoMQTT()) - Log.trace(F("2GtoMQTT OK" CR)); -#endif -#ifdef ZgatewayRFM69 - if (RFM69toMQTT()) - Log.trace(F("RFM69toMQTT OK" CR)); -#endif -#ifdef ZgatewaySERIAL - SERIALtoMQTT(); -#endif -#ifdef ZactuatorFASTLED - FASTLEDLoop(); -#endif -#ifdef ZactuatorPWM - PWMLoop(); -#endif -#ifdef ZgatewayRTL_433 - RTL_433Loop(); -# ifdef ZmqttDiscovery - if (SYSConfig.discovery) - launchRTL_433Discovery(false); -# endif -#endif } - } else { // disconnected from network + } else if (!SYSConfig.offline) { // disconnected from network #ifdef ESP32 //esp_task_wdt_reset(); #endif Log.warning(F("Network disconnected" CR)); + gatewayState = GatewayState::NTWK_DISCONNECTED; ErrorIndicatorON(); delay(2000); // add a delay to avoid ESP32 crash and reset #ifdef ESP32 @@ -2569,28 +2507,124 @@ void loop() { #if defined(ZdisplaySSD1306) loopSSD1306(); #endif - -/** - * Deep-sleep for the ESP8266 & ESP32 - e.g. DEEP_SLEEP_IN_US 30000000 for 30 seconds / wake by ESP32_EXT0_WAKE_PIN. - * Everything is off and (almost) all execution state is lost. - */ -#if defined(DEEP_SLEEP_IN_US) || defined(ESP32_EXT0_WAKE_PIN) - if (ready_to_sleep) { - delay(250); //Give some time for last MQTT messages to be sent -# ifdef DEEP_SLEEP_IN_US - Log.notice(F("Entering deep sleep for %l us." CR), DEEP_SLEEP_IN_US); -# endif -# ifdef ESP32_EXT0_WAKE_PIN - Log.notice(F("Entering deep sleep, EXT0 Wakeup by pin : %l." CR), ESP32_EXT0_WAKE_PIN); -# endif -# ifdef ESP8266 - ESP.deepSleep(DEEP_SLEEP_IN_US); -# endif -# ifdef ESP32 - esp_deep_sleep_start(); -# endif - } +#ifdef ZsensorBME280 + MeasureTempHumAndPressure(); //Addon to measure Temperature, Humidity, Pressure and Altitude with a Bosch BME280/BMP280 #endif +#ifdef ZsensorHTU21 + MeasureTempHum(); //Addon to measure Temperature, Humidity, of a HTU21 sensor +#endif +#ifdef ZsensorLM75 + MeasureTemp(); //Addon to measure Temperature of an LM75 sensor +#endif +#ifdef ZsensorAHTx0 + MeasureAHTTempHum(); //Addon to measure Temperature, Humidity, of an 'AHTx0' sensor +#endif +#ifdef ZsensorHCSR04 + MeasureDistance(); //Addon to measure distance with a HC-SR04 +#endif +#ifdef ZsensorBH1750 + MeasureLightIntensity(); //Addon to measure Light Intensity with a BH1750 +#endif +#ifdef ZsensorMQ2 + MeasureGasMQ2(); +#endif +#ifdef ZsensorTEMT6000 + MeasureLightIntensityTEMT6000(); +#endif +#ifdef ZsensorTSL2561 + MeasureLightIntensityTSL2561(); +#endif +#ifdef ZsensorC37_YL83_HMRD + MeasureC37_YL83_HMRDWater(); //Addon for leak detection with a C-37 YL-83 H-MRD +#endif +#ifdef ZsensorDHT + MeasureTempAndHum(); //Addon to measure the temperature with a DHT +#endif +#ifdef ZsensorSHTC3 + MeasureTempAndHum(); //Addon to measure the temperature with a DHT +#endif +#ifdef ZsensorDS1820 + MeasureDS1820Temp(); //Addon to measure the temperature with DS1820 sensor(s) +#endif +#ifdef ZsensorINA226 + MeasureINA226(); +#endif +#ifdef ZsensorHCSR501 + MeasureHCSR501(); +#endif +#ifdef ZsensorGPIOInput + MeasureGPIOInput(); +#endif +#ifdef ZsensorGPIOKeyCode + MeasureGPIOKeyCode(); +#endif +#ifdef ZsensorADC + MeasureADC(); //Addon to measure the analog value of analog pin +#endif +#ifdef ZsensorTouch + MeasureTouch(); +#endif +#ifdef ZgatewayLORA + LORAtoMQTT(); +# ifdef ZmqttDiscovery + if (SYSConfig.discovery) + launchLORADiscovery(false); +# endif +#endif +#ifdef ZgatewayRF + RFtoMQTT(); +#endif +#ifdef ZgatewayRF2 + RF2toMQTT(); +#endif +#ifdef ZgatewayWeatherStation + ZgatewayWeatherStationtoMQTT(); +#endif +#ifdef ZgatewayGFSunInverter + ZgatewayGFSunInverterMQTT(); +#endif +#ifdef ZgatewayPilight + PilighttoMQTT(); +#endif +#ifdef ZgatewayBT +# ifdef ZmqttDiscovery + if (SYSConfig.discovery) + launchBTDiscovery(false); +# endif +#endif +#ifdef ZgatewaySRFB + SRFBtoMQTT(); +#endif +#ifdef ZgatewayIR + IRtoMQTT(); +#endif +#ifdef Zgateway2G + if (_2GtoMQTT()) + Log.trace(F("2GtoMQTT OK" CR)); +#endif +#ifdef ZgatewayRFM69 + if (RFM69toMQTT()) + Log.trace(F("RFM69toMQTT OK" CR)); +#endif +#ifdef ZgatewaySERIAL + SERIALtoMQTT(); +#endif +#ifdef ZactuatorFASTLED + FASTLEDLoop(); +#endif +#ifdef ZactuatorPWM + PWMLoop(); +#endif +#ifdef ZgatewayRTL_433 + RTL_433Loop(); +# ifdef ZmqttDiscovery + if (SYSConfig.discovery) + launchRTL_433Discovery(false); +# endif +#endif + if (ready_to_sleep) { + sleep(); + } } /** @@ -2717,6 +2751,7 @@ String stateMeasures() { SYSdata["tempc"] = round2(intTemperatureRead()); # endif SYSdata["freestck"] = uxTaskGetStackHighWaterMark(NULL); + SYSdata["powermode"] = SYSConfig.powerMode; #endif SYSdata["eth"] = ethConnected; @@ -2734,12 +2769,6 @@ String stateMeasures() { SYSdata["ip"] = ip2CharArray(WiFi.localIP()); SYSdata["mac"] = (char*)WiFi.macAddress().c_str(); } - -#ifdef ZgatewayBT -# ifdef ESP32 - SYSdata["lowpowermode"] = (int)lowpowermode; -# endif -#endif #ifdef ZboardM5STACK M5.Power.begin(); SYSdata["m5battlevel"] = (int8_t)M5.Power.getBatteryLevel(); @@ -3080,6 +3109,7 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) { # endif # endif Log.warning(F("Starting firmware update" CR)); + gatewayState = GatewayState::REMOTE_OTA_IN_PROGRESS; SendReceiveIndicatorON(); ErrorIndicatorON(); @@ -3422,6 +3452,26 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding SYSConfig.XtoMQTT = SYSdata["xtomqtt"]; Log.notice(F("xtomqtt: %T" CR), SYSConfig.XtoMQTT); } + if (SYSdata.containsKey("offline") && SYSdata["offline"].is()) { + SYSConfig.offline = SYSdata["offline"]; + Log.notice(F("offline: %T" CR), SYSConfig.offline); + if (SYSConfig.offline) { + gatewayState = GatewayState::OFFLINE; +// Disconnect MQTT +#if !MQTT_BROKER_MODE + mqtt->disconnect(); +#else + mqtt->stop(); +#endif + // Disconnect network + if (WiFi.status() == WL_CONNECTED) + WiFi.disconnect(true); + } + } + if (SYSdata.containsKey("powermode") && SYSdata["powermode"].is()) { + SYSConfig.powerMode = SYSdata["powermode"]; + Log.notice(F("Power mode: %d" CR), SYSConfig.powerMode); + } if (SYSdata.containsKey("disc")) { if (SYSdata["disc"].is()) { if (SYSdata["disc"] == true && SYSConfig.discovery == false) @@ -3435,25 +3485,9 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding } Log.notice(F("Discovery state: %T" CR), SYSConfig.discovery); } -#ifdef ESP32 if (SYSdata.containsKey("save") && SYSdata["save"].as()) { - StaticJsonDocument jsonBuffer; - JsonObject jo = jsonBuffer.to(); - jo["disc"] = SYSConfig.discovery; - jo["ohdisc"] = SYSConfig.ohdiscovery; - jo["xtomqtt"] = SYSConfig.XtoMQTT; -# ifdef RGB_INDICATORS - jo["rgbb"] = SYSConfig.rgbbrightness; -# endif - // Save config into NVS (non-volatile storage) - String conf = ""; - serializeJson(jsonBuffer, conf); - preferences.begin(Gateway_Short_Name, false); - int result = preferences.putString("SYSConfig", conf); - preferences.end(); - Log.notice(F("SYS Config_save: %s, result: %d" CR), conf.c_str(), result); + SYSConfig_save(); } -#endif if (restartESP) { ESPRestart(7); } diff --git a/prod_env.ini.example b/prod_env.ini.example index 2cfefe8..78a651a 100644 --- a/prod_env.ini.example +++ b/prod_env.ini.example @@ -77,7 +77,7 @@ build_flags = '-DMQTT_USER="lolin-esp32"' '-DMQTT_PASS="abcdefghi"' '-DMQTT_SERVER="192.168.1.17"' - '-DDEFAULT_LOW_POWER_MODE=2' + '-DDEFAULT_LOW_POWER_MODE=INTERVAL' ;hacked Sonoff RF-Bridge [env:sonoff-rfbridge-hacked]