Web Streaming & Home Assistant Integration
Overview
Web streaming and Home Assistant integration is a planned feature for bbl-shutter-cam that enables remote monitoring of your Raspberry Pi camera via a web interface and integration with Home Assistant. This allows you to view live camera feeds and remote snapshots while maintaining the Bluetooth shutter as the primary trigger for reliable time-lapse capture.
Status: Planned for Stage 4 (post-v1.0.0)
Target Device: Raspberry Pi Zero 2W (and larger models)
Why Web Streaming?
Use Cases
- Remote Monitoring: Check your 3D print progress from another room or device
- Home Assistant Integration: Include your camera feed in your smart home dashboard
- Live Preview: Verify camera positioning and lighting before starting a print
- Troubleshooting: Visually diagnose issues with camera angle, focus, or lighting
Design Philosophy
- Optional & Lightweight: Disabled by default; enabled only when you need it
- On-Demand: Stream starts when you access it, stops automatically when idle
- Bluetooth-First: The physical Bluetooth shutter remains the preferred trigger for consistent time-lapses
- Zero Latency Between Shutter & Capture: Photo is captured instantly on button press, with no web server intervention
Architecture
Single Process Design
The web server and Bluetooth listener run in the same systemd service:
bbl-shutter-cam run --profile my-printer --web-port 8080
↓
└─ BLE listener (always active)
└─ Flask web server (optional, if --web-port specified)
This keeps the deployment simple and reduces resource overhead compared to separate services.
Capture Paths
Path 1: Bluetooth Shutter (Primary)
Physical shutter press → BLE signal → rpicam-still capture → photo saved
- Reliable, no network dependency
- Best for time-lapse sequences
- Zero software latency
Path 2: Web UI or Home Assistant (Secondary)
Web button click → Flask endpoint → rpicam-still capture → JPEG response
- Useful for manual testing and verification
- Requires network connectivity
- Slightly higher latency (~1-2 seconds)
Path 3: Streaming (Preview Only)
User accesses /stream → Flask starts MJPEG encoder → Live feed streamed
- Preview only, not for capture
- Auto-stops on disconnect or timeout
- No resource overhead when not in use
Planned Features
1. HTTP API Endpoints
/snapshot Endpoint
- Purpose: Fetch a single JPEG image on demand
- Method: GET
- Response: Raw JPEG data
- Overhead: Minimal; no continuous encoding
- Use: Home Assistant snapshots, manual verification
- Example:
curl http://raspberrypi.local:8080/snapshot > photo.jpg
/stream Endpoint
- Purpose: Live MJPEG stream preview
- Method: GET
- Response: Motion JPEG stream
- Auto-Timeout: 300 seconds default (configurable)
- Behavior: Stops automatically when client disconnects
- Resolution: 640×480 default (configurable per hardware)
- Frame Rate: 10-15 fps (Pi Zero 2W optimized)
- Example:
<img src="http://raspberrypi.local:8080/stream" width="640" height="480" />
/capture Endpoint (Manual Trigger)
- Purpose: Manually trigger photo capture via web/Home Assistant
- Method: POST
- Response: JPEG of just-captured image
- Use: Testing camera settings, manual verification during setup
- Example:
curl -X POST http://raspberrypi.local:8080/capture
2. Web User Interface
A minimal, mobile-friendly web dashboard featuring:
- Live camera preview (MJPEG stream)
- Manual capture button
- Stream start/stop controls
- Last captured timestamp
- Connection status indicator
- Responsive design for phones, tablets, desktops
3. Home Assistant Integration
Configure bbl-shutter-cam as a camera entity in Home Assistant:
camera:
- platform: generic
name: "Printer Camera"
still_image_url: "http://raspberrypi.local:8080/snapshot"
stream_source: "http://raspberrypi.local:8080/stream"
framerate: 12
verify_ssl: false
Features:
- Snapshot support for dashboard tiles
- Stream support for live view cards
- Motion detection triggers (if desired)
- Automation integration (if manual capture endpoint added)
4. Configuration
New optional [server] section in profile config:
[profiles.my-printer]
# ... existing camera and BLE config ...
[profiles.my-printer.server]
# Optional streaming settings (all with sensible defaults)
web_port = 8080
stream_resolution = "640x480"
stream_fps = 12
stream_timeout_seconds = 300
jpeg_quality = 80
enable_manual_capture = true
All settings are optional with hardware-aware defaults:
- Pi 5: 1080p, 30 fps
- Pi 4: 800×600, 20 fps
- Pi Zero 2W: 640×480, 12 fps
5. Systemd Service (Restored)
The original decision to remove systemd service support is being reversed for this feature. A unified service template will support:
[Service]
ExecStart=/usr/local/bin/bbl-shutter-cam run --profile my-printer --web-port 8080
Type=notify
Restart=on-failure
RestartSec=10
StartLimitInterval=60
StartLimitBurst=3
The service provides:
- Auto-restart on crash
- Startup notifications
- Clean systemd integration
- Optional, can still run in foreground for debugging
Resource Requirements
Memory Footprint (Pi Zero 2W)
| Component | Usage | Notes |
|---|---|---|
| Python runtime | ~30 MB | Base interpreter |
| Flask server | ~15 MB | Idle, listening |
| Streaming (active) | ~20 MB | MJPEG encoder |
| Snapshots | ~5 MB | Per-request, released |
| BLE listener | ~10 MB | Constant |
| Total idle | ~65 MB | 12% of 512 MB RAM |
| Total streaming | ~85 MB | 16% of 512 MB RAM |
CPU Impact (Pi Zero 2W)
| Scenario | CPU Usage | Throttle Risk |
|---|---|---|
| Idle (BLE only) | 1-2% | None |
| Streaming 10 fps | 15-25% | Low |
| Streaming 20 fps | 35-45% | Moderate |
| Capture + stream | 50%+ | High (thermal) |
Recommendation: Keep streaming at 10-15 fps on Pi Zero 2W. Capture photos use GPU encoder (minimal CPU impact).
Network Requirements
- Snapshot: 200-400 KB per image (configurable quality)
- Stream: 100-200 Kbps at 12 fps @ 640×480
- Minimum: 1 Mbps connection recommended
- LAN only: Streaming not designed for remote WAN access (security risk)
Safety & Stability Considerations
Auto-Timeout Design
Streaming stops automatically to prevent resource exhaustion:
- Client disconnect: Stream stops immediately
- No new data consumed for 300 sec: Stream stops automatically
- User closes browser: Stream stops instantly
This prevents accidental resource leaks.
Single Stream Limitation
Only one client can stream at a time on Pi Zero 2W:
- Second connection request fails gracefully
- User sees “stream in use” message
- First client must terminate for next to connect
This avoids CPU/memory overload.
Thermal Management
Continuous streaming may trigger CPU throttling on Pi Zero 2W after ~5-10 minutes:
- Normal in enclosure environments (printer heat)
- Auto-timeout prevents sustained throttling
- Bluetooth shutter remains responsive even during throttle
- Consider heatsink or improved ventilation if needed
Network Security
- Current: No authentication (assumes trusted local network)
- Future: Optional HTTP Basic Auth in phase 2
- Recommendation: Use on local network only; don’t expose to internet without authentication
- Firewall: Consider UFW rules limiting web port access
Implementation Timeline
Phase 1 (Immediate)
- Create
streaming.pymodule - Implement
/snapshotendpoint - Build simple HTML web UI
- Add basic server startup in
runcommand - Write initial documentation
Phase 2 (Following)
- Implement
/streamwith MJPEG encoder - Add timeout and auto-cleanup logic
- Integrate with config system
- Add Home Assistant integration guide
- Create troubleshooting docs
Phase 3 (Future)
- Optional MQTT support
- Web-based camera settings UI
- Historical image gallery
- Performance metrics dashboard
Comparison: Streaming Technologies
Why MJPEG (Motion JPEG)?
| Aspect | MJPEG | H.264 | VP8 |
|---|---|---|---|
| CPU Load | Moderate | High | High |
| Setup Complexity | Simple | Complex | Complex |
| Browser Support | Native | Varies | Varies |
| Latency | ~1-2s | 0.5-1s | 0.5-1s |
| Pi Zero 2W | ✅ Viable | ⚠️ Possible | ❌ Hard |
| Headless Friendly | ✅ Yes | ⚠️ GPU needed | ✅ Yes |
| Quality | Good | Excellent | Good |
Decision: MJPEG chosen for simplicity and Pi Zero 2W compatibility. Can revisit if performance requirements change.
Known Limitations & Workarounds
| Limitation | Reason | Workaround |
|---|---|---|
| Single stream only | Resource constraint | Use Home Assistant polling of snapshots |
| No authentication (v1) | Network Trust assumption | Use firewall rules, LAN only |
| 10-15 fps max (Zero 2W) | Hardware performance | Monitor, not capture; use BLE for stills |
| No H.264 codec | CPU overhead | MJPEG sufficient for preview use case |
| No persistent video recording | Encoding overhead | Use time-lapse stills + external tools |
Future Enhancements
Potential improvements after initial release:
- MQTT integration for advanced Home Assistant automations
- WebSocket support for lower-latency streaming
- Multi-stream support on Pi 4/5
- H.264 hardware acceleration research
- Remote WAN access with reverse proxy guide
- Performance metrics and monitoring
- Camera parameter tuning via web UI
- Image gallery and archive viewer
Getting Started (When Available)
# Enable streaming on default port 8080
bbl-shutter-cam run --profile my-printer --web-port 8080
# Access the web UI
open http://localhost:8080
# In Home Assistant, add to configuration.yaml
camera:
- platform: generic
name: "My Printer"
still_image_url: "http://raspberrypi.local:8080/snapshot"
stream_source: "http://raspberrypi.local:8080/stream"
Related Documentation
- Interactive Camera Tuning - Optimize image quality (both live and captured)
- Systemd Service - Background operation and auto-start
- Headless Operation - Running without display
- Troubleshooting - Common issues and solutions
- Home Assistant Integration - (Planned docs)
Questions or Feedback?
This is a planned feature. Please share your use cases, hardware constraints, or feature requests via:
- GitHub Issues on the project repository
- Discussions in the README or Contributing guide
Your input helps prioritize and shape the implementation!