Ingest kind:30078 ATM status beacons into dca_telemetry #24
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Gap surfaced 2026-05-15 during end-to-end testing of S5: the
TelemetrySnapshotmodel +dca_telemetrytable +upsert_beacon_snapshotCRUD are in place, but no subscriber writes to them. The ATM
publishes a kind:30078 status beacon every boot (and on state changes —
cassette swap, internet outage recovery, etc.) but the events land on
the relay and disappear;
dca_telemetryis empty for every machine.Observed payload
From the boot beacon during the 2026-05-15 Sintra test:
Sparse today —
cash_levelis qualitative ("good"), no denominationsor counts. The richer payload (denominations_json, fees_json,
limits_json, geo, version) lands when
lamassu-next#43shipsupstream. The model + CRUD already have nullable columns for those
fields, so the subscriber doesn't have to wait for #43 to land — it
just upserts what's present.
What's already in place
models.TelemetrySnapshotwith all the post-#43 fields nullablecrud.upsert_beacon_snapshot(machine_id, ...)— COALESCE-basedupsert that preserves prior values when the incoming payload omits
a field
crud.get_telemetry(machine_id)— single-row read by machineWhat's missing
The actual kind:30078 listener. Two approaches:
Option A (preferred): subscribe via
subscribe_payments-style RPCLNbits' nostr-transport (
aiolabs/lnbitsPR #4) registerssubscribe_paymentsfor Payment objects. A parallelsubscribe_events(kinds=[30078], authors=[<machine_npub>...])wouldlet satmachineadmin's
tasks.pyopen one long-lived sub at startupfor every active machine's npub. The handler upserts via
upsert_beacon_snapshot. This is the layered design from thesecurity epic (#13, S4-adjacent — same event kind the operator's
fleet roster uses, but
d-tag scopes them apart).Blocker: nostr-transport doesn't expose
subscribe_eventsyet(only
subscribe_payments). Filing the upstream LNbits primitivework is a prerequisite. See
aiolabs/lnbits#14for the security-side tracker — the event-subscribe RPC fits there.
Option B (fallback): direct relay subscription
Have satmachineadmin spin up its own websocket subscription to the
configured relay(s), filtered on
kinds:[30078]+authors:[active machine npubs]. Verify NIP-01 signature on each event, parse contentJSON, call
upsert_beacon_snapshot. Self-contained, no LNbitsprimitive required, but duplicates the relay-pool machinery.
Recommendation
Land Option A: file the upstream RPC primitive on
aiolabs/lnbitsfirst, then the satmachineadmin consumer. Until that primitive lands,
the worklist of unattributed knowledge — "what's the cash level on
machine X right now?" — answers from SSH-into-the-machine instead of
the operator dashboard.
Acceptance criteria
dca_machinesrow, keyedby
machine_npub. Restarts cleanly on container restart.pubkeymatches a known active machine_npub (else dropped + logged)["d"]tag scoped to a status namespace if/when bitspireadopts one (e.g.
bitspire-status:{npub})upsert_beacon_snapshotbeacon_received_atupdated on every successful upsert (alreadyin the CRUD)
cash_levelchip on the Fleet tablamassu-next#43lands, the richer fields(
denominations_json,fees_json,limits_json) appear in themachine detail view without further code changes
Out of scope
aiolabs/satmachineadmin#18)— same event kind but different concern: operator-signed config
about which ATMs are in the fleet, vs. ATM-signed status
References
~/dev/shared/extensions/satmachineadmin/models.py:368—TelemetrySnapshot~/dev/shared/extensions/satmachineadmin/crud.py:1111—upsert_beacon_snapshot~/dev/shared/extensions/satmachineadmin/migrations.py—dca_telemetryschemaregtest-lnbits-1docker logs, 2026-05-1520:41:33.95 (
kind 30078, "{...sintra...}")2026-05-26 — coordinate with S4 (#18) on kind:30078 usage
S4 (#18 — NIP-78 per-machine config + fleet roster) is starting now on the satmachineadmin side and uses the same event kind as this issue's ingestion target:
useAvailabilityBroadcastin lamassu-next)atm-availabilitybitspire-config:<machine_id>bitspire-fleetThree replaceable kind:30078 events per (operator, machine) pair, each disambiguated by
d-tag + author.Implications for this issue's ingestion code:
d="atm-availability"in the subscription, OR byauthors=[atm_npubs_only], to avoid pulling in operator-published config/roster events.aiolabs/lamassu-next#43) will add fees/limits/denominations to the beacon payload over time. Update the dca_telemetry schema to absorb those fields when they appear, but don't block ingestion of the minimal current shape.Sequencing: this issue is independent of S4 implementation-wise but benefits from landing the d-tag discipline now so we don't collide downstream. When S4 publishes the first kind:30078 with
d="bitspire-config:...", this ingestor should silently skip rather than try to parse as a beacon.➡️ Migrated to aiolabs/spirekeeper#13 (aiolabs/spirekeeper#13).
The v2-bitspire line of this extension now lives in its own repo,
aiolabs/spirekeeper. Tracking for this issue continues there; closing here. (Issue numbers were reassigned in the new repo.)