fix: bulletproof mesh serial connection — PrivateDevices, auto-detect fallback, backoff
Root cause: systemd PrivateDevices=yes hid /dev/ttyUSB* from the service, preventing .198 from connecting to its Heltec V3 after the security hardening. Changes: - Set PrivateDevices=no in systemd service (serial access needs physical devices; other hardening layers remain: NoNewPrivileges, ProtectSystem, RestrictNamespaces) - Add SupplementaryGroups=dialout for explicit serial permissions - Add fallback auto-detect when configured serial path fails to open - Add exponential backoff on reconnect (5s→60s cap) to reduce log spam - Add pre-open device existence check with actionable error messages - Add udev rule (99-mesh-radio.rules) for stable /dev/mesh-radio symlink - Add /dev/mesh-radio to serial candidate list (checked first) - Add Connect button per detected device in Mesh UI - Deploy udev rule to both servers and ISO build - Fix FEDI_HASH unbound variable in deploy script - Fix deploy binary step to handle hung service stop gracefully Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ const messageText = ref('')
|
||||
const sendError = ref('')
|
||||
const broadcasting = ref(false)
|
||||
const configuring = ref(false)
|
||||
const connectingDevice = ref<string | null>(null)
|
||||
const chatScrollEl = ref<HTMLElement | null>(null)
|
||||
let pollInterval: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
@@ -302,6 +303,15 @@ async function handleToggleEnabled() {
|
||||
} finally { configuring.value = false }
|
||||
}
|
||||
|
||||
async function handleConnectDevice(devicePath: string) {
|
||||
connectingDevice.value = devicePath
|
||||
try {
|
||||
await mesh.configure({ enabled: true, device_path: devicePath } as Partial<import('@/stores/mesh').MeshStatus>)
|
||||
} finally {
|
||||
connectingDevice.value = null
|
||||
}
|
||||
}
|
||||
|
||||
function signalBars(rssi: number | null): number {
|
||||
if (rssi === null) return 0
|
||||
if (rssi > -60) return 4
|
||||
@@ -397,6 +407,14 @@ function truncatePubkey(hex: string | null): string {
|
||||
<div v-for="dev in mesh.status.detected_devices" :key="dev" class="mesh-device-row">
|
||||
<div class="mesh-device-indicator" />
|
||||
<span class="mesh-device-path">{{ dev }}</span>
|
||||
<button
|
||||
v-if="!mesh.status?.device_connected"
|
||||
class="glass-button mesh-connect-btn"
|
||||
:disabled="connectingDevice !== null"
|
||||
@click="handleConnectDevice(dev)"
|
||||
>
|
||||
{{ connectingDevice === dev ? 'Connecting...' : 'Connect' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -951,6 +969,13 @@ function truncatePubkey(hex: string | null): string {
|
||||
font-family: monospace;
|
||||
font-size: 0.8rem;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mesh-connect-btn {
|
||||
padding: 3px 12px;
|
||||
font-size: 0.75rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ─── Off-grid banner ─── */
|
||||
|
||||
Reference in New Issue
Block a user