Smarter-Than-It-Seems Doorbell

Published on Sun, 19 July, 2020 | 1400 words
Tags: hardware raspberry pi doorbell mqtt python home assistant self-hosted

I have mid-range hearing loss in my left ear. While this has actually increased my sensitivity to extremely high or low frequency sounds that many don’t notice, more common things are inaudible to me unless I am wearing a hearing aid, and even then I have difficulty with sounds coming from far away, and sounds mixed with other sounds of similar frequency. As the office, the room of my house in which I spend most of my awake time - particularly while working from home during a global pandemic - is so far away from the front door, this means I have trouble hearing the doorbell.

Now yes, I could get a different bell chime. Something that makes a horrible siren noise that can be heard by anything that isn’t stone deaf. Or I could get one of the more modern electronic doorbells that are wireless, or have proprietary apps and cloud services. But I, like many people I know, get a bit wary these days when going near a doorbell that looks remotely technical, in case it’s sending my photo to some server farm in the Ukraine. Also, I like my doorbell! It’s a proper old-style electromechanical affair. As one pizza delivery driver once commented to me, “it’s got a really satisfying ‘dong’ noise”. So my only option, really, was to retro-fit my existing doorbell with modern tech. What I really want is a doorbell that looks and sounds like a proper doorbell, but sends my phone a message when someone presses it.

There was a version 1 of this project, which I didn’t blog about because it was very hacked-together and didn’t go brilliantly. Fibaro manufacture a universal binary sensor for about £35. The idea is that you put it into any circuit with a switch, and the state of the switch will be broadcast to a Z-Wave network. A doorbell seemed to me to be the ideal place to use one of these things. I could program the Z-Wave network to do pretty much anything to alert me to a caller at the door including sending my phone an SMS message (which in turn gets displayed on my Pebble smartwatch). I did just this, and it worked for a while. Problem was that the Fibaro device didn’t allow enough current to flow quickly enough to actually trigger the bell, so I had to put a relay in the circuit. To make matters worse, the sensor introduced a noticeable lag into the system, to the point where people would press the bell and release it quicker than the device could trigger the relay, meaning the bell didn’t ring (although the SMS did get sent.) The final nail in the coffin was when I opted to move all my home automation to the brilliant Home Assistant - it uses OpenZWave to communicate with Z-Wave devices, and this is not without its own problems. So a better solution was needed, and, like all my problems, I solved it by throwing a Raspberry Pi at it.

The device, all tested and about to be installed

My version 2, which works much better, is based around a PiRelay Shield. This is a daughterboard that sits on top of a Pi (in my case a model 3A+) and is controllable with Python. The relays handle an electromechanical doorbell very well, the only hardware modification I needed to make was something to allow input from a bell push. This was made easier by the fact that the PiRelay has its own set of GPIO pins on top, identical to those of the Pi underneath, that simply work as a pass through. The relays only use six pins between them (+5V, ground, plus one for each relay) and these are configurable. So it was a simple case of choosing a GPIO pin that wasn’t being used, and hooking the bell push up to that plus the 3.3V pin via a 330Ω resistor, much as I did with my button panel project. Rather than soldering wires to the pins of a Raspberry Pi, I had a plug-in connector (albeit for an original Pi) lying around, so I soldered to that instead, and hid the resistor with some heat-shrink to make it look a bit nicer. I finished it off with a chock block so I could connect it to the wires in the wall that were already attached to my doorbell push.

The flylead for connecting the Pi to the bell push

Once I’d done that, I needed to write some software. The software was possibly the simplest thing I’ve ever written - I did wonder several times if an Arduino would have been a better fit for this project than the full Linux system that a Raspberry Pi provides - but simple is good. The library for the PiRelay allows the turning on and off of the relays with a single line of Python, so the rest is just recycled from the button panel project.


import RPi.GPIO as GPIO
import paho.mqtt.client as mqtt
import PiRelay
import time

topic = "yggdrasil/notify/doorbell/entryway"
host = "trypticon"
client = mqtt.Client("pi-doorbell-mqtt")

GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

relay = PiRelay.Relay("RELAY1")

while True:
    if GPIO.input(10) == GPIO.HIGH:
        time.sleep(0.01) # Eliminate phantom button presses
        if GPIO.input(10) == GPIO.HIGH:
            client.publish(topic, "on")
            time.sleep(.5) # Make sure the relay is open long enough to ensure the bell rings
            while GPIO.input(10) == GPIO.HIGH:
            client.publish(topic, "off")

The above code waits for the button (connected to pin 10 / GPIO15) to be pressed for more than 0.01 of a second. This eliminates phantom presses. When the button is pressed, it opens relay 1, publishes ‘on’ to the MQTT server and topic specified in the variables, then waits for the button to be released. Once it’s released, it publishes an ‘off’ message before closing the relay. I configured this script to run via systemd, which ensures the script runs in the background when the Pi is booted, but you don’t have to do this. Once I had the code working, it was time to physically install it into the doorbell.

The inside of my doorbell chime

You’ll note that in the image above, my doorbell has no batteries. This is simply because I’ve hooked it up to the mains via a 6V DC transformer instead. I just don’t see the point in using batteries in a non-portable device that can easily be mains-powered.

To install, I basically needed to put the Pi into the doorbell circuit between the bell chime and the push button. I disconnected the wires leading from the push button to the bell chime and connected them to the Pi’s GPIO. Then I connected Relay 1’s NO (Normally Open) and COM (Common) terminals to the place on the bell chime from which I’d just disconnected the push button. And that’s about it. Just for aesthetic value (and the fact that the Pi didn’t quite fit into the bell enclosure itself, even without the batteries) I mounted the Pi inside a cupboard in the room next to the front door, just to hide it out of the way.

The finished thing, installed in a cupboard

The final step was to configure Home Assistant to see the device as an MQTT device. At time of writing this requires some modifications to the configuration.yaml. I did it like so

platform: mqtt
name: "Doorbell"
state_topic: "yggdrasil/notify/doorbell/entryway"
payload_on: "on"
payload_off: "off"

and then configured an automation to respond to this, for example

- id: '1589150537974'
  alias: Send SMS on Doorbell
  description: ''
  - entity_id: binary_sensor.doorbell
    platform: state
    to: 'on'
  condition: []
  - data_template:
      message: Doorbell rang at {{ now().strftime("%-I:%M%p").lower() }}
      - '...'
    service: notify.send_sms_from_yggdrasil

The notification notify.send_sms_from_yggdrasil is a Twilio integration that I previously set up. The ‘…’ is just where I’ve removed my phone number before putting this script on the web!

So that’s it, really. Obviously now it’s all hooked up through Home Assistant I can make the bell push do pretty much anything. I’m having thoughts of making it turn the outside light red and triggering spooky sound effects and maybe a hidden smoke machine in time for Halloween.