ESPHome 2025.7.3
Loading...
Searching...
No Matches
esp32_touch_common.cpp
Go to the documentation of this file.
1#ifdef USE_ESP32
2
3#include "esp32_touch.h"
4#include "esphome/core/log.h"
5#include <cinttypes>
6
7#include "soc/rtc.h"
8
9namespace esphome {
10namespace esp32_touch {
11
12static const char *const TAG = "esp32_touch";
13
17 const char *atten_s = get_voltage_attenuation_str(this->voltage_attenuation_);
18
19 ESP_LOGCONFIG(TAG,
20 "Config for ESP32 Touch Hub:\n"
21 " Meas cycle: %.2fms\n"
22 " Sleep cycle: %.2fms\n"
23 " Low Voltage Reference: %s\n"
24 " High Voltage Reference: %s\n"
25 " Voltage Attenuation: %s\n"
26 " Release Timeout: %" PRIu32 "ms\n",
27 this->meas_cycle_ / (8000000.0f / 1000.0f), this->sleep_cycle_ / (150000.0f / 1000.0f), lv_s, hv_s,
28 atten_s, this->release_timeout_ms_);
29}
30
32 for (auto *child : this->children_) {
33 LOG_BINARY_SENSOR(" ", "Touch Pad", child);
34 ESP_LOGCONFIG(TAG,
35 " Pad: T%u\n"
36 " Threshold: %" PRIu32 "\n"
37 " Benchmark: %" PRIu32,
38 (unsigned) child->touch_pad_, child->threshold_, child->benchmark_);
39 }
40}
41
43 // Queue size calculation: children * 4 allows for burst scenarios where ISR
44 // fires multiple times before main loop processes.
45 size_t queue_size = this->children_.size() * 4;
46 if (queue_size < 8)
47 queue_size = 8;
48
49#ifdef USE_ESP32_VARIANT_ESP32
50 this->touch_queue_ = xQueueCreate(queue_size, sizeof(TouchPadEventV1));
51#else
52 this->touch_queue_ = xQueueCreate(queue_size, sizeof(TouchPadEventV2));
53#endif
54
55 if (this->touch_queue_ == nullptr) {
56 ESP_LOGE(TAG, "Failed to create touch event queue of size %" PRIu32, (uint32_t) queue_size);
57 this->mark_failed();
58 return false;
59 }
60 return true;
61}
62
64 if (this->touch_queue_) {
65 vQueueDelete(this->touch_queue_);
66 this->touch_queue_ = nullptr;
67 }
68}
69
71 bool is_wakeup_source = false;
72
73 // Check if any pad is configured for wakeup
74 for (auto *child : this->children_) {
75 if (child->get_wakeup_threshold() != 0) {
76 is_wakeup_source = true;
77
78#ifdef USE_ESP32_VARIANT_ESP32
79 // ESP32 v1: No filter available when using as wake-up source.
80 touch_pad_config(child->get_touch_pad(), child->get_wakeup_threshold());
81#else
82 // ESP32-S2/S3 v2: Set threshold for wakeup
83 touch_pad_set_thresh(child->get_touch_pad(), child->get_wakeup_threshold());
84#endif
85 }
86 }
87
88 if (!is_wakeup_source) {
89 // If no pad is configured for wakeup, deinitialize touch pad
90 touch_pad_deinit();
91 }
92}
93
95 if (this->setup_mode_ && now - this->setup_mode_last_log_print_ > SETUP_MODE_LOG_INTERVAL_MS) {
96 for (auto *child : this->children_) {
97#ifdef USE_ESP32_VARIANT_ESP32
98 ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(),
99 (uint32_t) child->get_touch_pad(), child->value_);
100#else
101 // Read the value being used for touch detection
102 uint32_t value = this->read_touch_value(child->get_touch_pad());
103 ESP_LOGD(TAG, "Touch Pad '%s' (T%d): %d", child->get_name().c_str(), child->get_touch_pad(), value);
104#endif
105 }
106 this->setup_mode_last_log_print_ = now;
107 }
108}
109
112 return false;
113 }
114 this->last_release_check_ = now;
115 return true;
116}
117
119 if (!child->initial_state_published_) {
120 // Check if enough time has passed since startup
121 if (now > this->release_timeout_ms_) {
122 child->publish_initial_state(false);
123 child->initial_state_published_ = true;
124 ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (initial)", child->get_name().c_str());
125 }
126 }
127}
128
130 // Disable the loop to save CPU cycles when all pads are off and not in setup mode.
131 if (pads_off == this->children_.size() && !this->setup_mode_) {
132 this->disable_loop();
133 }
134}
135
137 // Calculate release timeout based on sleep cycle
138 // Design note: Hardware limitation - interrupts only fire reliably on touch (not release)
139 // We must use timeout-based detection for release events
140 // Formula: 3 sleep cycles converted to ms, with MINIMUM_RELEASE_TIME_MS minimum
141 // Per ESP-IDF docs: t_sleep = sleep_cycle / SOC_CLK_RC_SLOW_FREQ_APPROX
142
143 uint32_t rtc_freq = rtc_clk_slow_freq_get_hz();
144
145 // Calculate timeout as 3 sleep cycles
146 this->release_timeout_ms_ = (this->sleep_cycle_ * 1000 * 3) / rtc_freq;
147
150 }
151
152 // Check for releases at 1/4 the timeout interval
153 // Since hardware doesn't generate reliable release interrupts, we must poll
154 // for releases in the main loop. Checking at 1/4 the timeout interval provides
155 // a good balance between responsiveness and efficiency.
157}
158
159} // namespace esp32_touch
160} // namespace esphome
161
162#endif // USE_ESP32
virtual void mark_failed()
Mark this component as failed.
void disable_loop()
Disable this component's loop.
const StringRef & get_name() const
constexpr const char * c_str() const
Definition string_ref.h:69
void publish_initial_state(bool new_state)
Publish the initial state, this will not make the callback manager send callbacks and is meant only f...
Simple helper class to expose a touch pad value as a binary sensor.
void check_and_disable_loop_if_all_released_(size_t pads_off)
void publish_initial_state_if_needed_(ESP32TouchBinarySensor *child, uint32_t now)
static const char * get_high_voltage_reference_str(touch_high_volt_t ref)
static constexpr uint32_t MINIMUM_RELEASE_TIME_MS
static const char * get_low_voltage_reference_str(touch_low_volt_t ref)
std::vector< ESP32TouchBinarySensor * > children_
Definition esp32_touch.h:90
uint32_t read_touch_value(touch_pad_t pad) const
static const char * get_voltage_attenuation_str(touch_volt_atten_t atten)
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7