Skill: porygonthebot/frigate (version 1.0.3)

--- name: frigate description: Access Frigate NVR cameras with session-based authentication. Get live snapshots, retrieve motion events, and fetch stream URLs. Includes CLI helper script for doorbell, driveway, front, east, mailbox, and garage cameras. --- # Frigate NVR Integration Access Frigate NVR server at `FRIGATE_URL` with credentials from `FRIGATE_USER` and `FRIGATE_PASS` environment variables. ## Authentication Frigate uses session-based authentication (not HTTP Basic Auth): ```python import requests session = requests.Session() response = session.post( f"{FRIGATE_URL}/api/login", json={"user": FRIGATE_USER, "password": FRIGATE_PASS}, verify=False # For self-signed certificates ) # session.cookies contains frigate_token for subsequent requests ``` ## Common Operations ### Get Camera List ```python response = session.get(f"{FRIGATE_URL}/api/config", verify=False) config = response.json() cameras = list(config.get('cameras', {}).keys()) # Returns: ['driveway', 'front', 'east', 'mailbox', 'garage', 'doorbell'] ``` ### Get Snapshot from Camera ```python snapshot = session.get( f"{FRIGATE_URL}/api/{camera_name}/latest.jpg", verify=False ) # Save: with open(f"/tmp/{camera_name}.jpg", "wb") as f: f.write(snapshot.content) ``` ### Get Motion Events ```python events = session.get( f"{FRIGATE_URL}/api/events?cameras={camera_name}&has_clip=1", verify=False ).json() # Returns list of motion detection events with timestamps ``` ### Get Camera Stream URL ```python config = session.get(f"{FRIGATE_URL}/api/config", verify=False).json() stream_config = config.get('go2rtc', {}).get('streams', {}).get(camera_name) # Returns RTSP/WebRTC stream URLs ``` ## Environment Variables Required: - `FRIGATE_URL` - Frigate server URL (e.g., `https://server.local:8971/`) - `FRIGATE_USER` - Username for authentication - `FRIGATE_PASS` - Password for authentication Optional: - None required beyond the above ## Example: Send Doorbell Snapshot to Telegram ```python import requests session = requests.Session() session.post(f"{FRIGATE_URL}/api/login", json={"user": FRIGATE_USER, "password": FRIGATE_PASS}, verify=False) # Get doorbell snapshot snapshot = session.get(f"{FRIGATE_URL}/api/doorbell/latest.jpg", verify=False) # Send to Telegram from clawdbot import message message(action="send", channel="telegram", target="3215551212", message="Doorbell snapshot", path="/tmp/doorbell_snapshot.jpg") ``` ## Notes - Always use `verify=False` for self-signed certificates on home networks - Session tokens expire after 24 hours (configurable via `session_length`) - The `/api/cameras` endpoint doesn't exist; use `/api/config` for camera info - Frigate version 0.16+ uses this authentication model ## Bundled Resources - **Scripts**: See [scripts/frigate.py](scripts/frigate.py) for CLI utility with commands: `list`, `snapshot`, `events`, `stream` - **API Reference**: See [references/api.md](references/api.md) for complete API documentation

path: references/api.md
content: # Frigate API Reference

## Authentication

### POST /api/login
Authenticate and receive a session cookie.

**Request:**
```json
{
  "user": "username",
  "password": "password"
}
```

**Response:** Empty body on success

**Cookie:** `frigate_token=<JWT token>`

**Example:**
```python
import requests
session = requests.Session()
session.post(
    "https://server.local:8971/api/login",
    json={"user": "username", "password": "password123"},
    verify=False
)
```

## Configuration

### GET /api/config
Get full Frigate configuration including cameras, streams, and settings.

**Response:**
```json
{
  "version": "0.16-0",
  "cameras": {
    "driveway": {
      "detect": {
        "enabled": true,
        "width": 640,
        "height": 480,
        "fps": 5
      },
      "rtmp": { ... },
      "rtsp": { ... }
    }
  },
  "go2rtc": {
    "streams": {
      "driveway_cam": ["rtsp://...@..."]
    }
  }
}
```

