Skip to main content

Test Devices

Test Devices turns real Android handsets at remote sites into a remotely-controllable test farm. From OmniWeb you can watch a phone's screen live, drive it (tap, swipe, type, hardware keys), place calls and send texts, and run scheduled health checks — VoLTE registration, signal, connectivity — whose pass/fail results are exported to Prometheus for alerting and dashboards.

← Back to Operations Guide

It exists to answer the question a NOC keeps asking about a remote cell site: "is a real phone actually working on this network right now?" — registered for VoLTE, able to call, text, and reach the internet — without anyone driving to the site.

Architecture

Each host with phones plugged in via ADB runs a lightweight agent. The agent dials out to central OmniWeb, so sites behind NAT need no inbound access. Live video uses WebRTC (UDP) so it survives lossy, high-latency links far better than TCP screen-sharing; input and test results are relayed through central.

Network paths matter. The web UI, input and call setup ("signalling") ride the control plane over HTTPS to the OmniWeb server, but the live screen video streams directly between the operator's browser and the agent host over UDP — it does not pass through the server. If a browser can reach the server but not the agent host over UDP, the console will hang on "Connecting…". See Network Requirements for the firewall rule to request and how to recognise the problem.

ComponentRole
Phone agentDiscovers ADB devices, captures the screen, injects input, runs host test scripts. One per site; installed by the device_tester Ansible role.
Central OmniWebDevice registry, WebRTC signalling relay, script dispatch, results history, Prometheus metrics.
PrometheusScrapes scheduled-test results from /api/android/metrics.

Device types

The farm is no longer phones-only. Every connected device is one of three kinds, auto-detected by the agent and shown with its own badge (and the Android robot logo for phones) in the fleet:

KindWhat it isConsole
Android phoneA normal handset (Android 5.0+ / API 21+) over ADBLive screen + full control
USB modemA cellular module exposing AT ports (e.g. Quectel EP06)AT-driven cellular console — status, calls, SMS, cell lock, VoLTE
Old-Android dongleA cheap LTE dongle running old Android (API < 21, e.g. UZ801) too old for the live-screen viewPoll-based screencap view + control
RAN Simulator UEA virtual UE from the RAN Simulator — no hardwareUE control panel — attach/detach, idle, out-of-coverage, IMS register, SMS, calls

Clicking a device opens the console appropriate to its kind. Inside any console the Swap phone button (top-right) switches to another device without going back to the fleet grid.

Simulated UEs from the RAN Simulator appear in the fleet tagged as simulators, so you can drive emulated subscribers alongside real handsets — and the Test Devices filter lets you narrow to just the RAN Simulator UEs. They use the same UE control panel shown in the RAN Simulator's own Network Map, so there is one place to attach, idle, drop out of coverage, register to IMS, and send SMS/calls. See RAN Simulator for the full UE lifecycle.

Adding a device to a site

A device joins the fleet automatically once the agent host at that site can see it over ADB. There are two steps: enable ADB on the handset, then — if the agent runs in a VM or container — pass the USB device through to it.

1. Enable ADB on the phone

  1. On the handset, open Settings → About phone and tap Build number seven times to unlock Developer options.
  2. In Settings → System → Developer options, turn on USB debugging.
  3. Plug the phone into the agent host with a data-capable USB cable.
  4. The phone shows an "Allow USB debugging?" prompt with the host's RSA key — tick Always allow from this computer and accept. (Without the tick, the prompt returns every time it re-connects and the device shows as unauthorized.)

A normal handset needs nothing more — the test scripts and live screen use only standard ADB. Keep the screen unlocked for the first connection so the prompt can be accepted.

2. Pass the USB device through to the agent host

Skip this if the agent runs on bare metal. If the agent host is a virtual machine or container, the hypervisor owns the USB port, so the device must be forwarded:

