Temperature-based light color

Temperature-based light color

Automatically change the color of one or more Home Assistant lights based on a temperature sensor.

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

Features

  • :thermometer: Use a temperature sensor to control one or more lights
  • :artist_palette: RGB color interpolation between configurable cold, normal, and hot colors
  • :light_bulb: Color-temperature interpolation between configurable Kelvin values
  • :thermometer: Configurable minimum, normal, and maximum temperatures
  • :stopwatch: Configurable light transition duration
  • :counterclockwise_arrows_button: Optional minimum temperature-change threshold to reduce unnecessary updates
  • :light_bulb: Option to update only lights that are already on
  • :bright_button: Automatically synchronizes a light when it is turned on
  • :rocket: Synchronizes eligible lights when Home Assistant starts
  • :shield: Ignores unavailable and unknown temperature sensor states
  • :chart_increasing: Temperatures outside the configured range use the corresponding endpoint color

The temperature range is divided into two phases:

Cold ─────────────► Normal ─────────────► Hot

The configured normal color is reached at the configured normal temperature.

Requirements

Temperature sensor

The selected sensor must:

  • Be a sensor entity
  • Have the temperature device class
  • Provide a numeric temperature state
  • Use Β°C, as the blueprint’s temperature thresholds are configured in Β°C

Lights

One or more light entities can be selected.

For RGB mode, the lights must support RGB color.

For Color temperature mode, the lights must support color temperature and a compatible Kelvin range.

The exact result can depend on the capabilities of the individual light or light integration.

Only update lights that are already on

This option is enabled by default.

When enabled, temperature changes only affect lights that are currently on. The blueprint will not turn an off light on.

When a configured light is subsequently turned on, its color is automatically synchronized with the current temperature.

If the option is disabled, the blueprint can also update lights that are currently off, which may turn them on.

Minimum temperature change

Use Minimum temperature change to prevent frequent small sensor fluctuations from causing unnecessary light updates.

For example, with a threshold of 0.5 Β°C, changes smaller than 0.5 Β°C are ignored.

Set it to 0 to process every temperature state change.

Temperature range

The configured temperatures must satisfy:

Minimum < Normal < Maximum

Temperatures below or above the configured range are clamped to the cold or hot color respectively.

For more detailed information about the interpolation, configuration options, and troubleshooting, see the project README.

Installation

Click the Import Blueprint button at the top of this post, or import the blueprint manually using:

https://raw.githubusercontent.com/tobus3000/hass-temperature-based-light-color-blueprint/refs/heads/main/blueprints/automation/tobus3000/temperature_based_light_colors.yaml

Alternatively:

  1. Go to Settings β†’ Automations & scenes β†’ Blueprints
  2. Select Import Blueprint
  3. Enter the raw GitHub URL
  4. Select Preview
  5. Import the blueprint

Full blueprint

