diff --git a/esphome/components/esp32_touch/__init__.py b/esphome/components/esp32_touch/__init__.py index 3c9bef9665..0180d18104 100644 --- a/esphome/components/esp32_touch/__init__.py +++ b/esphome/components/esp32_touch/__init__.py @@ -12,25 +12,112 @@ from esphome.const import ( ) from esphome.core import TimePeriod from esphome.components import esp32 +from esphome.components.esp32 import get_esp32_variant, gpio +from esphome.components.esp32.const import ( + VARIANT_ESP32, + VARIANT_ESP32S2, + VARIANT_ESP32S3, +) AUTO_LOAD = ["binary_sensor"] DEPENDENCIES = ["esp32"] +CONF_DEBOUNCE_COUNT = "debounce_count" +CONF_DENOISE_GRADE = "denoise_grade" +CONF_DENOISE_CAP_LEVEL = "denoise_cap_level" +CONF_FILTER_MODE = "filter_mode" +CONF_NOISE_THRESHOLD = "noise_threshold" +CONF_JITTER_STEP = "jitter_step" +CONF_SMOOTH_MODE = "smooth_mode" +CONF_WATERPROOF_GUARD_RING = "waterproof_guard_ring" +CONF_WATERPROOF_SHIELD_DRIVER = "waterproof_shield_driver" + esp32_touch_ns = cg.esphome_ns.namespace("esp32_touch") ESP32TouchComponent = esp32_touch_ns.class_("ESP32TouchComponent", cg.Component) +TOUCH_PADS = { + VARIANT_ESP32: { + 4: cg.global_ns.TOUCH_PAD_NUM0, + 0: cg.global_ns.TOUCH_PAD_NUM1, + 2: cg.global_ns.TOUCH_PAD_NUM2, + 15: cg.global_ns.TOUCH_PAD_NUM3, + 13: cg.global_ns.TOUCH_PAD_NUM4, + 12: cg.global_ns.TOUCH_PAD_NUM5, + 14: cg.global_ns.TOUCH_PAD_NUM6, + 27: cg.global_ns.TOUCH_PAD_NUM7, + 33: cg.global_ns.TOUCH_PAD_NUM8, + 32: cg.global_ns.TOUCH_PAD_NUM9, + }, + VARIANT_ESP32S2: { + 1: cg.global_ns.TOUCH_PAD_NUM1, + 2: cg.global_ns.TOUCH_PAD_NUM2, + 3: cg.global_ns.TOUCH_PAD_NUM3, + 4: cg.global_ns.TOUCH_PAD_NUM4, + 5: cg.global_ns.TOUCH_PAD_NUM5, + 6: cg.global_ns.TOUCH_PAD_NUM6, + 7: cg.global_ns.TOUCH_PAD_NUM7, + 8: cg.global_ns.TOUCH_PAD_NUM8, + 9: cg.global_ns.TOUCH_PAD_NUM9, + 10: cg.global_ns.TOUCH_PAD_NUM10, + 11: cg.global_ns.TOUCH_PAD_NUM11, + 12: cg.global_ns.TOUCH_PAD_NUM12, + 13: cg.global_ns.TOUCH_PAD_NUM13, + 14: cg.global_ns.TOUCH_PAD_NUM14, + }, + VARIANT_ESP32S3: { + 1: cg.global_ns.TOUCH_PAD_NUM1, + 2: cg.global_ns.TOUCH_PAD_NUM2, + 3: cg.global_ns.TOUCH_PAD_NUM3, + 4: cg.global_ns.TOUCH_PAD_NUM4, + 5: cg.global_ns.TOUCH_PAD_NUM5, + 6: cg.global_ns.TOUCH_PAD_NUM6, + 7: cg.global_ns.TOUCH_PAD_NUM7, + 8: cg.global_ns.TOUCH_PAD_NUM8, + 9: cg.global_ns.TOUCH_PAD_NUM9, + 10: cg.global_ns.TOUCH_PAD_NUM10, + 11: cg.global_ns.TOUCH_PAD_NUM11, + 12: cg.global_ns.TOUCH_PAD_NUM12, + 13: cg.global_ns.TOUCH_PAD_NUM13, + 14: cg.global_ns.TOUCH_PAD_NUM14, + }, +} -def validate_voltage(values): - def validator(value): - if isinstance(value, float) and value.is_integer(): - value = int(value) - value = cv.string(value) - if not value.endswith("V"): - value += "V" - return cv.one_of(*values)(value) - return validator +TOUCH_PAD_DENOISE_GRADE = { + "BIT12": cg.global_ns.TOUCH_PAD_DENOISE_BIT12, + "BIT10": cg.global_ns.TOUCH_PAD_DENOISE_BIT10, + "BIT8": cg.global_ns.TOUCH_PAD_DENOISE_BIT8, + "BIT4": cg.global_ns.TOUCH_PAD_DENOISE_BIT4, +} +TOUCH_PAD_DENOISE_CAP_LEVEL = { + "L0": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L0, + "L1": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L1, + "L2": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L2, + "L3": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L3, + "L4": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L4, + "L5": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L5, + "L6": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L6, + "L7": cg.global_ns.TOUCH_PAD_DENOISE_CAP_L7, +} + +TOUCH_PAD_FILTER_MODE = { + "IIR_4": cg.global_ns.TOUCH_PAD_FILTER_IIR_4, + "IIR_8": cg.global_ns.TOUCH_PAD_FILTER_IIR_8, + "IIR_16": cg.global_ns.TOUCH_PAD_FILTER_IIR_16, + "IIR_32": cg.global_ns.TOUCH_PAD_FILTER_IIR_32, + "IIR_64": cg.global_ns.TOUCH_PAD_FILTER_IIR_64, + "IIR_128": cg.global_ns.TOUCH_PAD_FILTER_IIR_128, + "IIR_256": cg.global_ns.TOUCH_PAD_FILTER_IIR_256, + "JITTER": cg.global_ns.TOUCH_PAD_FILTER_JITTER, +} + +TOUCH_PAD_SMOOTH_MODE = { + "OFF": cg.global_ns.TOUCH_PAD_SMOOTH_OFF, + "IIR_2": cg.global_ns.TOUCH_PAD_SMOOTH_IIR_2, + "IIR_4": cg.global_ns.TOUCH_PAD_SMOOTH_IIR_4, + "IIR_8": cg.global_ns.TOUCH_PAD_SMOOTH_IIR_8, +} LOW_VOLTAGE_REFERENCE = { "0.5V": cg.global_ns.TOUCH_LVOLT_0V5, @@ -50,15 +137,74 @@ VOLTAGE_ATTENUATION = { "0.5V": cg.global_ns.TOUCH_HVOLT_ATTEN_0V5, "0V": cg.global_ns.TOUCH_HVOLT_ATTEN_0V, } +TOUCH_PAD_WATERPROOF_SHIELD_DRIVER = { + "L0": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L0, + "L1": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L1, + "L2": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L2, + "L3": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L3, + "L4": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L4, + "L5": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L5, + "L6": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L6, + "L7": cg.global_ns.TOUCH_PAD_SHIELD_DRV_L7, +} + + +def validate_touch_pad(value): + value = gpio.validate_gpio_pin(value) + variant = get_esp32_variant() + if variant not in TOUCH_PADS: + raise cv.Invalid(f"ESP32 variant {variant} does not support touch pads.") + + pads = TOUCH_PADS[variant] + if value not in pads: + raise cv.Invalid(f"Pin {value} does not support touch pads.") + return cv.enum(pads)(value) + + +def validate_variant_vars(config): + if get_esp32_variant() == VARIANT_ESP32: + variant_vars = { + CONF_DEBOUNCE_COUNT, + CONF_DENOISE_GRADE, + CONF_DENOISE_CAP_LEVEL, + CONF_FILTER_MODE, + CONF_NOISE_THRESHOLD, + CONF_JITTER_STEP, + CONF_SMOOTH_MODE, + CONF_WATERPROOF_GUARD_RING, + CONF_WATERPROOF_SHIELD_DRIVER, + } + for vvar in variant_vars: + if vvar in config: + raise cv.Invalid(f"{vvar} is not valid on {VARIANT_ESP32}") + elif ( + get_esp32_variant() == VARIANT_ESP32S2 or get_esp32_variant() == VARIANT_ESP32S3 + ) and CONF_IIR_FILTER in config: + raise cv.Invalid( + f"{CONF_IIR_FILTER} is not valid on {VARIANT_ESP32S2} or {VARIANT_ESP32S3}" + ) + + return config + + +def validate_voltage(values): + def validator(value): + if isinstance(value, float) and value.is_integer(): + value = int(value) + value = cv.string(value) + if not value.endswith("V"): + value += "V" + return cv.one_of(*values)(value) + + return validator + 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, + # common options cv.Optional(CONF_SLEEP_DURATION, default="27306us"): cv.All( cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=436906)) ), @@ -74,13 +220,47 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_VOLTAGE_ATTENUATION, default="0V"): validate_voltage( VOLTAGE_ATTENUATION ), + # ESP32 only + cv.Optional(CONF_IIR_FILTER): cv.positive_time_period_milliseconds, + # ESP32-S2/S3 only + cv.Optional(CONF_DEBOUNCE_COUNT): cv.int_range(min=0, max=7), + cv.Optional(CONF_FILTER_MODE): cv.enum( + TOUCH_PAD_FILTER_MODE, upper=True, space="_" + ), + cv.Optional(CONF_NOISE_THRESHOLD): cv.int_range(min=0, max=3), + cv.Optional(CONF_JITTER_STEP): cv.int_range(min=0, max=15), + cv.Optional(CONF_SMOOTH_MODE): cv.enum( + TOUCH_PAD_SMOOTH_MODE, upper=True, space="_" + ), + cv.Optional(CONF_DENOISE_GRADE): cv.enum( + TOUCH_PAD_DENOISE_GRADE, upper=True, space="_" + ), + cv.Optional(CONF_DENOISE_CAP_LEVEL): cv.enum( + TOUCH_PAD_DENOISE_CAP_LEVEL, upper=True, space="_" + ), + cv.Optional(CONF_WATERPROOF_GUARD_RING): validate_touch_pad, + cv.Optional(CONF_WATERPROOF_SHIELD_DRIVER): cv.enum( + TOUCH_PAD_WATERPROOF_SHIELD_DRIVER, upper=True, space="_" + ), } ).extend(cv.COMPONENT_SCHEMA), + cv.has_none_or_all_keys(CONF_DENOISE_GRADE, CONF_DENOISE_CAP_LEVEL), + cv.has_none_or_all_keys( + CONF_DEBOUNCE_COUNT, + CONF_FILTER_MODE, + CONF_NOISE_THRESHOLD, + CONF_JITTER_STEP, + CONF_SMOOTH_MODE, + ), + cv.has_none_or_all_keys(CONF_WATERPROOF_GUARD_RING, CONF_WATERPROOF_SHIELD_DRIVER), esp32.only_on_variant( supported=[ esp32.const.VARIANT_ESP32, + esp32.const.VARIANT_ESP32S2, + esp32.const.VARIANT_ESP32S3, ] ), + validate_variant_vars, ) @@ -89,7 +269,6 @@ 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])) sleep_duration = int(round(config[CONF_SLEEP_DURATION].total_microseconds * 0.15)) cg.add(touch.set_sleep_duration(sleep_duration)) @@ -114,3 +293,33 @@ async def to_code(config): VOLTAGE_ATTENUATION[config[CONF_VOLTAGE_ATTENUATION]] ) ) + + if get_esp32_variant() == VARIANT_ESP32: + if CONF_IIR_FILTER in config: + cg.add(touch.set_iir_filter(config[CONF_IIR_FILTER])) + + if get_esp32_variant() == VARIANT_ESP32S2 or get_esp32_variant() == VARIANT_ESP32S3: + if CONF_FILTER_MODE in config: + cg.add(touch.set_filter_mode(config[CONF_FILTER_MODE])) + if CONF_DEBOUNCE_COUNT in config: + cg.add(touch.set_debounce_count(config[CONF_DEBOUNCE_COUNT])) + if CONF_NOISE_THRESHOLD in config: + cg.add(touch.set_noise_threshold(config[CONF_NOISE_THRESHOLD])) + if CONF_JITTER_STEP in config: + cg.add(touch.set_jitter_step(config[CONF_JITTER_STEP])) + if CONF_SMOOTH_MODE in config: + cg.add(touch.set_smooth_level(config[CONF_SMOOTH_MODE])) + if CONF_DENOISE_GRADE in config: + cg.add(touch.set_denoise_grade(config[CONF_DENOISE_GRADE])) + if CONF_DENOISE_CAP_LEVEL in config: + cg.add(touch.set_denoise_cap(config[CONF_DENOISE_CAP_LEVEL])) + if CONF_WATERPROOF_GUARD_RING in config: + cg.add( + touch.set_waterproof_guard_ring_pad(config[CONF_WATERPROOF_GUARD_RING]) + ) + if CONF_WATERPROOF_SHIELD_DRIVER in config: + cg.add( + touch.set_waterproof_shield_driver( + config[CONF_WATERPROOF_SHIELD_DRIVER] + ) + ) diff --git a/esphome/components/esp32_touch/binary_sensor.py b/esphome/components/esp32_touch/binary_sensor.py index 2cdf1343c3..e9322b3080 100644 --- a/esphome/components/esp32_touch/binary_sensor.py +++ b/esphome/components/esp32_touch/binary_sensor.py @@ -1,87 +1,18 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.core import CORE from esphome.components import binary_sensor from esphome.const import ( CONF_PIN, CONF_THRESHOLD, CONF_ID, ) -from esphome.components.esp32 import gpio -from esphome.components.esp32.const import ( - KEY_ESP32, - KEY_VARIANT, - VARIANT_ESP32, - VARIANT_ESP32S2, - VARIANT_ESP32S3, -) -from . import esp32_touch_ns, ESP32TouchComponent +from . import esp32_touch_ns, ESP32TouchComponent, validate_touch_pad DEPENDENCIES = ["esp32_touch", "esp32"] CONF_ESP32_TOUCH_ID = "esp32_touch_id" CONF_WAKEUP_THRESHOLD = "wakeup_threshold" -TOUCH_PADS = { - VARIANT_ESP32: { - 4: cg.global_ns.TOUCH_PAD_NUM0, - 0: cg.global_ns.TOUCH_PAD_NUM1, - 2: cg.global_ns.TOUCH_PAD_NUM2, - 15: cg.global_ns.TOUCH_PAD_NUM3, - 13: cg.global_ns.TOUCH_PAD_NUM4, - 12: cg.global_ns.TOUCH_PAD_NUM5, - 14: cg.global_ns.TOUCH_PAD_NUM6, - 27: cg.global_ns.TOUCH_PAD_NUM7, - 33: cg.global_ns.TOUCH_PAD_NUM8, - 32: cg.global_ns.TOUCH_PAD_NUM9, - }, - VARIANT_ESP32S2: { - 1: cg.global_ns.TOUCH_PAD_NUM1, - 2: cg.global_ns.TOUCH_PAD_NUM2, - 3: cg.global_ns.TOUCH_PAD_NUM3, - 4: cg.global_ns.TOUCH_PAD_NUM4, - 5: cg.global_ns.TOUCH_PAD_NUM5, - 6: cg.global_ns.TOUCH_PAD_NUM6, - 7: cg.global_ns.TOUCH_PAD_NUM7, - 8: cg.global_ns.TOUCH_PAD_NUM8, - 9: cg.global_ns.TOUCH_PAD_NUM9, - 10: cg.global_ns.TOUCH_PAD_NUM10, - 11: cg.global_ns.TOUCH_PAD_NUM11, - 12: cg.global_ns.TOUCH_PAD_NUM12, - 13: cg.global_ns.TOUCH_PAD_NUM13, - 14: cg.global_ns.TOUCH_PAD_NUM14, - }, - VARIANT_ESP32S3: { - 1: cg.global_ns.TOUCH_PAD_NUM1, - 2: cg.global_ns.TOUCH_PAD_NUM2, - 3: cg.global_ns.TOUCH_PAD_NUM3, - 4: cg.global_ns.TOUCH_PAD_NUM4, - 5: cg.global_ns.TOUCH_PAD_NUM5, - 6: cg.global_ns.TOUCH_PAD_NUM6, - 7: cg.global_ns.TOUCH_PAD_NUM7, - 8: cg.global_ns.TOUCH_PAD_NUM8, - 9: cg.global_ns.TOUCH_PAD_NUM9, - 10: cg.global_ns.TOUCH_PAD_NUM10, - 11: cg.global_ns.TOUCH_PAD_NUM11, - 12: cg.global_ns.TOUCH_PAD_NUM12, - 13: cg.global_ns.TOUCH_PAD_NUM13, - 14: cg.global_ns.TOUCH_PAD_NUM14, - }, -} - - -def validate_touch_pad(value): - value = gpio.validate_gpio_pin(value) - variant = CORE.data[KEY_ESP32][KEY_VARIANT] - if variant not in TOUCH_PADS: - raise cv.Invalid(f"ESP32 variant {variant} does not support touch pads.") - - pads = TOUCH_PADS[variant] - if value not in pads: - raise cv.Invalid(f"Pin {value} does not support touch pads.") - return cv.enum(pads)(value) - - ESP32TouchBinarySensor = esp32_touch_ns.class_( "ESP32TouchBinarySensor", binary_sensor.BinarySensor ) @@ -90,8 +21,8 @@ CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(ESP32TouchBinarySensor).exten { 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): cv.uint32_t, + cv.Optional(CONF_WAKEUP_THRESHOLD, default=0): cv.uint32_t, } ) diff --git a/esphome/components/esp32_touch/esp32_touch.cpp b/esphome/components/esp32_touch/esp32_touch.cpp index 0e3d3d9fd5..e43c3b844c 100644 --- a/esphome/components/esp32_touch/esp32_touch.cpp +++ b/esphome/components/esp32_touch/esp32_touch.cpp @@ -5,6 +5,8 @@ #include "esphome/core/log.h" #include "esphome/core/hal.h" +#include + namespace esphome { namespace esp32_touch { @@ -13,18 +15,58 @@ static const char *const TAG = "esp32_touch"; void ESP32TouchComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up ESP32 Touch Hub..."); touch_pad_init(); +// set up and enable/start filtering based on ESP32 variant +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + if (this->filter_configured_()) { + touch_filter_config_t filter_info = { + .mode = this->filter_mode_, + .debounce_cnt = this->debounce_count_, + .noise_thr = this->noise_threshold_, + .jitter_step = this->jitter_step_, + .smh_lvl = this->smooth_level_, + }; + touch_pad_filter_set_config(&filter_info); + touch_pad_filter_enable(); + } + if (this->denoise_configured_()) { + touch_pad_denoise_t denoise = { + .grade = this->grade_, + .cap_level = this->cap_level_, + }; + touch_pad_denoise_set_config(&denoise); + touch_pad_denoise_enable(); + } + + if (this->waterproof_configured_()) { + touch_pad_waterproof_t waterproof = { + .guard_ring_pad = this->waterproof_guard_ring_pad_, + .shield_driver = this->waterproof_shield_driver_, + }; + touch_pad_waterproof_set_config(&waterproof); + touch_pad_waterproof_enable(); + } +#else if (this->iir_filter_enabled_()) { touch_pad_filter_start(this->iir_filter_); } +#endif 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_); for (auto *child : this->children_) { +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + touch_pad_config(child->get_touch_pad()); +#else // Disable interrupt threshold touch_pad_config(child->get_touch_pad(), 0); +#endif } +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); + touch_pad_fsm_start(); +#endif } void ESP32TouchComponent::dump_config() { @@ -92,38 +134,168 @@ void ESP32TouchComponent::dump_config() { } ESP_LOGCONFIG(TAG, " Voltage Attenuation: %s", atten_s); +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + if (this->filter_configured_()) { + const char *filter_mode_s; + switch (this->filter_mode_) { + case TOUCH_PAD_FILTER_IIR_4: + filter_mode_s = "IIR_4"; + break; + case TOUCH_PAD_FILTER_IIR_8: + filter_mode_s = "IIR_8"; + break; + case TOUCH_PAD_FILTER_IIR_16: + filter_mode_s = "IIR_16"; + break; + case TOUCH_PAD_FILTER_IIR_32: + filter_mode_s = "IIR_32"; + break; + case TOUCH_PAD_FILTER_IIR_64: + filter_mode_s = "IIR_64"; + break; + case TOUCH_PAD_FILTER_IIR_128: + filter_mode_s = "IIR_128"; + break; + case TOUCH_PAD_FILTER_IIR_256: + filter_mode_s = "IIR_256"; + break; + case TOUCH_PAD_FILTER_JITTER: + filter_mode_s = "JITTER"; + break; + default: + filter_mode_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Filter mode: %s", filter_mode_s); + ESP_LOGCONFIG(TAG, " Debounce count: %" PRIu32, this->debounce_count_); + ESP_LOGCONFIG(TAG, " Noise threshold coefficient: %" PRIu32, this->noise_threshold_); + ESP_LOGCONFIG(TAG, " Jitter filter step size: %" PRIu32, this->jitter_step_); + const char *smooth_level_s; + switch (this->smooth_level_) { + case TOUCH_PAD_SMOOTH_OFF: + smooth_level_s = "OFF"; + break; + case TOUCH_PAD_SMOOTH_IIR_2: + smooth_level_s = "IIR_2"; + break; + case TOUCH_PAD_SMOOTH_IIR_4: + smooth_level_s = "IIR_4"; + break; + case TOUCH_PAD_SMOOTH_IIR_8: + smooth_level_s = "IIR_8"; + break; + default: + smooth_level_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Smooth level: %s", smooth_level_s); + } + + if (this->denoise_configured_()) { + const char *grade_s; + switch (this->grade_) { + case TOUCH_PAD_DENOISE_BIT12: + grade_s = "BIT12"; + break; + case TOUCH_PAD_DENOISE_BIT10: + grade_s = "BIT10"; + break; + case TOUCH_PAD_DENOISE_BIT8: + grade_s = "BIT8"; + break; + case TOUCH_PAD_DENOISE_BIT4: + grade_s = "BIT4"; + break; + default: + grade_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Denoise grade: %s", grade_s); + + const char *cap_level_s; + switch (this->cap_level_) { + case TOUCH_PAD_DENOISE_CAP_L0: + cap_level_s = "L0"; + break; + case TOUCH_PAD_DENOISE_CAP_L1: + cap_level_s = "L1"; + break; + case TOUCH_PAD_DENOISE_CAP_L2: + cap_level_s = "L2"; + break; + case TOUCH_PAD_DENOISE_CAP_L3: + cap_level_s = "L3"; + break; + case TOUCH_PAD_DENOISE_CAP_L4: + cap_level_s = "L4"; + break; + case TOUCH_PAD_DENOISE_CAP_L5: + cap_level_s = "L5"; + break; + case TOUCH_PAD_DENOISE_CAP_L6: + cap_level_s = "L6"; + break; + case TOUCH_PAD_DENOISE_CAP_L7: + cap_level_s = "L7"; + break; + default: + cap_level_s = "UNKNOWN"; + break; + } + ESP_LOGCONFIG(TAG, " Denoise capacitance level: %s", cap_level_s); + } +#else if (this->iir_filter_enabled_()) { - ESP_LOGCONFIG(TAG, " IIR Filter: %ums", this->iir_filter_); + ESP_LOGCONFIG(TAG, " IIR Filter: %" PRIu32 "ms", this->iir_filter_); } else { ESP_LOGCONFIG(TAG, " IIR Filter DISABLED"); } +#endif + if (this->setup_mode_) { - ESP_LOGCONFIG(TAG, " Setup Mode ENABLED!"); + 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()); + ESP_LOGCONFIG(TAG, " Pad: T%" PRIu32, (uint32_t) child->get_touch_pad()); + ESP_LOGCONFIG(TAG, " Threshold: %" PRIu32, child->get_threshold()); } } +uint32_t ESP32TouchComponent::component_touch_pad_read(touch_pad_t tp) { +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + uint32_t value = 0; + if (this->filter_configured_()) { + touch_pad_filter_read_smooth(tp, &value); + } else { + touch_pad_read_raw_data(tp, &value); + } +#else + uint16_t value = 0; + if (this->iir_filter_enabled_()) { + touch_pad_read_filtered(tp, &value); + } else { + touch_pad_read(tp, &value); + } +#endif + return value; +} + 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_) { - uint16_t value; - if (this->iir_filter_enabled_()) { - touch_pad_read_filtered(child->get_touch_pad(), &value); - } else { - touch_pad_read(child->get_touch_pad(), &value); - } - - child->value_ = value; - child->publish_state(value < child->get_threshold()); + child->value_ = this->component_touch_pad_read(child->get_touch_pad()); +#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) + child->publish_state(child->value_ < child->get_threshold()); +#else + child->publish_state(child->value_ > child->get_threshold()); +#endif if (should_print) { - ESP_LOGD(TAG, "Touch Pad '%s' (T%u): %u", child->get_name().c_str(), child->get_touch_pad(), value); + ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(), + (uint32_t) child->get_touch_pad(), child->value_); } App.feed_wdt(); @@ -138,10 +310,12 @@ void ESP32TouchComponent::loop() { void ESP32TouchComponent::on_shutdown() { bool is_wakeup_source = false; +#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) if (this->iir_filter_enabled_()) { touch_pad_filter_stop(); touch_pad_filter_delete(); } +#endif for (auto *child : this->children_) { if (child->get_wakeup_threshold() != 0) { @@ -151,8 +325,10 @@ void ESP32TouchComponent::on_shutdown() { touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); } +#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)) // No filter available when using as wake-up source. touch_pad_config(child->get_touch_pad(), child->get_wakeup_threshold()); +#endif } } @@ -161,7 +337,7 @@ void ESP32TouchComponent::on_shutdown() { } } -ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint16_t threshold, uint16_t wakeup_threshold) +ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold) : touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {} } // namespace esp32_touch diff --git a/esphome/components/esp32_touch/esp32_touch.h b/esphome/components/esp32_touch/esp32_touch.h index c954a14654..0ba7ed6255 100644 --- a/esphome/components/esp32_touch/esp32_touch.h +++ b/esphome/components/esp32_touch/esp32_touch.h @@ -21,25 +21,37 @@ class ESP32TouchBinarySensor; class ESP32TouchComponent : public Component { public: - void register_touch_pad(ESP32TouchBinarySensor *pad) { children_.push_back(pad); } - - void set_setup_mode(bool setup_mode) { setup_mode_ = setup_mode; } - - void set_iir_filter(uint32_t iir_filter) { iir_filter_ = iir_filter; } - - void set_sleep_duration(uint16_t sleep_duration) { sleep_cycle_ = sleep_duration; } - - void set_measurement_duration(uint16_t meas_cycle) { meas_cycle_ = meas_cycle; } + void register_touch_pad(ESP32TouchBinarySensor *pad) { this->children_.push_back(pad); } + void set_setup_mode(bool setup_mode) { this->setup_mode_ = setup_mode; } + void set_sleep_duration(uint16_t sleep_duration) { this->sleep_cycle_ = sleep_duration; } + void set_measurement_duration(uint16_t meas_cycle) { this->meas_cycle_ = meas_cycle; } void set_low_voltage_reference(touch_low_volt_t low_voltage_reference) { - low_voltage_reference_ = low_voltage_reference; + this->low_voltage_reference_ = low_voltage_reference; } - void set_high_voltage_reference(touch_high_volt_t high_voltage_reference) { - high_voltage_reference_ = high_voltage_reference; + this->high_voltage_reference_ = high_voltage_reference; } + void set_voltage_attenuation(touch_volt_atten_t voltage_attenuation) { + this->voltage_attenuation_ = voltage_attenuation; + } +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + void set_filter_mode(touch_filter_mode_t filter_mode) { this->filter_mode_ = filter_mode; } + void set_debounce_count(uint32_t debounce_count) { this->debounce_count_ = debounce_count; } + void set_noise_threshold(uint32_t noise_threshold) { this->noise_threshold_ = noise_threshold; } + void set_jitter_step(uint32_t jitter_step) { this->jitter_step_ = jitter_step; } + void set_smooth_level(touch_smooth_mode_t smooth_level) { this->smooth_level_ = smooth_level; } + void set_denoise_grade(touch_pad_denoise_grade_t denoise_grade) { this->grade_ = denoise_grade; } + void set_denoise_cap(touch_pad_denoise_cap_t cap_level) { this->cap_level_ = cap_level; } + void set_waterproof_guard_ring_pad(touch_pad_t pad) { this->waterproof_guard_ring_pad_ = pad; } + void set_waterproof_shield_driver(touch_pad_shield_driver_t drive_capability) { + this->waterproof_shield_driver_ = drive_capability; + } +#else + void set_iir_filter(uint32_t iir_filter) { this->iir_filter_ = iir_filter; } +#endif - void set_voltage_attenuation(touch_volt_atten_t voltage_attenuation) { voltage_attenuation_ = voltage_attenuation; } + uint32_t component_touch_pad_read(touch_pad_t tp); void setup() override; void dump_config() override; @@ -49,38 +61,63 @@ class ESP32TouchComponent : public Component { void on_shutdown() override; protected: - /// Is the IIR filter enabled? - bool iir_filter_enabled_() const { return iir_filter_ > 0; } +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + bool filter_configured_() const { + return (this->filter_mode_ != TOUCH_PAD_FILTER_MAX) && (this->smooth_level_ != TOUCH_PAD_SMOOTH_MAX); + } + bool denoise_configured_() const { + return (this->grade_ != TOUCH_PAD_DENOISE_MAX) && (this->cap_level_ != TOUCH_PAD_DENOISE_CAP_MAX); + } + bool waterproof_configured_() const { + return (this->waterproof_guard_ring_pad_ != TOUCH_PAD_MAX) && + (this->waterproof_shield_driver_ != TOUCH_PAD_SHIELD_DRV_MAX); + } +#else + bool iir_filter_enabled_() const { return this->iir_filter_ > 0; } +#endif - uint16_t sleep_cycle_{}; - uint16_t meas_cycle_{65535}; - touch_low_volt_t low_voltage_reference_{}; - touch_high_volt_t high_voltage_reference_{}; - touch_volt_atten_t voltage_attenuation_{}; std::vector children_; bool setup_mode_{false}; - uint32_t setup_mode_last_log_print_{}; + uint32_t setup_mode_last_log_print_{0}; + // common parameters + uint16_t sleep_cycle_{4095}; + uint16_t meas_cycle_{65535}; + touch_low_volt_t low_voltage_reference_{TOUCH_LVOLT_0V5}; + touch_high_volt_t high_voltage_reference_{TOUCH_HVOLT_2V7}; + touch_volt_atten_t voltage_attenuation_{TOUCH_HVOLT_ATTEN_0V}; +#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) + touch_filter_mode_t filter_mode_{TOUCH_PAD_FILTER_MAX}; + uint32_t debounce_count_{0}; + uint32_t noise_threshold_{0}; + uint32_t jitter_step_{0}; + touch_smooth_mode_t smooth_level_{TOUCH_PAD_SMOOTH_MAX}; + touch_pad_denoise_grade_t grade_{TOUCH_PAD_DENOISE_MAX}; + touch_pad_denoise_cap_t cap_level_{TOUCH_PAD_DENOISE_CAP_MAX}; + touch_pad_t waterproof_guard_ring_pad_{TOUCH_PAD_MAX}; + touch_pad_shield_driver_t waterproof_shield_driver_{TOUCH_PAD_SHIELD_DRV_MAX}; +#else uint32_t iir_filter_{0}; +#endif }; /// 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_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_; } + touch_pad_t get_touch_pad() const { return this->touch_pad_; } + uint32_t get_threshold() const { return this->threshold_; } + void set_threshold(uint32_t threshold) { this->threshold_ = threshold; } + uint32_t get_value() const { return this->value_; } + uint32_t get_wakeup_threshold() const { return this->wakeup_threshold_; } protected: friend ESP32TouchComponent; - touch_pad_t touch_pad_; - uint16_t threshold_; - uint16_t value_; - const uint16_t wakeup_threshold_; + touch_pad_t touch_pad_{TOUCH_PAD_MAX}; + uint32_t threshold_{0}; + uint32_t value_{0}; + const uint32_t wakeup_threshold_{0}; }; } // namespace esp32_touch