Hawkbit DDI Client
轻量级纯 Python OTA 更新代理,零依赖(仅 Python 3 标准库),可在 Android adb shell 和 Linux 主机上运行。
功能
| 功能 | 说明 |
|---|---|
| 轮询 | GET /{tenant}/controller/v1/{controllerId} 查询部署任务,自动适配服务端建议的轮询间隔 |
| 断点下载 | HTTP Range 请求实现断点续传,临时 .tmp 文件保留至下载完成 |
| SHA256 校验 | 下载完成后自动与部署元数据中的哈希值比对 |
| 状态上报 | 完整状态链:download → downloaded → proceeding → closed(success/failure) |
| 设备 SN 检测 | 自动检测序列号:Android ro.serialno → DMI product_serial → /etc/machine-id → hostname |
| 设备属性上报 | 首次连接自动上报设备属性(osType, platform, hwRevision, kernel…),供 Hawkbit target filter 匹配 |
| 认证 | 支持 GatewayToken 和 TargetToken,也支持从文件读取:--gateway-token @/etc/hawkbit/gateway.key |
| 取消/确认 | 处理 cancelAction(取消任务)和 confirmationBase(headless 自动确认) |
设备属性上报
脚本在首次轮询时自动调用 PUT …/configData 上报以下属性:
| 属性 | 来源 | 示例 |
|---|---|---|
osType |
/system/build.prop 或 uname |
android / linux |
platform |
platform.machine() |
aarch64 / x86_64 |
kernel |
os.uname().release |
6.17.0-35-generic |
hwRevision |
DMI product_name + product_version | VMware Virtual Platform |
manufacturer |
DMI sys_vendor 或 Android ro.product.manufacturer | VMware, Inc. |
hostname |
socket.gethostname() |
device-001 |
swVersion |
/etc/hawkbit/current_version(可选) |
V1.0.0.0 |
扩展属性:创建 /etc/hawkbit/device_attrs.json 添加自定义属性:
{"dept": "production", "region": "east", "owner": "team-a"}
这些属性在 Hawkbit 里就是 target 的 attributes,管理员创建 target filter 时可以直接用:
属性 osType=android AND hwRevision=VMware → 自动分配 V2.0 更新
## 快速开始
```bash
# 网关令牌,每 30 秒轮询
python3 ddi-client.py -u https://hawkbit.example.com -t DEFAULT --gateway-token s3cret -i 30
# 网关令牌从文件读取(生产推荐)
echo "s3cret" > /etc/hawkbit/gateway.key
chmod 600 /etc/hawkbit/gateway.key
python3 ddi-client.py -u https://hawkbit.example.com -t DEFAULT \
--gateway-token @/etc/hawkbit/gateway.key -i 30
# 目标令牌,单次轮询
python3 ddi-client.py -u http://10.0.0.1:8080 -t DEFAULT --target-token tok --once
# 自定义设备 ID + 自定义属性文件,调试模式
python3 ddi-client.py -u https://hawkbit:8443 -t prod \
--gateway-token @/etc/hawkbit/gateway.key \
--controller-id edge-042 -d /data/ota -v
命令行参数
-u, --base-url Hawkbit 服务端地址(必填)
-t, --tenant 租户名称,如 DEFAULT(必填)
--gateway-token Gateway 安全令牌
--target-token Target 安全令牌
--controller-id 控制器 ID,默认自动检测设备序列号
-d, --download-dir 下载目录,默认 /tmp/hawkbit
-i, --polling-interval 轮询间隔(秒),默认 60,可被服务端覆盖
--no-verify 跳过 SHA256 校验
--no-resume 禁用断点续传
--no-ssl-verify 禁用 TLS 证书验证(不安全)
--once 仅轮询一次后退出
-v, --verbose 调试级日志
-h, --help 帮助信息
DDI API 流程
┌─────────┐ ① GET /{tenant}/controller/v1/{controllerId} ┌──────────┐
│ │ ────────────────────────────────────────────────────→ │ │
│ 设备 │ ←──── HAL links (deploymentBase / cancel / …) │ Hawkbit │
│ │ │ Server │
│ │ ② GET …/deploymentBase/{actionId} │ │
│ │ ────────────────────────────────────────────────────→ │ │
│ │ ←──── chunks[].artifacts[] (filename, SHA256, │ │
│ │ download URL) │ │
│ │ │ │
│ │ ③ GET …/softwaremodules/{id}/artifacts/{file} │ │
│ │ ────────────────────────────────────────────────────→ │ │
│ │ ←──── 二进制流(支持 Range 断点续传) │ │
│ │ │ │
│ │ ④ POST …/deploymentBase/{actionId}/feedback │ │
│ │ ───── {execution, result, details} ────────────────→ │ │
│ │ ←──── 200 OK │ │
└─────────┘ └──────────┘
状态上报 JSON 格式
{
"timestamp": 1750000000000,
"status": {
"execution": "download",
"result": {
"finished": "none"
},
"details": ["Starting download"]
}
}
| execution 值 | 含义 | result.finished |
|---|---|---|
download |
开始下载 | none |
downloaded |
下载完成 | none |
proceeding |
安装中 | none |
closed |
最终状态 | success / failure |
canceled |
已取消 | none |
rejected |
已拒绝 | none |
认证配置
Target Token(推荐,每设备独立令牌)
在 Hawkbit Management API 中为目标设置 security token:
curl -u admin:admin -X PUT \
-H "Content-Type: application/json" \
"http://<hawkbit>:9090/rest/v1/targets/<controllerId>" \
-d '{"securityToken": "my-device-token"}'
启用租户级 TargetToken 认证:
curl -u admin:admin -X PUT \
-H "Content-Type: application/json" \
"http://<hawkbit>:9090/rest/v1/system/configs/authentication.targettoken.enabled" \
-d '{"value": true}'
Gateway Token(所有设备共享同一令牌)
# 设置 token key
curl -u admin:admin -X PUT \
-H "Content-Type: application/json" \
"http://<hawkbit>:9090/rest/v1/system/configs/authentication.gatewaytoken.key" \
-d '{"value": "my-gateway-key"}'
# 启用
curl -u admin:admin -X PUT \
-H "Content-Type: application/json" \
"http://<hawkbit>:9090/rest/v1/system/configs/authentication.gatewaytoken.enabled" \
-d '{"value": true}'
设备 SN 检测优先级
| 优先级 | 来源 | 适用平台 |
|---|---|---|
| 1 | getprop ro.serialno |
Android |
| 2 | /sys/class/dmi/id/product_serial |
Linux (x86) |
| 3 | /sys/devices/virtual/dmi/id/product_serial |
Linux (ARM / 嵌入式) |
| 4 | /etc/machine-id |
systemd Linux |
| 5 | socket.gethostname() |
通用回退 |
安装钩子
下载完成后,脚本调用 _install(files, handling) 方法执行实际安装。默认实现仅做文件存在性检查,生产环境必须覆盖此方法。
方式一:子类继承
from ddi_client import HawkbitDDIClient
class MyClient(HawkbitDDIClient):
def _install(self, files, handling):
import subprocess
for f in files:
subprocess.run(["unzip", "-o", f, "-d", "/data/ota"], check=True)
return True
方式二:Monkey-Patch
client = HawkbitDDIClient(...)
client._install = lambda files, h: do_my_install(files)
兼容性
- Python ≥ 3.7
- Android (adb shell, 需安装 Python)
- Linux (x86_64 / aarch64 / armv7l)
- macOS
- Hawkbit DDI API v1
文件结构
ddi-client.py # 脚本本体(单文件,可直接部署)
无其他依赖文件。