ESP32/gen_udev_rules.py

69 lines
2.6 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import pyudev
def generate_rules():
context = pyudev.Context()
# Find all TTY devices driven by usb-serial drivers (CP210x, FTDI, etc.)
devices = []
for device in context.list_devices(subsystem='tty'):
if 'ID_VENDOR_ID' in device.properties and 'ID_MODEL_ID' in device.properties:
# We filter for USB serial devices only
parent = device.find_parent('usb', 'usb_interface')
if parent:
devices.append(device)
# Sort by their physical path so they are ordered by hub port
# The 'DEVPATH' usually looks like .../usb1/1-2/1-2.3/1-2.3.4...
devices.sort(key=lambda x: x.properties.get('DEVPATH', ''))
print(f"# Detected {len(devices)} devices. Generating rules...\n")
rules = []
hub_counter = 1
port_counter = 1
last_parent_path = None
for dev in devices:
# Get the unique physical path identifier (KERNELS)
# We need the parent USB interface kernel name (e.g., '1-1.2:1.0')
parent = dev.find_parent('usb', 'usb_interface')
if not parent: continue
kernels_path = parent.device_path.split('/')[-1]
# Simple heuristic to detect a new hub (big jump in path length or numbering)
# You might need to manually tweak the hub numbers in the file later.
# Generate the rule
# KERNELS matches the physical port.
# SYMLINK creates the static alias.
rule = f'SUBSYSTEM=="tty", KERNELS=="{kernels_path}", SYMLINK+="esp_port_{len(rules)+1:02d}"'
rules.append(rule)
print(f"Mapped {dev.device_node} ({kernels_path}) -> /dev/esp_port_{len(rules):02d}")
# Write to file
with open("99-esp32-static.rules", "w") as f:
f.write("# Persistent USB Serial mapping for ESP32 Hubs\n")
f.write("# Generated automatically. Do not edit unless topology changes.\n\n")
for r in rules:
f.write(r + "\n")
print(f"\n{'-'*60}")
print(f"SUCCESS: Generated {len(rules)} rules in '99-esp32-static.rules'.")
print(f"To install:\n 1. Review the file to ensure order is correct.")
print(f" 2. sudo cp 99-esp32-static.rules /etc/udev/rules.d/")
print(f" 3. sudo udevadm control --reload-rules")
print(f" 4. sudo udevadm trigger")
print(f"{'-'*60}")
if __name__ == '__main__':
# Requires 'pyudev'. Install with: sudo dnf install python3-pyudev (or pip install pyudev)
try:
import pyudev
generate_rules()
except ImportError:
print("Error: This script requires 'pyudev'.")
print("Install it via: pip install pyudev")