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, 传感器, 太阳能监控, 数据解析, 无后门, 物联网, 蓝牙, 逆向工具