From 3e7e0322e59e2cded25d39f69ce7b7723084362f Mon Sep 17 00:00:00 2001 From: agessaman Date: Fri, 28 Aug 2026 15:37:09 -0700 Subject: [PATCH] fix(display): make the USER button click immediate, 3 s hold to power off Power-off now needs a 3 second hold; any shorter press toggles the display. MomentaryButton reports a CLICK for any release short of its threshold, so that single value defines both. The button also felt unreliable - "a brief press doesn't wake it, more often than not". MomentaryButton's multi-click detection withholds a CLICK for MULTI_CLICK_WINDOW_MS (280 ms) after release, and folds a second press arriving inside that window into a DOUBLE_CLICK. Since the handler only acts on CLICK, an impatient second press produced nothing at all: press, see nothing, press again, still nothing. Multi-click is now off for these targets, so CLICK fires on release. Both settings are build flags defaulted in variants/heltec_v4_r8/target.cpp and overridden only on the two TFT observer bases, because the companion builds share this user_btn and do use double/triple click. DISPLAY_TOUCH_DEBUG additionally logs which input caused a toggle ("Display: button -> on"), so any remaining flake can be attributed to the button or to a spurious touch read rather than guessed at. --- examples/simple_repeater/UITask.cpp | 11 ++++++++--- examples/simple_repeater/UITask.h | 2 +- examples/simple_room_server/UITask.cpp | 11 ++++++++--- examples/simple_room_server/UITask.h | 2 +- variants/heltec_v4_r8/platformio.ini | 8 ++++++++ variants/heltec_v4_r8/target.cpp | 14 +++++++++++++- 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/examples/simple_repeater/UITask.cpp b/examples/simple_repeater/UITask.cpp index f845577c..61a7fedd 100644 --- a/examples/simple_repeater/UITask.cpp +++ b/examples/simple_repeater/UITask.cpp @@ -326,12 +326,17 @@ void UITask::updateActivityRows() { #endif #ifdef DISPLAY_TOUCH_TOGGLE -void UITask::toggleDisplay() { +void UITask::toggleDisplay(const char* source) { if (_display->isOn()) { _display->turnOff(); } else { _display->turnOn(); } +#ifdef DISPLAY_TOUCH_DEBUG + Serial.printf("Display: %s -> %s\n", source, _display->isOn() ? "on" : "off"); +#else + (void)source; +#endif #ifdef DISPLAY_REDRAW_ON_CHANGE _frame_valid = false; // wake draws one complete current frame #endif @@ -348,7 +353,7 @@ void UITask::loop() { int ev = user_btn.check(); if (ev == BUTTON_EVENT_CLICK) { #ifdef DISPLAY_TOUCH_TOGGLE - toggleDisplay(); // same action as tapping the panel + toggleDisplay("button"); // same action as tapping the panel #else if (_display->isOn()) { // TODO: any action ? @@ -392,7 +397,7 @@ void UITask::loop() { unsigned long now = millis(); if (millisReached(now, _next_touch)) { _next_touch = now + TOUCH_POLL_MILLIS; - if (_touch.checkTap(now)) toggleDisplay(); + if (_touch.checkTap(now)) toggleDisplay("touch"); } } #endif diff --git a/examples/simple_repeater/UITask.h b/examples/simple_repeater/UITask.h index 65ca1674..9c7a05ef 100644 --- a/examples/simple_repeater/UITask.h +++ b/examples/simple_repeater/UITask.h @@ -48,7 +48,7 @@ class UITask { CHSC6XTouch _touch; unsigned long _next_touch = 0; - void toggleDisplay(); + void toggleDisplay(const char* source); #endif #ifdef WITH_MQTT_BRIDGE diff --git a/examples/simple_room_server/UITask.cpp b/examples/simple_room_server/UITask.cpp index 998cc7e2..7b4470d2 100644 --- a/examples/simple_room_server/UITask.cpp +++ b/examples/simple_room_server/UITask.cpp @@ -303,12 +303,17 @@ void UITask::updateActivityRows() { #endif #ifdef DISPLAY_TOUCH_TOGGLE -void UITask::toggleDisplay() { +void UITask::toggleDisplay(const char* source) { if (_display->isOn()) { _display->turnOff(); } else { _display->turnOn(); } +#ifdef DISPLAY_TOUCH_DEBUG + Serial.printf("Display: %s -> %s\n", source, _display->isOn() ? "on" : "off"); +#else + (void)source; +#endif #ifdef DISPLAY_REDRAW_ON_CHANGE _frame_valid = false; // wake draws one complete current frame #endif @@ -327,7 +332,7 @@ void UITask::loop() { if (btnState != _prevBtnState) { if (btnState == USER_BTN_PRESSED) { // pressed? #ifdef DISPLAY_TOUCH_TOGGLE - toggleDisplay(); // same action as tapping the panel + toggleDisplay("button"); // same action as tapping the panel #else if (_display->isOn()) { // TODO: any action ? @@ -371,7 +376,7 @@ void UITask::loop() { unsigned long now = millis(); if (millisReached(now, _next_touch)) { _next_touch = now + TOUCH_POLL_MILLIS; - if (_touch.checkTap(now)) toggleDisplay(); + if (_touch.checkTap(now)) toggleDisplay("touch"); } } #endif diff --git a/examples/simple_room_server/UITask.h b/examples/simple_room_server/UITask.h index 96f63ac4..04704679 100644 --- a/examples/simple_room_server/UITask.h +++ b/examples/simple_room_server/UITask.h @@ -45,7 +45,7 @@ class UITask { CHSC6XTouch _touch; unsigned long _next_touch = 0; - void toggleDisplay(); + void toggleDisplay(const char* source); #endif #ifdef WITH_MQTT_BRIDGE diff --git a/variants/heltec_v4_r8/platformio.ini b/variants/heltec_v4_r8/platformio.ini index ec509b0a..cc6d5cc3 100644 --- a/variants/heltec_v4_r8/platformio.ini +++ b/variants/heltec_v4_r8/platformio.ini @@ -339,6 +339,10 @@ build_flags = ; Blanking is a runtime setting now: `set display.timeout `, 0 = stay on, ; 60 s default. Tap the Expansion Kit panel or press USER to toggle by hand. -D DISPLAY_TOUCH_TOGGLE=1 +; Hold 3 s to power off; any shorter press toggles the display, acted on the +; moment the button is released rather than 280 ms later. + -D USER_BTN_LONG_PRESS_MILLIS=3000 + -D USER_BTN_MULTICLICK=0 ; Diagnostic: logs the raw CHSC6X frame (and TP_INT) when it changes. Drop this ; and PIN_TOUCH_INT once touch is confirmed working. -D DISPLAY_TOUCH_DEBUG=1 @@ -414,6 +418,10 @@ build_flags = ; Blanking is a runtime setting now: `set display.timeout `, 0 = stay on, ; 60 s default. Tap the Expansion Kit panel or press USER to toggle by hand. -D DISPLAY_TOUCH_TOGGLE=1 +; Hold 3 s to power off; any shorter press toggles the display, acted on the +; moment the button is released rather than 280 ms later. + -D USER_BTN_LONG_PRESS_MILLIS=3000 + -D USER_BTN_MULTICLICK=0 ; Diagnostic: logs the raw CHSC6X frame (and TP_INT) when it changes. Drop this ; and PIN_TOUCH_INT once touch is confirmed working. -D DISPLAY_TOUCH_DEBUG=1 diff --git a/variants/heltec_v4_r8/target.cpp b/variants/heltec_v4_r8/target.cpp index 0b38531e..b1912d40 100644 --- a/variants/heltec_v4_r8/target.cpp +++ b/variants/heltec_v4_r8/target.cpp @@ -25,7 +25,19 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #ifdef DISPLAY_CLASS DISPLAY_CLASS display(&board.periph_power); - MomentaryButton user_btn(PIN_USER_BTN, 1000, true); + #ifndef USER_BTN_LONG_PRESS_MILLIS + #define USER_BTN_LONG_PRESS_MILLIS 1000 + #endif + // Multi-click detection holds a CLICK back for MULTI_CLICK_WINDOW_MS (280 ms) + // after release, and folds a second press inside that window into a + // DOUBLE_CLICK. Targets that only want a plain click set this to 0 so the + // event fires on release instead of being delayed - or swallowed when an + // impatient second press arrives. + #ifndef USER_BTN_MULTICLICK + #define USER_BTN_MULTICLICK 1 + #endif + MomentaryButton user_btn(PIN_USER_BTN, USER_BTN_LONG_PRESS_MILLIS, true, false, + USER_BTN_MULTICLICK); #endif bool radio_init() {