Put APRS stations on the live map, where they stay

The same window the aircraft use, given marks that are not aeroplanes.  It
already knew how to fetch a map, place an information box where it covers
nothing, glide it when its owner moves, draw range rings, put a flag where
the aerial stands and a scale along the bottom -- and not one of those has
anything to do with aviation.  What it did not know is that a mark might not
fade, might not point anywhere, and might be coloured by what it is rather
than by how high it is.  Those are three hooks rather than a second window,
and the aircraft map is untouched: every one of them defaults to exactly what
an aeroplane does.

Nothing fades, which is the difference asked for and the right one.  An
aeroplane that stops transmitting has flown out of range, and drawing it an
hour later where it was would be drawing something that is certainly not
there.  A fixed amateur station that stops transmitting is still exactly
where it was -- it beacons every half hour, and the gaps are silence rather
than absence.  So the picture accumulates and an evening of listening fills a
map.  Marks are ordered most-recently-heard first, because that is the order
the boxes are laid out in and an accumulating map has more marks on it than
it has room for boxes.

Marks are drawn by what they are: something moving as a body with a stalk
pointing where it is going, and anything fixed as a diamond, which is the one
shape on the picture with no front -- a house that beacons twice an hour is a
place, and a triangle would have it pointing north for no reason.  Colours
come off the altitude ramp, not because a station has an altitude but because
that ramp is the one set of colours all five themes define: warm to cold on
the default map, dim to bright on the phosphor ones, so a digipeater stays
distinguishable from a car everywhere without a colour being named here.

The box says what the station is, how far off and in which bearing, what it
is doing if it is moving, its altitude, its weather, its status, the
digipeaters it came through, how many packets and how many of those arrived
directly, and how strongly.  The heading prints the callsign once: an
aeroplane has two names and the heading was built for that.

Reachable both ways, as everything here is -- --window on the command line, w
in the menu -- with the same eight map settings the aircraft side has.

Forty new tests against nine deliberately broken builds.  Two of them survived
the first attempt, and both for the same reason: they asked whether the
rendered frames differed rather than whether the symbol did, and the strip
along the top carries a running clock, so two frames taken a millisecond apart
differ by a few hundred pixels whatever is on the map.  They now crop to the
mark.  That is the second time this session that a ticking header has made a
test pass for the wrong reason.  Full suite 2652 passed.  Built as
2026-09-21_01.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
This commit is contained in:
The Dust Council 2026-09-21 00:12:10 -07:00
parent 14ba77da9a
commit 2c7b1ba25e
10 changed files with 1049 additions and 19 deletions

View file

