Add Light Color Mapper blueprint
Maps color sensor states to lights in real-time with index-based pairing. Supports FPS throttling, brightness override, configurable behavior when sensors are unavailable, and a post-update callback action. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
67
Common/Light Color Mapper/README.md
Normal file
67
Common/Light Color Mapper/README.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Light Color Mapper
|
||||||
|
|
||||||
|
Syncs light colors in real-time from color sensor entities. Sensors and lights are paired by list index (sensor 0 → light 0, sensor 1 → light 1, etc.).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Real-time color sync from sensor entities to lights
|
||||||
|
- Index-based sensor-to-light mapping (add in matching order)
|
||||||
|
- FPS throttling for performance control (0–60 fps)
|
||||||
|
- Brightness override or per-sensor brightness from attributes
|
||||||
|
- Configurable behavior when sensors are unavailable (turn off, keep last, default color)
|
||||||
|
- Control entity (switch/input_boolean) to enable/disable
|
||||||
|
- Optional auto-off when the control entity is disabled
|
||||||
|
- Custom post-update callback action (runs after each update cycle)
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
The automation triggers on any state change from the configured color sensors. Each sensor is paired with a light by list position:
|
||||||
|
|
||||||
|
| Sensor Index | Light Index |
|
||||||
|
| --- | --- |
|
||||||
|
| Sensor 0 | Light 0 |
|
||||||
|
| Sensor 1 | Light 1 |
|
||||||
|
| Sensor 2 | Light 2 |
|
||||||
|
| ... | ... |
|
||||||
|
|
||||||
|
When a sensor updates, **all** sensor-light pairs are re-evaluated to keep lights in sync.
|
||||||
|
|
||||||
|
### FPS Throttling
|
||||||
|
|
||||||
|
The automation uses `mode: restart` with a trailing delay to throttle updates:
|
||||||
|
|
||||||
|
- **FPS = 0**: No throttle — every state change triggers an immediate update.
|
||||||
|
- **FPS > 0**: After processing all lights, a delay of `1000 / FPS` ms is added. If a new sensor state arrives during the delay, the automation restarts with the latest data. This naturally caps updates to the configured FPS.
|
||||||
|
|
||||||
|
### Sensor Requirements
|
||||||
|
|
||||||
|
Each color sensor should expose:
|
||||||
|
|
||||||
|
| Attribute | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| **State** | Hex color string (e.g., `#FF8800`) or `None` when not processing |
|
||||||
|
| `rgb_color` | Color as `[r, g, b]` list (used to set light color) |
|
||||||
|
| `brightness` | Brightness value 0–255 (used when no override is set) |
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
| Input | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| **Control Entity** | Switch or input_boolean that enables/disables the automation |
|
||||||
|
| **Turn Off Lights on Disable** | Turn off all mapped lights when the control entity is switched off (default: true) |
|
||||||
|
| **Color Sensors** | List of color sensor entities (index-mapped to lights) |
|
||||||
|
| **Lights** | List of light entities (index-mapped to sensors) |
|
||||||
|
| **Maximum FPS** | Update rate limit, 0 = unlimited (default: 0) |
|
||||||
|
| **Brightness Override** | Fixed brightness for all lights, 0 = use sensor brightness (default: 0) |
|
||||||
|
| **When Sensor is Unavailable** | Action when sensor is None/unavailable: Turn Off, Keep Last, or Set Default Color |
|
||||||
|
| **Default Color** | Color to apply when sensor is unavailable and action is "Set Default Color" |
|
||||||
|
| **Post-Update Action** | Custom action to run after all lights are updated (e.g., fire an event, call a service) |
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- If the sensor and light lists have different lengths, only the shorter count of pairs is used (extra entities are ignored).
|
||||||
|
- When the control entity is turned off and "Turn Off Lights on Disable" is enabled, only the paired lights (up to `pair_count`) are turned off.
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
Alexei Dolgolyov (<dolgolyov.alexei@gmail.com>)
|
||||||
327
Common/Light Color Mapper/blueprint.yaml
Normal file
327
Common/Light Color Mapper/blueprint.yaml
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
# 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 (0–255).
|
||||||
|
Set to 0 to use each sensor's brightness attribute instead.
|
||||||
|
default: 0
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
min: 0
|
||||||
|
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
|
||||||
|
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 }}
|
||||||
|
|
||||||
|
**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 }}"
|
||||||
|
|
||||||
|
# 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 }}"
|
||||||
|
|
||||||
|
- 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 }}"
|
||||||
Reference in New Issue
Block a user