Skip to main content

BLE Provisioning Protocol

Admiral OS uses Bluetooth Low Energy for out-of-box device setup and, once a device is claimed, for cloud-authorised field service (§4.11). The dashboard's Provision over Bluetooth and Repair over Bluetooth pages implement this protocol in the browser. This page covers the full provisioning protocol — advertising, GATT service and characteristic definitions, the provisioning state machine, security model, error codes, and implementation notes for both firmware and mobile clients.

Open for setup, sealed after claim

An unclaimed device accepts any setup session (protected by an on-screen pairing code on devices with a display). Once a device is claimed it no longer accepts open sessions: every capability requires a short-lived, session-bound access token issued by Admiral Cloud and verified on the device, offline (§4.11). A claimed device that has not received verification keys from the cloud does not advertise at all.


1. Overview​

The provisioning protocol allows a mobile companion app to:

  1. Discover one or more unconfigured Admiral devices in proximity.
  2. Identify a specific physical device via LED and on-screen pairing animation.
  3. Configure Wi-Fi and/or Ethernet credentials (individually or in batch across 10+ devices).
  4. Monitor multi-interface network connection status in real time.
  5. Retrieve a cloud-issued pairing key for account association.
  6. Read device metadata (firmware version, serial number, hardware revision).

Design Principles​

PrincipleDescription
Sealed After ClaimOpen setup is available only while unclaimed. After the claim, access needs a cloud-issued token bound to the session (§4.11). Factory reset returns the device to open setup.
Multi-device BatchingA mobile app can discover 10+ devices, push the same Wi-Fi config to all of them, and asynchronously harvest their pairing keys.
Stateless MobileThe mobile app does not persist BLE connection state. Admiral devices are the source of truth.
Minimal MTUPayloads fit within a 512-byte ATT MTU, falling back to 23-byte MTU with chunked transfers if needed.
Secure LinkAll sensitive data (Wi-Fi passwords, pairing keys) is protected via application-layer X25519 ECDH key exchange and AES-GCM encryption.

2. BLE Advertising & Discovery​

2.1 Advertising Modes​

Admiral devices advertise over BLE only when unprovisioned or when an error occurs before final setup completes.

ModeWhen ActiveIntervalConnectableNotes
SetupFactory reset / first boot / no Wi-Fi config100 msYesEnters power-save after 30 min; wakes on button press. With TimeoutMode enabled, drops advertisement after 1 min with no peers or 5 min of connection inactivity.
ConfiguringWi-Fi credentials received, device connecting200 msYesContinues advertising state changes.
ErrorWi-Fi connected but cloud unreachable, etc.150 msYesAllows mobile app to reconnect and correct the network config.
ServiceClaimed, holding cloud verification keysOnYesField service only; every session must authenticate with an access token (§4.11). Off if service mode is disabled or no keys have been received.

2.2 Advertising Packet (ADV_IND — 31 bytes)​

MAC Address: To avoid duplicate OUI collisions common in bulk generic microcontrollers, the device overrides the controller's primary physical MAC on boot with a Locally Administered Address (LAA) starting with 0x0A. The remaining 5 bytes are populated from a SHA-256 fingerprint of the true hardware serial number.

OffsetLengthTypeFieldValue
030x01Flags0x06 (LE General Discoverable)
340x0316-bit Service UUID0xFDA0
7140xFFManufacturer DataSee §2.3
21120x08Short Local NameUTF-8 (e.g., ADM-QWERT123)
UUID Short Form

The advertisement broadcasts the 16-bit short UUID 0xFDA0. The full 128-bit GATT service UUID is A0FD0001-C2E1-4F9C-8D2A-0B6C3E4D5F60 — 0xFDA0 is the little-endian byte-reversed form of the A0FD prefix. Mobile clients must use the full 128-bit UUID when discovering and connecting to GATT characteristics.

2.3 Manufacturer Specific Data (9 bytes payload)​

Byte 0: Protocol Version — 0x01
Byte 1: Device Type — 0x01 (Standard), 0x02 (Pro)
Byte 2: Provisioning State — See §2.4
Byte 3: Capability Flags — Bitmask (Bit 3: LED, Bit 4: Display Framebuffer)
Byte 4–7: Device ID Hash — Last 4 bytes of SHA-256(hardware serial number)
Byte 8: Reserved — 0x00

The 2-byte Company Identifier is transmitted as a separate BLE Manufacturer Data header field and is not included in the 9-byte payload above.

