"""USB identities for the fleet vs the (future) speaker Rally.""" from __future__ import annotations from pathlib import Path LOGITECH_VID = 0x046D # HD Pro C920 (this fleet) and the older 082d id. C920_PIDS = frozenset({0x08E5, 0x082D}) # Logi Rally Camera 0881; Rally Bar / Mini / Huddle variants. RALLY_PIDS = frozenset({0x0881, 0x087C, 0x089B, 0x08D3}) RALLY_IDENTITY = "rally" # Huddly IQ on the PCH/Dante hub — not a cam-NN slot. HUDDLY_VID = 0x2BD9 HUDDLY_PIDS = frozenset({0x0021}) def usb_vid_pid_from_sysfs(sysfs_device: str) -> tuple[int, int] | None: p = Path(sysfs_device) for _ in range(12): vend = p / "idVendor" prod = p / "idProduct" if vend.is_file() and prod.is_file(): try: return int(vend.read_text().strip(), 16), int(prod.read_text().strip(), 16) except ValueError: return None if str(p).startswith("/sys/devices"): p = p.parent else: return None return None def usb_vid_pid_of_video_node(video_node: str) -> tuple[int, int] | None: link = Path(f"/sys/class/video4linux/{Path(video_node).name}/device") try: real = str(link.resolve()) except OSError: return None return usb_vid_pid_from_sysfs(real) def is_c920_pid(pid: int) -> bool: return int(pid) in C920_PIDS def is_huddly_iq(vid: int, pid: int) -> bool: return int(vid) == HUDDLY_VID and int(pid) in HUDDLY_PIDS def is_fleet_video(vid: int, pid: int) -> bool: """True only for the 20 C920s. Rally, Huddly IQ, etc. stay out of cam-NN.""" return int(vid) == LOGITECH_VID and int(pid) in C920_PIDS def is_rally_pid(pid: int) -> bool: return int(pid) in RALLY_PIDS def looks_like_rally_name(name: str) -> bool: n = (name or "").lower() return "rally" in n