- fix race where periodic captures could overwrite pending event_start and event_stop metadata before simclient published - keep latest.jpg and meta.json synchronized so triggered screenshots are not lost - add stale pending trigger self-healing to recover from old or invalid metadata states - improve non-interactive capture reliability with DISPLAY and XAUTHORITY fallbacks - allow periodic idle captures in development mode so dashboard previews stay fresh without active events - add deeper simclient screenshot diagnostics for trigger and metadata handling - add regression test script for metadata preservation and trigger delivery - add root-cause and fix documentation for the screenshot MQTT issue - align and deduplicate README screenshot and troubleshooting sections; update release notes to March 2026 - fix scripts/start-dev.sh .env loading to ignore comments safely and remove export invalid identifier warnings
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:
scrotor ImageMagick (X11) ORgrimorgnome-screenshot(Wayland) - CEC Utils (for HDMI-CEC TV control - optional)
🚀 Quick Start
1. Installation
# Clone repository
cd ~/
git clone <repository-url> 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):
# 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
# 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:
./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:
- Server-side rendering: PPTX files are converted to PDF by the server using Gotenberg
- Client receives PDFs: Events contain pre-rendered PDF files ready for display
- Direct display: PDF files are displayed directly with Impressive (no client-side conversion needed)
- Auto-advance uses Impressive's built-in
--autoparameter - Loop mode uses Impressive's
--wrapparameter (infinite loop) - Auto-quit uses Impressive's
--autoquitparameter (exit after last slide)
Event JSON Format
Looping Presentation (Typical for Events)
{
"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
{
"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 presentationauto_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
{
"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 hostserverare 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_multiplierand then mapped to VLC's 0–100 scale. Example:volume: 0.8withaudio.video_volume_multiplier: 0.5results in 40% VLC volume. - If
python-vlcis not installed, the Display Manager will fall back to launching the externalvlcbinary. - 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-vlcmode; external VLC fallback is startup-parameter based.
- When
- 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}/configand is persisted locally insrc/config/client_settings.jsonfor the Display Manager. - Fullscreen behavior:
- External VLC fallback uses
--fullscreen. python-vlcmode 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.
- External VLC fallback uses
- Monitoring PID behavior:
- External VLC fallback reports the external
vlcprocess PID. python-vlcmode is in-process, so monitoring reports thedisplay_manager.pyruntime PID.
- External VLC fallback reports the external
🌐 Web Events
{
"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
./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):
./scripts/test-impressive.sh
Loop mode (infinite):
./scripts/test-impressive-loop.sh
Test MQTT Connectivity
./scripts/test-mqtt.sh
Verifies MQTT broker connectivity and topic access.
Test Screenshot Capture
./scripts/test-screenshot.sh
Captures test screenshot for dashboard monitoring.
Manual test:
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:developmentorproduction- Important: CEC TV control is automatically disabled in
developmentmode
- Important: CEC TV control is automatically disabled in
DEBUG_MODE- Enable debug output:1(on) or0(off)LOG_LEVEL- Logging verbosity:DEBUG,INFO,WARNING, orERROR
MQTT Configuration
MQTT_BROKER- Required. MQTT broker IP address or hostnameMQTT_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 active0- In production: capture only when a display process is active; in development: periodic idle captures are allowed so dashboard stays fresh1- 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 toMQTT_BROKERif emptyFILE_SERVER_PORT- File server port (default:8000)FILE_SERVER_SCHEME- Protocol:httporhttps(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:trueorfalse- Note: Automatically disabled when
ENV=developmentto avoid TV cycling during testing
- Note: Automatically disabled when
CEC_DEVICE- Target CEC device address (recommended:0for 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) 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_BROKERhost with port8000andhttpscheme - Use
FILE_SERVER_BASE_URLfor complete override, or set individual HOST/PORT/SCHEME variables
Best practices:
- Keep inline comments in
.envafter 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_SCHEMEandFILE_SERVER_PORT
MQTT Topics
Client → Server
infoscreen/discovery- Initial client announcementinfoscreen/{client_id}/heartbeat- Regular status updatesinfoscreen/{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 logsinfoscreen/{client_id}/logs/warn- Forwarded client warning logs
Server → Client
infoscreen/{client_id}/discovery_ack- Server response with client IDinfoscreen/{client_id}/group_id- Group assignmentinfoscreen/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:
which impressive
# If not found: sudo apt-get install impressive
Check logs:
tail -f logs/display_manager.log
Check disk space:
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: trueis setslide_intervalis specified (default: 10)
Test Impressive directly:
./scripts/test-impressive.sh
Presentation doesn't loop
Verify event JSON:
loop: trueis set
Test loop mode:
./scripts/test-impressive-loop.sh
File downloads fail
Symptoms:
Failed to resolve 'server'orNameResolutionErrorwhen downloading filesInvalid URL 'http # http or https://...'inlogs/simclient.log
What to check:
- Look for lines like
Lade Datei herunter von:inlogs/simclient.logto see the effective URL used - Ensure the URL host is the MQTT broker IP (or your configured file server), not
server - Verify
.envvalues don’t include inline comments as part of the value (e.g., keepFILE_SERVER_SCHEME=httpon its own line)
Fixes:
- If your API is on the same host as the broker: leave
FILE_SERVER_HOSTempty (defaults toMQTT_BROKER), keepFILE_SERVER_PORT=8000, and setFILE_SERVER_SCHEME=httporhttps - 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://<broker-ip>:8000/...- Followed by
"GET /... HTTP/1.1" 200andDatei 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-devicesandls /dev/video*after installingv4l-utils. - Disable hardware decoding so libVLC/ffmpeg uses software decoding (reliable but higher CPU). You can test this by launching the
vlcbinary with:
vlc --avcodec-hw=none 'http://<your-video-url>'
Or modify src/display_manager.py to create the libVLC instance with software-decoding forced:
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:
./scripts/test-mqtt.sh
MQTT reconnect and heartbeat behavior
- On reconnect, the client re-subscribes all topics in
on_connectand 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, andmonitoring.logare 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:
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:
# For X11:
sudo apt-get install scrot imagemagick
# For Wayland:
sudo apt-get install grim gnome-screenshot
Test screenshot capture:
export SCREENSHOT_ALWAYS=1 # Force capture even without active event
./scripts/test-screenshot.sh
ls -lh src/screenshots/
Check logs for session detection:
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:
cat src/screenshots/meta.json
stat src/screenshots/latest.jpg
- If
send_immediatelyis stucktruefor old metadata, restart both processes so simclient consumes and clears it. - If
latest.jpgtimestamp does not move while newscreenshot_*.jpgfiles appear, update to latest code (fix for periodiclatest.jpgupdate path) and restart display_manager.
Verify simclient is reading screenshots:
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:
[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:
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:
- simclient.py - MQTT communication, event management
- display_manager.py - Display application controller
Create similar systemd service for simclient.py.
Docker Deployment (Alternative)
docker-compose -f src/docker-compose.production.yml up -d
See src/CONTAINER_TRANSITION.md for details.
📝 Development
Development Mode
Set in .env:
ENV=development
DEBUG_MODE=1
LOG_LEVEL=DEBUG
HEARTBEAT_INTERVAL=10
Start Development Client
./scripts/start-dev.sh
View Logs
# 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.shalso 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
# 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
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
- Test changes with
./scripts/test-display-manager.sh - Verify MQTT communication with
./scripts/test-mqtt.sh - Update documentation
- Submit pull request
📄 License
[Add your license here]
🆘 Support
For issues or questions:
- Check logs in
logs/directory - Review troubleshooting section
- Test individual components with test scripts
- 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.pycapture,simclient.pytransmission). - 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.jpgandmeta.jsonsynchronization 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.