🐷 小猪 Piggy

你的私人 AI 伴侣 · 基于 xiaozhi WebSocket 协议 · Echo Show 全屏显示
最后更新:2026-05-28 · 版本 v1.0(DeepSeek V4 Flash + 硅基流动 CosyVoice2 + 多 ASR 可选)

🎯 目标

把一台越狱的 Echo Show 5 变成会说话、有表情的 AI 伴侣:

🏗️ 架构总览

┌─ Echo Show 5 (LineageOS 18.1) ─────────────────────┐ │ Fully Kiosk Browser (€8.90 买断) │ │ ┌──────────────────────────────────────────────┐ │ │ │ https://piggy.treetree.tech (远程加载) │ │ │ │ ├─ 🐷 Lottie/CSS 动画角色 (小猪 Piggy) │ │ │ │ ├─ Porcupine WASM 唤醒词 (浏览器端) │ │ │ │ ├─ getUserMedia (麦克风采集) │ │ │ │ └─ Web Audio API (TTS 播放) │ │ │ └──────────────────────────────────────────────┘ │ │ Echo Show 上只装 LineageOS + Fully Kiosk,零代码 │ └───────────────────────┬──────────────────────────────┘ │ WebSocket (wss://) ▼ ┌─ Droplet ─────────────────────────────────────────────┐ │ │ │ Cloudflare Tunnel (http2, Tunnel ID: 8eb7a559...) │ │ └─ piggy.treetree.tech → http://127.0.0.1:80 │ │ │ │ Nginx (port 80) │ │ ├─ / → /var/www/piggy/ (前端静态文件) │ │ └─ /xiaozhi/v1/ → 127.0.0.1:8000 (WebSocket) │ │ │ │ Docker: bridge │ │ └─ xiaozhi-server (:8000 WS, :8003 HTTP) │ │ ├─ ASR (语音识别) │ │ ├─ LLM (大语言模型) │ │ └─ TTS (语音合成) │ │ │ │ Docker: bridge (hermes-net) │ │ ├─ hermes-agent (含 API 网关 :8642) │ │ └─ syncthing │ │ │ │ Docker: host 模式 │ │ └─ homeassistant (:8123) │ └────────────────────────────────────────────────────────┘ 核心链路:Echo Show → Cloudflare Tunnel → Nginx → xiaozhi-server → 自动获得 Hermes 的记忆系统 (hindsight)、工具、技能

📡 现有基础设施

服务器
2核 / 3.8GB
DigitalOcean Droplet,当前可用 ~1406MB
已有服务
Hermes + HA
各服务独立 Docker 网桥,域名 *.treetree.tech
域名
treetree.tech
Cloudflare Tunnel 暴露服务,Nginx 做 WebSocket 代理
Echo Show
待越狱
越狱教程已写好,需要 Windows + microUSB

🐷 角色方案

素材来源:Piggy Emoji Expressions Animation Pack(IconScout,20 个表情)

1. 购买和下载

  1. 打开 LottieFiles Marketplace 链接,登录 LottieFiles 账号
  2. 购买素材包(通常 $10-30,一次性)
  3. 下载后得到 20 个 .json 文件(Lottie 格式),每个文件是一个表情动画
  4. 也可以在 iconscout.com 单独购买某个表情

2. 表情 → 状态映射

将 20 个表情映射到 Piggy 的 8 个状态:

Piggy 状态触发条件对应表情(优先级从高到低)文件名建议
idle连接成功,等待输入Winking → Cute Laugh → Adorableidle.json(用 Winking)
listening用户开始说话Attitude → Surprisedlistening.json(用 Attitude)
thinking用户说完,等待 LLMThinking → Suspiciousthinking.json(用 Thinking)
speakingTTS 开始播放Laughing → Cute Laughspeaking.json(用 Laughing)
happyLLM emotion: happyIn Love → Gratitude → Greedyhappy.json(用 In Love)
sadLLM emotion: sadSad → Cryingsad.json(用 Sad)
angryLLM emotion: angryAngry → Angry Stareangry.json(用 Angry)
disconnectedWebSocket 断连Shocked → Dizzydisconnected.json(用 Shocked)

💡 每个状态只需要 1 个 JSON 文件。剩余 12 个表情可以留着做随机彩蛋(比如长时间 idle 切到 Sleeping)。

3. 上传到项目

