Automatic Light Out

In my home I use YoLink switches for (smart) lights. While you can do a lot of control from their app, sooner or later you’ll end up with Home Assistant for automations.

In my case, I wanted a simple 2 minute timer every time my light switch gets pressed. Since each switch has additional 2 buttons, I wanted to use them to extend light-on state to 30 and 60 minutes. And most importantly, light automation should survive Home Assistant restart. Yes, one can probably just check lights manually after a restart, but I promise one won’t. So, it’s best to make restart survivable.

For lights on, rules are easy. YoLink switch is smart enough to turn on the list itself. So our only action is to start the timer.

triggers:
  - trigger: light.turned_on
    id: light_on
    target:
      entity_id: light.stairwell_light

actions:
  - choose:
      - conditions:
          - condition: trigger
            id: light_on
          - condition: state
            entity_id: timer.stairwell_light_off
            state: idle
        sequence:
          - action: timer.start
            target:
              entity_id: timer.stairwell_light_off
            data:
              duration: '00:02:00'

And what do we do when timer is reached? Well, we turn the light off.

triggers:
  - trigger: event
    id: timer_finished
    event_type: timer.finished
    event_data:
      entity_id: timer.stairwell_light_off

actions:
  - choose:
      - conditions:
          - condition: trigger
            id: timer_finished
        sequence:
          - action: light.turn_off
            target:
              entity_id: light.stairwell_light

These two cover 95% of what I needed. But we haven’t dealt with buttons yet. And with YoLink, that is a special task since they are not directly exposed. But they are exposed as events you can catch in Tools,Events menu, if you listen to yolink_event. With IDs in place, we can now adjust light-off timer to 30 or 60 minutes. In my case, due to 3-way switch setup, I had to capture 4 events.

triggers:
  - trigger: event
    id: button_1a
    event_type: yolink_event
    event_data:
      device_id: 8ff8e36d5d21125a07c9cb322f7d6be8
      type: button_1_short_press
  - trigger: event
    id: button_2a
    event_type: yolink_event
    event_data:
      device_id: 8ff8e36d5d21125a07c9cb322f7d6be8
      type: button_2_short_press
  - trigger: event
    id: button_1b
    event_type: yolink_event
    event_data:
      device_id: 87af18c6d107df22aaeb28b09f24b40d
      type: button_1_short_press
  - trigger: event
    id: button_1a
    event_type: yolink_event
    event_data:
      device_id: 87af18c6d107df22aaeb28b09f24b40d
      type: button_2_short_press

actions:
  - choose:
      - conditions:
          - condition: or
            conditions:
              - condition: trigger
                id: button_1a
              - condition: trigger
                id: button_1b
        sequence:
          - action: timer.start
            target:
              entity_id: timer.stairwell_light_off
            data:
              duration: '00:30:00'
          - action: light.turn_on
            target:
              entity_id: light.stairwell_light
      - conditions:
          - condition: or
            conditions:
              - condition: trigger
                id: button_2a
              - condition: trigger
                id: button_2b
        sequence:
          - action: timer.start
            target:
              entity_id: timer.stairwell_light_off
            data:
              duration: '01:00:00'
          - action: light.turn_on
            target:
              entity_id: light.stairwell_light

And now finally we’re onto the last condition - surviving HA restart. In theory, it should be as simple as just turning any light with expired timer off. But, in reality, that won’t work with YoLink switches because it takes a bit of time to establish communication with them. You also cannot check if light is on because light status is also a part that needs YoLink communication. So, the best you can do is to blindly turn on timer if one is not already on. If light is on, it will turn it off in 2 minutes. If light is off, we’ll turn it off again - not really an issue.

triggers:
  - trigger: homeassistant
    id: ha_start
    event: start

actions:
  - choose:
      - conditions:
          - condition: trigger
            id: ha_start
          - condition: timer.is_idle
            target:
              entity_id: timer.stairwell_light_off
        sequence:
          - action: timer.start
            target:
              entity_id: timer.stairwell_light_off
            data:
              duration:
                hours: 0
                minutes: 2
                seconds: 0

And only with all these is place we have our automation ready for the real life.

My full automation is below, adjust as needed.

alias: Stairwell Light
triggers:
  - trigger: homeassistant
    id: ha_start
    event: start
  - trigger: light.turned_on
    id: light_on
    target:
      entity_id: light.stairwell_light
  - trigger: light.turned_off
    id: light_off
    target:
      entity_id: light.stairwell_light
  - trigger: event
    id: button_1a
    event_type: yolink_event
    event_data:
      device_id: 8ff8e36d5d21125a07c9cb322f7d6be8
      type: button_1_short_press
  - trigger: event
    id: button_2a
    event_type: yolink_event
    event_data:
      device_id: 8ff8e36d5d21125a07c9cb322f7d6be8
      type: button_2_short_press
  - trigger: event
    id: button_1b
    event_type: yolink_event
    event_data:
      device_id: 87af18c6d107df22aaeb28b09f24b40d
      type: button_1_short_press
  - trigger: event
    id: button_1a
    event_type: yolink_event
    event_data:
      device_id: 87af18c6d107df22aaeb28b09f24b40d
      type: button_2_short_press
  - trigger: event
    id: timer_finished
    event_type: timer.finished
    event_data:
      entity_id: timer.stairwell_light_off
conditions: []
actions:
  - choose:
      - conditions:
          - condition: trigger
            id: ha_start
          - condition: timer.is_idle
            target:
              entity_id: timer.stairwell_light_off
        sequence:
          - action: timer.start
            target:
              entity_id: timer.stairwell_light_off
            data:
              duration:
                hours: 0
                minutes: 2
                seconds: 0
      - conditions:
          - condition: trigger
            id: light_on
          - condition: state
            entity_id: timer.stairwell_light_off
            state: idle
        sequence:
          - action: timer.start
            target:
              entity_id: timer.stairwell_light_off
            data:
              duration: '00:02:00'
      - conditions:
          - condition: trigger
            id: light_off
        sequence:
          - action: timer.cancel
            target:
              entity_id: timer.stairwell_light_off
      - conditions:
          - condition: or
            conditions:
              - condition: trigger
                id: button_1a
              - condition: trigger
                id: button_1b
        sequence:
          - action: timer.start
            target:
              entity_id: timer.stairwell_light_off
            data:
              duration: '00:30:00'
          - action: light.turn_on
            target:
              entity_id: light.stairwell_light
      - conditions:
          - condition: or
            conditions:
              - condition: trigger
                id: button_2a
              - condition: trigger
                id: button_2b
        sequence:
          - action: timer.start
            target:
              entity_id: timer.stairwell_light_off
            data:
              duration: '01:00:00'
          - action: light.turn_on
            target:
              entity_id: light.stairwell_light
      - conditions:
          - condition: trigger
            id: timer_finished
        sequence:
          - action: light.turn_off
            target:
              entity_id: light.stairwell_light
mode: queued