samr037/iohc-flipper
GitHub: samr037/iohc-flipper
基于 Flipper Zero 的 io-homecontrol 协议研究工具,支持 868 MHz 嗅探、跨厂商配对与单设备精确控制 Velux/Somfy 电动百叶窗及窗户。
Stars: 2 | Forks: 0
# iohc-flipper
一个能够处理 **io-homecontrol** 协议的 Flipper Zero FAP —— 这是 Velux、Somfy 等品牌用于电动百叶窗、遮阳篷和窗户的 868 MHz 专有 RF 协议。它可以嗅探真实的遥控器,学习其身份,并通过 **单扇窗体身份隔离** 和 **跨厂商配对**(已在真实硬件上验证了 Somfy + Velux),从单个 Flipper 控制多个百叶窗。
本项目基于我所拥有的硬件进行互操作性研究,符合欧盟 2009/24/EC 指令。
## 状态
| 阶段 | 功能 | 状态 |
|---|---|---|
| 1 | 868 MHz 被动嗅探器 (CC1101, FSK, 同步技巧) | ✅ |
| 2 | 帧解析器 (Ctrl B1/B2, dst/src, cmd, payload, seq, MAC, CRC-Kermit) | ✅ |
| 3 | 通过跨配对事件恢复安装密钥 | ✅ |
| 4 | 1W TX (HMAC 签名, 实时比特打包, UART 封装) | ✅ |
| 5 | Flipper 作为独立的已配对发射器 | ✅ |
| 5.5 | 完整的用户界面 (嗅探/保存/单扇控制/全部控制/身份备份) | ✅ |
| 5.6 | 单扇窗体身份 (通过 HMAC 进行电机隔离) | ✅ |
| 5.7 | 自动镜像备份 + JSON 导出,用于移交给 HA (Home Assistant) | ✅ |
| 6a | 每个设备的厂商字节 (通过嗅探自动检测) | ✅ |
| 6b | **Velux 配对与控制** | ✅ |
| 6c | 每个设备的 `man_id` —— 完全与厂商无关的 TX | ✅ |
| 7 | 加密的设备端存储 | ❌ 已跳过 (明文可接受;Flipper 仅作临时使用) |
| 8 | 提交至 Unleashed 应用目录 | ⏳ |
| 9 | 通过 SX1262 扩展板支持 2W (双向通信) | ⏳ |
| 10 | Home Assistant 网桥 (ESP32 / ESPHome / RPi) | ⏳ |
## 功能介绍
| 主菜单 | 嗅探与捕获 | 实时嗅探器 |
|---|---|---|
|  |  |  |
### 嗅探与捕获
在 Flipper 附近按下任意 io-homecontrol 遥控器上的按钮。应用程序会根据源遥控器对帧进行索引,从按键帧中自动检测厂商字节 (`0x43` Somfy, `0x61` Velux),并提供保存命名条目的选项。
### 单扇窗体身份隔离
每个保存的百叶窗都会获得自己全新的 `(src, install_key, seq)`。当你对百叶窗 A 按下 UP/DOWN/STOP 时,只有 A 的电机会做出反应 —— 其他设备会忽略该帧,因为 HMAC 是使用 A 的 install_key 签名的。不再有“一顿乱按影响所有百叶窗”的意外。
### 配对
Flipper 可以与电机进行配对 —— 无需外部编程器。
对于 Somfy:按住真正的 Smoove 遥控器上的 PROG 键,然后选择 `在此处配对 Flipper`。
对于 Velux:按住真正的 KLI 313 遥控器上的齿轮键,然后选择 `在此处配对 Flipper`。
配对序列会发出完整的 APPAIRAGE/PROG 脉冲串,包括 Velux 根据 KLI 313 手册第 10 页第 5 步所要求的 STOP+DOWN 后续动作。
### 身份备份与导出
身份 → 备份会写入带有时间戳的二进制快照 **以及** 一份可供未来 Home Assistant 网桥直接导入的 JSON 导出文件。每次保存时还会写入一个自动生成的 `*.bak.bin` 镜像文件。
JSON 格式:
```
{
"format": "iohc_flipper_export",
"version": 1,
"global_identity": { "src": "...", "install_key": "...", "seq": 142 },
"devices": [
{ "name": "user-C", "motor_addr": "0001BF", "vendor": "0x43",
"src": "67A315", "install_key": "...", "seq": 28 }
]
}
```
## 硬件
- 运行 [Unleashed 固件](https://github.com/DarkFlippers/unleashed-firmware) 的 **Flipper Zero**
(SDK API 87.8, target 7)。
- 内置 CC1101 sub-GHz 收发器。868 MHz 路径支持 +14 dBm,但实际环境中的可靠性取决于电机的 RSSI 余量。如果你需要更远的通信距离,SX1262 扩展板(阶段 9)可以为你增加约 10 dB 的增益。
## 构建与安装
```
# 一次性
git clone https://github.com/
/iohc-flipper.git
cd iohc-flipper
python3 -m venv .venv && .venv/bin/pip install ufbt pyserial flipperzero-protobuf pillow
# 构建 + 部署 + 启动
cd iohc_flipper
../.venv/bin/ufbt launch
```
该 FAP 也可以手动安装:将 `iohc_flipper/dist/iohc_flipper.fap` 复制到 Flipper SD 卡的 `/ext/apps/Sub-GHz/` 目录中。
## 使用指南
1. **启动**应用程序 (Apps → Sub-GHz → iohc_flipper)。
2. **嗅探与捕获** → 在 Flipper 附近按下真实遥控器上的按钮。
你会看到每个唯一的遥控器显示一行,并检测到其厂商字节。
按 OK 键 → 命名 → 保存。
3. **已保存的百叶窗** → 选择你的新条目 → `在此处配对 Flipper`。
- Somfy:首先按住真实 Smoove 遥控器上的 PROG 键(约 2 秒)。
- Velux:首先按住真实 KLI 313 遥控器上的齿轮键(约 2 秒)—— 电机会短暂地循环打开/关闭。
4. Flipper 发送配对脉冲串 → 绿色 LED 亮起 → 电机采用 Flipper 的身份。
5. 现在,从已保存的条目执行 UP/DOWN/STOP 将只控制该电机。
## 协议说明(有趣的部分)
### 同步编码技巧
CC1101 硬件同步检测器的解调时间比原始 io-homecontrol 字节的对齐需求提前了一个字节。通过将 `SYNC1/SYNC0 = 0x57FD` 视为 *前导码尾部 + UART 包装的 0xFF*,芯片会提前锁定,并且 `0x33`(下一个 iohc 字节)的包装从正确的位开始。嗅探和 TX 都可以在没有软件比特查找器的情况下正常工作。
### CRC-16/KERMIT
多项式为 `0x8408` (反转)。计算范围从 `Ctrl B2` 到 CRC 本身之前的最后一个字节。Somfy 和 Velux 均使用此算法。
### 1W 帧的 HMAC
使用构建的 IV 进行 AES-128-ECB:`frame_data + running_checksum + seq + 0x55 padding`,以发射器的 install_key 作为密钥。MAC 插槽是 1W 后缀的最后 6 个字节。已针对两个厂商的捕获帧进行了验证。
### 安装密钥封装 (cmd 0x30 配对帧)
使用 **公共 io-homecontrol transfer_key** 的 AES-CFB128:
```
0x34C3466ED88F4E8E16AA47394988 4373
```
IV 由重复 5 次的发射器 `src_addr` 加上末尾的一个 `src_addr[0]` 构建而成。单块 CFB 简化为 `output = install_key XOR AES_ECB(transfer_key, IV)`。
输出为 16 个字节 —— 原样放入 cmd 0x30 帧中。
相同的算法适用于 **Somfy 和 Velux**。特定于厂商的部分在别处(见下文)。
### 特定厂商的字节(*唯一*按厂商区分的代码路径)
| 字段 | 位置 | Somfy | Velux |
|---|---|---|---|
| 按键帧 `vendor` 字节 | cmd 0x00 payload[1] | `0x43` | `0x61` |
| 配对帧 `manufacturer_id` | cmd 0x30 byte[25] | `0x02` | `0x01` |
| 配对帧 `dst` | cmd 0x30 dst | 广播 `00 00 3F` | 类型代码 `00 00 BF` (窗户) / `00 00 FF` (百叶窗) / `00 03 7F` (其他) |
| 响铃后的 STOP+DOWN 后续动作 | 3 秒内 | 未使用 (无害) | **必需** |
`vendor` 和 `man_id` 都**按设备**作为原始观察到的线路字节存储(自阶段 6c 起,`devices.bin` v3)。TX 路径会原样读取它们 —— 热路径中没有厂商枚举或映射函数。`vendor` 来自嗅探到的 cmd 0x00 按键帧;`man_id` 来自嗅探到的 cmd 0x30 配对帧,并在捕获时带有备用方案(当我们在空中未看到配对帧时,通过 `iohc_man_id_default_for_vendor` 从 `vendor` 派生)。
这与 rspaargaren/iown-homecontrol-esp32sx1276 架构
([iohcRemote1W.cpp:221](https://github.com/rspaargaren/iown-homecontrol-esp32sx1276/blob/master/src/iohcRemote1W.cpp))
相匹配 —— 这也是标准的开源实现方法。
### 通过 HMAC 而非地址实现隐私
Velux NodeID (BF/FF/7F) 是*产品类型代码*,而不是唯一的设备 ID。
附近的所有窗户都会收到“发往 0000BF 的 REGLAGE”,但只有与发射器配对(匹配 install_key)的那个设备才会验证 HMAC。这使得仅靠广播的 TX 策略既能用于 Velux,也能像用于 Somfy 一样正常工作。
## 项目结构
```
iohc-flipper/
├── iohc_flipper/ # The FAP
│ ├── application.fam
│ └── src/
│ ├── iohc_app.c # App entry, view dispatcher, callback wiring
│ ├── radio/ # CC1101 driver (RX/TX, register init, calibration)
│ ├── phy/ # PHY layer (frame assembly from FIFO)
│ ├── iohc/ # Protocol: parse, build, CRC, HMAC, AES, key wrap
│ ├── state/ # Identity, device book, TX runner
│ ├── ui/ # Views: main menu, sniffer, capture, device list, identity
│ └── log/ # Per-session CSV/BIN log writer
├── tools/ # Python helpers (CLI, screen, RPC)
├── docs/ # Captures, backups, phase docs
├── refs/ # Upstream RE projects (gitignored)
├── PROGRESS.md # Full historical context (8000+ lines of context window)
├── BRIEF.md # Original project brief
├── SUMMARY.md # Protocol summary
├── ROADMAP.md # Long-term plan
├── CLAUDE.md # AI agent on-ramp
└── README.md # This file
```
## 路线图
- ~~**阶段 7**:加密的设备端存储~~ —— **已跳过**。SD 卡上的明文是可接受的:Flipper 只是一个临时的过渡工具,物理访问 SD 卡需要拿到设备本身,而且无论磁盘是否加密,都可以从任何捕获到的配对帧中恢复 install_key。
- **阶段 8**:提交至 Unleashed 应用目录 —— 图标、屏幕截图、MIT 风格的许可证。
- **阶段 9**:SX1262 GPIO 扩展板,可增加约 10 dB 的链路预算。可根据安装需求选用。
- **阶段 10**:Home Assistant 网桥。Flipper FAP 是一块垫脚石;从长远来看,该协议将寄宿在 HA 上(通过 ESPHome / ESP32 / RPi)。身份 → 备份中的 JSON 导出是迁移交接的产物。Seq 计数器在交接时手动迁移(在 HA 中进行一次性的表单填写)。
详情请参见 [ROADMAP.md](ROADMAP.md)。
## 许可证
iohc-flipper 是**双许可**的,你可以根据需要在以下许可证之间进行选择:
- [MIT 许可证](LICENSE) —— 适用于本仓库中的原始代码
- [Apache 许可证,版本 2.0](LICENSE-APACHE) —— 适用于衍生自上游 Apache-2.0 源代码的部分(参见 [NOTICE](NOTICE))
包含衍生代码的文件带有 `SPDX-License-Identifier: MIT OR Apache-2.0` 标头。其他所有内容默认仅适用 MIT 许可证。
## 来源与致谢
**复用的代码 (Apache 2.0 —— 在 [NOTICE](NOTICE) 中有适当的署名)**
- [rspaargaren/iown-homecontrol-esp32sx1276](https://github.com/rspaargaren/iown-homecontrol-esp32sx1276)
—— 我们 `hmac_1w.c` 中的 `compute_checksum()` 是对他们 `computeChecksum()` 的逐字移植;我们 `key_encrypt.c` 中的 `iohc_wrap_install_key()` 是对其 `encrypt_1W_key()` 的算法移植;公共的 iohc `transfer_key` 常量来自同一文件的第 47 行。
- [rspaargaren/iown-home](https://github.com/rspaargaren/iown-home) ——
决定性的 cmd 0x30 帧结构 (`enc_key[16] man_id ?? seq[2]`),记录在其 `docs/commands.md` 中。
**概念参考(未复用代码)**
- [Velocet/iown-homecontrol](https://github.com/Velocet/iown-homecontrol)
(CC0) —— io-homecontrol RE 总体项目。提供了一般的协议指导和命令 ID 参考。
- [merbanan/rtl_433](https://github.com/merbanan/rtl_433) (GPL-2.0+) ——
当硬件同步检测器提前一个字节锁定时,有关 sub-GHz 同步对齐的概念参考。针对 CC1101 的独立重新实现。
**主机固件**
- [DarkFlippers/unleashed-firmware](https://github.com/DarkFlippers/unleashed-firmware)
(GPL-3.0) —— Flipper Zero 固件。iohc-flipper 是一个动态加载的用户应用程序 (FAP),被 Flipper 社区视为具有库边界隔离的特性,从而允许 FAP 使用宽松的许可证。
制造商文档**
- Velux KLI 310/311/312/313 用户手册 ([PDF](https://www.velux.co.nz/~/media/marketing/ca/fr/integra/454416-2018-08%20integra%20support%20ca-fre.pdf))
—— 第 4、10、15 页 —— 官方配对程序 (REGLAGE / APPAIRAGE 按钮,STOP+DOWN 后续动作)。
**空中捕获数据**
- Smoove Origin IO (Somfy) 和 KLI 313 (Velux) 遥控器,基于项目作者自己的安装设备。捕获的帧位于 `docs/*.csv` 中(仅包含按键帧;带有 install_key 的 cmd 0x30 捕获已从公共分支中排除)。
## 免责声明
这是针对项目作者所拥有硬件进行的互操作性研究。欧盟指令 2009/24/EC 允许为实现互操作性而进行逆向工程。
**请勿对你不拥有的设备使用。** 此处记录的协议决策源自空中嗅探和公开的逆向工程项目;本文档中的任何内容均非源自受制造商 NDA(保密协议)约束的材料。标签:868MHz, CC1101, ESP32, Flipper Zero, HMAC, Home Assistant, io-homecontrol, RF嗅探, Somfy, SX1262, Velux, 信号拦截, 协议分析, 客户端加密, 密钥恢复, 无线电安全, 无线电控制, 智能家居, 智能百叶窗, 权限提升, 物联网, 硬件黑客, 跨厂商配对, 逆向工具