Introduction

Xiao is an Android application for prototyping, testing, and debugging connected devices and network services.

Android 9+ (API 28) v1.1.0
Xiao version covered by this manual: 1.1.0. Minimum Android 9 (API 28); target API 36. Available on Google Play Store only.

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

  1. Install Xiao from the Google Play Store and grant Bluetooth plus notification permissions when prompted.
  2. Connect phone and IoT device to the same Wi-Fi network (for Wi-Fi or MQTT testing).
  3. Use Playground → LAN Port Scanner or mDNS Browser to discover device IP or broker.
  4. Create a project via Link a Project matching your device protocol.
  5. Open View Project, confirm availability, and run Make Request against your first payload.
  6. Enable Verbose logging in Settings if you need to diagnose connection issues.

System Requirements & Installation

Getting Xiao running on your device.

Hardware & Software Requirements

RequirementDetails
Operating systemAndroid 9 (Pie) or later
BluetoothRequired for BLE projects, emulator, and Classic BT
NFCRequired only for NFC Tools (Playground)
Wi-FiRequired for LAN tools, TCP/UDP, MQTT, API, WebSocket, MITM, Ktor server
StorageSpace for app data, logs, exported .xiaofile backups, and saved CA certs

Installing Xiao

Xiao is available exclusively on the Google Play Store. It is not distributed via third-party download sites.
  1. On your Android device, open the Google Play Store app.
  2. Search for Xiao and confirm the listing matches the official app.
  3. Tap Install and wait for the download and installation to finish.
  4. Launch Xiao from the app drawer or the Play Store Open button.
  5. Enable automatic updates in Play Store so you always have the latest version.

First Launch Checklist

  1. Open Xiao — the Home tab appears with an empty project grid if none exist.
  2. Grant permissions when prompted (Bluetooth, notifications, location if required for scanning).
  3. Optionally open Settings and review defaults before your first connection.
  4. 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.

PermissionRequired forIf denied
InternetAPI, MQTT, WebSocket, FCM, proxy, downloadsRemote features unavailable
Network stateDetecting connectivity, showing SSID/IP in LAN toolsSome status info hidden
Bluetooth scan / connect / advertiseBLE projects, emulator, Classic BTBluetooth features blocked
Location (Android 10 and below)BLE/Wi-Fi scan per OS policyScan may fail; manual IP/MAC entry still works
Nearby devices (Android 12+)BLE without tying to locationBLE may not work on newer Android
NFCNFC Tools read/writeNFC screen exits with message
NotificationsForeground service alerts (server, emulator, proxy, automations); Notify nodesServices may still run with reduced visibility; Notify nodes show toast instead
Exact alarmsSchedule and Routine automation triggersScheduled 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

  1. Tap Link a Project in the bottom bar.
  2. Read the communication mode descriptions. Each card shows range (Short Range, Local Network, Internet) and connection style (Direct, Broker, Remote).
  3. Select your mode: Bluetooth LE, Bluetooth Classic, Wi-Fi Sockets, MQTT, API Server, or Web Socket.
  4. Fill Project Info: choose a name and icon; optional device identifier.
  5. Complete Connection Settings (varies by type — see protocol chapters).
  6. Add at least one payload section (endpoint, topic, socket, or characteristic) except for Bluetooth Classic.
  7. Tap Save. If validation fails, fix highlighted fields (empty names, missing UUIDs, duplicate payload names).

Editing an Existing Project

  1. Open the project from Home or Projects.
  2. Tap the edit (pencil) icon in the title bar.
  3. Modify fields or add/remove payload sections.
  4. 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 typeOn open behavior
BLEScans for device; connects GATT using stored MAC; discovers services
Classic BTChecks pairing/connection; shows warning if not bonded
Wi-FiResolves IP; checks reachability on same network
MQTTValidates broker settings; connects when you send/subscribe
API / WebSocketChecks base URL / WS URL availability
Projects referencing Xiao emulated BLE service UUIDs display a disclaimer that the peripheral is emulated.

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

