Skip to main content
Let’s build a system that monitors a Pittsburgh webcam and sends you an SMS via Twilio when snow is detected.
Remember: Jobs auto-stop after 10 minutes. For continuous monitoring, your webhook should restart the job.

How to use examples

Use this recipe as a template:
  • Replace the stream URL with your own live source.
  • Replace the condition with your domain-specific event.
  • Keep the webhook + restart pattern for long-running monitoring.

The Setup

We’ll use:
  • Trio to monitor a Pittsburgh traffic cam
  • Twilio to send SMS alerts
  • A simple webhook receiver that restarts jobs when they expire

Step 1: Find a Live Stream

Pittsburgh has several public traffic cams. Search YouTube for “pittsburgh live cam” or “traffic cam live”.
The URL must be an active live stream. Regular videos and past streams will be rejected with a 400 error.

Step 2: Create the Webhook Receiver

Set these environment variables in your host:
  • TRIO_API_KEY (from the Trio console)
  • WEBHOOK_HOST (your public base URL, e.g., https://your-webhook-server.com)
  • TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN
  • TWILIO_PHONE, MY_PHONE
webhook_server.py
from fastapi import FastAPI, Request, BackgroundTasks
from twilio.rest import Client
import httpx
import os

app = FastAPI()

twilio_client = Client(
    os.environ["TWILIO_ACCOUNT_SID"],
    os.environ["TWILIO_AUTH_TOKEN"]
)

TRIO_API_BASE = "https://trio.machinefi.com/api"
TRIO_API_KEY = os.environ["TRIO_API_KEY"]

# Track current job
current_job_id = None
STREAM_URL = "https://youtube.com/watch?v=PITTSBURGH_LIVE_CAM"
CONDITION = "Is it snowing? Look for falling snowflakes or white accumulation."

async def start_live_monitor_job():
    """Start or restart the live monitor job."""
    global current_job_id

    async with httpx.AsyncClient() as client:
        response = await client.post(
            f"{TRIO_API_BASE}/live-monitor",
            json={
                "stream_url": STREAM_URL,
                "condition": CONDITION,
                "webhook_url": f"{os.environ['WEBHOOK_HOST']}/snow-alert",
                "interval_seconds": 30,
            },
            headers={"Authorization": f"Bearer {TRIO_API_KEY}"},
        )

        if response.status_code == 200:
            current_job_id = response.json()["job_id"]
            print(f"Started job: {current_job_id}")
        else:
            print(f"Failed to start job: {response.text}")

@app.on_event("startup")
async def startup():
    """Start monitoring on server startup."""
    await start_live_monitor_job()

@app.post("/snow-alert")
async def snow_alert(request: Request, background_tasks: BackgroundTasks):
    payload = await request.json()

    # Handle trigger events
    if payload.get("type") == "watch_triggered":
        data = payload.get("data", {})

        # Send SMS alert
        twilio_client.messages.create(
            body=f"It's snowing in Pittsburgh!\n\n{data.get('explanation', '')}",
            from_=os.environ["TWILIO_PHONE"],
            to=os.environ["MY_PHONE"],
        )
        print("Snow alert sent!")

    # Handle job status events (auto-stop after 10 min or after trigger)
    elif payload.get("type") == "job_stopped":
        data = payload.get("data", {})

        # Restart for continuous coverage when the job auto-stops
        if data.get("auto_stopped"):
            reason = data.get("reason", "unknown")
            print(f"Job auto-stopped ({reason}), restarting...")
            background_tasks.add_task(start_live_monitor_job)
        else:
            print("Job was manually stopped")

    return {"status": "ok"}
Deploy this to Railway, Vercel, or any hosting provider.

Step 3: Start Monitoring

The webhook server automatically starts the job on startup. If you need to manually start:
curl -X POST https://trio.machinefi.com/api/live-monitor \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "stream_url": "https://youtube.com/watch?v=PITTSBURGH_LIVE_CAM",
    "condition": "Is it snowing? Look for falling snowflakes or white accumulation.",
    "webhook_url": "https://your-webhook-server.com/snow-alert",
    "interval_seconds": 30
  }'

What Happens

  1. Trio validates the URL is a live stream
  2. Captures a frame every 30 seconds
  3. Pre-filter checks for motion (skips static frames)
  4. If motion detected, VLM analyzes the frame
  5. If snow is detected, webhook fires with watch_triggered
  6. Your server sends SMS via Twilio
  7. After 10 minutes (or after a trigger), job stops and sends job_stopped
  8. Your server restarts the job automatically for continuous coverage

Webhook Payloads

Watch Trigger

{
  "type": "watch_triggered",
  "timestamp": "2024-01-26T15:30:00Z",
  "source_url": "https://youtube.com/watch?v=PITTSBURGH_LIVE_CAM",
  "data": {
    "condition": "Is it snowing?",
    "triggered": true,
    "explanation": "Light snow is falling, visible as white particles against the dark buildings.",
    "prefilter_skipped": false,
    "frame_b64": "base64-encoded-image..."
  }
}

Job Auto-Stop (10 minutes)

{
  "type": "job_stopped",
  "timestamp": "2024-01-26T15:40:00Z",
  "source_url": "https://youtube.com/watch?v=PITTSBURGH_LIVE_CAM",
  "data": {
    "job_id": "abc123...",
    "status": "stopped",
    "checks_performed": 20,
    "triggers_fired": 0,
    "frames_skipped": 80,
    "auto_stopped": true,
    "reason": "max_duration_reached",
    "watch_duration_seconds": 600.0
  }
}

Cost Analysis

With 10-minute job cycles and 30-second intervals:
MetricPer Job (10 min)Per HourPer Day
Frames captured201202,880
VLM calls (with pre-filter)~5-10~30-60~720-1,440
VLM cost~$0.001~$0.006~$0.14
The pre-filter typically saves 50-70% on API costs by skipping static frames.

Monitoring Dashboard

Check your job status and metrics:
# Current jobs
curl https://trio.machinefi.com/api/jobs \
  -H "Authorization: Bearer YOUR_API_KEY"

# API usage metrics (internal endpoint)
curl https://trio.machinefi.com/api/metrics \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "X-Trio-Internal: true"

# Recent logs (internal endpoint)
curl "https://trio.machinefi.com/api/logs?level=INFO&limit=20" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "X-Trio-Internal: true"

Wrapping Up

You now have a production-ready snow alerting system that:
  • Automatically restarts after 10-minute job limits
  • Sends SMS alerts via Twilio
  • Costs less than $0.15/day with pre-filtering
The same pattern works for:
  • Rain detection
  • Fog/visibility monitoring
  • Traffic incident detection
  • Crowd density monitoring

Full API Reference

Explore all live monitor endpoint options