feat(portal): Workbench-Bridge support — device identity, reset profiles, proxy liveness#13
Open
sthomas69 wants to merge 1 commit into
Open
Conversation
…les, proxy liveness Adds the per-slot capability data and robustness the Workbench-Bridge Windows companion needs for remote flashing/monitoring. (The Activity-log Clear fix is submitted separately in its own PR, so it is intentionally excluded here.) - Per-slot device identity + classification: vid/pid, vendor/model, device_type, transport (uart-bridge | native-usb), chip_family, device_id (base MAC), and a reset_profile (reset_method classic|usb-jtag|gpio, gpio_boot/gpio_en, download_mode_capable). On-demand probe endpoints (esptool chip_id / read_mac), auto-identify on plug-in, surfaced via /api/devices. - Proxy liveness self-heal: _refresh_slot_health restarts a per-slot RFC2217 proxy whose tty re-enumerated under it (stale fd) via _tty_usb_id (busnum:devnum), debounced (PROXY_STALE_GRACE_S) — recovers after a native-USB download-reset without a manual proxy restart. - Dashboard: slot cards show device type / VID:PID / transport / chip / reset method / MAC; responsive grid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR adds (1) a stale-proxy auto-restart mechanism when a USB tty device re-enumerates under an existing RFC2217 proxy, and (2) an on-demand “Identify Device” feature that runs esptool chip_id, caches results per slot, and exposes them via the API/UI.
Changes:
- Track USB identity for each started proxy and restart proxies whose underlying USB device re-enumerated.
- Add
/api/devices/<slot>/identifyendpoint to run esptool, cachechip_info+device_id, and display it in the UI. - UI layout tweaks to support the new Identify button and display chip/MAC info.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+952
to
+959
| name = os.path.basename(devnode) # e.g. ttyACM0 | ||
| iface = os.path.realpath(f"/sys/class/tty/{name}/device") # .../1-1.1.2:1.0 | ||
| usbdev = os.path.dirname(iface) # .../1-1.1.2 (the USB device) | ||
| with open(os.path.join(usbdev, "busnum")) as f: | ||
| busnum = f.read().strip() | ||
| with open(os.path.join(usbdev, "devnum")) as f: | ||
| devnum = f.read().strip() | ||
| return f"{busnum}:{devnum}" |
Comment on lines
+1756
to
+1761
| was_debugging = bool(label and debug_controller.is_debugging(label)) | ||
| resume_chip = slot.get("_auto_debug_chip") | ||
| builtin_jtag = slot.get("_jtag_slot") == label | ||
| if was_debugging: | ||
| debug_controller.stop(label) | ||
| time.sleep(1) |
Comment on lines
+1878
to
+1882
| body = self._read_json() or {} | ||
| before = body.get("before", "default_reset") | ||
| if before not in ("default_reset", "no_reset", "no_reset_no_sync"): | ||
| before = "default_reset" | ||
| timeout = float(body.get("timeout", 30)) |
Comment on lines
+1792
to
+1797
| parsed["chip_family"] = _chip_family(parsed["chip"]) | ||
| parsed["before"] = before | ||
| slot["chip_info"] = parsed | ||
| if parsed.get("mac"): | ||
| slot["device_id"] = parsed["mac"] | ||
| result = {"ok": True, **parsed, "raw": tail} |
Comment on lines
+1874
to
+1876
| if not slot.get("present") or not slot.get("devnode"): | ||
| self._send_json({"ok": False, "error": f"{slot_id}: no device present"}) | ||
| return |
Comment on lines
+985
to
+994
| opened = slot.get("_proxy_dev_id") | ||
| current = _tty_usb_id(slot["devnode"]) if slot.get("present") else None | ||
| if opened and current and current != opened: | ||
| now = time.time() | ||
| if slot.get("_stale_since") is None: | ||
| slot["_stale_since"] = now | ||
| elif (now - slot["_stale_since"] >= PROXY_STALE_GRACE_S | ||
| and not slot.get("_proxy_restarting")): | ||
| slot["_proxy_restarting"] = True | ||
| slot["last_error"] = "Proxy devnode re-enumerated — restarting (stale fd)" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the per-slot capability data and robustness a remote-flashing companion (Workbench-Bridge, a Windows service that presents the Pi's RFC2217 slots as local COM ports) needs. Running on my bench.
What's in here
/api/devicesreports vid/pid, vendor/model,device_type,transport(uart-bridge | native-usb),chip_family,device_id(base MAC), and areset_profile(reset_method classic|usb-jtag|gpio, gpio_boot/gpio_en, download_mode_capable). On-demand probe endpoints (esptool chip_id / read_mac), auto-identify on plug-in._refresh_slot_healthrestarts a per-slot RFC2217 proxy whose tty re-enumerated under it (stale fd) via_tty_usb_id(busnum:devnum), debounced (PROXY_STALE_GRACE_S). Recovers after a native-USB download-reset without a manual restart. (This piece is broadly useful and self-contained — happy to split it into its own PR if you'd prefer to take just that.)python -m py_compileclean; deployed and serving on a live workbench (9 slots).Some of this (the identity/reset-profile detail) is motivated by the external bridge use-case, so take whatever's useful — I can carve it up however suits the project.