Skip to content

feat(portal): Workbench-Bridge support — device identity, reset profiles, proxy liveness#13

Open
sthomas69 wants to merge 1 commit into
SensorsIot:mainfrom
sthomas69:feature/workbench-bridge-support
Open

feat(portal): Workbench-Bridge support — device identity, reset profiles, proxy liveness#13
sthomas69 wants to merge 1 commit into
SensorsIot:mainfrom
sthomas69:feature/workbench-bridge-support

Conversation

@sthomas69

Copy link
Copy Markdown

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.

Note: the Activity-log Clear fix is submitted separately (#11), and is intentionally excluded from this branch to keep the diffs clean.

What's in here

  • Per-slot device identity + classification/api/devices reports 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.
  • 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 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.)
  • Dashboard — slot cards show device type / VID:PID / transport / chip / reset method / MAC; responsive grid.

python -m py_compile clean; 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.

…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>
Copilot AI review requested due to automatic review settings June 16, 2026 03:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>/identify endpoint to run esptool, cache chip_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 thread pi/portal.py
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 thread pi/portal.py
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 thread pi/portal.py
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 thread pi/portal.py
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 thread pi/portal.py
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 thread pi/portal.py
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)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants