Building a Raspberry Pi 3/4/5 Baby Monitor

After looking at reviews for baby monitors, a few things were clear:

  1. Manufacturers aren't putting good cameras in these monitors
  2. Some have night vision, some don't and the quality usually sucks.
  3. If the monitor can be viewed remotely, it sometimes runs insecure RF wireless and can be snooped on or intercepted
  4. Good monitors aren't actually baby monitors, they're just nice cameras (Nest Cam) and cost $300+

I knew there had to be a better, more affordable way to keep tabs on our little guy. A Raspberry Pi was a perfect solution--it has a camera module with 1080p resolution, it has USB ports for extra peripherals, it's portable, and it's (relatively) cheap – although in 2024, even a Raspberry Pi 5 kit costs $200. The good news is, this guide works down to a Raspberry Pi 3 or even a Pi Zero!

Check out the resulting image quality:

720p, low light

Image quality, low light

720p, high light

Image quality, daylight

It's possible to reach 1080p with the Pi camera, it's up to you--I found 720p to be perfectly acceptable but 1080p caused the image to "zoom in" a bit too much. If I figure that out, I'll update the guide accordingly.

Who This Guide is For

This guide is for Raspberry Pi enthusiasts, makers, and DIYers who prefer a cheaper, privacy-centric camera under their control that can be more secure than an IoT camera. I've tried not to assume you know anything about Linux.

I am a developer by trade, but I will try to keep this guide as simple as possible. You are presumably ready to get your hands (a little) dirty if you have a Pi, but if you're like me, Linux is not your forte.

The other nice thing about using a Raspberry Pi is that it's easy to use! There are many guides and tutorials available for the device.

If you get stuck, the comments at the bottom provide a forum to help each other 🀝

What This Guide Covers

This guide will show you how to build your own DIY baby monitor using a Raspberry Pi 3/4/5.

The image and sound will be way better than any low- to mid-level monitors (and cheaper!). Additionally, this will give you a lot of flexibility to add other functionality such as a speaker, etc.

Since the Raspberry Pi is under your control, you can choose to expose it only within your home network or securely over the Internet--no weird Internet of Things or cloud "phone home" nonsense or possible vulnerabilities that allow people to view your baby.

It will be as secure as your home network, and if you choose to expose it publicly, you can use encryption and strong passwords to secure it (this guide does not cover that).

In This Guide

Jump to Comments Section

Before You Begin

How To

Before You Begin

Jump to How To

Updates

2024-11-22 – Raspberry Pi OS and Picam 2 compatibility

I recently wiped my Raspberry Pi 3 and am setting it up as a self-contained video recording and editing system for my son who is now 7 years old (yes, the one in the picture)!

I was able to follow my own guide again to get everything set up again, but several commands no longer worked and needed tweaks. I also added some more screenshots and clarified a few steps.

Using the Built-in rpicamvid

I show you how to use and configure Picam for video streaming, but a commenter said they found this guide on using built-in rpicamvid a bit easier! That is another option for you.

Remote video streaming from Raspberry PI camera
Using Raspivid and NetCat in headless Raspberry PI (OS Lite) for remote video streaming and get video from a local network PC with VLC

Price Increases on Canakit

I updated the Amazon links to the latest Canakit starter kits and was surprised that the price had doubled since 2019. You may want to shop around, but I think Canakit is worth it.

With cams as low as $50 now, this is definitely more of a hobby project than it was back thenβ€”you'll probably spend more money and way more time on it, so if all you're looking for is a good baby cam, maybe a $280 Nanit makes sense now.

The rest of the hardware has mostly fallen in price.

2020-08-25

2019-11-13

  • Add video walkthrough pitch
  • The Kinobo mini USB mic is discontinued so I replaced it with a well-reviewed Samson GO portable mic
  • Add clarification for installing the right Binary distribution
  • Add clarification for picam-viewer installation

2019-06-08

  • Updated Binary section to reflect instructions for Raspbian Buster

2018-01-11

  • Fixed picam extraction command typo because the archive contains the original filename as the top-level folder

