feat(observers): per-observer activity endpoint - #135
Merged
Merged
Conversation
GET /observers/{id}/activity returns bucketed observation counts, LoRa
airtime, SNR/RSSI aggregates and a payload-type breakdown for one
observer. Airtime is computed at ingest from the raw frame length and
stored on the observation; intervals of 1h and up are served from an
hourly matview so no request path joins back to packets.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GET /api/v1/observers/{observerId}/activity?range=24h&interval=15m— a per-observer, time-bucketed view of what an observer heard: observation counts, LoRa airtime, SNR/RSSI aggregates and a whole-range payload-type breakdown. Feeds four new charts on the Stats → Observer tab.Design
packet_observations.airtime_ms(RadioLibgetTimeOnAir, MeshCore preamble rule,internal/lora). Ingest has the raw frame so the length is exact. Rows without radio params stay NULL.packets— the same join that overran/dev/shmfor the payload breakdown before migration 015.mv_observer_activity_hourly(observer, payload type, hour) over 30 days, refreshed with the other views.5m/15mreadpacket_observationsoveridx_observations_observer, capped at a 48h window.Migrations
030adds the column (ALTER only, so the lock is released immediately).031backfills the last 7 days with a throwaway SQL copy of the formula, like 015.032creates the matview + unique index.Verify before merging
These have only been reviewed, not executed — there is no Postgres on the dev box:
REFRESH … CONCURRENTLY(this view is keyed by observer, so it is larger than the IATA-keyed ones).EXPLAIN ANALYZEthe raw 24h/15m and hourly 720h/6h queries on a busy observer; both should useidx_observations_observerand never touchpackets.airtime_msvalues againstlora.TimeOnAirMs.Tests
Formula spot checks (SF7/62.5/CR5/50 B → 244.224 ms; SF10 trips LDRO), end-to-end frame-length reconstruction for flood, transport and 2-byte-hash paths, gomock store tests for both paths and all null gating, handler tests for every validation rule. Swagger regenerated. Docs in beacon-docs
api_contract.md.