feat: aggregated snapshot + wiring-graph APIs, MQTT device brokers
Backend
- snapshot: GET /api/v1/snapshot aggregates targets, devices, sources,
presets and system into one payload for the HA coordinator, collapsing
the prior ~2N+M request fan-out; per-section ?include= gating.
- graph: GET /api/v1/graph{,/schema,/dependents} backed by a pure,
unit-tested graph_schema engine — one authoritative connectable-field
registry so the editor no longer hard-codes topology in two places.
- devices: thread mqtt_source_id through DeviceCreate/Update/Response and
the routes for multi-broker MQTT; shared validate_mqtt_source_exists
(_mqtt_validation.py) reused by device + output-target routes; stop
update_device masking intentional 4xx as 500.
- shutdown: bound uvicorn graceful-shutdown via GRACEFUL_SHUTDOWN_TIMEOUT
(shared by __main__, android_entry, demo) so a lingering events WebSocket
can't strand LED targets or block process exit.
- access log: structured _access_log middleware attributing each request to
its authenticated token label (never the secret); uvicorn access_log off.
Frontend
- graph editor: generic schema-driven port/edge rendering, layout and
connection handling; service-worker refresh.
- device modals: MQTT broker EntitySelect for device_type=mqtt in add-device
and settings, wired into load/save/validate/dirty-check/clone.
- i18n: en/ru/zh keys.
Tests: graph routes + schema, snapshot routes, access log, mqtt_source_id
device regressions, bounded-shutdown entrypoint. 1614 passed.
This commit is contained in:
@@ -201,9 +201,19 @@ caller off the legacy path, then delete it.
|
||||
- [x] Field on `device_config.MQTTConfig`
|
||||
- [x] `MQTTLEDClient` acquires runtime in `connect()`, releases in `close()`
|
||||
- [x] Provider threads `mqtt_manager` via `ProviderDeps`
|
||||
- [ ] Device editor: MQTT source picker shown for `device_type=mqtt` *(UI still
|
||||
pending — backend accepts the field, but the device-create form doesn't
|
||||
expose it yet)*
|
||||
- [x] Device editor: MQTT source picker shown for `device_type=mqtt`. Turned
|
||||
out the API layer was *also* missing it (the TODO's "backend accepts the
|
||||
field" was wrong — `mqtt_source_id` lived in `device_store` +
|
||||
`device_config.MQTTConfig` but was dropped by `DeviceCreate/Update/Response`
|
||||
and the routes). Added: schema fields + route threading + referenced-source
|
||||
validation (`_validate_mqtt_source_exists`, mirrors output_targets) +
|
||||
`except HTTPException: raise` guard in `update_device` (it was masking its
|
||||
own 4xx as 500). Frontend: broker `EntitySelect` (reusing `mqttSourcesCache`)
|
||||
in both the add-device (`device-discovery.ts`) and settings
|
||||
(`devices.ts`) modals — shown for `device_type=mqtt`, wired into
|
||||
load/save/validate/dirty-check/clone. Empty = "first available broker".
|
||||
4 regression tests in `test_devices_routes.py::TestMqttSourceId`; full
|
||||
suite 1567 passing; en/ru/zh keys added.
|
||||
|
||||
### Phase 5 — `AutomationEngine`
|
||||
|
||||
@@ -213,8 +223,11 @@ caller off the legacy path, then delete it.
|
||||
### Phase 6 — `api/routes/system.py`
|
||||
|
||||
- [x] Replace integration status with `mqtt_manager.get_all_sources_status()`
|
||||
- [ ] Update frontend dashboard payload (MQTT widget now expects a list of
|
||||
sources instead of a single `enabled`/`connected` pair — surface in UI)
|
||||
- [x] Update frontend dashboard payload (MQTT widget now expects a list of
|
||||
sources instead of a single `enabled`/`connected` pair — surface in UI).
|
||||
Done: `dashboard.ts` `_renderMQTTIntegrationCard` renders one card per
|
||||
`mqttStatus.connections` entry; `_updateIntegrationsInPlace` iterates the
|
||||
list.
|
||||
|
||||
### Phase 7 — Startup migration
|
||||
|
||||
|
||||
Reference in New Issue
Block a user