Orbo is a modern, open-source video alarm system built with Go and OpenCV. It features real-time motion detection, AI-powered object detection (YOLO11), face recognition, and Telegram notifications. Designed as a cloud-native microservice, it can be deployed on Kubernetes, Docker, or Podman (including embedded Linux systems via meta-container-deploy).
- React Web UI: Modern dashboard with camera management, multi-camera grid layouts, and unified settings panel
- Per-Camera Event/Notification Control: Separate toggles for storing events and sending Telegram notifications per camera
- Real-Time Streaming: Low-latency WebSocket streaming with gRPC-based detection pipeline
- Dual Streaming Modes: MJPEG (traditional) and WebCodecs (low-latency WebSocket) streaming
- Camera Support: USB cameras (
/dev/video*), HTTP endpoints, and RTSP streams - Motion Detection: OpenCV-based with configurable sensitivity
- AI Object Detection: YOLO11 multi-task integration via gRPC - detection, pose estimation, segmentation, and more
- Face Recognition: InsightFace-based gRPC face detection and identity matching with persistent face database
- Configurable Bounding Box Colors: Customize colors for YOLO detections and face recognition (known/unknown faces)
- Sequential Detection Pipeline: Optimized detector chain (YOLO → Face) with proper annotation stacking
- Telegram Integration: Instant alerts with captured frames + bot commands for remote control
- REST API: Complete HTTP API for camera management and system control
- Database Persistence: SQLite for cameras, events, and configuration
- Cloud Native: Docker/Podman containers with Helm charts
- Security Focused: Non-root user, read-only filesystem, minimal privileges
- Go 1.24.5+ and OpenCV 4.8.0+ (for backend development)
- Node.js 22+ (for frontend development)
- Docker or Podman (for containerized deployment)
- Kubernetes + Helm (for production)
git clone <repository-url> && cd orbo
go mod download
goa gen orbo/design
# Terminal 1: Start backend
go run ./cmd/orbo
# Terminal 2: Start frontend dev server
cd web/frontend && npm install && npm run devThe frontend dev server runs on port 5173 and proxies API requests to the backend on port 8080.
cd deploy
make docker # Build (includes frontend)
make run # Run with camera accesscd deploy
make minikube-build && make minikube-build-yolo && make minikube-build-recognition
make minikube-deploy # CPU inference
make minikube-deploy-gpu # GPU inferenceTo enable face recognition:
helm upgrade orbo deploy/helm/orbo --set recognition.enabled=trueThe React-based web UI provides:
- Camera Management: Add, edit, delete cameras with live preview
- Per-Camera Event/Notification Control: Separate toggles for storing events and sending Telegram notifications (bounding boxes always visible)
- Multi-Camera Grid: Configurable layouts (1x1, 2x1, 2x2, 3x3) with detection status indicators
- Motion Events: Browse and filter detection events with thumbnails
- Settings Panel: Configure Pipeline, YOLO (multi-task selection, color picker), Face Recognition, and Telegram settings
- System Controls: Start/stop detection, view system status
cd web/frontend
npm install # Install dependencies
npm run dev # Start dev server with hot reload
npm run build # Production buildmake -C deploy frontend # Build React frontend
make -C deploy frontend-dev # Run dev server
make -C deploy frontend-clean # Clean build artifacts
make -C deploy full-build # Build frontend + backend| Variable | Description | Default |
|---|---|---|
AUTH_ENABLED |
Enable JWT authentication | false |
AUTH_USERNAME |
Admin username | admin |
AUTH_PASSWORD |
Admin password (plaintext or bcrypt hash) | - |
JWT_SECRET |
Secret for signing tokens | (random) |
JWT_EXPIRY |
Token expiration duration | 24h |
TELEGRAM_ENABLED |
Enable Telegram notifications | false |
TELEGRAM_BOT_TOKEN |
Telegram bot token | - |
TELEGRAM_CHAT_ID |
Telegram chat ID | - |
TELEGRAM_COOLDOWN |
Notification cooldown (seconds) | 30 |
| Detection Pipeline | ||
DETECTION_MODE |
Detection mode: disabled, visual_only, continuous, motion_triggered, scheduled, hybrid |
motion_triggered |
DETECTION_EXECUTION_MODE |
Execution mode: sequential (parallel removed for stability) |
sequential |
DETECTION_DETECTORS |
Comma-separated detector list (e.g., "yolo,face") | yolo |
DETECTION_SCHEDULE_INTERVAL |
Interval for scheduled/hybrid modes | 5s |
MOTION_SENSITIVITY |
Motion detection sensitivity (0.0-1.0) | 0.1 |
MOTION_COOLDOWN_SECONDS |
Cooldown after motion stops | 2 |
| Detector Services | ||
YOLO_ENABLED |
Enable YOLO detection | false |
YOLO_ENDPOINT |
YOLO service URL | http://yolo-service:8081 |
YOLO_DRAW_BOXES |
Draw bounding boxes | false |
YOLO_CLASSES_FILTER |
Classes to detect (e.g., "person,car") | all |
YOLO_BOX_COLOR |
Bounding box color (hex) | #0066FF |
YOLO_BOX_THICKNESS |
Bounding box line thickness (1-5) | 2 |
YOLO_TASKS |
Comma-separated YOLO11 tasks (detect,pose,segment,obb,classify) | detect |
RECOGNITION_ENABLED |
Enable face recognition | false |
RECOGNITION_SERVICE_ENDPOINT |
Face recognition service URL | http://recognition:8082 |
RECOGNITION_SIMILARITY_THRESHOLD |
Face match threshold (0.0-1.0) | 0.5 |
RECOGNITION_KNOWN_FACE_COLOR |
Known face box color (hex) | #00FF00 |
RECOGNITION_UNKNOWN_FACE_COLOR |
Unknown face box color (hex) | #FF0000 |
| Storage | ||
DATABASE_PATH |
SQLite database path | /app/frames/orbo.db |
FRAME_DIR |
Frame storage directory | /app/frames |
FRONTEND_DIR |
React frontend build path | /app/web/frontend/dist |
helm install orbo deploy/helm/orbo \
--set notifications.telegram.enabled=true \
--set notifications.telegram.botToken="your_token" \
--set notifications.telegram.chatId="your_chat_id" \
--set detection.mode=motion_triggered \
--set detection.executionMode=sequential \
--set "detection.detectors={yolo,face}"| Section | Description |
|---|---|
global |
Environment, log level |
orbo |
Main app: replicas, image, resources |
detection |
Pipeline config: mode, executionMode, detectors, motion settings |
yolo |
YOLO config, GPU settings |
recognition |
Face recognition config |
dinov3 |
DINOv3 config (optional) |
notifications |
Telegram settings |
storage |
Persistence, database path |
The modular detection pipeline supports:
Detection Modes:
| Mode | Description |
|---|---|
disabled |
Streaming only, no detection |
visual_only |
Run detection for bounding boxes but don't send alerts (useful for testing) |
continuous |
Run detection on every frame |
motion_triggered |
Detect only when motion is detected (default) |
scheduled |
Run detection at fixed intervals |
hybrid |
Motion-triggered OR scheduled (guaranteed coverage) |
Execution Mode:
The pipeline uses sequential execution: YOLO runs first, then Face Recognition triggers if a person is detected. This ensures proper annotation stacking and eliminates timing issues.
Per-Camera Configuration: Each camera can override global detection settings:
# Via API
curl -X PUT http://orbo/api/v1/cameras/{id}/detection-config \
-H "Content-Type: application/json" \
-d '{"mode": "continuous", "detectors": ["yolo", "face"]}'Cameras inherit from global defaults and can override: mode, executionMode, detectors, scheduleInterval, motionSensitivity, yoloConfidence, enableFaceRecog.
- Message @BotFather on Telegram and use
/newbot - Get chat ID from
https://api.telegram.org/bot<TOKEN>/getUpdates - Configure via environment variables or Helm values
Once configured, control Orbo directly from Telegram:
System Commands:
| Command | Description |
|---|---|
/status |
System status (cameras, detection stats, uptime) |
/cameras |
List all cameras with status and detection indicators |
/help |
Show available commands |
Camera Control:
| Command | Description |
|---|---|
/enable <name> |
Activate camera (start streaming) |
/disable <name> |
Deactivate camera |
/alerts_on <name> |
Enable both events and notifications for a camera |
/alerts_off <name> |
Disable both events and notifications (bounding boxes only) |
Detection:
| Command | Description |
|---|---|
/start_detection |
Start detection on all active cameras |
/stop_detection |
Stop all detection |
/snapshot <name> |
Capture and send a frame from a camera |
/events [limit] |
Show recent detection events (default: 5) |
Camera Status Icons:
- 👁️ Currently detecting
- 🔔 Alerts enabled
- 👁️🔔 Detecting with alerts
GET /healthz- Liveness probeGET /readyz- Readiness probe
POST /api/v1/auth/login- Authenticate and get JWT tokenGET /api/v1/auth/status- Check auth status
GET /api/v1/cameras- List camerasPOST /api/v1/cameras- Add cameraGET|PUT|DELETE /api/v1/cameras/{id}- Manage cameraPOST /api/v1/cameras/{id}/activate|deactivate- Control camera streamingPOST /api/v1/cameras/{id}/alerts/enable|disable- Toggle both events and notifications per cameraPUT /api/v1/cameras/{id}- Update camera (includesevents_enabled,notifications_enabledfields)GET /api/v1/cameras/{id}/frame- Get current frame
GET /api/v1/motion/events- List eventsGET /api/v1/motion/events/{id}- Get event detailsGET /api/v1/motion/events/{id}/frame- Get event frame
GET|PUT /api/v1/config/notifications- Telegram settingsPOST /api/v1/config/notifications/test- Test notificationGET|PUT /api/v1/config/yolo- YOLO settings (includes box_color, box_thickness)GET|PUT /api/v1/config/recognition- Face recognition settings (includes known/unknown face colors)POST /api/v1/config/recognition/test- Test face recognition serviceGET|PUT /api/v1/config/detection- Detection settingsGET|PUT /api/v1/config/pipeline- Pipeline configuration (mode, detectors, motion settings)
GET /api/v1/system/status- System statusPOST /api/v1/system/detection/start|stop- Control detection
POST /detect- Detect objects (JSON response)POST /detect/annotated- Detect with annotated image (configurable colors)POST /detect/security- Security-focused detectionGET /classes- List supported classes
YOLO11 Multi-Task Support:
The YOLO service supports multiple analysis tasks that can be enabled simultaneously:
| Task | Description | Output |
|---|---|---|
detect |
Object detection (default) | Bounding boxes for 80+ COCO classes |
pose |
Pose estimation | 17 human body keypoints with fall detection |
segment |
Instance segmentation | Pixel-level object masks |
obb |
Oriented bounding boxes | Rotated boxes for angled objects |
classify |
Image classification | Scene/category classification |
Configure via the web UI (Settings → YOLO → YOLO11 Tasks) or API:
curl -X PUT http://orbo/api/v1/config/yolo \
-H "Content-Type: application/json" \
-d '{"tasks": ["detect", "pose"], "box_color": "#0066FF", "box_thickness": 2}'Configurable YOLO Bounding Box Colors:
curl -X PUT http://orbo/api/v1/config/yolo \
-H "Content-Type: application/json" \
-d '{"box_color": "#0066FF", "box_thickness": 2}'POST /detect- Detect faces with age/gender estimationPOST /recognize- Detect and identify known facesPOST /recognize/annotated- Recognize with annotated image (configurable colors)POST /faces/register- Register a new face identityPOST /faces/{name}/add-image- Add additional image to existing identityGET /faces- List registered identities with image countsGET /faces/{name}/images- Get all images for an identityGET /faces/{name}/image- Get specific registered face imageDELETE /faces/{name}- Remove a registered identity
┌─────────────────────────────────────────────────────────────────┐
│ React Frontend │
│ (Camera UI, Grid View, Events, Settings) │
└───────────────────────────────┬─────────────────────────────────┘
│ HTTP / WebSocket
┌───────────────────────────────▼─────────────────────────────────┐
│ Goa REST API Server │
│ ┌─────────┬──────────┬─────────┬──────────┬─────────────────┐ │
│ │ Health │ Camera │ Motion │ Config │ System │ │
│ │ Service │ Service │ Service │ Service │ Service │ │
│ └─────────┴────┬─────┴────┬────┴─────┬────┴────────┬────────┘ │
└─────────────────┼──────────┼──────────┼─────────────┼───────────┘
│ │ │ │
┌─────────────▼───────────────────────────────────┴───────────┐
│ DETECTION PIPELINE (Modular) │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Frame Provider ││
│ │ (Single FFmpeg per camera, pub/sub) ││
│ └────────────────────────┬────────────────────────────────┘│
│ │ │
│ ┌────────────────┼────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ Streaming │ │ Detection │ │ Recording │ │
│ │ Pipeline │ │ Pipeline │ │ (future) │ │
│ └───────────────┘ └───────┬───────┘ └───────────────┘ │
│ │ │
│ ┌─────────────────────────▼─────────────────────────────┐ │
│ │ Detection Strategy │ │
│ │ (disabled | continuous | motion | scheduled | hybrid)│ │
│ └─────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ┌───────────────────┴───────────────────┐ │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ YOLO │─────────────────────────▶│ Face │ │
│ │ gRPC │ │ gRPC │ │
│ │(primary) │ │(person?) │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ └──────────────────┬───────────────────┘ │
│ │ │
│ ┌───────────────────────▼──────────────────────────────┐ │
│ │ Event Bus │ │
│ │ (pub/sub for detection results) │ │
│ └─────────┬──────────────┬─────────────────┬───────────┘ │
└────────────┼──────────────┼─────────────────┼───────────────┘
│ │ │
┌────────────▼───┐ ┌──────▼──────┐ ┌──────▼───────────┐
│ Streaming │ │ Telegram │ │ Database │
│ Bridge │ │ Notifier │ │ Persistence │
│ (MJPEG/WebWS) │ │ (alerts) │ │ (events) │
└────────────────┘ └─────────────┘ └──────────────────┘
│
┌────────▼────────────────────────────────────┐
│ Camera Sources │
│ ┌─────────┐ ┌────────┐ ┌──────────┐ │
│ │ USB │ │ HTTP │ │ RTSP │ │
│ │ /dev/* │ │ URLs │ │ Streams │ │
│ └─────────┘ └────────┘ └──────────┘ │
└─────────────────────────────────────────────┘
│
┌────────▼────────────────────────────────────┐
│ SQLite Database │
│ (cameras, events, configuration, │
│ per-camera detection settings) │
└─────────────────────────────────────────────┘
Orbo supports two streaming modes, selectable in the frontend:
| Mode | Protocol | Use Case |
|---|---|---|
| MJPEG | HTTP/1.1 multipart | Traditional, compatible with all browsers |
| WebCodecs | WebSocket binary | Low-latency, real-time viewing |
WebCodecs Architecture:
- Uses WebSocket (
/ws/video/{camera_id}) for direct binary frame delivery - Prioritizes annotated frames from YOLO/InsightFace detection pipeline
- Falls back to raw MJPEG frames when detection is disabled
- Binary message format:
[type:1byte][length:4bytes][jpeg_data]- Type
0= raw frame (no bounding boxes) - Type
1= annotated frame (with detection bounding boxes)
- Type
- Composite overlay broadcasts every processed frame to both MJPEG and WebCodecs simultaneously
orbo/
├── cmd/orbo/ # Application entry point
├── design/ # Goa API design
├── gen/ # Generated Goa code
├── internal/
│ ├── camera/ # Camera management
│ ├── database/ # SQLite layer
│ ├── detection/ # YOLO/GPU clients
│ ├── motion/ # Motion detection
│ ├── stream/ # MJPEG/WebCodecs streaming
│ ├── telegram/ # Notifications
│ └── services/ # Service implementations
├── web/
│ └── frontend/ # React + Vite + TypeScript frontend
│ ├── src/
│ │ ├── api/ # API client
│ │ ├── components/# React components
│ │ ├── hooks/ # React Query hooks
│ │ └── types/ # TypeScript types
│ └── dist/ # Production build
├── yolo-service/ # YOLO detection service (Python)
├── recognition-service/ # Face recognition service (InsightFace)
└── deploy/
├── Dockerfile
├── Makefile
└── helm/orbo/ # Helm charts
Ready-to-use Quadlet files are provided in deploy/podman/quadlet/:
# Create storage directories
sudo mkdir -p /var/lib/orbo/{frames,faces}
sudo chown 1000:1000 /var/lib/orbo/{frames,faces}
# Copy Quadlet files
sudo cp deploy/podman/quadlet/*.container /etc/containers/systemd/
# Reload and start
sudo systemctl daemon-reload
sudo systemctl start orbo.service
# With AI detection
sudo systemctl start yolo-service.service
sudo systemctl start recognition.serviceSee deploy/podman/README.md for full documentation.
Use meta-container-deploy for Yocto-based systems with automatic container management and systemd integration.
# In local.conf
DISTRO_FEATURES:append = " systemd virtualization"
CONTAINER_MANIFEST = "${THISDIR}/orbo-manifest.yaml"
IMAGE_INSTALL:append = " container-orbo"Container manifest and Quadlet files are provided in deploy/podman/ for seamless integration.
Camera not detected:
ls -la /dev/video*
sudo usermod -a -G video $USERPermission denied:
# Docker
sudo docker run --device=/dev/video0 ...
# Podman (rootless)
podman run --device /dev/video0 ...Orbo includes integrated face recognition powered by InsightFace. When enabled, the system automatically:
- Detects faces when YOLO identifies a person in the frame
- Matches faces against registered identities in the database
- Updates threat level to "high" for unknown faces
- Enhances notifications with face recognition results
Face data is stored in a persistent volume to survive pod restarts:
- Face embeddings:
/app/data/faces.pkl(pickle database) - Face images:
/app/data/faces/(JPEG images)
Enable persistence in Helm values:
recognition:
persistence:
enabled: true
size: 1GiCustomize the appearance of face detection boxes:
| Setting | Default | Description |
|---|---|---|
known_face_color |
#00FF00 (green) |
Color for recognized/known faces |
unknown_face_color |
#FF0000 (red) |
Color for unknown faces |
box_thickness |
2 | Line thickness (1-5 pixels) |
Configure via the web UI (Settings → Faces) or API:
curl -X PUT http://orbo/api/v1/config/recognition \
-H "Content-Type: application/json" \
-d '{"known_face_color": "#00FF00", "unknown_face_color": "#FF0000", "box_thickness": 3}'- Register faces via the web UI (Settings → Face Management) or API
- Enable recognition in Helm values or environment variables
- Face recognition runs automatically during person detection
- Event Cards: Show face badges (✅ known,
⚠️ unknown) - Event Details: Display identified names and unknown face count
- Face Management: Register, view, and delete face identities
- Color Picker: Configure bounding box colors in Settings → Faces
# Register a new face
curl -X POST http://orbo/recognition/faces/register \
-F "name=John" -F "file=@photo.jpg"
# Add additional image to existing identity (improves matching)
curl -X POST http://orbo/recognition/faces/John/add-image \
-F "file=@another_photo.jpg"
# List registered faces with image counts
curl http://orbo/recognition/faces
# Recognize faces in an image
curl -X POST http://orbo/recognition/recognize \
-F "file=@frame.jpg"When face recognition is enabled, alerts include:
- ✅ Identified person names
- ❓ Count of unknown faces
Planned features and improvements:
- Authentication - JWT-based login with protected API endpoints
- Face Recognition - InsightFace-based face detection and identity matching
- Multi-user Support - Multiple users with separate camera permissions
- Recording & Playback - Continuous recording with timeline navigation
- Cloud Storage - Optional backup to S3 for frames and recordings
- Zones & Masks - Define detection zones and ignore areas per camera
- Scheduling - Time-based detection rules (arm/disarm schedules)
- Webhooks - Custom HTTP callbacks on detection events
- Audio Detection - Sound-based alerts (glass breaking, alarms)
- License Plate Recognition - ALPR integration for vehicle identification
- Fork the repository
- Create a feature branch
- Make changes and add tests
- Submit a pull request
MIT License - see LICENSE file for details.
Built with ❤️ in Puglia, Italy by Marco Pennelli
