拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

claude-desktop-buddy BLE 无线协议深度解析:Nordic UART Service 与换行分隔 JSON 完整参考

claude-desktop-buddy BLE 无线协议深度解析:Nordic UART Service 与换行分隔 JSON 完整参考

claude-desktop-buddy BLE 无线协议深度解析:Nordic UART Service 与换行分隔 JSON 完整参考

【免费下载链接】claude-desktop-buddyReference and an example for the Bluetooth API for makers in Claude Cowork & Claude Code Desktop项目地址: https://gitcode.com/gh_mirrors/cl/claude-desktop-buddy

claude-desktop-buddy 是 Claude 桌面应用(Claude Cowork / Claude Code Desktop)面向硬件创客的 BLE 参考项目:它把会话状态、权限审批请求通过BLE Nordic UART Service(NUS)以换行分隔的 JSON推送到 ESP32 桌面宠物(M5StickC Plus),并支持在设备上一键批准/拒绝工具调用。本文完整拆解这套无线协议——UUID、心跳快照、权限回传、命令应答与文件夹无线推送——帮你用最少的代码让任意 BLE 设备接上 Claude。

协议概览:3 个 UUID 定义一切

设备侧不需要本项目中的任何代码,只要满足两个条件即可接入:

  1. 广播Nordic UART Service(业界事实标准的"BLE 串口");
  2. 能解析换行分隔 JSON(一个对象一行,\n结尾)。

Arduino、ESP32、nRF52,甚至树莓派加一块 BLE 蓝牙模块都能实现。

Nordic UART Service 核心 UUID 对照表

角色UUID
Service6e400001-b5a3-f393-e0a9-e50e24dcca9e
RX(桌面 → 设备,Write)6e400002-b5a3-f393-e0a9-e50e24dcca9e
TX(设备 → 桌面,Notify)6e400003-b5a3-f393-e0a9-e50e24dcca9e

设备命名技巧:广播名必须以Claude开头,桌面端的设备选择器会按此前缀过滤;再追加 BT MAC 的几字节,多台设备就不会混在一起。

连接与配对:硬件伴侣(Hardware Buddy)使用步骤

BLE 桥默认关闭,需要开发者模式:

  1. Help → Troubleshooting → Enable Developer Mode(菜单栏会多出 Developer 菜单);
  2. Developer → Open Hardware Buddy…打开配对窗口;
  3. 点击Connect,从扫描列表选中设备,首次连接授权 macOS 的蓝牙权限。

配对完成后桥会自动重连,窗口只用于初始配对、查看状态面板或拖拽推送文件夹。

传输层细节:MTU 分片与行重组

线上跑的一切都是UTF-8 编码的 JSON——每行一个对象,\n结尾。两个方向都要处理碎片:

  • 桌面 → 设备:Notify 会在 MTU 边界处把一行切成多包,设备端必须累积字节直到遇到\n再解析;
  • 设备 → 桌面:桌面端会自动重组多包行,你只管按字节发,回复由桥按协商 MTU 自动分片(见 src/ble_bridge.h 中的 NUS 注释说明)。

参考实现在 src/ble_bridge.cpp(行缓冲收发)和 src/data.h(JSON 解析入口_applyJson)。

心跳快照:桌面端主动推送的核心消息

桌面端在状态变化时发送快照,并每 10 秒发一次保活:

{ "total": 3, "running": 1, "waiting": 1, "msg": "approve: Bash", "entries": ["10:42 git push", "10:41 yarn test"], "tokens": 184502, "tokens_today": 31200, "prompt": { "id": "req_abc123", "tool": "Bash", "hint": "rm -rf /tmp/foo" } }
字段含义
total/running/waiting全部会话数 / 正在生成 / 被权限提示阻塞
msg适合小屏幕展示的一行摘要
entries最近的转录行,新的在前
tokens/tokens_today会话启动以来的累计 token / 今日 token(跨重启持久化,本地午夜归零)
prompt仅在需要权限决策时出现,其id是回传时要原样带回的凭证

实用派生信号:running > 0表示有会话在跑;waiting > 0表示有权限提示在等;total == 0表示空闲。约 30 秒收不到快照就应视为连接已断(参考实现里dataConnected()正是 30 秒阈值,见 src/data.h)。

回合事件与权限审批回传

每个回合完成会额外触发一条一次性事件,携带原始 SDK 内容数组(文本块、工具调用等)。超过 4KB(按 UTF-8 字节计)的事件会被丢弃:

{ "evt": "turn", "role": "assistant", "content": [{ "type": "text", "text": "..." }] }

从设备端批准或拒绝工具调用

当心跳里出现prompt时,设备通过 TX 特征发回一条即可:

{"cmd":"permission","id":"req_abc123","decision":"once"} {"cmd":"permission","id":"req_abc123","decision":"deny"}

