12 KiB
Display Manager - Event Display Controller
Overview
The Display Manager is a daemon process that monitors current_event.json and automatically controls display software (LibreOffice, Chromium, VLC) to show the appropriate content based on scheduled events.
Architecture
MQTT Server → simclient.py → current_event.json → display_manager.py → Display Software
├─ LibreOffice (presentations)
├─ Chromium (web pages)
└─ VLC/MPV (videos)
How It Works
- Event Reception:
simclient.pyreceives events via MQTT and writes them tocurrent_event.json - File Monitoring:
display_manager.pycontinuously monitors this file for changes - Event Processing: When changes detected, manager determines what to display
- Time-based Activation: Respects event
startandendtimes - Process Management: Starts appropriate display software and manages its lifecycle
- Clean Transitions: Gracefully terminates old software before starting new
Supported Event Types
⚠️ Important: Timestamps are in UTC
All event start and end times must be in UTC format (as stored in the server database). The Display Manager automatically converts these to the local timezone for comparison.
Example format: "2025-10-01 08:00:00" (interpreted as UTC)
1. Presentation Events (PowerPoint/PDF)
{
"id": 1,
"title": "Company Overview",
"start": "2025-10-01 08:00:00",
"end": "2025-10-01 18:00:00",
"presentation": {
"type": "slideshow",
"files": [
{
"name": "presentation.pptx",
"url": "http://server/files/presentation.pptx"
}
],
"slide_interval": 10,
"auto_advance": true
}
}
Supported Formats:
.pptx,.ppt(Microsoft PowerPoint) → LibreOffice Impress.odp(OpenDocument Presentation) → LibreOffice Impress.pdf(PDF documents) → Evince or Okular
Display Behavior:
- Fullscreen/presentation mode
- Auto-advance slides (if supported by viewer)
- Loops through presentation continuously
2. Web Page Events
{
"id": 2,
"title": "Dashboard Display",
"start": "2025-10-01 08:00:00",
"end": "2025-10-01 18:00:00",
"web": {
"url": "https://dashboard.example.com"
}
}
Display Behavior:
- Kiosk mode (fullscreen, no UI)
- Uses Chromium/Chrome browser
- Disables session restore and crash bubbles
3. Video Events
{
"id": 3,
"title": "Promotional Video",
"start": "2025-10-01 08:00:00",
"end": "2025-10-01 18:00:00",
"video": {
"url": "http://server/videos/promo.mp4",
"loop": true
}
}
Supported Formats:
- Local files or HTTP URLs
- All formats supported by VLC/MPV (mp4, avi, mkv, etc.)
Display Behavior:
- Fullscreen playback
- Optional looping
- Uses VLC or MPV player
Installation & Setup
Development Setup
- Install dependencies:
# Already in requirements.txt, but ensure these system packages are installed:
sudo apt-get update
sudo apt-get install -y \
libreoffice-impress \
chromium-browser \
vlc \
evince
- Start Display Manager:
./scripts/start-display-manager.sh
Production Setup (Systemd Service)
- Copy systemd service file:
sudo cp scripts/infoscreen-display.service /etc/systemd/system/
sudo systemctl daemon-reload
- Enable and start service:
sudo systemctl enable infoscreen-display.service
sudo systemctl start infoscreen-display.service
- Check status:
sudo systemctl status infoscreen-display.service
sudo journalctl -u infoscreen-display.service -f
Configuration
Configure via .env file:
# Display Manager Settings
DISPLAY_CHECK_INTERVAL=5 # How often to check for event changes (seconds)
LOG_LEVEL=INFO # Logging level (DEBUG, INFO, WARNING, ERROR)
ENV=production # Environment (development, production)
# Display environment
DISPLAY=:0 # X11 display (usually :0)
Usage
Starting the Display Manager
Development:
./scripts/start-display-manager.sh
Production (systemd):
sudo systemctl start infoscreen-display.service
Testing
Run the interactive test script:
./scripts/test-display-manager.sh
Test menu options:
- Check Display Manager status
- Create PRESENTATION test event
- Create WEBPAGE test event
- Create VIDEO test event
- Remove event (no display)
- Check active display processes
- View current event file
- Interactive test (cycle through events)
Manual Testing
Create a test event file:
cat > src/current_event.json <<EOF
{
"id": 999,
"title": "Test Presentation",
"start": "2025-01-01 00:00:00",
"end": "2025-12-31 23:59:59",
"presentation": {
"files": [{"name": "test.pptx"}]
}
}
EOF
Display Manager will detect the change within 5 seconds and start the presentation.
Stopping Display
Remove the event file:
rm src/current_event.json
Or create an empty event:
echo "{}" > src/current_event.json
Best Practices Implemented
✅ 1. Separation of Concerns
- MQTT Client (
simclient.py): Handles network communication - Display Manager (
display_manager.py): Handles display control - Communication via file:
current_event.json
✅ 2. Robust Process Management
- Clean process lifecycle (start → monitor → terminate)
- Graceful termination with fallback to force kill
- Process health monitoring and automatic restart
- PID tracking for debugging
✅ 3. Event State Machine
- Clear states: NO_EVENT → EVENT_ACTIVE → DISPLAY_RUNNING
- Proper state transitions
- Event change detection via file modification time
- Event deduplication (same event doesn't restart display)
✅ 4. Time-based Scheduling
- Respects event
startandendtimes - Automatically stops display when event expires
- Handles timezone-aware timestamps
✅ 5. Application Lifecycle Management
Starting Applications:
- Detects available software (LibreOffice, Chromium, VLC)
- Uses appropriate command-line flags for kiosk/fullscreen
- Sets correct environment variables (DISPLAY, XAUTHORITY)
Stopping Applications:
- First attempts graceful termination (SIGTERM)
- Waits 5 seconds for clean shutdown
- Falls back to force kill (SIGKILL) if needed
- Cleans up zombie processes
✅ 6. Error Handling & Logging
- Comprehensive error logging with context
- Rotating log files (2MB per file, 5 backups)
- Different log levels for development/production
- Exception handling around all external operations
✅ 7. File Watching Strategy
- Efficient: Only re-reads when file changes (mtime check)
- Handles missing files gracefully
- JSON parsing with error recovery
- Non-blocking I/O
✅ 8. Graceful Shutdown
- Signal handlers (SIGTERM, SIGINT)
- Stops current display before exiting
- Clean resource cleanup
✅ 9. Development Experience
- Test scripts for all functionality
- Interactive testing mode
- Verbose logging in development
- Easy manual testing
✅ 10. Production Readiness
- Systemd service integration
- Auto-restart on failure
- Resource limits and security settings
- Journal logging
Troubleshooting
Display Manager not starting
# Check logs
tail -f logs/display_manager.log
# Check if virtual environment activated
source venv/bin/activate
# Verify Python can import required modules
python3 -c "import paho.mqtt.client; print('OK')"
Display software not appearing
# Check DISPLAY variable
echo $DISPLAY
# Verify X11 authentication
xhost +local:
# Check if software is installed
which libreoffice chromium-browser vlc
# Check running processes
ps aux | grep -E 'libreoffice|chromium|vlc'
Events not triggering display changes
# Verify event file exists and is valid JSON
cat src/current_event.json | jq .
# Check file modification time
stat src/current_event.json
# Check Display Manager is running
pgrep -f display_manager.py
# Watch logs in real-time
tail -f logs/display_manager.log
Display software crashes
# Check for error messages
journalctl -xe | grep -E 'libreoffice|chromium|vlc'
# Verify files exist
ls -la src/presentation/
# Test manual start
libreoffice --impress --show src/presentation/test.pptx
Timezone / Event timing issues
Problem: Events not displaying at the expected time
Cause: Event times are in UTC, but you're thinking in local time
Solution:
# Check current UTC time
date -u
# Check current local time
date
# Check timezone offset
date +%Z
date +%z
# Test with UTC timestamp script
./scripts/test-utc-timestamps.sh
# View Display Manager timezone info in logs
tail -f logs/display_manager.log | grep -i "time\|utc"
Understanding UTC timestamps:
- Server stores times in UTC (database standard)
- Display Manager compares with current UTC time
- Events display correctly regardless of client timezone
Example:
- Event start:
2025-10-01 08:00:00(UTC) - Your timezone: CEST (UTC+2)
- Event will display at: 10:00:00 local time
Debugging timing issues:
- Check Display Manager logs for time comparisons
- Logs show: "Current time (UTC): ..." and "Event start time (UTC): ..."
- Use test script:
./scripts/test-utc-timestamps.sh - Verify server sends UTC timestamps (not local times)
Architecture Decisions
Why separate processes?
- Fault isolation: Display crash doesn't affect MQTT client
- Independent lifecycle: Can restart display without losing connection
- Simpler debugging: Separate logs and process monitoring
Why file-based communication?
- Simplicity: No IPC complexity (sockets, pipes, queues)
- Persistence: Event survives process restarts
- Debuggability: Can inspect/modify events manually
- Atomic operations: File writes are atomic
Why polling instead of inotify?
- Portability: Works on all systems
- Simplicity: No external dependencies
- Reliability: Catches events even if filesystem events missed
- Performance: 5-second interval is sufficient
Why subprocess instead of libraries?
- Flexibility: Can use any display software
- Reliability: Process isolation
- Feature completeness: Full application features (vs. library subset)
- Maintainability: No need to update when apps change
Performance Characteristics
- CPU Usage: Minimal when idle (<1%)
- Memory: ~20-30MB for manager + display software memory
- Startup Time: <1 second
- Event Detection: ~5 seconds average, max 5 seconds
- Display Transition: 1-3 seconds for clean shutdown + start
Future Enhancements
Potential improvements:
- Multi-display support: Handle multiple screens
- Playlist support: Cycle through multiple presentations
- Transition effects: Fade between content
- Health checks: Verify display is rendering correctly
- Remote control: MQTT commands to pause/resume
- Screenshot monitoring: Send actual display output to server
- Performance metrics: Track frame rates, response times
- Fallback content: Default display when no events active
Integration with MQTT Client
The Display Manager integrates seamlessly with simclient.py:
Server MQTT → simclient.py → current_event.json → display_manager.py → Screen
↓
Downloads files
to presentation/
simclient.py responsibilities:
- MQTT communication
- Event file downloads
- Writing
current_event.json
display_manager.py responsibilities:
- Reading
current_event.json - Time-based event activation
- Display software control
License & Support
Part of the Infoscreen Client 2025 project. See main README.md for license and contribution guidelines.