Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b5026a5
[GPIO][P001] Added “Wake on Button Press” functionality.
chromoxdor Mar 20, 2026
b1abf4a
[P001] Switched to EXT1 for all devices for lowest power consumption
chromoxdor Mar 21, 2026
cedc78d
[P001] changed a line according to Tons suggestion
chromoxdor Mar 21, 2026
6f3544a
[GPIO] Setting moved to Hardware tab
chromoxdor Mar 22, 2026
9cdac4d
[GPIO] Setting moved to Hardware tab (removes unnecessary functions)
chromoxdor Mar 22, 2026
3b5d8c7
[GPIO] add check for gpiowake event
chromoxdor Mar 22, 2026
ac6ece0
[GPIO] fixed a c&p mistake
chromoxdor Mar 22, 2026
2365dff
[GPIO] adding details expansion + rules-keywords
chromoxdor Mar 23, 2026
3e6c299
[GPIO] adding all the missing bits and pieces.
chromoxdor Mar 28, 2026
1ca3eb5
[GPIO] adding all the missing bits and pieces part 2
chromoxdor Mar 28, 2026
90a2071
[GPIO] adding all the missing bits and pieces part 3
chromoxdor Mar 29, 2026
e21f2ca
[GPIO] adding all the missing bits and pieces part 4
chromoxdor Mar 29, 2026
22a1649
[GPIO] adding all the missing bits and pieces part 5
chromoxdor Mar 29, 2026
1a5be1f
[GPIO] adding all the missing bits and pieces part 6
chromoxdor Mar 29, 2026
77a6f2b
[GPIO] adding all the missing bits and pieces part 7
chromoxdor Mar 29, 2026
749d9a3
[GPIO] adding all the missing bits and pieces part 8
chromoxdor Mar 30, 2026
37eaa99
[GPIO] adding all the missing bits and pieces part 9
chromoxdor Mar 30, 2026
839d30e
[GPIO] adding all the missing bits and pieces part 10
chromoxdor Mar 30, 2026
50f9811
[GPIO] adding all the missing bits and pieces part 11
chromoxdor Mar 30, 2026
f74635f
Merge branch 'mega' into GPIO]-P001]-add-wake-from-sleep-option
chromoxdor Apr 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/_Plugin_Helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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] = {};

Expand Down Expand Up @@ -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_num_t>(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
5 changes: 5 additions & 0 deletions src/_Plugin_Helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
14 changes: 13 additions & 1 deletion src/src/DataStructs/SettingsStruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
15 changes: 15 additions & 0 deletions src/src/DataStructs_templ/SettingsStruct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,21 @@ void SettingsStruct_tmpl<N_TASKS>::setPinBootState(int8_t gpio_pin, PinBootState
}
# endif // ifdef ESP32
}

# if SOC_PM_SUPPORT_EXT1_WAKEUP

// template<uint32_t N_TASKS>
// uint64_t SettingsStruct_tmpl<N_TASKS>::getWakeGpioMask() const {
// return WakeGpioMask;
// }

// template<uint32_t N_TASKS>
// void SettingsStruct_tmpl<N_TASKS>::setWakeGpioMask(uint64_t mask) {
// WakeGpioMask = mask;
// }

#endif

#if FEATURE_SPI
template<uint32_t N_TASKS>
bool SettingsStruct_tmpl<N_TASKS>::isSPI_enabled(uint8_t spi_bus) const {
Expand Down
22 changes: 22 additions & 0 deletions src/src/ESPEasyCore/ESPEasy_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -588,6 +595,21 @@ void ESPEasy_setup()
event += bitRead(gpio_strap, 5);
rulesProcessing(event);
}

# if SOC_PM_SUPPORT_EXT1_WAKEUP
if (Settings.UseRules)
{
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

#endif // ifdef ESP32

#if FEATURE_REPORTING
Expand Down
30 changes: 30 additions & 0 deletions src/src/WebServer/HardwarePage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -63,6 +67,22 @@ void handle_hardware() {
}
++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);

// 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);
}
Expand Down Expand Up @@ -116,6 +136,16 @@ void handle_hardware() {
for (int gpio = 0; gpio <= MAX_GPIO; ++gpio) {
addFormPinStateSelect(gpio, static_cast<int>(Settings.getPinBootState(gpio)));
}

# if SOC_PM_SUPPORT_EXT1_WAKEUP
Comment thread
chromoxdor marked this conversation as resolved.
Outdated
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);
Comment thread
chromoxdor marked this conversation as resolved.
Outdated
}
# endif // if SOC_PM_SUPPORT_EXT1_WAKEUP

addFormSeparator(2);

html_TR_TD();
Expand Down
19 changes: 19 additions & 0 deletions src/src/WebServer/Markup_Forms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Comment thread
chromoxdor marked this conversation as resolved.
Outdated

addFormCheckBox(label, checkboxId, checked);
}
}
# endif

// ********************************************************************************
// Retrieve return values from form/checkbox.
// ********************************************************************************
Expand Down
7 changes: 7 additions & 0 deletions src/src/WebServer/Markup_Forms.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
// ********************************************************************************
Expand Down