RPi Streaming Cameras for Equipment Monitoring#

An example of equipment monitoring happening at the Acceleration Consortium is available at https://www.youtube.com/@ac-hardware-streams.

This is intended to be run on a Raspberry Pi Zero 2W Raspberry Pi Camera Module 3 running RPi OS Lite (bookworm, 64-bit).

Note

Optionally, complete the following network setup steps, applicable to devices such as Raspberry Pis running RPi OS Lite.

  • Consider setting up Tailscale for secure remote access and management. Please refer to the Tailscale Setup Guide for detailed instructions on installation and configuration.

  • If you need to connect to a WPA2-Enterprise WiFi network (common in institutional environments), please refer to the Raspberry Pi WPA2-Enterprise WiFi Setup Guide first.

image

image

Bill of Materials#

The following components are required for the equipment monitoring setup.

Note

There is a standalone DigiKey cart available containing most (not all) of the required components, including the optionals of HDMI and USB-A port adapters

Core Hardware#

Camera Components#

Power#

Optional Troubleshooting Items#

These items are optional and don’t factor into the final price shown. They’re useful if you’re unable to SSH into the machine:

Mounting Hardware#

Option A: Off-the-shelf mount kit

Option B: DIY mounting solution (recommended):

Rod Clamp Assembly & Mounting#

Tools Required (separate from total cost)#

Total estimated cost: 109-115 CAD (as of 2025-05-31, excluding 3D printing, camera desk mount, hex nut, and tools) Tool costs: 30-45 CAD (separate from main components, not included in total)

Note: Most electronic components have verified working links to PiShop.ca. Hardware components like screws and nuts are available at local hardware stores or McMaster-Carr.

Hardware Setup#

Ensure you connect the camera cable properly. Follow these steps:

  1. Power off and disconnect your Raspberry Pi from any power source.

  2. Orient the camera ribbon cable so that the metal contacts face the connector on the Pi (with Pi Zero 2W lying flat on its back, metal contacts should be facing down)

  3. Carefully insert the ribbon cable fully into the camera connector (with camera facing upside down, the metal contacts should be facing down as well)

  4. Lock the connector latch to secure the cable.

  5. Reconnect power and turn on your Raspberry Pi.

Safety Note: Always disconnect power from your Raspberry Pi before attaching or removing the camera to prevent hardware damage.

The images below show the correct orientation and connection:

image image

The following shows an assembled camera setup, without any mounting hardware:

image

Codebase#

Refresh the system’s package list via:

sudo apt update

Optionally, upgrade the system packages to the latest versions via sudo apt upgrade -y (-y flag is used to automatically answer “yes” to any installation prompts)

Ensure that git is installed:

sudo apt-get install git -y

Clone the repository to your Raspberry Pi Zero 2W device via HTTPS (allows for git pull to work without needing to enter credentials each time):

git clone https://github.com/AccelerationConsortium/ac-training-lab.git

Navigate to the same directory as this README file. This assumes that your username is ac.

cd /home/ac/ac-training-lab/src/ac_training_lab/picam/

Secrets#

Make a copy of my_secrets_example.py called my_secrets.py:

cp my_secrets_example.py my_secrets.py

Fill in the necessary information (e.g., via nano my_secrets.py). Keep in mind this will store the credentials in plain-text format, so try to keep your Pi login secure and restrict the access scope for the credentials as much as possible.

Required Configuration Variables#

AUTH_BASE_URL#

The base URL of the GitHub auth service that issues JWTs for the Lambda. On first run, device.py opens a browser to this service, waits for login to complete, and caches the returned token locally in ~/.config/ac-picam/token.json.

Example: "http://tacozoid11.tail6a1dd7.ts.net:5000"

AUTH_TAILSCALE_IP (optional)#

Only needed when the client reaches the auth server one way, but the browser should be sent to a different Tailscale host or IP for login. In the common case, set AUTH_BASE_URL directly and leave this unset.

Example: "tacozoid11.tail6a1dd7.ts.net"

LAMBDA_FUNCTION_URL#

The AWS Lambda Function URL for the YouTube streaming service. This Lambda function handles YouTube API authentication and stream management.

Setup Steps:

  1. Deploy the ac-streaming-lambda-core Lambda service to your AWS account

  2. Copy the Lambda Function URL, which looks like https://your-unique-id.lambda-url.region.on.aws/

  3. Use this URL as your LAMBDA_FUNCTION_URL

Note: This client gets its JWT from the separate auth.py GitHub auth service. The Lambda itself separately needs YouTube OAuth credentials configured in AWS.

CAM_NAME#

A descriptive name for this specific camera device. This appears in YouTube broadcast titles and helps identify individual cameras when you have multiple devices.

Examples: "PiCam-01", "LabCam-A", "MainCamera"

WORKFLOW_NAME#

CRITICAL: This must be unique across all your streaming devices to prevent conflicts.

The workflow name is used to:

  • Create and organize YouTube playlists

  • Identify which streams to end/restart

  • Group related video streams

