From 2e3f42aedc6e8fcfb5f562ffbb668cb94c0d6917 Mon Sep 17 00:00:00 2001 From: alan Date: Sat, 4 Jan 2025 14:02:22 +0800 Subject: [PATCH 1/7] add deepsleep module for battery application --- usermods/sleep_manager/README.md | 41 +++ usermods/sleep_manager/sleep_manager.h | 363 +++++++++++++++++++++++++ wled00/usermods_list.cpp | 8 + 3 files changed, 412 insertions(+) create mode 100644 usermods/sleep_manager/README.md create mode 100644 usermods/sleep_manager/sleep_manager.h diff --git a/usermods/sleep_manager/README.md b/usermods/sleep_manager/README.md new file mode 100644 index 0000000000..3018273054 --- /dev/null +++ b/usermods/sleep_manager/README.md @@ -0,0 +1,41 @@ +# Sleep Manager Module for WLED + +## Overview + +The **SleepManager** module for WLED is designed to manage power consumption by enabling the ESP32 to enter deep sleep based on idle time or battery voltage levels. This module allows for more efficient battery use by automatically putting the device to sleep and waking it up based on predefined conditions. It is especially useful for battery-powered setups where minimizing power consumption is essential. + +## Features + +- **Idle-based Sleep**: Automatically puts the device to sleep after a specified period of inactivity. +- **Battery Voltage Monitoring**: Monitors the battery voltage and enters deep sleep when the voltage falls below a set threshold. +- **Custom GPIO Configuration**: Allows configuration of GPIO pins for controlling power actions (e.g., pull-up or pull-down). +- **Touchpad Wakeup**: Supports waking up the device using a touch sensor (configurable via `WAKEUP_TOUCH_PIN`). +- **Voltage Protection**: Prevents deep sleep if the voltage is too low, protecting the device from shutting down unintentionally. +- **Preset Wakeup**: Optionally allows setting a timer to wake the device up after a set period. + +## Configuration + +To configure the **SleepManager** module, you will need to add and adjust the following settings in your WLED setup: + +### Define GPIO Pins (`CONFIGPINS`) + +You can specify a set of GPIO pins for controlling the sleep behavior. The syntax for defining this configuration is: + +```cpp +// GPIO NUM,start pull up(1)down(0),end pull up(1)down(0)dis(-1)... +#define CONFIGPINS 0,1,1, 25,0,1, 26,1,0 +``` + + +Example `plantformio.ini`: + +``` +[env:esp32dev_debug] +extends = esp32_idf_V4 +board = esp32dev +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp32_V4} + -D USERMOD_SLEEP + ; GPIO NUM,start pull up(1)down(0),end pull up(1)down(0)dis(-1)... + -D CONFIGPINS="25, 0, 1, 26, 0, 1, 27, 1, 0, 0, -1, 1, 4, -1, 0" +``` \ No newline at end of file diff --git a/usermods/sleep_manager/sleep_manager.h b/usermods/sleep_manager/sleep_manager.h new file mode 100644 index 0000000000..c04e8ab569 --- /dev/null +++ b/usermods/sleep_manager/sleep_manager.h @@ -0,0 +1,363 @@ +#ifndef SLEEP_MANAGER_H +#define SLEEP_MANAGER_H + +#include "wled.h" +#include "esp_pm.h" +#include "esp_system.h" +#include +#include +#ifndef WAKEUP_TOUCH_PIN +#ifdef CONFIG_IDF_TARGET_ESP32S3 // ESP32S3 +#define WAKEUP_TOUCH_PIN 5 +#else +#define WAKEUP_TOUCH_PIN 15 +#endif +#endif // WAKEUP_TOUCH_PIN +#ifndef CONFIGPINS +#define CONFIGPINS 0, 1, 1 // GPIO NUM,start pull up(1)down(0),end pull up(1)down(0)dis(-1)... +#endif +class SleepManager : public Usermod +{ +private: + boolean enableSleep = false; + boolean sleepOnIdle = false; + int voltagePin = 34; + unsigned long voltageCheckInterval = 5; + unsigned long lastVoltageCheckTime = 0; + float voltage; + unsigned long lastLedOffTime = -1; + unsigned long idleWaitSeconds = 60; + bool isTestingBattery = false; + bool sleepNextLoop = false; + float minVoltage = 3.0; + float maxVoltage = 4.2; + float voltageDivRatio = 2.0; + float currentVoltage = 0.0; + bool presetWakeup = true; + +public: + virtual void setup() + { + phase_wakeup_reason(); + int confGpioPins[] = {CONFIGPINS}; + configureGpios(confGpioPins, sizeof(confGpioPins) / sizeof(confGpioPins[0]), true); + } + + virtual void loop() + { + if (!enableSleep) + { + return; + } + unsigned long currentMillis = millis(); + + if (currentMillis - lastVoltageCheckTime >= voltageCheckInterval * 1000) + { + lastVoltageCheckTime = currentMillis; + if (sleepNextLoop) + { + startDeepSeelp(true); + } + + if (sleepOnIdle && lastLedOffTime != -1 && currentMillis - lastLedOffTime > idleWaitSeconds * 1000) + { + DEBUG_PRINTLN("sleep on idle..."); + startDeepSeelp(false); + } + + float voltage = readVoltage() * voltageDivRatio; + DEBUG_PRINTF("Current voltage on IO%d: %.3f\n", voltagePin, voltage); + if (isTestingBattery) + { + minVoltage = voltage; + serializeConfig(); + } + + if (voltage < minVoltage) + { + if (voltage != 0) + { + DEBUG_PRINTLN("Voltage is below threshold. Entering deep sleep..."); + startDeepSeelp(false); + } + } + } + } + + virtual void onStateChange(uint8_t mode) + { + DEBUG_PRINTF("current bri value: %d,effect: %d\n", bri, effectCurrent); + if (bri == 0) + { + lastLedOffTime = millis(); + } + else + { + lastLedOffTime = -1; + } + } + + void startDeepSeelp(bool immediate) + { + if (immediate) + { + DEBUG_PRINTLN("Entering deep sleep..."); + if (presetWakeup) + { + int nextWakeupMin = findNextTimerInterval() - 1; + if (nextWakeupMin > 0) + { + esp_sleep_enable_timer_wakeup(nextWakeupMin * 60ULL * 1000000ULL); // wakeup for preset + DEBUG_PRINTF("wakeup after %d minites", nextWakeupMin); + DEBUG_PRINTLN(""); + } + } + int confGpioPins[] = {CONFIGPINS}; + configureGpios(confGpioPins, sizeof(confGpioPins) / sizeof(confGpioPins[0]), true); + WiFi.disconnect(); + WiFi.mode(WIFI_OFF); + touchSleepWakeUpEnable(WAKEUP_TOUCH_PIN, touchThreshold); + // ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(GPIO_NUM_26, 0)); // Conflicting wake-up triggers: touch ext0 + ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(1ULL << GPIO_NUM_0, ESP_EXT1_WAKEUP_ALL_LOW)); + delay(2000); // wati gpio level and wifi module restore ... +#ifndef ARDUINO_ARCH_ESP32C3 +#endif + esp_deep_sleep_start(); + } + else + { + sleepNextLoop = true; + briLast = bri; + bri = 0; + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } + } + + void configureGpios(int gpioPins[], int size, bool start) + { + for (int i = 0; i < size; i += 3) + { + int gpioPin = gpioPins[i]; + int startFlag = gpioPins[i + 1]; + int endFlag = gpioPins[i + 2]; + + if (start) + { + if (startFlag == 1) + { + pull_up_down(gpioPin, true, false); + } + else if (startFlag == 0) + { + pull_up_down(gpioPin, false, true); + } + else + { + pull_up_down(gpioPin, false, false); + } + } + else + { + if (endFlag == 1) + { + pull_up_down(gpioPin, true, false); + } + else if (endFlag == 0) + { + pull_up_down(gpioPin, false, true); + } + else + { + pull_up_down(gpioPin, false, false); + } + } + } + } + + void pull_up_down(int gpioPin, bool up, bool down) + { + gpio_pullup_dis((gpio_num_t)gpioPin); + gpio_pulldown_dis((gpio_num_t)gpioPin); + if (up) + { + ESP_ERROR_CHECK(gpio_pullup_en((gpio_num_t)gpioPin)); + } + if (down) + { + ESP_ERROR_CHECK(gpio_pulldown_en((gpio_num_t)gpioPin)); + } + } + + float readVoltage() + { + int adcValue = analogRead(voltagePin); + float voltageOut = (adcValue / float(4095)) * 3.3; + return voltageOut; + } + + // add wakeup reson,battery info + void addToJsonInfo(JsonObject &root) + { + JsonObject user = root["u"]; + if (user.isNull()) + user = root.createNestedObject("u"); + + currentVoltage = readVoltage(); + + float batteryPercentage = calculateBatteryPercentage(currentVoltage * voltageDivRatio); + + JsonArray percentage = user.createNestedArray(F("Battery Percentage")); + JsonArray voltage = user.createNestedArray(F("Current Voltage")); + JsonArray boot = user.createNestedArray(F("boot type")); + percentage.add(batteryPercentage); + percentage.add(F(" %")); + voltage.add(round(currentVoltage * voltageDivRatio * 100.0) / 100.0); + voltage.add(F(" V")); + boot.add(F(phase_wakeup_reason())); + } + + // 在配置中添加电压相关配置 + void addToConfig(JsonObject &root) + { + DEBUG_PRINTLN("sleep module addToConfig"); + JsonObject top = root.createNestedObject("Sleep Module"); + + top["enable Sleep"] = enableSleep; + top["voltage Check Interval"] = voltageCheckInterval; + top["voltage Pin"] = voltagePin; + top["Min Voltage"] = minVoltage; + top["Max Voltage"] = maxVoltage; + top["Voltage Div Ratio"] = voltageDivRatio; + top["sleep On Idle"] = sleepOnIdle; + top["idle Wait Seconds"] = idleWaitSeconds; + top["battery Test Enabled"] = false; + top["preset Wakeup"] = presetWakeup; + } + + bool readFromConfig(JsonObject &root) + { + DEBUG_PRINTLN("sleep module readFromConfig"); + JsonObject top = root["Sleep Module"]; + bool configComplete = !top.isNull(); + + configComplete &= getJsonValue(top["enable Sleep"], enableSleep); + configComplete &= getJsonValue(top["voltage Check Interval"], voltageCheckInterval); + configComplete &= getJsonValue(top["voltage Pin"], voltagePin); + configComplete &= getJsonValue(top["Min Voltage"], minVoltage); + configComplete &= getJsonValue(top["Max Voltage"], maxVoltage); + configComplete &= getJsonValue(top["Voltage Div Ratio"], voltageDivRatio); + configComplete &= getJsonValue(top["sleep On Idle"], sleepOnIdle); + configComplete &= getJsonValue(top["idle Wait Seconds"], idleWaitSeconds); + configComplete &= getJsonValue(top["battery Test Enabled"], isTestingBattery); + configComplete &= getJsonValue(top["preset Wakeup"], presetWakeup); + + return configComplete; + } + + int calculateBatteryPercentage(float voltage) + { + int percent = (voltage - minVoltage) / (maxVoltage - minVoltage) * 100.0; + if (percent < 0) + { + percent = 0; + } + if (percent > 100) + { + percent = 100; + } + return percent; + } + + int calculateTimeDifference(int hour1, int minute1, int hour2, int minute2) + { + int totalMinutes1 = hour1 * 60 + minute1; + int totalMinutes2 = hour2 * 60 + minute2; + if (totalMinutes2 < totalMinutes1) + { + totalMinutes2 += 24 * 60; + } + return totalMinutes2 - totalMinutes1; + } + + int findNextTimerInterval() + { + int currentHour = hour(localTime), currentMinute = minute(localTime), currentWeekday = weekdayMondayFirst(); + int minDifference = INT_MAX; + + for (uint8_t i = 0; i < 8; i++) + { + if (!(timerMacro[i] != 0 && (timerWeekday[i] & 0x01))) + { + continue; + } + + for (int dayOffset = 0; dayOffset < 7; dayOffset++) + { + int checkWeekday = ((currentWeekday + dayOffset) % 7); // 1-7 + if (checkWeekday == 0) + { + checkWeekday = 7; + } + + if ((timerWeekday[i] >> (checkWeekday)) & 0x01) + { + if (dayOffset == 0 && + (timerHours[i] < currentHour || + (timerHours[i] == currentHour && timerMinutes[i] <= currentMinute))) + { + continue; + } + + int targetHour = timerHours[i]; + int targetMinute = timerMinutes[i]; + int timeDifference = calculateTimeDifference( + currentHour, currentMinute, + targetHour + (dayOffset * 24), targetMinute); + + if (timeDifference < minDifference) + { + minDifference = timeDifference; + } + } + } + } + return minDifference; + } + const char *phase_wakeup_reason() + { + static char reson[20]; + esp_sleep_wakeup_cause_t wakeup_reason; + + wakeup_reason = esp_sleep_get_wakeup_cause(); + + switch (wakeup_reason) + { + case ESP_SLEEP_WAKEUP_EXT0: + DEBUG_PRINTLN("Wakeup caused by external signal using RTC_IO"); + strcpy(reson, "RTC_IO"); + break; + case ESP_SLEEP_WAKEUP_EXT1: + DEBUG_PRINTLN("Wakeup caused by external signal using RTC_CNTL"); + strcpy(reson, "RTC_CNTL"); + break; + case ESP_SLEEP_WAKEUP_TIMER: + DEBUG_PRINTLN("Wakeup caused by timer"); + strcpy(reson, "timer"); + break; + case ESP_SLEEP_WAKEUP_TOUCHPAD: + DEBUG_PRINTLN("Wakeup caused by touchpad"); + strcpy(reson, "touchpad"); + break; + case ESP_SLEEP_WAKEUP_ULP: + DEBUG_PRINTLN("Wakeup caused by ULP program"); + strcpy(reson, "ULP"); + break; + default: + DEBUG_PRINTF("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); + snprintf(reson, sizeof(reson), "other %d", wakeup_reason); + break; + } + return reson; + } +}; +#endif diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 3283e013b2..820bfd5a31 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -242,6 +242,10 @@ #include "../usermods/LD2410_v2/usermod_ld2410.h" #endif +#ifdef USERMOD_SLEEP +#include "../usermods/sleep_manager/sleep_manager.h" +#endif + void registerUsermods() { /* @@ -470,4 +474,8 @@ void registerUsermods() #ifdef USERMOD_POV_DISPLAY UsermodManager::add(new PovDisplayUsermod()); #endif + + #ifdef USERMOD_SLEEP + UsermodManager::add(new SleepManager()); + #endif } From 444c1b8e582a01accdc808304b7daefdf8d26d5b Mon Sep 17 00:00:00 2001 From: alan Date: Sun, 5 Jan 2025 00:30:04 +0800 Subject: [PATCH 2/7] merge new Features to exists deep sleep usermod --- usermods/deep_sleep/readme.md | 16 + usermods/deep_sleep/usermod_deep_sleep.h | 257 +++++++++++++--- usermods/sleep_manager/README.md | 41 --- usermods/sleep_manager/sleep_manager.h | 363 ----------------------- wled00/pin_manager.h | 3 +- wled00/usermods_list.cpp | 5 - 6 files changed, 235 insertions(+), 450 deletions(-) delete mode 100644 usermods/sleep_manager/README.md delete mode 100644 usermods/sleep_manager/sleep_manager.h diff --git a/usermods/deep_sleep/readme.md b/usermods/deep_sleep/readme.md index 006aa31fd9..a34fca5338 100644 --- a/usermods/deep_sleep/readme.md +++ b/usermods/deep_sleep/readme.md @@ -3,6 +3,14 @@ This usermod unleashes the low power capabilities of th ESP: when you power off your LEDs (using the UI power button or a macro) the ESP will be put into deep sleep mode, reducing power consumption to a minimum. During deep sleep the ESP is shut down completely: no WiFi, no CPU, no outputs. The only way to wake it up is to use an external signal or a button. Once it wakes from deep sleep it reboots so ***make sure to use a boot-up preset.*** +## Features + +- **Idle-based Sleep**: Automatically puts the device to sleep after a specified period of inactivity. +- **Custom GPIO Configuration**: Allows configuration of GPIO pins for controlling power actions (e.g., pull-up or pull-down). +- **Touchpad Wakeup**: Supports waking up the device using a touch sensor. +- **RTC IO Wakeup**: Supports waking up the device using RTC IO. +- **Preset Wakeup**: Optionally allows setting a timer to wake the device up after a set period. + # A word of warning When you disable the WLED option 'Turn LEDs on after power up/reset' and 'DelaySleep' is set to zero the ESP will go into deep sleep directly after power-up and only start WLED after it has been woken up. @@ -61,6 +69,14 @@ To override the default settings, place the `#define` in wled.h or add `-D DEEPS * `DEEPSLEEP_DISABLEPULL` - if defined, internal pullup/pulldown is disabled in deep sleep (default is ebnabled) * `DEEPSLEEP_WAKEUPINTERVAL` - number of seconds after which a wake-up happens automatically, sooner if button is pressed. 0 = never. accuracy is about 2% * `DEEPSLEEP_DELAY` - delay between power-off and sleep +* `DEEPSLEEP_WAKEUP_TOUCH_PIN` - specify GPIO pin used for touch-based wakeup; 5 for ESP32S3, 15 for other models +* `DEEPSLEEP_CONFIGPINS` - configure GPIO pins: NUM=start pull-up (1)/down (0), end pull-up (1)/down (0)/disable (-1),example "4,1,0" - pull io4 up at setup,down before deepsleep +* `DEEPSLEEP_WHEN_LOW_VOLTAGE` - if true, enters deep sleep when low voltage is detected +* `DEEPSLEEP_VOTAGE_PIN` - specify GPIO pin used for voltage monitoring (e.g., pin 34) +* `DEEPSLEEP_MIN_VOTAGE` - minimum voltage threshold to trigger deep sleep (in volts) +* `DEEPSLEEP_VOTAGE_DIV_RATIO` - voltage divider ratio used to monitor voltage on the defined pin +* `DEEPSLEEP_WAKEWHENHIGH` - wake up when the pin goes high (default is when the pin goes low) + example for env build flags: `-D USERMOD_DEEP_SLEEP` diff --git a/usermods/deep_sleep/usermod_deep_sleep.h b/usermods/deep_sleep/usermod_deep_sleep.h index 7f4efd5caf..fd4854c034 100644 --- a/usermods/deep_sleep/usermod_deep_sleep.h +++ b/usermods/deep_sleep/usermod_deep_sleep.h @@ -22,7 +22,16 @@ #ifndef DEEPSLEEP_DELAY #define DEEPSLEEP_DELAY 1 #endif - +#ifndef DEEPSLEEP_WAKEUP_TOUCH_PIN +#ifdef CONFIG_IDF_TARGET_ESP32S3 // ESP32S3 +#define DEEPSLEEP_WAKEUP_TOUCH_PIN 5 +#else +#define DEEPSLEEP_WAKEUP_TOUCH_PIN 15 +#endif +#endif // DEEPSLEEP_WAKEUP_TOUCH_PIN +#ifndef DEEPSLEEP_CONFIGPINS +#define DEEPSLEEP_CONFIGPINS 0, 1, 1 // GPIO NUM,start pull up(1)down(0),end pull up(1)down(0)dis(-1)... +#endif RTC_DATA_ATTR bool powerup = true; // variable in RTC data persists on a reboot class DeepSleepUsermod : public Usermod { @@ -34,10 +43,15 @@ class DeepSleepUsermod : public Usermod { uint8_t wakeupPin = DEEPSLEEP_WAKEUPPIN; uint8_t wakeWhenHigh = DEEPSLEEP_WAKEWHENHIGH; // wake up when pin goes high if 1, triggers on low if 0 bool noPull = true; // use pullup/pulldown resistor + bool enableTouchWakeup = false; + uint8_t touchPin = DEEPSLEEP_WAKEUP_TOUCH_PIN; int wakeupAfter = DEEPSLEEP_WAKEUPINTERVAL; // in seconds, <=0: button only + bool presetWake = true; // wakeup timer for preset int sleepDelay = DEEPSLEEP_DELAY; // in seconds, 0 = immediate int delaycounter = 5; // delay deep sleep at bootup until preset settings are applied uint32_t lastLoopTime = 0; + bool sleepNextLoop = false; // tag for next starting deep sleep + // string that are used multiple time (this will save some flash memory) static const char _name[]; static const char _enabled[]; @@ -62,6 +76,187 @@ class DeepSleepUsermod : public Usermod { return false; } + const char* phase_wakeup_reason() { + static char reson[20]; + esp_sleep_wakeup_cause_t wakeup_reason; + wakeup_reason = esp_sleep_get_wakeup_cause(); + switch (wakeup_reason) { + case ESP_SLEEP_WAKEUP_EXT0: + strcpy(reson, "RTC_IO"); + break; + case ESP_SLEEP_WAKEUP_EXT1: + strcpy(reson, "RTC_CNTL"); + break; + case ESP_SLEEP_WAKEUP_TIMER: + strcpy(reson, "timer"); + break; + case ESP_SLEEP_WAKEUP_TOUCHPAD: + strcpy(reson, "touchpad"); + break; + case ESP_SLEEP_WAKEUP_ULP: + strcpy(reson, "ULP"); + break; + case ESP_SLEEP_WAKEUP_UNDEFINED: + strcpy(reson, "RESET"); + break; + default: + snprintf(reson, sizeof(reson), "%d", wakeup_reason); + break; + } + return reson; + } + + void pull_up_down(int gpioPin, bool up, bool down) { + rtc_gpio_pullup_dis((gpio_num_t)gpioPin); + rtc_gpio_pulldown_dis((gpio_num_t)gpioPin); + if (up) { + ESP_ERROR_CHECK(rtc_gpio_pullup_en((gpio_num_t)gpioPin)); + } + if (down) { + ESP_ERROR_CHECK(rtc_gpio_pulldown_en((gpio_num_t)gpioPin)); + } + } + + void configureGpios(int gpioPins[], int size, bool start) { + for (int i = 2; i < size; i += 3) { + int gpioPin = gpioPins[i - 2]; + int flag = start? gpioPins[i - 1]: gpioPins[i]; + + if (start && flag != -1 && !PinManager::allocatePin(gpioPin, false, PinOwner::UM_DEEP_SLEEP)) { + DEBUG_PRINTF("failed to allocate GPIO for usermod deep sleep: %d\n", gpioPin); + continue; + } + + if (flag == 1) + pull_up_down(gpioPin, true, false); + else if (flag == 0) + pull_up_down(gpioPin, false, true); + } + } + + void startDeepSeelp(bool immediate) { + esp_err_t halerror = ESP_OK; + int nextWakeupMin = 0; + if (immediate) { + DEBUG_PRINTLN("DeepSleep UM: Entering deep sleep..."); + if (presetWake) { + nextWakeupMin = findNextTimerInterval() - 1; // wakeup before next preset + } + if (wakeupAfter > 0) { + nextWakeupMin = nextWakeupMin < wakeupAfter / 60.0 + ? nextWakeupMin + : wakeupAfter / 60.0; + } + if (nextWakeupMin > 0) { + esp_sleep_enable_timer_wakeup(nextWakeupMin * 60ULL * + (uint64_t)1e6); // wakeup for preset + DEBUG_PRINTF("wakeup after %d minites", nextWakeupMin); + DEBUG_PRINTLN(""); + } + WiFi.disconnect(); + WiFi.mode(WIFI_OFF); + int confGpioPins[] = {DEEPSLEEP_CONFIGPINS}; + configureGpios(confGpioPins, + sizeof(confGpioPins) / sizeof(confGpioPins[0]), false); + if (enableTouchWakeup) { + touchSleepWakeUpEnable(touchPin, touchThreshold); + } + #if defined(CONFIG_IDF_TARGET_ESP32C3) // ESP32 C3 + if(noPull) + gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_FLOATING); + else { // enable pullup/pulldown resistor + if(wakeWhenHigh) + gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLDOWN_ONLY); + else + gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLUP_ONLY); + } + if(wakeWhenHigh) + halerror = esp_deep_sleep_enable_gpio_wakeup(1<> (checkWeekday)) & 0x01) { + if (dayOffset == 0 && (timerHours[i] < currentHour || + (timerHours[i] == currentHour && + timerMinutes[i] <= currentMinute))) { + continue; + } + + int targetHour = timerHours[i]; + int targetMinute = timerMinutes[i]; + int timeDifference = calculateTimeDifference( + currentHour, currentMinute, targetHour + (dayOffset * 24), + targetMinute); + + if (timeDifference < minDifference) { + minDifference = timeDifference; + } + } + } + } + return minDifference; + } + public: inline void enable(bool enable) { enabled = enable; } // Enable/Disable the usermod @@ -71,6 +266,10 @@ class DeepSleepUsermod : public Usermod { void setup() { //TODO: if the de-init of RTC pins is required to do it could be done here //rtc_gpio_deinit(wakeupPin); + DEBUG_PRINTF("boot type: %s\n", phase_wakeup_reason()); + int confGpioPins[] = {DEEPSLEEP_CONFIGPINS}; + configureGpios(confGpioPins, sizeof(confGpioPins) / sizeof(confGpioPins[0]), + true); initDone = true; } @@ -102,51 +301,21 @@ class DeepSleepUsermod : public Usermod { return; } - DEBUG_PRINTLN(F("DeepSleep UM: entering deep sleep...")); powerup = false; // turn leds on in all subsequent bootups (overrides Turn LEDs on after power up/reset' at reboot) if(!pin_is_valid(wakeupPin)) return; - esp_err_t halerror = ESP_OK; pinMode(wakeupPin, INPUT); // make sure GPIO is input with pullup/pulldown disabled esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); //disable all wake-up sources (just in case) - if(wakeupAfter) - esp_sleep_enable_timer_wakeup((uint64_t)wakeupAfter * (uint64_t)1e6); //sleep for x seconds - - #if defined(CONFIG_IDF_TARGET_ESP32C3) // ESP32 C3 - if(noPull) - gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_FLOATING); - else { // enable pullup/pulldown resistor - if(wakeWhenHigh) - gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLDOWN_ONLY); - else - gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLUP_ONLY); - } - if(wakeWhenHigh) - halerror = esp_deep_sleep_enable_gpio_wakeup(1<(0 = never)');")); + oappend(SET_F("addInfo('DeepSleep:presetWake',1,'(wake up before next preset timer)');")); + oappend(SET_F("addInfo('DeepSleep:voltageCheckInterval',1,'seconds');")); oappend(SET_F("addInfo('DeepSleep:delaySleep',1,'seconds (0 = sleep at powerup)');")); // first string is suffix, second string is prefix } diff --git a/usermods/sleep_manager/README.md b/usermods/sleep_manager/README.md deleted file mode 100644 index 3018273054..0000000000 --- a/usermods/sleep_manager/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Sleep Manager Module for WLED - -## Overview - -The **SleepManager** module for WLED is designed to manage power consumption by enabling the ESP32 to enter deep sleep based on idle time or battery voltage levels. This module allows for more efficient battery use by automatically putting the device to sleep and waking it up based on predefined conditions. It is especially useful for battery-powered setups where minimizing power consumption is essential. - -## Features - -- **Idle-based Sleep**: Automatically puts the device to sleep after a specified period of inactivity. -- **Battery Voltage Monitoring**: Monitors the battery voltage and enters deep sleep when the voltage falls below a set threshold. -- **Custom GPIO Configuration**: Allows configuration of GPIO pins for controlling power actions (e.g., pull-up or pull-down). -- **Touchpad Wakeup**: Supports waking up the device using a touch sensor (configurable via `WAKEUP_TOUCH_PIN`). -- **Voltage Protection**: Prevents deep sleep if the voltage is too low, protecting the device from shutting down unintentionally. -- **Preset Wakeup**: Optionally allows setting a timer to wake the device up after a set period. - -## Configuration - -To configure the **SleepManager** module, you will need to add and adjust the following settings in your WLED setup: - -### Define GPIO Pins (`CONFIGPINS`) - -You can specify a set of GPIO pins for controlling the sleep behavior. The syntax for defining this configuration is: - -```cpp -// GPIO NUM,start pull up(1)down(0),end pull up(1)down(0)dis(-1)... -#define CONFIGPINS 0,1,1, 25,0,1, 26,1,0 -``` - - -Example `plantformio.ini`: - -``` -[env:esp32dev_debug] -extends = esp32_idf_V4 -board = esp32dev -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32_V4} - -D USERMOD_SLEEP - ; GPIO NUM,start pull up(1)down(0),end pull up(1)down(0)dis(-1)... - -D CONFIGPINS="25, 0, 1, 26, 0, 1, 27, 1, 0, 0, -1, 1, 4, -1, 0" -``` \ No newline at end of file diff --git a/usermods/sleep_manager/sleep_manager.h b/usermods/sleep_manager/sleep_manager.h deleted file mode 100644 index c04e8ab569..0000000000 --- a/usermods/sleep_manager/sleep_manager.h +++ /dev/null @@ -1,363 +0,0 @@ -#ifndef SLEEP_MANAGER_H -#define SLEEP_MANAGER_H - -#include "wled.h" -#include "esp_pm.h" -#include "esp_system.h" -#include -#include -#ifndef WAKEUP_TOUCH_PIN -#ifdef CONFIG_IDF_TARGET_ESP32S3 // ESP32S3 -#define WAKEUP_TOUCH_PIN 5 -#else -#define WAKEUP_TOUCH_PIN 15 -#endif -#endif // WAKEUP_TOUCH_PIN -#ifndef CONFIGPINS -#define CONFIGPINS 0, 1, 1 // GPIO NUM,start pull up(1)down(0),end pull up(1)down(0)dis(-1)... -#endif -class SleepManager : public Usermod -{ -private: - boolean enableSleep = false; - boolean sleepOnIdle = false; - int voltagePin = 34; - unsigned long voltageCheckInterval = 5; - unsigned long lastVoltageCheckTime = 0; - float voltage; - unsigned long lastLedOffTime = -1; - unsigned long idleWaitSeconds = 60; - bool isTestingBattery = false; - bool sleepNextLoop = false; - float minVoltage = 3.0; - float maxVoltage = 4.2; - float voltageDivRatio = 2.0; - float currentVoltage = 0.0; - bool presetWakeup = true; - -public: - virtual void setup() - { - phase_wakeup_reason(); - int confGpioPins[] = {CONFIGPINS}; - configureGpios(confGpioPins, sizeof(confGpioPins) / sizeof(confGpioPins[0]), true); - } - - virtual void loop() - { - if (!enableSleep) - { - return; - } - unsigned long currentMillis = millis(); - - if (currentMillis - lastVoltageCheckTime >= voltageCheckInterval * 1000) - { - lastVoltageCheckTime = currentMillis; - if (sleepNextLoop) - { - startDeepSeelp(true); - } - - if (sleepOnIdle && lastLedOffTime != -1 && currentMillis - lastLedOffTime > idleWaitSeconds * 1000) - { - DEBUG_PRINTLN("sleep on idle..."); - startDeepSeelp(false); - } - - float voltage = readVoltage() * voltageDivRatio; - DEBUG_PRINTF("Current voltage on IO%d: %.3f\n", voltagePin, voltage); - if (isTestingBattery) - { - minVoltage = voltage; - serializeConfig(); - } - - if (voltage < minVoltage) - { - if (voltage != 0) - { - DEBUG_PRINTLN("Voltage is below threshold. Entering deep sleep..."); - startDeepSeelp(false); - } - } - } - } - - virtual void onStateChange(uint8_t mode) - { - DEBUG_PRINTF("current bri value: %d,effect: %d\n", bri, effectCurrent); - if (bri == 0) - { - lastLedOffTime = millis(); - } - else - { - lastLedOffTime = -1; - } - } - - void startDeepSeelp(bool immediate) - { - if (immediate) - { - DEBUG_PRINTLN("Entering deep sleep..."); - if (presetWakeup) - { - int nextWakeupMin = findNextTimerInterval() - 1; - if (nextWakeupMin > 0) - { - esp_sleep_enable_timer_wakeup(nextWakeupMin * 60ULL * 1000000ULL); // wakeup for preset - DEBUG_PRINTF("wakeup after %d minites", nextWakeupMin); - DEBUG_PRINTLN(""); - } - } - int confGpioPins[] = {CONFIGPINS}; - configureGpios(confGpioPins, sizeof(confGpioPins) / sizeof(confGpioPins[0]), true); - WiFi.disconnect(); - WiFi.mode(WIFI_OFF); - touchSleepWakeUpEnable(WAKEUP_TOUCH_PIN, touchThreshold); - // ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(GPIO_NUM_26, 0)); // Conflicting wake-up triggers: touch ext0 - ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(1ULL << GPIO_NUM_0, ESP_EXT1_WAKEUP_ALL_LOW)); - delay(2000); // wati gpio level and wifi module restore ... -#ifndef ARDUINO_ARCH_ESP32C3 -#endif - esp_deep_sleep_start(); - } - else - { - sleepNextLoop = true; - briLast = bri; - bri = 0; - stateUpdated(CALL_MODE_DIRECT_CHANGE); - } - } - - void configureGpios(int gpioPins[], int size, bool start) - { - for (int i = 0; i < size; i += 3) - { - int gpioPin = gpioPins[i]; - int startFlag = gpioPins[i + 1]; - int endFlag = gpioPins[i + 2]; - - if (start) - { - if (startFlag == 1) - { - pull_up_down(gpioPin, true, false); - } - else if (startFlag == 0) - { - pull_up_down(gpioPin, false, true); - } - else - { - pull_up_down(gpioPin, false, false); - } - } - else - { - if (endFlag == 1) - { - pull_up_down(gpioPin, true, false); - } - else if (endFlag == 0) - { - pull_up_down(gpioPin, false, true); - } - else - { - pull_up_down(gpioPin, false, false); - } - } - } - } - - void pull_up_down(int gpioPin, bool up, bool down) - { - gpio_pullup_dis((gpio_num_t)gpioPin); - gpio_pulldown_dis((gpio_num_t)gpioPin); - if (up) - { - ESP_ERROR_CHECK(gpio_pullup_en((gpio_num_t)gpioPin)); - } - if (down) - { - ESP_ERROR_CHECK(gpio_pulldown_en((gpio_num_t)gpioPin)); - } - } - - float readVoltage() - { - int adcValue = analogRead(voltagePin); - float voltageOut = (adcValue / float(4095)) * 3.3; - return voltageOut; - } - - // add wakeup reson,battery info - void addToJsonInfo(JsonObject &root) - { - JsonObject user = root["u"]; - if (user.isNull()) - user = root.createNestedObject("u"); - - currentVoltage = readVoltage(); - - float batteryPercentage = calculateBatteryPercentage(currentVoltage * voltageDivRatio); - - JsonArray percentage = user.createNestedArray(F("Battery Percentage")); - JsonArray voltage = user.createNestedArray(F("Current Voltage")); - JsonArray boot = user.createNestedArray(F("boot type")); - percentage.add(batteryPercentage); - percentage.add(F(" %")); - voltage.add(round(currentVoltage * voltageDivRatio * 100.0) / 100.0); - voltage.add(F(" V")); - boot.add(F(phase_wakeup_reason())); - } - - // 在配置中添加电压相关配置 - void addToConfig(JsonObject &root) - { - DEBUG_PRINTLN("sleep module addToConfig"); - JsonObject top = root.createNestedObject("Sleep Module"); - - top["enable Sleep"] = enableSleep; - top["voltage Check Interval"] = voltageCheckInterval; - top["voltage Pin"] = voltagePin; - top["Min Voltage"] = minVoltage; - top["Max Voltage"] = maxVoltage; - top["Voltage Div Ratio"] = voltageDivRatio; - top["sleep On Idle"] = sleepOnIdle; - top["idle Wait Seconds"] = idleWaitSeconds; - top["battery Test Enabled"] = false; - top["preset Wakeup"] = presetWakeup; - } - - bool readFromConfig(JsonObject &root) - { - DEBUG_PRINTLN("sleep module readFromConfig"); - JsonObject top = root["Sleep Module"]; - bool configComplete = !top.isNull(); - - configComplete &= getJsonValue(top["enable Sleep"], enableSleep); - configComplete &= getJsonValue(top["voltage Check Interval"], voltageCheckInterval); - configComplete &= getJsonValue(top["voltage Pin"], voltagePin); - configComplete &= getJsonValue(top["Min Voltage"], minVoltage); - configComplete &= getJsonValue(top["Max Voltage"], maxVoltage); - configComplete &= getJsonValue(top["Voltage Div Ratio"], voltageDivRatio); - configComplete &= getJsonValue(top["sleep On Idle"], sleepOnIdle); - configComplete &= getJsonValue(top["idle Wait Seconds"], idleWaitSeconds); - configComplete &= getJsonValue(top["battery Test Enabled"], isTestingBattery); - configComplete &= getJsonValue(top["preset Wakeup"], presetWakeup); - - return configComplete; - } - - int calculateBatteryPercentage(float voltage) - { - int percent = (voltage - minVoltage) / (maxVoltage - minVoltage) * 100.0; - if (percent < 0) - { - percent = 0; - } - if (percent > 100) - { - percent = 100; - } - return percent; - } - - int calculateTimeDifference(int hour1, int minute1, int hour2, int minute2) - { - int totalMinutes1 = hour1 * 60 + minute1; - int totalMinutes2 = hour2 * 60 + minute2; - if (totalMinutes2 < totalMinutes1) - { - totalMinutes2 += 24 * 60; - } - return totalMinutes2 - totalMinutes1; - } - - int findNextTimerInterval() - { - int currentHour = hour(localTime), currentMinute = minute(localTime), currentWeekday = weekdayMondayFirst(); - int minDifference = INT_MAX; - - for (uint8_t i = 0; i < 8; i++) - { - if (!(timerMacro[i] != 0 && (timerWeekday[i] & 0x01))) - { - continue; - } - - for (int dayOffset = 0; dayOffset < 7; dayOffset++) - { - int checkWeekday = ((currentWeekday + dayOffset) % 7); // 1-7 - if (checkWeekday == 0) - { - checkWeekday = 7; - } - - if ((timerWeekday[i] >> (checkWeekday)) & 0x01) - { - if (dayOffset == 0 && - (timerHours[i] < currentHour || - (timerHours[i] == currentHour && timerMinutes[i] <= currentMinute))) - { - continue; - } - - int targetHour = timerHours[i]; - int targetMinute = timerMinutes[i]; - int timeDifference = calculateTimeDifference( - currentHour, currentMinute, - targetHour + (dayOffset * 24), targetMinute); - - if (timeDifference < minDifference) - { - minDifference = timeDifference; - } - } - } - } - return minDifference; - } - const char *phase_wakeup_reason() - { - static char reson[20]; - esp_sleep_wakeup_cause_t wakeup_reason; - - wakeup_reason = esp_sleep_get_wakeup_cause(); - - switch (wakeup_reason) - { - case ESP_SLEEP_WAKEUP_EXT0: - DEBUG_PRINTLN("Wakeup caused by external signal using RTC_IO"); - strcpy(reson, "RTC_IO"); - break; - case ESP_SLEEP_WAKEUP_EXT1: - DEBUG_PRINTLN("Wakeup caused by external signal using RTC_CNTL"); - strcpy(reson, "RTC_CNTL"); - break; - case ESP_SLEEP_WAKEUP_TIMER: - DEBUG_PRINTLN("Wakeup caused by timer"); - strcpy(reson, "timer"); - break; - case ESP_SLEEP_WAKEUP_TOUCHPAD: - DEBUG_PRINTLN("Wakeup caused by touchpad"); - strcpy(reson, "touchpad"); - break; - case ESP_SLEEP_WAKEUP_ULP: - DEBUG_PRINTLN("Wakeup caused by ULP program"); - strcpy(reson, "ULP"); - break; - default: - DEBUG_PRINTF("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); - snprintf(reson, sizeof(reson), "other %d", wakeup_reason); - break; - } - return reson; - } -}; -#endif diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index 73a4a36564..c129de4e76 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -66,7 +66,8 @@ enum struct PinOwner : uint8_t { UM_LDR_DUSK_DAWN = USERMOD_ID_LDR_DUSK_DAWN, // 0x2B // Usermod "usermod_LDR_Dusk_Dawn_v2.h" UM_MAX17048 = USERMOD_ID_MAX17048, // 0x2F // Usermod "usermod_max17048.h" UM_BME68X = USERMOD_ID_BME68X, // 0x31 // Usermod "usermod_bme68x.h -- Uses "standard" HW_I2C pins - UM_PIXELS_DICE_TRAY = USERMOD_ID_PIXELS_DICE_TRAY // 0x35 // Usermod "pixels_dice_tray.h" -- Needs compile time specified 6 pins for display including SPI. + UM_PIXELS_DICE_TRAY = USERMOD_ID_PIXELS_DICE_TRAY, // 0x36 // Usermod "pixels_dice_tray.h" -- Needs compile time specified 6 pins for display including SPI. + UM_DEEP_SLEEP = USERMOD_ID_DEEP_SLEEP // 0x37 // Usermod "usermod_deep_sleep.h" -- Needs pins to control pmos, nmos, other devices }; static_assert(0u == static_cast(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected"); diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index ce64cd5eab..6c03617aed 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -242,11 +242,6 @@ #include "../usermods/LD2410_v2/usermod_ld2410.h" #endif -#ifdef USERMOD_SLEEP -#include "../usermods/sleep_manager/sleep_manager.h" -#endif - - #ifdef USERMOD_DEEP_SLEEP #include "../usermods/deep_sleep/usermod_deep_sleep.h" #endif From 994c7e18088656ee6f33120bd057b7b4c1aa3f6f Mon Sep 17 00:00:00 2001 From: alan Date: Sun, 12 Jan 2025 11:52:38 +0800 Subject: [PATCH 3/7] remove gpio configuretion; add touch pin option --- usermods/deep_sleep/readme.md | 19 +-- usermods/deep_sleep/usermod_deep_sleep.h | 168 ++++++++++------------- wled00/usermods_list.cpp | 1 + 3 files changed, 72 insertions(+), 116 deletions(-) diff --git a/usermods/deep_sleep/readme.md b/usermods/deep_sleep/readme.md index a34fca5338..264f5f584f 100644 --- a/usermods/deep_sleep/readme.md +++ b/usermods/deep_sleep/readme.md @@ -1,15 +1,7 @@ # Deep Sleep usermod This usermod unleashes the low power capabilities of th ESP: when you power off your LEDs (using the UI power button or a macro) the ESP will be put into deep sleep mode, reducing power consumption to a minimum. -During deep sleep the ESP is shut down completely: no WiFi, no CPU, no outputs. The only way to wake it up is to use an external signal or a button. Once it wakes from deep sleep it reboots so ***make sure to use a boot-up preset.*** - -## Features - -- **Idle-based Sleep**: Automatically puts the device to sleep after a specified period of inactivity. -- **Custom GPIO Configuration**: Allows configuration of GPIO pins for controlling power actions (e.g., pull-up or pull-down). -- **Touchpad Wakeup**: Supports waking up the device using a touch sensor. -- **RTC IO Wakeup**: Supports waking up the device using RTC IO. -- **Preset Wakeup**: Optionally allows setting a timer to wake the device up after a set period. +During deep sleep the ESP is shut down completely: no WiFi, no CPU, no outputs. The only way to wake it up is by using an external signal, a button, or an automation timer set to the nearest preset time. Once it wakes from deep sleep it reboots so ***make sure to use a boot-up preset.*** # A word of warning @@ -69,14 +61,7 @@ To override the default settings, place the `#define` in wled.h or add `-D DEEPS * `DEEPSLEEP_DISABLEPULL` - if defined, internal pullup/pulldown is disabled in deep sleep (default is ebnabled) * `DEEPSLEEP_WAKEUPINTERVAL` - number of seconds after which a wake-up happens automatically, sooner if button is pressed. 0 = never. accuracy is about 2% * `DEEPSLEEP_DELAY` - delay between power-off and sleep -* `DEEPSLEEP_WAKEUP_TOUCH_PIN` - specify GPIO pin used for touch-based wakeup; 5 for ESP32S3, 15 for other models -* `DEEPSLEEP_CONFIGPINS` - configure GPIO pins: NUM=start pull-up (1)/down (0), end pull-up (1)/down (0)/disable (-1),example "4,1,0" - pull io4 up at setup,down before deepsleep -* `DEEPSLEEP_WHEN_LOW_VOLTAGE` - if true, enters deep sleep when low voltage is detected -* `DEEPSLEEP_VOTAGE_PIN` - specify GPIO pin used for voltage monitoring (e.g., pin 34) -* `DEEPSLEEP_MIN_VOTAGE` - minimum voltage threshold to trigger deep sleep (in volts) -* `DEEPSLEEP_VOTAGE_DIV_RATIO` - voltage divider ratio used to monitor voltage on the defined pin -* `DEEPSLEEP_WAKEWHENHIGH` - wake up when the pin goes high (default is when the pin goes low) - +* `DEEPSLEEP_WAKEUP_TOUCH_PIN` - specify GPIO pin used for touch-based wakeup example for env build flags: `-D USERMOD_DEEP_SLEEP` diff --git a/usermods/deep_sleep/usermod_deep_sleep.h b/usermods/deep_sleep/usermod_deep_sleep.h index fd4854c034..8fabbfdc58 100644 --- a/usermods/deep_sleep/usermod_deep_sleep.h +++ b/usermods/deep_sleep/usermod_deep_sleep.h @@ -2,6 +2,7 @@ #include "wled.h" #include "driver/rtc_io.h" +#include "soc/touch_sensor_periph.h" #ifdef ESP8266 #error The "Deep Sleep" usermod does not support ESP8266 @@ -22,6 +23,7 @@ #ifndef DEEPSLEEP_DELAY #define DEEPSLEEP_DELAY 1 #endif + #ifndef DEEPSLEEP_WAKEUP_TOUCH_PIN #ifdef CONFIG_IDF_TARGET_ESP32S3 // ESP32S3 #define DEEPSLEEP_WAKEUP_TOUCH_PIN 5 @@ -29,9 +31,6 @@ #define DEEPSLEEP_WAKEUP_TOUCH_PIN 15 #endif #endif // DEEPSLEEP_WAKEUP_TOUCH_PIN -#ifndef DEEPSLEEP_CONFIGPINS -#define DEEPSLEEP_CONFIGPINS 0, 1, 1 // GPIO NUM,start pull up(1)down(0),end pull up(1)down(0)dis(-1)... -#endif RTC_DATA_ATTR bool powerup = true; // variable in RTC data persists on a reboot class DeepSleepUsermod : public Usermod { @@ -106,102 +105,21 @@ class DeepSleepUsermod : public Usermod { return reson; } - void pull_up_down(int gpioPin, bool up, bool down) { - rtc_gpio_pullup_dis((gpio_num_t)gpioPin); - rtc_gpio_pulldown_dis((gpio_num_t)gpioPin); - if (up) { - ESP_ERROR_CHECK(rtc_gpio_pullup_en((gpio_num_t)gpioPin)); - } - if (down) { - ESP_ERROR_CHECK(rtc_gpio_pulldown_en((gpio_num_t)gpioPin)); - } - } - - void configureGpios(int gpioPins[], int size, bool start) { - for (int i = 2; i < size; i += 3) { - int gpioPin = gpioPins[i - 2]; - int flag = start? gpioPins[i - 1]: gpioPins[i]; - - if (start && flag != -1 && !PinManager::allocatePin(gpioPin, false, PinOwner::UM_DEEP_SLEEP)) { - DEBUG_PRINTF("failed to allocate GPIO for usermod deep sleep: %d\n", gpioPin); - continue; - } - - if (flag == 1) - pull_up_down(gpioPin, true, false); - else if (flag == 0) - pull_up_down(gpioPin, false, true); - } - } - void startDeepSeelp(bool immediate) { - esp_err_t halerror = ESP_OK; - int nextWakeupMin = 0; if (immediate) { - DEBUG_PRINTLN("DeepSleep UM: Entering deep sleep..."); - if (presetWake) { - nextWakeupMin = findNextTimerInterval() - 1; // wakeup before next preset - } - if (wakeupAfter > 0) { - nextWakeupMin = nextWakeupMin < wakeupAfter / 60.0 - ? nextWakeupMin - : wakeupAfter / 60.0; - } - if (nextWakeupMin > 0) { - esp_sleep_enable_timer_wakeup(nextWakeupMin * 60ULL * - (uint64_t)1e6); // wakeup for preset - DEBUG_PRINTF("wakeup after %d minites", nextWakeupMin); - DEBUG_PRINTLN(""); - } + esp_err_t halerror = ESP_OK; WiFi.disconnect(); - WiFi.mode(WIFI_OFF); - int confGpioPins[] = {DEEPSLEEP_CONFIGPINS}; - configureGpios(confGpioPins, - sizeof(confGpioPins) / sizeof(confGpioPins[0]), false); + WiFi.mode(WIFI_OFF); // Completely shut down the Wi-Fi module if (enableTouchWakeup) { touchSleepWakeUpEnable(touchPin, touchThreshold); } - #if defined(CONFIG_IDF_TARGET_ESP32C3) // ESP32 C3 - if(noPull) - gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_FLOATING); - else { // enable pullup/pulldown resistor - if(wakeWhenHigh) - gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLDOWN_ONLY); - else - gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLUP_ONLY); - } - if(wakeWhenHigh) - halerror = esp_deep_sleep_enable_gpio_wakeup(1< 0) { + esp_sleep_enable_timer_wakeup(nextWakeupMin * 60ULL * + (uint64_t)1e6); + DEBUG_PRINTF("wakeup after %d minites", nextWakeupMin); + DEBUG_PRINTLN(""); + } + + #if defined(CONFIG_IDF_TARGET_ESP32C3) // ESP32 C3 + if(noPull) + gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_FLOATING); + else { // enable pullup/pulldown resistor + if(wakeWhenHigh) + gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLDOWN_ONLY); + else + gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLUP_ONLY); + } + if(wakeWhenHigh) + halerror = esp_deep_sleep_enable_gpio_wakeup(1< Date: Mon, 13 Jan 2025 11:29:18 +0800 Subject: [PATCH 4/7] config for esp32 c3 --- usermods/deep_sleep/usermod_deep_sleep.h | 49 ++++++++++++++++-------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/usermods/deep_sleep/usermod_deep_sleep.h b/usermods/deep_sleep/usermod_deep_sleep.h index 8fabbfdc58..63051ae8c7 100644 --- a/usermods/deep_sleep/usermod_deep_sleep.h +++ b/usermods/deep_sleep/usermod_deep_sleep.h @@ -2,7 +2,9 @@ #include "wled.h" #include "driver/rtc_io.h" -#include "soc/touch_sensor_periph.h" +#ifndef CONFIG_IDF_TARGET_ESP32C3 + #include "soc/touch_sensor_periph.h" +#endif #ifdef ESP8266 #error The "Deep Sleep" usermod does not support ESP8266 @@ -184,7 +186,9 @@ class DeepSleepUsermod : public Usermod { void setup() { //TODO: if the de-init of RTC pins is required to do it could be done here //rtc_gpio_deinit(wakeupPin); - DEBUG_PRINTF("boot type: %s\n", phase_wakeup_reason()); + #ifdef WLED_DEBUG + DEBUG_PRINTF("boot type: %s\n", phase_wakeup_reason()); + #endif initDone = true; } @@ -280,6 +284,13 @@ class DeepSleepUsermod : public Usermod { //void connected() {} //unused, this is called every time the WiFi is (re)connected + void addToJsonInfo(JsonObject& root) { + JsonObject user = root["u"]; + if (user.isNull()) user = root.createNestedObject("u"); + JsonArray boot = user.createNestedArray(F("boot type")); + boot.add(F(phase_wakeup_reason())); + } + void addToConfig(JsonObject& root) override { JsonObject top = root.createNestedObject(FPSTR(_name)); @@ -288,8 +299,10 @@ void addToConfig(JsonObject& root) override top["gpio"] = wakeupPin; top["wakeWhen"] = wakeWhenHigh; top["pull"] = noPull; - top["enableTouchWakeup"] = enableTouchWakeup; - top["touchPin"] = touchPin; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + top["enableTouchWakeup"] = enableTouchWakeup; + top["touchPin"] = touchPin; + #endif top["presetWake"] = presetWake; top["wakeAfter"] = wakeupAfter; top["delaySleep"] = sleepDelay; @@ -310,8 +323,10 @@ void addToConfig(JsonObject& root) override } configComplete &= getJsonValue(top["wakeWhen"], wakeWhenHigh, DEEPSLEEP_WAKEWHENHIGH); // default to wake on low configComplete &= getJsonValue(top["pull"], noPull, DEEPSLEEP_DISABLEPULL); // default to no pullup/pulldown - configComplete &= getJsonValue(top["enableTouchWakeup"], enableTouchWakeup); - configComplete &= getJsonValue(top["touchPin"], touchPin, DEEPSLEEP_WAKEUP_TOUCH_PIN); + #ifndef CONFIG_IDF_TARGET_ESP32C3 + configComplete &= getJsonValue(top["enableTouchWakeup"], enableTouchWakeup); + configComplete &= getJsonValue(top["touchPin"], touchPin, DEEPSLEEP_WAKEUP_TOUCH_PIN); + #endif configComplete &= getJsonValue(top["presetWake"], presetWake); configComplete &= getJsonValue(top["wakeAfter"], wakeupAfter, DEEPSLEEP_WAKEUPINTERVAL); configComplete &= getJsonValue(top["delaySleep"], sleepDelay, DEEPSLEEP_DELAY); @@ -337,16 +352,18 @@ void addToConfig(JsonObject& root) override oappend(SET_F(");")); } } - // dropdown for touch wakeupPin - touch_sensor_channel_io_map[SOC_TOUCH_SENSOR_NUM]; - oappend(SET_F("dd=addDropdown('DeepSleep','touchPin');")); - for (int pin = 0; pin < SOC_TOUCH_SENSOR_NUM; pin++) { - oappend(SET_F("addOption(dd,'")); - oappend(String(touch_sensor_channel_io_map[pin]).c_str()); - oappend(SET_F("',")); - oappend(String(touch_sensor_channel_io_map[pin]).c_str()); - oappend(SET_F(");")); - } + #ifndef CONFIG_IDF_TARGET_ESP32C3 + // dropdown for touch wakeupPin + touch_sensor_channel_io_map[SOC_TOUCH_SENSOR_NUM]; + oappend(SET_F("dd=addDropdown('DeepSleep','touchPin');")); + for (int pin = 0; pin < SOC_TOUCH_SENSOR_NUM; pin++) { + oappend(SET_F("addOption(dd,'")); + oappend(String(touch_sensor_channel_io_map[pin]).c_str()); + oappend(SET_F("',")); + oappend(String(touch_sensor_channel_io_map[pin]).c_str()); + oappend(SET_F(");")); + } + #endif oappend(SET_F("dd=addDropdown('DeepSleep','wakeWhen');")); oappend(SET_F("addOption(dd,'Low',0);")); From 464abadf1fbf0ba2cfbbb79ec66fb394c0137890 Mon Sep 17 00:00:00 2001 From: alan Date: Mon, 13 Jan 2025 15:47:41 +0800 Subject: [PATCH 5/7] remove wakeup reason from ui --- usermods/deep_sleep/usermod_deep_sleep.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/usermods/deep_sleep/usermod_deep_sleep.h b/usermods/deep_sleep/usermod_deep_sleep.h index 63051ae8c7..a158bf1e1b 100644 --- a/usermods/deep_sleep/usermod_deep_sleep.h +++ b/usermods/deep_sleep/usermod_deep_sleep.h @@ -284,13 +284,6 @@ class DeepSleepUsermod : public Usermod { //void connected() {} //unused, this is called every time the WiFi is (re)connected - void addToJsonInfo(JsonObject& root) { - JsonObject user = root["u"]; - if (user.isNull()) user = root.createNestedObject("u"); - JsonArray boot = user.createNestedArray(F("boot type")); - boot.add(F(phase_wakeup_reason())); - } - void addToConfig(JsonObject& root) override { JsonObject top = root.createNestedObject(FPSTR(_name)); From cc29953113c597f74434a62eeef8f3bbd6efdc8d Mon Sep 17 00:00:00 2001 From: alan Date: Wed, 15 Jan 2025 15:17:59 +0800 Subject: [PATCH 6/7] add #ifdef in debug mode --- usermods/deep_sleep/usermod_deep_sleep.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/usermods/deep_sleep/usermod_deep_sleep.h b/usermods/deep_sleep/usermod_deep_sleep.h index a158bf1e1b..552a377f91 100644 --- a/usermods/deep_sleep/usermod_deep_sleep.h +++ b/usermods/deep_sleep/usermod_deep_sleep.h @@ -77,6 +77,7 @@ class DeepSleepUsermod : public Usermod { return false; } +#ifdef WLED_DEBUG const char* phase_wakeup_reason() { static char reson[20]; esp_sleep_wakeup_cause_t wakeup_reason; @@ -106,6 +107,7 @@ class DeepSleepUsermod : public Usermod { } return reson; } +#endif void startDeepSeelp(bool immediate) { if (immediate) { From 1767bc0897cb72688352e530153a335438ef2dd2 Mon Sep 17 00:00:00 2001 From: alan Date: Wed, 22 Jan 2025 20:30:55 +0800 Subject: [PATCH 7/7] For ESP32-C3 and ESP32-S2 development boards --- usermods/deep_sleep/usermod_deep_sleep.h | 39 ++++++------------------ 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/usermods/deep_sleep/usermod_deep_sleep.h b/usermods/deep_sleep/usermod_deep_sleep.h index 552a377f91..b5ee47b24f 100644 --- a/usermods/deep_sleep/usermod_deep_sleep.h +++ b/usermods/deep_sleep/usermod_deep_sleep.h @@ -27,11 +27,7 @@ #endif #ifndef DEEPSLEEP_WAKEUP_TOUCH_PIN -#ifdef CONFIG_IDF_TARGET_ESP32S3 // ESP32S3 -#define DEEPSLEEP_WAKEUP_TOUCH_PIN 5 -#else -#define DEEPSLEEP_WAKEUP_TOUCH_PIN 15 -#endif +#define DEEPSLEEP_WAKEUP_TOUCH_PIN -1 #endif // DEEPSLEEP_WAKEUP_TOUCH_PIN RTC_DATA_ATTR bool powerup = true; // variable in RTC data persists on a reboot @@ -109,28 +105,6 @@ class DeepSleepUsermod : public Usermod { } #endif - void startDeepSeelp(bool immediate) { - if (immediate) { - esp_err_t halerror = ESP_OK; - WiFi.disconnect(); - WiFi.mode(WIFI_OFF); // Completely shut down the Wi-Fi module - if (enableTouchWakeup) { - touchSleepWakeUpEnable(touchPin, touchThreshold); - } - delay(2000); // wati gpio level and wifi module restore ... - if (halerror == ESP_OK) - esp_deep_sleep_start(); // go into deep sleep - else - DEBUG_PRINTLN(F("sleep failed")); - } else { - // Not to be used for now - sleepNextLoop = true; - briLast = bri; - bri = 0; - stateUpdated(CALL_MODE_DIRECT_CHANGE); - } - } - int calculateTimeDifference(int hour1, int minute1, int hour2, int minute2) { int totalMinutes1 = hour1 * 60 + minute1; @@ -278,9 +252,15 @@ class DeepSleepUsermod : public Usermod { halerror = esp_sleep_enable_ext1_wakeup(1ULL << wakeupPin, ESP_EXT1_WAKEUP_ALL_LOW); #endif - + WiFi.disconnect(); + WiFi.mode(WIFI_OFF); // Completely shut down the Wi-Fi module + #ifndef CONFIG_IDF_TARGET_ESP32C3 + if (enableTouchWakeup && touchPin) { + touchSleepWakeUpEnable(touchPin, touchThreshold); + } + #endif delay(1); // wait for pin to be ready - if(halerror == ESP_OK) startDeepSeelp(true); // go into deep sleep + if(halerror == ESP_OK) esp_deep_sleep_start(); // go into deep sleep else DEBUG_PRINTLN(F("sleep failed")); } @@ -351,6 +331,7 @@ void addToConfig(JsonObject& root) override // dropdown for touch wakeupPin touch_sensor_channel_io_map[SOC_TOUCH_SENSOR_NUM]; oappend(SET_F("dd=addDropdown('DeepSleep','touchPin');")); + oappend(SET_F("addOption(dd,'Unused',-1);")); for (int pin = 0; pin < SOC_TOUCH_SENSOR_NUM; pin++) { oappend(SET_F("addOption(dd,'")); oappend(String(touch_sensor_channel_io_map[pin]).c_str());