core:network is the largest module tackled so far in this effort: BLE radio transport, TCP radio transport, MQTT (TCP + WebSocket transports), USB/Serial, mDNS/NSD discovery, and HTTP data sources for api.meshtastic.org all live here. BLE and Mock/Replay radio transports already work unchanged -- BaseRadioTransportFactory handles BLE directly via core:ble's Web Bluetooth actuals, and Mock/Replay are already commonMain-portable. A new WasmJsRadioTransportFactory implements the platform seam, failing loudly for TCP and Serial/USB addresses (no browser equivalent for raw sockets; WebSerial/WebUSB out of scope this pass). Raw TCP sockets are a permanent browser sandbox limitation, not a library gap (confirmed via Ktor's own docs/KTOR-6690, recorded earlier this session). TcpTransport/TcpRadioTransport move to nonWebMain. MQTT's transport composition becomes a real per-platform expect/actual (MqttTransportSelection.kt): nonWebMain composes TCP+WebSocket as before, wasmJs registers WebSocket only -- mqtt-client-transport-ws publishes a wasmJs Gradle variant, mqtt-client-transport-tcp does not (confirmed via Maven Central's module metadata directly, not assumed). New wasmJs actuals: WebNetworkMonitor (real navigator.onLine plus window online/offline events, via kotlinx-browser -- no custom JS interop needed), MqttTlsTrust.wasmJs.kt (null -- a browser page cannot influence TLS trust at all, the platform decision is the only one available), ConnectionFailures.wasmJs.kt (false -- Ktor's Js engine surfaces failures through the same IOException family the shared predicate already covers). CoreNetworkWasmJsModule wires a real HttpClient(Js) engine for the HTTP data sources; deliberately no @ComponentScan since commonMain's CoreNetworkModule scan already reaches this target's @Single classes. Like core:database's SingleDatabaseProvider and core:prefs's CorePrefsWasmJsModule, it's not registered anywhere yet -- no webApp module exists this pass. core:network's own applyHierarchyTemplate call (needed for the nonWeb/wasmJs split) can't coexist with the separate meshtastic.kmp.jvm.android convention plugin, which makes its own call -- Gradle only allows one per project. Replaced with a nested jvmAndroid group inside the custom nonWeb group; ConnectionFailures's existing jvmAndroidMain source set needed no changes. One small upstream fix: core:ble's classifyBleException() had no wasmJs counterpart, blocking core:network's commonMain BleRadioTransport.kt. Added as an honest `= null` (Kable doesn't exist on wasmJs at all, so nothing is ever a recognized Kable exception there) -- same disjoint-compilation shape as BleServiceExtensions.kt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
:core:ble
Overview
The :core:ble module contains the foundation for Bluetooth Low Energy (BLE) communication in the Meshtastic Android app. It uses the Kable multiplatform BLE library to provide a unified, Coroutine-based architecture across all supported targets (Android, Desktop, and future iOS).
This module abstracts platform-specific BLE operations behind common Kotlin interfaces (BleDevice, BleScanner, BleConnection, BleConnectionFactory), ensuring that business logic in commonMain remains platform-agnostic and testable.
Key Components
1. BleConnection
A robust wrapper around Kable's Peripheral that simplifies the connection lifecycle and service discovery using modern Coroutine APIs.
- Features:
- Connection & Await: Provides suspend functions to connect and wait for a terminal state (Connected or Disconnected).
- Unified Profile Helper: A
profilefunction that manages service discovery, characteristic setup, and lifecycle in a single block, with automatic timeout and error handling. - Observability: Exposes
connectionStateas a Flow for reactive UI and service updates. - Platform Setup: Seamlessly handles platform-specific configuration (like MTU negotiation on Android or direct connections on Desktop) via
platformConfig()extensions.
2. BluetoothRepository
A Singleton repository responsible for the global state of Bluetooth on the device.
- Features:
- State Management: Exposes a
StateFlow<BluetoothState>reflecting whether Bluetooth is enabled, permissions are granted, and which devices are bonded. - Permission Handling: Centralizes logic for checking Bluetooth and Location permissions across different platforms.
- Bonding: Simplifies the process of creating and validating bonds with peripherals.
- State Management: Exposes a
3. BleScanner
A wrapper around Kable's Scanner to provide a consistent and easy-to-use API for BLE scanning with built-in peripheral mapping.
4. BleRetry
A utility for executing BLE operations with retry logic, essential for handling the inherent unreliability of wireless communication.
Integration
The :core:ble module is used by BleRadioTransport in :core:network to implement the RadioTransport contract for Bluetooth devices.
Usage
Dependencies are managed via the version catalog (libs.versions.toml).
[versions]
kable = "0.44.2"
[libraries]
kable-core = { module = "com.juul.kable:kable-core", version.ref = "kable" }
Architecture
The module follows a clean multiplatform architecture approach:
- Repository Pattern:
BluetoothRepositorymediates data access. - Coroutines & Flow: All asynchronous operations use Kotlin Coroutines and Flows.
- Dependency Injection: Koin is used for dependency injection.
Testing
The module includes unit tests for key components, utilizing Kable's architecture and standard coroutine testing tools to ensure logic correctness.
Dependency Graph
graph TB
:core:ble[ble]:::kmp-library
:core:ble --> :core:common
:core:ble -.-> :core:di
:core:ble -.-> :core:model
:core:ble -.-> :core:testing
classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef compose-desktop-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-library-compose fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;