Initial import: clean snapshot from /home/olafn/infoscreen-dev (2025-10-25)
This commit is contained in:
457
src/DISPLAY_MANAGER.md
Normal file
457
src/DISPLAY_MANAGER.md
Normal file
@@ -0,0 +1,457 @@
|
||||
# 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
|
||||
|
||||
1. **Event Reception**: `simclient.py` receives events via MQTT and writes them to `current_event.json`
|
||||
2. **File Monitoring**: `display_manager.py` continuously monitors this file for changes
|
||||
3. **Event Processing**: When changes detected, manager determines what to display
|
||||
4. **Time-based Activation**: Respects event `start` and `end` times
|
||||
5. **Process Management**: Starts appropriate display software and manages its lifecycle
|
||||
6. **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)
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
1. **Install dependencies:**
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
|
||||
2. **Start Display Manager:**
|
||||
```bash
|
||||
./scripts/start-display-manager.sh
|
||||
```
|
||||
|
||||
### Production Setup (Systemd Service)
|
||||
|
||||
1. **Copy systemd service file:**
|
||||
```bash
|
||||
sudo cp scripts/infoscreen-display.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
2. **Enable and start service:**
|
||||
```bash
|
||||
sudo systemctl enable infoscreen-display.service
|
||||
sudo systemctl start infoscreen-display.service
|
||||
```
|
||||
|
||||
3. **Check status:**
|
||||
```bash
|
||||
sudo systemctl status infoscreen-display.service
|
||||
sudo journalctl -u infoscreen-display.service -f
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Configure via `.env` file:
|
||||
|
||||
```bash
|
||||
# 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:**
|
||||
```bash
|
||||
./scripts/start-display-manager.sh
|
||||
```
|
||||
|
||||
**Production (systemd):**
|
||||
```bash
|
||||
sudo systemctl start infoscreen-display.service
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
Run the interactive test script:
|
||||
```bash
|
||||
./scripts/test-display-manager.sh
|
||||
```
|
||||
|
||||
**Test menu options:**
|
||||
1. Check Display Manager status
|
||||
2. Create PRESENTATION test event
|
||||
3. Create WEBPAGE test event
|
||||
4. Create VIDEO test event
|
||||
5. Remove event (no display)
|
||||
6. Check active display processes
|
||||
7. View current event file
|
||||
8. Interactive test (cycle through events)
|
||||
|
||||
### Manual Testing
|
||||
|
||||
Create a test event file:
|
||||
```bash
|
||||
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:
|
||||
```bash
|
||||
rm src/current_event.json
|
||||
```
|
||||
|
||||
Or create an empty event:
|
||||
```bash
|
||||
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 `start` and `end` times
|
||||
- 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
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
# 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**:
|
||||
```bash
|
||||
# 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:**
|
||||
1. Check Display Manager logs for time comparisons
|
||||
2. Logs show: "Current time (UTC): ..." and "Event start time (UTC): ..."
|
||||
3. Use test script: `./scripts/test-utc-timestamps.sh`
|
||||
4. 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:
|
||||
|
||||
1. **Multi-display support**: Handle multiple screens
|
||||
2. **Playlist support**: Cycle through multiple presentations
|
||||
3. **Transition effects**: Fade between content
|
||||
4. **Health checks**: Verify display is rendering correctly
|
||||
5. **Remote control**: MQTT commands to pause/resume
|
||||
6. **Screenshot monitoring**: Send actual display output to server
|
||||
7. **Performance metrics**: Track frame rates, response times
|
||||
8. **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.
|
||||
Reference in New Issue
Block a user