# 下载的 JSON 文件重命名后放入 assets/lottie/
cp idle.json        /var/www/piggy/assets/lottie/
cp listening.json   /var/www/piggy/assets/lottie/
cp thinking.json    /var/www/piggy/assets/lottie/
cp speaking.json    /var/www/piggy/assets/lottie/
cp happy.json       /var/www/piggy/assets/lottie/
cp sad.json         /var/www/piggy/assets/lottie/
cp angry.json       /var/www/piggy/assets/lottie/
cp disconnected.json /var/www/piggy/assets/lottie/

# 提交到 git
cd /var/www/piggy
git add assets/lottie/
git commit -m "Add piggy Lottie expressions"
git push

4. 代码集成

在 index.html 中引入 Lottie Web:

<!-- index.html <head> 中添加 -->
<script src="lib/lottie.min.js"></script>

修改 piggy.js,用 Lottie 替换 CSS 动画:

class PiggyCharacter {
    constructor() {
        this.container = document.getElementById('piggy');
        this.anim = null;
        this.state = 'idle';
        this._loadAnimation('idle');
    }

    static ANIMATIONS = {
        idle:         '/assets/lottie/idle.json',
        listening:    '/assets/lottie/listening.json',
        thinking:     '/assets/lottie/thinking.json',
        speaking:     '/assets/lottie/speaking.json',
        happy:        '/assets/lottie/happy.json',
        sad:          '/assets/lottie/sad.json',
        angry:        '/assets/lottie/angry.json',
        disconnected: '/assets/lottie/disconnected.json',
    };

    setState(state) {
        if (this.state === state) return;
        this.state = state;
        this._loadAnimation(state);
    }

    _loadAnimation(state) {
        if (this.anim) this.anim.destroy();
        const path = PiggyCharacter.ANIMATIONS[state];
        if (!path) return;
        this.anim = lottie.loadAnimation({
            container: this.container,
            renderer: 'svg',
            loop: true,
            autoplay: true,
            path: path,
        });
    }
}

💡 Lottie 动画是矢量 SVG,自动缩放适配屏幕。文件通常 20-100KB,加载很快。

🎭 状态映射

小猪的角色状态与 xiaozhi 事件对应:

xiaozhi 事件角色状态小猪表现
WebSocket 连接建立😊 idle眨眼、微微摇晃、尾巴轻摆
{"type":"listen","state":"start"}👂 listening耳朵竖起、眼睛睁大
{"type":"listen","state":"stop"}🤔 thinking头顶冒问号、眼睛转圈
{"type":"tts","state":"start"}🗣️ speaking嘴巴动、表情开心
{"type":"tts","state":"stop"}😊 idle回到发呆
{"type":"llm","emotion":"happy"}😆 happy笑眼、跳动、爱心特效
{"type":"llm","emotion":"sad"}😢 sad垂眼、耳朵耷拉
{"type":"llm","emotion":"angry"}😠 angry皱眉、鼻孔喷气
连接断开😵 disconnected眼睛变×、显示"连接中..."

🧠 模型选择与注册

ASR(语音识别)

语音识别方案(✅ Qwen3 ASR Flash 为主力,Groq Whisper 免费备选):
方案成本延迟内存中文效果
Groq Whisper 免费 免费 (28,800s/天) ~300ms 0(云端) ⭐⭐⭐⭐
Qwen3 ASR Flash 推荐 ¥0.015/分钟 ~200ms 0(云端) ⭐⭐⭐⭐⭐
FunASR (本地) 免费 ~500ms ~800MB ❌ ⭐⭐⭐⭐⭐
阿里百炼 Paraformer 流式 ¥0.015/分钟 ~200ms 0(云端) ⭐⭐⭐⭐⭐

💡 阿里百炼 Paraformer 流式识别,延迟低,中文效果好。Qwen3 ASR Flash 基于大模型,准确率最高但非流式。Groq Whisper 免费备选。

💡 三个方案用同一个阿里云百炼 API Key(Paraformer 和 Qwen3ASRFlash)。

TTS(语音合成)

