mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-29 18:36:55 +00:00
- Add "Bootstrap Role (v2.1.0)" section to Eye-Remote-Implementation.md with capabilities, use cases, architecture, configuration, workflow, and security considerations - Update Table of Contents in Eye-Remote-Implementation.md to include bootstrap section - Add bootstrap reference to Eye Remote section in Home.md - Add bootstrap functionality note to Architecture-Boot.md with cross-reference to Eye-Remote-Bootstrap.md This cross-references the new Eye-Remote-Bootstrap feature across related documentation pages. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
583 lines
17 KiB
Markdown
583 lines
17 KiB
Markdown
# Eye Remote v2.0.0 Implementation Guide
|
|
|
|
## Table of Contents
|
|
|
|
1. [Project Overview](#project-overview)
|
|
2. [Implementation Timeline](#implementation-timeline)
|
|
3. [Architecture Design](#architecture-design)
|
|
4. [Component Details](#component-details)
|
|
5. [Build System](#build-system)
|
|
6. [Display Configuration](#display-configuration)
|
|
7. [API Reference](#api-reference)
|
|
8. [Development Tools](#development-tools)
|
|
9. [Bootstrap Role](#bootstrap-role)
|
|
10. [Deployment](#deployment)
|
|
11. [Lessons Learned](#lessons-learned)
|
|
|
|
---
|
|
|
|
## Project Overview
|
|
|
|
### Purpose
|
|
|
|
SecuBox Eye Remote provides a dedicated physical display for SecuBox security appliances. The circular 480x480 LCD shows real-time system metrics, alerts, and status information.
|
|
|
|
### Goals Achieved
|
|
|
|
- [x] Offline-capable SD card image (no internet at boot)
|
|
- [x] USB OTG connectivity with fallback to WiFi
|
|
- [x] Secure device pairing via QR codes
|
|
- [x] Real-time metrics dashboard
|
|
- [x] Chromium kiosk mode auto-start
|
|
- [x] HyperPixel 2.1 Round display support
|
|
- [x] Gateway emulator for development
|
|
|
|
### Tech Stack
|
|
|
|
| Layer | Technology |
|
|
|-------|------------|
|
|
| OS | Raspberry Pi OS Bookworm (armhf) |
|
|
| Display | X11 + fbdev + DPI framebuffer |
|
|
| Window Manager | Openbox |
|
|
| Browser | Chromium (kiosk mode) |
|
|
| Backend | FastAPI + Uvicorn |
|
|
| Auth | JWT + Device Tokens |
|
|
| Build | QEMU ARM emulation |
|
|
|
|
---
|
|
|
|
## Implementation Timeline
|
|
|
|
### Task Breakdown (14 Tasks)
|
|
|
|
| Task | Component | Status |
|
|
|------|-----------|--------|
|
|
| 1 | Metrics Models (`models/metrics.py`) | ✅ |
|
|
| 2 | Device Models (`models/device.py`) | ✅ |
|
|
| 3 | Pairing Models (`models/pairing.py`) | ✅ |
|
|
| 4 | Metrics Collection (`core/metrics.py`) | ✅ |
|
|
| 5 | Device Registry (`core/device_registry.py`) | ✅ |
|
|
| 6 | Pairing Manager (`core/pairing.py`) | ✅ |
|
|
| 7 | Devices Router (`api/routers/devices.py`) | ✅ |
|
|
| 8 | Pairing Router (`api/routers/pairing.py`) | ✅ |
|
|
| 9 | Metrics Router (`api/routers/metrics.py`) | ✅ |
|
|
| 10 | Gateway Emulator (`tools/secubox-eye-gateway/`) | ✅ |
|
|
| 11 | Debian Packaging (`debian/`) | ✅ |
|
|
| 12 | Build Script Update | ✅ |
|
|
| 13 | Integration Tests | ✅ |
|
|
| 14 | HyperPixel Fix (Legacy DPI) | ✅ |
|
|
|
|
### Development Approach
|
|
|
|
Used **Subagent-Driven Development**:
|
|
1. Fresh subagent dispatched per task
|
|
2. Spec compliance review after implementation
|
|
3. Code quality review before completion
|
|
4. Two-stage review ensures correctness
|
|
|
|
---
|
|
|
|
## Architecture Design
|
|
|
|
### System Architecture
|
|
|
|
```
|
|
SecuBox Appliance
|
|
┌─────────────────────────┐
|
|
│ │
|
|
│ ┌─────────────────┐ │
|
|
│ │ secubox-eye- │ │
|
|
│ │ remote.service │ │
|
|
│ │ │ │
|
|
│ │ FastAPI:8000 │ │
|
|
│ └────────┬────────┘ │
|
|
│ │ │
|
|
│ ┌────────▼────────┐ │
|
|
│ │ USB Host │ │
|
|
│ │ 10.55.0.1 │ │
|
|
│ └────────┬────────┘ │
|
|
│ │ │
|
|
└───────────┼────────────┘
|
|
│ USB OTG
|
|
│ (ECM + ACM)
|
|
┌───────────┼────────────┐
|
|
│ │ │
|
|
│ ┌────────▼────────┐ │
|
|
│ │ USB Gadget │ │
|
|
│ │ 10.55.0.2 │ │
|
|
│ └────────┬────────┘ │
|
|
│ │ │
|
|
│ ┌────────▼────────┐ │
|
|
│ │ nginx :8080 │ │
|
|
│ │ proxy → :8000 │ │
|
|
│ └────────┬────────┘ │
|
|
│ │ │
|
|
│ ┌────────▼────────┐ │
|
|
│ │ Chromium Kiosk │ │
|
|
│ │ localhost:8080 │ │
|
|
│ └────────┬────────┘ │
|
|
│ │ │
|
|
│ ┌────────▼────────┐ │
|
|
│ │ HyperPixel │ │
|
|
│ │ 480x480 LCD │ │
|
|
│ └─────────────────┘ │
|
|
│ │
|
|
│ RPi Zero W │
|
|
└─────────────────────────┘
|
|
```
|
|
|
|
### Data Flow
|
|
|
|
```
|
|
┌──────────┐ GET /metrics ┌──────────┐
|
|
│ Dashboard│◄──────────────────►│ FastAPI │
|
|
│ (JS) │ JSON response │ Backend │
|
|
└────┬─────┘ └────┬─────┘
|
|
│ │
|
|
│ fetch() every 2s │ reads /proc/*
|
|
│ │ os.statvfs()
|
|
▼ ▼
|
|
┌──────────┐ ┌──────────┐
|
|
│ Canvas │ │ Linux │
|
|
│ Rings │ │ Kernel │
|
|
└──────────┘ └──────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Component Details
|
|
|
|
### Models Layer
|
|
|
|
#### `models/metrics.py`
|
|
```python
|
|
class SystemMetrics(BaseModel):
|
|
cpu_percent: float # 0-100
|
|
memory_percent: float # 0-100
|
|
disk_percent: float # 0-100
|
|
cpu_temp: float # Celsius
|
|
load_avg_1: float # 1-minute load
|
|
uptime_seconds: int
|
|
hostname: str
|
|
timestamp: datetime
|
|
```
|
|
|
|
#### `models/device.py`
|
|
```python
|
|
class Device(BaseModel):
|
|
id: str # UUID
|
|
name: str
|
|
device_type: str # "eye-remote"
|
|
paired_at: datetime
|
|
last_seen: datetime
|
|
is_active: bool
|
|
|
|
class DeviceToken(BaseModel):
|
|
device_id: str
|
|
token_hash: str # SHA256
|
|
created_at: datetime
|
|
expires_at: Optional[datetime]
|
|
```
|
|
|
|
#### `models/pairing.py`
|
|
```python
|
|
class PairingSession(BaseModel):
|
|
session_id: str
|
|
gateway_url: str
|
|
expires_at: datetime
|
|
qr_data: str # JSON for QR code
|
|
|
|
class PairingRequest(BaseModel):
|
|
session_id: str
|
|
device_name: str
|
|
device_type: str = "eye-remote"
|
|
```
|
|
|
|
### Core Layer
|
|
|
|
#### `core/metrics.py`
|
|
- Reads CPU from `/proc/stat` (delta calculation)
|
|
- Reads memory from `/proc/meminfo`
|
|
- Reads disk via `os.statvfs('/')`
|
|
- Reads temperature from `/sys/class/thermal/thermal_zone0/temp`
|
|
- Caches results for 1 second (async)
|
|
|
|
#### `core/device_registry.py`
|
|
- Stores devices in `/var/lib/secubox/eye-remote/devices.json`
|
|
- Token validation with `secrets.compare_digest()`
|
|
- SHA256 token hashing
|
|
- Thread-safe file operations
|
|
|
|
#### `core/pairing.py`
|
|
- 5-minute session TTL
|
|
- QR code contains: gateway URL, session ID, timestamp
|
|
- Single-use sessions (consumed on completion)
|
|
|
|
### API Layer
|
|
|
|
#### Authentication
|
|
|
|
```python
|
|
# JWT for management endpoints
|
|
async def require_jwt(token: str = Depends(oauth2_scheme)):
|
|
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
|
|
return payload
|
|
|
|
# Device token for metrics endpoint
|
|
async def require_device_token(x_device_token: str = Header(...)):
|
|
device = registry.validate_token(x_device_token)
|
|
return device
|
|
```
|
|
|
|
#### Endpoints
|
|
|
|
| Method | Path | Auth | Purpose |
|
|
|--------|------|------|---------|
|
|
| GET | `/devices/` | JWT | List paired devices |
|
|
| POST | `/devices/pair` | JWT | Pair new device |
|
|
| DELETE | `/devices/{id}` | JWT | Unpair device |
|
|
| POST | `/pairing/start` | JWT | Start pairing session |
|
|
| GET | `/pairing/qr/{session_id}` | JWT | Get QR code PNG |
|
|
| POST | `/pairing/complete` | None | Complete pairing (from device) |
|
|
| GET | `/metrics/` | Device Token | Get system metrics |
|
|
|
|
---
|
|
|
|
## Build System
|
|
|
|
### QEMU-Based Offline Build
|
|
|
|
The build script creates a complete SD card image with all packages pre-installed using QEMU ARM emulation:
|
|
|
|
```bash
|
|
┌─────────────────────────────────────────────────────┐
|
|
│ Build Process │
|
|
├─────────────────────────────────────────────────────┤
|
|
│ 1. Decompress RPi OS Lite image │
|
|
│ 2. Expand image by 1GB for packages │
|
|
│ 3. Mount via loopback device │
|
|
│ 4. Copy qemu-arm-static for ARM emulation │
|
|
│ 5. chroot and apt-get install packages │
|
|
│ 6. Configure HyperPixel (legacy DPI mode) │
|
|
│ 7. Install Eye Remote services │
|
|
│ 8. Configure kiosk (LightDM + Openbox + Chromium) │
|
|
│ 9. Cleanup and create final image │
|
|
└─────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Packages Pre-installed
|
|
|
|
```
|
|
chromium-browser xserver-xorg xinit
|
|
lightdm openbox unclutter
|
|
nginx python3-pigpio pigpio
|
|
i2c-tools fonts-dejavu-core
|
|
```
|
|
|
|
---
|
|
|
|
## Display Configuration
|
|
|
|
### The HyperPixel Problem
|
|
|
|
**Issue:** Pi Zero W does not support KMS (Kernel Mode Setting) properly.
|
|
|
|
**Symptom:** Black screen with KMS overlays (`vc4-kms-v3d`, `vc4-kms-dpi-hyperpixel2r`).
|
|
|
|
**Solution:** Use legacy DPI mode with manual pixel timings.
|
|
|
|
### Working Configuration
|
|
|
|
```ini
|
|
# /boot/config.txt
|
|
|
|
# Legacy DPI overlay (NOT KMS)
|
|
dtoverlay=hyperpixel2r
|
|
|
|
# Manual DPI timings for ST7701S LCD
|
|
enable_dpi_lcd=1
|
|
display_default_lcd=1
|
|
dpi_group=2
|
|
dpi_mode=87
|
|
dpi_output_format=0x7f216
|
|
dpi_timings=480 0 10 16 55 480 0 15 60 15 0 0 0 60 0 19200000 6
|
|
framebuffer_width=480
|
|
framebuffer_height=480
|
|
```
|
|
|
|
### ST7701S LCD Initialization
|
|
|
|
The HyperPixel 2.1 Round uses an ST7701S LCD controller that requires SPI initialization at boot:
|
|
|
|
```python
|
|
# /usr/bin/hyperpixel2r-init (simplified)
|
|
import pigpio
|
|
|
|
pi = pigpio.pi()
|
|
# Bit-bang SPI commands to ST7701S
|
|
# Initialize display registers
|
|
# Enable backlight
|
|
pi.stop()
|
|
```
|
|
|
|
### Service Dependencies
|
|
|
|
```
|
|
pigpiod.service
|
|
└── hyperpixel2r-init.service
|
|
└── lightdm.service
|
|
└── chromium (kiosk)
|
|
```
|
|
|
|
---
|
|
|
|
## API Reference
|
|
|
|
### GET /api/v1/eye-remote/metrics/
|
|
|
|
**Auth:** `X-Device-Token` header
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"cpu_percent": 23.5,
|
|
"memory_percent": 45.2,
|
|
"disk_percent": 28.0,
|
|
"cpu_temp": 48.3,
|
|
"load_avg_1": 0.42,
|
|
"uptime_seconds": 86400,
|
|
"hostname": "secubox-pro",
|
|
"timestamp": "2026-04-21T20:30:00Z"
|
|
}
|
|
```
|
|
|
|
### POST /api/v1/eye-remote/pairing/start
|
|
|
|
**Auth:** JWT Bearer token
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"session_id": "abc123",
|
|
"expires_at": "2026-04-21T20:35:00Z",
|
|
"qr_url": "/api/v1/eye-remote/pairing/qr/abc123"
|
|
}
|
|
```
|
|
|
|
### POST /api/v1/eye-remote/pairing/complete
|
|
|
|
**Auth:** None (uses session_id)
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"session_id": "abc123",
|
|
"device_name": "Living Room Eye",
|
|
"device_type": "eye-remote"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"device_id": "dev_xyz789",
|
|
"token": "raw_token_for_device_storage",
|
|
"gateway_url": "http://10.55.0.1:8000"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Development Tools
|
|
|
|
### Gateway Emulator
|
|
|
|
Simulates SecuBox metrics without physical hardware:
|
|
|
|
```bash
|
|
# Install
|
|
pip install -e tools/secubox-eye-gateway/
|
|
|
|
# Run with profile
|
|
secubox-eye-gateway --profile stressed --port 8765
|
|
|
|
# Profiles:
|
|
# idle - Low activity (CPU ~5%, temp ~40°C)
|
|
# normal - Typical load (CPU ~25%, temp ~50°C)
|
|
# busy - Heavy load (CPU ~65%, temp ~62°C)
|
|
# stressed - Near limits (CPU ~85%, temp ~72°C)
|
|
```
|
|
|
|
### Emulator Endpoints
|
|
|
|
| Endpoint | Description |
|
|
|----------|-------------|
|
|
| `GET /api/v1/health` | Health check |
|
|
| `GET /api/v1/system/metrics` | Simulated metrics |
|
|
| `GET /api/v1/eye-remote/discover` | Discovery info |
|
|
|
|
---
|
|
|
|
## Bootstrap Role (v2.1.0)
|
|
|
|
The Eye Remote can serve as a boot device for ESPRESSObin and MOCHAbin appliances, providing critical functionality during system initialization and recovery:
|
|
|
|
### Capabilities
|
|
|
|
- **Mass Storage LUN** — U-Boot loads kernel/DTB/initrd from active slot via USB Mass Storage
|
|
- **TFTP Shadow** — Test new images before promoting to active slot
|
|
- **Atomic Swap** — Safe active/shadow slot exchange with rollback protection
|
|
- **Boot Menu** — Interactive selection of kernel versions and boot parameters
|
|
|
|
### Use Cases
|
|
|
|
| Use Case | Benefit |
|
|
|----------|---------|
|
|
| **Factory Reset** | Boot fresh image without physical SD cards |
|
|
| **Recovery Boot** | Fallback when internal storage is corrupted |
|
|
| **Image Testing** | Try new Debian images before committing |
|
|
| **Firmware Updates** | Safe A/B slot switching with 4R rollback |
|
|
|
|
### Architecture
|
|
|
|
The Eye Remote exposes two USB LUNs:
|
|
|
|
1. **LUN 0** — Mass Storage (active boot image)
|
|
- Kernel + DTB + initrd partition
|
|
- Auto-synced from active slot
|
|
|
|
2. **LUN 1** — Shadow Test Storage
|
|
- Staging area for new images
|
|
- Isolated from live system
|
|
|
|
### Configuration
|
|
|
|
Bootstrap is configured in `/etc/secubox/eye-remote.toml`:
|
|
|
|
```toml
|
|
[bootstrap]
|
|
enabled = true
|
|
mass_storage_lun = 0
|
|
shadow_lun = 1
|
|
auto_sync_interval = 300 # 5 minutes
|
|
max_rollback_slots = 4
|
|
```
|
|
|
|
### Workflow
|
|
|
|
```
|
|
1. User initiates image test via dashboard
|
|
↓
|
|
2. Eye Remote downloads image to shadow LUN
|
|
↓
|
|
3. User selects "Boot from Shadow" in U-Boot menu
|
|
↓
|
|
4. System tests image on next reboot
|
|
↓
|
|
5. User confirms success → Image promoted to active
|
|
↓
|
|
6. Or rejects → Automatic rollback to previous active
|
|
```
|
|
|
|
### Security Considerations
|
|
|
|
- Bootstrap operations are **JWT-authenticated** only
|
|
- All slot operations are **logged** to audit trail
|
|
- Image integrity verified via **SHA256 checksums**
|
|
- Rollback protected against **malicious substitution** via timestamp validation
|
|
|
|
---
|
|
|
|
**Full documentation:** See [Eye-Remote-Bootstrap](Eye-Remote-Bootstrap.md) for detailed implementation, testing procedures, and troubleshooting.
|
|
|
|
---
|
|
|
|
## Deployment
|
|
|
|
### SD Card Flashing
|
|
|
|
```bash
|
|
# Build image
|
|
sudo ./remote-ui/round/build-eye-remote-image.sh \
|
|
-i raspios-lite-armhf.img.xz \
|
|
-s "WiFiSSID" -p "password"
|
|
|
|
# Flash
|
|
sudo dd if=/tmp/secubox-eye-remote-2.0.0.img \
|
|
of=/dev/sdX bs=4M status=progress
|
|
|
|
# Or compressed
|
|
xz -9 /tmp/secubox-eye-remote-2.0.0.img
|
|
xzcat *.img.xz | sudo dd of=/dev/sdX bs=4M status=progress
|
|
```
|
|
|
|
### First Boot Checklist
|
|
|
|
- [ ] Insert SD card
|
|
- [ ] Connect USB DATA port (middle) to SecuBox
|
|
- [ ] Wait 60 seconds
|
|
- [ ] Display shows dashboard
|
|
- [ ] SSH accessible: `ssh pi@10.55.0.2`
|
|
|
|
### OTA Updates
|
|
|
|
```bash
|
|
# Update dashboard
|
|
scp index.html pi@10.55.0.2:/var/www/secubox-round/
|
|
|
|
# Update backend (on SecuBox host)
|
|
apt update && apt install secubox-eye-remote
|
|
|
|
# Restart services
|
|
systemctl restart secubox-eye-remote
|
|
```
|
|
|
|
---
|
|
|
|
## Lessons Learned
|
|
|
|
### 1. KMS vs Legacy DPI
|
|
|
|
**Problem:** Assumed KMS would work everywhere since it's the "modern" approach.
|
|
|
|
**Reality:** Pi Zero W (BCM2835) has limited GPU support. KMS overlays cause black screen.
|
|
|
|
**Solution:** Always test on actual hardware. Use legacy DPI mode for Pi Zero W.
|
|
|
|
### 2. ST7701S Initialization
|
|
|
|
**Problem:** Display stayed black even with correct overlay.
|
|
|
|
**Reality:** ST7701S LCD controller requires SPI commands at boot.
|
|
|
|
**Solution:** `hyperpixel2r-init` script using pigpio for GPIO/SPI access.
|
|
|
|
### 3. QEMU Package Installation
|
|
|
|
**Problem:** Pi Zero W is slow. Installing packages at first boot takes forever.
|
|
|
|
**Reality:** ARM emulation via QEMU allows pre-installing packages during image build.
|
|
|
|
**Solution:** QEMU chroot in build script. Offline-capable images.
|
|
|
|
### 4. Token Security
|
|
|
|
**Problem:** Device tokens stored in plain text.
|
|
|
|
**Reality:** Compromised token = unauthorized access.
|
|
|
|
**Solution:** SHA256 hash stored server-side. `secrets.compare_digest()` for timing-safe comparison.
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- [Pimoroni HyperPixel 2.1 Round](https://github.com/pimoroni/hyperpixel2r)
|
|
- [Raspberry Pi DPI Display](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#parallel-display-interface-dpi)
|
|
- [pigpio Library](http://abyz.me.uk/rpi/pigpio/)
|
|
- [FastAPI Documentation](https://fastapi.tiangolo.com/)
|
|
|
|
---
|
|
|
|
*CyberMind · SecuBox Eye Remote v2.0.0 · April 2026*
|