June 21, 2021

Home automation adventures

For the past six weeks or so I've been playing around with home automation. It's a rather large and complex subject and I've only just started, but thought it might be worth writing up what I've found so far.

The adventure started when the kids gave me a new Raspberry Pi for my birthday near the beginning of May. I installed Home Assistant on it and, a bit later, Node Red. Then, over the next few weeks, much to my wife's dismay, I purchased 10 smart light bulbs, a few motion sensors and half a dozen smart plugs -- gradually changing the house into a version of HAL. Each time she would come home from work, some wall switch or another would stop working as it did... She's been very patient!

Home Assistant

The first piece of this, and the cornerstone, is Home Assistant. It is a very active open source project, compatible with (at the time of writing) more than 1,800 devices. Using "integrations", Home Assistant allows you to tie together incompatible products, from manufacturers who all want to be your sole home automation provider. Rather than going all Apple, or all Google, or all Amazon/Alexa, or having six different apps on your phone, you can you use the best bits and pieces from several different ecosystems. You want to trigger music on two different brands of Wifi speaker, turn on a smart switch in one room when a bulb toggles in another, or tell a Google Home speaker to activate an Apple device? All of this and more are possible.

And it's not just devices -- I can also tie together APIs, such as Google's Text-to-Speech or The Met Office's weather API.

Can you do this easily? Well... It's not too bad, but expect a learning curve. Freedom comes at a cost.

To install Home Assistant on the Pi, I used the docker container installation option. This installs the core of the software in a container, but you miss out on some one-click integration with add-ons. You can still use add-ons, but you have to install them manually, using some docker tricks. This wasn't an issue for me, since one of my motivations was to learn those docker tricks. Other options include installing a Home Assistant Operating System or even buying a fully configured box.

The software exposes a web dashboard, which you can configure with various buttons and switches, to run your house.

To help fund the open source project, there is also a mobile app, letting you connect to that local dashboard to control Home Assistant while you are out of the house. It's very optional, but I found it useful enough to subscribe (£5 a month).

Automations

