Prusa Buddy3D Cameras and UniFi Protect

Motivation: This blog post gathers knowledge regarding Prusa’s Buddy3D cameras. Information in the post can be applied to both the spherical and the core one triangular variants. This post will also demonstrate a method of converting Prusa’s RTSP streams to UniFi Protect compatible ONVIF output, allowing the user to stream the camera footage in the Prusa App, Prusa Connect, and their UniFi Protect setup. This is especially useful since Prusa App/Connect does not store footage while UniFi Protect does.

Buddy3D Firmware

Changelogs

You can find the latest version of the firmware and its changelog here: https://prusaconnect.sleekplan.app/changelog

Updating

I believe these cameras are supposed to update themselves, however, if the camera does not have internet access, this mechanism will obviously not work.

Firmware files be found on: https://connect-ota.prusa3d.com/file/cam-3.1.3.tar, with version 3.1.3 being the latest firmware at time of writing. Replace 3.1.3 with whatever the changelog says is the newest version.

To update, rename cam-3.1.3.tar to cus_update_ota.tar, load onto a microSD card, plug the card into the camera, and power on the camera. A voice will indicate whether the firmware was successfully updated.

Streaming RTSP

Once the camera is hooked up to Prusa Connect, you have the option of turning on the local RTSP stream on the Connect website. As per time of writing, FHD is not particularly reliable possibly because of cpu/mem constraints. Use SD or HD instead.

You can view the RTSP stream w/ VLC.

UniFi Protect

Allow 3rd-Party Cameras

UniFi Protect, as per time of writing, allows users to add 3rd-party ONVIF cameras to their ecosystem. To turn on the feature, goto https://unifi.ui.com -> Protect tab -> Settings -> General -> Discover 3rd-Party Cameras.

Converting RTSP to ONVIF via go2rtc

To convert the rtsp stream to ONVIF, use the ghcr.io/alexxit/go2rtc docker image. UniFi Protect is finnicky as it wants a unique LAN ip for each camera feed. This is not an issue if you only have 1 Buddy3D camera. If you want to stream multiple Buddy3D cameras into Protect, use MacVLANs to give each container instance a unique MAC and IP address. Note that MacVLANs are only supported on Linux docker hosts. I believe an IPVLAN would also work here, but I haven’t tested that

Here is an example of a 2 camera setup:

# File: docker-compose.yaml
version: "3.9"

services:
  go2rtc-prusa-core-one:
    image: ghcr.io/alexxit/go2rtc:latest
    container_name: prusa-core-one-camera
    restart: unless-stopped

    # By default, each container will get a new mac address everytime it is brought up and down. If you're using IP <-> MAC
    # binding in UniFi, you may want to freeze the MAC address. I recommend removing this value on first invocation, use
    # `docker network inspect go2rtc_go2rtc_net` to determine container MAC addresses <-> IP address mapping, then freeze
    # it here for future restarts
    mac_address: "02:42:c0:a8:00:7b" # Must be unique, optional
    networks:
      go2rtc_net:
        ipv4_address: 192.168.0.123 # pick a free IP on your LAN. Reserve address in UniFi (e.g. make static IP)

    volumes:
      - ./go2rtc_prusa_core_one.yaml:/config/go2rtc.yaml

    environment:
      - TZ=America/Chicago

  go2rtc-prusa-xl:
    image: ghcr.io/alexxit/go2rtc:latest
    container_name: prusa-xl-camera
    restart: unless-stopped

    # By default, each container will get a new mac address everytime it is brought up and down. If you're using IP <-> MAC
    # binding in UniFi, you may want to freeze the MAC address. I recommend removing this value on first invocation, use
    # `docker network inspect go2rtc_go2rtc_net` to determine container MAC addresses <-> IP address mapping, then freeze
    # it here for future restarts
    mac_address: "02:42:c0:a8:00:8b" # Must be unique, optional
    networks:
      go2rtc_net:
        ipv4_address: 192.168.0.124 # pick a different free IP on your LAN. Reserve address in UniFi (e.g. make static IP)

    volumes:
      - ./go2rtc_prusa_xl.yaml:/config/go2rtc.yaml

    environment:
      - TZ=America/Chicago

networks:
  go2rtc_net:
    driver: macvlan
    driver_opts:
      parent: eth0 # your host interface. Use `ifconfig` to find interface names. Typically, named eth0 or wlan0
    ipam:
      config:
        - subnet: 192.168.0.0/24 # Replace w/ CIDR of your LAN
          gateway: 192.168.0.1 # Replace w/ gateway address of your LAN
# File go2rtc_prusa_core_one.yaml
api:
  onvif: true
streams:
  cam1: rtsp://admin:admin@192.168.0.12:554/live # Prusa's RTSP stream is not password protected, use whatever values (e.g. admin/admin)
# File go2rtc_prusa_xl.yaml
api:
  onvif: true
streams:
  cam1: rtsp://admin:admin@192.168.0.13:554/live # Prusa's RTSP stream is not password protected, use whatever values (e.g. admin/admin)

Bring containers up via docker compose up -d. Each container will have a gortc ONVIF server runing on port :1984.

Add to UniFi Protect

Depending on network conditions, UniFi Protect might not actually auto-discover the ONVIF containers. To add manually, go to UniFi Protect Tab -> Question Mark Circle "Cannot Find Your Device?" -> try advanced adoption. Fill out

IP Address: 192.168.0.123:1984 # Don't forget the port number
Username: admin
Password: admin