Merge pull request #121 from edwardtfn/nvs-optimization

Nvs optimization
This commit is contained in:
Edward Firmo
2025-08-06 16:33:35 +02:00
committed by GitHub
7 changed files with 853 additions and 17 deletions

View File

@@ -30,6 +30,7 @@ substitutions:
LIGHT_INDIVIDUAL_RESTORE_MODE: RESTORE_DEFAULT_OFF LIGHT_INDIVIDUAL_RESTORE_MODE: RESTORE_DEFAULT_OFF
LIGHT_ATTRS_DEFAULT: '0x64FFFFFF' # brightness=100, RGB=255,255,255 LIGHT_ATTRS_DEFAULT: '0x64FFFFFF' # brightness=100, RGB=255,255,255
LIGHT_DUAL_ATTRS_DEFAULT: '0x64FFFFFF64FFFFFF' # Both lights: brightness=100, RGB=255,255,255
TAG_CORE_HW_LEDS: core.hw.leds TAG_CORE_HW_LEDS: core.hw.leds
@@ -559,6 +560,22 @@ script:
ESP_LOGI("${TAG_CORE_HW_LEDS}", "Restored light attributes: brightness=%d%%, RGB=(%d,%d,%d)", ESP_LOGI("${TAG_CORE_HW_LEDS}", "Restored light attributes: brightness=%d%%, RGB=(%d,%d,%d)",
attrs.brightness, attrs.red, attrs.green, attrs.blue); attrs.brightness, attrs.red, attrs.green, attrs.blue);
- id: light_attributes_restore_dual
mode: parallel
parameters:
light_ptr: light::LightState*
attr_global_ptr: uint64_t*
group_index: uint8_t # 1 or 2
then:
- lambda: |-
auto attrs_pair = tx_ultimate_easy::unpack_dual_light_attributes(*attr_global_ptr);
tx_ultimate_easy::LightAttributes attrs = (group_index == 1) ? attrs_pair.first : attrs_pair.second;
auto call = light_ptr->make_call();
call.set_brightness(attrs.brightness / 100.0f);
call.set_rgb(attrs.red / 255.0f, attrs.green / 255.0f, attrs.blue / 255.0f);
call.perform();
- id: light_attributes_save - id: light_attributes_save
mode: parallel mode: parallel
parameters: parameters:
@@ -578,6 +595,32 @@ script:
ESP_LOGD("${TAG_CORE_HW_LEDS}", "Saved light attributes: brightness=%d%%, RGB=(%d,%d,%d)", ESP_LOGD("${TAG_CORE_HW_LEDS}", "Saved light attributes: brightness=%d%%, RGB=(%d,%d,%d)",
attrs.brightness, attrs.red, attrs.green, attrs.blue); attrs.brightness, attrs.red, attrs.green, attrs.blue);
- id: light_attributes_save_dual
mode: parallel
parameters:
light_ptr: light::LightState*
attr_global_ptr: uint64_t*
group_index: uint8_t # 1 or 2 (which group within the dual pack)
then:
- lambda: |-
auto current = light_ptr->current_values;
tx_ultimate_easy::LightAttributes new_attrs = {
.brightness = uint8_t(current.get_brightness() * 100.0f),
.red = uint8_t(current.get_red() * 255.0f),
.green = uint8_t(current.get_green() * 255.0f),
.blue = uint8_t(current.get_blue() * 255.0f)
};
// Unpack existing dual attributes
auto existing = tx_ultimate_easy::unpack_dual_light_attributes(*attr_global_ptr);
// Update the appropriate group
if (group_index == 1) {
*attr_global_ptr = tx_ultimate_easy::pack_dual_light_attributes(new_attrs, existing.second);
} else {
*attr_global_ptr = tx_ultimate_easy::pack_dual_light_attributes(existing.first, new_attrs);
}
select: select:
# EU relay light mode template # EU relay light mode template
- &relay_light_mode_eu - &relay_light_mode_eu

View File

