From 6cbd1479c6bdb351799b327423ecff4a99cf2dc2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 30 Jun 2025 13:46:47 -0500 Subject: [PATCH] loop --- .../components/esp32_touch/esp32_touch_v1.cpp | 17 +++++++++++++++++ .../components/esp32_touch/esp32_touch_v2.cpp | 10 ++++++++++ 2 files changed, 27 insertions(+) diff --git a/esphome/components/esp32_touch/esp32_touch_v1.cpp b/esphome/components/esp32_touch/esp32_touch_v1.cpp index e805bf5f4c..7b46cd9280 100644 --- a/esphome/components/esp32_touch/esp32_touch_v1.cpp +++ b/esphome/components/esp32_touch/esp32_touch_v1.cpp @@ -148,6 +148,7 @@ void ESP32TouchComponent::loop() { } last_release_check = now; + size_t pads_off = 0; for (auto *child : this->children_) { touch_pad_t pad = child->get_touch_pad(); @@ -158,6 +159,7 @@ void ESP32TouchComponent::loop() { child->publish_initial_state(false); this->initial_state_published_[pad] = true; ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (initial)", child->get_name().c_str()); + pads_off++; } } else if (child->last_state_) { // Pad is currently in touched state - check for release timeout @@ -170,9 +172,23 @@ void ESP32TouchComponent::loop() { child->last_state_ = false; child->publish_state(false); ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (timeout)", child->get_name().c_str()); + pads_off++; } + } else { + // Pad is already off + pads_off++; } } + + // Disable the loop to save CPU cycles when all pads are off and not in setup mode. + // The loop will be re-enabled by the ISR when any touch pad is touched. + // v1 hardware limitations require us to check all pads are off because: + // - v1 only generates interrupts on touch events (not releases) + // - We must poll for release timeouts in the main loop + // - We can only safely disable when no pads need timeout monitoring + if (pads_off == this->children_.size() && !this->setup_mode_) { + this->disable_loop(); + } } void ESP32TouchComponent::on_shutdown() { @@ -242,6 +258,7 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) { // Send to queue from ISR - non-blocking, drops if queue full BaseType_t x_higher_priority_task_woken = pdFALSE; xQueueSendFromISR(component->touch_queue_, &event, &x_higher_priority_task_woken); + component->enable_loop_soon_any_context(); if (x_higher_priority_task_woken) { portYIELD_FROM_ISR(); } diff --git a/esphome/components/esp32_touch/esp32_touch_v2.cpp b/esphome/components/esp32_touch/esp32_touch_v2.cpp index a34353e22a..b9e3da52c4 100644 --- a/esphome/components/esp32_touch/esp32_touch_v2.cpp +++ b/esphome/components/esp32_touch/esp32_touch_v2.cpp @@ -303,6 +303,15 @@ void ESP32TouchComponent::loop() { break; } } + if (!this->setup_mode_) { + // Disable the loop to save CPU cycles when not in setup mode. + // The loop will be re-enabled by the ISR when any touch event occurs. + // Unlike v1, we don't need to check if all pads are off because: + // - v2 hardware generates interrupts for both touch AND release events + // - We don't need to poll for timeouts or releases + // - All state changes are interrupt-driven + this->disable_loop(); + } } void ESP32TouchComponent::on_shutdown() { @@ -327,6 +336,7 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) { // Send event to queue for processing in main loop xQueueSendFromISR(component->touch_queue_, &event, &x_higher_priority_task_woken); + component->enable_loop_soon_any_context(); if (x_higher_priority_task_woken) { portYIELD_FROM_ISR();