# Infoscreen Client - Display Manager Digital signage system for Raspberry Pi that displays presentations, videos, and web content in kiosk mode. Centrally managed via MQTT with automatic client discovery, heartbeat monitoring, and screenshot-based dashboard monitoring. ## 🎯 Key Features - **Automatic Presentation Display** - Server renders PPTX to PDF; client displays PDFs with Impressive - **Auto-Advance Slideshows** - Configurable timing for automatic slide progression - **Loop Mode** - Presentations can loop infinitely or quit after last slide - **HDMI-CEC TV Control** - Automatic TV power on/off based on event scheduling - **MQTT Integration** - Real-time event management from central server - **Group Management** - Organize clients into groups for targeted content - **Heartbeat Monitoring** - Regular status updates and screenshot dashboard - **Client Process Monitoring** - Health-state bridge, crash/restart tracking, and monitoring log - **Screenshot Dashboard** - Automatic screen capture with Wayland/X11 support, client-side compression - **Multi-Content Support** - Presentations, videos, and web pages - **Kiosk Mode** - Full-screen display with automatic startup ## πŸ“‹ System Requirements ### Hardware - Raspberry Pi 4/5 (or compatible) - HDMI display - Network connectivity (WiFi or Ethernet) - SSD storage recommended ### Software - Raspberry Pi OS (Bookworm or newer) - Python 3.x - Impressive (PDF presenter with auto-advance) - Chromium browser (for web content) - VLC or MPV (for video playback) - Screenshot tools: `scrot` or ImageMagick (X11) OR `grim` or `gnome-screenshot` (Wayland) - CEC Utils (for HDMI-CEC TV control - optional) ## πŸš€ Quick Start ### 1. Installation ```bash # Clone repository cd ~/ git clone infoscreen-dev cd infoscreen-dev # Install system dependencies sudo apt-get update sudo apt-get install -y \ python3 python3-pip python3-venv \ impressive \ chromium-browser vlc \ cec-utils \ scrot imagemagick # For Wayland systems, install screenshot tools: # sudo apt-get install grim gnome-screenshot # Create Python virtual environment python3 -m venv venv source venv/bin/activate # Install Python dependencies pip install -r src/requirements.txt ``` ### 2. Configuration Create `.env` file in project root (or copy from `.env.template`): ```bash # Screenshot capture behavior SCREENSHOT_ALWAYS=0 # Set to 1 for testing (forces capture even without active display) # Environment ENV=production # development | production (CEC disabled in development) DEBUG_MODE=0 # 1 to enable debug mode LOG_LEVEL=INFO # DEBUG | INFO | WARNING | ERROR # MQTT Configuration MQTT_BROKER=192.168.1.100 # Your MQTT broker IP/hostname MQTT_PORT=1883 # Timing (seconds) HEARTBEAT_INTERVAL=60 # How often client sends status updates SCREENSHOT_INTERVAL=180 # How often simclient transmits screenshots SCREENSHOT_CAPTURE_INTERVAL=180 # How often display_manager captures screenshots DISPLAY_CHECK_INTERVAL=15 # How often display_manager checks for new events # File/API Server (used to download presentation files) # Defaults to MQTT_BROKER host with port 8000 and http scheme FILE_SERVER_HOST= # Optional; if empty, defaults to MQTT_BROKER FILE_SERVER_PORT=8000 # Default API port FILE_SERVER_SCHEME=http # http or https # FILE_SERVER_BASE_URL= # Optional full override, e.g., http://192.168.1.100:8000 # HDMI-CEC TV Control (optional) CEC_ENABLED=true # Enable automatic TV power control CEC_DEVICE=0 # Target device (0 recommended for TV) CEC_TURN_OFF_DELAY=30 # Seconds to wait before turning off TV CEC_POWER_ON_WAIT=5 # Seconds to wait after power ON (for TV boot) CEC_POWER_OFF_WAIT=5 # Seconds to wait after power OFF ``` ### 3. Start Services ```bash # Start MQTT client (handles events, heartbeat, discovery) cd ~/infoscreen-dev/src python3 simclient.py # In another terminal: Start Display Manager cd ~/infoscreen-dev/src python3 display_manager.py ``` Or use the startup script: ```bash ./scripts/start-display-manager.sh ``` ## πŸ“Š Presentation System ### How It Works The system uses **Impressive** as the PDF presenter with native auto-advance and loop support: 1. **Server-side rendering**: PPTX files are converted to PDF by the server using Gotenberg 2. **Client receives PDFs**: Events contain pre-rendered PDF files ready for display 3. **Direct display**: PDF files are displayed directly with Impressive (no client-side conversion needed) 4. **Auto-advance** uses Impressive's built-in `--auto` parameter 5. **Loop mode** uses Impressive's `--wrap` parameter (infinite loop) 6. **Auto-quit** uses Impressive's `--autoquit` parameter (exit after last slide) ### Event JSON Format #### Looping Presentation (Typical for Events) ```json { "id": "event_123", "start": "2025-10-01 14:00:00", "end": "2025-10-01 16:00:00", "presentation": { "files": [ { "name": "slides.pptx", "url": "https://server/files/slides.pptx" } ], "auto_advance": true, "slide_interval": 10, "loop": true } } ``` **Result:** Slides advance every 10 seconds, presentation loops infinitely until event ends. #### Single Playthrough ```json { "presentation": { "files": [{"name": "welcome.pptx"}], "auto_advance": true, "slide_interval": 5, "loop": false } } ``` **Result:** Slides advance every 5 seconds, exits after last slide. ### Presentation Parameters | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `auto_advance` | boolean | `false` | Enable automatic slide advancement | | `slide_interval` | integer | `10` | Seconds between slides | | `loop` | boolean | `false` | Loop presentation vs. quit after last slide | ### Scheduler-Specific Fields The scheduler may send additional fields that are preserved in `current_event.json`: | Field | Type | Description | |-------|------|-------------| | `page_progress` | boolean | Show overall progress bar in presentation (Impressive `--page-progress`). Can be provided at `presentation.page_progress` (preferred) or top-level. | | `auto_progress` | boolean | Show per-page auto-advance countdown (Impressive `--auto-progress`). Can be provided at `presentation.auto_progress` (preferred) or top-level. | | `occurrence_of_id` | integer | Original event ID for recurring events | | `recurrence_rule` | string | iCal recurrence rule (RRULE format) | | `recurrence_end` | string | End date for recurring events | **Note:** All fields from the scheduler are automatically preserved when events are stored in `current_event.json`. The client does not filter or modify scheduler-specific metadata. #### Progress Bar Display When using Impressive PDF presenter: - `page_progress: true` - Shows a progress bar at the bottom indicating position in the presentation - `auto_progress: true` - Shows a countdown progress bar for each slide during auto-advance - Both options can be enabled simultaneously for maximum visual feedback ## πŸŽ₯ Video Events ```json { "video": { "url": "https://server/videos/intro.mp4", "loop": true, "autoplay": true, "volume": 0.8 } } ``` Notes: - The Display Manager prefers `python-vlc` (libvlc) when available. This gives programmatic control over playback (autoplay, loop, volume) and ensures the player is cleanly stopped and released when events end. - Supported video event fields: - `url` (string): HTTP/HTTPS or streaming URL. URLs using the placeholder host `server` are rewritten to the configured file server (see File/API Server configuration). - `autoplay` (boolean): start playback automatically when the event becomes active (default: true). - `loop` (boolean): loop playback indefinitely. - `volume` (float): 0.0–1.0 (mapped internally to VLC's 0–100 volume scale). - Effective playback volume is calculated as `event.video.volume * client_config.audio.video_volume_multiplier` and then mapped to VLC's 0–100 scale. Example: `volume: 0.8` with `audio.video_volume_multiplier: 0.5` results in 40% VLC volume. - If `python-vlc` is not installed, the Display Manager will fall back to launching the external `vlc` binary. - External VLC audio rendering behavior: - When `muted: true` (or effective volume resolves to 0), fallback starts VLC with `--no-audio`. - When not muted, fallback applies startup loudness with `--gain=<0.00-1.00>` derived from effective volume. - Runtime volume updates are best-effort in `python-vlc` mode; external VLC fallback is startup-parameter based. - HDMI-CEC remains the recommended mechanism for TV power control only. TV volume via CEC is not implemented because support is device-dependent and much less reliable than controlling VLC directly. - The client-wide multiplier is intended to be sent over the existing MQTT config topic `infoscreen/{client_id}/config` and is persisted locally in `src/config/client_settings.json` for the Display Manager. - Fullscreen behavior: - External VLC fallback uses `--fullscreen`. - `python-vlc` mode enforces fullscreen on startup and retries fullscreen toggling briefly because video outputs may attach asynchronously. - For a truly panel-free fullscreen (no taskbar), run the Display Manager inside a minimal kiosk X session or a dedicated user session without a desktop panel. - Monitoring PID behavior: - External VLC fallback reports the external `vlc` process PID. - `python-vlc` mode is in-process, so monitoring reports the `display_manager.py` runtime PID. ## 🌐 Web Events ```json { "web": { "url": "https://dashboard.example.com" } } ``` Opens webpage in Chromium kiosk mode (fullscreen, no UI). ## πŸ—‚οΈ Project Structure ``` infoscreen-dev/ β”œβ”€β”€ .env # Environment configuration β”œβ”€β”€ README.md # This file β”œβ”€β”€ IMPRESSIVE_INTEGRATION.md # Detailed presentation system docs β”œβ”€β”€ src/ β”‚ β”œβ”€β”€ simclient.py # MQTT client (events, heartbeat, discovery) β”‚ β”œβ”€β”€ display_manager.py # Display controller (manages applications) β”‚ β”œβ”€β”€ requirements.txt # Python dependencies β”‚ β”œβ”€β”€ current_event.json # Current active event (runtime) β”‚ β”œβ”€β”€ config/ # Persistent client data β”‚ β”‚ β”œβ”€β”€ client_uuid.txt β”‚ β”‚ └── last_group_id.txt β”‚ β”œβ”€β”€ presentation/ # Downloaded presentation files β”‚ └── screenshots/ # Dashboard screenshots β”œβ”€β”€ scripts/ β”‚ β”œβ”€β”€ start-dev.sh # Start development client β”‚ β”œβ”€β”€ start-display-manager.sh # Start Display Manager β”‚ β”œβ”€β”€ test-display-manager.sh # Interactive testing β”‚ β”œβ”€β”€ test-impressive.sh # Test Impressive (auto-quit mode) β”‚ β”œβ”€β”€ test-impressive-loop.sh # Test Impressive (loop mode) β”‚ β”œβ”€β”€ test-mqtt.sh # Test MQTT connectivity β”‚ β”œβ”€β”€ test-screenshot.sh # Test screenshot capture β”‚ β”œβ”€β”€ test-utc-timestamps.sh # Test event timing β”‚ └── present-pdf-auto-advance.sh # PDF presentation wrapper └── logs/ # Application logs ``` ## πŸ§ͺ Testing ### Test Display Manager ```bash ./scripts/test-display-manager.sh ``` Interactive menu for testing: - Check Display Manager status - Create test events (presentation, video, webpage) - View active processes - Cycle through different event types ### Test Impressive Presentation **Single playthrough (auto-quit):** ```bash ./scripts/test-impressive.sh ``` **Loop mode (infinite):** ```bash ./scripts/test-impressive-loop.sh ``` ### Test MQTT Connectivity ```bash ./scripts/test-mqtt.sh ``` Verifies MQTT broker connectivity and topic access. ### Test Screenshot Capture ```bash ./scripts/test-screenshot.sh ``` Captures test screenshot for dashboard monitoring. **Manual test:** ```bash export SCREENSHOT_ALWAYS=1 export SCREENSHOT_CAPTURE_INTERVAL=5 python3 src/display_manager.py & sleep 15 ls -lh src/screenshots/ ``` ## πŸ”§ Configuration Details ### Environment Variables All configuration is done via `.env` file in the project root. Copy `.env.template` to `.env` and adjust values for your environment. #### Environment - `ENV` - Environment mode: `development` or `production` - **Important:** CEC TV control is automatically disabled in `development` mode - `DEBUG_MODE` - Enable debug output: `1` (on) or `0` (off) - `LOG_LEVEL` - Logging verbosity: `DEBUG`, `INFO`, `WARNING`, or `ERROR` #### MQTT Configuration - `MQTT_BROKER` - **Required.** MQTT broker IP address or hostname - `MQTT_PORT` - MQTT broker port (default: `1883`) - `MQTT_USERNAME` - Optional. MQTT authentication username (if broker requires it) - `MQTT_PASSWORD` - Optional. MQTT authentication password (if broker requires it) #### Timing Configuration (seconds) - `HEARTBEAT_INTERVAL` - How often client sends status updates to server (default: `60`) - `SCREENSHOT_INTERVAL` - How often simclient transmits screenshots via MQTT (default: `180`) - `SCREENSHOT_CAPTURE_INTERVAL` - How often display_manager captures screenshots (default: `180`) - `DISPLAY_CHECK_INTERVAL` - How often display_manager checks for new events (default: `15`) #### Screenshot Configuration - `SCREENSHOT_ALWAYS` - Force screenshot capture even when no display is active - `0` - In production: capture only when a display process is active; in development: periodic idle captures are allowed so dashboard stays fresh - `1` - Always capture screenshots (useful for testing) #### File/API Server Configuration These settings control how the client downloads presentation files and other content. - `FILE_SERVER_HOST` - Optional. File server hostname/IP. Defaults to `MQTT_BROKER` if empty - `FILE_SERVER_PORT` - File server port (default: `8000`) - `FILE_SERVER_SCHEME` - Protocol: `http` or `https` (default: `http`) - `FILE_SERVER_BASE_URL` - Optional. Full base URL override (e.g., `http://192.168.1.100:8000`) - When set, this takes precedence over HOST/PORT/SCHEME settings #### HDMI-CEC TV Control (Optional) Automatic TV power management based on event scheduling. - `CEC_ENABLED` - Enable automatic TV control: `true` or `false` - **Note:** Automatically disabled when `ENV=development` to avoid TV cycling during testing - `CEC_DEVICE` - Target CEC device address (recommended: `0` for TV) - `CEC_TURN_OFF_DELAY` - Seconds to wait before turning off TV after last event ends (default: `30`) - `CEC_POWER_ON_WAIT` - Seconds to wait after power ON command for TV to boot (default: `5`) - `CEC_POWER_OFF_WAIT` - Seconds to wait after power OFF command (default: `5`, increase for slower TVs) ### File Server URL Resolution The MQTT client ([src/simclient.py](src/simclient.py)) downloads presentation files and videos from the configured file server. **URL Rewriting:** - Event URLs using placeholder host `server` (e.g., `http://server:8000/...`) are automatically rewritten to the configured file server - By default, file server = `MQTT_BROKER` host with port `8000` and `http` scheme - Use `FILE_SERVER_BASE_URL` for complete override, or set individual HOST/PORT/SCHEME variables **Best practices:** - Keep inline comments in `.env` after a space and `#` to avoid parsing issues - Match the scheme (`http`/`https`) to your actual server configuration - For HTTPS or non-standard ports, explicitly set `FILE_SERVER_SCHEME` and `FILE_SERVER_PORT` ### MQTT Topics #### Client β†’ Server - `infoscreen/discovery` - Initial client announcement - `infoscreen/{client_id}/heartbeat` - Regular status updates - `infoscreen/{client_id}/dashboard` - Screenshot images (base64) - `infoscreen/{client_id}/health` - Process health state (`event_id`, process, pid, status) - `infoscreen/{client_id}/logs/error` - Forwarded client error logs - `infoscreen/{client_id}/logs/warn` - Forwarded client warning logs #### Server β†’ Client - `infoscreen/{client_id}/discovery_ack` - Server response with client ID - `infoscreen/{client_id}/group_id` - Group assignment - `infoscreen/events/{group_id}` - Event commands for group ### Client Identification **Hardware Token:** SHA256 hash of: - CPU serial number - MAC addresses (all network interfaces) **Persistent UUID:** Stored in `src/config/client_uuid.txt` **Group Membership:** Stored in `src/config/last_group_id.txt` ## πŸ” Troubleshooting ### Display Manager doesn't start presentations **Check Impressive installation:** ```bash which impressive # If not found: sudo apt-get install impressive ``` **Check logs:** ```bash tail -f logs/display_manager.log ``` **Check disk space:** ```bash df -h ``` **Note:** PPTX conversion happens server-side via Gotenberg. The client only receives and displays pre-rendered PDF files. ### Slides don't auto-advance **Verify event JSON:** - `auto_advance: true` is set - `slide_interval` is specified (default: 10) **Test Impressive directly:** ```bash ./scripts/test-impressive.sh ``` ### Presentation doesn't loop **Verify event JSON:** - `loop: true` is set **Test loop mode:** ```bash ./scripts/test-impressive-loop.sh ``` ### File downloads fail Symptoms: - `Failed to resolve 'server'` or `NameResolutionError` when downloading files - `Invalid URL 'http # http or https://...'` in `logs/simclient.log` What to check: - Look for lines like `Lade Datei herunter von:` in `logs/simclient.log` to see the effective URL used - Ensure the URL host is the MQTT broker IP (or your configured file server), not `server` - Verify `.env` values don’t include inline comments as part of the value (e.g., keep `FILE_SERVER_SCHEME=http` on its own line) Fixes: - If your API is on the same host as the broker: leave `FILE_SERVER_HOST` empty (defaults to `MQTT_BROKER`), keep `FILE_SERVER_PORT=8000`, and set `FILE_SERVER_SCHEME=http` or `https` - To override fully, set `FILE_SERVER_BASE_URL` (e.g., `http://192.168.1.100:8000`); this takes precedence over host/port/scheme - After changing `.env`, restart the simclient process Expected healthy log sequence: - `Lade Datei herunter von: http://:8000/...` - Followed by `"GET /... HTTP/1.1" 200` and `Datei erfolgreich heruntergeladen:` ### VLC hardware decode / renderer issues If you see messages like: ``` [h264_v4l2m2m @ ...] Could not find a valid device [h264_v4l2m2m @ ...] can't configure decoder [... ] avcodec decoder error: cannot start codec (h264_v4l2m2m) ``` that indicates libVLC / ffmpeg attempted to use the platform V4L2 M2M hardware decoder but the kernel/device isn't available. Options to resolve: - Enable the V4L2 M2M codec driver on the system (platform-specific; on Raspberry Pi ensure correct kernel/firmware and codec modules are loaded). Check `v4l2-ctl --list-devices` and `ls /dev/video*` after installing `v4l-utils`. - Disable hardware decoding so libVLC/ffmpeg uses software decoding (reliable but higher CPU). You can test this by launching the `vlc` binary with: ```bash vlc --avcodec-hw=none 'http://' ``` Or modify `src/display_manager.py` to create the libVLC instance with software-decoding forced: ```python instance = vlc.Instance('--avcodec-hw=none', '--no-video-title-show', '--no-video-deco') ``` This is the fastest workaround if hardware decode is not required or not available on the device. ### MQTT connection issues **Test broker connectivity:** ```bash ./scripts/test-mqtt.sh ``` ### MQTT reconnect and heartbeat behavior - On reconnect, the client re-subscribes all topics in `on_connect` and re-sends discovery to re-register. - Heartbeats are sent only when connected. During brief reconnect windows, Paho may return rc=4 (`NO_CONN`). - A single rc=4 warning after broker restarts or short network stalls is expected; the next heartbeat usually succeeds. - Investigate only if rc=4 repeats across multiple intervals without subsequent successful heartbeat logs. ### Monitoring and UTC timestamps Client-side monitoring is implemented with a health-state bridge between `display_manager.py` and `simclient.py`. - Health bridge file: `src/current_process_health.json` - Local monitoring log: `logs/monitoring.log` - Process states: `running`, `crashed`, `stopped` - Restart tracking: bounded restart attempts per active event UTC timestamp policy: - `display_manager.log`, `simclient.log`, and `monitoring.log` are written in UTC (`...Z`) - MQTT payload timestamps (heartbeat/dashboard/health/log messages) are UTC ISO timestamps - Screenshot metadata timestamps are UTC ISO timestamps This prevents daylight-saving and timezone drift issues across clients. ### VLC/PulseAudio warnings in remote sessions Warnings such as `pulse audio output error: overflow, flushing` can appear when testing through remote desktop/audio forwarding (for example, NoMachine) or virtual/dummy display setups. - If playback and audio are stable on a real HDMI display, this is usually non-fatal. - If warnings appear only in remote sessions, treat them as environment-related rather than a core video playback bug. ### Screenshots not uploading **Check which session type you're running:** ```bash echo $WAYLAND_DISPLAY # Set if Wayland echo $DISPLAY # Set if X11 echo $XAUTHORITY # Should point to ~/.Xauthority for X11 captures ``` If `DISPLAY` is empty for non-interactive starts (systemd/nohup/ssh), the display manager now falls back to `:0` and tries `~/.Xauthority` automatically. **Install appropriate screenshot tool:** ```bash # For X11: sudo apt-get install scrot imagemagick # For Wayland: sudo apt-get install grim gnome-screenshot ``` **Test screenshot capture:** ```bash export SCREENSHOT_ALWAYS=1 # Force capture even without active event ./scripts/test-screenshot.sh ls -lh src/screenshots/ ``` **Check logs for session detection:** ```bash tail -f logs/display_manager.log | grep -i screenshot # Should show: "Screenshot session=wayland" or "Screenshot session=x11" ``` **If you see stale dashboard images after restarts:** ```bash cat src/screenshots/meta.json stat src/screenshots/latest.jpg ``` - If `send_immediately` is stuck `true` for old metadata, restart both processes so simclient consumes and clears it. - If `latest.jpg` timestamp does not move while new `screenshot_*.jpg` files appear, update to latest code (fix for periodic `latest.jpg` update path) and restart display_manager. **Verify simclient is reading screenshots:** ```bash tail -f logs/simclient.log | grep -i screenshot # Should show: "Dashboard heartbeat sent with screenshot: latest.jpg" ``` ## πŸ“š Documentation - **IMPRESSIVE_INTEGRATION.md** - Detailed presentation system documentation - **HDMI_CEC_SETUP.md** - HDMI-CEC setup and troubleshooting - **src/DISPLAY_MANAGER.md** - Display Manager architecture - **src/IMPLEMENTATION_SUMMARY.md** - Implementation overview - **src/README.md** - MQTT client documentation ## πŸ” Security - Hardware-based client identification (non-spoofable) - Configurable MQTT authentication - Local-only file storage - No sensitive data in logs ## 🚒 Production Deployment ### Systemd Service Create `/etc/systemd/system/infoscreen-display.service`: ```ini [Unit] Description=Infoscreen Display Manager After=network.target [Service] Type=simple User=olafn WorkingDirectory=/home/olafn/infoscreen-dev/src Environment="DISPLAY=:0" Environment="XAUTHORITY=/home/olafn/.Xauthority" ExecStart=/home/olafn/infoscreen-dev/venv/bin/python3 /home/olafn/infoscreen-dev/src/display_manager.py Restart=always RestartSec=10 [Install] WantedBy=multi-user.target ``` Enable and start: ```bash sudo systemctl daemon-reload sudo systemctl enable infoscreen-display sudo systemctl start infoscreen-display sudo systemctl status infoscreen-display ``` ### Auto-start on Boot Both services (simclient.py and display_manager.py) should start automatically: 1. **simclient.py** - MQTT communication, event management 2. **display_manager.py** - Display application controller Create similar systemd service for simclient.py. ### Docker Deployment (Alternative) ```bash docker-compose -f src/docker-compose.production.yml up -d ``` See `src/CONTAINER_TRANSITION.md` for details. ## πŸ“ Development ### Development Mode Set in `.env`: ```bash ENV=development DEBUG_MODE=1 LOG_LEVEL=DEBUG HEARTBEAT_INTERVAL=10 ``` ### Start Development Client ```bash ./scripts/start-dev.sh ``` ### View Logs ```bash # Display Manager tail -f logs/display_manager.log # MQTT Client tail -f logs/simclient.log # Both tail -f logs/*.log ``` ## πŸ“Ί HDMI-CEC TV Control The system includes automatic TV power control via HDMI-CEC. The TV turns on when events start and turns off (with delay) when no events are active. ### Development mode behavior - When `ENV=development`, HDMI-CEC is automatically disabled by the Display Manager to avoid constantly switching the TV during development. - The test script `scripts/test-hdmi-cec.sh` also respects this: menu option 5 (Display Manager CEC integration) will detect development mode and skip the integration test. Manual options (1–4) still work for direct cec-client testing. To test CEC end-to-end, temporarily set `ENV=production` in `.env` and restart the Display Manager, or use the manual commands in the test script. ### Quick Setup ```bash # Install CEC utilities sudo apt-get install cec-utils # Test CEC connection echo "scan" | cec-client -s -d 1 # Configure in .env CEC_ENABLED=true CEC_DEVICE=0 # Use 0 for best performance CEC_TURN_OFF_DELAY=30 CEC_POWER_ON_WAIT=5 # Adjust if TV is slow to boot CEC_POWER_OFF_WAIT=2 ``` ### Features - **Auto Power On**: TV turns on when event starts - **Auto Power Off**: TV turns off after configurable delay when events end - **Smart Switching**: TV stays on when switching between events - **Configurable Delay**: Prevent rapid on/off cycles ### Testing ```bash echo "on 0" | cec-client -s -d 1 # Turn on echo "standby 0" | cec-client -s -d 1 # Turn off echo "pow 0" | cec-client -s -d 1 # Check status ``` ## 🀝 Contributing 1. Test changes with `./scripts/test-display-manager.sh` 2. Verify MQTT communication with `./scripts/test-mqtt.sh` 3. Update documentation 4. Submit pull request ## πŸ“„ License [Add your license here] ## πŸ†˜ Support For issues or questions: 1. Check logs in `logs/` directory 2. Review troubleshooting section 3. Test individual components with test scripts 4. Check MQTT broker connectivity --- **Last Updated:** March 2026 **Status:** βœ… Production Ready **Tested On:** Raspberry Pi 5, Raspberry Pi OS (Bookworm) ## Recent Changes ### November 2025 - Screenshot pipeline implemented with a two-process model (`display_manager.py` capture, `simclient.py` transmission). - Wayland/X11 screenshot tool fallback chains added. - Dashboard payload format extended with screenshot and system metadata. - Scheduler event type support extended (`presentation`, `webuntis`, `webpage`, `website`). - Website autoscroll support added (CDP injection + extension fallback). ### March 2026 - Event-trigger screenshots (`event_start`, `event_stop`) hardened against periodic overwrite races. - `latest.jpg` and `meta.json` synchronization improved for reliable dashboard updates. - Stale/invalid pending trigger metadata now self-heals instead of blocking periodic updates. - Display environment fallbacks (`DISPLAY=:0`, `XAUTHORITY`) improved for non-interactive starts. - Development mode allows periodic idle captures to keep dashboard previews fresh when no event is active.