@@ -69,10 +69,29 @@ globals:
initial_value: '0' # All switches default to OFF initial_value: '0' # All switches default to OFF
# Bit layout: [unused(3)][sw_relay4][sw_relay3][sw_relay2][sw_relay1][sw_expose_leds] # Bit layout: [unused(3)][sw_relay4][sw_relay3][sw_relay2][sw_relay1][sw_expose_leds]
- id: attr_light_output_1 - &global_attr_dual_light
type: uint32_t id: attr_light_rl_1_1_both # 1-gang: relay 1, both groups
type: uint64_t
restore_value: true restore_value: true
initial_value: '${LIGHT_ATTRS_DEFAULT}' initial_value: '${LIGHT_DUAL_ATTRS_DEFAULT}'
- id: attr_light_rl_1_2_both # 2-gang: relay 1, both groups
<<: *global_attr_dual_light
- id: attr_light_rl_2_2_both # 2-gang: relay 2, both groups
<<: *global_attr_dual_light
- id: attr_light_rl_1_3_both # 3-gang: relay 1, both groups
<<: *global_attr_dual_light
- id: attr_light_rl_2_3_both # 3-gang: relay 2, both groups
<<: *global_attr_dual_light
- id: attr_light_rl_3_3_both # 3-gang: relay 3, both groups
<<: *global_attr_dual_light
- id: attr_light_rl_1_4_both # 4-gang: relay 1, both groups
<<: *global_attr_dual_light
- id: attr_light_rl_2_4_both # 4-gang: relay 2, both groups
<<: *global_attr_dual_light
- id: attr_light_rl_3_4_both # 4-gang: relay 3, both groups
<<: *global_attr_dual_light
- id: attr_light_rl_4_4_both # 4-gang: relay 4, both groups
<<: *global_attr_dual_light
light: light:
# These lights are used for the physical relays to be shown as lights # These lights are used for the physical relays to be shown as lights
@@ -96,12 +115,6 @@ light:
- switch.is_on: sw_relay_1 - switch.is_on: sw_relay_1
then: then:
- switch.turn_off: sw_relay_1 - switch.turn_off: sw_relay_1
on_state:
then:
- script.execute:
id: light_attributes_save
light_ptr: !lambda return id(light_output_1);
attr_global_ptr: !lambda return &id(attr_light_output_1);
- id: light_output_2 - id: light_output_2
name: Light output 2 name: Light output 2
output: output_relay_2 output: output_relay_2
@@ -173,6 +186,12 @@ light:
- id: light_full - id: light_full
from: 9 from: 9
to: 9 to: 9
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_1_1_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_1_1_both);
group_index: 1
- id: light_eu_rl_1_1_top - id: light_eu_rl_1_1_top
name: Light - Relay 1 of 1 (top) name: Light - Relay 1 of 1 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -180,6 +199,12 @@ light:
- id: light_full - id: light_full
from: 23 from: 23
to: 23 to: 23
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_1_1_top);
attr_global_ptr: !lambda return &id(attr_light_rl_1_1_both);
group_index: 2
- id: light_eu_rl_1_2_bottom - id: light_eu_rl_1_2_bottom
name: Light - Relay 1 of 2 (bottom) name: Light - Relay 1 of 2 (bottom)
<<: *light_partition_relays <<: *light_partition_relays
@@ -187,6 +212,12 @@ light:
- id: light_full - id: light_full
from: 11 from: 11
to: 11 to: 11
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_1_2_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_1_2_both);
group_index: 1
- id: light_eu_rl_1_2_top - id: light_eu_rl_1_2_top
name: Light - Relay 1 of 2 (top) name: Light - Relay 1 of 2 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -194,6 +225,12 @@ light:
- id: light_full - id: light_full
from: 21 from: 21
to: 21 to: 21
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_1_2_top);
attr_global_ptr: !lambda return &id(attr_light_rl_1_2_both);
group_index: 2
- id: light_eu_rl_2_2_bottom - id: light_eu_rl_2_2_bottom
name: Light - Relay 2 of 2 (bottom) name: Light - Relay 2 of 2 (bottom)
<<: *light_partition_relays <<: *light_partition_relays
@@ -201,6 +238,12 @@ light:
- id: light_full - id: light_full
from: 7 from: 7
to: 7 to: 7
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_2_2_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_2_2_both);
group_index: 1
- id: light_eu_rl_2_2_top - id: light_eu_rl_2_2_top
name: Light - Relay 2 of 2 (top) name: Light - Relay 2 of 2 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -208,6 +251,12 @@ light:
- id: light_full - id: light_full
from: 25 from: 25
to: 25 to: 25
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_2_2_top);
attr_global_ptr: !lambda return &id(attr_light_rl_2_2_both);
group_index: 2
- id: light_eu_rl_1_3_bottom - id: light_eu_rl_1_3_bottom
name: Light - Relay 1 of 3 (bottom) name: Light - Relay 1 of 3 (bottom)
<<: *light_partition_relays <<: *light_partition_relays
@@ -215,6 +264,12 @@ light:
- id: light_full - id: light_full
from: 12 from: 12
to: 12 to: 12
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_1_3_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_1_3_both);
group_index: 1
- id: light_eu_rl_1_3_top - id: light_eu_rl_1_3_top
name: Light - Relay 1 of 3 (top) name: Light - Relay 1 of 3 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -222,6 +277,12 @@ light:
- id: light_full - id: light_full
from: 20 from: 20
to: 20 to: 20
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_1_3_top);
attr_global_ptr: !lambda return &id(attr_light_rl_1_3_both);
group_index: 2
- id: light_eu_rl_2_3_bottom - id: light_eu_rl_2_3_bottom
name: Light - Relay 2 of 3 (bottom) name: Light - Relay 2 of 3 (bottom)
<<: *light_partition_relays <<: *light_partition_relays
@@ -229,6 +290,12 @@ light:
- id: light_full - id: light_full
from: 9 from: 9
to: 9 to: 9
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_2_3_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_2_3_both);
group_index: 1
- id: light_eu_rl_2_3_top - id: light_eu_rl_2_3_top
name: Light - Relay 2 of 3 (top) name: Light - Relay 2 of 3 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -236,6 +303,12 @@ light:
- id: light_full - id: light_full
from: 23 from: 23
to: 23 to: 23
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_2_3_top);
attr_global_ptr: !lambda return &id(attr_light_rl_2_3_both);
group_index: 2
- id: light_eu_rl_3_3_bottom - id: light_eu_rl_3_3_bottom
name: Light - Relay 3 of 3 (bottom) name: Light - Relay 3 of 3 (bottom)
<<: *light_partition_relays <<: *light_partition_relays
@@ -243,6 +316,12 @@ light:
- id: light_full - id: light_full
from: 6 from: 6
to: 6 to: 6
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_3_3_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_3_3_both);
group_index: 1
- id: light_eu_rl_3_3_top - id: light_eu_rl_3_3_top
name: Light - Relay 3 of 3 (top) name: Light - Relay 3 of 3 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -250,6 +329,12 @@ light:
- id: light_full - id: light_full
from: 26 from: 26
to: 26 to: 26
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_3_3_top);
attr_global_ptr: !lambda return &id(attr_light_rl_3_3_both);
group_index: 2
- id: light_eu_rl_1_4_bottom - id: light_eu_rl_1_4_bottom
name: Light - Relay 1 of 4 (bottom) name: Light - Relay 1 of 4 (bottom)
<<: *light_partition_relays <<: *light_partition_relays
@@ -257,6 +342,12 @@ light:
- id: light_full - id: light_full
from: 12 from: 12
to: 12 to: 12
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_1_4_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_1_4_both);
group_index: 1
- id: light_eu_rl_1_4_top - id: light_eu_rl_1_4_top
name: Light - Relay 1 of 4 (top) name: Light - Relay 1 of 4 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -264,6 +355,12 @@ light:
- id: light_full - id: light_full
from: 20 from: 20
to: 20 to: 20
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_1_4_top);
attr_global_ptr: !lambda return &id(attr_light_rl_1_4_both);
group_index: 2
- id: light_eu_rl_2_4_bottom - id: light_eu_rl_2_4_bottom
name: Light - Relay 2 of 4 (bottom) name: Light - Relay 2 of 4 (bottom)
<<: *light_partition_relays <<: *light_partition_relays
@@ -271,6 +368,12 @@ light:
- id: light_full - id: light_full
from: 10 from: 10
to: 10 to: 10
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_2_4_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_2_4_both);
group_index: 1
- id: light_eu_rl_2_4_top - id: light_eu_rl_2_4_top
name: Light - Relay 2 of 4 (top) name: Light - Relay 2 of 4 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -278,6 +381,12 @@ light:
- id: light_full - id: light_full
from: 22 from: 22
to: 22 to: 22
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_2_4_top);
attr_global_ptr: !lambda return &id(attr_light_rl_2_4_both);
group_index: 2
- id: light_eu_rl_3_4_bottom - id: light_eu_rl_3_4_bottom
name: Light - Relay 3 of 4 (bottom) name: Light - Relay 3 of 4 (bottom)
<<: *light_partition_relays <<: *light_partition_relays
@@ -285,6 +394,12 @@ light:
- id: light_full - id: light_full
from: 8 from: 8
to: 8 to: 8
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_3_4_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_3_4_both);
group_index: 1
- id: light_eu_rl_3_4_top - id: light_eu_rl_3_4_top
name: Light - Relay 3 of 4 (top) name: Light - Relay 3 of 4 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -292,6 +407,12 @@ light:
- id: light_full - id: light_full
from: 24 from: 24
to: 24 to: 24
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_3_4_top);
attr_global_ptr: !lambda return &id(attr_light_rl_3_4_both);
group_index: 2
- id: light_eu_rl_4_4_bottom - id: light_eu_rl_4_4_bottom
name: Light - Relay 4 of 4 (bottom) name: Light - Relay 4 of 4 (bottom)
<<: *light_partition_relays <<: *light_partition_relays
@@ -299,6 +420,12 @@ light:
- id: light_full - id: light_full
from: 6 from: 6
to: 6 to: 6
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_4_4_bottom);
attr_global_ptr: !lambda return &id(attr_light_rl_4_4_both);
group_index: 1
- id: light_eu_rl_4_4_top - id: light_eu_rl_4_4_top
name: Light - Relay 4 of 4 (top) name: Light - Relay 4 of 4 (top)
<<: *light_partition_relays <<: *light_partition_relays
@@ -306,6 +433,12 @@ light:
- id: light_full - id: light_full
from: 26 from: 26
to: 26 to: 26
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_eu_rl_4_4_top);
attr_global_ptr: !lambda return &id(attr_light_rl_4_4_both);
group_index: 2
- id: light_us_rl_1_1_left - id: light_us_rl_1_1_left
name: Light - Relay 1 of 1 (left) name: Light - Relay 1 of 1 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -313,6 +446,12 @@ light:
- id: light_full - id: light_full
from: 15 from: 15
to: 24 to: 24
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_1_1_left);
attr_global_ptr: !lambda return &id(attr_light_rl_1_1_both);
group_index: 1
- id: light_us_rl_1_1_right - id: light_us_rl_1_1_right
name: Light - Relay 1 of 1 (right) name: Light - Relay 1 of 1 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -323,6 +462,12 @@ light:
- id: light_full - id: light_full
from: 0 from: 0
to: 8 to: 8
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_1_1_right);
attr_global_ptr: !lambda return &id(attr_light_rl_1_1_both);
group_index: 2
- id: light_us_rl_1_2_left - id: light_us_rl_1_2_left
name: Light - Relay 1 of 2 (left) name: Light - Relay 1 of 2 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -330,6 +475,12 @@ light:
- id: light_full - id: light_full
from: 20 from: 20
to: 24 to: 24
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_1_2_left);
attr_global_ptr: !lambda return &id(attr_light_rl_1_2_both);
group_index: 1
- id: light_us_rl_1_2_right - id: light_us_rl_1_2_right
name: Light - Relay 1 of 2 (right) name: Light - Relay 1 of 2 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -340,6 +491,12 @@ light:
- id: light_full - id: light_full
from: 0 from: 0
to: 3 to: 3
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_1_2_right);
attr_global_ptr: !lambda return &id(attr_light_rl_1_2_both);
group_index: 2
- id: light_us_rl_2_2_left - id: light_us_rl_2_2_left
name: Light - Relay 2 of 2 (left) name: Light - Relay 2 of 2 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -347,6 +504,12 @@ light:
- id: light_full - id: light_full
from: 15 from: 15
to: 19 to: 19
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_2_2_left);
attr_global_ptr: !lambda return &id(attr_light_rl_2_2_both);
group_index: 1
- id: light_us_rl_2_2_right - id: light_us_rl_2_2_right
name: Light - Relay 2 of 2 (right) name: Light - Relay 2 of 2 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -354,6 +517,12 @@ light:
- id: light_full - id: light_full
from: 4 from: 4
to: 8 to: 8
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_2_2_right);
attr_global_ptr: !lambda return &id(attr_light_rl_2_2_both);
group_index: 2
- id: light_us_rl_1_3_left - id: light_us_rl_1_3_left
name: Light - Relay 1 of 3 (left) name: Light - Relay 1 of 3 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -361,6 +530,12 @@ light:
- id: light_full - id: light_full
from: 22 from: 22
to: 23 to: 23
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_1_3_left);
attr_global_ptr: !lambda return &id(attr_light_rl_1_3_both);
group_index: 1
- id: light_us_rl_1_3_right - id: light_us_rl_1_3_right
name: Light - Relay 1 of 3 (right) name: Light - Relay 1 of 3 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -368,6 +543,12 @@ light:
- id: light_full - id: light_full
from: 0 from: 0
to: 1 to: 1
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_1_3_right);
attr_global_ptr: !lambda return &id(attr_light_rl_1_3_both);
group_index: 2
- id: light_us_rl_2_3_left - id: light_us_rl_2_3_left
name: Light - Relay 2 of 3 (left) name: Light - Relay 2 of 3 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -375,6 +556,12 @@ light:
- id: light_full - id: light_full
from: 19 from: 19
to: 20 to: 20
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_2_3_left);
attr_global_ptr: !lambda return &id(attr_light_rl_2_3_both);
group_index: 1
- id: light_us_rl_2_3_right - id: light_us_rl_2_3_right
name: Light - Relay 2 of 3 (right) name: Light - Relay 2 of 3 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -382,6 +569,12 @@ light:
- id: light_full - id: light_full
from: 3 from: 3
to: 4 to: 4
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_2_3_right);
attr_global_ptr: !lambda return &id(attr_light_rl_2_3_both);
group_index: 2
- id: light_us_rl_3_3_left - id: light_us_rl_3_3_left
name: Light - Relay 3 of 3 (left) name: Light - Relay 3 of 3 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -389,6 +582,12 @@ light:
- id: light_full - id: light_full
from: 16 from: 16
to: 17 to: 17
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_3_3_left);
attr_global_ptr: !lambda return &id(attr_light_rl_3_3_both);
group_index: 1
- id: light_us_rl_3_3_right - id: light_us_rl_3_3_right
name: Light - Relay 3 of 3 (right) name: Light - Relay 3 of 3 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -396,6 +595,12 @@ light:
- id: light_full - id: light_full
from: 6 from: 6
to: 7 to: 7
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_3_3_right);
attr_global_ptr: !lambda return &id(attr_light_rl_3_3_both);
group_index: 2
- id: light_us_rl_1_4_left - id: light_us_rl_1_4_left
name: Light - Relay 1 of 4 (left) name: Light - Relay 1 of 4 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -403,6 +608,12 @@ light:
- id: light_full - id: light_full
from: 23 from: 23
to: 24 to: 24
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_1_4_left);
attr_global_ptr: !lambda return &id(attr_light_rl_1_4_both);
group_index: 1
- id: light_us_rl_1_4_right - id: light_us_rl_1_4_right
name: Light - Relay 1 of 4 (right) name: Light - Relay 1 of 4 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -413,6 +624,12 @@ light:
- id: light_full - id: light_full
from: 0 from: 0
to: 0 to: 0
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_1_4_right);
attr_global_ptr: !lambda return &id(attr_light_rl_1_4_both);
group_index: 2
- id: light_us_rl_2_4_left - id: light_us_rl_2_4_left
name: Light - Relay 2 of 4 (left) name: Light - Relay 2 of 4 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -420,6 +637,12 @@ light:
- id: light_full - id: light_full
from: 21 from: 21
to: 22 to: 22
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_2_4_left);
attr_global_ptr: !lambda return &id(attr_light_rl_2_4_both);
group_index: 1
- id: light_us_rl_2_4_right - id: light_us_rl_2_4_right
name: Light - Relay 2 of 4 (right) name: Light - Relay 2 of 4 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -427,6 +650,12 @@ light:
- id: light_full - id: light_full
from: 1 from: 1
to: 2 to: 2
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_2_4_right);
attr_global_ptr: !lambda return &id(attr_light_rl_2_4_both);
group_index: 2
- id: light_us_rl_3_4_left - id: light_us_rl_3_4_left
name: Light - Relay 3 of 4 (left) name: Light - Relay 3 of 4 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -434,6 +663,12 @@ light:
- id: light_full - id: light_full
from: 17 from: 17
to: 18 to: 18
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_3_4_left);
attr_global_ptr: !lambda return &id(attr_light_rl_3_4_both);
group_index: 1
- id: light_us_rl_3_4_right - id: light_us_rl_3_4_right
name: Light - Relay 3 of 4 (right) name: Light - Relay 3 of 4 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -441,6 +676,12 @@ light:
- id: light_full - id: light_full
from: 5 from: 5
to: 6 to: 6
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_3_4_right);
attr_global_ptr: !lambda return &id(attr_light_rl_3_4_both);
group_index: 2
- id: light_us_rl_4_4_left - id: light_us_rl_4_4_left
name: Light - Relay 4 of 4 (left) name: Light - Relay 4 of 4 (left)
<<: *light_partition_relays <<: *light_partition_relays
@@ -448,6 +689,12 @@ light:
- id: light_full - id: light_full
from: 15 from: 15
to: 16 to: 16
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_4_4_left);
attr_global_ptr: !lambda return &id(attr_light_rl_4_4_both);
group_index: 1
- id: light_us_rl_4_4_right - id: light_us_rl_4_4_right
name: Light - Relay 4 of 4 (right) name: Light - Relay 4 of 4 (right)
<<: *light_partition_relays <<: *light_partition_relays
@@ -455,6 +702,12 @@ light:
- id: light_full - id: light_full
from: 7 from: 7
to: 8 to: 8
on_state:
- script.execute:
id: light_attributes_save_dual
light_ptr: !lambda return id(light_us_rl_4_4_right);
attr_global_ptr: !lambda return &id(attr_light_rl_4_4_both);
group_index: 2
output: output:
- id: output_relay_1 - id: output_relay_1
@@ -871,7 +1124,7 @@ script:
id: sl_relay_4_mode id: sl_relay_4_mode
index: !lambda return std::min((uint8_t)((id(relay_modes_packed) >> 12) & 0x0F), (uint8_t)2); index: !lambda return std::min((uint8_t)((id(relay_modes_packed) >> 12) & 0x0F), (uint8_t)2);
# Switch states (new - your improved version) # Switch states
- if: - if:
condition: condition:
lambda: return (id(relay_switches_packed) & 0x01) == 0; lambda: return (id(relay_switches_packed) & 0x01) == 0;
@@ -911,6 +1164,72 @@ script:
# update lights based on new relay statuses (catch up, as this should be done when each relay is updated) # update lights based on new relay statuses (catch up, as this should be done when each relay is updated)
- script.execute: show_relay_status - script.execute: show_relay_status
# Light attributes restoration
- lambda: |-
// Restore all light attributes based on current model and gang count
switch (id(gang_count)) {
case 1: // 1-Gang
if (id(is_us_model)) {
light_attributes_restore_dual->execute(id(light_us_rl_1_1_left), &id(attr_light_rl_1_1_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_1_1_right), &id(attr_light_rl_1_1_both), 2);
} else {
light_attributes_restore_dual->execute(id(light_eu_rl_1_1_bottom), &id(attr_light_rl_1_1_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_1_1_top), &id(attr_light_rl_1_1_both), 2);
}
break;
case 2: // 2-Gang
if (id(is_us_model)) {
light_attributes_restore_dual->execute(id(light_us_rl_1_2_left), &id(attr_light_rl_1_2_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_1_2_right), &id(attr_light_rl_1_2_both), 2);
light_attributes_restore_dual->execute(id(light_us_rl_2_2_left), &id(attr_light_rl_2_2_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_2_2_right), &id(attr_light_rl_2_2_both), 2);
} else {
light_attributes_restore_dual->execute(id(light_eu_rl_1_2_bottom), &id(attr_light_rl_1_2_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_1_2_top), &id(attr_light_rl_1_2_both), 2);
light_attributes_restore_dual->execute(id(light_eu_rl_2_2_bottom), &id(attr_light_rl_2_2_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_2_2_top), &id(attr_light_rl_2_2_both), 2);
}
break;
case 3: // 3-Gang
if (id(is_us_model)) {
light_attributes_restore_dual->execute(id(light_us_rl_1_3_left), &id(attr_light_rl_1_3_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_1_3_right), &id(attr_light_rl_1_3_both), 2);
light_attributes_restore_dual->execute(id(light_us_rl_2_3_left), &id(attr_light_rl_2_3_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_2_3_right), &id(attr_light_rl_2_3_both), 2);
light_attributes_restore_dual->execute(id(light_us_rl_3_3_left), &id(attr_light_rl_3_3_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_3_3_right), &id(attr_light_rl_3_3_both), 2);
} else {
light_attributes_restore_dual->execute(id(light_eu_rl_1_3_bottom), &id(attr_light_rl_1_3_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_1_3_top), &id(attr_light_rl_1_3_both), 2);
light_attributes_restore_dual->execute(id(light_eu_rl_2_3_bottom), &id(attr_light_rl_2_3_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_2_3_top), &id(attr_light_rl_2_3_both), 2);
light_attributes_restore_dual->execute(id(light_eu_rl_3_3_bottom), &id(attr_light_rl_3_3_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_3_3_top), &id(attr_light_rl_3_3_both), 2);
}
break;
case 4: // 4-Gang
if (id(is_us_model)) {
light_attributes_restore_dual->execute(id(light_us_rl_1_4_left), &id(attr_light_rl_1_4_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_1_4_right), &id(attr_light_rl_1_4_both), 2);
light_attributes_restore_dual->execute(id(light_us_rl_2_4_left), &id(attr_light_rl_2_4_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_2_4_right), &id(attr_light_rl_2_4_both), 2);
light_attributes_restore_dual->execute(id(light_us_rl_3_4_left), &id(attr_light_rl_3_4_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_3_4_right), &id(attr_light_rl_3_4_both), 2);
light_attributes_restore_dual->execute(id(light_us_rl_4_4_left), &id(attr_light_rl_4_4_both), 1);
light_attributes_restore_dual->execute(id(light_us_rl_4_4_right), &id(attr_light_rl_4_4_both), 2);
} else {
light_attributes_restore_dual->execute(id(light_eu_rl_1_4_bottom), &id(attr_light_rl_1_4_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_1_4_top), &id(attr_light_rl_1_4_both), 2);
light_attributes_restore_dual->execute(id(light_eu_rl_2_4_bottom), &id(attr_light_rl_2_4_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_2_4_top), &id(attr_light_rl_2_4_both), 2);
light_attributes_restore_dual->execute(id(light_eu_rl_3_4_bottom), &id(attr_light_rl_3_4_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_3_4_top), &id(attr_light_rl_3_4_both), 2);
light_attributes_restore_dual->execute(id(light_eu_rl_4_4_bottom), &id(attr_light_rl_4_4_both), 1);
light_attributes_restore_dual->execute(id(light_eu_rl_4_4_top), &id(attr_light_rl_4_4_both), 2);
}
break;
}
- id: show_relay_status - id: show_relay_status
mode: restart mode: restart
then: then:
@@ -964,16 +1283,13 @@ script:
ESP_LOGV("${TAG_STD_HW_RELAYS}", "Light Mode for Relay %" PRIu8 ": %s", i + 1, light_mode.c_str()); ESP_LOGV("${TAG_STD_HW_RELAYS}", "Light Mode for Relay %" PRIu8 ": %s", i + 1, light_mode.c_str());
// Use light_set_state for light updates // Use light_set_state for light updates
if (relay_state) { if (light_mode != "${LIGHT_MODE_DISABLED_TEXT}") {
if (light_mode == light_mode_group_1 || light_mode == "${LIGHT_MODE_BOTH_TEXT}") { if (light_mode == light_mode_group_1 || light_mode == "${LIGHT_MODE_BOTH_TEXT}") {
light_set_state->execute(1, i, true); // Left/bottom light light_set_state->execute(1, i, relay_state); // Left/bottom light
} }
if (light_mode == light_mode_group_2 || light_mode == "${LIGHT_MODE_BOTH_TEXT}") { if (light_mode == light_mode_group_2 || light_mode == "${LIGHT_MODE_BOTH_TEXT}") {
light_set_state->execute(2, i, true); // Right/top light light_set_state->execute(2, i, relay_state); // Right/top light
} }
} else {
light_set_state->execute(1, i, false); // Turn off left/bottom light
light_set_state->execute(2, i, false); // Turn off right/top light
} }
} }