语音合成方案(✅ 已决定:硅基流动 CosyVoice2 为主力,EdgeTTS 免费备选):
方案成本音质延迟特色
硅基流动 CosyVoice2 推荐 $7.15/百万字符 ⭐⭐⭐⭐⭐ ~300ms 双向流式,首音 0.3s,情感控制强。model: FunAudioLLM/CosyVoice2-0.5B,voice: :alex(男) / :diana(女) 等
EdgeTTS 备选 免费 ⭐⭐⭐⭐ ~1-2s 音色多,中文 zh-CN-XiaoxiaoNeural 甜,适合调试
FishSpeech (本地) 免费 ⭐⭐⭐⭐⭐ ~1s 可克隆任意音色,但吃资源 (~1GB)
小米 MiMo V2.5 🆕 待观察 限时免费 ⭐⭐⭐⭐⭐ 不支持流式 大模型 TTS,支持声音克隆 + 风格指令 + 方言。⚠️ API 格式不兼容(用 chat/completions 而非 audio/speech),且暂无实时流式,无法用于实时语音对话。等官方支持流式后再接入。

💡 流式管线优势:LLM 首 Token 到达即触发 TTS 边合成边发音频,CosyVoice2 首音 ~0.15s。整体响应延迟从 ~4s 降到 ~1.5s。

🔧 技术栈

层技术说明
前端原生 HTML/CSS/JS单文件,零依赖,Echo Show 兼容性最佳
动画Lottie Web + CSS fallbackLottie 渲染小猪表情,CSS 做简单微动
通信WebSocket (xiaozhi 协议)JSON 状态帧 + Opus binary 音频帧
音频采集getUserMedia + Web Audio API浏览器麦克风 → PCM/OPUS → WebSocket
音频播放Web Audio API接收 base64 音频 → 解码 → 播放
后端xiaozhi-esp32-server (Docker)已验证的开源方案,9.6k stars
ASRQwen3 ASR Flash / Groq Whisper大模型识别 ¥0.015/分钟;Groq 免费备选
LLMDeepSeek V4 Flash速度快,中文强,¥0.5/百万Token
TTS硅基流动 CosyVoice2流式,首音 ~0.15s,$7.15/百万字符,情感控制强
VADSileroVAD本地运行,极轻量 (~5MB)
唤醒词Porcupine WASM (浏览器端)路线 B:纯浏览器 WebAssembly,支持中文自定义唤醒词,无需装 App
设备端Fully Kiosk Browser€8.90 买断,全屏/常亮/防退出/麦克风授权/开机自启
反代Cloudflare Tunnel + NginxCloudflare Tunnel (http2) 暴露到公网,nginx 监听 80 端口做 WebSocket 代理
仓库GitHub: piggy-display已有:treetree17/piggy-display (私有)

💾 内存预估

组件内存说明
已有服务 (Hermes + HA + Syncthing)~2509MB当前占用 (65%)
xiaozhi-esp32-server🟡 ~200-300MB纯 API 模式,无本地 ASR/TTS
SileroVAD~5MB极轻量
新增总计~300MB
剩余可用~700MB⚠️ 比较紧张,需要监控

⚠️ 如果后续上 FishSpeech (本地 TTS),需要额外 ~1GB,当前服务器不够。方案:停掉不用的服务,或升级到 8GB Droplet。

🚀 部署步骤

两种 LLM 配置方案(二选一):
A. DeepSeek V4 Flash 直连(推荐)— 按量计费,¥0.5/百万Token。
B. Hermes API 网关(可选)— xiaozhi-server 通过 Hermes 中转调用 LLM,自动获得记忆、工具、技能。

Phase 1 xiaozhi-server Docker 部署

📌 操作须知
• 所有命令都在宿主机上执行(SSH 登录后的环境),不在任何容器内
• 编辑文件用 nano 文件路径(保存:Ctrl+O → 回车 → 退出:Ctrl+X)
• 或用 tee 一次性写入(代码块中已提供,直接复制粘贴即可)
• 路径说明:/opt/data/xiaozhi/ = 宿主机目录,/opt/xiaozhi-esp32-server/data/ = 容器内映射路径

1. 创建目录

mkdir -p /opt/data/xiaozhi
mkdir -p ~/xiaozhi-stack

2. docker-compose.yml — 在宿主机创建:

sudo nano ~/xiaozhi-stack/docker-compose.yaml

粘贴以下内容:

services:
  xiaozhi-server:
    image: ghcr.m.daocloud.io/xinnan-tech/xiaozhi-esp32-server:server_latest
    container_name: xiaozhi-server
    restart: unless-stopped
    security_opt:
      - seccomp:unconfined
    ports:
      - '127.0.0.1:8000:8000'   # WebSocket
      - '127.0.0.1:8003:8003'   # HTTP/OTA
    volumes:
      - /opt/data/xiaozhi:/opt/xiaozhi-esp32-server/data
    extra_hosts:
      - 'host.docker.internal:host-gateway'
    deploy:
      resources:
        limits:
          memory: 256M
          cpus: '0.5'