@ -2149,6 +2149,15 @@ only what is shown and can be changed afterwards on an old log.
| Say what is arriving | `--diagnose` / `--no-diagnose` | no | each second taken apart stage by stage |
| Keep on screen for | `--hold` | 1800 s | how long a sensor stays after its last message |
| Show readings in | `--units` | metric | metric or imperial, for the display and the export |
| — | `--window` | — | open the live map instead of a table |
| Map reaches | `--radius` | 50 km | how far around the aerial the window reaches |
| Theme | `--theme` | night | how the window looks; the same five as the aircraft map |
| Map brightness | `--map-brightness` | 70 | how bright the ground under the stations is |
| Draw a real map | `--basemap` / `--no-basemap` | yes | fetch map tiles |
| Range rings | `--window-rings` / `--no-window-rings` | yes | faint discs around the aerial |
| Box translucency | `--box-opacity` | 85 | how solid the card behind each box is |
| Leave a trail | `--trails` / `--no-trails` | yes | the path behind anything that moved |
| Map tiles from | `--tiles` | OpenStreetMap | where tiles come from |
| Only named sensors | `--only-named` / `--all-sensors` | no | ignore anything without a name |
| Show unreadable models | `--unknown` / `--no-unknown` | yes | list sensors whose model cannot be read |
| Report at the end | `--report` / `--no-report` | yes | print what each sensor said |
@ -2267,6 +2276,7 @@ you will actually hear.
```bash
bandsaunter aprs listen, and show who is out there
bandsaunter aprs --region europe ...on 144.800 instead
bandsaunter aprs --window a live map of the stations, which accumulate
bandsaunter aprs --simulate a channel full of stations that are not there
bandsaunter packets --kml turn a log into something Google Earth opens
```
@ -2429,6 +2439,61 @@ busy, sixteen bits is strong but not infinite.
It decodes down to about 8 dB of signal-to-noise and finds nothing at all in
pure noise.
### A window, while it happens
`bandsaunter aprs --window` opens the same map the aircraft use, with the
stations on it instead of aeroplanes — a real map underneath, an information
box beside each station, a leader line to the mark it belongs to, range rings
around the aerial and a red flag where you are.
```
144.39 MHz 6 on the map 6 seen 812 packets 1:01:40 d detail t trails g map q quit
┌──────────────────┐
┌────────────────────┐ ◈────────┤ W1AW-1 │
│ K7XYZ-3 │ │ │ symbol digipeater│
│ symbol yacht │ │ │ away 7 km NNW │
│ away 19 km NNW │ ◈╌╌╌╌╌╌╯ │ says Seattle… │
│ says yagi │ ╎ └──────────────────┘
└────────────────────┘ ╎ ⌂
```
**The one difference from the aircraft map is that nothing fades.** An
aeroplane that stops transmitting has flown out of range, and drawing it an
hour later where it was would be drawing something that is certainly not
there. A fixed amateur station that stops transmitting is still exactly where
it was — it beacons every half hour, and the gaps are silence rather than
absence. So the picture accumulates, and an evening of listening fills a map.
Marks are drawn by what they are, and coloured off the same altitude ramp the
aircraft use — which is the one set of colours every theme defines, so a
digipeater stays distinguishable from a car on all five:
| what | drawn as |
|---|---|
| something moving | a body with a stalk, pointing where it is going |
| a digipeater or gateway | a diamond, brightest of the fixed things |
| a weather station | a diamond, mid-ramp |
| an object somebody placed | a diamond, low |
| a fixed station | a diamond, dimmest |
A diamond because it is the one shape on the picture with no front: a house
that beacons twice an hour is a place, and drawing it as a triangle would
have it pointing north for no reason.
The box says what the station is, how far off and in which bearing, what it is
doing if it is moving, its altitude, its weather, its status or comment, the
digipeaters it came through, how many packets and how many of those arrived
directly, and how strongly. Boxes are placed where they cover nothing else and
glide when their station moves, and where there is no room for one the mark is
still drawn — with an evening's accumulation there are usually more marks than
there is room for boxes, so the most recently heard get them.
The same keys as the aircraft map: `d` cycles how much each box says, `t`
trails, `g` the map underneath, `[` and `]` its brightness, `+`/`-` the range,
`q` quits. `--radius` sets how far it reaches to begin with, `--theme` picks
from the same five, and `--at LAT,LON` is what puts the flag and the rings
anywhere useful.
### Afterwards
Three tables, because they answer different questions. **Stations heard** is
@ -2469,6 +2534,15 @@ version that can.
| Keep on screen for | `--hold` | 3600 s | how long a station stays after its last packet |
| Receiver at | `--at` | blank | where the aerial is, for distances |
| Show readings in | `--units` | metric | metric or imperial, for the display and the export |
| — | `--window` | — | open the live map instead of a table |
| Map reaches | `--radius` | 50 km | how far around the aerial the window reaches |
| Theme | `--theme` | night | how the window looks; the same five as the aircraft map |
| Map brightness | `--map-brightness` | 70 | how bright the ground under the stations is |
| Draw a real map | `--basemap` / `--no-basemap` | yes | fetch map tiles |
| Range rings | `--window-rings` / `--no-window-rings` | yes | faint discs around the aerial |
| Box translucency | `--box-opacity` | 85 | how solid the card behind each box is |
| Leave a trail | `--trails` / `--no-trails` | yes | the path behind anything that moved |
| Map tiles from | `--tiles` | OpenStreetMap | where tiles come from |
| Show what cannot be read | `--unparsed` / `--no-unparsed` | yes | list packets in unknown formats |
| Include relayed packets | `--digipeated` / `--direct-only` | yes | count what reached you through a digipeater |
| Report at the end | `--report` / `--no-report` | yes | print what was heard |