Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebuild Button click engine #50

Merged
merged 13 commits into from
Dec 22, 2024
2 changes: 1 addition & 1 deletion .test/esphome_ard_basic.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
packages:
basic_package: !include ../TX-Ultimate-Easy-ESPHome.yaml # Basic package
basic_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml # Basic package

esp32:
framework:
Expand Down
2 changes: 1 addition & 1 deletion .test/esphome_idf53_bluetooth_proxy.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
packages:
basic_package: !include ../TX-Ultimate-Easy-ESPHome.yaml # Core package
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml

esp32:
Expand Down
2 changes: 1 addition & 1 deletion .test/esphome_idf_bluetooth_proxy.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
packages:
basic_package: !include ../TX-Ultimate-Easy-ESPHome.yaml # Core package
core_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml
...
235 changes: 115 additions & 120 deletions ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_buttons.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,111 +20,53 @@ substitutions:
BUTTON_3_ACTION_TEXT: "Relay 3 (toggle)"
BUTTON_4_ACTION_TEXT: "Relay 4 (toggle)"

binary_sensor:
- id: bs_button_1
name: Button 1
icon: mdi:gesture-tap-box
internal: false
platform: template
on_click:
then:
- script.execute:
id: button_action
component: bs_button_1
event: click
on_double_click:
then:
- script.execute:
id: button_action
component: bs_button_1
event: double_click
on_multi_click:
- timing: &long_click-timing
- ON for at least 0.8s
invalid_cooldown: ${invalid_cooldown}
then:
- script.execute:
id: button_action
component: bs_button_1
event: long_click
BUTTON_CLICK_MIN_LENGTH: '50' # The minimum duration the click should last, in msec
BUTTON_CLICK_MAX_LENGTH: '350' # The maximum duration the click should last, in msec
BUTTON_MULTI_CLICK_DELAY: '500' # The time to wait for another click, in msec
BUTTON_PRESS_TIMEOUT: '10000' # Ignore if button is pressed for longer than this time, in msec
BUTTON_LONG_PRESS_DELAY: '800' # The time to wait to consider a long press, in msec

- id: bs_button_2
binary_sensor:
- &binary_sensor_button_base
id: bs_button_2
name: Button 2
icon: mdi:gesture-tap-box
internal: true
platform: template
on_click:
then:
- script.execute:
id: button_action
component: bs_button_2
event: click
on_double_click:
then:
- script.execute:
id: button_action
component: bs_button_2
event: double_click
on_multi_click:
- timing: *long_click-timing
invalid_cooldown: ${invalid_cooldown}
then:
- script.execute:
id: button_action
component: bs_button_2
event: long_click
internal: true

- id: bs_button_3
name: Button 3
icon: mdi:gesture-tap-box
internal: true
platform: template
on_click:
then:
- script.execute:
id: button_action
component: bs_button_3
event: click
on_double_click:
then:
- script.execute:
id: button_action
component: bs_button_3
event: double_click
on_multi_click:
- timing: *long_click-timing
invalid_cooldown: ${invalid_cooldown}
then:
- script.execute:
id: button_action
component: bs_button_3
event: long_click
<<: *binary_sensor_button_base

- id: bs_button_4
name: Button 4
icon: mdi:gesture-tap-box
internal: true
platform: template
on_click:
then:
- script.execute:
id: button_action
component: bs_button_4
event: click
on_double_click:
then:
- script.execute:
id: button_action
component: bs_button_4
event: double_click
on_multi_click:
- timing: *long_click-timing
invalid_cooldown: ${invalid_cooldown}
then:
- script.execute:
id: button_action
component: bs_button_4
event: long_click
<<: *binary_sensor_button_base

- id: bs_button_1
name: Button 1
internal: false
<<: *binary_sensor_button_base

globals:
- id: button_press_button
type: uint8_t
restore_value: false
initial_value: '0'

- id: button_press_position
type: uint8_t
restore_value: false
initial_value: '0'

- id: button_press_start_time
type: uint32_t
restore_value: false
initial_value: '0'

- id: click_counter
type: uint8_t
restore_value: false
initial_value: '0'

script:
- id: !extend boot_initialize
Expand Down Expand Up @@ -162,9 +104,28 @@ script:
parameters:
component: string
event: string
then: # There's nothing here so far
# Extended by:
# - core_api
then:
# Extended by:
# - core_api
- lambda: |-
ESP_LOGI("core_hw_buttons", "Button '%s' action: '%s'", component.c_str(), event.c_str());
id(button_press_button) = 0;
id(click_counter) = 0;
id(button_press_start_time) = 0;
buttons_release->execute();

- id: button_click_event
mode: restart
then:
- delay:
milliseconds: ${BUTTON_MULTI_CLICK_DELAY}
- lambda: |-
const std::string button_name = "bs_button_" + std::to_string(id(button_press_button));
std::string event_name;
if (id(click_counter) == 1) event_name = "click";
else if (id(click_counter) == 2) event_name = "double_click";
else event_name = std::to_string(id(click_counter)) + "_click";
button_action->execute(button_name.c_str(), event_name.c_str());