FieldRequiredDescription
Project nameYesDisplay name on Home/Projects grid; pick a custom icon
Select a Bluetooth deviceYesDropdown scan of nearby BLE devices; shows name and signal type
Service UUIDPer payloadParent GATT service for each characteristic
Characteristic UUIDYesUUID for read/write/notify/indicate operations
OperationYesREAD, WRITE, NOTIFY, or INDICATE
Send/Receive payloadsVariesTyped fields for data you write or expect back

Device Selection Workflow

  1. Ensure Bluetooth is enabled on your phone.
  2. 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).
  3. Select your peripheral. Xiao requests available GATT services from the device to help pre-fill UUIDs.
  4. 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 180F or 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-00805f9b34fb for 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.

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

  1. From View Project, open the RFCOMM terminal.
  2. Select the appropriate profile/service if multiple are available.
  3. Send raw text or hex data; received data appears in the terminal stream.
  4. Use macros for repeated commands; manage macro clearing in Settings → Bluetooth → Clear macros.
Enable Force Restricted Protocols in Settings if you need restricted Classic profiles in RFCOMM.

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

FieldRequiredDescription
Project nameYesName and icon for the project card
Device name / identifierNoHuman-readable label for your MCU or board
IP addressYesTarget IPv4 on the LAN (e.g. 192.168.1.50)
Socket — PortYesTCP or UDP port number
Socket — ProtocolYesTCP or UDP per payload section
Transmit / Receive payloadsYesTyped 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

FieldRequiredTypical value
Client IDRecommendedUnique string per client (e.g. xiao-phone-01)
Broker addressYesIP or hostname (e.g. test.mosquitto.org or 192.168.1.10)
PortYes1883 plain, 8883 TLS
Username / PasswordIf broker requiresBroker account credentials
TLS/SSLAs neededEnable when broker requires encryption
Topic (per payload)YesMQTT topic string for publish/subscribe

Complete Project Editor Walkthrough

  1. Enter Project name and optional device identifier (e.g. greenhouse-sensor-hub).
  2. Set Client ID to a unique string not used by other clients on the same broker.
  3. Enter Broker address — IP for local Mosquitto (e.g. 192.168.1.20) or public hostname.
  4. Set Port: 1883 for plain MQTT, 8883 for TLS.
  5. If the broker requires auth, fill Username and Password.
  6. Set TLS/SSL to Enable when using port 8883 or when Force TLS is on in Settings.
  7. Tap Add under Topics. Enter topic path (e.g. devices/sensor/temperature).
  8. Define Publish payload fields and Subscribe response fields if you expect replies.
  9. Save the project. Open View Project and confirm broker availability.
  10. 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

