Docs menu

Connect

MQTT reference

Topic layout, the state and event payloads, the command list and delivery details for talking to Kiosky over MQTT.

View as Markdown llms.txt

Kiosky speaks plain MQTT, so any system can use it, not only Home Assistant. This page is the reference. For setup and automations see Home Assistant integration.

Kiosky connects as an MQTT 3.1.1 client. Messages are published and subscribed at QoS 1. TLS is optional and set under Settings, Connections, MQTT.

Topics#

Everything lives under <base>/<device_id>. The base topic defaults to kiosk. The device id is a lower-case slug of the device name: letters and digits, with other characters collapsed to _, accents removed and at most 40 characters. Hallway Tablet gives hallway_tablet, so topics start kiosk/hallway_tablet/.

Topic Direction Retained Payload
kiosk/<id>/availability tablet to broker yes, and the last will online or offline
kiosk/<id>/state tablet to broker yes JSON of all values, see State
kiosk/<id>/event tablet to broker no {"type": "...", ...}, see Events
kiosk/<id>/camera/snapshot tablet to broker no JPEG bytes
kiosk/<id>/cmd/<command> broker to tablet n/a command payload, see Commands
homeassistant/<component>/<id>/<object>/config tablet to broker yes Home Assistant discovery config

Retained messages on cmd/ topics are ignored, so an old command is not replayed when the tablet reconnects. Only direct children of cmd/ count; cmd/a/b is not a command.

Base topic rules: it must be non-empty, have no wildcards (#, +), no leading /, no spaces and be at most 128 characters.

State#

kiosk/<id>/state is a flat JSON object. It is published whenever a value changes (with a small minimum gap) and at least every publish interval (60 seconds by default, from 5 to 3600 in the config). Unknown values are null.

Key Type Meaning
screen "ON" / "OFF" OFF only while the screen is off.
brightness number 0 to 255.
screen_stage string active, dimmed, screensaver or off.
screensaver "ON" / "OFF"
battery number Percent.
charging boolean
battery_temp number Degrees C.
light_lux number
proximity boolean
url string Current page.
dashboard string Name of the dashboard on screen.
volume number 0 to 100.
wifi_rssi number dBm. Left out when network info is not shared.
ip string Left out when network info is not shared.
uptime_s number Seconds.
memory_free_mb, storage_free_mb number
app_version, webview_version string
last_interaction ISO time Last touch.
kiosk_mode string none, soft or device_owner.
charge_wanted boolean Battery care: charger should be on.
memory_trim_count number
motion boolean
kiosk_paused boolean
kiosk_paused_until ISO time null when not paused, or paused until resumed.
kiosk_lock "ON" / "OFF" OFF while paused.
presence boolean Only present while face presence is on.
tamper boolean Only present while tamper detection is on.
voice_state string Only while voice is on: off, idle, listening, processing, responding.
microphone "ON" / "OFF" Only while voice is on.
voice_last_command string Only while voice is on and sharing the transcript.

IP address and Wi-Fi signal (ip, wifi_rssi) are included only when the broker connection has a Username, or Share IP and Wi-Fi over MQTT is on. On an anonymous broker everyone on the LAN could read them.

Events#

Events are not retained and use the topic kiosk/<id>/event. Each payload has a type and optional string fields. Values are length-capped and never carry secrets or full URLs.

type Fields When
command_rejected command, reason A command was refused or invalid.
exit_gesture The exit corner was tapped five times.
wrong_pin attempts_left or locked_out A wrong admin PIN.
page_error The page failed to load.
popup_shown host or cameras A popup appeared.
popup_dismissed host or cameras, reason A popup closed.
audio_error Audio failed.
device_moved Tamper detection fired.
kiosk_paused until The lock was paused. until is an ISO time or indefinite.
kiosk_resumed reason timeout, user, remote or idle.
wake_word_heard The wake word was heard (voice on).

Example refusal:

json
{"type": "command_rejected", "command": "reboot", "reason": "Remote unlock is turned off on this tablet"}

Commands#

Publish to kiosk/<id>/cmd/<command>. The payload is either a plain value that fills the command's main argument, or a JSON object. Optional arguments need JSON. Payloads are limited to 4096 bytes. Invalid or refused commands produce a command_rejected event and nothing else, so subscribe to event while testing.

Command Plain payload JSON payload
reload empty
load_url https://example.com/page {"url": "..."}
screen on / off {"state": "on"}
brightness 128 {"level": 128}
screensaver on / off {"state": "off"}
dashboard Energy {"name": "Energy"}
tts Hello {"text": "Hello", "volume": 60}
play audio URL {"url": "...", "volume": 60}
stop_audio empty
volume 40 {"level": 40}
toast Hello {"text": "Hello", "duration": 8}
popup URL or camera.<name> {"url": "...", "timeout": 30, "title": "..."} or {"camera": ["camera.a", "camera.b"], "timeout": 30, "title": "..."}
dismiss_popup empty
snapshot empty
microphone on / off {"state": "off"}
kiosk_lock on / off {"state": "on"}
kiosk_resume empty
kiosk_pause 30 {"minutes": 30}
launch_app package name, or empty {"package": "com.example.app"} or {}
exit_app_mode empty
restart_app empty
clear_cache empty
reboot empty

Argument limits and details are the same as for REST, so see the command table. on also accepts true and 1, and off accepts false and 0. Command names are case-insensitive.

Policy#

Every command passes one central policy, whatever its source. Over MQTT:

  • Benign commands (everything that only changes what is shown or heard) always run.
  • Sensitive commands (kiosk_pause, kiosk_lock off, launch_app, exit_app_mode, restart_app, clear_cache, reboot) are refused with command_rejected unless Allow remote unlock & app control is on, on the tablet.
  • reboot also needs full lock (Device Owner), whatever the switch says.

The Kiosk lock, Restart app and Relaunch app entities are not even created in Home Assistant while remote unlock is off. See Security.

Discovery#

With Home Assistant discovery on, Kiosky publishes a retained config for every entity at homeassistant/<component>/<id>/<object>/config. All entities share one device block with the identifier kiosky_<id>, the device name, model, manufacturer, app version and a link to the admin page. The full entity list is in Home Assistant integration.

When you rename the device, Kiosky clears the old retained availability and state. Discovery configs for entities that no longer apply are cleared, too, for example when you switch off remote unlock.

Quick test#

With the Mosquitto command-line tools:

bash
# watch everything the tablet publishes
mosquitto_sub -h BROKER -u USER -P PASSWORD -t 'kiosk/hallway_tablet/#' -v

# show a toast
mosquitto_pub -h BROKER -u USER -P PASSWORD -t 'kiosk/hallway_tablet/cmd/toast' -m '{"text":"Hello","duration":5}'