View File

@@ -0,0 +1,51 @@
// tx_ultimate_easy_light.cpp
#include "esphome/core/log.h"
#include "tx_ultimate_easy_light.h"
#include <cinttypes>
#include <string>
namespace esphome {
namespace tx_ultimate_easy {
// Constant definitions
const LightAttributes LIGHT_ATTRS_DEFAULT = {100, 255, 255, 255};
const uint32_t LIGHT_ATTRS_DEFAULT_PACKED = 0x64FFFFFF;
const uint64_t DEFAULT_DUAL_LIGHT_ATTRS_PACKED = 0x64FFFFFF64FFFFFF;
// Function implementations
uint32_t pack_light_attributes(const LightAttributes& attr) {
return (uint32_t(attr.brightness) << 24) |
(uint32_t(attr.red) << 16) |
(uint32_t(attr.green) << 8) |
(uint32_t(attr.blue));
}
LightAttributes unpack_light_attributes(uint32_t packed) {
return {
.brightness = uint8_t((packed >> 24) & 0xFF),
.red = uint8_t((packed >> 16) & 0xFF),
.green = uint8_t((packed >> 8) & 0xFF),
.blue = uint8_t(packed & 0xFF)
};
}
uint64_t pack_dual_light_attributes(const LightAttributes& group1_attrs, const LightAttributes& group2_attrs) {
uint32_t group1_packed = pack_light_attributes(group1_attrs);
uint32_t group2_packed = pack_light_attributes(group2_attrs);
return (uint64_t(group2_packed) << 32) | uint64_t(group1_packed);
}
std::pair<LightAttributes, LightAttributes> unpack_dual_light_attributes(uint64_t packed) {
uint32_t group1_packed = uint32_t(packed & 0xFFFFFFFF); // Lower 32 bits
uint32_t group2_packed = uint32_t((packed >> 32) & 0xFFFFFFFF); // Upper 32 bits
return std::make_pair(
unpack_light_attributes(group1_packed),
unpack_light_attributes(group2_packed)
);
}
} // namespace tx_ultimate_easy
} // namespace esphome

