# ppclock SDK · API 参考(v0.2.0-beta) > 面向二次开发的签名级参考。协议细节见 `docs/protocol.md`,固件内部见 `docs/firmware-analysis.md`。MCP 服务器(ppclock-mcp)工具参考见 `docs/sdk/MCP.md`。 ## 安装与入口 ```bash pip install -e . # 依赖:bleak, pillow ppclock --help # CLI ppclock-bridge --host 0.0.0.0 --port 8971 # BLE 桥服务端 ``` ```python from ppclock import PPClient ``` ## PPClient(统一门面,async) ### 工厂与扫描 | 方法 | 签名 | 说明 | |---|---|---| | `via_local` | `(mac: str|None=None, timeout=10.0) -> PPClient` | 本机 BLE(bleak);mac 省略自动扫描 `NRF-` 前缀 | | `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)` | 对时;`tz=8` 为北京时(dt 缺省时生效) | | `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;`HM42_AIO_*` 会自动补齐双平面并使用厂商图像会话 | | `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 五写两读)。 ## 不变量(使用约束) 1. 命令写一律走 **331f(alt)**;1f1f 仅 ATT-ACK 不执行(实机证据)。 2. 图像块 244B(`03|04`+`ff|00`+2B BE 偏移),整图结束 `01`、小图结束 `AA`。 3. 时间/日期中「十进制直拼」字段为 BCD(休眠小时、倒计时月日),`dd` 帧内为真 hex——勿混。 4. 离线:除 BLE/LAN bridge 外无任何网络依赖。