- id: buttons_release
mode: restart
Expand Down Expand Up @@ -195,34 +156,68 @@ script:
touch_x: uint8_t
then:
- lambda: |-
id(button_press_start_time) = millis();
id(button_press_position) = touch_x;
uint8_t button = 0;
auto model_index = sl_tx_model_gang->active_index();
if (model_index.has_value()) {
uint8_t model_idx = model_index.value() + 1;
switch (model_idx) {
case 1: // 1 Gang
bs_button_1->publish_state(true);
break;
case 2: // 2 Gang
if (touch_x <= 5) bs_button_1->publish_state(true);
else bs_button_2->publish_state(true);
break;
case 3: // 3 Gang
if (touch_x <= 3) bs_button_1->publish_state(true);
else if (touch_x <= 7) bs_button_2->publish_state(true);
else bs_button_3->publish_state(true);
break;
case 4: // 4 Gang
if (touch_x <= 2) bs_button_1->publish_state(true);
else if (touch_x <= 5) bs_button_2->publish_state(true);
else if (touch_x <= 8) bs_button_3->publish_state(true);
else bs_button_4->publish_state(true);
break;
}
const uint8_t model_idx = model_index.value() + 1; // Increment for 1-based indexing
if (model_idx == 1) {
button = 1; // Single button, always 1
} else {
const uint8_t step = ${TOUCH_POSITION_MAX_VALUE} / model_idx; // Width of each button region
button = (touch_x / step) + 1; // Determine button region
if (button > model_idx)
button = model_idx; // Clamp to max button count
}
}
// Update binary sensor
switch (button) {
case 1:
bs_button_1->publish_state(true);
break;
case 2:
bs_button_2->publish_state(true);
break;
case 3:
bs_button_3->publish_state(true);
break;
case 4:
bs_button_4->publish_state(true);
break;
}
// Update counters
if (id(button_press_button) == button) {
id(click_counter)++;
} else {
id(click_counter) = 1;
id(button_press_button) = button;
}

- id: !extend touch_on_release
then:
- script.execute: buttons_release
- lambda: |-
uint32_t current_time = millis();
buttons_release->execute();
if (id(button_press_start_time) > 0 and
id(button_press_start_time) < current_time) {
uint32_t press_duration = current_time - id(button_press_start_time);
// Handle overflow (optional, since it's unlikely to happen here)
ESP_LOGI("core_hw_buttons", "Button press duration: %" PRIu32 " ms", press_duration);
if (press_duration < ${BUTTON_CLICK_MIN_LENGTH}) {
ESP_LOGW("core_hw_buttons", "Ignoring button press (too short)");
} else if (press_duration >= ${BUTTON_CLICK_MIN_LENGTH} and
press_duration <= ${BUTTON_CLICK_MAX_LENGTH}) { // Short/normal click
button_click_event->execute();
} else if (press_duration >= ${BUTTON_LONG_PRESS_DELAY} and press_duration <= ${BUTTON_PRESS_TIMEOUT}) {
button_action->execute(("bs_button_" + std::to_string(id(button_press_button))).c_str(), "long_click");
} else if (press_duration > ${BUTTON_PRESS_TIMEOUT}) { // Timeout or invalid
ESP_LOGW("core_hw_buttons", "Button press cancelled or timed out after ${BUTTON_PRESS_TIMEOUT} ms");
}
} else {
ESP_LOGW("core_hw_buttons", "Press event timestamp not recorded yet");
}
id(button_press_start_time) = 0;
edwardtfn marked this conversation as resolved.
Show resolved Hide resolved

- id: !extend touch_swipe_left
then:
Expand Down
13 changes: 8 additions & 5 deletions ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_touch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
##### - For normal system use, modifications to this file are NOT required. #####
####################################################################################################
---
substitutions:
TOUCH_POSITION_MAX_VALUE: '10' # Maximum touch position value

binary_sensor:
- id: bs_multi_touch
name: Multi-touch
Expand Down Expand Up @@ -61,7 +64,7 @@ external_components:
- source:
type: git
url: https://github.com/edwardtfn/TX-Ultimate-Easy
ref: ${version}
ref: v${version}
refresh: 1h
components:
- tx_ultimate_easy
Expand Down Expand Up @@ -233,8 +236,8 @@ tx_ultimate_easy:
ESP_LOGD("tx_ultimate_easy", " Position: %i", touch.x);

uart:
id: uart_touch
tx_pin: GPIO19
rx_pin: GPIO22
baud_rate: 115200
- id: uart_touch
tx_pin: GPIO19
rx_pin: GPIO22
baud_rate: 115200
...
2 changes: 1 addition & 1 deletion TX-Ultimate-Easy-ESPHome.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ wifi:
packages:
remote_package:
url: https://github.com/edwardtfn/TX-Ultimate-Easy
ref: dev
ref: latest
refresh: 30s
files:
- ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
Expand Down
Loading