Automations, timers, and you

For a while now, I’ve been automating my apartment using the automations component of Home Assistant. In fact, I had amassed quite the collection of automations and was starting to have a problem keeping track of them all and their various interactions (intentional or otherwise). So earlier this year when Home Assistant introduced automation debugging I decided to sit down and refactor the whole thing.

At first, I considered deploying and using MQTT which, it seems, a lot of Home Assistant users do. However, I wasn’t overly excited at running another container or at learning Yet Another Thing. Likewise, I considered Node-RED and discarded it too. I’m probably making things harder for myself by sticking to editing YAML in Vim but I knew my needs weren’t overly complicated and by sticking to ’the basics’ I knew it would force me to stop being overly-clever and make something that Just Works™. So I sat down with the new debugging tool, wrote out all of my ‘what do i want automated’ needs, and pored back over the automation documentation.

And that’s when I realized that a timer was the component I’d been overlooking all this time. Timers, it turns out, can be used very much in an MQTT-lite fashion. You see, you can have one or more routines triggered by the same timer; in fact, some set of routines can listen for timer (re)start and another set can listen for timer finish/idle. Mix-n-match these up and you can make some very interesting actions happen. And it means my automations each generally do one thing and only one thing (KISS) which, in turn, means they are less likely to fail and easier to debug when they do. I was stoked! I was also annoyed at not having paid any attention to timers from the get-go, but what are you gonna do?

My first task was thinking about what timers I’d need. I knew right away I’d want a timer.away for when I leave home:

timer:
  away:
    duration: 00:05:00

But what other timers do I need? I quickly realized that I need a timer for almost every switch I have defined in Home Assistant. I could get away with fewer, but I allowed myself a little bit of cleverness and created one for each switch with the name of the timer being the name of the switch it controls. So, for example, I have a TP Link Kasa smart switch controlling my hallway light called switch.hallway_light. So I created a matching timer called timer.switch_hallway_light. This allows me to to write a simple automation like this:

- alias: Trigger - Start light switch trigger
  id: '1625266493'
  description: 'When a light turns on, start its corresponding power off trigger'
  trigger:
    - platform: state
      entity_id: switch.bar_light
      to: 'on'
    - platform: state
      entity_id: switch.closet_light
      to: 'on'
    - platform: state
      entity_id: switch.dining_room_light
      to: 'on'
    - platform: state
      entity_id: switch.entryway_light
      to: 'on'
    - platform: state
      entity_id: switch.hallway_light
      to: 'on'
  condition: []
  action:
     - service: timer.start
       data:
         duration: '0:10:00'
       target:
         entity_id: "timer.{{ trigger.entity_id.split('.')|join('_') }}"

What this does is exactly what it says in the description. Whenever one of the lights in the trigger section turns on, it starts the corresponding timer. The magic is in the very last line of the automation:

entity_id: "timer.\{\{ trigger.entity_id.split('.')|join('_') \}\}"

What we’re doing here it taking the entity id that fired the automation (e.g. what switch did we turn on) from the trigger.entity_id value then we swap out the . for a _ which gives us the name of our timer. So here we have one automation, that does one very simple thing which makes it kinda hard to break this automation.

So we’ve turned on the hallway light, and started our timer. What happens when the timer runs out? Well, we have an automation that is triggered by that:

- alias: Trigger - Kill the lights
  id: '1625267293'
  description: 'When a timer runs out, kill its corresponding light'
  trigger:
    - platform: event
      event_type: timer.finished
      event_data:
        entity_id: timer.switch_bar_light
    - platform: event
      event_type: timer.finished
      event_data:
        entity_id: timer.switch_closet_light
    - platform: event
      event_type: timer.finished
      event_data:
        entity_id: timer.switch_dining_room_light
    - platform: event
      event_type: timer.finished
      event_data:
        entity_id: timer.switch_entryway_light
    - platform: event
      event_type: timer.finished
      event_data:
        entity_id: timer.switch_hallway_light
  condition: []
  action:
  - service: homeassistant.turn_off
    target:
      entity_id: "switch.\{\{ trigger.event.data.entity_id.split('_')[1:4]|join('_') \}\}"

As you can see, it’s basically the opposite of the previous automation. We list which timers we care about, and when they finish, we munge the timer name a bit to get the switch’s name and then we turn that switch off. Simplicity.

Hopefully, you can see the utility of timers in Home Assistant. This is just a very basic example of how I use them, but I think it illustrates their user pretty well. I still have just over 50 automations, but that’s way down from what I had, and the automations themselves are now way simpler. Overall, I consider this a win.

Happy hacking!