FieldDescription
Base URLRoot URL (e.g. https://api.example.com/v1)
API keyOptional key sent per project configuration
AuthorizationOptional auth header value (Bearer token, etc.)
Header key / Header valueOptional extra HTTP header pair
Endpoint pathRelative path per payload (e.g. /devices/status)
HTTP methodGET, POST, PUT, or DELETE
Send / Receive payloadsRequest 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

FieldDescription
Server URLFull ws:// or wss:// URL including path if required
API key / AuthorizationOptional credentials
Header key / Header valueCustom handshake headers
ChannelLogical channel name per payload section
Send / ReceiveMessage 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

TypeUse for
BooleanFlags, switches; optional custom True/False labels (comma-separated)
IntegerCounts, IDs, enums with numeric values; optional unit
FloatSensor readings; optional unit (e.g. °C, %, V)
StringPlain text, tokens, short messages
JSONNested objects built from child payload items
XMLResponse formatted as XML where supported
ImagePick 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

  1. Verify the project shows online/available where applicable.
  2. Open the desired payload from View Project.
  3. Fill every required field. For JSON types, expand nested items.
  4. For Image type, tap Pick image and select a file from storage.
  5. Tap the action button. Wait for the spinner to stop.
  6. Review Receive tiles. Tap image tiles to view full size or save to files.
  7. If the request fails, check Logs and Troubleshooting.

Behavior by Connectivity Type

TypeSend actionConnection notes
APIHTTP request with method from projectUses OkHttp; supports custom headers
Wi-Fi TCPOpens socket, sends bytes, reads responseTimeout from Wi-Fi settings
Wi-Fi UDPSends datagram; may wait for replyUDP buffer size configurable
MQTTPublishes to topic; subscribes for response if definedUses HiveMQ MQTT 5 client
WebSocketSends text/binary framePersistent connection with ping
BLE READTriggers GATT readRequires active GATT connection
BLE WRITEWrites characteristic valueValidates payload against characteristic size
BLE NOTIFY/INDICATEEnables notifications; shows streaming dataLeave 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.

  1. Ensure MQTT broker settings are correct and broker is reachable.
  2. Open MQTT Live View from View Project.
  3. Trigger your IoT device or use Make Request to publish.
  4. 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.

  1. Open MQTT Dashboard from View Project.
  2. If empty, tap add metric. Select a topic from your project configuration.
  3. Map data points from the payload to dashboard tiles (name, unit, accent color).
  4. Save the metric. Tiles update as new messages arrive.
  5. Edit or remove metrics from the dashboard management UI.
Dashboard data is stored per project ID. Export the project to backup dashboard definitions inside the .xiaofile.

Export, Import & Logs

Backup and diagnostics.

Exporting a Project (.xiaofile)

  1. Open View Project for the project to export.
  2. Use the export action (share/save flow).
  3. Pick a destination in the system document picker.
  4. The file uses MIME type application/x-xiaofile and extension .xiaofile.

Importing a Project

  1. From Home, use import to select a .xiaofile from storage, OR
  2. Open the file from another app; choose Xiao when prompted.
  3. 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:

PieceRole
NodesSteps — read data, send data, branch, delay, notify, etc.
WiresOrder and branching between steps
Start nodeWhen and how the flow begins
TokensPlaceholders 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

  1. Tap Automations → Add.
  2. Enter a name.
  3. The canvas opens with a Start node (default: On Demand).
  4. Add nodes, wire them, configure each node, then Run or Start.

Automations — Canvas & Controls

Editing the flow graph and running automations.

Canvas Gestures

ActionHow
PanDrag empty canvas
ZoomPinch
Add nodeTap + (bottom-right)
RecenterTap the recenter button (next to +) when nodes are off-screen
Configure nodeDouble-tap the node
ConnectDrag from an output port (right) to an input port (left)
Disconnect wireLong-press the wire
Rename automationToolbar pencil icon
Run historyToolbar history icon
Double tap on a node to edit. Long press a wire to disconnect.

Ports

Most nodes have one input (left) and one output (right).

NodePorts
StartOutput only
ConditionInput + True (upper right) + False (lower right)
LoopInput + Out (body, upper right) + Done (after loop, lower right)
JoinMultiple inputs + one output
Notify, LogInput 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 typeIdleActive
On DemandRun (blue)Interrupt (orange)
Background typesStart (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.

On Demand / single-trigger runs: wiring MQTT Read and BLE Read directly off Start runs both in one Run — each blocks in turn.
Runner trigger: each listener branch runs independently when its event arrives.

Fan-in (Many Nodes → One Node)

TargetBehavior
Normal nodeRuns once on first arrival; duplicate queue entries are skipped
JoinWaits 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.
  • LoopOut 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.

TriggerRuns whenBackground?Control
On DemandYou tap RunNoRun / Interrupt
RunnerEvents on wired listener branchesYesStart / Stop
ScheduleOnce at chosen date/timeYesStart / Stop
RoutineRepeating time on selected weekdaysYesStart / Stop
API PollHTTP call every N ms (min 5 s)YesStart / Stop
BLE Read PollBLE read every N ms (min 5 s)YesStart / Stop
MQTT MessageMessage on configured topicYesStart / Stop
BLE NotifyBLE notification receivedYesStart / Stop
Wi‑Fi MessageData on Wi‑Fi socketYesStart / Stop
WebSocket MessageWebSocket message receivedYesStart / 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

NodeWhat it doesKey settings
Call APIHTTP requestProject, endpoint, payload, timeout, output name, format
MQTT ReadWait for next message on topicProject, endpoint, output name, format. No timeout — waits forever
BLE ReadRead characteristic onceProject, endpoint, timeout (empty = forever), output name, format
BLE NotifyWait for next BLE notificationSame as BLE Read
Wi‑Fi ReadWait for socket dataSend payload, timeout, output name, format
WebSocket ReadWait for WS messageSend payload, timeout, output name, format

Send Data

NodeWhat it doesKey settings
MQTT PublishPublish to topicProject, endpoint, payload template
BLE WriteWrite characteristicProject, endpoint, payload template
Wi‑Fi SendSend on TCP socketProject, endpoint, payload template
WebSocket SendSend WS messageProject, endpoint, payload template

Payload templates support {{tokens}}.

Transform Data

NodeWhat it doesKey settings
TransformToken substitution → plain textPayload template
Build PayloadToken substitution → JSON (fields parsed)Payload template
Parse JSONExtract value by dot pathSource, JSON path
Set VariableStore for later stepsName, value → {{local.name}}
JoinWait for all inputs; merge outputsOutput variable name (default joined)
ConditionBranch true/falseSource, operator, compare value

Condition Operators

OperatorMeaning
EXISTSSource is not blank (default)
EQ / NEEqual / not equal
GT / LT / GTE / LTENumeric compare
CONTAINSSource contains value
CHANGEDSource differs from last run for this automation

Wire True for pass, False for fail.

Flow Control

NodeWhat it doesKey settings
LoopRepeat Out branch N timesCount 1–100, delay 0–60 000 ms; then Done
DelayPause0–30 000 ms (default 500)
DebounceSuppress rapid repeats in-pathCooldown 0–60 000 ms (default 3000)
NotifySystem notificationTitle, body, optional image, dismiss previous
LogWrite to logcat tag AutomationMessage. 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.temperature22.5.

Response Formats

TransportFormatsNotes
BLEByte Array (default), JSON, RawByte Array uses same decoding as Make Request
APIJSON (default), Raw
MQTT / Wi‑Fi / WebSocketJSON (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

NodeTimeout
MQTT ReadNot configurable — waits indefinitely
BLE Read / NotifyOptional; empty = forever
Wi‑Fi / WebSocket ReadOptional; empty = forever
Call APIOptional; app default if empty

Stopping a background automation disconnects BLE opened for it.

Other Limits

SettingLimit
Delay0–30 000 ms
Debounce0–60 000 ms
Loop count1–100
Loop delay0–60 000 ms
API / BLE poll intervalMin 5000 ms
Run historyLast 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)

  1. Create MQTT project; confirm it connects.
  2. Automations → Add → name it MQTT temp alert.
  3. Start: MQTT Message, project, endpoint, output mqtt_in.
  4. + → Notify, wire Start → Notify.
  5. Notify body: Reading: {{mqtt_in.temp}}
  6. Settings → Automations background → Enable
  7. Tap Start. Publish {"temp":28} to your topic.

2 — On Demand: Wait for MQTT, Call API

  1. Start: On Demand.
  2. MQTT Read [msg] — waits until a message.
  3. Build PayloadCall API [result] → Notify.
  4. 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 APIMQTT 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).

StoredNot stored
Steps, timing, errorsFull 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

StatMeaning
RunningBackground automations currently active
Total runsLifetime runs (all automations)
Success / FailedLifetime outcomes
TodayRuns 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.

ProblemCheck
Start disabled / background toastSettings → Automations background → Enable
Cannot edit canvasStop (background) or Interrupt (on-demand run)
No Interrupt visibleOnly shown while an On Demand run is active
Recenter dimmedAll nodes already visible — no action needed
Project not foundCreate matching project type under Projects
MQTT never firesStarted? Topic matches? Background enabled?
Duplicate runs skippedNormal — 3 s cooldown or 2 s duplicate window
BLE timeoutIncrease timeout; ensure device connected
Token unchanged in outputTypo; upstream failed; output name not set
Notify missingGrant notification permission
Join stuckAll wired branches must complete and reach Join
Runner branch isolatedExpected — use Join for shared downstream steps
[RAW DATA] in historyBy design for Raw format — use JSON when possible

Quick Reference

Controls

TriggerIdle buttonWhile active
On DemandRunInterrupt
BackgroundStartStop

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

  1. Set output variable names on every data node.
  2. Test with On Demand + Run before Start in background.
  3. Use Join when Runner branches must meet before one step.
  4. Use Interrupt to cancel a long Run (e.g. stuck on MQTT Read).
  5. Use Recenter if you panned away and lost the graph.
  6. Prefer Byte Array for known BLE characteristics.
  7. 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.

  1. Open Playground → Bluetooth Emulator.
  2. Grant Bluetooth advertise permission if prompted.
  3. Set the advertised device name.
  4. Tap Add GATT Services — pick predefined services (Heart Rate, Battery, etc.) or custom UUIDs.
  5. For each service, Add Characteristic: alias, UUID, permissions (read/write/notify/indicate), initial hex or ASCII value.
  6. Optional: Clone Device to copy GATT layout from a real peripheral.
  7. Toggle Enable to start advertising. Other phones/apps can connect and read/write characteristics.
Android limits advertisement customization: TX power, flags, and appearance may be system-controlled. Only one Service Data and one Manufacturer Data block per packet may appear due to platform limits.

NFC Tools

Read and write NDEF-formatted NFC tags. Requires NFC hardware.

Reading Tags

  1. Enable NFC in Android settings.
  2. Open NFC Tools; hold a tag to the phone's NFC antenna.
  3. Parsed records appear in a popup — tap records for actions (open URL, copy text, etc.).

Writing Tags

  1. Tap Add Record.
  2. Choose Preset or Custom mode.
  3. Preset types: Text, Website (URL), Location, Contact (vCard), Android (package name), MIME (type|data).
  4. Custom mode: set TNF, record type, ID, payload encoding (UTF-8 or hex).
  5. Stage multiple records if needed.
  6. 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.

  1. Open Ktor Server from Playground.
  2. Set the listening port (LAN IP and port are displayed for clients on your network).
  3. Add routes: method (GET/POST/PUT/DELETE/PATCH), path, optional DSL handler body.
  4. Toggle Enable — server runs as foreground service; monitor request count and uptime.
  5. Use SQL Runner to execute SQL against the server's SQLite database.
  6. 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

  1. Enter service type (e.g. _http._tcp., _mqtt._tcp., _adb._tcp.).
  2. Tap Scan; wait for progress to complete.
  3. Tap a service for host, port, address, and type details.
  4. Copy address or open HTTP URLs in browser.

LAN Port Scanner

  1. Connect to Wi-Fi; review Current network card (SSID, your IP, gateway, scan range).
  2. Tap Start to scan the subnet.
  3. Browse hosts with open ports; common services are labeled.
  4. 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.

  1. Open MITM Interceptor; note your phone LAN IP and proxy port.
  2. On the client device/app, set HTTP proxy to phone_ip:port.
  3. Tap Save CA Certificate; save the PEM file via system picker.
  4. Install CA on client: Settings → Security → Encryption & credentials → Install certificate → CA certificate.
  5. Verify SHA-256 fingerprint matches the value shown in Xiao.
  6. Toggle proxy Enable on the phone.
  7. Optionally enable HTTPS Interception (requires proxy stopped to change).
  8. Browse Captured traffic; tap entries for full request/response headers and bodies.
Certificate-pinned apps (Google, many banking apps) cannot be decrypted. HTTPS without interception is tunneled only. Use only on networks and devices you are authorized to test.

FCM Tester

Send Firebase Cloud Messaging notifications without a backend server.

  1. Open FCM Tester from Playground.
  2. Manage service accounts — import Firebase service account JSON.
  3. Select active account.
  4. Choose target mode: Token (device FCM token) or Topic.
  5. Enter notification title and body.
  6. Add optional data payload key-value pairs, or switch to raw JSON mode.
  7. 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.

Open FCM reference

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.

ADB & Remote Shell

Native ADB protocol client — no adb binary required on the phone.

Key Management

  1. Tap Manage ADB Keys.
  2. Add Key — paste RSA private key in PEM format (PKCS#1 or PKCS#8, 2048-bit, with BEGIN/END markers).
  3. 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)

  1. Switch toggle to Remote (TCP).
  2. Tap Setup Connection → Manage Devices to add target IP/host.
  3. New devices: mDNS discovers ADB port (5555 default; alternates 5554, 5556, 5558).
  4. If discovery times out, enter port manually and retry.
  5. 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

SettingDefaultDescription
Keep screen awakeDisablePrevents screen timeout during active sessions
Allow background executionEnableKeeps BLE emulator, Ktor server, and connections alive when app is minimized
Pretty print JSONEnableIndents JSON in Make Request and MITM capture detail views
Log entries limit1000Max log rows retained (minimum 100)
Clear web dataActionWipes WebView cookies, cache, HTTP auth, and form data
Clear LogsActionPermanently deletes all XiaoLogger entries
Stop all servicesActionStops BLE Emulator, Ktor Server, and background Automations foreground services
Automations backgroundDisableEnable to allow Start on background triggers (Runner, Schedule, MQTT Message, etc.)
Clear automation run historyActionDeletes run history for all automations

Bluetooth

SettingDefaultDescription
BLE scan modeBalancedBalanced saves power; Aggressive finds devices faster
RSSI representationIconShow signal as icon bars or numeric dBm value
BLE scan timeout5 secAuto-stop BLE scan after duration (min 1 sec)
BLE MTU517 bytesGATT MTU request size (min 23)
BLE auto reconnectEnableReconnect GATT after link loss
Discovery timeout12 secClassic Bluetooth device scan duration (min 5 sec)

Wi-Fi & Network

SettingDefaultDescription
Connection timeout10 secTCP/UDP socket connect timeout (min 3 sec)
Read timeout5 secWait for peer data after connect (min 1 sec)
TCP No-DelayEnableDisables Nagle algorithm for immediate small packet send
UDP buffer size64 KBReceive buffer for UDP datagrams (min 8 KB)

MQTT

SettingDefaultDescription
Force TLS/SSLDisableRequires encrypted broker connection for all MQTT projects
Keep alive60 secMQTT heartbeat interval sent to broker
Max inflight messages20Concurrent QoS 1 and 2 messages in flight
Default QoS1Default publish quality: 0=fire-and-forget, 1=at least once, 2=exactly once

Performance & Debug

SettingDefaultDescription
Verbose loggingEnableDetailed internal debug lines in Logs
Log network packetsEnableLog raw TCP, MQTT, and WebSocket payload bytes
Max concurrent connections10Cap simultaneous active network connections (min 1)
Reduce UI updatesEnableThrottle dashboard/list refresh under heavy MQTT traffic

Troubleshooting

Common problems and fixes.

Projects & Payloads

ProblemLikely causeFix
Cannot save projectMissing payload or invalid fieldsAdd payload section; fill UUIDs/topics; unique names
Import failedCorrupt or wrong fileRe-export .xiaofile from source device
Make Request spins foreverTimeout too low or device offlineIncrease timeout in Settings; check availability

Bluetooth

ProblemFix
Device not in dropdownEnable BT; increase scan timeout; use Aggressive mode; move closer
GATT connect failsVerify UUIDs; disconnect other centrals; retry with auto reconnect
Classic profiles emptyPair device in system settings first

Wi-Fi & Network

ProblemFix
IP unreachableSame subnet; correct IP; disable VPN; ping from LAN Scan
mDNS finds nothingCorrect service type suffix (_tcp.); same network; location permission
LAN scan emptyConnect Wi-Fi; wait for full scan; check firewall on targets

Playground Services

ProblemFix
MITM no HTTPS decryptInstall CA on client; not pinned app; enable interception
Ktor route 500Check DSL syntax; use SQL Runner to verify DB state
FCM send failedValid service account JSON; correct token/topic; network access
ADB unauthorizedAccept RSA fingerprint on target; correct private key loaded
Automation Start disabledEnable Settings → Automations background; grant alarm permission for schedules
Join never completesAll wired branches must finish and reach the Join node

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 UUIDService name
1800Generic Access
1801Generic Attribute
1802Immediate Alert
1803Link Loss
1804Tx Power
1805Current Time
1809Health Thermometer
180ADevice Information
180DHeart Rate
180FBattery Service
1810Blood Pressure
1811Alert Notification
1812Human Interface Device (HID)
1816Cycling Speed and Cadence
1818Cycling Power
181AEnvironmental Sensing
1822Pulse Oximeter
1826Fitness 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.

Request Tokens

TokenResolves 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

TokenResolves 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:

ButtonCommandPurpose
InterruptinterruptStop the currently running foreground shell job
ClearclearClear terminal scrollback
PwdpwdPrint working directory
LslsList directory contents
PspsList running processes
HelptoyboxList 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