Initial import: clean snapshot from /home/olafn/infoscreen-dev (2025-10-25)

This commit is contained in:
RobbStarkAustria
2025-10-25 17:42:27 +02:00
commit 8ca9f69f6f
111 changed files with 8612 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
[Unit]
Description=Infoscreen Display Manager
Documentation=https://github.com/RobbStarkAustria/infoscreen_client_2025
After=network.target graphical.target
Wants=network-online.target
[Service]
Type=simple
User=olafn
Group=olafn
WorkingDirectory=/home/olafn/infoscreen-dev
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/olafn/.Xauthority"
Environment="ENV=production"
# Start display manager
ExecStart=/home/olafn/infoscreen-dev/scripts/start-display-manager.sh
# Restart on failure
Restart=on-failure
RestartSec=10
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=infoscreen-display
# Security settings
NoNewPrivileges=true
PrivateTmp=true
# Resource limits
LimitNOFILE=65536
[Install]
WantedBy=graphical.target

View File

@@ -0,0 +1,163 @@
#!/bin/bash
# PDF Presentation with Auto-Advance
# Works for both native PDF and converted PPTX files
PDF_FILE="$1"
INTERVAL="${2:-10}"
LOOP="${3:-false}"
if [ -z "$PDF_FILE" ]; then
echo "Usage: $0 <file.pdf> [interval-seconds] [loop:true|false]"
exit 1
fi
if [ ! -f "$PDF_FILE" ]; then
echo "Error: File not found: $PDF_FILE"
exit 1
fi
echo "=========================================="
echo " PDF Presentation Mode"
echo "=========================================="
echo ""
echo "File: $(basename "$PDF_FILE")"
echo "Auto-advance: ${INTERVAL}s per slide"
echo "Loop: $LOOP"
echo ""
# Count pages in PDF
PAGE_COUNT=$(pdfinfo "$PDF_FILE" 2>/dev/null | grep "Pages:" | awk '{print $2}')
if [ -z "$PAGE_COUNT" ] || [ "$PAGE_COUNT" -eq 0 ]; then
echo "Warning: Could not determine page count, assuming 10 pages"
PAGE_COUNT=10
else
echo "Detected $PAGE_COUNT pages"
fi
echo ""
# Check for required tools
if ! command -v xdotool &> /dev/null; then
echo "Error: xdotool not installed"
echo "Install with: sudo apt-get install xdotool"
exit 1
fi
# Choose best PDF viewer (prefer Impressive for auto-advance)
PDF_VIEWER=""
PDF_VIEWER_CMD=""
if command -v impressive &> /dev/null; then
PDF_VIEWER="impressive"
PDF_VIEWER_CMD="impressive --fullscreen --nooverview --auto $INTERVAL"
if [ "$LOOP" = "true" ]; then
PDF_VIEWER_CMD="$PDF_VIEWER_CMD --wrap"
else
PDF_VIEWER_CMD="$PDF_VIEWER_CMD --autoquit"
fi
# Impressive handles auto-advance natively, no xdotool needed!
echo "Using Impressive (built-in auto-advance)..."
$PDF_VIEWER_CMD "$PDF_FILE"
exit 0
elif command -v evince &> /dev/null; then
PDF_VIEWER="evince"
PDF_VIEWER_CMD="evince --presentation"
elif command -v okular &> /dev/null; then
PDF_VIEWER="okular"
PDF_VIEWER_CMD="okular --presentation"
else
echo "Error: No suitable PDF viewer found"
echo "Install impressive: sudo apt-get install impressive"
exit 1
fi
echo "Using PDF viewer: $PDF_VIEWER"
echo "Starting presentation mode..."
echo ""
# Start PDF viewer in presentation mode
$PDF_VIEWER_CMD "$PDF_FILE" &
VIEWER_PID=$!
echo "Viewer PID: $VIEWER_PID"
echo "Waiting for viewer to start..."
sleep 5
# Verify it's still running
if ! ps -p $VIEWER_PID > /dev/null 2>&1; then
echo "Error: PDF viewer exited unexpectedly"
exit 1
fi
echo "Starting auto-advance..."
echo "Press Ctrl+C to stop"
echo ""
# Auto-advance loop
CURRENT_PAGE=1
MAX_LOOPS=0
if [ "$LOOP" = "false" ]; then
# Calculate total slides to advance (pages - 1, since we start on page 1)
MAX_ADVANCES=$((PAGE_COUNT - 1))
else
# Infinite loop
MAX_ADVANCES=999999
fi
ADVANCE_COUNT=0
while ps -p $VIEWER_PID > /dev/null 2>&1 && [ $ADVANCE_COUNT -lt $MAX_ADVANCES ]; do
sleep $INTERVAL
# Find the PDF viewer window
VIEWER_WINDOW=$(xdotool search --pid $VIEWER_PID 2>/dev/null | tail -1)
if [ -z "$VIEWER_WINDOW" ]; then
# Fallback: search by window name
VIEWER_WINDOW=$(xdotool search --name "$(basename "$PDF_FILE")" 2>/dev/null | tail -1)
fi
if [ -n "$VIEWER_WINDOW" ]; then
# Ensure window is focused
xdotool windowactivate --sync "$VIEWER_WINDOW" 2>/dev/null
sleep 0.2
# Send Right Arrow or Page Down (both work in most PDF viewers)
xdotool key --clearmodifiers --window "$VIEWER_WINDOW" Right
CURRENT_PAGE=$((CURRENT_PAGE + 1))
ADVANCE_COUNT=$((ADVANCE_COUNT + 1))
echo "[$(date '+%H:%M:%S')] Advanced to page $CURRENT_PAGE"
# Check if we've reached the end
if [ $CURRENT_PAGE -gt $PAGE_COUNT ]; then
if [ "$LOOP" = "true" ]; then
echo "Reached end, looping back to start..."
CURRENT_PAGE=1
else
echo ""
echo "Reached end of presentation (page $PAGE_COUNT)"
echo "Keeping viewer open..."
# Keep viewer running, just stop advancing
wait $VIEWER_PID
exit 0
fi
fi
else
# Fallback: send key to active window
xdotool key --clearmodifiers Right
CURRENT_PAGE=$((CURRENT_PAGE + 1))
ADVANCE_COUNT=$((ADVANCE_COUNT + 1))
echo "[$(date '+%H:%M:%S')] Advanced (fallback) #$ADVANCE_COUNT"
fi
done
echo ""
echo "Presentation ended"
exit 0

