# FreeKiosk REST API Documentation
**Control, monitor, and automate kiosks over HTTP with JSON responses**
Docs Home β’
Integrations β’
MQTT
## Table of Contents
- [Overview](#overview)
- [Configuration](#configuration)
- [Getting Started](#getting-started)
- [Features](#features)
- [Troubleshooting](#troubleshooting)
- [Related Resources](#related-resources)
FreeKiosk includes a built-in REST API server for integration with **Home Assistant** and other smart home platforms.
## Overview
| Feature | Details |
|---|---|
| **Default Port** | 8080 |
| **Protocol** | HTTP (HTTPS planned) |
| **Authentication** | Optional API Key (X-Api-Key header) |
| **Format** | JSON responses |
> [!NOTE]
> Some API features require **Device Owner mode** for full functionality (true screen off, reboot). The HTTP server remains accessible even when the screen is off (v1.2.4+). See [Installation Guide](installation.md#advanced-install-device-owner-mode) for Device Owner setup instructions.
## Enabling the API
### Via UI
| Step | Action |
|---|---|
| **1** | 5-tap on secret button β PIN |
| **2** | Go to **Advanced** tab |
| **3** | Toggle **Enable REST API** |
| **4** | Set port (default: 8080) and optional API key |
| **5** | Save settings |
### Via ADB (Headless)
```bash
adb shell am start -n com.freekiosk/.MainActivity \
--es pin "1234" \
--es rest_api_enabled "true" \
--es rest_api_port "8080" \
--es rest_api_key "your_secret_key"
```
> [!NOTE]
> See [ADB Configuration Guide](ADB-Configuration) for full headless provisioning.
## Endpoints Reference
### Status & Info (GET)
#### `GET /api/status`
Returns complete device status in one call.
```json
{
"success": true,
"data": {
"battery": { "level": 85, "charging": true, "temperature": 25.5 },
"screen": { "on": true, "brightness": 75, "screensaverActive": false },
"webview": { "currentUrl": "http://...", "canGoBack": false, "loading": false },
"device": { "model": "SM-T510", "manufacturer": "samsung", "android": "11" },
"wifi": { "connected": true, "ssid": "Home", "rssi": -45, "ip": "192.168.1.50" },
"sensors": { "light": 150.5, "proximity": 5, "accelerometer": {...} },
"autoBrightness": { "enabled": true, "min": 10, "max": 100, "currentLightLevel": 150.5 },
"kiosk": { "enabled": true, "pinEnabled": true },
"audio": { "volume": 50 },
"storage": { "totalMB": 32000, "availableMB": 15000 },
"memory": { "totalMB": 4096, "availableMB": 2048 }
},
"timestamp": 1704672000
}
```
#### `GET /api/battery`
```json
{
"success": true,
"data": {
"level": 85,
"charging": true,
"plugged": "usb",
"temperature": 25.5,
"voltage": 4.2,
"health": "good",
"technology": "Li-ion"
}
}
```
**π Fields:**
| Field | Range/Type | Description |
|---|---|---|
| **level** | 0-100 | Battery percentage |
| **charging** | boolean | Whether the device is charging |
| **plugged** | string | Power source: `usb`, `ac`, `wireless`, or `none` |
| **temperature** | number | Battery temperature in Β°C |
| **voltage** | number | Battery voltage in V |
| **health** | string | `good`, `overheat`, `dead`, `over_voltage`, `failure`, `cold`, or `unknown` |
| **technology** | string | Battery chemistry (e.g., `Li-ion`) |
```
#### `GET /api/brightness`
```json
{
"success": true,
"data": { "brightness": 75 }
}
```
#### `GET /api/screen`
Returns screen status with separated physical and overlay states.
```json
{
"success": true,
"data": {
"on": true,
"brightness": 75,
"screensaverActive": false
}
}
```
**Field Descriptions:**
| Field | Value | Description |
|---|---|---|
| **on** | `true`/`false` | Physical screen state from `PowerManager.isInteractive` |
| **brightness** | 0-100 | Current brightness percentage |
| **screensaverActive** | `true`/`false` | Whether the screensaver overlay is showing |
**Physical Screen State (`on`):**
- `true` = screen is physically on (consuming power)
- `false` = screen is physically off (power button pressed or `lockNow()` called)
- Note: Returns `true` even when screensaver overlay is active
**Screensaver State (`screensaverActive`):**
- `true` = screensaver overlay is covering content (screen may be dimmed)
- `false` = normal content is visible
**Interpreting Combined States:**
```javascript
// Screen physically on + content visible
{ "on": true, "screensaverActive": false }
// Screen physically on + screensaver overlay (dimmed/attenuated)
{ "on": true, "screensaverActive": true }
// Screen physically off (power button or Device Owner lockNow())
{ "on": false, "screensaverActive": false }
```
**Use Cases:**
- To check if screen is consuming power: `on === true`
- To check if content is visible to user: `on === true && screensaverActive === false`
- To check if in power-saving mode: `on === false || screensaverActive === true`
#### `GET /api/sensors`
Returns light, proximity, and accelerometer data.
```json
{
"success": true,
"data": {
"light": 150.5,
"proximity": 5,
"accelerometer": { "x": 0.1, "y": 0.2, "z": 9.8 }
}
}
```
#### `GET /api/storage`
```json
{
"success": true,
"data": {
"totalMB": 32000,
"availableMB": 15000,
"usedMB": 17000,
"usedPercent": 53
}
}
```
#### `GET /api/memory`
```json
{
"success": true,
"data": {
"totalMB": 4096,
"availableMB": 2048,
"usedMB": 2048,
"usedPercent": 50,
"lowMemory": false
}
}
```
#### `GET /api/wifi`
```json
{
"success": true,
"data": {
"connected": true,
"ssid": "HomeNetwork",
"rssi": -45,
"ip": "192.168.1.50"
}
}
```
#### `GET /api/info`
Device information.
```json
{
"success": true,
"data": {
"ip": "192.168.1.50",
"hostname": "freekiosk",
"version": "1.2.11",
"isDeviceOwner": true,
"kioskMode": true
}
}
```
**Field Descriptions:**
| Field | Type | Description |
|---|---|---|
| **isDeviceOwner** | boolean | Whether the app has Device Owner privileges (required for reboot, lock, true screen off) |
| **kioskMode** | boolean | Whether kiosk lock task mode is currently active |
#### `GET /api/health`
Simple health check.
```json
{
"success": true,
"data": { "status": "ok" }
}
```
#### `GET /api/screenshot`
Returns a PNG image of the current screen.
**Response**: `image/png` binary data
**Usage examples:**
```bash
# Save screenshot to file
curl http://TABLET_IP:8080/api/screenshot -o screenshot.png
# Display in HTML
```
> π‘ The screenshot is captured from the app's root view. It works even when the screensaver overlay is active.
#### `GET /api/camera/photo`
Take a photo using the device camera. **(v1.2.5+)**
**Query Parameters:**
| Parameter | Default | Description |
|---|---|---|
| **camera** | `back` | Camera to use: `front` or `back` |
| **quality** | `80` | JPEG compression quality (1-100) |
**Examples:**
```
GET /api/camera/photo?camera=back&quality=80
GET /api/camera/photo?camera=front&quality=60
```
**Response**: `image/jpeg` binary data
**Notes:**
- First capture may take 1-2 seconds (camera initialization + auto-exposure)
- Camera permission must be granted (already included in app permissions)
- Photo resolution is automatically optimized (~1.2MP) for fast HTTP transfer
- Higher quality values produce larger files
#### `GET /api/camera/list`
List available cameras on the device. **(v1.2.5+)**
```json
{
"success": true,
"data": {
"cameras": [
{ "id": "0", "facing": "back", "maxWidth": 4032, "maxHeight": 3024 },
{ "id": "1", "facing": "front", "maxWidth": 2560, "maxHeight": 1920 }
]
}
}
```
### Control Commands (POST)
#### `POST /api/brightness`
Set screen brightness (disables auto-brightness if enabled).
> β οΈ When **App Brightness Control** is disabled in settings, this endpoint is ignored (brightness is managed by the system/Tasker).
```json
{ "value": 75 }
```
#### `POST /api/autoBrightness/enable`
Enable automatic brightness adjustment based on ambient light sensor.
> β οΈ When **App Brightness Control** is disabled in settings, this endpoint is ignored.
```json
{ "min": 10, "max": 100, "offset": 10 }
```
- `min`: Minimum brightness percentage (0-100, default: 10)
- `max`: Maximum brightness percentage (0-100, default: 100)
- `offset`: *(optional)* Fixed percentage added to calculated brightness (0-100, default: keeps current setting). E.g. `10` means +10% brighter than what the sensor calculates
> π‘ Uses a logarithmic curve for natural perception. Brightness is calculated based on ambient light level (10-1000 lux range), then the offset is added (capped at 100%).
#### `POST /api/autoBrightness/disable`
Disable automatic brightness and restore previous manual brightness setting.
#### `GET /api/autoBrightness`
Get current auto-brightness status.
```json
{
"success": true,
"data": {
"enabled": true,
"min": 10,
"max": 100,
"currentLightLevel": 250.5
}
}
```
#### `GET|POST /api/screen/on`
Turn screen on / wake device.
#### `GET|POST /api/screen/off`
Turn screen off.
> β οΈ **Device Owner Required for Full Screen Control**
>
> | Feature | No privileges | Device Admin | AccessibilityService (API 28+) | Device Owner |
> |---------|--------------|--------------|-------------------------------|---------------|
> | `screen/off` | β οΈ Dims to 0% brightness | β
`lockNow()` | β
`GLOBAL_ACTION_LOCK_SCREEN` | β
`lockNow()` |
> | `screen/on` | Restores brightness | Wakes device | Wakes device | Wakes device |
> | `lock` | β Error | β
Works | β
Works | β
Works |
> | `reboot` | β Not available | β Not available | β Not available | β
Works |
> | Kiosk mode | β οΈ User prompt | β οΈ User prompt | β οΈ User prompt | β
Silent |
>
> **Understanding `"on"` vs `"screensaverActive"`:**
> - `"on"` reports the **physical screen state** (PowerManager.isInteractive)
> - `"screensaverActive"` reports whether the **screensaver overlay** is showing
> - These are **independent**: screensaver can be active while screen is physically on
>
> **FreeKiosk uses a 4-tier approach for screen off:**
> 1. **Device Owner**: `DevicePolicyManager.lockNow()` β true screen off
> 2. **Device Admin**: `DevicePolicyManager.lockNow()` β also works, no Device Owner needed
> 3. **AccessibilityService (API 28+)**: `GLOBAL_ACTION_LOCK_SCREEN` β works without any admin privilege
> 4. **Fallback**: Dims brightness to 0% (screen stays on but appears black)
>
> This means FreeKiosk can coexist with an existing MDM that holds Device Owner β just activate Device Admin or the AccessibilityService and screen lock works fully.
>
> To enable Device Owner mode, see [Installation Guide](installation.md#advanced-install-device-owner-mode).
#### `GET|POST /api/screensaver/on`
Enable the screensaver setting. The screensaver will activate automatically after the configured inactivity timeout.
#### `GET|POST /api/screensaver/off`
Disable the screensaver setting. The screensaver will no longer activate on inactivity. If the screensaver is currently active, it will be deactivated.
#### `GET|POST /api/reload`
Reload the current WebView page.
#### `POST /api/url`
Navigate to a new URL.
```json
{ "url": "https://example.com" }
```
#### `GET|POST /api/wake`
Wake from screensaver.
#### `POST /api/tts`
Text-to-speech. Uses Android native TextToSpeech engine (handled server-side, no JS bridge dependency).
```json
{ "text": "Hello World" }
```
**Parameters:**
- `text` (string, required): The text to speak
- `language` (string, optional): BCP 47 language tag (e.g. `"zh-CN"`, `"en-US"`, `"fr"`, `"ja"`, `"ko"`). If omitted, the language is **auto-detected** from the text content based on Unicode script analysis (CJK β Chinese, Hangul β Korean, Hiragana/Katakana β Japanese, Arabic script β Arabic, Thai β Thai, Devanagari β Hindi, Cyrillic β Russian, Latin β device default)
**Examples:**
```json
{ "text": "δ½ ε₯½δΈη" }
{ "text": "Hello World", "language": "en-US" }
{ "text": "γγγ«γ‘γ―", "language": "ja" }
```
> π‘ Language is auto-detected from text content when `language` is not specified. The appropriate TTS voice is selected before each utterance. Requires the target language TTS data to be installed on the Android device (check Android Settings β TTS).
#### `POST /api/volume`
Set media volume (0-100).
```json
{ "value": 50 }
```
#### `GET /api/volume`
Get current media volume.
```json
{
"success": true,
"data": { "level": 80, "maxLevel": 100 }
}
```
#### `POST /api/toast`
Show a toast notification.
```json
{ "text": "Message displayed!" }
```
#### `POST /api/js`
Execute JavaScript in WebView.
```json
{ "code": "alert('Hello!')" }
```
#### `GET|POST /api/clearCache`
Clear WebView cache, cookies, localStorage and reload. Performs a full native cache clear including:
- WebView cache (HTTP cache, images, scripts)
- Cookies (all domains)
- Web Storage (localStorage, sessionStorage)
- Form data
Then forces a full WebView remount.
#### `POST /api/app/launch`
Launch an external app.
```json
{ "package": "com.spotify.music" }
```
#### `GET|POST /api/reboot`
Reboot device (requires Device Owner mode). Executed natively without JS bridge dependency.
#### `GET|POST /api/lock`
Lock device screen. Uses `DevicePolicyManager.lockNow()` (Device Owner) or `GLOBAL_ACTION_LOCK_SCREEN` (AccessibilityService, API 28+) to truly turn off the screen.
> β οΈ Without Device Owner or AccessibilityService, this endpoint returns an error. Use `/api/screen/off` as a fallback (dims to 0 brightness).
#### `GET|POST /api/restart-ui`
Restart the FreeKiosk app UI. Calls `activity.recreate()` to fully restart the React Native activity without rebooting the device. Useful for troubleshooting UI issues remotely.
### Audio Control (POST)
#### `POST /api/audio/play`
Play audio from URL.
```json
{
"url": "https://example.com/sound.mp3",
"loop": false,
"volume": 50
}
```
#### `GET|POST /api/audio/stop`
Stop currently playing audio.
#### `GET|POST /api/audio/beep`
Play a short beep sound.
### Remote Control - Android TV (GET or POST)
Perfect for controlling Android TV devices or navigating apps.
> **How it works**: Remote key events are dispatched natively using the **AccessibilityService** (cross-app, works in external apps) or `activity.dispatchKeyEvent()` (fallback, FreeKiosk only). When the AccessibilityService is enabled:
> - Keys work across **all apps** (WebView, external apps, Android launcher)
> - D-pad navigation highlights UI elements (buttons, links, inputs)
> - Back, Home, and Recents trigger the corresponding system actions
>
> Without the AccessibilityService, keys only work within FreeKiosk's own Activity.
| Endpoint | Key |
|----------|-----|
| `GET\|POST /api/remote/up` | D-pad Up |
| `GET\|POST /api/remote/down` | D-pad Down |
| `GET\|POST /api/remote/left` | D-pad Left |
| `GET\|POST /api/remote/right` | D-pad Right |
| `GET\|POST /api/remote/select` | Select/Enter |
| `GET\|POST /api/remote/back` | Back |
| `GET\|POST /api/remote/home` | Home |
| `GET\|POST /api/remote/menu` | Menu |
| `GET\|POST /api/remote/playpause` | Play/Pause |
### Keyboard Emulation (GET or POST) β¨οΈ
Simulate keyboard input on the device. Three modes are available:
#### Single Key Press: `GET|POST /api/remote/keyboard/{key}`
Press a single keyboard key. The key name is in the URL path.
```bash
# Press letter 'a'
curl http://tablet-ip:8080/api/remote/keyboard/a
# Press Enter
curl http://tablet-ip:8080/api/remote/keyboard/enter
# Press F5 (refresh in most browsers)
curl http://tablet-ip:8080/api/remote/keyboard/f5
# Press Escape
curl http://tablet-ip:8080/api/remote/keyboard/escape
# Press Space
curl http://tablet-ip:8080/api/remote/keyboard/space
```
**Supported keys:**
| Category | Keys |
|----------|------|
| Letters | `a` through `z` |
| Digits | `0` through `9` |
| Function | `f1` through `f12` |
| Navigation | `up`, `down`, `left`, `right`, `home`, `end`, `pageup`, `pagedown` |
| Editing | `enter` / `return`, `space`, `tab`, `backspace`, `delete` / `del`, `insert`, `escape` / `esc` |
| Toggles | `capslock`, `numlock`, `scrolllock` |
| Modifiers | `shift`, `ctrl` / `control`, `alt`, `meta` / `win` / `cmd` |
| Media | `playpause`, `play`, `pause`, `stop`, `next` / `nexttrack`, `previous` / `prevtrack`, `volumeup`, `volumedown`, `mute` |
| Android | `back`, `menu`, `search`, `power`, `select` / `center`, `androidhome` |
| Symbols | `period` / `dot`, `comma`, `minus` / `dash`, `plus`, `equals`, `semicolon`, `apostrophe` / `quote`, `slash`, `backslash`, `leftbracket`, `rightbracket`, `grave` / `backtick`, `at`, `pound` / `hash`, `star` / `asterisk` |
| Single char | Any single character: `.`, `,`, `-`, `=`, `/`, `;`, `'`, etc. |
> π‘ **Note**: In the keyboard endpoint, `home` maps to the keyboard Home key (cursor to beginning of line), NOT the Android Home button. Use `androidhome` or `/api/remote/home` for the Android Home button.
#### Keyboard Shortcut: `GET|POST /api/remote/keyboard?map={combo}`
Send a keyboard shortcut with modifier keys. Format: `modifier1+modifier2+key`.
```bash
# Copy (Ctrl+C)
curl "http://tablet-ip:8080/api/remote/keyboard?map=ctrl+c"
# Paste (Ctrl+V)
curl "http://tablet-ip:8080/api/remote/keyboard?map=ctrl+v"
# Select All (Ctrl+A)
curl "http://tablet-ip:8080/api/remote/keyboard?map=ctrl+a"
# Close tab (Ctrl+W)
curl "http://tablet-ip:8080/api/remote/keyboard?map=ctrl+w"
# Alt+F4
curl "http://tablet-ip:8080/api/remote/keyboard?map=alt+f4"
# Ctrl+Shift+A (uppercase A with Ctrl)
curl "http://tablet-ip:8080/api/remote/keyboard?map=ctrl+shift+a"
```
**Supported modifiers:** `ctrl` / `control`, `alt`, `shift`, `meta` / `win` / `cmd`
Response:
```json
{
"success": true,
"data": {
"executed": true,
"command": "keyboardCombo",
"map": "ctrl+c",
"key": "c",
"keyCode": 31,
"modifiers": ["ctrl"],
"metaState": 28672
}
}
```
#### Type Text: `POST /api/remote/text`
Type a full text string into the currently focused input field.
```bash
curl -X POST http://tablet-ip:8080/api/remote/text \
-H "Content-Type: application/json" \
-d '{"text": "Hello World!"}'
```
Response:
```json
{
"success": true,
"data": {
"executed": true,
"command": "keyboardText",
"textLength": 12
}
}
```
> #### Accessibility Service (recommended for External App mode)
>
> By default, keyboard emulation only works inside FreeKiosk's WebView. To inject keys into **external apps** (e.g., when using External App display mode), you need to enable the **FreeKiosk Accessibility Service**:
>
> 1. Go to **Settings β Advanced β Accessibility Service** and tap **"Open Accessibility Settings"**
> 2. In Android settings, find **FreeKiosk** under "Installed Services" and enable it
> 3. The status indicator in FreeKiosk settings will show **"β Active"** when ready
>
> **Device Owner shortcut**: If FreeKiosk is set as Device Owner, you can enable the service automatically without visiting Android settings β just tap **"Enable Automatically"** in Advanced Settings.
>
> **How it works**: When the Accessibility Service is active, FreeKiosk uses it for all keyboard injection (both WebView and external apps). When disabled, it falls back to `dispatchKeyEvent()` which only works within FreeKiosk's own Activity.
>
> **Privacy ROMs** (e/OS, LineageOS, CalyxOS, GrapheneOS): The Accessibility Service approach works on all ROMs, unlike the `Instrumentation` method which requires a signature-level permission that privacy ROMs block.
>
> #### π Android Version Compatibility
>
> The injection method depends on the device's Android version:
>
> | Feature | Android 13+ (API 33+) | Android 5β12 (API 21β32) |
> |---|---|---|
> | **Back / Home / Recents** | β
`performGlobalAction()` | β
`performGlobalAction()` |
> | **DPAD navigation** (up, down, left, right) | β
`InputMethod.sendKeyEvent()` | β
Accessibility tree traversal + scroll |
> | **Select / Enter** (on UI elements) | β
`InputMethod.sendKeyEvent()` | β
`ACTION_CLICK` on focused element |
> | **Play/Pause** | β
`InputMethod.sendKeyEvent()` | β
`GLOBAL_ACTION_HEADSETHOOK` (API 31+) |
> | **Printable keys** (a-z, 0-9, symbols) | β
`InputMethod.sendKeyEvent()` | β
`ACTION_SET_TEXT` (appends char) |
> | **Backspace** | β
`InputMethod.sendKeyEvent()` | β
`ACTION_SET_TEXT` (removes last char) |
> | **Text input** | β
`InputMethod.commitText()` | β
`ACTION_SET_TEXT` (appends text) |
> | **Shift + letter** (e.g. Shift+A β 'A') | β
`InputMethod.sendKeyEvent()` | β
`ACTION_SET_TEXT` (shifted char) |
> | **Non-printable keys** (Tab, Escape, F1-F12) | β
`InputMethod.sendKeyEvent()` | β οΈ Limited (`input keyevent` β requires root) |
> | **Ctrl/Alt combos** (Ctrl+C, Alt+F4) | β
`InputMethod.sendKeyEvent()` | β οΈ Limited (meta state lost) |
>
> **Summary**: On Android 13+, everything works via InputMethod APIs. On Android 5β12, most remote control operations work: DPAD navigation via accessibility tree traversal, Select via `ACTION_CLICK`, Play/Pause via global action (API 31+), text/printable keys via `ACTION_SET_TEXT`. Only Tab, F-keys, and Ctrl/Alt shortcuts are limited.
### GPS Location (GET)
#### `GET /api/location`
Returns the device's last known GPS coordinates. Uses GPS, Network, and Passive location providers.
> β οΈ **Requires**: Location permission granted + GPS enabled on the device.
```bash
curl http://tablet-ip:8080/api/location
```
Response:
```json
{
"success": true,
"data": {
"executed": true,
"command": "getLocation",
"available": true,
"latitude": 48.8566,
"longitude": 2.3522,
"accuracy": 15.0,
"altitude": 35.0,
"speed": 0.0,
"bearing": 0.0,
"provider": "gps",
"time": 1704672000000,
"providers": ["gps", "network", "passive"]
}
}
```
If no location is available:
```json
{
"success": true,
"data": {
"executed": true,
"command": "getLocation",
"available": false,
"error": "No location available. Ensure GPS is enabled and location permission is granted.",
"providers": ["network", "passive"]
}
}
```
## Authentication
If an API key is configured, include it in requests:
```bash
curl -H "X-Api-Key: your-api-key" http://tablet-ip:8080/api/status
```
## Home Assistant Integration
### Basic Sensors
```yaml
# configuration.yaml
rest:
- resource: http://TABLET_IP:8080/api/status
scan_interval: 30
sensor:
- name: "Tablet Battery"
value_template: "{{ value_json.data.battery.level }}"
unit_of_measurement: "%"
device_class: battery
- name: "Tablet Brightness"
value_template: "{{ value_json.data.screen.brightness }}"
unit_of_measurement: "%"
- name: "Tablet Light Sensor"
value_template: "{{ value_json.data.sensors.light | round(0) }}"
unit_of_measurement: "lx"
device_class: illuminance
- name: "Tablet WiFi Signal"
value_template: "{{ value_json.data.wifi.rssi }}"
unit_of_measurement: "dBm"
device_class: signal_strength
binary_sensor:
- name: "Tablet Screen"
value_template: "{{ value_json.data.screen.on }}"
device_class: power
- name: "Tablet Charging"
value_template: "{{ value_json.data.battery.charging }}"
device_class: battery_charging
- name: "Tablet Screensaver"
value_template: "{{ value_json.data.screen.screensaverActive }}"
- resource: http://TABLET_IP:8080/api/location
scan_interval: 300
sensor:
- name: "Tablet GPS Latitude"
value_template: "{{ value_json.data.latitude | default('unavailable') }}"
- name: "Tablet GPS Longitude"
value_template: "{{ value_json.data.longitude | default('unavailable') }}"
- name: "Tablet GPS Accuracy"
value_template: "{{ value_json.data.accuracy | default('unavailable') }}"
unit_of_measurement: "m"
- resource: http://TABLET_IP:8080/api/battery
scan_interval: 60
sensor:
- name: "Tablet Battery Temperature"
value_template: "{{ value_json.data.temperature }}"
unit_of_measurement: "Β°C"
device_class: temperature
- name: "Tablet Battery Health"
value_template: "{{ value_json.data.health }}"
```
### REST Commands
```yaml
rest_command:
tablet_screen_on:
url: http://TABLET_IP:8080/api/screen/on
method: POST
tablet_screen_off:
url: http://TABLET_IP:8080/api/screen/off
method: POST
tablet_brightness:
url: http://TABLET_IP:8080/api/brightness
method: POST
content_type: "application/json"
payload: '{"value": {{ brightness }}}'
tablet_navigate:
url: http://TABLET_IP:8080/api/url
method: POST
content_type: "application/json"
payload: '{"url": "{{ url }}"}'
tablet_reload:
url: http://TABLET_IP:8080/api/reload
method: POST
tablet_lock:
url: http://TABLET_IP:8080/api/lock
method: POST
tablet_restart_ui:
url: http://TABLET_IP:8080/api/restart-ui
method: POST
tablet_tts:
url: http://TABLET_IP:8080/api/tts
method: POST
content_type: "application/json"
payload: '{"text": "{{ message }}", "language": "{{ language | default(\'\') }}"}'
tablet_volume:
url: http://TABLET_IP:8080/api/volume
method: POST
content_type: "application/json"
payload: '{"value": {{ volume }}}'
tablet_beep:
url: http://TABLET_IP:8080/api/audio/beep
method: POST
tablet_toast:
url: http://TABLET_IP:8080/api/toast
method: POST
content_type: "application/json"
payload: '{"text": "{{ message }}"}'
tablet_screensaver_on:
url: http://TABLET_IP:8080/api/screensaver/on
method: POST
tablet_screensaver_off:
url: http://TABLET_IP:8080/api/screensaver/off
method: POST
tablet_keyboard_key:
url: "http://TABLET_IP:8080/api/remote/keyboard/{{ key }}"
method: GET
tablet_keyboard_combo:
url: "http://TABLET_IP:8080/api/remote/keyboard?map={{ combo }}"
method: GET
tablet_type_text:
url: http://TABLET_IP:8080/api/remote/text
method: POST
content_type: "application/json"
payload: '{"text": "{{ text }}"}'
```
### Screenshot Camera
```yaml
camera:
- platform: generic
name: "Tablet Screenshot"
still_image_url: http://TABLET_IP:8080/api/screenshot
content_type: image/png
```
### Device Camera (Photo)
```yaml
camera:
- platform: generic
name: "Tablet Camera (Back)"
still_image_url: http://TABLET_IP:8080/api/camera/photo?camera=back&quality=80
content_type: image/jpeg
- platform: generic
name: "Tablet Camera (Front)"
still_image_url: http://TABLET_IP:8080/api/camera/photo?camera=front&quality=80
content_type: image/jpeg
```
> π‘ **Tip**: Use the front camera as a basic security camera, or the back camera for monitoring. Combine with automations to capture photos on motion detection events.
### Example Automations
#### Auto-brightness based on room light
```yaml
automation:
- alias: "Tablet Auto Brightness"
trigger:
- platform: state
entity_id: sensor.living_room_light_level
action:
- service: rest_command.tablet_brightness
data:
brightness: "{{ (states('sensor.living_room_light_level') | float / 10) | int | min(100) }}"
```
#### Turn off screen at night
```yaml
automation:
- alias: "Tablet Screen Off at Night"
trigger:
- platform: time
at: "23:00:00"
action:
- service: rest_command.tablet_screensaver_on
```
#### Wake tablet on motion
```yaml
automation:
- alias: "Wake Tablet on Motion"
trigger:
- platform: state
entity_id: binary_sensor.living_room_motion
to: "on"
condition:
- condition: state
entity_id: binary_sensor.tablet_screensaver
state: "on"
action:
- service: rest_command.tablet_screensaver_off
```
#### Doorbell notification
```yaml
automation:
- alias: "Doorbell Alert on Tablet"
trigger:
- platform: state
entity_id: binary_sensor.doorbell
to: "on"
action:
- service: rest_command.tablet_beep
- service: rest_command.tablet_toast
data:
message: "Someone is at the door!"
- service: rest_command.tablet_navigate
data:
url: "http://homeassistant:8123/lovelace/cameras"
```
## Testing with cURL
```bash
# Get status
curl http://TABLET_IP:8080/api/status
# Set brightness
curl -X POST -H "Content-Type: application/json" \
-d '{"value": 50}' http://TABLET_IP:8080/api/brightness
# Play beep
curl -X POST http://TABLET_IP:8080/api/audio/beep
# Save screenshot
curl http://TABLET_IP:8080/api/screenshot -o screenshot.png
# Show toast
curl -X POST -H "Content-Type: application/json" \
-d '{"text": "Hello!"}' http://TABLET_IP:8080/api/toast
# Keyboard: press Enter
curl http://TABLET_IP:8080/api/remote/keyboard/enter
# Keyboard: Ctrl+A (select all)
curl "http://TABLET_IP:8080/api/remote/keyboard?map=ctrl+a"
# Type text into focused field
curl -X POST -H "Content-Type: application/json" \
-d '{"text": "Hello World!"}' http://TABLET_IP:8080/api/remote/text
# Get GPS location
curl http://TABLET_IP:8080/api/location
```
## Error Responses
```json
{
"success": false,
"error": "Error message",
"timestamp": 1704672000
}
```
Common errors:
- `401 Unauthorized` - Invalid or missing API key
- `403 Forbidden` - Control commands disabled
- `404 Not Found` - Unknown endpoint
- `500 Internal Error` - Server error
## See Also
- [ADB Configuration Guide](ADB-Configuration) - Headless provisioning via ADB
- [MDM Specification](MDM-SPEC) - Enterprise deployment
- [Installation Guide](Installation) - Manual setup
## Changelog
### v1.2.0
- Initial REST API release
- 40+ endpoints for full device control
- Home Assistant integration ready
- Sensors: battery, brightness, light, proximity, storage, memory, WiFi
- Controls: screen, brightness, volume, audio, navigation, remote
- Screenshot capture
- Audio playback (URL, beep)