2.4 Provisioning State Byte​

ValueStateDescription
0x00UNPROVISIONEDReady for setup. BLE active.
0x01WIFI_CONFIGUREDCredentials received, attempting to connect.
0x02WIFI_CONNECTEDConnected to Wi-Fi. Resolving cloud connection.
0x03CLOUD_PAIREDPairing key received from cloud, waiting for mobile confirmation.
0x04FULLY_PROVISIONEDMobile confirmed registration. BLE advertising shuts down.
0xFFERRORSetup failed. Check Error characteristic (§4.10).

3. Provisioning State Machine​

The provisioning lifecycle ensures the device can safely traverse from unconfigured to cloud-paired without getting stuck.

Organic Connections: The Admiral OS runs a background daemon monitoring active network interfaces. If an Ethernet cable is attached, or a previously saved Wi-Fi network reconnects organically during the setup loop, the device asynchronously advances to WIFI_CONNECTED (0x02) and then CLOUD_PAIRED (0x03), pushing notifications to the mobile app. The mobile app must listen for state notifications and dynamically skip the Wi-Fi configuration UI if the device is already online.

State Transitions​

FromToTrigger
UNPROVISIONEDWIFI_CONFIGUREDMobile writes Wi-Fi credentials via Network Config characteristic
UNPROVISIONEDWIFI_CONNECTEDOrganic Ethernet or saved Wi-Fi connects
WIFI_CONFIGUREDWIFI_CONNECTEDSuccessful Wi-Fi authentication and DHCP lease
WIFI_CONNECTEDCLOUD_PAIREDAdmiral Cloud issues ephemeral pairing key
CLOUD_PAIREDFULLY_PROVISIONEDMobile writes COMPLETE to Prov Control characteristic
AnyERROR (0xFF)Authentication failure, DHCP timeout, cloud unreachable
FULLY_PROVISIONEDUNPROVISIONEDPhysical factory reset (10-second pinhole button hold)

Re-entering Setup​

  1. Physical Factory Reset: Holding the pinhole reset button for 10 seconds clears all saved configurations (Wi-Fi credentials under /admrl/conf/, custom local settings). The device rolls back to UNPROVISIONED and restarts BLE advertising on next boot.
  2. Setup Mode Recovery: If pairing is aborted or fails before full provisioning, the system remains in or reverts to setup mode and re-initializes the setup-mode BLE advertisement automatically.

4. GATT Service & Characteristic Definitions​

4.1 Services​

#Service NameUUIDType
1Generic Access0x1800Standard BLE
2Admiral ProvisioningA0FD0001-C2E1-4F9C-8D2A-0B6C3E4D5F60Custom Primary

4.2 Characteristics​

Base UUID: A0FD????-C2E1-4F9C-8D2A-0B6C3E4D5F60

NameShort UUIDPropertiesSecurityDescription
Device State0010Read, NotifyEncryptedCurrent provisioning and network status.
Command0011WriteEncrypt+AuthSend commands (Identify, Scan Wi-Fi, etc.).
Cmd Response0012Read, NotifyEncrypt+AuthResponses to commands, chunked.
Network Config0020WriteEncrypt+AuthPush SSID / password / IP settings / link type.
Network Status0021Read, NotifyEncryptedCurrent interface state (IP, link type, label).
Wi-Fi Scan0022Read, NotifyEncryptedPaginated list of discovered SSIDs.
Pairing Key0030Read, NotifyApp-EncryptedEphemeral token from the Admiral Cloud.
Prov Control0040WriteEncryptedSession lifecycle (Start, Complete, Abort).
Session PubKey0050ReadNoneDevice's ephemeral X25519 public key.
Access Info0052ReadNoneWhether the device is open or claimed, its device ID (claimed only) and a per-session challenge. See §4.11.
Access Token0080WriteEncryptedA cloud-issued access token (claimed devices). See §4.11.
Service Request0081WriteEncryptedAuthenticated service commands (claimed devices).
Service Response0082Read, NotifyEncryptedResponses to service commands and the access result.
Error Info00F0Read, NotifyEncryptedDetailed error domains, codes, and messages.
note

All Notify characteristics require the client to write 0x0001 to the CCCD descriptor 0x2902.


4.3 Device State — A0FD0010​

20 bytes. Notified on any change.

