- Fix _pollUntilConnected overwriting real error with generic timeout
message — stop polling once backend reaches error state
- Fix battery % calculation: was battery_mv/42 (71% at empty); now
(battery_mv-3000)/12 for a proper 0-100% LiPo curve
- Improve auto-detect: scan available ports rather than blindly using
/dev/ttyUSB0; update label to show fallback so users know what to expect
- Add port refresh button (↻) — previously required switching modes
and back if device was plugged in after panel opened
- Add baud rate selector to serial config strip (default 115200,
options up to 921600) and wire it through to the connect request
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Enable debug=True on MeshCore.create_ble() to surface verbose logs
- Disconnect any existing BlueZ connection before bleak connects to
avoid conflicts from prior bluetoothctl/pairing sessions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Log node_id hint in request_traceroute instead of silently dropping it
- Replace asyncio.shield/wait_for pattern with _wait_or_stop() to prevent orphan tasks on retry delays
- Poll _stop_event every 1s in _do_connect keep-alive loop to handle stop() race before _asyncio_stop is set
- Extract pubkey_prefix/sender_id in _on_channel_msg instead of hardcoding "unknown"
- Close coroutine and log in _submit() when worker is not running to prevent ResourceWarning
- Cap battery_pct at 100 to prevent values exceeding 100%
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements AsyncWorker — the daemon asyncio thread that owns the meshcore
library connection, subscribes to all relevant EventTypes, and feeds events
back into MeshcoreClient via on_message/on_node/on_telemetry/on_traceroute/
on_connected/on_error. Includes retry-with-backoff (3 attempts: 5s/15s/45s),
thread-safe send_text/request_traceroute/scan_ble_sync for Flask callers,
and a standalone _scan_ble() coroutine using bleak.BleakScanner.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>