-
Notifications
You must be signed in to change notification settings - Fork 30
MQTT
Real-time telemetry, command topics, and Home Assistant auto-discovery
Docs Home • Integrations • REST API
FreeKiosk includes a native MQTT client for real-time integration with Home Assistant and other MQTT-based platforms.
| Feature | Details |
|---|---|
| Protocol | MQTT v5 / v3.1.1 (HiveMQ Client) |
| Default Port | 1883 |
| Discovery | Home Assistant MQTT Discovery (auto-creates device + entities) |
| Push-based | Real-time status updates (no polling needed) |
| LWT | Availability tracking via Last Will and Testament |
Tip
MQTT vs REST API: MQTT is push-based — the tablet publishes status updates automatically every N seconds. The REST API requires polling. MQTT is the preferred integration for Home Assistant. Both can run simultaneously.
| Step | Action |
|---|---|
| 1 | 5-tap + PIN to enter FreeKiosk settings |
| 2 | Go to Advanced tab |
| 3️⃣ MQTT Section | Scroll to MQTT section |
| 4️⃣ Enable MQTT | Toggle MQTT switch |
| 5️⃣ Configure Broker | Enter broker URL (e.g. 192.168.1.100) |
| 6️⃣ Set Credentials | Configure port, username, password |
| 7️⃣ Connect | Press Connect button |
| 8️⃣ Verify Status | Check connection indicator shows Connected |
Note
Settings are saved automatically as you type. Connection is only established when you press "Connect" — no auto-reconnect on every keystroke.
MQTT settings are included in FreeKiosk backup/restore. You can configure one device and export the configuration to others.
| Setting | Default | Description |
|---|---|---|
| Enable MQTT | Off | Master toggle for MQTT client |
| Broker URL | (empty) | MQTT broker hostname or IP address (required) |
| Port | 1883 | MQTT broker port (1-65535) |
| Username | (empty) | MQTT username (optional) |
| Password | (empty) | MQTT password (stored in Android Keychain, optional) |
| Client ID | (auto) | MQTT client ID (auto-generated as freekiosk_{deviceId} if empty) |
| Device Name | (empty) | Friendly name used in MQTT topics and HA device name (e.g. "lobby", "entrance"). If empty, uses Android ID. |
| Base Topic | freekiosk |
Base MQTT topic prefix for this device |
| Discovery Prefix | homeassistant |
Home Assistant MQTT discovery prefix |
| Status Interval | 30 | How often to publish status (5-3600 seconds) |
| Allow Remote Control | On | Enable commands via MQTT (brightness, reload, etc.) |
| Always-on Motion Detection | Off | Run camera-based motion detection continuously (higher battery usage) |
For a device with deviceName = lobby (or deviceId if no name set) and default base topic freekiosk:
| Purpose | Topic | QoS | Retained |
|---|---|---|---|
| Availability (LWT) | freekiosk/lobby/availability |
1 | Yes |
| State (all data) | freekiosk/lobby/state |
0 | Yes |
| Commands | freekiosk/lobby/set/{entity} |
1 | No |
| Discovery | homeassistant/{component}/freekiosk_{deviceId}/{objectId}/config |
1 | Yes |
The topic identifier is either the configured Device Name (sanitized: lowercased, spaces replaced with underscores) or the ANDROID_ID if no name is set. This makes topics human-readable when using device names (e.g. freekiosk/lobby/state instead of freekiosk/9774d56d682e549c/state).
| Status | Action | Retained |
|---|---|---|
| Online | Published on successful connection | "online" |
| Offline | Published via LWT on unexpected disconnect | "offline" |
| Graceful disconnect | Publishes before disconnecting | "offline" |
A JSON object published periodically (default: every 30 seconds) containing all device data:
{
"battery": {
"level": 85,
"charging": true
},
"screen": {
"on": true,
"brightness": 75,
"screensaverActive": false
},
"wifi": {
"ssid": "HomeNetwork",
"signalLevel": 83,
"ip": "192.168.1.50"
},
"device": {
"ip": "192.168.1.50",
"version": "1.2.12",
"kioskMode": true,
"isDeviceOwner": true,
"motionAlwaysOn": false
},
"sensors": {
"light": 150.5
},
"memory": {
"usedPercent": 41
},
"storage": {
"availableMB": 27685
},
"audio": {
"volume": 50
},
"webview": {
"currentUrl": "http://192.168.1.244",
"motionDetected": false
}
}FreeKiosk automatically publishes MQTT Discovery configurations on connect/reconnect. All entities appear under a single device in Home Assistant.
| Requirement | Details |
|---|---|
| Home Assistant | With MQTT integration configured |
| MQTT Broker | Accessible by both HA and the tablet (e.g. Mosquitto) |
| Discovery | MQTT Discovery enabled in HA (enabled by default) |
All entities are grouped under one HA device:
| Field | Value |
|---|---|
| Name | FreeKiosk {deviceName} (or FreeKiosk {deviceId} if no name set) |
| Model | FreeKiosk |
| Manufacturer | FreeKiosk |
| SW Version | (app version) |
| Configuration URL | http://{localIp}:8080 |
| Entity | Value Template | Device Class | Unit |
|---|---|---|---|
| Battery Level | battery.level |
battery | % |
| Brightness | screen.brightness |
— | % |
| WiFi SSID | wifi.ssid |
— | — |
| WiFi Signal | wifi.signalLevel |
— | % |
| Light Sensor | sensors.light |
illuminance | lx |
| IP Address | device.ip |
— | — |
| App Version | device.version |
— | — |
| Memory Used | memory.usedPercent |
— | % |
| Storage Free | storage.availableMB |
— | MB |
| Current URL | webview.currentUrl |
— | — |
| Volume | audio.volume |
— | % |
| Entity | Value Template | Device Class |
|---|---|---|
| Screen | screen.on |
power |
| Screensaver | screen.screensaverActive |
— |
| Battery Charging | battery.charging |
battery_charging |
| Kiosk Mode | device.kioskMode |
— |
| Device Owner | device.isDeviceOwner |
— |
| Motion | webview.motionDetected |
motion |
| Entity | Command Topic | Min | Max | Unit |
|---|---|---|---|---|
| Brightness Control | .../set/brightness |
0 | 100 | % |
| Volume Control | .../set/volume |
0 | 100 | % |
| Entity | Command Topic | Payload |
|---|---|---|
| Screen Power | .../set/screen |
ON / OFF |
| Screensaver | .../set/screensaver |
ON / OFF |
| Always-on Motion Detection | .../set/motion_always_on |
ON / OFF |
| Entity | Command Topic | Icon |
|---|---|---|
| Reload | .../set/reload |
mdi:reload |
| Wake | .../set/wake |
mdi:alarm |
| Reboot | .../set/reboot |
mdi:restart |
| Clear Cache | .../set/clear_cache |
mdi:delete-sweep |
| Lock | .../set/lock |
mdi:lock |
| Remote Up | .../set/remote_up |
mdi:arrow-up-bold |
| Remote Down | .../set/remote_down |
mdi:arrow-down-bold |
| Remote Left | .../set/remote_left |
mdi:arrow-left-bold |
| Remote Right | .../set/remote_right |
mdi:arrow-right-bold |
| Remote Select | .../set/remote_select |
mdi:radiobox-marked |
| Remote Back | .../set/remote_back |
mdi:arrow-left-circle |
| Remote Home | .../set/remote_home |
mdi:home |
| Remote Menu | .../set/remote_menu |
mdi:menu |
| Remote Play/Pause | .../set/remote_playpause |
mdi:play-pause |
| Entity | Command Topic | Description |
|---|---|---|
| Navigate URL | .../set/url |
Navigate WebView to a URL |
| Text to Speech | .../set/tts |
Speak text aloud on the tablet |
| Toast Message | .../set/toast |
Show a toast notification on screen |
| Keyboard Key | .../set/keyboard_key |
Press a single key (e.g. enter, a, f5) |
| Keyboard Combo | .../set/keyboard_combo |
Press a key combination (e.g. ctrl+c, alt+f4) |
| Keyboard Text | .../set/keyboard_text |
Type a text string into focused field |
Total: 42 entities auto-discovered in Home Assistant.
Commands are sent by publishing to {baseTopic}/{topicId}/set/{entity}.
| Topic Suffix | Command | Payload | Description |
|---|---|---|---|
| brightness | setBrightness |
0-100 (integer) |
Set screen brightness |
| volume | setVolume |
0-100 (integer) |
Set media volume |
| screen | screenOn / screenOff |
ON / OFF
|
Turn screen on or off |
| screensaver | screensaverOn / screensaverOff |
ON / OFF
|
Enable/disable screensaver |
| motion_always_on | setMotionAlwaysOn |
ON / OFF
|
Toggle always-on motion detection |
| reload | reload | any | Reload WebView |
| wake | wake | any | Wake from screensaver |
| reboot | reboot | any | Reboot device (Device Owner required) |
| clear_cache | clearCache | any | Clear WebView cache |
| lock | lockDevice | any | Lock device screen |
| url | setUrl | URL string | Navigate to URL |
| tts | tts | text string | Text-to-speech (handled natively) |
| toast | toast | text string | Show toast notification (handled natively) |
| launch_app | launchApp | package name | Launch external app |
| execute_js | executeJs | JS code string | Execute JavaScript in WebView |
| audio_play | audioPlay | JSON {"url":"...","loop":false,"volume":50}
|
Play audio from URL |
| audio_stop | audioStop | any | Stop audio playback |
| audio_beep | audioBeep | any | Play beep sound |
| rotation_start | rotationStart | any | Start URL rotation |
| rotation_stop | rotationStop | any | Stop URL rotation |
| restart_ui | restartUi | any | Restart app UI |
| remote_up | remoteKey (up) | PRESS |
D-pad Up |
| remote_down | remoteKey (down) | PRESS |
D-pad Down |
| remote_left | remoteKey (left) | PRESS |
D-pad Left |
| remote_right | remoteKey (right) | PRESS |
D-pad Right |
| remote_select | remoteKey (select) | PRESS |
D-pad Select / Enter |
| remote_back | remoteKey (back) | PRESS |
Back |
| remote_home | remoteKey (home) | PRESS |
Home |
| remote_menu | remoteKey (menu) | PRESS |
Menu |
| remote_playpause | remoteKey (playpause) | PRESS |
Media Play/Pause |
| keyboard_key | keyboardKey | key name (e.g. enter, a, f5) |
Press a single key |
| keyboard_combo | keyboardCombo | combo string (e.g. ctrl+c) |
Press a key combination |
| keyboard_text | keyboardText | text string | Type text into focused field |
Note
Commands have full parity with the REST API. Both interfaces dispatch through the same native command handler. Remote control and keyboard commands are handled natively via the AccessibilityService (cross-app) or Activity key dispatch (in-app). TTS and Toast are also handled natively (no JS round-trip).
FreeKiosk can detect motion using the device camera and report it as a binary sensor in Home Assistant.
| Mode | Behavior | Battery Impact |
|---|---|---|
| Default | Motion detection only runs during screensaver (to wake the screen on movement) | Minimal |
| Always-on | Continuous motion detection via HA switch or MQTT setting | Higher |
Always-on mode: Enable "Always-on Motion Detection" in MQTT settings or via the HA switch entity to run motion detection continuously. The motion_detected binary sensor will update in real-time. Note: this uses the camera continuously and increases battery usage.
Note
Camera permission must be granted for motion detection to work. FreeKiosk requests this permission automatically on first launch.
The MQTT client automatically reconnects when the connection is lost (WiFi drop, broker restart). On reconnect, it:
| Step | Action |
|---|---|
| 1 | Publishes "online" to the availability topic |
| 2 | Re-publishes all 42 HA Discovery configs |
| 3 | Re-subscribes to command topics |
| 4 | Resumes periodic status publishing |
If the connection is lost unexpectedly, the broker publishes "offline" to the availability topic. Home Assistant will show the device as "Unavailable".
MQTT and the REST API can run simultaneously. Both use the same internal command handler and status data. Enabling MQTT does not disable the REST API.
# Subscribe to all FreeKiosk topics
mosquitto_sub -h BROKER_IP -t "freekiosk/#" -v
# Check device availability
mosquitto_sub -h BROKER_IP -t "freekiosk/TOPIC_ID/availability"
# Read device state
mosquitto_sub -h BROKER_IP -t "freekiosk/TOPIC_ID/state"
# Set brightness to 50%
mosquitto_pub -h BROKER_IP -t "freekiosk/TOPIC_ID/set/brightness" -m "50"
# Turn screen off
mosquitto_pub -h BROKER_IP -t "freekiosk/TOPIC_ID/set/screen" -m "OFF"
# Turn screen on
mosquitto_pub -h BROKER_IP -t "freekiosk/TOPIC_ID/set/screen" -m "ON"
# Navigate to URL
mosquitto_pub -h BROKER_IP -t "freekiosk/TOPIC_ID/set/url" -m "https://example.com"
# Reload WebView
mosquitto_pub -h BROKER_IP -t "freekiosk/TOPIC_ID/set/reload" -m "PRESS"
# Play audio
mosquitto_pub -h BROKER_IP -t "freekiosk/TOPIC_ID/set/audio_play" -m '{"url":"https://example.com/sound.mp3","volume":50}'
# Text-to-speech
mosquitto_pub -h BROKER_IP -t "freekiosk/TOPIC_ID/set/tts" -m "Hello from Home Assistant"
# Show toast
mosquitto_pub -h BROKER_IP -t "freekiosk/TOPIC_ID/set/toast" -m "Hello!"
# Toggle always-on motion detection
mosquitto_pub -h BROKER_IP -t "freekiosk/TOPIC_ID/set/motion_always_on" -m "ON"
# View HA discovery configs
mosquitto_sub -h BROKER_IP -t "homeassistant/#" -vReplace BROKER_IP with your MQTT broker IP and TOPIC_ID with the device name (e.g. lobby) or Android ID if no name is configured.
automation:
- alias: "Wake Tablet on Room Motion"
trigger:
- platform: state
entity_id: binary_sensor.freekiosk_abc123_motion
to: "on"
condition:
- condition: state
entity_id: binary_sensor.freekiosk_abc123_screensaver_active
state: "on"
action:
- service: mqtt.publish
data:
topic: "freekiosk/lobby/set/wake"
payload: "PRESS"automation:
- alias: "Tablet Screen Off at Night"
trigger:
- platform: time
at: "23:00:00"
action:
- service: mqtt.publish
data:
topic: "freekiosk/lobby/set/screen"
payload: "OFF"automation:
- alias: "Tablet Screen On in Morning"
trigger:
- platform: time
at: "07:00:00"
action:
- service: mqtt.publish
data:
topic: "freekiosk/lobby/set/screen"
payload: "ON"automation:
- alias: "Doorbell Alert on Tablet"
trigger:
- platform: state
entity_id: binary_sensor.doorbell
to: "on"
action:
- service: mqtt.publish
data:
topic: "freekiosk/lobby/set/audio_beep"
payload: "PRESS"
- service: mqtt.publish
data:
topic: "freekiosk/lobby/set/toast"
payload: "Someone is at the door!"
- service: mqtt.publish
data:
topic: "freekiosk/lobby/set/url"
payload: "http://homeassistant:8123/lovelace/cameras"automation:
- alias: "Tablet Auto Brightness via MQTT"
trigger:
- platform: state
entity_id: sensor.living_room_light_level
action:
- service: mqtt.publish
data:
topic: "freekiosk/lobby/set/brightness"
payload: >-
{{ (states('sensor.living_room_light_level') | float / 10) | int | min(100) }}automation:
- alias: "Announce Weather on Tablet"
trigger:
- platform: time
at: "08:00:00"
action:
- service: mqtt.publish
data:
topic: "freekiosk/lobby/set/tts"
payload: "Good morning! Today's forecast is {{ states('weather.home') }}."type: entities
title: Tablet
entities:
- entity: sensor.freekiosk_abc123_battery_level
- entity: binary_sensor.freekiosk_abc123_battery_charging
- entity: binary_sensor.freekiosk_abc123_screen_on
- entity: number.freekiosk_abc123_brightness_control
- entity: number.freekiosk_abc123_volume_control
- entity: switch.freekiosk_abc123_screen_power
- entity: switch.freekiosk_abc123_screensaver
- entity: switch.freekiosk_abc123_motion_always_on
- entity: binary_sensor.freekiosk_abc123_motion_detected
- entity: text.freekiosk_abc123_tts
- entity: text.freekiosk_abc123_toast
- entity: sensor.freekiosk_abc123_wifi_ssid
- entity: sensor.freekiosk_abc123_wifi_signal
- entity: button.freekiosk_abc123_reload
- entity: button.freekiosk_abc123_wake
- entity: button.freekiosk_abc123_reboot| Check | Solution |
|---|---|
| MQTT Integration | Verify MQTT integration is configured in HA |
| Broker Reachability | Check broker URL is correct and reachable from tablet |
| Discovery Enabled | Check MQTT Discovery is enabled in HA (Settings > Integrations > MQTT > Configure) |
| Discovery Messages | Use mosquitto_sub -h BROKER_IP -t "homeassistant/#" -v to verify discovery messages |
| Issue | Solution |
|---|---|
| First Status Publish | Wait for the first status publish (up to 30 seconds by default) |
| State Topic | Check: mosquitto_sub -h BROKER_IP -t "freekiosk/TOPIC_ID/state"
|
| Binary Sensors | Ensure state JSON contains expected boolean fields |
| TTS/Toast | These always show empty — this is by design (fire-and-forget commands) |
| Cause | Solution |
|---|---|
| WiFi Stability | Check WiFi stability on the tablet |
| Client ID Conflict | Verify broker allows the configured client ID |
| Duplicate Client | Check if another client is using the same client ID |
| Normal Behavior | The client auto-reconnects automatically — brief disconnections are normal |
| Issue | Solution |
|---|---|
| Version Bug | This is resolved in the latest version. Ensure you're running v1.2.12+ |
| State Update | The tablet immediately publishes updated state after executing screen on/off commands |
| Issue | Solution |
|---|---|
| Camera Permission | Grant camera permission to the app (requested automatically on first launch) |
| Default Behavior | By default, motion only activates during screensaver |
| Always-on Mode | Enable "Always-on Motion Detection" for continuous detection |
| Debug Logs | Check logs: `adb logcat |
| Issue | Solution |
|---|---|
| Location Permission | Grant location permissions (requested automatically on first launch) |
| Android Requirement | Android requires location permissions to read WiFi SSID (Android 8.0+) |
| Issue | Solution |
|---|---|
| TTS Engine | Ensure the device has a TTS engine installed (most Android devices include Google TTS) |
| Volume | Check device volume is not muted |
| Native Handling | TTS is handled natively by the MQTT module — no need for the REST API to be running |
| Component | Details |
|---|---|
| MQTT Library | HiveMQ MQTT Client (com.hivemq:hivemq-mqtt-client:1.3.12) |
| Connection | Automatic reconnect with exponential backoff |
| Clean Session | Yes (no persistent subscriptions) |
| Keep Alive | 30 seconds |
| Thread Safety | MQTT callbacks are dispatched to the main thread via Handler(Looper.getMainLooper())
|
| Password Storage | Encrypted in Android Keychain (same as REST API key) |
| TTS & Toast | Handled natively in the MQTT module (no JS round-trip) |
| Document | Focus |
|---|---|
| REST API Documentation | HTTP-based integration (polling) |
| ADB Configuration Guide | Headless provisioning via ADB |
| Installation Guide | Device setup |
| Integrations Overview | Comparison of integration methods |