5
scripts/start-dev.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
cd "$(dirname "$0")/.."
source venv/bin/activate
export $(cat .env | xargs)
python3 src/simclient.py

View File

@@ -0,0 +1,43 @@
#!/bin/bash
# Start Display Manager - Controls display software for infoscreen events
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
VENV_PATH="$PROJECT_ROOT/venv"
DISPLAY_MANAGER="$PROJECT_ROOT/src/display_manager.py"
echo "🖥️ Starting Display Manager..."
echo "Project root: $PROJECT_ROOT"
# Check if virtual environment exists
if [ ! -d "$VENV_PATH" ]; then
echo "❌ Virtual environment not found at: $VENV_PATH"
echo "Please create it with: python3 -m venv venv"
exit 1
fi
# Activate virtual environment
source "$VENV_PATH/bin/activate"
# Check if display_manager.py exists
if [ ! -f "$DISPLAY_MANAGER" ]; then
echo "❌ Display manager not found at: $DISPLAY_MANAGER"
exit 1
fi
# Make sure DISPLAY is set (required for GUI applications)
if [ -z "$DISPLAY" ]; then
export DISPLAY=:0
echo "📺 DISPLAY not set, using: $DISPLAY"
fi
# Check if we're in development or production
ENV="${ENV:-development}"
echo "Environment: $ENV"
# Start display manager
echo "Starting display manager..."
echo "---"
python3 "$DISPLAY_MANAGER"

210
scripts/test-display-manager.sh Executable file
View File

@@ -0,0 +1,210 @@
#!/bin/bash
# Test Display Manager functionality
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
EVENT_FILE="$PROJECT_ROOT/src/current_event.json"
echo "🧪 Testing Display Manager"
echo "========================="
echo ""
# Function to create test event
create_test_event() {
local event_type=$1
echo "📝 Creating test event: $event_type"
case $event_type in
"presentation")
cat > "$EVENT_FILE" <<EOF
{
"id": 999,
"title": "Test Presentation with Impressive",
"start": "2025-01-01 00:00:00",
"end": "2025-12-31 23:59:59",
"presentation": {
"type": "slideshow",
"files": [
{
"name": "LPUV4I_Folien_Nowitzki_Bewertungskriterien.pptx",
"url": "http://example.com/test.pptx"
}
],
"auto_advance": true,
"slide_interval": 5,
"loop": true
}
}
EOF
;;
"webpage")
cat > "$EVENT_FILE" <<EOF
{
"id": 998,
"title": "Test Webpage",
"start": "2025-01-01 00:00:00",
"end": "2025-12-31 23:59:59",
"web": {
"url": "https://www.wikipedia.org"
}
}
EOF
;;
"video")
cat > "$EVENT_FILE" <<EOF
{
"id": 997,
"title": "Test Video",
"start": "2025-01-01 00:00:00",
"end": "2025-12-31 23:59:59",
"video": {
"url": "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
"loop": false
}
}
EOF
;;
"none")
echo "📝 Removing event file (no active event)"
rm -f "$EVENT_FILE"
;;
esac
if [ -f "$EVENT_FILE" ]; then
echo "✅ Event file created:"
cat "$EVENT_FILE"
fi
echo ""
}
# Function to check if display manager is running
check_display_manager() {
if pgrep -f "display_manager.py" > /dev/null; then
echo "✅ Display Manager is running"
echo " PID: $(pgrep -f display_manager.py)"
return 0
else
echo "❌ Display Manager is NOT running"
return 1
fi
}
# Function to check for display processes
check_display_processes() {
echo "🔍 Active display processes:"
# Check for LibreOffice
if pgrep -f "libreoffice.*impress" > /dev/null; then
echo " 📊 LibreOffice Impress: PID $(pgrep -f 'libreoffice.*impress')"
fi
# Check for browsers
if pgrep -f "chromium.*kiosk" > /dev/null; then
echo " 🌐 Chromium (kiosk): PID $(pgrep -f 'chromium.*kiosk')"
fi
# Check for video players
if pgrep -f "vlc" > /dev/null; then
echo " 🎬 VLC: PID $(pgrep -f 'vlc')"
fi
if pgrep -f "mpv" > /dev/null; then
echo " 🎬 MPV: PID $(pgrep -f 'mpv')"
fi
# Check for PDF viewers
if pgrep -f "evince" > /dev/null; then
echo " 📄 Evince: PID $(pgrep -f 'evince')"
fi
# Check for Impressive
if pgrep -f "impressive" > /dev/null; then
echo " 📊 Impressive: PID $(pgrep -f 'impressive')"
fi
echo ""
}
# Main menu
echo "Display Manager Test Menu"
echo "========================="
echo ""
echo "What would you like to test?"
echo "1) Check Display Manager status"
echo "2) Create PRESENTATION test event"
echo "3) Create WEBPAGE test event"
echo "4) Create VIDEO test event"
echo "5) Remove event (no display)"
echo "6) Check active display processes"
echo "7) View current event file"
echo "8) Interactive test (cycle through events)"
echo "9) Exit"
echo ""
read -p "Enter choice [1-9]: " choice
case $choice in
1)
check_display_manager
check_display_processes
;;
2)
create_test_event "presentation"
echo "⏱️ Display Manager will pick this up within 5 seconds..."
;;
3)
create_test_event "webpage"
echo "⏱️ Display Manager will pick this up within 5 seconds..."
;;
4)
create_test_event "video"
echo "⏱️ Display Manager will pick this up within 5 seconds..."
;;
5)
create_test_event "none"
echo "⏱️ Display Manager will stop display within 5 seconds..."
;;
6)
check_display_manager
check_display_processes
;;
7)
if [ -f "$EVENT_FILE" ]; then
echo "📄 Current event file:"
cat "$EVENT_FILE"
else
echo "❌ No event file found"
fi
;;
8)
echo "🔄 Interactive test - cycling through event types"
echo " Display Manager must be running for this test!"
echo ""
check_display_manager || exit 1
echo "1⃣ Testing PRESENTATION (10 seconds)..."
create_test_event "presentation"
sleep 10
echo "2⃣ Testing WEBPAGE (10 seconds)..."
create_test_event "webpage"
sleep 10
echo "3⃣ Testing NO EVENT (5 seconds)..."
create_test_event "none"
sleep 5
echo "4⃣ Back to PRESENTATION..."
create_test_event "presentation"
echo "✅ Interactive test complete!"
;;
9)
echo "👋 Goodbye!"
exit 0
;;
*)
echo "❌ Invalid choice"
exit 1
;;
esac

92
scripts/test-impressive-loop.sh Executable file
View File

@@ -0,0 +1,92 @@
#!/bin/bash
# Test Impressive with LOOP mode (for events/kiosks)
echo "=========================================="
echo " Test: Impressive with LOOP"
echo "=========================================="
echo ""
echo "This tests kiosk/event mode where the"
echo "presentation loops continuously."
echo ""
cd ~/infoscreen-dev
PPTX=$(find src/presentation -name "*.pptx" | head -1)
if [ -z "$PPTX" ]; then
echo "Error: No PPTX file found"
exit 1
fi
# Convert to PDF
PDF="/tmp/impressive_loop_test.pdf"
echo "Converting PPTX to PDF..."
libreoffice --headless --convert-to pdf --outdir /tmp "$PPTX" > /dev/null 2>&1
PPTX_BASE=$(basename "$PPTX" .pptx)
ACTUAL_PDF="/tmp/${PPTX_BASE}.pdf"
if [ -f "$ACTUAL_PDF" ]; then
cp "$ACTUAL_PDF" "$PDF"
fi
if [ ! -f "$PDF" ]; then
echo "Error: PDF conversion failed"
exit 1
fi
PAGE_COUNT=$(pdfinfo "$PDF" 2>/dev/null | grep "Pages:" | awk '{print $2}')
echo "[OK] PDF ready: $PAGE_COUNT pages"
echo ""
echo "Starting Impressive in LOOP mode..."
echo ""
echo "Settings:"
echo " - Auto-advance: 3 seconds per slide"
echo " - Loop: YES (--wrap)"
echo " - Will go: Slide 1 → 2 → 3 → 4 → 5 → 1 → 2 → ..."
echo ""
echo "What to watch for:"
echo " ✅ Advances through all $PAGE_COUNT slides"
echo " ✅ After slide $PAGE_COUNT, goes back to slide 1"
echo " ✅ Continues looping forever"
echo ""
echo "Press 'Q' or Escape to quit"
echo ""
sleep 2
# Start with --wrap for loop mode
impressive \
--fullscreen \
--nooverview \
--auto 3 \
--wrap \
--nologo \
"$PDF"
echo ""
echo "=========================================="
echo " Test Complete"
echo "=========================================="
echo ""
read -p "Did it loop back to slide 1 after slide $PAGE_COUNT? (y/n): " worked
if [ "$worked" = "y" ]; then
echo ""
echo "✅ Perfect! Impressive loop mode works!"
echo ""
echo "This is ideal for:"
echo " - Event displays (loop presentation during event)"
echo " - Kiosk mode (continuous display)"
echo " - Information screens (repeat content)"
echo ""
echo "Event JSON should use:"
echo ' "loop": true'
else
echo ""
echo "Something unexpected?"
read -p "What happened?: " issue
echo "Issue: $issue"
fi
rm -f "$PDF"

