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
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
Trio validates the URL is a live stream
Captures a frame every 30 seconds
Pre-filter checks for motion (skips static frames)
If motion detected, VLM analyzes the frame
If snow is detected, webhook fires with watch_triggered
Your server sends SMS via Twilio
After 10 minutes (or after a trigger), job stops and sends job_stopped
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:
Metric Per Job (10 min) Per Hour Per Day Frames captured 20 120 2,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