From ece771edb06f0110050baac322a093214b89f6c8 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Tue, 19 May 2026 09:06:12 -0500 Subject: [PATCH] docs: comprehensive accuracy audit and CI fix (#5489) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../org/meshtastic/buildlogic/DocsTasks.kt | 2 +- docs/_config.yml | 80 +++++++++--------- docs/_includes/language_switcher.html | 45 ++++++---- docs/assets/screenshots/README.md | 1 - .../messages-and-channels_channel_list.png | Bin 77302 -> 0 bytes .../screenshots/messages_channel_info.png | Bin 1656 -> 0 bytes .../settings-radio-user_lora_config.png | Bin 12667 -> 0 bytes docs/developer.md | 1 - docs/developer/adding-a-feature-module.md | 11 +-- docs/developer/architecture.md | 8 +- docs/developer/codebase.md | 29 ++++--- docs/developer/contributing.md | 23 +++-- docs/developer/navigation-and-deep-links.md | 22 ++--- docs/developer/persistence.md | 26 ++++-- docs/developer/testing.md | 8 +- docs/developer/transport.md | 16 ++-- docs/translations.md | 20 ++--- docs/user.md | 1 - docs/user/connections.md | 25 ++++-- docs/user/desktop.md | 30 +++++-- docs/user/discovery.md | 2 +- docs/user/firmware.md | 2 + docs/user/messages-and-channels.md | 11 ++- docs/user/mqtt.md | 11 ++- docs/user/nodes.md | 12 +-- docs/user/settings-module-admin.md | 8 +- docs/user/settings-radio-user.md | 30 ++++--- docs/user/signal-meter.md | 8 +- 28 files changed, 247 insertions(+), 185 deletions(-) delete mode 100644 docs/assets/screenshots/messages-and-channels_channel_list.png delete mode 100644 docs/assets/screenshots/messages_channel_info.png delete mode 100644 docs/assets/screenshots/settings-radio-user_lora_config.png diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/DocsTasks.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/DocsTasks.kt index 450b05e3b..15cbdca9e 100644 --- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/DocsTasks.kt +++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/DocsTasks.kt @@ -61,7 +61,7 @@ class DocsTasks : Plugin { bundleDir.set(outputDir.map { it.dir("common") }) schemaFile.set( project.rootProject.layout.projectDirectory - .file("specs/003-app-docs-markdown/contracts/keyword-index-schema.json") + .file("specs/20260507-161858-app-docs-markdown/contracts/keyword-index-schema.json") ) } diff --git a/docs/_config.yml b/docs/_config.yml index 4b76bae58..bd7c6dc00 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -28,12 +28,12 @@ color_scheme: meshtastic # Default front-matter for pages in subdirectories defaults: - scope: - path: "user" + path: "user/" values: parent: User Guide layout: default - scope: - path: "developer" + path: "developer/" values: parent: Developer Guide layout: default @@ -41,229 +41,229 @@ defaults: # They use a dedicated locale layout with a back-link to the English version. # Auto-generated from Android app locales (values-* resource dirs). - scope: - path: "ar" + path: "ar/" values: layout: locale_page locale: ar nav_exclude: true - scope: - path: "be" + path: "be/" values: layout: locale_page locale: be nav_exclude: true - scope: - path: "bg" + path: "bg/" values: layout: locale_page locale: bg nav_exclude: true - scope: - path: "ca" + path: "ca/" values: layout: locale_page locale: ca nav_exclude: true - scope: - path: "cs" + path: "cs/" values: layout: locale_page locale: cs nav_exclude: true - scope: - path: "de" + path: "de/" values: layout: locale_page locale: de nav_exclude: true - scope: - path: "el" + path: "el/" values: layout: locale_page locale: el nav_exclude: true - scope: - path: "es" + path: "es/" values: layout: locale_page locale: es nav_exclude: true - scope: - path: "et" + path: "et/" values: layout: locale_page locale: et nav_exclude: true - scope: - path: "fi" + path: "fi/" values: layout: locale_page locale: fi nav_exclude: true - scope: - path: "fr" + path: "fr/" values: layout: locale_page locale: fr nav_exclude: true - scope: - path: "ga" + path: "ga/" values: layout: locale_page locale: ga nav_exclude: true - scope: - path: "gl" + path: "gl/" values: layout: locale_page locale: gl nav_exclude: true - scope: - path: "he" + path: "he/" values: layout: locale_page locale: he nav_exclude: true - scope: - path: "hr" + path: "hr/" values: layout: locale_page locale: hr nav_exclude: true - scope: - path: "ht" + path: "ht/" values: layout: locale_page locale: ht nav_exclude: true - scope: - path: "hu" + path: "hu/" values: layout: locale_page locale: hu nav_exclude: true - scope: - path: "is" + path: "is/" values: layout: locale_page locale: is nav_exclude: true - scope: - path: "it" + path: "it/" values: layout: locale_page locale: it nav_exclude: true - scope: - path: "ja" + path: "ja/" values: layout: locale_page locale: ja nav_exclude: true - scope: - path: "ko" + path: "ko/" values: layout: locale_page locale: ko nav_exclude: true - scope: - path: "lt" + path: "lt/" values: layout: locale_page locale: lt nav_exclude: true - scope: - path: "nl" + path: "nl/" values: layout: locale_page locale: nl nav_exclude: true - scope: - path: "no" + path: "no/" values: layout: locale_page locale: no nav_exclude: true - scope: - path: "pl" + path: "pl/" values: layout: locale_page locale: pl nav_exclude: true - scope: - path: "pt" + path: "pt/" values: layout: locale_page locale: pt nav_exclude: true - scope: - path: "pt-rBR" + path: "pt-rBR/" values: layout: locale_page locale: pt-rBR nav_exclude: true - scope: - path: "ro" + path: "ro/" values: layout: locale_page locale: ro nav_exclude: true - scope: - path: "ru" + path: "ru/" values: layout: locale_page locale: ru nav_exclude: true - scope: - path: "sk" + path: "sk/" values: layout: locale_page locale: sk nav_exclude: true - scope: - path: "sl" + path: "sl/" values: layout: locale_page locale: sl nav_exclude: true - scope: - path: "sq" + path: "sq/" values: layout: locale_page locale: sq nav_exclude: true - scope: - path: "sr" + path: "sr/" values: layout: locale_page locale: sr nav_exclude: true - scope: - path: "sv" + path: "sv/" values: layout: locale_page locale: sv nav_exclude: true - scope: - path: "tr" + path: "tr/" values: layout: locale_page locale: tr nav_exclude: true - scope: - path: "uk" + path: "uk/" values: layout: locale_page locale: uk nav_exclude: true - scope: - path: "zh-rCN" + path: "zh-rCN/" values: layout: locale_page locale: zh-rCN nav_exclude: true - scope: - path: "zh-rTW" + path: "zh-rTW/" values: layout: locale_page locale: zh-rTW diff --git a/docs/_includes/language_switcher.html b/docs/_includes/language_switcher.html index 1b0cf4238..3fe3bb662 100644 --- a/docs/_includes/language_switcher.html +++ b/docs/_includes/language_switcher.html @@ -15,44 +15,56 @@ {% assign locales = site.data.locales %} {% if locales and current_path %} +{% assign path_parts = current_path | split: "/" %} +{% assign first_segment = path_parts[0] %} + +{% comment %} Build the list of available translations first {% endcomment %} +{% assign has_translations = false %} + +{% if locales[first_segment] %} + {% comment %} We're on a translated page — English link is always available {% endcomment %} + {% assign has_translations = true %} + {% assign remaining_parts = path_parts | slice: 1, path_parts.size %} + {% assign en_path = remaining_parts | join: "/" | replace: ".md", "" %} +{% else %} + {% comment %} Check if any translated version exists {% endcomment %} + {% assign en_relative = current_path | replace: ".md", "" %} + {% for locale in locales %} + {% assign locale_code = locale[0] %} + {% assign locale_file = locale_code | append: "/" | append: en_relative | append: ".md" %} + {% for p in site.pages %} + {% if p.path == locale_file %} + {% assign has_translations = true %} + {% break %} + {% endif %} + {% endfor %} + {% if has_translations %}{% break %}{% endif %} + {% endfor %} +{% endif %} + +{% if has_translations %}
🌐 English
{% endif %} +{% endif %} diff --git a/docs/assets/screenshots/README.md b/docs/assets/screenshots/README.md index 5fb2efe28..edf5ca8d1 100644 --- a/docs/assets/screenshots/README.md +++ b/docs/assets/screenshots/README.md @@ -30,7 +30,6 @@ Then copy the relevant light-mode PNGs from the reference directory. The Examples: - `onboarding_welcome.png` - `connections_bluetooth_scan.png` -- `messages-and-channels_channel_list.png` - `firmware_disclaimer.png` ## Guidelines diff --git a/docs/assets/screenshots/messages-and-channels_channel_list.png b/docs/assets/screenshots/messages-and-channels_channel_list.png deleted file mode 100644 index 4054990a14befb64349f07d48b60b726ce2620b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77302 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�!lu5A==3!;JwBGOfwf`AZuRgn^^ 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 diff --git a/docs/assets/screenshots/messages_channel_info.png b/docs/assets/screenshots/messages_channel_info.png deleted file mode 100644 index 6f022378f80c00b3072e2cf319e6a6a708aef466..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1656 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 SQ3rZ({H}NXa{k4;kN*!m*bcJ* diff --git a/docs/developer.md b/docs/developer.md index 3802081cd..19785e5c7 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -3,7 +3,6 @@ title: Developer Guide layout: default nav_order: 2 has_children: true -parent: "" --- # Developer Guide diff --git a/docs/developer/adding-a-feature-module.md b/docs/developer/adding-a-feature-module.md index e2bc3634d..ae290dbda 100644 --- a/docs/developer/adding-a-feature-module.md +++ b/docs/developer/adding-a-feature-module.md @@ -23,15 +23,10 @@ mkdir -p feature/my-feature/src/{commonMain,commonTest,androidMain,jvmMain,iosMa ```kotlin plugins { alias(libs.plugins.meshtastic.kmp.feature) - alias(libs.plugins.meshtastic.kotlinx.serialization) - id("meshtastic.kmp.jvm.android") } kotlin { - android { - namespace = "org.meshtastic.feature.myfeature" - androidResources.enable = false - } + androidLibrary { withHostTest { } } sourceSets { commonMain.dependencies { @@ -82,8 +77,8 @@ class FeatureMyFeatureModule ## 5. Register DI in App/Desktop Add your module to: -- `app/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.kt` -- `desktop/src/main/kotlin/org/meshtastic/desktop/di/DesktopKoinModule.kt` +- `androidApp/src/main/kotlin/org/meshtastic/app/di/AppKoinModule.kt` +- `desktopApp/src/main/kotlin/org/meshtastic/desktop/di/DesktopKoinModule.kt` ## 6. Add Navigation Routes diff --git a/docs/developer/architecture.md b/docs/developer/architecture.md index c3d5395ff..8d1bacc1b 100644 --- a/docs/developer/architecture.md +++ b/docs/developer/architecture.md @@ -16,7 +16,7 @@ The Meshtastic Android/Desktop/iOS application follows a modular Kotlin Multipla ``` ┌─────────────────────────────────────────────┐ -│ app / desktop │ Platform entry points +│ androidApp / desktopApp │ Platform entry points ├─────────────────────────────────────────────┤ │ feature/* modules │ UI + Business Logic ├─────────────────────────────────────────────┤ @@ -28,7 +28,7 @@ The Meshtastic Android/Desktop/iOS application follows a modular Kotlin Multipla ## Module Categories -### `app/` — Android Application +### `androidApp/` — Android Application The Android application entry point: - Activity, Application, and Manifest definitions @@ -36,13 +36,13 @@ The Android application entry point: - Flavor-specific bindings (`google/`, `fdroid/`) - Android-only integrations (widgets, services) -### `desktop/` — Desktop JVM Application +### `desktopApp/` — Desktop JVM Application The Desktop (Linux/macOS/Windows) entry point: - Compose Desktop window management - Desktop-specific DI (`DesktopKoinModule`) - Platform stubs for Android-only capabilities -- Serial transport implementation +- BLE (Kable), Serial, and TCP transport implementations ### `feature/*` — Feature Modules diff --git a/docs/developer/codebase.md b/docs/developer/codebase.md index 045223dfa..9f67c6e97 100644 --- a/docs/developer/codebase.md +++ b/docs/developer/codebase.md @@ -16,11 +16,11 @@ Repository layout, namespacing conventions, and build system overview. ``` Meshtastic-Android/ -├── app/ # Android application module +├── androidApp/ # Android application module │ ├── src/main/ # Shared Android code │ ├── src/google/ # Google Play flavor (Gemini, proprietary) │ └── src/fdroid/ # F-Droid flavor (FOSS-only) -├── desktop/ # Desktop JVM application +├── desktopApp/ # Desktop JVM application ├── feature/ # Feature modules (KMP) │ ├── intro/ │ ├── messaging/ @@ -33,22 +33,27 @@ Meshtastic-Android/ │ ├── wifi-provision/ │ └── widget/ ├── core/ # Core infrastructure modules (KMP) +│ ├── api/ +│ ├── barcode/ +│ ├── ble/ │ ├── common/ -│ ├── navigation/ -│ ├── ui/ -│ ├── resources/ -│ ├── model/ │ ├── data/ │ ├── database/ │ ├── datastore/ -│ ├── prefs/ -│ ├── repository/ -│ ├── service/ │ ├── di/ +│ ├── domain/ +│ ├── model/ +│ ├── navigation/ │ ├── network/ -│ ├── ble/ +│ ├── nfc/ +│ ├── prefs/ │ ├── proto/ -│ └── testing/ +│ ├── repository/ +│ ├── resources/ +│ ├── service/ +│ ├── takserver/ +│ ├── testing/ +│ └── ui/ ├── build-logic/ # Convention plugins and build helpers │ └── convention/ ├── docs/ # Documentation source (markdown) @@ -115,7 +120,7 @@ Located in `build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/`: ./gradlew assembleGoogleDebug assembleFdroidDebug # Desktop run -./gradlew :desktop:run +./gradlew :desktopApp:run ``` ## Version Catalog Highlights diff --git a/docs/developer/contributing.md b/docs/developer/contributing.md index 7783fac1a..f5d0bbaf6 100644 --- a/docs/developer/contributing.md +++ b/docs/developer/contributing.md @@ -14,15 +14,26 @@ Guidelines for contributing to the Meshtastic Android/Desktop/iOS project. ## Branch Naming -Feature branches follow the pattern: -``` -{issue-number}-{short-description} -``` +Branches use conventional-commit style prefixes: + +| Prefix | Use for | +|--------|---------| +| `feat/` | New user-visible behavior | +| `fix/` | Bug fixes | +| `refactor/` | Code structure changes | +| `chore/` | Tooling, deps, CI, cleanup | +| `docs/` | Documentation only | +| `build/` | Build system changes | +| `ci/` | CI workflow changes | +| `test/` | Test additions or fixes | +| `deps/` | Dependency updates | + +Numeric spec prefixes (e.g., `003-app-docs-markdown`) are also valid for spec-driven work. Examples: -- `003-app-docs-markdown` -- `001-local-mesh-discovery` +- `feat/desktop-ble-transport` - `fix/bluetooth-reconnect` +- `003-app-docs-markdown` ## Development Workflow diff --git a/docs/developer/navigation-and-deep-links.md b/docs/developer/navigation-and-deep-links.md index 08622c60a..c86afdf85 100644 --- a/docs/developer/navigation-and-deep-links.md +++ b/docs/developer/navigation-and-deep-links.md @@ -24,7 +24,7 @@ interface Graph : Route // Graph roots for navigation hierarchies @Serializable sealed interface SettingsRoute : Route { - @Serializable data class SettingsGraph(val destNum: Int?) : SettingsRoute, Graph + @Serializable data class Settings(val destNum: Int? = null) : SettingsRoute, Graph @Serializable data object DeviceConfiguration : SettingsRoute @Serializable data object HelpDocs : SettingsRoute @Serializable data class HelpDocPage(val pageId: String) : SettingsRoute @@ -54,7 +54,7 @@ meshtastic://meshtastic/{path} | URI Path | Route | Notes | |----------|-------|-------| -| `/settings` | `SettingsRoute.SettingsGraph(null)` | Settings root | +| `/settings` | `SettingsRoute.Settings(null)` | Settings root | | `/settings/helpDocs` | `SettingsRoute.HelpDocs` | Docs browser | | `/settings/helpDocs/{pageId}` | `SettingsRoute.HelpDocPage(pageId)` | Specific doc page | | `/settings/help-docs` | `SettingsRoute.HelpDocs` | Compatibility alias | @@ -70,7 +70,7 @@ Deep links synthesize a full backstack, not just the target screen: ```kotlin // /settings/helpDocs/messages-and-channels produces: listOf( - SettingsRoute.SettingsGraph(null), + SettingsRoute.Settings(null), SettingsRoute.HelpDocs, SettingsRoute.HelpDocPage("messages-and-channels"), ) @@ -90,9 +90,9 @@ This ensures the user can navigate "up" correctly. Each feature module provides entries via an extension function: ```kotlin -fun EntryProviderScope<*>.docsEntries(backStack: NavBackStack) { +fun EntryProviderScope.docsEntries(backStack: NavBackStack) { entry { DocsBrowserScreen(backStack) } - entry { DocsPageRouteScreen(it.pageId, backStack) } + entry { route -> DocsPageRouteScreen(route.pageId, backStack) } } ``` @@ -105,17 +105,5 @@ Deep link routing is tested in: core/navigation/src/commonTest/kotlin/org/meshtastic/core/navigation/DeepLinkRouterTest.kt ``` -Example: -```kotlin -@Test -fun `help docs deep link routes correctly`() { - val result = DeepLinkRouter.route(CommonUri.parse("meshtastic://meshtastic/settings/helpDocs")) - assertEquals( - listOf(SettingsRoute.SettingsGraph(null), SettingsRoute.HelpDocs), - result, - ) -} -``` - --- diff --git a/docs/developer/persistence.md b/docs/developer/persistence.md index 9b42538e9..4f1f1f472 100644 --- a/docs/developer/persistence.md +++ b/docs/developer/persistence.md @@ -35,20 +35,30 @@ The primary structured data store: | Entity | Description | |--------|-------------| -| Nodes | All known mesh nodes and metadata | -| Messages | Message history (channel and direct) | -| Waypoints | Shared geographic points | -| Telemetry | Device, environment, power metrics | -| Channels | Channel configurations | +| `NodeEntity` | All known mesh nodes and their metadata | +| `MyNodeEntity` | The local node's own info | +| `Packet` | Message history (channel and direct), waypoints, and telemetry data | +| `ContactSettings` | Per-contact mute and read-state | +| `ReactionEntity` | Emoji reactions on messages | +| `MeshLog` | Raw mesh protocol logs | +| `MetadataEntity` | Device metadata (firmware version, hardware model) | +| `QuickChatAction` | User-configured quick-chat messages | +| `DeviceHardwareEntity` | Cached device hardware catalog | +| `FirmwareReleaseEntity` | Cached firmware release info | +| `TracerouteNodePositionEntity` | Traceroute hop position data | + +> 💡 **Note:** Waypoints, telemetry, and channel data are stored within the `Packet` entity (using the `port_num` field to distinguish packet types) rather than in separate tables. ## DataStore Preferences **Module:** `core:datastore` For lightweight key-value preferences: -- Connection state -- Last connected device -- UI preferences +- Local radio configuration (LocalConfig proto) +- Module configuration (ModuleConfig proto) +- Channel set data +- Local statistics +- Recently connected device addresses ## Core Prefs diff --git a/docs/developer/testing.md b/docs/developer/testing.md index 816ab6527..d1ed344fc 100644 --- a/docs/developer/testing.md +++ b/docs/developer/testing.md @@ -55,12 +55,12 @@ Located in `commonTest` or `jvmTest` source sets. ### Screenshot Tests -Preferred: **Roborazzi** (Gradle-native, Ubuntu CI compatible) -Fallback: **Paparazzi** (Android-view-centric) +Uses Android Gradle Plugin's native screenshot testing framework: ```bash -./gradlew recordDocsScreenshots # Record golden images -./gradlew verifyDocsScreenshots # Compare against goldens +./gradlew :screenshot-tests:updateDebugScreenshotTest # Record golden images +./gradlew :screenshot-tests:validateDebugScreenshotTest # Compare against goldens +./gradlew :screenshot-tests:copyDocsScreenshots # Copy reference images to docs pipeline ``` ## Test Organization diff --git a/docs/developer/transport.md b/docs/developer/transport.md index 15467f0ba..82faaa269 100644 --- a/docs/developer/transport.md +++ b/docs/developer/transport.md @@ -24,9 +24,9 @@ App ← RadioController → Transport (BLE | Serial | TCP) ## Bluetooth Low Energy (BLE) **Module:** `core:ble` -**Platforms:** Android, (planned: iOS) +**Platforms:** Android, Desktop (JVM via Kable), iOS (planned) -The primary transport for Android mobile devices: +The primary transport for mobile devices and also available on desktop: - Service discovery for Meshtastic GATT services - Characteristic-based read/write for protobuf packets - Connection state management and automatic reconnection @@ -35,7 +35,7 @@ The primary transport for Android mobile devices: ### Key Classes - `core/ble/` — BLE scanning, connection, and GATT operations -- Platform-specific implementations in `androidMain` +- Platform-specific implementations in `androidMain` and `jvmMain` (Kable) ## USB Serial @@ -51,7 +51,7 @@ Serial communication over USB: ### Key Classes - Serial prober and transport factory in `core/network` -- Desktop-specific serial in `desktop/src/main/kotlin/.../radio/` +- Desktop-specific serial in `desktopApp/src/main/kotlin/.../radio/` ## TCP/IP @@ -70,13 +70,17 @@ The `RadioTransportFactory` interface abstracts transport creation: ```kotlin interface RadioTransportFactory { - fun createTransport(config: TransportConfig): RadioTransport + val supportedDeviceTypes: List + fun createTransport(address: String, service: RadioInterfaceService): RadioTransport + fun isMockTransport(): Boolean + fun isAddressValid(address: String?): Boolean + fun toInterfaceAddress(interfaceId: InterfaceId, rest: String): String } ``` Platform-specific implementations: - **Android:** Supports BLE + USB + TCP -- **Desktop:** Supports USB + TCP (no BLE) +- **Desktop:** Supports BLE (Kable) + USB + TCP - **iOS:** Planned BLE + TCP ## Connection Lifecycle diff --git a/docs/translations.md b/docs/translations.md index 347d70d00..feda7aaa5 100644 --- a/docs/translations.md +++ b/docs/translations.md @@ -10,14 +10,17 @@ This documentation is translated by the community via [Crowdin](https://crowdin. ## Available Languages +{% assign any_locale_exists = false %} {% for locale in site.data.locales %} {% assign locale_code = locale[0] %} {% assign locale_info = locale[1] %} -{% assign locale_index = locale_code | append: "/index.md" %} +{% assign locale_prefix = locale_code | append: "/" %} {% assign has_content = false %} {% for p in site.pages %} - {% if p.path contains locale_code %} + {% assign page_path_check = p.path | slice: 0, locale_prefix.size %} + {% if page_path_check == locale_prefix %} {% assign has_content = true %} + {% assign any_locale_exists = true %} {% break %} {% endif %} {% endfor %} @@ -27,19 +30,6 @@ This documentation is translated by the community via [Crowdin](https://crowdin. {% endif %} {% endfor %} -{% comment %} Show notice if no translations exist yet {% endcomment %} -{% assign any_locale_exists = false %} -{% for locale in site.data.locales %} - {% assign locale_code = locale[0] %} - {% for p in site.pages %} - {% if p.path contains locale_code %} - {% assign any_locale_exists = true %} - {% break %} - {% endif %} - {% endfor %} - {% if any_locale_exists %}{% break %}{% endif %} -{% endfor %} - {% unless any_locale_exists %} > No translations available yet. Want to help? [Join our Crowdin project →](https://crowdin.com/project/meshtastic-android) {% endunless %} diff --git a/docs/user.md b/docs/user.md index 72fcfbf5b..1b88fac94 100644 --- a/docs/user.md +++ b/docs/user.md @@ -3,7 +3,6 @@ title: User Guide layout: default nav_order: 1 has_children: true -parent: "" --- # User Guide diff --git a/docs/user/connections.md b/docs/user/connections.md index 574433b50..0f69adb81 100644 --- a/docs/user/connections.md +++ b/docs/user/connections.md @@ -80,25 +80,36 @@ Some Meshtastic radios support WiFi connectivity, allowing TCP-based connections 3. Enter the radio's IP address and port (default: 4403). 4. Tap **Connect**. +![WiFi scanning for devices](/assets/screenshots/connections_wifi_scanning.png) + +When a device is found, it appears in the connection list: + +![WiFi device found](/assets/screenshots/connections_wifi_device_found.png) + +A successful connection is confirmed with a status indicator: + +![WiFi connection success](/assets/screenshots/connections_wifi_success.png) + ### When to Use TCP - Radio is on the same local network - Testing with a simulated radio - Environments where Bluetooth has interference issues -## Connection Priority +## Reconnection Behavior -The app attempts connections in this order: -1. Last successful Bluetooth device -2. USB (if detected) -3. Manual TCP (if configured) +The app reconnects to the **last selected device** on startup. You can manually switch transports from the connections screen at any time. + +To disconnect from a radio, use the disconnect button on the connections screen: + +![Disconnect from radio](/assets/screenshots/connections_disconnect.png) ## Desktop Connections On Desktop (Linux/macOS/Windows), the app supports: -- **USB Serial** — primary connection method +- **Bluetooth (BLE)** — via the Kable library; works on macOS, Linux, and Windows +- **USB Serial** — primary wired connection method - **TCP/IP** — for network-connected radios -- Bluetooth is **not** currently supported on Desktop See [Desktop App](desktop) for platform-specific details and keyboard shortcuts. diff --git a/docs/user/desktop.md b/docs/user/desktop.md index 2734b9ab3..8921fcb3f 100644 --- a/docs/user/desktop.md +++ b/docs/user/desktop.md @@ -24,7 +24,7 @@ The Desktop app shares its core codebase with the Android app through Kotlin Mul ### Linux - Download the `.deb` or `.AppImage` package from the releases page -- Or build from source using `./gradlew :desktop:run` +- Or build from source using `./gradlew :desktopApp:run` ### macOS @@ -53,9 +53,13 @@ For network-connected radios: 1. Enter the radio's IP address and port (default: 4403). 2. Click **Connect**. -### Bluetooth +### Bluetooth (BLE) -> ⚠️ **Note:** Bluetooth is not currently supported on the Desktop app. Use USB or TCP connections. +Bluetooth Low Energy is supported on Desktop via the [Kable](https://github.com/JuulLabs/kable) library: + +1. Ensure your system has a Bluetooth adapter. +2. The app scans for nearby Meshtastic radios automatically. +3. Select your device from the connections screen. ## Feature Parity @@ -65,7 +69,7 @@ For network-connected radios: | Node List | ✓ | ✓ | Full parity | | Map | ✓ | ✓ | Full parity | | Settings | ✓ | ✓ | Full parity | -| Bluetooth | ✓ | ✗ | USB/TCP on desktop | +| Bluetooth (BLE) | ✓ | ✓ | Via Kable on desktop | | Firmware Update OTA | ✓ | ✗ | Use web flasher | | Notifications | ✓ | ✓ | Native OS notifications | | Widgets | ✓ | ✗ | Android-only | @@ -99,13 +103,27 @@ The Desktop app uses the same Compose Multiplatform UI with adaptations for larg The Desktop app provides in-app toggles for controlling which notifications are shown — messages, new nodes, and low battery alerts. Access these from **Settings → Notifications** within the app. +## Built-in Documentation Browser + +The Desktop app includes a built-in documentation browser for quick access to help content without leaving the application. + +![Docs browser with table of contents](/assets/screenshots/docs-browser_toc.png) + +The browser supports full-text search across all documentation: + +![Searching the docs browser](/assets/screenshots/docs-browser_search.png) + +Individual doc pages render with full formatting: + +![A documentation page](/assets/screenshots/docs-browser_page.png) + ## Building from Source ```bash git clone https://github.com/meshtastic/Meshtastic-Android.git cd Meshtastic-Android git submodule update --init -./gradlew :desktop:run +./gradlew :desktopApp:run ``` Requirements: @@ -114,10 +132,10 @@ Requirements: ## Known Limitations -- No Bluetooth support - No OTA firmware updates (use web flasher) - Some Android-specific features (widgets, specific notification channels) are unavailable - Performance may vary on low-spec hardware running Compose Desktop +- BLE bonding is not yet supported on desktop (pairing works without bonding) ## Related Topics diff --git a/docs/user/discovery.md b/docs/user/discovery.md index 55c5d8d34..7a0fba364 100644 --- a/docs/user/discovery.md +++ b/docs/user/discovery.md @@ -96,7 +96,7 @@ The node list itself is a powerful discovery tool when you use its filtering and ### Infrastructure Audit -- Disable **Exclude infrastructure** to see Router, Repeater, and Router Client nodes. +- Disable **Exclude infrastructure** to see Router, Repeater, Router Late, and Client Base nodes. - Check their signal quality and last-heard times to verify your infrastructure nodes are healthy. See [Nodes](nodes) for full details on filtering and sorting options. diff --git a/docs/user/firmware.md b/docs/user/firmware.md index 05fc04169..0b0697ca4 100644 --- a/docs/user/firmware.md +++ b/docs/user/firmware.md @@ -78,6 +78,8 @@ If the update appears frozen: - If truly stuck, power-cycle the radio - Attempt the update again +![Firmware update error](/assets/screenshots/firmware_error.png) + ### Device Won't Boot After Update If your device fails to boot: diff --git a/docs/user/messages-and-channels.md b/docs/user/messages-and-channels.md index 80a7195e5..0f8ed3175 100644 --- a/docs/user/messages-and-channels.md +++ b/docs/user/messages-and-channels.md @@ -42,6 +42,8 @@ Channels support multiple encryption levels: 3. Configure the channel name and encryption key. 4. Share the channel URL/QR code with others who need access. +Tapping a channel shows its details and sharing options. + ## Direct Messages Direct messages (DMs) are point-to-point encrypted communications between two specific nodes. @@ -57,8 +59,11 @@ Direct messages (DMs) are point-to-point encrypted communications between two sp | State | Icon | Meaning | |-------|------|---------| | Queued | ⏳ | Message waiting to be sent | -| Sent | ✓ | Message transmitted to mesh | +| En route | ✓ | Delivered to the radio, awaiting acknowledgment | | Delivered | ✓✓ | Acknowledgment received from recipient | +| Received | ✓ | Message received from the mesh (incoming) | +| S&F Routing | 🔗 | Store & Forward: message being routed through an S&F node | +| S&F Confirmed | 🔗 | Store & Forward: delivery confirmed via S&F node | | Error | ✗ | Delivery failed after retries | ### Delivery Errors @@ -92,9 +97,7 @@ Pre-configured messages for rapid communication: ![Quick chat option](/assets/screenshots/messages_quick_chat.png) -The channel list shows each channel with its latest message preview: - -![Channel list item showing channel name and last message](/assets/screenshots/messages-and-channels_channel_list.png) +The channel list shows each channel with its latest message preview. ### Message Bubbles diff --git a/docs/user/mqtt.md b/docs/user/mqtt.md index f79bffc3e..94c4c9db1 100644 --- a/docs/user/mqtt.md +++ b/docs/user/mqtt.md @@ -2,7 +2,7 @@ title: MQTT nav_order: 11 last_updated: 2026-05-13 -description: Bridge your mesh to the internet — MQTT broker setup, encryption layers, JSON output, and map reporting. +description: Bridge your mesh to the internet — MQTT broker setup, encryption layers, and map reporting. aliases: - mqtt - internet-bridge @@ -46,7 +46,7 @@ A gateway node with internet access (WiFi or Ethernet) publishes mesh messages t | Password | Broker authentication | large4cats | | Root Topic | Base topic for messages | msh | | Encryption | Encrypt MQTT payload | Enabled | -| JSON Output | Publish JSON alongside protobuf | Disabled | +| ~~JSON Output~~ | ⚠️ **Deprecated** — JSON packet support has been removed from firmware; this field is ignored | Disabled | | TLS | Secure connection to broker | Disabled | | Map Reporting | Report position to public map | Disabled | @@ -83,14 +83,13 @@ Configure per-channel which directions are active to control message flow and ai ## Message Formats -MQTT supports two message formats: +MQTT uses protobuf message format: | Format | Description | Use case | |--------|-------------|----------| -| **Protobuf** (default) | Binary Meshtastic protobuf encoding | Node-to-node mesh bridging | -| **JSON** | Human-readable JSON encoding | Home automation, logging, custom integrations | +| **Protobuf** | Binary Meshtastic protobuf encoding | Node-to-node mesh bridging | -When **JSON Output** is enabled, the gateway publishes both protobuf and JSON versions of each message to separate topics. +> ⚠️ **Note:** JSON output support was removed from firmware. The `json_enabled` setting is still visible in the app for legacy compatibility but has no effect on current firmware versions. ## Encryption & Privacy diff --git a/docs/user/nodes.md b/docs/user/nodes.md index b66a94b6e..ec5f2ebd9 100644 --- a/docs/user/nodes.md +++ b/docs/user/nodes.md @@ -39,11 +39,13 @@ Nodes can be configured with different roles that affect their mesh behavior: | Role | Description | |------|-------------| | Client | Standard end-user device | +| Client Base | Treats favorited-node traffic as Router Late priority; all other traffic as Client | | Client Mute | Receives but doesn't retransmit | | Client Hidden | Like Client Mute, plus hides from node list | | Router | Prioritizes message forwarding; stays awake to relay | -| Router Client | Routes and operates as a client | -| Repeater | Retransmits only; no user interface | +| Router Late | Infrastructure node that rebroadcasts once, but only after all other modes (provides supplemental coverage) | +| ~~Router Client~~ | ⚠️ **Deprecated** (removed in firmware 2.3.15) — no longer selectable; use Router or Client instead | +| ~~Repeater~~ | ⚠️ **Deprecated** (removed in firmware 2.7.11) — no longer selectable; use Router instead | | Tracker | Optimized for position reporting at regular intervals | | Sensor | Optimized for telemetry reporting | | TAK | Interoperates with TAK systems (sends/receives CoT) | @@ -55,9 +57,9 @@ Nodes can be configured with different roles that affect their mesh behavior: Most users should keep the default **Client** role. Consider a different role when: - **Router** — You have a node in a fixed, elevated location with reliable power (rooftop, hilltop). Routers stay awake continuously to relay messages for others and are essential for extending mesh coverage. Don't use Router on battery-powered handheld devices. -- **Router Client** — Like Router, but the device is also used as a personal client. Good for a home base station that you also send messages from. +- **Router Late** — An infrastructure node that always rebroadcasts packets once but only after all other routing modes have had their turn. Provides supplemental coverage for local clusters without competing with primary routers. +- **Client Base** — Treats traffic from/to your favorited nodes with Router Late priority (ensuring those messages get extra relay coverage) while handling everything else as a normal Client. - **Client Mute** — You want to receive mesh traffic but not contribute to relaying. Useful for monitoring-only devices or to reduce congestion in dense areas. -- **Repeater** — A dedicated relay node with no screen or user interaction. Optimized purely for forwarding; lowest power consumption of the relay roles. - **Tracker** — An unattended device whose sole purpose is broadcasting its GPS position (e.g., a vehicle, pet, or asset). Sleeps between broadcasts to conserve battery. - **Sensor** — An unattended device reporting environmental telemetry (temperature, humidity, air quality). Similar power profile to Tracker. - **TAK / TAK Tracker** — Only needed if interoperating with ATAK/WinTAK systems. See [TAK Integration](tak) for details. @@ -100,7 +102,7 @@ Type in the search field to filter nodes by name or short name. The filter updat | **Only online** | Show only nodes heard within the last 15 minutes | | **Only direct** | Show only nodes with direct (non-relayed) connections | | **Include unknown** | Show nodes that haven't sent user info yet | -| **Exclude infrastructure** | Hide infrastructure-role nodes (Router, Repeater, Router Client) | +| **Exclude infrastructure** | Hide infrastructure-role nodes (Router, Repeater, Router Late, Client Base) | | **Exclude MQTT** | Hide nodes heard only via MQTT internet bridge | | **Show ignored** | Show nodes you've previously dismissed or muted | diff --git a/docs/user/settings-module-admin.md b/docs/user/settings-module-admin.md index c866ef08f..5cd31e7a7 100644 --- a/docs/user/settings-module-admin.md +++ b/docs/user/settings-module-admin.md @@ -21,6 +21,10 @@ Module settings use a card-based layout with toggle switches, dropdowns, text fi ![Dropdown selector](/assets/screenshots/settings_dropdown.png) +![Text field](/assets/screenshots/settings_text_field.png) + +![Settings card layout](/assets/screenshots/settings_titled_card.png) + ## Module Configuration ### MQTT Module @@ -34,7 +38,7 @@ Bridges mesh messages to and from an MQTT broker for internet connectivity. This | Username | Authentication username | | Password | Authentication password | | Encryption | Encrypt MQTT payloads | -| JSON Output | Also publish in JSON format | +| ~~JSON Output~~ | ⚠️ **Deprecated** — JSON support removed from firmware; field is ignored | | TLS | Use secure connection | | Root Topic | Base MQTT topic path | | Map Report | Publish position for public map | @@ -112,7 +116,7 @@ Pre-configured messages accessible from the device's physical buttons (for radio | Setting | Description | |---------|-------------| -| Enabled | Activate canned messages | +| ~~Enabled~~ | ⚠️ **Deprecated** — current firmware may ignore this toggle | | Messages | Newline-separated list of messages | | Send Bell | Play bell sound on send | | Rotary Encoder | Enable rotary encoder input | diff --git a/docs/user/settings-radio-user.md b/docs/user/settings-radio-user.md index 7bed4a4d8..f2bd9e2d8 100644 --- a/docs/user/settings-radio-user.md +++ b/docs/user/settings-radio-user.md @@ -28,8 +28,6 @@ Configure your radio hardware and user identity parameters. After modifying settings, tap **Save** to write the configuration to your radio. The device may reboot to apply changes. -![Settings appearance section](/assets/screenshots/settings-radio-user_lora_config.png) - ## Radio Configuration ### Device Config @@ -37,8 +35,6 @@ After modifying settings, tap **Save** to write the configuration to your radio. | Setting | Description | Default | |---------|-------------|---------| | Role | Node behavior (Client, Router, etc.) | Client | -| Serial Output | Enable serial console output | Disabled | -| Debug Log | Enable verbose debug logging | Disabled | | Rebroadcast Mode | How the node retransmits messages | All | | Node Info Broadcast (s) | Interval for broadcasting node info | 10800 | | Double-tap Button | Action for double-tap button press | Disabled | @@ -62,11 +58,18 @@ After modifying settings, tap **Save** to write the configuration to your radio. |--------|-------|-------|-----------|----------| | Short Turbo | ~1 km | 21.9 kbps | −5 dB | Dense urban with line-of-sight; data-heavy applications | | Short Fast | ~3 km | 10.9 kbps | −7.5 dB | Urban neighborhoods; buildings within a few blocks | +| Short Slow | ~5 km | 5.5 kbps | −10 dB | Suburban short-range; moderate building density | | Medium Fast | ~5 km | 5.5 kbps | −10 dB | Suburban areas; moderate building density | +| Medium Slow | ~8 km | 1.1 kbps | −12.5 dB | Suburban/rural; moderate range with slower speed | +| Long Turbo | ~10 km | 4.4 kbps | −10 dB | Similar range to Long Fast but with 500 kHz bandwidth; faster throughput | | Long Fast | ~10 km | 1.1 kbps | −12.5 dB | **General use (default)** — balanced range and speed | | Long Moderate | ~20 km | 0.34 kbps | −15 dB | Rural with some terrain; occasional use | -| Long Slow | ~30 km | 0.18 kbps | −17.5 dB | Sparse rural; maximum reliable range | -| Very Long Slow | ~40+ km | 0.09 kbps | −20 dB | Extreme range experiments; very slow throughput | +| Lite Fast | ~5 km | 5.5 kbps | −10 dB | EU 866 MHz SRD band (125 kHz BW); comparable to Medium Fast | +| Lite Slow | ~10 km | 1.1 kbps | −12.5 dB | EU 866 MHz SRD band (125 kHz BW); comparable to Long Fast | +| Narrow Fast | ~5 km | 2.7 kbps | −10 dB | EU 868 MHz band (62.5 kHz BW); avoids interference with other devices | +| Narrow Slow | ~10 km | 1.1 kbps | −12.5 dB | EU 868 MHz band (62.5 kHz BW); comparable to Long Fast | +| ~~Long Slow~~ | ~30 km | 0.18 kbps | −17.5 dB | ⚠️ **Deprecated** — still selectable but may be removed in a future firmware release | +| ~~Very Long Slow~~ | ~40+ km | 0.09 kbps | −20 dB | ⚠️ **Deprecated** — still selectable but may be removed in a future firmware release | #### Choosing a Modem Preset @@ -78,8 +81,9 @@ The modem preset controls the fundamental tradeoff between **range** and **data **Practical guidance:** - **Urban mesh (many nodes, short distances):** Use **Long Fast** (default) or **Short Fast**. Higher speed means less airtime congestion when many nodes share the channel. -- **Rural/sparse mesh (few nodes, long distances):** Use **Long Moderate** or **Long Slow**. Range matters more than speed when nodes are far apart. -- **Fixed infrastructure links:** Use **Short Turbo** for dedicated point-to-point links with good antennas and line-of-sight. +- **Rural/sparse mesh (few nodes, long distances):** Use **Long Moderate**. Range matters more than speed when nodes are far apart. +- **EU 866/868 MHz regulatory compliance:** Use **Lite Fast**, **Lite Slow**, **Narrow Fast**, or **Narrow Slow** — these are optimized for the EU SRD/868 MHz bands with narrower bandwidths. +- **Fixed infrastructure links:** Use **Short Turbo** or **Long Turbo** for dedicated point-to-point links with good antennas and line-of-sight. - **Mixed environments:** Stick with **Long Fast** — it's the community default and ensures compatibility with others in your area. > ⚠️ **Important:** All nodes on the same channel **must** use the same modem preset. Nodes with mismatched presets cannot communicate even if they share the same frequency and encryption key. @@ -92,9 +96,9 @@ The modem preset controls the fundamental tradeoff between **range** and **data |---------|-------------| | Screen Timeout | Time before display sleeps | | Display Units | Metric or Imperial | -| GPS Format | DMS, Decimal, UTM, MGRS, OLC | | OLED Type | Auto, SSD1306, SH1106, SH1107 | -| Compass North | True North or Magnetic North | +| Compass Orientation | Rotation offset for compass display (0°, 90°, 180°, 270°) | +| ~~Compass North~~ | ⚠️ **Deprecated** — replaced by Compass Orientation; still visible in older firmware | ### Position Config @@ -126,6 +130,8 @@ The modem preset controls the fundamental tradeoff between **range** and **data | NTP Server | Time synchronization server | | Syslog Server | Remote logging server | +![IP address field](/assets/screenshots/settings_ipv4_field.png) + ### Bluetooth Config | Setting | Description | @@ -142,8 +148,12 @@ The modem preset controls the fundamental tradeoff between **range** and **data | Admin Key | Key for remote administration | | Private Key | Your node's private key (handle securely) | | Admin Channel Enabled | Allow admin commands via channel | +| Debug Log | Output live debug logging over serial/bluetooth | +| Serial Enabled | Enable serial console access (moved from Device Config) | | Managed Mode | Restrict non-admin channel changes | +![Password field](/assets/screenshots/settings_password_field.png) + Settings use standard preference controls — dropdowns, toggles, and sliders: | Control | Screenshot | diff --git a/docs/user/signal-meter.md b/docs/user/signal-meter.md index 3f573ca4d..ce2d0a66d 100644 --- a/docs/user/signal-meter.md +++ b/docs/user/signal-meter.md @@ -52,10 +52,10 @@ Here is exactly how the app decides how many bars (or what color) to show you: | Level | Bars | Criteria | Meaning | |-------|------|----------|---------| -| Good | 3 | RSSI better than `-115 dBm` **AND** SNR above the baseline limit for your preset | Signal is both loud and clear — healthy connection. | -| Fair | 2 | Falls between Good and Bad | Signal getting quieter or noisier, but the radio understands the message fine. | -| Bad | 1 | RSSI drops to `-120 dBm` or worse, **OR** SNR within `5.5 dB` of your preset's absolute breaking point | Barely hanging on — at the edge of range or heavy interference. | -| None | 0 | RSSI worse than `-126 dBm` **AND** SNR has fallen `7.5 dB` below the ideal limit | Transmission completely buried in static. | +| Good | 3 | RSSI better than `-115 dBm` **AND** SNR better than `-7 dB` | Signal is both loud and clear — healthy connection. | +| Fair | 2 | RSSI better than `-126 dBm` with good SNR, **OR** SNR better than `-15 dB` with good RSSI | Signal getting quieter or noisier, but still decodable. | +| Bad | 1 | Falls between Fair and None thresholds | At the edge of range or experiencing interference. | +| None | 0 | RSSI worse than `-126 dBm` **AND** SNR worse than `-15 dB` | Transmission completely buried in noise. | ---