115
scripts/test-impressive.sh Executable file
View File

@@ -0,0 +1,115 @@
#!/bin/bash
# Test Impressive - Python PDF presenter with native auto-advance
echo "=========================================="
echo " Test: Impressive PDF Presenter"
echo "=========================================="
echo ""
echo "Impressive is a Python-based PDF presenter with"
echo "BUILT-IN auto-advance. No xdotool needed!"
echo ""
# Check if impressive is installed
if ! command -v impressive &> /dev/null; then
echo "Impressive not installed. Installing..."
echo ""
sudo apt-get update
sudo apt-get install -y impressive
if [ $? -ne 0 ]; then
echo "Error: Could not install impressive"
exit 1
fi
fi
echo "Impressive installed: $(which impressive)"
echo ""
# Convert PPTX to PDF
cd ~/infoscreen-dev
PPTX=$(find src/presentation -name "*.pptx" | head -1)
if [ -z "$PPTX" ]; then
echo "Error: No PPTX file found"
exit 1
fi
PDF="/tmp/impressive_test.pdf"
echo "Converting PPTX to PDF..."
libreoffice --headless --convert-to pdf --outdir /tmp "$PPTX" > /dev/null 2>&1
PPTX_BASE=$(basename "$PPTX" .pptx)
ACTUAL_PDF="/tmp/${PPTX_BASE}.pdf"
if [ -f "$ACTUAL_PDF" ]; then
cp "$ACTUAL_PDF" "$PDF"
fi
if [ ! -f "$PDF" ]; then
echo "Error: PDF conversion failed"
exit 1
fi
PAGE_COUNT=$(pdfinfo "$PDF" 2>/dev/null | grep "Pages:" | awk '{print $2}')
echo "[OK] PDF ready: $PAGE_COUNT pages"
echo ""
echo "Starting Impressive with 3-second auto-advance..."
echo ""
echo "Impressive features:"
echo " - Native auto-advance (no xdotool!)"
echo " - Fullscreen by default"
echo " - Professional transitions"
echo " - Loop support"
echo ""
echo "Controls:"
echo " Right Arrow / Space = Next slide"
echo " Left Arrow = Previous slide"
echo " Q / Escape = Quit"
echo ""
sleep 2
# Start Impressive with auto-advance
# --auto 3 = auto-advance every 3 seconds
# --fullscreen = fullscreen mode
# --nooverview = skip overview at start
# --autoquit = quit after last slide (for non-loop mode)
impressive \
--fullscreen \
--auto 3 \
--nooverview \
--autoquit \
"$PDF"
echo ""
echo "=========================================="
echo " Test Complete"
echo "=========================================="
echo ""
read -p "Did it work perfectly? (y/n): " worked
if [ "$worked" = "y" ]; then
echo ""
echo "✅ EXCELLENT! Impressive is your solution!"
echo ""
echo "Why Impressive is perfect:"
echo " ✅ Built-in auto-advance (no xdotool hacks)"
echo " ✅ Reliable on Raspberry Pi"
echo " ✅ Professional presenter tool"
echo " ✅ Supports loop mode natively"
echo " ✅ Fast and lightweight"
echo ""
echo "Next steps:"
echo " 1. Update Display Manager to use Impressive"
echo " 2. Simple command: impressive --auto N --fullscreen file.pdf"
echo " 3. Works for both PPTX (convert to PDF) and PDF files"
else
echo ""
echo "What didn't work?"
read -p "Describe the issue: " issue
echo "Issue: $issue"
fi
rm -f "$PDF"

9
scripts/test-mqtt.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
source "$(dirname "$0")/../.env"
echo "Testing MQTT connection to $MQTT_BROKER:$MQTT_PORT"
echo "Publishing test message..."
mosquitto_pub -h "$MQTT_BROKER" -p "$MQTT_PORT" -t "infoscreen/test" -m "Hello from Pi development setup"
echo "Subscribing to test topic (press Ctrl+C to stop)..."
mosquitto_sub -h "$MQTT_BROKER" -p "$MQTT_PORT" -t "infoscreen/test"

174
scripts/test-progress-bars.sh Executable file
View File

@@ -0,0 +1,174 @@
#!/bin/bash
# Test script for page_progress and auto_progress features in presentations
echo "=========================================="
echo "Progress Bar Features Test"
echo "=========================================="
echo ""
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Check if MQTT broker is configured
if [ -f ../.env ]; then
source ../.env
MQTT_HOST=${MQTT_BROKER:-localhost}
else
MQTT_HOST=localhost
fi
echo -e "${YELLOW}Using MQTT broker: ${MQTT_HOST}${NC}"
echo ""
# Menu for testing different progress bar configurations
echo "Select a test configuration:"
echo ""
echo "1. No progress bars (default)"
echo "2. Page progress only (overall position)"
echo "3. Auto-progress only (per-page countdown)"
echo "4. Both progress bars (maximum feedback)"
echo ""
read -p "Enter choice (1-4): " choice
case $choice in
1)
PAGE_PROG=false
AUTO_PROG=false
DESC="No progress bars"
;;
2)
PAGE_PROG=true
AUTO_PROG=false
DESC="Page progress only (--page-progress)"
;;
3)
PAGE_PROG=false
AUTO_PROG=true
DESC="Auto-progress only (--auto-progress)"
;;
4)
PAGE_PROG=true
AUTO_PROG=true
DESC="Both progress bars"
;;
*)
echo "Invalid choice"
exit 1
;;
esac
echo ""
echo -e "${BLUE}Configuration: $DESC${NC}"
echo " page_progress: $PAGE_PROG"
echo " auto_progress: $AUTO_PROG"
echo ""
# Create test event with progress bar settings
TEST_EVENT=$(cat <<EOF
{
"id": 888,
"group_id": 2,
"title": "Progress Bar Test Event",
"start": "2025-01-01T00:00:00+00:00",
"end": "2025-12-31T23:59:59+00:00",
"presentation": {
"type": "slideshow",
"auto_advance": true,
"slide_interval": 5,
"loop": true,
"page_progress": $PAGE_PROG,
"auto_progress": $AUTO_PROG,
"files": [
{
"name": "Wissenschaftliches Arbeiten Literaturrecherche.pdf",
"url": "http://server:8000/api/files/test.pdf"
}
]
}
}
EOF
)
echo "Sending test event to MQTT..."
echo ""
mosquitto_pub -h "$MQTT_HOST" -t "infoscreen/events/2" -m "$TEST_EVENT"
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Event sent successfully${NC}"
else
echo -e "${RED}✗ Failed to send event${NC}"
exit 1
fi
echo ""
echo "Waiting for Display Manager to process event..."
sleep 3
echo ""
echo "Checking Display Manager log for progress bar settings..."
echo ""
LOG_FILE="../logs/display_manager.log"
if [ -f "$LOG_FILE" ]; then
echo -e "${YELLOW}Recent log entries:${NC}"
tail -30 "$LOG_FILE" | grep -E "(progress|Progress|Impressive)" | tail -10
else
echo -e "${YELLOW}Log file not found: $LOG_FILE${NC}"
fi
echo ""
echo "=========================================="
echo "Expected Behavior"
echo "=========================================="
echo ""
case $choice in
1)
echo "• No progress indicators visible"
echo "• Clean presentation display"
;;
2)
echo "• Progress bar at bottom of screen"
echo "• Shows current position: [=====> ] 50%"
echo "• Updates as slides change"
;;
3)
echo "• Countdown bar for each slide"
echo "• Shows time remaining until next slide"
echo "• Resets on each slide transition"
;;
4)
echo "• Overall progress bar at bottom"
echo "• Per-slide countdown overlay"
echo "• Both indicators update in real-time"
;;
esac
echo ""
echo "=========================================="
echo "Impressive Command Options"
echo "=========================================="
echo ""
echo "The Display Manager translates event fields to Impressive options:"
echo ""
echo "Event Field → Impressive Option"
echo "-------------------- → ------------------"
echo "page_progress: true → --page-progress (or -q)"
echo "auto_progress: true → --auto-progress (or -k)"
echo ""
echo "Check the impressive.out.log for the exact command used:"
echo " tail -20 ../logs/impressive.out.log"
echo ""
echo -e "${GREEN}Test complete!${NC}"
echo ""
echo "Tips:"
echo " • Press 'q' to quit the presentation"
echo " • Run this script again to test different configurations"
echo " • Check logs/display_manager.log for detailed output"
echo ""

143
scripts/test-scheduler-fields.sh Executable file
View File

