Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Meshtastic/Extensions/SwiftData/NodeInfoEntityExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,21 @@ extension NodeInfoEntity {
return try? ctx.fetch(descriptor).first
}

/// The receiving radio's most recent noise floor (dBm) from Local Stats telemetry
/// (`DeviceMetrics.noise_floor`), or nil when it's absent, zero, or older than the
/// online threshold (2 h). Used to compute a real link margin (`rssi - noiseFloor`)
/// for signal-quality rating instead of guessed fixed RSSI thresholds.
var recentNoiseFloor: Int32? {
guard let stats = latestLocalStats,
let time = stats.time,
let noiseFloor = stats.noiseFloor,
noiseFloor != 0,
let twoHoursAgo = Calendar.current.date(byAdding: .minute, value: -120, to: Date()),
time.compare(twoHoursAgo) == .orderedDescending
else { return nil }
return noiseFloor
}

var hasLocalStats: Bool {
guard let ctx = modelContext else { return false }
let nodeNum = self.num
Expand Down
106 changes: 53 additions & 53 deletions Meshtastic/Resources/docs/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
"section": "user",
"navOrder": 14,
"keywords": [
"quot",
"messages",
"carplay",
"siri",
Expand Down Expand Up @@ -73,7 +72,8 @@
"device",
"contact",
"channels",
"automatically"
"automatically",
"ago"
],
"charCount": 3378
},
Expand Down Expand Up @@ -185,12 +185,12 @@
"location",
"ios",
"first",
"amp",
"within",
"tip",
"time",
"tapping",
"started"
"started",
"setup"
],
"charCount": 2899
},
Expand Down Expand Up @@ -374,20 +374,20 @@
"show",
"section",
"row",
"radio",
"public",
"location",
"direct",
"detail",
"client",
"supported",
"see",
"quality",
"position",
"mesh",
"map",
"long",
"local",
"links",
"hops"
"map"
],
"charCount": 9146
"charCount": 9447
},
{
"id": "settings",
Expand Down Expand Up @@ -434,38 +434,38 @@
"section": "user",
"navOrder": 12,
"keywords": [
"signal",
"quot",
"snr",
"rssi",
"signal",
"noise",
"meter",
"rssi",
"radio",
"limit",
"meshtastic",
"than",
"floor",
"static",
"radio",
"background",
"dbm",
"bars",
"bad",
"understand",
"than",
"preset",
"loud",
"lora",
"bars",
"using",
"uses",
"them",
"specific",
"understand",
"still",
"lora",
"local",
"clarity",
"below",
"bad",
"app",
"above",
"two",
"see",
"out",
"message",
"means",
"limit",
"like",
"good",
"friend"
"relative",
"rating",
"power"
],
"charCount": 3992
"charCount": 4810
},
{
"id": "tak",
Expand Down Expand Up @@ -499,10 +499,10 @@
"zip",
"tip",
"read",
"quot",
"primary",
"position",
"pickers"
"pickers",
"lora"
],
"charCount": 6073
},
Expand Down Expand Up @@ -561,7 +561,6 @@
"localizer",
"local",
"translate",
"amp",
"translation",
"review",
"open",
Expand All @@ -580,7 +579,8 @@
"english",
"directly",
"bin",
"automatically"
"automatically",
"version"
],
"charCount": 4753
},
Expand All @@ -602,7 +602,6 @@
"distances",
"distance",
"date",
"amp",
"telemetry",
"meshtastic",
"device",
Expand All @@ -619,7 +618,8 @@
"change",
"altitude",
"uses",
"time"
"time",
"settings"
],
"charCount": 4753
},
Expand Down Expand Up @@ -680,7 +680,6 @@
"mesh",
"local",
"channel",
"quot",
"show",
"region",
"list",
Expand All @@ -694,10 +693,11 @@
"message",
"jul",
"docs",
"amp",
"waypoints",
"watch",
"verified"
"verified",
"translation",
"translate"
],
"charCount": 6609
},
Expand All @@ -707,7 +707,6 @@
"section": "developer",
"navOrder": 3,
"keywords": [
"quot",
"settings",
"view",
"settingsnavigationstate",
Expand Down Expand Up @@ -736,7 +735,8 @@
"create",
"adding",
"url",
"tests"
"tests",
"testing"
],
"charCount": 2664
},
Expand Down Expand Up @@ -830,7 +830,6 @@
"accessorymanager",
"logger",
"root",
"quot",
"packet",
"extensions",
"ble",
Expand All @@ -853,7 +852,8 @@
"tips",
"tcp",
"swiftdata",
"subsystems"
"subsystems",
"strings"
],
"charCount": 3538
},
Expand Down Expand Up @@ -915,7 +915,6 @@
"nodes",
"nodenum",
"deep",
"amp",
"tak",
"lora",
"links",
Expand All @@ -931,7 +930,8 @@
"swift",
"serial",
"security",
"routes"
"routes",
"route"
],
"charCount": 3040
},
Expand Down Expand Up @@ -980,7 +980,6 @@
"section": "developer",
"navOrder": 7,
"keywords": [
"quot",
"locale",
"unit",
"measurement",
Expand All @@ -1003,13 +1002,14 @@
"format",
"device",
"date",
"amp",
"universal",
"unitspeed",
"unitlength",
"text",
"string",
"nodes"
"nodes",
"measurementformatter",
"formatter"
],
"charCount": 6352
},
Expand Down Expand Up @@ -1065,7 +1065,6 @@
"swift",
"xml",
"route",
"quot",
"atak",
"wire",
"try",
Expand All @@ -1087,7 +1086,8 @@
"zstd",
"via",
"supportstakv2",
"routes"
"routes",
"protobuf"
],
"charCount": 7653
},
Expand All @@ -1098,7 +1098,6 @@
"navOrder": 6,
"keywords": [
"test",
"quot",
"tests",
"snapshots",
"run",
Expand Down Expand Up @@ -1126,7 +1125,8 @@
"try",
"suite",
"screenshots",
"scale"
"scale",
"saved"
],
"charCount": 3697
},
Expand Down
2 changes: 2 additions & 0 deletions Meshtastic/Resources/docs/markdown/user/nodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Each node is configured with a role that determines how it behaves on the mesh.