💡 extra_hosts 让容器内可通过 host.docker.internal:8642 访问宿主机的 Hermes API。默认配置不需要这行,但留着也没坏处。

3. data/.config.yaml — 在宿主机编辑:

sudo nano /opt/data/xiaozhi/.config.yaml

粘贴以下内容(替换 YOUR_XXX 为你的实际密钥):

根据选择的 LLM 方案,使用对应的配置:

默认配置:DeepSeek V4 Flash 直连

server:
  ip: 0.0.0.0
  port: 8000
  http_port: 8003
  websocket: wss://piggy.treetree.tech/xiaozhi/v1/

selected_module:
  ASR: Qwen3ASRFlash
  LLM: DeepSeekLLM
  TTS: CosyVoiceSiliconflow
  VAD: SileroVAD
  Intent: nointent
  Memory: nomem

ASR:
  Qwen3ASRFlash:
    type: qwen3_asr_flash
    api_key: YOUR_DASHSCOPE_API_KEY
    base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
    model_name: qwen3-asr-flash
    output_dir: tmp/
    enable_lid: true  # 自动语种检测
    enable_itn: true  # 逆文本归一化

  # 备选:阿里百炼 Paraformer 流式(WebSocket 流式,延迟低)
  AliyunBLStreamASR:
    type: aliyunbl_stream
    api_key: YOUR_DASHSCOPE_API_KEY  # 同一个阿里云百炼 API Key
    model: paraformer-realtime-v2
    format: pcm
    sample_rate: 16000
    output_dir: tmp/
    punctuation_prediction_enabled: true
    inverse_text_normalization_enabled: true

  # 备选:Groq Whisper(免费,每天 28,800 秒)
  GroqASR:
    type: openai
    api_key: YOUR_GROQ_KEY
    base_url: https://api.groq.com/openai/v1/audio/transcriptions
    model_name: whisper-large-v3-turbo
    language: "zh"  # 强制识别为中文
    prompt: "这是中文对话,包含少量英语单词。"  # 引导模型识别中文为主、偶尔夹杂英语
    output_dir: tmp/

  # 备选:讯飞流式 ASR(需注册讯飞开放平台)
  XunfeiStreamASR:
    type: xunfei_stream
    app_id: YOUR_APP_ID
    api_key: YOUR_API_KEY
    api_secret: YOUR_API_SECRET
    domain: slm
    language: zh_cn
    accent: mandarin

LLM:
  DeepSeekLLM:
    type: openai
    model_name: deepseek-chat
    url: https://api.deepseek.com
    api_key: YOUR_DEEPSEEK_API_KEY
    temperature: 0.7

TTS:
  # 备选:EdgeTTS(免费,无需 API Key)
  EdgeTTS:
    type: edge
    voice: zh-CN-XiaoxiaoNeural
    output_dir: tmp/

  # 备选:硅基流动 CosyVoice2(可能不稳定)
  CosyVoiceSiliconflow:
    type: siliconflow
    model: FunAudioLLM/CosyVoice2-0.5B
    voice: FunAudioLLM/CosyVoice2-0.5B:diana
    access_token: YOUR_SILICONFLOW_API_KEY
    output_dir: tmp/

VAD:
  SileroVAD:
    type: silero
    threshold: 0.5
    model_dir: models/snakers4_silero-vad
    min_silence_duration_ms: 500

prompt: |
  你是小猪 Piggy,一只可爱的小猪 AI 伴侣。说话简短可爱,喜欢用 emoji。
  你住在 Echo Show 屏幕上,会随情绪变换表情。

🔄 切换 ASR / TTS 方案

在宿主机编辑 /opt/data/xiaozhi/.config.yaml,修改两处即可,重启容器生效:

sudo nano /opt/data/xiaozhi/.config.yaml
# 1. 改 selected_module.TTS
selected_module:
  TTS: CosyVoiceSiliconflow   # ← 改这里(可选值见下表)