Byte(s)FieldValues
0Provisioning StateSee §2.4
1Wi-Fi State0x00 Idle · 0x01 Scanning · 0x02 Connecting · 0x03 Connected · 0x04 Has IP
2Cloud State0x00 Idle · 0x01 Connecting · 0x04 Key Ready
3Last Error Code0x00 if none
4–7Uptimeuint32_t, seconds

4.4 Command & Response — A0FD0011 / A0FD0012​

Write to 0011, read or subscribe to 0012.

Request format: [Cmd ID] [Seq Num] [Payload Length (uint16)] [Payload…]

Response format: [Cmd ID] [Seq Num] [Chunk Index (uint8)] [Total Chunks (uint8)] [Payload Slice…]

All responses use application-layer chunking (max 128 bytes per slice) to prevent truncation across varying MTU sizes.

Commands​

IDCommandPayloadDescription
0x01IDENTIFYDuration uint8 (seconds)Triggers physical setup indicators and system display animation.
0x02SCAN_WIFINoneTriggers an async Wi-Fi network scan.
0x03GET_WIFI_PAGEPage number uint8Requests a page of scan results from A0FD0022.
0x04GET_SAVED_WIFINoneReturns a JSON array of previously saved network profiles.
0x05GET_HARDWARE_INFONoneReturns device metadata and active display topology.
0x06GET_ETHERNET_CFGNoneReturns saved Ethernet IP/DHCP configuration.
0x07GET_WIFI_IP_CFGSSID stringReturns saved IP/DHCP configuration for a specific Wi-Fi network.

Response Payloads​

  • 0x01 (IDENTIFY) and 0x03 (GET_WIFI_PAGE): Empty acknowledgment. Chunk Index 0x00, Total Chunks 0x01, empty payload.
  • 0x02 (SCAN_WIFI): [Status uint8 (0x00 = OK)] [Network Count uint8]
  • 0x04 (GET_SAVED_WIFI): JSON array of saved network objects.
    [{ "ssid": "Network1", "priority": 100 }]
  • 0x05 (GET_HARDWARE_INFO): JSON object with device metadata and display topology.
    {
    "mfg": "Admiral Edge",
    "mdl": "ADM-DEVX",
    "sn": "ADM-CA2B61A9",
    "fw": "0.1.7",
    "displays": "HDMI-A-1 @ 3840x2160 @ 60 Hz | DP-1 @ 1920x1080 @ 144 Hz"
    }
    note

    Hardware identifiers are transmitted via this command rather than the standard 0x180A GATT Device Information Service due to platform-specific system profile limitations.

  • 0x06 (GET_ETHERNET_CFG): JSON IP settings object. An empty {} signifies default DHCP.
    { "dhcp": false, "ip": "192.168.1.50/24", "gw": "192.168.1.1", "dns": "8.8.8.8" }
  • 0x07 (GET_WIFI_IP_CFG): Same JSON format as 0x06, scoped to the requested SSID.

4.5 Network Config — A0FD0020​

Accepts a chunked, application-layer encrypted JSON payload containing network credentials or configuration actions.

Chunking​

Payloads must be fragmented into 128-byte chunks with a ~30 ms delay between writes:

[Chunk Index (uint8, 0-based)] [Total Chunks (uint8)] [Payload Fragment…]

Reassembled payload (minimum 28 bytes):

[Nonce (12 bytes)] [AES-GCM Ciphertext + 16-byte Auth Tag]

Session Key Exchange​

  1. Mobile reads the device's ephemeral X25519 public key from A0FD0050.
  2. Mobile derives the shared AES-256 secret via ECDH and transmits its own public key via the PROV_CTRL START command (A0FD0040) to open the crypto session.
  3. Mobile encrypts the JSON payload with AES-GCM and pushes the chunked blob.

Payload Actions​

Payloads require an "action" key:

save — Push or update a network configuration.

{
"action": "save",
"priority": 100,
"type": "wifi",
"ssid": "MyNetwork",
"psk": "password",
"ip": "192.168.1.50/24",
"gateway": "192.168.1.1",
"dns": "8.8.8.8, 1.1.1.1"
}
  • Set "type": "ethernet" to skip Wi-Fi authentication and apply settings directly to the Ethernet adapter.
  • Transmitting "psk": "" on an update preserves the existing stored passphrase while merging other fields.
  • Static ip fields must use CIDR notation (e.g., 192.168.1.50/24). Bare IP addresses without a prefix length are rejected by the client before transmission.