View File

@@ -0,0 +1,113 @@
// tx_ultimate_easy_light.h
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h"
#include "esphome/components/uart/uart_component.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/switch/switch.h"
#include "esphome/components/light/addressable_light.h"
#include <array>
namespace esphome {
namespace tx_ultimate_easy {
/**
* @brief Light attributes structure for storing color and brightness data.
*
* This structure represents the visual attributes of a light without the state (on/off).
* It's designed to be packed efficiently into a 32-bit integer for NVS storage.
* RGB components use the full 8-bit range (0-255) while brightness uses percentage (0-100).
*/
struct LightAttributes {
uint8_t brightness; ///< Light brightness percentage (0-100, where 100 = full brightness)
uint8_t red; ///< Red color component (0-255)
uint8_t green; ///< Green color component (0-255)
uint8_t blue; ///< Blue color component (0-255)
};
/**
* @brief Packs LightAttributes structure into a 32-bit integer for storage.
*
* Bit layout: [brightness(8)][red(8)][green(8)][blue(8)]
* This allows efficient storage in ESPHome globals with restore_value support.
* Note: Brightness values > 100 will be clamped to 100 during packing.
*
* @param attr The LightAttributes structure to pack
* @return uint32_t Packed representation suitable for NVS storage
*
* @example
* LightAttributes attrs = {75, 255, 128, 64};
* uint32_t packed = pack_light_attributes(attrs); // Returns 0x4BFF8040
*/
uint32_t pack_light_attributes(const LightAttributes& attr);
/**
* @brief Unpacks a 32-bit integer back into LightAttributes structure.
*
* Reverses the packing operation to extract individual color and brightness values.
* Brightness values > 100 in the packed data will be clamped to 100.
*
* @param packed The packed 32-bit representation
* @return LightAttributes The unpacked structure with individual components
*
* @example
* uint32_t packed = 0x4BFF8040;
* LightAttributes attrs = unpack_light_attributes(packed);
* // attrs.brightness = 75, attrs.red = 255, attrs.green = 128, attrs.blue = 64
*/
LightAttributes unpack_light_attributes(uint32_t packed);
/**
* @brief Default light attributes for initialization.
*
* Provides sensible defaults for new lights:
* - Brightness: 100 (full brightness)
* - Red: 255 (full intensity)
* - Green: 255 (full intensity)
* - Blue: 255 (full intensity)
* Result: Pure white color at full brightness
*/
extern const LightAttributes LIGHT_ATTRS_DEFAULT;
/**
* @brief Pre-packed version of DEFAULT_LIGHT_ATTRS for convenience.
*
* This constant contains LIGHT_ATTRS_DEFAULT already packed into uint32_t format,
* suitable for direct use in ESPHome YAML initial_value fields.
*
* Value: 0x64FFFFFF (brightness=100, RGB=255,255,255)
*/
extern const uint32_t LIGHT_ATTRS_DEFAULT_PACKED;
/**
* @brief Packs two LightAttributes into a single uint64_t for dual light storage.
*
* Bit layout: [group2_light(32)][group1_light(32)]
* Each light uses 32 bits: [brightness(8)][red(8)][green(8)][blue(8)]
*
* @param group1_attrs First light attributes (stored in lower 32 bits)
* @param group2_attrs Second light attributes (stored in upper 32 bits)
* @return uint64_t Packed representation suitable for NVS storage
*/
uint64_t pack_dual_light_attributes(const LightAttributes& group1_attrs, const LightAttributes& group2_attrs);
/**
* @brief Unpacks uint64_t back into two LightAttributes structures.
*
* @param packed The packed 64-bit representation
* @return std::pair<LightAttributes, LightAttributes> Pair of (group1, group2) attributes
*/
std::pair<LightAttributes, LightAttributes> unpack_dual_light_attributes(uint64_t packed);
/**
* @brief Pre-packed version of dual default attributes for convenience.
*
* Value: 0x64FFFFFF64FFFFFF (both lights: brightness=100, RGB=255,255,255)
*/
extern const uint64_t DEFAULT_DUAL_LIGHT_ATTRS_PACKED;
} // namespace tx_ultimate_easy
} // namespace esphome

View File

@@ -0,0 +1,227 @@
// tx_ultimate_easy_touch.cpp
#include "esphome/core/log.h"
#include "tx_ultimate_easy_touch.h"
#include <cinttypes>
#include <string>
namespace esphome {
namespace tx_ultimate_easy {
void TxUltimateEasy::setup() {
ESP_LOGI(TAG, "TX Ultimate Easy is initialized");
}
void TxUltimateEasy::loop() {
bool found = false;
std::array<int, UART_RECEIVED_BYTES_SIZE> uart_received_bytes{};
int byte = -1;
int i = 0;
while (this->available()) {
byte = this->read();
if (byte == HEADER_BYTE_1) {
this->handle_touch(uart_received_bytes);
i = 0;
}
if (i < UART_RECEIVED_BYTES_SIZE) {
uart_received_bytes[i] = byte;
i++;
}
if (byte != 0x00) {
found = true;
}
}
if (found) this->handle_touch(uart_received_bytes);
}
void TxUltimateEasy::handle_touch(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
ESP_LOGV(TAG, "------------");
ESP_LOGV(TAG, "- UART-Log -");
ESP_LOGV(TAG, "------------");
for (int i = 0; i < UART_RECEIVED_BYTES_SIZE; i++) {
ESP_LOGV(TAG, "UART - Log - Byte[%i]: %i", i, uart_received_bytes[i]);
}
if (this->is_valid_data(uart_received_bytes)) {
this->send_touch_(this->get_touch_point(uart_received_bytes));
}
}
void TxUltimateEasy::dump_config() {
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 Change to round up instead of truncate (integer division)
const uint8_t width = (TOUCH_MAX_POSITION + gang_count_) / this->gang_count_; // Width of each button region
if (width < 1) // 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) {
this->trigger_touch_event_.trigger(tp);
switch (tp.state) {
case TOUCH_STATE_RELEASE:
if (tp.x >= 17) {
tp.x -= 16;
ESP_LOGV(TAG, "Long touch - Released (x=%d)", tp.x);
this->trigger_long_touch_release_.trigger(tp);
} else {
ESP_LOGV(TAG, "Touch - Released (x=%d)", tp.x);
this->trigger_release_.trigger(tp);
}
break;
case TOUCH_STATE_PRESS:
ESP_LOGV(TAG, "Touch - Pressed (x=%d)", tp.x);
this->trigger_touch_.trigger(tp);
break;
case TOUCH_STATE_SWIPE_LEFT:
ESP_LOGV(TAG, "Swipe - Left (x=%d)", tp.x);
this->trigger_swipe_left_.trigger(tp);
break;
case TOUCH_STATE_SWIPE_RIGHT:
ESP_LOGV(TAG, "Swipe - Right (x=%d)", tp.x);
this->trigger_swipe_right_.trigger(tp);
break;
case TOUCH_STATE_MULTI_TOUCH:
ESP_LOGV(TAG, "Multi touch - Released");
this->trigger_multi_touch_release_.trigger(tp);
break;
default:
break;
}
}
bool TxUltimateEasy::is_valid_data(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
if (uart_received_bytes[0] != HEADER_BYTE_1 ||
uart_received_bytes[1] != HEADER_BYTE_2 ||
uart_received_bytes[2] != VALID_DATA_BYTE_2 ||
uart_received_bytes[3] != VALID_DATA_BYTE_3) {
return false;
}
int state = this->get_touch_state(uart_received_bytes);
return (state == TOUCH_STATE_PRESS ||
state == TOUCH_STATE_RELEASE ||
state == TOUCH_STATE_SWIPE_LEFT ||
state == TOUCH_STATE_SWIPE_RIGHT ||
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) {
switch (uart_received_bytes[4]) {
case TOUCH_STATE_RELEASE:
case TOUCH_STATE_MULTI_TOUCH:
return uart_received_bytes[5];
case TOUCH_STATE_SWIPE_LEFT:
case TOUCH_STATE_SWIPE_RIGHT:
// uart_received_bytes[5] indicates swipe direction:
// 12 = find last touch position (scan right to left)
// 13 = find first touch position (scan left to right)
// Bytes 6-7 contain a 10-bit bitmap of touch positions:
// Byte 7: bits 0-7 represent positions 1-8
// Byte 6: bits 0-1 represent positions 9-10
switch (uart_received_bytes[5]) {
case 12:
for (uint8_t i = 10; i > 0; i--) {
if (i > 8
? uart_received_bytes[6] & (1 << (i - 9))
: uart_received_bytes[7] & (1 << (i - 1))) {
return i;
}
}
break;
case 13:
for (uint8_t i = 1; i <= 10; i++) {
if (i > 8
? uart_received_bytes[6] & (1 << (i - 9))
: uart_received_bytes[7] & (1 << (i - 1))) {
return i;
}
}
break;
}
return uart_received_bytes[5];
default:
return uart_received_bytes[6];
}
}
int TxUltimateEasy::get_touch_state(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
int state = uart_received_bytes[4];
if (state == TOUCH_STATE_PRESS && uart_received_bytes[5] != 0)
state = TOUCH_STATE_RELEASE;
if (state == TOUCH_STATE_RELEASE && uart_received_bytes[5] == TOUCH_STATE_MULTI_TOUCH)
state = TOUCH_STATE_MULTI_TOUCH;
if (state == TOUCH_STATE_SWIPE) {
state = (uart_received_bytes[5] == TOUCH_STATE_SWIPE_RIGHT) ? TOUCH_STATE_SWIPE_RIGHT :
(uart_received_bytes[5] == TOUCH_STATE_SWIPE_LEFT) ? TOUCH_STATE_SWIPE_LEFT : state;
}
return state;
}
TouchPoint TxUltimateEasy::get_touch_point(const std::array<int, UART_RECEIVED_BYTES_SIZE> &uart_received_bytes) {
TouchPoint tp;
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);
switch (tp.state) {
case TOUCH_STATE_RELEASE:
tp.state_str = "RELEASE";
break;
case TOUCH_STATE_PRESS:
tp.state_str = "PRESS";
break;
case TOUCH_STATE_SWIPE:
tp.state_str = "SWIPE";
break;
case TOUCH_STATE_MULTI_TOUCH:
tp.state_str = "MULTI_TOUCH";
break;
case TOUCH_STATE_SWIPE_RIGHT:
tp.state_str = "SWIPE_RIGHT";
break;
case TOUCH_STATE_SWIPE_LEFT:
tp.state_str = "SWIPE_LEFT";
break;
default:
tp.state_str = "Unknown";
break;
}
return tp;
}
} // namespace tx_ultimate_easy
} // namespace esphome

