gpsd: scan all SKY frames for richest snapshot, use single-pass parse#620
gpsd: scan all SKY frames for richest snapshot, use single-pass parse#620octalparrot wants to merge 1 commit into
Conversation
2b91581 to
346099c
Compare
Multi-constellation receivers (e.g. Quectel LC29H, GPS+GLONASS+Galileo+ BeiDou) emit SKY messages in a repeating cycle: several DOP-only frames with empty `satellites:[]` and missing `nSat` (gpsd-side fall-back when the receiver is between PRR reports), interleaved with frames that progressively accumulate the constellation snapshot. Sampling a single SKY (whether the first or the last in the gpspipe buffer) hits the empty DOP-only frame ~80% of the time and returns 0. Rewrite as a single Python pass that: - iterates over every line in the gpspipe buffer - tracks the *latest* TPV (for mode/lat/lon/alt) - tracks the SKY with the highest accumulated satellite count (preferring `len(satellites)`, falling back to nSat/uSat) - emits a pipe-delimited record consumed by bash for the final JSON Reduces the number of subprocess invocations from 9 (one per metric) to 1 and produces stable readings across consecutive polls. Other changes: - Bump LINES from 20 to 50 to guarantee at least one full constellation cycle is captured (LC29H cycles ~10 SKY frames). - Tolerate missing keys (`get(...)` instead of indexing) so partial frames no longer silently drop output values via 2>/dev/null. - Use `uSat` for satellites_used (reliable summary) with a per-sat used-flag count as fallback for older gpsd builds. Tested on gpsd 3.25 + Quectel LC29H multi-constellation GNSS HAT on Debian 13 Trixie (aarch64): previously returned 0/0 on >80% of polls, now stably returns ~75/65 across 10 consecutive runs.
346099c to
7b68044
Compare
|
Consider just converting this entirely to python or the like if you are already going this far? |
|
Tested this on a Unicore UM980 (multi-constellation GPS/GLONASS/Galileo/BeiDou Confirms both the bug and the fix. Before (current With this PR: stable, valid output across consecutive polls: {"data":{"mode":"3","hdop":"0.7","vdop":"1.3","satellites":"42","satellites_used":"13"}, "error":"0", "version":"3.25"}
{"data":{"mode":"3","hdop":"0.7","vdop":"1.3","satellites":"42","satellites_used":"14"}, "error":"0", "version":"3.25"}
{"data":{"mode":"3","hdop":"0.8","vdop":"1.4","satellites":"43","satellites_used":"12"}, "error":"0", "version":"3.25"}
{"data":{"mode":"3","hdop":"0.7","vdop":"1.3","satellites":"43","satellites_used":"13"}, "error":"0", "version":"3.25"}42–43 visible / 12–14 used, consistent run to run, graph populates. The single-pass FWIW the same partial- |
Summary
The
snmp/gpsdextend script returned0/0forsatellites/satellites_usedon a multi-constellation receiver (Quectel LC29H + gpsd 3.25, GPS+GLONASS+Galileo+BeiDou) on roughly 80% of polls. Investigation showed the receiver emits SKY frames in a repeating cycle:Selecting a single SKY (whether the first via
grep -m 1or the last viatail -1) randomly hits the empty DOP-only frame most of the time. Both approaches were unreliable on multi-constellation hardware.Changes
Rewrite the parse step as a single Python pass that:
gpspipebuffermode/lat/lon/alt)len(satellites)and falling back tonSat/uSat)This reduces subprocess invocations from 9 (one Python per metric) to 1 and is robust against partial / DOP-only frames.
Other changes:
LINESfrom 20 to 50 to guarantee at least one full constellation cycle is captured (LC29H cycles ~10 SKY frames).d.get(...)so partial frames no longer silently drop values via2>/dev/null.uSatsummary forsatellites_usedwith per-satusedflag count as fallback for older gpsd builds that don't expose summary fields.Reproduction
Before (10 consecutive runs on LC29H + gpsd 3.25):
After:
Test plan
cgps -sgpsdapplication polls extend OID, RRDsatellites/satellites_usedpopulate correctlynSat/uSat, populatedsatellites[]) returns the expected count0/0instead of crashingNote for downstream graph maxima
The LibreNMS-side
gpsd.inc.phpPHP module declaresaddDataset('satellites', 'GAUGE', 0, 40)and the same forsatellites_used. Modern multi-constellation receivers routinely report 70–80+ satellites visible, exceeding this DS maximum and causing RRD to recordUnknown(graphed as 0). A companion PR tolibrenms/librenmsraising those maxima to 200 will be filed separately so this extend script's output is actually consumed correctly.