Count only the first copy of each advert per radio
CI / test-and-build (3.10) (push) Canceled after 0s
CI / test-and-build (3.11) (push) Canceled after 0s
CI / test-and-build (3.12) (push) Canceled after 0s
CI / test-and-build (3.13) (push) Canceled after 0s

The node tables counted every reception of an advert, including copies
the Repeater had already heard: another repeater re-flooding what we
forwarded, or an echo of our own transmission. Those landed on the
other radio, so nodes looked like they were heard on both.

The Repeater dedups across all its radios with one seen-packets cache,
so is_duplicate = false marks the radio that first heard each advert.
Both node tables now filter on it.

Bump to 0.1.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
richandClaude Opus 5.5 committed 2026-10-06 20:14:39 -04:00
1 parent e7b16bf240
commit 6bb8f72a19
6 files changed
+19 -13

No files matched your search

+6 -3
View File
@@ -60,9 +60,12 @@ Notes on the schema:
- **Which radio hears which node comes from adverts.** Only ADVERT packets name
their sender (`src_pubkey`). **Nodes heard by radio** lists each radio/node pair.
**Node coverage by radio** has one row per node and a column per radio, and
highlights nodes heard on only one radio. Adverts are flooded, so set
**Advert hops** to *Direct only* to count only adverts heard straight from the
node rather than through a relay.
highlights nodes heard on only one radio. Both count only the first copy of
each advert (`is_duplicate = false`). The Repeater dedups across all its
radios, so a later copy, such as another repeater re-flooding what we
forwarded, is not counted as a receive on the radio that heard it. Adverts
are flooded, so set **Advert hops** to *Direct only* to count only adverts
heard straight from the node rather than through a relay.
- **Packets are idempotent.** A packet seen live and again during backfill gets
the same timestamp and tags, so InfluxDB overwrites it instead of duplicating it.
+4 -4
View File
@@ -1193,7 +1193,7 @@
"type": "influxdb",
"uid": "${datasource}"
},
"query": "SELECT count(\"rssi\") AS \"adverts\" FROM \"openhop_packet\" WHERE \"repeater\" =~ /^$repeater$/ AND \"type_name\" = 'ADVERT' AND \"src_pubkey\" != '' AND \"hop_count\" <= $max_hops AND $timeFilter AND \"rx_radio_id\" =~ /^$radio$/ GROUP BY \"rx_radio_id\", \"src_pubkey\"",
"query": "SELECT count(\"rssi\") AS \"adverts\" FROM \"openhop_packet\" WHERE \"repeater\" =~ /^$repeater$/ AND \"type_name\" = 'ADVERT' AND \"src_pubkey\" != '' AND \"is_duplicate\" = 'false' AND \"hop_count\" <= $max_hops AND $timeFilter AND \"rx_radio_id\" =~ /^$radio$/ GROUP BY \"rx_radio_id\", \"src_pubkey\"",
"rawQuery": true,
"refId": "A",
"resultFormat": "table"
@@ -1203,7 +1203,7 @@
"type": "influxdb",
"uid": "${datasource}"
},
"query": "SELECT last(\"rssi\") AS \"last RSSI (dBm)\", \"snr\" AS \"last SNR (dB)\" FROM \"openhop_packet\" WHERE \"repeater\" =~ /^$repeater$/ AND \"type_name\" = 'ADVERT' AND \"src_pubkey\" != '' AND \"hop_count\" <= $max_hops AND $timeFilter AND \"rx_radio_id\" =~ /^$radio$/ GROUP BY \"rx_radio_id\", \"src_pubkey\"",
"query": "SELECT last(\"rssi\") AS \"last RSSI (dBm)\", \"snr\" AS \"last SNR (dB)\" FROM \"openhop_packet\" WHERE \"repeater\" =~ /^$repeater$/ AND \"type_name\" = 'ADVERT' AND \"src_pubkey\" != '' AND \"is_duplicate\" = 'false' AND \"hop_count\" <= $max_hops AND $timeFilter AND \"rx_radio_id\" =~ /^$radio$/ GROUP BY \"rx_radio_id\", \"src_pubkey\"",
"rawQuery": true,
"refId": "B",
"resultFormat": "table"
@@ -1362,7 +1362,7 @@
"type": "influxdb",
"uid": "${datasource}"
},
"query": "SELECT count(\"rssi\") AS \"adverts\" FROM \"openhop_packet\" WHERE \"repeater\" =~ /^$repeater$/ AND \"type_name\" = 'ADVERT' AND \"src_pubkey\" != '' AND \"hop_count\" <= $max_hops AND $timeFilter GROUP BY \"rx_radio_id\", \"src_pubkey\"",
"query": "SELECT count(\"rssi\") AS \"adverts\" FROM \"openhop_packet\" WHERE \"repeater\" =~ /^$repeater$/ AND \"type_name\" = 'ADVERT' AND \"src_pubkey\" != '' AND \"is_duplicate\" = 'false' AND \"hop_count\" <= $max_hops AND $timeFilter GROUP BY \"rx_radio_id\", \"src_pubkey\"",
"rawQuery": true,
"refId": "A",
"resultFormat": "table"
@@ -1372,7 +1372,7 @@
"type": "influxdb",
"uid": "${datasource}"
},
"query": "SELECT count(\"adverts\") AS \"radios\" FROM (SELECT count(\"rssi\") AS \"adverts\" FROM \"openhop_packet\" WHERE \"repeater\" =~ /^$repeater$/ AND \"type_name\" = 'ADVERT' AND \"src_pubkey\" != '' AND \"hop_count\" <= $max_hops AND $timeFilter GROUP BY \"rx_radio_id\", \"src_pubkey\") GROUP BY \"src_pubkey\"",
"query": "SELECT count(\"adverts\") AS \"radios\" FROM (SELECT count(\"rssi\") AS \"adverts\" FROM \"openhop_packet\" WHERE \"repeater\" =~ /^$repeater$/ AND \"type_name\" = 'ADVERT' AND \"src_pubkey\" != '' AND \"is_duplicate\" = 'false' AND \"hop_count\" <= $max_hops AND $timeFilter GROUP BY \"rx_radio_id\", \"src_pubkey\") GROUP BY \"src_pubkey\"",
"rawQuery": true,
"refId": "B",
"resultFormat": "table"
+1 -1
View File
@@ -2,7 +2,7 @@
"schema": 1,
"id": "community.influxdb",
"name": "InfluxDB Exporter",
"version": "0.1.3",
"version": "0.1.4",
"description": "Pushes Repeater metrics, per-packet events, logs and node/GPS snapshots to a remote InfluxDB (v1, v2 or v3) for Grafana dashboards.",
"runtime": {
"type": "python",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "openhop-influxdb-plugin"
version = "0.1.3"
version = "0.1.4"
description = "openHop Repeater plugin that pushes metrics, packets, logs and snapshots to InfluxDB"
readme = "README.md"
requires-python = ">=3.10"
+6 -3
View File
@@ -229,10 +229,13 @@ panel("timeseries", "Drops by radio", [target(
# ADVERT packets carry the advertiser's pubkey (src_pubkey), so they show which
# radio heard which node. A counts adverts; B's selector time is the last one
# heard; C looks up names from the latest neighbour snapshot (any time).
# Adverts are flooded, so $max_hops can narrow them to ones heard straight from
# the node (0 hops) rather than through a relay.
# Only the first copy of each advert counts: the Repeater dedups across all its
# radios, so later copies (another repeater re-flooding what we forwarded, or an
# echo of our own transmission) are is_duplicate and say nothing about which
# radio first heard the node. Adverts are flooded, so $max_hops can also narrow
# them to ones heard straight from the node (0 hops) rather than through a relay.
ADV_ALL = (f'{R} AND "type_name" = \'ADVERT\' AND "src_pubkey" != \'\' '
'AND "hop_count" <= $max_hops AND $timeFilter')
'AND "is_duplicate" = \'false\' AND "hop_count" <= $max_hops AND $timeFilter')
ADV = f'{ADV_ALL} AND "rx_radio_id" =~ /^$radio$/'
NAMES = target(f'SELECT last("node_name") AS "name" FROM "openhop_advert" WHERE {R} '
'GROUP BY "pubkey", "contact_type"', "C", fmt="table")
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.1.3"
__version__ = "0.1.4"