feat(mesh-ui): RNode settings editor with live device read-back + region presets
Demo images / Build & push demo images (push) Successful in 3m49s

The LoRa device panel's Reticulum section (operator .126 top priority):

- Shows the device's CURRENT settings first — the radio-confirmed r_*
  values from mesh.rnode-config (online badge, port, frequency, bw,
  SF, CR, txpower, airtime limits), with a Refresh action.
- Every RNodeInterface parameter is editable: enabled, serial port
  (auto-detect when blank), frequency, bandwidth (RNode's discrete
  set), SF 5-12, CR 4/5-4/8, txpower, airtime short/long %.
- "Set recommended for <region>" fills the fields from per-region
  plans (EU868 = the operator-validated Portugal plan incl. 25%/10%
  duty-cycle locks); driven by the existing region selector above.
- Apply & Confirm on Device: persists, restarts the radio daemon, and
  reports the radio's own confirmation (green ✓ only when the device
  read-back matches; amber/red messages say what actually happened).
- Action buttons stack in a column (operator layout request).
- Reboot Radio surfaces the backend's real acknowledgement message.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-06 09:08:19 -04:00
co-authored by Claude Fable 5
parent 45fa8b6c6f
commit 3cef1d09f4
2 changed files with 251 additions and 3 deletions
+26 -1
View File
@@ -863,12 +863,35 @@ export const useMeshStore = defineStore('mesh', () => {
}
async function rebootRadio(seconds = 2) {
return rpcClient.call<{ reboot: boolean; seconds: number }>({
// Long timeout: Reticulum reboots restart the sidecar daemon and the
// backend waits for the acknowledgement instead of fire-and-forgetting.
return rpcClient.call<{ reboot: boolean; seconds: number; message?: string }>({
method: 'mesh.reboot-radio',
params: { seconds },
timeout: 30000,
})
}
/** Persisted RNode RF settings + live radio-confirmed state (Reticulum). */
async function getRnodeConfig() {
return rpcClient.call<{
settings: Record<string, unknown>
live: Record<string, unknown> | null
live_error: string | null
}>({ method: 'mesh.rnode-config', timeout: 20000 })
}
/** Apply RNode RF settings: persists, restarts the radio daemon, waits for
* the radio's own read-back confirmation (up to ~50s). */
async function applyRnodeConfig(settings: Record<string, unknown>) {
return rpcClient.call<{
applied: boolean
confirmed?: boolean
live?: Record<string, unknown> | null
message: string
}>({ method: 'mesh.rnode-config-apply', params: { settings }, timeout: 70000 })
}
async function getOutbox() {
try {
return await rpcClient.call<{ count: number; messages?: unknown[] }>({ method: 'mesh.outbox' })
@@ -1155,6 +1178,8 @@ export const useMeshStore = defineStore('mesh', () => {
sendReply,
sendReaction,
rebootRadio,
getRnodeConfig,
applyRnodeConfig,
getOutbox,
sendReadReceipt,
forwardMessage,