I recently Tweeted about the Raspberry Pi baby monitor that I built and got heaps of comments, thanks! Here's a build guide, as promised. Apparently, the build looks like Johnny 5 from the 1986 film Short Circuit. I was born after that film and haven't seen it but yeh, it kinda does.

Photo of baby monitor v1 - 1 of 2 Photo of baby monitor v1 - 2 of 2

Kit list

  • x1 baby human
  • x1 Raspberry Pi. I used the Pi Zero WH, but I would strongly suggest that you use the Raspberry Pi 4 or a Pi with more than a single core. With the Pi Zero WH, the single core is almost pegged the whole time. To prevent the stream from becoming unresponsive, I have a Cron job to restart the camera stream, which works but it's not ideal. The issue is that the stream is using most of a core which makes everything else is a bit slow.
  • x1 Raspberry Pi Zero camera adapter if you're using the Pi Zero W (please don't). Core Electronics link
  • x2 bread boards. I used only 1 board start with, but the heat from the Raspberry Pi itself was causing elevated temperature readings so I had to move the sensor further away from the Pi. Link
  • x1 Adafruit DHT22 temperature/humidity sensor. Link
  • x1 ModMyPi night vision camera board. Link
  • x1 10K Ω resistor. Link
  • x3 male-female jumper cables. Link
  • x3 male-male jumper cables. The male-male ones are just for connecting the two boards together. Link

My specific build also used the following, but you can probably do better:

  1. Brown rice (any type of rice is probably compatible, but I've only tested brown). I'm using this rice, which is probably a bit too fancy for this use case
  2. Part of my wooden chopping board that snapped off. Can't lend you mine, go get your own

via GIPHY

Temperature and humidity

For the DHT22, I followed an article from PiMyLifeUp.com. Diagram:

DHT22 sensor wiring

You'll notice that they've got an extra red jumper on their version - I think they just wanted to space things out a bit. I didn't bother with the extra cable but my resistor is kinda squeezed in. Their article covers the whole DHT22 set up, I'm not going to write out the same thing here.

Once you have wired everything up, let's test that it's working.

Make sure you have Python 3 and pip installed and then install the library to interface with the DHT22:

sudo pip3 install Adafruit_DHT

Run this command to test that we're getting readings from the DHT22:

import Adafruit_DHT

DHT_SENSOR = Adafruit_DHT.DHT22
Adafruit_DHT.read_retry(DHT_SENSOR, 4, retries=2)

You should see something like:

(48.400001525878906, 23.299999237060547)

which is the humidity and temperature respectively. You can read the full Python docs here. If you get (None, None) then re-seat the jumpers and DHT22. Also, I'm using GPIO pin 4 - make sure you change the 4 to whichever GPIO pin that you're using.

Track record high/low temperatures

This was a feature request from the wife. Also, in a future project, I would like to start tracking temperatures/humidities in all our rooms and outside, throughout the year. I have a Cron job that measures the temperature via the DHT22 every 1 minute and stores the readings in an sqlite3 database, so we can calculate record highs and lows. You'll need a few extra packages if you want this feature:

pip3 install sqlite3 datetime pytz

Create the database like this:

sqlite3 /home/pi/sensors/sensors.db

Create the table:

CREATE TABLE hourly(id INTEGER PRIMARY KEY AUTOINCREMENT, temperature NUMERIC, humidity NUMERIC, currentdate DATE, currentime TIME);

Here's the Crontab config (add with sudo crontab -e):

* * * * * python3 /home/pi/sensors/minutely.py >> /home/pi/sensors/logs/minutely.log 2>&1

and here's the minutely.py code:

import Adafruit_DHT
from datetime import datetime
import sqlite3
import pytz

DHT_SENSOR = Adafruit_DHT.DHT22
DHT_PIN = 4

tz = pytz.timezone('Australia/Sydney')
now = datetime.now(tz).isoformat()
humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN, retries=2)

if humidity is not None and temperature is not None:
    conn = sqlite3.connect('/home/pi/sensors/sensors.db')
    c = conn.cursor()
    c.execute('insert into minutely values (?,?,?)', (now, temperature, humidity))
    conn.commit()
    

Change the timezone from Sydney to UTC, or whatever you prefer. Note that this is "best effort"; we use read_retry to try getting the sensor data but if it keeps failing, we don't insert anything into the database. I've been running this code for a few weeks now and once, I noticed that the DHT22 stopped working; re-seating the DHT22 seemed to fix the problem (maybe if it was on a soldered board, it would be ok). Rebooting the Pi doesn't help.

Camera

Raspberry Pi cover camera setup in their documentation. It's just:

sudo raspi-config

and then you need to go to Interfacing Options, select Camera and follow the prompt to enable the camera. You'll have to reboot. The documentation shows you how to take some test photos/videos to make sure it's working.

Putting it all together

We want to end up with something like this but you can customise how you like:

Baby monitor screenshot

Now we have:

  • Current temperature and humidity
  • Record high/low temperatures
  • Working night vision camera

So now we need to put it all together so we can use all this data, and display it in a web browser. Here's the code to do this, which is a fork of existing code by Dave Jones. Follow the instructions in the README.md file but it's just:

$ git clone https://github.com/cjwfuller/pistreaming
$ cd pistreaming
$ python3 server.py
Initializing websockets server on port 8084
Initializing HTTP server on port 8082
Initializing camera
Initializing broadcast thread
Spawning background conversion process
Starting websockets thread
Starting HTTP server thread
Starting broadcast thread
  

To keep this running, I run this in tmux:

$ sudo apt install tmux
$ tmux
$ python3 server.py
...
...
  

Notice from the server.py that I'm running the Python server on port 8080, this is because I run NGINX on port 80 and get it to forward the requests to Python. I don't cover NGINX here but, just install it, start it, enable it at boot and use something like this:

upstream picam {
        server localhost:8080;
}

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        location / {
                proxy_pass http://picam;
        }
}
  

You'll notice that I'm able to access the stream with http://babycam.fuller.local. This is configured via a DNS server on my home network which is actually a Pi Hole too. I might do another blog post on this but they've made the setup so trivial now.

Enhancements

There are plenty of ways this build can be improved:

  • Make it more koala like, less killer robot to avoid scaring the baby! Putting this at the top of the list - folks on Twitter think the baby is going to freak her out with the current look!
  • Upgrade the rice/chopping board setup to perhaps a cheap camera tripod
  • Upgrade from the Raspberry Pi Zero WH to a Pi with more than 1 core
  • Write a start script, so when the Pi reboots, the stream doesn't have to be manually started
  • Graph the minutely temperature/humidity readings

Thanks! Reach out if you have any questions or comments!