Skip to content

KingKiosk MQTT Element Architecture Reference

This document describes the KingDSP-style MQTT architecture for KingKiosk.

Canonical control uses the same system vs element model at two scopes:

  1. Device scope, system-level - kingkiosk/{device_id}/system/cmd
  2. Device scope, element-level - kingkiosk/{device_id}/element/{element_id}/cmd
  3. Fleet scope, system-level - kingkiosk/fleet/{fleet_id}/cmd
  4. Fleet scope, element-level - kingkiosk/fleet/{fleet_id}/element/{element_id}/cmd

Legacy command ingress topic families (especially .../command and widget/window-scoped command paths) are deprecated. Some clients still subscribe for backward compatibility, but behavior is not guaranteed cross-platform. Use canonical system/cmd and element/{id}/cmd for stable automation.

Admin UI Contract (Definitive)

If you are building or rewriting the King Admin interface, treat the following as the stable MQTT API contract:

  • Ingress (commands)
  • Device/system: kingkiosk/{device_id}/system/cmd
  • Element-scoped: kingkiosk/{device_id}/element/{element_id}/cmd (first routed to registered element handlers, then unified dispatcher fallback when applicable)
  • Fleet/system broadcast: kingkiosk/fleet/{fleet_id}/cmd
  • Fleet/element broadcast: kingkiosk/fleet/{fleet_id}/element/{element_id}/cmd
  • Egress (responses)
  • System responses: kingkiosk/{device_id}/system/response
  • Element responses: kingkiosk/{device_id}/element/{element_id}/response
  • State & events (for UI rendering)
  • Device capabilities: kingkiosk/{device_id}/info (retained)
  • Device communications events: kingkiosk/{device_id}/communications/event (non-retained)
  • Element state: kingkiosk/{device_id}/element/{element_id}/state (retained)
  • Element events: kingkiosk/{device_id}/element/{element_id}/event (non-retained)

Rules:

  • Prefer canonical topics; do not rely on legacy command-ingress families (.../command, widget/window-scoped command topics) for new integrations.
  • For any command, if response_topic is omitted, the app will default to the canonical system/element response topic based on the ingress topic.
  • For “full coverage” control surfaces (create windows, move/resize, tiling, etc.), rely on the System Commands section (system/cmd). Treat element commands as widget-specific enhancements.
  • Fleet topics are command ingress only; each receiving device publishes responses on its own canonical response topics.
  • For fleet element broadcasts, {element_id} is taken from the topic path and is authoritative.

Table of Contents

  1. Overview
  2. Platform Compatibility Matrix
  3. Topic Structure
  4. Element Commands
  5. Element State
  6. Element Events
  7. System Commands
  8. Device Info
  9. Signed Envelope Format
  10. Widget Type Reference
  11. Integration Examples

Platform Compatibility Matrix

KingKiosk runs on 8 platforms. Most widgets are available natively on every platform. Widgets marked FS require the Feature Server (KingKiosk Core) which provides server-side Chromium rendering streamed over WebRTC.

Widget / Feature Availability

Widget / Feature Android iOS macOS Windows Linux Raspberry Pi 4/5 tvOS Web
Web Browser FS FS
YouTube Player FS FS
Custom Widget SDK FS FS
Clock
Weather
Calendar
Gauge
Chart (line, bar, pie)
Carousel
Media Player (video/audio)
RTSP Camera
Image / MQTT Image
Map
Alarmo (alarm panel)
MQTT Button
Timer
Audio Visualizer
DLNA Player
Animated Text
Canvas
Video Conference FS FS FS FS FS FS FS FS (HTTPS)
Audio Call (SIP) FS FS FS FS FS FS FS FS (HTTPS)

Capabilities by Platform

Capability Android iOS macOS Windows Linux Raspberry Pi 4/5 tvOS Web
Kiosk Mode ✅ Full ✅ Guided Access ⚠️ Best-effort ⚠️ Best-effort ⚠️ Best-effort
Intercom / WebRTC FS ⚠️ HTTPS only
TTS ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS
Person Detection ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS FS FS
Object Detection ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS FS FS
Facial Detection & Recognition ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS FS FS
Motion Detection ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS ✅ +FS FS FS
Camera / Mic Input ⚠️ Continuity Camera ⚠️ HTTPS only
DLNA Renderer
Screen Brightness
Screenshot Capture
Home Assistant Discovery
OS Home Screen Widgets ✅ (iOS 17+)

Legend: - ✅ = Supported natively - ✅ +FS = Native on-device support; Feature Server enhances with higher-quality server-side processing (e.g., Piper TTS, GPU-accelerated detection) - FS = Requires Feature Server (KingKiosk Core) - ⚠️ = Partial or conditional support (see notes) - — = Not available on this platform

Platform Notes: - tvOS — Continuity Camera: Requires Apple TV 4K (2nd generation or later) paired with an iPhone or iPad running iOS 17+. The iOS device provides the camera and microphone feed to the Apple TV over AirPlay. - iOS — OS Home Screen Widgets: Requires iOS 17 or later for interactive widget support (App Intents). - Web: Camera, microphone, and intercom features require a secure context (HTTPS).


Overview

The architecture has one command model (system vs element) at two scopes (device vs fleet):

  1. Device scope
  2. System commands: control the whole device (.../system/cmd)
  3. Element commands: control one element/window (.../element/{element_id}/cmd)
  4. Fleet scope
  5. System commands: fan out one command to all subscribed devices (.../fleet/{fleet_id}/cmd)
  6. Element commands: fan out one command to the same element id on all subscribed devices (.../fleet/{fleet_id}/element/{element_id}/cmd)

Key Benefits

  • Granular control: Send commands directly to a specific element
  • Fleet fan-out: Broadcast one system or element command to all subscribed devices
  • Automatic state publishing: Registered elements can publish their state automatically
  • Event streaming: Real-time events from registered elements (errors, state changes)
  • Device discovery: Retained info topic for capabilities discovery
  • Signed envelopes: Optional HMAC signing for secure command delivery

Implementation Status (Current)

  • The app subscribes to canonical element topics. Only widgets/controllers that explicitly register will receive element-level commands via the registration-based router.
  • Registration is done via MqttWidgetMixin (implementation detail).
  • Unregistered elements are handled via the unified dispatcher (window/tiling/etc.) when applicable.
  • kingkiosk/{device_id}/system/cmd is accepted by the app and is routed to the unified dispatcher when no explicit system handler is registered.
  • Fleet subscriptions are opt-in via subscribe_fleet; devices can subscribe to layout (.../layout), fleet system commands (.../cmd), and fleet element commands (.../element/+/cmd).
  • Some clients also subscribe to legacy kingkiosk/{device_id}/window/+/command for backward compatibility. Treat this as deprecated and use system/cmd for stable behavior. Calendar bidirectional sync details: see docs/CALENDAR_MQTT_SYNC.md.

Feature Server Autodiscovery

KingKiosk clients support automatic discovery of the Feature Server (KingKiosk Core3) via MQTT. This eliminates the need for manual server URL configuration across multiple devices.

Discovery Topic

Topic: kingkiosk/core3/api (retained)

Payload Format:

{
  "api_url": "http://192.168.1.100:3000",
  "version": "3.2.1"
}

Fields: - api_url (string, required): Full HTTP/HTTPS URL to the Feature Server API endpoint - version (string, optional): Server version string for compatibility checking

Client Behavior

When a KingKiosk client receives a message on kingkiosk/core3/api:

  1. Parse and validate the api_url field
  2. Normalize the host (extract base URL from api_url if needed)
  3. Check manual override - If user has enabled "manual override lock", ignore the autodiscovered value
  4. Update server URL - If not locked, automatically update the Feature Server connection to use the new URL
  5. Connect - Attempt connection to the autodiscovered server

Manual Override Lock

Users can enable "manual override lock" in settings to prevent autodiscovery from changing their manually configured server URL. This is useful for: - Testing against a specific server instance - Using a non-production server - Temporarily isolating a device from the main server

When manual override is enabled, the client: - Still subscribes to kingkiosk/core3/api - Logs incoming discovery messages (for debugging) - Does NOT update the server URL or reconnect

Server Implementation

The Feature Server (KingKiosk Core3) should: 1. Publish on startup to kingkiosk/core3/api with retain: true 2. Include full URL in api_url (e.g., http://192.168.1.100:3000) 3. Re-publish on config change if the server URL changes

Example: Server Announcement

mosquitto_pub -h broker.local -t "kingkiosk/core3/api" -r -m '{
  "api_url": "http://192.168.1.100:3000",
  "version": "3.2.1"
}'

Native OS Widgets

KingKiosk supports creating native home screen widgets (Android) and home/lock screen widgets (iOS) that update via MQTT independently of the main app. This is achieved by adding the os_widget: true parameter to supported widget creation commands.

Supported Widget Types

Widget Kind iOS Support Android Support Notes
gauge Radial, linear, and thermometer styles
chart Line charts with sparkline view
weather Current conditions + forecast
alarmo Security system status and controls
mqttButton ✅ (iOS 17+) Toggle buttons with state feedback
sensor Simple numeric value display
counter Numeric counter display
clock Current time (no MQTT needed)
canvas Snapshot-based visual diagrams

Architecture

Data Flow:

MQTT Broker
┌───────────────────────────────────┐
│  KingKiosk App (Flutter)          │
│  • MqttOsWidgetMixin              │ ← Intercepts widget creation
│  • WidgetDataService              │ ← Writes to shared storage
│  • WidgetConfig serialization     │
└───────────────────────────────────┘
    ↓ (App Group shared storage)
┌───────────────────────────────────┐
│  Native Widget Extension          │
│  • iOS: WidgetKit                 │
│  • Android: Glance/AppWidget      │
│  • LightMQTTClient (WebSocket)    │ ← Connects to MQTT independently
│  • Reads WidgetConfig from shared │
│  • Subscribes to configured topic │
│  • Renders natively               │
└───────────────────────────────────┘

Storage Structure: - Widget configs: Stored in shared storage at key kk_widget_{widgetId} as JSON - Cached values: Stored at key kk_cache_{widgetId} with value + history - MQTT config: Stored at key kk_mqtt_config with broker connection info - Registered IDs: List stored at key kk_registered_widget_ids

Creating an OS Widget

Add the os_widget: true parameter to any supported widget creation command. The widget will be created both in-app (optional) and registered as a native OS widget.

Example: Gauge Widget

Topic: kingkiosk/{device_id}/system/cmd

Payload:

{
  "command": "create_gauge",
  "window_id": "temp_sensor_1",
  "gauge_type": "radial",
  "title": "Living Room",
  "min": 50,
  "max": 90,
  "unit": "°F",
  "mqtt_topic": "homeassistant/sensor/living_room_temp/state",
  "json_field": "temperature",
  "os_widget": true,
  "thresholds": [
    {"value": 70, "color": "#4CAF50"},
    {"value": 75, "color": "#FFC107"},
    {"value": 80, "color": "#F44336"}
  ]
}

What Happens: 1. MqttOsWidgetMixin intercepts the command 2. Extracts a WidgetConfig from the payload 3. Calls WidgetDataService.registerOsWidget(config) 4. Widget config is written to shared storage as JSON 5. Native widget extension reads the config on its next timeline refresh 6. Widget appears in the device's widget picker (user adds it to home screen) 7. Widget independently subscribes to the MQTT topic and updates

Example: MQTT Button Widget

Topic: kingkiosk/{device_id}/system/cmd

Payload:

{
  "command": "mqtt_button",
  "action": "configure",
  "window_id": "porch_light_btn",
  "mode": "toggle",
  "label": "Porch Light",
  "publish_topic": "zigbee2mqtt/porch_light/set",
  "publish_payload": "{\"state\": \"TOGGLE\"}",
  "subscribe_topic": "zigbee2mqtt/porch_light",
  "status_path": "state",
  "icon": "light_bulb",
  "icon_off": "light_bulb_outline",
  "color_on": "0xFFFFC107",
  "color_off": "0xFF757575",
  "os_widget": true
}

Interaction Flow: 1. User adds button widget to home screen 2. Widget displays current state by subscribing to zigbee2mqtt/porch_light 3. User taps button on home screen 4. Widget publishes to zigbee2mqtt/porch_light/set with payload 5. Widget receives updated state from subscription topic 6. Button color/icon updates to reflect new state

Example: Alarmo Security Widget

Topic: kingkiosk/{device_id}/system/cmd

Payload:

{
  "command": "alarmo_widget",
  "window_id": "home_security",
  "mqtt_base_topic": "alarmo",
  "available_modes": ["armed_away", "armed_home", "armed_night", "disarmed"],
  "require_code": true,
  "code_length": 4,
  "os_widget": true
}

Widget Update Mechanisms

Native OS widgets update via two mechanisms:

  1. Direct MQTT subscription (primary)
  2. Widget extension connects to MQTT broker using LightMQTTClient
  3. Subscribes to the topic specified in WidgetConfig.mqttTopic
  4. Updates immediately when messages arrive
  5. Frequency limited by OS (iOS: ~15-60min, Android: configurable)

  6. Cached value fallback (secondary)

  7. Main app writes latest values to shared storage via WidgetDataService.writeCachedValue()
  8. Widget reads cached value on timeline refresh
  9. Provides instant display even if MQTT connection fails
  10. Maintains 48-point history for sparkline charts

Widget Lifecycle

Registration:

// In MQTT command handler (after creating Flutter widget):
maybeCreateOsWidget(payload, WidgetKind.gauge);

Updates:

// When widget value changes:
maybeUpdateOsWidgetValue(windowId, value, stringValue: "72°F");

Removal:

// When widget is closed:
maybeRemoveOsWidget(windowId);

Or via MQTT:

{
  "command": "close_window",
  "window_id": "temp_sensor_1"
}

MQTT Config for Widget Extensions

Widget extensions require MQTT connection credentials to operate independently. These are written to shared storage via WidgetDataService.writeMqttConfig() when the main app connects to MQTT.

Config Structure (stored at kk_mqtt_config):

{
  "wsUrl": "wss://broker.local:8884/mqtt",
  "host": "broker.local",
  "port": 1883,
  "username": "kingkiosk",
  "password": "secret",
  "useTLS": true,
  "allowSelfSigned": true,
  "hmacEnabled": false,
  "hmacSecret": "",
  "deviceName": "kitchen_tablet"
}

Important: Widget extensions use WebSocket MQTT connections, not TCP: - Secure: wss:// on port 8884 (not 8883) - Insecure: ws:// on port 1884 (not 1883)

Platform-Specific Implementation

iOS (WidgetKit)

  • App Group: group.com.ki.kingkiosk
  • Widget Kinds: KingKioskGaugeWidget, KingKioskChartWidget, etc.
  • Refresh Policy: Timeline-based, OS-controlled (15-60 min typical)
  • Interactive Widgets: Supported on iOS 17+ via App Intents
  • Storage: UserDefaults with app group suite

Android (Glance/AppWidget)

  • Widget Receivers: GaugeWidgetReceiver, ChartWidgetReceiver, etc.
  • Package: com.ki.king_kiosk.widgets.receivers
  • Refresh Policy: Configurable update intervals
  • Interactive Widgets: Full click handler support
  • Storage: SharedPreferences with process name

Debugging

Check registered widgets:

final service = Get.find<WidgetDataService>();
print(service.registeredWidgetIds); // Set<String>

Verify widget config in shared storage:

final configJson = await HomeWidget.getWidgetData<String>('kk_widget_temp_sensor_1');
final config = WidgetConfig.fromJsonString(configJson);
print(config.toJson());

Check cached value:

final cacheJson = await HomeWidget.getWidgetData<String>('kk_cache_temp_sensor_1');
final cache = jsonDecode(cacheJson);
print(cache['currentValue']); // Latest value
print(cache['dataPoints']); // History (up to 48 points)


Topic Structure

Command Topics (Subscribe)

Topic Description
kingkiosk/{device_id}/system/cmd New system-level commands
kingkiosk/{device_id}/element/{element_id}/cmd Canonical per-element commands
kingkiosk/fleet/{fleet_id}/cmd Fleet system command bus (fan-out to subscribed devices)
kingkiosk/fleet/{fleet_id}/element/{element_id}/cmd Fleet element command bus (topic-addressed element fan-out)
kingkiosk/fleet/{fleet_id}/element/+/cmd Fleet element subscription filter used by subscribe_fleet
kingkiosk/{device_id}/window/{window_id}/command Legacy compatibility path (deprecated; prefer system/cmd)

State/Event Topics (Publish)

Topic Retained Description
kingkiosk/{device_id}/info Yes Device capabilities and active widgets
kingkiosk/{device_id}/status Yes Online/offline status (LWT)
kingkiosk/{device_id}/system/state Yes System state (tiling mode, screen info)
kingkiosk/{device_id}/feature_server/state Yes Feature Server connection/settings state snapshot (enabled, connected, reconnecting, URL, errors).
kingkiosk/{device_id}/element/{element_id}/state Yes Element state
kingkiosk/{device_id}/element/{element_id}/event No Element events
kingkiosk/{device_id}/element/{element_id}/response No Element command response (includes correlation_id; generated when omitted)
kingkiosk/{device_id}/system/response No System command response
kingkiosk/fleet/{fleet_id}/layout Optional (retain on publish) Shared fleet layout bus used by replicate_layout and subscribe_fleet

Notes: - Fleet command topics (.../fleet/{fleet_id}/cmd and .../fleet/{fleet_id}/element/{element_id}/cmd) are ingress channels. - Responses for fleet-delivered commands still publish per device on canonical system/element response topics unless an allowed response_topic override is used.


Element Commands

Send commands directly to a specific element using its element_id.

Topic Format

kingkiosk/{device_id}/element/{element_id}/cmd

Command Payload Format

{
  "command": "command_name",
  "correlation_id": "optional-tracking-id",
  ...additional parameters...
}

Notes

  • Element-scoped commands are first offered to registered element handlers (MqttWidgetRouter.registerWidget(...)); when no handler is registered, the unified dispatcher fallback may still process compatible commands.
  • Per-element command schemas are widget-specific. This document treats system commands as the stable contract; element commands should be considered optional unless explicitly documented for a given widget.
  • Window geometry/stacking is controlled via system commands on kingkiosk/{device_id}/system/cmd (e.g. move_window, resize_window, set_opacity, maximize_window, etc.).

Example: Send command to a clock element

Topic: kingkiosk/my-device/element/clock-1/cmd

Payload:

{
  "command": "set_mode",
  "mode": "digital",
  "correlation_id": "req-12345"
}

Response (on kingkiosk/my-device/element/clock-1/response):

{
  "status": "success",
  "mode": "digital",
  "correlation_id": "req-12345",
  "widget_id": "clock-1"
}


Element State

Each registered element automatically publishes its state when: - Element is created/registered - After any command is processed - When publishState() is called programmatically

Topic Format

kingkiosk/{device_id}/element/{element_id}/state

State Payload Example (Clock Widget)

{
  "type": "clock",
  "element_id": "clock-1",
  "widget_id": "clock-1",
  "mode": "analog",
  "visible": true,
  "minimized": false,
  "show_numbers": true,
  "show_second_hand": true,
  "theme": "auto",
  "background_mode": "transparent",
  "background_opacity": 0.6
}

Element Events

Registered elements publish non-retained events for real-time notifications.

Topic Format

kingkiosk/{device_id}/element/{element_id}/event

Event Types

Event Description Additional Fields
created Widget was created type
closed Widget was closed type
error Error occurred message, code (optional)
state_changed State transition from, to
clicked User interaction x, y (optional)
ended Playback ended -

Event Payload Example

{
  "event": "error",
  "message": "Stream disconnected",
  "code": "STREAM_TIMEOUT",
  "element_id": "video-1",
  "widget_id": "video-1",
  "timestamp": "2024-12-19T10:30:00.000Z"
}

System Commands

System-level commands control the device as a whole.

Topic Format

kingkiosk/{device_id}/system/cmd

Supported System Commands

System commands sent to kingkiosk/{device_id}/system/cmd are routed through the unified command dispatcher.

This section lists the actual system command strings that are wired up in the current dispatcher. Detailed parameters for the non-window system commands are documented in the code-derived section System (Non-Window) Commands.

Common notes:

  • Many handlers support response_topic to control where results are published.
  • Unless noted otherwise, response_topic defaults to kingkiosk/{device_id}/system/response.
  • Widget creation commands can include os_widget: true to also register the widget as a native OS widget (home screen widget on Android, home/lock screen widget on iOS). See Native OS Widgets section for details.

Core system command families:

Category Commands
Volume set_volume, mute, unmute
Brightness set_brightness, get_brightness, restore_brightness, request_brightness_permission, check_brightness_permission, resume_kiosk_after_permission
Notifications alert, notify
Halo halo_effect
Screensaver screensaver, screen_saver
Settings / FAB lock lock_fab, unlock_fab, lock_settings, unlock_settings
Person detection person_detection
Screenshot screenshot
Cache cache, cache_control, clear_cache
TTS tts, speak, say
STT stt, speech_to_text, listen
Background set_background, get_background
Provisioning provision, get_config
Telemetry set_telemetry, get_telemetry
AI ai_agent, ai, provision_ai_chatbot, setup_ai_chatbot, configure_ai_chatbot
Batch / scripting batch, kill_batch_script, batch_status, wait
Fleet management replicate_layout, subscribe_fleet, unsubscribe_fleet, broadcast_fleet_command, publish_fleet_command
Screen schedule set_screen_schedule, list_screen_schedule, enable_screen_schedule, disable_screen_schedule, screen_schedule_status, trigger_screen_schedule
Conflict resolution conflict_resolution
MQTT button mqtt_button, mqtt_action_status, action_status

Example: Create a clock via system command

Topic: kingkiosk/my-device/system/cmd

Payload:

{
  "command": "open_clock",
  "window_id": "clock-living-room",
  "name": "Living Room Clock",
  "mode": "analog",
  "show_numbers": true,
  "theme": "dark",
  "x": 100,
  "y": 100,
  "width": 300,
  "height": 300
}


Device Info

The device info topic provides discovery information about the device's capabilities and current state.

Topic Format

kingkiosk/{device_id}/info

Info Payload

{
  "device_id": "my-device",
  "version": "2.1.0",
  "platform": "macos",
  "app_start_timestamp": "2024-12-19T10:00:00.000Z",
  "capabilities": {
    "webview": true,
    "video": true,
    "rtsp": true,
    "webrtc": true,
    "audio": true,
    "visualizer": true,
    "tts": true,
    "stt": true,
    "camera": true,
    "microphone": true,
    "facial_recognition": true,
    "person_detection": true,
    "dlna_renderer": true,
    "screen_share": true
  },
  "widget_types": [
    "webview", "video", "audio", "rtsp", "webrtc",
    "image", "mqtt_image", "map", "visualizer", "gauge",
    "line_chart", "bar_chart", "pie_chart", "carousel",
    "clock", "weather", "calendar", "alarmo",
    "mqtt_button", "timer", "dlna_player", "video_call"
  ],
  "active_widgets": ["clock-1"],
  "widget_count": 1,
  "tiling_mode": "floating",
  "hmac_signing": false,
  "timestamp": "2024-12-19T10:30:00.000Z"
}

Notes: - tiling_mode is currently a placeholder value in the info payload. - active_widgets includes only widgets that have registered with the per-widget router. - timestamp is the time this info payload was published (it may be refreshed during the app run). - app_start_timestamp stays constant for the lifetime of the running app process.


Signed Envelope Format

For secure command delivery, commands can be wrapped in a signed envelope using HMAC-SHA256.

Envelope Format

{
  "ts": 1703001234,
  "msg": "{\"command\":\"play\"}",
  "sig": "a1b2c3d4e5f6..."
}

Signature Computation

sig = hex(HMAC-SHA256(secret, "topic\ntimestamp\nmsg"))

Where: - topic = the full MQTT topic the message is published to - timestamp = the ts value (Unix seconds) as a string - msg = the JSON-encoded message string

Important: - Signed envelopes are topic-aware: the signature depends on the full MQTT topic the message is published to. - If useSignedEnvelopes is enabled and a shared secret is configured, the app enforces verification for inbound signed envelopes. - Invalid signatures or invalid/expired timestamps are rejected (the command is ignored). - If signing is disabled or no secret is configured, the app will still unwrap the envelope for compatibility. - The envelope timestamp used by the implementation is Unix seconds.

Example (Python)

import hmac
import hashlib
import json
import time

def create_signed_envelope(topic, message, secret):
  ts = int(time.time())
  msg = json.dumps(message, separators=(',', ':'))

  sig_data = f"{topic}\n{ts}\n{msg}"
  sig = hmac.new(
    secret.encode(),
    sig_data.encode(),
    hashlib.sha256
  ).hexdigest()

  return {
    "ts": ts,
    "msg": msg,
    "sig": sig
  }

Widget Type Reference

This section is code-derived: it documents the JSON keys that are actually parsed/used by the current implementation.

There are three relevant command planes:

  1. System commands: publish to kingkiosk/{device_id}/system/cmd. These create windows/tiles and perform global actions.
  2. Element-scoped commands: publish to kingkiosk/{device_id}/element/{element_id}/cmd. Registered element handlers process these first; compatible commands may still be handled by dispatcher fallback.

Common Window Geometry Keys

Most “create/open” commands accept the following top-level keys:

Key Type Notes
window_id string Optional. If omitted, an ID may be auto-generated by the tile creator.
title / name string Widget title/name (varies by command).
x, y number Optional position in pixels.
width, height number Optional size in pixels.
opacity number Optional. Defaults to 1.0.

Many commands also accept:

Key Type Notes
response_topic string Optional. If omitted, the app defaults to kingkiosk/{device_id}/system/response for system commands, or kingkiosk/{device_id}/element/{element_id}/response for element commands.

Shared Window Surface Contract

All widget windows now share a root surface contract. This controls the outer window shell for the widget. It is separate from any visual background the widget may draw inside its own content.

Preferred syntax for create/open commands:

Key Type Default Notes
surface.appearance_mode string - Convenience preset: transparent, translucent, or opaque. Applies shared window-shell defaults and, for participating widgets, suppresses or seeds the widget's base background.
surface.background_mode string - transparent, color, gradient, or image.
surface.background_color string - Hex color for color/gradient modes. Accepts #RRGGBB or #AARRGGBB.
surface.background_image_url string - URL used when background_mode: image.
surface.background_opacity number 1.0 Background layer opacity only. Does not fade the widget content.
surface.preserve_aspect_ratio bool true Used by the built-in floating resize handle.
surface.scale_content bool widget-dependent Scales the whole widget content as a single unit to keep text, labels, and graphics in proportion.
surface.design_width number tile width at creation Optional design-space width used when scale_content is enabled.
surface.design_height number tile height at creation Optional design-space height used when scale_content is enabled.

Equivalent top-level aliases are also accepted by the shared window layer:

Alias Key Equivalent Surface Key
appearance_mode, appearanceMode surface.appearance_mode
window_appearance_mode, windowAppearanceMode surface.appearance_mode
window_background_mode, windowBackgroundMode surface.background_mode
window_background_color, windowBackgroundColor surface.background_color
window_background_image_url, windowBackgroundImageUrl surface.background_image_url
window_background_opacity, windowBackgroundOpacity surface.background_opacity
window_preserve_aspect_ratio, windowPreserveAspectRatio surface.preserve_aspect_ratio
window_scale_content, windowScaleContent surface.scale_content
window_design_width, windowDesignWidth surface.design_width
window_design_height, windowDesignHeight surface.design_height

Behavior notes:

  • appearance_mode is a preset layer. Explicit surface.background_*, window_background_*, or widget-specific background_* keys override it.
  • transparent removes the shared shell background and asks participating widgets to suppress their default base background too.
  • translucent applies a semi-transparent dark shell/background preset without fading the widget content itself.
  • opaque applies a solid dark shell/background preset.
  • opacity still controls the entire window, including the widget content. background_opacity only controls the shared background layer.
  • preserve_aspect_ratio defaults to true.
  • scale_content defaults to true for most native Flutter widgets. It defaults to false for platform-view and texture-heavy windows such as browser, media, YouTube, PDF, remote browser, and call surfaces, because forced transforms can break rendering there.
  • design_width and design_height let you choose the design size used by proportional scaling instead of using the tile's creation size.
  • Some widgets already had their own internal background model, including clock, carousel, canvas, animatedText, and rss. Their top-level background_* keys still style the widget itself. appearance_mode now seeds those widget backgrounds too when explicit widget background keys are not set. Use surface or the window_* aliases when you want exact outer-shell control.
  • For widgets that did not already have widget-managed backgrounds, legacy top-level background_* keys are also accepted as shared window-surface aliases for backward compatibility.

Example:

{
  "command": "create_gauge",
  "window_id": "power-main",
  "gauge_id": "power-main",
  "appearance_mode": "translucent",
  "surface": {
    "preserve_aspect_ratio": true,
    "scale_content": true,
    "design_width": 320,
    "design_height": 320
  }
}

Transparent preset example:

{
  "command": "alarmo_widget",
  "window_id": "alarm-panel",
  "appearance_mode": "transparent",
  "opacity": 1.0
}

System (Window/Layout) Commands

These are system-level window/layout commands handled by the main dispatcher. Send them on kingkiosk/{device_id}/system/cmd.

Unless explicitly stated, these commands use the payload key command to select the handler.

Window Management (close_window, maximize_window, minimize_window, bring_to_front, send_to_back)

Accepted command strings:

  • Close: close_window
  • Maximize: maximize_window
  • Minimize: minimize_window
  • Bring to front: bring_to_front (aliases: bring_front, to_front)
  • Send to back: send_to_back (aliases: send_back, to_back)

Top-level keys:

Key Type Default Notes
command string (required) One of the management commands above.
window_id string (required) ID of the tile/window to act on.
response_topic string kingkiosk/{device}/system/response Publishes {success, command, window_id, timestamp} or {success:false, error, ...}.

Close All Windows (close_all_windows)

Top-level keys:

Key Type Default Notes
command string (required) Must be close_all_windows.
response_topic string kingkiosk/{device}/system/response Publishes {success:true, closed_count, ...}.

Notes:

  • After closing tiles, it attempts to stop background audio (best-effort; errors are logged but do not fail the command).

Window Mode (window_mode, set_window_mode)

Top-level keys:

Key Type Default Notes
command string (required) window_mode or set_window_mode.
mode string (required) tiling/tile, floating/float, or toggle.

Notes:

  • The window-mode handler itself logs state changes; the unified system router still returns a command response on the system response topic.

Update Window Geometry (update_window, move_window, resize_window)

Top-level keys:

Key Type Default Notes
command string (required) update_window, move_window, or resize_window (all route to the same handler).
window_id string (required) Target tile/window ID.
x, y number - If both present, updates position.
width, height number - If both present, updates size.
showBorder / show_border bool - If provided, shows or hides the shared thin white window border for that tile.

Notes:

  • If neither a complete (x,y) pair nor a complete (width,height) pair is provided, the command is ignored (logged as missing parameters).
  • Values for x, y, width, and height are interpreted as physical pixels and are internally converted to logical pixels by dividing by the device pixel ratio.
  • The geometry handler logs updates directly; the unified system router still returns a command response on the system response topic.
  • resize_window applies the width and height you send. If the widget has scale_content: true, its content still scales proportionally inside the resulting rectangle. The built-in drag resize handle also honors preserve_aspect_ratio: true by default.

Shared Window Border (showBorder, show_border)

All windowed widget creation commands accept showBorder (camelCase preferred) and show_border (legacy alias) for the shared thin white window outline.

  • Default: false
  • Use showBorder: true to render the border.
  • Use update_window with window_id plus showBorder: true/false to change an existing window.
  • On creation commands, the same flag is also honored when passed inside surface, config, or metadata.

Widget Convenience (show_widget, hide_widget)

Top-level keys:

Key Type Default Notes
command string (required) show_widget or hide_widget.
type string (required) For show_widget: clock, weather, calendar, music, photos, finance, fitness, news (others are ignored). For hide_widget: use all to close all tiles, or any string to match by tile name.
style string - Only applied for clock/weather (stored in the created tile config).
ai_enhanced bool false Only applied for clock/weather (stored in config).

Notes:

  • These handlers log actions directly; the unified system router still returns a command response on the system response topic.
  • hide_widget closes the most recently created tile whose name contains type (case-insensitive), unless type == all.

DLNA Player (dlna_player, open_dlna_player)

This widget reflects and controls the built-in DLNA/UPnP renderer. It now supports audio, video, and images (and will classify content based on DIDL-Lite metadata and/or URI).

Top-level keys:

Key Type Default Notes
command string (required) dlna_player or alias open_dlna_player.
name string DLNA Player Tile title.
window_id string (auto) If provided, used as tile ID.
opacity, x, y, width, height number - Optional geometry.
response_topic string kingkiosk/{device}/system/response Publishes {success, command:'dlna_player', window_id, name, timestamp} or error payload.

Note:

  • When window_id is omitted, the handler publishes a generated ID in the response (dlna_{timestamp}), which may not match the actual auto-generated tile ID used by the controller.

Remote Browser (create_remote_browser, add_remote_browser)

This widget provides a thin-client browser experience by streaming a server-rendered Chromium browser over WebRTC through the Feature Server. Designed primarily for tvOS (Apple TV) and iOS devices where local browser rendering is limited.

Architecture: - Server runs a Browser Producer Agent (BPA) with Chromium + Puppeteer - Media is routed through the Feature Server SFU pipeline (H.264 video + Opus audio) - Client connects to the Feature Server/Core (SignalingService) via WebSocket - Control input (pointer, keyboard, navigation) is sent via DataChannel (SCTP) - Telemetry (URL changes, load state, stats) is received via DataChannel - Sessions can be created client-side (when session_id is omitted) or joined (when session_id + join token are provided)

