# Raspberry Pi - Zero 2 W RTSP Server

## Introduction

While setting up my smart home I was looking into creating a cost effective [NVR](https://en.wikipedia.org/wiki/Network_video_recorder) that would allow for a high degree of privacy and control. The choice of NVR software fell on the excellent [Frigate NVR](https://frigate.video/), it integrates well with Home Assistant and supports hardware accelerated object detection via the [little AI chip](https://coral.ai/products/accelerator) I had lying around.

The other part was having affordable, power-efficient camera hardware. There are many network-attached cameras on the market, but most of them require external services to set up/function and software wise they are black-boxes which raises considerable privacy concerns.

The choice fell on the Raspberry Pi Zero 2 running the default Raspberry Pi OS. The original Raspberry Pi Zero (v1) boards unfortunately are not suitable for streaming video in Full-HD, the CPUs were running at the limit and got too hot started heavily throttling. Fortunately the Raspberry Pi Zero 2 alleviated these issues at a similar price point (once they became available again in 2023/24).

The video to Frigate has to be an RTSP stream, to facilitate this we will be running [MediaMTX](https://github.com/bluenviron/mediamtx) via docker.

## OS Setup

To set up the boot media for the Pi Zero we run Raspberry Pi imager

1. Click `Choose device` -&gt; `Raspberry Pi Zero 2 W`.
2. Click `Choose OS` -&gt; `Raspberry Pi OS (other)` -&gt; `Raspberry Pi OS (Legacy, 32 bit) Lite`.
3. Click `Choose Storage` -&gt; Select the SD Card.
4. Click `Next` -&gt; `Edit Settings`.
5. Under `General` set desired hostname, credentials, etc.
6. Under `Services` -&gt; `Enable SSH`. 7 Click `Yes` to create the boot media for the Pi Zero.

Now we transfer the Micro-SD card to the Raspberry Pi Zero with a connected camera.

## Hardware check

We will do this part locally on the Raspberry Pi, so we need to connect a keyboard and display to it, for the Pi Zero we’ll need two adapters to connect a keyboard and a monitor:

- USB-A -&gt; micro-USB
- HDMI -&gt; micro-HDMI

Boot up the Pi Zero and wait for the initial file system resize to complete.

Once it reboots we can log in as the picam user and do a short test of whether the camera is recognized by the OS:

<div class="expressive-code" id="bkmrk-terminal-window-libc"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">libcamera-hello</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>This should open a window on top of the terminal screen for a few seconds that shows the a camera feed.

## Network Setup

We want to set a static IP that will persist on the SD Card in case I want to switch it over to another Raspberry Pi.

For this we edit the dhcp daemon config

<div class="expressive-code" id="bkmrk-terminal-window-sudo"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo nano /etc/dhcpcd.conf</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Towards the bottom we should see some commented out entries we can use. We just uncomment them and change the `ip_address` to our desired IP:

<div class="expressive-code" id="bkmrk-%2Fetc%2Fdhcpcd.conf-sta"><figure class="frame has-title not-content"><figcaption class="header"><span class="title">/etc/dhcpcd.conf</span></figcaption>```
```

<div class="ec-line"><div class="code">static ip_address=192.168.1.100/24</div></div>```
```

<div class="ec-line"><div class="code">static routers=192.168.1.1</div></div>```
```

<div class="ec-line"><div class="code">static domain_name_server=192.168.1.1</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>If there are any Raspberry Pi configurations we still want to change (e.g. enabling SSH in case we haven’t yet or setting the hostname)

Once we reboot we should be able to SSH into the machine

<div class="expressive-code" id="bkmrk-terminal-window-rebo"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">reboot</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>## Upgrade/Install dependencies

We will install docker from the Debian repo after updating the OS packages:

<div class="expressive-code" id="bkmrk-terminal-window-sudo-1"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo apt-get update</div></div>```
```

<div class="ec-line"><div class="code">sudo apt-get upgrade -y</div></div>```
```

<div class="ec-line"><div class="code">sudo apt-get install -y docker.io</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Now we need to add the user to the docker group so it will have the right permissions

<div class="expressive-code" id="bkmrk-terminal-window-sudo-2"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo usermod -aG docker admin</div></div>```
```

<div class="ec-line"><div class="code">newgrp docker</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>## RSTP Server setup

With docker set up we can now use it to run MediaMTX as the RTSP server, lets start it up:

<div class="expressive-code" id="bkmrk-terminal-window-dock"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">docker run --rm -it --network=host --privileged --tmpfs /dev/shm:exec -v /run/udev:/run/udev:ro -e MTX-PATHS-CAM-SOURCE=rpiCamera bluenviron/mediamtx:latest-ffmpeg-rpi</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Once we verified it runs correctly we can set up the service. Create a script to run it:

<div class="expressive-code" id="bkmrk-terminal-window-mkdi"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">mkdir -p /home/admin/src/scripts</div></div>```
```

<div class="ec-line"><div class="code">nano /home/admin/src/scripts/mediamtx.sh</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>with the following content (note, we’re removing `-it` from the above command for this script, as we don’t run an interactive shell for the service):

<div class="expressive-code" id="bkmrk-%2Fhome%2Fadmin%2Fsrc%2Fscri"><figure class="frame has-title not-content"><figcaption class="header"><span class="title">/home/admin/src/scripts/mediamtx.sh</span></figcaption>```
```

<div class="ec-line"><div class="code">\#!/bin/bash</div></div>```
```

<div class="ec-line"><div class="code">\# Will be exposed at rtsp://[ip]:8554/cam</div></div>```
```

<div class="ec-line"><div class="code">docker run --rm --network=host --privileged --tmpfs /dev/shm:exec -v /run/udev:/run/udev:ro -e MTX_PATHS_CAM_SOURCE=rpiCamera bluenviron/mediamtx:latest-ffmpeg-rpi</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>then make it executable:

<div class="expressive-code" id="bkmrk-terminal-window-chmo"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">chmod +x /home/admin/src/scripts/mediamtx.sh</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Now we add the service:

<div class="expressive-code" id="bkmrk-terminal-window-sudo-3"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo nano /etc/systemd/system/mediamtx.service</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>with:

<div class="expressive-code" id="bkmrk-%2Fetc%2Fsystemd%2Fsystem%2F"><figure class="frame has-title not-content"><figcaption class="header"><span class="title">/etc/systemd/system/mediamtx.service</span></figcaption>```
```

<div class="ec-line"><div class="code">[Unit]</div></div>```
```

<div class="ec-line"><div class="code">Description=MediaMTX</div></div>```
```

<div class="ec-line"><div class="code">After=network.target</div></div>```
```

<div class="ec-line"><div class="code">  
</div></div>```
```

<div class="ec-line"><div class="code">[Service]</div></div>```
```

<div class="ec-line"><div class="code">ExecStart=/home/admin/src/scripts/mediamtx.sh</div></div>```
```

<div class="ec-line"><div class="code">Restart=always</div></div>```
```

<div class="ec-line"><div class="code">RestartSec=3</div></div>```
```

<div class="ec-line"><div class="code">User=admin</div></div>```
```

<div class="ec-line"><div class="code">Group=docker</div></div>```
```

<div class="ec-line"><div class="code">  
</div></div>```
```

<div class="ec-line"><div class="code">[Install]</div></div>```
```

<div class="ec-line"><div class="code">WantedBy=default.target</div></div>```
```

<div class="copy"><div>  
</div></div></figure></div>Then we start it and activate startup on system start.

<div class="expressive-code" id="bkmrk-terminal-window-sudo-4"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="sr-only">Terminal window</span></figcaption>```
```

<div class="ec-line"><div class="code">sudo systemctl daemon-reload</div></div>```
```

<div class="ec-line"><div class="code">sudo systemctl start mediamtx</div></div>```
```

<div class="ec-line"><div class="code">\# Check logs to see if it starts up correctly</div></div>```
```

<div class="ec-line"><div class="code">journalctl -u mediamtx -f</div></div>```
```

<div class="ec-line"><div class="code">sudo systemctl enable mediamtx</div></div>```
```

take from [here](https://www.nephridium-labs.com/guides/picam/)

</figure></div>