id必须与prompt.id完全一致;"once"批准本次工具调用,"deny"拒绝。桌面端会把决定转发给会话管理器——这就是"桌上小宠物帮你点批准"的原理。

连接时的一次性消息

消息说明
{ "time": [1775731234, -25200] }时间同步:epoch 秒 + 时区偏移(秒),设备据此校准 RTC
{ "cmd": "owner", "name": "Felix" }用户账户名(名),可显示在屏幕上

命令与应答(ack)协议

桌面端每发一条带cmd的命令,都期望一条对应的 ack:

{ "ack": "<与cmd相同>", "ok": true, "n": 0 }

ok:false时可附带error:"...";n是通用计数器(如 chunk 应答里的已写字节数)。

命令用途你应回传的 ack
{"cmd":"status"}桌面端每几秒轮询一次,填充 Hardware Buddy 状态面板见下方状态响应
{"cmd":"name","name":"Clawd"}设置设备显示名{"ack":"name","ok":true}
{"cmd":"owner","name":"Felix"}设置用户名{"ack":"owner","ok":true}
{"cmd":"unpair"}清除已存绑定(用户点"忘记"时触发){"ack":"unpair","ok":true}

状态响应示例(没有的字段可以直接省略):

{ "ack": "status", "ok": true, "data": { "name": "Clawd", "sec": true, "bat": { "pct": 87, "mV": 4012, "mA": -120, "usb": true }, "sys": { "up": 8412, "heap": 84200 }, "stats": { "appr": 42, "deny": 3, "vel": 8, "nap": 12, "lvl": 5 } } }

bat.mA为负值表示正在充电;sec: true表示链路已加密(下一节详述)。

文件夹推送:BLE 无线文件传输

Hardware Buddy 窗口里有个拖放区:把一个文件夹拖进去,其扁平内容会被流式推送到设备。传输层与内容无关——GIF、配置、固件镜像都行,总量需在 1.8MB 以内。

桌面: {"cmd":"char_begin","name":"bufo","total":184320} 设备: {"ack":"char_begin","ok":true} 桌面: {"cmd":"file","path":"manifest.json","size":412} 设备: {"ack":"file","ok":true} 桌面: {"cmd":"chunk","d":"<base64>"} → 设备逐块 ack,n=已写字节 桌面: {"cmd":"file_end"} → 设备 ack,n=最终大小 (每个文件重复 file/chunk/file_end …) 桌面: {"cmd":"char_end"} → 设备: {"ack":"char_end","ok":true}

几个关键规则:

  • 桌面端发送文件夹内所有普通文件(不递归、跳过隐藏文件),每块 base64 编码,收到 ack 才发下一块——协议是顺序的,无需整文件缓存;
  • char_begin.name取文件夹名,若文件夹内有manifest.json且带"name"字段则以后者为准;
  • 不想收文件?不 ackchar_begin即可,桌面端几秒超时后告知用户失败;
  • 安全提醒:写入前务必校验file.path,拒绝..与绝对路径。设备端参考实现在 src/xfer.h。

角色包格式可参考示例 characters/bufo/manifest.json,离线烧录可用 tools/flash_character.py 走 USB 绕过 BLE 往返。

安全配对:LE Secure Connections 绑定

转录片段和工具调用提示都会走这条链路——不加密的设备在无线电范围内可被廉价 nRF 嗅探棒直接嗅出。推荐做法:

  • NUS 特征(及 TX CCCD)标记为仅加密,广播 DisplayOnly IO 能力;
  • 首次 GATT 访问触发系统配对,桌面端提示用户输入设备显示的6 位 passkey,此后链路 AES-CCM 加密,重连复用 LTK 无需再提示;
  • 链路加密后在 status ack 中带"sec": true;收到{"cmd":"unpair"}时清除本地绑定。

设备端实现见 src/ble_bridge.h 中的bleSecure()/blePasskey()/bleClearBonds()三个接口。

小结与参考入口

整套协议可以浓缩为一句话:NUS 三 UUID + 每行一个 JSON + 10 秒保活 + 30 秒判死 + 命令必须 ack。想动手实现前,建议按这个顺序阅读:

  • 协议权威定义:REFERENCE.md
  • BLE 桥实现:src/ble_bridge.cpp、src/ble_bridge.h
  • 快照解析与状态机:src/data.h、src/stats.h
  • 文件推送接收端:src/xfer.h
  • 工程配置(ESP32 + Arduino + LittleFS):platformio.ini

⚠️ 该 BLE API 仅在桌面应用开启开发者模式时可用,面向创客与开发者,不属于官方支持的产品功能。

【免费下载链接】claude-desktop-buddyReference and an example for the Bluetooth API for makers in Claude Cowork & Claude Code Desktop项目地址: https://gitcode.com/gh_mirrors/cl/claude-desktop-buddy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表