123 lines
5.0 KiB
Markdown
123 lines
5.0 KiB
Markdown
# ppclock — 4.2寸墨水屏设备离线 SDK 与 CLI
|
||
|
||
替代厂商 Web 上位机(mspppclock.tech)与 Android App 的**完全离线**开发包:
|
||
Python SDK(`PPClient`)+ CLI(`ppclock`)+ BLE 桥(`ppclock-bridge`),
|
||
全部功能经真机验证(协议三线逆向 + 实机互证)。
|
||
|
||
设备:4.2" 400×300 黑/白/红三色墨水屏,Dialog DA14585 BLE SoC(广播名前缀 `NRF-`)。
|
||
|
||
> AI 消费向项目卡见 [`llms.txt`](llms.txt);签名级 API 见 [`docs/sdk/API.md`](docs/sdk/API.md)。
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
python3 -m venv .venv
|
||
.venv/bin/pip install -e ".[dev]" # 依赖:bleak、pillow(dev: pytest)
|
||
```
|
||
|
||
运行要求:蓝牙适配器(本机 bleak)**或** 他机蓝牙经 `ppclock-bridge` 桥接。**不需要互联网**。
|
||
|
||
## SDK 用法(二次开发)
|
||
|
||
```python
|
||
from ppclock import PPClient
|
||
|
||
async with PPClient.via_local() as dev: # 本机蓝牙
|
||
await dev.set_time(tz=8) # 北京时间
|
||
await dev.set_mode("clock1")
|
||
|
||
async with PPClient.via_bridge("192.168.61.35:8971") as dev: # 经 bridge
|
||
await dev.upload_image("photo.jpg", slot=0) # 传图(6 种抖动可选)
|
||
await dev.render_template("custom", {"text": "你好【红字】"})
|
||
await dev.countdown(date(2026, 12, 31), prefix="目标")
|
||
await dev.activate_auto() # 离线激活(无需厂商服务器)
|
||
```
|
||
|
||
设备操作全集:对时(tz)/模式/切换/传图/6 模板/倒计时/休眠/停车牌/轮播/LUT/WiFi/raw/OTA,
|
||
见 [`docs/sdk/API.md`](docs/sdk/API.md)。
|
||
|
||
## MCP 服务器(agent 直挂)
|
||
|
||
`ppclock-mcp` 在蓝牙物理所在机器上跑单层 MCP 服务器,13 个工具覆盖对时/模式/传图/
|
||
模板/倒计时/休眠等日常操作:
|
||
|
||
```bash
|
||
pip install -e ".[mcp]" # 追加依赖 mcp
|
||
|
||
# stdio —— Claude Code 等本机 agent 直挂
|
||
claude mcp add ppclock -- ppclock-mcp --mac AA:BB:CC:DD:EE:FF
|
||
|
||
# streamable HTTP —— 局域网 agent 平台(Bearer 鉴权,端点 /mcp)
|
||
PPCLOCK_MCP_TOKEN=<token> ppclock-mcp --transport http --host 0.0.0.0 --port 8972
|
||
```
|
||
|
||
连接管理为方案 C(按需连接+空闲保持、串行、掉线重连一次);OTA/激活/LUT/WiFi/轮播
|
||
有意不暴露。工具参考与部署指南见 [`docs/sdk/MCP.md`](docs/sdk/MCP.md)。
|
||
|
||
## CLI 用法
|
||
|
||
```bash
|
||
ppclock scan # 扫描设备(NRF- 前缀)
|
||
ppclock --mac AA:BB:CC:DD:EE:FF time --tz 8 # 对时(北京时间)
|
||
ppclock image photo.jpg --slot 0 # 传图到图一
|
||
ppclock template custom --data '{"text":"你好【世界】"}'
|
||
ppclock countdown 2026-12-31 --prefix 目标
|
||
ppclock batch job.jsonl --json # 批量执行(单连接)
|
||
```
|
||
|
||
- 全命令支持 `--json` 机器可读输出(`{"ok","cmd","data"|"error"}`,退出码 0/1/2/3)
|
||
- `batch`:JSONL 批量(`{"argv":[...]}` 每行一条,单连接执行,agent 编排友好)
|
||
|
||
## BLE bridge(蓝牙在他机时)
|
||
|
||
本机无蓝牙(或 USB/IP 透传断流)时,把 BLE 桥接到蓝牙物理所在机:
|
||
|
||
```bash
|
||
# 蓝牙所在机(Windows/Linux,仅需 bleak)
|
||
pip install bleak
|
||
ppclock-bridge --host 0.0.0.0 --port 8971 # 或 python -m ppclock.bridge_server
|
||
|
||
# 使用方(全部 SDK/CLI 透明可用)
|
||
ppclock --via bridge://192.168.61.35:8971 --json scan
|
||
export PPCLOCK_VIA=bridge://192.168.61.35:8971
|
||
```
|
||
|
||
协议:JSONL over TCP v1(`ping/scan/connect/write/read/request_device_id/ota/services/close`),
|
||
仅限可信 LAN(无鉴权)。详见 `docs/sdk/API.md` §Bridge RPC。
|
||
|
||
## 固件工具
|
||
|
||
```bash
|
||
.venv/bin/python tools/fw_info.py app/firmware-PP_da14585_4.2_CH.img # 镜像头解析
|
||
.venv/bin/python tools/fw_pack.py body.bin out.img # 修改后重打包(CRC 重算)
|
||
ppclock --json ota firmware.img # 预检(不烧录)
|
||
ppclock --json ota firmware.img --yes # SUOTA 烧录(高危,需授权)
|
||
```
|
||
|
||
本机设备为裸闪存布局(无产品头)→ SUOTA 止于设备内部门禁;工厂布局与线刷恢复路径见
|
||
[`docs/firmware-layout.md`](docs/firmware-layout.md)。
|
||
|
||
## 真机全链路测试
|
||
|
||
```bash
|
||
.venv/bin/python tools/field_test.py # 引导式:自动判定+目视确认
|
||
```
|
||
|
||
结果自动写入 `docs/field-test-result.md`。
|
||
|
||
## 离线说明
|
||
|
||
- **激活**:原厂流程依赖云端 `key_generator.php`;本 SDK 用固件逆向出的本地 keygen
|
||
(`activate_auto`:EFEF 取 ID → MAC 反解 → 本地算码),实机验证。
|
||
- 模板渲染、二维码(本地 qrcode 库)、六种抖动全部本地实现,无 CDN/服务器依赖。
|
||
- 天气(CITY 代码)属原厂云功能,本地化范围外;`wifi` 命令仅透传(且本固件 no-op)。
|
||
|
||
## 开发
|
||
|
||
```bash
|
||
.venv/bin/python -m pytest tests/ -q # 207 测试
|
||
```
|
||
|
||
治理规则见 `GOVERNANCE.md`;变更记录 `CHANGELOG.md`;决策日志 `DECISIONS.md`。
|
||
协议规范(唯一事实源):`docs/protocol.md`;固件内部:`docs/firmware-analysis.md`。
|