Implements PUSH architecture - Bridge receives config from Odoo via HTTP NEW FEATURES: - HTTP Config Server (FastAPI on port 8080) - POST /config: Receive device configuration from Odoo - GET /config: Query currently active configuration - GET /health: Health check endpoint with device statistics - Optional Bearer token authentication (BRIDGE_API_TOKEN) - Config Validation (Pydantic models) - BridgeConfig, DeviceConfig, SessionConfig schemas - Validation: unique device_id, unique mqtt_topic - Threshold validation: working_threshold_w > standby_threshold_w - Dynamic Device Management (DeviceManager) - Device diff detection (add/update/remove) - Automatic MQTT subscribe/unsubscribe for topic changes - SessionDetector lifecycle management - Active session closing on device removal - Config Persistence - Saves received config to /data/config-active.yaml - Bridge startup: loads config-active.yaml as fallback - Docker volume iot-bridge-data:/data for persistence NEW FILES: - iot_bridge/config_server.py - FastAPI HTTP server - iot_bridge/device_manager.py - Device lifecycle management - iot_bridge/tests/test-config-push.sh - Integration test script - iot_bridge/tests/test-config-push.json - Test configuration MODIFIED FILES: - iot_bridge/main.py - Integrated HTTP server in thread - iot_bridge/mqtt_client.py - Added subscribe()/unsubscribe() - iot_bridge/requirements.txt - Added fastapi, uvicorn, pydantic - iot_bridge/Dockerfile - EXPOSE 8080, HTTP healthcheck - odoo/docker-compose.dev.yaml - Port 8080, volume /data TESTING: Verified via iot_bridge/tests/test-config-push.sh: ✅ Config push via HTTP works (200 OK) ✅ Old devices removed, new devices added ✅ MQTT topics dynamically updated (subscribe/unsubscribe) ✅ Config persisted to /data/config-active.yaml ✅ Health endpoint shows last_config_update timestamp ✅ Bridge restarts load config-active.yaml automatically NEXT STEP: Phase 3.2 - Implement Odoo-side config push (Model hooks)
35 lines
953 B
JSON
35 lines
953 B
JSON
{
|
|
"devices": [
|
|
{
|
|
"device_id": "shaper-origin-pm",
|
|
"machine_name": "Shaper Origin CNC",
|
|
"mqtt_topic": "shelly/shaper-origin/status/pm1:0",
|
|
"parser_type": "shelly_pm",
|
|
"session_config": {
|
|
"standby_threshold_w": 20.0,
|
|
"working_threshold_w": 100.0,
|
|
"start_debounce_s": 3.0,
|
|
"stop_debounce_s": 15.0,
|
|
"message_timeout_s": 20.0,
|
|
"heartbeat_interval_s": 30.0
|
|
}
|
|
},
|
|
{
|
|
"device_id": "test-device-manual",
|
|
"machine_name": "Test Device - Manual Simulation",
|
|
"mqtt_topic": "test-device/status/pm1:0",
|
|
"parser_type": "shelly_pm",
|
|
"session_config": {
|
|
"standby_threshold_w": 10.0,
|
|
"working_threshold_w": 50.0,
|
|
"start_debounce_s": 2.0,
|
|
"stop_debounce_s": 10.0,
|
|
"message_timeout_s": 15.0,
|
|
"heartbeat_interval_s": 30.0
|
|
}
|
|
}
|
|
],
|
|
"timestamp": "2026-02-12T10:00:00Z",
|
|
"version": "1.0"
|
|
}
|