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

@@ -0,0 +1,55 @@
[Unit]
Description=Infoscreen Simclient (MQTT communication)
Documentation=https://github.com/RobbStarkAustria/infoscreen_client_2025
# Simclient needs network before starting — MQTT will fail otherwise.
After=network-online.target
Wants=network-online.target
# Publish an MQTT alert if systemd gives up restarting (StartLimitBurst exceeded).
OnFailure=infoscreen-notify-failure@%n.service
[Service]
# notify: simclient sends READY=1 via sd_notify once fully initialised.
# WatchdogSec: if WATCHDOG=1 is not sent within this window, systemd kills
# and restarts the process — detects hung/deadlocked main loops.
Type=notify
WatchdogSec=60
User=olafn
Group=olafn
WorkingDirectory=/home/olafn/infoscreen-dev
# Load all client configuration from the local .env file.
# Keep .env mode 600; systemd reads it as root before dropping privileges.
EnvironmentFile=/home/olafn/infoscreen-dev/.env
# Start simclient
ExecStart=/home/olafn/infoscreen-dev/scripts/start-simclient.sh
# Restart on failure (non-zero exit or signal).
# This covers crash recovery AND the reboot-command lifecycle:
# 1. Server sends reboot_host command
# 2. Simclient publishes accepted + execution_started, then exits
# 3. Systemd restarts simclient within RestartSec seconds
# 4. On reconnect, heartbeat loop detects pending_recovery_command and
# publishes completed — closing the lifecycle cleanly.
Restart=on-failure
RestartSec=10
# Prevent rapid restart thrash: allow at most 5 restarts in 60 seconds.
StartLimitIntervalSec=60
StartLimitBurst=5
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=infoscreen-simclient
# Security settings
NoNewPrivileges=true
PrivateTmp=true
# Resource limits
LimitNOFILE=65536
[Install]
# Simclient runs in multi-user mode — no graphical session required.
WantedBy=multi-user.target