summaryrefslogtreecommitdiff
path: root/api_layers/arduino_layer.py
diff options
context:
space:
mode:
Diffstat (limited to 'api_layers/arduino_layer.py')
-rw-r--r--api_layers/arduino_layer.py40
1 files changed, 40 insertions, 0 deletions
diff --git a/api_layers/arduino_layer.py b/api_layers/arduino_layer.py
index a3c3584..07520d6 100644
--- a/api_layers/arduino_layer.py
+++ b/api_layers/arduino_layer.py
@@ -575,6 +575,46 @@ class ArduinoLayer:
return desc
return ""
+ @staticmethod
+ def port_serial_number(port: str) -> str:
+ """USB serial number for a currently-connected port, if the OS/driver
+ exposes one — empty string if unavailable or the port isn't enumerable."""
+ if not _SERIAL_AVAILABLE:
+ return ""
+ try:
+ for p in serial.tools.list_ports.comports():
+ if p.device == port:
+ return getattr(p, "serial_number", None) or ""
+ except Exception as e:
+ print(f"[ArduinoLayer] port_serial_number() error: {e}")
+ return ""
+
+ @staticmethod
+ def find_port_by_identity(description: str = "", serial_number: str = "") -> Optional[str]:
+ """Re-map a device saved in a profile to whatever port it enumerates
+ as on *this* machine — COM/tty numbers aren't stable across machines
+ (or even across replugs on Linux). Prefers USB serial number (unique
+ even between two identical board models); falls back to an exact
+ description-string match. Returns None if nothing matches — caller
+ should fall back to the saved port as-is (device will show ERROR
+ until the operator fixes it manually)."""
+ if not _SERIAL_AVAILABLE:
+ return None
+ try:
+ ports = list(serial.tools.list_ports.comports())
+ except Exception as e:
+ print(f"[ArduinoLayer] find_port_by_identity() error: {e}")
+ return None
+ if serial_number:
+ for p in ports:
+ if (getattr(p, "serial_number", None) or "") == serial_number:
+ return p.device
+ if description:
+ for p in ports:
+ if (p.description or "") == description:
+ return p.device
+ return None
+
def __repr__(self):
mode = "SIM" if self.simulate else f"HW:{self.port}@{self.baud}"
return f"<ArduinoLayer {mode} pins={self.analog_pins}>"