Files
infoscreen/MQTT_EVENT_PAYLOAD_GUIDE.md
RobbStarkAustria 38800cec68 feat(video): add streamable video events & dashboard controls
Add end-to-end support for video events: server streaming, scheduler
metadata, API fields, and dashboard UI.

- Server: range-capable streaming endpoint with byte-range support.
- Scheduler: emits `video` object; best-effort HEAD probe adds
  `mime_type`, `size`, `accept_ranges`; placeholders for richer
  metadata (duration/resolution/bitrate/qualities/thumbnails).
- API/DB: accept and persist `event_media_id`, `autoplay`, `loop`,
  `volume` for video events.
- Frontend: Event modal supports video selection + playback options;
  FileManager increased upload size and client-side duration check
  (max 10 minutes).
- Docs/UX: bumped program-info, added UX-only changelog and updated
  Copilot instructions for contributors.
- Notes: metadata extraction (ffprobe), checksum persistence, and
  HLS/DASH transcoding are recommended follow-ups (separate changes).
2025-10-25 16:48:14 +00:00

8.5 KiB

MQTT Event Payload Guide

Overview

This document describes the MQTT message structure used by the Infoscreen system to deliver event information from the scheduler to display clients. It covers best practices, payload formats, and versioning strategies.

MQTT Topics

Event Distribution

  • Topic: infoscreen/events/{group_id}
  • Retained: Yes
  • Format: JSON array of event objects
  • Purpose: Delivers active events to client groups

Per-Client Configuration

  • Topic: infoscreen/{uuid}/group_id
  • Retained: Yes
  • Format: Integer (group ID)
  • Purpose: Assigns clients to groups

Message Structure

General Principles

  1. Type Safety: Always include event_type to allow clients to parse appropriately
  2. Backward Compatibility: Add new fields without removing old ones
  3. Extensibility: Use nested objects for event-type-specific data
  4. UTC Timestamps: All times in ISO 8601 format with timezone info

Base Event Structure

Every event includes these common fields:

{
  "id": 123,
  "title": "Event Title",
  "start": "2025-10-19T09:00:00+00:00",
  "end": "2025-10-19T09:30:00+00:00",
  "group_id": 1,
  "event_type": "presentation|website|webuntis|video|message|other",
  "recurrence_rule": "FREQ=WEEKLY;BYDAY=MO,WE,FR" or null,
  "recurrence_end": "2025-12-31T23:59:59+00:00" or null
}

Event Type-Specific Payloads

Presentation Events

{
  "id": 123,
  "event_type": "presentation",
  "title": "Morning Announcements",
  "start": "2025-10-19T09:00:00+00:00",
  "end": "2025-10-19T09:30:00+00:00",
  "group_id": 1,
  "presentation": {
    "type": "slideshow",
    "files": [
      {
        "name": "slides.pdf",
        "url": "http://server:8000/api/files/converted/abc123.pdf",
        "checksum": null,
        "size": null
      }
    ],
    "slide_interval": 10000,
    "auto_advance": true,
    "page_progress": true,
    "auto_progress": true
  }
}

Fields:

  • type: Always "slideshow" for presentations
  • files: Array of file objects with download URLs
  • slide_interval: Milliseconds between slides (default: 5000)
  • auto_advance: Whether to automatically advance slides
  • page_progress: Show page number indicator
  • auto_progress: Enable automatic progression

Website Events

{
  "id": 124,
  "event_type": "website",
  "title": "School Website",
  "start": "2025-10-19T09:00:00+00:00",
  "end": "2025-10-19T09:30:00+00:00",
  "group_id": 1,
  "website": {
    "type": "browser",
    "url": "https://example.com/page"
  }
}

Fields:

  • type: Always "browser" for website display
  • url: Full URL to display in embedded browser

WebUntis Events

{
  "id": 125,
  "event_type": "webuntis",
  "title": "Schedule Display",
  "start": "2025-10-19T09:00:00+00:00",
  "end": "2025-10-19T09:30:00+00:00",
  "group_id": 1,
  "website": {
    "type": "browser",
    "url": "https://webuntis.example.com/schedule"
  }
}

Note: WebUntis events use the same payload structure as website events. The URL is fetched from system settings (webuntis_url) rather than being specified per-event. Clients treat webuntis and website event types identically—both display a website.

Video Events

{
  "id": 126,
  "event_type": "video",
  "title": "Video Playback",
  "start": "2025-10-19T09:00:00+00:00",
  "end": "2025-10-19T09:30:00+00:00",
  "group_id": 1,
  "video": {
    "type": "media",
    "url": "http://server:8000/api/eventmedia/stream/123/video.mp4",
    "autoplay": true,
    "loop": false,
    "volume": 0.8
  }
}

