Compare commits
15 Commits
v2024.12.3
...
v2024.12.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5d941c460 | ||
|
|
9b134a786a | ||
|
|
be0fc353f6 | ||
|
|
fbc5cb79cc | ||
|
|
c65acc3298 | ||
|
|
4d8107faf2 | ||
|
|
65bbd901b1 | ||
|
|
8c610a406a | ||
|
|
696e3bf28d | ||
|
|
5ae4564e6a | ||
|
|
857c43940d | ||
|
|
8668fe8dc9 | ||
|
|
976a903118 | ||
|
|
35cc0c4a8e | ||
|
|
5c4581563e |
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
packages:
|
packages:
|
||||||
basic_package: !include ../TX-Ultimate-Easy-ESPHome.yaml # Basic package
|
basic_package: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml # Basic package
|
||||||
|
|
||||||
esp32:
|
esp32:
|
||||||
framework:
|
framework:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
packages:
|
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
|
addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml
|
||||||
|
|
||||||
esp32:
|
esp32:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
packages:
|
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
|
addon_bluetooth_proxy: !include ../ESPHome/TX-Ultimate-Easy-ESPHome_addon_ble_proxy.yaml
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ improv_serial:
|
|||||||
id: serial_improv
|
id: serial_improv
|
||||||
|
|
||||||
logger:
|
logger:
|
||||||
level: INFO
|
level: DEBUG
|
||||||
|
|
||||||
ota:
|
ota:
|
||||||
platform: esphome
|
platform: esphome
|
||||||
|
|||||||
@@ -20,111 +20,53 @@ substitutions:
|
|||||||
BUTTON_3_ACTION_TEXT: "Relay 3 (toggle)"
|
BUTTON_3_ACTION_TEXT: "Relay 3 (toggle)"
|
||||||
BUTTON_4_ACTION_TEXT: "Relay 4 (toggle)"
|
BUTTON_4_ACTION_TEXT: "Relay 4 (toggle)"
|
||||||
|
|
||||||
binary_sensor:
|
BUTTON_CLICK_MIN_LENGTH: '50' # The minimum duration the click should last, in msec
|
||||||
- id: bs_button_1
|
BUTTON_CLICK_MAX_LENGTH: '350' # The maximum duration the click should last, in msec
|
||||||
name: Button 1
|
BUTTON_MULTI_CLICK_DELAY: '250' # The time to wait for another click, in msec
|
||||||
icon: mdi:gesture-tap-box
|
BUTTON_PRESS_TIMEOUT: '10000' # Ignore if button is pressed for longer than this time, in msec
|
||||||
internal: false
|
BUTTON_LONG_PRESS_DELAY: '800' # The time to wait to consider a long press, in msec
|
||||||
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
|
|
||||||
|
|
||||||
- id: bs_button_2
|
binary_sensor:
|
||||||
|
- &binary_sensor_button_base
|
||||||
|
id: bs_button_2
|
||||||
name: Button 2
|
name: Button 2
|
||||||
icon: mdi:gesture-tap-box
|
icon: mdi:gesture-tap-box
|
||||||
internal: true
|
|
||||||
platform: template
|
platform: template
|
||||||
on_click:
|
internal: true
|
||||||
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
|
|
||||||
|
|
||||||
- id: bs_button_3
|
- id: bs_button_3
|
||||||
name: Button 3
|
name: Button 3
|
||||||
icon: mdi:gesture-tap-box
|
<<: *binary_sensor_button_base
|
||||||
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
|
|
||||||
|
|
||||||
- id: bs_button_4
|
- id: bs_button_4
|
||||||
name: Button 4
|
name: Button 4
|
||||||
icon: mdi:gesture-tap-box
|
<<: *binary_sensor_button_base
|
||||||
internal: true
|
|
||||||
platform: template
|
- id: bs_button_1
|
||||||
on_click:
|
name: Button 1
|
||||||
then:
|
internal: false
|
||||||
- script.execute:
|
<<: *binary_sensor_button_base
|
||||||
id: button_action
|
|
||||||
component: bs_button_4
|
globals:
|
||||||
event: click
|
- id: button_press_button
|
||||||
on_double_click:
|
type: uint8_t
|
||||||
then:
|
restore_value: false
|
||||||
- script.execute:
|
initial_value: '0'
|
||||||
id: button_action
|
|
||||||
component: bs_button_4
|
- id: button_press_position
|
||||||
event: double_click
|
type: uint8_t
|
||||||
on_multi_click:
|
restore_value: false
|
||||||
- timing: *long_click-timing
|
initial_value: '0'
|
||||||
invalid_cooldown: ${invalid_cooldown}
|
|
||||||
then:
|
- id: button_press_start_time
|
||||||
- script.execute:
|
type: uint32_t
|
||||||
id: button_action
|
restore_value: false
|
||||||
component: bs_button_4
|
initial_value: '0'
|
||||||
event: long_click
|
|
||||||
|
- id: click_counter
|
||||||
|
type: uint8_t
|
||||||
|
restore_value: false
|
||||||
|
initial_value: '0'
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- id: !extend boot_initialize
|
- id: !extend boot_initialize
|
||||||
@@ -162,9 +104,31 @@ script:
|
|||||||
parameters:
|
parameters:
|
||||||
component: string
|
component: string
|
||||||
event: string
|
event: string
|
||||||
then: # There's nothing here so far
|
then:
|
||||||
# Extended by:
|
# Extended by:
|
||||||
# - core_api
|
# - 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
|
||||||
|
parameters:
|
||||||
|
button_id: uint8_t
|
||||||
|
click_count: uint8_t
|
||||||
|
then:
|
||||||
|
- delay:
|
||||||
|
milliseconds: ${BUTTON_MULTI_CLICK_DELAY}
|
||||||
|
- lambda: |-
|
||||||
|
const std::string button_name = "bs_button_" + std::to_string(button_id);
|
||||||
|
std::string event_name;
|
||||||
|
if (click_count == 1) event_name = "click";
|
||||||
|
else if (click_count == 2) event_name = "double_click";
|
||||||
|
else event_name = std::to_string(click_count) + "_click";
|
||||||
|
button_action->execute(button_name.c_str(), event_name.c_str());
|
||||||
|
|
||||||
- id: buttons_release
|
- id: buttons_release
|
||||||
mode: restart
|
mode: restart
|
||||||
@@ -187,42 +151,78 @@ script:
|
|||||||
then:
|
then:
|
||||||
- script.execute:
|
- script.execute:
|
||||||
id: touch_on_press_buttons
|
id: touch_on_press_buttons
|
||||||
touch_x: !lambda return touch_x;
|
touch_position: !lambda return touch_position;
|
||||||
|
|
||||||
- id: touch_on_press_buttons
|
- id: touch_on_press_buttons
|
||||||
mode: restart
|
mode: restart
|
||||||
parameters:
|
parameters:
|
||||||
touch_x: uint8_t
|
touch_position: uint8_t
|
||||||
then:
|
then:
|
||||||
- lambda: |-
|
- lambda: |-
|
||||||
|
id(button_press_start_time) = millis();
|
||||||
|
id(button_press_position) = touch_position;
|
||||||
|
uint8_t button = 0;
|
||||||
auto model_index = sl_tx_model_gang->active_index();
|
auto model_index = sl_tx_model_gang->active_index();
|
||||||
if (model_index.has_value()) {
|
if (model_index.has_value()) {
|
||||||
uint8_t model_idx = model_index.value() + 1;
|
const uint8_t model_idx = model_index.value() + 1; // Increment for 1-based indexing
|
||||||
switch (model_idx) {
|
if (model_idx == 1) {
|
||||||
case 1: // 1 Gang
|
button = 1; // Single button, always 1
|
||||||
bs_button_1->publish_state(true);
|
} else {
|
||||||
break;
|
const uint8_t width = ${TOUCH_POSITION_MAX_VALUE} / model_idx; // Width of each button region
|
||||||
case 2: // 2 Gang
|
ESP_LOGV("core_hw_buttons", "Button regions: width=%" PRIu8 ", touch_position=%" PRIu8,
|
||||||
if (touch_x <= 5) bs_button_1->publish_state(true);
|
width, touch_position);
|
||||||
else bs_button_2->publish_state(true);
|
button = (touch_position / width) + 1; // Determine button region
|
||||||
break;
|
if (button > model_idx)
|
||||||
case 3: // 3 Gang
|
button = model_idx; // Clamp to max button count
|
||||||
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);
|
// Update binary sensor
|
||||||
break;
|
switch (button) {
|
||||||
case 4: // 4 Gang
|
case 1:
|
||||||
if (touch_x <= 2) bs_button_1->publish_state(true);
|
bs_button_1->publish_state(true);
|
||||||
else if (touch_x <= 5) bs_button_2->publish_state(true);
|
break;
|
||||||
else if (touch_x <= 8) bs_button_3->publish_state(true);
|
case 2:
|
||||||
else bs_button_4->publish_state(true);
|
bs_button_2->publish_state(true);
|
||||||
break;
|
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
|
- id: !extend touch_on_release
|
||||||
then:
|
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(id(button_press_button), id(click_counter));
|
||||||
|
} 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;
|
||||||
|
|
||||||
- id: !extend touch_swipe_left
|
- id: !extend touch_swipe_left
|
||||||
then:
|
then:
|
||||||
|
|||||||
@@ -11,55 +11,6 @@
|
|||||||
##### - For normal system use, modifications to this file are NOT required. #####
|
##### - For normal system use, modifications to this file are NOT required. #####
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
---
|
---
|
||||||
binary_sensor:
|
|
||||||
- id: !extend bs_button_1
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- if:
|
|
||||||
condition:
|
|
||||||
- lambda: return sl_button_1_action->active_index().has_value();
|
|
||||||
- lambda: return sl_button_1_action->active_index().value() == 1;
|
|
||||||
- and: &button_click_no_other_click
|
|
||||||
- lambda: return not bs_multi_touch->state;
|
|
||||||
- lambda: return not bs_swipe_left->state;
|
|
||||||
- lambda: return not bs_swipe_down->state;
|
|
||||||
- lambda: return not bs_swipe_right->state;
|
|
||||||
then:
|
|
||||||
- switch.toggle: sw_relay_1
|
|
||||||
|
|
||||||
- id: !extend bs_button_2
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- if:
|
|
||||||
condition:
|
|
||||||
- lambda: return sl_button_2_action->active_index().has_value();
|
|
||||||
- lambda: return sl_button_2_action->active_index().value() == 1;
|
|
||||||
- and: *button_click_no_other_click
|
|
||||||
then:
|
|
||||||
- switch.toggle: sw_relay_2
|
|
||||||
|
|
||||||
- id: !extend bs_button_3
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- if:
|
|
||||||
condition:
|
|
||||||
- lambda: return sl_button_3_action->active_index().has_value();
|
|
||||||
- lambda: return sl_button_3_action->active_index().value() == 1;
|
|
||||||
- and: *button_click_no_other_click
|
|
||||||
then:
|
|
||||||
- switch.toggle: sw_relay_3
|
|
||||||
|
|
||||||
- id: !extend bs_button_4
|
|
||||||
on_click:
|
|
||||||
then:
|
|
||||||
- if:
|
|
||||||
condition:
|
|
||||||
- lambda: return sl_button_4_action->active_index().has_value();
|
|
||||||
- lambda: return sl_button_4_action->active_index().value() == 1;
|
|
||||||
- and: *button_click_no_other_click
|
|
||||||
then:
|
|
||||||
- switch.toggle: sw_relay_4
|
|
||||||
|
|
||||||
globals:
|
globals:
|
||||||
- id: boot_initialization_relays
|
- id: boot_initialization_relays
|
||||||
type: bool
|
type: bool
|
||||||
@@ -159,6 +110,45 @@ script:
|
|||||||
}
|
}
|
||||||
id(boot_initialization_relays) = true;
|
id(boot_initialization_relays) = true;
|
||||||
|
|
||||||
|
- id: !extend button_click_event
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
// Handle only single clicks
|
||||||
|
if (click_count != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Ignore if other touch events are active
|
||||||
|
if (bs_multi_touch->state ||
|
||||||
|
bs_swipe_left->state ||
|
||||||
|
bs_swipe_down->state ||
|
||||||
|
bs_swipe_right->state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle relay if corresponding button action is enabled
|
||||||
|
switch (button_id) {
|
||||||
|
case 1:
|
||||||
|
if (sl_button_1_action->active_index().has_value() and
|
||||||
|
sl_button_1_action->active_index().value() == 1)
|
||||||
|
sw_relay_1->toggle();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (sl_button_2_action->active_index().has_value() and
|
||||||
|
sl_button_2_action->active_index().value() == 1)
|
||||||
|
sw_relay_2->toggle();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (sl_button_3_action->active_index().has_value() and
|
||||||
|
sl_button_3_action->active_index().value() == 1)
|
||||||
|
sw_relay_3->toggle();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (sl_button_4_action->active_index().has_value() and
|
||||||
|
sl_button_4_action->active_index().value() == 1)
|
||||||
|
sw_relay_4->toggle();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
- id: show_relay_status
|
- id: show_relay_status
|
||||||
mode: restart
|
mode: restart
|
||||||
then:
|
then:
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
##### - For normal system use, modifications to this file are NOT required. #####
|
##### - For normal system use, modifications to this file are NOT required. #####
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
---
|
---
|
||||||
|
substitutions:
|
||||||
|
TOUCH_POSITION_MAX_VALUE: '10' # Maximum touch position value returned by the touch pad via uart
|
||||||
|
|
||||||
binary_sensor:
|
binary_sensor:
|
||||||
- id: bs_multi_touch
|
- id: bs_multi_touch
|
||||||
name: Multi-touch
|
name: Multi-touch
|
||||||
@@ -61,7 +64,7 @@ external_components:
|
|||||||
- source:
|
- source:
|
||||||
type: git
|
type: git
|
||||||
url: https://github.com/edwardtfn/TX-Ultimate-Easy
|
url: https://github.com/edwardtfn/TX-Ultimate-Easy
|
||||||
ref: ${version}
|
ref: v${version}
|
||||||
refresh: 1h
|
refresh: 1h
|
||||||
components:
|
components:
|
||||||
- tx_ultimate_easy
|
- tx_ultimate_easy
|
||||||
@@ -124,7 +127,7 @@ script:
|
|||||||
- id: touch_on_press
|
- id: touch_on_press
|
||||||
mode: restart
|
mode: restart
|
||||||
parameters:
|
parameters:
|
||||||
touch_x: uint8_t
|
touch_position: uint8_t
|
||||||
then:
|
then:
|
||||||
# Extended by:
|
# Extended by:
|
||||||
# - HW Buttons
|
# - HW Buttons
|
||||||
@@ -203,16 +206,28 @@ tx_ultimate_easy:
|
|||||||
id: tx_ultimate
|
id: tx_ultimate
|
||||||
uart: uart_touch
|
uart: uart_touch
|
||||||
|
|
||||||
|
on_long_touch_release:
|
||||||
|
- lambda: |-
|
||||||
|
const uint8_t touch_position = static_cast<uint8_t>(touch.x);
|
||||||
|
if (touch_position > ${TOUCH_POSITION_MAX_VALUE}) { // Check for valid range
|
||||||
|
ESP_LOGE("tx_ultimate_easy", "Invalid long-touch position: %" PRIu8, touch_position);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI("tx_ultimate_easy", "Long-touch released at position %" PRIu8, touch_position);
|
||||||
|
}
|
||||||
|
|
||||||
on_multi_touch_release:
|
on_multi_touch_release:
|
||||||
- lambda: ESP_LOGI("tx_ultimate_easy", "Multi-touch released");
|
- lambda: ESP_LOGI("tx_ultimate_easy", "Multi-touch released");
|
||||||
- script.execute: touch_on_multi_touch_release
|
- script.execute: touch_on_multi_touch_release
|
||||||
|
|
||||||
on_press:
|
on_press:
|
||||||
- lambda: |-
|
- lambda: |-
|
||||||
ESP_LOGI("tx_ultimate_easy", "Pressed at position %" PRIu8, static_cast<uint8_t>(touch.x));
|
const uint8_t touch_position = static_cast<uint8_t>(touch.x);
|
||||||
- script.execute:
|
if (touch_position > ${TOUCH_POSITION_MAX_VALUE}) { // Check for valid range
|
||||||
id: touch_on_press
|
ESP_LOGE("tx_ultimate_easy", "Invalid touch position: %" PRIu8, touch_position);
|
||||||
touch_x: !lambda return static_cast<uint8_t>(touch.x);
|
} else {
|
||||||
|
ESP_LOGI("tx_ultimate_easy", "Pressed at position %" PRIu8, touch_position);
|
||||||
|
touch_on_press->execute(touch_position);
|
||||||
|
}
|
||||||
|
|
||||||
on_release:
|
on_release:
|
||||||
- lambda: ESP_LOGI("tx_ultimate_easy", "Released");
|
- lambda: ESP_LOGI("tx_ultimate_easy", "Released");
|
||||||
@@ -233,8 +248,8 @@ tx_ultimate_easy:
|
|||||||
ESP_LOGD("tx_ultimate_easy", " Position: %i", touch.x);
|
ESP_LOGD("tx_ultimate_easy", " Position: %i", touch.x);
|
||||||
|
|
||||||
uart:
|
uart:
|
||||||
id: uart_touch
|
- id: uart_touch
|
||||||
tx_pin: GPIO19
|
tx_pin: GPIO19
|
||||||
rx_pin: GPIO22
|
rx_pin: GPIO22
|
||||||
baud_rate: 115200
|
baud_rate: 115200
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ wifi:
|
|||||||
packages:
|
packages:
|
||||||
remote_package:
|
remote_package:
|
||||||
url: https://github.com/edwardtfn/TX-Ultimate-Easy
|
url: https://github.com/edwardtfn/TX-Ultimate-Easy
|
||||||
ref: dev
|
ref: latest
|
||||||
refresh: 30s
|
refresh: 30s
|
||||||
files:
|
files:
|
||||||
- ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
|
- ESPHome/TX-Ultimate-Easy-ESPHome_core.yaml
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ DEPENDENCIES = ['uart']
|
|||||||
CONF_TX_ULTIMATE_EASY = "tx_ultimate_easy"
|
CONF_TX_ULTIMATE_EASY = "tx_ultimate_easy"
|
||||||
|
|
||||||
CONF_UART = "uart"
|
CONF_UART = "uart"
|
||||||
|
CONF_GANG_COUNT = "gang_count"
|
||||||
|
|
||||||
CONF_ON_TOUCH_EVENT = "on_touch_event"
|
CONF_ON_TOUCH_EVENT = "on_touch_event"
|
||||||
CONF_ON_PRESS = "on_press"
|
CONF_ON_PRESS = "on_press"
|
||||||
@@ -33,6 +34,7 @@ CONFIG_SCHEMA = cv.Schema({
|
|||||||
cv.GenerateID(): cv.declare_id(TxUltimateTouch),
|
cv.GenerateID(): cv.declare_id(TxUltimateTouch),
|
||||||
|
|
||||||
cv.Required(CONF_UART): cv.use_id(uart),
|
cv.Required(CONF_UART): cv.use_id(uart),
|
||||||
|
cv.Optional(CONF_GANG_COUNT, default=1): cv.int_range(min=1, max=4),
|
||||||
|
|
||||||
cv.Optional(CONF_ON_TOUCH_EVENT): automation.validate_automation(single=True),
|
cv.Optional(CONF_ON_TOUCH_EVENT): automation.validate_automation(single=True),
|
||||||
cv.Optional(CONF_ON_PRESS): automation.validate_automation(single=True),
|
cv.Optional(CONF_ON_PRESS): automation.validate_automation(single=True),
|
||||||
@@ -49,6 +51,9 @@ async def register_tx_ultimate_easy(var, config):
|
|||||||
uart_component = await cg.get_variable(config[CONF_UART])
|
uart_component = await cg.get_variable(config[CONF_UART])
|
||||||
cg.add(var.set_uart_component(uart_component))
|
cg.add(var.set_uart_component(uart_component))
|
||||||
|
|
||||||
|
if CONF_GANG_COUNT in config:
|
||||||
|
cg.add(var.set_gang_count(config[CONF_GANG_COUNT]))
|
||||||
|
|
||||||
if CONF_ON_TOUCH_EVENT in config:
|
if CONF_ON_TOUCH_EVENT in config:
|
||||||
await automation.build_automation(
|
await automation.build_automation(
|
||||||
var.get_trigger_touch_event(),
|
var.get_trigger_touch_event(),
|
||||||
|
|||||||
@@ -48,6 +48,35 @@ namespace esphome {
|
|||||||
|
|
||||||
void TxUltimateEasy::dump_config() {
|
void TxUltimateEasy::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "TX Ultimate Easy");
|
ESP_LOGCONFIG(TAG, "TX Ultimate Easy");
|
||||||
|
ESP_LOGCONFIG(TAG, " Gang count: %" PRIu8, this->gang_count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TxUltimateEasy::set_gang_count(const uint8_t gang_count) {
|
||||||
|
// Hardware supports maximum of 4 touch-sensitive buttons
|
||||||
|
if (gang_count < 1 or gang_count > 4)
|
||||||
|
return false;
|
||||||
|
this->gang_count_ = gang_count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TxUltimateEasy::get_button_from_position(const uint8_t position) {
|
||||||
|
// Validate position bounds
|
||||||
|
if (position > TOUCH_MAX_POSITION)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Special case for single gang (only one button exists)
|
||||||
|
if (this->gang_count_ == 1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// Calculate button number
|
||||||
|
const uint8_t width = (TOUCH_MAX_POSITION + 1) / this->gang_count_; // Width of each button region
|
||||||
|
if (width < 1 or width > this->gang_count_) // Invalid width - and prevents division by zero
|
||||||
|
return 0;
|
||||||
|
const uint8_t button = std::min(
|
||||||
|
static_cast<uint8_t>((position / width) + 1), // Convert position to button index
|
||||||
|
this->gang_count_ // Clamp to max gang count
|
||||||
|
);
|
||||||
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TxUltimateEasy::send_touch_(TouchPoint tp) {
|
void TxUltimateEasy::send_touch_(TouchPoint tp) {
|
||||||
@@ -103,7 +132,8 @@ namespace esphome {
|
|||||||
state == TOUCH_STATE_SWIPE_LEFT ||
|
state == TOUCH_STATE_SWIPE_LEFT ||
|
||||||
state == TOUCH_STATE_SWIPE_RIGHT ||
|
state == TOUCH_STATE_SWIPE_RIGHT ||
|
||||||
state == TOUCH_STATE_MULTI_TOUCH) &&
|
state == TOUCH_STATE_MULTI_TOUCH) &&
|
||||||
(uart_received_bytes[6] >= 0 || state == TOUCH_STATE_MULTI_TOUCH);
|
// Multi-touch events may have x < 0, all other events require valid x position
|
||||||
|
(uart_received_bytes[6] >= 0 || state == TOUCH_STATE_MULTI_TOUCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TxUltimateEasy::get_touch_position_x(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
|
int TxUltimateEasy::get_touch_position_x(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
|
||||||
@@ -133,6 +163,8 @@ namespace esphome {
|
|||||||
TouchPoint TxUltimateEasy::get_touch_point(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
|
TouchPoint TxUltimateEasy::get_touch_point(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
|
||||||
TouchPoint tp;
|
TouchPoint tp;
|
||||||
tp.x = this->get_touch_position_x(uart_received_bytes);
|
tp.x = this->get_touch_position_x(uart_received_bytes);
|
||||||
|
if (tp.x >= 0)
|
||||||
|
tp.button = this->get_button_from_position(static_cast<uint8_t>(tp.x));
|
||||||
tp.state = this->get_touch_state(uart_received_bytes);
|
tp.state = this->get_touch_state(uart_received_bytes);
|
||||||
switch (tp.state) {
|
switch (tp.state) {
|
||||||
case TOUCH_STATE_RELEASE:
|
case TOUCH_STATE_RELEASE:
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace tx_ultimate_easy {
|
namespace tx_ultimate_easy {
|
||||||
|
// Touch Max Position
|
||||||
|
constexpr uint8_t TOUCH_MAX_POSITION = 10;
|
||||||
|
|
||||||
// Touch State Constants
|
// Touch State Constants
|
||||||
constexpr uint8_t TOUCH_STATE_RELEASE = 0x01;
|
constexpr uint8_t TOUCH_STATE_RELEASE = 0x01;
|
||||||
constexpr uint8_t TOUCH_STATE_PRESS = 0x02;
|
constexpr uint8_t TOUCH_STATE_PRESS = 0x02;
|
||||||
@@ -32,6 +35,7 @@ namespace esphome {
|
|||||||
static const char *TAG = "tx_ultimate_easy";
|
static const char *TAG = "tx_ultimate_easy";
|
||||||
|
|
||||||
struct TouchPoint {
|
struct TouchPoint {
|
||||||
|
uint8_t button = 0;
|
||||||
int8_t x = -1;
|
int8_t x = -1;
|
||||||
int8_t state = -1;
|
int8_t state = -1;
|
||||||
std::string state_str = "Unknown";
|
std::string state_str = "Unknown";
|
||||||
@@ -53,6 +57,10 @@ namespace esphome {
|
|||||||
void loop() override;
|
void loop() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
|
uint8_t get_gang_count() { return this->gang_count_; }
|
||||||
|
bool set_gang_count(const uint8_t gang_count);
|
||||||
|
uint8_t get_button_from_position(const uint8_t position);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void send_touch_(TouchPoint tp);
|
void send_touch_(TouchPoint tp);
|
||||||
void handle_touch(const std::array<int, UART_RECEIVED_BYTES_SIZE> &bytes);
|
void handle_touch(const std::array<int, UART_RECEIVED_BYTES_SIZE> &bytes);
|
||||||
@@ -70,6 +78,8 @@ namespace esphome {
|
|||||||
Trigger<TouchPoint> trigger_multi_touch_release_;
|
Trigger<TouchPoint> trigger_multi_touch_release_;
|
||||||
Trigger<TouchPoint> trigger_long_touch_release_;
|
Trigger<TouchPoint> trigger_long_touch_release_;
|
||||||
|
|
||||||
|
uint8_t gang_count_ = 1;
|
||||||
|
|
||||||
}; // class TxUltimateEasy
|
}; // class TxUltimateEasy
|
||||||
|
|
||||||
} // namespace tx_ultimate_easy
|
} // namespace tx_ultimate_easy
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2024.12.3
|
2024.12.4
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
version: 2024.12.3
|
version: 2024.12.4
|
||||||
|
|||||||
Reference in New Issue
Block a user