b00mhauercode/magrgb-controller

GitHub: b00mhauercode/magrgb-controller

为 Secretlab Magnus XL RGB 灯带逆向实现了 HAP-BLE 与 Thread 双协议控制器,并提供 WLED 桥接以兼容 SignalRGB。

Stars: 0 | Forks: 0

# Secretlab MAGRGB 控制器 包含两个网桥 — 选择适合您设置的一个: | 网桥 | 传输方式 | 速度 | 要求 | |---|---|---|---| | `magnus_wled_bridge_thread.py` | Thread/UDP over IPv6 | ~20 Hz | Nanoleaf Desktop app(启动时运行一次) | | `magnus_wled_bridge_hapble.py` | HAP-BLE (encrypted GATT) | ~10 Hz | HAP 配对 (`pair.py`) | **推荐:Thread/UDP** — 更快,无需 BLE 配对,且 Nanoleaf Desktop app 只需运行一次即可启用流模式。 ## 目录 1. [设备识别](#device-identification) 2. [逆向工程之旅](#the-reverse-engineering-journey) 3. [协议规范](#protocol-specification) 4. [初始设置 — Thread/UDP(推荐)](#initial-setup--threadudp-recommended) 5. [初始设置 — HAP-BLE(备选)](#initial-setup--hap-ble-fallback) 6. [脚本参考](#script-reference) 7. [SignalRGB 集成](#signalrgb-integration) 8. [架构](#architecture) 9. [本仓库中的文件](#files-in-this-repo) 10. [未来工作](#future-work) 11. [故障排除](#troubleshooting) 12. [法律声明](#legal) ## 设备识别 | 字段 | 值 | |---|---| | 产品 | Secretlab Magnus XL RGB Desk Strip | | OEM | Nanoleaf (作为 MAGRGB 销售) | | BLE 广播名称 | `Secretlab MAGRGB XXBJ` | | 协议 | HAP-BLE (Apple HomeKit Accessory Protocol over Bluetooth LE) | | 电源 | USB | ### BLE 广播 恢复出厂设置后,设备在**两个同时存在的地址**上进行广播 — 每个协议一个: | 地址 | 制造商 ID | 协议 | 用途 | |---|---|---|---| | `XX:XX:XX:XX:XX:XX` | `76` (Apple) | HAP-BLE | HomeKit 配对 + 控制 | | `YY:YY:YY:YY:YY:YY` | `2059` (Nanoleaf) | LTPDU | Nanoleaf app + Thread 控制 | ### HAP-BLE GATT 服务 | 服务 UUID | 用途 | |---|---| | `00001800-0000-1000-8000-00805f9b34fb` | Generic Access (设备名称) | | `0000003e-0000-1000-8000-0026bb765291` | HAP Accessory Information | | `00000055-0000-1000-8000-0026bb765291` | HAP Pairing (Pair-Setup `0x4C`, Pair-Verify `0x4E`) | | `00000043-0000-1000-8000-0026bb765291` | **HAP Lightbulb** — 颜色控制位于此 | | `00000701-0000-1000-8000-0026bb765291` | Nanoleaf 场景/效果服务 | | `6d2ae1c4-9aea-11ea-bb37-0242ac130002` | Nanoleaf LTPDU 传输 (加密) | ### HAP Lightbulb 特征 IID | 特征 | HAP UUID | IID | |---|---|---| | 开 / 关 | `00000025-...-0026bb765291` | 51 | | 亮度 (0–100) | `00000008-...-0026bb765291` | 52 | | 色调 (0–360°) | `00000013-...-0026bb765291` | 53 | | 饱和度 (0–100%) | `0000002f-...-0026bb765291` | 54 | ## 逆向工程之旅 ### 阶段 1 — 识别协议 灯带通过 Android/iOS 上的 **Nanoleaf app** 控制,这意味着 BLE 流量会告诉我们协议。第一步是捕获 Android HCI snoop 日志。 **snoop 日志显示的内容:** 日志捕获了发送到句柄 `0x008e` 和 `0x0090` 的**加密变长数据包** — 这是发送到 MAGRGB 的实际 Nanoleaf app 流量,使用 X25519 + AES-CTR(Nanoleaf 的 LTPDU 协议)或 HAP-BLE ChaCha20-Poly1305 加密。由于密钥是每次会话临时的,因此无法仅从捕获中解密这些数据包。 ### 阶段 2 — 理解双协议架构 GATT 服务枚举(参见 `discover_services.py`)显示设备同时暴露了 HAP-BLE 和 Nanoleaf LTPDU 服务树: - HAP 服务(`0026bb765291` UUID 命名空间)→ Apple HomeKit 协议 - LTPDU 服务(`6d2ae1c4-9aea-11ea-bb37-0242ac130002`)→ Nanoleaf 基于 Thread/CoAP 的专有协议 设备还使用**两个制造商 ID** 进行广播 — Apple 的 (76) 用于 HomeKit 发现,Nanoleaf 的 (2059) 用于 Nanoleaf app — 在两个独立的轮换 BLE 地址上。 这解释了为什么 aiohomekit 的 BLE 扫描器(过滤 Apple 制造商 ID 76)在正常运行期间找不到设备:它已配对并广播加密的通知广播,而不是可配对的广播。 ### 阶段 3 — HAP-BLE 配对 恢复设备出厂设置后,HAP 地址广播标准的未加密 HomeKit 广播(制造商数据以 `0x06` 开头)。aiohomekit 的正常发现仍然找不到它,因为广播使用的是 **Nanoleaf 的广播地址**,而不是 Apple 的。 **解决方案:** 完全绕过 aiohomekit 基于扫描器的发现。使用 `BleakScanner.find_device_by_address()` 直接获取 BLEDevice,然后直接调用 aiohomekit 的底层 `drive_pairing_state_machine()` 与 HAP Pair-Setup 特征(`0x4C`)。 SRP 配对使用设备上打印的 **8 位 HomeKit 设置代码**,格式为 `XXX-XX-XXX`。格式很重要 — aiohomekit 的 `check_pin_format` 会拒绝任何其他格式。 **配对流程:** ``` 1. BleakScanner.find_device_by_address(HAP_MAC) 2. AIOHomeKitBleakClient.connect() 3. drive_pairing_state_machine(PAIR_SETUP, perform_pair_setup_part1()) → device returns SRP salt + public key 4. drive_pairing_state_machine(PAIR_SETUP, perform_pair_setup_part2(pin, uuid, salt, pubkey)) → device returns long-term key pair (AccessoryLTPK, iOSDeviceLTSK, etc.) 5. Save pairing_data to pairing.json ``` ### 阶段 4 — 特征控制 有了有效的配对,HAP-BLE 控制通过 aiohomekit 的 `BlePairing.put_characteristics()` 进行。一个兼容性问题:aiohomekit 的 `BlePairing` 类期望由完整的控制器/扫描器基础设施驱动,如果广播回调触发时 `_accessories_state` 为 `None`,则会崩溃。 **修复:** 在加载配对后立即使用空的 `AccessoriesState(Accessories(), 0, None, 0)` 预初始化 `_accessories_state`。 颜色以 **HSV 空间**(而非 RGB)通信,因为 HAP 的 Lightbulb 服务使用色调 + 饱和度 + 亮度作为独立的特征。来自 SignalRGB 的 WLED DRGB 流的 RGB 值使用 Python 的 `colorsys.rgb_to_hsv()` 进行转换。 ## 协议规范 ### HAP-BLE 会话 HAP-BLE 在配对后使用标准的 Pair-Verify 握手(X25519 + Ed25519)建立 ChaCha20-Poly1305 加密会话。aiohomekit 透明地处理此过程。 ### 特征写入格式 控制数据包通过 aiohomekit 的 `put_characteristics([(aid, iid, value)])` 发送: | 参数 | 值 | |---|---| | AID | `1` (BLE 外设始终为 1) | | IID_ON | `51` — 布尔值 | | IID_BRI | `52` — 整数 0–100 | | IID_HUE | `53` — 整数 0–360 | | IID_SAT | `54` — 整数 0–100 | ### 颜色转换 ``` import colorsys def rgb_to_hapsv(r, g, b): h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255) return round(h * 360), round(s * 100), round(v * 100) ``` ### 关闭 vs 开启 HAP 有一个独立的开关特征 (IID 51)。发送 RGB `(0,0,0)` **不会**关闭灯 — 您必须向 IID_ON 写入 `False`。网桥会自动处理此问题。 ## 初始设置 — Thread/UDP(推荐) ### 要求 - Python 3.9+ - Windows 10/11 - 已安装并运行 **Nanoleaf Desktop app**(启用流模式时需要一次) - 设备可通过 Thread IPv6 访问(它通过 Apple TV 边界路由器连接) ``` pip install -r requirements.txt ``` ### 步骤 1 — 首先通过 Nanoleaf 移动应用配对 1. 将灯带恢复出厂设置(按住重置约 10 秒直到灯闪烁) 2. 在开机后的 15 分钟内,在 iOS 或 Android 上打开 **Nanoleaf 移动应用** → 添加设备 → 按照蓝牙配对流程操作 3. 移动应用通过您的 Apple TV(或其他 Thread 边界路由器)将设备配置到 Thread 4. 一旦移动应用显示设备已连接,Desktop 应用和网桥就能访问它 ### 步骤 2 — 获取您的设备信息 打开 Wireshark 并在 Nanoleaf Desktop 应用打开时捕获回环适配器(`127.0.0.1`)。过滤器: ``` tcp.port == 15765 and http ``` 查找 `POST /essentials/state` 请求 — JSON 主体包含您设备的 `id`、`ip` (Thread IPv6)、`token`、`port` 和 `eui64`。 或者 — 如果这些值在之前的会话中已设置且设备此后未恢复出厂设置,则它们已存在于 `config_local.py` 中。 ### 步骤 3 — 更新 config_local.py ``` DEVICE_MAC = "XX:XX:XX:XX:XX:XX" # BLE MAC (only needed for HAP bridge) DEVICE_INFO = { "controlVersion": 2, "defaultName": "Secretlab MAGRGB XXBJ", "id": "NXXXXXXXXX", "ip": "fdXX:XXXX:XXXX:0:XXXX:XXXX:XXXX:XXXX", # Thread IPv6 "model": "NL62", "port": 5683, "token": "XXXXXXXXXXXXXXXX", "eui64": "XXXXXXXXXXXXXXXX", } ``` ### 步骤 4 — 验证连接性 ``` ping -6 ``` 应通过 Apple TV 边界路由器在约 1–30ms 内回复。 ### 步骤 5 — 运行网桥 首先打开 Nanoleaf Desktop 应用(仅在首次启动时需要),然后: ``` python magnus_wled_bridge_thread.py ``` 输出: ``` WLED UDP on 127.0.0.2:21325 WLED HTTP on :80 Enabling stream control via Nanoleaf Desktop... OK: b'' Streaming to [fdc5:...]:60222 Ready. ``` 首次成功运行后,设备将保持流模式 — 您可以关闭 Nanoleaf Desktop 应用,它将继续工作,直到设备断电。 ## 初始设置 — HAP-BLE(备选) 如果 Thread 路径不可用(无 Apple TV,或设备未在 Thread 上),请使用此方法。 ### 要求 - Python 3.9+ - Windows 10/11 配备 **Bluetooth LE 适配器** - 设备恢复出厂设置(按住重置按钮约 10 秒直到灯闪烁) ### 步骤 1 — 查找 HAP MAC ``` python scan.py python scan_adv.py ``` 查找 `Secretlab MAGRGB XXBJ`。HAP 地址在广播数据中包含 `Manufacturer: {76: '06...'}`。 在 `config_local.py` 中设置它: ``` DEVICE_MAC = "XX:XX:XX:XX:XX:XX" # Apple manufacturer ID address ``` ### 步骤 2 — 配对(一次性) ``` python pair.py XXX-XX-XXX ``` 输入设备标签上的 8 位 HomeKit 设置代码。这将创建 `pairing.json` — 切勿提交它。 ### 步骤 3 — 测试 ``` python test.py ``` 灯带应循环:红 → 绿 → 蓝 → 白 50% → 关。 ### 步骤 4 — 运行网桥 ``` python magnus_wled_bridge_hapble.py ``` ## 脚本参考 | 脚本 | 用途 | 使用方法 | |---|---|---| | `magnus_wled_bridge_thread.py` | **推荐网桥** — Thread/UDP, ~20 Hz | `python magnus_wled_bridge_thread.py` | | `magnus_wled_bridge_hapble.py` | 备选网桥 — HAP-BLE, ~10 Hz, 需配对 | `python magnus_wled_bridge_hapble.py` | | `pair.py` | 一次性 HAP-BLE 配对,保存 `pairing.json` | `python pair.py XXX-XX-XXX` | | `test.py` | HAP-BLE 颜色循环测试 — 红/绿/蓝/白/关 | `python test.py` | | `scan.py` | 列出所有附近的 BLE 设备 | `python scan.py` | | `scan_adv.py` | 显示 MAGRGB 地址的原始广播数据 | `python scan_adv.py` | | `discover_services.py` | 枚举 GATT 服务和特征 | `python discover_services.py` | ## SignalRGB 集成 灯带作为 **WLED 设备** 暴露给 SignalRGB — 无需自定义插件。 ### 设置 **步骤 1 — 启动网桥(以管理员身份运行以使用端口 80)** Thread/UDP(推荐): ``` python magnus_wled_bridge_thread.py ``` HAP-BLE(备选,需先配对): ``` python magnus_wled_bridge_hapble.py ``` **步骤 2 在 SignalRGB 中添加** 1. 打开 SignalRGB → **Home → Lighting Services → WLED** 2. 在 "Discover WLED device by IP" 中输入 `127.0.0.2` 并按回车 3. SignalRGB 调用端口 80 上的 `/json/info`,获取返回的 `"brand": "WLED"` 并添加设备 4. 点击 **Link** — **"Magnus RGB Strip"** 现已位于您的画布上 **步骤 3 — 分配效果** 拖动画布上的 Magnus RGB Strip 区块并分配任意效果。 ### Windows 自动启动 1. 打开 **任务计划程序** → **创建任务** 2. **常规:** 名称 `Magnus RGB Bridge`,勾选 **使用最高权限运行** 3. **触发器:** 启动时,延迟 30 秒 4. **操作:** 启动 `python`,参数 `C:\path\to\MAGRGB-controller\magnus_wled_bridge_thread.py`,起始于 `C:\path\to\MAGRGB-controller` 5. 保存 ## 架构 ### Thread/UDP(推荐) ``` ╔══════════════════════════════════════════════════════════════════╗ ║ YOUR PC (127.0.0.2) ║ ║ ║ ║ ┌──────────┐ ┌───────────────────────────────────────────┐ ║ ║ │SignalRGB │ │ magnus_wled_bridge_thread.py │ ║ ║ │ │──▶│ HTTP :80 (WLED discovery) │ ║ ║ │ │ │ UDP :21325 (DRGB color stream) │ ║ ║ └──────────┘ │ averages zones → single RGB │ ║ ║ │ UDP socket → [Thread IPv6]:60222 ~20 Hz│ ║ ║ └───────────────────┬───────────────────────┘ ║ ╚══════════════════════════════════════╪═══════════════════════════╝ │ IPv6/UDP :60222 ┌───────▼────────┐ │ Apple TV │ │ Thread Border │ │ Router │ └───────┬────────┘ │ Thread radio ┌───────▼────────┐ │ Secretlab │ │ MAGRGB (NL62) │ └────────────────┘ ``` ### HAP-BLE(备选) ``` ╔══════════════════════════════════════════════════════════════════╗ ║ YOUR PC (127.0.0.2) ║ ║ ║ ║ ┌──────────┐ ┌───────────────────────────────────────────┐ ║ ║ │SignalRGB │ │ magnus_wled_bridge_hapble.py │ ║ ║ │ │──▶│ HTTP :80 / UDP :21325 │ ║ ║ └──────────┘ │ RGB→HSV conversion │ ║ ║ │ aiohomekit put_characteristics ~10 Hz │ ║ ║ └───────────────────┬───────────────────────┘ ║ ╚══════════════════════════════════════╪═══════════════════════════╝ │ BLE (ChaCha20-Poly1305) ┌───────▼────────┐ │ Secretlab │ │ MAGRGB │ │ HAP-BLE GATT │ └────────────────┘ ``` ## 本仓库中的文件 | 文件 | 用途 | |---|---| | `magnus_wled_bridge_thread.py` | **推荐网桥** — Thread/UDP 到设备, ~20 Hz, 无需 BLE | | `magnus_wled_bridge_hapble.py` | **备选网桥** — HAP-BLE via aiohomekit, ~10 Hz, 需配对 | | `pair.py` | 一次性 HAP-BLE SRP 配对,保存 `pairing.json` | | `test.py` | HAP-BLE 颜色循环测试 — 红/绿/蓝/白/关 | | `scan.py` | BLE 扫描器 — 列出所有附近的设备及其名称和 MAC | | `scan_adv.py` | 广播扫描器 — 显示 MAGRGB 地址的原始制造商数据 | | `discover_services.py` | GATT 服务枚举器 — 列出所有服务和特征 | | `compat.py` | HAP-BLE 脚本使用的 Bleak 2.x 兼容性垫片 | | `config.py` | 配置模板 — 复制到 `config_local.py` | | `config_local.py` | 您的设备配置 (MAC + Thread DEVICE_INFO) — gitignored | | `requirements.txt` | Python 依赖项 | | `pairing.json` | 您的长期 HAP 密钥对 — 由 `pair.py` 生成,gitignored | ## 未来工作 - [x] Thread/UDP 流 — 20 Hz 单色通过 Nanoleaf 外部控制协议 - [x] HAP-BLE 单色控制通过灯泡特征 (IID 51–54) - [ ] 分区颜色控制 — 设备在 Thread/Nanoleaf 生态系统中仅暴露 panelID=0;HAP-BLE STRIPES (IID 60) 支持分区但产生动画(非静态)颜色,且设备忽略静态写入 - [ ] 直接 CoAP 流传输到设备 IPv6:5683 — 绕过 Nanoleaf Desktop app,消除“运行应用一次”的启动要求 - [ ] 启动时自动检测 HAP MAC 地址(处理重置后的地址轮换) ## 故障排除 ### 网桥有流但灯不亮 — 恢复出厂设置后 **症状:** 网桥打印 `OK: b'{"...":{"isSuccess":true}}'` 并发送 `Thread -> rgb(...)` 行,但灯带不亮。 **原因:** 恢复出厂设置会分配新的 Thread IPv6 地址和 token。`config_local.py` 仍有旧地址,因此 UDP 数据包无处可去。 **修复:** 1. 首先通过 **Nanoleaf 移动应用** 配对(参见 [初始设置 — Thread/UDP](#initial-setup--threadudp-recommended) 步骤 1)。Desktop 应用无法配置 Thread 设备 — 只有移动应用可以。 2. 从 Wireshark 获取新地址。在回环适配器上捕获,过滤器: tcp.port == 15765 and http 查找 `POST /essentials/state` — 请求 JSON 包含当前的 `ip` 和 `token`。 3. 更新 `config_local.py`: DEVICE_INFO = { ... "ip": "fdXX:XXXX:XXXX:0:XXXX:XXXX:XXXX:XXXX", "token": "XXXXXXXXXXXXXXXX", ... } 4. 重启网桥。 ### Nanoleaf Desktop 应用找不到设备 **原因:** NL62 (MAGRGB) 仅支持 Thread。Desktop 应用要求: - 您的网络上有 Thread 边界路由器(Apple TV 4K, HomePod mini, Google Nest Hub 2nd gen 等) - 设备已配置到 Thread — **只有 Nanoleaf 移动应用可以做到这一点** **修复:** 首先通过移动应用配对,然后重新打开 Desktop 应用。一旦设备在 Thread 网络上,它将自动出现。 ## 法律声明 本项目是为作者拥有的硬件进行个人互操作性使用而开发的。出于互操作性目的的逆向工程根据 DMCA §1201(f)(美国)和其他司法管辖区的同等条款是被允许的。 未隶属于、未受认可或未连接到 Secretlab、Nanoleaf 或 Apple。所有商标均为其各自所有者的财产。 使用风险自负。
标签:GATT, HAP-BLE, HomeKit, Nanoleaf, Python, RGB灯控, Secretlab, SignalRGB, Thread协议, UDP通信, WLED, 云资产清单, 协议分析, 无后门, 智能家居, 权限提升, 桌子灯带, 桥接器, 物联网, 硬件黑客, 蓝牙低功耗, 跨平台集成, 逆向工具, 逆向工程