Requirements:

  • Must be unique across all devices (see Issue #290)

  • Keep it concise due to YouTube character limits

  • Use descriptive names for your experimental setup or location

Examples: "SDLT-Toronto-001", "MyLab-Setup-A", "AC-Synthesis-Bench"

PRIVACY_STATUS#

Controls the visibility of your YouTube live stream:

  • "private" - Only you can view (requires YouTube account login)

  • "public" - Anyone can find and view the stream

  • "unlisted" - Anyone with the link can view, but it won’t appear in search results

Recommendation:

  • Use "unlisted" for lab monitoring. This provides controlled access while keeping streams discoverable by your team.

  • If you use "private", you must provide access by adding a Google account for each person.

  • Each person added to the channel will be able to see all videos in the channel.

  • With "unlisted", you can share specific playlists or videos individually.

Camera Orientation Settings#

  • CAMERA_VFLIP - Set to True to flip the camera image vertically

  • CAMERA_HFLIP - Set to True to flip the camera image horizontally

Adjust these based on your camera mounting orientation to ensure the video appears right-side-up.

Dependencies#

If not already installed (not pre-installed on RPi OS Lite), install picamera2 via:

sudo apt install python3-picamera2 --no-install-recommends

libcamera should be automatically installed after installing picamera2. Otherwise, one would use sudo apt install -y python3-libcamera (libcamera also does not come preinstalled on RPi OS Lite versions).

Also install FFmpeg:

sudo apt install ffmpeg --no-install-recommends

Use the venv command to create a virtual environment to a new folder venv with the --system-site-packages flag so that it can use the picamera2 and libcamera libraries and activate the environment via the following commands:

python3 -m venv --system-site-packages venv
source venv/bin/activate

While one could use the built-in Python installation (this device is intended to be run via a single top-level script, the RPi device (in our case RPi Zero 2W) requires minimal setup (i.e., can easily be reflashed), and the RPi device is intended for a single purpose with a single set of requirements (i.e., a “point-and-shoot” camera)), the extra steps involved to make this work are as equally onerous as using a venv [context], hence we only include instructions assuming a venv.

Install the Python dependency used by the client:

pip install -r requirements.txt

“Local” (i.e., not RPi OS) OS Development#

For local development (e.g., on your PC rather than the Raspberry Pi to make version control easier) with a dummy version of picamera2 (very minimal mock package), while in the same folder as this README file, additionally run pip install -e ./dummy_pkg/. WARNING: do not install this on the Raspberry Pi for the toolhead camera – the imports will overlap with the “real” system packages picamera2 and libcamera.

Running the Device#

To start the device manually and ensure that it’s functioning normally, run:

python3 device.py

On first run, the script opens a browser for GitHub login and caches the Lambda token automatically in ~/.config/ac-picam/token.json. If Lambda returns 401, the script retries the login flow automatically. On non-Raspberry Pi machines, it stops after the Lambda dry-run once it has obtained the stream URL.

Automatic startup#

To create the file, run nano (or other editor of choice):

sudo nano /etc/systemd/system/device.service

Copy the following code into the file (right click to paste), save it via Ctrl+O and Enter and exit via Ctrl+X. This assumes that your username is ac.

[Unit]
Description=Start picam device.py script
After=network-online.target
Wants=network-online.target

[Service]
# Launch the device script (adjust the path as needed)
WorkingDirectory=/home/ac/ac-training-lab/src/ac_training_lab/picam
# Best to specify the full path to the Python interpreter or use ExecSearchPath
ExecStart=/home/ac/ac-training-lab/src/ac_training_lab/picam/venv/bin/python3 device.py
# Restart whenever the script exits ('always' because sometimes it throws an error but still exits gracefully)
Restart=always
RestartSec=10

# Limit restart attempts to avoid a rapid infinite loop (e.g., up to max 9 times per day, assuming a StartLimitBurst of 3, 28800 seconds == 8 hours, "h" syntax wasn't working on RPi, so using seconds)
StartLimitInterval=3600
StartLimitBurst=3

# Allow up to 60 seconds for the script to start properly
TimeoutStartSec=60

[Install]
WantedBy=multi-user.target

Run:

sudo systemctl daemon-reload
sudo systemctl enable device.service

Run:

sudo crontab -e

Add the following at the end of the crontab file:

#
# Restart at 5 am, 1 pm, and 9 pm, local time (set up during flashing, or specified manually via e.g., `sudo timedatectl set-timezone America/New_York`)
0 5,13,21 * * * /sbin/shutdown -r now

Manually start the service by running:

sudo systemctl start device.service

Note: This is the end of the picam setup. On reboot, a livestream should automatically start.


This command tells systemd to run your service immediately (as if it had been triggered at boot). To check its status, use:

sudo systemctl status device.service

To view any logs:

sudo journalctl -u device.service -f

Starting the service with systemd is recommended since it applies all the configured options (dependencies, restart behavior, etc.).

For more details, see the systemctl(1) manual.

To stop the service (for example, while you work on fixing it / pulling new changes), run:

sudo systemctl stop device.service

This command stops the running instance of the service immediately. If you also want to prevent it from starting at boot until you’ve fixed it, you can disable it with:

sudo systemctl disable device.service

To get it to reflect the new changes, run:

sudo systemctl daemon-reload

You can list all available service unit files by running:

systemctl list-unit-files --type=service

This will display a list of service files along with their state (enabled, disabled, static, etc.). It shows unit files from all directories (such as /etc/systemd/system, /usr/lib/systemd/system, and /run/systemd/system).

For a list of all loaded (active or inactive) service units, you can use:

systemctl list-units --all --type=service

For more details on managing services, check out the systemctl(1) manual [transcript].

Troubleshooting#

If you get the error:

Codec AVOption preset (Encoding preset) has not been used for any stream. The most likely reason is either wrong type (e.g. a video option with no video streams) or that it is a private option of some decoder which was not actually used for any stream.`

then follow these steps:

  1. Run rpicam-hello (Trixie) or libcamera-hello (Bookworm) to check if the camera is detected and working.

  2. Verify that the physical connections are correct according to the hardware setup instructions above.

  3. Try swapping out the camera with a new one to help with debugging.

  4. If the issue persists, try swapping out the Pi Zero 2W with a new one. Related issue(s):