delete — Remove a saved network profile.

{ "action": "delete", "ssid": "MyNetwork" }

reset — Wipe all Wi-Fi networks and reset Ethernet to DHCP.

{ "action": "reset" }

4.6 Network Status — A0FD0021​

Returns the active network state across all concurrent live interfaces. Proactively notifies the client when an organic connection (Ethernet or saved Wi-Fi) is detected, allowing the mobile app to bypass the Wi-Fi setup step.

Format: [Interface Count (uint8)] followed by per-interface records:

[Link Type (uint8)] [IPv4 Address (4 bytes)] [RSSI (1 byte)] [Label Length (uint8)] [Label (UTF-8)]
  • Link Type 0x02 = hardwired Ethernet. Other values represent Wi-Fi.
  • If fully disconnected, the interface list is empty: [0x00].
  • SD-WAN failover events (gateway priority shifts from L4 health checks) update this characteristic and push a notification automatically.

4.7 Wi-Fi Scan Results — A0FD0022​

Returns paginated results after a SCAN_WIFI command, triggered page-by-page with GET_WIFI_PAGE.

Header: [Page Number (uint8)] [List Count (uint8)]

Per network record (repeated List Count times):

[SSID Length (uint8)] [SSID (UTF-8)] [RSSI (int8)] [Security (uint8: 0x00=Open, 0x02=Encrypted)]

4.8 Pairing Key — A0FD0030​

Returns the cloud pairing key sealed with the established session secret.

Format: [Nonce (12 bytes)] [AES-GCM Ciphertext + 16-byte Auth Tag]

The Device State characteristic (§4.3) transitions Cloud State to 0x04 (Key Ready) when the key is available. The mobile client decrypts it using the existing session secret.

Pairing key validity is tied to the device's installation lifecycle, not a time-based TTL. The key is invalidated immediately upon successful cloud account association to prevent replay attacks.


4.9 Provisioning Control — A0FD0040​

Controls the session lifecycle.

Byte(s)FieldValues
0Control Action0x01 START · 0x02 COMPLETE · 0x03 ABORT
1–32Mobile Public Key32-byte X25519 public key (on START only)
  • START (0x01): Transmits the mobile's X25519 public key and opens the encrypted session. Must be called before writing to any encrypted characteristic (Network Config). Establishing the session immediately on initialization also ensures the device can encrypt and push the Cloud Pairing Key even if it connects organically via Ethernet and skips the Wi-Fi setup.
  • COMPLETE (0x02): Signals successful account registration. Triggers immediate shutdown of the BLE stack.
  • ABORT (0x03): Tears down the active session. The device remains in or reverts to setup mode.

4.10 Error Info — A0FD00F0​

Notified on failure. See §6 for the full error code table.


4.11 Service Access — A0FD0052 / 0080 / 0081 / 0082​

A claimed device stays reachable over Bluetooth for field service, but only to someone the Admiral Cloud has authorised. Authorisation works while the device is offline.

Open and service modes. 0052 returns JSON:

{"v":2,"mode":"open|service","did":"<device uuid>","nonce":"<b64url>","confirm":true,"verified":false,"busy":false}
  • nonce: 16 random bytes (base64url, no padding), fresh at each START. It is single use: any authentication attempt, good or bad, consumes it.

  • confirm (open mode): the device has a display and requires the on-screen pairing code. verified: the current session has confirmed it.

  • busy (service mode): another authenticated session is live, so a START from a different client will be refused.

  • open: the device is not claimed. Anyone in range may provision it, exactly as in §3. The pairing key is delivered.

  • service: the device is claimed. A session does nothing until it presents a valid access token. The pairing key is never sent, and network details are not published to an unauthorised session.

Getting access.

  1. The console connects, reads 0050 and 0052, and starts a session (PROV_CTRL START, §4.9). Starting a session issues a fresh nonce; read 0052 again.
  2. The console asks the cloud for a token for that device, sending the nonce and the session's public key. The cloud checks the signed-in user's permission on the device and signs a token for five minutes.
  3. The console writes the token, encrypted and chunked, to 0080. The device verifies the signature with public keys it received when it last connected to the cloud, so no network is needed.

What a token binds. The device ID, the session's public key and the nonce. A captured token is useless on any other connection, and the nonce is single use. Tokens carry scopes, which the device enforces. Scopes are not hierarchical.