2017-10-25

  • Thanks to Andrew for pointing out some differences between different Raspbian versions! I updated the Picam installation step.
  • I updated my Picam arguments to be what I'm using now after some testing. The args I'm using seem pretty stable now.

2017-10-02

  • I missed the fact that the /run/shm directories are blown away on Pi restarts. The startup script now ensures they exist (should fix slow feeds).
  • I updated my picam-viewer web player to use Video.js now which should support more devices.
  • The comments have reported that the Pi Zero works well for this!

The Hardware

Here's what you'll need (I've marked πŸ‘Ά with what the guide is using):

You can snag all the hardware needed for ~$200 off Amazon. I went with a 32GB SD card but that's just me, you could configure this to store all videos/photos on a network device or cloud account.

The gooseneck LED light is optional--I want to be able to have the monitor have a night-light attached vs. having to have a separate ambient light at night.

For mounting the Pi, it's up to you. I need to mount it to the bassinet/crib and a clamp-based gooseneck mount is perfect for me (at least until the little guy starts moving around and grabbing things!). You may want to wall-mount it, use cardboard, etc. Use whatever works for you!

Nightvision Support

Originally I had planned to use the Pi NoIR camera module because it can see infrared light. However, since infrared light is still light (just not visible) I didn't really want to take a chance of accidentally "shining" it straight onto my son's face. There is no real evidence to suggest that infrared baby monitors are dangerous to infants--but concentrated IR is still not good to have directed at you. The fact is that nightvision baby monitors probably use a very low light level and it's probably not dangerous at all.

If you want to add nightvision to this monitor, simply replace the normal camera module above with the Pi NoIR Camera module. You will then need to find a suitable infrared light to use at night.

I have opted to use a simple flexible USB light that I can shine specifically where it makes sense and won't be in the baby's line of sight. It has an on/off switch which comes in handy for my wife at night to simply lean over and switch on too.

Programmable LED Light

While I opted for a simple on/off nightlight, you could potentially go crazy with a BlinkStick Nano USB light that is programmable, so you could have it automatically turn on in low-light conditions, program light shows, or what have you.

How To

Installing the Pi Camera

To install the camera on the Pi, firmly insert the end of the cable with the silver pins facing toward the HDMI port.

I picked the Canakit because the case allows you to attach the camera on the inside, allowing an integrated camera.

Canakit camera case

Configuring the Pi

First things first, we need to configure our Raspberry Pi. The software installation guide on the Raspberry Pi documentation site is perfect and easy to understand.

I used the Raspberry Pi OS imager:

Raspberry Pi Imager Settings

You will see a screen like this:

Click "Edit Settings" so you can configure some stuff upfront:

  • Wi-Fi: You must configure this to connect to your Wi-Fi. You can do it once you boot into the OS, but you might as well do it now.
  • Hostname: I used babypi but the default is raspberrypi
  • Username/password: Good to set for security.
  • Timezone: When you boot up the OS, it should be set automatically, but you can also set it upfront.
πŸ‘¨β€πŸ’»
Advanced Users: You can also set up SSH here. This will allow you to use the Pi without the user interface enabled; you just need to know the IP address or hostname. You can disable the GUI after booting up the OS and going into Menu -> Preferences -> Raspberry Pi OS Configuration.

Follow all the steps until your SD card has the Raspberry Pi OS.

Connect the Pi via HDMI to a monitor or TV. Connect a mouse/keyboard to the Pi for configuring. Connect an Ethernet cable unless you want to use Wi-Fi during the guide.

Boot up your Pi (i.e. plug it in) and it should boot into the OS.

Updating Raspberry Pi OS

I'm sorry I have to delve into the command-line but because Raspberry Pi is a Linux device, most of the power user features are only available through there. Hey, presumably you're reading this because you want a power-user baby monitor! We have to get our hands a little dirty.

Launch the Terminal app on the Pi (it's in the menu bar at the top).

Run the following command:

sudo apt-get update && sudo apt full-upgrade

When the prompt changes to a changelog, press Ctrl-C to close the wall of text, then Enter to continue.

This takes awhile! This updates Raspberry Pi OS to the latest updates including security patches. You want to run this every so often to keep the operating system up-to-date. You can also follow the official documentation here.

There are more technical guides on automatic updating so you don't need to login to keep it up-to-date.

πŸ‘‰
If using the OS user interface, there is an "Update" option in the top menu bar but that didn't work for me. Using the Terminal was the most reliable way to update.

Configure IPv6 (Optional)

The Raspberry Pi can be pinged and connected to via the hostname raspberrypi.local or whatever name you chose in the imager (plus .local at the end).

πŸ‘‰
2025 Update: When I updated to Raspberry Pi OS, I had no trouble accessing the Raspberry Pi from my MacBook or Google Pixel with Chrome/VLC and the babypi.local hostname.

I did not verify whether you still need to update IPv6 in the latest OS, so maybe this isn't applicable anymore. I am leaving it in for reference just in case.

However, if you use the IP address, it defaults to a long one (IPv6). Web browsers can have trouble connecting to the Pi with this enabled, so we need to disable IPv6 hostname resolution.

sudo nano /etc/avahi/avahi-daemon.conf

On the line use-ipv6=yes change yes to no. Press Ctrl-O to save (hit Enter), then Ctrl-X to exit.

Now reboot! sudo reboot

You should be able to ping your Pi from another machine:

ping babypi.local
ping -4 babypi.local

The second command forces the ping to return the IPv4 address. On Windows you may need the Bonjour service installed if you don't have iTunes installed.

Some devices (my Android phone for example) still won't be able to use babypi.local so you'll still need the IP address of your Pi, which you can see with ip addr show.

Note: I had some issues on Windows trying to access http://babypi.local in my browser. When I pinged my Pi, I got a private address space back (198.105.x.x) instead of the local IP. I changed my router's DNS to Google's public DNS servers and for some reason that worked. I think CenturyLink (my ISP) was somehow interfering since it would always redirect to some proprietary search results page. However, with the knowledge I have of networking and DNS, this still makes no sense to me!

Installing Picam

Because we want to stream both audio and video from the camera and USB microphone, we need to use a software project called Picam.

Make sure to run all commands from the Pi user directory, i.e. your prompt should look like:

pi@raspberrypi:~ $

The ~ denotes your user's home directory.

Run the following command in the terminal to install some Picam dependencies:

sudo apt-get install libharfbuzz0b libfontconfig libepoxy0

Then this entire thing (if you are using SSH, just copy/paste otherwise have fun!):

cat > make_dirs.sh <<'EOF'
#!/bin/bash
DEST_DIR=~/picam
SHM_DIR=/run/shm

mkdir -p $SHM_DIR/rec
mkdir -p $SHM_DIR/hooks
mkdir -p $SHM_DIR/state
mkdir -p $DEST_DIR/archive

ln -sfn $DEST_DIR/archive $SHM_DIR/rec/archive
ln -sfn $SHM_DIR/rec $DEST_DIR/rec
ln -sfn $SHM_DIR/hooks $DEST_DIR/hooks
ln -sfn $SHM_DIR/state $DEST_DIR/state
EOF

Then the following, to execute the script we just made and create the required directories:

chmod +x make_dirs.sh
./make_dirs.sh

Downloading the right version

Raspberry Pi OS and Picam Binary Release (1.4.7+, 2.x)

πŸ‘‰
The latest Picam 2.x releases work on the latest Raspberry Pi OS version, and it's what I'm using in 2024.

Use the latest version release (2.0.12 as of Dec 2024):

wget https://github.com/iizukanao/picam/releases/download/v2.0.12/picam-2.0.12-`uname -m`.tar.gz -O picam-2.0.12.tar.gz
tar zxvf picam-2.0.12.tar.gz
cp picam-2.0.12/picam ~/picam/

Replace 2.0.12 with the latest version string if applicable.

This script:

  • Downloads the file to the current directory as picam-{version}.tar.gz
  • Extracts the archive to the picam-{version} folder
  • Copies the extracted sub-folder picam-{version}/picam to a top-level ~/picam folder in your HOME directory

Jessie or Stretch (Picam 1.4.6)

πŸ‘‰
If you are using Jessie or Stetch on your Pi, you need the right binary file! Thanks to Andrew for pointing this out in the comments.

This is only applicable to Picam v1.4.6

Now we install Picam directly using the link above:

wget <URL ABOVE> -O picam.tar.gz
tar xvf picam.tar.gz
cp picam/picam ~/picam/

Configuring Picam

We now have Picam installed! It's time to get a stream working.

To configure Picam to use our microphone, we need to know what its "device ID" is. Run the following to list any USB recording devices:

arecord -l

The name will be Card # and Device #, so for example, here is mine:

**** List of CAPTURE Hardware Devices ****
card 1: Device [USB Audio Device], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

You see "card 1" and "device 0" so my microphone ID will be hw:1,0.

Now, let's make a script we can run to start Picam. Replace "hw:1,0" with your device ID above if it's different.

First, create a new run_picam.sh bash script file and mark it as executable:

touch run_picam.sh
chmod +x run_picam.sh

Now, use the nano editor to edit the script:

nano run_picam.sh

The nano editor is very straightforward to use. Ctrl-O to save, Ctrl-X to exit.

Copy and paste or write this script:

#!/bin/sh

# !!! Change to your user home directory!
PI_USER=/home/<your-username>

sudo $PI_USER/make_dirs.sh

sudo $PI_USER/picam/picam \
  -o /run/shm/hls \
  --time --alsadev hw:1,0 \
  > /var/log/picam.log 2>&1
πŸ‘‰
Important: Change <your-username> to your Raspberry Pi OS username.

My path for example is /home/kamran

Because Picam writes to some system directories, it is running using sudo although I am positive with the correct permissions, you wouldn't need to.

The script starts Picam with an HLS stream output to the RAM drive (fast) and uses our microphone as the recording device. It also writes out the current timestamp in the bottom corner of the stream. There are a ton of other options, too, including subtitles, etc. The default video resolution is 720p, which is fine enough for a baby cam ton of other options.

The script also writes the Picam output to /var/log/picam.log for debugging purposes.

Test the script by typing sudo run_picam.sh. You will not see any output because it is outputting to the log file.

Open a new Terminal tab (File -> New Tab) and type in the following:

cat /var/log/picam.log

You should see:

kamran@babypi:~ $ cat /var/log/picam.log
created state dir: ./state
created hooks dir: ./hooks
created directory: ./rec
created directory: ./rec/tmp
created directory: ./rec/archive
created HLS output directory: /run/shm/hls
configuring devices
capturing started

You can quit the run_picam.sh script by hitting Ctrl-C to exit.

πŸ‘‰
You can also run the top command to verify picam is running.

Running Picam at startup

There's a great post on how to run a script at startup. We want Picam to run right away when the Pi boots up, so let's do that!

Create the script:

sudo nano /etc/init.d/picam

Then copy/paste the following:

#! /bin/sh
# /etc/init.d/picam

### BEGIN INIT INFO
# Provides:          picam
# Required-Start:    $remote_fs $syslog $network
# Required-Stop:     $remote_fs $syslog $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Simple script to start Picam at boot
# Description:       A simple script to start Picam at boot
### END INIT INFO

# If you want a command to always run, put it here

# Carry out specific functions when asked to by the system
case "$1" in
  start)
    echo "Starting Picam"
    # run application you want to start
    sudo /home/pi/run_picam.sh
    ;;
  stop)
    echo "Stopping Picam"
    # kill application you want to stop
    killall picam
    ;;
  *)
    echo "Usage: /etc/init.d/picam {start|stop}"
    exit 1
    ;;
