> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.rhombus.community/llms.txt
> Use this file to discover all available pages before exploring further.

# EdgeCaster RTSP Gateway

> Run EdgeCaster on a Raspberry Pi 5 or any Ubuntu/Debian machine to re-broadcast Rhombus camera streams as sub-second-latency RTSP for legacy VMS, NVR, and third-party video systems.

**EdgeCaster** is a local edge gateway that pulls Rhombus Secure Raw Streams (H.264 over HTTPS) and re-broadcasts them as standard RTSP on your local network using bundled [MediaMTX](https://github.com/bluenviron/mediamtx). It runs on a Raspberry Pi 5, a mini-PC, or any Ubuntu/Debian machine, so legacy VMS, NVR, and third-party AI/video systems that require RTSP can consume video from Rhombus cameras with sub-second added latency. You manage it from a simple web dashboard; it runs 24/7 and heals itself when a stream drops.

<Warning>
  Rhombus does not support RTSP natively because it is not a secure protocol. EdgeCaster bridges this gap for environments that require RTSP compatibility by converting Rhombus's encrypted raw streams locally on your network. Deploy EdgeCaster only on trusted networks.
</Warning>

## How It Works

```text theme={null}
Rhombus Camera
     │
     │ Secure Raw Stream (HTTPS H.264)
     ▼
EdgeCaster (Raspberry Pi 5 / mini-PC / Ubuntu-Debian machine)
     │ FFmpeg stream copy (no transcoding)
     ▼
MediaMTX (RTSP server, port 8554)
     │
     ▼
External Systems (VMS / NVR / AI)
```

EdgeCaster uses the Rhombus API to discover cameras, creates secure raw streams via `createRawHttpStream`, and pipes them through FFmpeg (stream copy — no transcoding) to MediaMTX, which serves them as standard RTSP.

### Sub-Second Latency, Always the Latest Frame

Because streams are copied rather than transcoded (`-c copy`), there is no decode/encode delay. EdgeCaster minimizes latency by stripping buffering at every hop instead:

* **FFmpeg** runs with no input buffering, low-delay flags, reduced probe/analyze time for fast startup, and zeroed mux delay and preload, so packets are forwarded the instant they arrive. The tunables (probe size, analyze duration, stall threshold) are exposed in `/etc/edgecaster/config.yaml` if you need to adjust them on-device.
* **MediaMTX** is tuned for low latency and fast failure detection: its control API is enabled on localhost, and a short read timeout drops a stalled publisher quickly. Each RTSP reader gets its own queue, so a slow consumer cannot add latency to the publisher or to other readers.

The result: EdgeCaster always pushes the newest frame with sub-second added latency inside the device. End-to-end ("glass-to-glass") latency also depends on the camera's GOP/keyframe interval and your consuming system's own buffer, which EdgeCaster doesn't control.

### Unlimited Concurrent Streams

There is no fixed stream limit — the device runs as many streams as its network and CPU allow. Because stream copy is very light, real-world testing on a Raspberry Pi 5 showed a handful of 1080p streams plus multiple RTSP readers at roughly 3% CPU, leaving large headroom. `max_streams: 0` (the default) means unlimited; set a positive value in `config.yaml` if you want an optional hard safety ceiling.

### 24/7 Self-Healing

EdgeCaster monitors each stream at the **frame level** using FFmpeg's progress output — not just "is the process alive" — so a frozen-but-alive feed (no new frames) is detected within seconds by a watchdog. All failure triggers (process exit, frozen feed, dead process) funnel through one recovery path that guarantees exactly one relaunch, with no double-restart races. Recovery re-fetches a fresh Secure Raw Stream URL from Rhombus (stream tokens expire) and resumes, typically within seconds.

If a stream keeps failing, EdgeCaster retries fast (every 5 seconds, up to 10 times), then backs off to every 5 minutes — and keeps trying forever. It never permanently gives up on a 24/7 device. Frozen-feed recovery uses a lighter, faster backoff.

## Features

* Sub-second added latency, always-latest-frame restreaming (stream copy, no transcoding)
* Unlimited concurrent streams — as many as your device's network and CPU allow
* 24/7 self-healing with frame-level stall detection and automatic stream URL refresh
* Live health dashboard with real-time metrics over Server-Sent Events
* Webhook alerts for stream drops and device strain (Slack, Make.com, or any HTTP listener)
* Live logs viewer in the dashboard — no SSH needed
* Optional one-click secure public access via a Cloudflare quick tunnel
* Automatic camera discovery via the Rhombus API
* Persistent stream state across reboots; streams auto-restore on startup
* Nightly auto-updates, a one-line installer, and a ready-to-flash Raspberry Pi image

## Requirements

| Component | Requirement |
| - | - |
| **Device** | Raspberry Pi 5 (8 GB RAM recommended) or any Ubuntu/Debian machine (mini-PC, VM) |
| **Architecture** | arm64, amd64, or armv7 |
| **Network** | Wired Gigabit Ethernet |
| **OS** | Ubuntu or Debian (the Pi image ships Ubuntu Server 24.04) |
| **Rhombus** | Org API Key |

## Install

<Tabs>
  <Tab title="One-Line Install">
    On any machine running **Ubuntu or Debian** (Raspberry Pi, mini-PC, or virtual machine), run:

    ```bash theme={null}
    curl -fsSL https://raw.githubusercontent.com/RhombusSystems/edgecaster-stream-converter/main/scripts/bootstrap.sh | sudo bash
    ```

    The script downloads and installs everything — FFmpeg, MediaMTX, systemd services — then prints the web address to open.
  </Tab>

  <Tab title="Raspberry Pi Image">
    Flash a ready-to-use image — no typing required:

    <Steps>
      <Step title="Get the image">
        Ask Rhombus for the EdgeCaster SD-card image, or build one yourself (see the next tab).
      </Step>

      <Step title="Flash it">
        Write the `.img.xz` file to an SD card with the free [Raspberry Pi Imager](https://www.raspberrypi.com/software/).
      </Step>

      <Step title="Boot">
        Put the card in a **Raspberry Pi 5**, connect it to your network with an Ethernet cable, and power it on.
      </Step>

      <Step title="Open the dashboard">
        Wait a few minutes, then open `http://edgecaster.local` in a web browser.
      </Step>
    </Steps>

    On first boot the device sets its hostname to `edgecaster`, creates the `edgecaster` user (default password: `edgecaster`), and starts all services.

    <Warning>
      Change the default password immediately after first login: `passwd edgecaster`
    </Warning>
  </Tab>

  <Tab title="Git Checkout / Image Builder">
    Install from a git checkout:

    ```bash theme={null}
    git clone https://github.com/RhombusSystems/edgecaster-stream-converter.git
    cd edgecaster-stream-converter
    sudo bash scripts/install.sh
    ```

    The installer keeps a git checkout on the device, so manual installs receive nightly auto-updates just like the Pi image.

    To build a flashable SD-card image instead:

    ```bash theme={null}
    # Cloud-init mode (smaller image, needs internet on first boot)
    sudo bash image/build-image.sh

    # Pre-baked mode (larger image, no internet needed on first boot)
    sudo bash image/build-image.sh --prebaked
    ```

    Output is a flashable `.img.xz`.
  </Tab>
</Tabs>

## Set Up (2 Minutes)

<Steps>
  <Step title="Open the dashboard">
    Open EdgeCaster in a web browser: `http://edgecaster.local` or `http://<device-ip>`.
  </Step>

  <Step title="Paste your Rhombus Org API Key">
    Your cameras appear automatically.
  </Step>

  <Step title="Toggle a camera on">
    Flip the switch next to any camera to start its RTSP stream.
  </Step>

  <Step title="Connect your systems">
    Copy the camera's RTSP link into your VMS, NVR, or AI system:

    ```text theme={null}
    rtsp://<device-ip>:8554/front_door
    rtsp://<device-ip>:8554/warehouse
    rtsp://<device-ip>:8554/parking_lot
    ```

    Camera names are normalized to URL-safe slugs and persisted, so RTSP paths survive reboots. Test with VLC: `vlc rtsp://<device-ip>:8554/<stream-name>`
  </Step>
</Steps>

## Web Dashboard

The dashboard is a clean, responsive operator console that works on any device or browser — on mobile, the sidebar becomes a drawer. A persistent status pulse (live stream count and a health dot) is always visible in the top bar.

### Live Health Metrics

The dashboard streams metrics live (about once per second) over Server-Sent Events — no manual refresh: active streams, cameras found, CPU %, memory %, temperature, power/throttle status (under-voltage and throttling), 1-minute load average, uptime, and per-stream throughput and reader counts.

<Note>
  **Raspberry Pi temperature and power/throttle metrics require the Raspberry Pi kernel** (`linux-raspi`). On the Ubuntu `-generic`/`virtual` kernel these read "N/A" because the OS exposes no thermal sensors. Fix: `sudo apt-get install -y linux-raspi && sudo reboot`. Everything else works regardless.
</Note>

### Webhook Alerts

EdgeCaster can send an alert to a generic webhook — a Slack incoming webhook, Make.com, or any HTTP listener — when:

* A stream drops or can't recover
* The Pi reports **under-voltage** (power constrained)
* The Pi reports **thermal throttling**
* CPU or load average stays high

Thresholds are configurable, each alert has a cooldown, and alerts clear on recovery so the webhook isn't spammed. Set it up under **Settings → Alerts**, which includes a **Send test alert** button. Active alerts also show on the dashboard.

### Live Logs

A **Logs** tab (under **Cameras**) shows the device's logs live in a terminal-style console — useful for diagnosing a camera or connection issue without SSH:

* Sources: **Application**, **Streams**, and **Rhombus API**
* New lines stream in live, with color-coded log levels
* Pause and clear controls

## Public Access (Optional)

To reach the dashboard from outside your network, go to **Settings → Public Access**, set a **username and password**, and click **Turn on public access**. EdgeCaster creates a secure public link via a **Cloudflare quick tunnel** and shows it. No Cloudflare account, token, or configuration is required.

The access model: on your **local network you never log in**; the **public link always requires** the username and password. Only traffic arriving over the public tunnel is challenged (HTTP Basic auth); the password is stored hashed, never in plaintext.

<Warning>
  * The public link is **ephemeral** — it changes each time public access restarts. That's the trade-off for needing zero Cloudflare credentials.
  * The link exposes camera controls: use a strong password and turn public access off when you don't need it.
  * Only the web dashboard is exposed publicly — **RTSP is not tunneled** and stays on the LAN.
</Warning>

Public access requires the `cloudflared` helper, which the installer includes.

## Network Ports

| Port | Purpose |
| - | - |
| **80** | Web UI |
| **8554** | RTSP streams (MediaMTX) |
| 8000 | Backend API (internal, localhost only) |
| 9997 | MediaMTX control API (internal, localhost only) |

## Rhombus API Endpoints Used

EdgeCaster interacts with 5 Rhombus API endpoints automatically:

| Endpoint | Purpose |
| - | - |
| `POST /api/camera/getMinimalCameraStateList` | Discover cameras in your organization |
| `POST /api/camera/createRawHttpStream` | Create a secure raw stream for a camera |
| `POST /api/camera/deleteRawHttpStream` | Clean up stream when disabled |
| `POST /api/camera/getRawHttpStreams` | List existing raw streams |
| `POST /api/location/getLocationLabelsForOrg` | Resolve location names for the UI |

## Managing Services

EdgeCaster runs as systemd services (`edgecaster` and `mediamtx`) with watchdog integration. Enabled cameras and their RTSP slugs persist across reboots, and streams auto-restore on startup.

```bash theme={null}
# Check status
sudo systemctl status edgecaster mediamtx

# View logs
journalctl -u edgecaster -f

# Restart
sudo systemctl restart edgecaster

# Update now (also runs nightly on its own)
sudo bash /opt/edgecaster/scripts/edgecaster-update.sh

# Uninstall
sudo bash /opt/edgecaster/scripts/uninstall.sh
```

## Auto-Updates

EdgeCaster checks for updates hourly and applies them (git fast-forward) during a configurable window (default: 2:00–5:00 AM). All install methods auto-update, including manual git-checkout installs. Configure via the web UI Settings page or directly:

```yaml theme={null}
# /etc/edgecaster/config.yaml
auto_update_enabled: true
update_hour_start: 2
update_hour_end: 5
```

## Configuration

Configuration lives in `/etc/edgecaster/config.yaml`; runtime state (enabled cameras and RTSP slugs) lives in `/var/lib/edgecaster/state.json`; logs live in `/var/log/edgecaster/`. Notable keys:

```yaml theme={null}
# /etc/edgecaster/config.yaml
max_streams: 0               # 0 = unlimited (default); positive value = hard ceiling
stall_threshold_seconds: 6   # frozen-feed detection threshold
ffmpeg_probesize: 500000     # lower = faster startup
ffmpeg_analyzeduration: 1000000
alerts_enabled: false
alert_webhook_url: ""
cpu_alert_threshold: 85      # percent, sustained
temp_alert_threshold_c: 80
load_alert_threshold: 0      # 1-min load average; 0 = disabled
```

## Local Development

<CodeGroup>
  ```bash Backend theme={null}
  python3 -m venv venv
  source venv/bin/activate
  pip install -r requirements.txt
  cd backend
  uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
  ```

  ```bash Frontend theme={null}
  cd frontend
  npm install
  npm run dev
  # Dev server on http://localhost:5173, proxies /api to backend
  ```

  ```bash Tests theme={null}
  pip install pytest pytest-asyncio
  python -m pytest backend/tests/ -v
  ```
</CodeGroup>

## EdgeCaster API

The EdgeCaster backend exposes a local REST API:

| Method | Path | Description |
| - | - | - |
| `GET` | `/api/auth/status` | Check setup state |
| `GET` | `/api/settings` | Get app settings |
| `POST` | `/api/settings/api-key` | Set Rhombus API key |
| `PUT` | `/api/settings/update-schedule` | Configure auto-update window |
| `PUT` | `/api/settings/alerts` | Configure webhook alerts |
| `POST` | `/api/settings/alerts/test` | Send a test alert |
| `GET` | `/api/settings/public-access` | Get public access status |
| `POST` | `/api/settings/public-access/credentials` | Set public access username/password |
| `POST` | `/api/settings/public-access/enable` | Turn on public access |
| `POST` | `/api/settings/public-access/disable` | Turn off public access |
| `POST` | `/api/settings/discovery/refresh` | Refresh camera list from Rhombus |
| `GET` | `/api/cameras` | List discovered cameras |
| `GET` | `/api/streams` | List active RTSP streams |
| `POST` | `/api/streams/{uuid}/enable` | Start RTSP stream for a camera |
| `POST` | `/api/streams/{uuid}/disable` | Stop RTSP stream |
| `GET` | `/api/system/status` | System health snapshot |
| `GET` | `/api/system/stream` | Live system status (Server-Sent Events, \~1s) |
| `GET` | `/api/logs` | Log snapshot |
| `GET` | `/api/logs/stream` | Live log tail (Server-Sent Events) |
| `GET` | `/api/logs/sources` | List available log sources |

## Limitations

* RTSP authentication is not enabled in v1 — restrict access via network controls (can be added via MediaMTX config)
* Consuming systems must be on the local network — RTSP is not tunneled by public access
* Secure raw stream tokens expire automatically; EdgeCaster re-fetches them on recovery
* No login on the LAN web UI — trusted network deployment only (public access adds a login for the public tunnel only)

## Security Notes

* Your API key is stored in `/etc/edgecaster/config.yaml` (owned by the `edgecaster` user, not world-readable)
* API keys are never logged or exposed in API responses
* The systemd service runs with hardened security: `NoNewPrivileges`, `ProtectSystem=strict`, `ProtectHome`, `PrivateTmp`
* RTSP streams are unauthenticated — restrict port 8554 access at the network level
* With public access on, only tunnel traffic is challenged with HTTP Basic auth; the password is stored hashed (never plaintext) and LAN traffic is never challenged

## Troubleshooting

<AccordionGroup>
  <Accordion title="No cameras found">
    Verify your Rhombus API key is valid and has access to cameras. Check that the device can reach `api2.rhombussystems.com`. Try refreshing discovery from the Settings page.
  </Accordion>

  <Accordion title="Stream not starting">
    Check FFmpeg is installed (`ffmpeg -version`), MediaMTX is running (`systemctl status mediamtx`), and the camera is online. Check the **Logs** tab under Cameras, or view logs with `journalctl -u edgecaster -f`.
  </Accordion>

  <Accordion title="RTSP URL not working">
    Confirm the stream shows "running" in the web UI. Test with VLC: `vlc rtsp://<device-ip>:8554/<path>`. Check that port 8554 is not blocked by a firewall.
  </Accordion>

  <Accordion title="Temperature or power status shows N/A">
    On a Raspberry Pi running the Ubuntu `-generic` or `virtual` kernel, the OS exposes no thermal sensors. Install the Pi kernel: `sudo apt-get install -y linux-raspi && sudo reboot`. All other metrics work regardless.
  </Accordion>

  <Accordion title="Public link stopped working">
    The public link is ephemeral — it changes each time public access restarts (for example after a reboot). Open **Settings → Public Access** on the LAN to see the current link.
  </Accordion>

  <Accordion title="Auto-update not running">
    Check the timer: `systemctl status edgecaster-update.timer`. Verify the installation is git-based (`.git` folder exists) and the current time falls within the update window.
  </Accordion>
</AccordionGroup>

## Need Help?

Email [support@rhombus.com](mailto:support@rhombus.com) and we'll help you get set up. It helps to include what you were doing and anything shown on the dashboard.

## Resources

<CardGroup cols={2}>
  <Card title="GitHub Repository" icon="github" href="https://github.com/RhombusSystems/edgecaster-stream-converter">
    Source code, image builder, and issue tracker
  </Card>

  <Card title="Streaming Video Guide" icon="video" href="/implementations/streaming-video">
    Direct streaming integration without RTSP conversion
  </Card>

  <Card title="React SDK" icon="react" href="/implementations/react-sdk">
    Embed camera streams in React applications
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/overview">
    Full documentation for raw stream and camera endpoints
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.