ScopeGrants
diagIdentify, hardware info, device info, workload status, diagnostics.
networkWi-Fi scan and saved networks, Ethernet and IP configuration, network changes.
operateWorkload control and diagnostics mode, on-device screen control.
adminPower (reboot and power off), setup completion, unpair.

Scopes follow the user's strongest capability on the device:

Device capabilityScopes
View devicesdiag
Operate devicesdiag, operate, network
Delete devicesdiag, operate, network, admin

Tokens are valid for five minutes by default (15 minutes at most).

Service requests. After authentication the console sends encrypted requests to 0081 and receives encrypted responses on 0082. Request and response frames are tagged so a captured message cannot be replayed in the other direction, and each request carries a counter that must increase. Wi-Fi and Ethernet management uses the existing characteristics (0011, 0020), which now require the network scope on a claimed device.

One session at a time. While an authenticated session is live, a different client's START is refused and the owner is left untouched. A session is live for 30 seconds after its last request; the console sends a session.ping every 10 seconds to keep a quiet session, and a disconnect frees the device immediately, so a dropped link never locks anyone out. On a claimed device ABORT is ignored, because a write cannot be attributed to a connection and would let any client end the owner's session.

Pairing code (unclaimed devices with a screen). The key exchange on an unclaimed device is unauthenticated, so a device with a screen defends against a relay in range: it shows an 8 digit code derived from both public keys and the shared secret, and holds back the pairing key, network details and every command until the user types that code into the console and the console sends it in PROV_CTRL command 0x04 (VERIFY). The console first checks the typed code against its own derivation and sends nothing on a mismatch, because a relay has different keys on each side. The device ends the session after three wrong codes. Devices without a screen keep the open flow. Writing off to /admrl/conf/ble-verify disables the code for fleets that provision with an app that cannot send VERIFY.

Rotation and revocation. The cloud sends the device its current set of verification keys on every connection. Removing a key removes its tokens' validity from the fleet on next check-in. Five failed authentications in a row lock authentication on the device for 60 seconds; this counter is device-wide, not per client.

Turning it off. Writing off to /admrl/conf/ble-service-mode stops a claimed device advertising at all.


5. Identify & Display Integration​

Admiral devices feature an LED and an integrated display.

When the mobile app writes the IDENTIFY command (0x01) to A0FD0011:

  1. The BLE daemon parses the requested duration (default: 10 seconds).
  2. The system LED switches to an active pulsing pattern.
  3. The device updates the system display, entering an active Pairing Animation (such as a pulsing connection ring, animated PIN, or avatar).
  4. After the specified duration, the LED and display revert to their default states.

This ensures a user in a room with multiple identical Admiral devices can identify exactly which unit they are configuring.


6. Error Codes​

Delivered via the Error Info characteristic (A0FD00F0).

DomainCodeCategoryDescriptionResolution
0x110x11Wi-FiSSID Not FoundTrigger a new scan and prompt the user.
0x110x12NetworkConfiguration / Payload ErrorCheck credential payload formatting or valid IP ranges.
0x110x13NetworkDHCP TimeoutConnected to network but failed to obtain IP. Verify the backend router.
0x110x14Wi-FiAuthentication FailedPassword rejected by access point. Prompt user to re-enter.
0x110x15NetworkDelete Network FailedVerify the target SSID matches stored profiles.
0x110x16NetworkReset Network FailedOS failed to safely clear previous configuration state.
0x210x21CloudUnreachableVerify the network has internet access and retry.
0x210x22CloudKey Generation FailedAdmiral Cloud backend failure.
0x300x30SystemDisplay ErrorSystem could not render to display.

7. Timing & Constraints​

ParameterValueDescription
Max Concurrent BLE Clients1Admiral device accepts only one BLE central at a time.
Setup Timeout (No Peers)60 sWith TimeoutMode enabled, drops advertisement after 1 min with no peer connections.
Setup Timeout (With Peers)5 minDrops advertisement after 5 min of connection inactivity.
Connection Idle Timeout30 sDevice disconnects if no writes occur within 30 seconds.
Wi-Fi Scan Timeout5 sScan results must be returned within 5 seconds.
Identify Default Duration10 sLED/splash sequence duration if not explicitly specified.

Power-Save Supervisor​

