Skip to content

Conversation

@brianignacio5
Copy link
Collaborator

Description

This pull request adds robust device reconnection support to the TypeScript example, improving the user experience when a serial device is unexpectedly disconnected. The main changes include tracking device info for reconnection, implementing a callback for device loss, and refactoring the console reading loop to support automatic reconnection.

Device reconnection and management:

  • Added tracking of deviceInfo to store USB vendor and product IDs, enabling identification and reconnection to the same device after disconnection. [1] [2] [3]
  • Implemented a device lost callback in the Transport class and set it up in the UI logic, allowing the app to detect when the device is lost and attempt to reconnect automatically. [1] [2] [3]

Console reading and reconnection logic:

  • Refactored the console reading loop into a separate startConsoleReading function, which handles errors and waits for reconnection if the device is lost.
  • Added logic to attempt reconnection by searching for previously authorized devices matching the original device's USB IDs, updating the transport, and restarting the console read loop upon successful reconnection.

These changes make the application more resilient to device disconnects, providing a smoother workflow for users interacting with serial devices.

Checklist

Before submitting a Pull Request, please ensure the following:

  • 🚨 This PR does not introduce breaking changes.
  • All CI checks (GH Actions) pass.
  • Documentation is updated as needed.
  • Tests are updated or added as necessary.
  • Code is well-commented, especially in complex areas.
  • Git history is clean — commits are squashed to the minimum necessary.

@brianignacio5 brianignacio5 self-assigned this Oct 15, 2025
@github-actions
Copy link

github-actions bot commented Oct 15, 2025

Download the artifacts for this pull request:

@tyeth
Copy link

tyeth commented Oct 15, 2025

Hey Brian 👋
This doesn't reconnect for me on Windows as in general usb reconnections take over 1second (it's as bad as 3seconds on my slowest laptop - but that might be with the sketch / circuitpython loading after tinyuf2 bootloader delay too).
serialLib.getPorts returns [].
If I run the developer tools and break at the reconnection, then allow it to check the available ports after hearing the usb reconnection noise in windows - about 1s after rebooting device, then the reconnection works correctly. Nice work!
Makes me think it would be worth adding a retry check of the available ports (maybe once per second up to 5times then bail).
Also worth adding a subsequent message on failure as currently nothing is emitted after this (the attempt is over)

[DEVICE LOST] Device disconnected. Click 'Reconnect' to restore connection...
[CONSOLE] Connection lost, waiting for reconnection...
[RECONNECT] Attempting to reconnect...
image

Oh and I didn't see the reconnect button at all, but maybe I merged/rebased it out 😂

@brianignacio5
Copy link
Collaborator Author

brianignacio5 commented Oct 16, 2025

Hi @tyeth Thank you for testing and review this PR.

I've added the configurable timeout and a retry loop with configurable max retries. Pleas take a look when you can.

The reconnect button was an initial idea I had but is better that is does this automatically so I remove such idea, that was a leftover log output I also fixed.

@tyeth
Copy link

tyeth commented Oct 16, 2025

Seems to work well! On a circuitpython device (has tinyuf2 delay) I don't see the connection until fourth try (and this is the quicker usb computer).
image

First attempt thought I didn't see any reconnection attempt at all when rebooting device, but not sure what I'd done there as totally unable to recreate. I had definitely connected already, but no serial output from device (expected) so wonder if that related. I then retried the test and worked fine, also tested serial was seen as expected. Looks good and cannot recreate.

On a related pogramming / disconnect note, the feather huzzah32 v1 (and Espressif ESP32-C3 DevkitM-1-N4) seem to only tolerate 115200bps, stalling at esploader.main in changeBaud where it calls disconnect(then sleep then connect) on the device/transport at any other baud rate, seemingly never recovering from the disconnect call (I did come back to one tab tens of minutes later and it had timed out but continued on to write firmware). I wonder if we can safely attempt higher speeds then retry at 115k if needed (but that disconnect stalling is a nightmare).
image
(Crashes/stalls on first highlighted disconnect of changeBaud)

Chip Magic: 0xf01d83
Detecting chip type... ESP32
Chip is ESP32-D0WD-V3 (revision 3)
Features: Wi-Fi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None

The other related thought was that we might wish to listen for and reconnect to more than one serial device's PID/VID (i.e. the jtag serial port first, before tinyusb kicks in and changes the device vid/pid for the circuitpython cdc / arduino tinyusb serial port), but that's more of an end-user implementation detail that might affect the retry logic.

@brianignacio5
Copy link
Collaborator Author

Seems to work well! On a circuitpython device (has tinyuf2 delay) I don't see the connection until fourth try (and this is the quicker usb computer). image

First attempt thought I didn't see any reconnection attempt at all when rebooting device, but not sure what I'd done there as totally unable to recreate. I had definitely connected already, but no serial output from device (expected) so wonder if that related. I then retried the test and worked fine, also tested serial was seen as expected. Looks good and cannot recreate.

On a related pogramming / disconnect note, the feather huzzah32 v1 (and Espressif ESP32-C3 DevkitM-1-N4) seem to only tolerate 115200bps, stalling at esploader.main in changeBaud where it calls disconnect(then sleep then connect) on the device/transport at any other baud rate, seemingly never recovering from the disconnect call (I did come back to one tab tens of minutes later and it had timed out but continued on to write firmware). I wonder if we can safely attempt higher speeds then retry at 115k if needed (but that disconnect stalling is a nightmare). image (Crashes/stalls on first highlighted disconnect of changeBaud)

Chip Magic: 0xf01d83
Detecting chip type... ESP32
Chip is ESP32-D0WD-V3 (revision 3)
Features: Wi-Fi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None

The other related thought was that we might wish to listen for and reconnect to more than one serial device's PID/VID (i.e. the jtag serial port first, before tinyusb kicks in and changes the device vid/pid for the circuitpython cdc / arduino tinyusb serial port), but that's more of an end-user implementation detail that might affect the retry logic.

Regarding the baud rate changing I haven't found issues with the boards I have here. I have tested some 3rd party boards which fail with higher baud rate but they also fails with same issue in esptool.py :

A fatal error occurred: Unable to verify flash chip connection (Serial data stream stopped: Possible serial noise or corruption.).

I'll try to get a ESP32-C3 DevkitM-1-N4 and test this, my older ESP32-C3 DevkitM-1 does work though.

If the VID and PID changes I'm not sure how we can get the right serial device when doing the reconnection as done here, WebSerial doesn't really provide the serial port name (like /dev/cu*) so would be tricky to know which board is which.

@tyeth
Copy link

tyeth commented Oct 22, 2025

Thanks Brian, yeah you're right to call our the PID/VID changes, but my hope was that once the user has had the device in bootloader/JTAG-serial mode once, and additionally connected in normal running mode (circuitpython CDC / tinyusb serial) once, then we'd have access to both forever in reconnection terms. I should probably test that theory before getting too excited...

With the C3 / huzzah32 v1, I wonder if there's a way to make the disconnect / timeout occur more quickly, or on a related note if we can detect timeouts more rapidly in the initial stages (before large reads/writes of the flash as that is obviously much more likely to timeout).

I also wonder if we can do anything after a timeout in the early stages, like does disconnecting the serial port (even though the transport is dead) help at all, and would the board be able to run esptool again without physically disconnecting or rebooting the device. That of course assumes that calling disconnect or whatever doesn't stall indefinitely or for too long to be useful in UI feedback terms.

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.

3 participants