View File

@@ -0,0 +1,86 @@
// tx_ultimate_easy_touch.h
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h"
#include "esphome/components/uart/uart_component.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/switch/switch.h"
#include "esphome/components/light/addressable_light.h"
#include <array>
namespace esphome {
namespace tx_ultimate_easy {
// Touch Max Position
constexpr uint8_t TOUCH_MAX_POSITION = 10;
// Touch State Constants
constexpr uint8_t TOUCH_STATE_RELEASE = 0x01;
constexpr uint8_t TOUCH_STATE_PRESS = 0x02;
constexpr uint8_t TOUCH_STATE_SWIPE = 0x03;
constexpr uint8_t TOUCH_STATE_MULTI_TOUCH = 0x0B;
constexpr uint8_t TOUCH_STATE_SWIPE_RIGHT = 0x0C;
constexpr uint8_t TOUCH_STATE_SWIPE_LEFT = 0x0D;
// UART Constants
constexpr int UART_RECEIVED_BYTES_SIZE = 15;
constexpr int HEADER_BYTE_1 = 0xAA;
constexpr int HEADER_BYTE_2 = 0x55;
constexpr int VALID_DATA_BYTE_2 = 0x01;
constexpr int VALID_DATA_BYTE_3 = 0x02;
// Log tag
static const char *TAG = "tx_ultimate_easy";
struct TouchPoint {
uint8_t button = 0;
int8_t x = -1;
int8_t state = -1;
std::string state_str = "Unknown";
};
class TxUltimateEasy : public uart::UARTDevice, public Component {
public:
Trigger<TouchPoint> *get_trigger_touch_event() { return &this->trigger_touch_event_; }
Trigger<TouchPoint> *get_trigger_touch() { return &this->trigger_touch_; }
Trigger<TouchPoint> *get_trigger_release() { return &this->trigger_release_; }
Trigger<TouchPoint> *get_trigger_swipe_left() { return &this->trigger_swipe_left_; }
Trigger<TouchPoint> *get_trigger_swipe_right() { return &this->trigger_swipe_right_; }
Trigger<TouchPoint> *get_trigger_multi_touch_release() { return &this->trigger_multi_touch_release_; }
Trigger<TouchPoint> *get_trigger_long_touch_release() { return &this->trigger_long_touch_release_; }
void set_uart_component(esphome::uart::UARTComponent *uart_component) { this->set_uart_parent(uart_component); }
void setup() override;
void loop() 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:
void send_touch_(TouchPoint tp);
void handle_touch(const std::array<int, UART_RECEIVED_BYTES_SIZE> &bytes);
TouchPoint get_touch_point(const std::array<int, UART_RECEIVED_BYTES_SIZE> &bytes);
bool is_valid_data(const std::array<int, UART_RECEIVED_BYTES_SIZE> &bytes);
int get_touch_position_x(const std::array<int, UART_RECEIVED_BYTES_SIZE> &bytes);
int get_touch_state(const std::array<int, UART_RECEIVED_BYTES_SIZE> &bytes);
Trigger<TouchPoint> trigger_touch_event_;
Trigger<TouchPoint> trigger_touch_;
Trigger<TouchPoint> trigger_release_;
Trigger<TouchPoint> trigger_swipe_left_;
Trigger<TouchPoint> trigger_swipe_right_;
Trigger<TouchPoint> trigger_multi_touch_release_;
Trigger<TouchPoint> trigger_long_touch_release_;
uint8_t gang_count_ = 1;
}; // class TxUltimateEasy
} // namespace tx_ultimate_easy
} // namespace esphome

View File

@@ -1 +1 @@
version: 2025.8.2 version: 2025.8.2dev