Fields:

  • type: Always "media" for video playback
  • url: Video streaming URL with range request support
  • autoplay: Whether to start playing automatically (default: true)
  • loop: Whether to loop the video (default: false)
  • volume: Playback volume from 0.0 to 1.0 (default: 0.8)

Message Events (Future)

{
  "id": 127,
  "event_type": "message",
  "title": "Important Announcement",
  "start": "2025-10-19T09:00:00+00:00",
  "end": "2025-10-19T09:30:00+00:00",
  "group_id": 1,
  "message": {
    "type": "html",
    "content": "<h1>Important</h1><p>Message content</p>",
    "style": "default"
  }
}

Best Practices

1. Type-Based Parsing

Clients should:

  1. Read the event_type field first
  2. Switch/dispatch based on type
  3. Parse type-specific nested objects (presentation, website, etc.)
// Example client parsing
function parseEvent(event) {
  switch (event.event_type) {
    case 'presentation':
      return handlePresentation(event.presentation);
    case 'website':
    case 'webuntis':
      return handleWebsite(event.website);
    case 'video':
      return handleVideo(event.video);
    // ...
  }
}

2. Graceful Degradation

  • Always provide fallback values for optional fields
  • Validate URLs before attempting to load
  • Handle missing or malformed data gracefully

3. Performance Optimization

  • Cache downloaded presentation files
  • Use checksums to avoid re-downloading unchanged content
  • Preload resources before event start time

4. Time Handling

  • Always parse ISO 8601 timestamps with timezone awareness
  • Compare event start/end times in UTC
  • Account for clock drift on embedded devices

5. Error Recovery

  • Retry failed downloads with exponential backoff
  • Log errors but continue operation
  • Display fallback content if event data is invalid

Message Flow

  1. Scheduler queries active events from database
  2. Scheduler formats events with type-specific payloads
  3. Scheduler publishes JSON array to infoscreen/events/{group_id} (retained)
  4. Client receives retained message on connect
  5. Client parses events and schedules display
  6. Client downloads resources (presentations, etc.)
  7. Client displays events at scheduled times

Versioning Strategy

Adding New Event Types

  1. Add enum value to EventType in models/models.py
  2. Update scheduler's format_event_with_media() in scheduler/db_utils.py
  3. Update events API in server/routes/events.py
  4. Add icon mapping in get_icon_for_type()
  5. Document payload structure in this guide

Adding Fields to Existing Types

  • Safe: Add new optional fields to nested objects
  • Unsafe: Remove or rename existing fields
  • Migration: Provide both old and new field names during transition

Example: Adding a New Field

{
  "event_type": "presentation",
  "presentation": {
    "type": "slideshow",
    "files": [...],
    "slide_interval": 10000,
    "transition_effect": "fade"  // NEW FIELD (optional)
  }
}

Old clients ignore unknown fields; new clients use enhanced features.

Common Pitfalls

  1. Hardcoding Event Types: Use event_type field, not assumptions
  2. Timezone Confusion: Always use UTC internally
  3. Missing Error Handling: Network failures, malformed URLs, etc.
  4. Resource Leaks: Clean up downloaded files periodically
  5. Not Handling Recurrence: Events may repeat; check recurrence_rule

System Settings Integration

Some event types rely on system-wide settings rather than per-event configuration:

WebUntis / Supplement Table URL

  • Setting Key: supplement_table_url
  • API Endpoint: GET/POST /api/system-settings/supplement-table
  • Usage: Automatically applied when creating webuntis events
  • Default: Empty string (must be configured by admin)
  • Description: This URL is shared for both Vertretungsplan (supplement table) and WebUntis displays

Presentation Defaults

  • presentation_interval: Default slide interval (seconds)
  • presentation_page_progress: Show page indicators by default
  • presentation_auto_progress: Auto-advance by default

These are applied when creating new events but can be overridden per-event.

Testing Recommendations

  1. Unit Tests: Validate payload serialization/deserialization
  2. Integration Tests: Full scheduler → MQTT → client flow
  3. Edge Cases: Empty event lists, missing URLs, malformed data
  4. Performance Tests: Large file downloads, many events
  5. Time Tests: Events across midnight, timezone boundaries, DST
  • AUTH_SYSTEM.md - Authentication and authorization
  • DATABASE_GUIDE.md - Database schema and models
  • .github/copilot-instructions.md - System architecture overview
  • scheduler/scheduler.py - Event publishing implementation
  • scheduler/db_utils.py - Event formatting logic

Changelog

  • 2025-10-19: Initial documentation
    • Documented base event structure
    • Added presentation and website/webuntis payload formats
    • Established best practices and versioning strategy