Festive Room Motion Lights

We have some rooms with Hue spot bulbs in the ceiling, they have a whole bunch of scenes and the usual setup - but a motion sensor trips on a few bulbs in each room through HA when people walk through or go into that room without actually turning on the lights using any of the usual mechanisms.

Thought it would be fun to setup some festive motion lights - so rather than just ‘turning on’ a motion triggered scene I use this script to randomly set some (generally highly) saturated colours on the bulbs:

alias: Random Room Lights
sequence:
  - variables:
      settings: >-
        {%- macro pick_hue() -%} {{ range(0,360) | random }} {%- endmacro -%}
        {%- macro pick_saturation() -%} {{ range(30,100) | random }} {%- endmacro -%}
        {%- macro pick_brightness() -%} {{ range(180,255) | random }} {%- endmacro -%}
        {%- macro pick_hs(lights) -%}
          {%- for light in lights -%}
            "{{ light }}": {"state":"on","hs_color": [ {{ pick_hue()|trim }}, {{ pick_saturation()|trim}} ],"brightness": {{ pick_brightness()|trim}}},
          {%- endfor -%}
        {%- endmacro -%}
        {%- macro breakdown_group(group, exclude) %}
          {%- if group is string -%}
          {%- set entities = iif(state_attr(group, 'is_hue_group'),
            state_attr(group, 'lights') | map('lower') | map('regex_replace', '^(.*)', 'light.\\1'),
            state_attr(group, 'entity_id') | map('lower'))
            | list -%}
          {%- else -%}
            {%- set entities = group | map('lower') -%}
          {%- endif -%}
          {{- iif(exclude is defined, entities | reject('in', exclude), entities) | join(',') -}}
        {%- endmacro -%}
        {%- set lights = (breakdown_group(room,exclude) | trim).split(',') -%}
        {{- ("{" + pick_hs(lights)[:-1] + "}") | from_json -}}
  - service: scene.apply
    data:
      entities: "{{ settings }}"
mode: parallel
icon: mdi:palette-outline
max: 10

You can call it with:

data:
  room: light.room_group
  exclude:[ "light.bulb1", "light.christmas_tree"]

…and it will work out if the room_group is a Hue defined light group or a HA defined light group.

You can also call it with:

data:
  room: ["light.bulb1","light.bulb2"]

…if you prefer.

For my setup I have a script per room that calls this one (just for separation reasons!), here is an example for the lounge which has 8 hue bulbs in the ceiling four of which get turned on with motion:

alias: Special Motion Lounge
sequence:
  - service: script.turn_on
    data:
      variables:
        room:
          - light.mlr2
          - light.mlc4
          - light.mlc2
          - light.mll2
    target:
      entity_id: script.random_room_lights
mode: parallel
icon: mdi:palette-outline
max: 10

I want to always keep one bulb off so I can tell the difference between the lights having been turned on by the motion detection or by someone putting a scene on… (as scenes can be turned on by mechanisms that are outside of HA control and I don’t want the motion to kill the lights if someone happens to have turned a scene on in the Hue app for example).

I have this blueprint for my motion lights which is a massively hacked version of just about every combination of motion light blueprint I’ve found that is now a Swiss army knife of motion triggering:

