“What is our lil’ doggo up to while I am away?” I thought to myself commuting to work. “Does she nibble on the door frame?” “Or maybe she feasts on some mattresses? “Naah,” I would not notice that.

I always regarded her as a good dog. Such a calm and collected creature. Unless there is a cat. Or a traffic sign. Or a gate barrier. Or anything for that matter. The only difference between these things is her movement direction. Cats = forward, anything else = backwards. Yep, she is one scaredy-cat. However she never did anything wrong, except that time when she decided to munch on some shampoo. Who knew dogs practice oral hygiene.

While that accident sure bubbled up, she seems to be quite OK being alone at home. But you can never be sure. Especially when living in multi apartment building. Does she bark all the time, waking neighbors’ baby? Is she jumping all the time, making neighbors below contemplating their flat choices? “Am I about to be evicted?” “And most importantly does she sleep on the couch?!”

For that matter I have dug up my old Raspberry Pi 2 determined to put my skepticism to rest. Armed with the RPi and a new camera module, it was time to put everything to the test (sick rhymes yo). The final product would look like this:

All in all, RPi connects through the WiFi adapter to the home network, starts the VPN server and finally provides live stream through the web server. Live stream can only be accessed by people having access to the VPN server, ie. whoever gets a client private key from ME (muahaha, no butt naked live streams to everyone on the internetz - unfortunately or rather fortunately for the ladies out there).

I put it on the amplifier due to the power outlet proximity and additionally it has a nice view of the whole room and of the entrance (in case she is barking at the door when someone passes by).

Hardware used

I already had:

I had to buy:

The assembly of components was trivial. The only thing worth mentioning is the camera being upside down when coming out of the case. We flip the camera programatically, since this is the most natural from the cable standpoint of view.

I installed Raspbian Buster with desktop and recommended software as the 2016 OS already installed was out of date.

Setup WiFi connection and static IP

WiFi Connection

As I was keen on using RPi through SSH and developing on my local computer I setup WiFi with a static IP address first.

We open sudo vim /etc/wpa_supplicant/wpa_supplicant.conf file and enter:

1network={
2    scan_ssid=1
3    ssid="<wifi_name>"
4    psk="<wifi_pass>"
5}

As I have a hidden SSID on my home network I also added the scan_ssid=1 flag.

Static IP

We want the RPi to be always accessible on the same IP (192.168.0.244) in our LAN. This has to be done on two sides

  1. Router setup: reserve 192.168.0.244 IP for our RPi.

    • We locate MAC address of our RPi by running ifconfig and looking for ether entry. It should be something like 02:01:03:6d:6e:5d.
    • We open our router control panel (by going to 192.168.0.1 or whatever the default gateway address is), go to DHCP section and reserve 192.168.0.244 IP for 02:01:03:6d:6e:5d MAC address. What this essentially means, if a device with a MAC address 02:01:03:6d:6e:5d tries to connect to our network, it will be assigned 192.168.0.244 IP.
  2. RPi setup: We have to tell our DHCP on RPi which static IP belongs to the RPi. We open sudo vim /etc/dhcpcd.conf and add

    1interface wlan0
    2static ip_address=192.168.0.244/24
    3static routers=192.168.0.1
    4static domain_name_servers=192.168.0.1 8.8.8.8
    

And that is it! When RPi boots it will connect to our SSID. Router will reserve 192.168.0.244 IP and we can then connect to it e.g. ssh -X pi@192.168.0.244 as we can always be sure that RPi will reside on that IP.

Setup OpenVPN

We create a VPN to secure our live stream.

  1. We have to enable tun module first, we run modprobe tun and to make sure this runs every time we boot the RPi, we pen sudo vim /etc/modules and append tun into a new line.

  2. We follow the instructions in this repo to install OpenVPN. This comes as a life saver as setting up VPN can be a rather daunting process.

  3. After the installation is done we get a client.ovpn, which can be used by OpenVPN client. As the port forwarding is still not setup, we can modify client.ovpn file to use our LAN connection. We open the file vim client.ovpn and change remote to remote 192.168.0.244 1194. Additionally we do not want all of our Internet traffic to be routed through VPN so we add the following line:

    1pull-filter ignore redirect-gateway
    
  4. We use the client.ovpn file on some other computer in the LAN to connect to the VPN:

    1sudo openvpn --config ~/.ovpn/client.ovpn
    
  5. We can test the connection with a simple ping ping 10.8.0.1. If everything works correctly we get the response:

    1PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
    264 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=8.43 ms
    364 bytes from 10.8.0.1: icmp_seq=2 ttl=64 time=3.18 ms
    

Additional clients

