Async protocol library for Huawei ESM-48100 batteries
Project description
huawei-esm48100
Huawei ESM-48100 电池的异步 Python 通信库,实时传输默认严格只读。
当前仓库已根据两台 ESM-48100B1 的实机抓包实现:
- Modbus RTU CRC16、读保持寄存器请求和响应解析;
- USB/本地串口传输(基于
serialx),按通信参数计算 Modbus RTU 3.5 字符静默时间,并为 USB 转向保留至少 10 ms; - TCP 透明串口服务器传输;
- 多个从站共享同一传输连接的异步客户端;
- 长时间空闲后的只读唤醒、CRC/超时重试和异常尾随数据清理;
- 电压、电流、SOC、SOH、统计量、告警和 1–24 节单体数据解码;
- 设置寄存器的只读回读;
- 华为电子标签
0x41/0x06只读分块采集与 ASCII 档案解析; - 支持扫描、连续读取、原始帧和完整性摘要的命令行工具。
[!WARNING] 实时传输默认只允许功能码
0x03,以及严格匹配格式的只读电子标签0x41/0x05/0x04元数据查询和0x41/0x06/0x04分块读取。0x06、0x10和其他厂商私有功能默认拒绝发送。只有调用方显式启用不安全请求后, 库才允许五个经过抓包确认、带范围检查及写后读回的高级设置。不同型号或 固件仍需独立抓包验证。
完整的证据、寄存器表、私有电子标签帧和安全说明见 PROTOCOL.md。
开发安装
虚拟环境只用于开发和独立硬件测试,不能复制到另一台机器,也不参与 Home Assistant 生产部署。每台机器应从本机 Python 重新创建环境。
Windows PowerShell:
.\scripts\setup-venv.ps1
.\.venv\Scripts\python.exe -m pytest
如果本机执行策略禁止直接运行 .ps1,可以只对这一次启动绕过策略:
powershell.exe -NoProfile -ExecutionPolicy Bypass `
-File ".\scripts\setup-venv.ps1"
自动发现失败时可指定 Python:
.\scripts\setup-venv.ps1 `
-Python "C:\Program Files\Python313\python.exe"
若已有环境来自另一台机器,脚本会把它移动到
.venv-stale-<时间戳> 后重建。只有明确使用 -Recreate 时才直接删除旧环境。
普通 Linux 开发环境:
bash scripts/setup-venv.sh
.venv/bin/python -m pytest
只安装运行依赖:
.\scripts\setup-venv.ps1 -RuntimeOnly
bash scripts/setup-venv.sh --runtime-only
两个脚本都要求 Python 3.12 或更高版本,并在结束前验证包可以导入。
Home Assistant 生产安装
HACS 只安装 custom_components/huawei_esm48100。Home Assistant 随后读取
集成的 manifest.json,自动安装固定版本的 huawei-esm48100 包。HA OS、
Supervised 和 Container 生产环境都不运行本仓库的 setup-venv 脚本。
因此正式 HACS 发布前,必须先把与 manifest.json 对应的协议库版本发布到
PyPI。
CI 与 PyPI 发布
.github/workflows/tests.yml 在 Ubuntu 上测试 Python 3.12、3.13 和 3.14,
并构建 wheel/sdist 后执行 twine check。
.github/workflows/publish.yml 在 GitHub Release 发布时:
- 检查 Release tag(允许
v前缀)与pyproject.toml版本一致; - 构建并检查 wheel 和 source distribution;
- 使用 PyPI Trusted Publishing 的短期 OIDC 凭据发布,不使用仓库 API Token。
首次发布前,需要在 PyPI 创建 Pending Trusted Publisher:
PyPI project: huawei-esm48100
GitHub owner: 实际仓库所有者
GitHub repository: https://github.com/GImDX/huawei-esm48100
Workflow: publish.yml
Environment: pypi
同时在 GitHub 仓库创建名为 pypi 的 Environment,并建议为它启用人工审批。
之后将 pyproject.toml 版本更新为目标版本,创建相同版本的 Release tag,
例如 v0.1.0,即可触发发布。
读取原始寄存器
本地串口:
esm48100 read \
--transport serial \
--port /dev/serial/by-id/usb-... \
--baudrate 9600 \
--slave 0xd6 \
--register 0x0000 \
--count 7 \
--raw
TCP 透明串口服务器:
esm48100 read \
--transport tcp \
--host 192.0.2.10 \
--tcp-port 5020 \
--slave 0xd6 \
--register 0x0000 \
--count 6
TCP 模式发送和接收的仍然是带 CRC 的 Modbus RTU 帧。它不是带 MBAP 头的 Modbus TCP。
串口首次打开默认等待 2 秒,然后用安全的 0x0000 × 1 读取唤醒设备。
read 单次响应超时默认 3 秒,初始恢复窗口默认 60 秒。连续测试示例:
esm48100 read `
--transport serial --port COM4 --baudrate 9600 --parity N `
--slave 0xD6 --register 0x0000 --count 7 `
--repeat 20 --interval 3 --raw
扫描华为上位机使用的默认地址集合:
esm48100 scan --transport serial --port COM4 --raw
扫描不是对每个地址只读取一次,而是在 60 秒恢复窗口内轮询尚未响应的地址。
扫描的单次响应超时默认 0.5 秒,正常在线设备的实测响应为 45–90 ms;如透明
串口服务器延迟较高,可显式增大 --timeout。同一地址的重试轮次默认至少
间隔 3 秒;候选地址较多且一轮本身超过 3 秒时不会额外等待。
PowerShell 中需要手工等待总线空闲时,应使用:
Start-Sleep -Seconds 600
read 每轮都会打印 requested_count、received_count、地址范围和连续性。
使用 --json 可生成一行一个完整结果的 JSON,避免依赖终端文本复制。
只读实机探针
仓库内的探针支持本地串口和透明 TCP 串口服务器。它保持同一个传输连接, 先静置,再测试安全唤醒并连续读取完整快照。探针不会启用危险请求,输出 JSONL 结果和逐帧调试日志。
本地串口:
.\.venv\Scripts\python.exe .\scripts\hardware_probe.py `
--transport serial `
--port COM4 `
--addresses 0xD6,0xD7 `
--idle-seconds 600 `
--rounds 20 `
--interval 3
透明 TCP 串口服务器:
.\.venv\Scripts\python.exe .\scripts\hardware_probe.py `
--transport tcp `
--host 192.0.2.10 `
--tcp-port 1145 `
--addresses 0xD6,0xD7 `
--idle-seconds 0 `
--rounds 10 `
--interval 3
未指定 --transport 时仍默认使用 serial,因此旧的串口探针命令保持兼容。
TCP 模式下,波特率、校验位和停止位由串口服务器自身配置。
JSONL 是判断轮次和字段是否完整的依据;终端文本只用于观察进度,复制时缺行 不会被误判为协议解析缺失。
离线解析 Device Monitoring Studio 抓包
esm48100 decode-capture C:\path\to\Data_view_writes.txt --direction request
esm48100 decode-capture C:\path\to\Data_view_reads.txt --direction response
每个输入记录输出一行 JSON,并列出 CRC 有效的 RTU 帧与无法识别的剩余字节。 此命令不打开串口。
Python API
from huawei_esm48100 import EsmClient
from huawei_esm48100.transports import TcpRtuTransport
transport = TcpRtuTransport("192.0.2.10", 5020)
client = EsmClient(transport, slave_address=0xD6)
snapshot = await client.read_snapshot()
print(snapshot.bus_voltage_v)
print(snapshot.pack_voltage_v)
print(snapshot.state_of_charge)
print(snapshot.cell_voltages_v)
await transport.close()
项目边界
- 一个 transport 代表一条物理或透明转发的 RS485 总线。
- 多个
EsmClient可以共享同一个 transport,并由 transport 串行化请求。 - 一条 RS485 总线只支持一个主站;不支持同时运行华为上位机、串口助手或 另一个轮询程序。传输层仍会丢弃完整的无关 RTU 帧,并在畸形帧后恢复边界, 避免一次残留数据持续污染后续事务。
- 默认传输只允许功能码
0x03;HACS 只有在用户显式启用高级控制实体后才会 打开危险请求开关。 - 高级设置只发送一次写请求,不会因响应异常盲目重发。标准
0x06回显会被 校验;若回显缺失或损坏,则恢复输入流并以目标寄存器读回作为最终确认。 - 电子标签只放行已验证的
0x41/0x05/0x04元数据查询和0x41/0x06/0x04分块读取请求,并读取索引0x0000–0x000A;不会复现 上位机的隐式时钟写入、结束帧或其他私有操作。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file huawei_esm48100-0.1.0.tar.gz.
File metadata
- Download URL: huawei_esm48100-0.1.0.tar.gz
- Upload date:
- Size: 49.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d48c20c76ffc82ba6823faafa6a9afa1f29ce07d88996ea20896abd48cc88767
|
|
| MD5 |
bf067dd1297a4825f7b8cf97f10cc243
|
|
| BLAKE2b-256 |
76de9c389cb2efbaf3e4d267228e5dfb19f2dcad58f34a1585eb04c731c1c256
|
Provenance
The following attestation bundles were made for huawei_esm48100-0.1.0.tar.gz:
Publisher:
publish.yml on GImDX/huawei-esm48100
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
huawei_esm48100-0.1.0.tar.gz -
Subject digest:
d48c20c76ffc82ba6823faafa6a9afa1f29ce07d88996ea20896abd48cc88767 - Sigstore transparency entry: 2284316854
- Sigstore integration time:
-
Permalink:
GImDX/huawei-esm48100@5ed1a3652c1e792f960f8a6439660e08717dcf8b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/GImDX
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5ed1a3652c1e792f960f8a6439660e08717dcf8b -
Trigger Event:
release
-
Statement type:
File details
Details for the file huawei_esm48100-0.1.0-py3-none-any.whl.
File metadata
- Download URL: huawei_esm48100-0.1.0-py3-none-any.whl
- Upload date:
- Size: 31.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ebcd3ade77709f8aa274f4ee04caf33c79590302cee889ec827b10eacb6f3296
|
|
| MD5 |
2e8dbd10df943ac3f59b2048b6e26681
|
|
| BLAKE2b-256 |
7d87fa79e8e4ff3b40638960830f692200f933a1dd2b3d572bb4152da8690f31
|
Provenance
The following attestation bundles were made for huawei_esm48100-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on GImDX/huawei-esm48100
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
huawei_esm48100-0.1.0-py3-none-any.whl -
Subject digest:
ebcd3ade77709f8aa274f4ee04caf33c79590302cee889ec827b10eacb6f3296 - Sigstore transparency entry: 2284316980
- Sigstore integration time:
-
Permalink:
GImDX/huawei-esm48100@5ed1a3652c1e792f960f8a6439660e08717dcf8b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/GImDX
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5ed1a3652c1e792f960f8a6439660e08717dcf8b -
Trigger Event:
release
-
Statement type: