From b5026a5071573fef0aaf0af2d8d58b7f7de6210c Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sat, 21 Mar 2026 00:27:43 +0100 Subject: [PATCH 01/19] =?UTF-8?q?[GPIO][P001]=20Added=20=E2=80=9CWake=20on?= =?UTF-8?q?=20Button=20Press=E2=80=9D=20functionality.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I tried to integrate the feature, though I am not sure if the structure is fine with you since I more or less guestimated some things, but I am happy to receive your suggestions. It also would help to do more testing on e.g. ESP32-S2,ESP32-C3,... - Add a checkbox in the switch plugin if the selected GPIO can wake the device from deep sleep. - tested on ESP32-S3 and ESP32-C6 --- src/_P001_Switch.ino | 92 ++++++++++++++++++++++ src/src/Helpers/_Plugin_Helper_GPIO.cpp | 4 +- src/src/Helpers/_Plugin_Helper_GPIO.h | 4 +- src/src/PluginStructs/P001_data_struct.cpp | 3 +- src/src/PluginStructs/P001_data_struct.h | 1 + 5 files changed, 101 insertions(+), 3 deletions(-) diff --git a/src/_P001_Switch.ino b/src/_P001_Switch.ino index 0780d4850b..281e5bcb34 100644 --- a/src/_P001_Switch.ino +++ b/src/_P001_Switch.ino @@ -11,6 +11,19 @@ # include "src/PluginStructs/P001_data_struct.h" +# ifdef ESP32 +# include "esp_sleep.h" +# if defined(CONFIG_IDF_TARGET_ESP32) || \ + defined(CONFIG_IDF_TARGET_ESP32S2) || \ + defined(CONFIG_IDF_TARGET_ESP32S3) +# include "driver/rtc_io.h" +# endif // if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) +void setupGpioWakeup(uint8_t pin, + bool wakeOnLow = true); // if ever needed we can also add support for wakeOnHigh, but for now + // when using a switch/button, the wakeup will be triggered by the pin going low (active + // low) +# endif // ifdef ESP32 + // ####################################################################################################### // #################################### Plugin 001: Input Switch ######################################### // ####################################################################################################### @@ -125,6 +138,14 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) P001_LP_MIN_INT, P001_SAFE_BTN); + # ifdef ESP32 + + if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)CONFIG_PIN1)) { + addFormCheckBox(F("Wake from sleep"), F("sw_wake"), P001_WAKE_BTN); + addFormNote(F("Make sure to enable the internal pull-up resistor or add an external pull-up resistor!")); + } +# endif // ifdef ESP32 + # if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS if (switchtype != PLUGIN_001_TYPE_DIMMER) { @@ -160,6 +181,13 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) P001_LP_MIN_INT, P001_SAFE_BTN); + # ifdef ESP32 + + if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)CONFIG_PIN1)) { + P001_WAKE_BTN = isFormItemChecked(F("sw_wake")); + } + # endif // ifdef ESP32 + # if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS P001_MQTT_DEVICECLASS = getFormItemInt(F("devcls")); # endif // if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS @@ -190,10 +218,34 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { + // apply INIT only if PORT is in range. Do not start INIT if port not set in the device page. if (validGpio(CONFIG_PIN1)) { success = initPluginTaskData(event->TaskIndex, new (std::nothrow) P001_data_struct(event)); + + # ifdef ESP32 + + // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/system/sleep_modes.html#external-wakeup-ext0 + # if defined(CONFIG_IDF_TARGET_ESP32) || \ + defined(CONFIG_IDF_TARGET_ESP32S2) || \ + defined(CONFIG_IDF_TARGET_ESP32S3) + + // this would need adaption if we ever want to support wakeOnHigh as well + // if (wakeOnLow) { + rtc_gpio_pullup_dis((gpio_num_t)CONFIG_PIN1); + + // } else { + // rtc_gpio_pulldown_dis(gpio); + // } + rtc_gpio_deinit((gpio_num_t)CONFIG_PIN1); + # endif // if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) + + if (P001_WAKE_BTN) { + setupGpioWakeup(CONFIG_PIN1, true); + } + # endif // ifdef ESP32 + } break; } @@ -248,4 +300,44 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) return success; } +# ifdef ESP32 + +void setupGpioWakeup(uint8_t pin, bool wakeOnLow) { + gpio_num_t gpio = static_cast(pin); + + pinMode(pin, wakeOnLow ? INPUT_PULLUP : INPUT_PULLDOWN); + + if (esp_sleep_is_valid_wakeup_gpio(gpio)) { + # if defined(CONFIG_IDF_TARGET_ESP32) || \ + defined(CONFIG_IDF_TARGET_ESP32S2) || \ + defined(CONFIG_IDF_TARGET_ESP32S3) + + // Configure RTC pull resistors + if (wakeOnLow) { + rtc_gpio_pullup_en(gpio); + } else { + rtc_gpio_pulldown_en(gpio); + } + + esp_sleep_enable_ext0_wakeup(gpio, wakeOnLow ? 0 : 1); + + # elif defined(CONFIG_IDF_TARGET_ESP32C2) || \ + defined(CONFIG_IDF_TARGET_ESP32C3) || \ + defined(CONFIG_IDF_TARGET_ESP32C6) + + uint64_t mask = 1ULL << gpio; + + esp_deep_sleep_enable_gpio_wakeup( + mask, + wakeOnLow ? ESP_GPIO_WAKEUP_GPIO_LOW : ESP_GPIO_WAKEUP_GPIO_HIGH + ); + + # else // if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) + # warning "Unknown ESP32 target — GPIO wakeup not configured" + # endif // if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) + } +} + +# endif // ifdef ESP32 + #endif // USES_P001 diff --git a/src/src/Helpers/_Plugin_Helper_GPIO.cpp b/src/src/Helpers/_Plugin_Helper_GPIO.cpp index 2093b1903f..b187913b91 100644 --- a/src/src/Helpers/_Plugin_Helper_GPIO.cpp +++ b/src/src/Helpers/_Plugin_Helper_GPIO.cpp @@ -18,7 +18,8 @@ GPIO_plugin_helper_data_t::GPIO_plugin_helper_data_t( bool safeButton, bool sendBootState, uint8_t switchType, - uint8_t dimmerValue) : + uint8_t dimmerValue, + bool wakeButton) : _portStatus_key(createKey(pluginNumber, pin)), _debounceInterval_ms(debounceInterval_ms), _doubleClickMaxInterval_ms(doubleClickMaxInterval_ms), @@ -32,6 +33,7 @@ GPIO_plugin_helper_data_t::GPIO_plugin_helper_data_t( _switchType(switchType), _dimmerValue(dimmerValue), _safeButton(safeButton), + _wakeButton(false), _sendBootState(sendBootState), _longpressFired(false) { diff --git a/src/src/Helpers/_Plugin_Helper_GPIO.h b/src/src/Helpers/_Plugin_Helper_GPIO.h index a9ecec864d..6a983d599b 100644 --- a/src/src/Helpers/_Plugin_Helper_GPIO.h +++ b/src/src/Helpers/_Plugin_Helper_GPIO.h @@ -32,7 +32,8 @@ struct GPIO_plugin_helper_data_t { bool safeButton, bool sendBootState, uint8_t switchType = SWITCH_TYPE_NORMAL_SWITCH, - uint8_t dimmerValue = 0); + uint8_t dimmerValue = 0, + bool wakeButton = false); ~GPIO_plugin_helper_data_t(); @@ -66,6 +67,7 @@ struct GPIO_plugin_helper_data_t { const uint8_t _dimmerValue; const bool _safeButton; const bool _sendBootState; + const bool _wakeButton; bool _longpressFired; }; diff --git a/src/src/PluginStructs/P001_data_struct.cpp b/src/src/PluginStructs/P001_data_struct.cpp index 13acef231c..f2b6734315 100644 --- a/src/src/PluginStructs/P001_data_struct.cpp +++ b/src/src/PluginStructs/P001_data_struct.cpp @@ -32,7 +32,8 @@ P001_data_struct::P001_data_struct(struct EventStruct *event) : P001_SAFE_BTN != 0, P001_BOOTSTATE, (P001_getSwitchType(event) == PLUGIN_001_TYPE_DIMMER) ? SWITCH_TYPE_DIMMER : P001_BUTTON_TYPE, - P001_DIMMER_VALUE) + P001_DIMMER_VALUE, + P001_WAKE_BTN) { uint8_t pinModeValue = PIN_MODE_INPUT; diff --git a/src/src/PluginStructs/P001_data_struct.h b/src/src/PluginStructs/P001_data_struct.h index 2a7ea1542f..217cff7271 100644 --- a/src/src/PluginStructs/P001_data_struct.h +++ b/src/src/PluginStructs/P001_data_struct.h @@ -49,6 +49,7 @@ # define P001_LONGPRESS PCONFIG(5) # define P001_LP_MIN_INT PCONFIG_FLOAT(2) # define P001_SAFE_BTN PCONFIG_FLOAT(3) +# define P001_WAKE_BTN PCONFIG_FLOAT(7) # if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS # define P001_MQTT_DEVICECLASS PCONFIG(6) From b1abf4ac18f807d2cc26b05fa08869ab6c7837f0 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sat, 21 Mar 2026 14:21:26 +0100 Subject: [PATCH 02/19] [P001] Switched to EXT1 for all devices for lowest power consumption --- src/_P001_Switch.ino | 92 +++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/src/_P001_Switch.ino b/src/_P001_Switch.ino index 281e5bcb34..2fc41ecbb5 100644 --- a/src/_P001_Switch.ino +++ b/src/_P001_Switch.ino @@ -13,11 +13,7 @@ # ifdef ESP32 # include "esp_sleep.h" -# if defined(CONFIG_IDF_TARGET_ESP32) || \ - defined(CONFIG_IDF_TARGET_ESP32S2) || \ - defined(CONFIG_IDF_TARGET_ESP32S3) -# include "driver/rtc_io.h" -# endif // if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) +# include "driver/rtc_io.h" void setupGpioWakeup(uint8_t pin, bool wakeOnLow = true); // if ever needed we can also add support for wakeOnHigh, but for now // when using a switch/button, the wakeup will be triggered by the pin going low (active @@ -138,13 +134,16 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) P001_LP_MIN_INT, P001_SAFE_BTN); - # ifdef ESP32 + # ifdef ESP32 if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)CONFIG_PIN1)) { addFormCheckBox(F("Wake from sleep"), F("sw_wake"), P001_WAKE_BTN); - addFormNote(F("Make sure to enable the internal pull-up resistor or add an external pull-up resistor!")); + addFormNote(F("For pins without internal pull-up, add external resistor if unstable.")); } -# endif // ifdef ESP32 + else { + P001_WAKE_BTN = 0; + } + # endif // ifdef ESP32 # if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS @@ -186,6 +185,9 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)CONFIG_PIN1)) { P001_WAKE_BTN = isFormItemChecked(F("sw_wake")); } + else { + P001_WAKE_BTN = 0; + } # endif // ifdef ESP32 # if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS @@ -226,22 +228,15 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) # ifdef ESP32 - // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/system/sleep_modes.html#external-wakeup-ext0 - # if defined(CONFIG_IDF_TARGET_ESP32) || \ - defined(CONFIG_IDF_TARGET_ESP32S2) || \ - defined(CONFIG_IDF_TARGET_ESP32S3) - - // this would need adaption if we ever want to support wakeOnHigh as well - // if (wakeOnLow) { - rtc_gpio_pullup_dis((gpio_num_t)CONFIG_PIN1); + if (P001_WAKE_BTN) { + // this would need adaption if we ever want to support wakeOnHigh as well + // if (wakeOnLow) { + rtc_gpio_pullup_dis((gpio_num_t)CONFIG_PIN1); - // } else { - // rtc_gpio_pulldown_dis(gpio); - // } - rtc_gpio_deinit((gpio_num_t)CONFIG_PIN1); - # endif // if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) + // } else { + // rtc_gpio_pulldown_dis(gpio); + // } - if (P001_WAKE_BTN) { setupGpioWakeup(CONFIG_PIN1, true); } # endif // ifdef ESP32 @@ -305,37 +300,46 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) void setupGpioWakeup(uint8_t pin, bool wakeOnLow) { gpio_num_t gpio = static_cast(pin); + // Configure pin mode (important for stable level during sleep) pinMode(pin, wakeOnLow ? INPUT_PULLUP : INPUT_PULLDOWN); - if (esp_sleep_is_valid_wakeup_gpio(gpio)) { - # if defined(CONFIG_IDF_TARGET_ESP32) || \ - defined(CONFIG_IDF_TARGET_ESP32S2) || \ - defined(CONFIG_IDF_TARGET_ESP32S3) + if (!esp_sleep_is_valid_wakeup_gpio(gpio)) { + return; + } - // Configure RTC pull resistors - if (wakeOnLow) { - rtc_gpio_pullup_en(gpio); - } else { - rtc_gpio_pulldown_en(gpio); - } +# if SOC_PM_SUPPORT_EXT1_WAKEUP - esp_sleep_enable_ext0_wakeup(gpio, wakeOnLow ? 0 : 1); + // ---------------------------- + // UNIVERSAL SOLUTION (ALL ESP32s) + // ---------------------------- + uint64_t mask = 1ULL << gpio; - # elif defined(CONFIG_IDF_TARGET_ESP32C2) || \ - defined(CONFIG_IDF_TARGET_ESP32C3) || \ - defined(CONFIG_IDF_TARGET_ESP32C6) + esp_sleep_ext1_wakeup_mode_t mode; - uint64_t mask = 1ULL << gpio; +# if CONFIG_IDF_TARGET_ESP32 - esp_deep_sleep_enable_gpio_wakeup( - mask, - wakeOnLow ? ESP_GPIO_WAKEUP_GPIO_LOW : ESP_GPIO_WAKEUP_GPIO_HIGH - ); + // Classic ESP32 only supports ALL_LOW or ANY_HIGH + mode = wakeOnLow ? ESP_EXT1_WAKEUP_ALL_LOW + : ESP_EXT1_WAKEUP_ANY_HIGH; +# else // if CONFIG_IDF_TARGET_ESP32 - # else // if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) - # warning "Unknown ESP32 target — GPIO wakeup not configured" - # endif // if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) + // All newer chips (S2, S3, C2, C3, C6, H2, ...) + mode = wakeOnLow ? ESP_EXT1_WAKEUP_ANY_LOW + : ESP_EXT1_WAKEUP_ANY_HIGH; +# endif // if CONFIG_IDF_TARGET_ESP32 + + // Configure RTC pull resistors + if (wakeOnLow) { + rtc_gpio_pullup_en(gpio); + } else { + rtc_gpio_pulldown_en(gpio); } + + esp_sleep_enable_ext1_wakeup_io(mask, mode); + +# else // if SOC_PM_SUPPORT_EXT1_WAKEUP + # warning "No supported GPIO wakeup method on this target" +# endif // if SOC_PM_SUPPORT_EXT1_WAKEUP } # endif // ifdef ESP32 From cedc78d7db285568e08ad2b81f27f7a055a67849 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sat, 21 Mar 2026 14:26:25 +0100 Subject: [PATCH 03/19] [P001] changed a line according to Tons suggestion --- src/src/Helpers/_Plugin_Helper_GPIO.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/Helpers/_Plugin_Helper_GPIO.cpp b/src/src/Helpers/_Plugin_Helper_GPIO.cpp index b187913b91..c78875326c 100644 --- a/src/src/Helpers/_Plugin_Helper_GPIO.cpp +++ b/src/src/Helpers/_Plugin_Helper_GPIO.cpp @@ -33,7 +33,7 @@ GPIO_plugin_helper_data_t::GPIO_plugin_helper_data_t( _switchType(switchType), _dimmerValue(dimmerValue), _safeButton(safeButton), - _wakeButton(false), + _wakeButton(wakeButton), _sendBootState(sendBootState), _longpressFired(false) { From 6f3544ae309bb91b65ffaa4f0731d2af31fdb5c0 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sun, 22 Mar 2026 23:52:25 +0100 Subject: [PATCH 04/19] [GPIO] Setting moved to Hardware tab - added "System#BootCause" and "System#GPIOWake" events - moved gpio-wake related functions to _Plugin_Helper --- src/_P001_Switch.ino | 96 -------------------- src/_Plugin_Helper.cpp | 51 +++++++++++ src/_Plugin_Helper.h | 5 + src/src/DataStructs/SettingsStruct.h | 14 ++- src/src/DataStructs_templ/SettingsStruct.cpp | 53 +++++++++++ src/src/ESPEasyCore/ESPEasy_setup.cpp | 18 ++++ src/src/Helpers/_Plugin_Helper_GPIO.cpp | 4 +- src/src/Helpers/_Plugin_Helper_GPIO.h | 4 +- src/src/PluginStructs/P001_data_struct.cpp | 3 +- src/src/PluginStructs/P001_data_struct.h | 1 - src/src/WebServer/HardwarePage.cpp | 32 ++++++- src/src/WebServer/Markup_Forms.cpp | 19 ++++ src/src/WebServer/Markup_Forms.h | 7 ++ 13 files changed, 196 insertions(+), 111 deletions(-) diff --git a/src/_P001_Switch.ino b/src/_P001_Switch.ino index 2fc41ecbb5..0780d4850b 100644 --- a/src/_P001_Switch.ino +++ b/src/_P001_Switch.ino @@ -11,15 +11,6 @@ # include "src/PluginStructs/P001_data_struct.h" -# ifdef ESP32 -# include "esp_sleep.h" -# include "driver/rtc_io.h" -void setupGpioWakeup(uint8_t pin, - bool wakeOnLow = true); // if ever needed we can also add support for wakeOnHigh, but for now - // when using a switch/button, the wakeup will be triggered by the pin going low (active - // low) -# endif // ifdef ESP32 - // ####################################################################################################### // #################################### Plugin 001: Input Switch ######################################### // ####################################################################################################### @@ -134,17 +125,6 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) P001_LP_MIN_INT, P001_SAFE_BTN); - # ifdef ESP32 - - if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)CONFIG_PIN1)) { - addFormCheckBox(F("Wake from sleep"), F("sw_wake"), P001_WAKE_BTN); - addFormNote(F("For pins without internal pull-up, add external resistor if unstable.")); - } - else { - P001_WAKE_BTN = 0; - } - # endif // ifdef ESP32 - # if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS if (switchtype != PLUGIN_001_TYPE_DIMMER) { @@ -180,16 +160,6 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) P001_LP_MIN_INT, P001_SAFE_BTN); - # ifdef ESP32 - - if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)CONFIG_PIN1)) { - P001_WAKE_BTN = isFormItemChecked(F("sw_wake")); - } - else { - P001_WAKE_BTN = 0; - } - # endif // ifdef ESP32 - # if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS P001_MQTT_DEVICECLASS = getFormItemInt(F("devcls")); # endif // if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS @@ -220,27 +190,10 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { - // apply INIT only if PORT is in range. Do not start INIT if port not set in the device page. if (validGpio(CONFIG_PIN1)) { success = initPluginTaskData(event->TaskIndex, new (std::nothrow) P001_data_struct(event)); - - # ifdef ESP32 - - if (P001_WAKE_BTN) { - // this would need adaption if we ever want to support wakeOnHigh as well - // if (wakeOnLow) { - rtc_gpio_pullup_dis((gpio_num_t)CONFIG_PIN1); - - // } else { - // rtc_gpio_pulldown_dis(gpio); - // } - - setupGpioWakeup(CONFIG_PIN1, true); - } - # endif // ifdef ESP32 - } break; } @@ -295,53 +248,4 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) return success; } -# ifdef ESP32 - -void setupGpioWakeup(uint8_t pin, bool wakeOnLow) { - gpio_num_t gpio = static_cast(pin); - - // Configure pin mode (important for stable level during sleep) - pinMode(pin, wakeOnLow ? INPUT_PULLUP : INPUT_PULLDOWN); - - if (!esp_sleep_is_valid_wakeup_gpio(gpio)) { - return; - } - -# if SOC_PM_SUPPORT_EXT1_WAKEUP - - // ---------------------------- - // UNIVERSAL SOLUTION (ALL ESP32s) - // ---------------------------- - uint64_t mask = 1ULL << gpio; - - esp_sleep_ext1_wakeup_mode_t mode; - -# if CONFIG_IDF_TARGET_ESP32 - - // Classic ESP32 only supports ALL_LOW or ANY_HIGH - mode = wakeOnLow ? ESP_EXT1_WAKEUP_ALL_LOW - : ESP_EXT1_WAKEUP_ANY_HIGH; -# else // if CONFIG_IDF_TARGET_ESP32 - - // All newer chips (S2, S3, C2, C3, C6, H2, ...) - mode = wakeOnLow ? ESP_EXT1_WAKEUP_ANY_LOW - : ESP_EXT1_WAKEUP_ANY_HIGH; -# endif // if CONFIG_IDF_TARGET_ESP32 - - // Configure RTC pull resistors - if (wakeOnLow) { - rtc_gpio_pullup_en(gpio); - } else { - rtc_gpio_pulldown_en(gpio); - } - - esp_sleep_enable_ext1_wakeup_io(mask, mode); - -# else // if SOC_PM_SUPPORT_EXT1_WAKEUP - # warning "No supported GPIO wakeup method on this target" -# endif // if SOC_PM_SUPPORT_EXT1_WAKEUP -} - -# endif // ifdef ESP32 - #endif // USES_P001 diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index 5c720cc649..5591486159 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -12,6 +12,10 @@ #include "src/Helpers/Misc.h" #include "src/Helpers/StringParser.h" +# ifdef SOC_PM_SUPPORT_EXT1_WAKEUP +# include "driver/rtc_io.h" +# endif + PluginTaskData_base *Plugin_task_data[TASKS_MAX] = {}; @@ -206,3 +210,50 @@ int checkDeviceVTypeForTask(struct EventStruct *event) { } return -1; } + +# if SOC_PM_SUPPORT_EXT1_WAKEUP +void setupGpioWakeup(uint64_t ext1_mask) { + + # if CONFIG_IDF_TARGET_ESP32 + auto new_mode = ESP_EXT1_WAKEUP_ALL_LOW; +# else + auto new_mode = ESP_EXT1_WAKEUP_ANY_LOW; +# endif // if CONFIG_IDF_TARGET_ESP32 + +// If no pins left → disable wakeup completely + if (ext1_mask == 0) { + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT1); + return; + } + + // Loop through all possible GPIOs (0–63 for bitmask) + for (int gpio = 0; gpio < 64; ++gpio) { + + // Check if this GPIO is part of the mask + if (ext1_mask & (1ULL << gpio)) { + + gpio_num_t rtc_gpio = static_cast(gpio); + + // Configure RTC pull-up (wake on LOW) + rtc_gpio_pullup_en(rtc_gpio); + rtc_gpio_pulldown_dis(rtc_gpio); + } + } + esp_sleep_enable_ext1_wakeup_io(ext1_mask, new_mode); +} + +int8_t getWakeupGPIO() { + if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_EXT1) { + return -1; // Not an EXT1 wakeup + } + + uint64_t wakeMask = esp_sleep_get_ext1_wakeup_status(); + + if (wakeMask == 0) { + return -1; + } + + // Get first active GPIO (fast version) + return __builtin_ctzll(wakeMask); +} +# endif diff --git a/src/_Plugin_Helper.h b/src/_Plugin_Helper.h index 9848ab0ed0..cc70acc554 100644 --- a/src/_Plugin_Helper.h +++ b/src/_Plugin_Helper.h @@ -168,4 +168,9 @@ int getValueCountForTask(taskIndex_t taskIndex); // Return pconfig_index int checkDeviceVTypeForTask(struct EventStruct *event); +#if SOC_PM_SUPPORT_EXT1_WAKEUP +void setupGpioWakeup(uint64_t ext1_mask); +int8_t getWakeupGPIO(); +#endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + #endif // PLUGIN_HELPER_H diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index d16376482c..e0c98eceda 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -357,12 +357,24 @@ class SettingsStruct_tmpl , int8_t& index_high #endif ) const; - + + # if SOC_PM_SUPPORT_EXT1_WAKEUP + //uint64_t WakeGpioMask = 0; + #endif public: PinBootState getPinBootState(int8_t gpio_pin) const; void setPinBootState(int8_t gpio_pin, PinBootState state); +# if SOC_PM_SUPPORT_EXT1_WAKEUP + // --- Wake GPIO mask handling --- + // uint64_t getWakeGpioMask() const; + // void setWakeGpioMask(uint64_t mask); + + // void addWakeGpio(uint8_t pin); + // void removeWakeGpio(uint8_t pin); + # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + #if FEATURE_SPI bool getSPI_pins(int8_t spi_gpios[3], uint8_t spi_bus = 0, diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index c389576415..034bf81e89 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -986,6 +986,59 @@ void SettingsStruct_tmpl::setPinBootState(int8_t gpio_pin, PinBootState } # endif // ifdef ESP32 } + +# if SOC_PM_SUPPORT_EXT1_WAKEUP +// template +// uint64_t SettingsStruct_tmpl::getWakeGpioMask() const { +// uint64_t mask = 0; +// for (int i = 0; i < 8; ++i) { +// mask |= (uint64_t)(this->WakeGpioMask_bytes[i]) << (i * 8); +// } +// return mask; +// } + +// template +// void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { +// for (int i = 0; i < 8; ++i) { +// this->WakeGpioMask_bytes[i] = (mask >> (i * 8)) & 0xFF; +// } +// } + +// template +// void SettingsStruct_tmpl::addWakeGpio(uint8_t pin) { +// uint64_t mask = getWakeGpioMask(); +// mask |= (1ULL << pin); +// setWakeGpioMask(mask); +// } + +// template +// void SettingsStruct_tmpl::removeWakeGpio(uint8_t pin) { +// uint64_t mask = getWakeGpioMask(); +// mask &= ~(1ULL << pin); +// setWakeGpioMask(mask); +// } +//-----------------------------------------uint64 +// template +// uint64_t SettingsStruct_tmpl::getWakeGpioMask() const { +// return WakeGpioMask; +// } + +// template +// void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { +// WakeGpioMask = mask; +// } + +// template +// void SettingsStruct_tmpl::addWakeGpio(uint8_t pin) { +// WakeGpioMask |= (1ULL << pin); +// } + +// template +// void SettingsStruct_tmpl::removeWakeGpio(uint8_t pin) { +// WakeGpioMask &= ~(1ULL << pin); +// } +#endif + #if FEATURE_SPI template bool SettingsStruct_tmpl::isSPI_enabled(uint8_t spi_bus) const { diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 5fdbec68f7..92df0ad38f 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -561,6 +561,13 @@ void ESPEasy_setup() String event = F("System#Wake"); rulesProcessing(event); // TD-er: Process events in the setup() now. } + + if (Settings.UseRules) + { + String event = F("System#BootCause="); + event += lastBootCause; + rulesProcessing(event); // TD-er: Process events in the setup() now. + } #ifdef ESP32 if (Settings.UseRules) @@ -588,6 +595,17 @@ void ESPEasy_setup() event += bitRead(gpio_strap, 5); rulesProcessing(event); } + + # if SOC_PM_SUPPORT_EXT1_WAKEUP + if (Settings.UseRules) + { + String event = F("System#GPIOWake="); + event += getWakeupGPIO(); + rulesProcessing(event); + setupGpioWakeup(64); // Todo: need to get the mask from settings struct + } + # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + #endif // ifdef ESP32 #if FEATURE_REPORTING diff --git a/src/src/Helpers/_Plugin_Helper_GPIO.cpp b/src/src/Helpers/_Plugin_Helper_GPIO.cpp index c78875326c..2093b1903f 100644 --- a/src/src/Helpers/_Plugin_Helper_GPIO.cpp +++ b/src/src/Helpers/_Plugin_Helper_GPIO.cpp @@ -18,8 +18,7 @@ GPIO_plugin_helper_data_t::GPIO_plugin_helper_data_t( bool safeButton, bool sendBootState, uint8_t switchType, - uint8_t dimmerValue, - bool wakeButton) : + uint8_t dimmerValue) : _portStatus_key(createKey(pluginNumber, pin)), _debounceInterval_ms(debounceInterval_ms), _doubleClickMaxInterval_ms(doubleClickMaxInterval_ms), @@ -33,7 +32,6 @@ GPIO_plugin_helper_data_t::GPIO_plugin_helper_data_t( _switchType(switchType), _dimmerValue(dimmerValue), _safeButton(safeButton), - _wakeButton(wakeButton), _sendBootState(sendBootState), _longpressFired(false) { diff --git a/src/src/Helpers/_Plugin_Helper_GPIO.h b/src/src/Helpers/_Plugin_Helper_GPIO.h index 6a983d599b..a9ecec864d 100644 --- a/src/src/Helpers/_Plugin_Helper_GPIO.h +++ b/src/src/Helpers/_Plugin_Helper_GPIO.h @@ -32,8 +32,7 @@ struct GPIO_plugin_helper_data_t { bool safeButton, bool sendBootState, uint8_t switchType = SWITCH_TYPE_NORMAL_SWITCH, - uint8_t dimmerValue = 0, - bool wakeButton = false); + uint8_t dimmerValue = 0); ~GPIO_plugin_helper_data_t(); @@ -67,7 +66,6 @@ struct GPIO_plugin_helper_data_t { const uint8_t _dimmerValue; const bool _safeButton; const bool _sendBootState; - const bool _wakeButton; bool _longpressFired; }; diff --git a/src/src/PluginStructs/P001_data_struct.cpp b/src/src/PluginStructs/P001_data_struct.cpp index f2b6734315..13acef231c 100644 --- a/src/src/PluginStructs/P001_data_struct.cpp +++ b/src/src/PluginStructs/P001_data_struct.cpp @@ -32,8 +32,7 @@ P001_data_struct::P001_data_struct(struct EventStruct *event) : P001_SAFE_BTN != 0, P001_BOOTSTATE, (P001_getSwitchType(event) == PLUGIN_001_TYPE_DIMMER) ? SWITCH_TYPE_DIMMER : P001_BUTTON_TYPE, - P001_DIMMER_VALUE, - P001_WAKE_BTN) + P001_DIMMER_VALUE) { uint8_t pinModeValue = PIN_MODE_INPUT; diff --git a/src/src/PluginStructs/P001_data_struct.h b/src/src/PluginStructs/P001_data_struct.h index 217cff7271..2a7ea1542f 100644 --- a/src/src/PluginStructs/P001_data_struct.h +++ b/src/src/PluginStructs/P001_data_struct.h @@ -49,7 +49,6 @@ # define P001_LONGPRESS PCONFIG(5) # define P001_LP_MIN_INT PCONFIG_FLOAT(2) # define P001_SAFE_BTN PCONFIG_FLOAT(3) -# define P001_WAKE_BTN PCONFIG_FLOAT(7) # if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS # define P001_MQTT_DEVICECLASS PCONFIG(6) diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index da114daaaa..8d958e155b 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -21,6 +21,10 @@ #include "../Helpers/StringConverter.h" #include "../Helpers/StringGenerator_GPIO.h" +# ifdef SOC_PM_SUPPORT_EXT1_WAKEUP +#include "../../_Plugin_Helper.h" +static uint64_t wakeGpioMask = 0; +# endif // ******************************************************************************** // Web Interface hardware page @@ -51,18 +55,26 @@ void handle_hardware() { Settings.Pin_sd_cs = getFormItemInt(F("sd")); int gpio = 0; + # if SOC_PM_SUPPORT_EXT1_WAKEUP while (gpio <= MAX_GPIO) { - if (isSerialConsolePin(gpio)) { - // do not add the pin state select for these pins. - } else { - if (validGpio(gpio)) { + if (validGpio(gpio)) { String int_pinlabel('p'); int_pinlabel += gpio; Settings.setPinBootState(gpio, static_cast(getFormItemInt(int_pinlabel))); - } } + if (validGpio(gpio)) { + char checkboxId[8]; // "WoL" + max 2 digits + null terminator + snprintf(checkboxId, sizeof(checkboxId), "WoL%d", gpio); + + // if the checkbox is checked, set the corresponding bit in wakeMask + if (isFormItemChecked(checkboxId)) { + wakeGpioMask |= (1ULL << gpio); + } + } ++gpio; } + # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + error += SaveSettings(); addHtmlError(error); } @@ -116,6 +128,16 @@ void handle_hardware() { for (int gpio = 0; gpio <= MAX_GPIO; ++gpio) { addFormPinStateSelect(gpio, static_cast(Settings.getPinBootState(gpio))); } + + # if SOC_PM_SUPPORT_EXT1_WAKEUP + addFormSubHeader(F("GPIO wake from sleep")); + addFormNote(F("For pins without internal pull-up, add external resistor if unstable.")); + for (int gpio = 0; gpio <= MAX_GPIO; ++gpio) { + addFormPinWakeSelect(gpio, wakeGpioMask); + setupGpioWakeup(wakeGpioMask); + } + # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + addFormSeparator(2); html_TR_TD(); diff --git a/src/src/WebServer/Markup_Forms.cpp b/src/src/WebServer/Markup_Forms.cpp index 524085b3dc..022e8f8fd0 100644 --- a/src/src/WebServer/Markup_Forms.cpp +++ b/src/src/WebServer/Markup_Forms.cpp @@ -638,6 +638,25 @@ void addFormPinStateSelect(int gpio, int choice) } } +// ******************************************************************************** +// Add a GPIO wake select list +// ******************************************************************************** +# if SOC_PM_SUPPORT_EXT1_WAKEUP +void addFormPinWakeSelect(int gpio, uint64_t wakeGpioMask){ + if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) { + // Check if this GPIO is part of the wake mask + bool checked = (wakeGpioMask & (1ULL << gpio)) != 0; + char label[20]; // "Wake from GPIO-" + GPIO number + null + char checkboxId[10]; // "WoL" + GPIO number + null + + snprintf(checkboxId, sizeof(checkboxId), "WoL%d", gpio); + snprintf(label, sizeof(label), "Wake from GPIO-%d", gpio); + + addFormCheckBox(label, checkboxId, checked); + } + } +# endif + // ******************************************************************************** // Retrieve return values from form/checkbox. // ******************************************************************************** diff --git a/src/src/WebServer/Markup_Forms.h b/src/src/WebServer/Markup_Forms.h index 29d6e2021e..105fcbb8c7 100644 --- a/src/src/WebServer/Markup_Forms.h +++ b/src/src/WebServer/Markup_Forms.h @@ -308,6 +308,13 @@ void addFormSelector_YesNo(const __FlashStringHelper * label, void addFormPinStateSelect(int gpio, int choice); +// ******************************************************************************** +// Add a GPIO wake select list +// ******************************************************************************** +# if SOC_PM_SUPPORT_EXT1_WAKEUP +void addFormPinWakeSelect(int gpio, uint64_t wakeGpioMask); +# endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + // ******************************************************************************** // Retrieve return values from form/checkbox. // ******************************************************************************** From 9cdac4d047188329c825b45bb9f836f3ced06b31 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sun, 22 Mar 2026 23:57:36 +0100 Subject: [PATCH 05/19] [GPIO] Setting moved to Hardware tab (removes unnecessary functions) --- src/src/DataStructs_templ/SettingsStruct.cpp | 38 -------------------- 1 file changed, 38 deletions(-) diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 034bf81e89..72d86d8985 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -988,36 +988,7 @@ void SettingsStruct_tmpl::setPinBootState(int8_t gpio_pin, PinBootState } # if SOC_PM_SUPPORT_EXT1_WAKEUP -// template -// uint64_t SettingsStruct_tmpl::getWakeGpioMask() const { -// uint64_t mask = 0; -// for (int i = 0; i < 8; ++i) { -// mask |= (uint64_t)(this->WakeGpioMask_bytes[i]) << (i * 8); -// } -// return mask; -// } -// template -// void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { -// for (int i = 0; i < 8; ++i) { -// this->WakeGpioMask_bytes[i] = (mask >> (i * 8)) & 0xFF; -// } -// } - -// template -// void SettingsStruct_tmpl::addWakeGpio(uint8_t pin) { -// uint64_t mask = getWakeGpioMask(); -// mask |= (1ULL << pin); -// setWakeGpioMask(mask); -// } - -// template -// void SettingsStruct_tmpl::removeWakeGpio(uint8_t pin) { -// uint64_t mask = getWakeGpioMask(); -// mask &= ~(1ULL << pin); -// setWakeGpioMask(mask); -// } -//-----------------------------------------uint64 // template // uint64_t SettingsStruct_tmpl::getWakeGpioMask() const { // return WakeGpioMask; @@ -1028,15 +999,6 @@ void SettingsStruct_tmpl::setPinBootState(int8_t gpio_pin, PinBootState // WakeGpioMask = mask; // } -// template -// void SettingsStruct_tmpl::addWakeGpio(uint8_t pin) { -// WakeGpioMask |= (1ULL << pin); -// } - -// template -// void SettingsStruct_tmpl::removeWakeGpio(uint8_t pin) { -// WakeGpioMask &= ~(1ULL << pin); -// } #endif #if FEATURE_SPI From 3b5d8c70d991cfe4f72659533d2502a946ec66fe Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Mon, 23 Mar 2026 00:19:05 +0100 Subject: [PATCH 06/19] [GPIO] add check for gpiowake event --- src/src/ESPEasyCore/ESPEasy_setup.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 92df0ad38f..e66b8119fe 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -599,9 +599,13 @@ void ESPEasy_setup() # if SOC_PM_SUPPORT_EXT1_WAKEUP if (Settings.UseRules) { - String event = F("System#GPIOWake="); - event += getWakeupGPIO(); - rulesProcessing(event); + int8_t wakePin = getWakeupGPIO(); + + if (wakePin >= 0) { + String event = F("System#GPIOWake="); + event += wakePin; + rulesProcessing(event); + } setupGpioWakeup(64); // Todo: need to get the mask from settings struct } # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP From ac6ece07c581b29fab477b4a25c46d3c632f0c65 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Mon, 23 Mar 2026 00:33:30 +0100 Subject: [PATCH 07/19] [GPIO] fixed a c&p mistake --- src/src/WebServer/HardwarePage.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 8d958e155b..e229fb6c1d 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -55,13 +55,21 @@ void handle_hardware() { Settings.Pin_sd_cs = getFormItemInt(F("sd")); int gpio = 0; - # if SOC_PM_SUPPORT_EXT1_WAKEUP while (gpio <= MAX_GPIO) { - if (validGpio(gpio)) { + if (isSerialConsolePin(gpio)) { + // do not add the pin state select for these pins. + } else { + if (validGpio(gpio)) { String int_pinlabel('p'); int_pinlabel += gpio; Settings.setPinBootState(gpio, static_cast(getFormItemInt(int_pinlabel))); + } } + ++gpio; + } + + # if SOC_PM_SUPPORT_EXT1_WAKEUP + while (gpio <= MAX_GPIO) { if (validGpio(gpio)) { char checkboxId[8]; // "WoL" + max 2 digits + null terminator snprintf(checkboxId, sizeof(checkboxId), "WoL%d", gpio); From 2365dff0c3cbd714c6c8cee9fe1714b715e8e927 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:02:13 +0100 Subject: [PATCH 08/19] [GPIO] adding details expansion + rules-keywords --- src/src/WebServer/HardwarePage.cpp | 16 +++++++++++----- static/espeasy.js | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index e229fb6c1d..f3d1cc11aa 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -67,20 +67,22 @@ void handle_hardware() { } ++gpio; } - + # if SOC_PM_SUPPORT_EXT1_WAKEUP + gpio = 0; + wakeGpioMask = 0; while (gpio <= MAX_GPIO) { if (validGpio(gpio)) { char checkboxId[8]; // "WoL" + max 2 digits + null terminator snprintf(checkboxId, sizeof(checkboxId), "WoL%d", gpio); - // if the checkbox is checked, set the corresponding bit in wakeMask if (isFormItemChecked(checkboxId)) { wakeGpioMask |= (1ULL << gpio); } - } + } ++gpio; } + setupGpioWakeup(wakeGpioMask); # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP error += SaveSettings(); @@ -132,18 +134,22 @@ void handle_hardware() { #endif // if FEATURE_SD addFormSubHeader(F("GPIO boot states")); - + addFormDetailsStart(0); + for (int gpio = 0; gpio <= MAX_GPIO; ++gpio) { addFormPinStateSelect(gpio, static_cast(Settings.getPinBootState(gpio))); } + addFormDetailsEnd(); # if SOC_PM_SUPPORT_EXT1_WAKEUP addFormSubHeader(F("GPIO wake from sleep")); + addFormDetailsStart(0); + addFormNote(F("For pins without internal pull-up, add external resistor if unstable.")); for (int gpio = 0; gpio <= MAX_GPIO; ++gpio) { addFormPinWakeSelect(gpio, wakeGpioMask); - setupGpioWakeup(wakeGpioMask); } + addFormDetailsEnd(); # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP addFormSeparator(2); diff --git a/static/espeasy.js b/static/espeasy.js index d7a9b6822c..c1991ce179 100644 --- a/static/espeasy.js +++ b/static/espeasy.js @@ -15,7 +15,7 @@ var commonCommands = ["AccessInfo", "Background", "Build", "ClearAccessBlock", " "GPIO", "GPIOToggle", "LongPulse", "LongPulse_mS", "Monitor", "Pulse", "PWM", "Servo", "Status", "Tone", "RTTTL", "UnMonitor", "Provision", "Provision,Config", "Provision,Security", "Provision,Notification", "Provision,Provision", "Provision,Rules", "Provision,CustomCdnUrl", "Provision,Firmware"]; var commonEvents = ["Clock#Time", "Login#Failed", "MQTT#Connected", "MQTT#Disconnected", "MQTTimport#Connected", "MQTTimport#Disconnected", "Rules#Timer", "System#Boot", - "System#BootMode", "System#Sleep", "System#Wake", "TaskExit#", "TaskInit#", "ThingspeakReply", "Time#Initialized", "Time#Set", "WiFi#APmodeDisabled", "WiFi#APmodeEnabled", + "System#BootMode", "System#BootCause", "System#GPIOWake", "System#Sleep", "System#Wake", "TaskExit#", "TaskInit#", "ThingspeakReply", "Time#Initialized", "Time#Set", "WiFi#APmodeDisabled", "WiFi#APmodeEnabled", "WiFi#ChangedAccesspoint", "WiFi#ChangedWiFichannel", "WiFi#Connected", "WiFi#Disconnected"]; var commonPlugins = [ //P003 From 3e6c2992be6babd25fdd2f19d449b8591274ed7e Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sat, 28 Mar 2026 21:55:20 +0100 Subject: [PATCH 09/19] [GPIO] adding all the missing bits and pieces. --- src/_Plugin_Helper.cpp | 4 ++-- src/_Plugin_Helper.h | 4 ++-- src/src/CustomBuild/define_plugin_sets.h | 6 ++++++ src/src/DataStructs/SettingsStruct.h | 22 +++++++++++--------- src/src/DataStructs_templ/SettingsStruct.cpp | 20 ++++++++++-------- src/src/ESPEasyCore/ESPEasy_setup.cpp | 6 +++--- src/src/Helpers/ESPEasy_checks.cpp | 2 +- src/src/WebServer/HardwarePage.cpp | 18 ++++++++-------- src/src/WebServer/Markup_Forms.cpp | 2 +- src/src/WebServer/Markup_Forms.h | 4 ++-- 10 files changed, 49 insertions(+), 39 deletions(-) diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index 5591486159..c998b8238d 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -12,7 +12,7 @@ #include "src/Helpers/Misc.h" #include "src/Helpers/StringParser.h" -# ifdef SOC_PM_SUPPORT_EXT1_WAKEUP +# ifdef FEATURE_EXT1_WAKEUP # include "driver/rtc_io.h" # endif @@ -211,7 +211,7 @@ int checkDeviceVTypeForTask(struct EventStruct *event) { return -1; } -# if SOC_PM_SUPPORT_EXT1_WAKEUP +# if FEATURE_EXT1_WAKEUP void setupGpioWakeup(uint64_t ext1_mask) { # if CONFIG_IDF_TARGET_ESP32 diff --git a/src/_Plugin_Helper.h b/src/_Plugin_Helper.h index cc70acc554..850ccde339 100644 --- a/src/_Plugin_Helper.h +++ b/src/_Plugin_Helper.h @@ -168,9 +168,9 @@ int getValueCountForTask(taskIndex_t taskIndex); // Return pconfig_index int checkDeviceVTypeForTask(struct EventStruct *event); -#if SOC_PM_SUPPORT_EXT1_WAKEUP +#if FEATURE_EXT1_WAKEUP void setupGpioWakeup(uint64_t ext1_mask); int8_t getWakeupGPIO(); -#endif // if SOC_PM_SUPPORT_EXT1_WAKEUP +#endif // if FEATURE_EXT1_WAKEUP #endif // PLUGIN_HELPER_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 82b1d4ed35..a8cb4c88b1 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -4545,3 +4545,9 @@ To create/register a plugin, you have to : #endif // if !FEATURE_SPI && !FEATURE_I2C && !FEATURE_MODBUS && !FEATURE_CAN && !FEATURE_WRMBUS && !FEATURE_WIMBUS #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H + +#if SOC_PM_SUPPORT_EXT1_WAKEUP +#define FEATURE_EXT1_WAKEUP 1 +#else +#define FEATURE_EXT1_WAKEUP 0 +#endif diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index e0c98eceda..3c650c4bf6 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -358,22 +358,16 @@ class SettingsStruct_tmpl #endif ) const; - # if SOC_PM_SUPPORT_EXT1_WAKEUP - //uint64_t WakeGpioMask = 0; - #endif public: PinBootState getPinBootState(int8_t gpio_pin) const; void setPinBootState(int8_t gpio_pin, PinBootState state); -# if SOC_PM_SUPPORT_EXT1_WAKEUP + # if FEATURE_EXT1_WAKEUP // --- Wake GPIO mask handling --- - // uint64_t getWakeGpioMask() const; - // void setWakeGpioMask(uint64_t mask); - - // void addWakeGpio(uint8_t pin); - // void removeWakeGpio(uint8_t pin); - # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + uint64_t getWakeGpioMask() const; + void setWakeGpioMask(uint64_t mask); + # endif // if FEATURE_EXT1_WAKEUP #if FEATURE_SPI bool getSPI_pins(int8_t spi_gpios[3], @@ -601,7 +595,15 @@ class SettingsStruct_tmpl int8_t SPI1_SCLK_pin = -1; int8_t SPI1_MISO_pin = -1; int8_t SPI1_MOSI_pin = -1; + #ifdef ESP32 + uint32_t wakePin_bitmask_lLo=0; + uint32_t wakePin_bitmask_lHi=0; + // int8_t wakeOnLow = 1; + + unsigned int OLD_TaskDeviceID[N_TASKS - 10] = {0}; // UNUSED: this can be reused + #else unsigned int OLD_TaskDeviceID[N_TASKS - 8] = {0}; // UNUSED: this can be reused + #endif // FIXME TD-er: When used on ESP8266, this conversion union may not work // It might work as it is 32-bit in size. diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 72d86d8985..03ac53f06e 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -987,17 +987,19 @@ void SettingsStruct_tmpl::setPinBootState(int8_t gpio_pin, PinBootState # endif // ifdef ESP32 } -# if SOC_PM_SUPPORT_EXT1_WAKEUP +# if FEATURE_EXT1_WAKEUP -// template -// uint64_t SettingsStruct_tmpl::getWakeGpioMask() const { -// return WakeGpioMask; -// } +template +uint64_t SettingsStruct_tmpl::getWakeGpioMask() const { + return (static_cast(wakePin_bitmask_lHi) << 32) | + wakePin_bitmask_lLo; +} -// template -// void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { -// WakeGpioMask = mask; -// } +template +void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { + wakePin_bitmask_lLo = static_cast(mask & 0xFFFFFFFFULL); + wakePin_bitmask_lHi = static_cast(mask >> 32); +} #endif diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index e66b8119fe..7e4573f44c 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -596,7 +596,7 @@ void ESPEasy_setup() rulesProcessing(event); } - # if SOC_PM_SUPPORT_EXT1_WAKEUP + # if FEATURE_EXT1_WAKEUP if (Settings.UseRules) { int8_t wakePin = getWakeupGPIO(); @@ -606,9 +606,9 @@ void ESPEasy_setup() event += wakePin; rulesProcessing(event); } - setupGpioWakeup(64); // Todo: need to get the mask from settings struct + setupGpioWakeup(Settings.getWakeGpioMask()); } - # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + # endif // if FEATURE_EXT1_WAKEUP #endif // ifdef ESP32 diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 07a7e6fe5d..b9b9e709b8 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -178,7 +178,7 @@ void run_compiletime_checks() { static_assert(198u == offsetof(SettingsStruct, TaskDeviceNumber), "NOTIFICATION_MAX has changed?"); // All settings related to N_TASKS - static_assert((232 + TASKS_MAX) == offsetof(SettingsStruct, OLD_TaskDeviceID), ""); // 32-bit alignment, so offset of 2 bytes. + static_assert((240 + TASKS_MAX) == offsetof(SettingsStruct, OLD_TaskDeviceID), ""); // 32-bit alignment, so offset of 2 bytes. static_assert((200 + (67 * TASKS_MAX)) == offsetof(SettingsStruct, ControllerEnabled), ""); // Used to compute true offset. diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index f3d1cc11aa..847fe29744 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -21,9 +21,8 @@ #include "../Helpers/StringConverter.h" #include "../Helpers/StringGenerator_GPIO.h" -# ifdef SOC_PM_SUPPORT_EXT1_WAKEUP +# ifdef FEATURE_EXT1_WAKEUP #include "../../_Plugin_Helper.h" -static uint64_t wakeGpioMask = 0; # endif // ******************************************************************************** @@ -68,9 +67,9 @@ void handle_hardware() { ++gpio; } - # if SOC_PM_SUPPORT_EXT1_WAKEUP + # if FEATURE_EXT1_WAKEUP gpio = 0; - wakeGpioMask = 0; + uint64_t wakeGpioMask = 0; while (gpio <= MAX_GPIO) { if (validGpio(gpio)) { char checkboxId[8]; // "WoL" + max 2 digits + null terminator @@ -82,8 +81,9 @@ void handle_hardware() { } ++gpio; } - setupGpioWakeup(wakeGpioMask); - # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + Settings.setWakeGpioMask(wakeGpioMask); // save the bitmask + setupGpioWakeup(wakeGpioMask); //attach gpios for wakeup + # endif // if FEATURE_EXT1_WAKEUP error += SaveSettings(); addHtmlError(error); @@ -141,16 +141,16 @@ void handle_hardware() { } addFormDetailsEnd(); - # if SOC_PM_SUPPORT_EXT1_WAKEUP + # if FEATURE_EXT1_WAKEUP addFormSubHeader(F("GPIO wake from sleep")); addFormDetailsStart(0); addFormNote(F("For pins without internal pull-up, add external resistor if unstable.")); for (int gpio = 0; gpio <= MAX_GPIO; ++gpio) { - addFormPinWakeSelect(gpio, wakeGpioMask); + addFormPinWakeSelect(gpio, Settings.getWakeGpioMask()); } addFormDetailsEnd(); - # endif // if SOC_PM_SUPPORT_EXT1_WAKEUP + # endif // if FEATURE_EXT1_WAKEUP addFormSeparator(2); diff --git a/src/src/WebServer/Markup_Forms.cpp b/src/src/WebServer/Markup_Forms.cpp index 022e8f8fd0..64b473f960 100644 --- a/src/src/WebServer/Markup_Forms.cpp +++ b/src/src/WebServer/Markup_Forms.cpp @@ -641,7 +641,7 @@ void addFormPinStateSelect(int gpio, int choice) // ******************************************************************************** // Add a GPIO wake select list // ******************************************************************************** -# if SOC_PM_SUPPORT_EXT1_WAKEUP +# if FEATURE_EXT1_WAKEUP void addFormPinWakeSelect(int gpio, uint64_t wakeGpioMask){ if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) { // Check if this GPIO is part of the wake mask diff --git a/src/src/WebServer/Markup_Forms.h b/src/src/WebServer/Markup_Forms.h index 105fcbb8c7..80c30e3d70 100644 --- a/src/src/WebServer/Markup_Forms.h +++ b/src/src/WebServer/Markup_Forms.h @@ -311,9 +311,9 @@ void addFormPinStateSelect(int gpio, // ******************************************************************************** // Add a GPIO wake select list // ******************************************************************************** -# if SOC_PM_SUPPORT_EXT1_WAKEUP +# if FEATURE_EXT1_WAKEUP void addFormPinWakeSelect(int gpio, uint64_t wakeGpioMask); -# endif // if SOC_PM_SUPPORT_EXT1_WAKEUP +# endif // if FEATURE_EXT1_WAKEUP // ******************************************************************************** // Retrieve return values from form/checkbox. From 1ca3eb5bfd8fd9b41dbaa27b3f92312ebdec86fb Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sat, 28 Mar 2026 22:21:29 +0100 Subject: [PATCH 10/19] [GPIO] adding all the missing bits and pieces part 2 --- src/_Plugin_Helper.cpp | 2 +- src/src/CustomBuild/define_plugin_sets.h | 2 +- src/src/DataStructs/SettingsStruct.h | 3 +-- src/src/Helpers/ESPEasy_checks.cpp | 5 +++++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index c998b8238d..a00e9cf096 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -12,7 +12,7 @@ #include "src/Helpers/Misc.h" #include "src/Helpers/StringParser.h" -# ifdef FEATURE_EXT1_WAKEUP +# if FEATURE_EXT1_WAKEUP # include "driver/rtc_io.h" # endif diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index a8cb4c88b1..3dda63954f 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -4546,7 +4546,7 @@ To create/register a plugin, you have to : #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H -#if SOC_PM_SUPPORT_EXT1_WAKEUP +#if SOC_PM_SUPPORT_EXT1_WAKEUP && defined(ESP32) #define FEATURE_EXT1_WAKEUP 1 #else #define FEATURE_EXT1_WAKEUP 0 diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index 3c650c4bf6..ae81a3fa50 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -598,8 +598,7 @@ class SettingsStruct_tmpl #ifdef ESP32 uint32_t wakePin_bitmask_lLo=0; uint32_t wakePin_bitmask_lHi=0; - // int8_t wakeOnLow = 1; - + // int8_t wakeOnLow = 1; // Chromoxdor: a checkbox for wake on LOW or HIGH can be added later, but for now this is as far as i go unsigned int OLD_TaskDeviceID[N_TASKS - 10] = {0}; // UNUSED: this can be reused #else unsigned int OLD_TaskDeviceID[N_TASKS - 8] = {0}; // UNUSED: this can be reused diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index b9b9e709b8..f7e86eec89 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -178,9 +178,14 @@ void run_compiletime_checks() { static_assert(198u == offsetof(SettingsStruct, TaskDeviceNumber), "NOTIFICATION_MAX has changed?"); // All settings related to N_TASKS + #ifdef ESP32 static_assert((240 + TASKS_MAX) == offsetof(SettingsStruct, OLD_TaskDeviceID), ""); // 32-bit alignment, so offset of 2 bytes. + #else + static_assert((232 + TASKS_MAX) == offsetof(SettingsStruct, OLD_TaskDeviceID), ""); // 32-bit alignment, so offset of 2 bytes. + #endif static_assert((200 + (67 * TASKS_MAX)) == offsetof(SettingsStruct, ControllerEnabled), ""); + // Used to compute true offset. //const size_t offset = offsetof(SettingsStruct, ControllerEnabled); //check_size(); From 90a2071b6df700a4c045c846a12ae43fd16d3bcb Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sun, 29 Mar 2026 17:06:47 +0200 Subject: [PATCH 11/19] [GPIO] adding all the missing bits and pieces part 3 - added documentation - added "GPIO-Wakeup" mode for devices that do not support "EXT1-Wakeup" --- docs/source/Hardware/Hardware.rst | 43 ++++++ docs/source/Plugin/P000_events.repl | 37 +++++ src/_Plugin_Helper.cpp | 138 ++++++++++++------- src/_Plugin_Helper.h | 4 +- src/src/CustomBuild/define_plugin_sets.h | 11 +- src/src/DataStructs/SettingsStruct.h | 13 +- src/src/DataStructs_templ/SettingsStruct.cpp | 6 +- src/src/ESPEasyCore/ESPEasy_setup.cpp | 4 +- src/src/Helpers/ESPEasy_checks.cpp | 7 +- src/src/WebServer/HardwarePage.cpp | 28 ++-- src/src/WebServer/Markup_Forms.cpp | 2 +- src/src/WebServer/Markup_Forms.h | 4 +- 12 files changed, 216 insertions(+), 81 deletions(-) diff --git a/docs/source/Hardware/Hardware.rst b/docs/source/Hardware/Hardware.rst index 1b290f245a..13df9fd34f 100644 --- a/docs/source/Hardware/Hardware.rst +++ b/docs/source/Hardware/Hardware.rst @@ -101,3 +101,46 @@ If the board supports PSRAM, it hides GPIO-26 (GPIO-26 is missing from the range, as it can not be used if PSRAM is present) Overview of the GPIO pin mapping of ESP32-S2 (link to Espressif documentation): `ESP32-S2 Saola1 `_ + +-------------------- +GPIO wake from sleep +-------------------- + +.. note:: + This feature is only available on ESP32 devices. + +Supported GPIO pins can be selected to wake the unit from deep sleep. +The signal level (HIGH or LOW) is configured globally and applies to **all** selected pins. +GPIO wake-up on newer devices supports per-pin trigger level configuration, but this comes at the cost of higher power consumption. +**TODO:** Integrate per-pin trigger level selection for GPIO wake-up. + +When the unit wakes up from deep sleep, an event is generated with the GPIO number that caused the wakeup. +``"EVENT: System#GPIOWake=XX"``, where ``XX`` is the GPIO number. + +Make sure to add a pull-up or pull-down resistor to the selected GPIO pin(s) if they are not already present, to avoid false wakeups. +(some GPIO pins have internal pull-up or pull-down resistors, but not all of them, and the internal pull-up/down may not be sufficient for stable operation in all cases) + +.. note:: + + Depending on the ESP32 variant, two different wake-up mechanisms are used. + + **EXT1 Wake-up (RTC)** + + If ``SOC_PM_SUPPORT_EXT1_WAKEUP`` is available, EXT1 wake-up is used: + + - Only works on RTC-capable pins + - Very low power (RTC domain) + + **GPIO Wake-up (Fallback)** + + On platforms without EXT1 support (e.g. ESP32-C3), GPIO wake-up is used: + + - Works on more pins (not RTC-limited) + - Slightly higher power usage (HP domain) + + **Summary** + + - EXT1: preferred, low power + - GPIO wake-up: fallback for newer chips, more flexible but less efficient + + The firmware automatically selects the correct method at compile time. \ No newline at end of file diff --git a/docs/source/Plugin/P000_events.repl b/docs/source/Plugin/P000_events.repl index b23bac7025..eeb19706a8 100644 --- a/docs/source/Plugin/P000_events.repl +++ b/docs/source/Plugin/P000_events.repl @@ -70,6 +70,30 @@ GPIO,15,1 endon + " + " + ``System#BootCause`` + Added: 2026-03-29 + Triggered at boot time. + "," + + .. code-block:: none + + on System#BootCause do + LogEntry,'Bootcause: %eventvalue1%' + endon + + Possible bootcauses can be: + + * 0: Manual Reboot + * 1: Cold Boot + * 2: Deep Sleep + * 3: Soft Reboot + * 10: External Watchdog + * 11: SW Watchdog + * 12: Exception + * 20: PWR Unstable + " " ``System#BootMode`` @@ -104,6 +128,19 @@ See 'Boot Strapping Pins' documentation for the boot strapping pins for all ESP32-series chips. + " + " + ``System#GPIOWake`` + Added: 2026-03-29 + Triggered at boot time. + "," + + .. code-block:: none + + on System#GPIOWake do + LogEntry,'GPIO that caused the wakeup: %eventvalue1%' + endon + " " ``System#Boot`` diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index a00e9cf096..c081f926f9 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -12,14 +12,13 @@ #include "src/Helpers/Misc.h" #include "src/Helpers/StringParser.h" -# if FEATURE_EXT1_WAKEUP -# include "driver/rtc_io.h" -# endif +#if FEATURE_PIN_WAKEUP +# include "driver/rtc_io.h" +#endif PluginTaskData_base *Plugin_task_data[TASKS_MAX] = {}; - String PCONFIG_LABEL(int n) { if (n < PLUGIN_CONFIGVAR_MAX) { return concat(F("pconf_"), n); @@ -51,9 +50,9 @@ bool initPluginTaskData(taskIndex_t taskIndex, PluginTaskData_base *data) { } // 2nd heap may have been active to allocate the PluginTaskData, but here we need to keep the default heap active - # ifdef USE_SECOND_HEAP + #ifdef USE_SECOND_HEAP HeapSelectDram ephemeral; - # endif // ifdef USE_SECOND_HEAP + #endif // ifdef USE_SECOND_HEAP clearPluginTaskData(taskIndex); @@ -65,16 +64,18 @@ bool initPluginTaskData(taskIndex_t taskIndex, PluginTaskData_base *data) { #if FEATURE_PLUGIN_STATS const uint8_t valueCount = getValueCountForTask(taskIndex); + for (size_t i = 0; i < valueCount; ++i) { if (Cache.enabledPluginStats(taskIndex, i)) { Plugin_task_data[taskIndex]->initPluginStats(i); } } - #endif + #endif // if FEATURE_PLUGIN_STATS #if FEATURE_PLUGIN_FILTER - // TODO TD-er: Implement init - #endif + // TODO TD-er: Implement init + + #endif // if FEATURE_PLUGIN_FILTER } else { delete data; @@ -85,7 +86,7 @@ bool initPluginTaskData(taskIndex_t taskIndex, PluginTaskData_base *data) { PluginTaskData_base* getPluginTaskData(taskIndex_t taskIndex) { if (pluginTaskData_initialized(taskIndex)) { - + if (!Plugin_task_data[taskIndex]->baseClassOnly()) { return Plugin_task_data[taskIndex]; } @@ -100,7 +101,6 @@ PluginTaskData_base* getPluginTaskDataBaseClassOnly(taskIndex_t taskIndex) { return nullptr; } - bool pluginTaskData_initialized(taskIndex_t taskIndex) { if (!validTaskIndex(taskIndex)) { return false; @@ -109,29 +109,24 @@ bool pluginTaskData_initialized(taskIndex_t taskIndex) { (Plugin_task_data[taskIndex]->_taskdata_pluginID == Settings.getPluginID_for_task(taskIndex)); } -String getPluginCustomArgName(int varNr) { - return getPluginCustomArgName(F("pc_arg"), varNr); -} +String getPluginCustomArgName(int varNr) { return getPluginCustomArgName(F("pc_arg"), varNr); } -String getPluginCustomArgName(const __FlashStringHelper * label, int varNr) { - return concat(label, varNr + 1); -} +String getPluginCustomArgName(const __FlashStringHelper *label, int varNr) { return concat(label, varNr + 1); } -int getFormItemIntCustomArgName(int varNr) { - return getFormItemInt(getPluginCustomArgName(varNr)); -} +int getFormItemIntCustomArgName(int varNr) { return getFormItemInt(getPluginCustomArgName(varNr)); } // Helper function to create formatted custom values for display in the devices overview page. // When called from PLUGIN_WEBFORM_SHOW_VALUES, the last item should add a traling div_br class // if the regular values should also be displayed. // The call to PLUGIN_WEBFORM_SHOW_VALUES should only return success = true when no regular values should be displayed // Note that the varNr of the custom values should not conflict with the existing variable numbers (e.g. start at VARS_PER_TASK) -void pluginWebformShowValue(taskIndex_t taskIndex, uint8_t varNr, const __FlashStringHelper * label, const String& value, bool addTrailingBreak) { +void pluginWebformShowValue(taskIndex_t taskIndex, uint8_t varNr, const __FlashStringHelper *label, const String& value, + bool addTrailingBreak) { pluginWebformShowValue(taskIndex, varNr, String(label), value, addTrailingBreak); } void pluginWebformShowValue(taskIndex_t taskIndex, - uint8_t varNr, + uint8_t varNr, const String& label, const String& value, bool addTrailingBreak) { @@ -179,11 +174,12 @@ bool pluginOptionalTaskIndexArgumentMatch(taskIndex_t taskIndex, const String& s return found_taskIndex == taskIndex; } -bool pluginWebformShowGPIOdescription(taskIndex_t taskIndex, - const __FlashStringHelper * newline, - String& description) +bool pluginWebformShowGPIOdescription(taskIndex_t taskIndex, + const __FlashStringHelper *newline, + String & description) { struct EventStruct TempEvent(taskIndex); + TempEvent.String1 = newline; return PluginCall(PLUGIN_WEBFORM_SHOW_GPIO_DESCR, &TempEvent, description); } @@ -203,6 +199,7 @@ int checkDeviceVTypeForTask(struct EventStruct *event) { String dummy; event->idx = -1; + if (PluginCall(PLUGIN_GET_DEVICEVTYPE, event, dummy)) { return event->idx; // pconfig_index } @@ -211,49 +208,98 @@ int checkDeviceVTypeForTask(struct EventStruct *event) { return -1; } -# if FEATURE_EXT1_WAKEUP -void setupGpioWakeup(uint64_t ext1_mask) { +#if FEATURE_PIN_WAKEUP - # if CONFIG_IDF_TARGET_ESP32 - auto new_mode = ESP_EXT1_WAKEUP_ALL_LOW; -# else - auto new_mode = ESP_EXT1_WAKEUP_ANY_LOW; -# endif // if CONFIG_IDF_TARGET_ESP32 +void setupGpioWakeup(uint64_t ext1_mask) { -// If no pins left → disable wakeup completely + // disable wakeup completely if nothin is selected if (ext1_mask == 0) { - esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT1); + #if FEATURE_PIN_WAKEUP == 1 + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT1); + #else + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_GPIO); + #endif return; } - // Loop through all possible GPIOs (0–63 for bitmask) - for (int gpio = 0; gpio < 64; ++gpio) { +#if FEATURE_PIN_WAKEUP == 1 + // --- EXT1 Wakeup (supported on classic ESP32/S2/S3) --- + esp_sleep_ext1_wakeup_mode_t new_mode; + + if (Settings.wakeOnHigh()) { + new_mode = ESP_EXT1_WAKEUP_ANY_HIGH; + } else { + #if CONFIG_IDF_TARGET_ESP32 + new_mode = ESP_EXT1_WAKEUP_ALL_LOW; + #else + new_mode = ESP_EXT1_WAKEUP_ANY_LOW; + #endif + } - // Check if this GPIO is part of the mask + // Configure pull-ups/pull-downs for all pins in the mask + for (int gpio = 0; gpio < 64; ++gpio) { if (ext1_mask & (1ULL << gpio)) { - gpio_num_t rtc_gpio = static_cast(gpio); - // Configure RTC pull-up (wake on LOW) - rtc_gpio_pullup_en(rtc_gpio); - rtc_gpio_pulldown_dis(rtc_gpio); + if (!Settings.wakeOnHigh()) { + rtc_gpio_pullup_en(rtc_gpio); + rtc_gpio_pulldown_dis(rtc_gpio); + } else { + rtc_gpio_pullup_dis(rtc_gpio); + rtc_gpio_pulldown_en(rtc_gpio); + } } } + + esp_sleep_enable_ext1_wakeup_io(ext1_mask, new_mode); + +#elif FEATURE_PIN_WAKEUP == 2 + // --- GPIO-based wakeup for chips without EXT1 (e.g. ESP32-C3) --- + esp_deepsleep_gpio_wake_up_mode_t gpio_mode = + Settings.wakeOnHigh() ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW; + + // Configure all pins in the mask + for (int gpio = 0; gpio < 64; ++gpio) { + if (ext1_mask & (1ULL << gpio)) { + gpio_num_t rtc_gpio = static_cast(gpio); + + // if (!Settings.wakeOnHigh()) { + // gpio_pullup_en(rtc_gpio); + // gpio_pulldown_dis(rtc_gpio); + // } else { + // gpio_pullup_dis(rtc_gpio); + // gpio_pulldown_en(rtc_gpio); + // } + } + } + + esp_deep_sleep_enable_gpio_wakeup(ext1_mask, gpio_mode); + +#endif } int8_t getWakeupGPIO() { - if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_EXT1) { - return -1; // Not an EXT1 wakeup - } + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); +#if FEATURE_PIN_WAKEUP == 1 + if (cause != ESP_SLEEP_WAKEUP_EXT1) { + return -1; + } uint64_t wakeMask = esp_sleep_get_ext1_wakeup_status(); +#else + if (cause != ESP_SLEEP_WAKEUP_GPIO) { + return -1; + } + uint64_t wakeMask = esp_sleep_get_gpio_wakeup_status(); +#endif if (wakeMask == 0) { return -1; } - // Get first active GPIO (fast version) + // Return first active GPIO return __builtin_ctzll(wakeMask); } -# endif + +#endif // if FEATURE_PIN_WAKEUP diff --git a/src/_Plugin_Helper.h b/src/_Plugin_Helper.h index 850ccde339..6024512dcd 100644 --- a/src/_Plugin_Helper.h +++ b/src/_Plugin_Helper.h @@ -168,9 +168,9 @@ int getValueCountForTask(taskIndex_t taskIndex); // Return pconfig_index int checkDeviceVTypeForTask(struct EventStruct *event); -#if FEATURE_EXT1_WAKEUP +#if FEATURE_PIN_WAKEUP void setupGpioWakeup(uint64_t ext1_mask); int8_t getWakeupGPIO(); -#endif // if FEATURE_EXT1_WAKEUP +#endif // if FEATURE_PIN_WAKEUP #endif // PLUGIN_HELPER_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 3dda63954f..d56f16263a 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -4546,8 +4546,11 @@ To create/register a plugin, you have to : #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H -#if SOC_PM_SUPPORT_EXT1_WAKEUP && defined(ESP32) -#define FEATURE_EXT1_WAKEUP 1 -#else -#define FEATURE_EXT1_WAKEUP 0 +#if defined(ESP32) +#if SOC_PM_SUPPORT_EXT1_WAKEUP +#define FEATURE_PIN_WAKEUP 1 +#else // if no EXT1_WAKEUP support, we can use GPIO wakeup + // (TODO: -add per-pin trigger level control for GPIO wakeup) +#define FEATURE_PIN_WAKEUP 2 +#endif #endif diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index ae81a3fa50..efc040399b 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -363,11 +363,12 @@ class SettingsStruct_tmpl PinBootState getPinBootState(int8_t gpio_pin) const; void setPinBootState(int8_t gpio_pin, PinBootState state); - # if FEATURE_EXT1_WAKEUP + # if FEATURE_PIN_WAKEUP // --- Wake GPIO mask handling --- uint64_t getWakeGpioMask() const; void setWakeGpioMask(uint64_t mask); - # endif // if FEATURE_EXT1_WAKEUP + bool& wakeOnHigh(); + # endif // if FEATURE_PIN_WAKEUP #if FEATURE_SPI bool getSPI_pins(int8_t spi_gpios[3], @@ -595,14 +596,10 @@ class SettingsStruct_tmpl int8_t SPI1_SCLK_pin = -1; int8_t SPI1_MISO_pin = -1; int8_t SPI1_MOSI_pin = -1; - #ifdef ESP32 uint32_t wakePin_bitmask_lLo=0; uint32_t wakePin_bitmask_lHi=0; - // int8_t wakeOnLow = 1; // Chromoxdor: a checkbox for wake on LOW or HIGH can be added later, but for now this is as far as i go - unsigned int OLD_TaskDeviceID[N_TASKS - 10] = {0}; // UNUSED: this can be reused - #else - unsigned int OLD_TaskDeviceID[N_TASKS - 8] = {0}; // UNUSED: this can be reused - #endif + boolean wakeOnHigh_ckd = false; + unsigned int OLD_TaskDeviceID[N_TASKS - 11] = {0}; // UNUSED: this can be reused // FIXME TD-er: When used on ESP8266, this conversion union may not work // It might work as it is 32-bit in size. diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 03ac53f06e..02f1bcc237 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -987,7 +987,7 @@ void SettingsStruct_tmpl::setPinBootState(int8_t gpio_pin, PinBootState # endif // ifdef ESP32 } -# if FEATURE_EXT1_WAKEUP +# if FEATURE_PIN_WAKEUP template uint64_t SettingsStruct_tmpl::getWakeGpioMask() const { @@ -1001,6 +1001,10 @@ void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { wakePin_bitmask_lHi = static_cast(mask >> 32); } +template +bool& SettingsStruct_tmpl::wakeOnHigh() { + return wakeOnHigh_ckd; +} #endif #if FEATURE_SPI diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 7e4573f44c..317753a0d6 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -596,7 +596,7 @@ void ESPEasy_setup() rulesProcessing(event); } - # if FEATURE_EXT1_WAKEUP + # if FEATURE_PIN_WAKEUP if (Settings.UseRules) { int8_t wakePin = getWakeupGPIO(); @@ -608,7 +608,7 @@ void ESPEasy_setup() } setupGpioWakeup(Settings.getWakeGpioMask()); } - # endif // if FEATURE_EXT1_WAKEUP + # endif // if FEATURE_PIN_WAKEUP #endif // ifdef ESP32 diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index f7e86eec89..7d3542c7b3 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -178,14 +178,9 @@ void run_compiletime_checks() { static_assert(198u == offsetof(SettingsStruct, TaskDeviceNumber), "NOTIFICATION_MAX has changed?"); // All settings related to N_TASKS - #ifdef ESP32 - static_assert((240 + TASKS_MAX) == offsetof(SettingsStruct, OLD_TaskDeviceID), ""); // 32-bit alignment, so offset of 2 bytes. - #else - static_assert((232 + TASKS_MAX) == offsetof(SettingsStruct, OLD_TaskDeviceID), ""); // 32-bit alignment, so offset of 2 bytes. - #endif + static_assert((244 + TASKS_MAX) == offsetof(SettingsStruct, OLD_TaskDeviceID), ""); // 32-bit alignment, so offset of 2 bytes. static_assert((200 + (67 * TASKS_MAX)) == offsetof(SettingsStruct, ControllerEnabled), ""); - // Used to compute true offset. //const size_t offset = offsetof(SettingsStruct, ControllerEnabled); //check_size(); diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 847fe29744..7382f04406 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -21,8 +21,9 @@ #include "../Helpers/StringConverter.h" #include "../Helpers/StringGenerator_GPIO.h" -# ifdef FEATURE_EXT1_WAKEUP +# ifdef FEATURE_PIN_WAKEUP #include "../../_Plugin_Helper.h" +#include "driver/rtc_io.h" # endif // ******************************************************************************** @@ -67,11 +68,12 @@ void handle_hardware() { ++gpio; } - # if FEATURE_EXT1_WAKEUP + # if FEATURE_PIN_WAKEUP gpio = 0; uint64_t wakeGpioMask = 0; + Settings.wakeOnHigh() = isFormItemChecked(F("WoHi")); // Wake on HIGH or LOW while (gpio <= MAX_GPIO) { - if (validGpio(gpio)) { + if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) { char checkboxId[8]; // "WoL" + max 2 digits + null terminator snprintf(checkboxId, sizeof(checkboxId), "WoL%d", gpio); // if the checkbox is checked, set the corresponding bit in wakeMask @@ -83,7 +85,7 @@ void handle_hardware() { } Settings.setWakeGpioMask(wakeGpioMask); // save the bitmask setupGpioWakeup(wakeGpioMask); //attach gpios for wakeup - # endif // if FEATURE_EXT1_WAKEUP + # endif // if FEATURE_PIN_WAKEUP error += SaveSettings(); addHtmlError(error); @@ -141,16 +143,24 @@ void handle_hardware() { } addFormDetailsEnd(); - # if FEATURE_EXT1_WAKEUP - addFormSubHeader(F("GPIO wake from sleep")); + # if FEATURE_PIN_WAKEUP + #if FEATURE_PIN_WAKEUP == 1 + addFormSubHeader(F("EXT1 Wake-up Pins")); + #else + addFormSubHeader(F("GPIO Wake-up")); + #endif addFormDetailsStart(0); - - addFormNote(F("For pins without internal pull-up, add external resistor if unstable.")); + addFormCheckBox(F("Wake on HIGH"), F("WoHi"), Settings.wakeOnHigh()); + #if FEATURE_PIN_WAKEUP == 1 + addFormNote(F("(default: Wake on LOW) Add an external Pull-Resistor if needed!")); + #else + addFormNote(F("(default: Wake on LOW) No external pull-up/down resistors are needed")); + #endif for (int gpio = 0; gpio <= MAX_GPIO; ++gpio) { addFormPinWakeSelect(gpio, Settings.getWakeGpioMask()); } addFormDetailsEnd(); - # endif // if FEATURE_EXT1_WAKEUP + # endif // if FEATURE_PIN_WAKEUP addFormSeparator(2); diff --git a/src/src/WebServer/Markup_Forms.cpp b/src/src/WebServer/Markup_Forms.cpp index 64b473f960..732ef2bbe2 100644 --- a/src/src/WebServer/Markup_Forms.cpp +++ b/src/src/WebServer/Markup_Forms.cpp @@ -641,7 +641,7 @@ void addFormPinStateSelect(int gpio, int choice) // ******************************************************************************** // Add a GPIO wake select list // ******************************************************************************** -# if FEATURE_EXT1_WAKEUP +# if FEATURE_PIN_WAKEUP void addFormPinWakeSelect(int gpio, uint64_t wakeGpioMask){ if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) { // Check if this GPIO is part of the wake mask diff --git a/src/src/WebServer/Markup_Forms.h b/src/src/WebServer/Markup_Forms.h index 80c30e3d70..22c9807bef 100644 --- a/src/src/WebServer/Markup_Forms.h +++ b/src/src/WebServer/Markup_Forms.h @@ -311,9 +311,9 @@ void addFormPinStateSelect(int gpio, // ******************************************************************************** // Add a GPIO wake select list // ******************************************************************************** -# if FEATURE_EXT1_WAKEUP +# if FEATURE_PIN_WAKEUP void addFormPinWakeSelect(int gpio, uint64_t wakeGpioMask); -# endif // if FEATURE_EXT1_WAKEUP +# endif // if FEATURE_PIN_WAKEUP // ******************************************************************************** // Retrieve return values from form/checkbox. From e21f2ca9824a6ac92face81ebf8a60c987c5f2df Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sun, 29 Mar 2026 18:11:07 +0200 Subject: [PATCH 12/19] [GPIO] adding all the missing bits and pieces part 4 - using bitmask instead of bool for wakeonhigh - refining docs --- docs/source/Hardware/Hardware.rst | 7 ++++--- src/src/DataStructs/SettingsStruct.h | 9 +++++---- src/src/DataStructs_templ/SettingsStruct.cpp | 13 +++++++++++-- src/src/WebServer/HardwarePage.cpp | 2 +- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/docs/source/Hardware/Hardware.rst b/docs/source/Hardware/Hardware.rst index 13df9fd34f..87845a97d1 100644 --- a/docs/source/Hardware/Hardware.rst +++ b/docs/source/Hardware/Hardware.rst @@ -117,8 +117,9 @@ GPIO wake-up on newer devices supports per-pin trigger level configuration, but When the unit wakes up from deep sleep, an event is generated with the GPIO number that caused the wakeup. ``"EVENT: System#GPIOWake=XX"``, where ``XX`` is the GPIO number. -Make sure to add a pull-up or pull-down resistor to the selected GPIO pin(s) if they are not already present, to avoid false wakeups. +Make sure to add a pull-up or pull-down resistor to the selected GPIO pin(s) when needed, to avoid false wakeups. (some GPIO pins have internal pull-up or pull-down resistors, but not all of them, and the internal pull-up/down may not be sufficient for stable operation in all cases) +For **GPIO Wake-up** all internal pull-up/down resistors should work. No need to add them anywhere as this is done automatically. .. note:: @@ -126,12 +127,12 @@ Make sure to add a pull-up or pull-down resistor to the selected GPIO pin(s) if **EXT1 Wake-up (RTC)** - If ``SOC_PM_SUPPORT_EXT1_WAKEUP`` is available, EXT1 wake-up is used: + If ``SOC_PM_SUPPORT_EXT1_WAKEUP`` is available, EXT1 wake-up is used (e.g. ESP32 classic, ESP32-S2, ESP32-S3, ESP32-C6): - Only works on RTC-capable pins - Very low power (RTC domain) - **GPIO Wake-up (Fallback)** + **GPIO Wake-up** On platforms without EXT1 support (e.g. ESP32-C3), GPIO wake-up is used: diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index efc040399b..3b7f5d10f7 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -367,7 +367,8 @@ class SettingsStruct_tmpl // --- Wake GPIO mask handling --- uint64_t getWakeGpioMask() const; void setWakeGpioMask(uint64_t mask); - bool& wakeOnHigh(); + bool wakeOnHigh(); + void setWakeOnHigh(bool value); # endif // if FEATURE_PIN_WAKEUP #if FEATURE_SPI @@ -596,9 +597,9 @@ class SettingsStruct_tmpl int8_t SPI1_SCLK_pin = -1; int8_t SPI1_MISO_pin = -1; int8_t SPI1_MOSI_pin = -1; - uint32_t wakePin_bitmask_lLo=0; - uint32_t wakePin_bitmask_lHi=0; - boolean wakeOnHigh_ckd = false; + uint32_t wakePin_bitmask_lLo = 0; + uint32_t wakePin_bitmask_lHi = 0; + uint32_t wakeOnHigh_ckd = 0; unsigned int OLD_TaskDeviceID[N_TASKS - 11] = {0}; // UNUSED: this can be reused // FIXME TD-er: When used on ESP8266, this conversion union may not work diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 02f1bcc237..5998496676 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -1002,8 +1002,17 @@ void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { } template -bool& SettingsStruct_tmpl::wakeOnHigh() { - return wakeOnHigh_ckd; +bool SettingsStruct_tmpl::wakeOnHigh() { + return (wakeOnHigh_ckd & 0x1) != 0; +} + +template +void SettingsStruct_tmpl::setWakeOnHigh(bool value) { + if (value) { + wakeOnHigh_ckd |= 0x1; + } else { + wakeOnHigh_ckd &= ~0x1; + } } #endif diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 7382f04406..76ae90b8a9 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -71,7 +71,7 @@ void handle_hardware() { # if FEATURE_PIN_WAKEUP gpio = 0; uint64_t wakeGpioMask = 0; - Settings.wakeOnHigh() = isFormItemChecked(F("WoHi")); // Wake on HIGH or LOW + Settings.setWakeOnHigh(isFormItemChecked(F("WoHi"))); // Wake on HIGH or LOW while (gpio <= MAX_GPIO) { if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) { char checkboxId[8]; // "WoL" + max 2 digits + null terminator From 22a1649143f00882f906ea80cb703c1a7f560f5f Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sun, 29 Mar 2026 20:54:10 +0200 Subject: [PATCH 13/19] [GPIO] adding all the missing bits and pieces part 5 - adding all what was suggested.... --- src/_Plugin_Helper.cpp | 6 +++--- src/src/DataStructs/SettingsStruct.h | 6 +++--- src/src/DataStructs_templ/SettingsStruct.cpp | 8 ++------ src/src/Helpers/ESPEasy_checks.cpp | 2 +- src/src/WebServer/HardwarePage.cpp | 10 +++------- src/src/WebServer/Markup_Forms.cpp | 9 +++------ 6 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index c081f926f9..2054059694 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -216,7 +216,7 @@ void setupGpioWakeup(uint64_t ext1_mask) { if (ext1_mask == 0) { #if FEATURE_PIN_WAKEUP == 1 esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT1); - #else + #elif FEATURE_PIN_WAKEUP == 2 esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_GPIO); #endif return; @@ -238,7 +238,7 @@ void setupGpioWakeup(uint64_t ext1_mask) { // Configure pull-ups/pull-downs for all pins in the mask for (int gpio = 0; gpio < 64; ++gpio) { - if (ext1_mask & (1ULL << gpio)) { + if (bitRead(ext1_mask, gpio)) { gpio_num_t rtc_gpio = static_cast(gpio); if (!Settings.wakeOnHigh()) { @@ -261,7 +261,7 @@ void setupGpioWakeup(uint64_t ext1_mask) { // Configure all pins in the mask for (int gpio = 0; gpio < 64; ++gpio) { - if (ext1_mask & (1ULL << gpio)) { + if (bitRead(ext1_mask, gpio)) { gpio_num_t rtc_gpio = static_cast(gpio); // if (!Settings.wakeOnHigh()) { diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index 3b7f5d10f7..ac7b23e1ac 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -533,7 +533,7 @@ class SettingsStruct_tmpl uint32_t WireClockStretchLimit = 0; union { struct { - uint32_t unused_00 : 1; // Bit 0 + uint32_t wakeOnHigh_ckd : 1; // Bit 0 //used for wake on high or low uint32_t unused_01 : 1; // Bit 1 uint32_t unused_02 : 1; // Bit 2 uint32_t unused_03 : 1; // Bit 3 @@ -599,8 +599,8 @@ class SettingsStruct_tmpl int8_t SPI1_MOSI_pin = -1; uint32_t wakePin_bitmask_lLo = 0; uint32_t wakePin_bitmask_lHi = 0; - uint32_t wakeOnHigh_ckd = 0; - unsigned int OLD_TaskDeviceID[N_TASKS - 11] = {0}; // UNUSED: this can be reused + + unsigned int OLD_TaskDeviceID[N_TASKS - 10] = {0}; // UNUSED: this can be reused // FIXME TD-er: When used on ESP8266, this conversion union may not work // It might work as it is 32-bit in size. diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 5998496676..68d6deb681 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -1003,16 +1003,12 @@ void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { template bool SettingsStruct_tmpl::wakeOnHigh() { - return (wakeOnHigh_ckd & 0x1) != 0; + return bitRead(VariousBits_3._all_bits, 0); // Bit 0 = wakeOnHigh_ckd } template void SettingsStruct_tmpl::setWakeOnHigh(bool value) { - if (value) { - wakeOnHigh_ckd |= 0x1; - } else { - wakeOnHigh_ckd &= ~0x1; - } + bitWrite(VariousBits_3._all_bits, 0, value); // Bit 0 = wakeOnHigh_ckd } #endif diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 7d3542c7b3..b9b9e709b8 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -178,7 +178,7 @@ void run_compiletime_checks() { static_assert(198u == offsetof(SettingsStruct, TaskDeviceNumber), "NOTIFICATION_MAX has changed?"); // All settings related to N_TASKS - static_assert((244 + TASKS_MAX) == offsetof(SettingsStruct, OLD_TaskDeviceID), ""); // 32-bit alignment, so offset of 2 bytes. + static_assert((240 + TASKS_MAX) == offsetof(SettingsStruct, OLD_TaskDeviceID), ""); // 32-bit alignment, so offset of 2 bytes. static_assert((200 + (67 * TASKS_MAX)) == offsetof(SettingsStruct, ControllerEnabled), ""); // Used to compute true offset. diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 76ae90b8a9..58175f5de7 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -74,12 +74,8 @@ void handle_hardware() { Settings.setWakeOnHigh(isFormItemChecked(F("WoHi"))); // Wake on HIGH or LOW while (gpio <= MAX_GPIO) { if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) { - char checkboxId[8]; // "WoL" + max 2 digits + null terminator - snprintf(checkboxId, sizeof(checkboxId), "WoL%d", gpio); - // if the checkbox is checked, set the corresponding bit in wakeMask - if (isFormItemChecked(checkboxId)) { - wakeGpioMask |= (1ULL << gpio); - } + String checkboxId = strformat(F("WoL%d"), gpio); + bitWrite(wakeGpioMask, gpio, isFormItemChecked(checkboxId)); } ++gpio; } @@ -149,7 +145,7 @@ void handle_hardware() { #else addFormSubHeader(F("GPIO Wake-up")); #endif - addFormDetailsStart(0); + addFormDetailsStart(Settings.getWakeGpioMask() != 0); addFormCheckBox(F("Wake on HIGH"), F("WoHi"), Settings.wakeOnHigh()); #if FEATURE_PIN_WAKEUP == 1 addFormNote(F("(default: Wake on LOW) Add an external Pull-Resistor if needed!")); diff --git a/src/src/WebServer/Markup_Forms.cpp b/src/src/WebServer/Markup_Forms.cpp index 732ef2bbe2..bc2b17de05 100644 --- a/src/src/WebServer/Markup_Forms.cpp +++ b/src/src/WebServer/Markup_Forms.cpp @@ -645,12 +645,9 @@ void addFormPinStateSelect(int gpio, int choice) void addFormPinWakeSelect(int gpio, uint64_t wakeGpioMask){ if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) { // Check if this GPIO is part of the wake mask - bool checked = (wakeGpioMask & (1ULL << gpio)) != 0; - char label[20]; // "Wake from GPIO-" + GPIO number + null - char checkboxId[10]; // "WoL" + GPIO number + null - - snprintf(checkboxId, sizeof(checkboxId), "WoL%d", gpio); - snprintf(label, sizeof(label), "Wake from GPIO-%d", gpio); + bool checked = bitRead(wakeGpioMask, gpio); + String checkboxId = strformat(F("WoL%d"), gpio); + String label = strformat(F("Wake from GPIO-%d"), gpio); addFormCheckBox(label, checkboxId, checked); } From 1a5be1f0fb2250d2a0842ac0a3eaf80174011c89 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:10:10 +0200 Subject: [PATCH 14/19] [GPIO] adding all the missing bits and pieces part 6 - cleanup + refinements --- src/_Plugin_Helper.cpp | 8 -------- src/src/DataStructs_templ/SettingsStruct.cpp | 4 ++-- src/src/WebServer/HardwarePage.cpp | 8 +++++++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index 2054059694..3d2fa47a2a 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -263,14 +263,6 @@ void setupGpioWakeup(uint64_t ext1_mask) { for (int gpio = 0; gpio < 64; ++gpio) { if (bitRead(ext1_mask, gpio)) { gpio_num_t rtc_gpio = static_cast(gpio); - - // if (!Settings.wakeOnHigh()) { - // gpio_pullup_en(rtc_gpio); - // gpio_pulldown_dis(rtc_gpio); - // } else { - // gpio_pullup_dis(rtc_gpio); - // gpio_pulldown_en(rtc_gpio); - // } } } diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 68d6deb681..4cf1ec3e95 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -1003,12 +1003,12 @@ void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { template bool SettingsStruct_tmpl::wakeOnHigh() { - return bitRead(VariousBits_3._all_bits, 0); // Bit 0 = wakeOnHigh_ckd + return VariousBits_3.wakeOnHigh_ckd; } template void SettingsStruct_tmpl::setWakeOnHigh(bool value) { - bitWrite(VariousBits_3._all_bits, 0, value); // Bit 0 = wakeOnHigh_ckd + VariousBits_3.wakeOnHigh_ckd = value; } #endif diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 58175f5de7..535ad7cbf8 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -132,7 +132,13 @@ void handle_hardware() { #endif // if FEATURE_SD addFormSubHeader(F("GPIO boot states")); - addFormDetailsStart(0); + bool expandBootStates{}; + int gpio = 0; + while (!expandBootStates && gpio <= MAX_GPIO) { + expandBootStates = Settings.getPinBootState(gpio) != PinBootState::Default_state; + ++gpio; + } + addFormDetailsStart(expandBootStates); for (int gpio = 0; gpio <= MAX_GPIO; ++gpio) { addFormPinStateSelect(gpio, static_cast(Settings.getPinBootState(gpio))); From 77a6f2bf22f6be075171ead1d9ce788219db5827 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:34:28 +0200 Subject: [PATCH 15/19] [GPIO] adding all the missing bits and pieces part 7 --- src/src/DataStructs/SettingsStruct.h | 9 +++++---- src/src/DataStructs_templ/SettingsStruct.cpp | 9 --------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index ac7b23e1ac..b382b0b2fe 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -363,13 +363,14 @@ class SettingsStruct_tmpl PinBootState getPinBootState(int8_t gpio_pin) const; void setPinBootState(int8_t gpio_pin, PinBootState state); - # if FEATURE_PIN_WAKEUP +#if FEATURE_PIN_WAKEUP // --- Wake GPIO mask handling --- uint64_t getWakeGpioMask() const; void setWakeGpioMask(uint64_t mask); - bool wakeOnHigh(); - void setWakeOnHigh(bool value); - # endif // if FEATURE_PIN_WAKEUP + + inline bool wakeOnHigh() { return VariousBits_3.wakeOnHigh_ckd; } + inline void setWakeOnHigh(bool value) { VariousBits_3.wakeOnHigh_ckd = value; } +#endif // if FEATURE_PIN_WAKEUP #if FEATURE_SPI bool getSPI_pins(int8_t spi_gpios[3], diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 4cf1ec3e95..c6636e92b7 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -1001,15 +1001,6 @@ void SettingsStruct_tmpl::setWakeGpioMask(uint64_t mask) { wakePin_bitmask_lHi = static_cast(mask >> 32); } -template -bool SettingsStruct_tmpl::wakeOnHigh() { - return VariousBits_3.wakeOnHigh_ckd; -} - -template -void SettingsStruct_tmpl::setWakeOnHigh(bool value) { - VariousBits_3.wakeOnHigh_ckd = value; -} #endif #if FEATURE_SPI From 749d9a3fc1ee0f46c60d4613bae2f330927280ab Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Mon, 30 Mar 2026 10:58:15 +0200 Subject: [PATCH 16/19] [GPIO] adding all the missing bits and pieces part 8 - added a warning to the docs - added missing monitor keywords --- docs/source/Hardware/Hardware.rst | 8 ++++++-- static/espeasy.js | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/source/Hardware/Hardware.rst b/docs/source/Hardware/Hardware.rst index 87845a97d1..1251dc48ac 100644 --- a/docs/source/Hardware/Hardware.rst +++ b/docs/source/Hardware/Hardware.rst @@ -115,7 +115,7 @@ GPIO wake-up on newer devices supports per-pin trigger level configuration, but **TODO:** Integrate per-pin trigger level selection for GPIO wake-up. When the unit wakes up from deep sleep, an event is generated with the GPIO number that caused the wakeup. -``"EVENT: System#GPIOWake=XX"``, where ``XX`` is the GPIO number. +``"EVENT: System#GPIOWake=X"``, where ``X`` is the GPIO number. Make sure to add a pull-up or pull-down resistor to the selected GPIO pin(s) when needed, to avoid false wakeups. (some GPIO pins have internal pull-up or pull-down resistors, but not all of them, and the internal pull-up/down may not be sufficient for stable operation in all cases) @@ -144,4 +144,8 @@ For **GPIO Wake-up** all internal pull-up/down resistors should work. No need to - EXT1: preferred, low power - GPIO wake-up: fallback for newer chips, more flexible but less efficient - The firmware automatically selects the correct method at compile time. \ No newline at end of file + The firmware automatically selects the correct method at compile time. + +.. warning:: + When using this feature, be aware that if you are also using a GPIO in rules (e.g., Monitor,GPIO,8) or in a Plugin Task (P001), you might get an event at wakeup if the button is pressed slightly too long, which can cause unexpected behavior. + If this is unwanted, take precautions such as monitoring the GPIO a bit later after boot (e.g., with a timer), or disabling the corresponding task and enabling it later after boot (e.g., with a timer) to avoid this. \ No newline at end of file diff --git a/static/espeasy.js b/static/espeasy.js index c1991ce179..ff6c2092f6 100644 --- a/static/espeasy.js +++ b/static/espeasy.js @@ -12,7 +12,7 @@ var commonCommands = ["AccessInfo", "Background", "Build", "ClearAccessBlock", " "UdpPort", "UdpTest", "Unit", "UseNTP", "WdConfig", "WdRead", "WiFi", "WiFiAllowAP", "WiFiAPMode", "WiFiConnect", "WiFiDisconnect", "WiFiKey", "WiFiKey2", "WiFiMode", "WiFiScan", "WiFiSSID", "WiFiSSID2", "WiFiSTAMode", "Event", "AsyncEvent", - "GPIO", "GPIOToggle", "LongPulse", "LongPulse_mS", "Monitor", "Pulse", "PWM", "Servo", "Status", "Tone", "RTTTL", "UnMonitor", + "GPIO", "GPIOToggle", "LongPulse", "LongPulse_mS", "Monitor", "Monitor,GPIO", "Pulse", "PWM", "Servo", "Status", "Tone", "RTTTL", "UnMonitor", "UnMonitor,GPIO", "Provision", "Provision,Config", "Provision,Security", "Provision,Notification", "Provision,Provision", "Provision,Rules", "Provision,CustomCdnUrl", "Provision,Firmware"]; var commonEvents = ["Clock#Time", "Login#Failed", "MQTT#Connected", "MQTT#Disconnected", "MQTTimport#Connected", "MQTTimport#Disconnected", "Rules#Timer", "System#Boot", "System#BootMode", "System#BootCause", "System#GPIOWake", "System#Sleep", "System#Wake", "TaskExit#", "TaskInit#", "ThingspeakReply", "Time#Initialized", "Time#Set", "WiFi#APmodeDisabled", "WiFi#APmodeEnabled", From 37eaa99835b0884c479ce1a9e980a565a6509ed6 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Mon, 30 Mar 2026 12:12:43 +0200 Subject: [PATCH 17/19] [GPIO] adding all the missing bits and pieces part 9 - added a "disable pull resistors" checkbox for EXT1 Wakeup --- docs/source/Hardware/Hardware.rst | 1 + src/_Plugin_Helper.cpp | 16 +++++++++++----- src/src/DataStructs/SettingsStruct.h | 6 ++++-- src/src/WebServer/HardwarePage.cpp | 4 ++++ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/docs/source/Hardware/Hardware.rst b/docs/source/Hardware/Hardware.rst index 1251dc48ac..35187ef32d 100644 --- a/docs/source/Hardware/Hardware.rst +++ b/docs/source/Hardware/Hardware.rst @@ -110,6 +110,7 @@ GPIO wake from sleep This feature is only available on ESP32 devices. Supported GPIO pins can be selected to wake the unit from deep sleep. +For ESP32 devices with EXT1 wake-up support, the internal RTC-Resistors can be disabled globally and it applies to **all** selected pins. The signal level (HIGH or LOW) is configured globally and applies to **all** selected pins. GPIO wake-up on newer devices supports per-pin trigger level configuration, but this comes at the cost of higher power consumption. **TODO:** Integrate per-pin trigger level selection for GPIO wake-up. diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index 3d2fa47a2a..91921ad1e8 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -241,12 +241,18 @@ void setupGpioWakeup(uint64_t ext1_mask) { if (bitRead(ext1_mask, gpio)) { gpio_num_t rtc_gpio = static_cast(gpio); - if (!Settings.wakeOnHigh()) { - rtc_gpio_pullup_en(rtc_gpio); - rtc_gpio_pulldown_dis(rtc_gpio); - } else { + if (!Settings.getWakePulls()) { + if (!Settings.wakeOnHigh()) { + rtc_gpio_pullup_en(rtc_gpio); + rtc_gpio_pulldown_dis(rtc_gpio); + } else { + rtc_gpio_pullup_dis(rtc_gpio); + rtc_gpio_pulldown_en(rtc_gpio); + } + } + else { rtc_gpio_pullup_dis(rtc_gpio); - rtc_gpio_pulldown_en(rtc_gpio); + rtc_gpio_pulldown_dis(rtc_gpio); } } } diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index b382b0b2fe..6e0f47583d 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -370,6 +370,8 @@ class SettingsStruct_tmpl inline bool wakeOnHigh() { return VariousBits_3.wakeOnHigh_ckd; } inline void setWakeOnHigh(bool value) { VariousBits_3.wakeOnHigh_ckd = value; } + inline bool getWakePulls() { return VariousBits_3.diableWakePulls; } + inline void setWakePulls(bool value) { VariousBits_3.diableWakePulls = value; } #endif // if FEATURE_PIN_WAKEUP #if FEATURE_SPI @@ -534,8 +536,8 @@ class SettingsStruct_tmpl uint32_t WireClockStretchLimit = 0; union { struct { - uint32_t wakeOnHigh_ckd : 1; // Bit 0 //used for wake on high or low - uint32_t unused_01 : 1; // Bit 1 + uint32_t wakeOnHigh_ckd : 1; // Bit 0 //HardwarePage: used for wake on high or low + uint32_t diableWakePulls : 1; // Bit 1 //HardwarePage: used for for disabling pulls in general uint32_t unused_02 : 1; // Bit 2 uint32_t unused_03 : 1; // Bit 3 uint32_t unused_04 : 1; // Bit 4 diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 535ad7cbf8..b0969e5292 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -72,6 +72,7 @@ void handle_hardware() { gpio = 0; uint64_t wakeGpioMask = 0; Settings.setWakeOnHigh(isFormItemChecked(F("WoHi"))); // Wake on HIGH or LOW + Settings.setWakePulls(isFormItemChecked(F("WakePulls"))); // disable internal pulls for wakeup pins while (gpio <= MAX_GPIO) { if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) { String checkboxId = strformat(F("WoL%d"), gpio); @@ -152,6 +153,9 @@ void handle_hardware() { addFormSubHeader(F("GPIO Wake-up")); #endif addFormDetailsStart(Settings.getWakeGpioMask() != 0); + #if FEATURE_PIN_WAKEUP == 1 + addFormCheckBox(F("Disable internal pulls"), F("WakePulls"), Settings.getWakePulls()); + #endif addFormCheckBox(F("Wake on HIGH"), F("WoHi"), Settings.wakeOnHigh()); #if FEATURE_PIN_WAKEUP == 1 addFormNote(F("(default: Wake on LOW) Add an external Pull-Resistor if needed!")); From 839d30e02d406935e0eb23c9b46e8925bc810b3c Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Mon, 30 Mar 2026 12:44:47 +0200 Subject: [PATCH 18/19] [GPIO] adding all the missing bits and pieces part 10 - refinements --- docs/source/Hardware/Hardware.rst | 2 +- src/_Plugin_Helper.cpp | 7 ------- src/src/WebServer/HardwarePage.cpp | 2 ++ 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/source/Hardware/Hardware.rst b/docs/source/Hardware/Hardware.rst index 35187ef32d..7b979cca05 100644 --- a/docs/source/Hardware/Hardware.rst +++ b/docs/source/Hardware/Hardware.rst @@ -128,7 +128,7 @@ For **GPIO Wake-up** all internal pull-up/down resistors should work. No need to **EXT1 Wake-up (RTC)** - If ``SOC_PM_SUPPORT_EXT1_WAKEUP`` is available, EXT1 wake-up is used (e.g. ESP32 classic, ESP32-S2, ESP32-S3, ESP32-C6): + If ``SOC_PM_SUPPORT_EXT1_WAKEUP`` is available, EXT1 wake-up is used (e.g. ESP32 classic, ESP32-S2, ESP32-S3, ESP32-C6, ESP32-H2): - Only works on RTC-capable pins - Very low power (RTC domain) diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index 91921ad1e8..a6582230a8 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -265,13 +265,6 @@ void setupGpioWakeup(uint64_t ext1_mask) { esp_deepsleep_gpio_wake_up_mode_t gpio_mode = Settings.wakeOnHigh() ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW; - // Configure all pins in the mask - for (int gpio = 0; gpio < 64; ++gpio) { - if (bitRead(ext1_mask, gpio)) { - gpio_num_t rtc_gpio = static_cast(gpio); - } - } - esp_deep_sleep_enable_gpio_wakeup(ext1_mask, gpio_mode); #endif diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index b0969e5292..6be869135b 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -72,7 +72,9 @@ void handle_hardware() { gpio = 0; uint64_t wakeGpioMask = 0; Settings.setWakeOnHigh(isFormItemChecked(F("WoHi"))); // Wake on HIGH or LOW + #if FEATURE_PIN_WAKEUP == 1 Settings.setWakePulls(isFormItemChecked(F("WakePulls"))); // disable internal pulls for wakeup pins + #endif while (gpio <= MAX_GPIO) { if (esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) { String checkboxId = strformat(F("WoL%d"), gpio); From 50f98118c8d9d1911bdd65005138418950884da0 Mon Sep 17 00:00:00 2001 From: chromoxdor <33860956+chromoxdor@users.noreply.github.com> Date: Mon, 30 Mar 2026 15:29:12 +0200 Subject: [PATCH 19/19] [GPIO] adding all the missing bits and pieces part 11 - fixed typos --- src/src/DataStructs/SettingsStruct.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index 6e0f47583d..a344303742 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -370,8 +370,8 @@ class SettingsStruct_tmpl inline bool wakeOnHigh() { return VariousBits_3.wakeOnHigh_ckd; } inline void setWakeOnHigh(bool value) { VariousBits_3.wakeOnHigh_ckd = value; } - inline bool getWakePulls() { return VariousBits_3.diableWakePulls; } - inline void setWakePulls(bool value) { VariousBits_3.diableWakePulls = value; } + inline bool getWakePulls() { return VariousBits_3.disableWakePulls; } + inline void setWakePulls(bool value) { VariousBits_3.disableWakePulls = value; } #endif // if FEATURE_PIN_WAKEUP #if FEATURE_SPI @@ -537,7 +537,7 @@ class SettingsStruct_tmpl union { struct { uint32_t wakeOnHigh_ckd : 1; // Bit 0 //HardwarePage: used for wake on high or low - uint32_t diableWakePulls : 1; // Bit 1 //HardwarePage: used for for disabling pulls in general + uint32_t disableWakePulls : 1; // Bit 1 //HardwarePage: used for disabling internal pulls in general uint32_t unused_02 : 1; // Bit 2 uint32_t unused_03 : 1; // Bit 3 uint32_t unused_04 : 1; // Bit 4