
claude-desktop-buddy 内部是怎么工作的状态机、ble_bridge 与 xfer 文件夹推送架构走读【免费下载链接】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-buddyclaude-desktop-buddy 是一个跑在 ESP32 上的开源桌面电子宠物固件通过BLE 蓝牙连接 Claude 桌面应用把会话状态、审批提示实时显示在设备屏幕上还能在设备上直接批准或拒绝操作。本文带你完整走读它内部的三大核心架构src/main.cpp 里的七状态机、src/ble_bridge.cpp 蓝牙数据桥以及 src/xfer.h 的文件夹推送协议帮你快速看懂这个项目是怎么运转的。项目全貌一只吃审批的电子宠物 这个项目的硬件形态是一块 M5StickC PlusESP32 彩色屏 IMU 按键固件用 Arduino 框架开发通过 platformio.ini 配置构建它的工作方式非常养宠没连接 Claude 时→ 睡觉闭眼、慢呼吸有会话在跑时→ 忙碌擦汗打工有待审批的操作时→ 警觉LED 闪烁提醒你你在设备上点了批准后→ 撒花庆祝每消耗 5 万 token 升一级→ 放彩带整个设备本质上是 Claude 桌面端的一个蓝牙外设桌面上的 Hardware Buddy 窗口负责配对和监控设备负责显示和按键交互。配对入口在 Claude 的菜单里需先开启开发者模式第一层ble_bridge —— 用 Nordic UART 服务当串口设备与桌面通信走的是BLE Nordic UART ServiceNUS这是蓝牙上的虚拟串口事实标准。src/ble_bridge.h 的注释直接写明了三个关键 UUID服务 / 写 / 通知任何支持 NUS 的设备Arduino、nRF52、树莓派都能接入。设计上有几个值得学习的点行缓冲协议。线上所有数据都是 UTF-8 的 JSON一个对象一行以\n结尾。BLE 通知会在 MTU 边界被切碎所以设备端不直接解析包而是逐字节攒到换行符才解析——src/data.h 里的_LineBuf就是这个行缓冲USB 和 BLE 各挂一条共用同一个_applyJson解析入口。统一收发接口。src/ble_bridge.h 只暴露了bleInit / bleWrite / bleRead / bleAvailable这几个函数对上层来说它就是一个带连接的串口。安全配对。NUS 特性被标记为仅加密可访问首次 GATT 访问会触发操作系统级配对设备屏幕显示 6 位 passkey之后链路走 AES 加密。数据到达后的处理逻辑在 src/data.h 的_applyJson中先检查是否带cmd字段有则交给 xfer 处理否则按心跳快照解析填充会话数、消息、token 数、审批提示等字段到一个全局的TamaState结构体里。它还实现了简单的三种数据模式src/data.h模式触发条件行为demo菜单开启演示每 8 秒自动切换 5 个假场景live10 秒内收到过 JSON使用实时数据asleep无数据归零显示No Claude connected超过 30 秒没收到快照dataConnected()就判定连接断开宠物随之睡着。第二层状态机 —— 7 个 PersonaState 驱动一切动画核心状态机非常简洁。src/main.cpp 定义了 7 个状态枚举sleep / idle / busy / attention / celebrate / dizzy / heart状态分两层这是整个状态机最巧妙的设计src/main.cppbaseState基础状态每轮loop()都由纯函数derive()从TamaState推导出来activeState当前状态实际渲染的状态平时跟随基础状态但可被一次性事件临时抢占derive()的判定只有 4 条规则按优先级从高到低src/main.cpp没连接 → idle 有等待审批 → attention 刚完成会话 → celebrate ≥3 个会话在跑 → busy 其他 → idle而triggerOneShot(状态, 时长)src/main.cpp负责临时抢占摇一摇设备触发dizzy2 秒、快速批准5 秒内触发heart2 秒、升级触发celebrate3 秒。到期后自动落回基础状态——这样撒花不会掩盖等待审批的紧急提示因为derive()里attention的优先级最高。每轮loop()的完整节拍src/main.cpp就是dataPoll()从 USB/BLE 读入最新 JSONderive()推导基础状态一次性事件未到期则维持审批提示到来时蜂鸣器叫一声、强制切到审批界面按按键A 批准B 拒绝长按 A 菜单7 个状态 × 18 个 ASCII 物种src/buddies/ 每种动物一个文件加上可选的 GIF 模式动画渲染就完全被状态机驱动了。第三层xfer —— 把整个文件夹流式推到设备最硬核的部分是 src/xfer.h 的文件夹推送协议把 Hardware Buddy 窗口里的拖拽文件夹一个 GIF 角色包上限 1.8MB通过 BLE 分块传到设备文件系统。完整握手流程在 REFERENCE.md 有权威定义char_begin → 设备检查空间、清旧角色、建目录回 ack file → 设备打开 /characters/名字/路径回 ack chunk → base64 分块写入每块都回 ack file_end → 校验字节数、关文件回 ack char_end → 加载角色切到 GIF 模式几个工程细节非常值得借鉴先算账再动手char_begin时先计算清空旧角色后能腾出多少空间不够就直接回ok:false并附上缺多少 KB——不碰文件系统失败时当前角色完好无损src/xfer.h。每块都回 ack因为 LittleFS 写盘可能卡在闪存擦除上而 UART 接收缓冲只有约 256 字节不回 ack 发送端就会溢出丢数据src/xfer.h。ack 双路广播设备不追踪命令是从 USB 还是 BLE 来的_xAck同时写到两条流无连接的那条会自动丢弃。协议是纯文本 JSON桌面端等待每个 ack 才发下一块——串行 确认天然可靠不需要重传机制。xfer 顺带还承担了所有设备管理命令name宠物名、owner主人名、status状态面板轮询、unpair擦除配对都集中在同一个xferCommand()入口分发。周边模块与上手路径统计与升级src/stats.h 用 NVS 持久化审批数、响应速度环形缓冲和等级每 5 万 token 升一级——这就是celebrate状态的触发源。GIF 角色渲染src/character.cpp 负责解码 96px 宽的 GIF 并渲染角色包示例见 characters/bufo/manifest.json声明了 7 个状态对应的 GIF 文件。调试工具tools/test_xfer.py 可模拟桌面端走一遍文件夹推送协议tools/flash_character.py 则绕过 BLE直接把角色包写进 Flash 走 USB 烧录迭代动画时能省掉蓝牙往返。上手建议先读 REFERENCE.md协议规范再看 src/data.h数据入口→ src/main.cpp主循环与状态机→ src/xfer.h推送协议三层由内而外一天就能吃透整个架构。【免费下载链接】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),仅供参考