Skip to content

Use noise floor (Local Stats) for signal-quality rating instead of fixed RSSI thresholds #2042

Description

@garthvh

Background

Per meshtastic/design#15, Android hit the same cross-platform signal-quality question and settled on SNR-only rating (RSSI still displayed, just not used to determine the quality tier). From Meshtastic-Android#5446 (@GUVWAF, Android maintainer):

In the end it's SNR that matters; the "packet RSSI" we use is the real strength of only the signal here, but to judge whether that's enough we would need to know the noise floor... I would either remove the check for RSSI in both places.

Android went with removing RSSI from the rating entirely (Meshtastic-Android#5903). iOS should do better than that, not just match it — see below.

Current iOS behavior

Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift's getLoRaSignalStrength(snr:rssi:preset:) blends fixed, guessed RSSI thresholds (-115/-120/-126) together with the SNR-vs-preset-limit comparison to decide the 4-tier bar rating (None/Bad/Fair/Good). This is a different algorithm from getSnrColor(snr:preset:) in the same file, which is already SNR-only. So today iOS has two signal functions that can disagree on the same reading.

Fix: use the actual noise floor, not guessed RSSI thresholds

GUVWAF's blocker for using RSSI was not knowing the noise floor. We have it: DeviceMetrics.noise_floor (protobufs/meshtastic/telemetry.proto:455, field 15, int32, dBm — noiseFloor in telemetry.pb.swift) is transmitted as part of a node's Local Stats telemetry (metricsType == 4NodeInfoEntityExtension.swift's latestLocalStats/hasLocalStats). This is the receiving node's own radio noise floor, not a per-packet value.

Use it:

  1. When the connected/receiving node has a recent Local Stats reading, compute the actual link margin as rssi - noiseFloor instead of comparing RSSI to the fixed -115/-120/-126 guesses.
  2. Combine that real margin with the existing SNR-vs-preset-limit comparison (getSnrColor's bands) to produce the quality tier — this makes iOS's rating more accurate than Android's SNR-only model, not just a port of it.
  3. Fallback: when Local Stats / noise_floor isn't available for the connected node (absent or stale), fall back to SNR-only, matching Android's determineSignalQuality exactly (drop the guessed fixed RSSI thresholds entirely — don't keep them as the fallback, since they're the inaccurate thing being replaced).
  4. Unify getLoRaSignalStrength() and getSnrColor() so the bar indicator and the SNR text color can never disagree on the same reading (they can today).

Reference

Cross-platform alignment tracking issue: meshtastic/design#15. Related: Meshtastic-Apple#2041 (separate bug — wrong SNR floor for LongSlow), found during the same audit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions