dzerik/nivona-ble-emulator

GitHub: dzerik/nivona-ble-emulator

ESP32 BLE 外设模拟器,无需真实咖啡机即可离线开发与调试 Home Assistant 集成及进行 BLE 协议研究。

Stars: 1 | Forks: 0

# Nivona BLE Emulator [![build](https://static.pigsec.cn/wp-content/uploads/repos/cas/05/052bc9eaea1744e860f382f618f1146be38e27dfd499bb29c253bcd1827fad60.svg)](https://github.com/dzerik/nivona-ble-emulator/actions/workflows/build.yml) **版本:** 见 [`VERSION`](VERSION) · **更新日志:** [`CHANGELOG.md`](CHANGELOG.md) · **Tags:** `emu-v` 一个 BLE 外设模拟器,可在 ESP32 上模拟 Nivona NICR/NIVO 咖啡机,用于在没有真机的情况下离线开发 Home Assistant 的 `melitta_barista` 集成。同时也可配合官方 Nivona Android 应用进行协议逆向工程。 实现了完整的 Eugster BLE 协议(service `AD00`)——包括 HU 握手、RC4 帧加密、所有已记录的 `H*` 命令、按系列区分的配方布局,以及模拟冲泡周期的有限状态机。 ## 硬件 可在构建时使用 `-DBOARD=` 进行选择(默认为 `xiao_c6`): | BOARD | Chip | Flash | 备注 | | ----- | ---- | ----- | ----- | | `xiao_c6` (默认) | ESP32-C6 | 4 MB | Seeed XIAO ESP32-C6。GPIO3/14 上的 RF 开关(PCB 天线 / 外部 U.FL)。 | | `xiao_s3` | ESP32-S3 | 8 MB | Seeed XIAO ESP32-S3 / S3 Plus (OPI PSRAM)。 | | `waveshare_c6_lcd_1_47` | ESP32-C6 | 8 MB | Waveshare ESP32-C6-Touch-LCD-1.47 — 增加了 **触摸屏前面板 UI**(JD9853 LCD + AXS5106L 触摸,LVGL);见[触摸屏 UI](#touchscreen-ui)。 | 开发板配置文件位于 `boards//`(每个都提供了 `board.c`、`sdkconfig.board` 和 `partitions.csv`)。通用配置位于 `sdkconfig.defaults` 中。显示/触摸驱动和触摸屏 UI 仅在开发板配置中设置 `CONFIG_NIVONA_BOARD_HAS_DISPLAY=y` 时才会编译,以确保无头开发板保持精简。 ## 功能 | 层级 | 实现状态 | | -------------- | --------------------- | | Advertising | 随机静态地址 (F1:…),制造商数据 `0x0D` + 客户过滤器 | | DIS (`180A`) | 制造商 / 型号 / 序列号 / 硬件 / 固件 / 软件版本号 | | GATT `AD00` | AD01 (控制), AD02 (通知), AD03 (写入), AD04/5 (存根), AD06 (名称) | | Security | Just Works 配对 + 绑定 (NVS 持久化) | | Framing | `S + cmd + [kp] + payload + cs + E`, RC4, MTU 分块, 按命令大小门控 | | HU 握手 | 完整的双轮验证 + 会话密钥协商 | | Commands | HX (状态), HV, HL, HI, HS, HR/HW, HA/HB, HE (冲泡), HZ, HY, HD, HN, Hp, HC/HJ (存根) | | FSM | process / sub_process / info / manipulation / progress | | 冲泡周期 | READY → PRODUCT,进度 0→100%,异步主动推送 HX | | Storage | 保存在 NVS 中的数字和字母数字寄存器 | | 系列切换 | CLI `family` 命令可选择 600/700/79x/900/900-light/1030/1040/8000 | | 触摸屏 UI | 仅限 Waveshare 开发板 — 在 172×320 LVGL 显示屏上实现实时前面板(状态、冲泡、取消、确认、加水/豆、系列选择) | ## 前置条件 - **ESP-IDF 5.4+** — 已使用 v5.4.1 RISC-V 工具链测试 - 主机对开发板的串口访问权限(原生 USB Serial/JTAG) - 开发板可连接的 WiFi 网络(用于 OTA 和 telnet) ## 设置 ``` # 1. 设置 WiFi 凭据(一次性操作,永不提交) cp main/wifi_secrets.h.template main/wifi_secrets.h $EDITOR main/wifi_secrets.h # fill WIFI_SSID / WIFI_PASS # 2. 构建并烧录 . $IDF_PATH/export.sh idf.py -DBOARD=xiao_c6 build # default; or xiao_s3 / waveshare_c6_lcd_1_47 idf.py -DBOARD=xiao_c6 -p /dev/ttyACM0 flash monitor # 切换 board(target/flash 变更):idf.py -DBOARD= fullclean ``` 首次通过 USB 刷写后,所有后续更新均可通过空中网络 (OTA) 进行: ``` curl -X POST --data-binary @build/nivona_emulator.bin \ http://nivona-emu.local/ota ``` ## 运行时端点 | 端点 | 用途 | | ------------------------------- | ----------------------------------------------------------- | | `GET http:///` | 固件版本、IDF 版本、编译时间 | | `GET http:///diag` | 所有诊断计数器的 JSON (连接、帧、HU、HX 等) | | `POST http:///ota` | 刷写新的 `nivona_emulator.bin` — 主体为原始二进制文件 | | `POST http:///reboot` | 重启设备 | | `telnet 23` | 交互式 CLI — 请参阅下方的命令 | mDNS:开发板会将自身宣告为 `MDNS_HOSTNAME.local`(默认为 `nivona-emu.local`),因此你可以用它来代替 IP。 ## CLI 命令(telnet 或 USB 控制台) ``` help list registered commands status show FSM state (process, sub_process, manip, progress) diag show diagnostic counters brew start a brew cycle with the given process value cancel cancel active brew trigger set a manipulation (water_empty / beans_empty / tray_full / clean / descale / none) dump dump persisted register store family switch emulated family — 600 / 700 / 79x / 900 / 900-light / 1030 / 1040 / 8000. Takes effect on reboot. pair enter pairing mode (wipes bonds, restarts advertising) forget wipe stored BLE bonds reboot reboot the device ``` ## 触摸屏 UI 在 `waveshare_c6_lcd_1_47` 开发板上,1.47″ 172×320 触摸屏即为机器的前面板——它是与 CLI 和 BLE 操作同步的另一个前端。它使用 LVGL 基于 Espressif 的 `esp_lcd_jd9853`(面板)和 `esp_lcd_touch_axs5106`(触摸)驱动程序(两者均在 `components/` 下进行第三方托管)构建,并且仅在开发板配置设置 `CONFIG_NIVONA_BOARD_HAS_DISPLAY=y` 时才会编译。 - **主页** — 型号 + BLE 连接指示点;实时状态磁贴(READY / 带有进度的 BREWING / 提示横幅);冲泡、取消、确认、加水/豆和系列的磁贴;耗材状态栏。 - **冲泡选择器** — 当前系列的配方;点击开始冲泡。 - **加水/豆** — 水 / 咖啡豆 / 清空残渣盘。 - **系列选择器** — 切换模拟的系列(重启后生效)。 状态从 FSM 中以约 7 Hz 的频率轮询;按钮调用与 telnet/USB CLI 相同的内部 API(`nivona_brew_start`, `nivona_maint_handle_confirm`, `nivona_consumable_set`, `nivona_family_set`)。 ## 测试 `tests/test_emulator.py` 中的 Python 测试涵盖了协议辅助程序、HTTP 诊断以及完整的 BLE 往返流程。在已连接的开发板上运行: ``` pip install bleak pytest pytest-asyncio requests EMU_IP=192.168.1.29 EMU_MAC=F1:32:04:33:52:DA python3 tests/test_emulator.py # 或 python3 -m pytest tests/ -v -s ``` ## 架构 ``` boards// per-board profile: board.c (board_hal impl) + sdkconfig.board + partitions.csv components/ ├── esp_lcd_jd9853/ vendored JD9853 LCD panel driver (Espressif, Apache-2.0) ├── esp_lcd_touch_axs5106/ vendored AXS5106L touch driver (Espressif, Apache-2.0) └── nivona_ui/ LVGL touchscreen front panel (display boards only) main/ ├── main.c application entry: lifecycle, board_early_init(), SM config ├── nivona_ble.c/h advertising, GAP events, scan response ├── nivona_gatt.c/h GATT service AD00 with 6 characteristics ├── nivona_dis.c/h Device Information Service (180A) ├── nivona_frame.c/h framing (S/E, checksum, RC4, per-cmd size gating) ├── nivona_crypto.c/h RC4 + HU verifier + HU lookup table ├── nivona_dispatch.c/h command router with HU / HX / HV / HL / HI / HR / HW / … ├── nivona_fsm.c/h process state machine (thread-safe) ├── nivona_store.c/h numerical + alphanumeric register store with NVS ├── nivona_brew.c/h async brew cycle task, unsolicited HX pushes ├── nivona_cli.c/h esp_console REPL (USB Serial/JTAG) ├── nivona_wifi.c/h WiFi STA + mDNS ├── nivona_ota.c/h HTTP server (status / diag / ota / reboot) └── nivona_telnet.c/h TCP:23 bridge to esp_console + log mirroring ``` ## 协议参考 - 上游逆向工程(实地笔记 + 参考客户端): `https://github.com/mpapierski/esp-coffee-bridge` — 特别是 `docs/NIVONA.md` - HA 集成 — 协议常量的真实来源: `../custom_components/melitta_barista/protocol.py` `../custom_components/melitta_barista/brands/nivona/`(包,按系列拆分为 `_family_.py`;加密在 `_crypto.py` 中,寄存器基类在 `_registers.py` 中,序列号前缀到系列的映射在 `_prefixes.py` 中) ## 安全说明 - `main/wifi_secrets.h` 已被 `.gitignore` 忽略。切勿提交它。 - 该模拟器接受任何配对请求(Just Works)。请勿将其暴露在不受信任的网络中。 - OTA 没有身份验证。请将端口 80 保留在受信任的 LAN 中。 ## 许可证 MIT — 见 [`LICENSE`](LICENSE)。与父级 `melitta-barista-ha` 集成相匹配。 ## 法律与商标 这是一个研究和互操作性工具。它与 Nivona Apparate GmbH 或 Eugster / Frismag AG **没有**任何附属、认可或赞助关系。“Nivona”、“NICR”和“NIVO”是其各自所有者的商标,此处仅出于描述性目的使用 — 有关完整的立场声明、欧盟/美国/俄罗斯的法律依据以及处理任何合法关切的合作渠道,请参阅 [`LEGAL.md`](LEGAL.md)。 ## 安全 漏洞报告请通过 GitHub Security Advisories 提交,请勿作为公开 issue 提出 — 详见 [`SECURITY.md`](SECURITY.md)。 ## 贡献 有关构建快速入门、分支/提交规范和 PR 检查清单,请参阅 [`CONTRIBUTING.md`](CONTRIBUTING.md)。
标签:ESP32, 协议逆向, 客户端加密, 嵌入式开发, 智能家居, 物联网, 蓝牙低功耗(BLE), 逆向工具