feat: availability broadcast (Kind 30078) + WiFi auto-connect
Wire up the availability broadcast composable to publish the ATM's status as a replaceable Kind 30078 Nostr event. Publishes on availability change (debounced) and as a 5-minute heartbeat so monitors can detect offline machines. Also adds WiFi auto-connect for BATM3: reads SSID/PSK from /var/lib/lamassu-atm/wifi.conf at boot. Credentials stay local. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7afcc6fc5d
commit
67c7c12ade
3 changed files with 82 additions and 1 deletions
|
|
@ -93,9 +93,22 @@ export function useAvailabilityBroadcast(options: UseAvailabilityBroadcastOption
|
|||
{ deep: true }
|
||||
)
|
||||
|
||||
// Heartbeat: republish every 5 minutes so monitors know the machine is alive.
|
||||
// If the latest Kind 30078 event is older than ~10 minutes, the machine is offline.
|
||||
const heartbeatInterval = setInterval(
|
||||
() => {
|
||||
publish(computeAvailability())
|
||||
},
|
||||
5 * 60 * 1000
|
||||
)
|
||||
|
||||
// Publish immediately on setup
|
||||
const initial = computeAvailability()
|
||||
publish(initial)
|
||||
|
||||
return { computeAvailability }
|
||||
function stop() {
|
||||
clearInterval(heartbeatInterval)
|
||||
}
|
||||
|
||||
return { computeAvailability, stop }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {
|
|||
type ManagementResponse,
|
||||
} from '@lamassu/clink'
|
||||
import type { TransactionRecord } from '@/types/state'
|
||||
import { useAvailabilityBroadcast } from '@/composables/useAvailabilityBroadcast'
|
||||
|
||||
// Check if we're running in Electron
|
||||
const isElectron = typeof window !== 'undefined' && window.electronAPI !== undefined
|
||||
|
|
@ -308,6 +309,10 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
return snapshot.value?.context ?? null
|
||||
})
|
||||
|
||||
const inventory = computed((): Record<number, number> => {
|
||||
return context.value?.inventory ?? {}
|
||||
})
|
||||
|
||||
const fiatSymbol = computed(() => {
|
||||
const symbols: Record<string, string> = { USD: '$', GTQ: 'Q', EUR: '€', GBP: '£', MXN: '$' }
|
||||
return symbols[fiatCode.value] || fiatCode.value
|
||||
|
|
@ -557,6 +562,9 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
|
||||
// Initialize state machine with real services
|
||||
initialize(servicesWithInventory)
|
||||
|
||||
// Start broadcasting availability (Kind 30078) with 5-minute heartbeat
|
||||
startAvailabilityBroadcast(services.nostrClient, services.identity, 'atm')
|
||||
} catch (error) {
|
||||
console.error('[ATM] Failed to connect to Lightning.Pub:', error)
|
||||
connectionStatus.value = 'error'
|
||||
|
|
@ -847,6 +855,9 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
}
|
||||
})
|
||||
|
||||
// Start broadcasting availability (Kind 30078)
|
||||
startAvailabilityBroadcast(lightning.nostrClient, lightning.identity, 'atm')
|
||||
|
||||
console.log('[ATM] Fully initialized with HAL + Lightning')
|
||||
} catch (error) {
|
||||
console.error('[ATM] HAL initialization failed:', error)
|
||||
|
|
@ -1099,6 +1110,9 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
|
||||
// Real hardware connected — disable mock bill simulator
|
||||
debugMode.value = false
|
||||
// Start broadcasting availability (Kind 30078)
|
||||
startAvailabilityBroadcast(lightning.nostrClient, lightning.identity, 'atm')
|
||||
|
||||
console.log('[ATM] Fully initialized with HAL (IPC) + Lightning')
|
||||
} catch (error) {
|
||||
console.error('[ATM] HAL initialization failed:', error)
|
||||
|
|
@ -1225,6 +1239,23 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
}
|
||||
}
|
||||
|
||||
/** Start broadcasting ATM availability (Kind 30078) with 5-minute heartbeat */
|
||||
let stopAvailabilityBroadcast: (() => void) | null = null
|
||||
|
||||
function startAvailabilityBroadcast(nostrClient: any, identity: any, model: string) {
|
||||
if (stopAvailabilityBroadcast) return
|
||||
|
||||
const { stop } = useAvailabilityBroadcast({
|
||||
nostrClient,
|
||||
identity,
|
||||
inventory,
|
||||
balanceSats,
|
||||
fiatCode: fiatCode.value,
|
||||
model,
|
||||
})
|
||||
stopAvailabilityBroadcast = stop
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
actor,
|
||||
|
|
|
|||
|
|
@ -68,6 +68,43 @@
|
|||
hybrid-sleep.enable = false;
|
||||
};
|
||||
|
||||
# WiFi: read credentials from /var/lib/lamassu-atm/wifi.conf (not in repo)
|
||||
# Format: SSID=MyNetwork\nPSK=MyPassword
|
||||
system.activationScripts.wifi-setup = ''
|
||||
WIFI_CONF="/var/lib/lamassu-atm/wifi.conf"
|
||||
if [ -f "$WIFI_CONF" ]; then
|
||||
SSID=$(grep '^SSID=' "$WIFI_CONF" | cut -d= -f2-)
|
||||
PSK=$(grep '^PSK=' "$WIFI_CONF" | cut -d= -f2-)
|
||||
if [ -n "$SSID" ] && [ -n "$PSK" ]; then
|
||||
CONN_FILE="/etc/NetworkManager/system-connections/$SSID.nmconnection"
|
||||
if [ ! -f "$CONN_FILE" ]; then
|
||||
cat > "$CONN_FILE" << EOF
|
||||
[connection]
|
||||
id=$SSID
|
||||
type=wifi
|
||||
autoconnect=true
|
||||
|
||||
[wifi]
|
||||
mode=infrastructure
|
||||
ssid=$SSID
|
||||
|
||||
[wifi-security]
|
||||
key-mgmt=wpa-psk
|
||||
psk=$PSK
|
||||
|
||||
[ipv4]
|
||||
method=auto
|
||||
|
||||
[ipv6]
|
||||
method=auto
|
||||
EOF
|
||||
chmod 600 "$CONN_FILE"
|
||||
echo "[WiFi] Created connection for $SSID"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
|
||||
# eGalax touchscreen (Dell 9030 AIO built-in panel)
|
||||
# The eGalax HID descriptor confuses libinput (treats it as touchpad).
|
||||
# Fix: unbind from usbhid at boot, bind to usbtouchscreen kernel module,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue