# Kiosky > Kiosky is an Android kiosk app for wall-mounted tablets: it locks a device to a dashboard, website, signage page or a single app, with first-class Home Assistant support (MQTT discovery, voice, camera popups), a local REST API and optional Pro features. Kiosky runs on Android 8.0 and newer. These pages are the complete user documentation; each link is the Markdown version of a page. To configure a tablet with an AI assistant, start with the "Set up Kiosky with an AI assistant" page. --- Source: https://kiosky.enraio.com/docs/ # Kiosky documentation > Everything you need to set up, lock down and automate an Android tablet with Kiosky, for people and for AI assistants. Kiosky turns an Android tablet or phone into a kiosk: a wall panel, an info screen, a signage display or a single-purpose device. It shows a dashboard, a website or one app, keeps it running, and can lock the device so nobody wanders off into Android. It works with any web page and has first-class support for Home Assistant. These pages are the complete user guide. If you are new, read [Getting started](https://kiosky.enraio.com/docs/getting-started.md) and then [Choosing a mode](https://kiosky.enraio.com/docs/modes.md). If you would like an AI assistant such as Claude to configure the tablet for you, go straight to [Set up Kiosky with an AI assistant](https://kiosky.enraio.com/docs/ai-setup.md). ## How the docs are organised - **Start here** covers install, the setup wizard and the choice between a normal app and a locked kiosk. - **Use Kiosky** covers dashboards, screen and power behaviour, and the camera and sensors. - **Connect** covers Home Assistant, the REST API and MQTT. - **Reference** covers Kiosky Pro and security. - **Help** covers troubleshooting and the AI assistant guide. ## For agents and scripts Every page is also available as plain Markdown at the same address with a `.md` ending, for example `/docs/rest-api.md`. The index for agents is [`/llms.txt`](https://kiosky.enraio.com/llms.txt) and the whole documentation in one file is [`/llms-full.txt`](https://kiosky.enraio.com/llms-full.txt). > **Note.** Kiosky is under active development. Where a feature is planned but not built yet, these pages say "Coming soon" instead of describing it as if it worked. --- Source: https://kiosky.enraio.com/docs/getting-started # Getting started > What Kiosky is, what you need, how to install it and how the five-step setup wizard works. ## What Kiosky is Kiosky is an Android kiosk app. You point it at a dashboard, a website, a signage page or a single installed app, and it keeps that on screen. It can: - show any web page full screen in a built-in browser, with several dashboards you can rotate, schedule or switch remotely; - lock the tablet so only Kiosky is usable (a "soft lock" with no computer, or a "full lock" through Android's Device Owner mode), or just run as a normal app that stays out of your way; - manage the screen: brightness, dimming, a clock or photo screensaver, night schedules, battery care; - talk to Home Assistant (or any MQTT system), expose a local REST API and a web admin page, and act as a voice satellite; - use the front camera for motion, presence and snapshots, entirely on the device. Home Assistant is a first-class citizen, but it is not required. Kiosky works just as well with openHAB, Node-RED, Grafana, a status page or any URL. ## What you need | Need | Details | |---|---| | Android device | Android 8.0 (API 26) or newer. Tablets and phones both work. | | A page to show | Any `http://` or `https://` address the tablet can reach. | | Computer with `adb` | Only for the optional **full lock** (Device Owner). Soft lock and normal mode need no computer. | | Home Assistant | Optional. For sign-in, camera popups and voice you need a long-lived access token from your HA profile. | | MQTT broker | Optional. Needed for Home Assistant entities and MQTT commands. | | Kiosky Pro | Optional. See [Kiosky Pro](https://kiosky.enraio.com/docs/pro.md). | A front camera is only needed for the motion, presence and QR-import features. A microphone is only needed for voice. ## Install Kiosky is distributed through Google Play. > **Coming soon.** The public Google Play listing is not live yet. This page will link to it when it is. Open the app once it is installed. If no dashboard or app has been configured yet, the setup wizard starts by itself. ## The setup wizard The wizard has five steps. A progress rail shows where you are, and **Back** is available on every step except the first. You can change every answer later in Settings. ### Step 1: What to show Pick what this tablet displays: - **Home Assistant**: a kiosk-friendly URL for your HA instance, with Home Assistant sign-in and integration switched on. - **Another dashboard or website**: openHAB, Node-RED, Grafana, a status page, signage, any URL. - **A single app**: lock the tablet to one installed app, such as a vendor dashboard, a music app or a signage player. ### Step 2: Dashboard address (or app) For the two web choices, enter the address. The default for Home Assistant is `http://homeassistant.local:8123`. If you omit the scheme, Kiosky adds `http://`. - For Home Assistant there is an **Add ?kiosk to the URL** switch (on by default). It appends `?kiosk` so a kiosk-mode card in your HA frontend can hide the header and sidebar. Kiosky can also hide the header on its own, see [Dashboards & browser](https://kiosky.enraio.com/docs/dashboards.md#hiding-the-home-assistant-header-and-sidebar). - **Test connection** checks that the tablet can reach the address and reports "Reachable" with the HTTP status or "Not reachable from this device". - A plain `http://` address works on a home network but is not encrypted. Kiosky warns you. - If the address redirects to a different host, Kiosky adds that host to the allowed hosts automatically. For **A single app**, choose the app from the list of installed apps. Kiosky keeps it on screen and reopens it if it closes. Dimming and the screensaver are not available in app mode because Kiosky cannot see touches inside another app. The first dashboard you create is named **Home**. ### Step 3: Admin PIN Set a PIN of 4 to 12 digits. It protects leaving the kiosk and changing settings. You can **Skip** this step, but then anyone who knows the exit gesture can open Settings. You can add a PIN later under Settings, Lock & security, Admin PIN. The exit gesture is shown on this step: **tap the top-left corner of the screen 5 times quickly**. ### Step 4: Kiosk lock Choose how Kiosky should run: - **Locked kiosk**: Kiosky owns the screen. For full lock the step shows the `adb` command to run on a computer and updates by itself when Device Owner becomes active. If you would rather not use a computer, **Use soft lock** makes Kiosky the home app instead. - **Normal app**: Home and Back work and other apps stay usable. Kiosky keeps Home Assistant, MQTT, voice and sensors running in the background, opens on boot and comes to the front when Home Assistant shows something. [Choosing a mode](https://kiosky.enraio.com/docs/modes.md) explains the differences in depth. ### Step 5: Keep running Android likes to stop background apps. This step walks you through the permissions that keep Kiosky alive: - **Battery optimisation**: exempt Kiosky. - **Status notification**: allow the notification that shows the kiosk service is running. - **Manufacturer battery manager**: on Honor, Huawei, Xiaomi, Redmi, Poco, Samsung, OnePlus, Oppo, Realme and Motorola devices Kiosky shows the manufacturer-specific steps and an **Open** button for app settings. See [Troubleshooting](https://kiosky.enraio.com/docs/troubleshooting.md#start-on-boot-and-vendor-auto-start-screens) for each vendor. - **Default home app**: needed for soft lock, so the Home button returns to Kiosky. - **Come back to the front**: allow "Display over other apps" so Kiosky can reopen itself after a crash and come forward when Home Assistant needs it. Tap **Start kiosk** (or **Start Kiosky** in normal mode) to finish. ## After setup Your dashboard is on screen. To open Settings at any time, **tap the top-left corner 5 times**, then enter the PIN if you set one. Settings has eight groups: | Group | What it holds | |---|---| | Dashboard | Kiosk mode (browser or single app), start URL, allowed hosts, reload, page display, navigation, extra dashboards, Home Assistant sign-in and theme, rotation and planner | | Kiosky Pro | Plan and activation | | Screen & power | Appearance, keep-screen-on, brightness, idle timers, screensaver and photo frame, night mode, battery care | | Lock & security | Kiosk lock, Device Owner lock options, allowed apps, pausing, exiting, admin PIN, remote-control switches | | Voice | Voice assistant, wake word | | Camera & sensors | Motion, presence, tamper, live stream, QR config import | | Connections | REST API and admin page, MQTT | | Device | Device name and info, daily maintenance, backup and restore, logs | On a narrow screen the groups appear as a list; on a tablet they form a sidebar. ## Next steps - Decide how locked the tablet should be: [Choosing a mode](https://kiosky.enraio.com/docs/modes.md). - Add more dashboards or a schedule: [Dashboards & browser](https://kiosky.enraio.com/docs/dashboards.md). - Connect Home Assistant: [Home Assistant integration](https://kiosky.enraio.com/docs/home-assistant.md). - Let an assistant do the setup: [Set up Kiosky with an AI assistant](https://kiosky.enraio.com/docs/ai-setup.md). --- Source: https://kiosky.enraio.com/docs/modes # Choosing a mode > Normal app, soft lock or full lock (Device Owner), single-app mode, pausing the lock and leaving the kiosk. Kiosky can run in three ways. You choose at setup and can change it any time under **Settings, Lock & security, Kiosk lock, Mode** (the choices are **Normal app** and **Locked**). | | Normal app | Soft lock | Full lock (Device Owner) | |---|---|---|---| | Computer needed | No | No | Yes, one `adb` command | | Home and Back buttons | Work normally | Home returns to Kiosky | Blocked by default | | Status bar and notifications | Normal | Normal | Blocked by default | | Other apps | Usable | Reachable through Home or Recents | Only apps you allow | | Easy to escape | Yes, by design | Fairly | No | | Remote screen off in single-app mode | No | No | Yes | Pick **normal app** for a tablet you also use yourself. Pick **soft lock** for a quick, computer-free lock that is fine at home. Pick **full lock** for a tablet that must stay on the dashboard, such as a hallway panel or a public display. ## Normal app Kiosky runs like any other app, but keeps its background services (Home Assistant, MQTT, the REST API, voice and sensors) running while you use other apps. Under **Lock & security** the **Normal app** card has these options: | Setting | Default | What it does | |---|---|---| | Start on boot | On | Opens Kiosky when the tablet turns on. | | Show on remote command | On | Brings Kiosky to the front when something remote shows content: loading a URL, switching dashboard, a popup, a camera popup, or turning the screen on. | | Return when screen turns off | Off | Brings Kiosky back to the front when the screen turns off, so the next wake shows the dashboard. | It also has two buttons for things Android needs you to allow: - **Allow auto-start** opens your manufacturer's auto-start screen (see [Troubleshooting](https://kiosky.enraio.com/docs/troubleshooting.md#start-on-boot-and-vendor-auto-start-screens)). The hint names your brand, for example HONOR. - **Allow "Display over other apps"** is needed so Kiosky can come to the front from the background. If Kiosky is still your home app from an earlier lock, a **Choose home app** button lets you pick your usual launcher again. ## Soft lock Soft lock makes Kiosky the default home app. Press Home and you land back in Kiosky. It needs no computer, but a determined user can still reach other apps through Recents. 1. Under **Lock & security, Kiosk lock**, set **Mode** to **Locked**. 2. Tap **Set home app** and choose Kiosky in the Android dialog. In the setup wizard this is the **Use soft lock** button on the Kiosk lock step. ## Full lock (Device Owner) Full lock uses Android's Device Owner mode. It blocks the status bar, the lock screen, the Home and Overview buttons and the power menu, and only lets the allowed apps run. It is the strongest lock Android offers to a normal app. > **Warning.** Android only lets an app become Device Owner on a device that has no accounts. **Remove all accounts first** (Settings, Accounts), including the Google account, or the command fails. 1. On the tablet, remove all accounts under **Settings, Accounts**. 2. Turn on **USB debugging** (Settings, Developer options). See [Troubleshooting](https://kiosky.enraio.com/docs/troubleshooting.md#usb-debugging-and-file-transfer) if the option is missing. 3. Connect the tablet to a computer and run: ```bash adb shell dpm set-device-owner com.enraio.kiosky/com.enraio.kiosky.feature.kiosk.KioskAdminReceiver ``` The tablet shows **Full lock active (Device Owner)** in the wizard, and a **Device Owner** chip in Settings. Kiosky shows the exact command for your build in Settings, Lock & security, Kiosk lock, with a **Copy command** button in the wizard. Debug builds use the application id `com.enraio.kiosky.debug`, so copy the command from the app rather than typing it if you run one. To remove Device Owner later, use **Remove Device Owner** in the same place. That turns the lock off, and locking again needs the `adb` command again. ### Lock options With Device Owner active, **Settings, Lock & security, Lock options (Device Owner)** controls what stays available while the tablet is locked. Changes apply the next time the kiosk locks (reopen the app). The options are saved even before Device Owner is active. | Option | Default | |---|---| | Block the status bar | On | | Hide the lock screen | On | | Allow the home button | Off | | Allow the overview (recents) button | Off | | Allow the power menu | Off | | Allow notifications | Off | | Grant microphone, camera and notification permissions automatically | On | **Settings, Lock & security, Other apps** lists apps that can be opened from the kiosk, for example a music or camera app. Tap **Edit allowed apps** to choose them. Full lock also lets Kiosky turn the screen off from a schedule or command and reboot the device. ## Single-app mode Instead of a dashboard, Kiosky can keep one installed app on screen. Choose **A single app** in the wizard, or go to **Settings, Dashboard, Kiosk mode** and set **Show** to **Single app**. - Kiosky stays the home app and reopens the app when it closes or crashes, waiting longer if it keeps crashing. **Reopen delay** is 1 to 30 seconds (default 2). - **Open app now** starts the app straight away. - Dimming and the screensaver are off, because Kiosky cannot see touches inside another app. - With soft lock, Home or Recents can leave the app. Screen off from a schedule or command needs full lock. - The exit corner and reopening after a kill need **Display over other apps**. The settings row shows **Done** or an **Allow** button. The exit corner is a 48 dp area at the top left. ## Leaving the kiosk **Open Settings.** Tap the top-left corner of the screen 5 times quickly. If you set an admin PIN, enter it. In single-app mode the same five taps work on the corner overlay. Wrong PINs are throttled: after 5 wrong attempts Kiosky locks PIN entry for 30 seconds, doubling with each further failure up to 15 minutes. The lockout survives a reboot. Every wrong attempt and every exit gesture is also published as an event for Home Assistant (`wrong_pin`, `exit_gesture`). ### Use the tablet normally for a while **Settings, Lock & security, Use tablet normally** unlocks the tablet temporarily and locks it again by itself. Choose **15 min**, **1 h**, **4 h** or **Until I resume**. While paused you see when the lock returns, and can tap **Resume now** or **+15 min**. No pause, with all extensions, lasts longer than 24 hours. **Lock again when idle** (on by default) resumes the lock after the screen has been off for 2 minutes. You can also pause from Home Assistant or the REST API, which needs [remote unlock](https://kiosky.enraio.com/docs/security.md#remote-control-policy) to be enabled: ```bash curl -X POST http://TABLET_IP:2323/api/command \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ -d '{"command":"kiosk_pause","args":{"minutes":30}}' ``` `kiosk_resume` ends the pause. See [REST API](https://kiosky.enraio.com/docs/rest-api.md#commands) for every command. ### Exit permanently **Settings, Lock & security, Exit kiosk permanently** turns the lock off for good and opens Android Settings. The lock does not come back by itself. To lock again, switch **Mode** back to **Locked**. --- Source: https://kiosky.enraio.com/docs/dashboards # Dashboards & browser > Multiple dashboards, rotation and planner, allowed hosts, zoom, reload, Home Assistant sign-in and theme, hiding the HA header, and the JavaScript bridge. Everything on this page lives under **Settings, Dashboard**. It applies when **Kiosk mode, Show** is set to **Browser** (the default). For single-app mode see [Choosing a mode](https://kiosky.enraio.com/docs/modes.md#single-app-mode). ## The start URL The **Dashboard** card holds the first dashboard, which is named **Home**: | Field | Meaning | |---|---| | Start URL | The page the tablet opens on start. Must be `http://` or `https://`. | | Extra allowed hosts | Comma-separated hosts, besides your dashboards, that pages may navigate to. | | Reload every N minutes | Automatic reload. `0` turns it off. The maximum is 1440 (one day). | Tap **Save dashboard** to apply. The **Reload** command and the Home Assistant **Reload** button do the same on demand. ## Allowed hosts Kiosky only navigates to hosts it trusts: the host of each dashboard URL (any port) plus your extra allowed hosts. Everything else, other schemes included, is blocked. The same list gates the `load_url` and `popup` commands and sound URLs for `play`. An allowed-host entry is one of: | Entry | Matches | |---|---| | `example.com` | exactly that host, any port | | `*.example.com` | any subdomain, but not `example.com` itself (list both if you want both) | | `example.com:8123` | that host on that port only | | `*.example.com:8123` | any subdomain on that port only | If a dashboard redirects through another host (a login page, a CDN), add that host here. The setup wizard adds a redirect target for you when it sees one. ## Multiple dashboards **More dashboards** adds extra named dashboards beside Home. Enter a **Name** (up to 64 characters, unique ignoring case) and a **URL**, then **Add dashboard**. **Remove** deletes one. With two or more dashboards you can: - **Swipe between dashboards**: switch on under **Navigation** and swipe in from the left or right screen edge. - **Show a home button**: a floating button that returns to the first dashboard. - **Switch by command**: the `dashboard` command, or the Dashboard select entity in Home Assistant. See [Home Assistant integration](https://kiosky.enraio.com/docs/home-assistant.md). - **Rotate or schedule** them, below. > **Note.** Dashboard rotation and the planner are listed among the candidate Pro features in the app. While Kiosky Pro is in development every feature is unlocked. See [Kiosky Pro](https://kiosky.enraio.com/docs/pro.md). ### Rotation **Dashboard rotation** cycles dashboards while the screen is on and untouched. Turn on **Rotate dashboards**, then set: | Setting | Default | Range | |---|---|---| | Switch every | 60 s | 5 to 600 s in the app (the config accepts up to 3600) | | Pause after a touch | 60 s | 0 to 600 s | | Dashboards in the rotation | all | at least two | ### Planner The **Dashboard planner** shows a dashboard during a daily window. Add up to 24 rules, each with a dashboard, **From** and **To** times (`HH:mm`, the window may cross midnight) and the weekdays on which the window starts. The first matching rule wins. Priority, from highest: the night page (see [Screen, power & screensaver](https://kiosky.enraio.com/docs/screen-power.md#night-mode)), then planner rules, then rotation. A manual switch (a swipe or a command) holds until the next rule starts or ends. ## Page display and navigation | Setting | Default | Notes | |---|---|---| | Text zoom | 100% | The slider runs 50 to 300%. | | Desktop mode | Off | Asks sites for their desktop layout. | | User-agent override | blank | Blank uses the default. Up to 300 characters. An explicit value wins over Desktop mode. | | Swipe between dashboards | Off | Swipe in from the left or right edge. | | Pull to refresh | Off | Pull down from the top edge to reload. | | Home button | Off | Floating button back to the first dashboard. | ## Home Assistant Under **Home Assistant sign-in**, enter your **Home Assistant address** (for example `http://homeassistant.local:8123`) and a **Long-lived access token**, then **Save sign-in**. Create the token in Home Assistant under your profile, Security, Long-lived access tokens. - The dashboard logs in without the login screen. The token is stored encrypted and is only given to the address you entered. - A saved token shows "A token is saved. Leave blank to keep it." **Remove token** deletes it. - Changing the address to a different origin removes the stored token, so a token can never be sent to a new server by accident. - A token is not sent to a plain `http://` address that is not on your local network. Use `https://` for public addresses. - The same token powers camera popups and voice. See [Camera & sensors](https://kiosky.enraio.com/docs/camera-sensors.md) and [Home Assistant integration](https://kiosky.enraio.com/docs/home-assistant.md#voice-and-assist). ### Home Assistant theme **Home Assistant theme on this tablet** sets an HA theme for this tablet only. Enter a theme name such as `Graphite` (blank keeps HA's default), choose **Light or dark** (Auto follows the tablet's setting), and tap **Save theme**. ### Hiding the Home Assistant header and sidebar Under **Custom CSS and JavaScript**, **Hide Home Assistant chrome** is built in and needs no HACS card. Choose: - **Show**: nothing is hidden. - **Hide header**: hides HA's top bar and keeps the sidebar for navigation. - **Hide both**: hides the header and the sidebar. To bring the hidden parts back, **double-tap within the top 48 pixels of the screen**. They reappear for 15 seconds and then hide again. The revealing tap is swallowed so it cannot press whatever appears underneath. The preset applies to your Home Assistant address. It works by editing HA's page styles, so a major change to the HA frontend can break it. If that happens, switch to **Show**. ## Custom CSS and JavaScript Add your own rules under **Custom CSS and JavaScript**: a **URL pattern** (for example `ha.local:8123/*`, where `*` matches any run of characters), **CSS** and **JavaScript**, then **Add rule**. You can have up to 20 rules, each part up to 20,000 characters. Rules run on matching pages only. > **Warning.** Injected scripts run inside your pages with full access to them. Only add code you trust. Over the network, changing injection rules is a protected change, see [Security](https://kiosky.enraio.com/docs/security.md#protected-settings). ## Web access: the JavaScript bridge, microphone and camera Under **Web access** you list origins (scheme, host and port, such as `http://ha.local:8123`), comma separated: - **JS bridge origins**: pages from these origins get a `window.kiosk` object. Leave empty to turn the bridge off. - **Microphone / camera origins**: pages from these origins may use the microphone or camera. They also need `https`. Leave empty to deny. The bridge returns promises: ```js // Read a limited device state: screen, screen_stage, brightness, battery, // charging, light_lux, dashboard, volume, app_version (no IP, SSID or URLs) const state = await window.kiosk.getState(); // Run a command a page is allowed to run await window.kiosk.command("toast", { text: "Hello from the page", duration: 5 }); // Listen for events such as popup_shown window.kiosk.onEvent((event) => console.log(event)); ``` A page can only run `reload`, `load_url`, `dashboard`, `screen`, `brightness`, `screensaver`, `tts`, `play`, `stop_audio`, `volume`, `toast`, `popup` and `dismiss_popup`. Reboot, restart, cache clearing and snapshots are never available to pages, whatever your remote-control settings say. --- Source: https://kiosky.enraio.com/docs/screen-power # Screen, power & screensaver > Brightness, idle dimming, screen off, the clock and photo-frame screensaver, night mode, daily maintenance and battery care. A kiosk screen should be bright when someone is there and quiet when nobody is. Kiosky does this with an idle pipeline: **dim**, then **screensaver**, then **screen off**, each after a delay you choose, with any touch (or motion, if you enable it) waking it again. Most settings are under **Settings, Screen & power**. Night mode and battery care are also under **Settings, Screen & power**. Daily maintenance, backup and logs are under **Settings, Device**. ## Screen & power | Setting | Default | Notes | |---|---|---| | Appearance | Auto | **Auto**, **Light** or **Dark** for Kiosky's own screens. Auto follows the system. | | Keep screen on | Charging | **Never**, **Charging** or **Always**. | | Auto brightness | On | Uses the light sensor between the minimum and maximum. Turn off for fixed brightness. | | Minimum / dimmed brightness | 10 | 0 to 255. Also the level used when dimmed. | | Maximum brightness | 255 | 0 to 255. The minimum can never exceed the maximum. | | Dim after | 2 min | 0 to 60 min. 0 is off. | | Screensaver after | 5 min | 0 to 120 min. 0 is off. | | Screen off after | 15 min | 0 to 240 min. 0 is off. | The stages run in that order: a tablet idle for 2 minutes dims, at 5 minutes starts the screensaver and at 15 minutes turns the screen off. The current stage is reported as `screen_stage` (`active`, `dimmed`, `screensaver` or `off`) in the REST and MQTT state. > **Note.** In single-app mode Kiosky cannot see touches inside the other app, so dimming and the screensaver are switched off there. See [Choosing a mode](https://kiosky.enraio.com/docs/modes.md#single-app-mode). You can also set the screen and brightness from outside: the `screen` and `brightness` commands (0 to 255), and in Home Assistant the **Screen** light entity. See the [REST API](https://kiosky.enraio.com/docs/rest-api.md#commands) and [MQTT reference](https://kiosky.enraio.com/docs/mqtt.md#commands). ## Screensaver **Settings, Screen & power, Screensaver, Show when idle** chooses what appears after the idle delay: | Choice | What it shows | |---|---| | Off | Nothing. The dashboard stays until the screen turns off. | | Black | A black screen. | | Clock | A large clock. The default. | | Photos | A photo frame, below. | The delay is the **Screensaver after** slider. Picking a type while it is off turns it back on with the default delay. The `screensaver` command (`on` or `off`) and the Home Assistant **Screensaver** switch start and stop it by hand. ### Photo frame **Photo frame** options: | Setting | Default | Notes | |---|---|---| | Change photo every | 30 s | 5 to 600 s. | | Shuffle | On | | | Clock and date | On | Over the bottom of the photo. | | Slow zoom | Off | A gentle Ken Burns drift. | | Scaling | Fill | **Fill** crops to cover the screen, **Fit** shows the whole photo. | Sources are additive: every source you configure feeds one playlist. - **Folders on this device**: tap **Add folder** and pick a folder such as Pictures. Sub-folders are included. You can add up to 8 folders. - **Immich**: enter your **Server URL** (for example `http://immich.lan:2283`), choose **Photos from** Random, Favourites or an Album (then enter the album id), and paste an API key created in your Immich account settings. The key is stored hidden and never exported. - **Image URLs**: one `https` image URL per line, up to 100. Home Assistant media (for example `/media/local/photo.jpg` on your HA host) is fetched with your HA token. Other hosts must be in your [allowed hosts](https://kiosky.enraio.com/docs/dashboards.md#allowed-hosts). ## Night mode **Settings, Screen & power, Night mode** applies a daily window. Turn on **Night schedule**, set **From** and **To** (`HH:mm`, local time, default 22:30 to 06:30, and the window may cross midnight) and choose what happens **During the window**: - **Dim** - **Screen off** - **Other page**: show another page. Enter the **Night page URL**; its host must be a dashboard host or an allowed host. **Window starts on** picks the weekdays the window begins. Lower-case day labels are off. The night page overrides the dashboard planner and rotation. See [Dashboards & browser](https://kiosky.enraio.com/docs/dashboards.md#planner). ## Daily maintenance **Settings, Device, Daily maintenance** can restart the app and reboot the device at fixed times: - **Restart the app at**: a local `HH:mm`, or leave empty. - **Reboot the device at**: a local `HH:mm`. This needs full lock (Device Owner) and is disabled without it. Tap **Save maintenance** to apply. ## Battery care A tablet on a charger for years can swell its battery. **Settings, Screen & power, Battery care** keeps the charge between a minimum and a maximum by telling Home Assistant when to switch the charger. 1. Turn on **Enable battery care**. 2. Set **Charge when at or below** (5 to 95%, default 40%) and **Stop charging at or above** (10 to 100%, default 80%). The minimum must be below the maximum. 3. In Home Assistant, use the **Charging wanted** binary sensor to switch a smart plug: ON means "charge now", OFF means "stop". For systems other than Home Assistant, set a **Webhook** URL. Kiosky calls it on every change with a body like: ```json {"charge_wanted": true, "battery": 38} ``` The webhook URL is stored hidden, replaced with **Save webhook** and cleared with **Remove**. Battery care needs a smart plug or other way to switch power; Kiosky only signals when. ## Backup and logs **Settings, Device, Backup & restore** exports your settings to a JSON file and imports them from a file or an `http(s)` URL. Passwords, tokens, the PIN and the battery webhook are never included. **Logs** shows the last log lines with tokens and passwords masked, and offers **Save to file** and **Share**. The same logs are at `GET /api/logs`. --- Source: https://kiosky.enraio.com/docs/home-assistant # Home Assistant integration > Connect Kiosky to Home Assistant over MQTT, every entity it creates, example automations in YAML, and the Assist voice satellite. Kiosky works with Home Assistant in three ways, which you can mix: 1. **Dashboard sign-in and theme**: the tablet shows your HA dashboard, logged in with a long-lived token. See [Dashboards & browser](https://kiosky.enraio.com/docs/dashboards.md#home-assistant). 2. **MQTT with discovery**: the tablet appears in HA as a device with sensors, switches, buttons and more, and accepts commands. This page covers it. 3. **Voice**: the tablet is an Assist satellite with an on-device wake word. See [Voice and Assist](#voice-and-assist) below. MQTT is not required. The same commands are also available over the local [REST API](https://kiosky.enraio.com/docs/rest-api.md), which you can call from HA with `rest_command`. ## Set up MQTT You need an MQTT broker that Home Assistant also uses, for example the Mosquitto add-on with the MQTT integration. Create a broker user for the tablet. 1. On the tablet open **Settings, Connections, MQTT**. 2. Turn on **Enable MQTT**. 3. Fill in **Broker host**, **Port** (default 1883; use 8883 with TLS) and, if your broker requires it, **Username** and **Password**. 4. Turn on **TLS** if your broker uses it. 5. Leave **Base topic** as `kiosk` unless you need another prefix. 6. Leave **Home Assistant discovery** on (the default). 7. Tap **Save MQTT**. The status chip goes from **Connecting** to **Connected**, or shows the error. A saved password shows "A password is saved. Leave blank to keep it." and **Remove password** clears it. The card also shows the topic prefix it will use, for example `kiosk/hallway_tablet/...`. The tablet appears in Home Assistant under **Settings, Devices & services, MQTT** with the name you set in **Settings, Device, Device name**. The device id used in topics is a lower-case slug of that name with underscores, for example `Hallway Tablet` becomes `hallway_tablet`. Renaming the device changes every topic; Kiosky clears the retained messages left under the old id. > **Security.** An anonymous broker lets anyone on your network read state and send commands. Use a broker account and TLS. Kiosky shows warnings under **Lock & security, Security** when the broker is anonymous or has no TLS. See [Security](https://kiosky.enraio.com/docs/security.md). IP address and Wi-Fi signal are published (and their sensors created) only when the connection uses a **Username**, or when you turn on **Share IP and Wi-Fi over MQTT** under **Lock & security, Security**. ## Entities Kiosky publishes retained discovery configs on `homeassistant////config`, so HA creates the entities by itself. Every entity belongs to one device, whose **Visit** link opens the tablet's admin page, and goes unavailable when the tablet goes offline. Some entities appear only when they apply: hardware that exists, features you switched on, or remote control you allowed. | Entity | Component / object id | Appears when | Notes | |---|---|---|---| | Screen | `light` / `screen` | always | On/off and brightness 0 to 255. | | Screensaver | `switch` / `screensaver` | always | On while the screensaver shows. | | Kiosk lock | `switch` / `kiosk_lock` | remote unlock allowed | On is locked. Off pauses the lock for 60 minutes. | | Volume | `number` / `volume` | always | 0 to 100 %. | | Reload | `button` / `reload` | always | Reloads the page. | | Restart app | `button` / `restart_app` | remote unlock allowed | | | Relaunch app | `button` / `relaunch_app` | remote unlock allowed and single-app mode | Reopens the configured app. | | Speak | `notify` / `tts` | always | Speaks the message on the tablet. | | Load URL | `text` / `load_url` | always | Shows the current URL; setting it navigates. | | Event | `event` / `event` | always | See [event types](#events). | | Dashboard | `select` / `dashboard` | at least one dashboard | Options are your dashboard names. | | Battery | `sensor` / `battery` | device has a battery | Percent. | | Charging | `binary_sensor` / `charging` | device has a battery | | | Charging wanted | `binary_sensor` / `charging_wanted` | device has a battery | Battery care: on means charge now. | | Battery temperature | `sensor` / `battery_temperature` | reported by device | Degrees C. | | Light level | `sensor` / `light_level` | light sensor | Lux. | | Proximity | `binary_sensor` / `proximity` | proximity sensor | Occupancy class. | | Motion | `binary_sensor` / `motion` | camera ready | Camera-based. | | Camera snapshot | `image` / `snapshot` | camera ready | The latest JPEG. | | Take snapshot | `button` / `take_snapshot` | camera ready | | | Presence | `binary_sensor` / `presence` | face presence on | Someone is in view, never who. | | Tamper | `binary_sensor` / `tamper` | tamper detection on | Tablet moved. | | Current URL | `sensor` / `current_url` | always | Truncated to 255 characters. | | Wi-Fi signal | `sensor` / `wifi_signal` | network info shared | Diagnostic, dBm. | | IP address | `sensor` / `ip_address` | network info shared | Diagnostic. | | Uptime | `sensor` / `uptime` | always | Diagnostic, seconds. | | Memory free | `sensor` / `memory_free` | always | Diagnostic, MB. | | Storage free | `sensor` / `storage_free` | always | Diagnostic, MB. | | App version | `sensor` / `app_version` | always | Diagnostic. | | WebView version | `sensor` / `webview_version` | always | Diagnostic. | | Memory trim events | `sensor` / `memory_trim_count` | always | Diagnostic. | | Last interaction | `sensor` / `last_interaction` | always | Diagnostic, timestamp. | | Microphone | `switch` / `microphone` | voice on | Privacy switch for the mic. | | Voice state | `sensor` / `voice_state` | voice on | `off`, `idle`, `listening`, `processing`, `responding`. | | Last voice command | `sensor` / `voice_last_command` | voice on and sharing on | The transcript. Turn off under **Voice** for privacy. | | Wake word | `event` / `wake_word` | voice on | Fires `wake_word_heard`. | Entity unique ids look like `kiosky__`. ### Events The **Event** entity mirrors `kiosk//event`. Its event types are: | Type | When | |---|---| | `command_rejected` | A command was refused. Attributes `command` and `reason`. | | `exit_gesture` | Someone tapped the exit corner. | | `wrong_pin` | A wrong admin PIN. Attributes `attempts_left` or `locked_out`. | | `page_error` | The page failed to load. | | `popup_shown` | A popup appeared. Attribute `host` (URL popups) or `cameras` (count). | | `popup_dismissed` | A popup closed. Adds `reason`. | | `audio_error` | Audio could not play. | | `device_moved` | Tamper detection fired. | | `kiosk_paused` | The lock was paused. Attribute `until` (an ISO time or `indefinite`). | | `kiosk_resumed` | The lock returned. Attribute `reason`: `timeout`, `user`, `remote` or `idle`. | ## Example automations These examples publish to the tablet's command topics. Replace `hallway_tablet` with your device id, which is shown at the top of **Settings, Connections, MQTT** (the "Topics:" line). The YAML uses the Home Assistant 2024.10 format (`triggers:`, `actions:`, `trigger:`, `action:`). ### Show the door camera when someone is at the door ```yaml automation: - alias: Hallway tablet shows front door camera triggers: - trigger: state entity_id: binary_sensor.front_door_person to: "on" actions: - action: mqtt.publish data: topic: kiosk/hallway_tablet/cmd/popup payload: >- {"camera": "camera.front_door", "timeout": 30, "title": "Front door"} ``` `camera` takes one entity id or an array of up to four (`["camera.front_door", "camera.driveway"]`). `timeout` is in seconds (default 60, up to 3600) and `title` is optional. The popup needs the Home Assistant address and token saved under **Dashboard, Home Assistant sign-in**. It wakes the screen, and you can close it with `dismiss_popup`: ```yaml - delay: "00:00:30" - action: mqtt.publish data: topic: kiosk/hallway_tablet/cmd/dismiss_popup payload: "" ``` To show a web page instead of a camera, send a URL: `{"url": "https://example.com/alert", "timeout": 20}`. The host must be an allowed host. ### Wake the screen when someone arrives ```yaml automation: - alias: Hallway tablet wakes on presence triggers: - trigger: state entity_id: binary_sensor.hallway_motion to: "on" actions: - action: mqtt.publish data: topic: kiosk/hallway_tablet/cmd/screen payload: "on" ``` If you enable face presence on the tablet itself, use its **Presence** entity as the trigger instead. Or tick **Wake screen on face** or **Wake screen on motion** in the app, see [Camera & sensors](https://kiosky.enraio.com/docs/camera-sensors.md). ### Make the tablet speak ```yaml automation: - alias: Announce laundry done triggers: - trigger: state entity_id: sensor.washer_state to: "finished" actions: - action: mqtt.publish data: topic: kiosk/hallway_tablet/cmd/tts payload: '{"text": "The washing machine has finished.", "volume": 60}' ``` `volume` is optional (0 to 100). The **Speak** notify entity does the same through `notify.send_message`. Speech comes from the tablet's own Android text-to-speech engine. ### Switch dashboard at a set time ```yaml automation: - alias: Evening dashboard triggers: - trigger: time at: "18:00:00" actions: - action: select.select_option target: entity_id: select.hallway_tablet_dashboard data: option: Evening ``` You can also publish `{"name": "Evening"}` or just `Evening` to `kiosk/hallway_tablet/cmd/dashboard`. For fixed daily windows, the built-in [planner](https://kiosky.enraio.com/docs/dashboards.md#planner) needs no automation. ### React to someone moving the tablet ```yaml automation: - alias: Tablet tamper alert triggers: - trigger: state entity_id: binary_sensor.hallway_tablet_tamper to: "on" actions: - action: notify.mobile_app_phone data: message: The hallway tablet was moved. ``` Entity ids such as `select.hallway_tablet_dashboard` are chosen by Home Assistant from the device and entity names. Check the real id in **Settings, Devices & services, Entities**. ## Voice and Assist Kiosky can be a voice satellite for Home Assistant Assist. A wake word runs on the tablet, and audio is only sent to Home Assistant after the wake word is heard. **Requirements** - A Home Assistant with an Assist pipeline that has speech-to-text and text-to-speech (Home Assistant Cloud, or local Whisper and Piper). - The Home Assistant address and a long-lived token. - The microphone permission. **Settings, Voice, Voice assistant** 1. Turn on **Enable voice**. 2. Enter the **Home Assistant URL** and **Long-lived access token** (Profile, Security in HA). The token is stored encrypted. **Remove token** deletes it. 3. Optionally enter an **Assist pipeline id**. Blank uses your preferred pipeline. 4. Tap **Allow microphone** and grant the permission. 5. Choose a **Wake word**: Okay Nabu (the default), Hey Jarvis or Hey Mycroft. 6. Adjust **Wake threshold**. Lower wakes more easily and falsely more often. Higher needs a clearer wake word. Each model has its own default. 7. Tap **Save voice**. A status chip tells you whether Kiosky is listening and why not, for example "Paused while the screen is off". | Toggle | Default | Effect | |---|---|---| | Microphone | On | A privacy switch, also in Home Assistant as the **Microphone** switch. | | Listen only while the screen is on | On | | | Listen only while charging | Off | | | Chime on wake word | On | | | Show what was heard | On | Shows the transcript on screen. | | Share last command with Home Assistant | On | Publishes the transcript as a sensor. | Short commands are handled on the tablet without a round trip to Home Assistant. They are matched against the whole sentence, in English: "screen off", "go home", "volume up", "volume down", "set volume to 40", "stop", "reload", and "show ". Anything else goes to your Assist pipeline, and the spoken answer plays on the tablet. > **Note.** Wake word accuracy depends on microphone distance and room noise. There is no pipeline picker yet, so enter the pipeline id by hand. Voice needs a Home Assistant address that uses a certificate trusted by Android; self-signed HTTPS is not supported for the voice connection. Voice is among the candidate [Kiosky Pro](https://kiosky.enraio.com/docs/pro.md) features. --- Source: https://kiosky.enraio.com/docs/camera-sensors # Camera & sensors > Motion wake, face presence, tamper detection, snapshots, the MJPEG stream, camera popups and QR config import. Kiosky can use the tablet's front camera and sensors to wake the screen, report presence to Home Assistant and send snapshots. Everything is **off by default** and processed on the device. Find the settings under **Settings, Camera & sensors**. > **Note.** Camera features are among the candidate [Kiosky Pro](https://kiosky.enraio.com/docs/pro.md) features. While Pro is in development every feature is unlocked. ## Privacy at a glance - Motion and face detection analyse frames on the tablet and discard them. Frames never leave the device. - Face detection only counts faces. It never recognises anyone, and no image is stored or sent. - Only snapshots (on request, or on motion if you enable it) leave the device, and only to your MQTT broker or to a REST client that has your API token. - The live stream is the one feature that sends camera frames continuously, and only to a client that has your API token. - While the camera is on, Android shows its green camera indicator. ## Camera permission Under **Camera**, **Camera permission** shows **Granted** or an **Allow** button. It is needed for motion detection, snapshots and QR scanning. If no prompt appears, open Android settings, Apps, Kiosky, Permissions, Camera. On Device Owner tablets the permission can be granted automatically (see [Lock options](https://kiosky.enraio.com/docs/modes.md#lock-options)). If the device has no camera, the section says so, and the camera entities are not created. ## Motion detection Turn on **Motion detection** to analyse the front camera at low resolution. | Setting | Default | Notes | |---|---|---| | Motion detection | Off | | | Wake screen on motion | Off | Treats movement like a touch. It wakes the screen from dim, screensaver and off. | | Snapshot on motion | Off | Publishes a photo to MQTT when motion starts, at most every 30 seconds. | | Sensitivity | 50% | 0% needs large movement, 100% is very sensitive. | | Analysis rate | 2 fps | 1 to 10 frames per second. | **Live preview** lets you tune sensitivity while watching the detector: it shows **Motion** or **Still** and the percentage of the image that changed against what is needed. Motion is reported to Home Assistant as the **Motion** binary sensor, and as `motion` in the REST and MQTT state. ## Face presence **Face presence** reports a presence sensor to Home Assistant by counting faces in view. It uses ML Kit on the front camera, which costs roughly 3 to 6% CPU at 2 fps, so it is opt-in. | Setting | Default | Notes | |---|---|---| | Face presence | Off | Creates the **Presence** binary sensor. | | Wake screen on face | Off | Treats a face in view like a touch. | | Detection rate | 2 fps | 1 to 4 fps. | | Hold time | 30 s | 5 to 600 s. Presence stays on this long after the last face. | ## Tamper detection **Tamper detection** uses the accelerometer, at low power, to flag the tablet being lifted, shaken or turned. It publishes a `device_moved` event and sets the **Tamper** binary sensor. **Sensitivity** runs from 0% (needs a real lift) to 100% (any nudge); the default is 50%. ## Snapshots A snapshot is a JPEG of the front camera. Three ways to get one: - In the app, **Take a test snapshot** under **Camera**. - Send the `snapshot` command (REST, MQTT or the **Take snapshot** button in Home Assistant). The JPEG is published to `kiosk//camera/snapshot` and appears as the **Camera snapshot** image entity. - `GET /api/camera/snapshot` returns a JPEG, no older than a couple of seconds, over the [REST API](https://kiosky.enraio.com/docs/rest-api.md#camera). ## Live stream The REST server can serve the front camera as an MJPEG stream. 1. Turn on **Settings, Connections, Remote access, REST API & admin page** (the stream is served by that server). 2. Under **Camera & sensors, Live camera stream**, turn the stream on. 3. Set **Frame rate** (1 to 5 fps, default 2) and **Largest side** (160 to 1280 px, default 480). JPEG quality is 60 by default (the config accepts 30 to 90). The camera only runs while a viewer is connected, and at most 2 viewers can connect at once. Turning the stream on is a protected setting, so it can only be changed on the tablet unless you allow remote security changes (see [Security](https://kiosky.enraio.com/docs/security.md#protected-settings)). The app shows the exact values to use. In Home Assistant add a **Generic MJPEG camera** (the `mjpeg` integration) with: ```text URL: http://TABLET_IP:2323/api/camera/stream Username: kiosky Password: Authentication: basic ``` HA's `mjpeg` camera cannot send a Bearer header, so this one path also accepts HTTP Basic with the fixed username `kiosky` and your token as the password. A `?token=` query is deliberately not supported, because it would leak into URLs and logs. ## Camera popups Home Assistant can pop a camera feed over the dashboard, for example when the doorbell rings. This uses the **Home Assistant** camera, not the tablet's own camera. - Save your Home Assistant address and token under **Dashboard, Home Assistant sign-in**. - Send the `popup` command with a `camera` entity id (or up to four), an optional `timeout` in seconds and an optional `title`: ```json {"command": "popup", "args": {"camera": ["camera.front_door", "camera.driveway"], "timeout": 30, "title": "Doorbell"}} ``` Kiosky reads each camera from Home Assistant (an MJPEG stream, or one JPEG per second when the server does not stream), reconnecting if it drops. The popup wakes the screen and closes on its timeout, on the close button, with Back, or with `dismiss_popup`. See [Home Assistant integration](https://kiosky.enraio.com/docs/home-assistant.md#show-the-door-camera-when-someone-is-at-the-door) for an automation. ## Import settings with a QR code Under **Camera**, **Scan QR to import config** reads a QR code that contains either a Kiosky config as JSON or a link to one (`http` or `https`, no username in the link). Nothing is applied until you review a list of changes and tap **Apply**. A partial config only changes the fields it contains, and everything else keeps its value. ## Troubleshooting If the camera will not start, another app may be using it, or the permission is missing. See [Troubleshooting](https://kiosky.enraio.com/docs/troubleshooting.md#camera-is-busy-or-unavailable). --- Source: https://kiosky.enraio.com/docs/rest-api # REST API reference > The local REST API and web admin page: authentication, every endpoint, the command list, reading and writing config, rate limits and mDNS discovery. Each tablet can run a small HTTP server on your local network. It serves a web admin page and a JSON API for state, commands and configuration. It is **off by default** and meant for your LAN only. > **Warning.** The API uses plain HTTP, so the token can be read by anyone on the same Wi-Fi. Never forward the port to the internet. See [Security](https://kiosky.enraio.com/docs/security.md). ## Turn it on 1. Open **Settings, Connections, Remote access**. 2. Turn on **REST API & admin page**. The status chip shows **Running on port 2323**. 3. Under **API token** tap **Show** or **Copy**. A token is created when you first turn remote access on. 4. The **Admin page** line shows the address, such as `http://192.168.1.50:2323/`. | Setting | Default | Notes | |---|---|---| | REST API & admin page | Off | | | Port | 2323 | 1024 to 65535. Tap **Apply**. | | API token | generated | 43 characters of base64url (32 random bytes). **Regenerate** locks out every client using the old token at once. | The server listens on all network interfaces of the tablet. The examples below use `TABLET_IP` for its address and `$KIOSKY_TOKEN` for the token. ## Authentication Every endpoint except `GET /api/info` needs the token in an `Authorization` header: ```bash curl -H "Authorization: Bearer $KIOSKY_TOKEN" http://TABLET_IP:2323/api/state ``` | Status | Meaning | |---|---| | `401` | Missing or invalid token. The `WWW-Authenticate` header says `Bearer`. | | `429` | Too many failed attempts. The `Retry-After` header gives the seconds to wait. | The one exception is `GET /api/camera/stream`, which also accepts HTTP Basic with the username `kiosky` and the token as the password, for clients such as Home Assistant's MJPEG camera that cannot send a Bearer header. Tokens in the URL query are not supported. Errors are JSON of the form `{"error": "message"}`. Responses carry `Cache-Control: no-store`. There is no CORS, so browsers on other sites cannot call the API. ### Rate limits - Failed authentication is counted per client address. **5 failures within 60 seconds** lock that address out for 60 seconds. Each further lockout doubles, up to 15 minutes. - A successful request clears the address's record. - A global ceiling guards against guessing from many addresses: **50 failures within 60 seconds from all clients combined** lock everyone out for 60 seconds. - Request bodies are limited to 256 KiB (`413` above that). Command payloads are limited to 4096 characters. ## Endpoints | Method | Path | Auth | Returns | |---|---|---|---| | GET | `/` | none | The web admin page (HTML). | | GET | `/api/info` | none | App, device name, id, version. | | GET | `/api/state` | token | Device state as JSON. | | POST | `/api/command` | token | Runs a [command](#commands). | | GET | `/api/config` | token | The whole configuration as JSON. | | PATCH | `/api/config` | token | Changes only the fields in the body. `?dryRun=true` only checks. | | PUT | `/api/config` | token | Replaces the whole configuration. `?dryRun=true` only checks. | | GET | `/api/screenshot` | token | A PNG of the visible screen. | | GET | `/api/camera/snapshot` | token | A JPEG from the front camera. | | GET | `/api/camera/stream` | token or Basic | MJPEG stream. | | GET | `/api/logs` | token | Recent log lines as text. | ### GET /api/info Public, so a client can confirm it found a Kiosky tablet before it has a token. ```bash curl http://TABLET_IP:2323/api/info ``` ```json {"app": "Kiosky", "name": "Hallway Tablet", "id": "hallway_tablet", "version": "0.1.0"} ``` `id` is a lower-case slug of the device name with underscores. It is the same id used in the mDNS records and in the MQTT topics (`kiosk/hallway_tablet/...`). ### GET /api/state ```bash curl -H "Authorization: Bearer $KIOSKY_TOKEN" http://TABLET_IP:2323/api/state ``` ```json { "battery": {"levelPercent": 87, "charging": true, "temperatureC": 29.5}, "screenOn": true, "brightness": 120, "currentUrl": "http://homeassistant.local:8123/lovelace/0?kiosk", "lightLux": 85.0, "proximityNear": null, "motion": false, "network": {"ssid": "home", "rssiDbm": -52, "ipAddress": "192.168.1.50"}, "appVersion": "0.1.0", "webViewVersion": "130.0.6723.58", "uptimeSeconds": 86400, "memoryFreeMb": 812, "storageFreeMb": 20480, "screenStage": "active", "kioskMode": "device_owner", "lastInteractionEpochMs": 1763040000000, "kioskPaused": false, "kioskPausedUntilEpochMs": null } ``` | Field | Meaning | |---|---| | `battery` | `levelPercent`, `charging`, `temperatureC`, or `null` without a battery. | | `screenOn`, `brightness` | Screen state and current brightness (0 to 255, may be `null`). | | `currentUrl` | The page on screen. | | `lightLux`, `proximityNear` | Sensor readings, `null` when there is no sensor. | | `motion` | Camera motion, when motion detection is on. | | `network` | `ssid`, `rssiDbm`, `ipAddress`. | | `screenStage` | `active`, `dimmed`, `screensaver` or `off`. | | `kioskMode` | `none`, `soft` or `device_owner`. | | `lastInteractionEpochMs` | Time of the last touch. | | `kioskPaused`, `kioskPausedUntilEpochMs` | Whether the lock is paused and until when (`null` means until resumed). | MQTT publishes a flatter state with more keys (volume, dashboard, presence, tamper, voice). See the [MQTT reference](https://kiosky.enraio.com/docs/mqtt.md#state). ### POST /api/command The body is a JSON object with a `command` name and optional `args`. `args` is either an object, or a single plain value that fills the command's main argument. ```bash curl -X POST http://TABLET_IP:2323/api/command \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ -d '{"command": "brightness", "args": {"level": 128}}' # the same, with a plain value curl -X POST http://TABLET_IP:2323/api/command \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ -d '{"command": "brightness", "args": 128}' ``` | Status | Body | Meaning | |---|---|---| | `202` | `{"ok": true}` | Accepted and queued. It does not wait for the command to finish. | | `400` | `{"error": "'level' must be 0–255"}` | Invalid command, missing or bad argument, or invalid JSON. | | `403` | `{"error": "Remote unlock is turned off on this tablet"}` | A sensitive command while remote unlock is off. | | `409` | `{"error": "Reboot requires Device Owner"}` | The device cannot do this. | | `413` | | Body too large. | | `503` | `{"error": "Command queue is full"}` | Try again shortly. | ## Commands The command names and arguments are shared by REST, MQTT and the page bridge. In the table, **Main arg** is the one a plain `args` value fills. | Command | Arguments | Notes | |---|---|---| | `reload` | none | Reloads the page. | | `load_url` | `url` (main) | Must be an `http(s)` URL on an [allowed host](https://kiosky.enraio.com/docs/dashboards.md#allowed-hosts). | | `screen` | `state`: `on` or `off` (main) | `true`, `false`, `1` and `0` also work. | | `brightness` | `level`: 0 to 255 (main) | | | `screensaver` | `state`: `on` or `off` (main) | | | `dashboard` | `name` (main) | Name of a configured dashboard. | | `tts` | `text` (main, up to 1000 characters), `volume` 0 to 100 (optional) | Speaks with Android text-to-speech. | | `play` | `url` (main), `volume` 0 to 100 (optional) | Plays audio from an allowed host. | | `stop_audio` | none | | | `volume` | `level`: 0 to 100 (main) | Media volume. | | `toast` | `text` (main), `duration` 1 to 60 seconds (default 4) | Shows a banner. Up to 3 show at once. | | `popup` | `url` (main) or `camera`; `timeout` 1 to 3600 seconds (default 60); `title` up to 80 characters | A URL popup, or a Home Assistant camera popup with `camera` as one entity id or up to four, for example `camera.front_door`. | | `dismiss_popup` | none | | | `snapshot` | none | Takes a camera photo and publishes it. | | `microphone` | `state`: `on` or `off` (main) | The voice mic privacy switch. | | `kiosk_lock` | `state`: `on` or `off` (main) | `on` resumes the lock, `off` pauses it for 60 minutes. | | `kiosk_resume` | none | Ends a pause. | | `kiosk_pause` | `minutes`: 1 to 1440 (main) | Sensitive. Unlocks the tablet, then re-locks. | | `launch_app` | `package` (main, optional) | Sensitive. No package opens the single-app mode app. | | `exit_app_mode` | none | Sensitive. Leaves single-app mode. | | `restart_app` | none | Sensitive. | | `clear_cache` | none | Sensitive. | | `reboot` | none | Sensitive. Needs full lock (Device Owner), else `409`. | Examples: ```json {"command": "toast", "args": {"text": "Dinner is ready", "duration": 10}} {"command": "popup", "args": {"camera": "camera.front_door", "timeout": 30}} {"command": "popup", "args": {"url": "https://example.com/alert", "title": "Alert"}} {"command": "dashboard", "args": "Energy"} {"command": "kiosk_pause", "args": {"minutes": 30}} ``` **Sensitive** commands (`kiosk_pause`, `kiosk_lock` with `off`, `launch_app`, `exit_app_mode`, `restart_app`, `clear_cache`, `reboot`) are refused with `403` unless you turned on **Allow remote unlock & app control** on the tablet. See [Security](https://kiosky.enraio.com/docs/security.md#remote-control-policy). Everything else is benign and always allowed. ## Configuration ### GET /api/config Returns the whole configuration as pretty-printed JSON. Secrets are never in it: the HA token, MQTT password, admin PIN, API token, Immich key and webhook URL are stored separately. ```bash curl -H "Authorization: Bearer $KIOSKY_TOKEN" http://TABLET_IP:2323/api/config ``` ```json { "version": 1, "device": {"name": "Hallway Tablet", "theme": "auto"}, "browser": { "dashboards": [{"name": "Home", "url": "http://homeassistant.local:8123/lovelace/0"}], "allowedHosts": [], "reloadIntervalMinutes": 0, "zoomPercent": 100 }, "kiosk": {"enabled": true, "mode": "browser"}, "power": { "keepScreenOn": "when_charging", "idle": {"dimAfterSeconds": 120, "screensaverAfterSeconds": 300, "offAfterSeconds": 900}, "brightness": {"mode": "auto", "min": 10, "max": 255} }, "server": {"enabled": true, "port": 2323}, "remote": {"allowUnlock": false, "allowSecurityChanges": false} } ``` The real response includes every section with all its defaults. The example above is cut for length. ### PATCH /api/config `PATCH` changes only the fields you send. The body is a partial JSON object that is deep-merged onto the current configuration: objects merge key by key, while arrays and scalar values replace the current value. Anything you leave out keeps its current value. This is the safe way to make a change. ```bash # 1. check it without saving: dim after 1 minute curl -X PATCH "http://TABLET_IP:2323/api/config?dryRun=true" \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ -d '{"power": {"idle": {"dimAfterSeconds": 60}}}' # 2. save it curl -X PATCH http://TABLET_IP:2323/api/config \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ -d '{"power": {"idle": {"dimAfterSeconds": 60}}}' ``` Because arrays replace, to change one dashboard send the whole `browser.dashboards` array. | Status | Body | Meaning | |---|---|---| | `200` | `{"ok": true, "saved": true}` | Merged, saved and applied. | | `200` | `{"ok": true, "saved": false}` | `dryRun=true`: the merged config is valid, nothing was saved. | | `403` | `{"error": "protected", "message": "...", "paths": ["kiosk.enabled"]}` | The change touches a protected setting. Nothing was saved. | | `413` | | Body larger than 256 KiB. | | `422` | `{"error": "Config is invalid", "errors": [{"path": "power.idle.dimAfterSeconds", "message": "Must be 0–86400"}]}` | The body is not a JSON object (`path` is `$`), or the merged config failed validation. Nothing was saved. | The merge is repeated inside the atomic save, so a change made at the same moment to other fields is not lost. `dryRun` is only active for the exact value `true`. Always dry-run first. The `remote` settings cannot be changed over REST. ### PUT /api/config `PUT` **replaces** the entire configuration with the body. Fields you leave out go back to their defaults, they are not kept. Use it only when you really want to replace everything, for example to restore a backup: `GET /api/config`, edit, then `PUT` the full document. It supports `?dryRun=true` and returns the same statuses as `PATCH`. ```bash curl -s -H "Authorization: Bearer $KIOSKY_TOKEN" http://TABLET_IP:2323/api/config > config.json # restore or replace: check first, then save curl -X PUT "http://TABLET_IP:2323/api/config?dryRun=true" \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ --data @config.json curl -X PUT http://TABLET_IP:2323/api/config \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ --data @config.json ``` If a `PUT` body has no `remote` key, the tablet keeps its own `remote` settings. Files with a newer `version` than the app supports are rejected. ### Protected settings Some settings decide who can control or reach the tablet. A `PUT` or `PATCH` that changes any of them returns `403` and saves nothing, unless **Allow remote security changes** is on in the tablet's settings. The `remote` settings themselves can never be changed over REST. | Path prefix | Why | |---|---| | `kiosk` | The lock, single-app mode, allowed apps. | | `remote` | The switches that govern remote control. Never over REST. | | `server` | The REST server itself (enabled, port). | | `camera.stream` | The camera stream. | | `homeAssistant.baseUrl` | Where the HA token is sent. | | `browser.injections` | Scripts that run in your pages. | | `browser.allowedHosts` | What the browser may reach. | | `browser.bridgeOrigins`, `browser.mediaOrigins` | Pages that get the bridge or the microphone. | | `mqtt.host`, `mqtt.port`, `mqtt.tls`, `mqtt.username`, `mqtt.publishNetworkInfo` | Where MQTT credentials and state go. | Changing the Home Assistant origin or the MQTT host also deletes the saved HA token or MQTT password, so a secret never follows a changed address. ### Config reference These are the settings most often changed, with their defaults. Times are local `HH:mm`. | Path | Default | Notes | |---|---|---| | `device.name` | `"Kiosky"` | 1 to 64 characters. Drives topic and mDNS names. | | `device.theme` | `"auto"` | `auto`, `light`, `dark`. | | `browser.dashboards[]` | `[]` | `{"name", "url"}`, unique names. | | `browser.allowedHosts[]` | `[]` | Protected. See [allowed hosts](https://kiosky.enraio.com/docs/dashboards.md#allowed-hosts). | | `browser.reloadIntervalMinutes` | `0` | 0 to 1440. | | `browser.zoomPercent` | `100` | 25 to 500. | | `browser.pullToRefresh`, `desktopMode`, `swipeDashboards`, `homeButton` | `false` | | | `browser.rotation` | off | `enabled`, `intervalSeconds` (5 to 3600, default 60), `pauseSeconds` (0 to 3600, default 60), `dashboards[]`. | | `browser.planner[]` | `[]` | `{"dashboard", "from", "to", "days"}`, up to 24 rules. | | `kiosk.enabled` | `false` | Protected. Locked or normal app. | | `kiosk.mode` | `"browser"` | Protected. `browser` or `app`. | | `kiosk.app` | none | Protected. `{"package", "activity"}`. | | `kiosk.normal` | see below | Protected. `startOnBoot` true, `showOnCommand` true, `returnOnScreenOff` false. | | `power.keepScreenOn` | `"when_charging"` | `never`, `when_charging`, `always`. | | `power.idle` | 120 / 300 / 900 | `dimAfterSeconds`, `screensaverAfterSeconds`, `offAfterSeconds` (0 turns a stage off). | | `power.brightness` | `auto`, 10, 255 | `mode` (`auto` or `manual`), `min`, `max`. | | `power.night` | off | `from` 22:30, `to` 06:30, `action` (`dim`, `off`, `url`), `days` 1 to 7, `url`. | | `power.battery` | off | `enabled`, `minPercent` 40, `maxPercent` 80. | | `wake.touch`, `wake.motion` | `true`, `false` | | | `screensaver.type` | `"clock"` | `none`, `clock`, `photos`. | | `screensaver.photos` | | `folderUris`, `immich`, `urls`, `intervalSeconds` 30, `shuffle` true, `fit`, `kenBurns`, `showClock`. | | `homeAssistant` | off | `enabled`, `baseUrl` (protected), `theme`, `themeMode`. | | `mqtt` | off | `enabled`, `host`, `port` 1883, `tls`, `username`, `baseTopic` "kiosk", `discovery` true, `publishIntervalSeconds` 60. | | `server` | off, 2323 | Protected. | | `maintenance` | none | `restartAppAt`, `rebootAt`. | | `camera.motion` | off | `enabled`, `sensitivity` 0.5, `fps` 2, `snapshotOnMotion`. | | `camera.face` | off | `enabled`, `wakeOnFace`, `fps` 2, `holdSeconds` 30. | | `camera.tamper` | off | `enabled`, `sensitivity` 0.5. | | `camera.stream` | off | Protected. `enabled`, `fps` 2, `maxEdgePx` 480, `quality` 60. | | `voice` | off | `enabled`, `wakeWord` "okay_nabu", `micMuted`, `listenOnlyWhenScreenOn` true, `listenOnlyWhenCharging` false, `showTranscript`, `publishLastCommand`, `chime`, `pipelineId`. | | `remote` | both `false` | `allowUnlock`, `allowSecurityChanges`. Never over REST. | ## Other endpoints ### Screenshot `GET /api/screenshot` returns a PNG of the screen (`image/png`), or `503` with `"No visible screen to capture"` when nothing is on screen. ```bash curl -H "Authorization: Bearer $KIOSKY_TOKEN" http://TABLET_IP:2323/api/screenshot -o screen.png ``` ### Camera `GET /api/camera/snapshot` returns a JPEG no older than a couple of seconds, or `503` ("Camera unavailable"). `GET /api/camera/stream` returns `multipart/x-mixed-replace` MJPEG. It answers `404` ("Camera stream is disabled") unless the stream is turned on, and `503` when 2 viewers are already connected or the camera does not start within 15 seconds. See [Camera & sensors](https://kiosky.enraio.com/docs/camera-sensors.md#live-stream). ### Logs `GET /api/logs?lines=200` returns plain text. `lines` defaults to 500 and is limited to 1 to 2000. Tokens and passwords are masked. ## Admin page Open `http://TABLET_IP:2323/` in a browser, paste the API token and tap **Connect**. The page offers quick actions (reload, screen on and off, restart app, brightness, load a URL), live state, and a JSON editor for the configuration with **Reload from device**, **Validate** and **Save**. It talks to the same API. ## Discover tablets on the network (mDNS) While the server runs, the tablet announces itself over mDNS/DNS-SD as both `_kiosk._tcp` and `_http._tcp`. The service name is the device name (Android may append ` (2)` if there is a conflict), and the TXT records are: | Key | Value | |---|---| | `id` | The slug, such as `hallway_tablet`. | | `version` | The app version. | | `path` | `/` | Android cannot publish a `.local` host name, so resolve the service name to an address and port instead: ```bash # macOS dns-sd -B _kiosk._tcp local dns-sd -L "Hallway Tablet" _kiosk._tcp local # Linux avahi-browse -rt _kiosk._tcp ``` Then call `GET /api/info` on the address and port to confirm. If mDNS is blocked on your network, use the IP address shown in the app (**Settings, Device**, or **Connections, Remote access**) and the port. ## Home Assistant without MQTT You can drive a tablet from Home Assistant with `rest_command`: ```yaml rest_command: kiosky_hallway_toast: url: "http://192.168.1.50:2323/api/command" method: POST headers: Authorization: !secret kiosky_hallway_bearer # "Bearer " Content-Type: application/json payload: '{"command": "toast", "args": {"text": "{{ message }}", "duration": 8}}' ``` Keep the token in `secrets.yaml`, never in a file you share. --- Source: https://kiosky.enraio.com/docs/mqtt # MQTT reference > Topic layout, the state and event payloads, the command list and delivery details for talking to Kiosky over MQTT. 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](https://kiosky.enraio.com/docs/home-assistant.md). 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 `/`. 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//availability` | tablet to broker | yes, and the last will | `online` or `offline` | | `kiosk//state` | tablet to broker | yes | JSON of all values, see [State](#state) | | `kiosk//event` | tablet to broker | no | `{"type": "...", ...}`, see [Events](#events) | | `kiosk//camera/snapshot` | tablet to broker | no | JPEG bytes | | `kiosk//cmd/` | broker to tablet | n/a | command payload, see [Commands](#commands) | | `homeassistant////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//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//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//cmd/`. 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.` | `{"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](https://kiosky.enraio.com/docs/rest-api.md#commands). `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](https://kiosky.enraio.com/docs/security.md#remote-control-policy). ## Discovery With **Home Assistant discovery** on, Kiosky publishes a retained config for every entity at `homeassistant////config`. All entities share one device block with the identifier `kiosky_`, the device name, model, manufacturer, app version and a link to the admin page. The full entity list is in [Home Assistant integration](https://kiosky.enraio.com/docs/home-assistant.md#entities). 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}' ``` --- Source: https://kiosky.enraio.com/docs/pro # Kiosky Pro > Plans and prices, which features Pro covers, how to activate a tablet with a QR code, how to manage devices and how the 30-day offline grace works. Kiosky is free to use as a kiosk. **Kiosky Pro** adds capabilities for smart-display setups. One principle holds throughout: reliability and safety are never paywalled, and the kiosk never stops working because a licence ran out. ## Plans | Plan | Price | Notes | |---|---|---| | Free | $0 | The kiosk, lockdown and the basics. No account needed. | | Pro yearly | $12.99 per year | Starts with a 30-day free trial. | | Pro lifetime | $29.99 once | One payment, no renewal. | | Fleet | Priced per device | For businesses. Coming soon. | Prices are in US dollars. Google Play and the web checkout show local prices and add tax where it applies. Pro covers up to **3 devices** on one Kiosky account. For the current launch offer and refund terms see [Pricing](https://kiosky.enraio.com/pricing.html) and the [FAQ](https://kiosky.enraio.com/faq.html). Pro belongs to a **Kiosky account**, not to a Google account. A tablet with no Google account on it, which is normal for full lock, activates the same way. ## What Pro unlocks The app tracks these features as the Pro set: | Feature | Where to find it | |---|---| | Voice assistant | Settings, Voice. See [Home Assistant integration](https://kiosky.enraio.com/docs/home-assistant.md#voice-and-assist). | | Camera motion detection | Settings, Camera & sensors. See [Camera & sensors](https://kiosky.enraio.com/docs/camera-sensors.md#motion-detection). | | Camera presence | Settings, Camera & sensors. See [face presence](https://kiosky.enraio.com/docs/camera-sensors.md#face-presence). | | Camera snapshots and stream | See [Snapshots](https://kiosky.enraio.com/docs/camera-sensors.md#snapshots) and the [live stream](https://kiosky.enraio.com/docs/camera-sensors.md#live-stream). | | Photo screensaver | Settings, Screen & power. See [Photo frame](https://kiosky.enraio.com/docs/screen-power.md#photo-frame). | | Dashboard planner and rotation | Settings, Dashboard. See [Dashboards & browser](https://kiosky.enraio.com/docs/dashboards.md#rotation). | | Remote REST API and web admin | Settings, Connections. See [REST API reference](https://kiosky.enraio.com/docs/rest-api.md). | | Priority popups | The `popup` command. See [Camera popups](https://kiosky.enraio.com/docs/camera-sensors.md#camera-popups). | The [pricing page](https://kiosky.enraio.com/pricing.html) lists the intended free and Pro split in full, including the allowed-apps launcher, scheduled restart, night schedule and battery care. The free tier keeps the Device Owner and home-app lock, the exit gesture and admin PIN, pausing for normal use, start on boot, one page with an allow-list, idle dim and off, the clock screensaver, MQTT with core sensors and commands, and config export and import as a file. > **Note.** Licence enforcement is switched off in the current build, so every feature is unlocked while Pro is in development. Settings shows "Every feature is unlocked while Pro is in development". The exact list of Pro features is finalised before launch, and the pricing page is the source of truth for it. When enforcement is on and your licence does not include a feature, Settings shows a small **Pro** badge next to it. Nothing on the kiosk screen ever nags you. ## Activate a tablet Activation links one tablet to your Kiosky account. You need a phone or computer to approve it. 1. On the tablet, open Settings (tap the top-left corner 5 times, then the PIN) and go to **Kiosky Pro**. 2. Tap **Activate Pro** (or **Activate**). The tablet shows a QR code and an 8-character code like `ABCD-EFGH`, with a countdown to its expiry. 3. On your phone, scan the QR code, or open the address shown and type the code. 4. Sign in with your email. You receive a 6-digit code (valid for 10 minutes) and a one-time sign-in link. Either works. 5. Review the tablet's name, model and plan, then tap **Approve**. **Deny** cancels. 6. The tablet shows "This tablet is activated. Thank you." If you deny it, it says so. If the code expires, tap **Try again**. The tablet itself keeps a private key in Android Keystore and signs its requests, so an activation cannot be copied to another device. ## Manage your devices - **See your plan.** Under **Settings, Kiosky Pro**, the card shows the **Plan** (Free, Pro or Fleet), its status, **Valid until** and a short **Device ID**. - **Refresh now** asks the licence server for a fresh licence straight away. - **Deactivate this device** frees its seat on your account. Pro features switch off on that tablet until you activate it again. - **When all 3 slots are in use**, the approval page says "All device slots are in use" and lists your devices. Remove one there to free a slot, then approve the new tablet. ## Offline grace and expiry A kiosk on a LAN may rarely reach the internet, so licences are built to survive being offline: - The tablet stores a signed licence and refreshes it about once a day when it can reach the licence server. - A licence is valid for up to 30 days. If the tablet cannot refresh, it keeps working on the licence it has. The status then reads **Offline grace** with "Could not refresh recently. Works offline until this date." - If a licence passes its end date the status becomes **Expired**: "Pro features are off. The kiosk keeps running." Settings keep their values, and Pro-only features switch off. - A yearly plan that is cancelled keeps working until the end of the paid year, plus a short grace period. - If a device's licence is revoked (for example after you remove it from your account), Settings says "This device's licence was revoked". Status values you may see: **Active**, **Offline grace**, **Expired** and **Not activated**. --- Source: https://kiosky.enraio.com/docs/security # Security > The admin PIN, the remote-control policy, protected settings, API token handling and guidance for keeping Kiosky on your local network. A kiosk is usually a tablet on a wall that many people can touch, connected to your home or office network. Kiosky's defaults assume that. This page explains the controls and what each one protects. ## Admin PIN The admin PIN protects leaving the kiosk and changing settings. Set it in the setup wizard, or under **Settings, Lock & security, Admin PIN**. - A PIN is 4 to 12 digits. It is stored as a hash, never as text. - **No PIN set:** the exit gesture opens Settings for anyone. Kiosky warns you with "No PIN set: the exit gesture opens settings for anyone." - Wrong attempts are throttled. After 5 wrong PINs entry locks for 30 seconds, and each further failure doubles the lock, up to 15 minutes. The lockout survives reboots. - Each wrong PIN and each exit gesture is published as an event (`wrong_pin`, `exit_gesture`), so you can be alerted. See [Home Assistant integration](https://kiosky.enraio.com/docs/home-assistant.md#events). The exit gesture is five quick taps on the top-left corner. ## Remote-control policy Commands can reach the tablet from several places: the on-device UI, local voice, MQTT, the REST API, a web page through the bridge, and the app's own schedules. Every command passes one central policy, whatever its source. Commands fall into two classes: | Class | Commands | Effect | |---|---|---| | Benign | `reload`, `load_url`, `screen`, `brightness`, `screensaver`, `dashboard`, `tts`, `play`, `stop_audio`, `volume`, `toast`, `popup`, `dismiss_popup`, `snapshot`, `microphone`, `kiosk_resume`, `kiosk_lock on` | Change what is shown or heard. The kiosk stays locked. | | Sensitive | `kiosk_pause`, `kiosk_lock off`, `launch_app`, `exit_app_mode`, `restart_app`, `clear_cache`, `reboot` | Unlock the tablet, open other apps, or restart the device or app. | Two switches on the tablet control what the network may do. Both are **off by default** and live under **Settings, Lock & security, Security**: | Switch | Default | What it allows | |---|---|---| | Allow remote unlock & app control | Off | Lets MQTT and the REST API run the sensitive commands above. | | Allow remote security changes | Off | Lets `PUT /api/config` change [protected settings](#protected-settings). | Turning either on asks you to confirm, because anyone who can publish to your MQTT broker or holds the REST token could then unlock the tablet and open other apps, or switch off the kiosk lock, point Kiosky at another server or inject scripts. Only turn them on with an authenticated broker on a network you trust. What each source may do: | Source | Benign | Sensitive | |---|---|---| | On-device UI, local voice, the app's schedules | yes | yes | | MQTT and REST | yes | only with **Allow remote unlock** on | | A web page (the `window.kiosk` bridge) | a short allow-list only | never | A refused REST command returns `403` with "Remote unlock is turned off on this tablet". A refused MQTT command produces a `command_rejected` event. `reboot` additionally needs full lock (Device Owner) and returns `409` otherwise. When **Allow remote unlock** is off, Home Assistant does not even get the **Kiosk lock**, **Restart app** and **Relaunch app** entities. ## Protected settings Some configuration decides who can reach or control the tablet. Over the network, `PUT /api/config` can change these only when **Allow remote security changes** is on, and the `remote` switches themselves can never be changed over REST: `kiosk`, `remote`, `server`, `camera.stream`, `homeAssistant.baseUrl`, `browser.injections`, `browser.allowedHosts`, `browser.bridgeOrigins`, `browser.mediaOrigins`, `mqtt.host`, `mqtt.port`, `mqtt.tls`, `mqtt.username` and `mqtt.publishNetworkInfo`. A blocked change returns `403` with `"error": "protected"` and the list of paths, and saves nothing. Settings changed on the tablet itself, or imported on the tablet by QR, file or URL after a review of the differences, are not limited this way. See the [REST API reference](https://kiosky.enraio.com/docs/rest-api.md#protected-settings). ## Secrets These are never part of the configuration, exports, logs or REST responses: - the Home Assistant token - the MQTT password - the admin PIN (stored as a hash) - the REST API token - the Immich API key and the battery webhook URL Secrets are kept in encrypted storage on the device. Exports from **Settings, Device, Backup & restore** leave them out. Logs mask tokens and passwords. Changing the Home Assistant origin or the MQTT host deletes the matching saved token or password, so a secret never follows an address change. ## The API token - It is generated on the tablet when you first turn remote access on: 32 random bytes, 43 characters. - Show or copy it under **Settings, Connections, Remote access, API token**. The copy is marked sensitive, so Android hides it from clipboard previews where it can. - **Regenerate** replaces it. The old token stops working at once, so update every client. - Send it only in an `Authorization: Bearer` header. Do not put it in URLs, chat messages, screenshots, tickets, issue trackers or public repositories. Keep it in a password manager, a Home Assistant `secrets.yaml` or your platform's secret store. - The one exception is the camera stream, which accepts HTTP Basic with the user `kiosky` and the token as the password, because Home Assistant's MJPEG camera cannot send a header. - If a token leaks, regenerate it and check that **Allow remote unlock** and **Allow remote security changes** are still off. - Repeated wrong tokens are rate limited per address (5 failures in 60 seconds lock that address out), with a global ceiling on top. See [REST API reference](https://kiosky.enraio.com/docs/rest-api.md#rate-limits). ## Keep it on your local network The REST server uses plain HTTP, so its token and responses travel unencrypted. Settings says so in the Security card: "The REST API runs over plain HTTP: its token can be read by anyone on this Wi-Fi. TLS is coming later." - **Never forward port 2323 (or whatever port you chose) to the internet**, and do not expose it through a reverse proxy, a tunnel or a cloud service without your own authentication and TLS in front of it. - Put tablets on a trusted network or a separate VLAN, and use a guest network for visitors. - Turn the REST server off when you do not use it: **Settings, Connections, Remote access**. - Use an MQTT broker with a user account and TLS. The Security card warns about an anonymous broker and about MQTT without TLS. - Use `https` for Home Assistant on public addresses. A Home Assistant token is not sent to a plain `http` address outside your local network. - Pages only get the `window.kiosk` bridge, the microphone or the camera if you list their origin, and the microphone and camera also need `https`. - Keep injected scripts (**Custom CSS and JavaScript**) to code you trust. ## Privacy Camera analysis and voice wake word detection run on the tablet. Audio goes to Home Assistant only after the wake word. Camera frames never leave the device except snapshots you request and the optional live stream. See [Camera & sensors](https://kiosky.enraio.com/docs/camera-sensors.md#privacy-at-a-glance). The Security card summarises warnings (anonymous broker, no TLS, token over plain HTTP) in one place, or shows **No warnings**. --- Source: https://kiosky.enraio.com/docs/troubleshooting # Troubleshooting > Fixes for tablets that stop starting, battery and vendor auto-start screens, overlay permission, USB debugging, a busy camera, voice that will not wake and dashboards that will not load. Start with the first section. Most "Kiosky stopped on its own" problems are the manufacturer's battery manager. ## Kiosky stops, or does not start after a reboot Several Android skins aggressively stop background apps and block apps from starting at boot. You need to allow Kiosky in three places: 1. **Battery optimisation.** In the setup wizard's **Keep running** step, tap **Allow** next to **Battery optimisation** and choose to let Kiosky run unrestricted. Without it Android may stop the kiosk in the background. 2. **The manufacturer's battery or auto-start manager**, covered below. 3. **Start on boot.** In normal-app mode, check **Settings, Lock & security, Normal app, Start on boot** is on. Locked kiosks always open on boot. Also check **Display over other apps** (next section), which lets Kiosky reopen itself after a crash. ### Start on boot and vendor auto-start screens In the setup wizard and in **Settings, Lock & security, Normal app**, Kiosky shows the steps for your device's manufacturer, and an **Open** or **Allow auto-start** button that jumps to the vendor's auto-start screen when it can find one. Vendor menus change between versions, so if a name below does not match, look for the closest "auto-start", "app launch", "background activity" or "battery" entry for Kiosky. | Vendor | What to do | |---|---| | Honor, Huawei | Settings, Battery, **App launch**, Kiosky. Turn off **Manage automatically**, then enable **Auto-launch**, **Secondary launch** and **Run in background**. Kiosky can also open the Startup manager of the Honor or Huawei system manager. | | Xiaomi, Redmi, Poco | Settings, Apps, Kiosky, **Battery saver**: **No restrictions**. Also enable **Autostart** (the Security app's autostart screen). | | Oppo, Realme | Settings, Battery, Kiosky: allow **background activity** and **auto-launch**. Kiosky can also open the Oppo or ColorOS startup app list. | | OnePlus | Settings, Battery, Kiosky: allow background activity and auto-launch. Kiosky can open OnePlus's launch manager. | | Vivo, iQOO | Kiosky opens Vivo's **background startup manager** (also the iQOO secure app) when it exists. Allow Kiosky there, and set Kiosky to unrestricted in the battery settings. | | Samsung | Settings, Battery, **Background usage limits**: add Kiosky to **Never sleeping apps**. | | Motorola | Settings, Battery, **Battery usage**, Kiosky: set to **Unrestricted**. | | Asus | Kiosky can open Asus Mobile Manager's auto-start screen. Allow Kiosky there. | After changing these, restart the tablet once and check that Kiosky comes up by itself. ## Display over other apps Kiosky needs **Display over other apps** to: - come to the front by itself in normal-app mode (for a remote popup, a camera or a loaded page); - reopen after a crash or a kill, and in single-app mode show the exit corner. If it is missing, the wizard says "Allow 'Display over other apps' so Kiosky can reopen itself…" and shows an **Allow** button. In Settings the same button is on the **Normal app** card and the **Kiosk mode** card. Without the permission, remote commands still run, but Kiosky cannot raise itself above another app. ## USB debugging and file transfer You need USB debugging for the full lock command. 1. Open **Settings, About tablet** and tap **Build number** seven times to enable Developer options. On some skins it is under Software information. 2. Open **Developer options** and turn on **USB debugging**. 3. Connect the cable. If the tablet asks for a USB mode, choose **File transfer** (MTP). Some tablets only expose `adb` in that mode, not in "Charging only". 4. Accept the **Allow USB debugging?** prompt on the tablet and tick **Always allow from this computer**. 5. On the computer, `adb devices` should list the tablet as `device`. `unauthorized` means you have not accepted the prompt yet. An empty list means the cable, the port or the USB mode is wrong. Try another cable, as many are charge-only. If `dpm set-device-owner` fails with a message about accounts or users, remove every account in **Settings, Accounts** (including Google) and run it again. See [Choosing a mode](https://kiosky.enraio.com/docs/modes.md#full-lock-device-owner). ## Camera is busy or unavailable Android lets only one app use the camera at a time. - Close other apps that use the camera (video calls, camera apps) and try again. - Check **Settings, Camera & sensors, Camera permission** shows **Granted**. - If **Camera snapshot** or the stream says "Camera unavailable" (`503`), the camera did not start within 15 seconds or is held by another app. Disable motion or face detection to see whether Kiosky itself was the one holding it, then re-enable one at a time. - The live stream allows 2 viewers at once. A third gets `503` "Too many stream viewers". - Restart the app from the admin page or with the `restart_app` command if it keeps failing. ## Voice does not wake **Settings, Voice** shows a status chip with the reason. The values and what to do: | Status | Fix | |---|---| | Voice is turned off | Turn on **Enable voice** and tap **Save voice**. | | Microphone is muted | Turn **Microphone** on, here or with the Home Assistant switch. | | Microphone permission not granted | Tap **Allow microphone**, or open app settings. | | Home Assistant URL or token missing | Enter the URL and a long-lived token and save. | | Paused while the screen is off | Turn off **Listen only while the screen is on**, or wake the screen. | | Paused while not charging | Turn off **Listen only while charging**, or plug the tablet in. | If the chip says "Listening for the wake word" but nothing happens: - Say the wake word clearly and closer to the tablet. Accuracy drops with distance and room noise. - Lower **Wake threshold** a little (lower wakes more easily). Try another wake word: Okay Nabu, Hey Jarvis or Hey Mycroft. - Make sure your Home Assistant Assist pipeline has speech-to-text and text-to-speech. Leave the pipeline id blank to use the preferred one. - Use a Home Assistant address with a certificate Android trusts. Self-signed HTTPS does not work for voice. - Allow Kiosky to run in the background (see the first section). The microphone service can only start while Kiosky is visible, so after the app was killed it resumes listening once Kiosky is back on screen. - While listening, a **MIC** pill and a "Microphone on" notification show. If they are missing, the microphone is off. ## The dashboard does not load Kiosky shows a plain-language message with the technical code in small print, and retries by itself. Use **Retry now** to try straight away. | Message | What it means | |---|---| | No internet connection | Wi-Fi is off or the network changed. | | That address couldn't be found | Wrong address or a DNS problem. `homeassistant.local` needs mDNS on the network. Try the IP address. | | The dashboard took too long to answer | The server is busy, asleep or unreachable. | | The server refused the connection | The service is down, restarting or on a different port. | | The connection dropped while loading the page | A flaky network. | | A secure connection couldn't be made | The certificate is invalid, expired or not trusted by Android. | | The server is having a problem | An HTTP 5xx from the server. | Other checks: - In setup, **Test connection** tells you whether the tablet can reach the address. The tablet may be on a different network or VLAN from the server. - A page that redirects to another host (a login or SSO page) needs that host under **Extra allowed hosts**. See [Dashboards & browser](https://kiosky.enraio.com/docs/dashboards.md#allowed-hosts). Navigation to other hosts is blocked. - A `load_url` or `popup` that does nothing is usually a host that is not allowed. Watch for a `command_rejected` event. - If the Home Assistant login screen appears, check the address and token under **Dashboard, Home Assistant sign-in**. A token is not sent to a plain `http` address on a public network; use `https`. - If the Home Assistant header or sidebar is missing and you cannot get it back, double-tap within the top 48 pixels of the screen, or set **Hide Home Assistant chrome** to **Show**. ## Connections **The REST API does not answer.** Check **Settings, Connections, Remote access** shows **Running on port ...**, use the IP address shown there, and that the tablet and your computer are on the same network. `401` means a wrong token, and `429` means too many wrong tokens: wait for the `Retry-After` seconds. See the [REST API reference](https://kiosky.enraio.com/docs/rest-api.md). **The tablet does not appear in Home Assistant.** Check the MQTT chip says **Connected**, **Home Assistant discovery** is on, and that your discovery prefix in Home Assistant is the default `homeassistant`. Subscribe to `kiosk/#` on the broker to confirm messages arrive. See the [MQTT reference](https://kiosky.enraio.com/docs/mqtt.md). **A command does nothing.** Subscribe to `kiosk//event` and look for `command_rejected`. It names the reason, for example "Remote unlock is turned off on this tablet". **I changed the device name and my topics changed.** The topics and entity ids follow the device name. Update your automations, or rename the device back. ## Still stuck Open **Settings, Device, Logs** to see recent log lines (tokens and passwords are masked), then **Save to file** or **Share** them when you ask for help. Email `support@enraio.com`. --- Source: https://kiosky.enraio.com/docs/ai-setup # Set up Kiosky with an AI assistant > A ready-to-copy prompt and the exact steps an AI agent should follow to find a tablet, read and change its config safely, send commands and build Home Assistant automations. An AI assistant that can run shell commands or make HTTP requests (Claude Code, for example) can configure a Kiosky tablet for you through its local REST API. This page has two parts: a short guide for you, and the exact procedure and safety rules for the agent. The agent should read the whole page. Everything the agent does uses the documented [REST API](https://kiosky.enraio.com/docs/rest-api.md). Machine-readable versions of these docs are at [`/llms.txt`](https://kiosky.enraio.com/llms.txt) and [`/llms-full.txt`](https://kiosky.enraio.com/llms-full.txt), and this page is available as Markdown at `/docs/ai-setup.md`. ## For you: what to prepare 1. **Finish the setup wizard on the tablet**, so it already shows a dashboard. See [Getting started](https://kiosky.enraio.com/docs/getting-started.md). 2. **Turn on the REST API.** On the tablet open **Settings, Connections, Remote access** and switch on **REST API & admin page**. Note the port (2323 by default) and the tablet's IP address. 3. **Copy the API token** (**Show** or **Copy** under **API token**). 4. **Give the token to the agent without pasting it into the chat** if you can: set it as an environment variable in the terminal where the agent runs. ```bash export KIOSKY_TOKEN='paste-the-token-here' ``` In fish use `set -x KIOSKY_TOKEN 'paste-the-token-here'`. 5. Make sure your computer is on the same network as the tablet. 6. Paste the prompt below into your assistant and fill in the goal. What the agent **cannot** do over REST, so you do it on the tablet: set the admin PIN, change **Allow remote unlock** or **Allow remote security changes**, enter the Home Assistant token, the MQTT password or the Immich API key (secrets are never part of the config), and provision full lock (Device Owner needs `adb`). By default the agent also cannot change the protected settings, such as the MQTT broker address. > **Warning.** The tablet's API uses plain HTTP and the token controls the tablet. Keep it on your home network, never forward the port to the internet, and rotate the token (**Regenerate**) when you are done if you shared it anywhere you do not control. ## Copy this prompt ```text You are going to configure an Android kiosk tablet running Kiosky through its local REST API. First read the Kiosky documentation: https://kiosky.enraio.com/docs/ai-setup.md (follow its "Steps for the agent" and "Safety rules" exactly), and use https://kiosky.enraio.com/docs/rest-api.md and https://kiosky.enraio.com/llms-full.txt as the reference. Do not guess setting names, command names or config paths; take them from those pages or from GET /api/config. Tablet address: Port: 2323 The API token is in the environment variable KIOSKY_TOKEN. Never print it, never write it into a file, log, chat message or Home Assistant YAML (use secrets), and never send it anywhere except the tablet's Authorization header. My goal: Rules: discover and read before you change anything; save a backup of the current config; always use PATCH /api/config?dryRun=true before saving (PATCH changes only the fields you send, PUT replaces everything); ask me before any sensitive command (reboot, restart_app, clear_cache, kiosk_pause, launch_app, exit_app_mode), before touching protected settings or the lock, and before changing anything that needs me at the tablet. Tell me what you changed when you finish, and how to roll it back. ``` ## Steps for the agent Follow these in order. Stop and ask the human whenever a step says so. `TABLET` is the tablet's `host:port`. ### 1. Find the tablet If the human gave an IP address, use it with port 2323 unless they said otherwise. Otherwise discover it with mDNS. The tablet advertises `_kiosk._tcp` and `_http._tcp` while the REST server runs. ```bash # macOS dns-sd -B _kiosk._tcp local dns-sd -L "" _kiosk._tcp local # prints host, port and TXT records # Linux avahi-browse -rt _kiosk._tcp ``` Android cannot publish a `.local` host name, so use the resolved IP address and port, not a `.local` name. If mDNS finds nothing, ask for the IP address (**Settings, Device** or **Connections, Remote access** on the tablet). Confirm it is a Kiosky tablet. This endpoint needs no token: ```bash curl -s http://TABLET/api/info # {"app":"Kiosky","name":"Hallway Tablet","id":"hallway_tablet","version":"0.1.0"} ``` Check that `app` is `"Kiosky"`. Note `name`. If the request fails, the REST server may be off: ask the human to switch on **REST API & admin page**. Never scan other hosts or ports looking for it. ### 2. Use the token safely The token is in the environment variable `KIOSKY_TOKEN`. If it is not set, ask the human to set it; do not ask them to paste it into the chat. Pass it only as a header: ```bash curl -s -H "Authorization: Bearer $KIOSKY_TOKEN" http://TABLET/api/state ``` - `401` means a wrong or old token. Ask the human to check it. Do not try variations or other tokens. - `429` means the address is locked out after failed attempts. Stop, wait the number of seconds in the `Retry-After` header, and ask the human before retrying. - Do not echo the variable, print request headers, or run commands with `-v` or `--trace` that would show the header. ### 3. Read the current state ```bash curl -s -H "Authorization: Bearer $KIOSKY_TOKEN" http://TABLET/api/state ``` Read `kioskMode` (`none`, `soft`, `device_owner`), `screenStage`, `currentUrl`, `battery` and `network`. Report anything odd to the human before changing it. ### 4. Read the config and keep a backup ```bash curl -s -H "Authorization: Bearer $KIOSKY_TOKEN" http://TABLET/api/config > kiosky-config.backup.json ``` `kiosky-config.backup.json` is your rollback. It contains no secrets, but it does describe the tablet, so keep it private. Use the exact names in this file (and the [config reference](https://kiosky.enraio.com/docs/rest-api.md#config-reference)) for every change. ### 5. Change the config safely Use `PATCH /api/config` for changes. It deep-merges the partial JSON you send onto the current config: objects merge key by key, and arrays and scalar values replace the current value. Fields you leave out keep their current value. Send only what you intend to change. ```bash # Example: rotate two dashboards every 45 seconds (arrays replace, so send the whole dashboards list) cat > kiosky-patch.json <<'JSON' { "browser": { "dashboards": [ {"name": "Home", "url": "http://homeassistant.local:8123/lovelace/0?kiosk"}, {"name": "Energy", "url": "http://homeassistant.local:8123/energy?kiosk"} ], "rotation": {"enabled": true, "intervalSeconds": 45, "pauseSeconds": 60} } } JSON ``` Rules for the patch: - Dashboard names must be unique, 1 to 64 characters, and URLs must be `http(s)`. - `power.night` and `maintenance` times are `HH:mm`. Weekdays are 1 (Monday) to 7 (Sunday). - Do not touch `remote`. You cannot change it over REST. - The protected paths are `kiosk`, `remote`, `server`, `camera.stream`, `homeAssistant.baseUrl`, `browser.injections`, `browser.allowedHosts`, `browser.bridgeOrigins`, `browser.mediaOrigins`, `mqtt.host`, `mqtt.port`, `mqtt.tls`, `mqtt.username`, `mqtt.publishNetworkInfo`. Changing one returns `403 protected`. Do **not** work around this. Tell the human which setting you need and why, and ask them to change it on the tablet (**Settings**) or to turn on **Allow remote security changes** themselves if they accept the risk. ### 6. Dry run, then save ```bash # validate only, nothing is saved curl -s -X PATCH "http://TABLET/api/config?dryRun=true" \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ --data @kiosky-patch.json # {"ok":true,"saved":false} ``` Read the result: - `200 {"ok":true,"saved":false}`: valid. Tell the human what will change, get a go-ahead for anything beyond what they asked for, then save. - `422`: read `errors[].path` and `errors[].message`, fix the patch and dry-run again. A path of `$` means the body was not a JSON object. - `403 protected`: see the rule above. Nothing was saved. Then save, and verify: ```bash curl -s -X PATCH http://TABLET/api/config \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ --data @kiosky-patch.json # {"ok":true,"saved":true} curl -s -H "Authorization: Bearer $KIOSKY_TOKEN" http://TABLET/api/config | jq -S . > after.json diff <(jq -S . kiosky-config.backup.json) after.json # shows exactly what changed ``` To roll back, `PUT` the backup (this replaces everything with the backup): ```bash curl -s -X PUT http://TABLET/api/config \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ --data @kiosky-config.backup.json ``` ### 7. Send commands to test Commands return `202 {"ok":true}` when queued. Start with harmless ones: ```bash curl -s -X POST http://TABLET/api/command \ -H "Authorization: Bearer $KIOSKY_TOKEN" -H "Content-Type: application/json" \ -d '{"command":"toast","args":{"text":"Configured by an assistant","duration":6}}' ``` Other useful, benign commands: `reload`, `dashboard` (`{"name":"Energy"}`), `screen` (`{"state":"on"}`), `brightness` (`{"level":128}`), `screensaver`, `load_url` (host must be allowed), `popup`, `dismiss_popup`, `tts`, `volume`. The full list with arguments is in the [REST API reference](https://kiosky.enraio.com/docs/rest-api.md#commands). To see what is on screen, fetch `GET /api/screenshot` to a local file (a PNG). Sensitive commands (`reboot`, `restart_app`, `clear_cache`, `kiosk_pause`, `kiosk_lock` with `off`, `launch_app`, `exit_app_mode`) are refused with `403` unless the human enabled **Allow remote unlock**. **Ask the human before sending any of them,** and never ask them to turn the switch on just to make your job easier. ### 8. Create Home Assistant automations Only do this if the human wants it and has given you a way to edit Home Assistant (their own tooling, a Home Assistant MCP server, or a file they gave you access to). Do not ask for or store the Home Assistant token in the Kiosky config. 1. **Find the device id.** The device id is the lower-case slug of the device name with `_` between words, the same as `id` from `/api/info` and the mDNS `id` record, for example `Hallway Tablet` is `hallway_tablet` (the same value as `id` from `/api/info`). Topics are `kiosk//cmd/`. 2. **Check MQTT is connected.** The tablet's MQTT chip must say **Connected** and Home Assistant discovery must be on. If `mqtt.enabled` is false, MQTT host, port, TLS and username are protected, and the password is a secret, so the human must enter them on the tablet under **Settings, Connections, MQTT**. See [Home Assistant integration](https://kiosky.enraio.com/docs/home-assistant.md#set-up-mqtt). 3. **Look up real entity ids** in Home Assistant instead of guessing them (the tablet creates entities such as `select._dashboard` and `binary_sensor._tamper`; the exact id depends on the device name). 4. **Write the automation** with `mqtt.publish` to the command topic. Example: show a camera when someone is at the door. ```yaml automation: - alias: Hallway tablet shows front door camera triggers: - trigger: state entity_id: binary_sensor.front_door_person to: "on" actions: - action: mqtt.publish data: topic: kiosk/hallway_tablet/cmd/popup payload: >- {"camera": "camera.front_door", "timeout": 30, "title": "Front door"} ``` Camera popups need the Home Assistant address and token saved on the tablet under **Dashboard, Home Assistant sign-in**. If they are not, ask the human to add them. 5. **Validate** the Home Assistant configuration (Developer tools, or `check_config`) before reloading automations. 6. **Test** by publishing the same payload yourself with the REST API (`popup` with a `camera` argument), or by triggering the automation once, and ask the human to confirm they see it. 7. **Keep secrets out of YAML.** If an automation uses `rest_command` against the REST API, put the `Bearer ` string in `secrets.yaml` and reference it with `!secret`. Prefer MQTT automations, which need no token. More examples (wake on presence, text to speech, switch dashboard, tamper alert) are on the [Home Assistant integration](https://kiosky.enraio.com/docs/home-assistant.md#example-automations) page. ### 9. Report Tell the human, briefly: what you found, what you changed (a diff), what you tested and what worked, which things they still need to do on the tablet, and how to roll back (`PUT` the backup file). Delete temporary files that hold anything private. Do not include the token in the report. ## Safety rules These apply to the agent for the whole session. 1. **Never expose port 2323 to the internet.** Do not create port forwards, tunnels, reverse proxies or cloud relays to the tablet. Use the REST API only from the local network. 2. **Never print or paste the token.** Not in the chat, not in logs, not in `curl -v` output, not in command lines that get recorded, not in files you commit, not in gists, issues, pull requests, tickets, screenshots or any other public or shared place. Pass it only in the `Authorization` header, from the environment variable. 3. **Ask before enabling remote unlock or security changes.** **Allow remote unlock & app control** and **Allow remote security changes** can only be changed on the tablet, by the person standing at it. Explain what each one allows (see [Security](https://kiosky.enraio.com/docs/security.md#remote-control-policy)) and let them decide. Do not suggest them as a shortcut. 4. **Ask before every sensitive or disruptive action:** reboot, restart, clear cache, pausing the lock, opening other apps, leaving single-app mode, turning the camera, microphone or face detection on, and regenerating the API token (it locks out every other client). 5. **Read first, then dry-run, then save.** Keep a backup. Use `PATCH` for changes. `PUT` replaces the whole config, so use it only to restore the backup. 6. **Respect `403 protected`, `403` policy refusals and `409`.** Do not look for another way around them. 7. **Respect rate limits.** After a `401` or `429`, stop. Do not retry in a loop. Never try to guess a token. 8. **Stay on the tablet you were pointed at.** Do not scan the network for other tablets or services. 9. **Keep Home Assistant secrets out of Kiosky and Kiosky secrets out of Home Assistant YAML.** Use `secrets.yaml` or your platform's secret store. 10. **Do not change what you were not asked to.** Mention opportunities (for example, "you could add a night schedule") and let the human choose.