blueprint:
  name: Special Motion Trigger
  description: "
    Turn on an entity when motion is detected, and turn it off after a
    delay.\n\n Optionally specify an illumination threshold sensor to
    only let the automation run when that has been triggered. A time of
    day sensor can also be provided to limit turn on times only if that
    sensor is active.\n\n Add a blocking entity at either the start of the
    automation or before the turn off actions, to prevent the automation
    running any further if either of those entities are turned on.\n\n
    If the entity to be turned on is something that can't be turned off,
    such as a scene, then add a different entity to turn off. Can also
    be used to apply the turn on action onto one entity and the turn off
    action onto another.\n\nAn optional 'special on entity' can be called on
    'special days' detected by a boolean helper that can be triggered by 
    a calendar or any other way you see fit.\n\n
    Phil.
    \n"
  domain: automation
  input:
    motion_sensor_disabled:
      name: (OPTIONAL) Sensor Disabled Switch.
      description: Master helper switch to disable the motion sensor.
      default:
      selector:
        entity:
          domain:
            - input_boolean
            - binary_sensor
    motion_sensor:
      name: Motion Sensor.
      description: The sensor used to trigger the automation.
      selector:
        entity: {}
    target_on_entity:
      name: Target On Entity
      description: Light, group, switch, script, or scene to turn on when 
        motion is detected.
      selector:
        entity: {}
    special_on_entity:
      name: Special On Entity
      description: Light, group, switch, script, or scene to turn on when 
        motion is detected on special days.
      selector:
        entity: {}
    brightness_pct:
      name: Brightness Percentage.
      description: Set the brightness percentage for the turn on entity if greater than zero.
      default: 0
      selector:
        number:
          min: 0
          max: 100
          unit_of_measurement: "%"
    illuminance_threshold:
      name: (OPTIONAL) Illuminance Threshold.
      description: Helper entity (binary_sensor) for the illumination level
        below which the automation will proceed. Leaving this blank prevents 
        any illumination test being performed.
      default:
      selector:
        entity:
          domain: binary_sensor
    block_on_entity:
      name: (OPTIONAL) Block On Entity.
      description: If this entity is 'on' then it will stop the automation 
        running. Leaving this blank means no check will be made.
      default:
      selector:
        entity: {}
    timer_entity:
      name: (OPTIONAL) Active Timer.
      description: Helper entity (input_boolean) limiting the automation
        to only run when this timer is active.
      default:
      selector:
        entity:
          domain: binary_sensor
    wait_time:
      name: (OPTIONAL) Wait Time.
      description: Helper entity (input_number) specifiying how many
        minutes to wait before starting the turn off actions. Leaving it
        blank means stop before turning off.
      default:
      selector:
        entity:
          domain: input_number
    block_off_entity:
      name: (OPTIONAL) Block Off Entity.
      description: If this entity is 'on' then it will stop the automation
        running the turn off actions. Leaving it blank means no check will
        be made.
      default:
      selector:
        entity: {}
    target_off_entity:
      name: (OPTIONAL) Target Off Entity.
      description: The actual entity to turn off. If blank the Target
        On Entity will be turned off.  Must be provided if the Target On
        Entity is a scene or a script (which can't be 'turned off').
      default:
      selector:
        entity: {}
mode: restart
max_exceeded: silent
variables:
  motion_sensor_disabled: !input 'motion_sensor_disabled'
  motion_sensor: !input 'motion_sensor'
  target_on_entity: !input 'target_on_entity'
  special_on_entity: !input 'special_on_entity'
  brightness_pct: !input 'brightness_pct'
  illuminance_threshold: !input 'illuminance_threshold'
  block_on_entity: !input 'block_on_entity'
  timer_entity: !input 'timer_entity'
  wait_time: !input 'wait_time'
  block_off_entity: !input 'block_off_entity'
  target_off_entity: !input 'target_off_entity'
trigger:
  platform: state
  entity_id: !input 'motion_sensor'
  to: 'on'
condition:
- condition: template
  value_template: "{{ motion_sensor_disabled == none or 
    states[motion_sensor_disabled].state == 'off' }}"
- condition: template
  value_template: "{{ block_on_entity == none or 
    states[block_on_entity].state == 'off' }}"
- condition: template
  value_template: "
    {% if target_off_entity != none %}
       {% set test_entity = target_off_entity %}
    {% else %}
       {% set test_entity = target_on_entity %}
    {% endif %}
    {{ states[test_entity].state == 'on' or
       ((illuminance_threshold == none or
         states[illuminance_threshold].state == 'on') and
        (timer_entity == none or
         states[timer_entity].state == 'on')) }}
    "
action:
- choose:
  - conditions:
    - condition: template
      value_template: "{{ states['input_boolean.special_day'].state == 'on' and
        special_on_entity != none }}"
    sequence:
    - service: homeassistant.turn_on
      entity_id: !input 'special_on_entity'
  default:
    - choose:
      - conditions:
        - condition: template
          value_template: "{{ brightness_pct != 0 }}"
        sequence:
        - service: homeassistant.turn_on
          entity_id: !input 'target_on_entity'
          data:
            brightness_pct: !input 'brightness_pct'
      default:
        - service: homeassistant.turn_on
          entity_id: !input 'target_on_entity'
- condition: template
  value_template: "{{ wait_time != none }}"
- wait_for_trigger:
    platform: state
    entity_id: !input 'motion_sensor'
    from: 'on'
    to: 'off'
- delay:
    minutes: "{{ states[wait_time].state | int(0) }}"
- condition: template
  value_template: "{{ block_off_entity == none or 
    states[block_off_entity].state == 'off' }}"
- choose:
  - conditions:
    - condition: template
      value_template: "{{ target_off_entity != none }}"
    sequence:
    - service: homeassistant.turn_off
      entity_id: !input 'target_off_entity'
  default:
  - service: homesasistant.turn_off
    entity_id: !input 'target_on_entity'

Then an example automation based on that Blueprint like this:

  alias: Lounge Special Motion Lights
  description: Lounge motion lights with special scene selection
  use_blueprint:
    path: phil/special_motion_trigger.yaml
    input:
      motion_sensor_disabled: binary_sensor.lounge_entertainment_areas_active
      motion_sensor: binary_sensor.lounge_sensor_motion
      target_on_entity: scene.lounge_motion_triggered
      special_on_entity: script.special_motion_lounge
      illuminance_threshold: binary_sensor.lounge_illumination_threshold
      block_on_entity: light.mll1
      wait_time: input_number.lounge_turn_off_delay
      block_off_entity: light.mll1
      target_off_entity: light.lounge

Nice side effect of doing this was as the random colours get spread across the room lights, they change every time the motion script is triggered again - which works out really well :slight_smile:

5 Likes