ADR 0024: network health apart from device health, and the locations a network provides
Date: 2026-09-10. Status: accepted. Decisions D161 to D164. Phase 23.
Context
Architecture 20 says network health and device health must be distinct: a collar can be
healthy but poorly connected, or connected well while reporting faults. ADR 0023 had put the
last satellite session as a line in the health card, the only visible place at the time, and
that mixed the two. The same look raised the locations a network provides: an Iridium session's
estimate, ThingPark's DevEUI_location (network geolocation, which some KPN collars get), The
Things Stack's location_solved. They are useful as an alternative location for a collar whose
GNSS fails, and misleading on the main map without anyone asking: a 64 km circle next to a
good fix on the first live Rock7 delivery.
Decision
- A Connectivity tab on the device page and on the entity page (for the device tracking
it), one card per data source the device has an identity on, from
GET /devices/{id}/connectivity: the connection state and the last uplink, join and downlink, then for LoRaWAN the gateways heard in the period with the best one and its share, the mean signal and the frame counter gaps, and for Iridium the last session with its outcome, the counter, missed sessions, sessions, bytes and redeliveries in the period. The health card is the device's own status again. - Network locations are positions of record type
network. Adapters put aNetworkLocationon the inbound message (or the ingest derives one from a satellite session the network stands by); the decoder writes it next to the driver's records with the radius as accuracy and the method in the attributes; the canonical key keeps it apart from a device fix at the same moment. One table, one curation, one export. - Every reader takes device fixes by default.
device_fix()andsources_filter()inshared/curation/effective.py; the positions list, the tracks, the records read, the rules' replay and the integrations exclude network positions unlesssources=networkorall(an integration needsinclude_network_positionsin its settings); the heatmap and the coverage read device fixes only; exports keep every row with its record type. The map draws the network locations as circles of their radius on the Coverage tab's "Network locations" layer, fromGET /projects/{id}/map/network-locations. - The location source is a setting per entity and per device.
location_sourceisdevice(default),network, ordevice_else_networkwithlocation_fallback_hours. The decoder applies it when it sets the current position: a device fix newer than the newest fix known always takes the position; a network location counts only when the setting isnetwork(newest wins) ordevice_else_networkand no device fix arrived within the fallback period before it. Both current states keeplatest_position_kindandlatest_fix_time; the map's features carryposition_kindand the panels say "network estimate". Live rules see a network position only for an entity that opted in.
Consequences
- Migration 0024 adds the two setting columns to entities and devices and the two state columns to both current-state tables.
- Positions written before this release are all device fixes; nothing changes for them.
- The satellite sessions layer of ADR 0023 is replaced by the network locations layer, which covers LoRaWAN geolocation as well.
- Recorded live on 2026-09-13: KPN embeds the geolocation fields in every uplink of a device
that has it on (
DevLAT,DevLON,DevLocTime,DevLocRadius, ...) rather than posting a separateDevEUI_locationreport, and repeats the last solved location on every uplink. The adapter reads the fields from both; the canonical key keeps one position perDevLocTime.