# 2. 确认对应 TTS 配置段存在
TTS:
  # 推荐:EdgeTTS(免费,稳定,无需 API Key)
  EdgeTTS:
    type: edge
    voice: zh-CN-XiaoxiaoNeural    # 微软甜美女声
    format: mp3  # 指定输出格式为 MP3,避免 WAV 格式错误
    output_dir: tmp/

  # 备选:硅基流动 CosyVoice2(可能不稳定)
  CosyVoiceSiliconflow:
    type: siliconflow
    model: FunAudioLLM/CosyVoice2-0.5B
    voice: FunAudioLLM/CosyVoice2-0.5B:diana     # 欢快女声(可选: :alex :benjamin :charles :david :anna :bella :claire :diana)
    access_token: 你的_SILICONFLOW_API_KEY
    output_dir: tmp/

💡 CosyVoice2 可用音色::alex(男声)、:diana(女声,欢快)、更多见 SiliconFlow 文档。格式:FunAudioLLM/CosyVoice2-0.5B:音色名。

💡 提示:硅基流动 CosyVoice2 支持流式合成,首音延迟低。如果遇到稳定性问题,可随时切换到 EdgeTTS(免费备选)。

TTS 名称selected_module 值modelvoice价格
CosyVoice2 (SiliconFlow)CosyVoiceSiliconflowFunAudioLLM/CosyVoice2-0.5B:alex / :diana$7.15/百万字符
EdgeTTSEdgeTTS—zh-CN-XiaoxiaoNeural免费
火山引擎 豆包2.0HuoshanDoubleStreamTTS—zh_female_wanwanxiaohe_moon_bigtts~42元/月
阿里百炼 CosyVoiceAliBLTTScosyvoice-v2longcheng_v2按量计费
OpenAI TTSOpenAITTStts-1alloy / nova 等$15/百万字符

💡 完整 TTS 列表见 xiaozhi-server 官方 config.yaml。

🔄 切换 LLM 方案

方案 A:DeepSeek V4 Flash 直连(默认,已在上面 config.yaml 中配置好)

无需额外操作,selected_module.LLM: DeepSeekLLM 即可。

方案 B:Hermes API 网关(可选,需先启用 Hermes API Server)

与方案 A 的区别:LLM 调用经过 Hermes 中转,自动获得记忆、工具、技能。只需改两处:

sudo nano /opt/data/xiaozhi/.config.yaml
# /opt/data/xiaozhi/.config.yaml — 改两处

selected_module:
  LLM: HermesLLM          # ← 从 DeepSeekLLM 改为 HermesLLM
  Memory: nomem            # Hermes 自带记忆,xiaozhi 侧关闭

LLM:
  HermesLLM:
    type: openai
    model_name: hermes-agent
    url: http://host.docker.internal:8642/v1
    api_key: piggy-secret-key    # 需与 Hermes API_SERVER_KEY 一致

启用 Hermes API Server 步骤:

# 1. 在宿主机编辑 /opt/hermes/.env,添加:
nano /opt/hermes/.env

添加以下三行:

API_SERVER_ENABLED=true
API_SERVER_HOST=127.0.0.1
API_SERVER_KEY=piggy-secret-key

# 2. 重启 Hermes
docker compose -f /opt/hermes/docker-compose.yml restart gateway

# 3. 验证
curl -s http://127.0.0.1:8642/health

# 4. 改好 config.yaml(见上面),重启 xiaozhi-server
cd ~/xiaozhi-stack && docker compose restart

4. 启动 xiaozhi-server

# 预检端口占用
ss -tlnp | grep -E ':8000|:8003' && echo "⚠️ 端口被占用,先停掉冲突服务" || echo "✅ 端口空闲"

cd ~/xiaozhi-stack && docker compose up -d
docker logs -f xiaozhi-server
# 看到 "Websocket地址是 ws://..." 即成功

Phase 2 前端部署

1. 克隆仓库

git clone git@github.com:treetree17/piggy-display.git /var/www/piggy

2. 验证文件

ls -la /var/www/piggy/
# 应该看到: index.html, css/, js/, assets/, lib/, nginx/

3. 后续更新

cd /var/www/piggy && git pull

Phase 3 Nginx 配置

1. 创建配置文件 — 在宿主机用 tee 一次性写入(比手动 nano 不容易出错):

