From 992bf636e0dd640ce24b8159aebae4843542c4b6 Mon Sep 17 00:00:00 2001 From: ssmithx Date: Thu, 23 Jul 2026 02:31:46 +0000 Subject: [PATCH] fix(mesh): board auto-detect used the wrong signal, false-flagged Heltec V3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "couldn't confirm the board automatically" warning was checking the display label text (/v3/i, /v4/i) instead of the same vid:pid table the backend actually uses to resolve the board. A Heltec V3's CP2102 bridge chip reports "CP2102 USB to UART Bridge Controller" in its USB strings, not "Heltec", so meshDeviceImages.ts's fallback label ("LoRa radio (CP2102 serial)") never matched the regex — showing the low-confidence warning (and leaving the board picker empty) even though the backend's resolve_flash_board can safely auto-detect V3 via vid:pid 10c4:ea60. Now checks the same vid:pid directly from detected_device_info, matching mesh::flash::resolve_flash_board exactly. V4 still has no auto-match entry, same as the backend — its vid:pid (303a:1001) is the ESP32-S3's generic native-USB descriptor, not V4-specific, so manual selection is still required there. Co-Authored-By: Claude Sonnet 5 --- .../components/mesh/MeshDeviceSetupModal.vue | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/neode-ui/src/components/mesh/MeshDeviceSetupModal.vue b/neode-ui/src/components/mesh/MeshDeviceSetupModal.vue index ae2fe414..5582c4ca 100644 --- a/neode-ui/src/components/mesh/MeshDeviceSetupModal.vue +++ b/neode-ui/src/components/mesh/MeshDeviceSetupModal.vue @@ -453,10 +453,27 @@ const starting = ref(false) const flashJob = ref(null) let flashPollTimer: ReturnType | null = null -// Best-effort guess from the already-resolved board image label — the user -// can always override; a wrong guess just means the checkbox below draws -// their attention to the warning before anything destructive happens. -const boardAutoDetected = computed(() => /v4/i.test(deviceImage.value.label) || /v3/i.test(deviceImage.value.label)) +const detectedInfo = computed(() => + mesh.status?.detected_device_info?.find(d => d.path === devicePath.value) +) + +// Mirrors mesh::flash::resolve_flash_board (core/archipelago/src/mesh/flash.rs) +// exactly — matching on the display label was wrong: a Heltec V3's CP2102 +// bridge chip reports "CP2102 USB to UART Bridge Controller" in its USB +// strings, not "Heltec", so meshDeviceImages.ts falls back to a generic +// "LoRa radio (CP2102 serial)" label that never matched /v3/i, showing the +// "couldn't confirm automatically" warning even though the backend CAN +// safely auto-detect V3 via vid:pid. Heltec V4 deliberately has no entry +// here, same reasoning as the backend: its vid:pid (303a:1001) is the +// ESP32-S3's generic native-USB descriptor, not V4-specific, so it can't be +// safely auto-matched and always requires manual selection. +const resolvedFlashBoard = computed(() => { + const info = detectedInfo.value + if (info?.vid?.toLowerCase() === '10c4' && info?.pid?.toLowerCase() === 'ea60') return 'heltec-v3' + return '' +}) + +const boardAutoDetected = computed(() => !!resolvedFlashBoard.value) const flashStageLabel = computed(() => { switch (flashJob.value?.stage) { @@ -472,7 +489,7 @@ const flashStageLabel = computed(() => { function openFlashStep() { flashFamily.value = (probe.value?.kind as FlashFirmwareFamily) ?? '' - flashBoard.value = /v4/i.test(deviceImage.value.label) ? 'heltec-v4' : /v3/i.test(deviceImage.value.label) ? 'heltec-v3' : '' + flashBoard.value = resolvedFlashBoard.value flashConfirmed.value = false flashJob.value = null error.value = ''