diff --git a/.omp/skills/usbtoggle-relay/SKILL.md b/.omp/skills/usbtoggle-relay/SKILL.md index 35bbc2e..5871432 100644 --- a/.omp/skills/usbtoggle-relay/SKILL.md +++ b/.omp/skills/usbtoggle-relay/SKILL.md @@ -67,11 +67,18 @@ reboot** — nooit hardcoden. Detectie: ```bash cd /Users/eddy/src/usbtoggle -./relay 1 [poort] # relais aan → USB afgekoppeld (module uit) -./relay 0 [poort] # relais uit → USB aangekoppeld (module aan) -./relay id [poort] # identificatie (chip-ID) +./relay 1 # relais aan → USB afgekoppeld (module uit) +./relay 0 # relais uit → USB aangekoppeld (module aan) +./relay id # identificatie (chip-ID) +./relay 1 /dev/cu.usbserial-XXXX # poort expliciet opgeven (alleen als auto-detect faalt) ``` +- Zonder poortargument zoekt het script de module **automatisch**: het + probeert alle CH340-poorten (`VID:PID=1A86:7523`) met het `id`-commando + en gebruikt de eerste die `ID usbtoggle-relay` antwoordt. De module + wordt dus gevonden waar die ook is aangesloten; de poortnaam hoeft + nooit hardcoded te worden. + - Replies: `ON` / `OFF` / `ID ...`; exit 0 = gelukt, exit 1 = fout (usage, poort niet te openen, geen geldige reply). - Het script opent de poort met DTR/RTS gedeasserted (geen CH340 auto-reset); diff --git a/README.md b/README.md index 6419986..38db630 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,14 @@ Sluit aan via USB en stuur commando's: ```bash ./relay 1 # relais aan ./relay 0 # relais uit -./relay 1 /dev/cu.usbserial-XXXX # poort opgeven als default afwijkt ./relay id # toont module-ID (chip-ID, uniek per chip, onafhankelijk van USB-poort) +./relay 1 /dev/cu.usbserial-XXXX # poort expliciet opgeven (alleen als auto-detect faalt) ``` +Zonder poortargument zoekt het script de module zelf: het probeert alle +CH340-poorten met het `id`-commando en gebruikt de eerste die `ID +usbtoggle-relay` antwoordt — waar de module ook is aangesloten. + ## Pinnen | Component | GPIO | diff --git a/relay b/relay index 405c5bb..ba3d346 100755 --- a/relay +++ b/relay @@ -1,9 +1,42 @@ #!/usr/bin/env python3 -"""Toggle the USB relay via serial: ./relay 1|0|id [serial_port].""" +"""Toggle the USB relay via serial: ./relay 1|0|id [serial_port]. + +Without an explicit port the relay board is found automatically: every +USB serial port is probed with the ID command until one answers. +""" import sys import serial +import serial.tools.list_ports -DEFAULT_PORT = "/dev/cu.usbserial-2110" + +def find_relay_port() -> str | None: + """Find the relay board by probing CH340 ports with the ID command.""" + candidates = [ + p.device + for p in serial.tools.list_ports.comports() + if "1A86:7523" in (p.hwid or "") + ] + for dev in candidates: + try: + s = serial.Serial() + s.port = dev + s.baudrate = 115200 + s.timeout = 1 + s.dtr = False + s.rts = False + s.open() + try: + s.readline() # gooi boot-banner weg + s.reset_input_buffer() + s.write(b"?") + s.flush() + if s.readline().decode(errors="replace").startswith("ID "): + return dev + finally: + s.close() + except serial.SerialException: + continue + return None def main() -> int: if len(sys.argv) not in (2, 3) or sys.argv[1] not in ("0", "1", "id"): @@ -11,7 +44,15 @@ def main() -> int: return 1 command = sys.argv[1] serial_cmd = "?" if command == "id" else command - port = sys.argv[2] if len(sys.argv) == 3 else DEFAULT_PORT + if len(sys.argv) == 3: + port = sys.argv[2] + else: + port = find_relay_port() + if port is None: + print("ERROR: no relay module found on any USB serial port", + file=sys.stderr) + return 1 + print(f"Using {port}", file=sys.stderr) try: # dtr/rts expliciet uit vóór open: voorkomt (of beperkt) de CH340 # auto-reset (DTR->RST) bij het openen van de poort. pyserial 3.5