Source Code
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.
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#
Raspberry Pi Zero 2W (or Zero 2WH) - $21.50 CAD
MicroSD Card 32GB Class 10 - $13.95 CAD
MicroSD Card Reader - $2.95 CAD
Aluminum Heatsink for Raspberry Pi B+/2/3 (2-Pack) - $2.45 CAD
Alternative: Heat Sink Kit for RPi Zero - $5.95 CAD [OPTIONAL - better cooling]
Note: The cheaper heat sink is the default as it doesn’t require additional hardware. The more expensive one provides better cooling.
Camera Components#
Raspberry Pi Camera Module 3 - $35.00 CAD
Raspberry Pi Zero Camera Cable - $3.95 CAD [OPTIONAL]
Note: The RPi Camera Module 3 comes with a long cable you can use, but you can replace it with this shorter cable for cleaner mounting
Power#
Compact 2A Power Adapter with USB-A socket - $16.65 CAD
USB-A male to Micro USB male cable (2m) - $3.19 CAD
Note: Pi Zero 2W uses micro USB for power, not USB-C
USB-A extension cable (2m) - $5.54 CAD [OPTIONAL]
International Power Adapter - $33.93 CAD [OPTIONAL, for international]
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:
Mini HDMI Plug to Standard HDMI Jack Adapter - $3.45 CAD [OPTIONAL]
6FT High Speed HDMI Cable With Ethernet - $2.95 CAD [OPTIONAL]
USB OTG Host Cable - MicroB OTG male to A female - $3.45 CAD [OPTIONAL]
Wireless Keyboard and Mouse Combo with USB Dongle - Amazon [OPTIONAL]
External Monitor [OPTIONAL]
Note: These items provide a simple fix for situations where SSH access is unavailable
Mounting Hardware#
Option A: Off-the-shelf mount kit
Pro Mini Camera Mount for Raspberry Pi Zero - $7.95 CAD
Note: Off-the-shelf mount works but might need to be secured so the two laser cut pieces don’t wobble relative to each other
Option B: DIY mounting solution (recommended):
3D Printable PiCam Mount (STL files in repository)
M2 Hardware (4 pieces needed):
M2 Nylon Hex Standoff Spacer Screw Nut Assortment Kit (150 Pieces) - $7.95 CAD - PiShop.ca
Note: This kit contains 150+ pieces including screws, nuts, and standoffs. You only need 4 M2Ă—12mm screws and 4 M2 nuts from this kit.
M2.5 Hardware (4 pieces needed):
White Nylon Screw and Stand-off Set - M2.5 - 420 pieces - $18.95 CAD - PiShop.ca
Note: This kit contains 420+ pieces including screws, nuts, and standoffs. You only need 4 M2.5Ă—8mm screws, 4 M2.5 nuts, and 4 M2.5Ă—8mm standoffs from this kit.
Note: Assembly instructions available at ThePiHut
Rod Clamp Assembly & Mounting#
Camera Desk Mount Table Stand - Prime Cables (~$20-30 CAD)
1/4”-20 Hex Nut (7/16” hex driver required, or finger-tighten) - McMaster-Carr for secure rod mounting (~$5-10 CAD)
Tools Required (separate from total cost)#
Small Precision Screwdriver Set - McMaster-Carr (~$15-20 CAD)
2.5mm Hex Key/Allen Wrench - McMaster-Carr (~$10-15 CAD)
7/16” Hex Nut Driver Tool - McMaster-Carr (~$5-10 CAD)
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:
Power off and disconnect your Raspberry Pi from any power source.
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)
Carefully insert the ribbon cable fully into the camera connector (with camera facing upside down, the metal contacts should be facing down as well)
Lock the connector latch to secure the cable.
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:
The following shows an assembled camera setup, without any mounting hardware:
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:
Deploy the
ac-streaming-lambda-coreLambda service to your AWS accountCopy the Lambda Function URL, which looks like
https://your-unique-id.lambda-url.region.on.aws/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 toTrueto flip the camera image verticallyCAMERA_HFLIP- Set toTrueto 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:
Run
rpicam-hello(Trixie) orlibcamera-hello(Bookworm) to check if the camera is detected and working.Verify that the physical connections are correct according to the hardware setup instructions above.
Try swapping out the camera with a new one to help with debugging.
If the issue persists, try swapping out the Pi Zero 2W with a new one. Related issue(s):