@@ -0,0 +1,143 @@
#!/bin/bash
# Test script to verify scheduler fields (page_progress, auto_progress) are preserved
echo "=========================================="
echo "Scheduler Fields Preservation Test"
echo "=========================================="
echo ""
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Check if MQTT broker is configured
if [ -f ../.env ]; then
source ../.env
MQTT_HOST=${MQTT_BROKER:-localhost}
else
MQTT_HOST=localhost
fi
echo -e "${YELLOW}Using MQTT broker: ${MQTT_HOST}${NC}"
echo ""
# Test event with scheduler fields
TEST_EVENT='{
"id": 999,
"occurrence_of_id": 999,
"group_id": 2,
"title": "Test Event with Scheduler Fields",
"start": "2025-01-01T10:00:00+00:00",
"end": "2025-12-31T23:59:59+00:00",
"recurrence_rule": "FREQ=DAILY",
"recurrence_end": "2025-12-31T23:59:59",
"presentation": {
"type": "slideshow",
"auto_advance": true,
"slide_interval": 10,
"page_progress": true,
"auto_progress": true,
"files": [
{
"name": "test.pdf",
"url": "http://server:8000/api/files/test.pdf"
}
]
}
}'
echo "1. Sending test event with scheduler fields to MQTT..."
echo ""
echo "Event contains:"
echo " - page_progress: true (show overall progress bar)"
echo " - auto_progress: true (show per-page countdown)"
echo " - recurrence_rule: FREQ=DAILY"
echo " - occurrence_of_id: 999"
echo ""
mosquitto_pub -h "$MQTT_HOST" -t "infoscreen/events/2" -m "$TEST_EVENT"
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Event sent successfully${NC}"
else
echo -e "${RED}✗ Failed to send event${NC}"
exit 1
fi
echo ""
echo "2. Waiting for event to be processed..."
sleep 2
echo ""
echo "3. Checking current_event.json for scheduler fields..."
echo ""
EVENT_FILE="../src/current_event.json"
if [ ! -f "$EVENT_FILE" ]; then
echo -e "${RED}✗ Event file not found: $EVENT_FILE${NC}"
exit 1
fi
echo -e "${YELLOW}Current event content:${NC}"
cat "$EVENT_FILE" | jq '.'
echo ""
# Check for specific fields
echo "4. Verifying scheduler fields are preserved..."
echo ""
PAGE_PROGRESS=$(cat "$EVENT_FILE" | jq -r '.[0].page_progress // .page_progress // "not_found"')
AUTO_PROGRESS=$(cat "$EVENT_FILE" | jq -r '.[0].auto_progress // .auto_progress // "not_found"')
OCCURRENCE_ID=$(cat "$EVENT_FILE" | jq -r '.[0].occurrence_of_id // .occurrence_of_id // "not_found"')
RECURRENCE=$(cat "$EVENT_FILE" | jq -r '.[0].recurrence_rule // .recurrence_rule // "not_found"')
if [ "$PAGE_PROGRESS" = "true" ]; then
echo -e "${GREEN}✓ page_progress preserved: $PAGE_PROGRESS${NC}"
else
echo -e "${RED}✗ page_progress missing or incorrect: $PAGE_PROGRESS${NC}"
fi
if [ "$AUTO_PROGRESS" = "true" ]; then
echo -e "${GREEN}✓ auto_progress preserved: $AUTO_PROGRESS${NC}"
else
echo -e "${RED}✗ auto_progress missing or incorrect: $AUTO_PROGRESS${NC}"
fi
if [ "$OCCURRENCE_ID" = "999" ]; then
echo -e "${GREEN}✓ occurrence_of_id preserved: $OCCURRENCE_ID${NC}"
else
echo -e "${RED}✗ occurrence_of_id missing or incorrect: $OCCURRENCE_ID${NC}"
fi
if [ "$RECURRENCE" = "FREQ=DAILY" ]; then
echo -e "${GREEN}✓ recurrence_rule preserved: $RECURRENCE${NC}"
else
echo -e "${RED}✗ recurrence_rule missing or incorrect: $RECURRENCE${NC}"
fi
echo ""
echo "5. Checking simclient log for debug messages..."
echo ""
LOG_FILE="../logs/simclient.log"
if [ -f "$LOG_FILE" ]; then
echo -e "${YELLOW}Recent log entries mentioning scheduler fields:${NC}"
tail -20 "$LOG_FILE" | grep -E "page_progress|auto_progress" || echo " (no debug messages - set LOG_LEVEL=DEBUG to see them)"
else
echo -e "${YELLOW}Log file not found: $LOG_FILE${NC}"
fi
echo ""
echo "=========================================="
echo -e "${GREEN}Test Complete${NC}"
echo "=========================================="
echo ""
echo "Summary:"
echo " - Scheduler fields (page_progress, auto_progress) should be preserved in current_event.json"
echo " - All metadata from the scheduler is automatically stored without filtering"
echo " - Set LOG_LEVEL=DEBUG in .env to see field logging in simclient.log"
echo ""

27
scripts/test-screenshot.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
SCREENSHOT_DIR="$(dirname "$0")/../screenshots"
mkdir -p "$SCREENSHOT_DIR"
# Ensure DISPLAY is set for screenshot capture
if [ -z "$DISPLAY" ]; then
export DISPLAY=:0
fi
# Test screenshot capture
echo "Testing screenshot capture with DISPLAY=$DISPLAY"
if scrot "$SCREENSHOT_DIR/test_$(date +%Y%m%d_%H%M%S).png" 2>/dev/null; then
echo "✅ Screenshot captured successfully"
echo "📁 Screenshot saved to: $SCREENSHOT_DIR"
ls -la "$SCREENSHOT_DIR"/test_*.png | tail -1
else
echo "❌ Screenshot failed with scrot, trying imagemagick..."
if import -window root "$SCREENSHOT_DIR/test_$(date +%Y%m%d_%H%M%S).png" 2>/dev/null; then
echo "✅ Screenshot captured with imagemagick"
echo "📁 Screenshot saved to: $SCREENSHOT_DIR"
ls -la "$SCREENSHOT_DIR"/test_*.png | tail -1
else
echo "❌ Screenshot capture failed. Check DISPLAY variable and X11 access."
echo "💡 Try: export DISPLAY=:0"
echo "💡 Or run from local Pi terminal instead of SSH"
fi
fi

