ppclock SDK · API 参考(v0.2.0-beta)
面向二次开发的签名级参考。协议细节见 docs/protocol.md,固件内部见 docs/firmware-analysis.md。MCP 服务器(ppclock-mcp)工具参考见 docs/sdk/MCP.md。
安装与入口
PPClient(统一门面,async)
工厂与扫描
| 方法 |
签名 |
说明 |
via_local |
`(mac: str |
None=None, timeout=10.0) -> PPClient` |
via_bridge |
(host: str, mac=None, timeout=10.0, port=None) -> PPClient |
经 bridge 远程 BLE;host 可含 :port(默认 8971) |
via_uri |
(uri: str, mac=None, timeout=10.0) -> PPClient |
"local" 或 "bridge://host[:port]" |
scan_devices |
async (uri="local", timeout=5.0) -> list[dict] |
[{name, address, rssi}],按 uri 选择本机/桥扫描 |
生命周期:async with PPClient.via_*(...) as dev: —— 进入连接、退出断开。
时钟与显示
| 方法 |
签名 |
说明 |
set_time |
`async (dt=None, tz: float |
None=None)` |
set_mode |
async (mode: str) |
clock1-3/calendar1-3/image0-3/tricolor/mono |
toggle |
async (name: str) |
invert/font/rotate180/hour_format/clock_color |
clear |
async () |
刷屏(EPD 00+01) |
图像
| 方法 |
签名 |
说明 |
upload_image |
async (source, slot=None, algo="atkinson", mono=False, size=(400,300), **adjust) -> dict |
source=路径或 PIL.Image;algo∈none/floydsteinberg/atkinson/bayer/stucki/jarvis;adjust∈threshold/diffusion/brightness/contrast/saturation/rotate;返回 {"bytes_bw","bytes_red","small","slot"}。小图(3500B/9000B)自动走 cod=04 |
render_template |
async (name, payload=None, slot=None, algo="atkinson") -> dict |
6 模板本地渲染上传:schedule/businesscard/memo/course/qrcode/custom;payload 见 src/ppclock/templates.py docstring |
倒计时与文字
| 方法 |
签名 |
说明 |
countdown |
async (d: date, mode="clock", prefix=None) |
mode=clock/calendar;prefix 时钟≤8 单位、日历≤4 字(中文=1,其他=0.5) |
countdown_off |
async () |
关闭倒计时 |
calendar_text |
async (text: str) |
设置日历中文字并切日历模式一(upload_rili 序列) |
其他命令
| 方法 |
签名 |
说明 |
parking |
async (number: str) |
停车牌(纯数字;⚠ 本固件不显示,K1 待查) |
sleep |
async (on: bool, start_h: int, end_h: int) |
休眠时段(0-23 时) |
rotation |
async (count=None, interval=None, unit="min") |
轮播数量 1-4 / 间隔(⚠ 本固件 no-op) |
lut |
async (value: int) |
LUT 校准:0x01-0f 红、0x10-f0 黑 |
wifi |
async (ssid, password, city="") |
WiFi 透传(⚠ 本固件 no-op) |
raw |
async (data: bytes, channel="rxtx") |
高级直发;channel=rxtx/epd/alt(alt=331f) |
激活与固件
| 方法 |
签名 |
说明 |
activate |
async (code_hex: str) |
下发激活码(6 字节 hex) |
activate_auto |
async () -> dict |
离线激活:EFEF→反解 MAC→keygen→下发;返回 {device_id, mac, code} |
get_device_id |
async () -> str |
14 hex 设备 ID |
ota |
async (image: bytes, on_progress=None) -> dict |
SUOTA 升级(高危,需调用方先完成授权);⚠ 裸布局设备止于产品头门禁(docs/firmware-layout.md) |
子包速查
| 模块 |
关键导出 |
ppclock.protocol |
GATT UUID 常量、全部帧构造函数、keygen_code/recover_mac_from_device_id(纯函数) |
ppclock.image_pipeline |
process_image/adjust_pixels/dither_pixels/pack_plane、ALGORITHMS |
ppclock.templates |
render_template(name, payload) |
ppclock.transports.base |
Transport 协议(自定义传输实现规范)、TransportError |
ppclock.transports.local |
BLETransport、scan |
ppclock.transports.bridge |
BridgeTransport、scan、parse_via、BridgeError |
ppclock.firmware.image |
parse_image/unpack_body/pack_image('pQ' 镜像) |
ppclock.firmware.ota |
run_ota/package_image/xor_checksum/STATUS_ERRORS |
ppclock.bridge_server |
run()(ppclock-bridge 入口) |
ppclock.mcp_server |
main()(ppclock-mcp 入口,stdio/HTTP 双模)、build_server、TokenAuthMiddleware |
ppclock.device_manager |
DeviceManager(方案 C:按需连接+空闲保持、串行、重连重试一次) |
ppclock.mcp_tools |
register_tools(13 工具注册)、decode_image_source |
Bridge RPC 协议(v1,JSONL/TCP,默认 8971)
请求 {"id":N,"op":...} → 响应 {"id":N,"ok":bool,"data":...,"error":...};OTA 期间穿插 {"event":"ota_stage|ota_block_sent|ota_progress",...}。
ops:ping / scan{timeout} / connect{address,timeout,subscribe} / write{char,data,response} / read{char} / request_device_id{timeout} / ota{image,gpio_map?,max_blocks?} / services / close
char 映射:epd=图像通道、rxtx=1f1f(遗留)、alt=331f(活命令通道)、dis_model/dis_fw、spota_*(SUOTA 五写两读)。
不变量(使用约束)
- 命令写一律走 331f(alt);1f1f 仅 ATT-ACK 不执行(实机证据)。
- 图像块 244B(
03|04+ff|00+2B BE 偏移),整图结束 01、小图结束 AA。
- 时间/日期中「十进制直拼」字段为 BCD(休眠小时、倒计时月日),
dd 帧内为真 hex——勿混。
- 离线:除 BLE/LAN bridge 外无任何网络依赖。