### GET /api/version
Get Frigate version.

**Response:**
```json
{
  "version": "0.16-0"
}
```

## Cameras

### GET /api/camera/notifications
Get active camera notifications.

### GET /api/camera/<name>/best.jpg
Get the best frame for a camera.

### GET /api/camera/<name>/latest.jpg
Get the latest frame for a camera.

**Example:**
```python
snapshot = session.get(
    "https://server.local:8971/api/doorbell/latest.jpg",
    verify=False
)
with open("doorbell.jpg", "wb") as f:
    f.write(snapshot.content)
```

## Events

### GET /api/events
Get motion/events.

**Query Parameters:**
- `cameras` - Comma-separated camera names
- `limit` - Maximum number of events (default: 10)
- `has_clip` - Filter for events with clips (1/0)
- `has_snapshot` - Filter for events with snapshots (1/0)

**Example:**
```python
events = session.get(
    "https://server.local:8971/api/events?cameras=doorbell,front&limit=20",
    verify=False
).json()
```

**Response:**
```json
[
  {
    "id": "...",
    "camera": "doorbell",
    "start_time": "2026-01-27T20:00:00Z",
    "end_time": "2026-01-27T20:01:00Z",
    "top_score": 0.85,
    "labels": ["person", "car"]
  }
]
```

### DELETE /api/events/<event_id>
Delete an event.

## Clips and Snapshots

### GET /api/clips/<camera_name>
Get clips for a camera.

### GET /api/clips/<camera_name>/<event_id>.mp4
Download a specific clip.

## Statistics

### GET /api/stats
Get system statistics.

**Response:**
```json
{
  "cpu_usages": {...},
  "gpu_usages": {...},
  "mem_usages": {...},
  "recordings": {...},
  "cameras": {...}
}
```

## Bird's Eye View

### GET /api/birdseye
Get Bird's Eye View configuration.

## Zones

### GET /api/zones
Get all zone definitions.

### GET /api/zones/<camera_name>
Get zones for a specific camera.

## WebRTC Streams

The go2rtc configuration provides WebRTC stream URLs:

```json
{
  "go2rtc": {
    "streams": {
      "driveway_cam": [
        "rtsp://username:password@192.168.1.100:554/live",
        "ffmpeg:driveway_cam#audio=aac"
      ]
    },
    "webrtc": {
      "candidates": ["192.168.0.157:8555"]
    }
  }
}
```

## Error Responses

All endpoints return appropriate HTTP status codes:

- `200` - Success
- `400` - Bad Request
- `401` - Unauthorized (invalid or missing session)
- `404` - Not Found
- `500` - Server Error

Error response format:
```json
{
  "success": false,
  "message": "Error description"
}
```

## Session Management

- Session tokens expire after 24 hours (configurable via `session_length`)
- Tokens are JWTs containing: `{"sub": "username", "role": "viewer", "exp": timestamp}`
- Use `refresh_time` to refresh tokens before expiration (default: 12 hours)

## Complete Example

```python
import requests
import os

# Configuration
FRIGATE_URL = os.environ.get("FRIGATE_URL", "https://server.local:8971/")
FRIGATE_USER = os.environ.get("FRIGATE_USER", "username")
FRIGATE_PASS = os.environ.get("FRIGATE_PASS", "")

# Login
session = requests.Session()
session.post(
    f"{FRIGATE_URL}/api/login",
    json={"user": FRIGATE_USER, "password": FRIGATE_PASS},
    verify=False
)

# Get cameras
config = session.get(f"{FRIGATE_URL}/api/config", verify=False).json()
cameras = list(config['cameras'].keys())

# Get snapshot from first camera
snapshot = session.get(
    f"{FRIGATE_URL}/api/{cameras[0]}/latest.jpg",
    verify=False
)

# Get recent events
events = session.get(
    f"{FRIGATE_URL}/api/events?limit=10",
    verify=False
).json()

print(f"Found {len(cameras)} cameras: {cameras}")
print(f"Recent events: {len(events)}")
```