sudo tee /etc/nginx/sites-available/piggy > /dev/null << 'EOF'
server {
    listen 80;
    http2 off;
    server_name piggy.treetree.tech;

    # 拒绝访问隐藏文件(.git/ 等)
    location ~ /\\. {
        deny all;
        return 404;
    }

    # 前端静态文件
    root /var/www/piggy;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    # WebSocket 代理 → xiaozhi-server
    location /xiaozhi/v1/ {
        proxy_pass http://127.0.0.1:8000/xiaozhi/v1/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }

    # OTA 接口
    location /xiaozhi/ota/ {
        proxy_pass http://127.0.0.1:8003/xiaozhi/ota/;
        proxy_set_header Host $host;
    }
}
EOF

💡 SSL 由 Cloudflare Tunnel 自动处理(Tunnel 终止 TLS),nginx 只需监听 80 端口。不需要配置 A 记录或 SSL 证书。

2. 启用站点

# 创建软链接启用站点
sudo ln -s /etc/nginx/sites-available/piggy /etc/nginx/sites-enabled/

# 测试配置语法(必须看到 "syntax is ok" 才继续)
sudo nginx -t

# 重载 nginx(不用 restart,不断现有连接)
sudo systemctl reload nginx

3. 验证

# 在服务器上
curl -sI https://piggy.treetree.tech/                              # → 200 OK
curl -s https://piggy.treetree.tech/assets/lottie/cool.json | head -c 100  # → JSON 数据

# 验证 WebSocket 代理(返回 400 说明代理通了)
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8000/xiaozhi/v1/  # → 400

4. Cloudflare Tunnel

piggy.treetree.tech 通过 Cloudflare Tunnel 暴露,不需要 A 记录。Tunnel 配置:

# Tunnel 配置文件:/etc/cloudflared/config.yaml
# Tunnel ID:8eb7a559-55e7-4f74-9471-a44ad5c49794
tunnel: 8eb7a559-55e7-4f74-9471-a44ad5c49794
credentials-file: /home/hermes/.cloudflared/8eb7a559-55e7-4f74-9471-a44ad5c49794.json
protocol: http2

ingress:
  - hostname: piggy.treetree.tech
    service: http://localhost:80
  - service: http_status:404

💡 在 Cloudflare Dashboard → Zero Trust → Networks → Tunnels 中管理。使用 http2 协议(QUIC 可能导致 context deadline exceeded)。

Phase 4 Echo Show 部署

Echo Show 上只装两样东西:LineageOS + Fully Kiosk Browser。零代码,纯显示终端。

1. 越狱 + 刷 LineageOS

按教程操作:pub.treetree.tech/echo-show-jailbreak

2. 购买 Fully Kiosk Browser

官网:fully-kiosk.com,€8.90 一次性买断(一个设备一个 license)。购买后会收到 APK 下载链接和 license key。

3. ADB sideload 安装

# 确认 ADB 已连接
adb devices

# 安装 Fully Kiosk APK(下载后放在当前目录)
adb install fully-kiosk-browser-xxx.apk

# 如果安装失败(签名冲突),先卸载旧版
adb uninstall de.ozerov.fully

4. Fully Kiosk 设置

打开 Fully Kiosk,在 Settings 中配置:

设置项值说明
Start URLhttps://piggy.treetree.tech开机后自动打开的页面
Kiosk Mode → Enable Kiosk ModeON锁定全屏,隐藏状态栏,防退出
Kiosk Mode → Keep Screen OnON屏幕常亮
Kiosk Mode → Autostart on BootON开机自动启动 Fully Kiosk
Kiosk Mode → Prevent SleepON防止设备休眠
Web Content Settings → Autoplay Video/AudioON自动播放音频(TTS)
Permissions → Access MicrophoneON自动授权麦克风(PLUS 功能,€8.90 已含)
Permissions → Access CameraOFF不需要摄像头
Remote Administration → Enable Remote AdminON开启本地 REST API(用于手势切换页面)
Remote Administration → Remote Admin from Local NetworkON局域网内可调用 API

5. 手势切换:Piggy ↔ HA Dashboard

Fully Kiosk 支持手势触发动作。配置双击切换页面,无需在 Piggy 页面上加任何按钮,全屏体验不受影响:

设置值说明
Settings → Gestures → Double TapAction: Load URL → https://ha.treetree.tech双击屏幕从 Piggy 切到 HA Dashboard

HA Dashboard 切回 Piggy:

在 HA 中使用 Fully Kiosk 集成,添加按钮调用 fully_kiosk.load_url 切回 Piggy:

# HA button card 或 automation
action: fully_kiosk.load_url
target:
  device_id: <echo-show-device-id>
data:
  url: https://piggy.treetree.tech

6. 开发者选项(兜底)

Android 设置 → 开发者选项 → Stay Awake(充电时屏幕常亮)。万一 Fully Kiosk 没自动启动,至少屏幕不会灭。

7. 验证清单

✅ 已验证方案:Reddit/XDA 多人成功在 Echo Show + LineageOS 上用 Fully Kiosk 跑 HA Dashboard。Mark Watt Tech 有完整视频教程(14万播放)。

Phase 5 集成 Home Assistant

  1. xiaozhi-server 配置 HA MCP 接入
  2. 实现语音控制家居("开灯"、"空调调到25度")
  3. 意图识别 → function_call → HA 服务调用

📚 参考项目

项目借鉴点状态
xiaozhi-esp32-server 后端核心:WebSocket 协议、ASR/LLM/TTS 管线、Docker 部署
内置 digital-human 模块可参考前端实现
v0.9.3 · 9.6k⭐
xiaozhi-esp32 官方固件,定义了通信协议(JSON 状态帧 + OPUS 音频帧) 16k⭐
Duolingo Lily + Rive 状态机驱动模式:idle → listening → thinking → speaking → emotion 参考设计
py-xiaozhi Python WebSocket 客户端实现,可参考协议细节 2.7k⭐
LottieFiles 表情包 现成的可爱表情动画(笑脸、哭脸、眨眼),Web 原生渲染 待挑选

⚠️ 风险评估

等级风险缓解措施
中 服务器内存不足(剩余 ~700MB) 纯 API 模式不跑本地 ASR/TTS;监控内存,必要时停 Piper TTS 或升级 Droplet
中 xiaozhi-server 内存占用超预期 先用最简化安装(无数据库),观察实际占用
低 Echo Show Silk 浏览器不支持 WebSocket 越狱后用 Chromium,不依赖 Silk
低 Echo Show 麦克风采集延迟 越狱后用标准 Android API,比 Fire OS 兼容性好
低 Lottie 在低端设备渲染卡顿 备选方案 B(纯 CSS),先测 Lottie 性能
低 Porcupine WASM 在低端设备性能 Porcupine 极轻量(设计目标就是嵌入式),Echo Show 的 ARM Cortex-A53 够用
低 Echo Show 麦克风权限 Fully Kiosk PLUS 自动授权麦克风;Porcupine WASM 直接用 getUserMedia
低 xiaozhi-server WebSocket 协议浏览器兼容性 官方 digital-human 已有浏览器端实现,协议兼容

🚀 后续提升事项

⚡ 流式延迟优化(已应用)

参考 xiaozhi-performance-research 的测试数据,采用流式配置可将整体响应延迟从 ~4s 降低到 ~1.5s:

模块非流式流式收益
ASR等整段说完 (~1s)边听边出文字 (~0.8s 首词)-0.2s
LLM等完整回答首 Token 到达即触发 TTS并行
TTSEdgeTTS ~1-2sEdgeTTS ~0.3s 首音-1s+
总计~3-4s~1.5s-2.5s

💡 三级流水线:ASR 边听边识别 → LLM 首 Token 即触发 TTS → TTS 边合成边发音频。不是串行等待。

Phase 3.5 语音唤醒(路线 B)

🔊 TTS 音色升级

🎨 角色升级

💡 智能家居集成

🧠 记忆系统

🔒 安全加固

当前安全架构:

⚠️ 潜在风险:WebSocket 端点无认证,任何人知道 URL 就能连接,消耗 Groq/OpenCode 额度。单人使用风险低,但建议加 Cloudflare 保护。

🛡️ Cloudflare WAF 配置(推荐)

在 Cloudflare 层面拦截未授权访问,不改 nginx,不改代码。

方式一:WAF Custom Rule(精确控制)

只允许你的 Echo Show IP 访问 WebSocket 路径,其他请求直接 block:

  1. 登录 dash.cloudflare.com → 选 treetree.tech
  2. 左侧 Security → WAF → Custom rules → Create rule
  3. 配置:
字段值
Rule namepiggy-ws-protection
When incoming requests matchURI path contains "/xiaozhi/" AND IP address does not equal <你的 Echo Show IP>
ThenBlock

💡 Echo Show 在家里,IP 基本固定。如果有多设备,用 IP is not in {IP1, IP2} 加白名单。

方式二:Rate Limiting(防刷)

即使不知道你的 IP,也能防止脚本暴力刷接口:

  1. Cloudflare → Security → WAF → Rate limiting rules → Create rule
  2. 配置:
字段值
Rule namepiggy-rate-limit
When incoming requests matchURI path contains "/xiaozhi/"
Rate10 requests per 1 minute
ActionBlock for 10 minutes

💡 正常语音对话不会超过 10 req/min(一次对话 = 1 次 WebSocket 连接)。此规则防的是脚本批量连接。

方式三:Cloudflare Access(最强,需 Zero Trust)

在 /xiaozhi/ 路径前加一层身份验证,只有通过认证的设备才能访问:

  1. Cloudflare → Zero Trust → Access → Applications → Add application
  2. 选 Self-hosted,填 piggy.treetree.tech/xiaozhi/
  3. Policy:允许你的邮箱 或 One-time PIN
  4. Echo Show 首次访问时会弹 Cloudflare 登录页,认证后 Cookie 有效期内免登

⚠️ 这个方案最安全,但 Echo Show 上的浏览器需要能完成 OAuth 流程。Fully Kiosk 支持。

📋 当前安全状态总结

层级保护状态
网络层UFW 仅开 22/80/443✅ 已有
容器层端口绑定 127.0.0.1✅ 已有
传输层Cloudflare TLS✅ 已有
应用层WebSocket 认证⚠️ 建议加 Cloudflare WAF
速率限制防暴力刷接口⚠️ 建议加 Rate Limiting

单人使用 + Echo Show 在家里:当前保护已够用。如果担心被扫到,加 Cloudflare WAF 规则(方式一)5 分钟搞定。

📅 时间线

阶段内容预计时间前置条件
Week 1后端 Docker 部署 + Nginx 配置1-2 天无
Week 1-2前端基础页面(WebSocket + 音频)3-5 天后端可用
Week 2-3小猪角色动画开发3-5 天角色风格确定
Week 3Echo Show 越狱 + 部署1-2 天设备到手
Week 4HA 集成 + 调优2-3 天前端稳定

📁 仓库架构

仓库名:piggy-display(独立仓库,方案 A)

piggy-display/
├── index.html              ← 主页面(路线 C 核心,单文件可运行)
├── css/
│   └── style.css           ← 样式 + 小猪角色 CSS 动画
├── js/
│   ├── websocket.js        ← xiaozhi WebSocket 协议(音频帧/状态帧)
│   ├── audio.js            ← getUserMedia 麦克风采集 + Web Audio 播放
│   └── piggy.js            ← 小猪角色状态机(idle/listening/thinking/speaking/emotion)
├── assets/
│   └── lottie/             ← 小猪 Lottie 动画文件
├── wakeword/               ← 路线 B(Porcupine WASM 唤醒词)
│   ├── porcupine/          ← Porcupine 模型文件 (.ppn)
│   └── wakeword.js          ← 浏览器端唤醒词引擎
│   └── models/             ← Porcupine .ppn 模型文件
├── nginx/
│   └── piggy.conf          ← Nginx server block 配置
└── README.md

为什么独立仓库:

🛠️ 运维操作

临时下线(维护模式)

# 移除 nginx 链接(站点立即不可访问)
sudo rm /etc/nginx/sites-enabled/piggy
sudo systemctl reload nginx

恢复上线

# 恢复 nginx 链接
sudo ln -s /etc/nginx/sites-available/piggy /etc/nginx/sites-enabled/piggy
sudo systemctl reload nginx

更新前端代码

cd /var/www/piggy
sudo git fetch origin
sudo git reset --hard origin/main
# 验证更新
sudo git log --oneline -1

手动重启

# 1. 更新前端代码
cd /var/www/piggy && git pull

# 2. 重启 xiaozhi-server
docker restart xiaozhi-server

# 3. 重启 nginx
sudo systemctl restart nginx

# 4. 验证服务
curl -s http://127.0.0.1:8000/xiaozhi/v1/ | head -1

故障排查

# TTS 故障排查(宿主机运行)
sudo bash /opt/data/scripts/piggy-tts-debug.sh

音频诊断

# TTS 音频问题诊断(宿主机运行)
sudo bash /opt/data/scripts/piggy-audio-diagnosis.sh

查看实时日志

# xiaozhi-server 日志
docker logs xiaozhi-server -f --tail 50

# nginx 访问日志
sudo tail -f /var/log/nginx/access.log | grep piggy

🔗 参考链接