You can get quite far with just the Home Assistant software, turning on and off lights and switches using various events and inputs. These so-called automations are put together using a visual editor and stored using YAML. For example, I bought a starter set for Philips Hue and configured the lights to turn on when the sun is setting. (To be clear, you can do this with the Philips Hue app, but I don't want several different apps to control my house.)

The wizard-like visual editor steps you though creating a response to some event. The ultimate outcome is a piece of YAML, looking like this, but many users could probably avoid ever seeing the YAML:

YAML to turn on a couple of lights when the sun is less than 10% from the horizon

As a software engineer, I think that's pretty readable and would often drop down into Home Assistant's built-in YAML editor to write this stuff directly. You can get more complicated, with nested OR and AND conditions. However, at some point, YAML starts to get hard to read and maintain, or the wizard interface just hasn't thought of some wrinkle that you need. At that point, I turned to Node Red.

Node Red

Node Red and Home Assistant are a popular combination. The two together let you write more complex automations, called flows. The flows are assembled using widgets from a palette, connected with lines indicating sequences and branches, in a visual way.

But underneath it all, it's just NodeJS. The widgets come from NPM packages, one of which lets you write flows that can be triggered from Home Assistant buttons, or respond to its events. It also gives me the ability to drop down to writing code, or write my own widgets, making it nearly infinitely extensible.

Here's an example: My simple sunset routine (above) worked pretty well, but it has some compromises. I had set the trigger elevation a bit higher than it needs to be (the sun sets behind our neighbouring houses at an elevation of about 5 percent) because it gets very dark in the house on cloudy days well before that trigger point. So, instead, I use a flow that can trigger on any one of several events -- the (location-adjusted) sun level or the level of light in various rooms, using sensors to measure lights levels.

This is what the flow looks like in Node Red:

A Node Red flow to turn lights on when one of several conditions are true.

Docker Compose

Both Home Assistant and Node Red run on my Raspberry Pi in docker containers. I bring them both up using a single docker-compose.yml file. This ensures that they are started/restarted/stopped/etc. together and can communicate with each other. Here is my current docker-compose configuration:

version: '3'
services:
  homeassistant:
    container_name: homeassistant
    image: homeassistant/raspberrypi4-homeassistant:stable
    volumes:
      - /home/eamonn/home_assistant:/config
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped
    network_mode: host
  nodered:
    container_name: nodered
    image: nodered/node-red
    ports:
      - "1880:1880"
    volumes:
      # Local path where all Node-RED config will be stored.
      - /home/eamonn/home-node-red:/data
    depends_on:
      - homeassistant
    environment:
      TZ: "Europe/London"
    restart: unless-stopped

The /config (for Home Assistant) and /data (for Node Red) point to local directories on the Pi, both of which are backed up to repositories in Github. I can rollback my configuration and flows to a known good state if I do something drastically wrong.

The restart setting (unless-stopped) ensures that the two of them restart when the Pi is rebooted.

Lights

The first thing I tackled was the lights. As mentioned, I started with a Philips Hue hub and two bulbs, but the Philips bulbs are really expensive. They work great, and look good, but I can't afford to light my whole house with these things.

Fortunately, the Philips Hue is based mostly on a standard protocol and I was able to buy eight more from several different (mostly Chinese) manufacturers for less than half the price. I was able to integrate those into the Philips Hue hub, usually with a click or two in the Philips app. Here's one example of a compatible Chinese-manufactured bulb.

The knock-offs lack one important feature -- the ability to configure what happens when the power goes off and then back on again (like, when the better half tries to turn the wall switch off and on). I guess this isn't part of the standard. This is a useful feature, but not worth the extra money. I just put the Philips ones where the switch-on behaviour is most desirable.

The bulbs, even the Philips ones, come in several flavours, only some of which support changing colours. I mostly don't use the colours and just need control over the "temperature" and brightness. I do have a couple of colour-capable bulbs, which are mostly useful for just showing off.

Smart plugs

A smart wall plug.

The next bit was to integrate some smart wall plugs. Our sun room (an extension to the back of the house) has no wall switch -- just an overhead light, connected to a mains plug high on one wall, and a floor lamp with four bulbs in the corner. For years, we used a pool cue to turn on the power for the main ceiling light and then had to turn on the lamp's four bulbs. Every. Time. I wanted to be able to turn on and off the overhead light and the floor lamp at the same time, as if connected to the same switch.

I put a smart bulb in the overhead light, leaving the power on, and then used Node Red to respond to a "turn on" or "turn off" event on this bulb and automatically toggle the floor lamp, which I connected to a smart plug. These are two entirely different products, with different APIs and protocols, but Home Assistant and Node Red are able to hide this complexity.

Turn on/off floor lamp when a bulb toggles.

Another good use of the smart switches was to control the clothes dryer. Our ageing dryer has a dodgy timer, but otherwise works fine. The timer would, very occasionally, fail to turn off the dryer, which is a dangerous fire hazard. What we've been doing is to put the clothes in and set a timer on our phones. When the alarm goes off, we'd have to go outside to the shed to check that the dryer stopped.

So, what I did was plug the dryer into one of the smart plugs, create a button in Home Assistant, tied to a flow in Node Red, that ensures the power shuts off again after an hour.

Button to run dryer for an hour

Dryer plug Node Red flow

Notice that last bit about "announcing" when the dryer is finished -- that's just a little showing off. I use a Home Assistant integration to connect to two speakers in the house, then use Google Text-to-Speech to tell us when the clothes are dry... Yes, completely unnecessary, but still fun.

I found these plugs work well, using the Tuya integration in Home Assistant.

Motion, time and presence

Another piece of the puzzle was to turn lights and power on and off in response to events. For example, I want the hallway lights to turn on when my wife comes home from a late shift. I want the bathroom light to turn on when we enter, but to control the brightness depending on the time of day (e.g., very dimly in the middle of the night). And I wanted to turn the power off to certain appliances overnight, such as the laptop chargers.

For this, I've tried a couple of different approaches. One was to listen for when our phones connect to the home Wifi. This is good enough to turn the lights off if neither of us are home, but it's slow to react and not good enough to, say, trigger the lights when we enter.

For that, I needed motion sensors. I've tried two so far. One is the Shelly Motion. This uses a rechargeable battery and connects to your Wifi directly. It also exposes other sensors -- the light and battery level and "tampering" (i.e., shaking the device). I don't really need the tampering and I only get a light-level event when motion is detected. I'm not that happy with it -- it was expensive, a bit fiddly to set up and the events I get from it are intermittent sometimes.

The second I tried is the Philips Hue motion sensor, which despite being the "brand-name" product was actually cheaper and connected to the Hue hub instead of directly to Wifi. The batteries (two AAAs) aren't rechargeable, but reportedly work for at least a year (and up to two). In addition to motion, these expose light levels (like the Shelly), but also temperature. That's much more useful than the tampering sensor and means I might be able to hook these up to the heat (or a fan or two) later.

By strategically placing these around the house, and checking the time of day, I can create some sophisticated flows that intelligently turn on lights (at the appropriate brightness level) and turn them off again when no motion is detected for a while.

Motion sensor flow

Music

The music integration was another response to a household frustration (like the broken dryer switch and pool cue light). Several years ago, I bought a couple of Bose SoundTouch speakers. They sound great and I can play the same music, synchronised, though both of them. But the software to control them is truly awful.

With Home Assistant, and the Bose SoundTouch integration, I can just create a couple of buttons that do exactly what I want without having to go anywhere near Bose's software.

Buttons in Home Assistant to control music

Scenes and routines

Another very nice feature of Home Assistant are "scenes", where you can set light levels and toggle smart plugs in several rooms to pre-set levels. For example, we have a "watching TV" scene that turns off several lights, and then dims others.

But you can't run scripts from Home Assistant scenes. This is where Node Red comes in. We have an empty (does nothing) scene in Home Assistant called "Good night". Node Red is configured to listen to the "scene activation" event from Home Assistant and do various things, such as shut off most lights, turn the TV off, turn on the bathroom lights, etc. Then, dim the lights in stages until they shutoff altogether in 15 minutes.

Bedtime flow in Node Red

The pink boxes in this flow are examples of calling saved, reusable routines. It's an easy way to reduce the complexity of flows, the same way you'd write your own modules or functions in node.

Tying it all together

At the end of the day, however, it's hard to beat the simplicity of a light switch. Finding your phone or navigating to a web page to turn on the dryer or the lights isn't very convenient. To address that aspect, I got (yet another) Raspberry Pi, and a compatible touch screen, to create something that hopefully bridges some of that gap.

A touchscreen showing Home Assistants dashboard

It's been a fun adventure, and I'll probably continue building it out for a while.

Tags: home-automation