# NDJSON 协议 1 UTF-8 中的 ASCII 扁平 JSON,一行一帧,以 LF 结束,JSON 本体最多 512 字节。固件解析器不接受嵌套、转义、重复/未知字段、负数、小数、控制字符或尾随内容。request_id 为 A-Z/a-z/0-9/下划线/点/冒号/短横线,1~64 字符;session_id 同字符集,1~48 字符。 ## 启动与心跳 启动输出 state;先读取 session_id 和 uptime_ms。输入未知默认禁止开锁。可信上位机每秒发送一次当前 session 心跳,状态轮询至少每秒一次。 ```json {"type":"state"} {"type":"heartbeat","session_id":"CURRENT_BOOT_SESSION"} ``` 设备 ack code 为 heartbeat_ok 或 session_mismatch。只收到心跳 ack 不代表门状态已刷新。Pico 每秒报告 state,主机通过显式 state 请求读取。 ## 开门命令 ```json {"type":"open","request_id":"req-001","session_id":"CURRENT_BOOT_SESSION","door_id":1,"pulse_ms":300,"issued_at_ms":1000,"ttl_ms":3000} ``` issued_at_ms 必须使用**本次启动的设备 uptime**,不能使用电脑 Unix 时间;示例 1000 需替换为最新状态值。door_id=1~8、pulse_ms=100~1000、ttl_ms=1~5000。收到时 `now-issued_at_ms >= ttl_ms` 即过期,未来时间拒绝。旧状态值叠加传输延迟可能耗尽有效期,应先刷新状态。 常见 code:accepted、duplicate、expired、session_mismatch、heartbeat_required、door_not_secure、busy、driver_rearming、fault、range_error、future_command。acceptance 只代表接受请求,不能扣库存、确认投递或收款。 接受过的 request_id 在最大 5s 窗口去重,64 个固定槽;拒绝请求不挤占接受记录。超过有效期重发旧命令得到 expired。该缓存不承诺永久业务去重,业务端另用持久化 Idempotency-Key 防止重放。 ## 设备状态 ```json {"type":"state","protocol":1,"platform":"host_sim","session_id":"CURRENT_BOOT_SESSION","uptime_ms":1000,"event_seq":2,"state":"idle","active_door":0,"output_mask":0,"door_closed_mask":255,"latch_locked_mask":255,"inputs_valid":true,"power_ok":true,"heartbeat_ok":true,"fault":"none","driver_ready":true} ``` 掩码 bit0 对应门 1,bit7 对应门 8;door_closed_mask/latch_locked_mask 的 1 表示已经去抖确认。必须结合 inputs_valid,不得把无效输入的旧掩码当有效证据。active_door 在 pulsing/wait_open 阶段可非零而门仍关闭;不能据此捏造开门。state=idle/pulsing/wait_open/wait_close/fault。即使 output_mask 归零,也需完成实际门循环才能完成业务。 ## 事件与 ACK ```json {"type":"event","session_id":"CURRENT_BOOT_SESSION","event_seq":3,"uptime_ms":1010,"code":"open_accepted","request_id":"req-001","door_id":1} {"type":"ack","session_id":"CURRENT_BOOT_SESSION","event_seq":3,"uptime_ms":1010,"code":"accepted","request_id":"req-001","door_id":1} ``` event_seq 只在固件事件发生时递增;同 seq、较新 uptime 的 state 是合法状态刷新,不能全部丢弃。相同 seq 和 uptime 的重复帧不能延长后台 freshness;同 session 的倒退 seq/uptime 被拒绝。新启动 session 使后台未完成流程进入异常隔离。 事件包括 boot、inputs_ready、door_open/door_closed、latch_unlocked/latch_locked、pulse_complete、cycle_complete、door_held_open 及具体故障。ACK 与事件可能共享序号,接收端需去重。故障通常还有 state 报告;平台只接受与当前命令匹配的 event/ack 到 /device/event,无命令的 boot/输入事件通过 state 同步。 ## 故障恢复与主机注入 ```json {"type":"clear_fault","session_id":"CURRENT_BOOT_SESSION"} {"type":"sim_inputs","door_closed_mask":255,"latch_locked_mask":255,"valid":1} ``` clear_fault 要求当前身份、心跳、全部门闭合且锁止;clock_regressed 与 event_seq_exhausted 不允许普通清除。clear_fault 不完成后台异常工单或恢复库存,后台仍需人工实物核对流程。 sim_inputs 仅允许主机以 --allow-sim-inputs 启动时使用;Pico 拒绝该命令。它没有占用或商品识别字段,业务联调用单独的软件 sidecar 标明占用来源。当前协议不加密、不认证,不适合直接接入公共网络。 ## V0.2 目标扩展 Pico state 另含 p24_adc(4次采样平均原始ADC)、fw="0.2.0"、hw="0.2"、transport="usb_cdc" 或 "uart0"。driver_ready=false 时拒绝新请求;至少1300ms硬件窗口再触发等待独立于门关/清故障。开锁还要求受保护24V读数在候选许可范围,USB单供电不满足。