What's Changed
🏗️ Features
- feat(export): add hop start and relay node columns to CSV export by @jamesarich in #5822
- feat(mqtt): add phone-local MQTT proxy cutoff control by @jamesarich in #5823
- feat(node): show our node shortname chip on the Nodes tab by @jamesarich in #5820
- feat(settings): add remote "Set time" admin action by @jamesarich in #5821
- feat(network): on-device capture-replay transport + ingestion fuzzing/hardening by @jamesarich in #5846
- perf(node): add stable keys and contentType to telemetry chart lists by @jamesarich in #5869
- feat(connections): list only BLE devices visible via scan by @jamesarich in #5877
- feat(ui): use modem-preset-relative SNR thresholds for signal quality by @jamesarich in #5903
- feat(firmware): link OTAFIX bootloader from slow-DFU success screen by @jamesarich in #5917
- feat(node): add GPX export to position log screen by @jamesarich in #5919
- feat: offline-first event firmware metadata (JSON schema + bundled asset) by @jamesarich in #5920
- feat(firmware): drive event firmware branding from bundled metadata by @jamesarich in #5929
- feat(lora): consume region→preset compatibility map + TINY presets (protobufs #951) by @jamesarich in #5834
- feat(lockdown): firmware lockdown mode (provision / unlock / lock-now) by @jamesarich in #5939
- feat(lora): gate region→preset map + TINY presets on firmware capability by @jamesarich in #5941
- feat(security): surface XEdDSA packet signing in node & messaging UI by @jamesarich in #5976
- fix(security): make XEdDSA signing shield green & prominent by @jamesarich in #5980
- Prevent Range Test from running on public/default channel by @dubsector in #5986
- feat(network): migrate TcpTransport to ktor-network (commonMain) by @jamesarich in #5995
- feat(ui): StatusSurface AA legibility + node-details signing/transport polish by @jamesarich in #5985
- feat: NFC tag writing for shared contacts and channels by @jamesarich in #6030
- feat: Waypoint geofences (editor, map overlays, alert engine) by @jamesarich in #6014
- feat(lora): default US region to LongTurbo preset by @jamesarich in #6009
- feat(connections): add deep link to trigger a connection by address by @jamesarich in #6036
- feat(desktop): add Flathub screenshots to metainfo.xml by @jamesarich in #6042
- feat(testing): debug-only skip_onboarding intent extra for AI/CI tooling by @jamesarich in #6044
- feat(discovery): surface received Mesh Beacon invitations by @jamesarich in #6043
- feat(firmware): nRF52 legacy BLE DFU — stock-bootloader fixes + stranded-device recovery by @jamesarich in #6041
- feat(settings): wire is_unmessagable/is_licensed into DeviceProfile export/import by @jamesarich in #6065
- Style GeoJSON overlays from simplestyle-spec (fill/stroke) by @garthvh in #6088
- feat(discovery): Mesh Beacon client with iOS 014-mesh-beacons parity by @jamesarich in #6097
- feat(messaging): translate chat messages in-place with on-device ML Kit (google flavor only) by @thebentern in #6103
- feat(database): unify device database across transports by @jamesarich in #6096
- feat: compute EPA NowCast AQI from PM2.5 history by @jamesarich in #6102
- Add secure key backup/restore/delete for security config by @jamesarich in #6105
- feat(messaging): @mention with deep-link to node detail (#6098) by @jamesarich in #6108
- feat(node): label power channels and fix pressure axis scale by @jamesarich in #6111
- Show outgoing message status text by @RCGV1 in #6121
- feat(map): Site Planner coverage integration — import + estimate by @jamesarich in #6136
- feat(node): show CO₂ sensor temperature & humidity on Air Quality page by @jamesarich in #6143
- feat(node): histogram of nodes per hop distance (#5745) by @jamesarich in #6146
- feat(map): F-Droid map-layer parity — share layer UI + logic in common source (#6138) by @jamesarich in #6148
- Promote CO2 temperatures to summary if no other temp is present. by @DaneEvans in #6153
- feat(firmware): Confirm local firmware files before flashing by @jeremiah-k in #6083
- feat(messaging): split Conversations into collapsible Channels/DM sections by @jamesarich in #6169
- perf(mqtt): drop payload-less client-proxy downlinks before forwarding by @thebentern in #6171
- feat(map): send a waypoint as a DM or to a specific channel by @joeyleake in #6218
- feat(firmware): nightly preview channel behind the hidden-features unlock by @jamesarich in #6225
- perf(r8): enable optimization for release builds (keep unobfuscated) by @jamesarich in #6275
- feat(analytics): restore RUM view tracking on Nav3 (Google flavor) by @jamesarich in #6281
- perf(analytics): match iOS Datadog RUM monitoring, drop dead timber dep by @jamesarich in #6278
- Align NFC contact import and share dialogs with Design Standards v1.4 by @thebentern in #6332
- feat(settings): add packet authenticity policy by @RCGV1 in #6178
- feat(messaging): redesign message bubbles toward the M3 conversation pattern by @jamesarich in #6368
- feat(notifications): align message notifications with Android best practices by @jamesarich in #6371
- feat(node): group related metric cards into vertical columns by @jamesarich in #6431
- feat(node): show AQI in the air quality graph and table by @jamesarich in #6434
🖥️ Desktop
- fix(data): stale firmware/hardware caches — stop cancelling slow API refreshes, prune pulled releases, seed from newer bundles by @jamesarich in #6060
- fix(geofence): restrict crossing alerts to creator, add per-geofence opt-in by @jamesarich in #6117
- fix(ble): refresh GATT cache around ESP32 OTA profile changes by @jeremiah-k in #6166
- Add firmware update notice by @RCGV1 in #6309
- fix: make NotificationManager.dispatch await the platform send by @jamesarich in #6326
- fix(database): make DB updates atomic across device switches by @jeremiah-k in #6256
- fix(ci): defer desktop packaging toolchain resolution by @jeremiah-k in #6401
🛠️ Fixes
- fix(mqtt): make the MQTT client-id unique per connection by @jamesarich in #5755
- fix(ble): Harden BLE connection lifecycle by @jeremiah-k in #5795
- fix(build): isolate ML Kit GenAI to the Google flavor (fix F-Droid rb-check) by @jamesarich in #5824
- fix(notifications): open node detail when tapping 'New Node Seen' notification by @LesterCheng in #5752
- fix(appfunctions): keep AppSearch document-factory constructors under R8 full mode by @jamesarich in #5829
- fix(service): resolve selected-device startup race by @jeremiah-k in #5828
- fix(database): defer FTS backfill on cold start and enforce single-connection pool by @jeremiah-k in #5841
- fix(ble): retrigger connection when bonding is interrupted by @jamesarich in #5849
- fix(desktop): terminate process on exit; quit on close when no tray by @jamesarich in #5858
- fix(settings): crash opening Position radio-config screen by @jamesarich in #5862
- fix(settings): gate Traffic Management config at firmware v2.8.0 by @jamesarich in #5864
- fix(network): retry transient connection/IO failures to api.meshtastic.org by @jamesarich in #5870
- fix(ui): recognize VPN and all networks for network scan availability by @jeremiah-k in #5882
- fix(data): separate refresh timeouts from Room persistence by @jeremiah-k in #5881
- fix(service): recover stalled WiFi/TCP handshakes by cycling active transport by @jeremiah-k in #5856
- fix(ui): prevent duplicate LazyColumn keys in node metrics logs by @jamesarich in #5890
- fix(network): preserve TCP reconnect backoff on short sessions by @jeremiah-k in #5893
- fix(connections): coordinate BLE and TCP scan lifecycle by @jeremiah-k in #5887
- fix(ui): show Wi-Fi unavailable banner only during active network scan by @jeremiah-k in #5892
- fix(network): migrate to mqtt-client 0.4.0 (IP-literal TLS fix) by @jamesarich in #5895
- fix(ble): require fresh advertisement for auto-reconnect by @jeremiah-k in #5912
- fix(firmware): harden ESP32 OTA + nRF DFU update paths (hardware-validated) by @jamesarich in #5915
- fix(firmware): batch of P3 OTA/DFU cleanups from the #5915 audit by @jamesarich in #5916
- fix(firmware): render chirpy mascot via painterResource in update dialog by @jamesarich in #5925
- fix(usb): Add serial presence recovery for USB replug by @jeremiah-k in #5923
- fix(data): Persist TAK module config by @jeremiah-k in #5933
- fix(usb): Suppress expected serial close warnings by @jeremiah-k in #5932
- refactor(connections): Derive DeviceType from InterfaceId by @jeremiah-k in #5935
- fix(usb): Surface permission denial as permanent disconnect by @jeremiah-k in #5943
- refactor(ble): Make Kable connect fallback explicitly bounded by @jeremiah-k in #5944
- refactor(connections): Show one active transport pane by @jeremiah-k in #5956
- fix(ble): Restore bounded bonded reconnect fallback by @jeremiah-k in #5960
- fix(docs): preserve #anchor when rewriting sibling links for Docusaurus by @jamesarich in #5963
- fix(ble): Bound Android bonding wait by @jeremiah-k in #5967
- fix(ble): Avoid duplicate bonding retries after pairing failure by @jeremiah-k in #5969
- fix(ble): Stop transport connect after failed bonding by @jeremiah-k in #5973
- fix(ble): Fail bonding promptly when polled state returns none by @jeremiah-k in #5982
- fix(car): wire notifications & emergency, fix TabTemplate crash, pin car-app to stable by @jamesarich in #5997
- fix(qr): Serialize channel import writes by @jeremiah-k in #5999
- fix(ui): stop node signal pill from wrapping; restore full-width spread by @jamesarich in #6007
- fix(car): suppress INVISIBLE_MEMBER in CarScreensTest for fdroid build by @jamesarich in #6010
- fix(docs): stop builds from churning tracked docs screenshots by @jamesarich in #6012
- fix(qr): Preserve incoming channels when adding from QR by @jeremiah-k in #6013
- fix(car): notification-only car messaging for production; park templated behind flag by @jamesarich in #6015
- fix(firmware): repair nRF USB firmware update and post-update reconnect by @jamesarich in #6018
- fix(ble): Handle scan registration failure by @jeremiah-k in #6019
- fix(discovery): show disabled reason below Start Analysis button by @jamesarich in #6027
- fix(qr): Stabilize scanner lifecycle and imports by @jeremiah-k in #6040
- fix(connections): label the connecting-card button "Stop Connecting" by @jamesarich in #6046
- fix(messages): Refresh channel placeholders after updates by @jeremiah-k in #6054
- fix(qr): Filter duplicate ADD imports by @jeremiah-k in #6056
- fix(ci): rename skip_author to ignore_usernames in .coderabbit.yaml by @jamesarich in #6069
- fix(qr): Apply channel replacements reliably by @jeremiah-k in #6072
- fix(logs): Allow access to DebugPanel Logs while disconnected by @jamesarich in #6074
- fix: harden against adversarial mesh-fuzz findings (crash, GC-thrash, unbounded growth, OOM) by @jamesarich in #6093
- fix: remove satellite-count chip from node-list metrics row by @jamesarich in #6100
- fix: derive phone-UI units from OS locale, not radio display config by @jamesarich in #6101
- fix(ui): align AdaptiveTwoPane split to the adaptive directive breakpoint by @jamesarich in #6112
- fix(settings): Apply manual channel writes in order by @jeremiah-k in #6077
- fix(settings): Generate fresh PSK for named manual channels by @jeremiah-k in #6076
- fix(discovery): let default-channel users start a scan by @jamesarich in #6120
- fix(discovery): ship a fresh LoRaConfig when switching to a beacon's preset by @jamesarich in #6135
- fix(runtime): harden BLE profile, OTA setup, and DB access by @jeremiah-k in #6126
- fix(messaging): use stored contact_key to avoid duplicate LazyColumn key crash (#6131) by @jamesarich in #6142
- fix(metrics): air-quality chart legend follows plotted data, not selection by @jamesarich in #6145
- fix(firmware): Keep bundled release discovery available by @jeremiah-k in #6082
- fix(dfu): Detect legacy bootloaders before secure fallback by @jeremiah-k in #6079
- fix(firmware): Retry ESP32 OTA service connections cleanly by @jeremiah-k in #6081
- fix(database): recover firmware metadata reads after DB pool churn by @jeremiah-k in #6177
- fix: address 2.8.0 release-audit findings by @jamesarich in #6189
- fix: keep node-mute authoritative over @mentions by @jamesarich in #6190
- fix: dedup node lists to prevent LazyColumn duplicate-key crash by @jamesarich in #6193
- fix(discovery): restore radio home config after an interrupted scan by @jamesarich in #6192
- fix(service): route notification quick-replies through the send pipeline; drop dead parcelize plugin by @jamesarich in #6196
- fix(firmware): never offer an alpha release older than current stable by @jamesarich in #6198
- fix(settings): keep the Debug Panel accessible while disconnected by @jamesarich in #6199
- fix(database): force Room single-connection pool on all platforms by @jamesarich in #6202
- fix(dfu): harden Legacy nRF52 recovery after BLE stalls by @jeremiah-k in #6201
- fix(dfu): classify disconnects from failed Legacy writes by @jeremiah-k in #6209
- fix(database): migrate device identity across firmware 2.8 renumbering by @jamesarich in #6228
- fix(database): make completed cross-transport merges retry-idempotent by @jamesarich in #6231
- fix(database): route all one-shot DB writes through the merge drain barrier by @jamesarich in #6233
- fix(database): make the injected DiscoveryDao follow the active database by @jamesarich in #6236
- fix(agents): datadog-rum-investigator blocked by Datadog MCP UUID mount prefix by @jamesarich in #6241
- Fix: add back navigation to Clean Node Database screen by @jamesarich in #6264
- fix: stabilize traceroute map node identity & fix log metric alignment by @jamesarich in #6270
- fix(connections): show device long names in the connection manager (#5808) by @jamesarich in #6271
- fix: adopt 2024 EPA PM2.5 AQI breakpoints for cross-platform alignment by @jamesarich in #6273
- fix(analytics): restore Datadog RUM network tracking (google) & unify service name by @jamesarich in #6280
- fix(connections): use a segmented button for transport selection by @jamesarich in #6285
- fix: silence false-positive Instantiatable lint on ExtensionAppFunctionService by @jamesarich in #6293
- fix: label channel share FAB "Import/Export" and announce Close when expanded by @jamesarich in #6303
- fix: normalize F-Droid QR camera frames by @RCGV1 in #6319
- fix: preserve add mode in legacy channel URLs by @RCGV1 in #6320
- fix: align channel QR share contract by @RCGV1 in #6325
- fix: keep cached data flowing when api.meshtastic.org is down by @jamesarich in #6335
- Fix literal backslashes in strings with escaped apostrophes by @thebentern in #6336
- fix(map): allow editing/deleting your own locked waypoint by @jamesarich in #6344
- fix(waypoint): reject non-owner modification of a stored locked waypoint by @jamesarich in #6348
- fix(nodes): refresh distance when display units change by @CatSu-OSM in #6351
- fix(map): retain camera across tab navigation by @CatSu-OSM in #6352
- fix(database): reduce write-lane pressure from one-shot reads by @jeremiah-k in #6255
- fix(nav): register /wifi-provision and /discovery as https App Links by @jamesarich in #6365
- fix(node): stop metric-card trailing values crushing to one-char-per-line by @jamesarich in #6374
- fix(node-metrics): apply full typography style instead of fontSize-only by @jamesarich in #6375
- fix(node): respect display units for position ground speed by @jamesarich in #6376
- fix(node): reconcile stale identity replays after renumbering by @jeremiah-k in #6259
- fix(ui): add horizontal padding for position flags list item by @dzmpr in #6369
- fix(messaging): reduce composer recomposition and typing jank by @jeremiah-k in #6318
- fix(ble): harden reconnect sessions and Android scan lifecycle by @jeremiah-k in #6384
- fix(settings): stop dropping admin config responses (0% stall, missing remote channels) by @jamesarich in #6391
- fix(hardware): throttle repeated catalog refreshes for cache misses by @jeremiah-k in #6399
- fix(firmware): decode manifests independent of content type by @jeremiah-k in #6400
- fix(firmware): don't treat unparseable version as "too old" (#3726) by @jamesarich in #6408
- fix(channels): store channel set per-device to stop cross-device duplicates (#4623) by @jamesarich in #6409
- fix(android): avoid retaining activity in Coil singleton factory by @jeremiah-k in #6403
- fix(messaging): use mesh time for message timestamps and grouping by @jamesarich in #6422
- fix(strings): correct English subnet label by @jamesarich in #6425
- fix(android): avoid resource stalls in connection status by @jeremiah-k in #6398
- fix(node): show node counts without truncation by @jamesarich in #6433
- fix(model): gate TAK module config on firmware 2.8.0 by @jamesarich in #6435
- fix(data): don't let coarse position reports overwrite precise coordinates by @jamesarich in #6432
- fix(car): drop CarAppService from production manifests to satisfy Play car-app review by @jamesarich in #6438
📝 Other Changes
- refactor(takserver): commonize TAK SDK pipeline, drop redundant zstd/xpp3 deps by @jamesarich in #5871
- refactor(settings): remove Traffic Management module config by @jamesarich in #5878
- refactor(firmware): dedupe BLE/DFU OTA transport + handler boilerplate by @jamesarich in #5918
- refactor(data): consolidate bundled-asset loading behind BundledAssetReader by @jamesarich in #5921
- refactor(core:ui): drop redundant SinglePaneSceneStrategy from NavDisplay by @jamesarich in #5934
- refactor: drop two over-engineered seams (enum + stdlib Base64) by @jamesarich in #5945
- refactor(ui): migrate MapView dialog to Compose M3 + drop legacy material dependency by @jamesarich in #5988
- refactor(settings): replace SimpleDateFormat with kotlinx-datetime by @jamesarich in #5992
- refactor(car): drop dead FuzzyNodeNameResolver duplicate by @jamesarich in #5994
- refactor(qr): apply channel imports atomically via edit-settings transaction by @jamesarich in #6170
- refactor(di): drop the F-Droid ApiService stub, use the real API client in both flavors by @jamesarich in #6226
- refactor(map): adopt maps-compose 8.4.0 stock clustering, drop custom renderer workaround by @jamesarich in #6301
- refactor(map): migrate custom overlays to the maps-utils 5.0 data layer by @jamesarich in #6304
- refactor(ui): remove StatusSurface scrim behind status-colored chips by @jamesarich in #6367
- perf(docs): skip Dokka when no API sources changed, drop test modules from aggregation by @jamesarich in #6412
- fix(desktop): restore eager JBR javaHome pin for ProGuard packaging by @jamesarich in #6414
New Contributors
- @LesterCheng made their first contribution in #5752
- @dubsector made their first contribution in #5986
- @garthvh made their first contribution in #6088
- @coderabbitai[bot] made their first contribution in #6180
- @madeofstown made their first contribution in #6210
- @joeyleake made their first contribution in #6218
- @sashko made their first contribution in #6315
- @CatSu-OSM made their first contribution in #6351
- @dzmpr made their first contribution in #6369
Full Changelog: v2.7.14...v2.8.0-open.3