The full node row shows the circle avatar, battery level, encryption status, last-heard time, device role, signal strength, and log indicators all at once.

The signal meter shown here (and on a node's detail screen) rates link quality from SNR relative to your radio preset — using your radio's recently reported noise floor when available — and the strength bar and the SNR text color always reflect the same rating. See [Signal Meter](signal-meter.md) for how it works.

<picture>
<source media="(prefers-color-scheme: dark)" srcset="../assets/screenshots/standard_directConnected_dark.png" />
<img src="../assets/screenshots/standard_directConnected.png" alt="Directly connected node, favorite, with signal meter" />
Expand Down
22 changes: 14 additions & 8 deletions Meshtastic/Resources/docs/markdown/user/signal-meter.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,29 @@ Depending on which Meshtastic preset you are using (e.g., `LongFast` vs. `ShortF

## 3. How the Signal Meter Calculates Quality

The Meshtastic apps take both RSSI and SNR and run them through a specific formula to assign your signal a quality rating (None, Bad, Fair, or Good). It specifically scales these values based on the physical limits of the radio preset you are using.
The quality rating (None, Bad, Fair, or Good) is based on **SNR relative to your preset's SNR Limit** — how much clarity headroom you have above the point where the radio can no longer decode. This is measured against the physical limit of the radio preset you are using, so the same SNR can mean different things on `LongFast` versus `ShortFast`.

Here is exactly how the app decides how many bars (or what color) to show you:

| Level | Bars | Criteria | Meaning |
| Level | Bars | Criteria (SNR relative to your preset's limit) | 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 | SNR **above** the limit | Clear headroom — healthy connection. |
| Fair | 2 | SNR at the limit, up to `5.5 dB` below it | Getting quieter or noisier, but the radio still understands the message fine. |
| Bad | 1 | SNR between `5.5 dB` and `7.5 dB` below the limit | Barely hanging on — at the edge of range or heavy interference. |
| None | 0 | SNR more than `7.5 dB` below the limit | Transmission completely buried in static. |

RSSI is still shown next to the meter, but it is no longer used to guess the rating with fixed thresholds — on its own, RSSI can't tell you how much of that power is signal versus noise.

**Using the real noise floor.** When your receiving radio has recently reported its own **noise floor** (part of its Local Stats telemetry), the app does one better: it computes your true link margin as `RSSI − noise floor` and checks that against the same preset limit too, then shows the **more conservative** of the two ratings. This catches the case where the reported SNR looks fine but local interference is quietly eating your margin. When no recent noise floor is available, the app simply uses the SNR-only rating above.

---

## 4. What This Means for You

Because Meshtastic's meter acts as a **"Clarity Meter"**, it behaves differently than what most people expect:

> **Tip — Don't panic over low RSSI:** You might see a seemingly terrible RSSI value like `-118 dBm`. On a cell phone, you would have zero bars. But if you have an SNR of `+2 dB`, Meshtastic will still show a strong signal! *The library is quiet, so the whisper is heard perfectly.*
> **Tip — Don't panic over low RSSI**
> You might see a seemingly terrible RSSI value like `-118 dBm`. On a cell phone, you would have zero bars. But if you have an SNR of `+2 dB`, Meshtastic will still show a strong signal! *The library is quiet, so the whisper is heard perfectly.*

> **Warning — Watch out for local noise:** If you hook up a massive antenna and see a great RSSI (e.g., `-90 dBm`) but your signal meter is only showing **1 Bar (Bad)**, you have a problem. It means you have local interference—perhaps a cheap power supply, a noisy computer, or a nearby radio tower—creating so much static that it is drowning out your mesh.
> **Warning — Watch out for local noise**
> If you hook up a massive antenna and see a great RSSI (e.g., `-90 dBm`) but your signal meter is only showing **1 Bar (Bad)**, you have a problem. It means you have local interference—perhaps a cheap power supply, a noisy computer, or a nearby radio tower—creating so much static that it is drowning out your mesh. When your radio knows its own noise floor, the meter accounts for exactly this by measuring your real margin above the noise.
1 change: 1 addition & 0 deletions Meshtastic/Resources/docs/user/nodes.html
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ <h2>Device Roles</h2>
<p><a href="https://meshtastic.org/blog/choosing-the-right-device-role/">Choosing the Right Device Role →</a></p>
<h2>Complete Node Row Examples</h2>
<p>The full node row shows the circle avatar, battery level, encryption status, last-heard time, device role, signal strength, and log indicators all at once.</p>
<p>The signal meter shown here (and on a node's detail screen) rates link quality from SNR relative to your radio preset — using your radio's recently reported noise floor when available — and the strength bar and the SNR text color always reflect the same rating. See <a href="signal-meter.html">Signal Meter</a> for how it works.</p>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="../assets/screenshots/standard_directConnected_dark.png" />
<img src="../assets/screenshots/standard_directConnected.png" alt="Directly connected node, favorite, with signal meter" />
Expand Down
Loading
Loading