149
scripts/test-utc-timestamps.sh Executable file
View File

@@ -0,0 +1,149 @@
#!/bin/bash
# Test UTC timestamp handling in Display Manager
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
EVENT_FILE="$PROJECT_ROOT/src/current_event.json"
echo "🕐 UTC Timestamp Test for Display Manager"
echo "=========================================="
echo ""
# Get current UTC and local times
UTC_NOW=$(date -u '+%Y-%m-%d %H:%M:%S')
LOCAL_NOW=$(date '+%Y-%m-%d %H:%M:%S')
TIMEZONE=$(date +%Z)
UTC_OFFSET=$(date +%z)
echo "📅 Current Time Information:"
echo " UTC Time: $UTC_NOW"
echo " Local Time: $LOCAL_NOW"
echo " Timezone: $TIMEZONE (UTC$UTC_OFFSET)"
echo ""
# Calculate timestamps for testing
# Start: 1 minute ago (UTC)
START_TIME=$(date -u -d '1 minute ago' '+%Y-%m-%d %H:%M:%S')
# End: 10 minutes from now (UTC)
END_TIME=$(date -u -d '10 minutes' '+%Y-%m-%d %H:%M:%S')
echo "🧪 Test Scenarios:"
echo ""
echo "1⃣ Test Active Event (should display NOW)"
echo " Create event with:"
echo " - Start: $START_TIME UTC (1 minute ago)"
echo " - End: $END_TIME UTC (in 10 minutes)"
echo ""
read -p "Press Enter to create test event..."
cat > "$EVENT_FILE" <<EOF
{
"id": 998,
"title": "UTC Test - Active Event",
"start": "$START_TIME",
"end": "$END_TIME",
"web": {
"url": "https://www.timeanddate.com/worldclock/timezone/utc"
}
}
EOF
echo "✅ Created test event:"
cat "$EVENT_FILE" | jq .
echo ""
echo "⏱️ Display Manager should detect this as ACTIVE and start displaying"
echo " Check the logs with: tail -f logs/display_manager.log"
echo ""
read -p "Press Enter to continue to next test..."
echo ""
# Test 2: Event in the future
FUTURE_START=$(date -u -d '5 minutes' '+%Y-%m-%d %H:%M:%S')
FUTURE_END=$(date -u -d '15 minutes' '+%Y-%m-%d %H:%M:%S')
echo "2⃣ Test Future Event (should NOT display yet)"
echo " Create event with:"
echo " - Start: $FUTURE_START UTC (in 5 minutes)"
echo " - End: $FUTURE_END UTC (in 15 minutes)"
echo ""
read -p "Press Enter to create future event..."
cat > "$EVENT_FILE" <<EOF
{
"id": 997,
"title": "UTC Test - Future Event",
"start": "$FUTURE_START",
"end": "$FUTURE_END",
"web": {
"url": "https://www.timeanddate.com/worldclock/timezone/utc"
}
}
EOF
echo "✅ Created future event:"
cat "$EVENT_FILE" | jq .
echo ""
echo "⏱️ Display Manager should detect this as NOT ACTIVE YET"
echo " It should stop any current display"
echo " Check logs: tail -f logs/display_manager.log"
echo ""
read -p "Press Enter to continue to next test..."
echo ""
# Test 3: Event in the past
PAST_START=$(date -u -d '30 minutes ago' '+%Y-%m-%d %H:%M:%S')
PAST_END=$(date -u -d '20 minutes ago' '+%Y-%m-%d %H:%M:%S')
echo "3⃣ Test Past Event (should NOT display - already ended)"
echo " Create event with:"
echo " - Start: $PAST_START UTC (30 minutes ago)"
echo " - End: $PAST_END UTC (20 minutes ago)"
echo ""
read -p "Press Enter to create past event..."
cat > "$EVENT_FILE" <<EOF
{
"id": 996,
"title": "UTC Test - Past Event",
"start": "$PAST_START",
"end": "$PAST_END",
"web": {
"url": "https://www.timeanddate.com/worldclock/timezone/utc"
}
}
EOF
echo "✅ Created past event:"
cat "$EVENT_FILE" | jq .
echo ""
echo "⏱️ Display Manager should detect this as ALREADY ENDED"
echo " It should stop any current display"
echo " Check logs: tail -f logs/display_manager.log"
echo ""
read -p "Press Enter to clean up..."
# Clean up
rm -f "$EVENT_FILE"
echo ""
echo "🧹 Cleaned up test event file"
echo ""
echo "📊 Summary:"
echo "==========="
echo ""
echo "✅ Test 1: Active event (past start, future end) → Should DISPLAY"
echo "✅ Test 2: Future event (future start, future end) → Should NOT display yet"
echo "✅ Test 3: Past event (past start, past end) → Should NOT display"
echo ""
echo "📝 The Display Manager should now correctly handle UTC timestamps!"
echo ""
echo "💡 Tips for debugging:"
echo " • Watch logs: tail -f logs/display_manager.log"
echo " • Check timezone: date; date -u"
echo " • The Display Manager logs show both UTC and comparison times"
echo ""

