20 KiB
20 KiB
Copilot Instructions - Infoscreen Client
Project Overview
This is an Infoscreen Client system for Raspberry Pi that creates digital signage displays. The client communicates with a server via MQTT to display presentations, videos, and web content in kiosk mode. It's designed for educational/research environments where multiple displays need to be centrally managed.
Architecture & Technology Stack
Core Technologies
- Python 3.x - Main application language
- MQTT (paho-mqtt) - Real-time messaging with server
- Impressive - PDF presenter with native auto-advance and loop support
- LibreOffice - PPTX to PDF conversion (headless mode)
- Environment Variables - Configuration management via
.envfiles - JSON - Data exchange format for events and configuration
- Base64 - Screenshot transmission encoding
- Threading - Background services (screenshot monitoring)
System Components
- Main Client (
simclient.py) - Core MQTT client and event processor - Display Manager (
display_manager.py) - Controls display applications (presentations, videos, web) - Discovery System - Automatic client registration with server
- Heartbeat Monitoring - Regular status updates and keepalive
- Event Processing - Handles presentation/content switching commands
- Screenshot Service - Dashboard monitoring via image capture
- File Management - Downloads and manages presentation files
- Group Management - Supports organizing clients into groups
Key Features & Functionality
MQTT Communication Patterns
- Discovery:
infoscreen/discovery→infoscreen/{client_id}/discovery_ack - Heartbeat: Regular
infoscreen/{client_id}/heartbeatmessages - Dashboard: Screenshot transmission via
infoscreen/{client_id}/dashboard - Group Assignment: Server sends group via
infoscreen/{client_id}/group_id - Events: Content commands via
infoscreen/events/{group_id}
Event Types Supported
{
"presentation": {
"files": [{"url": "https://server/file.pptx", "filename": "file.pptx"}],
"auto_advance": true,
"slide_interval": 10,
"loop": true
},
"web": {
"url": "https://example.com"
},
"video": {
"url": "https://server/video.mp4",
"loop": false,
"autoplay": true,
"volume": 0.8
}
}
Presentation System (Impressive-Based)
- PDF files are displayed natively with Impressive PDF presenter (no conversion needed)
- PPTX files are automatically converted to PDF using LibreOffice headless
- Auto-advance: Native Impressive
--autoparameter (no xdotool needed) - Loop mode: Impressive
--wrapparameter for infinite looping - Auto-quit: Impressive
--autoquitparameter to exit after last slide - Virtual Environment: Uses venv with pygame + pillow for reliable operation
- Reliable: Works consistently on Raspberry Pi without window focus issues
Client Identification
- Hardware Token: SHA256 hash of serial number + MAC addresses
- Persistent UUID: Stored in
config/client_uuid.txt - Group Membership: Persistent group assignment in
config/last_group_id.txt
Directory Structure
~/infoscreen-dev/
├── .env # Environment configuration
├── README.md # Complete project documentation
├── IMPRESSIVE_INTEGRATION.md # Presentation system details
├── QUICK_REFERENCE.md # Quick command reference
├── .github/ # GitHub configuration
│ └── copilot-instructions.md
├── src/ # Source code
│ ├── simclient.py # MQTT client (event management)
│ ├── display_manager.py # Display controller (Impressive integration)
│ ├── current_event.json # Current active event (runtime)
│ ├── config/ # Persistent client data
│ │ ├── client_uuid.txt
│ │ └── last_group_id.txt
│ ├── presentation/ # Downloaded presentation files & PDFs
│ └── screenshots/ # Screenshot captures for monitoring
├── scripts/ # Production & testing utilities
│ ├── start-dev.sh # Start development client
│ ├── start-display-manager.sh # Start Display Manager
│ ├── test-display-manager.sh # Interactive testing menu
│ ├── test-impressive.sh # Test Impressive (auto-quit)
│ ├── test-impressive-loop.sh # Test Impressive (loop mode)
│ ├── test-mqtt.sh # MQTT connectivity test
│ ├── test-screenshot.sh # Screenshot capture test
│ └── present-pdf-auto-advance.sh # PDF presentation wrapper
├── logs/ # Application logs
│ ├── simclient.log
│ └── display_manager.log
└── venv/ # Python virtual environment
Configuration & Environment Variables
Development vs Production
- Development:
ENV=development, verbose logging, frequent heartbeats - Production:
ENV=production, minimal logging, longer intervals
Key Environment Variables
# Environment
ENV=development|production
DEBUG_MODE=1|0
LOG_LEVEL=DEBUG|INFO|WARNING|ERROR
# MQTT Configuration
MQTT_BROKER=192.168.1.100 # Primary MQTT broker
MQTT_PORT=1883 # MQTT port
MQTT_BROKER_FALLBACKS=host1,host2 # Fallback brokers
# Timing (seconds)
HEARTBEAT_INTERVAL=10 # Status update frequency
SCREENSHOT_INTERVAL=30 # Dashboard screenshot frequency
# 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
FILE_SERVER_SCHEME=http # http or https
# FILE_SERVER_BASE_URL= # optional full override, e.g., http://192.168.1.100:8000
File Server URL Resolution
- The MQTT client (
simclient.py) downloads presentation files listed in events. - To avoid DNS issues when event URLs use
http://server:8000/..., the client normalizes such URLs to the configured file server. - By default, the file server host is the same as
MQTT_BROKER, with port8000and schemehttp. - You can override behavior using
.envvariables above;FILE_SERVER_BASE_URLtakes precedence over individual host/port/scheme. - Inline comments in
.envare supported; keep comments after a space and#so values stay clean.
Development Patterns & Best Practices
Error Handling
- Robust MQTT connection with fallbacks and retries
- Graceful degradation when services unavailable
- Comprehensive logging with rotating file handlers
- Exception handling for all external operations
State Management
- Event state persisted in
current_event.json - Client configuration persisted across restarts
- Group membership maintained with server synchronization
- Clean state transitions (delete old events on group changes)
Threading Architecture
- Main thread: MQTT communication and heartbeat
- Background thread: Screenshot monitoring service
- Thread-safe operations for shared resources
File Operations
- Automatic directory creation for all output paths
- Safe file operations with proper exception handling
- Atomic writes for configuration files
- Automatic cleanup of temporary/outdated files
Development Workflow
Local Development Setup
- Clone repository to
~/infoscreen-dev - Create virtual environment:
python3 -m venv venv - Install dependencies:
pip install -r src/requirements.txt(includes pygame + pillow for PDF slideshows) - Configure
.envfile with MQTT broker settings - Use
./scripts/start-dev.shfor MQTT client or./scripts/start-display-manager.shfor display manager - Important: Virtual environment must include pygame and pillow for PDF auto-advance to work
Testing Components
./scripts/test-mqtt.sh- MQTT connectivity./scripts/test-screenshot.sh- Screenshot capture./scripts/test-display-manager.sh- Interactive testing menu./scripts/test-impressive.sh- Test auto-quit presentation mode./scripts/test-impressive-loop.sh- Test loop presentation mode./scripts/test-utc-timestamps.sh- Event timing validation- Manual event testing via mosquitto_pub or test-display-manager.sh
Production Deployment
- Docker containerization available (
docker-compose.production.yml) - Systemd service integration for auto-start
- Resource limits and health checks configured
- Persistent volume mounts for data
Code Style & Conventions
Python Code Standards
- Environment variable parsing with fallback defaults
- Comprehensive docstrings for complex functions
- Logging at appropriate levels (DEBUG/INFO/WARNING/ERROR)
- Type hints where beneficial for clarity
- Exception handling with specific error types
Configuration Management
- Environment-first configuration (12-factor app principles)
- Support for inline comments in environment values
- Graceful handling of missing/invalid configuration
- Multiple environment file locations for flexibility
MQTT Message Handling
- JSON message format validation
- Robust payload parsing with fallbacks
- Topic-specific message handlers
- Retained message support where appropriate
Hardware Considerations
Target Platform
- Primary: Raspberry Pi 4/5 with desktop environment
- Storage: SSD recommended for performance
- Display: HDMI output for presentation display
- Network: WiFi or Ethernet connectivity required
System Dependencies
- Python 3.x runtime
- Network connectivity for MQTT
- Display server (X11) for screenshot capture
- Impressive - PDF presenter with auto-advance (primary presentation tool)
- pygame - Required for Impressive (installed in venv)
- Pillow/PIL - Required for Impressive PDF rendering (installed in venv)
- LibreOffice - PPTX to PDF conversion (headless mode)
- Chromium/Chrome - Web content display (kiosk mode)
- VLC or MPV - Video playbook
Video playback details (python-vlc)
- The Display Manager now prefers using python-vlc (libvlc) when available for video playback. This enables programmatic control (autoplay, loop, volume) and cleaner termination/cleanup. If python-vlc is not available, the external
vlcbinary is used as a fallback. - Supported video event fields:
url,autoplay(boolean),loop(boolean),volume(float 0.0-1.0). The manager convertsvolumeto VLC's 0-100 scale. - URLs using the placeholder host
server(for examplehttp://server:8000/...) are rewritten to the configured file server before playback. The resolution priority is:FILE_SERVER_BASE_URL>FILE_SERVER_HOST(orMQTT_BROKER) +FILE_SERVER_PORT+FILE_SERVER_SCHEME. - Hardware-accelerated decoding errors (e.g.,
h264_v4l2m2m) may appear when the platform does not expose a V4L2 M2M device. To avoid these errors the Display Manager can be configured to disable hw-decoding (see README env varVLC_HW_ACCEL). By default the manager will attempt hw-acceleration when libvlc supports it. - Fullscreen / kiosk: the manager will attempt to make libVLC windows fullscreen (remove decorations) when using python-vlc, and the README contains recommended system-level kiosk/session setup for a truly panel-free fullscreen experience.
Security & Privacy
Data Protection
- Hardware identification via cryptographic hash
- No sensitive data in plain text logs
- Local storage of minimal required data only
- Secure MQTT communication (configurable)
Network Security
- Configurable MQTT authentication (if broker requires)
- Firewall-friendly design (outbound connections only)
- Multiple broker fallback for reliability
Presentation System Architecture
How It Works
- PDF File Received → Event contains PDF file reference → Use directly (no conversion)
- PPTX File Received → Event contains PPTX file reference
- Convert to PDF → LibreOffice headless:
libreoffice --headless --convert-to pdf - Cache PDF → Converted PDF stored in
presentation/directory - Display with Impressive → Launch with venv environment and parameters:
--fullscreen- Full screen mode--nooverview- No slide overview--auto N- Auto-advance every N seconds--wrap- Loop infinitely (ifloop: true)--autoquit- Exit after last slide (ifloop: false)
Key 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 |
Why Impressive?
- ✅ Native auto-advance - No xdotool or window management hacks
- ✅ Built-in loop support - Reliable
--wrapparameter - ✅ Works on Raspberry Pi - No focus/window issues
- ✅ Simple integration - Clean command-line interface
- ✅ Maintainable - ~50 lines of code vs. 200+ with xdotool approaches
Implementation Location
- File:
src/display_manager.py - Method:
start_presentation() - Key Logic:
- Check if PDF file (use directly) or PPTX (needs conversion)
- Convert PPTX to PDF if needed (cached for reuse)
- Set up virtual environment for Impressive (pygame + pillow)
- Build Impressive command with appropriate parameters
- Launch process and monitor
Common Development Tasks
When working on this codebase:
- Adding new event types: Extend the event processing logic in
display_manager.py→start_display_for_event() - Modifying presentation behavior: Update
display_manager.py→start_presentation() - Configuration changes: Update environment variable parsing and validation
- MQTT topics: Follow the established
infoscreen/namespace pattern - Error handling: Always include comprehensive logging and graceful fallbacks
- State persistence: Use the established
config/directory pattern - Testing: Use
./scripts/test-display-manager.shfor interactive testing - Presentation testing: Use
./scripts/test-impressive*.shscripts - File download host resolution: If the API server differs from the MQTT broker or uses HTTPS, set
FILE_SERVER_*in.envor adjustresolve_file_url()insrc/simclient.py.
Troubleshooting Guidelines
Common Issues
- MQTT Connection: Check broker reachability, try fallback brokers
- Screenshots: Verify display environment and permissions
- File Downloads: Check network connectivity and disk space
- If event URLs use host
serverand DNS fails, the client rewrites toMQTT_BROKERby default. - Ensure
MQTT_BROKERpoints to the correct server IP; if the API differs, setFILE_SERVER_HOSTorFILE_SERVER_BASE_URL. - Match scheme/port via
FILE_SERVER_SCHEME/FILE_SERVER_PORTfor HTTPS or non-default ports.
- If event URLs use host
- Group Changes: Monitor log for group assignment messages
- Service Startup: Check systemd logs and environment configuration
Debugging Tools
- Log files in
logs/simclient.logandlogs/display_manager.logwith rotation - MQTT message monitoring with mosquitto_sub
- Interactive testing menu:
./scripts/test-display-manager.sh - Component test scripts:
test-impressive*.sh,test-mqtt.sh, etc. - Process monitoring: Check for
impressive,libreoffice,chromium,vlcprocesses
File download URL troubleshooting
- Symptoms:
Failed to resolve 'server'orNameResolutionErrorwhen downloading filesInvalid URL 'http # http or https://...'insimclient.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)
- Look for lines like
- 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 - After changing
.env, restart the simclient process
- If your API is on the same host as the broker: leave
- Expected healthy log sequence:
Lade Datei herunter von: http://<broker-ip>:8000/...- Followed by
"GET /... HTTP/1.1" 200andDatei erfolgreich heruntergeladen:
Important Notes for AI Assistants
Virtual Environment Requirements (Critical)
- pygame and pillow MUST be installed in venv - Required for Impressive to work
- Display manager uses venv context - Ensures Impressive has access to dependencies
- Installation command:
pip install pygame pillow(already in requirements.txt) - If pygame missing: Impressive will fail with "No module named 'pygame'" error
Presentation System
- ALWAYS use Impressive for PDF presentations (primary solution)
- DO NOT suggest xdotool approaches - they failed on Raspberry Pi due to window focus issues
- DO NOT suggest video conversion - adds complexity, had black screen issues
- PDF files are supported natively - no conversion needed
- PPTX conversion is automatic - LibreOffice headless handles PPTX→PDF
- Virtual environment is required - pygame + pillow must be available for Impressive
- Loop mode uses
--wrap- not custom scripts or workarounds - Auto-quit uses
--autoquit- native Impressive parameter
Testing Approach
- Use
./scripts/test-display-manager.shfor interactive testing - Use
./scripts/test-impressive-loop.shto verify loop functionality - Test individual components with specific test scripts
- Always check logs in
logs/directory for debugging
Code Changes
- Display logic is in
src/display_manager.py, notsimclient.py - MQTT client (
simclient.py) writes events tocurrent_event.json - Display Manager reads
current_event.jsonand launches appropriate applications - Two separate processes: simclient.py (MQTT) + display_manager.py (display control)
Documentation
- README.md - Start here for comprehensive overview
- IMPRESSIVE_INTEGRATION.md - Deep dive into presentation system
- QUICK_REFERENCE.md - Quick commands and examples
- Source code has extensive comments and logging
This system is designed for reliability and ease of maintenance in educational environments with multiple deployed clients. The Impressive-based presentation solution provides native auto-advance and loop support without complex window management hacks.
Recent changes (Oct 2025)
Summary of additions since the last Copilot instructions update:
- Added
event_typehandling for scheduler events:presentation,webuntis,webpage,website. The display manager now usesevent_typewhen available to pick the correct display path. - Implemented auto-scroll for long websites. Two strategies are available:
- CDP injection via DevTools websocket using
websocket-clientandrequests. The injector attempts to evaluate an auto-scroll script inside the page context. Default duration: 60s. - Local Chrome extension fallback (
src/chrome_autoscroll) loaded with--load-extensionwhen CDP handshake is blocked (403), ensuring reliable autoscroll operation.
- CDP injection via DevTools websocket using
- New helper scripts for debugging DevTools handshake:
scripts/test_cdp.pyandscripts/test_cdp_origins.py. - Updated
requirements.txtto includewebsocket-client.
Notes for Copilot:
- When adding or modifying display logic, prefer Impressive for PDF presentations and avoid xdotool approaches for slideshow control.
- For web events, ensure autoscroll is only activated for
event_type: "website"and keep the CDP injection optional/fallback-only when feasible.