PlatformHow to forward the device
Proxmox — VMqm set <vmid> -usbN host=<bus>-<port> to bind a physical port (the mapping survives swapping phones on that port), or host=<vendor>:<product> to follow one specific device. Find the ids with lsusb on the Proxmox host.
Proxmox — LXC containerAdd to /etc/pve/lxc/<ctid>.conf: a device-cgroup allow for USB (lxc.cgroup2.devices.allow: c 189:* rwm) and a bind-mount of the USB bus (lxc.mount.entry: /dev/bus/usb/<bus> dev/bus/usb/<bus> none bind,optional,create=dir), then restart the container. Re-plugging a device onto a different bus needs the matching bus mounted.
VMwareWith the VM running, VM → Removable Devices → &lt;phone&gt; → Connect (or add a USB controller and attach the device in the VM settings).

USB modems and old-Android dongles forward the same way — they appear as the same USB device class, so a bus that's passed through carries phones, modems and dongles alike.

3. Confirm it appears

On the agent host, adb devices should list the handset as device (not unauthorized or offline). Within a few seconds it appears in the Fleet View for that site. If it doesn't, see Troubleshooting.

Fleet View

The Test Devices view lists every connected handset across all sites, grouped by site. Each card shows the model, manufacturer, Android version, screen resolution, network operator, battery, and build — at a glance you can see which phones are online and healthy.

Test Devices fleet view — phones grouped by site with model, battery and operator

The fleet groups devices by site (e.g. "Cell Site 12", "Lab North"). Each card shows live status, battery, and operator. Select phones and a script to fan a test out across them; click a card to open its console.

Labelling a device. The pencil on a fleet card opens Edit device metadata, where you can give a device a friendly name and record its operator, IMSI and MSISDN. These are operator-assigned (modern Android hides the IMSI/MSISDN from ADB) and stick to the device even when it's offline — the name is what shows in the console headers and device pickers.

The sidebar's Test Devices entry expands to show each site (with a device count), the Agents view, the script library, the scheduler and the device tools, so you can jump straight where you need.

Running tests across devices

Select one or more phones, choose a script, and Run on selected fans it out in parallel. Results stream into a table — one row per device with a pass/fail badge, exit code, duration, and expandable output.

Agents

The Agents view (sidebar → Test Devices → Agents) lists every bench connected to this server — one row per site host — with its online status, IP, the devices it carries, when it registered, and its software version. It answers "which sites are actually reporting in, and from where?" at a glance, and is where you confirm a newly-installed bench has dialed in.

Agents view — every phone bench connected to the server, with site, IP, device count, version and registration time

Device Console

Clicking a phone opens its console: a live view of the screen with full remote control.

Device console — live phone screen on a call, with hardware keys, quick actions and the cellular validation panel

The console streams the phone's screen live. Click to tap, drag to swipe, type to enter text. A network-quality badge (top-right of the screen) shows green/amber/red at a glance — click it for the full stream stats (resolution, FPS, bitrate, 5-second packet-loss %, jitter, RTT). The hardware-key bar (back, home, recents, volume, power) and quick actions (Airplane, Dialer, Messages, Settings) sit below; a tabbed tool panel — Cellular validation, Scripts, Shell, Logcat, Files and Record — is alongside.

One viewer at a time. A device streams to one operator at a time. If someone else is already viewing it, the console shows "In use by &lt;user&gt; (&lt;IP&gt;)" — the IP lets you tell whether it's you on another machine or a different operator — with a Take over button to claim the stream. A dropped or reloaded console reconnects to its own session automatically rather than fighting for it.

Remote control

ActionHow
TapClick anywhere on the screen
SwipeClick and drag
TypeClick the screen, then type on your keyboard
Hardware keysBack, Home, Recents, Volume ±, Power buttons
Quick actionsOne-click Airplane toggle, or open the Dialer, Messages or Settings app. These fire in the background — they don't run a test or block the console.