esac

exit 0

This is an initialization script that will execute our run_picam.sh script we just made.

Mark it as executable:

sudo chmod +x /etc/init.d/picam

Now, let's test it.

sudo /etc/init.d/picam start

You should see the Picam output. Picam is now running in the background! You can stop it manually like this:

sudo /etc/init.d/picam stop

Now let's register it on startup:

sudo update-rc.d picam defaults

All set. We can test it out by rebooting the Pi and verifying the Picam process is running.

sudo reboot

Once the Pi is booted, type top to see running processes. You should see Picam at the top.

Linux "top" command running

Installing nginx

We've set up Picam to output a stream to a file but we need to expose that stream so we can connect to it from our devices or web browsers. "nginx" is a web server that can do that for us.

Let's install nginx:

sudo apt-get install nginx

Now let's expose the RAM stream as a directory:

sudo nano /etc/nginx/sites-available/default

In the editor, scroll down to right before location / { and add a new block above it:

location /hls/ {
    root /run/shm;
}

This adds a new /hls URL that points to the /run/shm/hls directory Picam is outputting the stream to.

Restart nginx to allow the changes to take effect:

sudo /etc/init.d/nginx restart

This starts the web server. Now you can browse (on the Pi or other device) to the root of the site and view the nginx welcome page.

For example, type in http://babypi.local/ to see the default nginx homepage:

If you type in http://babypi.local/hls/index.m3u8 the browser should download or display a video file. We'll get to how to view the video in a few minutes!

Mounting the monitor

Now that we've configured the baby Pi, we need to put it near the baby! As I mentioned at the start, I am just using a simple LED light to help when its dark. With a gooseneck mount, we can also position the monitor in whatever way we need that provides the best view of the crib. What's nice is that you can fit everything you need onto a single Pi, so it can travel with you.

It looks a bit like an angler fish but it does the job!

Viewing on a device

We're officially all set up! That's all that is needed to use our baby monitor.

In the first part where you configured the Pi, you choose a hostname (or didn't). You can now access the stream URL at http://babypi.local/hls/index.m3u8. You can open that up in any compatible software to view the livestream.

VLC Player

On a PC, Mac, Android, or iOS, I recommend VLC Media Player.

  1. Install VLC
  2. Open VLC
  3. Go to File
  4. Open Network Stream
  5. Paste in the URL
VLC screenshot of using mDNS URL

The steps are similar for Android and iOS, just choose "Stream" and type in the same URL.

You should now see a live stream with video and audio!

(Optionally) Adding a web player

VLC is a nice player but sometimes it might be nice to just hit the Pi directly in a web browser (open a new tab on your computer, etc.).

We can optionally add a stream player to our web server. Follow the steps below:

cd /var/www/html
sudo git clone https://github.com/kamranayub/picam-viewer.git .
IMPORTANT: Ensure you keep the period (.) at the end of that command! It will download the contents of the Git repository into the current one.

This will bring down a bare metal web player I put together. Feel free to edit it as you see fit. If you changed the URL to where the HLS stream is at on the server, you will need to edit config.json.

Now, open a browser and visit your Raspberry Pi (e.g. http://babypi.local/):

Browsing the babypi.local URL
Note: The viewer is very basic right now, I plan to add some functionality to change the exposure, resolution, white balance, and mute settings for Picam as well. Some Raspberry Pi configuration might be nice too such as rebooting. You can contribute back at https://github.com/kamranayub/picam-viewer

(Optionally) Exposing over the Internet

I have chosen not to expose my Pi to the internet, instead it sits securely on my network behind my router and is not accessible via the Internet. If you choose to expose it remotely, you will need to do the following to ensure it's secure:

  1. Set up Port Forwarding on your router to forward some random port to port 80 on the Pi
  2. Enable HLS encryption which is in the Picam documentation.
  3. Configure nginx to use HTTPS (and force it) and an SSL certificate (preferably a signed one) for the website
  4. Configure nginx to prompt for a username/password (Basic Authentication) which is secure as long as its over SSL
  5. Probably disable password authentication in SSH and switch to SSH keys

These steps are outside the scope of this guide but there are many tutorials online for Nginx, port forwarding, and SSL that you can follow to achieve this. If someone wants to write it up, I will happily add it to this guide! Just remember as soon as you allow your Pi to be exposed, you need to make sure it's the server is secure and encrypted.