e-gaulue/espa-silen-homeassistant

GitHub: e-gaulue/espa-silen-homeassistant

一个通过本地蓝牙 LE 桥接将 Espa Silen 泳池水泵接入 Home Assistant 的概念验证项目,让用户摆脱官方应用限制并实现自定义自动化控制。

Stars: 0 | Forks: 0

# Espa Silen → Home Assistant(概念验证) 从 **Home Assistant** 控制 **Espa "Silen" 变速泳池水泵**,而不是 被困在官方的 **evopool** 蓝牙应用程序中。 ## 为什么? Espa 的变速水泵(Silen Plus 2M 等)通过 **evopool** 手机应用程序使用蓝牙 LE 进行配置。该应用程序用于一次性*设置*水泵还不错,但 **非常不利于自动化**: - 没有真正的调度逻辑(更不用说基于太阳的调度了:“夜间低速,白天正常”), - 无法将水泵与泳池的其他设备**协调**——例如,仅在水泵实际运行得足够快时才运行盐 **加氯器**或**增压/清洁器**, - 无法与任何家庭自动化系统集成。 因此,水泵就闲置在那里,智能硬件背后却是一个愚蠢的应用程序。 在此之前,这里有一个自制的桥接方案。 ## 这是什么(以及不是什么) - ✅ 一种在本地读取/驱动此类水泵并将其接入 Home Assistant 的**方法**。 - ✅ **通用、可复用的代码**:一个带有身份验证的小型 HTTP 服务、蓝牙 连接/断开处理,以及**可直接适配的 Home Assistant 自动化**。 - ❌ **不是**一个开箱即用的产品,不是 Espa 协议的规范,也与 Espa 没有任何附属关系。 - ❌ 水泵的蓝牙数据帧为 **Espa 专有,不在此发布。** 解码你**自己**的设备(参见*方法*)并填补那两个占位实现。 ## 方法(解码你自己的水泵) 要使水泵发挥用处,你实际上只需要**两个操作**: 1. **读取**其当前状态——正在运行的*模式*和*速度*; 2. **设置**一项配置——实际上是配置屏幕上的**任何**值(两个过滤 速度、两个反冲洗速度、恒定模式速度、周期/初次过滤持续时间、斜坡)。单个配置写入即可携带所有这些值。在实践中,**低 过滤速度**是值得从 Home Assistant 进行*调度*的值,但你也可以写入 其中的任何值。 如何做到这一点(只需一个下午的时间,借助 AI 助手很容易实现): 1. **捕获** evopool 应用程序与水泵之间的蓝牙 LE 通信,当你在应用程序中按下 按钮时——例如 Android 的 *HCI snoop log*,或 iOS 通过 macOS 的 **PacketLogger**,或者专用的 BLE 嗅探器。在 Wireshark 中打开捕获文件。 2. **查找**应用程序写入和读取通知的单一特征值,并且, 通过在应用程序中一次更改一个值,**推断出**编码“速度”的几个字节 以及报告“模式/速度”的字节。LLM 在这方面非常擅长:将 带有注释的捕获内容(“我先设置了速度 X,然后是 Y”)喂给它,让它寻找规律。 3. **填补** [`evopool_agent.py`](evopool_agent.py) 中的 `ble_read()` 和 `ble_set()`,使用 提供的 `bt_session()` 辅助函数(通用的 `bluetoothctl` 连接 → 写入 → 通知 → 断开)。 4. 从 Home Assistant 进行**自动化**(见下文)。 ### 提示——让每个设置都易于识别 evopool *“配置”*屏幕显示了少量静态设置(速度为 1-10 的等级,外加几个持续时间)。将它们映射到字节的最快方法是:将**每个字段设置为** 一个独特、易记的值**,截图,捕获蓝牙写入——然后将它们全部** 设置为**另一组**独特的值并再次捕获。因为每个字段都有一个唯一的值, 你(或你的 AI)可以通过对比两次捕获内容和两次截图,立即 分辨出哪个字节携带了哪个设置。 | 捕获 A — 值为 `1 / 11 / 22 / 2 / 3 / 4 / 5 / 33 / 6` | 捕获 B — 值为 `5 / 44 / 55 / 6 / 7 / 8 / 9 / 66 / 10` | |:--:|:--:| | ![evopool 设置,值集 A](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/3f09d16d76002222.png) | ![evopool 设置,值集 B](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/3498b01a6e002223.png) | 将这两张截图**连同你的两份捕获文件**交给 AI 助手,让它将 “设置 → 值 → 字节”一一对应起来。这就是解码的全部步骤。*(截图仅显示了 应用程序自身的 UI——不包含任何专有内容。这里的标签是法语;你的应用程序的语言可能有所不同。)* ### 提示——读取实时状态(当前速度和功率) 上面的截图解码的是*静态配置*。水泵还会推送一个**实时状态** 通知,携带其运行的*模式*、*当前速度*和*消耗功率*。你需要对这个内容进行 **动态**解码——从设置开始,然后**改变这些值并进行观察**: - **当前速度。** 运行水泵并将速度从 `1 → 10` 逐步调整(从应用程序中,或通过你 新实现的 `ble_set`)。捕获每个步骤的状态通知。那个 **在每个速度下改变一次然后保持不变**的字节就是当前速度。记录每一对 `(速度 → 字节)` ——报告的值可能使用与 1-10 设置*不同的比例*,因此你需要 真实的映射关系(它通常与你已经在设置帧中发现的编码相匹配—— 将两者进行交叉核对)。 - **功率。** 你无法*设置*功率——这是一个测量值,因此使用不同的辨别方法:保持 **恒定**速度并连续捕获几个状态帧。那些 **在其他所有数据保持稳定时发生抖动**的字节就是实时读数(功率)。通过提高速度来确认: 功率应该上升,并且上升得**比线性更快**(变速水泵的功耗随速度 急剧上升)。它通常是一个 **16 位**的值——一对字节;尝试两种字节顺序。 **匿名示例。** 一个状态通知是一个具有长度帧的数据包(几十个字节)。 这是你预期看到的*结构*——每个字节都被掩码为 `xx`, **仅供说明,不是真实的设备转储**;捕获你自己的数据以获取 实际的字节和位置: ``` xx xx LL xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx CK EN ``` - `xx xx … LL` — 一个固定的头部,后跟一个长度字节;数据包以校验和 `CK`(通常是对有效载荷的简单异或运算)和终止符 `EN` 结尾。 - **mode** — 一个字节,每个运行状态(停止 / 过滤 / 反冲洗 / 恒定)持有一个固定的代码。 - **current speed** — 一个字节,*对于给定的速度是稳定的*,并在你更改它时发生阶跃 (通过 1 → 10 阶跃来定位它)。 - **power** — 一个 16 位的值,*在速度恒定时会发生漂移*,并且随速度急剧增长 (通过保持一个速度并捕获几帧来定位它)。 给你的 AI 提供什么信息:(1) 一个涵盖整个范围的 `运行速度 → 完整状态帧 (hex)` 列表,以及 (2) 在 **一个固定速度**下捕获的几帧。向它询问*“在每个速度下保持不变的字节”*(当前速度)和*“随速度增长且在恒定速度下波动的字节”*(功率)。在比较偏移量之前,将所有帧与状态帧的固定头部/标记对齐。 ## 架构 ``` Espa Silen pump ──BLE── small Linux box (BLE adapter, near the pool, e.g. a Raspberry Pi) │ evopool_agent.py (HTTP, Basic auth) │ GET /state -> {mode, niveau, puissance} │ POST /set -> {param, valeur} │ POST /pause (frees the BLE link for the app) ▼ Home Assistant (all the logic: schedules, interlocks, safety) ``` 水泵一次只接受**一个 BLE 连接**,因此代理在 每次调用时都会**连接、通信,然后断开连接**(并提供 `POST /pause` 以便在你想要使用 evopool 应用程序时让出连接)。读取是**按需**进行的:Home Assistant 按照自己的计划轮询 `/state`。 ## HTTP 服务 | 方法 | 路径 | 主体 | 返回值 | |---|---|---|---| | GET | `/state` | – | `{"mode","niveau","puissance","paused"}` | | POST | `/set` | `{"param":"filtr_basse","valeur":4}` | `202`(异步应用) | | POST | `/pause` | `{"minutes":5}` | 为 evopool 应用程序释放 BLE 链接 | | POST | `/resume` | – | – | `param` 可以是应用程序设置屏幕上显示的**任何**配置字段——两个 过滤速度、两个反冲洗速度、恒定模式速度、持续时间、斜坡—— 而不仅仅是 `filtr_basse`(它只是我们示例中进行调度的对象)。所有端点都需要 HTTP **Basic auth**(在 `config.ini` 中设置)。参见 [`config.example.ini`](config.example.ini)。 ## Home Assistant 集成 这是你可以直接复用的部分——这里没有任何专有内容。完整示例见 [`homeassistant/`](homeassistant/)。简而言之: - 一个 **`rest`** 传感器集读取 `/state` → `sensor.pump_mode`, `sensor.pump_speed`, `sensor.pump_power`; - 一个 **`rest_command`** 发布到 `/set`; - 一个 **`input_number`** 用于保存所需的过滤速度; - **自动化**随后完成 evopool 无法做到的事情,例如: - **调度**过滤速度(夜间低 / 白天正常 / 清洁器周期期间更高), - **联锁**:仅当水泵在高于某个速度运行时才运行加氯器;仅在 高于更高的速度时才运行增压泵, - **安全**:如果水泵停止或停止响应 → 切断加氯器 + 增压泵。 参见 [`homeassistant/automations.example.yaml`](homeassistant/automations.example.yaml) 获取 带有注释的示例(由传感器上的事件驱动,并以定期重新断言作为兜底措施)。 ## 运行说明 在具有 BlueZ 和 BLE 适配器的 Linux 机器上(Raspberry Pi 效果很好): ``` sudo apt install bluez python3 # or your distro's equivalent cp config.example.ini config.ini # set [ble] mac/char and [web] user/pass bluetoothctl trust AA:BB:CC:DD:EE:FF # so the agent connects without scanning every time python3 evopool_agent.py # serves on :8095 ``` 将其作为服务运行(systemd,或者 [`openwrt/`](openwrt/) 中的 OpenWrt `procd` 示例)。将所选的端口开放给你的 Home Assistant 主机。 ## 免责声明 这是一个**非官方的、业余爱好者制作的概念验证**,按**原样提供,不提供任何保证**。 它**不隶属于 Espa,也未获得 Espa 的认可或支持**,并且不包含 任何 **Espa 专有材料**——你拥有针对自己的设备进行逆向工程的权利。你对 自己的水泵和泳池所做的任何操作负责。参见 [`LICENSE`](LICENSE) (GPL-3.0)。
标签:API网关, Home Assistant, 智能家居, 物联网, 网络调试, 自动化, 蓝牙低功耗, 逆向工具