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:
- Device scope, system-level -
kingkiosk/{device_id}/system/cmd - Device scope, element-level -
kingkiosk/{device_id}/element/{element_id}/cmd - Fleet scope, system-level -
kingkiosk/fleet/{fleet_id}/cmd - 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_topicis 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¶
- Overview
- Platform Compatibility Matrix
- Topic Structure
- Element Commands
- Element State
- Element Events
- System Commands
- Device Info
- Signed Envelope Format
- Widget Type Reference
- 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):
- Device scope
- System commands: control the whole device (
.../system/cmd) - Element commands: control one element/window (
.../element/{element_id}/cmd) - Fleet scope
- System commands: fan out one command to all subscribed devices (
.../fleet/{fleet_id}/cmd) - 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/cmdis 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/+/commandfor backward compatibility. Treat this as deprecated and usesystem/cmdfor 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:
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:
- Parse and validate the
api_urlfield - Normalize the host (extract base URL from api_url if needed)
- Check manual override - If user has enabled "manual override lock", ignore the autodiscovered value
- Update server URL - If not locked, automatically update the Feature Server connection to use the new URL
- 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:
- Direct MQTT subscription (primary)
- Widget extension connects to MQTT broker using
LightMQTTClient - Subscribes to the topic specified in
WidgetConfig.mqttTopic - Updates immediately when messages arrive
-
Frequency limited by OS (iOS: ~15-60min, Android: configurable)
-
Cached value fallback (secondary)
- Main app writes latest values to shared storage via
WidgetDataService.writeCachedValue() - Widget reads cached value on timeline refresh
- Provides instant display even if MQTT connection fails
- Maintains 48-point history for sparkline charts
Widget Lifecycle¶
Registration:
// In MQTT command handler (after creating Flutter widget):
maybeCreateOsWidget(payload, WidgetKind.gauge);
Updates:
Removal:
Or via MQTT:
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:
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¶
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:
Response (on kingkiosk/my-device/element/clock-1/response):
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¶
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¶
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¶
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_topicto control where results are published. - Unless noted otherwise,
response_topicdefaults tokingkiosk/{device_id}/system/response. - Widget creation commands can include
os_widget: trueto 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¶
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¶
Signature Computation¶
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:
- System commands: publish to
kingkiosk/{device_id}/system/cmd. These create windows/tiles and perform global actions. - 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_modeis a preset layer. Explicitsurface.background_*,window_background_*, or widget-specificbackground_*keys override it.transparentremoves the shared shell background and asks participating widgets to suppress their default base background too.translucentapplies a semi-transparent dark shell/background preset without fading the widget content itself.opaqueapplies a solid dark shell/background preset.opacitystill controls the entire window, including the widget content.background_opacityonly controls the shared background layer.preserve_aspect_ratiodefaults totrue.scale_contentdefaults totruefor most native Flutter widgets. It defaults tofalsefor 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_widthanddesign_heightlet 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, andrss. Their top-levelbackground_*keys still style the widget itself.appearance_modenow seeds those widget backgrounds too when explicit widget background keys are not set. Usesurfaceor thewindow_*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, andheightare 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_windowapplies the width and height you send. If the widget hasscale_content: true, its content still scales proportionally inside the resulting rectangle. The built-in drag resize handle also honorspreserve_aspect_ratio: trueby 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: trueto render the border. - Use
update_windowwithwindow_idplusshowBorder: true/falseto change an existing window. - On creation commands, the same flag is also honored when passed inside
surface,config, ormetadata.
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_widgetcloses the most recently created tile whose name containstype(case-insensitive), unlesstype == 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_idis 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%:
Example - Zoom In (element-level, on kingkiosk/{device}/element/browser_1/cmd):
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):
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_brightnesspublishes toresponse_topiconly whenresponse_topicis provided and returns{brightness, type:'application'}.request_brightness_permission/check_brightness_permissionalways returnpermission_granted: true.resume_kiosk_after_permissionperforms 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
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
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):
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
Example: unlock FAB (alias + alternate PIN key)
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 tokingkiosk/{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 tokingkiosk/{device}/security_camera/statuswith{enabled, interval_seconds}.
Responses:
- Also publishes a standardized response to
kingkiosk/{device}/system/responsevia 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 tokingkiosk/{device}/screenshot_camera/statuswith{enabled, interval_seconds}.
Responses:
- Also publishes a standardized response to
kingkiosk/{device}/system/responsevia 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:
Example — enable periodic snapshots every 30 seconds:
Example — enable motion-triggered snapshots:
Example — set JPEG quality to 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}/screenshotas a raw base64 string (base64-encoded PNG bytes, retained). - If
confirm == true, publishes a status JSON payload tokingkiosk/{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,nuclearclear_imagesclear_datarefresh,refresh_resource(requiresurl)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 tocommand.
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 genericvaluekey) - 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, orerrorapplied_settings: list of settings appliedfailed_settings: map of setting key -> reasonscreen_states_imported: imported state namesscreen_states_failed: map of state name -> reasoncurrent_layout_applied: boolcorrelation_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:
settingsis an alias ofconfigfor compatibility.- When
include_secretsisfalse, secret fields are masked as***. - When
include_layoutsistrue, response includesscreen_states,screen_state_count, andcurrent_layout. - The
configobject 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
Example: disable telemetry
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
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 forsend_messagewithmessage,response,status,timestamp.kingkiosk/{device}/ai_agent/conversation_cleared(non-retained): emitted forclear_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(setsaction: 'list'and defaultslimitto 100)get_audit_history(setsaction: 'list'and defaultslimitto 100)clear_command_history(setsaction: 'clear')clear_audit_history(setsaction: 'clear')get_audit_stats(setsaction: '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/getstatsclearquery_by_time/query_time_range(requiresstart_timeandend_timeas ISO8601)query_by_correlation/query_correlation(requirescorrelation_id)query_by_command/query_command_type(requirescommand_type)query_by_source/query_source_type(requiressource_type)query_by_window/query_window(requireswindow_id)query_by_batch/query_batch(requiresbatch_id)query_by_status/query_response_status(requiresstatus)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_topicas JSON withcommand: 'audit_response'and includeaction,timestamp(ISO8601),device, and action-specific fields. - Errors are also published to
response_topicwithaction: 'error'and anerrorstring.
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/responseusing the unified response helper; success includessensors_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/responsevia the unified response helper with: window_countwindows(visual tile list when available)tiling_mode(when available)controller_countandcontrollers(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_urlsx,y,width,height,opacity,z_indexloop,minimized,maximizedmqtt_topic,mqtt_json_field,mqtt_is_base64,mqtt_update_interval_msmetadata
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:
batchdoes not currently publish an automatic completion event; use per-command responses inside the batch (where supported) or querybatch_status.batch_statuspublishes{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 tokingkiosk/{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_idcannot be empty and cannot contain/,+,#, or NUL.element_id(when used in a topic path) cannot be empty and cannot contain/,+,#, or NUL.target_topiccannot be empty and cannot contain+,#, or NUL.- If
target_topicis a fleet element command topic, it must be exactlykingkiosk/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_topicwhen 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 bothelement_idandwindow_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_topicis omitted, publishes tokingkiosk/fleet/{fleet_id}/cmd. - If
target_topicpoints at a fleet element bus, it must bekingkiosk/fleet/{fleet_id}/element/{element_id}/cmd. - For fleet element publish,
{element_id}from the topic is authoritative and is injected into payload aselement_idandwindow_idbefore publish. - Published payload is normalized and enriched with
source_device,fleet_id, andbroadcast_atwhen omitted.
Typical response statuses for fleet operations include:
replicatedsubscribedunsubscribedbroadcastedfleet_updateappliederror
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):
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:
-
Enum map — key-value pairs mapping string states to colors/icons:
-
Boolean colors — shorthand for true/false states:
-
Thresholds — numeric ranges (evaluated in order, first match wins):
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: nodelabel(string),subtitle(string)icon(object):{ "set": "material|sf", "name": "...", "color": "#AARRGGBB", "size_px": 24 }icon_size_px(number, optional alias foricon.size_px)label_font_size_px(number, default13)subtitle_font_size_px(number, default11)label_font_weight/subtitle_font_weight(string:normal|bold|w300|w500|w600)content_scale(number, default1.0) multiplies the node icon and both text sizes togethertype: texttext(string)font_size_px(number, default16)font_weight(string:normal|bold|w300|w500|w600)color(string:#RRGGBBor#AARRGGBB)align(string:left|center|right)type: shapeshape(string:rect|round_rect|circle|line)corner_radius_px(number, default8)stroke_width_px(number, default2)- Uses
style.fill_colorandstyle.stroke_color type: imagesource(object):{ "url": "..." }or{ "asset_id": "..." }fit(string:contain|cover|fill, defaultcontain)opacity(number, default1.0)type: embedembed(object):{ "widget_type": "gauge|chart|mqtt_button|mqtt_action_status", "id": "...", "config": { ... } }configis 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.0–1.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.0–1.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_colorvalueBarColor/value_bar_colorshowLabels/show_labelslabelFontSize/label_font_size/label_font_size_pxlabelColor/label_colorshow_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:
backgroundColororbackground_colorvalueBarColororvalue_bar_colorshowLabelsorshow_labelslabelFontSize,label_font_size, orlabel_font_size_pxlabelColororlabel_colorshow_indicatororshowIndicator
Lock/Unlock Commands¶
lock_gauge: Lock gauge to prevent user interaction
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:
For single-setpoint pointers, fallback payload is:
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
Other Gauge Commands¶
delete_gauge: Remove a gauge widgetlist_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¶
Create (create_carousel, create_video_carousel, create_image_carousel, create_widget_carousel)¶
| 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_statuscurrently does not publish a status payload; it simply returns a generic{success:true, command, timestamp}onresponse_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_mediais 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 tokingkiosk/{device}/status/media_health. - If a reset is performed successfully, publishes a report to
kingkiosk/{device}/status/media_resetwith:{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_fieldis provided (or payload looks like JSON), the handler tries to parse JSON and extract the image value. - If
is_base64 == trueand the extracted value is not adata:URL, the handler will prefixdata:image/png;base64,. - If
is_base64 == false, the handler may still auto-detect large base64 payloads and treat them asdata: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:
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 (0–9, *, # — 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:
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:
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:
Example — Hang up a specific endpoint:
Example — Send DTMF digits (SIP only):
Digits can be a single character or a sequence. Valid characters: 0–9, *, #.
Example — List active 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
intercomEnabledmust betruein device settings- Audio production must be enabled (
featureServerProduceAudio) - For receiving:
autoAcceptIncomingIntercomcontrols 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
| 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)
| 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/responseand/orkingkiosk/{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¶
3. Unregister in 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¶
- You send a JSON script object via MQTT.
- The engine parses the three HSL expressions once (compile step).
- On every frame (at the configured
fps), for every cell in the grid, the engine: - Sets the built-in variables (
t,cell_x,cell_y, etc.) to that cell's values. - Evaluates each expression (
h,s,l) to produce a number. - Converts the three numbers into a color:
HSLColor(hue, saturation, lightness). - 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.
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
fpsat 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 : 0still evaluatesexpensive_exprfor every cell (unlike the? :operator in most programming languages). Useif(cond, a, b)— it has the same behavior. Structure your grid size to minimize unnecessary computation. - For very large grids (1000+ cells), consider reducing
fpsto 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.
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¶
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¶
Marks the currently running firmware as stable. If not confirmed within 3 boots, the device automatically rolls back to the previous firmware.
rollback¶
Manually rolls back to the previous firmware partition and reboots.
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: Supportscolor,icon(crown watermark), andnonemodes 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