# Developer Guide This document is the developer-facing companion to the root [README.md](../README.md). It focuses on code structure, runtime boundaries, MQTT flow, and debugging during implementation work. For installation, operator usage, and deployment, start at [README.md](../README.md). ## Architecture The client is split into two cooperating processes: - `simclient.py`: MQTT communication, discovery, group assignment, event intake, heartbeat, dashboard publishing, power-intent intake. - `display_manager.py`: event polling, display orchestration, HDMI-CEC, screenshots, local process health state. Primary runtime flow: 1. `simclient.py` receives group and event messages over MQTT. 2. It writes the active event into `current_event.json`. 3. `display_manager.py` polls that file and starts or stops the display process. 4. `display_manager.py` writes health, screenshot, and power telemetry files. 5. `simclient.py` publishes dashboard, health, and power-state messages. ## Key Files - `display_manager.py`: display lifecycle, HDMI-CEC, screenshots, local fallback logic. - `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 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-simclient.sh # Terminal 2 ./scripts/start-display-manager.sh ``` Useful helpers: - `./dev-workflow.sh` - `./scripts/test-display-manager.sh` - `./scripts/test-mqtt.sh` - `./scripts/test-screenshot.sh` - `./scripts/test-power-intent.sh` - `./scripts/test-progress-bars.sh` ## MQTT Topics ### Client → Server - `infoscreen/discovery` - `infoscreen/{client_id}/heartbeat` - `infoscreen/{client_id}/dashboard` - `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 - `infoscreen/{client_id}/discovery_ack` - `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 Supported runtime content categories: - presentation - video - web / webpage / website / webuntis Presentation behavior is documented in [../IMPRESSIVE_INTEGRATION.md](../IMPRESSIVE_INTEGRATION.md). TV power coordination references: - [../TV_POWER_INTENT_SERVER_CONTRACT_V1.md](../TV_POWER_INTENT_SERVER_CONTRACT_V1.md) - [../TV_POWER_RUNBOOK.md](../TV_POWER_RUNBOOK.md) ## Debugging ### Logs ```bash tail -f ~/infoscreen-dev/logs/display_manager.log ~/infoscreen-dev/src/simclient.log ``` ### Runtime Files ```bash cat ~/infoscreen-dev/src/current_event.json cat ~/infoscreen-dev/src/current_process_health.json cat ~/infoscreen-dev/src/power_intent_state.json cat ~/infoscreen-dev/src/power_state.json ``` ### MQTT Inspection ```bash mosquitto_sub -h YOUR_BROKER_IP -t 'infoscreen/#' ``` ### Screenshots ```bash ls -lh ~/infoscreen-dev/src/screenshots/ cat ~/infoscreen-dev/src/screenshots/meta.json ``` ## Environment Notes - `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 - [../README.md](../README.md) - [DISPLAY_MANAGER.md](DISPLAY_MANAGER.md) - [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) - [../CLIENT_MONITORING_SETUP.md](../CLIENT_MONITORING_SETUP.md) - [../SCREENSHOT_MQTT_FIX.md](../SCREENSHOT_MQTT_FIX.md)