Admiral OS uses a multi-tiered power-save supervisor to balance discoverability with radio-silence best practices:

  • Unconnected Idle (1 min): If no peer connection is formed within 1 minute while TimeoutMode is active, the supervisor shuts down BLE advertising and sets advertising: false in system state.
  • Connected Inactivity (5 min): If a client connects to the GATT server but commits no writes (commands or config payloads) for 5 continuous minutes, the supervisor disconnects the link, tears down the advertiser, and enters a low-power quiet state.
  • Activity Reset: Any standard activity — new central connection, payload chunk write, identify command — resets the supervisor countdown to zero.

8. Security​

Application-Layer Encryption (X25519 ECDH + AES-GCM)​

BLE OS-level bonding is bypassed in favor of application-layer encryption to avoid cross-platform bonding complexities.

  • The Admiral device generates an ephemeral X25519 keypair on boot and exposes its public key on A0FD0050.
  • The mobile app generates its own ephemeral keypair, derives the AES-256 shared secret via ECDH, and transmits its public key strictly via the PROV_CTRL START command. This ordering prevents crypto-deadlocks on organic network connections.
  • Subsequent encrypted payloads (Wi-Fi credentials) omit public keys entirely — they are sealed with AES-GCM using the negotiated secret only.
  • Wi-Fi credentials are never readable back to the mobile app over BLE.

Post-Provisioning Access​

An unclaimed device accepts any session so that a fresh device can be set up with no prior trust. Once a device is claimed it is sealed: pairing is closed, the pairing key is never sent again, and every capability needs a cloud-issued, session-bound token that the device validates offline (§4.11). A fault on the device cannot reopen it. A device that has not received verification keys from the cloud does not advertise after it is claimed, as before.

A session that was already open when the claim happened stays open until it disconnects, so the setup flow can finish. Resetting the device to factory state (the pinhole button, §3) returns it to the open, unclaimed mode.


9. Multi-Device Batch Provisioning​

For deployments with many Admiral devices in the same space:

  1. Mobile app scans for ~10 seconds, accumulating unique Device IDs from advertisement packets.
  2. User selects multiple target devices in the mobile app.
  3. Mobile app provisions devices sequentially: connect → write Wi-Fi config → disconnect → next device.
  4. Devices connect to Wi-Fi and the Admiral Cloud in parallel asynchronously.
  5. Mobile app round-robins reconnections to read the Pairing Key from each device as they become ready.
  6. Mobile app sends a single batch API request to the Admiral Cloud with all collected keys.
  7. Mobile app round-robins reconnections to send PROVISIONING_COMPLETE to all devices, triggering their BLE shutdown.
tip

Do not hold a BLE connection open while a device is working through a long Wi-Fi connection phase. Disconnect, move to the next device, and return. Holding connections blocks the single-client limit unnecessarily.


10. Implementation Notes​

Firmware (admiral-os-ble-daemon)​

  • Monitor provisioning state on startup. Only enable the HCI interface if provisioning_status != FULLY_PROVISIONED.
  • The IDENTIFY command should trigger the device's physical identity indicators.
  • MAC Address Override: Before initiating any Bluetooth services, open a raw HCI management socket (AF_BLUETOOTH, BTPROTO_HCI) to issue the physical controller address override, enforcing unique LAAs across hardware variants.
  • GATT Cache Purging on Disconnect: To mitigate the iOS Bluetooth GATT service caching bug (where iOS fails to discover updated characteristics on reconnect), remove the device from the system's active device registry and momentarily cycle the advertiser. This forces iOS to prune its GATT service cache.

Mobile Application​

  • iOS: Use CBCentralManager. Android: Use BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner().
  • Filter scans on Service UUID 0xFDA0.
  • Subscribe to Device State (A0FD0010) and Network Status (A0FD0021) notifications immediately after connecting — both can fire before the UI has progressed past the discovery screen, particularly when Ethernet is already plugged in.
  • Always send PROV_CTRL START with the mobile's X25519 public key before writing to any encrypted characteristic.

11. Data Serialization​

  • Endianness: Little-endian for all multi-byte integers.

  • Strings / JSON: UTF-8 encoded.

  • Chunking: Large payloads (such as chunked command responses) use application-layer chunking to work around the BLE GATT 512-byte hard limit and OS driver-level packet queue limits. Maximum fragment size: 128 bytes. Enforce a ~30 ms delay between chunk writes.

    Byte 0: Chunk Index (0-based)
    Byte 1: Total Chunks
    Byte 2…: Payload Fragment