Introduction
Xiao is an Android application for prototyping, testing, and debugging connected devices and network services.
Overview
It combines three major areas of functionality:
- Projects — Saved device configurations with typed payloads for BLE, Bluetooth Classic, Wi-Fi sockets, HTTP APIs, MQTT, and WebSockets.
- Automations — Visual workflows that connect your Projects into automated sequences on a canvas. Run once on demand or leave them listening in the background.
- Playground — Standalone tools (BLE emulator, NFC, local HTTP server, network scanners, MITM proxy, FCM tester, shells) that work without creating a project.
Who Should Use Xiao
- Embedded and IoT developers testing firmware over BLE, Wi-Fi, or MQTT.
- Mobile developers debugging APIs, WebSockets, and push notifications.
- QA engineers validating device behavior, connectivity, and payload formats.
- Hardware teams emulating BLE peripherals when physical devices are unavailable.
Core Capabilities
Short-range radio
BLE GATT read/write/notify; Bluetooth Classic RFCOMM serial
Local network
TCP/UDP sockets; mDNS discovery; LAN port scanning
Internet / cloud
REST APIs; WebSockets; MQTT pub/sub; FCM push testing
Automations
Visual canvas workflows — MQTT triggers, schedules, API polls, conditions, loops, and notifications
On-device servers
Ktor HTTP server with DSL routes and SQLite. Xiao DSL for Ktor Server
Security / debug
MITM HTTP/HTTPS proxy with CA export; verbose packet logs
System access
Toybox shell; native ADB client over TCP/TLS
How the App Is Organized
The launcher uses bottom navigation with five destinations: Home (recent projects, automations, and import), Projects (full library), Link a Project (create new), Playground (tools), and Settings (global preferences). Opening a project launches View Project, your command center for that device or service. Automations live under Home → Automations and open on the canvas editor.
Typical First-Day Workflow
- Install Xiao from the Google Play Store and grant Bluetooth plus notification permissions when prompted.
- Connect phone and IoT device to the same Wi-Fi network (for Wi-Fi or MQTT testing).
- Use Playground → LAN Port Scanner or mDNS Browser to discover device IP or broker.
- Create a project via Link a Project matching your device protocol.
- Open View Project, confirm availability, and run Make Request against your first payload.
- Enable Verbose logging in Settings if you need to diagnose connection issues.
System Requirements & Installation
Getting Xiao running on your device.
Hardware & Software Requirements
| Requirement | Details |
|---|---|
| Operating system | Android 9 (Pie) or later |
| Bluetooth | Required for BLE projects, emulator, and Classic BT |
| NFC | Required only for NFC Tools (Playground) |
| Wi-Fi | Required for LAN tools, TCP/UDP, MQTT, API, WebSocket, MITM, Ktor server |
| Storage | Space for app data, logs, exported .xiaofile backups, and saved CA certs |
Installing Xiao
- On your Android device, open the Google Play Store app.
- Search for Xiao and confirm the listing matches the official app.
- Tap Install and wait for the download and installation to finish.
- Launch Xiao from the app drawer or the Play Store Open button.
- Enable automatic updates in Play Store so you always have the latest version.
First Launch Checklist
- Open Xiao — the Home tab appears with an empty project grid if none exist.
- Grant permissions when prompted (Bluetooth, notifications, location if required for scanning).
- Optionally open Settings and review defaults before your first connection.
- Create a project via Link a Project, or explore Playground tools immediately.
Recommended Test Environment
- Use a dedicated test phone rather than your daily driver when using MITM, ADB, or port scanning.
- Connect to a lab Wi-Fi network you control; avoid corporate or public networks for interception tools.
- Keep target IoT devices and your phone on the same subnet for Wi-Fi and mDNS features.
Permissions & Privacy
What Xiao requests and why. For full privacy details, see the Privacy Policy.
Xiao requests permissions only when a feature needs them. Denying a permission limits related features but does not crash the app.
| Permission | Required for | If denied |
|---|---|---|
| Internet | API, MQTT, WebSocket, FCM, proxy, downloads | Remote features unavailable |
| Network state | Detecting connectivity, showing SSID/IP in LAN tools | Some status info hidden |
| Bluetooth scan / connect / advertise | BLE projects, emulator, Classic BT | Bluetooth features blocked |
| Location (Android 10 and below) | BLE/Wi-Fi scan per OS policy | Scan may fail; manual IP/MAC entry still works |
| Nearby devices (Android 12+) | BLE without tying to location | BLE may not work on newer Android |
| NFC | NFC Tools read/write | NFC screen exits with message |
| Notifications | Foreground service alerts (server, emulator, proxy, automations); Notify nodes | Services may still run with reduced visibility; Notify nodes show toast instead |
| Exact alarms | Schedule and Routine automation triggers | Scheduled automations may not fire on time |
Location Permission
Android historically required location permission for Bluetooth and Wi-Fi scanning because scan results could infer user location. Xiao uses scanning solely to find devices and services on your network. No location data is stored or transmitted. If you prefer not to grant location access, enter IP addresses, ports, and MAC addresses manually in project settings.
Foreground Services
Bluetooth Emulator, Ktor Server, MITM Proxy, and background Automations run as foreground services while active. You will see a persistent notification. Stop services from within each tool, via Settings → Stop all services, from the Automations dashboard Stop all, or by disabling Allow background execution (services stop when you leave the app).
Projects — Core Workflow
Create, manage, and use saved configurations.
Creating a New Project
- Tap Link a Project in the bottom bar.
- Read the communication mode descriptions. Each card shows range (Short Range, Local Network, Internet) and connection style (Direct, Broker, Remote).
- Select your mode: Bluetooth LE, Bluetooth Classic, Wi-Fi Sockets, MQTT, API Server, or Web Socket.
- Fill Project Info: choose a name and icon; optional device identifier.
- Complete Connection Settings (varies by type — see protocol chapters).
- Add at least one payload section (endpoint, topic, socket, or characteristic) except for Bluetooth Classic.
- Tap Save. If validation fails, fix highlighted fields (empty names, missing UUIDs, duplicate payload names).
Editing an Existing Project
- Open the project from Home or Projects.
- Tap the edit (pencil) icon in the title bar.
- Modify fields or add/remove payload sections.
- Tap Save. When editing, saving returns you to the launcher Home tab.
Deleting a Project
Open View Project, tap delete, confirm. Deletion is permanent and removes all payload definitions for that project ID.
Automatic Connection Behavior
| Project type | On open behavior |
|---|---|
| BLE | Scans for device; connects GATT using stored MAC; discovers services |
| Classic BT | Checks pairing/connection; shows warning if not bonded |
| Wi-Fi | Resolves IP; checks reachability on same network |
| MQTT | Validates broker settings; connects when you send/subscribe |
| API / WebSocket | Checks base URL / WS URL availability |
Bluetooth LE Projects
GATT services, characteristics, and live data.
Use Bluetooth LE when your hardware exposes GATT services. Typical range is 10–20 metres. No internet connection is required.
Project Editor Fields
| Field | Required | Description |
|---|---|---|
| Project name | Yes | Display name on Home/Projects grid; pick a custom icon |
| Select a Bluetooth device | Yes | Dropdown scan of nearby BLE devices; shows name and signal type |
| Service UUID | Per payload | Parent GATT service for each characteristic |
| Characteristic UUID | Yes | UUID for read/write/notify/indicate operations |
| Operation | Yes | READ, WRITE, NOTIFY, or INDICATE |
| Send/Receive payloads | Varies | Typed fields for data you write or expect back |
Device Selection Workflow
- Ensure Bluetooth is enabled on your phone.
- Tap the device dropdown — Xiao scans using the BLE discovery timeout from Settings (default 12 seconds for Classic discovery; BLE scan timeout default 5 seconds).
- Select your peripheral. Xiao requests available GATT services from the device to help pre-fill UUIDs.
- Add characteristics manually or from discovered services.
BLE GATT Services
BLE devices expose data through GATT (Generic Attribute Profile). After Xiao connects to a peripheral, it discovers a tree of services, each containing one or more characteristics (and optional descriptors). Your project payloads target a specific characteristic inside a parent service.
- Service — A logical grouping of related functionality (for example Battery Service
180For a vendor-specific custom service). - Characteristic — A single data point you read, write, or subscribe to via NOTIFY/INDICATE (for example battery level or a sensor reading).
- UUID — Identifies each service and characteristic. Bluetooth SIG assigns 16-bit short UUIDs for standard profiles; custom firmware often uses 128-bit UUIDs. In Xiao, the full form is
0000XXXX-0000-1000-8000-00805f9b34fbfor 16-bit IDs.
When you pick a device in the project editor, Xiao lists discovered services to help you choose the correct Service UUID and Characteristic UUID. If your firmware documentation only lists short hex IDs (e.g. 180D), expand them to the full UUID or pick from the discovered list.
Bluetooth SIG GATT reference
Official assigned numbers for standard GATT services and characteristics — useful when matching firmware docs to UUIDs in your project.
Operations Explained
- READ — App reads characteristic value once when you send the request.
- WRITE — App writes your payload bytes/string to the characteristic.
- NOTIFY — Device pushes updates when value changes; response section defines expected format.
- INDICATE — Like NOTIFY but with acknowledgment at the link layer.
Tips for Reliable BLE Testing
- Keep the phone within a few metres during pairing and first connection.
- If scan finds nothing, switch BLE scan mode to Aggressive in Settings.
- Increase BLE MTU (default 517) only if both phone and device support larger packets.
- Enable BLE auto reconnect to restore GATT after brief disconnects.
Bluetooth Classic Projects
RFCOMM serial and profile-based communication.
Use Bluetooth Classic for serial-port (SPP) and other Classic profiles. The device must be paired with your phone in Android Bluetooth settings first.
Project Editor Fields
- Project name and icon — Same as other project types.
- Select a Bluetooth device — Dropdown of nearby Classic devices; stores name, MAC, scan type, and device type in project data.
Unlike other types, Classic projects do not require payload definitions. It will automatically detect supported profiles. Some of the profiles are restricted by Android system and might require root access.
RFCOMM Terminal Usage
- From View Project, open the RFCOMM terminal.
- Select the appropriate profile/service if multiple are available.
- Send raw text or hex data; received data appears in the terminal stream.
- Use macros for repeated commands; manage macro clearing in Settings → Bluetooth → Clear macros.
Wi-Fi Socket Projects
TCP and UDP on your local network.
Wi-Fi Socket projects send raw data to an IP address and port over TCP or UDP. Your phone and the target device must be on the same Wi-Fi network. If your device exposes HTTP REST APIs instead of raw sockets, use an API Server project.
Project Editor Fields
| Field | Required | Description |
|---|---|---|
| Project name | Yes | Name and icon for the project card |
| Device name / identifier | No | Human-readable label for your MCU or board |
| IP address | Yes | Target IPv4 on the LAN (e.g. 192.168.1.50) |
| Socket — Port | Yes | TCP or UDP port number |
| Socket — Protocol | Yes | TCP or UDP per payload section |
| Transmit / Receive payloads | Yes | Typed data definitions for send and response |
TCP vs UDP
- TCP — Connection-oriented; reliable ordered delivery. Use when device expects a persistent socket.
- UDP — Datagrams; fire-and-forget. Use for lightweight sensor packets or broadcast-style protocols.
Network Troubleshooting
- Error "IP unreachable" means subnet mismatch, wrong IP, device offline, or firewall blocking.
- Verify SSID shown in View Project matches your IoT device's network.
- Adjust connection timeout (Settings → Wi-Fi & Network) if device is slow to accept sockets.
- Enable TCP No-Delay for low-latency small packets; disable if batching is preferred.
MQTT Projects
Broker-based publish and subscribe.
MQTT projects communicate through a message broker. Your phone and IoT device both connect to the broker independently — they never connect to each other directly.
Connection Settings
| Field | Required | Typical value |
|---|---|---|
| Client ID | Recommended | Unique string per client (e.g. xiao-phone-01) |
| Broker address | Yes | IP or hostname (e.g. test.mosquitto.org or 192.168.1.10) |
| Port | Yes | 1883 plain, 8883 TLS |
| Username / Password | If broker requires | Broker account credentials |
| TLS/SSL | As needed | Enable when broker requires encryption |
| Topic (per payload) | Yes | MQTT topic string for publish/subscribe |
Complete Project Editor Walkthrough
- Enter Project name and optional device identifier (e.g. greenhouse-sensor-hub).
- Set Client ID to a unique string not used by other clients on the same broker.
- Enter Broker address — IP for local Mosquitto (e.g. 192.168.1.20) or public hostname.
- Set Port: 1883 for plain MQTT, 8883 for TLS.
- If the broker requires auth, fill Username and Password.
- Set TLS/SSL to Enable when using port 8883 or when Force TLS is on in Settings.
- Tap Add under Topics. Enter topic path (e.g. devices/sensor/temperature).
- Define Publish payload fields and Subscribe response fields if you expect replies.
- Save the project. Open View Project and confirm broker availability.
- Use Make Request to publish, MQTT Live View to monitor, and MQTT Dashboard to chart values over time.
API & WebSocket Projects
HTTP REST and persistent WebSocket channels.
API Server Projects
| Field | Description |
|---|---|
| Base URL | Root URL (e.g. https://api.example.com/v1) |
| API key | Optional key sent per project configuration |
| Authorization | Optional auth header value (Bearer token, etc.) |
| Header key / Header value | Optional extra HTTP header pair |
| Endpoint path | Relative path per payload (e.g. /devices/status) |
| HTTP method | GET, POST, PUT, or DELETE |
| Send / Receive payloads | Request body and response structure |
GET and DELETE requests append payload field placeholders to the URL path. POST and PUT send structured body fields.
WebSocket Projects
| Field | Description |
|---|---|
| Server URL | Full ws:// or wss:// URL including path if required |
| API key / Authorization | Optional credentials |
| Header key / Header value | Custom handshake headers |
| Channel | Logical channel name per payload section |
| Send / Receive | Message formats for outbound and inbound frames |
WebSocket connections persist until closed. Configure ping interval and auto reconnect under Settings → WebSocket (defaults: 30s ping, auto reconnect enabled).
Payload System
Data types, structure, and validation.
Payload Item Types
| Type | Use for |
|---|---|
| Boolean | Flags, switches; optional custom True/False labels (comma-separated) |
| Integer | Counts, IDs, enums with numeric values; optional unit |
| Float | Sensor readings; optional unit (e.g. °C, %, V) |
| String | Plain text, tokens, short messages |
| JSON | Nested objects built from child payload items |
| XML | Response formatted as XML where supported |
| Image | Pick a file; transmitted as base64 |
Validation Rules
- Payload names must be unique within a section and cannot be empty.
- JSON sections require at least one child item unless you remove the section entirely.
- Endpoint, topic, port, or UUID fields must be populated before save.
- Image fields must have a selected file before sending from Make Request.
- HTML response format disallows nested response payload definitions.
Make Request Screen
Send data and read responses.
Make Request is the runtime interface for every project payload. Open it by tapping any endpoint, topic, socket, or characteristic from View Project.
Screen Layout
- Title — Payload or endpoint name.
- Send section — Input fields for each payload item.
- Receive section — Appears after a successful response; shows formatted data tiles.
- Action button — Send, Transmit, or Publish depending on connectivity type.
- Spinner — Indicates request in progress.
Step-by-Step: Sending a Request
- Verify the project shows online/available where applicable.
- Open the desired payload from View Project.
- Fill every required field. For JSON types, expand nested items.
- For Image type, tap Pick image and select a file from storage.
- Tap the action button. Wait for the spinner to stop.
- Review Receive tiles. Tap image tiles to view full size or save to files.
- If the request fails, check Logs and Troubleshooting.
Behavior by Connectivity Type
| Type | Send action | Connection notes |
|---|---|---|
| API | HTTP request with method from project | Uses OkHttp; supports custom headers |
| Wi-Fi TCP | Opens socket, sends bytes, reads response | Timeout from Wi-Fi settings |
| Wi-Fi UDP | Sends datagram; may wait for reply | UDP buffer size configurable |
| MQTT | Publishes to topic; subscribes for response if defined | Uses HiveMQ MQTT 5 client |
| WebSocket | Sends text/binary frame | Persistent connection with ping |
| BLE READ | Triggers GATT read | Requires active GATT connection |
| BLE WRITE | Writes characteristic value | Validates payload against characteristic size |
| BLE NOTIFY/INDICATE | Enables notifications; shows streaming data | Leave screen open to receive updates |
MQTT Live View & Dashboard
Monitoring and visualization.
MQTT Live View
Opens from MQTT View Project. Displays a scrolling feed of MQTT traffic: messages received on subscribed topics and messages your app publishes. Each entry shows topic, payload, and timing.
- Ensure MQTT broker settings are correct and broker is reachable.
- Open MQTT Live View from View Project.
- Trigger your IoT device or use Make Request to publish.
- Observe messages appear in real time for debugging topic names and JSON structure.
MQTT Dashboard
Build visual dashboards from numeric or boolean fields in MQTT message payloads.
- Open MQTT Dashboard from View Project.
- If empty, tap add metric. Select a topic from your project configuration.
- Map data points from the payload to dashboard tiles (name, unit, accent color).
- Save the metric. Tiles update as new messages arrive.
- Edit or remove metrics from the dashboard management UI.
Export, Import & Logs
Backup and diagnostics.
Exporting a Project (.xiaofile)
- Open View Project for the project to export.
- Use the export action (share/save flow).
- Pick a destination in the system document picker.
- The file uses MIME type
application/x-xiaofileand extension.xiaofile.
Importing a Project
- From Home, use import to select a .xiaofile from storage, OR
- Open the file from another app; choose Xiao when prompted.
- The project appears in Home and Projects after successful import.
Logs Activity
Accessible from the Home screen header. Shows chronological log entries:
- Connectivity events (connect, disconnect, timeout).
- Settings changes (key and new value).
- Service lifecycle (BLE emulator, Ktor, MITM start/stop).
- Errors and warnings from managers.
Automations — Overview
Visual workflows that connect your Projects (MQTT, BLE, API, Wi‑Fi, WebSocket) into automated sequences.
Build flows on a canvas, run them once with Run, or leave them listening in the background with Start.
What Is an Automation?
An automation is a saved graph made of:
| Piece | Role |
|---|---|
| Nodes | Steps — read data, send data, branch, delay, notify, etc. |
| Wires | Order and branching between steps |
| Start node | When and how the flow begins |
| Tokens | Placeholders like {{sensor.temp}} filled in at run time |
Typical uses:
- MQTT message arrives → read BLE sensor → POST to API → notify
- Every weekday at 08:00 → call API → publish to MQTT
- Tap Run → wait for Wi‑Fi data → transform → send over WebSocket
Automations live under Home → Automations. Each one opens on the canvas editor.
Prerequisites
Create Projects First
Most nodes need a Project from Projects (MQTT broker, BLE device, API base URL, Wi‑Fi socket, WebSocket). Test the project with Make Request before wiring it into an automation.
If no matching project exists, the add-node palette shows: "No [type] Projects found. Create a [type] Project to add this node."
Background Setting
Settings → General → Automations background → Enable
Required for Runner, Schedule, Routine, MQTT Message, BLE Notify, Wi‑Fi Message, WebSocket Message, API Poll, and BLE Read Poll.
On Demand flows use Run only and do not need this setting.
Notifications & Alarms
- Notify nodes need notification permission. If denied, the flow still runs but shows a toast instead of a system notification.
- Schedule and Routine use Android exact alarms. Grant alarm permission if prompted.
Creating an Automation
- Tap Automations → Add.
- Enter a name.
- The canvas opens with a Start node (default: On Demand).
- Add nodes, wire them, configure each node, then Run or Start.
Automations — Canvas & Controls
Editing the flow graph and running automations.
Canvas Gestures
| Action | How |
|---|---|
| Pan | Drag empty canvas |
| Zoom | Pinch |
| Add node | Tap + (bottom-right) |
| Recenter | Tap the recenter button (next to +) when nodes are off-screen |
| Configure node | Double-tap the node |
| Connect | Drag from an output port (right) to an input port (left) |
| Disconnect wire | Long-press the wire |
| Rename automation | Toolbar pencil icon |
| Run history | Toolbar history icon |
Ports
Most nodes have one input (left) and one output (right).
| Node | Ports |
|---|---|
| Start | Output only |
| Condition | Input + True (upper right) + False (lower right) |
| Loop | Input + Out (body, upper right) + Done (after loop, lower right) |
| Join | Multiple inputs + one output |
| Notify, Log | Input only — terminal nodes |
You cannot connect the same output port to the same target twice.
Editing Lock
The canvas is read-only while a background automation is Started (listening) or an On Demand run is in progress. Use Stop (background) or Interrupt (on-demand run) to unlock editing. Changes save automatically when you leave the canvas (unless it is locked).
Run, Interrupt, Start, Stop
| Trigger type | Idle | Active |
|---|---|---|
| On Demand | Run (blue) | Interrupt (orange) |
| Background types | Start (blue) | Stop (orange) |
On Demand — Run and Interrupt
- Run — executes the full flow once from Start.
- While running, nodes highlight on the canvas (running / done / failed). Status shows: "Automation has started running… Tap interrupt to stop the flow."
- Interrupt — cancels the in-progress run (e.g. while waiting on MQTT Read). Shows "Run cancelled".
- Does not require Automations background to be enabled.
Background — Start and Stop
- Start — enables listening, schedules, or polls (depends on Start trigger type).
- Stop — disables background execution and unlocks the canvas.
- Requires Settings → Automations background → Enable.
- If background is disabled globally, Start is dimmed and status explains why.
The trash icon deletes the automation. It is disabled while running or listening.
How Flows Execute
Linear Chain
Start → Node A → Node B → Node C
Steps run one after another in wire order. Each step finishes before the next begins.
Fan-out (One Node → Many Children)
If Start (or any node) wires to two downstream nodes, both branches are queued and run sequentially (not in parallel threads). Order follows how wires were created.
Runner trigger: each listener branch runs independently when its event arrives.
Fan-in (Many Nodes → One Node)
| Target | Behavior |
|---|---|
| Normal node | Runs once on first arrival; duplicate queue entries are skipped |
| Join | Waits until every wired input branch has completed, then merges data and continues |
Use Join when you need data from multiple branches before the next step.
Condition and Loop
- Condition — only the True or False port fires per run.
- Loop — Out body repeats N times; then Done runs once.
Automations — Start Node (Triggers)
When and how your automation runs.
Double-tap Start → choose Trigger type. Options depend on which Project types you have.
| Trigger | Runs when | Background? | Control |
|---|---|---|---|
| On Demand | You tap Run | No | Run / Interrupt |
| Runner | Events on wired listener branches | Yes | Start / Stop |
| Schedule | Once at chosen date/time | Yes | Start / Stop |
| Routine | Repeating time on selected weekdays | Yes | Start / Stop |
| API Poll | HTTP call every N ms (min 5 s) | Yes | Start / Stop |
| BLE Read Poll | BLE read every N ms (min 5 s) | Yes | Start / Stop |
| MQTT Message | Message on configured topic | Yes | Start / Stop |
| BLE Notify | BLE notification received | Yes | Start / Stop |
| Wi‑Fi Message | Data on Wi‑Fi socket | Yes | Start / Stop |
| WebSocket Message | WebSocket message received | Yes | Start / Stop |
On Demand
{{trigger.*}}is empty at start — use MQTT Read, BLE Read, etc. mid-flow to wait for data.- Best for testing before enabling background Start.
Runner
Wire listener read nodes directly off Start (each branch is independent): MQTT Read, BLE Read, BLE Notify, Wi‑Fi Read, WebSocket Read.
When an event hits a branch, only that branch's downstream nodes run. Join synchronizes branches that must complete before a shared step. Runner keeps a persistent session — variables and Join state survive across separate branch runs.
Schedule & Routine
- Schedule — one-shot alarm at the configured date/time. Automation must be Started before that moment.
- Routine — repeating alarm at hour:minute on selected weekdays. Days: 1 = Mon … 7 = Sun. Next occurrence is rescheduled after each run.
API Poll / BLE Read Poll
- Select project + endpoint.
- Interval (ms) — minimum 5000.
- Poll result becomes trigger data (
{{trigger.raw}}, parsed fields).
MQTT / BLE / Wi‑Fi / WebSocket Message
- Project + endpoint (topic from endpoint config for MQTT).
- Optional Output variable name on Start (e.g.
mqtt_in). - Duplicate identical messages within 2 s ignored.
- 3 s minimum between full runs (background cooldown).
- Wi‑Fi and WebSocket: optional Send payload before listening.
Automations — Node Reference
Every built-in node type and its settings.
Read Data
| Node | What it does | Key settings |
|---|---|---|
| Call API | HTTP request | Project, endpoint, payload, timeout, output name, format |
| MQTT Read | Wait for next message on topic | Project, endpoint, output name, format. No timeout — waits forever |
| BLE Read | Read characteristic once | Project, endpoint, timeout (empty = forever), output name, format |
| BLE Notify | Wait for next BLE notification | Same as BLE Read |
| Wi‑Fi Read | Wait for socket data | Send payload, timeout, output name, format |
| WebSocket Read | Wait for WS message | Send payload, timeout, output name, format |
Send Data
| Node | What it does | Key settings |
|---|---|---|
| MQTT Publish | Publish to topic | Project, endpoint, payload template |
| BLE Write | Write characteristic | Project, endpoint, payload template |
| Wi‑Fi Send | Send on TCP socket | Project, endpoint, payload template |
| WebSocket Send | Send WS message | Project, endpoint, payload template |
Payload templates support {{tokens}}.
Transform Data
| Node | What it does | Key settings |
|---|---|---|
| Transform | Token substitution → plain text | Payload template |
| Build Payload | Token substitution → JSON (fields parsed) | Payload template |
| Parse JSON | Extract value by dot path | Source, JSON path |
| Set Variable | Store for later steps | Name, value → {{local.name}} |
| Join | Wait for all inputs; merge outputs | Output variable name (default joined) |
| Condition | Branch true/false | Source, operator, compare value |
Condition Operators
| Operator | Meaning |
|---|---|
| EXISTS | Source is not blank (default) |
| EQ / NE | Equal / not equal |
| GT / LT / GTE / LTE | Numeric compare |
| CONTAINS | Source contains value |
| CHANGED | Source differs from last run for this automation |
Wire True for pass, False for fail.
Flow Control
| Node | What it does | Key settings |
|---|---|---|
| Loop | Repeat Out branch N times | Count 1–100, delay 0–60 000 ms; then Done |
| Delay | Pause | 0–30 000 ms (default 500) |
| Debounce | Suppress rapid repeats in-path | Cooldown 0–60 000 ms (default 3000) |
| Notify | System notification | Title, body, optional image, dismiss previous |
| Log | Write to logcat tag Automation | Message. Not in app Logs screen |
Automations — Tokens & Data
Passing data between nodes and response formats.
Token Syntax
Syntax: {{name}} — resolved when the node runs.
{{trigger.raw}} Full trigger payload
{{trigger.topic}} MQTT topic
{{trigger.timestamp}} Event time (ms)
{{trigger.field.<key>}} JSON field from trigger
{{prev}} Previous node raw output
{{prev.<field>}} Previous node field
{{<output_name>}} Named node output (e.g. {{sensor}})
{{<output_name>.<field>}} Field from named output
{{local.<variable>}} Set Variable value
{{loop.index}} Loop iteration (0-based)
{{loop.count}} Total loop iterations
{{eval: ... }} Simple expression (>, <, &&)
{{node.<uuid>.raw}} Legacy — prefer output names
Output Variable Names
Set Output variable name on read/send nodes and on Start when using event triggers. This is the easiest way to reference data downstream. Token fields highlight in config fields as you type.
Examples
Linear chain: Start → BLE Read [sensor] → Build Payload → Call API [api_resp] → Notify
Notify body: Battery: {{sensor.Battery Level}} — API: {{api_resp.status}}
Set Variable + Condition: Set threshold = 25, then Condition {{sensor.temperature}} GT {{local.threshold}} → True/False → Notify.
Parse JSON: Source trigger.raw = {"data":{"temperature":22.5}}, path data.temperature → 22.5.
Response Formats
| Transport | Formats | Notes |
|---|---|---|
| BLE | Byte Array (default), JSON, Raw | Byte Array uses same decoding as Make Request |
| API | JSON (default), Raw | |
| MQTT / Wi‑Fi / WebSocket | JSON (default), Raw |
Raw payloads in run history appear as [RAW DATA] (not stored in full). JSON is stored with binary/image fields redacted.
Limits, Timeouts & Cooldowns
Read Timeouts
| Node | Timeout |
|---|---|
| MQTT Read | Not configurable — waits indefinitely |
| BLE Read / Notify | Optional; empty = forever |
| Wi‑Fi / WebSocket Read | Optional; empty = forever |
| Call API | Optional; app default if empty |
Stopping a background automation disconnects BLE opened for it.
Other Limits
| Setting | Limit |
|---|---|
| Delay | 0–30 000 ms |
| Debounce | 0–60 000 ms |
| Loop count | 1–100 |
| Loop delay | 0–60 000 ms |
| API / BLE poll interval | Min 5000 ms |
| Run history | Last 25 runs per automation |
Background Cooldown
Between full background runs: minimum 3 seconds. Identical messages within 2 seconds are skipped.
Debounce node = in-path suppression during one run. Background cooldown = between whole runs in the service.
Automations — Wiring & Join
Common flow patterns and Runner synchronization.
Simple Pipeline
Start → Delay → Transform → MQTT Publish
Split by Condition
Start → Condition
├─ True → Notify "alert"
└─ False → Log "ok"
Loop Sampling
Start → Loop [Out → BLE Read → Log] [Done → Notify "finished"]
Diamond (Avoid Without Join)
┌→ Process A ─┐
Start ──┤ ├→ Shared node ← only first arrival runs Shared
└→ Process B ─┘
Use Join instead of a shared normal node when both branches must contribute data.
Runner — Independent Branches
Start (Runner)
├─ MQTT Read [mqtt_a] ──→ Handle A
├─ MQTT Read [mqtt_b] ──→ Handle B
└─ BLE Notify [ble] ──→ Handle C
Each branch fires alone when its event arrives.
Runner — Synchronized Merge
Start (Runner)
├─ MQTT Read [mqtt] ──┐
└─ BLE Notify [ble] ──┴─→ Join [joined] → Call API
Join output:
{{joined}}— merged JSON of all branch raw outputs{{joined.branch_<nodeId>}}— one branch raw{{joined.<nodeId>_<field>}}— field from a branch- Individual names (
{{mqtt}},{{ble}}) still work if set on the read nodes
Join state persists in Runner — if MQTT arrives first, Join waits for BLE.
Automations — Examples
Step-by-step flows you can build today.
1 — MQTT → Notification (Beginner)
- Create MQTT project; confirm it connects.
- Automations → Add → name it
MQTT temp alert. - Start: MQTT Message, project, endpoint, output
mqtt_in. - + → Notify, wire Start → Notify.
- Notify body:
Reading: {{mqtt_in.temp}} - Settings → Automations background → Enable
- Tap Start. Publish
{"temp":28}to your topic.
2 — On Demand: Wait for MQTT, Call API
- Start: On Demand.
- MQTT Read [msg] — waits until a message.
- Build Payload → Call API [result] → Notify.
- Tap Run. Tap Interrupt if you need to cancel while waiting.
3 — MQTT → BLE → API
Start (MQTT) → BLE Read [ble] → Build Payload → Call API → Notify
Enable background Start for live MQTT triggering.
4 — Routine Morning Check
Start: Routine 08:00 Mon–Fri → Call API → MQTT Publish. Or use API Poll trigger for interval-based HTTP instead of clock time.
5 — Condition on Temperature
Start (BLE Notify) [evt] → Condition (GT 30) → True/False → Notify
6 — Loop Samples
Start → Loop (3×, 2 s delay)
Out → BLE Read [reading] → Log "sample {{loop.index}}: {{reading}}"
Done → Notify "Finished"
Automations — History & Dashboard
Debugging runs and managing background automations.
Run History
Canvas toolbar → history icon → run list for this automation. Tap a run → timeline of steps (name, status, duration). Read/send/API nodes may offer View output (sanitized).
| Stored | Not stored |
|---|---|
| Steps, timing, errors | Full Raw payloads ([RAW DATA]) |
| JSON outputs (redacted binaries) | Notify images |
| Delay / variable / condition summaries |
- Per automation: History → Clear
- All automations: Settings → Clear automation run history
Live Canvas (On Demand)
During Run, nodes show running / success / failed overlay. Interrupt stops the run. Failed nodes may toast the error reason.
Logcat
Log nodes and engine messages → Android logcat, tag Automation. Not the in-app Logs screen.
List Dashboard
| Stat | Meaning |
|---|---|
| Running | Background automations currently active |
| Total runs | Lifetime runs (all automations) |
| Success / Failed | Lifetime outcomes |
| Today | Runs today |
Stop all — disables every background automation at once.
List Actions
- Tap row → open canvas
- Long-press → Run (on-demand) or Enable/Disable (background), or Delete
Foreground Service
Active background automations show a low-priority Automations notification with the count listening. Runner keeps the service alive until Stop.
Automations — Troubleshooting
Common problems and quick reference.
| Problem | Check |
|---|---|
| Start disabled / background toast | Settings → Automations background → Enable |
| Cannot edit canvas | Stop (background) or Interrupt (on-demand run) |
| No Interrupt visible | Only shown while an On Demand run is active |
| Recenter dimmed | All nodes already visible — no action needed |
| Project not found | Create matching project type under Projects |
| MQTT never fires | Started? Topic matches? Background enabled? |
| Duplicate runs skipped | Normal — 3 s cooldown or 2 s duplicate window |
| BLE timeout | Increase timeout; ensure device connected |
| Token unchanged in output | Typo; upstream failed; output name not set |
| Notify missing | Grant notification permission |
| Join stuck | All wired branches must complete and reach Join |
| Runner branch isolated | Expected — use Join for shared downstream steps |
[RAW DATA] in history | By design for Raw format — use JSON when possible |
Quick Reference
Controls
| Trigger | Idle button | While active |
|---|---|---|
| On Demand | Run | Interrupt |
| Background | Start | Stop |
Token Cheat Sheet
{{trigger.raw}} {{trigger.field.KEY}} {{prev}} {{name.field}}
{{local.var}} {{loop.index}} {{joined}}
Node Palette
Read: Call API, MQTT/BLE/Wi‑Fi/WebSocket Read & Notify
Send: MQTT Publish, BLE Write, Wi‑Fi/WebSocket Send
Data: Transform, Build Payload, Parse JSON, Set Variable, Join, Condition
Flow: Loop, Delay, Debounce, Notify, Log
Tips
- Set output variable names on every data node.
- Test with On Demand + Run before Start in background.
- Use Join when Runner branches must meet before one step.
- Use Interrupt to cancel a long Run (e.g. stuck on MQTT Read).
- Use Recenter if you panned away and lost the graph.
- Prefer Byte Array for known BLE characteristics.
- Check Run History → View output when debugging payloads.
Playground: BLE Emulator & NFC
Simulate peripherals and program tags.
Bluetooth Emulator
Advertise a fake BLE peripheral from your phone. Runs as a foreground service.
- Open Playground → Bluetooth Emulator.
- Grant Bluetooth advertise permission if prompted.
- Set the advertised device name.
- Tap Add GATT Services — pick predefined services (Heart Rate, Battery, etc.) or custom UUIDs.
- For each service, Add Characteristic: alias, UUID, permissions (read/write/notify/indicate), initial hex or ASCII value.
- Optional: Clone Device to copy GATT layout from a real peripheral.
- Toggle Enable to start advertising. Other phones/apps can connect and read/write characteristics.
NFC Tools
Read and write NDEF-formatted NFC tags. Requires NFC hardware.
Reading Tags
- Enable NFC in Android settings.
- Open NFC Tools; hold a tag to the phone's NFC antenna.
- Parsed records appear in a popup — tap records for actions (open URL, copy text, etc.).
Writing Tags
- Tap Add Record.
- Choose Preset or Custom mode.
- Preset types: Text, Website (URL), Location, Contact (vCard), Android (package name), MIME (type|data).
- Custom mode: set TNF, record type, ID, payload encoding (UTF-8 or hex).
- Stage multiple records if needed.
- Tap Write to Tag and hold the tag until success toast appears.
Playground: Ktor, mDNS & LAN Scan
Servers and network discovery.
Ktor Server
Run an embedded HTTP server on your phone using the Ktor/CIO engine.
Xiao DSL for Ktor Server — Full Reference
Complete guide to @settings, @execute, @return, tokens, recipes, and troubleshooting for route handlers.
- Open Ktor Server from Playground.
- Set the listening port (LAN IP and port are displayed for clients on your network).
- Add routes: method (GET/POST/PUT/DELETE/PATCH), path, optional DSL handler body.
- Toggle Enable — server runs as foreground service; monitor request count and uptime.
- Use SQL Runner to execute SQL against the server's SQLite database.
- Use Database Viewer to inspect tables created by DSL routes.
@settings:
table: users
@execute:
- set: [email, name] from request.body
- upsert: true
@return:
status: 201
body: {"email": "{{col.email}}"}
mDNS Browser
- Enter service type (e.g.
_http._tcp.,_mqtt._tcp.,_adb._tcp.). - Tap Scan; wait for progress to complete.
- Tap a service for host, port, address, and type details.
- Copy address or open HTTP URLs in browser.
LAN Port Scanner
- Connect to Wi-Fi; review Current network card (SSID, your IP, gateway, scan range).
- Tap Start to scan the subnet.
- Browse hosts with open ports; common services are labeled.
- Per host: copy IP, Trace route, inspect ports for latency and TLS certificate info.
Playground: MITM & FCM Tester
Traffic inspection and push notifications.
MITM Interceptor
HTTP/HTTPS intercepting proxy for debugging clients on your LAN. Authorized testing only.
- Open MITM Interceptor; note your phone LAN IP and proxy port.
- On the client device/app, set HTTP proxy to phone_ip:port.
- Tap Save CA Certificate; save the PEM file via system picker.
- Install CA on client: Settings → Security → Encryption & credentials → Install certificate → CA certificate.
- Verify SHA-256 fingerprint matches the value shown in Xiao.
- Toggle proxy Enable on the phone.
- Optionally enable HTTPS Interception (requires proxy stopped to change).
- Browse Captured traffic; tap entries for full request/response headers and bodies.
FCM Tester
Send Firebase Cloud Messaging notifications without a backend server.
- Open FCM Tester from Playground.
- Manage service accounts — import Firebase service account JSON.
- Select active account.
- Choose target mode: Token (device FCM token) or Topic.
- Enter notification title and body.
- Add optional data payload key-value pairs, or switch to raw JSON mode.
- Tap send. Check target device for notification delivery.
Testing FirebaseMessagingService while the app is in the background: On Android, messages that include a notification payload (title and body) are handled by the system tray — onMessageReceived is not called until the app is in the foreground. To exercise your FCM service handler in the background, leave notification title and body empty and send data-only payloads (key-value pairs or raw JSON with only a data object). Put any fields your app needs (including display text) in the data map; your service can build a local notification from those keys if needed. If you send both notification and data while backgrounded, the notification appears in the tray and the data payload is delivered in the launcher intent extras when the user taps the notification — not via onMessageReceived on delivery.
Playground: Shells
Android Shell and ADB over TCP.
Android Shell
Toybox-based terminal on the device with boot-time system overview.
- Type commands in the input field; tap send or use quick actions (clear, pwd, interrupt).
- Supports core utilities exposed by Toybox on your Android build.
- Optional Shizuku integration for elevated commands where Shizuku is installed.
- Use curl and bridging helpers for network testing from the device itself.
Toybox
Android Shell uses Toybox — a single-binary collection of POSIX-style utilities. See the upstream project for command list, behavior, and documentation.
ADB & Remote Shell
Native ADB protocol client — no adb binary required on the phone.
Key Management
- Tap Manage ADB Keys.
- Add Key — paste RSA private key in PEM format (PKCS#1 or PKCS#8, 2048-bit, with BEGIN/END markers).
- Select active key. Invalid keys disable Connect until fixed.
Self Mode (localhost)
Connects to the ADB server on the same phone (wireless debugging). Tap Connect after key is active.
Remote Mode (TCP)
- Switch toggle to Remote (TCP).
- Tap Setup Connection → Manage Devices to add target IP/host.
- New devices: mDNS discovers ADB port (5555 default; alternates 5554, 5556, 5558).
- If discovery times out, enter port manually and retry.
- Connect and use terminal for shell commands on the remote device.
Settings Reference
Every preference explained.
Open Settings from the bottom navigation. All values persist locally in SharedPreferences under the XiaoPrefs store.
General
| Setting | Default | Description |
|---|---|---|
| Keep screen awake | Disable | Prevents screen timeout during active sessions |
| Allow background execution | Enable | Keeps BLE emulator, Ktor server, and connections alive when app is minimized |
| Pretty print JSON | Enable | Indents JSON in Make Request and MITM capture detail views |
| Log entries limit | 1000 | Max log rows retained (minimum 100) |
| Clear web data | Action | Wipes WebView cookies, cache, HTTP auth, and form data |
| Clear Logs | Action | Permanently deletes all XiaoLogger entries |
| Stop all services | Action | Stops BLE Emulator, Ktor Server, and background Automations foreground services |
| Automations background | Disable | Enable to allow Start on background triggers (Runner, Schedule, MQTT Message, etc.) |
| Clear automation run history | Action | Deletes run history for all automations |
Bluetooth
| Setting | Default | Description |
|---|---|---|
| BLE scan mode | Balanced | Balanced saves power; Aggressive finds devices faster |
| RSSI representation | Icon | Show signal as icon bars or numeric dBm value |
| BLE scan timeout | 5 sec | Auto-stop BLE scan after duration (min 1 sec) |
| BLE MTU | 517 bytes | GATT MTU request size (min 23) |
| BLE auto reconnect | Enable | Reconnect GATT after link loss |
| Discovery timeout | 12 sec | Classic Bluetooth device scan duration (min 5 sec) |
Wi-Fi & Network
| Setting | Default | Description |
|---|---|---|
| Connection timeout | 10 sec | TCP/UDP socket connect timeout (min 3 sec) |
| Read timeout | 5 sec | Wait for peer data after connect (min 1 sec) |
| TCP No-Delay | Enable | Disables Nagle algorithm for immediate small packet send |
| UDP buffer size | 64 KB | Receive buffer for UDP datagrams (min 8 KB) |
MQTT
| Setting | Default | Description |
|---|---|---|
| Force TLS/SSL | Disable | Requires encrypted broker connection for all MQTT projects |
| Keep alive | 60 sec | MQTT heartbeat interval sent to broker |
| Max inflight messages | 20 | Concurrent QoS 1 and 2 messages in flight |
| Default QoS | 1 | Default publish quality: 0=fire-and-forget, 1=at least once, 2=exactly once |
Performance & Debug
| Setting | Default | Description |
|---|---|---|
| Verbose logging | Enable | Detailed internal debug lines in Logs |
| Log network packets | Enable | Log raw TCP, MQTT, and WebSocket payload bytes |
| Max concurrent connections | 10 | Cap simultaneous active network connections (min 1) |
| Reduce UI updates | Enable | Throttle dashboard/list refresh under heavy MQTT traffic |
Troubleshooting
Common problems and fixes.
Projects & Payloads
| Problem | Likely cause | Fix |
|---|---|---|
| Cannot save project | Missing payload or invalid fields | Add payload section; fill UUIDs/topics; unique names |
| Import failed | Corrupt or wrong file | Re-export .xiaofile from source device |
| Make Request spins forever | Timeout too low or device offline | Increase timeout in Settings; check availability |
Bluetooth
| Problem | Fix |
|---|---|
| Device not in dropdown | Enable BT; increase scan timeout; use Aggressive mode; move closer |
| GATT connect fails | Verify UUIDs; disconnect other centrals; retry with auto reconnect |
| Classic profiles empty | Pair device in system settings first |
Wi-Fi & Network
| Problem | Fix |
|---|---|
| IP unreachable | Same subnet; correct IP; disable VPN; ping from LAN Scan |
| mDNS finds nothing | Correct service type suffix (_tcp.); same network; location permission |
| LAN scan empty | Connect Wi-Fi; wait for full scan; check firewall on targets |
Playground Services
| Problem | Fix |
|---|---|
| MITM no HTTPS decrypt | Install CA on client; not pinned app; enable interception |
| Ktor route 500 | Check DSL syntax; use SQL Runner to verify DB state |
| FCM send failed | Valid service account JSON; correct token/topic; network access |
| ADB unauthorized | Accept RSA fingerprint on target; correct private key loaded |
| Automation Start disabled | Enable Settings → Automations background; grant alarm permission for schedules |
| Join never completes | All wired branches must finish and reach the Join node |
Legal & Responsible Use
Important limitations.
Xiao provides professional debugging capabilities including HTTP/HTTPS interception, port scanning, ADB remote access, and on-device proxies. These tools are intended for development, QA, and authorized security testing on systems you own or have explicit permission to test.
- Do not intercept traffic of users who have not consented.
- Do not scan or probe networks without authorization.
- Comply with applicable laws, employment policies, and app terms of service.
- Certificate pinning in production apps prevents MITM decryption even with a user CA installed.
The software is provided as-is. You are solely responsible for how you deploy and use Xiao.
For how Xiao handles data on your device, see the standalone Privacy Policy.
Author: Saurav Sajeev (Developer) · Document date: June 10, 2026
Appendix: BLE Predefined Services
Available in Bluetooth Emulator.
When adding GATT services in the Bluetooth Emulator, Xiao offers standard Bluetooth SIG service UUIDs (16-bit short form shown). Full UUID format: 0000XXXX-0000-1000-8000-00805f9b34fb.
| Short UUID | Service name |
|---|---|
| 1800 | Generic Access |
| 1801 | Generic Attribute |
| 1802 | Immediate Alert |
| 1803 | Link Loss |
| 1804 | Tx Power |
| 1805 | Current Time |
| 1809 | Health Thermometer |
| 180A | Device Information |
| 180D | Heart Rate |
| 180F | Battery Service |
| 1810 | Blood Pressure |
| 1811 | Alert Notification |
| 1812 | Human Interface Device (HID) |
| 1816 | Cycling Speed and Cadence |
| 1818 | Cycling Power |
| 181A | Environmental Sensing |
| 1822 | Pulse Oximeter |
| 1826 | Fitness Machine |
Appendix: Xiao DSL for Ktor Server Tokens
Quick reference for route handlers.
Use these tokens inside @execute and @return blocks. For the complete token encyclopedia, directive syntax, and copy-paste recipes, see the dedicated Xiao DSL for Ktor Server reference.
Need the full Xiao DSL reference?
Every token, directive, error code, and 11 ready-made endpoint recipes are documented separately.
Request Tokens
| Token | Resolves to |
|---|---|
{{request.body}} | Raw request body string |
{{request.body.FIELD}} | JSON field from body |
{{request.path}} | URL path |
{{request.method}} | HTTP method |
{{request.uri}} | Full URI including query string |
{{request.param.NAME}} | Query parameter value |
{{request.header.NAME}} | Request header value |
Device & Environment Tokens
| Token | Resolves to |
|---|---|
{{device_model}} | Phone model name |
{{device_manufacturer}} | Manufacturer |
{{android_version}} | Android release version |
{{sdk_int}} | API level |
{{battery_level}} | Battery percentage |
{{Wi-Fi_ssid}} | Connected Wi-Fi network name |
{{Wi-Fi_ip}} | Phone Wi-Fi IPv4 address |
{{uuid}} | Random UUID v4 |
{{datetime}} | yyyy-MM-dd HH:mm:ss |
{{col.NAME}} | Column value from last write |
Appendix: Android Shell Quick Actions
Built-in terminal shortcuts.
Android Shell (Playground) exposes quick-action buttons above the terminal input:
| Button | Command | Purpose |
|---|---|---|
| Interrupt | interrupt | Stop the currently running foreground shell job |
| Clear | clear | Clear terminal scrollback |
| Pwd | pwd | Print working directory |
| Ls | ls | List directory contents |
| Ps | ps | List running processes |
| Help | toybox | List available Toybox applets on this device |
On startup, the shell runs a boot sequence reporting kernel version, device model, Android version, CPU ABI, user, working directory, SELinux mode, uptime, memory, storage, and network interfaces.
Example Manual Commands
curl -s https://httpbin.org/get
getprop ro.product.model
uname -a
ip addr show wlan0