# ClawPuter 🦞
[English](README.md)
M5Stack Cardputer (ESP32-S3) 上的像素风桌面伴侣。小龙虾角色 + 动画 + 实时天气 + AI 聊天 + 语音输入/TTS + macOS 桌面宠物同步。
## 为什么叫 "ClawPuter"?
有天下午去朋友的办公室,聊起了 [OpenClaw](https://github.com/openclaw),我也提到最近对硬件比较感兴趣。刚好朋友手边有一台 M5Stack **Cardputer**,就借给我玩。那个下午,一个想法就成型了:能不能把 OpenClaw 这样的数字生命,以更具身的形式呈现出来?Cardputer 是一个完美的载体。于是把两个名字拼在了一起:**Claw**(来自 OpenClaw)+ Card**puter** = **ClawPuter**。
## 功能
- **伴侣模式** — 像素小龙虾,支持待机、开心、睡觉、说话、伸懒腰、东张西望等动画。键盘方向键移动(按住持续走)。时光倒流天空(向左走=过去,向右走=未来)。NTP 时钟显示。
- **实时天气** — 每 15 分钟从 Open-Meteo 获取天气数据(免费,无需 API Key)。根据天气类型显示雨滴、雪花、雾气、雷电闪光等背景特效。宠物自动佩戴天气配饰(墨镜、雨伞、雪帽、口罩)。时钟旁显示实时温度。
- **天气模拟** — Fn+W 切换模拟模式,数字键 1-8 预览全部 8 种天气类型(晴天、多云、阴天、雾、小雨、大雨、雪、雷暴)。
- **聊天模式** — 键盘输入,AI 对话支持 SSE 流式响应(逐字显示),消息自动换行和翻页滚动。
- **像素画生成** — `/draw a cat` 生成 8x8 AI 像素画,渲染为 96x96 彩色网格嵌入聊天。`/draw16` 生成 16x16。16 色固定调色板,自动同步到 Mac 桌面。
- **语音输入** — 按住 Fn 键说话(最长 3 秒),松开后通过 Groq Whisper API 语音转文字,识别结果自动填入输入栏。
- **TTS 语音回复** — AI 回复通过扬声器朗读。按任意键可中断播放。麦克风和扬声器共享 GPIO 43,系统自动切换。
- **桌面宠物同步** — macOS 端桌面宠物应用,通过 UDP 接收小龙虾状态、位置和天气信息,实时同步动画。支持跟随模式(跟踪光标)和场景模式(天气面板)。
- **桌面双向控制** — Mac ↔ ESP32 双向通信。远程触发动画、发送文字/消息到 Cardputer、转发通知为 Toast 叠加层、查看同步聊天历史、弹窗展示高清像素画。宠物在 Chat Viewer 打开时自动停靠在窗口顶部。
- **OpenClaw 集成** — 局域网连接本地 OpenClaw Gateway。多模型自动切换(Kimi/Claude/GPT/Gemini),持久记忆,5400+ 社区技能。
- **双 WiFi + 离线模式** — 主 WiFi 连不上自动尝试备用(手机热点),Gateway IP 自动切换。所有 WiFi 都失败可进入离线模式(伴侣模式正常可用,聊天显示离线提示)。
- **运行时配置** — Setup 向导支持运行时修改 WiFi、Gateway、STT Host,编译时值作为默认,Fn+R 重置。
- **开机动画** — 小龙虾像素画逐行渐入,模式切换像素擦除过渡。
- **音效** — 按键咔嗒、开心音阶、AI 流式回复打字音、通知提示音。
## 快速开始
### 1. 设置环境变量
```bash
# WiFi
export WIFI_SSID=""
export WIFI_PASS=""
# AI 后端(OpenClaw Gateway)
export OPENCLAW_HOST="" # OpenClaw Gateway 局域网 IP
export OPENCLAW_PORT="" # Gateway 端口
export OPENCLAW_TOKEN=""
# 语音输入(可选,供 stt_proxy.py 使用)
export GROQ_API_KEY="" # 供 tools/stt_proxy.py 使用,非固件
export STT_PROXY_HOST="" # 运行 stt_proxy.py 的机器 IP
export STT_PROXY_PORT="8090" # STT 代理端口(默认 8090)
# 天气(可选)
export DEFAULT_CITY="Beijing" # 天气查询城市
# 备用 WiFi(可选,手机热点降级)
export WIFI_SSID2=""
export WIFI_PASS2=""
export OPENCLAW_HOST2="" # 热点网络上 Mac 的 IP
```
### 2. 编译烧录
```bash
pio run -t upload
```
首次烧录需要手动进入下载模式:按住 **G0** + 按 **Reset**,然后松开 G0。详见[烧录指南](docs/setup-and-flash.md)。
### 3. 启动 STT 代理(语音输入)
```bash
python3 tools/stt_proxy.py
```
代理运行在 Mac/PC 上,将 Cardputer 录制的音频转发到 Groq Whisper API 进行语音识别。需要在 `.env` 或环境变量中配置 `GROQ_API_KEY`。
### 4. 串口调试
```bash
pio device monitor
```
## 操作方式
| 按键 | 伴侣模式 | 聊天模式 |
|------|---------|---------|
| TAB | 切换到聊天 | 切换到伴侣 |
| `,`(按住) | 向左移动 | — |
| `/`(按住) | 向右移动 | — |
| `;`(按住) | 向上移动 | — |
| `.`(按住) | 向下移动 | — |
| 空格 / Enter | 角色开心跳跃 | 发送消息 |
| Backspace | — | 删除字符 |
| Fn(长按) | — | 按住说话,松开转文字 |
| Fn + ; | — | 向上翻页 |
| Fn + / | — | 向下翻页 |
| Fn + W | 切换天气模拟 | — |
| 1-8(天气模拟中) | 切换天气类型 | — |
| Fn + R | 重置配置 + Setup 向导 | — |
| 任意键(睡眠中) | 唤醒角色 | — |
| 任意键(TTS 播放中) | — | 中断语音播放 |
| TAB(Setup 中) | 退出向导,进入伴侣模式 | — |
## 玩法详解
### 伴侣模式 — 你的像素宠物
小龙虾生活在 240×135 像素的屏幕上,背景会随时间和天气动态变化:
- **日夜循环** — 天空颜色根据 NTP 实时时间变化。白天蓝天白云,17-19 点橙色夕阳,19 点后深色夜空配闪烁星星和月亮。
- **时光倒流天空** — 向左/右移动宠物会让天空偏移 ±12 小时。走到最左边看昨晚的星空,走到最右边看明天的日出。底部时钟始终显示真实时间。
- **自发动作** — 宠物每 8-15 秒随机伸懒腰或东张西望。30 秒无互动后自动入睡,显示 "Zzz" 动画。按任意键唤醒。
- **键盘移动** — 按住 `,` `/` `;` `.` 持续走动,精灵自动翻转朝向。
- **互动** — 按空格或 Enter 让宠物开心跳跃,配欢快音效。
### 天气系统
- **自动刷新**:每 15 分钟从 Open-Meteo 获取天气数据(免费,不需要 API Key),根据 `DEFAULT_CITY` 配置自动定位。
- **背景特效**:雨滴下落、雪花飘飞(带横向漂移)、雾气点阵闪烁、雷暴白色闪光。天空色调随天气变暗。
- **宠物配饰**:晴天/多云戴墨镜 🕶️、雨天/雷暴撑雨伞 ☂️、下雪戴红色雪帽 🎅、雾天/阴天戴口罩 😷。配饰随精灵左右翻转。
- **温度显示**:时钟旁显示当前温度(°),用竖线分隔。
- **模拟模式**:Fn+W 进入天气模拟,用数字键 1-8 切换 8 种天气:1=晴天 2=多云 3=阴天 4=雾 5=小雨 6=大雨 7=雪 8=雷暴。底部显示 `[SIM] 天气名称` 状态栏。再按 Fn+W 退出。
### 聊天模式 — AI 对话
- 键盘输入消息,Enter 发送。AI 回复逐字流式显示,配打字音效。
- **像素画**:输入 `/draw a cat` 生成 8x8 像素画,或 `/draw16 a heart` 生成 16x16。AI 返回十六进制编码的像素数据,渲染为 96x96 彩色网格嵌入聊天消息。16 色固定调色板,解析失败自动降级为普通文字。
- **语音输入**:按住 Fn 录音(最长 3 秒),松开后发送到 Groq Whisper 转文字。转写过程中显示 "Transcribing..." 进度条。
- **TTS 语音回复**:AI 回复完成后,通过扬声器朗读回复内容。按任意键可中断播放。
- **离线模式**:未连接 WiFi 时,发送消息显示 `[Offline] No network connection`。
### 桌面宠物同步与双向控制
macOS Swift 应用(`desktop/CardputerDesktopPet/`)通过局域网与 Cardputer 双向通信。
**ESP32 → Mac(UDP 19820):**
- 宠物状态、位置、天气 5Hz 广播同步
- 像素画生成后自动弹出 256x256 高清窗口,支持历史浏览
- 聊天消息实时同步到 Chat Viewer 窗口
**Mac → ESP32(UDP 19822):**
- **触发动画**:开心、待机、睡觉、说话 — 从菜单栏 Control 子菜单触发
- **发送文字**:在 Mac 输入,出现在 Cardputer 聊天输入框
- **发送消息**:输入并自动发送(相当于按 Enter)
- **转发通知**:发送 Toast 叠加层(应用名、标题、内容),Cardputer 屏幕顶部显示 3 秒
- **请求聊天历史**:拉取完整对话记录
**显示模式:**
- **跟随模式**(默认):透明精灵跟随光标,天气配饰同步。Chat Viewer 打开时宠物自动停靠在窗口顶部。
- **场景模式**:菜单栏下方 360x200 像素天气场景面板。
- 从菜单栏下拉菜单切换模式。
**构建桌面应用:**
```bash
cd desktop/CardputerDesktopPet && ./run.sh
```
自动编译 Swift 应用、打包为 `.app` bundle(含 `Info.plist`,macOS 本地网络权限所需)、Ad-hoc 签名、通过 `open` 启动。
### 联网与配置
- **双 WiFi**:主 WiFi 连不上 → 自动尝试备用 WiFi(如手机热点),Gateway IP 自动切换。
- **离线模式**:所有 WiFi 失败后,按 Tab 进入离线伴侣模式(动画、时钟、音效照常工作)。
- **运行时配置**:Fn+R 打开 Setup 向导,可修改 WiFi SSID/密码、Gateway 地址/端口/Token、STT Host,无需重新烧录。
- **WiFi 失败菜单**:连接失败后提供三个选项——重试 / Setup 向导 / 离线模式。
## 项目结构
```
src/
├── main.cpp # 入口,模式调度,WiFi/NTP
├── companion.h/cpp # 伴侣模式:动画、状态机、时钟、天气特效
├── chat.h/cpp # 聊天模式:消息气泡、输入栏、滚动、像素画渲染
├── ai_client.h/cpp # AI 客户端(OpenClaw/Claude),SSE 流式响应,/draw prompt 路由
├── voice_input.h/cpp # 按键说话录音、WAV 编码、STT 代理客户端
├── tts_playback.h/cpp # TTS 语音回复,PCM 下载 + DMA 播放
├── weather_client.h/cpp # Open-Meteo 天气 API、地理编码、15 分钟自动刷新
├── state_broadcast.h/cpp # UDP 状态广播 + 一次性像素画/聊天消息同步
├── cmd_server.h/cpp # 命令服务器(TCP 19821 + UDP 19822),Mac→ESP32 控制
├── sprites.h # 像素小龙虾素材(RGB565)
├── config.h/cpp # WiFi/API 配置,NVS 持久化
└── utils.h # 颜色定义、屏幕常量、定时器
desktop/
└── CardputerDesktopPet/
├── Sources/
│ ├── main.swift # 入口
│ ├── AppDelegate.swift # 菜单栏、模式切换、控制命令、停靠逻辑
│ ├── UDPListener.swift # UDP 接收器,提取源 IP
│ ├── TCPSender.swift # UDP 命令发送(Mac→ESP32)
│ ├── PetBehavior.swift # 移动逻辑、跟随模式、停靠目标
│ ├── PetWindow.swift # 透明宠物精灵窗口
│ ├── SceneWindow.swift # 天气场景面板
│ ├── PixelArtPopover.swift # 浮动 256x256 像素画展示
│ └── ChatViewerWindow.swift # 聊天历史查看器 + 远程发送
├── Info.plist # 应用 bundle 元数据 + 网络权限
└── run.sh # 编译、打包、签名、启动脚本
tools/
└── stt_proxy.py # 本地 HTTP 代理:ESP32 音频 → Groq Whisper API + TTS
```
## iPhone 热点小贴士
使用 iPhone 热点作为备用 WiFi 时:
1. **开启"最大化兼容性"** — 进入设置 > 个人热点,打开此选项。iPhone 默认 5GHz,ESP32 只支持 2.4GHz。
2. **保持热点设置页面打开** — iPhone 热点无设备连接时进入休眠,ESP32 扫描不到。需在 iPhone 上打开"个人热点"设置页面保持唤醒。
3. **UDP 广播被隔离** — iPhone 热点有客户端隔离,设备间 UDP 广播被过滤。固件已做绕过:同时发 broadcast + unicast 到 Gateway IP。
4. **查看 Mac 的热点 IP** — Mac 连上 iPhone 热点后,用 `ifconfig en0` 查看 IP(通常是 `172.20.10.x`),设为 `OPENCLAW_HOST2`。
## 硬件
- **M5Stack Cardputer** — ESP32-S3,240×135 IPS 屏幕,56 键键盘,PDM 麦克风(SPM1423),扬声器(与麦克风共享 GPIO 43)
- ESP32-S3 **仅支持 2.4GHz WiFi**(不支持 5GHz)
## OpenClaw 配置
本项目连接运行在 Mac 或 VPS 上的 OpenClaw Gateway:
1. [安装 OpenClaw](https://openclaw.ai)
2. 在 `~/.openclaw/openclaw.json` 中启用局域网绑定和 HTTP API:
```json
{
"gateway": {
"bind": "lan",
"http": {
"endpoints": {
"chatCompletions": { "enabled": true }
}
}
}
}
```
3. 重启 Gateway:`openclaw gateway restart`
4. 将 `OPENCLAW_HOST` 设为 Mac 的局域网 IP
完整集成方案见 [OpenClaw 调研文档](docs/openclaw-research.md)。
## 文档
- [环境搭建与烧录](docs/setup-and-flash.md)
- [硬件要点](docs/hardware-notes.md)
- [API 接入记录](docs/api-integration.md)
- [代码架构](docs/architecture.md)
- [OpenClaw 集成](docs/openclaw-research.md)
- [语音输入设计](docs/voice-input-design.md)
- [桌面宠物设计](docs/desktop-pet-design.md)
- [UDP 状态同步设计](docs/udp-state-sync-design.md)
- [像素画设计](docs/pixel-art-design.md)
- [桌面双向通信设计](docs/desktop-bidirectional-design.md)
- [ESP32 内存踩坑记录](docs/esp32-voice-chat-lessons.md)
- [问题排查](docs/troubleshooting.md)
- [路线图](docs/roadmap.md)
## 路线图
- [x] 流式响应(SSE 逐字显示)
- [x] 语音输入(按住说话 + Groq Whisper 语音转文字)
- [x] 桌面宠物同步(macOS 端通过 UDP 同步)
- [x] 双 WiFi + 离线模式 + 运行时配置
- [x] TTS 语音回复(AI 通过扬声器播放回复)
- [x] 宠物移动 + 时光倒流天空 + 桌面位置同步
- [x] 实时天气(Open-Meteo API + 背景特效 + 宠物配饰)
- [x] 天气模拟模式(Fn+W + 1-8 预览全部天气类型)
- [x] 像素画生成(/draw 命令,支持 8x8 和 16x16)
- [x] 桌面双向控制(Mac ↔ ESP32 命令、聊天同步、像素画同步、通知转发)
- [ ] 电量显示 + 低电量角色变虚弱
- [ ] 聊天历史持久化(NVS/SD 卡)
- [ ] 养成系统(饥饿值/心情值 + 洗澡/喂食等互动)
- [ ] 番茄钟
- [ ] BLE 手机通知推送
- [ ] 像素美术升级(星露谷风格,专业画师优化角色/背景/道具)
- [ ] 长语音 TTS 支持(服务端切片缓存或 SD 卡流式播放)
- [ ] M5Burner 固件发布(社区用户一键烧录)
完整路线图见 [roadmap.md](docs/roadmap.md)。
## 许可证
MIT