Files
alexei.dolgolyov eefc8993e3 Add min_brightness setting to Light Color Mapper
Adds a minimum brightness floor (default: 5) that prevents lights from
becoming too dim. Applied to both sensor brightness and default color paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 00:51:03 +03:00

343 lines
13 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Light Color Mapper
# Syncs light colors in real-time from color sensor entities.
# See README.md for detailed documentation.
#
# Author: Alexei Dolgolyov (dolgolyov.alexei@gmail.com)
blueprint:
name: "Custom: Light Color Mapper"
description: >
Maps color sensor states to lights in real-time.
Sensors and lights are paired by list index (sensor 0 → light 0, etc.).
Supports FPS throttling, brightness override, and configurable behavior
when sensors are unavailable.
domain: automation
# ===========================================================================
# INPUT CONFIGURATION
# ===========================================================================
input:
# -------------------------------------------------------------------------
# Control
# -------------------------------------------------------------------------
control_group:
name: "Control"
collapsed: false
input:
control_entity:
name: Control Entity
description: "Switch or input_boolean that enables/disables this automation."
selector:
entity:
domain:
- input_boolean
- switch
turn_off_on_disable:
name: Turn Off Lights on Disable
description: "Turn off all mapped lights when the control entity is switched off."
default: true
selector:
boolean:
# -------------------------------------------------------------------------
# Devices
# -------------------------------------------------------------------------
devices_group:
name: "Devices"
collapsed: false
input:
color_sensors:
name: Color Sensors
description: >
List of color sensor entities. Each sensor's state is a hex color
string (e.g., #FF8800) with attributes: r, g, b, brightness,
rgb_color. Sensors are mapped to lights by list index.
selector:
entity:
domain: sensor
multiple: true
lights:
name: Lights
description: >
List of light entities. Each light is paired with the sensor at the
same list index (sensor 0 → light 0, sensor 1 → light 1, etc.).
selector:
entity:
domain: light
multiple: true
# -------------------------------------------------------------------------
# Settings
# -------------------------------------------------------------------------
settings_group:
name: "Settings"
collapsed: false
input:
max_fps:
name: Maximum FPS
description: >
Maximum updates per second. With mode: restart, a trailing delay
throttles updates naturally — new state changes during the delay
restart the automation with fresh data. Set to 0 for unlimited.
default: 0
selector:
number:
min: 0
max: 60
mode: slider
brightness_override:
name: Brightness Override
description: >
Override brightness for all lights (0255).
Set to 0 to use each sensor's brightness attribute instead.
default: 0
selector:
number:
min: 0
max: 255
mode: slider
min_brightness:
name: Minimum Brightness
description: >
Minimum brightness for all lights (1255). If the sensor or
override brightness is below this value, this minimum is used
instead. Prevents lights from becoming too dim to see.
default: 5
selector:
number:
min: 1
max: 255
mode: slider
none_action:
name: When Sensor is Unavailable
description: "Action to take when a sensor state is None, unknown, or unavailable."
default: "turn_off"
selector:
select:
options:
- label: "Turn Off Light"
value: "turn_off"
- label: "Keep Last Color"
value: "keep_last"
- label: "Set Default Color"
value: "default_color"
default_color:
name: Default Color
description: >
Color to apply when a sensor is unavailable.
Only used when "When Sensor is Unavailable" is set to "Set Default Color".
default: [255, 255, 255]
selector:
color_rgb:
# -------------------------------------------------------------------------
# Callback Actions
# -------------------------------------------------------------------------
actions_group:
name: "Callback Actions"
collapsed: true
input:
post_update_action:
name: Post-Update Action
description: >
Custom action to run after all sensor-light pairs have been processed.
Runs once per update cycle, after all lights are set.
Leave empty to do nothing.
default: []
selector:
action:
# -------------------------------------------------------------------------
# Debug
# -------------------------------------------------------------------------
debug:
name: "Debug"
collapsed: true
input:
enable_debug_notifications:
name: Enable Debug Notifications
description: >
Send persistent notifications showing sensor states and light
updates for troubleshooting.
default: false
selector:
boolean:
# Restart mode ensures the latest sensor state always wins.
# Combined with a trailing delay (FPS throttle), incoming state changes
# during the delay cancel the current run and restart with fresh data.
mode: restart
# =============================================================================
# TRIGGERS
# =============================================================================
trigger:
# Any color sensor changes state
- platform: state
entity_id: !input color_sensors
id: "sensor_changed"
# Control entity toggled on/off
- platform: state
entity_id: !input control_entity
id: "control_changed"
# =============================================================================
# VARIABLES
# =============================================================================
variables:
# ---------------------------------------------------------------------------
# Input References
# ---------------------------------------------------------------------------
control_entity: !input control_entity
turn_off_on_disable: !input turn_off_on_disable
color_sensors: !input color_sensors
lights: !input lights
max_fps: !input max_fps
brightness_override: !input brightness_override
min_brightness: !input min_brightness
none_action: !input none_action
default_color: !input default_color
enable_debug_notifications: !input enable_debug_notifications
post_update_action: !input post_update_action
# ---------------------------------------------------------------------------
# Computed Values
# ---------------------------------------------------------------------------
# Use the shorter list length to avoid index-out-of-range errors
pair_count: "{{ [color_sensors | length, lights | length] | min }}"
# =============================================================================
# ACTIONS
# =============================================================================
action:
# ---------------------------------------------------------------------------
# Debug Logging
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Light Color Mapper Debug"
message: >
**Trigger:** {{ trigger.id }}
**Control:** {{ states(control_entity) }}
**Pairs:** {{ pair_count }}
**FPS:** {{ max_fps }}
**Brightness Override:** {{ brightness_override }}
**Min Brightness:** {{ min_brightness }}
**Sensor States:**
{% for i in range(pair_count | int) %}
{{ i }}: {{ color_sensors[i] }} = {{ states(color_sensors[i]) }} (rgb: {{ state_attr(color_sensors[i], 'rgb_color') }}, brightness: {{ state_attr(color_sensors[i], 'brightness') }})
{% endfor %}
# ---------------------------------------------------------------------------
# Check Control Entity
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ not is_state(control_entity, 'on') }}"
sequence:
# Turn off all mapped lights if configured
- choose:
- conditions:
- condition: template
value_template: "{{ turn_off_on_disable }}"
sequence:
- service: light.turn_off
target:
entity_id: "{{ lights[:pair_count | int] }}"
- stop: "Control entity is off"
# ---------------------------------------------------------------------------
# Process Each Sensor-Light Pair
# ---------------------------------------------------------------------------
- repeat:
count: "{{ pair_count | int }}"
sequence:
- variables:
idx: "{{ repeat.index - 1 }}"
current_sensor: "{{ color_sensors[idx] }}"
current_light: "{{ lights[idx] }}"
sensor_state: "{{ states(current_sensor) }}"
is_unavailable: "{{ sensor_state in ['None', 'none', 'unknown', 'unavailable', 'undefined'] or sensor_state | length == 0 }}"
- choose:
# Sensor is unavailable — apply configured action
- conditions:
- condition: template
value_template: "{{ is_unavailable }}"
sequence:
- choose:
# Turn off the light
- conditions:
- condition: template
value_template: "{{ none_action == 'turn_off' }}"
sequence:
- service: light.turn_off
target:
entity_id: "{{ current_light }}"
# Set default color
- conditions:
- condition: template
value_template: "{{ none_action == 'default_color' }}"
sequence:
- service: light.turn_on
target:
entity_id: "{{ current_light }}"
data:
rgb_color: "{{ default_color }}"
brightness: "{{ [brightness_override | int if brightness_override | int > 0 else 255, min_brightness | int] | max }}"
# keep_last — do nothing
# Sensor has valid state — apply color to light
default:
- variables:
sensor_rgb: "{{ state_attr(current_sensor, 'rgb_color') | default([255, 255, 255]) }}"
sensor_brightness: "{{ state_attr(current_sensor, 'brightness') | default(255) }}"
target_brightness: "{{ [brightness_override | int if brightness_override | int > 0 else sensor_brightness | int, min_brightness | int] | max }}"
- service: light.turn_on
target:
entity_id: "{{ current_light }}"
data:
rgb_color: "{{ sensor_rgb }}"
brightness: "{{ target_brightness }}"
# ---------------------------------------------------------------------------
# Post-Update Callback
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ post_update_action | length > 0 }}"
sequence: !input post_update_action
# ---------------------------------------------------------------------------
# FPS Throttle
# ---------------------------------------------------------------------------
# With mode: restart, new triggers during this delay cancel and restart
# the automation, effectively capping updates to max_fps per second.
- choose:
- conditions:
- condition: template
value_template: "{{ max_fps | int > 0 }}"
sequence:
- delay:
milliseconds: "{{ (1000 / (max_fps | int)) | int }}"