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` |
|:--:|:--:|
|  |  |
将这两张截图**连同你的两份捕获文件**交给 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, 智能家居, 物联网, 网络调试, 自动化, 蓝牙低功耗, 逆向工具