diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml index 9878e4f..5ecc15c 100644 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml +++ b/ESPHome/TX-Ultimate-Easy-ESPHome_core_hw_leds.yaml @@ -25,9 +25,9 @@ substitutions: LIGHT_TRANSITION_TURN_OFF: '0' # Transition time in msec LIGHT_BRIGHTNESS_TURN_ON: '0' # Brightness (1 to 100%, 0 to not set it) - LIGHT_FULL_RESTORE_MODE: RESTORE_DEFAULT_OFF - LIGHT_SIDES_RESTORE_MODE: RESTORE_DEFAULT_OFF - LIGHT_INDIVIDUAL_RESTORE_MODE: RESTORE_DEFAULT_OFF + LIGHT_FULL_RESTORE_MODE: ALWAYS_OFF + LIGHT_SIDES_RESTORE_MODE: ALWAYS_OFF + LIGHT_INDIVIDUAL_RESTORE_MODE: ALWAYS_OFF LIGHT_ATTRS_DEFAULT: '0x64FFFFFF' # brightness=100, RGB=255,255,255 LIGHT_DUAL_ATTRS_DEFAULT: '0x64FFFFFF64FFFFFF' # Both lights: brightness=100, RGB=255,255,255 @@ -39,6 +39,46 @@ esphome: build_flags: - -D TX_ULTIMATE_EASY_CORE_HW_LEDS +external_components: + - source: github://pr#10195 # To-do: Remove this when this PR is merged + components: [light] + refresh: 1h + +globals: + # light_full with effect support + - id: led_full_attrs + type: uint32_t + restore_value: true + initial_value: '${LIGHT_ATTRS_DEFAULT}' + # Basic attributes: brightness + RGB + + # For light_full effects + - id: led_full_effect_packed + type: uint32_t + restore_value: true + initial_value: '0x00000000' + # Stores: effect_index(16 bits) + effect_speed(8 bits) + reserved(8 bits) + # 0 = no effect/solid color, 1-10 = effect indices + + - id: led_main_packed_attrs + type: uint64_t + restore_value: true + initial_value: '${LIGHT_DUAL_ATTRS_DEFAULT}' + # light_eu(group1) + light_us(group2) - the main effect lights + + - id: led_main_packed_effect + type: uint32_t + restore_value: true + initial_value: '0x00000000' + # Shared between light_eu and light_us + + # Main user-facing LED lights only + - id: led_sides_packed_attrs + type: uint64_t + restore_value: true + initial_value: '${LIGHT_DUAL_ATTRS_DEFAULT}' + # EU: bottom(group1) + top(group2) OR US: left(group1) + right(group2) + light: # These lights are controlling the LEDs on the device - id: light_full @@ -108,6 +148,17 @@ light: - id: light_full from: 0 to: 27 + on_state: + then: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_eu); + attr_global_ptr: !lambda return &id(led_main_packed_attrs); + group_index: 1 + - script.execute: + id: light_effect_save + light_ptr: !lambda return id(light_eu); + effect_global_ptr: !lambda return &id(led_main_packed_effect); - &light_partition_with_effects_us id: light_us @@ -160,6 +211,17 @@ light: - id: light_full from: 0 to: 31 + on_state: + then: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_us); + attr_global_ptr: !lambda return &id(led_main_packed_attrs); + group_index: 2 + - script.execute: + id: light_effect_save + light_ptr: !lambda return id(light_us); + effect_global_ptr: !lambda return &id(led_main_packed_effect); - &light_partition_no_effects_disabled id: light_eu_bottom @@ -174,6 +236,13 @@ light: from: 6 to: 12 reversed: true + on_state: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_eu_bottom); + attr_global_ptr: !lambda return &id(led_sides_packed_attrs); + group_index: 1 + - id: light_eu_left name: Light - Left EU <<: *light_partition_no_effects_disabled @@ -182,6 +251,12 @@ light: from: 13 to: 19 reversed: true + on_state: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_eu_left); + attr_global_ptr: !lambda return &id(led_sides_packed_attrs); + group_index: 1 - id: light_eu_right name: Light - Right EU <<: *light_partition_no_effects_disabled @@ -194,6 +269,12 @@ light: from: 0 to: 5 reversed: false + on_state: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_eu_right); + attr_global_ptr: !lambda return &id(led_sides_packed_attrs); + group_index: 2 - id: light_eu_top name: Light - Top EU <<: *light_partition_no_effects_disabled @@ -202,6 +283,12 @@ light: from: 20 to: 26 reversed: false + on_state: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_eu_top); + attr_global_ptr: !lambda return &id(led_sides_packed_attrs); + group_index: 2 - id: light_us_bottom name: Light - Bottom US <<: *light_partition_no_effects_disabled @@ -210,6 +297,12 @@ light: from: 9 to: 14 reversed: true + on_state: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_us_bottom); + attr_global_ptr: !lambda return &id(led_sides_packed_attrs); + group_index: 1 - id: light_us_left name: Light - Left US <<: *light_partition_no_effects_disabled @@ -218,6 +311,12 @@ light: from: 15 to: 24 reversed: true + on_state: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_us_left); + attr_global_ptr: !lambda return &id(led_sides_packed_attrs); + group_index: 1 - id: light_us_right name: Light - Right US <<: *light_partition_no_effects_disabled @@ -230,6 +329,12 @@ light: from: 0 to: 8 reversed: false + on_state: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_us_right); + attr_global_ptr: !lambda return &id(led_sides_packed_attrs); + group_index: 2 - id: light_us_top name: Light - Top US <<: *light_partition_no_effects_disabled @@ -238,6 +343,12 @@ light: from: 25 to: 30 reversed: false + on_state: + - script.execute: + id: light_attributes_save_dual + light_ptr: !lambda return id(light_us_top); + attr_global_ptr: !lambda return &id(led_sides_packed_attrs); + group_index: 2 - &light_partition_individual_led id: light_00 @@ -642,4 +753,43 @@ script: *attr_global_ptr = tx_ultimate_easy::pack_dual_light_attributes(existing.first, new_attrs); } + - id: light_effect_save + mode: queued + parameters: + light_ptr: light::LightState* + effect_global_ptr: uint32_t* + then: + - lambda: |- + if (!light_ptr || !effect_global_ptr) return; + + uint32_t effect_index = light_ptr->get_current_effect_index(); + // Store effect index (16 bits) + reserved space for future use + *effect_global_ptr = effect_index & 0xFFFF; + + ESP_LOGD("${TAG_CORE_HW_LEDS}", "Saved effect index: %d", effect_index); + + - id: light_effect_restore + mode: parallel + parameters: + light_ptr: light::LightState* + effect_global_ptr: uint32_t* + then: + - lambda: |- + if (!light_ptr || !effect_global_ptr) return; + + uint32_t effect_index = *effect_global_ptr & 0xFFFF; + + if (effect_index == 0) return; // No effect + if (effect_index > light_ptr->get_effect_count()) { + ESP_LOGW("${TAG_CORE_HW_LEDS}", "Invalid effect index: %d (max: %d)", + effect_index, light_ptr->get_effect_count()); + return; + } + + auto call = light_ptr->turn_on(); + call.set_effect(effect_index); + call.perform(); + + ESP_LOGI("${TAG_CORE_HW_LEDS}", "Restored effect: %s (index=%d)", + light_ptr->get_effect_name_by_index(effect_index).c_str(), effect_index); ... diff --git a/ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml b/ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml index 23bb010..8fe7287 100644 --- a/ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml +++ b/ESPHome/TX-Ultimate-Easy-ESPHome_standard_hw_relays.yaml @@ -96,7 +96,7 @@ globals: type: uint16_t restore_value: true initial_value: '0' # Binary: 0000000000000000 = all relay modes set to option 0 (default action - switch) - # Bit layout: [unused][relay4(4)][relay3(4)][relay2(4)][relay1(4)] + # Bit layout: [relay4(4)][relay3(4)][relay2(4)][relay1(4)] # 16-bit value with 4 bits per relay: 0=Switch, 1=Light, 2=Not in use, 3-15=Reserved # Packed switch states - replaces 5 separate switches @@ -104,7 +104,7 @@ globals: type: uint8_t restore_value: true 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: [sw_relay4][sw_relay3][sw_relay2][sw_relay1][sw_expose_leds] light: # These lights are used for the physical relays to be shown as lights @@ -133,6 +133,7 @@ light: output: output_relay_2 platform: binary internal: true + restore_mode: ${RELAYS_LIGHT_RESTORE_MODE} on_turn_on: then: - if: @@ -152,6 +153,7 @@ light: output: output_relay_3 platform: binary internal: true + restore_mode: ${RELAYS_LIGHT_RESTORE_MODE} on_turn_on: then: - if: @@ -171,6 +173,7 @@ light: output: output_relay_4 platform: binary internal: true + restore_mode: ${RELAYS_LIGHT_RESTORE_MODE} on_turn_on: then: - if: @@ -910,8 +913,8 @@ script: // Set indicator (either switch or light) visible on Home Assistant auto relay_mode_index = sl_relay_1_mode->active_index(); if (relay_mode_index.has_value()) { - light_output_1->set_internal(false or relay_mode_index.value() != 1); - sw_relay_1->set_internal(false or relay_mode_index.value() != 0); + light_output_1->set_internal(relay_mode_index.value() != 1); + sw_relay_1->set_internal(relay_mode_index.value() != 0); } relay_mode_index = sl_relay_2_mode->active_index(); if (relay_mode_index.has_value()) { @@ -1119,11 +1122,13 @@ script: break; case 2: if (light_index >= id(gb_lights_2).size()) { - ESP_LOGE("${TAG_STD_HW_RELAYS}", "Invalid set with %s light for Relay %" PRIu8, light_mode_group_2.c_str(), light_index+1); + ESP_LOGE("${TAG_STD_HW_RELAYS}", + "Invalid set with %s light for Relay %" PRIu8, light_mode_group_2.c_str(), light_index+1); return; } if (state and !id(gb_lights_2)[light_index]->current_values.is_on()) { - ESP_LOGI("${TAG_STD_HW_RELAYS}", "Turn-on %s light for Relay %" PRIu8, light_mode_group_2.c_str(), light_index+1); + ESP_LOGI("${TAG_STD_HW_RELAYS}", + "Turn-on %s light for Relay %" PRIu8, light_mode_group_2.c_str(), light_index+1); auto call = id(gb_lights_2)[light_index]->turn_on(); if (LIGHT_TRANSITION_TURN_ON > 0) call.set_transition_length(LIGHT_TRANSITION_TURN_ON); // in ms @@ -1131,13 +1136,17 @@ script: call.set_brightness(LIGHT_BRIGHTNESS_TURN_ON / 100.0f); call.perform(); } else if (!state and id(gb_lights_2)[light_index]->current_values.is_on()) { - ESP_LOGI("${TAG_STD_HW_RELAYS}", "Turn-off %s light for Relay %" PRIu8, light_mode_group_2.c_str(), light_index+1); + ESP_LOGI("${TAG_STD_HW_RELAYS}", + "Turn-off %s light for Relay %" PRIu8, light_mode_group_2.c_str(), light_index+1); auto call = id(gb_lights_2)[light_index]->turn_off(); if (LIGHT_TRANSITION_TURN_OFF > 0) call.set_transition_length(LIGHT_TRANSITION_TURN_OFF); // in ms call.perform(); } break; + default: + ESP_LOGE("${TAG_STD_HW_RELAYS}", "Invalid light_group=%" PRIu8 " (expected 1 or 2)", light_group); + break; } - id: !extend restore_from_nvs