Prerequisites: - Feature Server must be enabled and connected in Settings > Networked Audio - The Feature Server/Core WebSocket must be reachable (typically ws://<host>:4000/ws) - To join an existing session, server_url must include ?token=<consumerJoinToken> (required for transport.*, consume, dataproducer.*, etc.) - If session_id is omitted, the client will call session.create, receive a join token, reconnect with ?token=..., and then publish the resolved session_id + tokenized server_url in widget state - Newly created sessions can stay in CREATING briefly while BPA/Chromium starts; clients will retry session.join until the session becomes READY/RUNNING (or time out)

Top-level keys for create_remote_browser / add_remote_browser:

Key Type Default Notes
command string (required) create_remote_browser or add_remote_browser.
window_id string (required) Unique ID for this browser tile.
name string Remote Browser Tile title.
server_url string (Settings) Feature Server/Core WebSocket URL (e.g. ws://192.168.0.114:4000/ws). If session_id is provided, must include ?token=....
initial_url string about:blank URL to load when session starts.
session_id string (optional) If provided, joins this session (requires server_url with ?token=...). If omitted, creates a new session.
video_profile string auto Video quality profile: auto, 720p30, 1080p30, 1080p60.
auto_connect bool true Whether to automatically connect when the tile is created.
show_overlay bool true Show URL bar and stats overlay.
show_cursor bool true Show cursor position indicator.
x, y number - Optional position (fractional 0-1 or pixels).
width, height number - Optional size (fractional 0-1 or pixels).
dark_mode bool false Enable dark mode for the browser session.
opacity number 1.0 Tile opacity.
response_topic string kingkiosk/{device}/system/response Response destination.

Remote Browser Control Commands:

Command Description Required Keys
connect_remote_browser Connect (creates session if needed) window_id
disconnect_remote_browser Disconnect from the session window_id
configure_remote_browser Update configuration window_id, optional: server_url, initial_url, session_id, video_profile, dark_mode
navigate_remote_browser Navigate to URL window_id, url (http/https only)
remote_browser_back Go back in history window_id
remote_browser_forward Go forward in history window_id
remote_browser_reload Reload current page window_id
remote_browser_click Simulate mouse click (at current pointer position; x/y are accepted for compatibility) window_id, optional: x, y, button (left/right/middle)
remote_browser_scroll Scroll the page window_id, delta_x, delta_y
remote_browser_key Send key press window_id, key (DOM code), optional: modifiers (accepted for compatibility)
remote_browser_text Input text directly window_id, text (max 10,000 chars)
remote_browser_zoom Set page zoom level window_id, level (0.25–5.0 absolute) or step (in/out relative)
remote_browser_clear_data Clear cookies/localStorage and restart session window_id
delete_remote_browser Remove the tile window_id
remove_remote_browser Alias for delete_remote_browser window_id
list_remote_browsers List all remote browser tiles (none)
remote_browser_status / get_remote_browser_status Debug/status snapshot (tracks, consumers, session) optional: window_id

Browser Persistence: - Browser state (cookies, localStorage, IndexedDB) persists automatically across sessions - Each tile has an isolated persistence profile (different tiles don't share cookies) - Use remote_browser_clear_data to clear all persisted data (useful for "logout" functionality)

Security Notes: - URL navigation is restricted to http:// and https:// schemes only (javascript:, file:, data: blocked) - Text input is limited to 10,000 characters to prevent abuse - Pointer coordinates are clamped to prevent overflow (-100 to 4096)

Example - Create Remote Browser:

{
  "command": "create_remote_browser",
  "window_id": "browser_1",
  "name": "Web Browser",
  "server_url": "ws://192.168.0.114:4000/ws",
  "initial_url": "https://www.google.com",
  "video_profile": "720p30",
  "auto_connect": true,
  "show_overlay": true
}

Example - Navigate to URL:

{
  "command": "navigate_remote_browser",
  "window_id": "browser_1",
  "url": "https://www.example.com"
}

Example - Send Key Press:

{
  "command": "remote_browser_key",
  "window_id": "browser_1",
  "key": "Enter",
  "modifiers": ["ctrl"]
}

Example - Zoom to 150%:

{
  "command": "remote_browser_zoom",
  "window_id": "browser_1",
  "level": 1.5
}

Example - Zoom In (element-level, on kingkiosk/{device}/element/browser_1/cmd):

{
  "command": "zoom",
  "step": "in"
}

Example - Configure with Session ID:

{
  "command": "configure_remote_browser",
  "window_id": "browser_1",
  "session_id": "new_session_xyz",
  "video_profile": "1080p30"
}

Example - Clear Browser Data (Logout/Reset):

{
  "command": "remote_browser_clear_data",
  "window_id": "browser_1"
}
This clears all cookies, localStorage, and other persisted browser state, then restarts the session. Useful for implementing "logout" functionality when using web apps that store auth tokens in cookies/localStorage.

Element-Level Commands (via kingkiosk/{device_id}/element/{window_id}/cmd):

The remote browser controller also supports element-scoped commands:

Command Description Payload Keys
configure Configure the browser optional: server_url, initial_url, session_id, video_profile, dark_mode
connect Connect (creates session if needed) (none)
disconnect Disconnect from session (none)
navigate / goto Navigate to URL url (http/https only)
back Go back (none)
forward Go forward (none)
reload Reload page (none)
click Simulate click at current pointer position button (optional, default left)
scroll Scroll page dx, dy
key Send key code (DOM KeyboardEvent.code)
text Input text text (max 10,000 chars)
zoom Set page zoom level level (0.25–5.0 absolute) or step (in/out relative, 10% per step)
widget_command Forward a command to a widget inside the remote browser (Custom Widget Bridge) widget_command (string), optional: payload (object)

widget_command also supports nested payload shape: {"command":"widget_command","payload":{"command":"foo","payload":{...}}}.

State Published (on kingkiosk/{device_id}/element/{window_id}/state):

{
  "type": "remoteBrowser",
  "widget_id": "browser_1",
  "server_url": "ws://192.168.0.114:4000/ws?token=REDACTED",
  "session_id": "abc123",
  "video_profile": "720p30",
  "dark_mode": false,
  "connected": true,
  "consuming": true,
  "has_control": true,
  "current_url": "https://www.google.com",
  "load_state": "complete",
  "stats": {
    "rtt_ms": 25,
    "fps": 30,
    "bitrate_kbps": 2500,
    "loss_pct": 0.1
  },
  "error": null
}

Input Mapping (tvOS/Apple TV Remote):

Input Action
D-pad Move pointer (with acceleration)
Select/Enter Click at current pointer position
Menu/Escape Navigate back
Play/Pause Send Space key
Touch swipe Scroll
Long press Right-click (context menu)

System (Non-Window) Commands

This section documents system-level commands that are not tied to a specific window type. These are sent on kingkiosk/{device_id}/system/cmd.

Unless explicitly stated, these commands use the payload key command to select the handler.

Volume (set_volume, mute, unmute)

Top-level keys:

Key Type Default Notes
command string (required) set_volume, mute, unmute.
value number/string - Only used by set_volume. Parsed as double in range [0.0, 1.0].
response_topic string kingkiosk/{device}/system/response Response is always published.

Response payloads:

  • set_volume: {success, command:'set_volume', volume, timestamp}
  • mute/unmute: {success, command:'mute'|'unmute', timestamp}

Brightness (set_brightness, get_brightness, restore_brightness, request_brightness_permission, check_brightness_permission, resume_kiosk_after_permission)

Top-level keys:

Key Type Default Notes
command string (required) One of the brightness commands above.
value number/string - Used by set_brightness. Parsed as double in range [0.0, 1.0].
response_topic string kingkiosk/{device}/system/response Used by most brightness actions.

Notes:

  • Brightness is implemented as application brightness (not global/system brightness).
  • get_brightness publishes to response_topic only when response_topic is provided and returns {brightness, type:'application'}.
  • request_brightness_permission / check_brightness_permission always return permission_granted: true.
  • resume_kiosk_after_permission performs Android-only behavior; on non-Android it returns {not_applicable:true}.

Notifications (notify, alert)

Top-level keys:

Key Type Default Notes
command string (required) notify or alert.
title string MQTT Notification / Alert -
message / body string (required) Message body (either key accepted).
response_topic string kingkiosk/{device}/system/response Handler publishes a result payload.

notify additional keys:

Key Type Default Notes
duration / duration_seconds / toast_duration number - Auto-dismiss seconds (Flutter toast + tvOS banner).
priority string normal One of low, normal, high (platform-dependent).
format / message_format string plain plain, markdown, segments (tvOS supports markdown + segments; HTML is not required).
markdown / message_markdown / body_markdown string - Convenience: markdown content (if set, treated as format: markdown).
segments / rich_segments array [] When format: "segments": list of { text, bold?, italic?, underline?, color?, font_size? }.
thumbnail / image_url / imageUrl / image string - Optional image URL shown in the banner (tvOS supports all keys).
is_html / html bool false HTML rendering is platform-dependent (tvOS currently uses markdown/segments instead).

alert additional keys:

Key Type Default Notes
type string info Used to derive default priority if priority is not set (error/warning/info/success).
priority string (derived) If provided, overrides type-derived priority (low/normal/high).
position string center String forwarded to the alert UI (implementation supports positioned alerts).
show_border bool true Border shown unless explicitly set to false.
border_color string - #RRGGBB or #AARRGGBB (optional).
auto_dismiss_seconds int/string - Optional auto-dismiss; clamped to [1, 300].
format / message_format string plain plain, markdown, segments (same rich text support as notify).
markdown / message_markdown / body_markdown string - Convenience: markdown content (if set, treated as format: markdown).
segments / rich_segments array [] When format: "segments": list of { text, bold?, italic?, underline?, color?, font_size? }.
is_html / html bool false Treat message as HTML.
thumbnail / image_url / imageUrl / image string - Network image URL.

Halo Effect (halo_effect)

Top-level keys:

Key Type Default Notes
command string (required) Must be halo_effect.
window_id string - If provided, applies halo to a specific window; otherwise applies global halo.
enabled bool true If false, disables the halo (global or window-scoped).
color string/int #FF0000 Hex string (parsed) or ARGB int. Defaults to red.
width number/string - Clamped to [1.0, 200.0] if provided.
intensity number/string - Clamped to [0.0, 1.0] if provided.
pulse_mode string none One of none, gentle, moderate, alert.
pulse_duration int/string 2000 Duration (ms), clamped to [100, 10000].
fade_in_duration int/string 800 Duration (ms), clamped to [50, 5000].
fade_out_duration int/string 1000 Duration (ms), clamped to [50, 5000].
confirm bool false If true, publishes a confirmation payload (see below).
response_topic string kingkiosk/{device}/system/response Always publishes {success, command:'halo_effect', window_id?, timestamp}.

Confirmation topics (only when confirm == true):

  • Global: kingkiosk/{device}/halo_effect/status
  • Window-scoped: kingkiosk/{device}/window/{window_id}/halo_effect/status

Screensaver (screensaver)

A full-screen overlay with independently bouncing items (clock, image, text, icon). Sits on top of all content when enabled. Tap anywhere to dismiss.

Top-level keys:

Key Type Default Notes
command string (required) Must be screensaver or screen_saver.
action string enable One of enable (aliases: on, start), disable (aliases: off, stop), toggle, wake, wake_up, deactivate, set_config (alias: configure), set_items, add_item, remove_item, update_item, clear_items, get_state.
items array - Array of screensaver item objects (see below). Used with enable or set_items.
item object - Single screensaver item object. Used with add_item.
item_id string - Item ID to target. Used with remove_item or update_item.
config object - Config updates for update_item.
background_color string/int #000000 Hex string or ARGB int for background.
background_opacity number 0.9 Background opacity (0.0-1.0).
idle_timeout int 0 Seconds of inactivity before auto-enable (0 = manual only).

Screensaver Item Object:

Key Type Default Notes
id string auto-generated Unique identifier for the item.
type string text One of clock, image, text, icon, logo.
config object {} Type-specific configuration (see below).
width number 150 Base width in logical pixels.
height number 80 Base height in logical pixels.
speed number 1.0 Movement speed multiplier (0.1-3.0). Higher = faster bouncing.
scale number 1.0 Size scale factor (0.5-3.0).

Type-specific config:

  • clock: { "show_seconds": true, "show_date": false, "font_size": 48, "text_color": "#FFFFFF" }
  • image/logo: { "url": "https://example.com/logo.png", "fit": "contain" }
  • text: { "text": "Hello", "font_size": 36, "font_weight": "bold", "text_color": "#FFFFFF" }
  • icon: { "icon": "star", "size": 64, "color": "#FFFFFF" } (icons: star, heart, home, settings, music, play, pause, stop, cloud, sun, moon)

Example: Enable screensaver with bouncing clock and logo

{
  "command": "screensaver",
  "action": "enable",
  "items": [
    {
      "id": "clock_1",
      "type": "clock",
      "config": { "show_seconds": true, "text_color": "#00FF00" },
      "width": 250,
      "height": 100,
      "speed": 1.0,
      "scale": 1.5
    },
    {
      "id": "logo_1",
      "type": "image",
      "config": { "url": "https://example.com/logo.png" },
      "width": 200,
      "height": 200,
      "speed": 0.7,
      "scale": 1.0
    }
  ],
  "background_color": "#000000",
  "background_opacity": 0.95
}

Example: Disable screensaver

{
  "command": "screensaver",
  "action": "disable"
}

Example: Add a text item to running screensaver

{
  "command": "screensaver",
  "action": "add_item",
  "item": {
    "id": "welcome_text",
    "type": "text",
    "config": { "text": "Welcome!", "font_size": 48, "text_color": "#FF6600" },
    "width": 300,
    "height": 80,
    "speed": 1.2
  }
}

Example: Get current screensaver state

{
  "command": "screensaver",
  "action": "get_state"
}

Response includes full state: { "enabled": true, "items": [...], "background_color": "#000000", ... }

Idle Screensaver (Settings-Based):

King Kiosk also includes an idle-based screensaver that activates automatically after a configurable timeout period. This is configured in Settings → App Settings → Screensaver with three modes:

Mode Behavior
off Idle screensaver disabled
dim Screen goes black after timeout
screensaver Bouncing clock appears after timeout

The idle screensaver timeout is configurable from 1-60 minutes.

Example: Wake from idle screensaver

Use this command to remotely dismiss the idle screensaver (whether in dim or clock mode):

{
  "command": "screensaver",
  "action": "wake"
}

Alternative actions: wake_up, deactivate

This command: 1. Disables any active MQTT-triggered bouncing screensaver 2. Deactivates the idle-based screensaver (restores brightness for dim mode, hides bouncing clock for screensaver mode) 3. Resets the idle timer so the screensaver won't immediately reactivate


Settings / FAB Lock (lock_fab, unlock_fab, lock_settings, unlock_settings)

PIN-protected remote lock/unlock for the settings FAB.

lock_fab and lock_settings are equivalent aliases.
unlock_fab and unlock_settings are equivalent aliases.

Top-level keys:

Key Type Default Notes
command string (required) One of lock_fab, unlock_fab, lock_settings, unlock_settings.
pin / settings_pin / settingsPin / code string/int (required) Settings PIN to authorize the action.
response_topic string kingkiosk/{device}/system/response Response published via unified response helper.
correlation_id string - Optional request correlation ID; echoed in responses.

Behavior:

  • Both lock and unlock commands require a valid settings PIN.
  • Lock commands set settings to locked and drive the normal FAB melt/ember transition.
  • Unlock commands set settings to unlocked and drive the normal reveal/awake transition.
  • Transitions continue from the current visual state (no forced reset), including current ember/menu workflow.
  • If no custom settings PIN is configured on device, the runtime fallback PIN is 1234.

Response payloads:

  • Success: {success:true, status:'success', command, message, locked, timestamp, device, ...}
  • Error: {success:false, status:'error', command, error, timestamp, device, ...}
  • Common errors: unsupported command, missing PIN, invalid PIN, settings controller unavailable.

Example: lock FAB

{
  "command": "lock_fab",
  "pin": "1234"
}

Example: unlock FAB (alias + alternate PIN key)

{
  "command": "unlock_settings",
  "settings_pin": "1234"
}

Person Detection (person_detection)

Top-level keys:

Key Type Default Notes
command string (required) Must be person_detection.
action string toggle One of enable, disable, toggle, status.
confirm bool false If true, publishes a confirmation payload.

Published topics:

  • Always publishes current status to kingkiosk/{device}/person_presence.
  • If confirm == true, also publishes to kingkiosk/{device}/person_detection/status.

Security Camera (security_camera)

Note: Local settings are authoritative. If the Security Camera is disabled in the app’s Settings, MQTT requests to enable it or change its interval will be rejected.

Controls the periodic “security camera” capture flow in the WebRTC media service.

Top-level keys:

Key Type Default Notes
command string (required) Must be security_camera.
action string - One of enable, disable, set_interval, status.
interval int/string 3 Used by enable and set_interval (seconds).

Published topics:

  • When enabled, publishes security camera snapshots to:
  • kingkiosk/{device}/camera/snapshot (raw PNG bytes, retained)
  • kingkiosk/{device}/camera/state (JSON metadata, retained)
  • For action == status, additionally publishes to kingkiosk/{device}/security_camera/status with {enabled, interval_seconds}.

Responses:

  • Also publishes a standardized response to kingkiosk/{device}/system/response via the unified response helper.

Screenshot Camera (screenshot_camera)

Controls the periodic “screenshot camera” capture flow in the screenshot service.

Note: Local settings are authoritative. If Screenshot Camera is disabled in the app’s Settings, MQTT requests to enable it or change its interval will be rejected.

Top-level keys:

Key Type Default Notes
command string (required) Must be screenshot_camera.
action string - One of enable, disable, set_interval, status.
interval int/string 5 Used by enable and set_interval (seconds).

Published topics:

  • When enabled, publishes screenshot camera snapshots to:
  • kingkiosk/{device}/screenshot/snapshot (raw PNG bytes, not retained)
  • kingkiosk/{device}/screenshot/state (JSON metadata, not retained)
  • For action == status, additionally publishes to kingkiosk/{device}/screenshot_camera/status with {enabled, interval_seconds}.

Responses:

  • Also publishes a standardized response to kingkiosk/{device}/system/response via the unified response helper.

Camera Snapshot (camera_snapshot)

Captures still images from the live camera feed (WebRTC on Flutter, Continuity Camera on tvOS) and publishes them to MQTT as a Home Assistant camera entity. Unlike screenshot (which captures the UI), this captures from the real camera.

Three trigger modes: 1. On-demand — Send action: capture for a single snapshot. 2. Periodic — Enable with action: enable for recurring captures at a configurable interval. 3. Motion-triggered — Enable with action: set_motion_trigger so motion detection automatically captures a snapshot when motion is detected.

Top-level keys:

Key Type Default Notes
command string (required) Must be camera_snapshot.
action string capture One of: capture, enable, disable, set_interval, set_motion_trigger, set_quality, status.
interval int 10 Capture interval in seconds (for enable and set_interval).
enabled bool - For set_motion_trigger: whether to trigger snapshots on motion detection.
quality int 80 JPEG compression quality 10-100 (for set_quality).
confirm bool false If true, publishes confirmation to response topic.

Action reference:

Action Description
capture / take / snapshot Take a single snapshot immediately.
enable / start Start periodic camera snapshots at interval seconds.
disable / stop Stop periodic camera snapshots.
set_interval Update the capture interval (restarts timer if enabled).
set_motion_trigger / motion_trigger Enable/disable auto-snapshot on motion detection.
set_quality Set JPEG compression quality (10-100).
status Publish current status to kingkiosk/{device}/camera_snapshot/status.

Published topics:

  • kingkiosk/{device}/camera/snapshot — Raw JPEG bytes (for HA camera entity, QoS 0, not retained).
  • kingkiosk/{device}/camera/state — JSON metadata: {timestamp, size_bytes, format, quality, source}.
  • kingkiosk/{device}/camera_snapshot/status — JSON status: {enabled, interval_seconds, motion_trigger, jpeg_quality, last_capture, last_capture_size}.

Home Assistant discovery:

  • Published as homeassistant/camera/{device}_camera_snapshot/config (retained).
  • Creates a camera entity in HA showing the latest camera snapshot.

Example — capture on demand:

{"command": "camera_snapshot", "action": "capture", "confirm": true}

Example — enable periodic snapshots every 30 seconds:

{"command": "camera_snapshot", "action": "enable", "interval": 30}

Example — enable motion-triggered snapshots:

{"command": "camera_snapshot", "action": "set_motion_trigger", "enabled": true}

Example — set JPEG quality to 60%:

{"command": "camera_snapshot", "action": "set_quality", "quality": 60}


Screenshot (screenshot)

Note: Local settings are authoritative. If screenshots are disabled locally (Screenshot Camera is OFF in Settings), MQTT screenshot requests will be rejected.

Top-level keys:

Key Type Default Notes
command string (required) Must be screenshot.
notify bool false If true, shows an on-device UI snackbar.
confirm bool false If true, publishes to kingkiosk/{device}/screenshot/status on success or error (independent of Home Assistant discovery).

Published topics:

  • When Home Assistant discovery is enabled, publishes screenshot payload to kingkiosk/{device}/screenshot as a raw base64 string (base64-encoded PNG bytes, retained).
  • If confirm == true, publishes a status JSON payload to kingkiosk/{device}/screenshot/status.

Decoding tip:

  • Avoid mosquitto_sub -v (it prefixes the topic, breaking base64 decode).
  • Capture exactly one payload and decode:
  • mosquitto_sub -t 'kingkiosk/<device>/screenshot' -C 1 -R > shot.b64
  • macOS: base64 -D shot.b64 > shot.png
  • Linux: base64 -d shot.b64 > shot.png

Cache (cache, cache_control, clear_cache)

Top-level keys:

Key Type Default Notes
command string (required) One of cache, cache_control, clear_cache (all route here).
action string stats See action list below.
url string - Required for refresh / refresh_resource.
response_topic string kingkiosk/{device}/system/response Response published via the unified response helper.

Supported action values:

  • clear, clear_all, nuclear
  • clear_images
  • clear_data
  • refresh, refresh_resource (requires url)
  • stats, get_stats

Text-to-Speech (tts, speak, say)

These commands forward an action map into the TTS service.

Feature Server transparent takeover: When the Feature Server is connected, speak, getVoices, and status commands automatically route through the Feature Server's high-quality Piper TTS engine. When disconnected, the same commands fall back to on-device TTS (FlutterTts on Flutter, AVSpeechSynthesizer on tvOS). No changes to the MQTT command format are required — the routing is transparent.

Top-level keys:

Key Type Default Notes
command string (required) tts, speak, or say.
response_topic string - If provided, publishes the TTS service result.
queue_first bool true Defaulted to true by the system handler (unless explicitly false). Also controls pre-init queuing behavior in the service.

TTS action selection:

  • The TTS service uses action (preferred), or falls back to command.

Common TTS keys:

Key Type Default Notes
action string speak Supported actions listed below.
text / message string - Used by speak/say/tts actions.
language string - Example: en-US.
voice string - Voice name. When Feature Server is connected, use a Piper voice ID (e.g. en_US-lessac-medium).
volume number - 0.0–1.0. Mapped to 0–100 for Feature Server.
speechRate / rate number - 0.0–1.0. Mapped to 0–100 for Feature Server.
pitch number - 0.5–2.0. Mapped to 0–100 for Feature Server (1.0 = 33).
queue bool false If true (or if already speaking), queues the speak.
force bool false If true, bypasses deduplication check.
dedupe_ms / dedupeMs / dedupe_window_ms int 1200 Deduplication window in milliseconds. If the same text+language+voice fingerprint is sent within this window, the duplicate is silently skipped.

Feature Server-only speak keys (ignored when using on-device TTS):

Key Type Default Notes
delivery_mode string url url (recommended) or inline (base64 in WS notification).
speaker_id string - Multi-speaker voice speaker selection.
appended_silence_ms int - Silence appended after synthesis (ms).

Supported TTS action values:

  • Speak: tts, speak, say
  • Playback control: stop, pause, resume
  • Settings: setVolume/volume, setRate/rate/speed, setPitch/pitch, setLanguage/language, setVoice/voice (each accepts the specific param or generic value key)
  • Service toggles: enable, disable
  • Info: status/getStatus, getLanguages, getVoices/voice_list/voices
  • Queue: clearQueue
  • Feature Server only: voice_pull/pull_voice/install_voice

Feature Server voice actions:

getVoices / voice_list — When Feature Server is connected, queries available Piper voices. Optional filter keys:

Key Type Notes
language / language_code string Filter by language (e.g. en_US).
quality string Filter by quality (x_low, low, medium, high).
query string Free-text search filter.
installed_only bool Only return installed voices.
limit int Max voices to return (default 25).

Response includes voices array with objects containing voiceId, name, languageCode, quality, installed, numSpeakers, etc.

voice_pull — Ensures a voice is downloaded/installed on the Feature Server. Requires voice parameter (e.g. en_US-lessac-medium). Only available when Feature Server is connected.

status / getStatus — When Feature Server is connected, response includes source: "feature_server", engine: "piper", and feature_server_connected: true.


Speech-to-Text (stt, speech_to_text, listen)

These commands forward an action map into the Speech-to-Text service.

Top-level keys:

Key Type Default Notes
command string (required) stt, speech_to_text, or listen.
response_topic string - If provided, publishes the STT service result.
action string start Action forwarded to the STT service.

Supported STT action values and keys:

Action Keys Notes
start / listen - Starts listening.
stop - Stops listening and returns {text, confidence}.
status - Returns service status.
enable / disable - Enables/disables service.
set_language language Sets language (e.g., en).
use_whisper use_whisper (bool) IO only; web always uses Web Speech.
set_mqtt_publishing / publish_to_mqtt enabled (bool) Controls transcription MQTT publishing.
set_send_to_ai_agent / send_to_ai_agent / ai_integration enabled (bool) Controls AI agent integration.
provision_ai_chatbot_only - Sets send_to_ai_agent=true and publish_to_mqtt=false.

Audio Input Device (unified_audio, audio_input, audio_devices)

These commands query and control the audio input device used by Speech-to-Text (and other UnifiedAudioService consumers).

This is the same device you select in the UI under Settings → Speech & AI → Audio Input Device.

Top-level keys:

Key Type Default Notes
command string (required) unified_audio, audio_input, or audio_devices.
action / command_action string status One of status (alias: getstatus), list_devices (aliases: list, devices), set_device (alias: setdevice).
device_id / deviceId string - Required for set_device.
response_topic string - If provided, publishes the action result payload.

Examples:

{ "command": "unified_audio", "action": "status", "response_topic": "kingkiosk/<device>/system/response" }
{ "command": "unified_audio", "action": "list_devices", "response_topic": "kingkiosk/<device>/system/response" }
{ "command": "unified_audio", "action": "set_device", "device_id": "1", "response_topic": "kingkiosk/<device>/system/response" }

Background (set_background, get_background)

set_background keys:

Key Type Default Notes
command string (required) Must be set_background.
type string - One of default, image, webview.
image_path / image_url string - Used when type == image.
web_url / url string - Used when type == webview.
response_topic string - If provided, publishes {success, message, type, image_path, web_url}.

get_background keys:

Key Type Default Notes
command string (required) Must be get_background.
response_topic string kingkiosk/{device}/status/background Response payload: { success: bool, background: { type, image_path, web_url } }.

Provision (provision)

Provision applies settings and can optionally import saved layouts so you can clone one device to another in a single command.

Top-level keys:

Key Type Default Notes
command string (required) Must be provision.
settings object - Optional. If present, settings are read from this object.
screen_states / screenStates array - Optional list of screen-state objects to import.
screen_state object - Optional single screen-state object to import.
current_layout / currentLayout object - Optional current layout snapshot to apply immediately.
overwrite bool true Used when importing screen states via provision.
correlation_id string - Optional. Echoed in the provision response.
response_topic string kingkiosk/{device}/system/response Provision always publishes a response.
(any other keys) any - If settings is not provided, non-reserved keys are treated as settings. Reserved keys include command/response/correlation/import flags and layout payload keys above.

Supported settings keys (case-insensitive, with common aliases):

Setting key(s) Type Notes
isDarkMode, darkMode, dark_mode bool Theme.
kioskMode, kiosk_mode bool Kiosk mode toggle.
showSystemInfo, show_system_info bool Toggle system info overlay.
kioskStartUrl, kiosk_start_url, startUrl string Start URL.
mqttEnabled, mqtt_enabled bool MQTT enable.
mqttBrokerUrl, mqtt_broker_url, brokerUrl string Broker host/url.
mqttBrokerPort, mqtt_broker_port, brokerPort int 1–65535.
mqttUsername, mqtt_username string Stored in secure storage.
mqttPassword, mqtt_password string Stored in secure storage.
deviceName, device_name string Sanitized and applied to MQTT device namespace.
mqttHaDiscovery, mqtt_ha_discovery, haDiscovery bool Also updates runtime discovery flag.
mqttUseSSL, mqtt_use_ssl, mqttSSL, mqtt_ssl bool Enabling may auto-adjust the port.
mqttAllowSelfSigned, mqtt_allow_self_signed, mqttSelfSigned, mqtt_self_signed bool -
mqttUseHmacAuth, mqtt_use_hmac_auth, mqttHmacAuth, mqtt_hmac_auth bool Enables/disables MQTT HMAC auth mode.
mqttHmacSecret, mqtt_hmac_secret, hmacSecret string Shared secret used by HMAC auth.
webviewAllowInvalidCerts, webview_allow_invalid_certs, allowInvalidWebviewCerts bool WebView hardening flag.
networkAllowInvalidCerts, network_allow_invalid_certs, allowInvalidCerts bool Network hardening flag for non-WebView requests.
enableEvalJs, enable_evaljs, evalJsEnabled, evaljs_enabled bool WebView hardening flag.
mqttCaCertPath, mqtt_ca_cert_path, mqttCaCert, mqtt_ca_cert string -
mqttClientCertPath, mqtt_client_cert_path, mqttClientCert, mqtt_client_cert string -
mqttClientKeyPath, mqtt_client_key_path, mqttClientKey, mqtt_client_key string -
personDetectionEnabled, person_detection_enabled, personDetection, person_detection bool Also updates person detection service state when available.
haAccessToken, ha_access_token, homeAssistantToken, home_assistant_token string Stored in secure storage and synced to AI agent service when available.
settingsPin, settings_pin, pin string Minimum length 4; stored in secure storage.
sendToAIAgent, send_to_ai_agent, aiIntegration, ai_integration bool Enables/disables Speech-to-AI integration.
aiAgentEnabled, ai_agent_enabled bool Enables/disables AI agent service; enabling may also enable Speech-to-AI.
aiEnabled, ai_enabled bool AI feature toggle.
aiProviderHost, ai_provider_host, aiProviderUrl string AI provider endpoint.
haBaseUrl, ha_base_url, homeAssistantUrl, home_assistant_url string Home Assistant base URL.
haAgentId, ha_agent_id, conversationAgent, conversation_agent string Home Assistant conversation agent id.
sipEnabled, sip_enabled bool SIP enable toggle.
sipServerHost, sip_server_host string SIP server host.
sipProtocol, sip_protocol string ws or wss.
selectedAudioInput, selected_audio_input string Selected audio input id/name.
selectedVideoInput, selected_video_input string Selected video input id/name.
selectedAudioOutput, selected_audio_output string Selected audio output id/name.
wyomingHost, wyoming_host string Wyoming host.
wyomingPort, wyoming_port int Wyoming port.
wyomingEnabled, wyoming_enabled bool Wyoming enable toggle.
featureServerEnabled, feature_server_enabled bool Enable/disable Feature Server.
featureServerAutoConnect, feature_server_auto_connect bool Auto-connect Feature Server when app starts.
featureServerUrl, feature_server_url string Feature Server host/IP (cross-platform safe format; avoid ws:// prefix).
featureServerUseHttps, feature_server_use_https bool Use secure WebSocket (wss) for Feature Server signaling.
featureServerProduceAudio, feature_server_produce_audio bool Include microphone audio when producing to Feature Server.
autoAcceptVideoconferenceCalls, auto_accept_videoconference_calls, autoAcceptVideoconference, auto_accept_videoconference bool Auto-open and join incoming recipient-side video conference calls. When false, the client publishes device-level communications events and does not show a built-in accept dialog.
intercomEnabled, intercom_enabled bool Enable intercom/broadcast participation.
autoAcceptIncomingIntercom, auto_accept_incoming_intercom, autoAcceptIntercom, auto_accept_intercom bool Auto-open incoming intercom broadcasts. When false, the client publishes device-level communications events and does not auto-open the broadcast.
intercomGroups, intercom_groups array Intercom groups (tvOS supports this directly; other clients may ignore).
websocketUrl, websocket_url string Websocket endpoint.
mediaServerUrl, media_server_url string Media server endpoint.
latestScreenshot, latest_screenshot string Metadata/path field.
autoLockEnabled, auto_lock_enabled bool Enable/disable auto-lock for settings screen.
autoLockTimeout, auto_lock_timeout, autoLockTimeoutMinutes, auto_lock_timeout_minutes double Auto-lock timeout in minutes (e.g. 1, 2, 5, 10, 15, 30, 60).
screensaverMode, screensaver_mode string Screensaver mode: off, dim, or clock (Flutter) / screensaver (tvOS).
screensaverTimeout, screensaver_timeout, screensaverTimeoutMinutes, screensaver_timeout_minutes double Screensaver timeout in minutes.
backgroundType, background_type string Background type: default, image, or webview.
backgroundImageUrl, background_image_url, backgroundImagePath, background_image_path string Background image URL/path.
backgroundWebUrl, background_web_url string Background WebView URL (Flutter only).
locationEnabled, location_enabled bool Enable location services (Flutter only).
brightnessLevel, brightness_level double Screen brightness 0–100 (Flutter only).
mqttReconnectOnStartup, mqtt_reconnect_on_startup bool Auto-reconnect MQTT on app startup.
kingDspDiscoveryEnabled, kingdsp_discovery_enabled, kingDspIntercomEnabled bool Enable KingDSP network discovery.
dlnaRendererEnabled, dlna_renderer_enabled bool Enable DLNA/UPnP media renderer.
enableContinuityCamera bool Enable Continuity Camera (tvOS only).
sttEnabled, stt_enabled, speechToTextEnabled, speech_to_text_enabled bool Enable speech-to-text service (Flutter).
autoSpeakResponses, auto_speak_responses bool Auto-speak AI responses (Flutter).
continueListening, continue_listening bool Continue listening after AI response (Flutter).
keepConversationHistory, keep_conversation_history bool Keep AI conversation history (Flutter).
ttsRate float TTS speech rate (tvOS, 0.0–1.0).
ttsPitch float TTS speech pitch (tvOS, 0.5–2.0).
ttsVolume float TTS speech volume (tvOS, 0.0–1.0).
ttsLanguage string TTS language code e.g. en-US (tvOS).
enablePersonDetection bool Enable person detection (tvOS).
enableFaceRecognition bool Enable face recognition (tvOS).
detectionInterval double ML detection interval in seconds (tvOS).
enableKingDSP bool Enable KingDSP audio streaming (tvOS).
kingDSPHost string KingDSP server host (tvOS).
kingDSPPort int KingDSP server port (tvOS, default 4954).
aiProvider string AI provider: openai, anthropic, google, custom, homeassistant (tvOS).
aiModel string AI model name (tvOS).
aiApiKey string AI API key; stored in secure storage (tvOS).
aiSystemPrompt string AI system prompt (tvOS).
aiMaxTokens int AI max tokens (tvOS).
aiTemperature double AI temperature 0.0–2.0 (tvOS).
aiAutoSpeak bool Auto-speak AI responses (tvOS).
aiListenAfterResponse bool Continue listening after AI response (tvOS).
aiKeepHistory bool Keep conversation history (tvOS).
sttLanguage string STT language code (tvOS).
sttModel string STT model name (tvOS).
sttTranslate bool Translate STT to English (tvOS).
sttUseVAD bool Use Voice Activity Detection for STT (tvOS).
ai_chatbot / ai_chat_bot / chatbot object See AI Chat Bot object below.

Provision response payload includes:

  • status: success, partial, or error
  • applied_settings: list of settings applied
  • failed_settings: map of setting key -> reason
  • screen_states_imported: imported state names
  • screen_states_failed: map of state name -> reason
  • current_layout_applied: bool
  • correlation_id (when provided in request)

AI Chat Bot object (ai_chatbot) keys:

Key Type Notes
provider string -
api_key string -
base_url string -
model string -
system_prompt string Stored under the systemPrompt key in the service config.

Feature Server provisioning example:

{
  "command": "provision",
  "settings": {
    "featureServerEnabled": true,
    "featureServerAutoConnect": true,
    "featureServerUrl": "192.168.1.50",
    "featureServerUseHttps": false,
    "featureServerProduceAudio": true,
    "intercomEnabled": true
  },
  "correlation_id": "provision-feature-server-001"
}

After provisioning, subscribe to:

kingkiosk/{device_id}/feature_server/state

The payload is retained and includes fields like enabled, connected, state, last_error, and reconnect metadata.


Get Config (get_config)

Top-level keys:

Key Type Default Notes
command string (required) Must be get_config.
include_secrets / includeSecrets bool true Include secret values (passwords/tokens/PIN/secrets) in returned config.
include_layouts / includeLayouts / include_screen_states bool true Include saved screen states and current layout snapshot.
correlation_id string - Optional. Echoed in response.
response_topic string kingkiosk/{device}/system/response -

Response payload:

{command:'get_config', status:'success', device_name, config:{...}, settings:{...}, timestamp, correlation_id?, screen_states?, screen_state_count?, current_layout?}

Notes:

  • settings is an alias of config for compatibility.
  • When include_secrets is false, secret fields are masked as ***.
  • When include_layouts is true, response includes screen_states, screen_state_count, and current_layout.
  • The config object includes all provisionable settings listed in the provision table above (including screensaver, background, auto-lock, networked audio, ML detection, TTS, STT, AI behavior, and MQTT reconnect settings). This allows admin tools to prepopulate settings screens with current device state.

Telemetry (set_telemetry, get_telemetry)

Enable, disable, or query anonymous crash reporting and diagnostics telemetry.

set_telemetry

Top-level keys:

Key Type Default Notes
command string (required) Must be set_telemetry.
enabled bool (required) true to enable crash reports & diagnostics, false to disable.

Response payload (published to kingkiosk/{device}/system/response):

{command:'set_telemetry', success:true, telemetryEnabled:true}

Example: enable telemetry

{
  "command": "set_telemetry",
  "payload": {
    "enabled": true
  }
}

Example: disable telemetry

{
  "command": "set_telemetry",
  "payload": {
    "enabled": false
  }
}
get_telemetry

Top-level keys:

Key Type Default Notes
command string (required) Must be get_telemetry.

Response payload (published to kingkiosk/{device}/system/response):

{command:'get_telemetry', telemetryEnabled:false}

Example: query telemetry state

{
  "command": "get_telemetry"
}

AI Agent (ai_agent / ai)

Top-level keys:

Key Type Default Notes
command string (required) ai_agent or ai.
action string - Required for most operations.

Supported action values and keys:

Action Keys Published topics / notes
enable enabled (bool, default true) Enables/disables AI agent service.
select_agent agent_index (int) Selects an agent by index.
configure_home_assistant base_url, access_token, agent_id (optional) Auto-discovers agents after config.
send_message message (string), conversation_id (optional) Sends text to AI agent.
create_conversation user_id (optional), user_name (optional) Publishes kingkiosk/{device}/ai_agent/conversation_created.
switch_user user_id, user_name Switches active conversation.
clear_conversation conversation_id (optional) Clears one or all conversations.
get_status - Publishes kingkiosk/{device}/ai_agent/status.
speech_integration enabled (bool, default true) Enables Speech-to-AI integration.
speech_mqtt_publishing / publish_speech_to_mqtt enabled (bool, default true) Enables transcription MQTT publishing.
discover_agents - Publishes kingkiosk/{device}/ai_agent/agents_discovered.
select_ha_agent agent_id Selects HA conversation agent.
configure_chat_bot provider, api_key, base_url, model Configures the local Chat Bot.

Additional published topics (implementation detail, but useful for admin UIs):

  • kingkiosk/{device}/ai_agent/message_response (non-retained): emitted for send_message with message, response, status, timestamp.
  • kingkiosk/{device}/ai_agent/conversation_cleared (non-retained): emitted for clear_conversation.

AI Provisioning (provision_ai_chatbot, setup_ai_chatbot, configure_ai_chatbot)

Top-level keys:

Key Type Default Notes
command string (required) One of the provisioning command aliases above.
provider string anthropic Supported: anthropic, openai, gemini, ollama.
api_key string - Provider API key (if needed).
base_url string - Used by providers like ollama.
model string (provider default) Defaults depend on provider.
system_prompt string (provider default) Defaults depend on provider.
enable_speech bool true Enables Speech-to-Text.
enable_tts bool true Enables Text-to-Speech.
chatbot_only_mode bool true Disables MQTT publishing of transcriptions when true.

Publishes status to kingkiosk/{device}/ai_provisioning/status.


Command History / Audit (mqtt_cmd_history + aliases)

This subsystem exposes the in-memory command audit/history service over MQTT.

Primary command:

  • mqtt_cmd_history

Aliases (mapped to mqtt_cmd_history internally):

  • get_command_history (sets action: 'list' and defaults limit to 100)
  • get_audit_history (sets action: 'list' and defaults limit to 100)
  • clear_command_history (sets action: 'clear')
  • clear_audit_history (sets action: 'clear')
  • get_audit_stats (sets action: 'stats')

Top-level keys:

Key Type Default Notes
command string (required) One of the command strings above.
action string list Only used when command == mqtt_cmd_history. See supported actions below.
limit int/string 100 Used for list and many queries.
response_topic string kingkiosk/{device}/system/response Responses are published to this topic (non-retained).

Supported action values (when using command: 'mqtt_cmd_history'):

  • list / get
  • stats
  • clear
  • query_by_time / query_time_range (requires start_time and end_time as ISO8601)
  • query_by_correlation / query_correlation (requires correlation_id)
  • query_by_command / query_command_type (requires command_type)
  • query_by_source / query_source_type (requires source_type)
  • query_by_window / query_window (requires window_id)
  • query_by_batch / query_batch (requires batch_id)
  • query_by_status / query_response_status (requires status)
  • replay (see below)

Action-specific keys:

Action Keys
query_by_time / query_time_range start_time (ISO8601), end_time (ISO8601), optional limit
query_by_correlation / query_correlation correlation_id
query_by_command / query_command_type command_type, optional limit
query_by_source / query_source_type source_type (example values: mqtt, touch, batch, api, local), optional limit
query_by_window / query_window window_id, optional limit
query_by_batch / query_batch batch_id
query_by_status / query_response_status status (expected: success, error, pending), optional limit
replay command_ids (list of ints/strings) OR correlation_id, optional dry_run (bool)

Response payloads:

  • Responses are published to response_topic as JSON with command: 'audit_response' and include action, timestamp (ISO8601), device, and action-specific fields.
  • Errors are also published to response_topic with action: 'error' and an error string.

Debug / Introspection (test_sensors, debug_sensors, test_location, debug_location, list_windows, debug_windows)

These are dispatcher-level debug helpers.

Sensors (test_sensors, debug_sensors)

Top-level keys:

Key Type Default Notes
command string (required) test_sensors or debug_sensors.

Behavior:

  • Attempts to publish current sensor values via the normal sensor publisher.
  • Responds on kingkiosk/{device}/system/response using the unified response helper; success includes sensors_available: true|false.
Location (test_location, debug_location)

Top-level keys:

Key Type Default Notes
command string (required) test_location or debug_location.

Behavior:

  • If sensors are unavailable (WASM mode), publishes an error response.
  • Otherwise requests location permission and publishes direct sensor topics:
  • kingkiosk/{device}/latitude (retained)
  • kingkiosk/{device}/longitude (retained)
  • kingkiosk/{device}/location_status (retained)
Window list (list_windows, debug_windows)

Top-level keys:

Key Type Default Notes
command string (required) list_windows or debug_windows.

Response:

  • Publishes a success payload to kingkiosk/{device}/system/response via the unified response helper with:
  • window_count
  • windows (visual tile list when available)
  • tiling_mode (when available)
  • controller_count and controllers (debug listing)

Live updates:

  • For always-on admin dashboards, prefer the retained window state feed:
  • Snapshot: kingkiosk/{device}/windows (retained)
  • Events: kingkiosk/{device}/windows/event (non-retained)
  • Diagnostics: kingkiosk/{device}/diagnostics/windows (retained)

Each windows[] item includes:

  • window_id, title, type, url, image_urls
  • x, y, width, height, opacity, z_index
  • loop, minimized, maximized
  • mqtt_topic, mqtt_json_field, mqtt_is_base64, mqtt_update_interval_ms
  • metadata

Batch / Script (batch, kill_batch_script, batch_status, wait)

The batch subsystem executes a sequence of commands.

Top-level keys:

Key Type Default Notes
command string (required) batch, kill_batch_script, batch_status, or wait.
response_topic string kingkiosk/{device}/system/response Optional override; must remain within kingkiosk/{device}/... and must not contain #, +, or NUL.

batch keys:

Key Type Notes
commands array Required. Each item may be a JSON object (with its own command) or a string.

wait step (in a batch) keys:

Key Type Default Notes
seconds number/string 1 Clamped to 0–300 seconds internally (milliseconds clamped to 0–300000).

Standalone wait command keys:

Key Type Default Notes
seconds number/string 1 Must be > 0 and <= 300.

Notes:

  • batch does not currently publish an automatic completion event; use per-command responses inside the batch (where supported) or query batch_status.
  • batch_status publishes {batch_running, batch_id, status, progress, total, kill_requested, ...}.

Screen State (save_screen_state, load_screen_state, list_screen_states, delete_screen_state, export_screen_state, import_screen_state)

These commands manage named saved layouts (window tiles + layout settings).

All commands in this section support:

  • response_topic (optional): publish response to a custom topic (defaults to kingkiosk/{device}/system/response)
  • correlation_id (optional): echoed in the response when provided

Response shape:

{status, message, timestamp, state_name?, command?, correlation_id?, ...data}

save_screen_state
Key Type Default Notes
name string (required) Screen state name.
overwrite bool false If false and the name exists, returns an error response.
response_topic string - Optional response topic.
correlation_id string - Optional request/response correlation id.

Success response includes: name, windowCount, savedAt.

load_screen_state
Key Type Notes
name string (required)
response_topic string Optional response topic.
correlation_id string Optional request/response correlation id.

Success response includes: name, windowCount, savedAt.

list_screen_states

Optional keys: response_topic, correlation_id.

Success response includes:

  • states: list of {name, windowCount, savedAt}
  • count
delete_screen_state
Key Type Notes
name string (required)
response_topic string Optional response topic.
correlation_id string Optional request/response correlation id.
export_screen_state
Key Type Notes
name string (required)
response_topic string Optional response topic.
correlation_id string Optional request/response correlation id.

Success response includes: name, windowCount, savedAt, exportedAt, and screen_state (full exported object).

import_screen_state
Key Type Default Notes
name string (required) Name to save the imported screen state as (overrides any name inside the imported object).
screen_state object (required) The exported screen state object (as produced by export_screen_state).
overwrite bool false If false and the name exists, returns an error response.
response_topic string - Optional response topic.
correlation_id string - Optional request/response correlation id.

Fleet Management (replicate_layout, subscribe_fleet, unsubscribe_fleet, broadcast_fleet_command, publish_fleet_command)

Fleet management uses device control topics plus fleet buses:

Topic Direction Purpose
kingkiosk/{device_id}/system/cmd Controller -> device Send fleet control commands (replicate_layout, subscribe_fleet, unsubscribe_fleet, broadcast_fleet_command)
kingkiosk/{device_id}/system/response (or valid response_topic) Device -> controller Ack/errors for fleet control commands
kingkiosk/fleet/{fleet_id}/layout Device/Controller -> fleet listeners Shared fleet layout bus carrying apply_layout snapshots
kingkiosk/fleet/{fleet_id}/cmd Device/Controller -> fleet listeners Shared fleet system command bus
kingkiosk/fleet/{fleet_id}/element/{element_id}/cmd Device/Controller -> fleet listeners Shared fleet element command bus (topic-addressed element routing)
kingkiosk/fleet/{fleet_id}/element/+/cmd Device subscription filter Wildcard filter devices subscribe to when command fan-out is enabled

Validation rules used by fleet commands:

  • fleet_id cannot be empty and cannot contain /, +, #, or NUL.
  • element_id (when used in a topic path) cannot be empty and cannot contain /, +, #, or NUL.
  • target_topic cannot be empty and cannot contain +, #, or NUL.
  • If target_topic is a fleet element command topic, it must be exactly kingkiosk/fleet/{fleet_id}/element/{element_id}/cmd.
  • Boolean keys (retain, auto_apply, subscribe/unsubscribe flags, allow-self flags) accept bool, number (0/1), and common string values (true/false, yes/no, on/off).
replicate_layout

Top-level keys:

Key Type Default Notes
fleet_id string - Provide either fleet_id or target_topic.
target_topic string - If set, publishes there instead of the default fleet layout topic.
retain bool false If true, publishes the layout retained.
response_topic string - Optional response topic for replication status. Must be inside the same device namespace when overridden.
correlation_id string - Optional request/response correlation id.

Publishes to:

  • Default: kingkiosk/fleet/{fleet_id}/layout
  • Or target_topic when provided.

Published payload on the fleet topic:

{command:'apply_layout', source_device, replicated_at, fleet_id, layout, window_count}

subscribe_fleet

Top-level keys:

Key Type Default Notes
fleet_id string (required) Fleet id to subscribe to.
auto_apply bool true If true, applies received layouts automatically.
subscribe_layout (include_layout) bool true Subscribe to kingkiosk/fleet/{fleet_id}/layout.
subscribe_commands (include_commands) bool true Subscribe to kingkiosk/fleet/{fleet_id}/cmd and kingkiosk/fleet/{fleet_id}/element/+/cmd.
allow_self_commands (allow_self) bool false If false, ignore command messages where source_device equals this device.
response_topic string - Optional response topic for subscription status. Must be inside the same device namespace when overridden.
correlation_id string - Optional request/response correlation id.

At least one of subscribe_layout or subscribe_commands must be true.

Behavior after subscribe:

  • auto_apply: true: incoming fleet layouts are applied immediately.
  • auto_apply: false: layout messages are observed but not applied; device reports fleet update status only.
  • Fleet command messages are normalized and executed through the same dispatcher path used for device commands.
  • For fleet element topics, {element_id} is parsed from the topic path and injected as both element_id and window_id.
unsubscribe_fleet

Top-level keys:

Key Type Default Notes
fleet_id string (required) Fleet id to unsubscribe from.
unsubscribe_layout (include_layout) bool true Unsubscribe from kingkiosk/fleet/{fleet_id}/layout.
unsubscribe_commands (include_commands) bool true Unsubscribe from both fleet command topics.
response_topic string - Optional response topic for unsubscribe status. Must be inside the same device namespace when overridden.
correlation_id string - Optional request/response correlation id.

At least one of unsubscribe_layout or unsubscribe_commands must be true.

broadcast_fleet_command (alias publish_fleet_command)

Top-level keys:

Key Type Default Notes
fleet_id string - Required unless target_topic is provided.
target_topic string - Optional explicit publish topic. Default is kingkiosk/fleet/{fleet_id}/cmd.
fleet_command (payload/message) object (required) Nested command object. Must include command.
retain bool false Retained publish flag on fleet bus.
response_topic string - Optional response topic for publish status. Must be inside the same device namespace when overridden.
correlation_id string - Optional request/response correlation id.

Behavior:

  • If target_topic is omitted, publishes to kingkiosk/fleet/{fleet_id}/cmd.
  • If target_topic points at a fleet element bus, it must be kingkiosk/fleet/{fleet_id}/element/{element_id}/cmd.
  • For fleet element publish, {element_id} from the topic is authoritative and is injected into payload as element_id and window_id before publish.
  • Published payload is normalized and enriched with source_device, fleet_id, and broadcast_at when omitted.

Typical response statuses for fleet operations include:

  • replicated
  • subscribed
  • unsubscribed
  • broadcasted
  • fleet_update
  • applied
  • error

Screen Schedule (set_screen_schedule, list_screen_schedule, enable_screen_schedule, disable_screen_schedule, screen_schedule_status, trigger_screen_schedule)

These commands manage a minimal time-based scheduler that applies saved screen states.

All schedule responses publish to kingkiosk/{device}/system/response with:

{type:'screen_schedule', status:'ok'|'error', message, timestamp, data?}

set_screen_schedule keys:

Key Type Default Notes
entries array (required) List of schedule entries.
enabled bool (no override) Optional. If present, overrides scheduler enabled state.

Schedule entry schema:

Key Type Default Notes
id string (auto) If missing/empty, an id is auto-generated.
screen_state / screenState string (required) Name of a saved screen state.
at string (required) Local time in HH:MM.
days array (all days) Optional. 1=Mon … 7=Sun.
enabled bool true -

trigger_screen_schedule keys:

Key Type Notes
id string Optional. Triggers a specific entry.
screen_state string Optional. Triggers a specific state.

Conflict Resolution (conflict_resolution)

Top-level keys:

Key Type Default Notes
command string (required) Must be conflict_resolution.
action string - get_status, set_strategy, clear, record_touch.
response_topic string kingkiosk/{device}/system/response -

set_strategy keys:

Key Type Notes
strategy string One of touch_priority, mqtt_priority, last_wins, queue, merge.
touch_cooldown_ms int/string Optional.
mqtt_cooldown_ms int/string Optional.
log_conflicts bool Optional.
publish_notifications bool Optional.

record_touch keys:

Key Type Notes
window_id string Optional. Records a touch interaction for a given window.

Map

Widget Type: map

Create/Open (system command: open_map)

Top-level keys:

Key Type Default Notes
command string (required) Must be open_map.
title string Map Window title.
window_id string map_{timestamp} If omitted, a map ID is generated.
opacity number 1.0 -
x, y, width, height number - Optional geometry.
provider object - Tile provider configuration.
initial_camera object - Initial map view.
interaction object - Interaction switches.
correlation_id string - Optional tracking id for response.
response_topic string kingkiosk/{device}/system/response Override response topic.

Provider config (provider) keys:

Key Type Default Notes
url_template string https://tile.openstreetmap.org/{z}/{x}/{y}.png Tile URL template.
subdomains array [] Used with {s} placeholder; ignored for OSM template.
headers object {} Extra HTTP headers for tile requests.
attribution string (c) OpenStreetMap contributors Attribution text (shown on map).

Notes: - If url_template uses https://{s}.tile.openstreetmap.org/..., the {s} subdomain portion is stripped and subdomains are ignored to comply with OSM guidance. - Use close_window on kingkiosk/{device_id}/system/cmd to close the map (window_id == element_id).

Initial camera (initial_camera) keys:

Key Type Default Notes
lat number 0.0 Latitude.
lon number 0.0 Longitude.
zoom number 1.0 Zoom level.
rotation number 0.0 Rotation in degrees (0 = north-up).

Interaction switches (interaction) keys:

Key Type Default Notes
touch_enabled bool true Enables local touch/gesture control.
remote_enabled bool true Enables MQTT element commands.
allow_user_drop_pins bool false Allows user taps to drop pins.

Element Commands

Element commands are sent to kingkiosk/{device_id}/element/{element_id}/cmd only if the map widget registers with the element router.

If interaction.remote_enabled is false, map-specific commands return an error response (except get_state, which is handled by the common widget mixin).

Command Parameters Description
set_camera camera, optional animate, duration_ms Move/rotate the map to a camera. animate/duration_ms are accepted but currently not used for animation.
fit_bounds bounds, optional padding_px, animate Fit camera to bounds. animate currently not used.
configure provider, initial_camera, interaction Update provider/interaction/camera settings.
add_pins pins Add pins (additive).
set_pins pins Replace all pins.
update_pins pins Partial update of existing pins by pin_id.
remove_pins pin_ids or pins Remove pins by id.
clear_pins - Remove all pins.
add_text text or texts Add text overlays (additive).
update_text text or texts Partial update of existing text overlays.
remove_text text_ids or text/texts Remove text overlays by id.
clear_text - Remove all text overlays.
get_state - Common widget command: returns current state.

Camera schema (camera):

Key Type Notes
lat number Latitude.
lon number Longitude.
zoom number Zoom level.
rotation number Rotation in degrees.

Bounds schema (bounds):

Key Type Notes
sw object South-west corner: { "lat": ..., "lon": ... }.
ne object North-east corner: { "lat": ..., "lon": ... }.

Pin schema (pins):

Key Type Notes
pin_id string Required identifier.
lat, lon number Required coordinates.
icon object { "type": "url|asset|base64|default", "value": "...", "content_type": "image/png" }.
size_px object { "w": 32, "h": 32 } (default 32x32).
anchor object { "x": 0.5, "y": 1.0 } (normalized).
z_index int Render order.
opacity number 0.0 to 1.0.
interactive bool Defaults to true.
metadata object Arbitrary JSON metadata.

Text overlay schema (text/texts):

Key Type Notes
text_id string Required identifier.
text string Display text.
anchor_type string geo or screen.
geo object { "lat": ..., "lon": ... } (for anchor_type: geo).
screen object { "x": 0.05, "y": 0.10 } (normalized, for anchor_type: screen).
z_index int Render order.
style object See style keys below.
interactive bool Defaults to false.
metadata object Arbitrary JSON metadata.

Text style schema (style):

Key Type Default Notes
font_size_px number 16.0 Font size in pixels.
font_weight string normal Accepts normal, bold, w300, w500, w600.
color string #FFFFFFFF Text color.
background_color string #00000000 Background color.
padding_px number 4.0 Padding around text.
corner_radius_px number 4.0 Rounded corners.

State fields (published on element state topic)

{
  "type": "map",
  "element_id": "map-1",
  "widget_id": "map-1",
  "camera": { "lat": 30.2672, "lon": -97.7431, "zoom": 14.0, "rotation": 0.0 },
  "counts": { "pins": 12, "text_overlays": 2 },
  "interaction": { "touch_enabled": true, "remote_enabled": true, "allow_user_drop_pins": false }
}

Map Events

Map-specific events are published on kingkiosk/{device_id}/element/{element_id}/event:

Event Payload Notes
camera_changed Includes camera, source (touch or remote), and phase (start, change, end).
pin_selected Includes pin_id, lat, lon, and metadata.
pin_dropped Emitted when allow_user_drop_pins is enabled and the user taps the map.
text_selected Includes text_id, text, and metadata (only if interactive is true).

Canvas

Widget Type: canvas

Create/Open (system command: open_canvas)

Top-level keys:

Key Type Default Notes
command string (required) Must be open_canvas.
title string Canvas Window title.
window_id string canvas_{timestamp} If omitted, an ID is generated.
opacity number 1.0 -
x, y, width, height number - Optional geometry.
doc object - Canvas document (see below).
interaction object - Interaction settings (see below). Overrides doc.interaction if both provided.
persist object - Persistence settings (see below).
background object - Canvas background settings (see below). Overrides doc.background if both provided.
grid object - Grid settings (see below). Overrides doc.grid if both provided.
viewport object - Viewport settings (see below). Overrides doc.viewport if both provided.
correlation_id string - Optional tracking id for response.
response_topic string kingkiosk/{device}/system/response Override response topic.

Notes: - window_id is also used as element_id/widget_id for element commands. - Close with close_window on kingkiosk/{device_id}/system/cmd using window_id. - The canvas document schema is versioned by doc.spec (currently kingkiosk.canvas.v1).

Canvas Document (doc)

This widget uses a single document that contains the full scene (objects + connections) and the view/config state.

doc keys:

Key Type Default Notes
spec string kingkiosk.canvas.v1 Schema identifier.
canvas_id string - Optional application-level id.
meta object - Arbitrary metadata.
background object - Background config (see below).
grid object - Grid config (see below).
viewport object - Viewport config (see below).
interaction object - Interaction config (see below).
objects array [] Canvas objects (see below).
connections array [] Connections between objects (see below).
resources object - Arbitrary JSON resource registry (currently stored/pass-through).

Background schema (background):

Key Type Default Notes
color string #00000000 #RRGGBB or #AARRGGBB.
blur_px number 0.0 Backdrop blur for the whole canvas.
image object - { "url": "..." } or { "asset_id": "..." }.

Grid schema (grid):

Key Type Default Notes
enabled bool false -
size_px number 20.0 Grid step size in pixels.
color string #22FFFFFF Grid line color.

Viewport schema (viewport):

Key Type Default Notes
zoom number 1.0 Scale factor. Ignored when fit is set.
pan_x number 0.0 Pan offset in pixels. Ignored when fit is set.
pan_y number 0.0 Pan offset in pixels. Ignored when fit is set.
min_zoom number - Optional clamp.
max_zoom number - Optional clamp.
fit string - Auto-fit mode. "content" = scale to fit all objects (maintain aspect ratio). "width" = fit content width. "height" = fit content height. When set, zoom/pan_x/pan_y are computed automatically at render time.
fit_padding number 8 Padding in logical pixels around content when auto-fit is active.

Auto-fit example (scale all objects to fill the canvas with 12px padding):

{
  "viewport": {
    "fit": "content",
    "fit_padding": 12
  }
}

Interaction schema (interaction):

Key Type Default Notes
touch_enabled bool true Enables local touch/drag interactions.
remote_enabled bool true Enables element-scoped MQTT commands (except get_state).
edit_mode bool false Enables local dragging (with touch_enabled).
snap_to_grid bool false Enables snapping while dragging.
snap_px number - If omitted, uses grid.size_px.
show_ports_in_view bool false Shows port markers on objects.
allow_add_objects bool false Reserved for future in-app add flows (currently not enforced for MQTT).
allow_add_connections bool false Reserved for future in-app add flows (currently not enforced for MQTT).

Persist schema (persist):

Key Type Default Notes
enabled bool true Enables persistence in local storage.
key string {device}:{window_id} Storage key (falls back to {window_id} if device id unavailable).
restore_on_start bool true Restores the last saved document on start.
publish_on_restore bool true Publishes retained state after restore.

Objects (objects)

Objects are positioned in canvas coordinates (affected by viewport.zoom/pan in the renderer).

Common object keys:

Key Type Default Notes
object_id string (required) Unique id.
type string node One of: node, text, shape, image, embed, group.
x, y number 0.0 Top-left position.
width, height number 0.0 Object size.
z_index int 0 Render order (used when no explicit order is set).
visible bool true -
locked bool false Prevents local dragging.
rotation_deg number 0.0 Rotation around object center.
style object {} Styling keys (see below).
ports array [] Optional port list (see below).
mqtt object {} Optional MQTT bindings: publish on tap and/or subscribe for live updates (see below).
metadata object {} Arbitrary metadata.

style keys currently used by the renderer: - color: object background color (default: transparent for text/shape, dark for others) - border_color: outline color - border_width: outline width - fill_color: (for shape) fill color - stroke_color: (for shape) stroke color

MQTT bindings (mqtt):

The mqtt object supports two sub-keys: publish (tap → publish) and subscribe (live inbound updates).

Publish (tap → publish):

If mqtt.publish is set, a local tap publishes to the specified topic.

Key Type Notes
publish.topic string Target topic.
publish.payload any JSON object → publish as JSON; otherwise published as a string.
publish.retain bool Retained publish when true.

Template variables: - publish.topic and string values anywhere under publish.payload support {device_id}, {device}, {window_id}, {object_id}, and {canvas_id}. - Exact-match placeholders like {device_id} or {{device_id}} keep the original value type when the variable is non-string; inline replacements render as strings. - This is useful for reusable canvases that need to publish local system commands such as kingkiosk/{device_id}/system/cmd.

Subscribe (live inbound updates):

If mqtt.subscribe is set (an array), the client subscribes to each listed topic and updates the object's visual properties in real time when messages arrive.

Key Type Default Notes
subscribe[].topic string (required) MQTT topic to subscribe to.
subscribe[].role string (required) Which visual property to update. One of: text, value, state, color, icon, flow.
subscribe[].json_field, subscribe[].json_path, subscribe[].value_path string - JSON extractor path. Matches gauge aliasing. Supports dot paths like "attributes.temperature" and JSONPath-like paths like "$.attributes.current_temperature" or "$['state']". If omitted, the raw message value is used.
subscribe[].path_syntax string "auto" Path parser mode: "auto" (treat $... paths as JSONPath-like, all others as dot paths), "dot", or "jsonpath".
subscribe[].coerce string - Type coercion: "number", "string", "bool". Applied after path extraction and default fallback.
subscribe[].default any - Fallback value when the extracted value is null, missing, or the payload cannot be read using the configured path.
subscribe[].map object - Value-to-visual mapping (see below). If omitted, the client falls back to mqtt.map on the same object/connection.

Subscribe roles:

Role Effect
text Sets the primary visible text. On text objects it updates text. On node objects it updates subtitle when the node already has both label and subtitle; otherwise it updates label.
value Sets secondary visible text, typically subtitle on node objects.
state Sets secondary visible text and resolves map entries to change color and icon based on the state value.
color Sets style.color. If a map is present, the incoming value is resolved through that map first.
icon Sets the object icon name (expects an icon name string, e.g. "lock", "lock_open").
flow Sets the animated and flow_speed properties on connections (numeric value → speed 0–10).

Path notes: - Canvas subscribe paths now match gauge-style field naming. Prefer json_field in new documents; json_path and value_path remain supported aliases. - JSONPath-like support is intentionally lightweight and covers the common forms used by HA payloads: $.state, $.attributes.current_temperature, $.items[0].value, and $['attributes']['friendly_name'].

Map schema (subscribe[].map):

The map object translates incoming values to visual properties. Three formats are supported:

  1. Enum map — key-value pairs mapping string states to colors/icons:

    {
      "map": {
        "on":      { "color": "#FF4CAF50", "icon": "lightbulb" },
        "off":     { "color": "#FF9E9E9E", "icon": "lightbulb_outline" },
        "unavailable": { "color": "#FFFF5722", "icon": "error" }
      }
    }
    

  2. Boolean colors — shorthand for true/false states:

    {
      "map": {
        "bool_colors": { "true": "#FF4CAF50", "false": "#FFFF5722" }
      }
    }
    

  3. Thresholds — numeric ranges (evaluated in order, first match wins):

    {
      "map": {
        "thresholds": [
          { "max": 30, "color": "#FF4CAF50" },
          { "max": 70, "color": "#FFFFC107" },
          { "max": 100, "color": "#FFFF5722" }
        ]
      }
    }
    

Complete subscribe example (smart home dashboard object):

{
  "object_id": "garage_door",
  "type": "node",
  "label": "Garage Door",
  "x": 200, "y": 300,
  "width": 120, "height": 60,
  "mqtt": {
    "publish": {
      "topic": "kingkiosk/ha/command/cover/garage_door",
      "payload": { "action": "toggle" }
    },
    "subscribe": [
      {
        "topic": "kingkiosk/ha/state/cover/garage_door",
        "role": "state",
        "json_field": "state",
        "map": {
          "enum": {
            "open":   { "color": "#FF4CAF50", "icon": "garage_open" },
            "closed": { "color": "#FF9E9E9E", "icon": "garage" },
            "opening": { "color": "#FFFFC107", "icon": "garage_open" },
            "closing": { "color": "#FFFFC107", "icon": "garage" }
          }
        }
      }
    ]
  }
}

Subscribe lifecycle: - Subscriptions are established when the canvas document is loaded. - When a new document replaces the old one, previous subscriptions are torn down first. - When the canvas window is closed, all subscriptions are unsubscribed. - Duplicate topics across objects share a single MQTT subscription internally.

Ports (ports) schema:

Key Type Default Notes
port_id string (required) Port identifier.
pos object - Either { "nx": 0..1, "ny": 0..1 } or { "edge": "north|south|east|west", "t": 0..1 }.
kind string - Optional label/typing (stored only).
label string - Optional label (stored only).
style object - Currently uses style.color for marker fill.

Notes: - If ports is omitted/empty, the renderer uses implicit ports: north, south, west, east, center. - For connections, if port_id is omitted (or does not match any declared port), the renderer falls back to the object center (and also supports the implicit port ids above).

Type-specific keys (stored on the object and used by the renderer):

  • type: node
  • label (string), subtitle (string)
  • icon (object): { "set": "material|sf", "name": "...", "color": "#AARRGGBB", "size_px": 24 }
  • icon_size_px (number, optional alias for icon.size_px)
  • label_font_size_px (number, default 13)
  • subtitle_font_size_px (number, default 11)
  • label_font_weight / subtitle_font_weight (string: normal|bold|w300|w500|w600)
  • content_scale (number, default 1.0) multiplies the node icon and both text sizes together
  • type: text
  • text (string)
  • font_size_px (number, default 16)
  • font_weight (string: normal|bold|w300|w500|w600)
  • color (string: #RRGGBB or #AARRGGBB)
  • align (string: left|center|right)
  • type: shape
  • shape (string: rect|round_rect|circle|line)
  • corner_radius_px (number, default 8)
  • stroke_width_px (number, default 2)
  • Uses style.fill_color and style.stroke_color
  • type: image
  • source (object): { "url": "..." } or { "asset_id": "..." }
  • fit (string: contain|cover|fill, default contain)
  • opacity (number, default 1.0)
  • type: embed
  • embed (object): { "widget_type": "gauge|chart|mqtt_button|mqtt_action_status", "id": "...", "config": { ... } }
  • config is passed through to the embedded widget using the same widget/controller config path as the standalone windowed version.
  • For supported embed types, prefer the same config keys documented in the corresponding widget sections instead of a canvas-specific subset.
  • type: group
  • No additional keys (renders as a transparent rectangle with a border).

Connections (connections)

Common connection keys:

Key Type Default Notes
connection_id string (required) Unique id.
from object (required) { "object_id": "...", "port_id": "..." } (port_id optional).
to object (required) { "object_id": "...", "port_id": "..." } (port_id optional).
style object - Connection style (see below).
route object - Connection routing (see below).
mqtt object {} Optional MQTT bindings (same schema as objects). Subscribe with role: "flow" to animate connections based on a numeric value.
metadata object {} Arbitrary metadata.

Connection style schema (style):

Key Type Default Notes
color string #FFFFFFFF Line color.
width_px number 2.0 Line width.
dash array [] Dash pattern list (alternating draw/gap lengths).
arrow string none none, end, both.
opacity number 1.0 -
animated bool false Renders an animated flow (moving dashes/highlight).
animation_speed int 3 Speed 1-5 (1=very slow at 0.3x, 2=0.6x, 3=1.0x, 4=1.5x, 5=very fast at 2.0x). Clamped to [1,5].

Connection route schema (route):

Key Type Default Notes
kind string auto If manual, uses points.
mode string orthogonal straight, curved, orthogonal.
points array [] For kind: manual: list of { "x": ..., "y": ... }.

Element Commands

Element commands are sent to kingkiosk/{device_id}/element/{element_id}/cmd after the widget is created/registered.

If interaction.remote_enabled is false, canvas-specific commands return an error response (except get_state, which is handled by the common widget mixin).

Command Parameters Description
configure optional interaction, background, grid, viewport Updates view/config settings (does not change objects/connections).
set_document doc Replace entire document (objects + connections + configs).
apply_patch optional base_rev, ops[] Apply a small patch to the document (see patch format below).
add_objects objects Add objects (additive).
set_objects objects Replace all objects.
update_objects objects Deep-merge object updates by object_id.
remove_objects object_ids Remove objects by id.
clear_objects - Remove all objects.
add_connections connections Add connections (additive).
set_connections connections Replace all connections.
update_connections connections Deep-merge connection updates by connection_id.
remove_connections connection_ids Remove connections by id.
clear_connections - Remove all connections.
get_state - Common widget command: returns current state.

Patch format (apply_patch):

Key Type Notes
base_rev int Optional optimistic concurrency; if provided and mismatched, returns {status:"error", code:"rev_mismatch", current_rev} and publishes event: patch_rejected.
ops array List of operations (see below).
correlation_id string Optional; echoed in events.

Patch operations (ops[]) are processed in order:

Key Type Notes
op string set, merge, delete, reorder.
path string JSON-pointer-like path, e.g. /objects/byId/{object_id}/x.
value any For set/merge.
ids array For reorder only.

Supported paths: - /objects/byId/{object_id} or /objects/byId/{object_id}/{field...} - /connections/byId/{connection_id} or /connections/byId/{connection_id}/{field...} - /objects with op: reorder and ids: ["obj1","obj2",...] sets render order - /connections with op: reorder and ids: ["c1","c2",...] sets render order

State fields (published on element state topic)

{
  "type": "canvas",
  "element_id": "canvas-1",
  "widget_id": "canvas-1",
  "rev": 12,
  "counts": { "objects": 7, "connections": 3 },
  "interaction": { "touch_enabled": true, "remote_enabled": true, "edit_mode": false },
  "doc": { "spec": "kingkiosk.canvas.v1", "objects": [], "connections": [] },
  "last_error": { "message": "..." }
}

Canvas Events

Canvas events are published on kingkiosk/{device_id}/element/{element_id}/event:

Event Description Fields
doc_changed Document changed rev, source
patch_applied Patch accepted rev, optional correlation_id
patch_rejected Patch rejected code, current_rev, optional correlation_id
object_moved Local drag interaction object_id, phase (start|change|end), x, y, source (touch)

Animated Text

Widget Type: animatedText

Create/Open (system command: open_animated_text)

Top-level keys:

Key Type Default Notes
command string (required) Must be open_animated_text.
title string Animated Text Window title.
window_id string animated_text_{timestamp} If omitted, an ID is generated.
opacity number 1.0 -
x, y, width, height number - Optional geometry.
spec object - Full animated text spec (see below).
text string - Convenience: text content if you aren't sending spec.
segments array - Optional rich text segments (overrides text).
layout object - Layout config.
style object - Text styling.
tokenization object - Tokenization config.
timeline object - Timeline config.
effects array - Effect list.
audio object - Audio config.
lod object - LOD config.
mqtt object - Stored in state; not used for auto-subscribe in current implementation.
animation object - Accepts { preset: "..." } as shorthand.
preset string - Preset name (see below).
id string - Optional spec id.
correlation_id string - Optional tracking id for response.
response_topic string kingkiosk/{device}/system/response Override response topic.

Notes: - window_id is also used as element_id/widget_id for element commands. - You can provide either a full spec object or top-level keys (they are merged into the spec). - If a new animated text window omits width and height, King Kiosk measures the text/spec and sizes the window to fit the content. Existing windows keep their current size when geometry is omitted. - Close with close_window on kingkiosk/{device_id}/system/cmd using window_id.

Animated Text Spec (spec)

This widget’s core configuration is a single spec object. The system open_animated_text command accepts either: - a full spec object (in spec), plus optional top-level overrides, or - top-level spec fields without spec.

Spec keys:

Key Type Default Notes
id string {window_id} If omitted, falls back to the window id.
text string "" Plain text content (ignored when segments is non-empty).
segments array [] Rich segments (see below).
layout object - Layout config (see below).
style object - Base style (see below).
tokenization object - Tokenization config (see below).
timeline object - Timeline config (see below).
effects array [] Effect stack (see below).
audio object - Optional audio config (see below).
lod object - Optional LOD config (see below).
mqtt object - Stored in state; not auto-subscribed in current implementation.
preset string - Preset name (applied at create time or via set_preset).

Segments schema (segments[]):

Key Type Default Notes
text string "" Segment content.
style object {} Partial style patch applied only for this segment (same keys as style).

Layout schema (layout):

Key Type Default Notes
wrap string word Controls line wrapping; set to none to disable wrapping.
maxLines / max_lines int - Max visible lines.
alignment string left left, center, right.
lineHeight / line_height number 1.0 -
letterSpacing / letter_spacing number 0.0 -
wordSpacing / word_spacing number 0.0 -
overflow string clip Stored only; renderer currently uses clipping.

Style schema (style):

Key Type Default Notes
fontFamily / font_family string - -
fontSize / font_size number 32.0 -
weight string 600 Passed through to Flutter’s FontWeight parsing.
color string #FFFFFFFF #RRGGBB or #AARRGGBB.
stroke object - See below.
shadow object - See below.

Stroke schema (style.stroke):

Key Type Default Notes
width number 0.0 -
color string #00000000 Stroke color.

Shadow schema (style.shadow):

Key Type Default Notes
blur number 0.0 Blur radius.
dx number 0.0 X offset.
dy number 0.0 Y offset.
color string #00000000 Shadow color.

Tokenization schema (tokenization):

Key Type Default Notes
mode string grapheme grapheme, word, line, segment.
animateBy / animate_by string character Stored only (not currently used).
preserveSpaces / preserve_spaces bool false When true, spaces become tokens and can animate.
rtl string auto Stored only (not currently used).

Timeline schema (timeline):

Key Type Default Notes
mode string once once or loop.
loopCount / loop_count int 0 Stored only (not currently enforced).
direction string forward Stored only (not currently enforced).
delayMs / delay_ms int 0 Delay before effects start.
repeatDelayMs / repeat_delay_ms int 0 Delay between loops.

Effects schema (effects[]):

Common keys:

Key Type Default Notes
type string fade See supported types below.
durationMs / duration_ms int 500 -
startOffsetMs / start_offset_ms / startOffset int 0 -
easing string linear Supported: linear, easeOutCubic, easeInOutCubic, easeOutBack.
stagger object - { "by": "tokenIndex", "eachMs": 0 } (alias: each_ms). Only eachMs is used by the renderer.

Supported effect types: - fade: uses numeric from/to (effect.from.opacity/effect.to.opacity also accepted). - typewriter: treated like fade (typically paired with token staggering). - slide: uses from: {x,y}, to: {x,y} in pixels. - scale: uses numeric from/to. - colorize: set mode: "solidLerp" with from/to colors, or set mode: "paletteCycle" with colors: ["#...","#..."] for palette interpolation. - marquee: scrolls the whole text group; uses speedPxPerSec (default 90), gapPx (default 48), and direction (left/right).

Audio schema (audio):

Key Type Default Notes
enabled bool false -
mode string perCharacter Stored only; the renderer emits at most one sound per token step.
sound string notification AudioService key.
volume number 0.2 Stored only; AudioService implementation decides final mix.
rateLimit object - { "maxPerSecond": 12, "burst": 4 } (alias: max_per_second for maxPerSecond).

LOD schema (lod):

Key Type Default Notes
maxGraphemes / max_graphemes int 0 If > 0 and the text exceeds this, the renderer falls back.
fallbackAnimateBy / fallback_animate_by string word Used as the fallback tokenization mode.

MQTT schema (mqtt):

Key Type Notes
subscribe.textTopic / subscribe.text_topic string Stored only.
subscribe.styleTopic / subscribe.style_topic string Stored only.
subscribe.effectTopic / subscribe.effect_topic string Stored only.
subscribe.triggerTopic / subscribe.trigger_topic string Stored only.
publish.eventsTopic / publish.events_topic string Stored only.

Background decoration keys (not part of spec, stored on the tile metadata):

Key Type Default Notes
background_mode string color transparent, color, gradient, image.
background_color string #000000 Base color for color/gradient.
background_opacity number 0.8 Clamped to 0.01.0.
background_image_url string - Used when background_mode: image.

Element Commands

Element commands are sent to kingkiosk/{device_id}/element/{element_id}/cmd after the widget is created/registered.

Command Parameters Description
configure any spec fields Replaces the entire spec from the payload (missing fields fall back to defaults). Prefer set_* commands for targeted updates.
set_text text Replace text content.
set_segments segments Replace segment list.
set_style style Replace text style.
set_layout layout Replace layout config.
set_tokenization tokenization Replace tokenization config.
set_timeline timeline Replace timeline config.
set_effects effects Replace effects list.
set_audio audio Replace audio config.
set_preset preset Apply a preset (see below).
trigger optional source Restarts animation sequence and publishes event: play.

Preset names currently supported: - typewriterShimmer - neonPulse - bounceCascade - alertFlash - tickerMarquee

State fields (published on element state topic)

Field Type Notes
type string animatedText
element_id string Same as window_id.
widget_id string Same as window_id.
spec object Full animated text spec currently applied.

Animated Text Events

Standard widget lifecycle events apply (created, closed, error). This widget also publishes:

Event Description Fields
doc_changed Spec updated via MQTT source
play Triggered animation restart source

Clock

Widget Type: clock

Create/Open (system command: open_clock)

Top-level keys:

Key Type Default Notes
command string (required) Must be open_clock.
title string Analog Clock Window title.
window_id string (auto) If provided, creates with that ID.
opacity number 1.0 -
x, y, width, height number - Optional geometry.
mode string - analog or digital.
image_url string - Network image URL.
theme string - auto, light, dark.
show_numbers bool/string - Truthy values accepted.
show_second_hand bool/string - Truthy values accepted.

Element Commands

This widget may optionally support element-scoped commands on kingkiosk/{device_id}/element/{element_id}/cmd only if it registers a handler with MqttWidgetRouter.registerWidget(...).

Clock configuration keys (used by open_clock):

Key Type Notes
mode string analog or digital.
image_url string Sets network_image_url.
show_numbers bool/string Truthy values accepted.
show_second_hand bool/string Truthy values accepted.
theme string -
background_mode string One of: transparent, gradient, color, image.
background_color string #RRGGBB or #AARRGGBB.
background_opacity number/string Clamped to 0.01.0.
background_image_url string -
visible bool -

Important distinction: the background_* keys above are part of the clock widget's own background system. If you want to style the shared outer window shell instead, use the shared window surface keys documented earlier (surface.* or window_* aliases).

Element Commands (topic: kingkiosk/{device_id}/element/{element_id}/cmd)

Clock currently implements element commands via the per-element router.

Command Parameters Description
set_mode mode Set display mode.
toggle_mode - Toggle analog/digital.
configure see configure keys above Configure appearance.
minimize - Minimize/hide.
maximize / restore - Restore.
close - Close.

State fields (published on element + widget state topics)

{
  "type": "clock",
  "element_id": "clock-1",
  "widget_id": "clock-1",
  "mode": "analog",
  "visible": true,
  "minimized": false,
  "show_numbers": true,
  "show_second_hand": true,
  "theme": "auto",
  "background_mode": "transparent",
  "background_opacity": 0.6
}

Weather (OpenWeather)

Widget Type: weather

Create/Open (system command: open_weather_client)

Top-level keys used:

Key Type Default Notes
command string (required) Must be open_weather_client.
name string Weather Window title.
window_id string (auto) -
opacity number 1.0 -
x, y, width, height number - Optional geometry.
api_key string - OpenWeather API key.
location string - City name (alternative to coordinates).
units string imperial metric, imperial, or standard.
language string en Controller maps: en, de, fr, es, it; others default to en.
show_forecast bool/string/int false Accepts true/false, "true"/"false", "yes"/"on", 1/0.
auto_refresh bool/int true If int > 0, treated as refresh interval seconds.
refresh_interval int/string 3600 (default) Parsed as int; controller fallback is 300 if parse fails.

Element Commands

Element-scoped commands on kingkiosk/{device_id}/element/{element_id}/cmd:

Command Parameters Description
configure Any config keys below Update widget configuration.
refresh - Force a weather data refresh.
toggle_forecast - Toggle forecast panel visibility.
set_location location (string) Change weather location.
hide - Hide the widget.
show - Show the widget.

Weather configuration keys (used by open_weather_client and configure):

Key Type Notes
api_key string Required for fetching.
location string City name.
latitude, longitude number/string Coordinate alternative.
units string metric, imperial, standard (default: imperial).
language string Mapped set; defaults to en.
show_forecast bool/string/int Accepts true/false, "true"/"false", 1/0.
auto_refresh bool/int If int > 0, also sets refresh interval seconds.
refresh_interval int/string Parsed int; default fallback 300.
allow_bad_cert bool/string/int DEV ONLY. Accepts true/false, "true"/"false", "yes"/"on", 1/0.

Note: latitude, longitude, and allow_bad_cert are only processed via element-level configure commands; they are not passed through the open_weather_client system command handler.


Alarmo

Widget Type: alarmo

Create/Open (system command: alarmo / alarmo_widget)

Top-level keys used:

Key Type Default Notes
command string (required) alarmo or alarmo_widget.
name string Alarmo Window title.
window_id string (auto) -
opacity number 1.0 -
x, y, width, height number - Optional geometry.
entity string - Home Assistant entity id.
require_code bool true Legacy shorthand — sets both require_code_to_arm and require_code_to_disarm.
require_code_to_arm bool true Whether a PIN is required for arming. Overrides require_code.
require_code_to_disarm bool true Whether a PIN is required for disarming. Overrides require_code.
code_required_modes object {} Per-mode override map, e.g. {"away": true, "home": false}. Keys are mode names (away, home, night, vacation, custom). When a mode is present in this map its value takes precedence over require_code_to_arm.
code_length int 4 PIN digit count.
mqtt_base_topic string "alarmo" Used by controller to construct state/command/event topics.
state_topic / command_topic / event_topic string legacy Accepted by create handler for backward compatibility.
area string optional For multi-area Alarmo. Slug format (lowercase, underscores).
available_modes array ["armed_away"] Strings like armed_away, armed_home, armed_night, armed_vacation, armed_custom_bypass.
auto_recovery bool true Enables auto recovery on arm failure.
force bool false Default state for "force arm" (bypass open sensors). Can be toggled in the UI.
skip_delay bool false Default state for "skip exit delay". Can be toggled in the UI.

Element Commands

Element-scoped commands on kingkiosk/{device_id}/element/{element_id}/cmd:

Command Parameters Description
configure Any config keys below Update widget configuration.
arm mode (string, e.g. away), optional code (string), optional force (bool), optional skip_delay (bool) Arm the alarm. force bypasses open sensors; skip_delay skips exit delay.
disarm optional code (string) Disarm the alarm.
set_force / force_arm value (bool) Enable/disable force arm toggle.
set_skip_delay / skip_delay value (bool) Enable/disable skip delay toggle.
minimize Minimize the window.
maximize / restore Restore the window.
close Close the window.

Alarmo configuration keys (used by alarmo / alarmo_widget create/open):

Key Type Notes
entity string Home Assistant entity id.
require_code bool Legacy shorthand — sets both arm and disarm code requirement.
require_code_to_arm bool Overrides require_code for arming.
require_code_to_disarm bool Overrides require_code for disarming.
code_required_modes object Per-mode override map, e.g. {"away": true, "home": false}.
code_length int PIN digit count (default 4).
mqtt_base_topic string Base topic (default alarmo).
area string Area name for multi-area setups.
auto_recovery bool Enable auto recovery on failure.
available_modes array Strings starting with armed_ are parsed into allowed arm modes.
force bool Default force arm state (bypass open sensors).
skip_delay bool Default skip exit delay state.

MQTT Button (MQTT Action Status)

Widget Type: mqtt_action_status (preferred system command name: mqtt_button)

Create/Configure (system command: mqtt_button / mqtt_action_status / action_status)

This handler supports “create on configure”: if action == configure and window_id does not exist, it will create a new tile.

Top-level keys used:

Key Type Default Notes
command string (required) mqtt_button / mqtt_action_status / action_status.
action string trigger Common values: configure (alias: update_config), trigger (alias: execute), publish/send, toggle, set_status.
window_id string - Required for window-scoped actions; optional for generic publish.
topic string - Convenience alias for publish_topic.
payload any - Convenience alias for publish_payload.
publish_topic / publishTopic string - MQTT topic to publish when triggered.
publish_payload / publishPayload object/any - MQTT payload published.
subscription_topic string - Topic to subscribe to for status.
label string - UI label.
mode / display_mode string - toggle/switch or icon_button/button.
icon_on, icon_off string - Icon names (controller maps these to icons).
color_on, color_off string - Named color string (e.g., red, green, blue, grey), hex string (#RRGGBB, #AARRGGBB), or 0x prefixed string.
size number 48.0 Icon size. Clamped to [16.0, 128.0].
confirm bool false If true, publishes an acknowledgement to kingkiosk/{device}/system/response.

Element Commands

This widget may optionally support element-scoped commands on kingkiosk/{device_id}/element/{element_id}/cmd only if it registers a handler with MqttWidgetRouter.registerWidget(...).


Charts

Charts are managed via the chart command set.

Rendering defaults now use a dark panel, animated transitions (400ms), gradient fills, rounded bars, styled tooltips, and a larger donut-style pie center.

Visual Defaults

Element Default
Panel background #161A24 → #0F1117 vertical gradient
Primary color #6366F1 (indigo)
Accent color #06B6D4 (cyan)
Grid lines Dashed horizontal lines (#4B5568 with alpha)
Pie palette Indigo, cyan, amber, red, violet, emerald, orange
Pie center radius 48
Bar corners Rounded top corners (6px)

create_chart

Key Type Default Notes
chart_id string (required) Identifier.
window_id string chart_id -
chart_type string - Preferred. Alias: type.
type string - Alias for chart_type.
max_points int 60 Max points retained.
mqtt_topic_prefix string kingkiosk Used for publish/subscribe topic construction.
title string - -
opacity, x, y, width, height number - Optional geometry.

append_chart_data

Key Type Notes
chart_id string Required.
value number Required.
mqtt_topic_prefix string Optional.

replace_chart_data

Key Type Notes
chart_id string Required.
values array Required.
mqtt_topic_prefix string Optional.

update_pie_chart

Key Type Notes
chart_id string Required.
slices array Required.
mqtt_topic_prefix string Optional (default kingkiosk).

Slice schema:

Key Type Notes
value number Required.
label string Optional.
color string/int Optional. Accepts #RRGGBB, #AARRGGBB, or int ARGB.

configure_chart

Key Type Notes
chart_id string Required.
config object Required.
mqtt_topic_prefix string Optional (default kingkiosk).

Known configure_chart command config keys:

Key Type Notes
type string bar, pie, line.
primaryColor string/int Color.

Note: configure_chart (system command) currently applies type and primaryColor. For title and full visual options, publish directly to the chart config topic below.

reset_chart

Key Type Notes
chart_id string Required.
mqtt_topic_prefix string Optional (default kingkiosk).

delete_chart

Key Type Notes
chart_id string Required.
window_id string Optional (defaults to chart_id).
mqtt_topic_prefix string Optional (default kingkiosk).

list_charts

No parameters. Returns a list of all chart tiles.

Direct MQTT Chart Topics (Controller-Level)

These topics are also supported by the chart controller and expose the full config surface.

Topic Direction Purpose
{prefix}/chart/{chartId}/config Subscribe Apply chart configuration
{prefix}/chart/{chartId}/data Subscribe Append/replace time-series data
{prefix}/chart/{chartId}/pie Subscribe Replace pie slices
{prefix}/chart/{chartId}/reset Subscribe Clear chart data

Config topic keys ({prefix}/chart/{chartId}/config):

Key Type Notes
type string line, bar, pie
title / chart_title string In-panel chart title
primaryColor string/int Primary chart color
showGrid bool Show dashed horizontal grid lines
showAxes bool Show axis labels
showDots bool Line chart dots
curvedLines bool Curved line interpolation
fillBelow bool Gradient fill under line
lineStrokeWidth number Line thickness
barWidth number Bar width
minY, maxY number Fixed y-axis bounds
showLabels bool Pie labels
pieCenterSpaceRadius number Donut center radius
pieSectionsSpace number Gap between pie slices
pieRadius number Pie slice radius

Data topic payloads ({prefix}/chart/{chartId}/data):

  • Append: { "append": 72.5 }
  • Replace: { "replace": [68, 70, 72] }
  • Replace (array form): [68, 70, 72]

MQTT Gauges

The Gauge widget provides visual representation of values within a range, supporting multiple display styles and interactive controls. Designed for kiosk applications like thermostats, meters, and dashboards.

Rendering is now fully custom-painted (no third-party gauge package), with animated value transitions (600ms, easeOutCubic) for both primary values and pointers.

Core Features

  • Display Styles: linear, circular/radial, semicircular, thermostat
  • Interactive Mode: User can adjust values via remote/touch/keyboard
  • Locked Mode: Display-only, values controlled via MQTT
  • Multi-Pointer Support: Multiple indicators on single gauge (e.g., current temp + setpoints)
  • Thresholds/Zones: Color zones based on value ranges
  • MQTT Bidirectional: Subscribes to value updates, publishes user changes
  • Thermostat Dual Setpoint Mode: Heat/cool range arc with current pointer and mode indicator (Heating / Cooling / Idle)
  • Safe Thermostat Interaction: In multi-pointer thermostat mode, setpoints update only when dragging a pointer handle (background taps do not change values)

Visual Defaults

Element Default
Track background #2A2D35
Value color theme #6366F1 → #06B6D4
Label color #B0B8C8
Track thickness 12px
Thermostat heat color #FF6B35
Thermostat cool color #4FC3F7

Create Gauge (create_gauge, create_mqtt_gauge)

Key Type Default Notes
gauge_id string (required*) Unique identifier for the gauge
window_id string gauge_id Window/tile identifier
title string "Gauge {gauge_id}" Display title
gauge_type string "linear" Style: "linear", "circular", "radial", "semicircular", "thermostat"
orientation string "horizontal" Linear gauge orientation: "horizontal" or "vertical" (only applies to gauge_type: "linear")
startAngle number (per type) Arc start angle in degrees (radial/semicircular/thermostat). Defaults: radial -30, circular 0, semicircular 180, thermostat 135.
endAngle number (per type) Arc end angle in degrees. Defaults: radial 210, circular 360, semicircular 0, thermostat 405. Override both to reposition the arc (e.g. startAngle: 0, endAngle: 180 for a bottom semicircle).
min number 0 Minimum value
max number 100 Maximum value
default_value number 0 Initial value (alias: value)
value number 0 Alias for default_value
unit string "" Unit label (e.g., "°F", "%", "kW")
interactive bool true Allow user to adjust value
locked bool false Lock primary value (read-only display)
step_size number null Increment step for user adjustments (alias: stepSize). If omitted/null, values are continuous (no snapping).
decimals number 0 Decimal places to display (0-4)
mqtt_topic_prefix string "kingkiosk" Base topic for pub/sub
color_mode string - "gradient", "thresholds", "solid", "zones"
show_min_max bool true Show min/max labels
show_value bool true Show current value
thresholds array - Color threshold definitions (see below)
zones array - Color zone definitions (see below)
backgroundColor string "#2A2D35" Track/arc background color. Use "#00000000" for fully transparent. Accepts #RRGGBB or #AARRGGBB.
valueBarColor string "#6366F1" Value bar/arc fill color.
thickness number 12 Track thickness in pixels.
valueBarThickness number 12 Value bar thickness in pixels.
borderRadius number 12 Corner radius for the widget.
enableAnimation bool true Enable animated value transitions.
animationDuration int 1000 Animation duration in milliseconds.
showLabels bool true Show tick/ruler labels.
show_indicator / showIndicator bool true Show the draggable end-cap/handle on linear gauges. Set false for a cleaner thermometer/fill-bar look.
rulerPosition string "bottom" Ruler label position: "top", "bottom", "left", "right", "center".
inverseRulers bool false Invert ruler direction.
labelFontSize number 12 Label font size.
labelColor string "#B0B8C8" Label text color.
config object - Additional configuration (pointers, zones)
os_widget bool false Create native OS widget (Android/iOS home screen)
mqtt_topic string - MQTT topic for OS widget to subscribe to (required if os_widget: true)
json_field string - OS widget JSON extraction path (for os_widget). In-app multi-pointer extraction uses pointers[].json_field.
opacity, x, y, width, height number - Optional geometry

Important: In-app gauges do not use top-level subscribe_topic / publish_topic. Use pointer-level MQTT fields in pointers[].

Important distinction: backgroundColor in the gauge config changes the gauge's internal track/arc background. It does not control the outer widget window background. To make the whole gauge tile transparent, colored, gradient-backed, or image-backed, use the shared window surface contract (surface.* or window_* aliases).

Gauge key aliases:

  • Styling keys accept either camelCase or snake_case where noted in the implementation.
  • backgroundColor / background_color
  • valueBarColor / value_bar_color
  • showLabels / show_labels
  • labelFontSize / label_font_size / label_font_size_px
  • labelColor / label_color
  • show_indicator / showIndicator

Threshold Object:

Key Type Required Notes
value number Yes Threshold value
color string Yes Hex color (e.g., "#3498db")
label string No Optional label (e.g., "Cold")

Zone Object:

Key Type Required Notes
min number Yes Zone start value
max number Yes Zone end value
color string Yes Hex color
label string No Optional label

Example: Create Thermostat Gauge (Dual Setpoints + Current Pointer + Humidity)

{
  "command": "create_gauge",
  "gauge_id": "upstairs-thermostat",
  "title": "Upstairs",
  "gauge_type": "thermostat",
  "min": 50,
  "max": 90,
  "unit": "°F",
  "step_size": 1,
  "mqtt_topic_prefix": "kingkiosk",
  "pointers": [
    {
      "id": "current",
      "label": "Current",
      "style": "needle",
      "color": "#E5E7EB",
      "locked": true,
      "subscribe_topic": "kingkiosk/ha/state/climate/upstairs",
      "json_field": "attributes.current_temperature"
    },
    {
      "id": "heat",
      "label": "Heat",
      "style": "dot",
      "color": "#FF6B35",
      "locked": false,
      "subscribe_topic": "kingkiosk/ha/state/climate/upstairs",
      "publish_topic": "kingkiosk/ha/command/climate/upstairs",
      "json_field": "attributes.target_temp_low"
    },
    {
      "id": "cool",
      "label": "Cool",
      "style": "dot",
      "color": "#4FC3F7",
      "locked": false,
      "subscribe_topic": "kingkiosk/ha/state/climate/upstairs",
      "publish_topic": "kingkiosk/ha/command/climate/upstairs",
      "json_field": "attributes.target_temp_high"
    },
    {
      "id": "humidity",
      "label": "Humidity",
      "style": "dot",
      "color": "#94A3B8",
      "locked": true,
      "subscribe_topic": "kingkiosk/ha/state/climate/upstairs",
      "json_field": "attributes.current_humidity"
    }
  ]
}

Thermostat dual-mode detection: - current < heat => Heating - current > cool => Cooling - otherwise => Idle

Thermostat center text behavior: - Dual setpoint: HEAT ... COOL, DRAG DOT TO ADJUST, plus mode text (Heating/Cooling/Idle) - If a humidity pointer is present, the center also shows HUMIDITY xx%

Example: Create Gauge with Native OS Widget

{
  "command": "create_gauge",
  "gauge_id": "outdoor_temp",
  "title": "Outdoor Temperature",
  "gauge_type": "radial",
  "min": -20,
  "max": 120,
  "unit": "°F",
  "decimals": 1,
  "color_mode": "thresholds",
  "thresholds": [
    {"value": 32, "color": "#3498db", "label": "Freezing"},
    {"value": 70, "color": "#2ecc71", "label": "Comfortable"},
    {"value": 90, "color": "#e74c3c", "label": "Hot"}
  ],
  "os_widget": true,
  "mqtt_topic": "weather/outdoor/temperature",
  "json_field": "temp_f"
}

This creates both an in-app gauge and registers it as a native OS widget that can be added to the Android home screen or iOS home/lock screen. The widget independently subscribes to weather/outdoor/temperature and extracts the value from the temp_f JSON field.

Update Gauge Value (set_value, set_gauge_value, update_gauge_value)

Key Type Required Notes
gauge_id string Yes* Gauge identifier
window_id string Yes* Alias for gauge_id
value number Yes New value to display
mqtt_topic_prefix string No Default "kingkiosk". Used to construct controller tag.

*Either gauge_id or window_id is required

Configure Gauge (set_gauge_config, configure_gauge)

Key Type Required Notes
gauge_id / window_id string Yes* Gauge identifier
config object No Optional nested config object (merged with top-level keys).
mqtt_topic_prefix string No Default "kingkiosk". Used to construct controller tag.
min number No Minimum value
max number No Maximum value
value number No Current value
unit string No Unit label
label string No Additional label text
gauge_type string No Display style
orientation string No Linear gauge orientation: "horizontal" or "vertical"
startAngle number No Arc start angle in degrees (radial/semicircular/thermostat)
endAngle number No Arc end angle in degrees
interactive bool No Allow user interaction
locked bool No Lock value display
step_size number No Step increment
decimals number No Decimal places
show_min_max bool No Show min/max labels
show_value bool No Show current value
color_mode string No "gradient", "thresholds", "solid", "zones"
thresholds array No Color threshold definitions
zones array No Color zone definitions
pointers array No Pointer definitions
backgroundColor string No Track/arc background color (#RRGGBB or #AARRGGBB). Use "#00000000" for fully transparent.
valueBarColor string No Value bar/arc fill color
thickness number No Track thickness in pixels
valueBarThickness number No Value bar thickness in pixels
borderRadius number No Corner radius
enableAnimation bool No Enable animated value transitions
animationDuration int No Animation duration in milliseconds
showLabels bool No Show tick/ruler labels
show_indicator / showIndicator bool No Show the linear-gauge end-cap/handle
rulerPosition string No "top", "bottom", "left", "right", "center"
inverseRulers bool No Invert ruler direction
labelFontSize number No Label font size
labelColor string No Label text color

Note: backgroundColor here is still the gauge's internal track/arc styling, not the shared outer window background.

Alias notes for set_gauge_config:

  • backgroundColor or background_color
  • valueBarColor or value_bar_color
  • showLabels or show_labels
  • labelFontSize, label_font_size, or label_font_size_px
  • labelColor or label_color
  • show_indicator or showIndicator

Lock/Unlock Commands

lock_gauge: Lock gauge to prevent user interaction

{
  "command": "lock_gauge",
  "gauge_id": "thermostat-1"
}

unlock_gauge: Unlock gauge to allow user interaction

toggle_gauge_lock: Toggle the lock state

Multi-Pointer Support

For thermostat-style gauges with multiple indicators (current temperature + setpoints):

Pointer Properties:

Property Type Required Default Notes
id string Yes - Unique pointer identifier
value number No 0 Initial value
label string No "" Pointer label
color string No "#00BFFF" Hex color
icon string No - Icon name
locked bool No false Prevent user adjustment
style string No "needle" "needle", "dot", "triangle", "line", "target"
subscribe_topic string No - MQTT topic to receive value updates
publish_topic string No - MQTT topic to publish user changes
publish_payload object No - Optional custom payload template. Supports {{value}}, {{pointer_id}}, {{gauge_id}}, {{timestamp}}, {{current}}, {{heat}}, {{cool}} tokens.
json_field string No - Dot-path field extractor for JSON payloads (aliases: json_path, value_path)

For Home Assistant climate payloads, a common mapping is: - current -> attributes.current_temperature - heat/low -> attributes.target_temp_low - cool/high -> attributes.target_temp_high - humidity -> attributes.current_humidity (renders as center text on thermostat gauges)

Auxiliary pointer values such as humidity are not clamped to gauge min/max; temperature-related pointers continue to clamp to the configured range.

All pointers may share one subscribe_topic; the controller de-duplicates subscriptions and updates each pointer using its own json_field.

Interaction behavior for thermostat multi-pointer gauges: - Drag must begin on/near an unlocked setpoint handle to adjust - Tap/click on the dial background does not change setpoints

When publish_topic matches */ha/command/climate/* and publish_payload is not provided, the gauge now publishes Home Assistant bridge-compatible commands by default:

{
  "service": "set_temperature",
  "data": {
    "target_temp_low": 68,
    "target_temp_high": 76
  }
}

For single-setpoint pointers, fallback payload is:

{
  "service": "set_temperature",
  "data": {
    "temperature": 72
  }
}

Custom range thermostat publish_payload examples:

Heat pointer template:

{
  "id": "heat",
  "publish_topic": "kingkiosk/ha/command/climate/upstairs",
  "publish_payload": {
    "service": "set_temperature",
    "data": {
      "target_temp_low": "{{value}}",
      "target_temp_high": "{{cool}}"
    }
  }
}

Cool pointer template:

{
  "id": "cool",
  "publish_topic": "kingkiosk/ha/command/climate/upstairs",
  "publish_payload": {
    "service": "set_temperature",
    "data": {
      "target_temp_low": "{{heat}}",
      "target_temp_high": "{{value}}"
    }
  }
}

Template variables accepted in publish_payload: - {{value}}, {{pointer_id}}, {{gauge_id}}, {{timestamp}} - {{current}}, {{heat}}, {{cool}}

set_pointer_value: Update a specific pointer's value

{
  "command": "set_pointer_value",
  "gauge_id": "nest-thermostat",
  "pointer_id": "current",
  "value": 72
}

add_pointer: Add a new pointer to a gauge

{
  "command": "add_pointer",
  "gauge_id": "nest-thermostat",
  "pointer": {
    "id": "humidity",
    "label": "Humidity",
    "color": "#9b59b6",
    "locked": true,
    "style": "dot"
  }
}

remove_pointer: Remove a pointer from a gauge

{
  "command": "remove_pointer",
  "gauge_id": "nest-thermostat",
  "pointer_id": "humidity"
}

Other Gauge Commands

  • delete_gauge: Remove a gauge widget
  • list_gauges: List all active gauge instances

State Publishing

When mqtt_topic_prefix is set, the gauge publishes state updates to:

{mqtt_topic_prefix}/state

Published State Format:

{
  "widget_id": "thermostat-1",
  "type": "gauge",
  "value": 72,
  "min": 50,
  "max": 90,
  "percentage": 55,
  "unit": "°F",
  "label": "Living Room",
  "style": "thermostat",
  "gauge_type": "thermostat",
  "color_mode": "zones",
  "decimals": 0,
  "formatted_value": "72 °F",
  "interactive": true,
  "locked": false,
  "step_size": 1,
  "show_min_max": true,
  "show_value": true,
  "pointers": [
    { "id": "current", "value": 72, "locked": true },
    { "id": "setpoint_high", "value": 76, "locked": false }
  ],
  "current_threshold": {
    "value": 70,
    "color": "#2ecc71",
    "label": "Comfort"
  },
  "timestamp": 1704153600
}

User Interaction Publishing

When a user adjusts an interactive pointer, the gauge publishes to:

{mqtt_topic_prefix}/user_input

{
  "gauge_id": "nest-thermostat",
  "pointer_id": "setpoint_high",
  "value": 75,
  "previous_value": 76,
  "timestamp": 1704153600
}

MQTT Topics

Topic Direction Notes
{prefix}/gauge/{gaugeId}/value Subscribe Receive value updates
{prefix}/gauge/{gaugeId}/config Subscribe Receive configuration
{prefix}/gauge/{gaugeId}/status Publish Publish status updates
{prefix}/gauge/{gaugeId}/set Publish Publish user-set values
{prefix}/state Publish Full state (retained)
{prefix}/user_input Publish User interaction events

Platform Notes

  • tvOS: Use Siri Remote D-pad to select pointers and adjust values
  • iOS: Touch/swipe on gauge to adjust, tap pointers to select
  • macOS: Keyboard arrows to adjust, mouse click to select pointers

Carousels

Key Type Notes
window_id string Required.
title string Optional.
items array Optional.
config object Optional; see below.
opacity, x, y, width, height number Optional geometry.

Carousel config keys:

Key Type Notes
auto_play bool -
interval int -
viewport_fraction number -
infinite_scroll bool -
reverse bool -
scroll_direction string vertical or horizontal.
enlarge_center_page bool -
show_indicator bool -
pause_on_interaction bool -
resume_timeout int -
enable_manual_control bool -
disable_center bool -
pad_ends bool -
page_snapping bool -
layout_mode string -

Other carousel commands: add_carousel_item, remove_carousel_item, update_carousel, delete_carousel, list_carousels, plus navigation (navigate_carousel/goto_carousel) with index or target_id and optional animate + duration (ms).

Config/status commands: set_carousel_config, get_carousel_status.

  • Both route to the same implementation which updates the carousel configuration by window_id.
  • get_carousel_status currently does not publish a status payload; it simply returns a generic {success:true, command, timestamp} on response_topic.

Top-level keys for set_carousel_config / get_carousel_status:

Key Type Notes
window_id string Required.
auto_play bool Optional.
interval int Optional.
viewport_fraction number Optional.
infinite_scroll bool Optional.
reverse bool Optional.
scroll_direction string vertical or horizontal. Note: omitting this defaults to horizontal (overrides any existing value).
enlarge_center_page bool Optional.
show_indicator bool Optional.
pause_on_interaction bool Optional.
resume_timeout int Optional.
enable_manual_control bool Optional.

Media (Video/Audio/Image/Web)

play_media

Key Type Default Notes
type string inferred video, audio, image, web, webrtc.
url string (required) Media URL.
style string - For audio: window or visualizer; for video: window or fullscreen (fullscreen not implemented).
loop bool/string false Truthy string accepted.
window_id string - For tiled display.
title string varies Defaults: Kiosk Video / Kiosk Audio / MQTT Image / WebRTC Stream.
opacity, x, y, width, height number - Optional geometry.
hardware_accel bool/string - Temporary hardware accel preference for this request.
allow_bad_cert bool/string false Applies to background audio playback (type: audio without window style).

Audio visualizer options (when type == audio and style == visualizer):

Key Type Default
visualizer_type string fft
bars int 64
smoothing number 0.8
color_scheme string rainbow
show_peaks bool true
peak_decay number 0.95
update_frequency int 60

youtube

Key Type Default Notes
url string (required) YouTube URL.
title string YouTube -
window_id string (auto) If omitted, auto-generated.
opacity, x, y, width, height number - Optional geometry.

Media window control (play, pause, close, plus enter_fullscreen/exit_fullscreen/toggle_fullscreen)

These are window-id based and routed to the appropriate window controller.

Legacy compatibility:

  • pause_media is accepted but deprecated. It logs a warning and routes to the same handler as {command:'pause', window_id: ...}.

Background audio control (play_audio, pause_audio, stop_audio, seek_audio)

These commands control the background audio playback service.

Top-level keys:

Key Type Default Notes
command string (required) One of play_audio, pause_audio, stop_audio, seek_audio.
url string - For play_audio: optional URL to play. If omitted, resumes current audio.
loop bool/string false For play_audio: loop playback. Truthy string accepted.
allow_bad_cert bool/string false For play_audio: allow invalid SSL certificates.
position number/string 0 Only used by seek_audio (seconds).

Notes:

  • These handlers perform actual media control actions via MediaControlService, but do not publish MQTT success/error responses.

Emergency media reset (reset_media)

This triggers the media recovery service to reset media resources.

Top-level keys:

Key Type Default Notes
command string (required) Must be reset_media.
force bool/string false If true, forces reset behavior in the recovery service.
test bool/string false If true, runs a health report only (no reset).

Published topics:

  • If test == true, publishes health status to kingkiosk/{device}/status/media_health.
  • If a reset is performed successfully, publishes a report to kingkiosk/{device}/status/media_reset with: {success:true, timestamp, resetCount, forced, audioRestored, audioUrl}.

Notes:

  • The handler attempts to capture/restore background audio across the reset when possible.

Web / PDF

open_browser / open_web / open_simple_web

Key Type Default
url / initial_url string (required)
title string Simple Web
window_id string (auto)
opacity, x, y, width, height number -

Note (tvOS): Apple TV maps open_browser / open_web / open_simple_web to create_remote_browser.

Note (Linux): Linux now maps open_browser / open_web / open_simple_web to create_remote_browser (remote browser), because local in-app webview support is not available.

Note (Flutter): open_browser / open_web are aliases for open_simple_web (SimpleWeb).

webrtc_player

Opens a native WHEP WebRTC stream tile for low-latency streaming.

Key Type Default
url string (required)
webrtc_url string -
title string WebRTC Player
window_id string (auto)
centered bool false
opacity, x, y, width, height number -

Example:

{
  "command": "webrtc_player",
  "url": "http://192.168.0.199:1984/webrtc.html?src=Backyard_Camera",
  "title": "Backyard Camera",
  "centered": true,
  "width": 640,
  "height": 480
}

open_pdf

Key Type Default
url string (required)
title string PDF Document
window_id string (auto)
opacity, x, y, width, height number -

Note: runtime web/PDF actions (refresh, paging, etc.) are not currently exposed as a canonical MQTT command surface. Treat these windows as configured via their open_* system commands.


Calendar

System command: calendar

Top-level keys:

Key Type Default Notes
action string - show, create, hide, add_event, remove_event, clear_events, go_to_date, format.
name string Calendar -
window_id string (auto) Used for create/hide.
opacity, x, y, width, height number - Optional geometry.

Event management actions are forwarded to CalendarController.handleMqttCalendarCommand(...).


Timers / Stopwatch

System commands:

Command Keys
stopwatch name, window_id, config (object), plus common geometry keys
timer_widget name, window_id, config (object), plus common geometry keys
timer_control timer_id (required), action (required), plus any additional keys forwarded to the timer window

Games

System commands:

Command Keys
stop_the_missiles title, optional window_id, optional game_type (default missile_command), optional config (object), optional opacity. Note: geometry keys (x, y, width, height) are parsed but not passed to the tile creator.
game_control window_id, action (start/restart/stop/pause/resume/toggle_sound/set_transparent/set_background_mode/set_background_opacity), plus payload forwarded
close_all_games No keys. Closes all game tiles.
game_state_query window_id (required). Publishes game state to kingkiosk/{device}/game_state.

MQTT Image Tile

System command: mqtt_image

This command creates and manages a tile that updates its displayed image based on MQTT messages.

Top-level keys used:

Key Type Default Notes
command string (required) Must be mqtt_image.
action string open open/create, update_topic, close.
window_name string auto Preferred name key.
name string - Alias for window_name.
window_id string - If provided, used as the tile ID and registers a window controller for basic window actions. Otherwise, window_name is used as the tile ID.
mqtt_topic string (required) Topic to subscribe for image updates.
json_field string - Optional. Extracts image data from JSON using dot notation (e.g. data.image). If omitted, common keys are auto-detected.
is_base64 bool/string false Parsed by toString().toLowerCase() == 'true'.
initial_image / url string - Optional initial display content.
update_interval int/string 0 Milliseconds; stored on the tile when > 0.
opacity number/string 1.0 -
x, y number/string 100 -
width, height number/string 800 / 600 -
response_topic string kingkiosk/{device}/system/response Receives {success, command:'mqtt_image', action, window_name, timestamp}.

Image payload behavior:

  • If json_field is provided (or payload looks like JSON), the handler tries to parse JSON and extract the image value.
  • If is_base64 == true and the extracted value is not a data: URL, the handler will prefix data:image/png;base64,.
  • If is_base64 == false, the handler may still auto-detect large base64 payloads and treat them as data:image/png;base64,....

LED Panel (Programmable Light Display)

A virtual programmable LED light panel. Renders a grid of illuminated shapes (squares, triangles, hexagons) that can be driven by built-in preset animations, per-cell MQTT color control, a JSON expression scripting engine, or scrolling pixel-font text.

Widget type: ledPanel

System Commands

create_led_panel
Key Type Default Notes
window_id string auto-generated Unique window identifier.
title string "LED Panel" Display name.
shape string "hexagon" Cell shape: square, triangle, hexagon.
rows int 8 Number of rows (1-100).
cols int 12 Number of columns (1-100).
gap number 2 Gap between cells in pixels (0-20).
render_mode string "flat" flat (2D) or wall3d (3D with shadows/glow).
brightness number 1.0 Global brightness multiplier (0.0-1.0).
preset string - Optional preset to start immediately.
preset_speed number 1.0 Speed multiplier for the initial preset.
text string - Optional text to display immediately.
scroll bool false Whether initial text should scroll.
scroll_speed number 50 Scroll speed for initial text.
opacity number 1.0 Window opacity.
x, y number - Optional window position.
width, height number 400x300 Optional window size.
configure_led_panel
Key Type Notes
window_id string Required. Target panel.
Any key from create_led_panel - Forwarded to panel controller.
delete_led_panel
Key Type Notes
window_id string Required. Panel to remove.
list_led_panels

No parameters. Returns a list of all active LED panel tiles on the device.


Element Commands

Sent to kingkiosk/{device_id}/element/{panel_id}/cmd.

set_cells

Set individual cell colors by index.

Key Type Notes
cells object Map of cell index (string) to color. Example: {"0": "#FF0000", "5": "#00FF00"}.
set_all

Fill all cells with a single color.

Key Type Notes
color string/int Color value. Accepts #RGB, #RRGGBB, #AARRGGBB, or int ARGB.
set_row

Set all cells in a row to one color.

Key Type Notes
row int Required. Zero-based row index.
color string/int Required. Color value.
set_column

Set all cells in a column to one color.

Key Type Notes
col int Required. Zero-based column index.
color string/int Required. Color value.
set_buffer

Set the entire cell color buffer at once.

Key Type Notes
colors array Array of color strings, one per cell in linear order (row-major).
fill_gradient

Apply a gradient fill across the panel.

Key Type Notes
start string/int Required. Start color.
end string/int Required. End color.
direction string "horizontal" (default) or "vertical".
preset

Start a built-in animation preset.

Key Type Default Notes
name string "rainbow_wave" Preset name (see list below).
speed number 1.0 Speed multiplier.
color string/int - Optional base color for presets that use one (solid, breathing, color_chase, wave).

Available presets:

Preset Description
rainbow_wave Hue cycles across cells with spatial phase offset.
breathing All cells pulse brightness in sync.
color_chase A highlight chases around the perimeter.
sparkle Random cells flash white briefly.
fire Warm orange/red flicker simulation.
matrix Green falling-code columns.
gradient_rotate Slowly rotating angular gradient.
solid Static single color (uses color parameter).
random Random colors per cell, re-randomized at interval.
wave Sine wave brightness pattern sweeping across grid.
stop

Stop the current animation. Cell colors are preserved.

No parameters.

clear

Stop the current animation and set all cells to black (off).

No parameters.

set_text

Display text using the built-in 5x7 pixel bitmap font.

Key Type Default Notes
text string "" Text to display. Supports A-Z, 0-9, common punctuation.
color string/int "#FFFFFF" Text (foreground) color.
bg string/int "#000000" Background color.
scroll bool false Enable scrolling marquee.
speed number 50 Scroll speed (pixels per second).
direction string "left" Scroll direction: left, right, up, down.
set_brightness
Key Type Notes
value number Brightness multiplier (0.0 = off, 1.0 = full).
run_script

Run a JSON expression-based animation script.

Key Type Notes
script object Script definition (see script format below).

Script format:

Key Type Default Notes
fps int 30 Target frames per second.
loop bool true Loop when duration expires.
duration number null Duration in seconds. null = infinite.
variables object {} User-defined variables available in expressions.
per_cell object (required) HSL expressions evaluated per cell per frame.
per_cell.h string "0" Hue expression (0-360).
per_cell.s string "1" Saturation expression (0.0-1.0).
per_cell.l string "0.5" Lightness expression (0.0-1.0).

Built-in variables available in expressions:

Variable Description
t Elapsed time in seconds.
frame Frame number since script start.
cell_x Cell column index (0-based).
cell_y Cell row index (0-based).
cell_index Linear cell index (row-major).
total_cells Total number of cells in the grid.
total_rows Number of rows.
total_cols Number of columns.
cell_dist_center Normalized distance from grid center (0.0-1.0).
cell_angle Angle from grid center in radians.
PI 3.14159...
User variables Any key defined in variables block.

Built-in functions: sin, cos, tan, asin, acos, atan, atan2, abs, floor, ceil, round, sqrt, pow, log, exp, min, max, clamp, lerp, fmod, mod, step, smoothstep, noise (2D simplex), random, sign, fract, if(cond, a, b).

Operators: +, -, *, /, %, ^ (power), ** (power), <, >, <=, >=, ==, !=, &&, ||, ? : (ternary).

configure

Reconfigure the panel at runtime.

Key Type Notes
shape string square, triangle, hexagon.
rows int Number of rows (1-100).
cols int Number of columns (1-100).
gap number Gap in pixels (0-20).
render_mode string flat or wall3d.
brightness number Global brightness (0.0-1.0).
define_glyph

Define a custom pixel-font glyph for text rendering.

Key Type Notes
char string Single character to define (e.g., "★").
bitmap array 2D array of 0/1 values. Each inner array is a row. Standard size: 5 wide x 7 tall.

Element State

Published to kingkiosk/{device_id}/element/{panel_id}/state (retained).

Key Type Description
type string Always "ledPanel".
widget_id string Panel window ID.
shape string Current shape.
rows int Current row count.
cols int Current column count.
gap number Current gap.
render_mode string Current render mode.
brightness number Current brightness.
active_preset string/null Name of running preset, or null.
scroll_text string Currently displayed text.
is_scrolling bool Whether text is scrolling.
total_cells int Total cell count in grid.

RSS Feed Widget

A multi-feed RSS reader with 6 display modes, content filtering, reader overlay, and QR share. Supports RSS 2.0, Atom, and JSON Feed formats. Merges multiple feeds with deduplication, source badges, and automatic refresh.

Widget type: rss

System Commands

create_rss
Key Type Default Notes
window_id string (required) Unique window identifier.
title string "RSS Feed" Display name.
feeds array [] Feed sources. Array of feed objects or simple URL strings.
display_mode string "carousel" ticker, carousel, grid, hero, quote, list.
rotation_interval int 8 Seconds between auto-advance. Alias: rotation_interval_sec.
ticker_speed number 50.0 Scroll speed for ticker mode (pixels/sec).
transition string "fade" Accepted config value: fade, slide, flip, zoom (stored and reported in state; current RSS views use mode-specific animations).
max_articles int 100 Maximum articles across all feeds.
show_images bool true Show article images.
show_source_badge bool true Show colored source name badge.
show_timestamp bool true Show relative time (e.g., "2h ago").
filter object - Content filter config (see filter keys below). Also accepts filters.
quiet_hours object - Quiet hours config (see quiet hours keys below).
background_mode string "transparent" transparent, color, gradient, image.
background_opacity number 0.6 Background layer opacity (0.0-1.0).
background_color string - Hex color for color mode (e.g., "#1A1A2E").
background_image_url string - URL for image mode.
opacity number 1.0 Window opacity.
x, y number - Optional window position.
width, height number 600x400 Optional window size.

Feed object keys:

Key Type Default Notes
url string (required) Feed URL (RSS 2.0, Atom, or JSON Feed).
title string - Display name for source badge. Falls back to feed's <title>.
color string - Badge color hex (e.g., "#FF6B35").
priority int 5 Source weighting hint. Higher values boost article rank in merge sorting.
refresh_interval int 300 Per-feed refresh interval in seconds.
enabled bool true Whether this feed is active.

Feeds also accept a simple string array: "feeds": ["https://feed1.com/rss", "https://feed2.com/atom"].

Filter object keys:

Key Type Default Notes
blocked_keywords array [] Regex patterns to block (matched against title + description).
allowed_keywords array [] Whitelist regex patterns. If non-empty, only matching articles pass.
blocked_categories array [] Category names to block (case-insensitive).
allowed_categories array [] Allowed categories. Empty = allow all.
family_mode bool false Enable built-in family-safe filter (blocks violence, adult, gambling, drugs).
custom_blocked_terms array [] Additional blocked terms. Applied when family_mode=true.

Quiet hours object keys:

Key Type Default Notes
enabled bool false Enable quiet hours.
start_hour int 22 Start hour (0-23).
start_minute int 0 Start minute (0-59).
end_hour int 7 End hour (0-23).
end_minute int 0 End minute (0-59).

Quiet hours also accept "start": "HH:MM" and "end": "HH:MM" string format.

delete_rss
Key Type Notes
window_id string Required. Widget to remove.
list_rss

No parameters. Returns all active RSS widgets on the device.

Response:

{
  "status": "success",
  "command": "list_rss",
  "rss_widgets": [
    { "window_id": "news-feed", "name": "News" }
  ],
  "count": 1
}


Element Commands

Sent to kingkiosk/{device_id}/element/{rss_widget_id}/cmd.

set_feeds

Replace all feed sources.

Key Type Notes
feeds array Array of feed objects (see feed object keys above).
add_feed

Add a single feed source. Top-level keys match feed object keys.

Key Type Notes
url string Required. Feed URL.
title string Optional. Source display name.
color string Optional. Badge hex color.
priority int Optional. Source weighting hint (higher values rank higher).
refresh_interval int Optional. Refresh seconds.
remove_feed
Key Type Notes
url string Required. URL of the feed to remove.
refresh

Force refresh all feeds. No parameters.

next / previous

Navigate to next or previous article. No parameters.

go_to
Key Type Notes
index int Required. Zero-based article index.
set_mode
Key Type Notes
mode string Required. ticker, carousel, grid, hero, quote, list.
set_config / configure

Update display configuration. All keys are optional.

Key Type Notes
rotation_interval int Seconds between auto-advance. Alias: rotation_interval_sec.
ticker_speed number Ticker scroll speed (pixels/sec).
transition string fade, slide, flip, zoom (stored and reported in state; current RSS views use mode-specific animations).
max_articles int Max article count.
show_images bool Show article images.
show_source_badge bool Show source badge.
show_timestamp bool Show time ago.
display_mode string ticker, carousel, grid, hero, quote, list.
background_mode string transparent, color, gradient, image.
background_opacity number 0.0-1.0.
background_color string Hex color.
background_image_url string Background image URL.
set_filters

Update content filters. Top-level keys match filter object keys (see create_rss).

set_quiet_hours

Update quiet hours. Top-level keys match quiet hours object keys (see create_rss).

share

Show QR overlay for current article and publish a share event. No parameters.

expand / collapse

Open or close the reader overlay for the current article. No parameters.

pause / resume

Pause or resume auto-rotation. No parameters.


Element State

Published to kingkiosk/{device_id}/element/{rss_widget_id}/state (retained).

Key Type Description
type string Always "rss".
widget_id string RSS widget window ID.
element_id string Same as widget_id.
display_mode string Current display mode.
feeds array Active feeds [{url, title}].
total_articles int Total article count.
current_index int Current article index.
current_article object {title, source, url} of current article.
is_loading bool Feed refresh in progress.
is_paused bool Auto-rotation paused.
is_expanded bool Reader overlay open.
last_refresh string ISO 8601 timestamp of last refresh.
filters_active bool Whether content filters are active.
quiet_hours_active bool Whether quiet hours are suppressing fetches.

Element Events

Published to kingkiosk/{device_id}/element/{rss_widget_id}/event (non-retained).

Event Fields Description
feed_loaded article_count Feeds refreshed successfully.
share article_url, article_title, source User shared an article (QR shown).
error message Feed fetch or parse error.

Video Conference

Multi-point video/audio conferencing with support for MediaSoup room bridges (intercom) and SIP calls. Each conference window can hold multiple independent endpoints simultaneously. Requires the Feature Server (KingKiosk Core 3) for WebRTC transport.

System Commands — Window Creation

Create or close a video conference window via kingkiosk/{device_id}/system/cmd.

Command Aliases
video_call open_video_call
audio_call open_audio_call

Top-level keys:

Key Type Required Description
command string yes video_call or audio_call
action string no show (default), create, hide, close
window_id string no Custom element ID. Auto-generated if omitted.
name / title string no Display name. Default: "Video Call" / "Audio Call"
x, y number no Position in logical pixels
width, height number no Size in logical pixels. Default: 800x600 (video), 320x120 (audio)
opacity number no 0.0–1.0, default 1.0
showBorder bool no Draw window border
response_topic string no Custom response topic

Example — Create a video call window:

{
  "command": "video_call",
  "action": "show",
  "window_id": "conf-lobby",
  "name": "Lobby Conference",
  "width": 1024,
  "height": 768
}

Example — Close a video call window:

{
  "command": "video_call",
  "action": "close",
  "window_id": "conf-lobby"
}

Element Commands — Conference Control

Once a video call window exists, control it via kingkiosk/{device_id}/element/{element_id}/cmd.

Command Required Params Description
list_rooms List available rooms from the Feature Server room directory
add_room_endpoint room_id Bridge to a MediaSoup room (intercom)
add_sip_endpoint sip_uri (or destination), optional video (bool), from_display (string) Dial a SIP destination. Accepts sip:user@host, user@host, 192.168.1.50, 192.168.1.50:5060
hangup_endpoint endpoint_id Hang up a specific endpoint
hangup_all Hang up all endpoints, return to idle
mute_mic Mute local microphone (idempotent)
unmute_mic Unmute local microphone (idempotent)
toggle_mic Toggle local microphone mute state
set_master_volume volume (0.0–1.0) Set master volume for all endpoints
mute_endpoint endpoint_id Mute a specific endpoint locally
unmute_endpoint endpoint_id Unmute a specific endpoint locally
set_endpoint_volume endpoint_id, volume (0.0–1.0) Set per-endpoint volume
send_dtmf digits (09, *, # — can be a sequence like "123#") Send DTMF to all active SIP endpoints
list_sip_calls List active SIP calls from the gateway (returns call IDs, states, URIs)
accept_incoming Accept an incoming call
reject_incoming Reject an incoming call

Example — List available rooms:

{
  "command": "list_rooms"
}

Response:

{
  "status": "success",
  "command": "list_rooms",
  "rooms": [
    {
      "room_id": "kingkiosk-kitchen-display",
      "display_name": "Kitchen Display",
      "peer_count": 1,
      "has_audio": true,
      "has_video": true,
      "is_callable": true,
      "peers": [
        { "peer_id": "abc123", "display_name": "Kitchen Display" }
      ]
    }
  ]
}

Example — Dial a room:

{
  "command": "add_room_endpoint",
  "payload": {
    "room_id": "kingkiosk-kitchen-display"
  }
}

Example — Dial a SIP endpoint:

{
  "command": "add_sip_endpoint",
  "payload": {
    "sip_uri": "reception@pbx.local",
    "video": true,
    "from_display": "Kitchen Display"
  }
}

Accepted destination forms: sip:user@host, sips:user@host, user@host, 192.168.1.50, 192.168.1.50:5060. The video and from_display fields are optional.

Important: The kiosk must already be joined to its MediaSoup room with an audio producer before dialing. For video calls it should also have a video producer. SIP call state is polled automatically (the gateway does not push state notifications).

Example — Set master volume and mute mic:

{
  "command": "set_master_volume",
  "payload": { "volume": 0.6 }
}
{
  "command": "mute_mic"
}

Example — Hang up a specific endpoint:

{
  "command": "hangup_endpoint",
  "payload": { "endpoint_id": "intercom-1711234567890" }
}

Example — Send DTMF digits (SIP only):

{
  "command": "send_dtmf",
  "payload": { "digits": "123#" }
}

Digits can be a single character or a sequence. Valid characters: 09, *, #.

Example — List active SIP calls:

{
  "command": "list_sip_calls"
}

Response includes all active SIP calls with their callId, state (INITIATING, RINGING, CONNECTED, ON_HOLD, TERMINATING, ENDED, FAILED), remoteUri, and media flags.

State Published

Topic: kingkiosk/{device_id}/element/{element_id}/state (retained)

{
  "type": "videoCall",
  "widget_id": "conf-lobby",
  "conference_active": true,
  "mic_muted": false,
  "master_volume": 0.8,
  "conference_duration": 125,
  "endpoint_count": 2,
  "has_incoming_call": false,
  "incoming_call_id": "",
  "incoming_from_user": "",
  "available_rooms_count": 3,
  "endpoints": [
    {
      "id": "intercom-1711234567890",
      "call_id": "intercom-1711234567890",
      "target_id": "kingkiosk-kitchen-display",
      "display_name": "Kitchen Display",
      "call_type": "intercom",
      "call_state": "connected",
      "is_locally_muted": false,
      "local_volume": 1.0,
      "duration": 125,
      "has_video": true,
      "formatted_duration": "02:05",
      "state_label": "Connected"
    },
    {
      "id": "sip-1711234568000",
      "call_id": "sip-call-42",
      "target_id": "sip:reception@pbx.local",
      "display_name": "reception@pbx.local",
      "call_type": "sip",
      "call_state": "connected",
      "is_locally_muted": false,
      "local_volume": 1.0,
      "duration": 90,
      "has_video": true,
      "formatted_duration": "01:30",
      "state_label": "Connected"
    }
  ]
}

Events Published

Topic: kingkiosk/{device_id}/element/{element_id}/event (non-retained)

Event Fields Description
incoming_call call_id, from_user, has_video An incoming call is waiting

State changes for endpoints (added, removed, state transitions) are reflected in the retained state topic, which updates automatically.

Device-Level Incoming Communications Events

Topic: kingkiosk/{device_id}/communications/event (non-retained)

These events are published for Feature Server recipient-side incoming communications. They are device-level notifications, not element-scoped widget events.

Event Fields Description
incoming_conference_call call_type, call_id, caller, auto_accept_enabled Incoming recipient-side video conference notification.
incoming_conference_call_accepted call_type, call_id, caller, auto_accepted Recipient-side conference auto-opened and joined.
incoming_conference_call_ended call_type, call_id, caller Conference bridge ended.
incoming_conference_call_rejected call_type, call_id, caller, reason Conference could not be attached locally. Current canonical reason is controller_unavailable.
incoming_intercom call_type, call_id, caller, group, auto_accept_enabled Incoming intercom broadcast notification.
incoming_intercom_accepted call_type, call_id, caller, group, auto_accepted Intercom broadcast auto-opened.
incoming_intercom_ended call_type, call_id Intercom broadcast ended.

Notes: - call_type is currently videoconference or intercom. - When autoAcceptVideoconferenceCalls is false, the client publishes incoming_conference_call and stays passive. There is no built-in accept dialog. - When autoAcceptIncomingIntercom is false, the client publishes incoming_intercom and stays passive. There is no built-in accept dialog. - Use these events for custom ringing sounds, alerts, dashboards, or Home Assistant / Node-RED automations.

Integration Example — Automated Conference from Home Assistant

# automation.yaml — Start a conference when doorbell rings
automation:
  - alias: "Doorbell Conference"
    trigger:
      - platform: state
        entity_id: binary_sensor.doorbell
        to: "on"
    action:
      # 1. Create video call window on the kitchen display
      - service: mqtt.publish
        data:
          topic: "kingkiosk/kitchen-display/system/cmd"
          payload: >
            {"command": "video_call", "window_id": "door-conf", "name": "Front Door"}

      # 2. Dial the door camera's room
      - delay: "00:00:02"
      - service: mqtt.publish
        data:
          topic: "kingkiosk/kitchen-display/element/door-conf/cmd"
          payload: >
            {"command": "add_room_endpoint", "payload": {"room_id": "kingkiosk-front-door"}}

      # 3. Unmute mic so occupant can speak
      - service: mqtt.publish
        data:
          topic: "kingkiosk/kitchen-display/element/door-conf/cmd"
          payload: >
            {"command": "unmute_mic"}

Intercom & Broadcast

One-to-many live audio/video broadcasting between KingKiosk devices. Unlike video conferencing (which uses element commands on a conference window), intercom is controlled via direct device-level MQTT topics. Requires the Feature Server (KingKiosk Core 3) for WebRTC transport.

Prerequisites

  • Feature Server must be connected
  • intercomEnabled must be true in device settings
  • Audio production must be enabled (featureServerProduceAudio)
  • For receiving: autoAcceptIncomingIntercom controls whether broadcasts auto-open or only emit MQTT events

Device-Level Commands

These commands are published directly to device topics, not via element or system command topics.

Start Broadcast

Topic: kingkiosk/{device_id}/intercom/start

{
  "group": "default"
}
Key Type Required Description
group string no Intercom group name. Default: "default". Only devices in the same group receive the broadcast.

Begins broadcasting audio and video from this device to all other devices in the same intercom group.

Stop Broadcast

Topic: kingkiosk/{device_id}/intercom/stop

{}

Stops the active broadcast from this device.

Toggle Broadcast

Topic: kingkiosk/{device_id}/intercom/toggle

{}

Starts broadcasting if idle, stops if currently broadcasting.

State Published

Topic: kingkiosk/{device_id}/intercom/status (retained)

{
  "broadcasting": true,
  "group": "default"
}
Field Type Description
broadcasting bool true if this device is currently broadcasting
group string Active intercom group name

Incoming Broadcast Events

When a broadcast reaches this device, events are published on the device-level communications topic (same events listed in the Video Conference section):

Topic: kingkiosk/{device_id}/communications/event (non-retained)

Event Fields Description
incoming_intercom call_type, call_id, caller, group, auto_accept_enabled Broadcast received. If auto_accept_enabled is true, the broadcast auto-opens.
incoming_intercom_accepted call_type, call_id, caller, group, auto_accepted Broadcast was accepted and opened on this device.
incoming_intercom_ended call_type, call_id Broadcast ended by the sender.

When autoAcceptIncomingIntercom is false, the client publishes incoming_intercom and stays passive — it does not auto-open the broadcast window. Use these events to trigger your own ringing, alerts, or automations.

Settings (via Remote Provisioning)

Key Type Description
intercomEnabled bool Enable/disable intercom participation
autoAcceptIncomingIntercom bool Auto-open incoming broadcasts. When false, only MQTT events are emitted.
intercomGroups array\<string> Intercom group memberships (devices only receive from matching groups)

Integration Example — Home Assistant Doorbell Broadcast

automation:
  - alias: "Doorbell Broadcast"
    trigger:
      - platform: state
        entity_id: binary_sensor.doorbell
        to: "on"
    action:
      - service: mqtt.publish
        data:
          topic: "kingkiosk/front-door/intercom/start"
          payload: '{"group": "default"}'
      - delay: "00:00:30"
      - service: mqtt.publish
        data:
          topic: "kingkiosk/front-door/intercom/stop"
          payload: '{}'

Integration Examples

Node-RED: Monitor and Control a Clock Widget

[
    {
        "id": "clock-state-sub",
        "type": "mqtt in",
    "topic": "kingkiosk/my-device/element/clock-1/state",
        "qos": "1"
    },
    {
        "id": "clock-cmd-pub",
        "type": "mqtt out",
    "topic": "kingkiosk/my-device/element/clock-1/cmd",
        "qos": "1"
    }
]

Home Assistant: Widget State Sensor

mqtt:
  sensor:
    - name: "Living Room Clock Mode"
      state_topic: "kingkiosk/my-device/element/clock-1/state"
      value_template: "{{ value_json.mode }}"
      json_attributes_topic: "kingkiosk/my-device/element/clock-1/state"

  button:
    - name: "Toggle Clock Mode"
      command_topic: "kingkiosk/my-device/element/clock-1/cmd"
      payload_press: '{"command": "toggle_mode"}'

Python: List All Widgets on a Device

import paho.mqtt.client as mqtt
import json

def on_message(client, userdata, msg):
    info = json.loads(msg.payload)
    print(f"Device: {info['device_id']}")
    print(f"Active widgets: {info['active_widgets']}")
    for widget_id in info['active_widgets']:
        print(f"  - {widget_id}")

client = mqtt.Client()
client.on_message = on_message
client.connect("broker.local", 1883)
client.subscribe("kingkiosk/+/info")
client.loop_forever()

Canonical Topic Summary

  • Send device-wide commands to kingkiosk/{device_id}/system/cmd
  • Send element-scoped commands (when supported) to kingkiosk/{device_id}/element/{element_id}/cmd
  • Broadcast fleet system commands to kingkiosk/fleet/{fleet_id}/cmd
  • Broadcast fleet element commands to kingkiosk/fleet/{fleet_id}/element/{element_id}/cmd
  • Subscribe for responses on kingkiosk/{device_id}/system/response and/or kingkiosk/{device_id}/element/{element_id}/response
  • Subscribe for retained element state on kingkiosk/{device_id}/element/{element_id}/state

Developer Guide: Adding MQTT Support to Widgets

To add per-widget MQTT support to a widget controller:

1. Add the Mixin

import '../../../widgets/mqtt_widget_mixin.dart';

class MyWidgetController extends GetxController
    with MqttWidgetMixin
    implements KioskWindowController {

  @override
  String get widgetId => windowName;

  @override
  String get widgetType => 'my_widget';

2. Register in onInit

@override
void onInit() {
  super.onInit();
  registerWithMqtt();
}

3. Unregister in onClose

@override
void onClose() {
  unregisterFromMqtt();
  super.onClose();
}

4. Handle Commands

@override
Future<Map<String, dynamic>?> handleMqttCommand(
    Map<String, dynamic> command) async {
  final cmd = command['command'] as String?;

  switch (cmd) {
    case 'my_command':
      doSomething();
      return {'status': 'success'};
    default:
      return null; // Let mixin handle common commands
  }
}

5. Build State

@override
Map<String, dynamic> buildState() {
  return {
    'type': widgetType,
    'widget_id': widgetId,
    'my_value': myValue,
    // ... other state fields
  };
}

6. Publish Events (Optional)

// Publish custom events
publishEvent({'event': 'my_event', 'data': someData});

// Convenience methods
publishSimpleEvent('clicked');
publishError('Something went wrong', 'ERR_CODE');
publishStateChange('idle', 'playing');

Appendix A: LED Panel Scripting Engine Reference

The LED Panel scripting engine is a lightweight expression evaluator that computes each cell's color on every animation frame. Scripts are defined as JSON and sent via the run_script element command. Each cell's color is specified in HSL (Hue, Saturation, Lightness) by evaluating three mathematical expressions per cell per frame.

How It Works

  1. You send a JSON script object via MQTT.
  2. The engine parses the three HSL expressions once (compile step).
  3. On every frame (at the configured fps), for every cell in the grid, the engine:
  4. Sets the built-in variables (t, cell_x, cell_y, etc.) to that cell's values.
  5. Evaluates each expression (h, s, l) to produce a number.
  6. Converts the three numbers into a color: HSLColor(hue, saturation, lightness).
  7. The resulting color map is rendered by the painter.

Because expressions are parsed once and evaluated numerically, performance is excellent even on large grids.

Script JSON Format

{
  "fps": 30,
  "loop": true,
  "duration": null,
  "variables": {
    "speed": 2.0,
    "hue_offset": 120
  },
  "per_cell": {
    "h": "(cell_x * 10 + t * speed + hue_offset) % 360",
    "s": "0.9",
    "l": "0.4 + 0.1 * sin(cell_dist_center * 6.28 - t * 3)"
  }
}
Field Type Default Description
fps int 30 Target frames per second. Higher values are smoother but use more CPU. 15-30 is usually sufficient.
loop bool true When duration expires, restart from t = 0 if true, otherwise stop.
duration number or null null Script duration in seconds. null means run forever until stopped.
variables object {} User-defined named constants available in all expressions. Values must be numbers.
per_cell object (required) Contains the three HSL expression strings.
per_cell.h string "0" Hue expression. Result is taken modulo 360. Range: 0 = red, 60 = yellow, 120 = green, 180 = cyan, 240 = blue, 300 = magenta.
per_cell.s string "1" Saturation expression. Clamped to 0.0-1.0. 0 = grayscale, 1 = fully saturated.
per_cell.l string "0.5" Lightness expression. Clamped to 0.0-1.0. 0 = black, 0.5 = full color, 1 = white.

The HSL Color Model

HSL is used instead of RGB because it maps naturally to the way people think about light panels:

  • Hue (0-360) is the color wheel position. Arithmetic on hue creates smooth color transitions — just add an offset or multiply by time.
  • Saturation (0-1) controls how vivid the color is. Useful for fading to gray.
  • Lightness (0-1) controls brightness. 0 is off/black, 0.5 is full color, 1 is white. This directly maps to "how bright is this cell?"

The engine automatically wraps negative hue values (e.g., -30 becomes 330) and clamps saturation and lightness to valid ranges.

Expression Syntax

Expressions follow standard mathematical notation. They are parsed using a recursive-descent parser with the following precedence (highest to lowest):

Precedence Operators / Constructs Associativity Example
1 (highest) Parentheses, function calls sin(t), (a + b)
2 Unary -, + Right -cell_x, +1
3 Power ^, ** Right 2 ^ 3 = 8
4 Multiply *, divide /, modulo % Left t * 2, h % 360
5 Add +, subtract - Left a + b - c
6 Comparison <, >, <=, >=, ==, != Left cell_x > 5
7 Logical AND && Left cell_x > 0 && cell_y > 0
8 Logical OR || Left a > 0 || b > 0
9 (lowest) Ternary ? : Right t > 5 ? 1.0 : 0.0

Truthiness: In logical and ternary operations, 0.0 is false and any non-zero value is true. Comparison operators return 1.0 for true and 0.0 for false.

Number literals: Integers (42), decimals (3.14), and scientific notation (1.5e3, 2e-4) are supported.

Built-in Variables

These variables are automatically set by the engine before evaluating each cell on each frame.

Time Variables

Variable Type Description
t float Elapsed time in seconds since the script started. This is your primary animation driver. Resets to 0 when a looping script restarts.
frame float Frame number since script start (0, 1, 2, ...). Useful for frame-counting effects.

Grid Variables (constant for the life of the script)

Variable Type Description
total_cells float Total number of cells in the grid.
total_rows float Number of rows in the grid.
total_cols float Number of columns in the grid. For triangle grids, this is the number of triangles per row (cols * 2 - 1).

Per-Cell Variables (change for each cell)

Variable Type Description
cell_x float Column index of the current cell (0-based).
cell_y float Row index of the current cell (0-based).
cell_index float Linear index of the current cell in row-major order (0, 1, 2, ...).
cell_dist_center float Normalized Euclidean distance from the cell to the grid center. Ranges from 0.0 (center cell) to 1.0 (corner cell). Useful for radial effects.
cell_angle float Angle in radians from the grid center to the cell, measured using atan2(row - centerRow, col - centerCol). Useful for spiral and angular effects.

Constants

Variable Value Description
PI 3.14159... Mathematical constant pi.

User Variables

Any key defined in the script's variables block is available as a named variable. User variables are set before built-in variables, so built-in names take precedence if there's a collision.

Built-in Functions

Trigonometric

Function Signature Description
sin(x) 1 arg Sine. Input in radians. Returns -1 to 1.
cos(x) 1 arg Cosine. Input in radians. Returns -1 to 1.
tan(x) 1 arg Tangent. Input in radians.
asin(x) 1 arg Arc sine. Input clamped to [-1, 1]. Returns radians.
acos(x) 1 arg Arc cosine. Input clamped to [-1, 1]. Returns radians.
atan(x) 1 arg Arc tangent. Returns radians.
atan2(y, x) 2 args Two-argument arc tangent. Returns radians (-PI to PI).

Rounding and Sign

Function Signature Description
floor(x) 1 arg Round down to nearest integer.
ceil(x) 1 arg Round up to nearest integer.
round(x) 1 arg Round to nearest integer (half-up).
abs(x) 1 arg Absolute value.
sign(x) 1 arg Returns -1, 0, or 1.
fract(x) 1 arg Fractional part: x - floor(x). Always in [0, 1).

Exponential and Power

Function Signature Description
sqrt(x) 1 arg Square root. Uses abs(x) to avoid NaN.
pow(x, y) 2 args x raised to the power y.
log(x) 1 arg Natural logarithm. Returns 0 for non-positive input.
exp(x) 1 arg e raised to the power x.

Clamping and Interpolation

Function Signature Description
min(a, b) 2 args Smaller of a and b.
max(a, b) 2 args Larger of a and b.
clamp(x, lo, hi) 3 args Constrain x to the range [lo, hi].
lerp(a, b, t) 3 args Linear interpolation: a + (b - a) * t. When t = 0 returns a, when t = 1 returns b.
step(edge, x) 2 args Returns 1.0 if x >= edge, else 0.0. Hard threshold.
smoothstep(edge0, edge1, x) 3 args Hermite interpolation between 0 and 1 when x is between edge0 and edge1. Produces an S-curve transition.

Modular Arithmetic

Function Signature Description
fmod(x, y) 2 args Floating-point remainder of x / y. Same as % operator. Returns 0 if y is 0.
mod(x, y) 2 args Alias for fmod.

Noise and Randomness

Function Signature Description
noise(x, y) 2 args 2D simplex noise. Returns values in approximately [-1, 1]. Smooth, continuous, and deterministic for the same inputs. Ideal for organic, natural-looking effects.
random() 0 args Random number in [0, 1). Different value each call. Non-deterministic — use noise() for repeatable patterns.

Conditional

Function Signature Description
if(cond, a, b) 3 args If cond is non-zero, returns a, else returns b. Equivalent to the ternary operator cond ? a : b. Note: unlike the ternary operator, both branches are always evaluated.

Recipes and Examples

1. Rainbow Wave

A classic hue sweep across the grid, scrolling over time.

{
  "per_cell": {
    "h": "(cell_x * 20 + cell_y * 15 + t * 40) % 360",
    "s": "1.0",
    "l": "0.5"
  }
}

The cell_x * 20 creates horizontal color variation, cell_y * 15 adds diagonal tilt, and t * 40 makes it move. Increase the multipliers for tighter color bands.

2. Pulsing Concentric Rings

Rings of light expand outward from the center.

{
  "variables": { "ring_count": 4, "speed": 2 },
  "per_cell": {
    "h": "200",
    "s": "0.8",
    "l": "0.15 + 0.35 * (0.5 + 0.5 * sin(cell_dist_center * ring_count * 6.28 - t * speed))"
  }
}

cell_dist_center * ring_count * 6.28 creates multiple sine wave rings. Subtracting t * speed makes them expand outward. Change ring_count to control density.

3. Fire Effect

Warm colors flickering upward using noise.

{
  "per_cell": {
    "h": "10 + 25 * noise(cell_x * 0.5, t * 2)",
    "s": "1.0",
    "l": "clamp(0.6 * (1 - cell_y / total_rows) + 0.15 * noise(cell_x * 0.8, cell_y * 0.5 + t * 3), 0.02, 0.7)"
  }
}

Hue varies between orange and red using noise. Lightness decreases from bottom to top (fire rises), with noise adding flicker. clamp prevents it from going fully black or white.

4. Color Zones (Threshold-Based)

Color cells based on their position — useful for status panels.

{
  "per_cell": {
    "h": "cell_x < total_cols * 0.33 ? 0 : cell_x < total_cols * 0.66 ? 60 : 120",
    "s": "0.9",
    "l": "0.45 + 0.05 * sin(t * 2)"
  }
}

Left third is red (hue 0), middle is yellow (60), right is green (120). The lightness gently pulses. Replace the thresholds with sensor-driven user variables for a live status board.

5. Spiral

A color spiral rotating from the center.

{
  "per_cell": {
    "h": "(cell_angle / PI * 180 + cell_dist_center * 360 + t * 60) % 360",
    "s": "0.85",
    "l": "0.3 + 0.2 * cell_dist_center"
  }
}

cell_angle provides the angular component, cell_dist_center adds radial twist, and t * 60 makes it rotate. Cells further from center are slightly brighter.

6. Lava Lamp (Smooth Organic Blobs)

{
  "per_cell": {
    "h": "noise(cell_x * 0.15, cell_y * 0.15 + t * 0.3) * 60 + 280",
    "s": "0.9",
    "l": "0.3 + 0.25 * smoothstep(-0.2, 0.5, noise(cell_x * 0.2 + t * 0.1, cell_y * 0.2 + t * 0.15))"
  }
}

Two layers of simplex noise at different scales create slowly drifting blobs. smoothstep sharpens the blob edges. Hue stays in the purple/magenta range (280 +/- 60).

7. Strobe / Flash to Beat

Flash all cells on a timed interval (e.g., every 0.5 seconds).

{
  "variables": { "bpm": 120 },
  "per_cell": {
    "h": "0",
    "s": "0",
    "l": "fract(t * bpm / 60) < 0.15 ? 1.0 : 0.02"
  }
}

t * bpm / 60 counts beats. fract() gives position within the current beat (0-1). The first 15% of each beat is a bright white flash, then dark. Adjust 0.15 for longer/shorter flashes.

8. Matrix / Digital Rain Per Column

{
  "per_cell": {
    "h": "120",
    "s": "1.0",
    "l": "clamp(0.5 - abs(cell_y - fmod(t * 4 + cell_x * 3.7, total_rows + 4)) * 0.15, 0.01, 0.5)"
  }
}

Each column has a "raindrop" position calculated from time and a per-column phase offset (cell_x * 3.7). Lightness falls off around the drop position using abs(). Green hue (120) for the classic Matrix look.

9. Smooth Color Cycling with Brightness Wave

{
  "per_cell": {
    "h": "t * 20",
    "s": "0.9",
    "l": "0.25 + 0.25 * sin(cell_x * 0.5 + cell_y * 0.3 + t * 1.5)"
  }
}

All cells share the same slowly changing hue, but lightness varies spatially as a diagonal sine wave. Simple yet visually rich.

10. Binary Clock (Advanced)

Display hours and minutes as binary columns (conceptual — requires at least 6 columns and 4 rows).

{
  "variables": { "on_hue": 200, "off_l": 0.05 },
  "per_cell": {
    "h": "on_hue",
    "s": "0.8",
    "l": "fmod(floor(fmod(t / 60, 60) / pow(2, 3 - cell_y)), 2) > 0.5 && cell_x < 6 ? 0.5 : off_l"
  }
}

This uses t / 60 as a minute counter, divides by powers of 2 per row to extract binary digits, and checks each bit. Each column represents a digit, each row a bit position.

Performance Tips

  • Keep fps at 30 or below. 60fps looks no different on most LED panel grids and doubles the CPU cost.
  • noise() is the most expensive function. One noise call per cell per frame is fine. Avoid stacking 3+ noise calls in a single expression on large grids (500+ cells).
  • Constant expressions are free. "s": "0.9" is parsed once and evaluates to a constant — no per-cell cost.
  • Ternary expressions short-circuit. cell_x > 5 ? expensive_expr : 0 still evaluates expensive_expr for every cell (unlike the ? : operator in most programming languages). Use if(cond, a, b) — it has the same behavior. Structure your grid size to minimize unnecessary computation.
  • For very large grids (1000+ cells), consider reducing fps to 15 and simplifying expressions. The engine processes all cells sequentially on the main thread.

KingKiosk Pico Edition — Specific Commands

The following commands are specific to KingKiosk Pico (ESP32 microcontroller edition) and are not available on the Flutter-based clients. These reflect the unique constraints and capabilities of an embedded wall-panel device.

start_ap_provisioning

Reboots the device into WiFi Access Point mode for first-time setup or reconfiguration. The device creates an open WiFi network (e.g., KingPico-F23438) and serves a web form at http://192.168.4.1 where WiFi, MQTT, and device settings can be configured.

{"command": "start_ap_provisioning"}

Also triggerable via a hidden 10-tap gesture: tap the screen 10 times within 5 seconds. A confirmation dialog appears showing current device info (name, MAC, WiFi/MQTT connection status with green/red indicators, timezone) before rebooting.

Auto-activates on first boot when no WiFi SSID is configured.


OTA Firmware Updates

Wall-mounted panels can't be reflashed via USB. KingKiosk Pico supports MQTT-driven over-the-air updates with automatic rollback protection.

update_firmware

{"command": "update_firmware", "url": "http://your-server/firmware.bin"}

Downloads firmware from the URL, writes it to the inactive OTA partition, and reboots. Progress events are published to kingkiosk/{device_id}/system/response.

confirm_update

{"command": "confirm_update"}

Marks the currently running firmware as stable. If not confirmed within 3 boots, the device automatically rolls back to the previous firmware.

rollback

{"command": "rollback"}

Manually rolls back to the previous firmware partition and reboots.

get_ota_status

{"command": "get_ota_status"}

Returns the current OTA state: running partition, firmware version, whether a rollback is available, and whether the current firmware is confirmed.


Alert Dialogs with Confirmation Buttons

While alert is available on all KingKiosk clients, the Pico edition implements the full confirmation button system with MQTT response — matching the Flutter client's centered modal dialog behavior.

{
  "command": "alert",
  "title": "Arm Security?",
  "message": "Arm the alarm system?",
  "type": "warning",
  "confirmation": true
}

When the user presses a button, the response is published:

{
  "success": true,
  "command": "alert",
  "confirmation": true,
  "selection_label": "Yes",
  "selection_value": "true"
}

This enables interactive automation workflows — ask the user a question on the wall panel and act on their response in Home Assistant or Node-RED.


Pico Limitations on Shared Commands

Some commands that exist on both Flutter and Pico have reduced functionality on Pico due to hardware constraints:

  • set_background: Supports color, icon (crown watermark), and none modes only. No image URLs or custom image backgrounds — the ESP32 lacks the RAM and HTTP client to download and decode arbitrary images at runtime.
  • alert: Plain text only. Rich text, markdown, segments, and thumbnail images are not supported.

Features Not Available on Pico

Due to the ESP32's hardware constraints (~200KB RAM, no GPU, no browser engine), the following Flutter client features are not available on KingKiosk Pico:

  • Feature Server integration (intercom, remote browser, RTSP export)
  • AI/ML features (person detection, facial recognition, motion detection)
  • TTS / STT (text-to-speech, speech recognition)
  • Web browser / WebView widgets
  • Media streaming (RTSP, DLNA, YouTube)
  • Custom Widget SDK (JavaScript-based)
  • Fleet management commands
  • Screen scheduling
  • Batch scripting