Add transition duration, scene activation, JSON presets, and group/area targeting to MQTT Light Control
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s

- Add configurable transition duration (0-10s) for smooth light changes
- Add scene activation support with 4 configurable scene slots
- Change preset format from key:value;key:value to JSON with expanded keys
- Add light group entity and area-based targeting options
This commit is contained in:
2026-01-25 04:19:40 +03:00
parent 7c605f721a
commit 31650380ea

View File

@@ -10,7 +10,10 @@
# - Brightness control (increment, hold, list-based, min/max) # - Brightness control (increment, hold, list-based, min/max)
# - Color temperature control (increment, hold, list-based) # - Color temperature control (increment, hold, list-based)
# - RGB/Hue control (increment, hold, list-based) # - RGB/Hue control (increment, hold, list-based)
# - Preset list support for quick scene switching # - Preset list support (JSON format) for quick scene switching
# - Scene activation support (up to 4 scenes)
# - Light group and area targeting
# - Configurable transition duration for smooth changes
# - Alternative light support (control secondary lights when primary are off) # - Alternative light support (control secondary lights when primary are off)
# - Persistent state storage via input_text entity # - Persistent state storage via input_text entity
# - Custom action callbacks for extending functionality # - Custom action callbacks for extending functionality
@@ -133,6 +136,25 @@ blueprint:
- input_text - input_text
multiple: true multiple: true
target_light_group:
name: Target Light Group (optional)
description: >
A light group entity to control. The group will be controlled as
a single entity. Can be used alongside individual lights.
default: null
selector:
entity:
domain: light
target_area:
name: Target Area (optional)
description: >
An area to control. All lights in the area will be discovered
and controlled. Provide the area ID (e.g., "living_room").
default: ""
selector:
text:
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Alternative Lights Configuration # Alternative Lights Configuration
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
@@ -443,6 +465,20 @@ blueprint:
selector: selector:
boolean: boolean:
transition_duration:
name: Transition Duration
description: >
Duration in seconds for light transitions (brightness, color changes).
Set to 0 for instant changes. Note: Hold actions ignore this setting
for immediate response.
default: 0
selector:
number:
min: 0
max: 10
step: 0.5
unit_of_measurement: "s"
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Brightness Increment Actions # Brightness Increment Actions
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
@@ -904,10 +940,12 @@ blueprint:
preset_list_entity: preset_list_entity:
name: Preset List Entity name: Preset List Entity
description: > description: >
An input_select entity containing preset values. Each entry must have An input_select entity containing preset values in JSON format.
the following layout: `key:value;key:value`, example Example: `{"color_temp_kelvin": 4000, "brightness": 255}`
`color_temp_kelvin:4000;brightness:255`. Supported keys are: Example with RGB: `{"rgb_color": [255, 0, 0], "brightness": 200}`
`color_temp_kelvin`, `rgb_color`, `brightness` Example with effect: `{"effect": "colorloop", "brightness": 128}`
Supported keys: brightness, color_temp_kelvin, rgb_color, hs_color,
xy_color, effect, transition
default: null default: null
selector: selector:
entity: entity:
@@ -920,6 +958,102 @@ blueprint:
selector: selector:
action: {} action: {}
# -------------------------------------------------------------------------
# Scene Activation Actions
# -------------------------------------------------------------------------
# Directly activate Home Assistant scenes via MQTT actions
Action_Group_Scene:
name: "Actions: Scene Activation"
collapsed: true
input:
action_scene_1:
name: Scene 1 Action ID
description: Action ID to activate Scene 1
default: ''
selector:
text:
scene_entity_1:
name: Scene 1 Entity
description: The scene entity to activate when Scene 1 Action ID is received
default: null
selector:
entity:
domain: scene
action_scene_1_callback:
name: Scene 1 Callback
description: Callback action triggered after Scene 1 activation
default: []
selector:
action: {}
action_scene_2:
name: Scene 2 Action ID
description: Action ID to activate Scene 2
default: ''
selector:
text:
scene_entity_2:
name: Scene 2 Entity
description: The scene entity to activate when Scene 2 Action ID is received
default: null
selector:
entity:
domain: scene
action_scene_2_callback:
name: Scene 2 Callback
description: Callback action triggered after Scene 2 activation
default: []
selector:
action: {}
action_scene_3:
name: Scene 3 Action ID
description: Action ID to activate Scene 3
default: ''
selector:
text:
scene_entity_3:
name: Scene 3 Entity
description: The scene entity to activate when Scene 3 Action ID is received
default: null
selector:
entity:
domain: scene
action_scene_3_callback:
name: Scene 3 Callback
description: Callback action triggered after Scene 3 activation
default: []
selector:
action: {}
action_scene_4:
name: Scene 4 Action ID
description: Action ID to activate Scene 4
default: ''
selector:
text:
scene_entity_4:
name: Scene 4 Entity
description: The scene entity to activate when Scene 4 Action ID is received
default: null
selector:
entity:
domain: scene
action_scene_4_callback:
name: Scene 4 Callback
description: Callback action triggered after Scene 4 activation
default: []
selector:
action: {}
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Common List Parameters # Common List Parameters
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
@@ -1117,17 +1251,38 @@ variables:
apply_common_options_to_newly_enabled_light: !input apply_common_options_to_newly_enabled_light apply_common_options_to_newly_enabled_light: !input apply_common_options_to_newly_enabled_light
target_lights_helper: !input target_lights_helper target_lights_helper: !input target_lights_helper
target_lights: !input target_lights target_lights: !input target_lights
target_light_group: !input target_light_group
target_area: !input target_area
best_source_light_for_options: !input best_source_light_for_options best_source_light_for_options: !input best_source_light_for_options
# Resolve all lights from either helper entities or direct selection # Resolve all lights from direct selection, helpers, groups, and areas
resolved_all_lights: >- resolved_all_lights: >-
{% set result = [] %} {% set result = [] %}
{% if target_lights_helper != '' %} {# Direct light selection #}
{% set result = target_lights_helper | map('states') | list %} {% if target_lights | length > 0 %}
{% elif target_lights | length > 0 %}
{% set result = result + target_lights %} {% set result = result + target_lights %}
{% endif %} {% endif %}
{{ result }} {# Helper-based selection #}
{% if target_lights_helper != '' %}
{% set result = result + (target_lights_helper | map('states') | list) %}
{% endif %}
{# Light group - add the group entity itself #}
{% if target_light_group is not none %}
{% set result = result + [target_light_group] %}
{% endif %}
{# Area-based selection #}
{% if target_area != '' %}
{% set area_lights = area_entities(target_area) | select('match', '^light\\.') | list %}
{% set result = result + area_lights %}
{% endif %}
{# Remove duplicates while preserving order #}
{% set seen = namespace(items=[]) %}
{% for item in result %}
{% if item not in seen.items %}
{% set seen.items = seen.items + [item] %}
{% endif %}
{% endfor %}
{{ seen.items }}
# Determine which lights are currently enabled (ON state) # Determine which lights are currently enabled (ON state)
enabled_lights_default: "{{ resolved_all_lights | select('is_state','on') | list }}" enabled_lights_default: "{{ resolved_all_lights | select('is_state','on') | list }}"
@@ -1259,6 +1414,7 @@ variables:
action_brightness_set_min_or_max: !input action_brightness_set_min_or_max action_brightness_set_min_or_max: !input action_brightness_set_min_or_max
result_max_brightness: !input max_brightness result_max_brightness: !input max_brightness
result_min_brightness: !input min_brightness result_min_brightness: !input min_brightness
transition_duration: !input transition_duration
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Color Temperature Action IDs and Limits # Color Temperature Action IDs and Limits
@@ -1311,6 +1467,18 @@ variables:
action_preset_list_up: !input action_preset_list_up action_preset_list_up: !input action_preset_list_up
action_preset_list_down: !input action_preset_list_down action_preset_list_down: !input action_preset_list_down
# ---------------------------------------------------------------------------
# Scene Action IDs and Entities
# ---------------------------------------------------------------------------
action_scene_1: !input action_scene_1
action_scene_2: !input action_scene_2
action_scene_3: !input action_scene_3
action_scene_4: !input action_scene_4
scene_entity_1: !input scene_entity_1
scene_entity_2: !input scene_entity_2
scene_entity_3: !input scene_entity_3
scene_entity_4: !input scene_entity_4
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Callbacks # Callbacks
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -1564,9 +1732,12 @@ action:
result_options_reference_light: "{{ alternative_target if alternative_target is not none else options_reference_light }}" result_options_reference_light: "{{ alternative_target if alternative_target is not none else options_reference_light }}"
color_mode: "{{ state_attr(result_options_reference_light, 'color_mode') if (result_options_reference_light is not none) else none }}" color_mode: "{{ state_attr(result_options_reference_light, 'color_mode') if (result_options_reference_light is not none) else none }}"
# Build light data (brightness, color) to apply # Build light data (brightness, color, transition) to apply
light_data: > light_data: >
{% set d = dict() %} {% set d = dict() %}
{% if transition_duration > 0 %}
{% set d = d | combine({ 'transition': transition_duration }) %}
{% endif %}
{% if not color_mode or (result_options_reference_light is none) or (not apply_common_options_to_newly_enabled_light) %} {% if not color_mode or (result_options_reference_light is none) or (not apply_common_options_to_newly_enabled_light) %}
{% if set_max_brightness_on_turn_on %} {% if set_max_brightness_on_turn_on %}
{% set d = d | combine({ 'brightness': result_max_brightness }) %} {% set d = d | combine({ 'brightness': result_max_brightness }) %}
@@ -1746,6 +1917,8 @@ action:
- service: light.turn_off - service: light.turn_off
target: target:
entity_id: "{{ lights_to_turn_off }}" entity_id: "{{ lights_to_turn_off }}"
data:
transition: "{{ transition_duration }}"
# Turn off the switches # Turn off the switches
- service: switch.turn_off - service: switch.turn_off
@@ -1824,6 +1997,7 @@ action:
entity_id: "{{ lights_to_control }}" entity_id: "{{ lights_to_control }}"
data: data:
brightness: "{{ result_brightness }}" brightness: "{{ result_brightness }}"
transition: "{{ transition_duration }}"
- choose: - choose:
- conditions: - conditions:
@@ -1865,6 +2039,7 @@ action:
entity_id: "{{ lights_to_control }}" entity_id: "{{ lights_to_control }}"
data: data:
brightness: "{{ result_brightness }}" brightness: "{{ result_brightness }}"
transition: "{{ transition_duration }}"
- choose: - choose:
- conditions: - conditions:
@@ -2220,6 +2395,9 @@ action:
light_data: > light_data: >
{% set d = dict() %} {% set d = dict() %}
{% if transition_duration > 0 %}
{% set d = d | combine({ 'transition': transition_duration }) %}
{% endif %}
{% set d = d | combine({ result_attribute: value_to_set }) %} {% set d = d | combine({ result_attribute: value_to_set }) %}
{% if has_switched_mode and state_key_prefix != '' %} {% if has_switched_mode and state_key_prefix != '' %}
{% set d = d | combine({ 'brightness': brightness_to_set }) %} {% set d = d | combine({ 'brightness': brightness_to_set }) %}
@@ -2363,6 +2541,9 @@ action:
light_data: > light_data: >
{% set d = dict() %} {% set d = dict() %}
{% if transition_duration > 0 %}
{% set d = d | combine({ 'transition': transition_duration }) %}
{% endif %}
{% set d = d | combine({ result_attribute: value_to_set }) %} {% set d = d | combine({ result_attribute: value_to_set }) %}
{{ d }} {{ d }}
@@ -2458,30 +2639,30 @@ action:
{{ [0, [(value_sequence | length - 1), next_index_preview]|min]|max }} {{ [0, [(value_sequence | length - 1), next_index_preview]|min]|max }}
{% endif %} {% endif %}
# Parse preset string (format: "key:value;key:value") # Parse preset JSON format
preset: "{{ value_sequence[next_index] | lower }}" preset_str: "{{ value_sequence[next_index] | trim }}"
light_data: > light_data: >
{% set parts = preset.split(";") %}
{% set ns = namespace(res=dict(), brightness_found=False) %} {% set ns = namespace(res=dict(), brightness_found=False) %}
{% for i in range(parts|length) %} {% set parsed = preset_str | from_json %}
{% set temp = parts[i].split(':') %} {% for key, value in parsed.items() %}
{% set key = temp[0] | trim %}
{% set value = temp[1] | trim %}
{% if key == 'brightness' %} {% if key == 'brightness' %}
{% set ns.res = ns.res | combine({ 'brightness': value | int }) %} {% set ns.res = ns.res | combine({ 'brightness': value | int }) %}
{% set ns.brightness_found = True %} {% set ns.brightness_found = True %}
{% elif key == 'color_temp_kelvin' %} {% elif key in ['color_temp_kelvin', 'effect', 'transition'] %}
{% set ns.res = ns.res | combine({ 'color_temp_kelvin': value | int }) %} {% set ns.res = ns.res | combine({ key: value }) %}
{% elif key == 'rgb_color' %} {% elif key in ['rgb_color', 'hs_color', 'xy_color'] %}
{% set ns.res = ns.res | combine({ 'rgb_color': value | from_json }) %} {% set ns.res = ns.res | combine({ key: value }) %}
{% elif key == 'color_mode' %}
{% set ns.res = ns.res | combine({ 'color_mode': value }) %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{# Preserve current brightness if not specified in preset #}
{% if not ns.brightness_found %} {% if not ns.brightness_found %}
{% set existing_brightness = state_attr(options_reference_light, 'brightness') | int %} {% set existing_brightness = state_attr(options_reference_light, 'brightness') | int %}
{% set ns.res = ns.res | combine({ 'brightness': existing_brightness }) %} {% set ns.res = ns.res | combine({ 'brightness': existing_brightness }) %}
{% endif %} {% endif %}
{# Add transition if not specified in preset #}
{% if 'transition' not in ns.res and transition_duration > 0 %}
{% set ns.res = ns.res | combine({ 'transition': transition_duration }) %}
{% endif %}
{{ ns.res }} {{ ns.res }}
# Apply preset to lights # Apply preset to lights
@@ -2525,6 +2706,70 @@ action:
value_template: "{{ any_action_callback != [] }}" value_template: "{{ any_action_callback != [] }}"
sequence: !input any_action_callback sequence: !input any_action_callback
# -----------------------------------------------------------------------
# SCENE ACTIVATION ACTIONS
# -----------------------------------------------------------------------
- conditions:
- condition: template
value_template: >
{{ action_id != '' and action_id in [action_scene_1, action_scene_2, action_scene_3, action_scene_4] }}
sequence:
- variables:
action_scene_1_callback: !input action_scene_1_callback
action_scene_2_callback: !input action_scene_2_callback
action_scene_3_callback: !input action_scene_3_callback
action_scene_4_callback: !input action_scene_4_callback
scene_to_activate: >
{% if action_id == action_scene_1 %}
{{ scene_entity_1 }}
{% elif action_id == action_scene_2 %}
{{ scene_entity_2 }}
{% elif action_id == action_scene_3 %}
{{ scene_entity_3 }}
{% elif action_id == action_scene_4 %}
{{ scene_entity_4 }}
{% else %}
{{ none }}
{% endif %}
# Activate the scene
- choose:
- conditions:
- condition: template
value_template: "{{ scene_to_activate is not none }}"
sequence:
- service: scene.turn_on
target:
entity_id: "{{ scene_to_activate }}"
data:
transition: "{{ transition_duration }}"
# Execute scene callbacks
- choose:
- conditions:
- condition: template
value_template: "{{ action_id == action_scene_1 and action_scene_1_callback != [] }}"
sequence: !input action_scene_1_callback
- conditions:
- condition: template
value_template: "{{ action_id == action_scene_2 and action_scene_2_callback != [] }}"
sequence: !input action_scene_2_callback
- conditions:
- condition: template
value_template: "{{ action_id == action_scene_3 and action_scene_3_callback != [] }}"
sequence: !input action_scene_3_callback
- conditions:
- condition: template
value_template: "{{ action_id == action_scene_4 and action_scene_4_callback != [] }}"
sequence: !input action_scene_4_callback
- choose:
- conditions:
- condition: template
value_template: "{{ any_action_callback != [] }}"
sequence: !input any_action_callback
# =========================================================================== # ===========================================================================
# CUSTOM ACTIONS HANDLER # CUSTOM ACTIONS HANDLER
# =========================================================================== # ===========================================================================