Commands Reference
Home > 3rd-Party Integration > Commands Reference
Commands Reference
The full set of commands a client can send over the Command characteristic, organized by category. For each command this page documents the wire format, the expected RSP, and any DATA records the device emits while the operation is running.
Start anywhere, stop universally. Every long-running scan and attack is stopped with the same command:
CMD:stopscan:. Every command receivesRSP:<command>:OKwithin 100 ms whether or not the operation has actually begun. TreatRSPas “accepted” and watchSTATUS:for the real state change. See GATT Reference for the full message-framing rules.
Conventions
Every command follows the same wire format:
CMD:<command>:[param=value[,param=value...]]
The trailing colon after the command name is always present, even when no parameters are supplied (CMD:stopscan:). Multi-value parameters use semicolons inside the value to separate entries (targets=AA:BB:CC:DD:EE:FF,6;11:22:33:44:55:66,11).
Typical reply flow for a long-running command:
-> CMD:<command>:...
<- RSP:<command>:OK (within 100 ms)
<- STATUS:2:<text> (operation actually begins)
<- DATA:... (live records, if applicable)
<- STATUS:1:Ready (after CMD:stopscan: or natural end)
A RSP:<command>:ERROR[:reason] instead of OK means the command was rejected. The reason text, when present, describes why.
Firmware Updates
Current release manifests live at
https://firmware.biscuitshop.us/<product>/<Prod|Beta>/manifest.json. Each
firmware entry includes size, the exact byte length of its OTA application
.bin, and sha256, the lowercase SHA-256 of those exact bytes. Neither value
describes the merged factory image. Treat missing or malformed integrity fields
as a non-installable release.
Read the Status characteristic before constructing an OTA command. When it
contains "otaProtocol":3, use standard RFC 4648 Base64 for both credential
fields and include the update mode:
CMD:ota:start3,<ssidBase64>,<passwordBase64>,<prod|beta>,<normal|force>
An open network is represented by an empty password field. SSIDs must contain 1–32 UTF-8 bytes; passwords must be empty, 8–63 UTF-8 bytes, or exactly 64 hexadecimal characters. Base64 safely preserves commas and leading or trailing spaces.
Use normal for an ordinary update. Use force only for an explicit reflash;
it bypasses the same-version shortcut but retains every integrity, image,
read-back, boot-health, and rollback check.
| Field | Value |
|---|---|
| RSP | RSP:ota:OK when accepted |
| Progress | OTA:STATUS:<stage> notifications |
| Completion | Reconnect, then verify the expected target revision and running partition |
Send CMD:ota:cancel: to cancel an update before its verified boot partition
has been committed. An accepted cancellation replies RSP:ota:OK:cancel, then
emits c5_error:cancelled, wroom_error:cancelled, or
wroom_uart_error:cancelled as the OTA:STATUS: stage. An idle or too-late
cancellation replies RSP:ota:ERROR:not_cancellable on Pro/Ultra. A single-chip
C5 can accept a late cancellation only if it safely restores the running slot;
otherwise it replies RSP:ota:ERROR:committed.
When Status reports "otaProtocol":2, use
CMD:ota:start2,<ssidBase64>,<passwordBase64>,<prod|beta>. If otaProtocol is
absent, the backward-compatible form is
CMD:ota:start,<ssid>,<password>[,beta]. Use it only for a nonempty password
and credentials without commas, control characters, or leading/trailing spaces;
otherwise tell the user that the older firmware cannot represent that network.
Keep the UI in Verifying through each installed chip’s reboot boundary. WROOM
and single-chip C5 installs require BLE reconnection; a Pro/Ultra C5 can be
verified with fresh reads over the uninterrupted WROOM BLE connection. For each
chip that performed a real install, require the expected new slot when the
pre-update partition was reported. If it was not reported, require a valid
post-boot ota_0 or ota_1 value rather than guessing one. When
lastOtaResult is present, wait for success; running means the new image is
still completing its first-boot health gate, which requires 30 continuous
healthy seconds.
For protocol v3, c5_complete or wroom_complete without the matching no-op
signal means a real install occurred. Require fresh partition and health-success
proof even when a separately fetched manifest suggested no version change.
Public OTA progress notifications use these stable shapes:
| Stage | Notifications |
|---|---|
| C5 update | c5_connecting, c5_retrying_start:<attempt>/<total>, c5_downloading, c5_retrying_manifest, c5_installing[:percent], c5_retrying_download[:detail], c5_already_current, c5_complete, c5_error:<code> |
| WROOM direct | wroom_connecting, wroom_wifi_retry:<attempt>/<total>, wroom_downloading, wroom_retrying_manifest[:detail], wroom_installing[:percent], wroom_retrying_download[:detail], wroom_already_current, wroom_direct_error:<code>, wroom_error:<code> |
| WROOM recovery | wroom_uart_fallback_starting, wroom_uart_fetching[:percent], wroom_uart_retrying:<phase>:<attempt>, wroom_uart_downloading[:percent], wroom_uart_installing, wroom_complete, wroom_uart_error:<code> |
Control failures can appear as error:busy, error:boot_verifying, or
error:timeout on Pro/Ultra; single-chip firmware prefixes its OTA failures as
c5_error:<code>. wroom_direct_error:<code> announces a recoverable direct
failure before recovery starts; wroom_error:<code> is terminal. Preserve the
exact stage string for support diagnostics.
For a normal protocol-3 request, c5_already_current is the C5 no-op terminal.
A single-chip client should finish without waiting for a reboot or partition
change; a Pro/Ultra client continues into its WROOM phase.
wroom_already_current similarly proves that no WROOM reboot is expected.
Older command forms may receive a compatibility completion after the explicit
no-op, but clients must treat *_already_current itself as terminal. A force
request performs a real install even when the version matches. Keep the exact
target version shown by the client; if the currently reported version differs,
report manifest drift because the channel moved between fetches.
Stable C5 network codes include wifi_radio_init, wifi_ssid_not_found,
wifi_authmode_unsupported, wifi_auth_failed, wifi_assoc_failed,
wifi_dhcp_timeout, wifi_disconnected, and wifi_captive_portal. Preserve
unknown lower-snake-case codes in diagnostics; other terminal codes identify
the failed manifest, download, image-validation, read-back, or boot-selection
stage.
WiFi Scanning
WiFi scans stream DATA: records as networks, stations, and frames are observed. Each scan is started with the listed command and stopped with CMD:stopscan:.
Access-point scan
CMD:scanap:
| Field | Value |
|---|---|
| RSP | RSP:scanap:OK |
| STATUS | STATUS:2:Scanning... |
| DATA | DATA:AP:SSID,BSSID,Channel,RSSI,Security |
Security is required and reports the network’s security type. Possible values: [OPEN], [WEP], [WPA_PSK], [WPA_ENTERPRISE], [WPA2_PSK], [WPA_WPA2_PSK], [WPA2_ENTERPRISE], [WPA3_PSK], [WPA3_ENTERPRISE], [WPA2_WPA3_PSK], [WPA2_WPA3_ENTERPRISE], [OWE], [WAPI_PSK], [UNDEFINED]. Personal and Enterprise remain distinct, and mixed tokens identify transition modes. OWE is encrypted, password-free Wi-Fi; ordinary open networks always include [OPEN]. Reject missing, empty, or incomplete bracketed security, and preserve complete unfamiliar bracketed tokens. Cipher details are not included in these labels.
Station scan
CMD:scansta:
Discovers stations associated with previously-scanned APs. Run scanap first.
| Field | Value |
|---|---|
| RSP | RSP:scansta:OK |
| DATA | DATA:STA:ClientMAC,ConnectedBSSID,Channel,RSSI |
Combined AP and station scan
CMD:scanall:
Emits both DATA:AP: and DATA:STA: records on the same stream.
Probe-request sniff
CMD:sniffprobe:
| Field | Value |
|---|---|
| DATA | DATA:PROBE:ClientMAC,RequestedSSID,Channel,RSSI |
Empty RequestedSSID indicates a broadcast probe.
Beacon sniff
CMD:sniffbeacon:
| Field | Value |
|---|---|
| DATA | DATA:BEACON:SSID,BSSID,Channel,RSSI,Security |
Deauth sniff
CMD:sniffdeauth:
| Field | Value |
|---|---|
| DATA | DATA:DEAUTH:SourceMAC,DestMAC,BSSID,Channel,RSSI,Type |
Type is deauth or disassoc. Broadcast destination FF:FF:FF:FF:FF:FF typically indicates an active attack.
Packet statistics
CMD:packetcount:
| Field | Value |
|---|---|
| DATA | DATA:STATS:Beacons,Probes,Deauths,Data,EAPOL,MinRSSI,MaxRSSI |
Updates every five seconds. Counters are cumulative since the scan started.
Pwnagotchi detection
CMD:sniffpwn:
| Field | Value |
|---|---|
| DATA | DATA:PWN:Name,MAC,Channel,RSSI,Identity,Pwnd |
Identity is the literal string pwnagotchi; Pwnd is the network-capture count the device claims.
Pineapple detection
CMD:sniffpinescan:
| Field | Value |
|---|---|
| DATA | DATA:PINE:SSID,MAC,Channel,RSSI,DetectionType |
DetectionType: SUSP_OUI, TAG+SUSP_CAP, or OTHER.
Channel analyzer
CMD:channelanalyze:
| Field | Value |
|---|---|
| DATA | DATA:CHANACT:... |
Channel-activity samples emitted every 500 ms.
WiFi Attacks
All WiFi attacks share CMD:attack:type=<attack>[,...], return RSP:attack:OK, and emit DATA:ATTACK:<type>,PacketsSent,TargetCount,DurationSeconds every two seconds while running. Stop with CMD:stopscan:.
Deauthentication
CMD:attack:type=deauth,mode=<basic|targeted|manual>,targets=<list>
| Mode | Target format (one entry; semicolons separate multiple) |
|---|---|
basic |
BSSID,Channel. Broadcasts deauth to the AP. |
targeted |
StationMAC,APBSSID,Channel. Deauths a specific station. |
manual |
SourceMAC,DestMAC,Channel. Custom source and destination. |
Maximum 25 targets per command. Band is inferred from channel (1-14 = 2.4 GHz, 36+ = 5 GHz); mixed-band lists are allowed.
DATA: DATA:ATTACK:deauth,PacketsSent,TargetCount,DurationSeconds
Beacon spam
CMD:attack:type=beacon,mode=<random|list|aplist|funny>[,ssids=SSID1;SSID2;...]
| Mode | Behavior |
|---|---|
random |
Continuously generated random SSIDs |
list |
Broadcasts the SSIDs in the ssids parameter |
aplist |
Clones the SSIDs in the ssids parameter |
funny |
Built-in humorous SSID list |
If an SSID contains a comma, replace it with _ before sending.
DATA: DATA:ATTACK:beacon,BeaconsSent,SSIDCount,DurationSeconds
Rick Roll
CMD:attack:type=rickroll
Beacon spam with built-in Rick Astley lyrics as SSIDs. DATA matches beacon spam with SSIDCount=8.
Probe-request spam
CMD:attack:type=probe,targets=SSID,BSSID,Channel;SSID,BSSID,Channel;...
DATA: DATA:ATTACK:probe,ProbesSent,TargetCount,DurationSeconds
Bad message
CMD:attack:type=badmsg[,targeted=true],targets=StationMAC,APBSSID,Channel,APSSID;...
Sends malformed association frames. targeted=true marks targets explicitly; default is broadcast to all provided stations.
DATA: DATA:ATTACK:badmsg,PacketsSent,TargetCount,DurationSeconds
Association sleep
CMD:attack:type=sleep[,targeted=true],targets=StationMAC,APBSSID,Channel,APSSID;...
Sends association frames with power-management flags to force stations into power-saving mode. Same parameter shape as badmsg.
DATA: DATA:ATTACK:sleep,PacketsSent,TargetCount,DurationSeconds
Bluetooth Scanning
All BT scans return RSP:sniffbt:OK (or RSP:sniffskim:OK) followed by STATUS:2:Scan started: <type>. Stop with CMD:stopscan:.
General BT discovery
CMD:sniffbt:type=all
The type parameter may be omitted (CMD:sniffbt: is equivalent).
| Field | Value |
|---|---|
| DATA | DATA:BT:DeviceName,MAC,RSSI,Type[,PayloadHex][,SF=XX] |
Type is BLE, Classic, or Unknown. Current firmware may append a nonzero SF=XX BLE-family hint. When no payload is present, an empty fifth field comes before the hint, for example DATA:BT:Popup,MAC,-62,BLE,,SF=01. The bit definitions and parser guidance are in Wardrive Integration.
AirTag scan
CMD:sniffbt:type=airtag
| Field | Value |
|---|---|
| DATA | DATA:BT:AirTag,MAC,RSSI,BLE,PayloadHex[,SF=XX] |
PayloadHex is the 22-byte public-key advertisement that uniquely identifies the AirTag across MAC rotations. Store this if you intend to spoof the AirTag later.
Flipper Zero scan
CMD:sniffbt:type=flipper
| Field | Value |
|---|---|
| DATA | DATA:BT:FlipperName,MAC,RSSI,BLE |
Flock scan
CMD:sniffbt:type=flock
| Field | Value |
|---|---|
| DATA | DATA:BT:FlockName,MAC,RSSI,BLE |
For the full Flock classification surface (including 2.4 GHz Wi-Fi-side matches), use CMD:wardriveall: instead. See Wardrive Integration.
Flock IE-fingerprint scan
Available on C5 firmware 1.5.8+; dual-radio models also require WROOM 1.5.7+.
CMD:flocksig:require_oui=<true|false>,band=<2.4|5|both>,full_sweep=<true|false>
| Field | Value |
|---|---|
| Response | RSP:flocksig:OK or RSP:flocksig:ERROR,<reason> |
| DATA | DATA:FLOCKSIG:MAC,RSSI,Channel,Method,FY1 |
All arguments are mandatory and invalid input leaves the current scan running. WIE4 means exact IE signature plus curated prefix; relaxed mode also emits non-prefix exact matches as experimental WIEC candidates. This isolated stream is not part of legacy Flock storage, reports, exports, rewards, notifications, or Node routing. Stop it with CMD:stopscan:. See Wardrive Integration for schedules and interpretation.
wardriveall also has an optional binary wardrive stream (opt-in) on a dedicated characteristic for higher throughput; the default remains the text DATA:* stream. See Binary wardrive (opt-in).
Credit-card skimmer scan
CMD:sniffskim:
| Field | Value |
|---|---|
| DATA | DATA:BT:SkimmerSignature,MAC,RSSI,Type |
Matches known Bluetooth modules commonly used in skimming devices (HC-05, HC-06, etc.).
Bluetooth Attacks
All BT attacks share CMD:attack:type=bt_<variant>, return RSP:attack:OK followed by STATUS:2:Attack started: bt_<variant>, and emit DATA:ATTACK:bt_<variant>,PacketsSent,VariantCount,DurationSeconds every two seconds. Stop with CMD:stopscan:.
| Command | Target / behavior |
|---|---|
CMD:attack:type=bt_apple |
Spoofs Apple Continuity adverts (iOS pairing popup spam) |
CMD:attack:type=bt_windows |
Spoofs Windows Swift Pair adverts |
CMD:attack:type=bt_samsung |
Spoofs Samsung pairing adverts |
CMD:attack:type=bt_google |
Spoofs Google Fast Pair adverts (Android) |
CMD:attack:type=bt_flipper |
Spoofs Flipper Zero adverts |
CMD:attack:type=bt_all |
Cycles through all five variants on a single dwell timer |
AirTag spoof
CMD:attack:type=bt_airtag,payload=<PayloadHex>
Alternate identifiers:
| Parameter | Use |
|---|---|
payload=<hex> |
Preferred. The 22-byte public key captured from a prior AirTag scan; works across MAC rotations |
mac=AA:BB:CC:DD:EE:FF |
Looks up the payload by MAC in the device’s last-scan list |
target=<index> |
Legacy index into the last-scan list |
payload takes priority over mac, which takes priority over target.
DATA: DATA:ATTACK:bt_airtag,PacketsSent,1,DurationSeconds
Evil Portal
The evil-portal surface manages a small library of captive-portal HTML files stored on the device, runs the portal attack, and streams captured credentials in real time.
List local portals
CMD:portallist:
| Field | Value |
|---|---|
| RSP | RSP:portallist:OK |
| DATA | DATA:PORTALLIST:{"portals":[{"name":"...","file":"...","size":...},...]} |
Fetch remote manifest
CMD:portalremote:ssid=<wifi>,password=<password>
Connects to the named Wi-Fi network and downloads the manifest of portals available on the upstream server.
| Field | Value |
|---|---|
| RSP | RSP:portalremote:OK or RSP:portalremote:ERROR:WiFi connection failed |
| DATA | DATA:PORTALLIST:{"files":[{"name":"...","filename":"..."},...]} |
Download a portal
CMD:portaldownload:ssid=<wifi>,password=<password>,file=<Filename.html>
| Field | Value |
|---|---|
| RSP | RSP:portaldownload:OK |
| STATUS | STATUS:2:Connecting to WiFi..., then STATUS:3:Portal downloaded |
Possible errors: WiFi connection failed, Portal not found on server, Storage full, Portal exceeds 30KB limit.
Delete a portal
CMD:portaldelete:file=<Filename.html>
RSP:portaldelete:OK or RSP:portaldelete:ERROR:Delete failed.
Start the attack
CMD:portalstart:ssid=<SSID>,bssid=<BSSID>,channel=<n>,file=<Filename.html>[,deauth=true]
| Parameter | Use |
|---|---|
ssid |
SSID the fake AP will broadcast |
bssid |
Target AP for the optional deauth |
channel |
Wi-Fi channel to operate on |
file |
Portal HTML file (must already be present locally) |
deauth |
When true, deauths clients off the target AP to drive them toward the fake one |
| Field | Value |
|---|---|
| RSP | RSP:portalstart:OK |
| STATUS | STATUS:2:Evil Portal active |
Possible errors: Missing file parameter, Portal not found.
Stop the attack
CMD:portalstop:
RSP:portalstop:OK.
Captured credentials
CMD:portalcreds:
| Field | Value |
|---|---|
| RSP | RSP:portalcreds:OK |
| DATA | One DATA:CRED:portal_file,email,password line per stored entry |
Captured credentials also arrive in real time as a victim submits a form. A DATA:CRED: line is emitted immediately whether or not the client has issued portalcreds.
Clear captured credentials
CMD:portalclearcreds:
RSP:portalclearcreds:OK or RSP:portalclearcreds:ERROR:Clear failed. Storage cap is 100 entries, FIFO. Oldest entries are evicted automatically.
Reset saved phone bonds
CMD:bondclearall:
Returns RSP:bondclearall:OK or RSP:bondclearall:ERROR. After OK, the Biscuit waits about 500 ms so the reply can arrive, disconnects, and resumes advertising without rebooting.
This clears every phone bond stored on the Biscuit. A BLE app cannot reliably remove the matching phone-side bond, so tell the user to forget the Biscuit in Bluetooth Settings before explicitly connecting again.
Universal stop
CMD:stopscan:
Stops any running scan, attack, wardrive, or evil-portal session.
| Field | Value |
|---|---|
| RSP | RSP:stopscan:OK |
| STATUS | STATUS:1:Ready (lands a few hundred ms after RSP) |
Treat STATUS:1:Ready as the actual “operation finished” signal. Buffered DATA: records may still arrive between the RSP and the STATUS.