PPTX Conversion: - Remove LibreOffice from client dependencies (server uses Gotenberg) - Update docs to reflect clients only display pre-rendered PDFs - Clarify server-side conversion workflow in README and copilot-instructions Screenshot System: - Add background screenshot capture in display_manager.py - Implement Wayland/X11 session detection with tool fallback - Add client-side image processing (downscale + JPEG compression) - Create timestamped files + latest.jpg symlink for easy access - Implement file rotation (max 20 screenshots by default) - Enhance simclient.py to transmit via MQTT dashboard topic - Add structured JSON payload with screenshot, timestamp, system info - New env vars: SCREENSHOT_CAPTURE_INTERVAL, SCREENSHOT_MAX_WIDTH, SCREENSHOT_JPEG_QUALITY, SCREENSHOT_MAX_FILES, SCREENSHOT_ALWAYS Architecture: Two-process design with shared screenshots/ volume
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
- 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:
# Environment
ENV=production
LOG_LEVEL=INFO
# MQTT Configuration
# Timing (seconds)
HEARTBEAT_INTERVAL=30
SCREENSHOT_INTERVAL=60 # How often simclient transmits screenshots
SCREENSHOT_CAPTURE_INTERVAL=60 # How often display_manager captures screenshots
DISPLAY_CHECK_INTERVAL=5
# Screenshot Configuration
SCREENSHOT_MAX_WIDTH=800 # Downscale to this width (preserves aspect)
SCREENSHOT_JPEG_QUALITY=70 # JPEG quality 1-95 (lower = smaller files)
SCREENSHOT_MAX_FILES=20 # Keep this many screenshots (rotation)
SCREENSHOT_ALWAYS=0 # Set to 1 to force capture even when no event active
# Timing (seconds)
HEARTBEAT_INTERVAL=30
SCREENSHOT_INTERVAL=60
DISPLAY_CHECK_INTERVAL=5
# File/API Server (used to download presentation files)
# Defaults to the same host as MQTT_BROKER, port 8000, scheme http.
# If incoming event URLs use host 'server' (or are host-less), simclient rewrites them to this server.
FILE_SERVER_HOST= # optional; if empty, defaults to MQTT_BROKER
FILE_SERVER_PORT=8000 # default API port
# http or https
FILE_SERVER_SCHEME=http
# 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 (auto-disabled in development)
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 (increase for slower TVs)
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).
- If
python-vlcis not installed, the Display Manager will fall back to launching the externalvlcbinary. - The manager attempts to make the player window fullscreen and remove window decorations. 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 (see the kiosk notes below).
🌐 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):
### Test Screenshot Capture
```bash
./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/
Verifies MQTT broker connectivity and topics.
### Test Screenshot Capture
```bash
./scripts/test-screenshot.sh
Captures test screenshot for dashboard monitoring.
🔧 Configuration Details
Environment Variables
Environment
ENV-developmentorproductionDEBUG_MODE- Enable debug output (1=on, 0=off)LOG_LEVEL-DEBUG,INFO,WARNING,ERROR
MQTT
MQTT_BROKER- Primary MQTT broker IP/hostnameMQTT_PORT- MQTT port (default: 1883)MQTT_BROKER_FALLBACKS- Comma-separated fallback brokersMQTT_USERNAME- Optional authenticationMQTT_PASSWORD- Optional authentication
Timing
HEARTBEAT_INTERVAL- Status update frequency (seconds)SCREENSHOT_INTERVAL- Dashboard screenshot frequency (seconds)DISPLAY_CHECK_INTERVAL- Event check frequency (seconds)
File/API Server
FILE_SERVER_HOST- Host/IP of the file server; defaults toMQTT_BROKERwhen emptyFILE_SERVER_PORT- Port of the file server (default: 8000)FILE_SERVER_SCHEME-httporhttps(default: http)FILE_SERVER_BASE_URL- Optional full override, e.g.,https://api.example.com:443
File Server URL Resolution
- The MQTT client (
src/simclient.py) downloads presentation files listed in events. - If an event contains URLs with host
server(e.g.,http://server:8000/...) or a missing host, the client rewrites them to the configured file server. - By default, the file server host is the same as
MQTT_BROKER, with port8000and schemehttp. - You can override this behavior using the
.envvariables above;FILE_SERVER_BASE_URLtakes precedence over the individual host/port/scheme. - Tip: When editing
.env, keep comments after a space and#so values stay clean.
MQTT Topics
Client → Server
infoscreen/discovery- Initial client announcementinfoscreen/{client_id}/heartbeat- Regular status updatesinfoscreen/{client_id}/dashboard- Screenshot images (base64)
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
Screenshots not uploading
Check which session type you're running:
echo $WAYLAND_DISPLAY # Set if Wayland
echo $DISPLAY # Set if X11
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"
Verify simclient is reading screenshots:
tail -f logs/simclient.log | grep -i screenshot
# Should show: "Dashboard heartbeat sent with screenshot: latest.jpg"
```ll topic subscriptions are restored in `on_connect` and a discovery message is re-sent on reconnect to re-register the client.
- Heartbeats are sent only when connected; if publish occurs during a brief reconnect window, Paho may return rc=4 (NO_CONN). The client performs a short retry and logs the outcome.
- Occasional `Heartbeat publish failed with code: 4` after broker restart or transient network hiccups is expected and not dangerous. It indicates "not connected at this instant"; the next heartbeat typically succeeds.
- When to investigate: repeated rc=4 with no succeeding "Heartbeat sent" entries over multiple intervals.
### Screenshots not uploading
**Test screenshot capture:**
```bash
./scripts/test-screenshot.sh
ls -l screenshots/
Check DISPLAY variable:
echo $DISPLAY # Should be :0
📚 Documentation
- IMPRESSIVE_INTEGRATION.md - Detailed presentation system documentation
- 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
## 📸 Screenshot System
The system includes automatic screenshot capture for dashboard monitoring with support for both X11 and Wayland display servers.
### Architecture
**Two-process design:**
1. **display_manager.py** - Captures screenshots on host OS (has access to display)
2. **simclient.py** - Transmits screenshots via MQTT (runs in container)
3. **Shared directory** - `src/screenshots/` volume-mounted between processes
### Screenshot Capture (display_manager.py)
## Recent changes (Nov 2025)
The following notable changes were added after the previous release and are included in this branch:
### Screenshot System Implementation
- **Screenshot capture** added to `display_manager.py` with background thread
- **Session detection**: Automatic Wayland vs X11 detection with appropriate tool selection
- **Wayland support**: `grim`, `gnome-screenshot`, `spectacle` (in order)
- **X11 support**: `scrot`, `import` (ImageMagick), `xwd`+`convert` (in order)
- **Image processing**: Client-side downscaling and JPEG compression for bandwidth optimization
- **File management**: Timestamped screenshots plus `latest.jpg` symlink, automatic rotation
- **Transmission**: Enhanced `simclient.py` to prefer `latest.jpg`, added detailed logging
- **Dashboard topic**: Structured JSON payload with screenshot, system info, and client status
- **Configuration**: New environment variables for capture interval, quality, max width, file rotation
- **Testing mode**: `SCREENSHOT_ALWAYS=1` forces capture even without active display
### Previous Changes (Oct 2025)
- **Wayland**: `grim` → `gnome-screenshot` → `spectacle`
- **X11**: `scrot` → `import` (ImageMagick) → `xwd`+`convert`
**Processing pipeline:**
1. Capture full-resolution screenshot to PNG
2. Downscale to configured max width (default 800px, preserves aspect ratio)
3. Convert to JPEG with configured quality (default 70)
4. Save timestamped file: `screenshot_YYYYMMDD_HHMMSS.jpg`
5. Create/update `latest.jpg` symlink for easy access
6. Rotate old screenshots (keeps max 20 by default)
**Capture timing:**
- Only captures when a display process is active (presentation/video/web)
- Can be forced with `SCREENSHOT_ALWAYS=1` for testing
- Default interval: 60 seconds
### Screenshot Transmission (simclient.py)
**Source selection:**
- Prefers `latest.jpg` symlink (fastest, most recent)
- Falls back to newest timestamped file if symlink missing
**MQTT topic:**
infoscreen/{client_id}/dashboard
**Payload structure:**
```json
{
"timestamp": "2025-11-30T14:23:45.123456",
"client_id": "abc123-def456-789",
"status": "alive",
"screenshot": {
"filename": "latest.jpg",
"data": "<base64-encoded-image>",
"timestamp": "2025-11-30T14:23:40.000000",
"size": 45678
},
"system_info": {
"hostname": "infoscreen-pi-01",
"ip": "192.168.1.50",
"uptime": 1732977825.123456
}
}
Configuration
# Capture settings (display_manager.py)
SCREENSHOT_CAPTURE_INTERVAL=60 # Seconds between captures
SCREENSHOT_MAX_WIDTH=800 # Downscale width (0 = no downscaling)
SCREENSHOT_JPEG_QUALITY=70 # JPEG quality 1-95
SCREENSHOT_MAX_FILES=20 # Number to keep before rotation
SCREENSHOT_ALWAYS=0 # Force capture even without active event
# Transmission settings (simclient.py)
SCREENSHOT_INTERVAL=60 # Seconds between MQTT publishes
Scalability Recommendations
Small deployments (<10 clients):
- Default settings work well
SCREENSHOT_CAPTURE_INTERVAL=30,SCREENSHOT_MAX_WIDTH=800,SCREENSHOT_JPEG_QUALITY=70
Medium deployments (10-50 clients):
- Reduce capture frequency:
SCREENSHOT_CAPTURE_INTERVAL=60 - Lower quality:
SCREENSHOT_JPEG_QUALITY=60-65 - Ensure broker has adequate bandwidth
Large deployments (50+ clients):
- Further reduce frequency:
SCREENSHOT_CAPTURE_INTERVAL=120 - Aggressive compression:
SCREENSHOT_JPEG_QUALITY=50-60,SCREENSHOT_MAX_WIDTH=640 - Consider implementing hash-based deduplication (skip if unchanged)
- Monitor MQTT broker load and consider retained message limits
Very large deployments (200+ clients):
- Consider HTTP storage + MQTT metadata pattern instead of base64-over-MQTT
- Implement screenshot upload to file server, publish only URL via MQTT
Troubleshooting
No screenshots being captured:
# Check session type
echo "Wayland: $WAYLAND_DISPLAY" # Set if Wayland
echo "X11: $DISPLAY" # Set if X11
# Check logs for tool detection
tail -f logs/display_manager.log | grep screenshot
# Install appropriate tools
sudo apt install scrot imagemagick # X11
sudo apt install grim # Wayland
Screenshots too large:
# Reduce quality and size
SCREENSHOT_MAX_WIDTH=640
SCREENSHOT_JPEG_QUALITY=50
Not transmitting over MQTT:
# Check simclient logs
tail -f logs/simclient.log | grep -i dashboard
# Should see:
# "Dashboard heartbeat sent with screenshot: latest.jpg (45678 bytes)"
# If NO_CONN errors, check MQTT broker connectivity
Last Updated: November 2025
Status: ✅ Production Ready
Tested On: Raspberry Pi 5, Raspberry Pi OS (Bookworm)
Recent changes (Nov 2025)
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
### Documentation
See [HDMI_CEC_SETUP.md](HDMI_CEC_SETUP.md) for complete documentation including:
- Detailed setup instructions
- Troubleshooting guide
- TV compatibility information
- Advanced configuration options
## 🤝 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:** October 2025
**Status:** ✅ Production Ready
**Tested On:** Raspberry Pi 5, Raspberry Pi OS (Bookworm)
## Recent changes (Oct 2025)
The following notable changes were added after the previous release and are included in this branch:
- Event handling: support for scheduler-provided `event_type` values (new types: `presentation`, `webuntis`, `webpage`, `website`). The display manager now prefers `event_type` when selecting which renderer to start.
- Web display: Chromium is launched in kiosk mode for web events. `website` events (scheduler) and legacy `web` keys are both supported and normalized.
- Auto-scroll feature: automatic scrolling for long websites implemented. Two mechanisms are available:
- CDP injection: The display manager attempts to inject a small auto-scroll script via Chrome DevTools Protocol (DevTools websocket) when possible (uses `websocket-client` and `requests`). Default injection duration: 60s.
- Extension fallback: When DevTools websocket handshakes are blocked (403), a tiny local Chrome extension (`src/chrome_autoscroll`) is loaded via `--load-extension` to run a content script that performs the auto-scroll reliably.
- Autoscroll enabled only for scheduler events with `event_type: "website"` (not for general `web` or `webpage`). The extension and CDP injection are only used when autoscroll is requested for that event type.
- New test utilities:
- `scripts/test_cdp.py` — quick DevTools JSON listing + Runtime.evaluate tester
- `scripts/test_cdp_origins.py` — tries several Origin headers to diagnose 403 handshakes
- Dependencies: `src/requirements.txt` updated to include `websocket-client` (used by the CDP injector).
- Small refactors and improved logging in `src/display_manager.py` to make event dispatch and browser injection more robust.
If you rely on autoscroll in production, review the security considerations around `--remote-debugging-port` (DevTools) and prefer the extension fallback if your Chromium build enforces strict websocket Origin policies.