There are some pretty cool smart doorbells out there, but they are expensive and the basic components of a wireless button, camera and a small computer are cheap! In fact the most expensive component in this project is the camera module, which is still a bargain at sub 20 USD.
An overview of the system is shown in Figure 1. When someone pushes the doorbell button, the button module transmits a 433 MHz RF signal to a receiver (not show) which sounds a chime. However, the RF signal can be freely intercepted (not ideal for security but pretty convenient), and here an RF module attached to a Raspberry Pi is used to intercept the RF signal. On receiving the signal, the Pi takes an image using the camera. This image can then be sent as a mobile notification, for example using the Telegram app. In this project, I actually send the image to my home automation system, Home-assistant.
Cheap wireless doorbells that communicate between a button and a chime via RF can be picked up for less than 10 pounds on Amazon, and I chose one (link) based purely on aesthetics, rather than any technical requirements, shown in Figure 2.
Perhaps I got a bit lucky, since my doorbell was compatible with the Python module Rpi-rf that I used to interpret intercepted RF signals. I have subsequently bought RF devices that were not compatible with Rpi-rf, and I am not sure if this is because they used a custom pulse encoding (to avoid interference) or chipset. So be warned, some experimentation may be required unless you go for a device with known compatibility with Rpi-rf. However, if you already have a wireless doorbell bought in the EU/USA, chances are you can use it.
Raspberry Pis have WiFi and Bluetooth antennas built-in, but not 433 MHz RF. Luckily RF transmitter/receiver pairs are incredibly cheap, and I paid just over a pound for mine, including shipping! Rpi-rf explains the wiring to the Pi GPIO.
For the Pi camera, a wide range of options are available, and a old webcam could be used. Assuming you are using an 'official' Raspberry Pi camera, follow the setup instructions here.
Hardware total costs (in pounds):
- Pi Zero W: 10
- Camera: 13
- Wireless doorbell: 9
- RF receiver: 1
- Home-assistant (optional): free!
- Total = 33 pounds
I will assume that you are comfortable with the Terminal on your Pi, and highlighted text
corresponds to commands entered at the Terminal. If you get warnings about permissions, add sudo
before any command. I SSH into my Pi and use Samba (described later) to access the Pi file structure. Check the IP address of the Pi by logging in manually and running hostname -I
which returns 192.168.0.21 in my case. I recommend setting a DHCP reservation on your router so that this IP doesn't change over time.
Before installing the packages required for this project I strongly recommend running sudo apt-get update
and sudo apt-get upgrade
to ensure your Pi firmware is up to date. We will also require the pip package manager, apt-get install python3-pip
. We are going to need the Rpi-rf package installed with sudo pip3 install rpi-rf
. If you want to follow this project and post images using MQTT then you need to install paho-mqtt and test the connection to your MQTT broker. Alternatively you could use requests to post images e.g. using the Telegram API.
The camera module is supported by the Rassbian OS so you will only need to install separate libraries if you are using a non-supported camera. Basic camera functionality is described here using raspistill
. Test that your camera works by taking and viewing an image with sudo raspistill -o
image.jpg
and viewing the image. Within our python scripts we will make use of the camera module for which the docs are here.
To browse the files on the Pi remotely, I recommend you set up Samba file sharing and setup an Apache web server to share folders of images from your Pi over the network. However, neither of these are essential for this project since we will be posting the images to your mobile, but I do find it convenient to have Samba setup so I can view the Pi file structure when using SSH. Also using Apache it is convenient to be able to browse the captured camera images from the browser.
To setup Samba file share, if you have SSH to your Pi you can copy+paste code from this tutorial.
The Apache setup process is described here, and installation consists of running sudo apt-get install apache2 -y
then pasting the IP of your Pi into the browser address bar on a remote computer attached to the network, you should see a splash screen if everything is working, shown below in Figure 3.
We next want to create a folder to save images. Apache creates its own folder structure at /var/www/html on the Pi. cd
to this folder then make a folder for the camera images with the command sudo mkdir images
and cd into this folder. Take an image with sudo raspistill -o test_image.jpg
. You can now navigate to the folder via the browser to view the image on your remote computer.
Step 1 is to determine the RF pulse sequence that the doorbell transmits when it is triggered. I actually did this process on a Pi 3 that I already had attached to a breadboard, shown in Figure 5 below.
The RF receiver (RX) module is wired up to the Pi following the RPi-rf wiring diagram. Three connections are required:
- 5V supply to GPIO pin 2
- Ground to GPIO pin 6 (GND)
- Data to GPIO pin 27
Navigate into the Rpi-rf folder and you will see there are two scripts where we want to use rpi-rf_receive. Navigate (using cd
in the Terminal) to the folder rpi-rf/scripts folder containing rpi-rf_receive.py and run the script using python3 rpi-rf_receive.py
. This will produce an output like the following (several lines ommited):
pi@raspberrypi:~/Documents/rpi-rf/scripts $ python3 rpi-rf_receive
07:17:35 - [INFO] rpi-rf_receive: Listening for codes on GPIO 27
07:17:35 - [INFO] rpi-rf_receive: 262144 [pulselength 665, protocol 2]
07:17:38 - [INFO] rpi-rf_receive: 9181186 [pulselength 290, protocol 1]
I noticed that a couple of signals change with each press, but one was constant in every press, 9181186 in my case. Therefore run the script a few times and look for a signal that appears with every press of the doorbell. OK this signal is all we need to move on to the more fun step of taking some photos!
Code on the PiI wanted to be able to trigger the camera when either the RF button is pressed, or when triggered by an MQTT post e.g. from my home automation system. The code below runs an MQTT listener on a background thread whilst listening out for RF button presses. The trick to getting my desired functionality was to place some code in the MQTT listener function on_message()
to trigger the camera to take an image with post_image()
when a the MQTT message 'ON' is received. The image is then posted over MQTT using to the MQTT channel 'dev/camera' to the MQTT broker at IP 192.168.0.100. A time stamped image is also saved for viewing with Apache.
# combine the MQTT and RF receive codes
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
import picamera
import argparse
import signal
import sys
import time
import logging
from rpi_rf import RFDevice
rfdevice = None
### camera
camera = picamera.PiCamera()
camera.vflip=True
#
def post_image():
print('Taking photo')
camera.capture('image.jpg')
file_name = 'image_' + str(datetime.now()) + '.jpg'
camera.capture(file_name) # time-stamped image
with open('image.jpg', "rb") as imageFile:
myFile = imageFile.read()
data = bytearray(myFile)
client.publish('dev/camera', data, mqttQos, mqttRetained) #
client.publish('dev/test', 'Capture!')
print(file_name + 'image published')
#
### MQTT
broker = '192.168.0.100'
topic ='dev/test'
mqttQos = 0
mqttRetained = False
#
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(topic)
# The callback for when a PUBLISH message is received from the server.
#
def on_message(client, userdata, msg):
payload = str(msg.payload.decode('ascii')) # decode the binary string
print(msg.topic + " " + payload)
process_trigger(payload)
#
def process_trigger(payload):
if payload == 'ON':
print('ON triggered')
post_image()
#
client = mqtt.Client()
client.on_connect = on_connect # call these on connect and on message
client.on_message = on_message
client.username_pw_set(username='user',password='pass') # need this
client.connect(broker)
#client.loop_forever() # don't get past this
client.loop_start() # run in background and free up main thread
### RF
#
def exithandler(signal, frame):
rfdevice.cleanup()
sys.exit(0)
logging.basicConfig(level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S',
format='%(asctime)-15s - [%(levelname)s] %(module)s: %(message)s', )
parser = argparse.ArgumentParser(description='Receives a decimal code via a 433/315MHz GPIO device')
parser.add_argument('-g', dest='gpio', type=int, default=27,
help="GPIO pin (Default: 27)")
args = parser.parse_args()
signal.signal(signal.SIGINT, exithandler)
rfdevice = RFDevice(args.gpio)
rfdevice.enable_rx()
timestamp = None
logging.info("Listening for codes on GPIO " + str(args.gpio))
code_of_interest = '9181186'
#
while True:
if rfdevice.rx_code_timestamp != timestamp:
timestamp = rfdevice.rx_code_timestamp
print(str(rfdevice.rx_code))
if str(rfdevice.rx_code) == code_of_interest:
post_image()
time.sleep(1) # prevent registering multiple times
time.sleep(0.01)
rfdevice.cleanup()
Copy the script to the images folder using sudo cp script_name /var/www/html/images
and cd
to that folder. Run the script with sudo nohup python3 script_name
and view the image on Apache, shown below in. Note that nohup
is required if you are connected to your Pi via SSH and want the script to continue running after you disconnect.
The code could be changed to post the image directly as a notification using the Requests library and the Telegram app. For an example see line 126 on this link using bot.sendPhoto(). However Home-assistant supports receipt of images over MQTT using the MQTT camera component, as well as notifications using a wide range of services.
Home-assistant IntegrationI will assume you have the MQTT component configured and tested as described in the Home-assistant docs. We then have to configure the MQTT camera component by adding the following to the configuration.yaml file:
camera:
- platform: mqtt
topic: dev/camera
The image taken previously is now viewable on Home-assistant, shown below.
Next we create a Home-assistant automation to send us a Telegram notification when the camera is triggered by the button. Whilst a single automation could handle both the trigger and the action of sending of the notification, I prefer to break this process up into an automation to detect the trigger and a separate script to send the camera image in a notification. Having the notification as a separate script allows me to reuse it in other automations, but does increase the amount of code.
First add the Telegram notification service to Home-assistant following the instructions here to get your api key and chat ID. Add your data to the configuration.yaml file, of the form:
notify:
- name: Telegram
platform: telegram
api_key: your_telegram_api
chat_id: your_telegram_chat_id
This adds the notify.Telegram service to Home-assistant. Next we add the automation:
automation:
- alias: Doorbell_pressed_automation
trigger:
platform: mqtt
topic: dev/test
payload: 'Capture!'
action:
- service: automation.turn_off
entity_id: automation.doorbell_pressed_automation
- service: script.turn_on
entity_id: script.doorbell_pressed_script
- delay: "00:00:5"
- service: automation.turn_on
entity_id: automation.doorbell_pressed_automation
This automation is listening for 'Capture!' on the MQTT dev/test channel (dev/camera did not work) and performing the action script.turn_on on the script doorbell_pressed_script below. Note that the call to the script is sandwiched between extra logic to turn off and back on the automation with a delay of five seconds between, this is required to prevent the automation from firing more than once every five seconds. This is required since we don't want to receive multiple locations if the person at the door hits the doorbell multiple times in quick succession, as some people do.
doorbell_pressed_script:
sequence:
- service: notify.Telegram
data:
title: Home Assistant Notification
message: --Doorbell Pressed--
data:
photo:
- url: http://192.168.0.21/images/image.jpg
caption: Doorbell View
In this script I am pulling the image from the Pi Apache server. I should also be able to send the file direct from Home-assistant, but I need to figure out how to do this. The notification is shown below in Figure 8.
It would also be nice to trigger the camera from Home-assistant, which we can do by creating a script to post 'ON' on the dev/test channel (triggering process_trigger()
) and adding a button to Home-assistant to run the script. I call the script dev_publish_on_script and the Home-assistant configuration.yaml entry is below:
dev_publish_on_script:
sequence:
- service: mqtt.publish
data: {"topic":"dev/test", "payload":"ON"}
I would also like to customise the appearance of the button, so I create a file called customize.yaml and add the following:
script.dev_publish_on_script:
friendly_name: 'Capture doorcam photo'
icon: mdi:camera
I then tell Home-assistant to load this file by placing inside configuration.yaml file the line customize: !include customize.yaml
. Now after restarting Home-assistant (to make the customisation take effect) I get a button on the Home-assistant GUI which triggers the Doorbell_pressed_automation
.
We would also like to display when the camera image was taken. To do this we create a template sensor which is displays the time when 'Capture!' is published on the dev/test channel by post_image()
. I have a sensor monitoring dev/test with the code:
sensor:
- platform: mqtt
name: "dev_test"
state_topic: "dev/test"
I need to access the attributes of this sensor, specifically the attribute state.last_changed
which I can check using the Templates tool in the Home-assistant GUI, shown below in Figure 9.
You will see that the attribute last_updated
is the string 2017-05-11 05:02:43.044553+00:00
and requires some formatting using strftime()
to display nicely. We now create the template sensor using:
sensor:
- platform: template
sensors:
camera_capture_time:
value_template: '{{states.sensor.dev_test.last_updated.strftime("%A %H:%M:%S")}}'
friendly_name: 'Camera captured time'
Finally I create a group for all the entities related to the doorbell camera, and then create a view for that group:
Doorcam_view:
view: yes
entities:
- group.Doorcam_group
Doorcam_group:
entities:
- sensor.dev_test
- script.dev_publish_on_script
- sensor.camera_capture_time
- camera.mqtt_camera
And the final product is shown below in Figure 10.
Camera, doorbell and notifications working. It can be activated from the Home-assistant and am on the way to having a nice interface.
To do
- Add a start-up script
- Use Pi zero and mount on door.
Comments