Ingest kind:30078 ATM status beacons into dca_telemetry #13
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 aiolabs/lamassu-next#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 #2) 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 (#8, 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...}")