feat: remote commands, systemd units, process observability, broker auth split

- Command intake (reboot/shutdown) on infoscreen/{uuid}/commands with ack lifecycle
- MQTT_USER/MQTT_PASSWORD_BROKER split from identity vars; configure_mqtt_security() updated
- infoscreen-simclient.service: Type=notify, WatchdogSec=60, Restart=on-failure
- infoscreen-notify-failure@.service + script: retained MQTT alert when systemd gives up (Gap 3)
- _sd_notify() watchdog keepalive in simclient main loop (Gap 1)
- broker_connection block in health payload: reconnect_count, last_disconnect_at (Gap 2)
- COMMAND_MOCK_REBOOT_IMMEDIATE_COMPLETE canary flag with safety guard
- SERVER_TEAM_ACTIONS.md: server-side integration action items
- Docs: README, CHANGELOG, src/README, copilot-instructions updated
- 43 tests passing
This commit is contained in:
RobbStarkAustria
2026-04-05 08:36:50 +02:00
parent 82f43f75ba
commit 0cd0d95612
28 changed files with 2487 additions and 36 deletions

View File

@@ -22,23 +22,52 @@ Primary runtime flow:
## Key Files
- `display_manager.py`: display lifecycle, HDMI-CEC, screenshots, local fallback logic.
- `simclient.py`: MQTT callbacks, event persistence, dashboard publishing, power-intent validation.
- `simclient.py`: MQTT callbacks, event persistence, dashboard publishing, power-intent validation, command intake.
- `current_event.json`: active event state consumed by the display manager.
- `current_process_health.json`: local health bridge for monitoring.
- `power_intent_state.json`: latest validated power intent from MQTT.
- `power_state.json`: latest applied power action telemetry.
- `screenshots/meta.json`: screenshot metadata used by the dashboard path.
- `../scripts/start-simclient.sh`: launcher for `simclient.py` (used by the systemd unit).
- `../scripts/start-display-manager.sh`: launcher for `display_manager.py`.
- `../scripts/infoscreen-simclient.service`: systemd unit for `simclient.py`.
- `../scripts/infoscreen-display.service`: systemd unit for `display_manager.py`.
- `../scripts/infoscreen-notify-failure@.service`: systemd template unit; fires on `OnFailure=`.
- `../scripts/infoscreen-notify-failure.sh`: publishes `service_failed` MQTT alert when a unit gives up.
## Developer Workflow
Typical local workflow:
On deployed devices, both processes are managed by systemd:
```bash
# Start / stop / restart
sudo systemctl start infoscreen-simclient infoscreen-display
sudo systemctl restart infoscreen-simclient infoscreen-display
# Follow logs
journalctl -u infoscreen-simclient -u infoscreen-display -f
```
First-time systemd setup:
```bash
sudo cp scripts/infoscreen-simclient.service /etc/systemd/system/
sudo cp scripts/infoscreen-display.service /etc/systemd/system/
sudo cp scripts/infoscreen-notify-failure@.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable infoscreen-simclient infoscreen-display
```
Or run `src/pi-setup.sh` which includes the above as step 14.
For local development without systemd:
```bash
cd ~/infoscreen-dev
source venv/bin/activate
# Terminal 1
./scripts/start-dev.sh
./scripts/start-simclient.sh
# Terminal 2
./scripts/start-display-manager.sh
@@ -51,6 +80,7 @@ Useful helpers:
- `./scripts/test-mqtt.sh`
- `./scripts/test-screenshot.sh`
- `./scripts/test-power-intent.sh`
- `./scripts/test-progress-bars.sh`
## MQTT Topics
@@ -59,8 +89,11 @@ Useful helpers:
- `infoscreen/discovery`
- `infoscreen/{client_id}/heartbeat`
- `infoscreen/{client_id}/dashboard`
- `infoscreen/{client_id}/health`
- `infoscreen/{client_id}/health` — includes `broker_connection` block with `reconnect_count`, `last_disconnect_at`
- `infoscreen/{client_id}/power/state`
- `infoscreen/{client_id}/commands/ack` — command acknowledgement (states: `accepted`, `rejected`, `execution_started`, `completed`, `failed`)
- `infoscreen/{client_id}/command/ack` — legacy ack topic (also published for compatibility)
- `infoscreen/{client_id}/service_failed` — retained alert published by `infoscreen-notify-failure.sh` when systemd gives up restarting a unit
### Server → Client
@@ -68,6 +101,7 @@ Useful helpers:
- `infoscreen/{client_id}/group_id`
- `infoscreen/events/{group_id}`
- `infoscreen/groups/{group_id}/power/intent`
- `infoscreen/{client_id}/commands` — remote command intake (`reboot`, `shutdown`)
## Event and Display Notes
@@ -118,6 +152,8 @@ cat ~/infoscreen-dev/src/screenshots/meta.json
- `ENV=development` disables HDMI-CEC in the display manager.
- `POWER_CONTROL_MODE` controls local vs hybrid vs mqtt power behavior.
- `COMMAND_HELPER_PATH` points to the shell script that executes privileged commands (reboot/shutdown). Use `mock-command-helper.sh` for local testing.
- `COMMAND_MOCK_REBOOT_IMMEDIATE_COMPLETE=1` makes a mock reboot complete immediately instead of waiting for process restart. Only works when the helper basename is `mock-command-helper.sh`.
- File download host rewriting is handled in `simclient.py` using `FILE_SERVER_*` settings.
## Related Documents