This commit adds the complete Dangerous Pi web management interface with all MVP features implemented and tested locally. ## New Features ### Backend (Python + FastAPI) - Complete FastAPI backend with async support - 40+ API endpoints (Health, PM3, WiFi, Updates, UPS, BLE, Plugins) - 6 managers: Session, WiFi, Update, UPS, BLE, Plugin - SQLite database with sessions, config, history, crash reports - Server-Sent Events (SSE) for real-time notifications - Mock PM3 worker for development without hardware ### WiFi Manager - Interface detection (USB vs built-in) - Network scanning with signal strength - Mode switching (AP/Client/Dual/Auto/Off) - Network connection with password support - Hidden SSID and saved networks support - Static IP and DHCP configuration - 10 WiFi API endpoints ### Update Manager - GitHub releases API integration - Automatic periodic update checks - Semantic version comparison - Update download with progress tracking - SHA256 checksum verification - Automatic installation with backup and rollback - PM3 client rebuild after updates - 6 Update API endpoints ### UPS Manager - I2C battery monitoring (MAX17040-compatible) - Battery percentage, voltage, current tracking - Power source detection (AC/Battery) - Safe shutdown triggers at configurable thresholds - Event callbacks for battery warnings - SSE and BLE notification integration - 3 UPS API endpoints ### BLE Manager - Bluetooth Low Energy notification support - Auto-detects BLE capability - Multiple notification types (updates, battery, shutdown, etc.) - BLE advertising management - Device connection tracking - 4 BLE API endpoints ### Plugin Framework - Dynamic plugin loading/unloading - Plugin lifecycle management (load, enable, disable, unload) - Hook system for extensibility - JSON-based metadata - Example "Hello World" plugin included - 7 Plugin API endpoints ### Frontend (Remix.js + React) - Cyberpunk-themed responsive UI - Dashboard with system status - PM3 command interface with history - Settings page with WiFi and Update management - Command logs viewer - Theme toggle (Dark/Light/Auto) - Server-side rendering (SSR) - Mobile-first responsive design ### System Integration - Systemd service with security hardening - Automated install/uninstall scripts - Environment configuration template - Hardware access groups (i2c, bluetooth, gpio, dialout) - Pi-gen stage 04 integration for OS image building - Port conflict resolution with ttyd-bash - I2C interface auto-enable for UPS HAT ### Testing - test_backend.py - Backend API tests - test_ups.py - UPS manager tests - test_ble.py - BLE manager tests - test_plugins.py - Plugin manager tests - All tests passing locally ### Documentation - 12 comprehensive documentation files - claude.md - AI development guide - WIFI_MANAGER.md - WiFi management guide - UPDATE_MANAGER.md - Update system guide - PORT_CONFLICT.md - Port conflict resolution guide - MVP_COMPLETE.md - MVP implementation summary - PROJECT_STATUS.md - Project status and roadmap - systemd/README.md - Service management docs - pi-gen integration documentation ## Technical Details - ~5,000+ lines of backend code - 11 Python dependencies (smbus2 added for UPS) - FastAPI with async/await throughout - Type hints and docstrings on all functions - RESTful API design with SSE for notifications - Security hardening (non-root, protected dirs, resource limits) ## Next Steps - Deploy to Raspberry Pi Zero 2 W hardware - Test with real Proxmark3 device - Test UPS HAT integration - Test BLE on Pi hardware - Build custom OS image with pi-gen - Performance optimization for Pi Zero 2 W 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
186 lines
5.1 KiB
Python
186 lines
5.1 KiB
Python
"""Update management API endpoints."""
|
|
from typing import Optional
|
|
from fastapi import APIRouter, HTTPException
|
|
from pydantic import BaseModel
|
|
|
|
from ..managers.update_manager import get_update_manager, UpdateStatus
|
|
from ..managers.ble_manager import get_ble_manager, NotificationType
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class UpdateCheckResponse(BaseModel):
|
|
"""Response model for update check."""
|
|
update_available: bool
|
|
current_version: str
|
|
latest_version: Optional[str] = None
|
|
release_date: Optional[str] = None
|
|
changelog: Optional[str] = None
|
|
is_prerelease: bool = False
|
|
download_size: Optional[int] = None
|
|
message: Optional[str] = None
|
|
|
|
|
|
class UpdateProgressResponse(BaseModel):
|
|
"""Response model for update progress."""
|
|
status: str
|
|
current_version: str
|
|
available_version: Optional[str] = None
|
|
download_progress: float = 0.0
|
|
error_message: Optional[str] = None
|
|
last_check: Optional[str] = None
|
|
|
|
|
|
class ReleaseNotesRequest(BaseModel):
|
|
"""Request model for release notes."""
|
|
version: Optional[str] = None
|
|
|
|
|
|
@router.get("/check", response_model=UpdateCheckResponse)
|
|
async def check_for_updates():
|
|
"""Check for available updates.
|
|
|
|
Returns:
|
|
UpdateCheckResponse with update status and info
|
|
"""
|
|
try:
|
|
manager = get_update_manager()
|
|
ble_manager = get_ble_manager()
|
|
result = await manager.check_for_updates()
|
|
|
|
# Send BLE notification if update is available
|
|
if result.get("update_available"):
|
|
await ble_manager.send_notification(
|
|
NotificationType.UPDATE_AVAILABLE,
|
|
f"Update available: v{result['latest_version']}",
|
|
{"version": result["latest_version"]}
|
|
)
|
|
|
|
return UpdateCheckResponse(**result)
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/progress", response_model=UpdateProgressResponse)
|
|
async def get_update_progress():
|
|
"""Get current update progress.
|
|
|
|
Returns:
|
|
UpdateProgressResponse with current status
|
|
"""
|
|
try:
|
|
manager = get_update_manager()
|
|
progress = await manager.get_progress()
|
|
|
|
return UpdateProgressResponse(
|
|
status=progress.status.value,
|
|
current_version=progress.current_version,
|
|
available_version=progress.available_version,
|
|
download_progress=progress.download_progress,
|
|
error_message=progress.error_message,
|
|
last_check=progress.last_check
|
|
)
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.post("/download")
|
|
async def download_update():
|
|
"""Download the available update.
|
|
|
|
Returns:
|
|
Success message
|
|
"""
|
|
try:
|
|
manager = get_update_manager()
|
|
success = await manager.download_update()
|
|
|
|
if success:
|
|
return {"message": "Update downloaded successfully"}
|
|
else:
|
|
raise HTTPException(status_code=500, detail="Download failed")
|
|
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.post("/install")
|
|
async def install_update():
|
|
"""Install the downloaded update.
|
|
|
|
Returns:
|
|
Success message
|
|
"""
|
|
try:
|
|
manager = get_update_manager()
|
|
ble_manager = get_ble_manager()
|
|
success = await manager.install_update()
|
|
|
|
if success:
|
|
# Send BLE notification
|
|
await ble_manager.send_notification(
|
|
NotificationType.UPDATE_COMPLETE,
|
|
"Update installed successfully",
|
|
{"restart_required": True}
|
|
)
|
|
|
|
return {
|
|
"message": "Update installed successfully. Please restart the service.",
|
|
"restart_required": True
|
|
}
|
|
else:
|
|
raise HTTPException(status_code=500, detail="Installation failed")
|
|
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.post("/release-notes", response_model=dict)
|
|
async def get_release_notes(request: ReleaseNotesRequest):
|
|
"""Get release notes for a specific version.
|
|
|
|
Args:
|
|
request: Version to get notes for (latest if not specified)
|
|
|
|
Returns:
|
|
Release notes as markdown
|
|
"""
|
|
try:
|
|
manager = get_update_manager()
|
|
notes = await manager.get_release_notes(request.version)
|
|
|
|
return {
|
|
"version": request.version or "latest",
|
|
"notes": notes
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/current-version")
|
|
async def get_current_version():
|
|
"""Get current system version.
|
|
|
|
Returns:
|
|
Current version info
|
|
"""
|
|
try:
|
|
manager = get_update_manager()
|
|
progress = await manager.get_progress()
|
|
|
|
return {
|
|
"version": progress.current_version,
|
|
"last_check": progress.last_check
|
|
}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|