From 7b1fa5b2fad6bd78b1fa1beb0cdf3ada4652da74 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 16 Mar 2023 16:05:15 +1300 Subject: [PATCH] Add touch pad support for esp32-s2/s3 --- esphome/components/esp32_touch/__init__.py | 21 ++- .../components/esp32_touch/binary_sensor.py | 17 +- esphome/components/esp32_touch/esp32_touch.h | 35 ++-- .../{esp32_touch.cpp => esp32_touch_v1.cpp} | 12 +- .../components/esp32_touch/esp32_touch_v2.cpp | 172 ++++++++++++++++++ 5 files changed, 228 insertions(+), 29 deletions(-) rename esphome/components/esp32_touch/{esp32_touch.cpp => esp32_touch_v1.cpp} (95%) create mode 100644 esphome/components/esp32_touch/esp32_touch_v2.cpp diff --git a/esphome/components/esp32_touch/__init__.py b/esphome/components/esp32_touch/__init__.py index 3c9bef9665..415d7365e3 100644 --- a/esphome/components/esp32_touch/__init__.py +++ b/esphome/components/esp32_touch/__init__.py @@ -51,14 +51,23 @@ VOLTAGE_ATTENUATION = { "0V": cg.global_ns.TOUCH_HVOLT_ATTEN_0V, } + +def _default_iir_filter(config): + if esp32.get_esp32_variant() == esp32.const.VARIANT_ESP32: + if CONF_IIR_FILTER not in config: + config[CONF_IIR_FILTER] = "0ms" + return config + + CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(ESP32TouchComponent), cv.Optional(CONF_SETUP_MODE, default=False): cv.boolean, - cv.Optional( - CONF_IIR_FILTER, default="0ms" - ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_IIR_FILTER): cv.All( + cv.positive_time_period_milliseconds, + esp32.only_on_variant(supported=[esp32.const.VARIANT_ESP32]), + ), cv.Optional(CONF_SLEEP_DURATION, default="27306us"): cv.All( cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=436906)) ), @@ -79,8 +88,11 @@ CONFIG_SCHEMA = cv.All( esp32.only_on_variant( supported=[ esp32.const.VARIANT_ESP32, + esp32.const.VARIANT_ESP32S2, + esp32.const.VARIANT_ESP32S3, ] ), + _default_iir_filter, ) @@ -89,7 +101,8 @@ async def to_code(config): await cg.register_component(touch, config) cg.add(touch.set_setup_mode(config[CONF_SETUP_MODE])) - cg.add(touch.set_iir_filter(config[CONF_IIR_FILTER])) + if CONF_IIR_FILTER in config: + cg.add(touch.set_iir_filter(config[CONF_IIR_FILTER])) sleep_duration = int(round(config[CONF_SLEEP_DURATION].total_microseconds * 0.15)) cg.add(touch.set_sleep_duration(sleep_duration)) diff --git a/esphome/components/esp32_touch/binary_sensor.py b/esphome/components/esp32_touch/binary_sensor.py index 2cdf1343c3..edda10daa1 100644 --- a/esphome/components/esp32_touch/binary_sensor.py +++ b/esphome/components/esp32_touch/binary_sensor.py @@ -7,7 +7,7 @@ from esphome.const import ( CONF_THRESHOLD, CONF_ID, ) -from esphome.components.esp32 import gpio +from esphome.components.esp32 import gpio, only_on_variant from esphome.components.esp32.const import ( KEY_ESP32, KEY_VARIANT, @@ -86,12 +86,23 @@ ESP32TouchBinarySensor = esp32_touch_ns.class_( "ESP32TouchBinarySensor", binary_sensor.BinarySensor ) +_threshold = cv.Any( + cv.All( + cv.uint16_t, + only_on_variant(supported=[VARIANT_ESP32]), + ), + cv.All( + cv.uint32_t, + only_on_variant(supported=[VARIANT_ESP32S2, VARIANT_ESP32S3]), + ), +) + CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(ESP32TouchBinarySensor).extend( { cv.GenerateID(CONF_ESP32_TOUCH_ID): cv.use_id(ESP32TouchComponent), cv.Required(CONF_PIN): validate_touch_pad, - cv.Required(CONF_THRESHOLD): cv.uint16_t, - cv.Optional(CONF_WAKEUP_THRESHOLD, default=0): cv.uint16_t, + cv.Required(CONF_THRESHOLD): _threshold, + cv.Optional(CONF_WAKEUP_THRESHOLD, default=0): _threshold, } ) diff --git a/esphome/components/esp32_touch/esp32_touch.h b/esphome/components/esp32_touch/esp32_touch.h index c954a14654..0e08f897f4 100644 --- a/esphome/components/esp32_touch/esp32_touch.h +++ b/esphome/components/esp32_touch/esp32_touch.h @@ -2,18 +2,14 @@ #ifdef USE_ESP32 -#include "esphome/core/component.h" #include "esphome/components/binary_sensor/binary_sensor.h" -#include +#include "esphome/core/component.h" + +#include +#include #include -#if ESP_IDF_VERSION_MAJOR >= 4 -#include -#else -#include -#endif - namespace esphome { namespace esp32_touch { @@ -25,7 +21,9 @@ class ESP32TouchComponent : public Component { void set_setup_mode(bool setup_mode) { setup_mode_ = setup_mode; } +#ifdef SOC_TOUCH_VERSION_1 void set_iir_filter(uint32_t iir_filter) { iir_filter_ = iir_filter; } +#endif void set_sleep_duration(uint16_t sleep_duration) { sleep_cycle_ = sleep_duration; } @@ -49,8 +47,11 @@ class ESP32TouchComponent : public Component { void on_shutdown() override; protected: +#ifdef SOC_TOUCH_VERSION_1 /// Is the IIR filter enabled? bool iir_filter_enabled_() const { return iir_filter_ > 0; } + uint32_t iir_filter_{0}; +#endif uint16_t sleep_cycle_{}; uint16_t meas_cycle_{65535}; @@ -60,27 +61,27 @@ class ESP32TouchComponent : public Component { std::vector children_; bool setup_mode_{false}; uint32_t setup_mode_last_log_print_{}; - uint32_t iir_filter_{0}; }; /// Simple helper class to expose a touch pad value as a binary sensor. class ESP32TouchBinarySensor : public binary_sensor::BinarySensor { public: - ESP32TouchBinarySensor(touch_pad_t touch_pad, uint16_t threshold, uint16_t wakeup_threshold); + ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold) + : touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {} touch_pad_t get_touch_pad() const { return touch_pad_; } - uint16_t get_threshold() const { return threshold_; } - void set_threshold(uint16_t threshold) { threshold_ = threshold; } - uint16_t get_value() const { return value_; } - uint16_t get_wakeup_threshold() const { return wakeup_threshold_; } + uint32_t get_threshold() const { return threshold_; } + void set_threshold(uint32_t threshold) { threshold_ = threshold; } + uint32_t get_value() const { return value_; } + uint32_t get_wakeup_threshold() const { return wakeup_threshold_; } protected: friend ESP32TouchComponent; touch_pad_t touch_pad_; - uint16_t threshold_; - uint16_t value_; - const uint16_t wakeup_threshold_; + uint32_t threshold_; + uint32_t value_; + const uint32_t wakeup_threshold_; }; } // namespace esp32_touch diff --git a/esphome/components/esp32_touch/esp32_touch.cpp b/esphome/components/esp32_touch/esp32_touch_v1.cpp similarity index 95% rename from esphome/components/esp32_touch/esp32_touch.cpp rename to esphome/components/esp32_touch/esp32_touch_v1.cpp index 0e3d3d9fd5..498d7bd0ec 100644 --- a/esphome/components/esp32_touch/esp32_touch.cpp +++ b/esphome/components/esp32_touch/esp32_touch_v1.cpp @@ -1,9 +1,13 @@ + #ifdef USE_ESP32 #include "esp32_touch.h" + +#if SOC_TOUCH_VERSION_1 + #include "esphome/core/application.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" +#include "esphome/core/log.h" namespace esphome { namespace esp32_touch { @@ -161,10 +165,8 @@ void ESP32TouchComponent::on_shutdown() { } } -ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint16_t threshold, uint16_t wakeup_threshold) - : touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {} - } // namespace esp32_touch } // namespace esphome -#endif +#endif // SOC_TOUCH_VERSION_1 +#endif // USE_ESP32 diff --git a/esphome/components/esp32_touch/esp32_touch_v2.cpp b/esphome/components/esp32_touch/esp32_touch_v2.cpp new file mode 100644 index 0000000000..67b9415ed9 --- /dev/null +++ b/esphome/components/esp32_touch/esp32_touch_v2.cpp @@ -0,0 +1,172 @@ +#ifdef USE_ESP32 + +#include "esp32_touch.h" + +#if SOC_TOUCH_VERSION_2 + +#include "esphome/core/application.h" +#include "esphome/core/defines.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace esp32_touch { + +static const char *const TAG = "esp32_touch"; + +void ESP32TouchComponent::setup() { + ESP_LOGCONFIG(TAG, "Setting up ESP32 Touch Hub..."); + touch_pad_init(); + + for (auto *child : this->children_) { + // Disable interrupt threshold + touch_pad_config(child->get_touch_pad()); + } + + touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_); + touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, this->voltage_attenuation_); + touch_pad_set_idle_channel_connect(TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT); + + for (auto *child : this->children_) { + touch_pad_set_cnt_mode(child->get_touch_pad(), TOUCH_PAD_SLOPE_DEFAULT, TOUCH_PAD_TIE_OPT_DEFAULT); + } + + touch_pad_denoise_t denoise = { + .grade = TOUCH_PAD_DENOISE_BIT4, + .cap_level = TOUCH_PAD_DENOISE_CAP_L4, + }; + touch_pad_denoise_set_config(&denoise); + touch_pad_denoise_enable(); + + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); + touch_pad_fsm_start(); +} + +void ESP32TouchComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Config for ESP32 Touch Hub:"); + ESP_LOGCONFIG(TAG, " Meas cycle: %.2fms", this->meas_cycle_ / (8000000.0f / 1000.0f)); + ESP_LOGCONFIG(TAG, " Sleep cycle: %.2fms", this->sleep_cycle_ / (150000.0f / 1000.0f)); + + const char *lv_s; + switch (this->low_voltage_reference_) { + case TOUCH_LVOLT_0V5: + lv_s = "0.5V"; + break; + case TOUCH_LVOLT_0V6: + lv_s = "0.6V"; + break; + case TOUCH_LVOLT_0V7: + lv_s = "0.7V"; + break; + case TOUCH_LVOLT_0V8: + lv_s = "0.8V"; + break; + default: + lv_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Low Voltage Reference: %s", lv_s); + + const char *hv_s; + switch (this->high_voltage_reference_) { + case TOUCH_HVOLT_2V4: + hv_s = "2.4V"; + break; + case TOUCH_HVOLT_2V5: + hv_s = "2.5V"; + break; + case TOUCH_HVOLT_2V6: + hv_s = "2.6V"; + break; + case TOUCH_HVOLT_2V7: + hv_s = "2.7V"; + break; + default: + hv_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " High Voltage Reference: %s", hv_s); + + const char *atten_s; + switch (this->voltage_attenuation_) { + case TOUCH_HVOLT_ATTEN_1V5: + atten_s = "1.5V"; + break; + case TOUCH_HVOLT_ATTEN_1V: + atten_s = "1V"; + break; + case TOUCH_HVOLT_ATTEN_0V5: + atten_s = "0.5V"; + break; + case TOUCH_HVOLT_ATTEN_0V: + atten_s = "0V"; + break; + default: + atten_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Voltage Attenuation: %s", atten_s); + + if (this->setup_mode_) { + ESP_LOGCONFIG(TAG, " Setup Mode ENABLED!"); + } + + for (auto *child : this->children_) { + LOG_BINARY_SENSOR(" ", "Touch Pad", child); + ESP_LOGCONFIG(TAG, " Pad: T%d", child->get_touch_pad()); + ESP_LOGCONFIG(TAG, " Threshold: %u", child->get_threshold()); + } +} + +void ESP32TouchComponent::loop() { + const uint32_t now = millis(); + bool should_print = this->setup_mode_ && now - this->setup_mode_last_log_print_ > 250; + for (auto *child : this->children_) { + uint32_t value; + + touch_pad_read_raw_data(child->get_touch_pad(), &value); + + child->value_ = value; + child->publish_state(value < child->get_threshold()); + + if (should_print) { + ESP_LOGD(TAG, "Touch Pad '%s' (T%u): %u", child->get_name().c_str(), child->get_touch_pad(), value); + } + + App.feed_wdt(); + } + + if (should_print) { + // Avoid spamming logs + this->setup_mode_last_log_print_ = now; + } +} + +void ESP32TouchComponent::on_shutdown() { + bool is_wakeup_source = false; + + for (auto *child : this->children_) { + if (child->get_wakeup_threshold() != 0) { + if (is_wakeup_source) { + ESP_LOGW(TAG, "Only a single touch pad can be used to wakeup. Ignoring %u", child->get_touch_pad()); + continue; + } + is_wakeup_source = true; + // Touch sensor FSM mode must be 'TOUCH_FSM_MODE_TIMER' to use it to wake-up. + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); + + touch_pad_sleep_channel_enable(child->get_touch_pad(), true); + touch_pad_sleep_set_threshold(child->get_touch_pad(), child->get_wakeup_threshold()); + } + } + + if (!is_wakeup_source) { + touch_pad_deinit(); + } +} + +} // namespace esp32_touch +} // namespace esphome + +#endif // SOC_TOUCH_VERSION_2 +#endif // USE_ESP32