diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a1995158..cdd518602 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,17 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [12.1.1.2] +## [12.1.1.3] +### Added + +### Changed + +### Fixed +- ESP32 touch button multi-press and hold detection (#16596) + +### Removed + +## [12.1.1.2] 20220927 ### Added - Berry has persistent MQTT subscriptions: auto-subscribe at (re)connection - Berry automated solidification of code @@ -22,10 +32,6 @@ All notable changes to this project will be documented in this file. - Zigbee report unprocessed attributes - Platformio one Platform for all Tasmota frameworks Core32 2.0.5 (#16644) -### Fixed - -### Removed - ## [12.1.1.1] 20220910 ### Added - Support for SGP40 gas and air quality sensor (#16341) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index afa312e5f..14c3e38ef 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -107,7 +107,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.1.1.2 +## Changelog v12.1.1.3 ### Added - Command ``SetOption46 0..255`` to add 0..255 * 10 milliseconds power on delay before initializing I/O [#15438](https://github.com/arendst/Tasmota/issues/15438) - Command ``SetOption146 1`` to enable display of ESP32 internal temperature @@ -148,5 +148,6 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Button response delay regression from v12.0.2.4 [#16319](https://github.com/arendst/Tasmota/issues/16319) - Lost module name in GUI regression from v12.0.2.4 - 20220803 [#16324](https://github.com/arendst/Tasmota/issues/16324) - Removed whitespace from JSON values with no decimals [#16365](https://github.com/arendst/Tasmota/issues/16365) +- ESP32 touch button multi-press and hold detection [#16596](https://github.com/arendst/Tasmota/issues/16596) ### Removed diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index 4c684321f..0262e889e 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -465,7 +465,9 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_KEY1_INV_NP) + MAX_KEYS, #ifdef ESP32 AGPIO(GPIO_KEY1_INV_PD) + MAX_KEYS, +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) AGPIO(GPIO_KEY1_TC) + MAX_KEYS, // Touch button +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 #endif AGPIO(GPIO_SWT1) + MAX_SWITCHES, // User connected external switches AGPIO(GPIO_SWT1_NP) + MAX_SWITCHES, diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index 874ab6219..2a74211ef 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C010102; // 12.1.1.2 +const uint32_t VERSION = 0x0C010103; // 12.1.1.3 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/tasmota_support/support_button_v3.ino b/tasmota/tasmota_support/support_button_v3.ino index 617235e81..f7cc71b56 100644 --- a/tasmota/tasmota_support/support_button_v3.ino +++ b/tasmota/tasmota_support/support_button_v3.ino @@ -46,9 +46,6 @@ struct BUTTON { uint32_t no_pullup_mask = 0; // key no pullup flag (1 = no pullup) uint32_t pulldown_mask = 0; // key pulldown flag (1 = pulldown) uint32_t inverted_mask = 0; // Key inverted flag (1 = inverted) -#ifdef ESP32 - uint32_t touch_mask = 0; // Touch flag (1 = inverted) -#endif // ESP32 uint16_t hold_timer[MAX_KEYS] = { 0 }; // Timer for button hold uint16_t dual_code = 0; // Sonoff dual received code uint8_t state[MAX_KEYS] = { 0 }; @@ -57,20 +54,19 @@ struct BUTTON { uint8_t window_timer[MAX_KEYS] = { 0 }; // Max time between button presses to record press count uint8_t press_counter[MAX_KEYS] = { 0 }; // Number of button presses within Button.window_timer uint8_t dual_receive_count = 0; // Sonoff dual input flag -#ifdef ESP32 - uint8_t touch_hits[MAX_KEYS] = { 0 }; // Hits in a row to filter out noise -#endif // ESP32 uint8_t first_change = 0; uint8_t present = 0; // Number of buttons found flag + uint8_t mutex; } Button; -#ifdef ESP32 +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) struct TOUCH_BUTTON { + uint32_t touch_mask = 0; // Touch flag (1 = enabled) uint32_t calibration = 0; // Bitfield uint32_t pin_threshold = TOUCH_PIN_THRESHOLD; - uint8_t hit_threshold = TOUCH_HIT_THRESHOLD; + uint8_t hits[MAX_KEYS] = { 0 }; // Hits in a row to filter out noise } TOUCH_BUTTON; -#endif // ESP32 +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 /********************************************************************************************/ @@ -86,16 +82,17 @@ void ButtonInvertFlag(uint32_t button_bit) { bitSet(Button.inverted_mask, button_bit); } -#ifdef ESP32 +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) void ButtonTouchFlag(uint32_t button_bit) { - bitSet(Button.touch_mask, button_bit); + bitSet(TOUCH_BUTTON.touch_mask, button_bit); } -#endif // ESP32 +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 /*********************************************************************************************/ void ButtonProbe(void) { - if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit + if (Button.mutex || (TasmotaGlobal.uptime < 4)) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit + Button.mutex = 1; uint32_t state_filter; uint32_t first_change = Button.first_change; @@ -119,8 +116,17 @@ void ButtonProbe(void) { for (uint32_t i = 0; i < MAX_KEYS; i++) { if (!PinUsed(GPIO_KEY1, i)) { continue; } - // Olimex user_switch2.c code to fix 50Hz induced pulses - if (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)) { + bool button_not_activated; +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) + if (bitRead(TOUCH_BUTTON.touch_mask, i)) { + if (ac_detect || bitRead(TOUCH_BUTTON.calibration, i +1)) { continue; } // Touch is slow. Takes 21mS to read + uint32_t value = touchRead(Pin(GPIO_KEY1, i)); + button_not_activated = ((value == 0) || (value > TOUCH_BUTTON.pin_threshold)); + } else +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 + button_not_activated = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); + + if (button_not_activated) { if (ac_detect) { // Enabled with ButtonDebounce x9 Button.state[i] |= 0x80; @@ -194,6 +200,7 @@ void ButtonProbe(void) { } } } + Button.mutex = 0; } void ButtonInit(void) { @@ -295,35 +302,22 @@ void ButtonHandler(void) { } else #endif // ESP8266 if (PinUsed(GPIO_KEY1, button_index)) { - button_present = 1; -#ifdef ESP32 -#ifndef CONFIG_IDF_TARGET_ESP32C3 - if (bitRead(Button.touch_mask, button_index)) { // Touch + +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) + if (bitRead(TOUCH_BUTTON.touch_mask, button_index) && bitRead(TOUCH_BUTTON.calibration, button_index +1)) { // Touch uint32_t _value = touchRead(Pin(GPIO_KEY1, button_index)); - button = NOT_PRESSED; - if (_value != 0) { // Probably read-error - if (_value < TOUCH_BUTTON.pin_threshold) { - if (++Button.touch_hits[button_index] > TOUCH_BUTTON.hit_threshold) { - if (!bitRead(TOUCH_BUTTON.calibration, button_index+1)) { - button = PRESSED; - } - } - } else { - Button.touch_hits[button_index] = 0; - } + if ((_value > 0) && (_value < TOUCH_BUTTON.pin_threshold)) { // Probably read-error (0) + TOUCH_BUTTON.hits[button_index]++; } else { - Button.touch_hits[button_index] = 0; - } - if (bitRead(TOUCH_BUTTON.calibration, button_index+1)) { - AddLog(LOG_LEVEL_INFO, PSTR("PLOT: %u, %u, %u,"), button_index+1, _value, Button.touch_hits[button_index]); // Button number (1..4), value, continuous hits under threshold + TOUCH_BUTTON.hits[button_index] = 0; } + AddLog(LOG_LEVEL_INFO, PSTR("PLOT: %u, %u, %u,"), button_index +1, _value, TOUCH_BUTTON.hits[button_index]); // Button number (1..4), value, continuous hits under threshold + continue; } else -#endif // not ESP32C3 -#endif // ESP32 - { // Normal button -// button = (digitalRead(Pin(GPIO_KEY1, button_index)) != bitRead(Button.inverted_mask, button_index)); - button = Button.virtual_state[button_index]; - } +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 + + button_present = 1; + button = Button.virtual_state[button_index]; } #ifdef USE_ADC else if (PinUsed(GPIO_ADC_BUTTON, button_index)) { diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index c7fb195d8..119cf39fe 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -46,7 +46,11 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix #endif // USE_DEVICE_GROUPS D_CMND_SETSENSOR "|" D_CMND_SENSOR "|" D_CMND_DRIVER "|" D_CMND_JSON #ifdef ESP32 - "|Info|" D_CMND_TOUCH_CAL "|" D_CMND_TOUCH_THRES "|" D_CMND_TOUCH_NUM "|" D_CMND_CPU_FREQUENCY + "|Info|" +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) + D_CMND_TOUCH_CAL "|" D_CMND_TOUCH_THRES "|" +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 + D_CMND_CPU_FREQUENCY #endif // ESP32 #endif //FIRMWARE_MINIMAL_ONLY ; @@ -81,7 +85,11 @@ void (* const TasmotaCommand[])(void) PROGMEM = { #endif // USE_DEVICE_GROUPS &CmndSetSensor, &CmndSensor, &CmndDriver, &CmndJson #ifdef ESP32 - , &CmndInfo, &CmndTouchCal, &CmndTouchThres, &CmndTouchNum, &CmndCpuFrequency + , &CmndInfo, +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) + &CmndTouchCal, &CmndTouchThres, +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 + &CmndCpuFrequency #endif // ESP32 #endif //FIRMWARE_MINIMAL_ONLY }; @@ -2608,6 +2616,7 @@ void CmndCpuFrequency(void) { ResponseCmndNumber(getCpuFrequencyMhz()); } +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) void CmndTouchCal(void) { if (XdrvMailbox.payload >= 0) { if (XdrvMailbox.payload == 0) { @@ -2630,12 +2639,6 @@ void CmndTouchThres(void) { } ResponseCmndNumber(TOUCH_BUTTON.pin_threshold); } - -void CmndTouchNum(void) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32)) { - TOUCH_BUTTON.hit_threshold = XdrvMailbox.payload; - } - ResponseCmndNumber(TOUCH_BUTTON.hit_threshold); -} +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 #endif // ESP32 diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index 97e9af40d..77163871e 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -1993,10 +1993,12 @@ void GpioInit(void) ButtonInvertFlag(mpin - AGPIO(GPIO_KEY1_INV_PD)); // 0 .. 3 mpin -= (AGPIO(GPIO_KEY1_INV_PD) - AGPIO(GPIO_KEY1)); } +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) else if ((mpin >= AGPIO(GPIO_KEY1_TC)) && (mpin < (AGPIO(GPIO_KEY1_TC) + MAX_KEYS))) { ButtonTouchFlag(mpin - AGPIO(GPIO_KEY1_TC)); // 0 .. 3 mpin -= (AGPIO(GPIO_KEY1_TC) - AGPIO(GPIO_KEY1)); } +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 #endif //ESP32 else if ((mpin >= AGPIO(GPIO_REL1_INV)) && (mpin < (AGPIO(GPIO_REL1_INV) + MAX_RELAYS))) { bitSet(TasmotaGlobal.rel_inverted, mpin - AGPIO(GPIO_REL1_INV));