OpenRGB可以调整部分外星人外设的灯光,目前不支持AW720M,在Mac上又不能安装AWCC,这一点戴尔做的属实垃圾,目前亲测成功的是,使用 Hidapi 向外设发送指令来更改灯光颜色。
整体流程:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# AW720M 灯光控制脚本(Mac) 通过 HID Feature Report 控制 Alienware AW720M 等设备的 RGB 灯光。 ## 遇到 externally-managed-environment 时(Homebrew Python) 系统禁止直接 `pip3 install` 时,可用下面任一方式,**无需手动建虚拟环境**。 ### 方式一:pipx run(推荐,零安装) 每次用 `pipx run` 自动带好 hidapi,不用激活 venv、不用改系统 Python: ```bash cd Hidapi # 首次使用需安装 pipx:brew install pipx && pipx ensurepath pipx run --spec hidapi python3 AW720M.py --list pipx run --spec hidapi python3 AW720M.py --r 255 --g 0 --b 0 ``` ### 方式二:允许 pip 安装到系统(一次安装,之后直接 python3) 接受 PEP 668 的覆盖方式,以后可直接 `python3 AW720M.py`: ```bash pip3 install --break-system-packages hidapi cd Hidapi python3 AW720M.py --list python3 AW720M.py --r 255 --g 0 --b 0 ``` ### 方式三:虚拟环境(传统做法) ```bash cd Hidapi python3 -m venv .venv source .venv/bin/activate pip install hidapi python3 AW720M.py --list python3 AW720M.py --r 255 --g 0 --b 0 ``` ## 使用 ```bash # 枚举本机 HID 设备,确认鼠标的 VID/PID python3 AW720M.py --list # 设置灯光颜色(不写死 VID/PID,按设备名称自动发现;或 --list 后用 --vid/--pid 指定) python3 AW720M.py --r 255 --g 0 --b 0 python3 AW720M.py --r 0 --g 255 --b 0 python3 AW720M.py --r 0 --g 0 --b 255 ``` (若用方式一,上述命令前加:`pipx run --spec hidapi`。) ## 提示「无法打开设备 / open failed」时 - 脚本**不写死 VID/PID**,设备 ID 从枚举结果动态获取;名称含 Alienware/AW720 等即会匹配。 1. **macOS 输入监控权限**:系统设置 → 隐私与安全性 → 输入监控 → 勾选「终端」(或你运行脚本的 App)。 2. **用 sudo 试一次**:`sudo python3 AW720M.py --r 255 --g 0 --b 0`(若这样能成功,多半是权限问题)。 3. 关闭 **Alienware Command Center、Dell 外设管理** 等可能占用 HID 的软件后再试。 4. **AW720M 请用 USB 线连接**(不要仅用蓝牙)再运行脚本。 5. **macOS 限制**:系统可能独占鼠标的 HID 接口,导致即使用 sudo 仍「open failed」。此时只能在 Windows 或 Linux 下用本脚本控制灯光。 6. 脚本会遍历所有匹配接口并尝试按 path / 按 vid:pid 打开;若仍失败,可用 `--list` 查看本机 VID:PID 后以 `--vid/--pid` 明确指定。 ## 参数说明 | 参数 | 说明 | |------|------| | `--list` | 列出所有 HID 设备(用于查看 VID/PID) | | `--vid 0xXXXX` | USB Vendor ID(不指定则按设备名称自动发现) | | `--pid 0xXXXX` | USB Product ID(不指定则按设备名称自动发现) | | `--r`, `--g`, `--b` | 红/绿/蓝 0–255 | | `--zone N` | 灯区索引,默认 0 | 协议参考 OpenRGB 的 Alienware 控制器实现。 |
Python3 脚本:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ AW720M 灯光控制(Mac,可不使用虚拟环境) 通过 HID Feature Report 设置 Alienware 鼠标/设备的 RGB 灯光。 依赖:pip3 install --user hidapi 或 brew install hidapi 后 pip 安装 hidapi """ from __future__ import print_function import argparse import sys import time try: import hid except ImportError: print("请先安装 hidapi:", file=sys.stderr) print(" 方式一(推荐,无需改系统):pipx run --spec hidapi python3 AW720M.py --list", file=sys.stderr) print(" 方式二(一次安装):pip3 install --break-system-packages hidapi", file=sys.stderr) print(" 方式三:python3 -m venv .venv && source .venv/bin/activate && pip install hidapi", file=sys.stderr) sys.exit(1) # 协议常量 # APIv4:34 字节 Feature Report(OpenRGB Alienware 笔记本/台式) REPORT_SIZE = 33 HIDAPI_REPORT_SIZE = REPORT_SIZE + 1 CMD_SET_COLOR = 0x27 # APIv7:65 字节 USB Interrupt OUT(Alienware 鼠标,如 AW610M/AW720M,见 alienfx-tools) APIv7_REPORT_SIZE = 65 APIv7_CMD_CONTROL = (0x40, 0x10, 0x0c, 0x00, 0x01) # COMMV7_control APIv7_EFFECT_COLOR = 1 # v7OpCodes[AlienFX_A_Color] # COMMV7_update:设色后发送以“提交”,否则后续设色可能不生效 APIv7_CMD_UPDATE = (0x40, 0x60, 0x07, 0x00, 0xc0, 0x4e, 0x00, 0x01) # 自动发现时仅按设备名称匹配,VID/PID 完全从枚举结果动态获取,不写死 NAME_KEYWORDS = ("alienware", "aw720", "g series") def _path_str(d): p = d.get("path") if p is None: return "" return p.decode("utf-8", errors="replace") if isinstance(p, bytes) else p def _str_lower(d, key): s = (d.get(key) or "").strip() or "" if isinstance(s, bytes): s = s.decode("utf-8", errors="replace") return s.lower() def _device_name_matches(d, keywords=NAME_KEYWORDS): """设备厂商或产品名包含任一关键词即视为匹配,用于动态发现。""" product = _str_lower(d, "product_string") manufacturer = _str_lower(d, "manufacturer_string") combined = product + " " + manufacturer return any(kw in combined for kw in keywords) def list_hid_devices(): """枚举所有 HID 设备,便于确认 AW720M 的 VID/PID。""" print("HID 设备列表(VID:PID 路径 厂商 产品):") print("-" * 60) for d in hid.enumerate(): print(" {:04x}:{:04x} {} {} {}".format( d["vendor_id"], d["product_id"], _path_str(d), (d.get("manufacturer_string") or "").strip() or "-", (d.get("product_string") or "").strip() or "-", )) print("-" * 60) print("未指定 --vid/--pid 时会按设备名称自动匹配(名称含 Alienware/AW720 等);VID:PID 从枚举动态获取。") def find_target_devices(vid=None, pid=None, name_keywords=None): """ 动态查找目标设备,不写死 VID/PID。 - 若指定了 vid+pid:枚举该 VID:PID 下所有 HID 接口,返回 [(path, vid, pid), ...]。 - 未指定:枚举全部设备,按厂商/产品名包含关键词匹配,返回匹配项的 path 与枚举得到的 vid/pid。 返回 [(path, vid, pid), ...],vid/pid 均来自枚举结果。 """ out = [] for d in hid.enumerate(vid if vid is not None else 0, pid if pid is not None else 0): v, p = d["vendor_id"], d["product_id"] if vid is not None and pid is not None: if v != vid or p != pid: continue else: if not _device_name_matches(d, name_keywords or NAME_KEYWORDS): continue out.append((d["path"], v, p)) return out def send_feature_report(dev, buf): """发送 HID Feature Report,并做短暂延时避免设备忙。""" dev.send_feature_report(bytes(buf)) time.sleep(0.06) def get_feature_report(dev, report_id=0x00, size=HIDAPI_REPORT_SIZE): """读取 HID Feature Report。""" return dev.get_feature_report(report_id, size) def set_color_apiv7(dev, r, g, b, zone=0, brightness=0x64, retries=5): """ APIv7:65 字节 USB Interrupt OUT,用于 Alienware 鼠标(AW610M/AW720M 等)。 先发 control 设色,再发 update 提交;重复 retries 次并加延时,提高“有时有效有时无效”时的成功率。 """ # 预建 control 与 update 包,避免重复逻辑 buf = bytearray(APIv7_REPORT_SIZE) buf[0] = 0x00 for i, byte_val in enumerate(APIv7_CMD_CONTROL): buf[1 + i] = byte_val buf[5] = APIv7_EFFECT_COLOR buf[6] = brightness & 0xFF buf[7] = zone & 0xFF buf[8] = r & 0xFF buf[9] = g & 0xFF buf[10] = b & 0xFF control_packet = bytes(buf) upd = bytearray(APIv7_REPORT_SIZE) upd[0] = 0x00 for i, byte_val in enumerate(APIv7_CMD_UPDATE): upd[1 + i] = byte_val update_packet = bytes(upd) time.sleep(0.05) # 打开设备后稍等再发,避免首包被丢 for _ in range(retries): dev.write(control_packet) time.sleep(0.12) dev.write(update_packet) time.sleep(0.12) def set_color_direct(dev, r, g, b, zones=(0,)): """ APIv4:34 字节 HID Feature Report,用于部分 Alienware 笔记本/台式。 部分设备不回复读取,发送后若读回失败则忽略。 """ buf = bytearray(HIDAPI_REPORT_SIZE) buf[0] = 0x00 buf[1] = 0x03 buf[2] = CMD_SET_COLOR buf[3] = r & 0xFF buf[4] = g & 0xFF buf[5] = b & 0xFF n = len(zones) buf[6] = (n >> 8) & 0xFF buf[7] = n & 0xFF for i, z in enumerate(zones): if 8 + i < len(buf): buf[8 + i] = z & 0xFF send_feature_report(dev, buf) try: get_feature_report(dev) except OSError: pass def open_device(vid, pid, path=None): """ 打开 HID 设备,兼容 hid.Device(新)与 hid.device()(旧)两种 API。 path 优先;否则用 vid/pid。 """ def open_by_path(p): if hasattr(hid, "Device"): return hid.Device(path=p) dev = hid.device() dev.open_path(p) return dev def open_by_vid_pid(v, p): if hasattr(hid, "Device"): return hid.Device(vid=v, pid=p) dev = hid.device() dev.open(v, p) return dev if path is not None: return open_by_path(path) return open_by_vid_pid(vid, pid) def main(): ap = argparse.ArgumentParser(description="AW720M / Alienware HID 灯光控制(可不使用虚拟环境)") ap.add_argument("--list", action="store_true", help="枚举 HID 设备并退出,用于查看 VID/PID") ap.add_argument("--vid", type=lambda x: int(x, 0), default=None, help="USB Vendor ID(不指定则按设备名称自动发现)") ap.add_argument("--pid", type=lambda x: int(x, 0), default=None, help="USB Product ID(不指定则按设备名称自动发现)") ap.add_argument("--no-report-id", action="store_true", help="部分设备不需要 Report ID,当前实现仍带 1 字节") ap.add_argument("--r", type=int, default=None, metavar="0-255", help="红色") ap.add_argument("--g", type=int, default=None, metavar="0-255", help="绿色") ap.add_argument("--b", type=int, default=None, metavar="0-255", help="蓝色") ap.add_argument("--zone", type=int, default=0, help="灯区索引,默认 0") args = ap.parse_args() if args.list: list_hid_devices() return r = args.r if args.r is not None else 255 g = args.g if args.g is not None else 0 b = args.b if args.b is not None else 0 r = max(0, min(255, r)) g = max(0, min(255, g)) b = max(0, min(255, b)) # 动态查找目标设备:未指定 vid/pid 时按名称匹配,vid/pid 一律从枚举结果取 candidates = find_target_devices(args.vid, args.pid) if not candidates: # 仅当用户同时指定了 vid 和 pid 时,再试一次直接按该 ID 打开 if args.vid is not None and args.pid is not None: candidates = [(None, args.vid, args.pid)] else: print("未找到名称匹配的设备(Alienware/AW720 等)。请运行 python3 AW720M.py --list 查看设备列表,并用 --vid/--pid 指定。", file=sys.stderr) sys.exit(2) # 对每个候选接口都打开并发送设色命令(不只看第一个能打开的),避免枚举顺序导致有时命中 LED 有时没命中 last_error = None any_open = False any_sent = False for path, vid_open, pid_open in candidates: dev = None try: dev = open_device(vid_open, pid_open, path=path) any_open = True except Exception as e: last_error = e continue try: try: set_color_apiv7(dev, r, g, b, zone=args.zone) any_sent = True except OSError: try: set_color_direct(dev, r, g, b, zones=(args.zone,)) any_sent = True except OSError: pass finally: if dev is not None: dev.close() # 若按 path 一个都没打开,再试一次仅用 vid/pid 打开 if not any_open and candidates: vid_open, pid_open = candidates[0][1], candidates[0][2] try: dev = open_device(vid_open, pid_open, path=None) any_open = True try: set_color_apiv7(dev, r, g, b, zone=args.zone) any_sent = True except OSError: try: set_color_direct(dev, r, g, b, zones=(args.zone,)) any_sent = True except OSError: pass finally: dev.close() except Exception as e: last_error = e if not any_open: print("无法打开 Alienware 设备:{}".format(last_error), file=sys.stderr) print("", file=sys.stderr) print("常见原因与处理:", file=sys.stderr) print(" 1. macOS 权限:系统设置 → 隐私与安全性 → 输入监控 → 勾选「终端」或你使用的 App。", file=sys.stderr) print(" 2. 尝试用 sudo 运行:sudo python3 AW720M.py --r 255 --g 0 --b 0", file=sys.stderr) print(" 3. 关闭 Alienware Command Center、Dell 外设管理等可能占用设备的软件后重试。", file=sys.stderr) print(" 4. AW720M 请用 USB 线连接(不要仅用蓝牙),再试。", file=sys.stderr) print(" 5. macOS 可能独占鼠标的 HID 接口,导致无法打开;可尝试在 Windows 或 Linux 下用本脚本。", file=sys.stderr) if not candidates or candidates[0][0] is None: print(" 6. 运行 python3 AW720M.py --list 查看本机 HID 设备,用 --vid/--pid 指定你的设备。", file=sys.stderr) sys.exit(2) if any_sent: print("已设置灯光 R={} G={} B={}".format(r, g, b)) else: print("已向设备各接口发送命令但均写失败;若灯光无变化可尝试关闭 Dell/Alienware 驱动或换 USB 口。", file=sys.stderr) if __name__ == "__main__": main() |
使用:
sudo python3 AW720M.py –r 255 –g 255 –b 255
来更改RGB颜色