The streamed screen is the live device — any app or web page renders and is fully drivable from the console. Here a test phone has a page open in the browser, controlled remotely:

Device console — a test phone under remote control with a live web page on screen

Viewing more than one phone

To watch several handsets at once — both ends of a test call, say — open one phone's console and click View second phone (top-right). Pick another phone from the list and its live screen opens alongside the first, with its own full controls: tap/swipe/type, hardware keys, quick actions, listen-to-audio and stream stats. Add more the same way, up to four screens at once.

Device console — two phones side by side, each with its own live screen and controls, while the tool panel stays on the primary device

Each extra screen carries its own picker to swap which phone it shows and an to close it. The arrangement is captured in the page address (?with=…), so a specific multi-phone layout can be bookmarked or shared.

The tabbed tool panel (Cellular, Scripts, Shell, …) always acts on the primary phone — the one you opened — which is named in the panel header so it's clear where a script or command will run.

Console tools

Alongside the screen, a tabbed tool panel keeps the per-device tools together — switch tabs without losing each tool's state:

TabWhat it does
CellularThe call / text / ping / speedtest validation tools (below)
ScriptsRun a library script on this device and see its full run history, with a one-click re-run on any past run
ShellAn interactive command/response console for the device
LogcatLive device log stream with text + level filtering
FilesBrowse, download, upload, rename and delete files on the device
RecordCapture a tap/swipe sequence as replayable script lines

Cellular Validation panel

Built-in tools for the checks an operator runs by hand, each taking the inputs you'd expect:

ToolInputsWhat it does
CallNumber, hold timeDials, confirms the call goes off-hook, holds, hangs up
TextNumber, messageSends an SMS and confirms it left the device
PingHost, countPings a host over the device's data connection
SpeedtestTest URLMeasures download throughput over the device's data link

The Number box remembers numbers you've recently called or texted (kept in your browser only, not on the server) and offers them as a dropdown, so re-dialling a test number is a click.

Scripts

The Scripts tab runs any library script against this one device and keeps its full run history — filterable by source, status and test — without leaving the console. Every past run has a re-run button, so repeating a check (or a script that just failed) is one click; scripts that take inputs re-prompt for them.

Device console — Scripts tab: run a library script and the device&#39;s run history, each row with a re-run button

Shell

The Shell tab is an interactive command/response console for the device — type a command, see its output and exit code, with ↑/↓ to recall history. It's the device analogue of the modem AT console, for the times a quick command is faster than writing a script.

Device console — Shell tab: an interactive device command console with output and exit codes

Logcat

The Logcat tab streams the device's live system log. Filter by free text and minimum level (Verbose → Fatal); levels are colour-coded. Start/Stop controls the stream, and stopping keeps what you've captured on screen so you can scroll back through it.

Device console — Logcat tab: live colour-coded device log stream with text and level filters

Files

The Files tab is a file manager for the device. Browse directories (starting at /sdcard), download a file to your machine, upload a file to the device, and rename, delete or create folders. Useful for pulling a capture or diagnostic file off a device, or pushing a config onto it.

Device console — Files tab: device file browser with download, upload, rename and delete

Gesture recording

Toggle Record, perform a tap/swipe sequence on the screen, and the console emits the equivalent adb input lines. Paste them into a folder script to turn a manual UI flow into a repeatable test.

USB Modem console

A USB cellular modem (Quectel EP06 and similar) appears in the fleet as a modem and opens a cellular console instead of a screen. AT commands are relayed agent → modem over its serial (AT) port; every command and response is logged to the Terminal tab as an audit trail.

