A fresh display shows Disconnected while its background scan fills the Bike picker. Scanning without a previously verified bike does not imply a reconnect attempt. Selecting a bike shows Connecting, followed by VESC service discovery and notification subscription. Connected means the Nordic UART Service write and notify characteristics have been found and its notification CCCD write succeeded; telemetry freshness is tracked separately by the application.
The selected candidate remains in memory during bounded retry attempts. Its address is saved to the ble NVS namespace only after notification subscription succeeds. A peer_ok marker records that verification. An older address without that marker can still be tried, but it cannot produce the remembered-peer reconnect state until it has been verified. Forget clears the saved address and marker, invalidates the current stream session and returns to Disconnected.
Saved bike association and Bluetooth SMP bonding serve different purposes. The verified association stores the selected BLE address and vehicle integration; the SMP bond stores connection security keys. A secured upstream device has a separate six-digit pairing prompt. The upstream PIN itself is not saved or reused by the proxy. Persistent bonds allow reconnection without inventing a default code; authentication changes require pairing again. Controller-specific behavior, changed credentials and private-address identity resolution still require hardware acceptance testing.
Asynchronous scan, connect, MTU, GATT discovery and subscription callbacks carry a generation token. A callback from an earlier attempt cannot promote a newer attempt to Connected. Notifications additionally require the current central connection handle, expected UART TX characteristic handle and ready state. Every disconnected, forgotten or paused stream invalidates queued telemetry and writes through its session identifier. OTA pause is displayed explicitly and prevents scanning or connecting until resumed.
The portable lifecycle tests cover fresh repeated scans, first-connect/discovery failures, successful subscription, restoration, disconnect/retry, late callbacks, pause/resume, unsupported authentication and Forget. Hardware testing with actual VESC controllers remains necessary for advertising variants, connection loss, MTU negotiation and security requirements. Controllers using rotating private addresses require identity resolution beyond a saved over-the-air address.
Optional VESC BLE proxy
The BLE proxy setting is off by default. The display advertises its own user-editable name, initially WB Disp, with the standard Nordic UART Service. This name is independent of the upstream BLE device, selected integration and discovered main controller. BLE and UART provide an ordinary VESC byte stream. CAN exposes a generic adapter with firmware discovery, CAN ping and explicit CAN forwarding; the phone supplies its own controller IDs. The proxy does not consult or rewrite the display client's main-controller route.
The proxy's PIN requirement comes only from the local bike lock PIN. Without a bike PIN it has no PIN requirement. With one, phone pairing requires that six-digit code and authenticated encryption. Changing or removing the bike PIN revokes old phone security sessions and bonds; upstream bonds remain independent. A configured bike PIN requires local unlock after boot before its numeric proxy passkey is available in RAM.
A connected phone owns the UART conversation, including before it enables notifications. VESC replies have no request identifier, so the display suspends its own polling, configuration writes and firmware maintenance for that lease. A display packet already in transmission finishes before phone data begins; queued display requests are discarded. Main-controller discovery also waits while the phone owns the conversation. The dashboard passively displays recognized telemetry replies from the phone conversation. If the app does not request the setup/package messages the selected integration recognizes, readings become stale rather than inventing measurements or injecting competing polls.
The BLE/UART bridge forwards raw bytes in order without imposing the dashboard decoder's 1024-byte packet limit. Native CAN necessarily terminates serial framing and uses the bounded VESC CAN packet codec before reframing replies for the phone. Phone and VESC MTUs may differ: upstream notifications are split into phone-sized notifications while retaining unsent bytes. Both directions have bounded queues and bounded allocation/retry waits. Proxy queue overflow or an unrecoverable send failure terminates the phone conversation and resets the upstream link instead of silently dropping bytes. A slow passive dashboard decoder can be reset independently without truncating a phone bulk transfer. Session/lease epochs reject queued bytes from previous connections.
Disabling the setting, a lost VESC connection, host reset or transfer failure ends the phone lease. After a phone leaves, the central link is reset before normal polling resumes so partial app packets and delayed replies cannot blend into a new display conversation. Display OTA reserves the proxy admission lock before starting; a phone already owning the VESC blocks OTA, while a later phone cannot acquire the reserved link.
The proxy provides the phone the VESC access normally available over its BLE dongle, including configuration and firmware commands. Enable it only when that access is wanted. Its pairing requirement follows the local bike PIN policy; this is separate from upstream BLE credentials. Hardware validation with a real VESC and phone app is required for discovery, both MTUs, sustained transfers, disconnects and app firmware-update behavior. Portable tests verify the ownership, default-off, maintenance and stale-stream policy, not radio interoperability.
Discovery prioritizes names containing WFB or wheel-e (case insensitive), while other NUS devices, VESC names and the saved peer remain selectable. Known scan candidates can receive name updates from separate scan-response packets. A matching device can displace a generic candidate when the six-entry cache is full. The UI sorts a snapshot; selection resolves the displayed BLE address under the central mutex rather than using a potentially reordered scan index.
The verified association stores the BLE address, selected integration policy and last connected name in one versioned NVS blob. Auto is the default and remains selected after discovery. It probes WFB and wheel-e packages on discovered motor controllers, then selects the first verified match. The probes run again on reconnect, including for renamed devices. Names only rank discovery candidates. When neither supported package is found, Auto can use read-only generic VESC telemetry. Mismatched custom replies are rejected and cannot enable writes.
The proxy advertises when its selected physical interface is ready, independently of display main-controller discovery. Changing Settings > BLE name restarts advertising with the new name. Legacy scan responses allow 29 bytes for a name; keep names short. The bridge pauses while the local screen is PIN-locked. This local access control does not authenticate a client's separate direct connection to the bike.
Encrypted BLE and credential changes
VESC Express's standard VESC service uses SMP with a fixed six-digit passkey when encrypted mode is selected. Its NUS characteristics require authenticated encryption. The display acts as a keyboard-capable central and prompts for the upstream PIN; a successful bond stores security keys rather than the entered PIN. This is separate from the scripting BLE interface, whose capabilities are different.
The implementation reference is VESC Express comm_ble.c at 511a026. Pairing retries must reject stale connection handles and remove rejected peer bonds rather than repeatedly replaying an old credential. An unencrypted upstream connection is not forced into SMP just because an earlier configuration used a PIN.
The proxy always follows the local bike PIN policy. Removing upstream BLE encryption therefore does not remove a configured proxy PIN, and changing the bike PIN does not overwrite the upstream bond. Real-device verification remains necessary for failed pairing, changed credentials, restored bonds, repeat pairing and phone-side cached-bond behavior.