path: scripts/frigate.py
content: #!/usr/bin/env python3
"""
Frigate NVR Helper Script

Usage:
    python frigate.py list                    # List all cameras
    python frigate.py snapshot <camera>       # Get snapshot from camera
    python frigate.py events <camera>         # Get motion events for camera
    python frigate.py stream <camera>         # Get stream URL for camera

Environment variables:
    FRIGATE_URL   - Frigate server URL
    FRIGATE_USER  - Username
    FRIGATE_PASS  - Password
"""

import os
import sys
import requests
import json
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

FRIGATE_URL = os.environ.get("FRIGATE_URL", "https://server.local:8971/")
FRIGATE_USER = os.environ.get("FRIGATE_USER", "username")
FRIGATE_PASS = os.environ.get("FRIGATE_PASS", "")


def login():
    """Authenticate with Frigate and return a session."""
    session = requests.Session()
    response = session.post(
        f"{FRIGATE_URL}/api/login",
        json={"user": FRIGATE_USER, "password": FRIGATE_PASS},
        verify=False
    )
    if response.status_code != 200:
        print(f"Login failed: {response.status_code}")
        sys.exit(1)
    return session


def list_cameras(session):
    """List all cameras."""
    config = session.get(f"{FRIGATE_URL}/api/config", verify=False).json()
    cameras = list(config.get('cameras', {}).keys())
    for cam in cameras:
        cam_config = config['cameras'][cam]
        detect = cam_config.get('detect', {})
        print(f"  - {cam}: {detect.get('width', '?')}x{detect.get('height', '?')}")
    return cameras


def get_snapshot(session, camera_name, output_path=None):
    """Get snapshot from a camera."""
    response = session.get(
        f"{FRIGATE_URL}/api/{camera_name}/latest.jpg",
        verify=False
    )
    if response.status_code != 200:
        print(f"Failed to get snapshot: {response.status_code}")
        return None
    
    if output_path:
        with open(output_path, "wb") as f:
            f.write(response.content)
        print(f"Saved to {output_path}")
    return response.content


def get_events(session, camera_name=None, limit=10):
    """Get motion events."""
    params = f"limit={limit}"
    if camera_name:
        params += f"&cameras={camera_name}"
    response = session.get(
        f"{FRIGATE_URL}/api/events?{params}",
        verify=False
    )
    events = response.json()
    for event in events[:limit]:
        print(f"  - {event.get('camera')}: {event.get('start_time')}")
    return events


def get_stream_url(session, camera_name):
    """Get stream URL for a camera."""
    config = session.get(f"{FRIGATE_URL}/api/config", verify=False).json()
    streams = config.get('go2rtc', {}).get('streams', {}).get(camera_name, [])
    if streams:
        print(f"  {camera_name}: {streams[0]}")
    return streams


def main():
    if len(sys.argv) < 2:
        print(__doc__)
        sys.exit(1)
    
    command = sys.argv[1].lower()
    
    session = login()
    
    if command == "list":
        print("Cameras:")
        list_cameras(session)
    elif command == "snapshot":
        camera = sys.argv[2] if len(sys.argv) > 2 else None
        if not camera:
            print("Usage: python frigate.py snapshot <camera_name>")
            sys.exit(1)
        output = sys.argv[3] if len(sys.argv) > 3 else None
        get_snapshot(session, camera, output)
    elif command == "events":
        camera = sys.argv[2] if len(sys.argv) > 2 else None
        print("Recent events:")
        get_events(session, camera)
    elif command == "stream":
        camera = sys.argv[2] if len(sys.argv) > 2 else None
        if not camera:
            cameras = list_cameras(session)
            print("\nAvailable cameras:")
            for cam in cameras:
                get_stream_url(session, cam)
        else:
            get_stream_url(session, camera)
    else:
        print(f"Unknown command: {command}")
        print(__doc__)
        sys.exit(1)


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: suspicious | static analysis:  | VirusTotal:  | SkillSpector:  ()