I will use multiple devices to access the VPN server. We can create additional clients by simple running ./openvpn-install.sh on the RPi and obtain multiple client .ovpn files. Those extra clients can always be easily revoked by running the same command (e.g. if the phone was stolen).

Setup live stream server

Install Motion

For live stream purposes we use Motion program, which monitors video signal from the camera. Besides being able to detect if a significant part of the picture has changed, it supports live stream out of the box.

  1. Install motion program

    1sudo apt-get install motion
    
  2. We are using one of the official camera modules:

    1sudo modprobe bcm2835-v4l2
    
  3. To start module automatically after every restart we add the following entry into the /etc/modules:

    1# /etc/modules: kernel modules to load at boot time.
    2#
    3# This file contains the names of kernel modules that should be loaded
    4# at boot time, one per line. Lines beginning with "#" are ignored.
    5
    6# ... other moduels
    7bcm2835-v4l2
    

    And edit sudo vim /etc/default/motion to set start_motion_daemon=yes:

    1# set to 'yes' to enable the motion daemon
    2start_motion_daemon=yes
    

    With this setting Motion server will run as a daemon in the background.

Config Motion

With the above configuration we can be sure that Motion will run whenever we plug the RPi into the outlet. Now we take a closer look at the Motion config. We open it with:

1sudo vim /etc/motion/motion.conf

And in our case we used the following configuration

 1# Start in daemon mode
 2daemon on
 3
 4# Image parameters
 5width 640
 6height 480
 7framerate 8
 8
 9# Allow stream to be visible outside localhost
10stream_localhost off
11stream_maxrate 8
12stream_motion on # set framerate to 1, when there is no motion
13
14# Do not save image on motion detection
15output_pictures off
16
17# Due to camera cable coming out of RPi forces camera to be upside down, we flip the axis
18flip_axis h

Whenever we change the configuration we can apply it with:

1sudo service motion restart

or

1sudo service motion start

If we started it for the first time.

Width, height and frame rate were defined empirically. I tested different settings and at first set resolution to HD. Although the stream worked it was laggy through the VPN. VPN stream encryption + camera processing is no bueno for RPi CPU. The picture is still good enough to see what little fella is up to. Additionally since she is mostly stationary we use stream_motion on to reduce the frame rate when she is not moving. flip_axis h was done purely because camera cable comes out of the RPi in such manner that image is upside down. Instead of twisting the cable, this will flip the axis horizontally and it will be OK.

Test the live stream

We can test the stream by visiting 192.168.0.244:8081 or 10.8.0.1:8081 if we are connected to the VPN and our live stream should be visible:

Live Stream Example

Flask server

Since we want to add additional actions (remote food dispense) to the web interface, we create a simple Flask web server. We add a simple HTML template that includes our live stream:

1<html>
2  <body>
3    <img src="http://10.8.0.1:8081" height="480" width="640"/>
4  </body>
5</html>

And a web.py server script:

 1from flask import (
 2    Flask,
 3)
 4
 5app = Flask(__name__)
 6app.config['DEBUG'] = True
 7
 8@app.route('/')
 9def index():
10    return render_template('index.html')
11
12if __name__ == '__main__':
13        app.run(host='0.0.0.0', port=8082)

Which we then run with

1python3 web.py

We can now visit http://10.8.0.1:8082 to see our server in action. As this is not meant for production environment, this is good enough as it is.

Code is available on my Github.

Port forwarding

Last but not least, we have to allow the outside traffic to access our VPN server. To forward our ports we log into our router and forward 1194 traffic to our RaspberryPI:

Port forwarding on the router. We redirect any traffic coming from 1194 to 192.168.0.244:1194, where our RPi OpenVPN server is running

I also had to change ISP settings to allow the port through the ISP’s firewall. Our ISP offers a special web platform where forwarding can be set.

Dynamic DNS and static IP

Since I am behind a dynamic IP, I opted for DynamicDNS solution NoIP. It assigns domain name to you router and it is stationary. It is supported out of the box on my router therefore I just registered the domain and entered the credentials into my router. Now my router pings NoIP every 6 hours to tell about the new IP address. It is free, however you have to confirm the chosen domain name every 30 days.

Conclusion

We created a RaspberryPI camera server using Motion program. It is secured with OpenVPN, which runs on RaspberryPI. To allow connections to the VPN we forward the port 1194 (port on which OpenVPN is running). We register NoIP account to circumvent ever changing IP address of our router. RaspberryPI is connected to our local network with WiFi and we configure it through SSH. We setup static IP for RaspberryPI. Due to WiFi we can plug in RPi anywhere in our house and stream should be working due to all our services running on boot.

Yes, that’s how I know you slept on the couch, doggy. evil grin