TabWhat it does
StatusOne-shot read of model / firmware / IMEI / IMSI / SIM, signal (CSQ + per-RAT QCSQ), operator, EPS registration, attach, IMS, IP, APN, DNS/PCO
ActionsSet APN (preset or custom, with PDP / IP type), attach/detach data, show IP + DNS, ping, send SMS, radio (airplane / reboot)
NetworksOperator scan (AT+COPS=?) and a serving/neighbour cell measurement (AT+QENG) → EARFCN / PCI / band / RSRP / RSRQ / SINR table
Cell lockLock to a specific EARFCN (+PCI) (AT+QNWLOCK), band lock (AT+QCFG="band"), RAT preference, or release back to auto
CallsDial / answer / hang up, an AT+CLCC call table, and an Enable / Disable VoLTE control (AT+QCFG="ims")
SMSRead the inbox (AT+CMGL), delete, and send
EventsEnables the relevant URCs and polls them into a timestamped log (registration / call / signal / new-SMS changes)
TerminalRaw AT entry plus the full request/response log

The full AT-command reference, with real EP06 responses, is in modem-at-commands.md.

VoLTE: the EP06 is VoLTE/IMS-only for voice. Enable VoLTE sets AT+QCFG="ims",1; an AT+CFUN=1,1 reboot may be needed to (de)register IMS, and it only registers if the network + SIM provision it and the correct carrier MBN is selected.

Old-Android dongles (screencap mode)

Cheap ~$10 LTE "MiFi" dongles (e.g. the UZ801, Qualcomm msm8916) run Android 4.4 (API 19), which is too old for the live-screen view. These devices fall back to a screencap console: the agent polls adb screencap for frames (a few per second — screencap itself is the bottleneck on this hardware) and injects adb input for control. You get a click-to-tap, type-to-text view — not smooth video, but enough to drive it.

The agent smooths over the rough edges of these dongles on the host side:

  • ADB unlock — they ship in RNDIS mode; a udev-triggered service curls the dongle's usbdebug.html to switch it into ADB mode. See agent/host-setup/mifi-dongle.
  • Auto-English — they ship in Chinese; the agent sets persist.sys.language to en-US the first time it sees an API-<21 device (disable with OMNIWEB_DONGLE_AUTO_ENGLISH=0).

Programmatic control (MCP)

