Smart Home Without a Phone

Published on Tue, 16 April, 2019 | 1300 words
Tags: raspberry pi xmpp python hardware errbot

One of my biggest gripes with many home automation systems is the reliance on some kind of app or website in order to control the system in question. When I’m at home and I want to turn the light on, I just want to hit a switch on the wall. This is one of the reasons I picked Philips Hue for my lights, as Philips actually market a soft switch. Unfortunately it’s US dimensions and doesn’t match my UK-standard light switches, but at least they tried. Quite a lot of other systems I’ve seen require you to unlock your phone and open an app in order to turn the light on or off, which is crazy. But it seems to be the norm these days - I’ve got a Garmin smart watch which, unlike my Pebble, doesn’t let you set an alarm from the device itself, it requires you to use the app which you have to install on your phone in advance. Yes, it’s a supposedly “smart” watch that lacks the basic functionality of a watch.

I’m just as guilty - most of my home-made home automation tech is based around Python code. One day a few months ago, my better half was working from home and called me to ask how to turn the heating on. There’s no motion sensor in our dining room, where she was, so the ‘intelligent’ heating manager I’d written thought the house was empty, and had turned the heating off. I had no simple answer to her question, as the way I’d do it is to SSH into the Raspberry Pi that controls the heating and tweak the configuration file - hardly user-friendly. It was this incident that inspired my latest home automation project.

Our kitchen and dining room are the same room, split by a room divider. This divider is basically a row of cupboards with a worktop, and it has a convenient row of power sockets at the top. The socket at the far left is not for power, but a standard UK telephone socket. We don’t actually have a landline, we use our mobiles for phoning people and we get our internet over a dedicated DSL. In fact, the actual incoming phone cable to the house was sheared completely off - presumably by the previous owner, or someone who didn’t like him very much - when we moved in, so even if we did want a phone line, we’d have to get a brand new one installed. Consequently, all the phone sockets in the house are useless and I’ve replaced them with ethernet (RJ45) sockets over time, all except for this one on the divider, which is still a phone socket that’s not connected to anything. I can’t reasonably connect it to the network due to its location, but it does have access to power through the back of the divider.

So the clever thing to do is obviously turn it into some kind of push-button control panel.

Front view Top view

I’d planned to simply replace the socket with a 1-gang blanking plate in order to make it a bit prettier (if completely non-functional), so I’d already purchased the blanking plate. I’d also already purchased a variety of coloured push-buttons for another project. So when I realised that a Raspberry Pi Zero fits snugly into a 1-gang back box with plenty of room to spare, I figured that this would be an excellent use for the redundant phone socket, and I could turn it into a button panel.

I drilled holes in the blanking plate and screwed three buttons into place before soldering a single common wire to one terminal of each. On the other terminal, I soldered a resistor (one per button) and another trailing wire, giving four wires. Meanwhile I soldered four wires to a Raspberry Pi Zero W, one to the 3.3V pin and the other three to three of the GPIO pins (11, 12 and 13 in my case, but you can use any).

I then put Raspbian onto a micro SD card, and booted the Pi. Once I was happy it was SSH-able and could run headless, I plugged it into power, which I’d dragged up from behind the back box in the kitchen, and joined the dangling ends of the three resistors to the three GPIO wires, and the common wire from the buttons to the 3.3V wire on the Pi, before screwing the blanking plate onto the back box.

Finished!

At this point I could have made the buttons do pretty much anything. If you’ve been following this blog for a while you’ll remember my ongoing project to make all my home automation communicate via an XMPP chat room. So of course this being no different, I installed Errbot on the Pi and began a new plugin.

from errbot import BotPlugin, botcmd, arg_botcmd, webhook
import RPi.GPIO as gpio, datetime, time

class Kitchen(BotPlugin):
    """
    Kitchen button panel
    """

    def activate(self):
 
        self.lastcall = float(datetime.datetime.utcnow().strftime("%s"))

        gpio.setwarnings(False)
        gpio.setmode(gpio.BOARD)
        gpio.setup(11, gpio.IN, pull_up_down=gpio.PUD_DOWN)
        gpio.setup(12, gpio.IN, pull_up_down=gpio.PUD_DOWN)
        gpio.setup(13, gpio.IN, pull_up_down=gpio.PUD_DOWN)

        gpio.add_event_detect(11, gpio.RISING, callback=self.button_callback, bouncetime=300)
        gpio.add_event_detect(12, gpio.RISING, callback=self.button_callback, bouncetime=300)
        gpio.add_event_detect(13, gpio.RISING, callback=self.button_callback, bouncetime=300)

        super(Kitchen, self).activate()

    def deactivate(self):
 
        gpio.cleanup()

        super(Kitchen, self).deactivate()

    def button_callback(self, channel):
 
        muc = "homeaut@trypticon"
        message = "//EVENT button/kitchen " + str(channel)
        time.sleep(.01)
        if gpio.input(channel):
            delay = float(datetime.datetime.utcnow().strftime("%s")) - 	self.lastcall
            self.lastcall = float(datetime.datetime.utcnow().strftime("%s"))
            if(delay >= 1.5):
                self.send(self.build_identifier(muc), message)

You’ll notice a lot of oddness involving timing. There is a good reason. Firstly, mechanical switches are never just plain on/off, the reality is that one actual button press will generally trigger several on/offs in rapid succession because: physics. This is offset by firstly the bouncetime value, but also the lastcall value which ignores any button presses that happen within 1.5 seconds of a previous button press. The second problem is the phantom keypress problem which I ran into - occasionally I’d get a random keypress registered from one or more of the buttons. This is what the sleep(.01) bit overcomes, once a button press is detected, it sleeps for 0.01 seconds and then checks the value of the switch again. If it’s still pressed, only then will it actually send a message saying that a button was pressed. This might not be important to you, depending on what you want the buttons to do, but in my case pressing the button actually costs me money by turning the heating on, so I didn’t want it to just happen randomly. homeaut@trypticon is the ID of the bot chatroom on my network.

So once that had all been done, I’ve now got a button panel in my kitchen which sends an event message to my home automation chatroom whenever one of the buttons is pressed. All I had to do then was write another plugin for the home automation bot which acts on these messages. This is done by overriding Errbot’s callback_message function. I have one button that turns the heating on for an hour, one that does the same for the hot water, and just for good measure one that turns off the light in the hallway and schedules it to come back on at sundown. But the way I’ve implemented it means that I should never have to touch the Pi within the button panel again, all the actual actions based on the button presses are handled by the other XMPP bots.