:feature:discovery
Overview
The :feature:discovery module implements Local Mesh Discovery: the app cycles the connected radio through a queue of LoRa modem presets, dwells on each for a configured duration while collecting packets, then persists and ranks the results so the user can see which preset (or beacon-advertised custom channel) has the most active mesh nearby. Sessions are stored via DiscoveryDao and can be revisited, mapped, summarised (AI or algorithmic), and exported.
Targets: Android · JVM (Desktop) · iOS (via meshtastic.kmp.feature convention plugin)
Scan Workflow
DiscoveryScanEngine— core scan engine. Cycles through a queue ofScanTargets, dwells on each while collecting packets, and persists aggregated results viaDiscoveryDao.DiscoveryScanState— state machine for the scan lifecycle:Idle → Preparing → Shifting → [Reconnecting] → Dwell → … → Analysis → Complete, withCancelling/Restoring/Failed/Pausedside paths.ScanTarget— one queue entry.channel == nullis a public-preset target; a non-null channel is a beacon-advertised custom channel: the engine tunes the radio's primary channel to that name+PSK (and region) for the dwell, then restores it.DiscoveryRankingEngine(scan/) — ranks preset results by unique node count, neighbor diversity, non-duplicate packet count, and SNR.Check24GhzCapability(scan/) — layered heuristic that determines whether the connected radio supports 2.4 GHz LoRa (SX1280), returningSupported/Unsupported/Unknown.
ViewModels & Screens
| ViewModel | Screen (ui/) |
Purpose |
|---|---|---|
DiscoveryViewModel |
DiscoveryScanScreen |
Scan setup and live progress (drives DiscoveryScanEngine) |
DiscoverySummaryViewModel |
DiscoverySummaryScreen |
Post-scan session summary, ranking, and export |
DiscoveryMapViewModel |
DiscoveryMapScreen |
Discovered-node map with per-preset filter chips (rendered via LocalDiscoveryMapProvider from core:ui) |
DiscoveryHistoryViewModel |
DiscoveryHistoryScreen |
Past session list with delete |
DiscoveryHistoryDetailViewModel |
DiscoveryHistoryDetailScreen |
Detail view of one stored session |
Navigation entries are registered by discoveryGraph() in navigation/DiscoveryNavigation.kt (Navigation 3, DiscoveryRoute.* keys).
Summary Layer: AI vs Algorithmic
Same Google-flavor Gemini Nano vs fallback split as :feature:docs:
ai/DiscoverySummaryAiProvider— interface for natural-language session/preset summaries.ai/AlgorithmicSummaryProvider— deterministic fallback delegating toDiscoverySummaryGenerator. Registered withbinds = []; each platform binds the interface explicitly: the Androidgoogleflavor bindsGeminiNanoSummaryProvider(in:androidApp), whilefdroid, Desktop, and iOS bind the algorithmic provider.ai/LoRaPresetReference— modem-preset reference data (bandwidth, spreading factor, link budget) used to enrich AI prompts and algorithmic summaries.
Export
Multiplatform export path in export/:
DiscoveryExporter— interface:export(DiscoveryExportData): ExportResult(success = bytes + MIME type + filename).DiscoveryReportFormatter— shared formatting of session/preset report lines and filenames.rememberExportSaver()/ExportSaverLauncher—expect/actualfile-save seam per platform (ExportSaver.android.kt→ SAF document picker,ExportSaver.jvm.kt→ file dialog,ExportSaver.ios.kt).PdfDiscoveryExporter(androidMain) renders a PDF report;TextDiscoveryExporter(jvmMain) renders plain text.
Mesh Beacon Invitations
UI for port-37 Mesh Beacon join invitations (ui/component/):
MeshBeaconInvitationCard— a received beacon offer with its advertised channel/region/preset; the user can survey the mesh first, join it, or dismiss. Shown onDiscoveryScanScreen.BeaconChannelsCard— scan-setup section listing distinct beacon-advertised custom channels; selecting a row adds a custom-channelScanTarget.
Key Dependencies
From feature/discovery/build.gradle.kts (commonMain):
core:common,core:data,core:database,core:di,core:model,core:navigation,core:network,core:prefs,core:repository,core:resources,core:service,core:uikotlinx.collections.immutableorg.meshtastic:protobufs(Maven artifact)