The same device-control stack is exposed as an MCP server, so an MCP client (Claude, scripts) can drive the farm: list_devices, screenshot, tap / swipe / input_text / key, adb_shell, list_scripts / run_script, and modem at_command / send_sms. It wraps the /api/android/* API and is bearer-token gated. Setup and the claude mcp add … command are in mcp/README.md.

Scripts

Tests are bash scripts that run on the agent host (so host tools like grep/awk are available) and target a device via ADB. There are two kinds:

  • Folder scripts — no-argument health checks, run with just the device. These appear in the library, the fan-out runner, and the scheduler. Examples: Device Connected, VoLTE Registration, Report Signal Strength, Toggle Airplane Mode.
  • Built-in tools — the parameterised UI tools (Call, Text, Ping, Speedtest) driven from the Cellular Validation panel. They take inputs and are not part of the library or scheduler.

Script library — folder health checks with descriptions and timeouts; click to view source

The script library lists the no-argument folder scripts. Each shows its description and timeout; click one to view its source (read-only). Recent runs appear below.

A script reports its result by exit code0 is a pass, anything else a fail — and its captured output is shown in the results table.

Scheduled Tests

Scheduled tests are defined declaratively in schedules.json in the scripts directory. The file is re-read on every cycle, so edits take effect without a restart. Each entry runs a folder script against its target devices on an interval.

Configuration

{
"schedules": [
{
"name": "VoLTE Registration",
"script": "volte_registration.sh",
"interval_seconds": 120,
"serials": [],
"enabled": true
}
]
}
ParameterTypeRequiredDefaultDescription
nameStringYes-Unique label for the schedule. Appears as the schedule label on the exported metric.
scriptStringYes-Filename of a folder script in the scripts directory to run.
interval_secondsIntegerNo300How often to run the script, in seconds. Minimum 30.
serialsListNo[]Device serials to target. An empty list means all currently-connected devices, so the schedule auto-follows whatever phones are plugged in.
enabledBooleanNotrueWhether the schedule is active. Set false to pause it without removing the entry.

Example: VoLTE check across a site

{
"name": "VoLTE Registration",
"script": "volte_registration.sh",
"interval_seconds": 120,
"serials": [],
"enabled": true
}

How it works: Every 120 seconds the scheduler runs volte_registration.sh against every connected phone. The script checks the device is voice-registered (IN_SERVICE) on LTE with VoPS (Voice-over-PS) support, and exits 0 if VoLTE is registered. The result becomes a Prometheus gauge per device.

Use case: Continuously prove that real handsets at a site can register for VoLTE, and alert the moment one can't.

Metrics

Central OmniWeb exposes the latest result of each scheduled test, per device, in Prometheus format at /api/android/metrics. Prometheus scrapes it as the android_device_tests job (configured automatically by the monitoring role).

Metric: omniweb_android_test_pass Type: Gauge Description: Result of the most recent scheduled run — 1 for pass, 0 for fail Labels:

  • phone — device model (e.g. SM-A536E)
  • serial — device serial number
  • site — the agent's site label (e.g. Cell Site 12)
  • agent — the agent host the device is attached to
  • script — the script that ran
  • schedule — the schedule name

Companion gauges share the same labels:

MetricDescription
omniweb_android_test_return_codeExit code of the last run
omniweb_android_test_duration_msDuration of the last run, in milliseconds
omniweb_android_test_last_run_timestamp_secondsUnix time of the last run

Example queries:

# Phones currently failing VoLTE registration
omniweb_android_test_pass{script="VoLTE Registration Status"} == 0

# Failing tests grouped by site
count by (site) (omniweb_android_test_pass == 0)

# A test that hasn't run recently (stale agent or device offline)
time() - omniweb_android_test_last_run_timestamp_seconds > 600

Troubleshooting

A phone doesn't appear in the fleet

Symptoms: A device is plugged in at a site but isn't listed under Test Devices.

Possible causes:

  • The phone isn't authorised for ADB on the agent host
  • The agent isn't running or can't reach central
  • The phone is in an offline/unauthorised ADB state
  • The central Test Devices service isn't running (Test Devices is served by its own dedicated backend service, separate from the main request pool)

Resolution:

  1. Confirm the phone shows as device (not unauthorized/offline) in ADB on the agent host, accepting the RSA prompt on the handset if needed.
  2. Check the agent service is running and that its configured central URL and token are correct.
  3. On central, confirm the Test Devices service is running and that the gateway routes /api/android/* to it. If the agent registered but the fleet is empty, this service is the usual cause.
  4. Verify the phone's USB connection; re-seat the cable if it shows as offline.

The console screen stays on "Connecting"

Symptoms: The device console opens but the screen never appears, while the rest of the UI — fleet list, device details, input — works normally and the device shows online.

Possible causes:

  • UDP is blocked between the browser's network and the agent host (the live video streams directly browser → agent host, not via the server — by far the most common cause)
  • The agent can't start screen capture on that handset

This is not an SSL or MTU problem: TLS is proven working (the UI loaded), and with MTU issues the video would connect and then tear rather than never starting. The tell-tale sign is a device that shows online in the fleet yet whose live view alone won't start.

Resolution:

  1. Confirm the browser's network can reach the agent host over UDP (the video path). This usually means a firewall/VLAN rule permitting the operator's subnet to the bench hosts over UDP — see Network Requirements for the exact rule to request and how to confirm the fix.
  2. Check the agent log for screen-capture errors; some handsets can't have their screen captured over ADB.

VoLTE / signal checks report "not readable"

Symptoms: VoLTE or signal scripts fail with the telephony state unreadable.

Possible causes:

  • The handset restricts telephony status to privileged access

Resolution:

  1. Use test handsets that expose telephony status to ADB. Vendor-locked consumer devices may hide it without privileged access.