tukutt/Victron-SolarSense-750-EspHome

GitHub: tukutt/Victron-SolarSense-750-EspHome

无需 bindkey 解码 Victron SolarSense 750 总日射表 BLE 广播帧的开源工具,支持 Python 脚本实时扫描与 ESPHome 集成 Home Assistant。

Stars: 0 | Forks: 0

# victron-solarsense750 解码由 **Victron SolarSense 750** 总日射表广播的 BLE Instant Readout 帧——**无需 bindkey**。 解码由 **Victron SolarSense 750** 总日射表广播的 BLE Instant Readout 帧——**无需 bindkey**。 ## TL;DR SolarSense 750 在 Victron manufacturer id `0x02E1` 下**以明文形式**广播其测量数据。此 repo 提供了一个轻量级、低依赖的 Python 脚本,可用于扫描设备并实时解码 payload,或离线解码粘贴的 hex 帧。 SolarSense 750 在 Victron manufacturer id `0x02E1` 下**以明文形式**广播其测量数据。此 repo 提供了一个轻量级、低依赖的 Python 脚本,可用于扫描设备并实时解码 payload,或离线解码粘贴的 hex 帧。 **测试固件 / Firmware testé :** `1.01` ## 解码字段 / Champs décodés 该帧分为两部分:一个 8 字节的 header,然后是一个遵循官方 Victron Solar Sense 布局的**位压缩记录**(已通过 Victron 源代码确认)。 ### Header (bytes 0..7) | Index | Field | Notes | | --------- | ----------------------------------- | ---------------------------------------------------- | | `0` | Record type | 常量 `0x10` | | `1` | State flag | 切换 `0x00` ↔ `0x80`,作用未知 | | `2:3` LE | Victron product id | SolarSense 750 为 `0xC050` | | `4` | — | 常量 `0xFF`,作用未知 | | `5:6` LE | Message counter / compteur | 16位,可用于 RX 质量诊断 | | `7` | — | 常量 `0x01`,作用未知 | ### 位压缩记录 (bytes 8..23, 按照 Victron 惯例低位优先) Bit 偏移量相对于 byte 8 的 bit 0。布局和缩放遵循 [victronenergy/dbus-ble-sensors `src/solarsense.c`](https://github.com/victronenergy/dbus-ble-sensors/blob/master/src/solarsense.c)。 | Bit range | Field | Encoding | NA value | | ---------- | -------------------- | ----------------------------------------------------- | ----------- | | `0..31` | ErrorCode | UN32 bitmask | — | | `32..39` | Charger Error | UN8 | `0xFF` | | `40..59` | Installation Power | UN20, 1 W | `0xFFFFF` | | `60..79` | Today's Yield | UN20, 0.01 kWh | `0xFFFFF` | | `80..93` | Irradiance | UN14, 0.1 W/m² | `0x3FFF` | | `94..104` | Cell Temperature | UN11, 0.1 °C, 偏移 −60 °C | `0x7FF` | | `105` | Unspecified Remnant | 1 bit | — | | `106..113` | Battery Voltage | UN8, 0.01 V, 偏移 +1.70 V | `0xFF` | | `114` | Tx Power Level | 0 = 0 dBm, 1 = +6 dBm | — | | `115..121` | Time Since Last Sun | UN7, 分段 → 分钟 (见下文) | `0x7F` | #### Time Since Last Sun 量化 ``` raw 0..29 → raw * 2 minutes (0..58 min, 2-min steps) raw 30..95 → 60 + 10 * (raw - 30) minutes (60..710 min, 10-min steps) raw 96..126 → 720 + 30 * (raw - 96) minutes (720..1620 min, 30-min steps) ``` 注意:Cerbo (Venus OS) 会以秒为单位报告分辨率更高的“Time since last sun”,这是它通过连接设备的 VE.Direct 接口在本地计算的。BLE 广播字段仅为分钟。 ### 告警 根据 Victron 源码,从广播中派生出的唯一告警是 **LowBattery**:在 `BatteryVoltage < 3.2 V` 时触发,通过 0.4 V 滞后清除(即仅在高于 3.6 V 时重置)。Python 解码器暴露了一个无状态的 `low_battery = battery_v < 3.2 V`;ESPHome 配置则实现了适当的滞后。 ## 要求 - Python ≥ 3.9 - BLE 适配器(内置或 USB) - [`uv`](https://docs.astral.sh/uv/)(推荐 — 通过 [PEP 723](https://peps.python.org/pep-0723/) header 自动处理依赖) 唯一的运行时依赖是 [`bleak`](https://github.com/hbldh/bleak)。 ## 用法 ### 1. 实时扫描 / Scan en direct 使用 `SOLARSENSE_MAC` 环境变量配置传感器 MAC 地址,然后运行: ``` export SOLARSENSE_MAC=AA:BB:CC:DD:EE:FF uv run solarsense_decode.py scan ``` 示例输出: ``` --- RSSI -55 dBm --- product_id : 0xC050 counter : 20803 error_code : 0x04001405 charger_error : 0 pv_power : 326 W yield : 6900 Wh irradiance : 38.4 W/m² cell_temp : 25.9 °C battery_v : 3.79 V low_battery : False tx_power : +6 dBm since_sun : 42 min state_flag : 0x00 bytes/octets : 0:10 1:00 2:50 3:c0 4:ff 5:43 6:51 7:01 8:05 ... ``` ### 2. 离线解码 / Décodage hors-ligne ``` uv run solarsense_decode.py decode 10e102a0... ``` hex 字符串中的空格和冒号将被忽略。 ## 查找 MAC 任何 BLE 扫描器都可以。使用 `bleak`: ``` uv run --with bleak python -c "import asyncio,bleak; \ print(asyncio.run(bleak.BleakScanner.discover()))" ``` 或者使用 `bluetoothctl scan on`、nRF Connect、LightBlue 等。该设备以 Victron 产品身份进行广播,manufacturer id 为 `0x02E1`。 ## 逆向工程过程 三个阶段: 1. 对一系列实时捕获的**差分分析**确定 payload 是未加密的(当 message counter 递增时,payload 几乎是恒定的——如果是基于计数器的 ciphertext,每个字节都会发生变化),并根据 VictronConnect 应用程序经验性地确定了 PV 功率、Irradiance、Cell Temperature 和今日 yield。 2. **与 Victron Solar Sense 字段表交叉核对**(由 Victron 开发人员慷慨提供)确认了该布局是一个从 byte 8 开始的位压缩记录。 3. **与 Victron 源码对齐** [dbus-ble-sensors `src/solarsense.c`](https://github.com/victronenergy/dbus-ble-sensors/blob/master/src/solarsense.c) 确认了每一个缩放因子,验证了 header magic bytes (`buf[0] == 0x10`, `buf[4] == 0xFF`, `buf[7] == 0x01`),并提供了非线性的 Time Since Last Sun 量化以及 LowBattery 告警阈值。 ## 通过 ESPHome 在 Home Assistant 中使用 提供了一个 [ESPHome 配置](esphome/solarsense.yaml)。将其刷入传感器 BLE 范围内的任何 ESP32,您将在 Home Assistant 中获得 **九个实体** ——六个数值传感器(Irradiance、Installation Power、 今日 Yield、Cell Temperature、Battery Voltage、Time Since Last Sun), 两个诊断文本传感器(error code、charger error)和一个 二进制传感器(low battery)——所有实体都带有正确的 `device_class` / `state_class`。Yield 以 `total_increasing`(单位 kWh)的形式暴露,因此可以直接接入 HA 的 Energy 仪表板,并且 Low Battery 传感器实现了 Victron 官方的 3.2 V 触发 / 3.6 V 释放滞后。 同一个 ESP32 还在**主动**模式下运行标准的 ESPHome `bluetooth_proxy:` 组件,因此它可以作为您其余 HA Bluetooth 设备(Xiaomi、Govee、Switchbot、官方 Victron 等)的完整 Bluetooth 代理。 ### 设置 1. 编辑 `esphome/solarsense.yaml` 并调整 `name`、`friendly_name`、 `min_version` 等,以匹配您的设置。 2. 添加到您的 ESPHome `secrets.yaml` 中: wifi_ssid: "your-ssid" wifi_password: "your-password" solarsense_mac: "AA:BB:CC:DD:EE:FF" 3. 编译并刷入: esphome run esphome/solarsense.yaml 4. ESP32 通过 ESPHome 集成显示在 Home Assistant 中; 九个实体(六个数值传感器、两个文本传感器和 Low Battery 二进制传感器)会自动添加。 ### 为什么在 ESP32 上解码而不是使用纯 BLE 代理? 单独的 `bluetooth_proxy:` 组件会将 SolarSense 广播转发给 Home Assistant,但目前没有 HA 集成知道如何解码此设备。在 ESPHome 内部解码会立即将帧转换为干净、带类型的传感器,同时仍然保持 ESP32 可用作其他所有设备的代理。 ## 状态 / Statut - ✅ Installation Power、Today's Yield、Irradiance、Cell Temperature、 Battery Voltage、Charger Error、Tx Power Level、Time Since Last Sun (以分钟为单位)、LowBattery 告警 —— 全部已根据 Victron 源码验证 - ✅ ErrorCode 作为原始的 32 位 bitmask 暴露;此处未映射各个位的含义 (需要额外的 Victron 文档) - ✅ Message counter(16 位)和 Victron product id (`0xC050`) —— 可用于 过滤和 RX 质量诊断 - ✅ Header magic bytes(位于索引 0、4、7 的 `0x10`、`0xFF`、`0x01`) 已验证,与 Victron 源码检查匹配 - 🟡 Header 的 Byte 1(切换 `0x00`/`0x80`) —— 未由 Victron 源码验证,作用未知 - 欢迎贡献 ## 免责声明 此项目**不隶属于 Victron Energy**。它依赖于公开的 BLE 广播,仅出于互操作性和教育目的提供。使用需自担风险。 ## 许可证 MIT
标签:Python, 传感器, 太阳能监控, 数据解析, 无后门, 物联网, 蓝牙, 逆向工具