Smart Home Automations

Posted Jun 11, 2022

A few years ago, I bought a Philips Hue starter kit on a whim. Since then, I have replaced all my lightbulbs with Hues and have been getting into the whole smart home thing. Many people see smart home tech as a gimmick, and I don’t blame them: most people who dip their toes into this space buy a Google Home and a couple of smart bulbs, and then leave it at that. You can now ask Google to turn the lights on, and it only takes twice as long as flipping the lightswitch. Truly the home of the future. No, the real value of connected devices is the ability to integrate them and automate everyday things and have fewer first world problems to deal with. That’s where Home Assistant shines – it integrates with almost anything. Here are a couple of things I do with my setup.

Lights on for multiple people

Like everyone with smart lights, I have an automation that turns on the light when I come home after dark. Where most automations fail in this area is dealing with more than one person in the home.

My old apartment was fitted with Hue bulbs in every socket, and I had a standard Hue app automation that turned on all the lights when my phone was close to home. One evening, my girlfriend was staying at my place and had gone to bed while I was out. When I arrived a hundred meters from my place, the automation helpfully turned on all the lights and jolted her awake. Imagine being alone and half-asleep when all your lights come on for no apparent reason. That would certainly make me uneasy.

I didn’t want to repeat that, so in Home Assistant, I have an automation that only turns on the lights if no one is already at home. This feature has since been added to the Hue app, but I automate more than just lights: my Netatmo radiator valves also lowers their target temperature when everyone leaves. Also, the lights only come on if it’s actually dark out.

In previous versions of Home Assistant, detecting if someone was already home was a bit convoluted. You’d have to create person groups in YAML and rely on a quirk where the trigger of the automation detected a state change before a condition would reflect it, but in version 2022.4, it’s as simple as triggering on a zone state change from 0 to 1 and vice versa.

  - platform: state
    entity_id: zone.home
    from: "0"
    to: "1"
  - condition: or
      - condition: sun
        before: sunrise
      - condition: sun
        after: sunset

Electricity price monitor

A few months ago, I made a forecast graph of the hour-by-hour electricity price with data pulled from Nord Pool, which lets me schedule power-hungry tasks for when it’s cheaper. Now I’m considering ways to collect long-term usage stats to see if we’re actually getting anything out of it. The other day I showed the graph to my friends, who were… well, let’s just say they weren’t as excited about it as me. This weird fascination is something I must have inherited from my dad; he had a habit of tracking this kind of stuff in excruciating detail. I used to think it was pretty lame, but after he passed away last year, I take comfort in the fact that I inherited some of his lameness.

Electricity price graph

In Home Assistant, I have embedded the graph on a dashboard running on an ancient 7 inch tablet that sits in my closet. The thing is actually so old it can’t run the Home Assistant app, but it can open the web interface in Chrome, which is good enough. The graph I use is hosted here, and the source code is available on GitHub. Note that it’s currently hardcoded to pull prices for the DK2 region (eastern Denmark).

Ancient tablet with Home Assistant Dashboard

E-bike battery charging

I have been riding bikes my whole life and I enjoy it. My last few jobs have given me a longer commute than I’m willing to make on a normal bike, so I have one with an electric motor. I use it daily for work, but the battery can only do one roundtrip on a single charge. Previously, I would charge it as soon as I got home, but as long as it’s ready in the morning, I don’t care when. Since power is usually cheaper at night, I’ve set up an automation that turns on the charger with a Shelly smart plug at 1 AM, and turns it off again when it’s done. On my tablet dashboard, it looks like this:

Battery charging automation entities

The automation depends on a software toggle, as I don’t usually use the bike on weekends or when it’s raining. To avoid turning on the charger for no reason, the automation itself turns off the toggle after it’s done. At first, I had set it up so I had to manually enable it every day when I got home. One day I forgot to do that, and I was met with no juice the next morning. Something had to be done.

Ideally, the system would detect if my bike had left (and later returned) and flip the toggle. I had already duct taped an AirTag to it (very stylish), but AirTags can’t yet be tracked by Home Assistant. As an alternative, I set up a passive zone at a point on my commute that I don’t otherwise visit, and flip the toggle if my phone enters it. That means that when I’m biking to work, the charger is automatically primed for charging, but if I take the train or work from home, the charger stays off. Some days, I bike to work, take the train home, and only bring the bike home the day after. To account for that, the zone only triggers in the afternoon.

Passive zone on a map

The “optimal charging start time” entity in the screenshot is an additional automation I’m working on that will eventually plan the best charging time by itself. It works like this:

  1. Get the electricity price forecast
  2. Find the cheapest 4 hour timespan that ends before 6 AM (when I usually wake up)
  3. Schedule the battery charger automation to run at that time

I’m just testing it out for now, which is why it’s just shown on the dashboard. The logic is exposed as a serverless function with my graph and Home Assistant polls it like this:

  - scan_interval: 3600 # 1 hour
    resource: ""
      hours: 4
      maxEndTime: >
        {{ (today_at("06:00") if now() < today_at("02:00") else today_at("06:00") + timedelta(days=1)).isoformat() }}
      - name: "Optimal charging start time"
        value_template: "{{ as_local(as_datetime(value_json.startTime)).time() }}"