75
scripts/test_cdp.py Executable file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""Quick CDP tester: lists targets and evaluates a small script in the first target.
Usage:
python3 scripts/test_cdp.py
Requires: requests, websocket-client
"""
import requests
import websocket
import json
def main():
try:
resp = requests.get('http://127.0.0.1:9222/json', timeout=3)
tabs = resp.json()
except Exception as e:
print('ERROR: could not fetch http://127.0.0.1:9222/json ->', e)
return
if not tabs:
print('No targets returned')
return
print('Found targets:')
for i, t in enumerate(tabs):
print(i, t.get('type'), t.get('url'), '-', t.get('title'))
target = tabs[0]
ws_url = target.get('webSocketDebuggerUrl')
print('\nUsing target[0]:', target.get('url'))
print('webSocketDebuggerUrl:', ws_url)
if not ws_url:
print('No webSocketDebuggerUrl for target')
return
try:
# Some Chromium builds require an Origin header to avoid 403 during the websocket handshake
try:
ws = websocket.create_connection(ws_url, timeout=5, header=["Origin: http://127.0.0.1"])
except TypeError:
# older websocket-client accepts origin kw instead
ws = websocket.create_connection(ws_url, timeout=5, origin="http://127.0.0.1")
except Exception as e:
print('ERROR: could not open websocket to', ws_url, '->', e)
return
idn = 1
# Enable runtime
msg = {'id': idn, 'method': 'Runtime.enable'}
ws.send(json.dumps(msg))
idn += 1
try:
print('Runtime.enable =>', ws.recv())
except Exception as e:
print('No response to Runtime.enable:', e)
# Evaluate a script that logs and returns a value
script = "console.log('cdp-test-log'); 12345"
msg = {'id': idn, 'method': 'Runtime.evaluate', 'params': {'expression': script, 'returnByValue': True}}
ws.send(json.dumps(msg))
idn += 1
try:
resp = ws.recv()
print('Runtime.evaluate =>', resp)
except Exception as e:
print('No response to Runtime.evaluate:', e)
ws.close()
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env python3
# scripts/test_cdp_origins.py
# Tries several Origin headers when connecting to Chromium DevTools websocket
import requests, websocket, json, sys, time
def try_origin(ws_url, origin_header):
try:
# websocket-client accepts header=[...] or origin=... depending on version
try:
ws = websocket.create_connection(ws_url, timeout=5, header=[f"Origin: {origin_header}"])
except TypeError:
ws = websocket.create_connection(ws_url, timeout=5, origin=origin_header)
return True, "connected"
except Exception as e:
return False, str(e)
def main():
try:
tabs = requests.get('http://127.0.0.1:9222/json', timeout=3).json()
except Exception as e:
print("ERROR: could not fetch DevTools json:", e)
return
if not tabs:
print("No DevTools targets found")
return
target = tabs[0]
ws_url = target.get('webSocketDebuggerUrl')
print("Using target url:", target.get('url'))
print("DevTools websocket:", ws_url)
if not ws_url:
print("No webSocketDebuggerUrl found in target")
return
# candidate origins to try
candidates = [
"http://127.0.0.1",
"http://localhost",
"https://www.computerbase.de", # page origin (use the exact scheme + host of the page)
"https://computerbase.de",
"null",
"chrome-devtools://devtools",
""
]
print("\nTrying origins (may need to match page origin exactly):")
for orig in candidates:
ok, msg = try_origin(ws_url, orig)
print(f"Origin={repr(orig):30} -> {ok} : {msg}")
# If one of them connected, try to send a Runtime.evaluate to confirm:
# (try the first that succeeded)
for orig in candidates:
try:
try:
ws = websocket.create_connection(ws_url, timeout=5, header=[f"Origin: {orig}"])
except TypeError:
ws = websocket.create_connection(ws_url, timeout=5, origin=orig)
print("\nConnected with origin:", orig)
msg_id = 1
payload = {"id": msg_id, "method": "Runtime.enable"}
ws.send(json.dumps(payload))
print("Runtime.enable ->", ws.recv())
msg_id += 1
payload = {"id": msg_id, "method": "Runtime.evaluate", "params": {"expression": "1+2", "returnByValue": True}}
ws.send(json.dumps(payload))
print("Runtime.evaluate ->", ws.recv())
ws.close()
break
except Exception as e:
# try next origin
continue
if __name__ == "__main__":
main()