mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-24 23:01:22 -04:00
docs: comprehensive accuracy audit and CI fix (#5489)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -61,7 +61,7 @@ class DocsTasks : Plugin<Project> {
|
||||
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")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 %}
|
||||
<details class="language-switcher" aria-label="Language options">
|
||||
<summary class="language-switcher-btn" title="View in another language">
|
||||
🌐 <span class="lang-current">English</span>
|
||||
</summary>
|
||||
<ul class="language-switcher-list">
|
||||
{% comment %} Always show English link back to source {% endcomment %}
|
||||
{% assign path_parts = current_path | split: "/" %}
|
||||
{% assign first_segment = path_parts[0] %}
|
||||
|
||||
{% comment %} Detect if we're currently IN a locale subdir {% endcomment %}
|
||||
{% if locales[first_segment] %}
|
||||
{% comment %} We're on a translated page — link back to English {% endcomment %}
|
||||
{% assign remaining_parts = path_parts | slice: 1, path_parts.size %}
|
||||
{% assign en_path = remaining_parts | join: "/" | replace: ".md", "" %}
|
||||
<li><a href="{{ en_path | relative_url }}" lang="en">English</a></li>
|
||||
{% endif %}
|
||||
|
||||
{% comment %} Show all available locale versions {% endcomment %}
|
||||
{% for locale in locales %}
|
||||
{% assign locale_code = locale[0] %}
|
||||
{% assign locale_info = locale[1] %}
|
||||
|
||||
{% if locales[first_segment] %}
|
||||
{% comment %} We're already on a translated page {% endcomment %}
|
||||
{% if locale_code == first_segment %}
|
||||
{% continue %}
|
||||
{% endif %}
|
||||
{% assign locale_path = locale_code | append: "/" | append: en_path %}
|
||||
{% else %}
|
||||
{% comment %} We're on an English page {% endcomment %}
|
||||
{% assign en_relative = current_path | replace: ".md", "" %}
|
||||
{% assign locale_path = locale_code | append: "/" | append: en_relative %}
|
||||
{% endif %}
|
||||
|
||||
{% comment %}
|
||||
Check if the translated file actually exists.
|
||||
Jekyll doesn't have a file_exists filter, so we check site.pages.
|
||||
{% endcomment %}
|
||||
{% assign locale_file = locale_path | append: ".md" %}
|
||||
{% assign page_exists = false %}
|
||||
{% for p in site.pages %}
|
||||
@@ -69,3 +81,4 @@
|
||||
</ul>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -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
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 76 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
@@ -3,7 +3,6 @@ title: Developer Guide
|
||||
layout: default
|
||||
nav_order: 2
|
||||
has_children: true
|
||||
parent: ""
|
||||
---
|
||||
|
||||
# Developer Guide
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/<scope>` | New user-visible behavior |
|
||||
| `fix/<scope>` | Bug fixes |
|
||||
| `refactor/<scope>` | Code structure changes |
|
||||
| `chore/<scope>` | Tooling, deps, CI, cleanup |
|
||||
| `docs/<scope>` | Documentation only |
|
||||
| `build/<scope>` | Build system changes |
|
||||
| `ci/<scope>` | CI workflow changes |
|
||||
| `test/<scope>` | Test additions or fixes |
|
||||
| `deps/<scope>` | 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
|
||||
|
||||
|
||||
@@ -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<NavKey>.docsEntries(backStack: NavBackStack<NavKey>) {
|
||||
entry<SettingsRoute.HelpDocs> { DocsBrowserScreen(backStack) }
|
||||
entry<SettingsRoute.HelpDocPage> { DocsPageRouteScreen(it.pageId, backStack) }
|
||||
entry<SettingsRoute.HelpDocPage> { 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,
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<DeviceType>
|
||||
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
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -3,7 +3,6 @@ title: User Guide
|
||||
layout: default
|
||||
nav_order: 1
|
||||
has_children: true
|
||||
parent: ""
|
||||
---
|
||||
|
||||
# User Guide
|
||||
|
||||
@@ -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**.
|
||||
|
||||

|
||||
|
||||
When a device is found, it appears in the connection list:
|
||||
|
||||

|
||||
|
||||
A successful connection is confirmed with a status indicator:
|
||||
|
||||

|
||||
|
||||
### 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:
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||
|
||||
The browser supports full-text search across all documentation:
|
||||
|
||||

|
||||
|
||||
Individual doc pages render with full formatting:
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -78,6 +78,8 @@ If the update appears frozen:
|
||||
- If truly stuck, power-cycle the radio
|
||||
- Attempt the update again
|
||||
|
||||

|
||||
|
||||
### Device Won't Boot After Update
|
||||
|
||||
If your device fails to boot:
|
||||
|
||||
@@ -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:
|
||||
|
||||

|
||||
|
||||
The channel list shows each channel with its latest message preview:
|
||||
|
||||

|
||||
The channel list shows each channel with its latest message preview.
|
||||
|
||||
### Message Bubbles
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
|
||||
@@ -21,6 +21,10 @@ Module settings use a card-based layout with toggle switches, dropdowns, text fi
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 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 |
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||
|
||||
## 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 |
|
||||
|
||||

|
||||
|
||||
### 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 |
|
||||
|
||||

|
||||
|
||||
Settings use standard preference controls — dropdowns, toggles, and sliders:
|
||||
|
||||
| Control | Screenshot |
|
||||
|
||||
@@ -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. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user