Raspberry Pi baby monitor

In this second of a multi-part post I will show how I added some lights to my Raspberry Pi baby monitor (using a RPi 3). The IR leds are not visible to humans, so it will not wake up the sleeping monster. I will also look at some of the software solutions for streaming audio/video over my network. Spoiler alert, in the end I have opted for the Fruitnanny system that Dmitry Ivanov developed.

Hardware, part 2

To be able to follow this guide, the hardware and associated installation from part 1 of this series (Raspberry Pi baby monitor – Hardware, part 1), is neither really advanced nor a requirement. The scripts I use are tailored to the hardware in part 1 and this part (i.e. you have a RPi, RPi Camera and BrightPi, however if you just want a smart RPi lamp this might help some too).

List of components

What you need (except the Raspberry Pi 3B with PiNOIR v2 camera):

  • BrightPi kit (board with pre-soldered components + the leds and pin connector)
  • Soldering iron and solder wire

Optional parts

  • A sturdy holder for the board
  • Sticky putty (brilliantly called “elephants bugger” in Denmark), which is good for holding LEDs in place while soldering

Soldering the LEDs

The BrightPi comes as a partial kit. There are two types of LEDs that need to be soldered on to the board, IR and visible light. Along with the LEDs there is also a connector that need to be soldered, if you want to use cables with connectors, and not solder the cables directly to the board. There are nice instructions at the Pi-supply site (https://learn.pi-supply.com/make/bright-pi-quickstart-faq/). I followed those and must admit that I am pretty happy with the results shown in the picture below.

The backside of the BrightPi after soldering all the pieces in place and connecting the wires.

Connect and mount the LEDs

Now we are ready to mount the LEDs to our set up. First I tested the LEDs though, just connecting the cables to the correct GPIO pins of the Pi. After this boot it up, and test the LEDs with the i2cset command (after enabling I2C in sudo raspi-config Interfacing Options>>I2C).

There are cool 3D print mounts for the BrightPi (e.g. https://www.thingiverse.com/thing:2784985), and the PiMoroni camera holder supports it (ugly though). Since I do not have a 3D printer (yet!) I opted for a LEGO mounting solution. I was already using a Raspberry Pi LEGO case, so I thought, if I get some nice pieces that fit and make it possible to direct the lamp that would be awesome. Another option might be to drill holes in the case to connect the screws of the BrightPi board to the camera board directly. Anyway, this is my current solution.

Now that is it, ready to flash the lights.

Temperature sensors

I also wanted to add some environmental sensors to monitor the baby room, because why not, this is a learning experience. So I bought the dirt-cheap but not great accuracy sensor DHT11. Hooked it up with wires according to specs and just let it hang outside the case for now.

Software

During the past year I tested several solutions to streaming video over my local network, and to the outside through VPN. The main solutions I tested were:

  • The RaspiCam interface.
  • The UV4L project WebRTC and MJPEG streamer
  • Simple VLC stream
  • Python Flask app
  • Python rpicam script
  • Dmitry Ivanov’s FruitNanny (GStreamer, Janus, NodeJS)

After testing all these solutions I opted for the polished “FruitNanny” baby monitor, by Dmitry Ivanov (https://ivadim.github.io/2017-08-21-fruitnanny/). Its is perhaps a bit complex, a lot of software pieces need to fit. I cannot seem to access it from the outside through my VPN though, so a minus on that one. However I managed to set things up pretty quick using the guide on a fresh Raspbian install. Below are some comments on all the options.

Comments on (some of) the software

RaspiCam interface. (link)

I tested this through the DietPi distribution. Very easy to install and low usage. The landing page starts streaming directly, you can run scripts from the interface (i.e. toggle light). Full screen is possible. However, no audio, or audio noise meter.

UV4L project. (link)

Also tested through the DietPi dist. THe UV4L is an advanced project, with loads of functionality (such as running meeting rooms etc). The project has two way audio and video in the form of a native WebRTC client, in my use case it was one way. You just “call” the RPi and get audio + video. It was tricky to get the right parameters to see anything in the dark (gain, shutter speed etc), since I couldn’t trigger the lights manually. Also it was pretty unreliable, parameters would reset on reboot, slow and most importantly has some huge ugly text written all over (thus not really ‘open’ software). I read somewhere you can email someone to get a code to remove the text, but I decided to just give up on UV4L.

Python flask app. (link)

Very cool and interesting code by Miguel Grinberg, but how to tie in audio is not obvious, and probably expensive resource wise.

While some of the problems I ran into could be solved fairly easy, such as creating a background script that would turn on the LEDs for the UV4L solution, it was just too cumbersome. I would have a script take a photo to check if it’s too dark and then turn on the lights etc, but then the camera stream could not have been triggered before this. So in the end I went with the FruitNanny project. However there where a few things to fix because they were different in my setup, namely the LEDs and how I like my play/pause button.

Fix: Controlling the LEDs

For controlling the baby monitor’s LEDs there are basically two options. CLI/Bash script control through i2cset or Python script with the BrightPi library. I ended up with the Python BrightPi library, and a script to replace the existing light.py file as follows.

#!/usr/bin/python
# file: /opt/fruitnanny/bin/light.py
import sys
from brightpi import *
# get cli argument
par = sys.argv[1]
# define convenience variables
LED_ALL = (1, 2, 3, 4, 5, 6, 7, 8)
LED_IR = LED_ALL[4:8]
ON = 1
OFF = 0
# now check the cli argument and do what is asked
if par == 'on':
    # turn on the IR LEDs, but first reset them
    bpi = BrightPi()
    bpi.reset()
    bpi.set_led_on_off(LED_IR, ON)
    # gain can be 0 to 15
    bpi.set_gain(13)
elif par == 'off':
    bpi = BrightPi()
    bpi.set_led_on_off(LED_ALL, OFF)
elif par == 'status':
    # here we are asking for the BrightPi status
    # so we use get_led_on_off method
    bpi = BrightPi()
    all = bpi.get_led_on_off(LED_ALL)
    # all now has the status of the LEDs
    # thus adding them all will show if any of them are on
    # but if all LEDs are off, 0+0...+0 = 0
    if reduce( lambda x,y: x+y, all)>0: print(1)
    else: print(0)

This can now be run to check the status and turn on/off the IR LEDs of the BrightPi. For example ./light.py on should turn the IR LEDs on (make sure you chmod +x light.py as well).

Now since the app previously used the Bash script light.sh we need to change this in the light.js file located in /opt/fruitnanny/server/routes/. So open the file for editing, and change every bin/light.sh status/on/off line to bin/light.py status/on/off, simple.

Fix: the play/pause button

While the baby monitor setup by Dmitry Ivanov is super sleek, the play/pause button always got me confused. When paused it shows the pause button and the play button when playing. While I do see the logic and convenience in this, I feel I want a more YouTube-like experience, where the play button shows when it is paused and vice versa.

If you are like me you need to edit two files /opt/fruitnanny/views/index.ejs and /opt/fruitnanny/public/project/js/video-player.js and change every fa-play to fa-pause and every fa-pause to fa-play. You can probably do it with some cool sed command combo. The ‘fa’ stands for Font Awesome (https://fontawesome.com), just a font that has a lot of nice icons.

Things left to do (or: Wishlist)

There are a few things I want to do

  • Light diffuser, the light is very spot-like. Would like to light the full image as evenly as possible.
  • Wall holder, put the contraption in a more stationary location.

If I end up with new things, tweaks, I will post the updates here.