blueprint:
  name: Temperature-based light color
  description: >
    Changes the color of one or more lights based on a configurable
    temperature sensor.

    The color changes through three configurable temperature points:
    cold, normal, and hot.

    The transition is split into two phases:
    cold β†’ normal and normal β†’ hot.

    For RGB mode, the colors are interpolated between the three
    configured RGB colors. This allows colors such as blue β†’ green β†’
    red, with the intermediate transition naturally passing through
    cyan, yellow, orange, and other intermediate colors.

    For color-temperature mode, the Kelvin value is interpolated
    through the same three temperature points.

    When "Only update lights that are already on" is enabled, the
    automation never turns an off light on. When a light is subsequently
    turned on, its color is synchronized with the current temperature.

    The configured color is also applied to eligible lights when
    Home Assistant starts.
  domain: automation
  author: tobus3000
  source_url: https://github.com/tobus3000/hass-temperature-based-light-color-blueprint
  homeassistant:
    min_version: "2024.10.0"

  input:
    temperature_sensor:
      name: Temperature sensor
      description: >
        The temperature sensor whose value controls the light color.
        The sensor state must be expressed in Β°C.
      selector:
        entity:
          filter:
            - domain: sensor
              device_class: temperature

    target_lights:
      name: Lights
      description: >
        One or more lights whose color should follow the temperature.
        The selected lights must support the selected color mode.
      selector:
        entity:
          multiple: true
          filter:
            - domain: light

    color_mode:
      name: Color mode
      description: >
        Choose between RGB color interpolation and color-temperature
        interpolation.
      default: rgb
      selector:
        select:
          options:
            - label: RGB color
              value: rgb
            - label: Color temperature
              value: color_temperature

    min_temperature:
      name: Minimum temperature
      description: >
        At or below this temperature, the cold color is used.
        Temperature thresholds are expressed in Β°C.
        Must be lower than the normal and maximum temperatures.
      default: 0
      selector:
        number:
          min: -50
          max: 100
          step: 0.5
          unit_of_measurement: "Β°C"
          mode: box

    normal_temperature:
      name: Normal temperature
      description: >
        The temperature at which the normal color is used.
        Temperature thresholds are expressed in Β°C.
        Must be between the minimum and maximum temperatures.
      default: 20
      selector:
        number:
          min: -50
          max: 100
          step: 0.5
          unit_of_measurement: "Β°C"
          mode: box

    max_temperature:
      name: Maximum temperature
      description: >
        At or above this temperature, the hot color is used.
        Temperature thresholds are expressed in Β°C.
        Must be higher than the normal and minimum temperatures.
      default: 30
      selector:
        number:
          min: -50
          max: 100
          step: 0.5
          unit_of_measurement: "Β°C"
          mode: box

    cold_temperature_rgb:
      name: Cold color
      description: >
        RGB color used at or below the minimum temperature.
      default: [0, 100, 255]
      selector:
        color_rgb:

    normal_temperature_rgb:
      name: Normal color
      description: >
        RGB color used at the normal temperature.
      default: [0, 255, 0]
      selector:
        color_rgb:

    hot_temperature_rgb:
      name: Hot color
      description: >
        RGB color used at or above the maximum temperature.
      default: [255, 0, 0]
      selector:
        color_rgb:

    cold_temperature_kelvin:
      name: Cold color temperature
      description: >
        Kelvin value used at or below the minimum temperature.
      default: 6500
      selector:
        color_temp:
          unit: kelvin
          min: 2000
          max: 6500

    normal_temperature_kelvin:
      name: Normal color temperature
      description: >
        Kelvin value used at the normal temperature.
      default: 4000
      selector:
        color_temp:
          unit: kelvin
          min: 2000
          max: 6500

    hot_temperature_kelvin:
      name: Hot color temperature
      description: >
        Kelvin value used at or above the maximum temperature.
      default: 2700
      selector:
        color_temp:
          unit: kelvin
          min: 2000
          max: 6500

    transition:
      name: Transition
      description: >
        Duration of the color transition.
      default: 2
      selector:
        number:
          min: 0
          max: 60
          step: 0.5
          unit_of_measurement: seconds
          mode: box

    min_temperature_change:
      name: Minimum temperature change
      description: >
        Ignore temperature changes smaller than this amount.
        Set to 0 to react to every sensor state change.
      default: 0.5
      selector:
        number:
          min: 0
          max: 10
          step: 0.1
          unit_of_measurement: "Β°C"
          mode: box

    only_update_lights_that_are_on:
      name: Only update lights that are already on
      description: >
        When enabled, off lights are never turned on by this automation.
        When a light is subsequently turned on, its color is synchronized
        with the current temperature.
      default: true
      selector:
        boolean:

mode: restart

variables:
  temperature_sensor: !input temperature_sensor
  target_lights: !input target_lights
  color_mode: !input color_mode

  min_temperature: !input min_temperature
  normal_temperature: !input normal_temperature
  max_temperature: !input max_temperature

  cold_temperature_rgb: !input cold_temperature_rgb
  normal_temperature_rgb: !input normal_temperature_rgb
  hot_temperature_rgb: !input hot_temperature_rgb

  cold_temperature_kelvin: !input cold_temperature_kelvin
  normal_temperature_kelvin: !input normal_temperature_kelvin
  hot_temperature_kelvin: !input hot_temperature_kelvin

  transition: !input transition
  min_temperature_change: !input min_temperature_change
  only_update_lights_that_are_on: !input only_update_lights_that_are_on

  temperature: "{{ states(temperature_sensor) | float(0) }}"

trigger:
  - trigger: state
    entity_id: !input temperature_sensor
    to: null
    id: temperature_changed

  - trigger: state
    entity_id: !input target_lights
    to: "on"
    id: light_turned_on

  - trigger: homeassistant
    event: start
    id: home_assistant_started

condition:
  - condition: template
    value_template: >
      {{ is_number(states(temperature_sensor)) }}

  - condition: template
    value_template: >
      {{
        min_temperature < normal_temperature
        and normal_temperature < max_temperature
      }}

  - condition: template
    value_template: >
      {% if trigger.id != 'temperature_changed' %}
        true
      {% elif trigger.from_state is none %}
        true
      {% elif trigger.from_state.state in ['unknown', 'unavailable', 'none', ''] %}
        true
      {% else %}
        {{
          (
            states(temperature_sensor) | float(0)
            - trigger.from_state.state | float(0)
          ) | abs >= min_temperature_change
        }}
      {% endif %}

action:
  - variables:
      lights_to_update: >
        {% if trigger.id == 'light_turned_on' %}
          {{ [trigger.entity_id] }}
        {% elif only_update_lights_that_are_on %}
          {{
            expand(target_lights)
            | selectattr('state', 'eq', 'on')
            | map(attribute='entity_id')
            | list
          }}
        {% else %}
          {{ target_lights }}
        {% endif %}

  - condition: template
    value_template: >
      {{ lights_to_update | count > 0 }}

  - choose:
      - conditions:
          - condition: template
            value_template: "{{ color_mode == 'rgb' }}"
        sequence:
          - variables:
              red: >
                {% set t = temperature | float(0) %}

                {% if t <= min_temperature %}
                  {{ cold_temperature_rgb[0] | int }}
                {% elif t < normal_temperature %}
                  {{
                    (
                      cold_temperature_rgb[0]
                      + (
                        (
                          (t - min_temperature)
                          / (normal_temperature - min_temperature)
                        )
                        * (
                          normal_temperature_rgb[0]
                          - cold_temperature_rgb[0]
                        )
                      )
                    ) | round(0) | int
                  }}
                {% elif t < max_temperature %}
                  {{
                    (
                      normal_temperature_rgb[0]
                      + (
                        (
                          (t - normal_temperature)
                          / (max_temperature - normal_temperature)
                        )
                        * (
                          hot_temperature_rgb[0]
                          - normal_temperature_rgb[0]
                        )
                      )
                    ) | round(0) | int
                  }}
                {% else %}
                  {{ hot_temperature_rgb[0] | int }}
                {% endif %}

              green: >
                {% set t = temperature | float(0) %}

                {% if t <= min_temperature %}
                  {{ cold_temperature_rgb[1] | int }}
                {% elif t < normal_temperature %}
                  {{
                    (
                      cold_temperature_rgb[1]
                      + (
                        (
                          (t - min_temperature)
                          / (normal_temperature - min_temperature)
                        )
                        * (
                          normal_temperature_rgb[1]
                          - cold_temperature_rgb[1]
                        )
                      )
                    ) | round(0) | int
                  }}
                {% elif t < max_temperature %}
                  {{
                    (
                      normal_temperature_rgb[1]
                      + (
                        (
                          (t - normal_temperature)
                          / (max_temperature - normal_temperature)
                        )
                        * (
                          hot_temperature_rgb[1]
                          - normal_temperature_rgb[1]
                        )
                      )
                    ) | round(0) | int
                  }}
                {% else %}
                  {{ hot_temperature_rgb[1] | int }}
                {% endif %}

              blue: >
                {% set t = temperature | float(0) %}

                {% if t <= min_temperature %}
                  {{ cold_temperature_rgb[2] | int }}
                {% elif t < normal_temperature %}
                  {{
                    (
                      cold_temperature_rgb[2]
                      + (
                        (
                          (t - min_temperature)
                          / (normal_temperature - min_temperature)
                        )
                        * (
                          normal_temperature_rgb[2]
                          - cold_temperature_rgb[2]
                        )
                      )
                    ) | round(0) | int
                  }}
                {% elif t < max_temperature %}
                  {{
                    (
                      normal_temperature_rgb[2]
                      + (
                        (
                          (t - normal_temperature)
                          / (max_temperature - normal_temperature)
                        )
                        * (
                          hot_temperature_rgb[2]
                          - normal_temperature_rgb[2]
                        )
                      )
                    ) | round(0) | int
                  }}
                {% else %}
                  {{ hot_temperature_rgb[2] | int }}
                {% endif %}

          - action: light.turn_on
            target:
              entity_id: "{{ lights_to_update }}"
            data:
              rgb_color:
                - "{{ red }}"
                - "{{ green }}"
                - "{{ blue }}"
              transition: "{{ transition }}"

      - conditions:
          - condition: template
            value_template: "{{ color_mode == 'color_temperature' }}"
        sequence:
          - variables:
              color_temperature_kelvin: >
                {% set t = temperature | float(0) %}

                {% if t <= min_temperature %}
                  {{ cold_temperature_kelvin | int }}
                {% elif t < normal_temperature %}
                  {{
                    (
                      cold_temperature_kelvin
                      + (
                        (
                          (t - min_temperature)
                          / (normal_temperature - min_temperature)
                        )
                        * (
                          normal_temperature_kelvin
                          - cold_temperature_kelvin
                        )
                      )
                    ) | round(0) | int
                  }}
                {% elif t < max_temperature %}
                  {{
                    (
                      normal_temperature_kelvin
                      + (
                        (
                          (t - normal_temperature)
                          / (max_temperature - normal_temperature)
                        )
                        * (
                          hot_temperature_kelvin
                          - normal_temperature_kelvin
                        )
                      )
                    ) | round(0) | int
                  }}
                {% else %}
                  {{ hot_temperature_kelvin | int }}
                {% endif %}

          - action: light.turn_on
            target:
              entity_id: "{{ lights_to_update }}"
            data:
              color_temp_kelvin: "{{ color_temperature_kelvin }}"
              transition: "{{ transition }}"

Source

Repository and issue tracking:

https://github.com/tobus3000/hass-temperature-based-light-color-blueprint