mirror of
https://github.com/78/xiaozhi-esp32.git
synced 2026-01-14 09:17:20 +08:00
Compare commits
No commits in common. "main" and "v2.0.1" have entirely different histories.
51
.github/workflows/build.yml
vendored
51
.github/workflows/build.yml
vendored
@ -14,10 +14,10 @@ permissions:
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
name: Determine variants to build
|
||||
name: Determine boards to build
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
variants: ${{ steps.select.outputs.variants }}
|
||||
boards: ${{ steps.select.outputs.boards }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -28,30 +28,30 @@ jobs:
|
||||
run: sudo apt-get update && sudo apt-get install -y jq
|
||||
|
||||
- id: list
|
||||
name: Get all variant list
|
||||
name: Get all board list
|
||||
run: |
|
||||
echo "all_variants=$(python scripts/release.py --list-boards --json)" >> $GITHUB_OUTPUT
|
||||
echo "all_boards=$(python scripts/release.py --list-boards --json)" >> $GITHUB_OUTPUT
|
||||
|
||||
- id: select
|
||||
name: Select variants based on changes
|
||||
name: Select boards based on changes
|
||||
env:
|
||||
ALL_VARIANTS: ${{ steps.list.outputs.all_variants }}
|
||||
ALL_BOARDS: ${{ steps.list.outputs.all_boards }}
|
||||
run: |
|
||||
EVENT_NAME="${{ github.event_name }}"
|
||||
|
||||
# push 到 main 分支,编译全部变体
|
||||
# For push to main branch, build all boards
|
||||
if [[ "$EVENT_NAME" == "push" ]]; then
|
||||
echo "variants=$ALL_VARIANTS" >> $GITHUB_OUTPUT
|
||||
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# pull_request 场景
|
||||
# For pull_request
|
||||
BASE_SHA="${{ github.event.pull_request.base.sha }}"
|
||||
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
|
||||
echo "Base: $BASE_SHA, Head: $HEAD_SHA"
|
||||
|
||||
CHANGED=$(git diff --name-only $BASE_SHA $HEAD_SHA || true)
|
||||
echo -e "Changed files:\n$CHANGED"
|
||||
echo "Changed files:\n$CHANGED"
|
||||
|
||||
NEED_ALL=0
|
||||
declare -A AFFECTED
|
||||
@ -60,10 +60,6 @@ jobs:
|
||||
NEED_ALL=1
|
||||
fi
|
||||
|
||||
if [[ "$file" == main/boards/common/* ]]; then
|
||||
NEED_ALL=1
|
||||
fi
|
||||
|
||||
if [[ "$file" == main/boards/* ]]; then
|
||||
board=$(echo "$file" | cut -d '/' -f3)
|
||||
AFFECTED[$board]=1
|
||||
@ -71,41 +67,40 @@ jobs:
|
||||
done <<< "$CHANGED"
|
||||
|
||||
if [[ "$NEED_ALL" -eq 1 ]]; then
|
||||
echo "variants=$ALL_VARIANTS" >> $GITHUB_OUTPUT
|
||||
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
|
||||
else
|
||||
if [[ ${#AFFECTED[@]} -eq 0 ]]; then
|
||||
echo "variants=[]" >> $GITHUB_OUTPUT
|
||||
echo "boards=[]" >> $GITHUB_OUTPUT
|
||||
else
|
||||
BOARDS_JSON=$(printf '%s\n' "${!AFFECTED[@]}" | sort -u | jq -R -s -c 'split("\n")[:-1]')
|
||||
FILTERED=$(echo "$ALL_VARIANTS" | jq -c --argjson boards "$BOARDS_JSON" 'map(select(.board as $b | $boards | index($b)))')
|
||||
echo "variants=$FILTERED" >> $GITHUB_OUTPUT
|
||||
JSON=$(printf '%s\n' "${!AFFECTED[@]}" | sort -u | jq -R -s -c 'split("\n")[:-1]')
|
||||
echo "boards=$JSON" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
|
||||
build:
|
||||
name: Build ${{ matrix.name }}
|
||||
name: Build ${{ matrix.board }}
|
||||
needs: prepare
|
||||
if: ${{ needs.prepare.outputs.variants != '[]' }}
|
||||
if: ${{ needs.prepare.outputs.boards != '[]' }}
|
||||
strategy:
|
||||
fail-fast: false # 单个变体失败不影响其它变体
|
||||
fail-fast: false # 单个 board 失败不影响其它 board
|
||||
matrix:
|
||||
include: ${{ fromJson(needs.prepare.outputs.variants) }}
|
||||
board: ${{ fromJson(needs.prepare.outputs.boards) }}
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: espressif/idf:release-v5.5
|
||||
image: espressif/idf:release-v5.4
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build current variant
|
||||
- name: Build current board
|
||||
shell: bash
|
||||
run: |
|
||||
source $IDF_PATH/export.sh
|
||||
python scripts/release.py ${{ matrix.board }} --name ${{ matrix.name }}
|
||||
python scripts/release.py ${{ matrix.board }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: xiaozhi_${{ matrix.name }}_${{ github.sha }}.bin
|
||||
name: xiaozhi_${{ matrix.board }}_${{ github.sha }}.bin
|
||||
path: build/merged-binary.bin
|
||||
if-no-files-found: error
|
||||
if-no-files-found: error
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,4 +16,3 @@ main/mmap_generate_emoji.h
|
||||
*.pyc
|
||||
*.bin
|
||||
mmap_generate_*.h
|
||||
.clangd
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(PROJECT_VER "2.1.0")
|
||||
set(PROJECT_VER "2.0.1")
|
||||
|
||||
# Add this line to disable the specific warning
|
||||
add_compile_options(-Wno-missing-field-initializers)
|
||||
|
||||
167
README.md
167
README.md
@ -1,73 +1,74 @@
|
||||
# An MCP-based Chatbot
|
||||
# An MCP-based Chatbot | 一个基于 MCP 的聊天机器人
|
||||
|
||||
(English | [中文](README_zh.md) | [日本語](README_ja.md))
|
||||
(中文 | [English](README_en.md) | [日本語](README_ja.md))
|
||||
|
||||
## Introduction
|
||||
## 视频
|
||||
|
||||
👉 [Human: Give AI a camera vs AI: Instantly finds out the owner hasn't washed hair for three days【bilibili】](https://www.bilibili.com/video/BV1bpjgzKEhd/)
|
||||
👉 [人类:给 AI 装摄像头 vs AI:当场发现主人三天没洗头【bilibili】](https://www.bilibili.com/video/BV1bpjgzKEhd/)
|
||||
|
||||
👉 [Handcraft your AI girlfriend, beginner's guide【bilibili】](https://www.bilibili.com/video/BV1XnmFYLEJN/)
|
||||
👉 [手工打造你的 AI 女友,新手入门教程【bilibili】](https://www.bilibili.com/video/BV1XnmFYLEJN/)
|
||||
|
||||
As a voice interaction entry, the XiaoZhi AI chatbot leverages the AI capabilities of large models like Qwen / DeepSeek, and achieves multi-terminal control via the MCP protocol.
|
||||
## 介绍
|
||||
|
||||
<img src="docs/mcp-based-graph.jpg" alt="Control everything via MCP" width="320">
|
||||
这是一个由虾哥开源的 ESP32 项目,以 MIT 许可证发布,允许任何人免费使用,或用于商业用途。
|
||||
|
||||
## Version Notes
|
||||
我们希望通过这个项目,能够帮助大家了解 AI 硬件开发,将当下飞速发展的大语言模型应用到实际的硬件设备中。
|
||||
|
||||
The current v2 version is incompatible with the v1 partition table, so it is not possible to upgrade from v1 to v2 via OTA. For partition table details, see [partitions/v2/README.md](partitions/v2/README.md).
|
||||
如果你有任何想法或建议,请随时提出 Issues 或加入 QQ 群:1011329060
|
||||
|
||||
All hardware running v1 can be upgraded to v2 by manually flashing the firmware.
|
||||
### 基于 MCP 控制万物
|
||||
|
||||
The stable version of v1 is 1.9.2. You can switch to v1 by running `git checkout v1`. The v1 branch will be maintained until February 2026.
|
||||
小智 AI 聊天机器人作为一个语音交互入口,利用 Qwen / DeepSeek 等大模型的 AI 能力,通过 MCP 协议实现多端控制。
|
||||
|
||||
### Features Implemented
|
||||

|
||||
|
||||
### 已实现功能
|
||||
|
||||
- Wi-Fi / ML307 Cat.1 4G
|
||||
- Offline voice wake-up [ESP-SR](https://github.com/espressif/esp-sr)
|
||||
- Supports two communication protocols ([Websocket](docs/websocket.md) or MQTT+UDP)
|
||||
- Uses OPUS audio codec
|
||||
- Voice interaction based on streaming ASR + LLM + TTS architecture
|
||||
- Speaker recognition, identifies the current speaker [3D Speaker](https://github.com/modelscope/3D-Speaker)
|
||||
- OLED / LCD display, supports emoji display
|
||||
- Battery display and power management
|
||||
- Multi-language support (Chinese, English, Japanese)
|
||||
- Supports ESP32-C3, ESP32-S3, ESP32-P4 chip platforms
|
||||
- Device-side MCP for device control (Speaker, LED, Servo, GPIO, etc.)
|
||||
- Cloud-side MCP to extend large model capabilities (smart home control, PC desktop operation, knowledge search, email, etc.)
|
||||
- Customizable wake words, fonts, emojis, and chat backgrounds with online web-based editing ([Custom Assets Generator](https://github.com/78/xiaozhi-assets-generator))
|
||||
- 离线语音唤醒 [ESP-SR](https://github.com/espressif/esp-sr)
|
||||
- 支持两种通信协议([Websocket](docs/websocket.md) 或 MQTT+UDP)
|
||||
- 采用 OPUS 音频编解码
|
||||
- 基于流式 ASR + LLM + TTS 架构的语音交互
|
||||
- 声纹识别,识别当前说话人的身份 [3D Speaker](https://github.com/modelscope/3D-Speaker)
|
||||
- OLED / LCD 显示屏,支持表情显示
|
||||
- 电量显示与电源管理
|
||||
- 支持多语言(中文、英文、日文)
|
||||
- 支持 ESP32-C3、ESP32-S3、ESP32-P4 芯片平台
|
||||
- 通过设备端 MCP 实现设备控制(音量、灯光、电机、GPIO 等)
|
||||
- 通过云端 MCP 扩展大模型能力(智能家居控制、PC桌面操作、知识搜索、邮件收发等)
|
||||
|
||||
## Hardware
|
||||
## 硬件
|
||||
|
||||
### Breadboard DIY Practice
|
||||
### 面包板手工制作实践
|
||||
|
||||
See the Feishu document tutorial:
|
||||
详见飞书文档教程:
|
||||
|
||||
👉 ["XiaoZhi AI Chatbot Encyclopedia"](https://ccnphfhqs21z.feishu.cn/wiki/F5krwD16viZoF0kKkvDcrZNYnhb?from=from_copylink)
|
||||
👉 [《小智 AI 聊天机器人百科全书》](https://ccnphfhqs21z.feishu.cn/wiki/F5krwD16viZoF0kKkvDcrZNYnhb?from=from_copylink)
|
||||
|
||||
Breadboard demo:
|
||||
面包板效果图如下:
|
||||
|
||||

|
||||

|
||||
|
||||
### Supports 70+ Open Source Hardware (Partial List)
|
||||
### 支持 70 多个开源硬件(仅展示部分)
|
||||
|
||||
- <a href="https://oshwhub.com/li-chuang-kai-fa-ban/li-chuang-shi-zhan-pai-esp32-s3-kai-fa-ban" target="_blank" title="LiChuang ESP32-S3 Development Board">LiChuang ESP32-S3 Development Board</a>
|
||||
- <a href="https://github.com/espressif/esp-box" target="_blank" title="Espressif ESP32-S3-BOX3">Espressif ESP32-S3-BOX3</a>
|
||||
- <a href="https://oshwhub.com/li-chuang-kai-fa-ban/li-chuang-shi-zhan-pai-esp32-s3-kai-fa-ban" target="_blank" title="立创·实战派 ESP32-S3 开发板">立创·实战派 ESP32-S3 开发板</a>
|
||||
- <a href="https://github.com/espressif/esp-box" target="_blank" title="乐鑫 ESP32-S3-BOX3">乐鑫 ESP32-S3-BOX3</a>
|
||||
- <a href="https://docs.m5stack.com/zh_CN/core/CoreS3" target="_blank" title="M5Stack CoreS3">M5Stack CoreS3</a>
|
||||
- <a href="https://docs.m5stack.com/en/atom/Atomic%20Echo%20Base" target="_blank" title="AtomS3R + Echo Base">M5Stack AtomS3R + Echo Base</a>
|
||||
- <a href="https://gf.bilibili.com/item/detail/1108782064" target="_blank" title="Magic Button 2.4">Magic Button 2.4</a>
|
||||
- <a href="https://www.waveshare.net/shop/ESP32-S3-Touch-AMOLED-1.8.htm" target="_blank" title="Waveshare ESP32-S3-Touch-AMOLED-1.8">Waveshare ESP32-S3-Touch-AMOLED-1.8</a>
|
||||
- <a href="https://gf.bilibili.com/item/detail/1108782064" target="_blank" title="神奇按钮 2.4">神奇按钮 2.4</a>
|
||||
- <a href="https://www.waveshare.net/shop/ESP32-S3-Touch-AMOLED-1.8.htm" target="_blank" title="微雪电子 ESP32-S3-Touch-AMOLED-1.8">微雪电子 ESP32-S3-Touch-AMOLED-1.8</a>
|
||||
- <a href="https://github.com/Xinyuan-LilyGO/T-Circle-S3" target="_blank" title="LILYGO T-Circle-S3">LILYGO T-Circle-S3</a>
|
||||
- <a href="https://oshwhub.com/tenclass01/xmini_c3" target="_blank" title="XiaGe Mini C3">XiaGe Mini C3</a>
|
||||
- <a href="https://oshwhub.com/movecall/cuican-ai-pendant-lights-up-y" target="_blank" title="Movecall CuiCan ESP32S3">CuiCan AI Pendant</a>
|
||||
- <a href="https://github.com/WMnologo/xingzhi-ai" target="_blank" title="WMnologo-Xingzhi-1.54">WMnologo-Xingzhi-1.54TFT</a>
|
||||
- <a href="https://oshwhub.com/tenclass01/xmini_c3" target="_blank" title="虾哥 Mini C3">虾哥 Mini C3</a>
|
||||
- <a href="https://oshwhub.com/movecall/cuican-ai-pendant-lights-up-y" target="_blank" title="Movecall CuiCan ESP32S3">璀璨·AI 吊坠</a>
|
||||
- <a href="https://github.com/WMnologo/xingzhi-ai" target="_blank" title="无名科技Nologo-星智-1.54">无名科技 Nologo-星智-1.54TFT</a>
|
||||
- <a href="https://www.seeedstudio.com/SenseCAP-Watcher-W1-A-p-5979.html" target="_blank" title="SenseCAP Watcher">SenseCAP Watcher</a>
|
||||
- <a href="https://www.bilibili.com/video/BV1BHJtz6E2S/" target="_blank" title="ESP-HI Low Cost Robot Dog">ESP-HI Low Cost Robot Dog</a>
|
||||
- <a href="https://www.bilibili.com/video/BV1BHJtz6E2S/" target="_blank" title="ESP-HI 超低成本机器狗">ESP-HI 超低成本机器狗</a>
|
||||
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<a href="docs/v1/lichuang-s3.jpg" target="_blank" title="LiChuang ESP32-S3 Development Board">
|
||||
<a href="docs/v1/lichuang-s3.jpg" target="_blank" title="立创·实战派 ESP32-S3 开发板">
|
||||
<img src="docs/v1/lichuang-s3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/espbox3.jpg" target="_blank" title="Espressif ESP32-S3-BOX3">
|
||||
<a href="docs/v1/espbox3.jpg" target="_blank" title="乐鑫 ESP32-S3-BOX3">
|
||||
<img src="docs/v1/espbox3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/m5cores3.jpg" target="_blank" title="M5Stack CoreS3">
|
||||
@ -76,90 +77,78 @@ Breadboard demo:
|
||||
<a href="docs/v1/atoms3r.jpg" target="_blank" title="AtomS3R + Echo Base">
|
||||
<img src="docs/v1/atoms3r.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/magiclick.jpg" target="_blank" title="Magic Button 2.4">
|
||||
<a href="docs/v1/magiclick.jpg" target="_blank" title="神奇按钮 2.4">
|
||||
<img src="docs/v1/magiclick.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/waveshare.jpg" target="_blank" title="Waveshare ESP32-S3-Touch-AMOLED-1.8">
|
||||
<a href="docs/v1/waveshare.jpg" target="_blank" title="微雪电子 ESP32-S3-Touch-AMOLED-1.8">
|
||||
<img src="docs/v1/waveshare.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/lilygo-t-circle-s3.jpg" target="_blank" title="LILYGO T-Circle-S3">
|
||||
<img src="docs/v1/lilygo-t-circle-s3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/xmini-c3.jpg" target="_blank" title="XiaGe Mini C3">
|
||||
<a href="docs/v1/xmini-c3.jpg" target="_blank" title="虾哥 Mini C3">
|
||||
<img src="docs/v1/xmini-c3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/movecall-cuican-esp32s3.jpg" target="_blank" title="CuiCan">
|
||||
<img src="docs/v1/movecall-cuican-esp32s3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/wmnologo_xingzhi_1.54.jpg" target="_blank" title="WMnologo-Xingzhi-1.54">
|
||||
<a href="docs/v1/wmnologo_xingzhi_1.54.jpg" target="_blank" title="无名科技Nologo-星智-1.54">
|
||||
<img src="docs/v1/wmnologo_xingzhi_1.54.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/sensecap_watcher.jpg" target="_blank" title="SenseCAP Watcher">
|
||||
<img src="docs/v1/sensecap_watcher.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/esp-hi.jpg" target="_blank" title="ESP-HI Low Cost Robot Dog">
|
||||
<a href="docs/v1/esp-hi.jpg" target="_blank" title="ESP-HI 超低成本机器狗">
|
||||
<img src="docs/v1/esp-hi.jpg" width="240" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## Software
|
||||
## 软件
|
||||
|
||||
### Firmware Flashing
|
||||
### 固件烧录
|
||||
|
||||
For beginners, it is recommended to use the firmware that can be flashed without setting up a development environment.
|
||||
新手第一次操作建议先不要搭建开发环境,直接使用免开发环境烧录的固件。
|
||||
|
||||
The firmware connects to the official [xiaozhi.me](https://xiaozhi.me) server by default. Personal users can register an account to use the Qwen real-time model for free.
|
||||
固件默认接入 [xiaozhi.me](https://xiaozhi.me) 官方服务器,个人用户注册账号可以免费使用 Qwen 实时模型。
|
||||
|
||||
👉 [Beginner's Firmware Flashing Guide](https://ccnphfhqs21z.feishu.cn/wiki/Zpz4wXBtdimBrLk25WdcXzxcnNS)
|
||||
👉 [新手烧录固件教程](https://ccnphfhqs21z.feishu.cn/wiki/Zpz4wXBtdimBrLk25WdcXzxcnNS)
|
||||
|
||||
### Development Environment
|
||||
### 开发环境
|
||||
|
||||
- Cursor or VSCode
|
||||
- Install ESP-IDF plugin, select SDK version 5.4 or above
|
||||
- Linux is better than Windows for faster compilation and fewer driver issues
|
||||
- This project uses Google C++ code style, please ensure compliance when submitting code
|
||||
- Cursor 或 VSCode
|
||||
- 安装 ESP-IDF 插件,选择 SDK 版本 5.4 或以上
|
||||
- Linux 比 Windows 更好,编译速度快,也免去驱动问题的困扰
|
||||
- 本项目使用 Google C++ 代码风格,提交代码时请确保符合规范
|
||||
|
||||
### Developer Documentation
|
||||
### 开发者文档
|
||||
|
||||
- [Custom Board Guide](docs/custom-board.md) - Learn how to create custom boards for XiaoZhi AI
|
||||
- [MCP Protocol IoT Control Usage](docs/mcp-usage.md) - Learn how to control IoT devices via MCP protocol
|
||||
- [MCP Protocol Interaction Flow](docs/mcp-protocol.md) - Device-side MCP protocol implementation
|
||||
- [MQTT + UDP Hybrid Communication Protocol Document](docs/mqtt-udp.md)
|
||||
- [A detailed WebSocket communication protocol document](docs/websocket.md)
|
||||
- [自定义开发板指南](main/boards/README.md) - 学习如何为小智 AI 创建自定义开发板
|
||||
- [MCP 协议物联网控制用法说明](docs/mcp-usage.md) - 了解如何通过 MCP 协议控制物联网设备
|
||||
- [MCP 协议交互流程](docs/mcp-protocol.md) - 设备端 MCP 协议的实现方式
|
||||
- [MQTT + UDP 混合通信协议文档](docs/mqtt-udp.md)
|
||||
- [一份详细的 WebSocket 通信协议文档](docs/websocket.md)
|
||||
|
||||
## Large Model Configuration
|
||||
## 大模型配置
|
||||
|
||||
If you already have a XiaoZhi AI chatbot device and have connected to the official server, you can log in to the [xiaozhi.me](https://xiaozhi.me) console for configuration.
|
||||
如果你已经拥有一个小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
|
||||
|
||||
👉 [Backend Operation Video Tutorial (Old Interface)](https://www.bilibili.com/video/BV1jUCUY2EKM/)
|
||||
👉 [后台操作视频教程(旧版界面)](https://www.bilibili.com/video/BV1jUCUY2EKM/)
|
||||
|
||||
## Related Open Source Projects
|
||||
## 相关开源项目
|
||||
|
||||
For server deployment on personal computers, refer to the following open-source projects:
|
||||
在个人电脑上部署服务器,可以参考以下第三方开源的项目:
|
||||
|
||||
- [xinnan-tech/xiaozhi-esp32-server](https://github.com/xinnan-tech/xiaozhi-esp32-server) Python server
|
||||
- [joey-zhou/xiaozhi-esp32-server-java](https://github.com/joey-zhou/xiaozhi-esp32-server-java) Java server
|
||||
- [AnimeAIChat/xiaozhi-server-go](https://github.com/AnimeAIChat/xiaozhi-server-go) Golang server
|
||||
- [xinnan-tech/xiaozhi-esp32-server](https://github.com/xinnan-tech/xiaozhi-esp32-server) Python 服务器
|
||||
- [joey-zhou/xiaozhi-esp32-server-java](https://github.com/joey-zhou/xiaozhi-esp32-server-java) Java 服务器
|
||||
- [AnimeAIChat/xiaozhi-server-go](https://github.com/AnimeAIChat/xiaozhi-server-go) Golang 服务器
|
||||
|
||||
Other client projects using the XiaoZhi communication protocol:
|
||||
使用小智通信协议的第三方客户端项目:
|
||||
|
||||
- [huangjunsen0406/py-xiaozhi](https://github.com/huangjunsen0406/py-xiaozhi) Python client
|
||||
- [TOM88812/xiaozhi-android-client](https://github.com/TOM88812/xiaozhi-android-client) Android client
|
||||
- [100askTeam/xiaozhi-linux](http://github.com/100askTeam/xiaozhi-linux) Linux client by 100ask
|
||||
- [78/xiaozhi-sf32](https://github.com/78/xiaozhi-sf32) Bluetooth chip firmware by Sichuan
|
||||
- [QuecPython/solution-xiaozhiAI](https://github.com/QuecPython/solution-xiaozhiAI) QuecPython firmware by Quectel
|
||||
|
||||
Custom Assets Tools:
|
||||
|
||||
- [78/xiaozhi-assets-generator](https://github.com/78/xiaozhi-assets-generator) Custom Assets Generator (Wake words, fonts, emojis, backgrounds)
|
||||
|
||||
## About the Project
|
||||
|
||||
This is an open-source ESP32 project, released under the MIT license, allowing anyone to use it for free, including for commercial purposes.
|
||||
|
||||
We hope this project helps everyone understand AI hardware development and apply rapidly evolving large language models to real hardware devices.
|
||||
|
||||
If you have any ideas or suggestions, please feel free to raise Issues or join the QQ group: 1011329060
|
||||
- [huangjunsen0406/py-xiaozhi](https://github.com/huangjunsen0406/py-xiaozhi) Python 客户端
|
||||
- [TOM88812/xiaozhi-android-client](https://github.com/TOM88812/xiaozhi-android-client) Android 客户端
|
||||
- [100askTeam/xiaozhi-linux](http://github.com/100askTeam/xiaozhi-linux) 百问科技提供的 Linux 客户端
|
||||
- [78/xiaozhi-sf32](https://github.com/78/xiaozhi-sf32) 思澈科技的蓝牙芯片固件
|
||||
- [QuecPython/solution-xiaozhiAI](https://github.com/QuecPython/solution-xiaozhiAI) 移远提供的 QuecPython 固件
|
||||
|
||||
## Star History
|
||||
|
||||
@ -169,4 +158,4 @@ If you have any ideas or suggestions, please feel free to raise Issues or join t
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
</a>
|
||||
|
||||
157
README_en.md
Normal file
157
README_en.md
Normal file
@ -0,0 +1,157 @@
|
||||
# An MCP-based Chatbot
|
||||
|
||||
(English | [中文](README.md) | [日本語](README_ja.md))
|
||||
|
||||
## Video
|
||||
|
||||
👉 [Human: Give AI a camera vs AI: Instantly finds out the owner hasn't washed hair for three days【bilibili】](https://www.bilibili.com/video/BV1bpjgzKEhd/)
|
||||
|
||||
👉 [Handcraft your AI girlfriend, beginner's guide【bilibili】](https://www.bilibili.com/video/BV1XnmFYLEJN/)
|
||||
|
||||
## Introduction
|
||||
|
||||
This is an open-source ESP32 project, released under the MIT license, allowing anyone to use it for free, including for commercial purposes.
|
||||
|
||||
We hope this project helps everyone understand AI hardware development and apply rapidly evolving large language models to real hardware devices.
|
||||
|
||||
If you have any ideas or suggestions, please feel free to raise Issues or join the QQ group: 1011329060
|
||||
|
||||
### Control Everything with MCP
|
||||
|
||||
As a voice interaction entry, the XiaoZhi AI chatbot leverages the AI capabilities of large models like Qwen / DeepSeek, and achieves multi-terminal control via the MCP protocol.
|
||||
|
||||

|
||||
|
||||
### Features Implemented
|
||||
|
||||
- Wi-Fi / ML307 Cat.1 4G
|
||||
- Offline voice wake-up [ESP-SR](https://github.com/espressif/esp-sr)
|
||||
- Supports two communication protocols ([Websocket](docs/websocket.md) or MQTT+UDP)
|
||||
- Uses OPUS audio codec
|
||||
- Voice interaction based on streaming ASR + LLM + TTS architecture
|
||||
- Speaker recognition, identifies the current speaker [3D Speaker](https://github.com/modelscope/3D-Speaker)
|
||||
- OLED / LCD display, supports emoji display
|
||||
- Battery display and power management
|
||||
- Multi-language support (Chinese, English, Japanese)
|
||||
- Supports ESP32-C3, ESP32-S3, ESP32-P4 chip platforms
|
||||
- Device-side MCP for device control (Speaker, LED, Servo, GPIO, etc.)
|
||||
- Cloud-side MCP to extend large model capabilities (smart home control, PC desktop operation, knowledge search, email, etc.)
|
||||
|
||||
## Hardware
|
||||
|
||||
### Breadboard DIY Practice
|
||||
|
||||
See the Feishu document tutorial:
|
||||
|
||||
👉 ["XiaoZhi AI Chatbot Encyclopedia"](https://ccnphfhqs21z.feishu.cn/wiki/F5krwD16viZoF0kKkvDcrZNYnhb?from=from_copylink)
|
||||
|
||||
Breadboard demo:
|
||||
|
||||

|
||||
|
||||
### Supports 70+ Open Source Hardware (Partial List)
|
||||
|
||||
- <a href="https://oshwhub.com/li-chuang-kai-fa-ban/li-chuang-shi-zhan-pai-esp32-s3-kai-fa-ban" target="_blank" title="LiChuang ESP32-S3 Development Board">LiChuang ESP32-S3 Development Board</a>
|
||||
- <a href="https://github.com/espressif/esp-box" target="_blank" title="Espressif ESP32-S3-BOX3">Espressif ESP32-S3-BOX3</a>
|
||||
- <a href="https://docs.m5stack.com/zh_CN/core/CoreS3" target="_blank" title="M5Stack CoreS3">M5Stack CoreS3</a>
|
||||
- <a href="https://docs.m5stack.com/en/atom/Atomic%20Echo%20Base" target="_blank" title="AtomS3R + Echo Base">M5Stack AtomS3R + Echo Base</a>
|
||||
- <a href="https://gf.bilibili.com/item/detail/1108782064" target="_blank" title="Magic Button 2.4">Magic Button 2.4</a>
|
||||
- <a href="https://www.waveshare.net/shop/ESP32-S3-Touch-AMOLED-1.8.htm" target="_blank" title="Waveshare ESP32-S3-Touch-AMOLED-1.8">Waveshare ESP32-S3-Touch-AMOLED-1.8</a>
|
||||
- <a href="https://github.com/Xinyuan-LilyGO/T-Circle-S3" target="_blank" title="LILYGO T-Circle-S3">LILYGO T-Circle-S3</a>
|
||||
- <a href="https://oshwhub.com/tenclass01/xmini_c3" target="_blank" title="XiaGe Mini C3">XiaGe Mini C3</a>
|
||||
- <a href="https://oshwhub.com/movecall/cuican-ai-pendant-lights-up-y" target="_blank" title="Movecall CuiCan ESP32S3">CuiCan AI Pendant</a>
|
||||
- <a href="https://github.com/WMnologo/xingzhi-ai" target="_blank" title="WMnologo-Xingzhi-1.54">WMnologo-Xingzhi-1.54TFT</a>
|
||||
- <a href="https://www.seeedstudio.com/SenseCAP-Watcher-W1-A-p-5979.html" target="_blank" title="SenseCAP Watcher">SenseCAP Watcher</a>
|
||||
- <a href="https://www.bilibili.com/video/BV1BHJtz6E2S/" target="_blank" title="ESP-HI Low Cost Robot Dog">ESP-HI Low Cost Robot Dog</a>
|
||||
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<a href="docs/v1/lichuang-s3.jpg" target="_blank" title="LiChuang ESP32-S3 Development Board">
|
||||
<img src="docs/v1/lichuang-s3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/espbox3.jpg" target="_blank" title="Espressif ESP32-S3-BOX3">
|
||||
<img src="docs/v1/espbox3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/m5cores3.jpg" target="_blank" title="M5Stack CoreS3">
|
||||
<img src="docs/v1/m5cores3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/atoms3r.jpg" target="_blank" title="AtomS3R + Echo Base">
|
||||
<img src="docs/v1/atoms3r.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/magiclick.jpg" target="_blank" title="Magic Button 2.4">
|
||||
<img src="docs/v1/magiclick.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/waveshare.jpg" target="_blank" title="Waveshare ESP32-S3-Touch-AMOLED-1.8">
|
||||
<img src="docs/v1/waveshare.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/lilygo-t-circle-s3.jpg" target="_blank" title="LILYGO T-Circle-S3">
|
||||
<img src="docs/v1/lilygo-t-circle-s3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/xmini-c3.jpg" target="_blank" title="XiaGe Mini C3">
|
||||
<img src="docs/v1/xmini-c3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/movecall-cuican-esp32s3.jpg" target="_blank" title="CuiCan">
|
||||
<img src="docs/v1/movecall-cuican-esp32s3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/wmnologo_xingzhi_1.54.jpg" target="_blank" title="WMnologo-Xingzhi-1.54">
|
||||
<img src="docs/v1/wmnologo_xingzhi_1.54.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/sensecap_watcher.jpg" target="_blank" title="SenseCAP Watcher">
|
||||
<img src="docs/v1/sensecap_watcher.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/esp-hi.jpg" target="_blank" title="ESP-HI Low Cost Robot Dog">
|
||||
<img src="docs/v1/esp-hi.jpg" width="240" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## Software
|
||||
|
||||
### Firmware Flashing
|
||||
|
||||
For beginners, it is recommended to use the firmware that can be flashed without setting up a development environment.
|
||||
|
||||
The firmware connects to the official [xiaozhi.me](https://xiaozhi.me) server by default. Personal users can register an account to use the Qwen real-time model for free.
|
||||
|
||||
👉 [Beginner's Firmware Flashing Guide](https://ccnphfhqs21z.feishu.cn/wiki/Zpz4wXBtdimBrLk25WdcXzxcnNS)
|
||||
|
||||
### Development Environment
|
||||
|
||||
- Cursor or VSCode
|
||||
- Install ESP-IDF plugin, select SDK version 5.4 or above
|
||||
- Linux is better than Windows for faster compilation and fewer driver issues
|
||||
- This project uses Google C++ code style, please ensure compliance when submitting code
|
||||
|
||||
### Developer Documentation
|
||||
|
||||
- [Custom Board Guide](main/boards/README.md) - Learn how to create custom boards for XiaoZhi AI
|
||||
- [MCP Protocol IoT Control Usage](docs/mcp-usage.md) - Learn how to control IoT devices via MCP protocol
|
||||
- [MCP Protocol Interaction Flow](docs/mcp-protocol.md) - Device-side MCP protocol implementation
|
||||
- [A detailed WebSocket communication protocol document](docs/websocket.md)
|
||||
|
||||
## Large Model Configuration
|
||||
|
||||
If you already have a XiaoZhi AI chatbot device and have connected to the official server, you can log in to the [xiaozhi.me](https://xiaozhi.me) console for configuration.
|
||||
|
||||
👉 [Backend Operation Video Tutorial (Old Interface)](https://www.bilibili.com/video/BV1jUCUY2EKM/)
|
||||
|
||||
## Related Open Source Projects
|
||||
|
||||
For server deployment on personal computers, refer to the following open-source projects:
|
||||
|
||||
- [xinnan-tech/xiaozhi-esp32-server](https://github.com/xinnan-tech/xiaozhi-esp32-server) Python server
|
||||
- [joey-zhou/xiaozhi-esp32-server-java](https://github.com/joey-zhou/xiaozhi-esp32-server-java) Java server
|
||||
- [AnimeAIChat/xiaozhi-server-go](https://github.com/AnimeAIChat/xiaozhi-server-go) Golang server
|
||||
|
||||
Other client projects using the XiaoZhi communication protocol:
|
||||
|
||||
- [huangjunsen0406/py-xiaozhi](https://github.com/huangjunsen0406/py-xiaozhi) Python client
|
||||
- [TOM88812/xiaozhi-android-client](https://github.com/TOM88812/xiaozhi-android-client) Android client
|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://star-history.com/#78/xiaozhi-esp32&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
39
README_ja.md
39
README_ja.md
@ -1,24 +1,26 @@
|
||||
# MCP ベースのチャットボット
|
||||
|
||||
(日本語 | [中文](README_zh.md) | [English](README.md))
|
||||
(日本語 | [中文](README.md) | [English](README_en.md))
|
||||
|
||||
## はじめに
|
||||
## 動画
|
||||
|
||||
👉 [人間:AIにカメラを装着 vs AI:その場で飼い主が3日間髪を洗っていないことを発見【bilibili】](https://www.bilibili.com/video/BV1bpjgzKEhd/)
|
||||
|
||||
👉 [手作りでAIガールフレンドを作る、初心者入門チュートリアル【bilibili】](https://www.bilibili.com/video/BV1XnmFYLEJN/)
|
||||
|
||||
## イントロダクション
|
||||
|
||||
これはエビ兄さんがオープンソースで公開しているESP32プロジェクトで、MITライセンスのもと、誰でも無料で、商用利用も可能です。
|
||||
|
||||
このプロジェクトを通じて、AIハードウェア開発を理解し、急速に進化する大規模言語モデルを実際のハードウェアデバイスに応用できるようになることを目指しています。
|
||||
|
||||
ご意見やご提案があれば、いつでもIssueを提出するか、QQグループ:1011329060 にご参加ください。
|
||||
|
||||
### MCPであらゆるものを制御
|
||||
|
||||
シャオジーAIチャットボットは音声インタラクションの入口として、Qwen / DeepSeekなどの大規模モデルのAI能力を活用し、MCPプロトコルを通じてマルチエンド制御を実現します。
|
||||
|
||||
<img src="docs/mcp-based-graph.jpg" alt="MCPであらゆるものを制御" width="320">
|
||||
|
||||
## バージョンノート
|
||||
|
||||
現在のv2バージョンはv1パーティションテーブルと互換性がないため、v1からv2へOTAでアップグレードすることはできません。パーティションテーブルの詳細については、[partitions/v2/README.md](partitions/v2/README.md)をご参照ください。
|
||||
|
||||
v1を実行しているすべてのハードウェアは、ファームウェアを手動で書き込むことでv2にアップグレードできます。
|
||||
|
||||
v1の安定版は1.9.2です。`git checkout v1`でv1に切り替えることができます。v1ブランチは2026年2月まで継続的にメンテナンスされます。
|
||||

|
||||
|
||||
### 実装済み機能
|
||||
|
||||
@ -34,7 +36,6 @@ v1の安定版は1.9.2です。`git checkout v1`でv1に切り替えることが
|
||||
- ESP32-C3、ESP32-S3、ESP32-P4チッププラットフォーム対応
|
||||
- デバイス側MCPによるデバイス制御(音量・明るさ調整、アクション制御など)
|
||||
- クラウド側MCPで大規模モデル能力を拡張(スマートホーム制御、PCデスクトップ操作、知識検索、メール送受信など)
|
||||
- カスタマイズ可能なウェイクワード、フォント、絵文字、チャット背景、オンラインWeb編集に対応 ([カスタムアセットジェネレーター](https://github.com/78/xiaozhi-assets-generator))
|
||||
|
||||
## ハードウェア
|
||||
|
||||
@ -121,10 +122,9 @@ Feishuドキュメントチュートリアルをご覧ください:
|
||||
|
||||
### 開発者ドキュメント
|
||||
|
||||
- [カスタム開発ボードガイド](docs/custom-board.md) - シャオジーAI用のカスタム開発ボード作成方法
|
||||
- [カスタム開発ボードガイド](main/boards/README.md) - シャオジーAI用のカスタム開発ボード作成方法
|
||||
- [MCPプロトコルIoT制御使用法](docs/mcp-usage.md) - MCPプロトコルでIoTデバイスを制御する方法
|
||||
- [MCPプロトコルインタラクションフロー](docs/mcp-protocol.md) - デバイス側MCPプロトコルの実装方法
|
||||
- [MQTT + UDP ハイブリッド通信プロトコルドキュメント](docs/mqtt-udp.md)
|
||||
- [詳細なWebSocket通信プロトコルドキュメント](docs/websocket.md)
|
||||
|
||||
## 大規模モデル設定
|
||||
@ -145,17 +145,6 @@ Feishuドキュメントチュートリアルをご覧ください:
|
||||
|
||||
- [huangjunsen0406/py-xiaozhi](https://github.com/huangjunsen0406/py-xiaozhi) Pythonクライアント
|
||||
- [TOM88812/xiaozhi-android-client](https://github.com/TOM88812/xiaozhi-android-client) Androidクライアント
|
||||
- [100askTeam/xiaozhi-linux](http://github.com/100askTeam/xiaozhi-linux) 百問科技提供のLinuxクライアント
|
||||
- [78/xiaozhi-sf32](https://github.com/78/xiaozhi-sf32) 思澈科技のBluetoothチップファームウェア
|
||||
- [QuecPython/solution-xiaozhiAI](https://github.com/QuecPython/solution-xiaozhiAI) 移遠提供のQuecPythonファームウェア
|
||||
|
||||
## プロジェクトについて
|
||||
|
||||
これはエビ兄さんがオープンソースで公開しているESP32プロジェクトで、MITライセンスのもと、誰でも無料で、商用利用も可能です。
|
||||
|
||||
このプロジェクトを通じて、AIハードウェア開発を理解し、急速に進化する大規模言語モデルを実際のハードウェアデバイスに応用できるようになることを目指しています。
|
||||
|
||||
ご意見やご提案があれば、いつでもIssueを提出するか、QQグループ:1011329060 にご参加ください。
|
||||
|
||||
## スター履歴
|
||||
|
||||
|
||||
168
README_zh.md
168
README_zh.md
@ -1,168 +0,0 @@
|
||||
# An MCP-based Chatbot
|
||||
|
||||
(中文 | [English](README.md) | [日本語](README_ja.md))
|
||||
|
||||
## 介绍
|
||||
|
||||
👉 [人类:给 AI 装摄像头 vs AI:当场发现主人三天没洗头【bilibili】](https://www.bilibili.com/video/BV1bpjgzKEhd/)
|
||||
|
||||
👉 [手工打造你的 AI 女友,新手入门教程【bilibili】](https://www.bilibili.com/video/BV1XnmFYLEJN/)
|
||||
|
||||
小智 AI 聊天机器人作为一个语音交互入口,利用 Qwen / DeepSeek 等大模型的 AI 能力,通过 MCP 协议实现多端控制。
|
||||
|
||||
<img src="docs/mcp-based-graph.jpg" alt="通过MCP控制万物" width="320">
|
||||
|
||||
### 版本说明
|
||||
|
||||
当前 v2 版本与 v1 版本分区表不兼容,所以无法从 v1 版本通过 OTA 升级到 v2 版本。分区表说明参见 [partitions/v2/README.md](partitions/v2/README.md)。
|
||||
|
||||
使用 v1 版本的所有硬件,可以通过手动烧录固件来升级到 v2 版本。
|
||||
|
||||
v1 的稳定版本为 1.9.2,可以通过 `git checkout v1` 来切换到 v1 版本,该分支会持续维护到 2026 年 2 月。
|
||||
|
||||
### 已实现功能
|
||||
|
||||
- Wi-Fi / ML307 Cat.1 4G
|
||||
- 离线语音唤醒 [ESP-SR](https://github.com/espressif/esp-sr)
|
||||
- 支持两种通信协议([Websocket](docs/websocket.md) 或 MQTT+UDP)
|
||||
- 采用 OPUS 音频编解码
|
||||
- 基于流式 ASR + LLM + TTS 架构的语音交互
|
||||
- 声纹识别,识别当前说话人的身份 [3D Speaker](https://github.com/modelscope/3D-Speaker)
|
||||
- OLED / LCD 显示屏,支持表情显示
|
||||
- 电量显示与电源管理
|
||||
- 支持多语言(中文、英文、日文)
|
||||
- 支持 ESP32-C3、ESP32-S3、ESP32-P4 芯片平台
|
||||
- 通过设备端 MCP 实现设备控制(音量、灯光、电机、GPIO 等)
|
||||
- 通过云端 MCP 扩展大模型能力(智能家居控制、PC桌面操作、知识搜索、邮件收发等)
|
||||
- 自定义唤醒词、字体、表情与聊天背景,支持网页端在线修改 ([自定义Assets生成器](https://github.com/78/xiaozhi-assets-generator))
|
||||
|
||||
## 硬件
|
||||
|
||||
### 面包板手工制作实践
|
||||
|
||||
详见飞书文档教程:
|
||||
|
||||
👉 [《小智 AI 聊天机器人百科全书》](https://ccnphfhqs21z.feishu.cn/wiki/F5krwD16viZoF0kKkvDcrZNYnhb?from=from_copylink)
|
||||
|
||||
面包板效果图如下:
|
||||
|
||||

|
||||
|
||||
### 支持 70 多个开源硬件(仅展示部分)
|
||||
|
||||
- <a href="https://oshwhub.com/li-chuang-kai-fa-ban/li-chuang-shi-zhan-pai-esp32-s3-kai-fa-ban" target="_blank" title="立创·实战派 ESP32-S3 开发板">立创·实战派 ESP32-S3 开发板</a>
|
||||
- <a href="https://github.com/espressif/esp-box" target="_blank" title="乐鑫 ESP32-S3-BOX3">乐鑫 ESP32-S3-BOX3</a>
|
||||
- <a href="https://docs.m5stack.com/zh_CN/core/CoreS3" target="_blank" title="M5Stack CoreS3">M5Stack CoreS3</a>
|
||||
- <a href="https://docs.m5stack.com/en/atom/Atomic%20Echo%20Base" target="_blank" title="AtomS3R + Echo Base">M5Stack AtomS3R + Echo Base</a>
|
||||
- <a href="https://gf.bilibili.com/item/detail/1108782064" target="_blank" title="神奇按钮 2.4">神奇按钮 2.4</a>
|
||||
- <a href="https://www.waveshare.net/shop/ESP32-S3-Touch-AMOLED-1.8.htm" target="_blank" title="微雪电子 ESP32-S3-Touch-AMOLED-1.8">微雪电子 ESP32-S3-Touch-AMOLED-1.8</a>
|
||||
- <a href="https://github.com/Xinyuan-LilyGO/T-Circle-S3" target="_blank" title="LILYGO T-Circle-S3">LILYGO T-Circle-S3</a>
|
||||
- <a href="https://oshwhub.com/tenclass01/xmini_c3" target="_blank" title="虾哥 Mini C3">虾哥 Mini C3</a>
|
||||
- <a href="https://oshwhub.com/movecall/cuican-ai-pendant-lights-up-y" target="_blank" title="Movecall CuiCan ESP32S3">璀璨·AI 吊坠</a>
|
||||
- <a href="https://github.com/WMnologo/xingzhi-ai" target="_blank" title="无名科技Nologo-星智-1.54">无名科技 Nologo-星智-1.54TFT</a>
|
||||
- <a href="https://www.seeedstudio.com/SenseCAP-Watcher-W1-A-p-5979.html" target="_blank" title="SenseCAP Watcher">SenseCAP Watcher</a>
|
||||
- <a href="https://www.bilibili.com/video/BV1BHJtz6E2S/" target="_blank" title="ESP-HI 超低成本机器狗">ESP-HI 超低成本机器狗</a>
|
||||
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<a href="docs/v1/lichuang-s3.jpg" target="_blank" title="立创·实战派 ESP32-S3 开发板">
|
||||
<img src="docs/v1/lichuang-s3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/espbox3.jpg" target="_blank" title="乐鑫 ESP32-S3-BOX3">
|
||||
<img src="docs/v1/espbox3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/m5cores3.jpg" target="_blank" title="M5Stack CoreS3">
|
||||
<img src="docs/v1/m5cores3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/atoms3r.jpg" target="_blank" title="AtomS3R + Echo Base">
|
||||
<img src="docs/v1/atoms3r.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/magiclick.jpg" target="_blank" title="神奇按钮 2.4">
|
||||
<img src="docs/v1/magiclick.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/waveshare.jpg" target="_blank" title="微雪电子 ESP32-S3-Touch-AMOLED-1.8">
|
||||
<img src="docs/v1/waveshare.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/lilygo-t-circle-s3.jpg" target="_blank" title="LILYGO T-Circle-S3">
|
||||
<img src="docs/v1/lilygo-t-circle-s3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/xmini-c3.jpg" target="_blank" title="虾哥 Mini C3">
|
||||
<img src="docs/v1/xmini-c3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/movecall-cuican-esp32s3.jpg" target="_blank" title="CuiCan">
|
||||
<img src="docs/v1/movecall-cuican-esp32s3.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/wmnologo_xingzhi_1.54.jpg" target="_blank" title="无名科技Nologo-星智-1.54">
|
||||
<img src="docs/v1/wmnologo_xingzhi_1.54.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/sensecap_watcher.jpg" target="_blank" title="SenseCAP Watcher">
|
||||
<img src="docs/v1/sensecap_watcher.jpg" width="240" />
|
||||
</a>
|
||||
<a href="docs/v1/esp-hi.jpg" target="_blank" title="ESP-HI 超低成本机器狗">
|
||||
<img src="docs/v1/esp-hi.jpg" width="240" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## 软件
|
||||
|
||||
### 固件烧录
|
||||
|
||||
新手第一次操作建议先不要搭建开发环境,直接使用免开发环境烧录的固件。
|
||||
|
||||
固件默认接入 [xiaozhi.me](https://xiaozhi.me) 官方服务器,个人用户注册账号可以免费使用 Qwen 实时模型。
|
||||
|
||||
👉 [新手烧录固件教程](https://ccnphfhqs21z.feishu.cn/wiki/Zpz4wXBtdimBrLk25WdcXzxcnNS)
|
||||
|
||||
### 开发环境
|
||||
|
||||
- Cursor 或 VSCode
|
||||
- 安装 ESP-IDF 插件,选择 SDK 版本 5.4 或以上
|
||||
- Linux 比 Windows 更好,编译速度快,也免去驱动问题的困扰
|
||||
- 本项目使用 Google C++ 代码风格,提交代码时请确保符合规范
|
||||
|
||||
### 开发者文档
|
||||
|
||||
- [自定义开发板指南](docs/custom-board.md) - 学习如何为小智 AI 创建自定义开发板
|
||||
- [MCP 协议物联网控制用法说明](docs/mcp-usage.md) - 了解如何通过 MCP 协议控制物联网设备
|
||||
- [MCP 协议交互流程](docs/mcp-protocol.md) - 设备端 MCP 协议的实现方式
|
||||
- [MQTT + UDP 混合通信协议文档](docs/mqtt-udp.md)
|
||||
- [一份详细的 WebSocket 通信协议文档](docs/websocket.md)
|
||||
|
||||
## 大模型配置
|
||||
|
||||
如果你已经拥有一个小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
|
||||
|
||||
👉 [后台操作视频教程(旧版界面)](https://www.bilibili.com/video/BV1jUCUY2EKM/)
|
||||
|
||||
## 相关开源项目
|
||||
|
||||
在个人电脑上部署服务器,可以参考以下第三方开源的项目:
|
||||
|
||||
- [xinnan-tech/xiaozhi-esp32-server](https://github.com/xinnan-tech/xiaozhi-esp32-server) Python 服务器
|
||||
- [joey-zhou/xiaozhi-esp32-server-java](https://github.com/joey-zhou/xiaozhi-esp32-server-java) Java 服务器
|
||||
- [AnimeAIChat/xiaozhi-server-go](https://github.com/AnimeAIChat/xiaozhi-server-go) Golang 服务器
|
||||
|
||||
使用小智通信协议的第三方客户端项目:
|
||||
|
||||
- [huangjunsen0406/py-xiaozhi](https://github.com/huangjunsen0406/py-xiaozhi) Python 客户端
|
||||
- [TOM88812/xiaozhi-android-client](https://github.com/TOM88812/xiaozhi-android-client) Android 客户端
|
||||
- [100askTeam/xiaozhi-linux](http://github.com/100askTeam/xiaozhi-linux) 百问科技提供的 Linux 客户端
|
||||
- [78/xiaozhi-sf32](https://github.com/78/xiaozhi-sf32) 思澈科技的蓝牙芯片固件
|
||||
- [QuecPython/solution-xiaozhiAI](https://github.com/QuecPython/solution-xiaozhiAI) 移远提供的 QuecPython 固件
|
||||
|
||||
## 关于项目
|
||||
|
||||
这是一个由虾哥开源的 ESP32 项目,以 MIT 许可证发布,允许任何人免费使用,修改或用于商业用途。
|
||||
|
||||
我们希望通过这个项目,能够帮助大家了解 AI 硬件开发,将当下飞速发展的大语言模型应用到实际的硬件设备中。
|
||||
|
||||
如果你有任何想法或建议,请随时提出 Issues 或加入 QQ 群:1011329060
|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://star-history.com/#78/xiaozhi-esp32&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
@ -1,36 +0,0 @@
|
||||
# BluFi 配网(集成 esp-wifi-connect)
|
||||
|
||||
本文档说明如何在小智固件中启用和使用 BluFi(BLE Wi‑Fi 配网),并结合项目内置的 `esp-wifi-connect` 组件完成 Wi‑Fi 连接与存储。官方
|
||||
BluFi
|
||||
协议说明请参考 [Espressif 文档](https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32/api-guides/ble/blufi.html)。
|
||||
|
||||
## 前置条件
|
||||
|
||||
- 需要支持 BLE 的芯片与固件配置。
|
||||
- 在 `idf.py menuconfig` 中启用 `WiFi Configuration Method -> Esp Blufi`(`CONFIG_USE_ESP_BLUFI_WIFI_PROVISIONING=y`
|
||||
)。如果只想用 BluFi,可关闭同一菜单下的 Hotspot/Acoustic 选项。
|
||||
|
||||
- 保持默认的 NVS 与事件循环初始化(项目的 `app_main` 已处理)。
|
||||
- CONFIG_BT_BLUEDROID_ENABLED、CONFIG_BT_NIMBLE_ENABLED这两个宏应二选一,不能同时启用。
|
||||
## 工作流程
|
||||
|
||||
1) 手机端通过 BluFi(如官方 EspBlufi App 或自研客户端)连接设备,发送 Wi‑Fi SSID/密码。
|
||||
2) 设备侧在 `ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP` 中将凭据写入 `SsidManager`(存储到 NVS,属于 `esp-wifi-connect` 组件)。
|
||||
3) 随后启动 `WifiStation` 扫描并连接;状态通过 BluFi 返回。
|
||||
4) 配网成功后设备会自动连接新 Wi‑Fi;失败则返回失败状态。
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 配置:在 menuconfig 开启 `Esp Blufi`。编译并烧录固件。
|
||||
2. 触发配网:设备首次启动且没有已保存的 Wi‑Fi 时会自动进入配网。
|
||||
3. 手机端操作:打开 EspBlufi App(或其他 BluFi 客户端),搜索并连接设备,可以选择是否加密,按提示输入 Wi‑Fi SSID/密码并发送。
|
||||
4. 观察结果:
|
||||
- 成功:BluFi 报告连接成功,设备自动连接 Wi‑Fi。
|
||||
- 失败:BluFi 返回失败状态,可重新发送或检查路由器。
|
||||
|
||||
## 注意事项
|
||||
|
||||
- BluFi 与 Hotspot/声波配网可以同时编译,但会同时启动,增加内存占用。建议在 menuconfig 中只保留一种方式。
|
||||
- 若多次测试,建议清除或覆盖存储的 SSID(`wifi` 命名空间),避免旧配置干扰。
|
||||
- 如果使用自定义 BluFi 客户端,需遵循官方协议帧格式,参考上文官方文档链接。
|
||||
- 官方文档中已提供EspBlufi APP下载地址
|
||||
File diff suppressed because it is too large
Load Diff
@ -8,8 +8,7 @@ config OTA_URL
|
||||
|
||||
choice
|
||||
prompt "Flash Assets"
|
||||
default FLASH_DEFAULT_ASSETS if !USE_EMOTE_MESSAGE_STYLE
|
||||
default FLASH_EXPRESSION_ASSETS if USE_EMOTE_MESSAGE_STYLE
|
||||
default FLASH_NONE_ASSETS
|
||||
help
|
||||
Select the assets to flash.
|
||||
|
||||
@ -17,12 +16,8 @@ choice
|
||||
bool "Do not flash assets"
|
||||
config FLASH_DEFAULT_ASSETS
|
||||
bool "Flash Default Assets"
|
||||
depends on !USE_EMOTE_MESSAGE_STYLE
|
||||
config FLASH_CUSTOM_ASSETS
|
||||
bool "Flash Custom Assets"
|
||||
config FLASH_EXPRESSION_ASSETS
|
||||
bool "Flash Emote Assets"
|
||||
depends on USE_EMOTE_MESSAGE_STYLE
|
||||
endchoice
|
||||
|
||||
config CUSTOM_ASSETS_FILE
|
||||
@ -83,38 +78,6 @@ choice
|
||||
bool "Ukrainian"
|
||||
config LANGUAGE_RO_RO
|
||||
bool "Romanian"
|
||||
config LANGUAGE_BG_BG
|
||||
bool "Bulgarian"
|
||||
config LANGUAGE_CA_ES
|
||||
bool "Catalan"
|
||||
config LANGUAGE_DA_DK
|
||||
bool "Danish"
|
||||
config LANGUAGE_EL_GR
|
||||
bool "Greek"
|
||||
config LANGUAGE_FA_IR
|
||||
bool "Persian"
|
||||
config LANGUAGE_FIL_PH
|
||||
bool "Filipino"
|
||||
config LANGUAGE_HE_IL
|
||||
bool "Hebrew"
|
||||
config LANGUAGE_HR_HR
|
||||
bool "Croatian"
|
||||
config LANGUAGE_HU_HU
|
||||
bool "Hungarian"
|
||||
config LANGUAGE_MS_MY
|
||||
bool "Malay"
|
||||
config LANGUAGE_NB_NO
|
||||
bool "Norwegian"
|
||||
config LANGUAGE_NL_NL
|
||||
bool "Dutch"
|
||||
config LANGUAGE_SK_SK
|
||||
bool "Slovak"
|
||||
config LANGUAGE_SL_SI
|
||||
bool "Slovenian"
|
||||
config LANGUAGE_SV_SE
|
||||
bool "Swedish"
|
||||
config LANGUAGE_SR_RS
|
||||
bool "Serbian"
|
||||
endchoice
|
||||
|
||||
choice BOARD_TYPE
|
||||
@ -123,65 +86,59 @@ choice BOARD_TYPE
|
||||
help
|
||||
Board type. 开发板类型
|
||||
config BOARD_TYPE_BREAD_COMPACT_WIFI
|
||||
bool "Bread Compact WiFi (面包板)"
|
||||
bool "面包板新版接线(WiFi)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_WIFI_LCD
|
||||
bool "Bread Compact WiFi + LCD (面包板)"
|
||||
bool "面包板新版接线(WiFi)+ LCD"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
|
||||
bool "Bread Compact WiFi + LCD + Camera (面包板)"
|
||||
bool "面包板新版接线(WiFi)+ LCD + Camera"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_ML307
|
||||
bool "Bread Compact ML307/EC801E (面包板 4G)"
|
||||
bool "面包板新版接线(ML307 AT)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_ESP32
|
||||
bool "Bread Compact ESP32 DevKit (面包板)"
|
||||
bool "面包板(WiFi) ESP32 DevKit"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_BREAD_COMPACT_ESP32_LCD
|
||||
bool "Bread Compact ESP32 DevKit + LCD (面包板)"
|
||||
bool "面包板(WiFi+ LCD) ESP32 DevKit"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_XMINI_C3_V3
|
||||
bool "Xmini C3 V3"
|
||||
bool "虾哥 Mini C3 V3"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_XMINI_C3_4G
|
||||
bool "Xmini C3 4G"
|
||||
bool "虾哥 Mini C3 4G"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_XMINI_C3
|
||||
bool "Xmini C3"
|
||||
bool "虾哥 Mini C3"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_ESP_KORVO2_V3
|
||||
bool "Espressif Korvo2 V3"
|
||||
config BOARD_TYPE_ESP32S3_KORVO2_V3
|
||||
bool "ESP32S3_KORVO2_V3开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_SPARKBOT
|
||||
bool "Espressif SparkBot"
|
||||
bool "ESP-SparkBot开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_SENSAIRSHUTTLE
|
||||
bool "Espressif ESP-SensairShuttle"
|
||||
depends on IDF_TARGET_ESP32C5
|
||||
config BOARD_TYPE_ESP_SPOT_S3
|
||||
bool "Espressif Spot-S3"
|
||||
bool "ESP-Spot-S3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_SPOT_C5
|
||||
bool "Espressif Spot-C5"
|
||||
depends on IDF_TARGET_ESP32C5
|
||||
config BOARD_TYPE_ESP_HI
|
||||
bool "Espressif ESP-HI"
|
||||
bool "ESP-HI"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_ESP_BOX_3
|
||||
bool "Espressif ESP-BOX-3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_BOX
|
||||
bool "Espressif ESP-BOX"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_BOX_LITE
|
||||
bool "Espressif ESP-BOX-Lite"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_P4_FUNCTION_EV_BOARD
|
||||
bool "Espressif ESP-P4-Function-EV-Board"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_ECHOEAR
|
||||
bool "EchoEar"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_BOX_3
|
||||
bool "ESP BOX 3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_BOX
|
||||
bool "ESP BOX"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_BOX_LITE
|
||||
bool "ESP BOX Lite"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_KEVIN_BOX_1
|
||||
bool "Kevin Box 1"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_KEVIN_BOX_2
|
||||
bool "Kevin Box 2"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@ -189,25 +146,25 @@ choice BOARD_TYPE
|
||||
bool "Kevin C3"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_KEVIN_SP_V3_DEV
|
||||
bool "Kevin SP V3"
|
||||
bool "Kevin SP V3开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_KEVIN_SP_V4_DEV
|
||||
bool "Kevin SP V4"
|
||||
bool "Kevin SP V4开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32_CGC
|
||||
bool "ESP32 CGC"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_ESP32_CGC_144
|
||||
bool "ESP32 CGC 144"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_KEVIN_YUYING_313LCD
|
||||
bool "鱼鹰科技 3.13LCD"
|
||||
bool "鱼鹰科技3.13LCD开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_CGC
|
||||
bool "CGC"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_CGC_144
|
||||
bool "CGC 144"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_LICHUANG_DEV_S3
|
||||
bool "立创·实战派 ESP32-S3"
|
||||
config BOARD_TYPE_LICHUANG_DEV
|
||||
bool "立创·实战派ESP32-S3开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LICHUANG_DEV_C3
|
||||
bool "立创·实战派 ESP32-C3"
|
||||
config BOARD_TYPE_LICHUANG_C3_DEV
|
||||
bool "立创·实战派ESP32-C3开发板"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_DF_K10
|
||||
bool "DFRobot 行空板 k10"
|
||||
@ -215,10 +172,10 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_DF_S3_AI_CAM
|
||||
bool "DFRobot ESP32-S3 AI智能摄像头模块"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_MAGICLICK_S3_2P4
|
||||
config BOARD_TYPE_MAGICLICK_2P4
|
||||
bool "神奇按钮 Magiclick_2.4"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_MAGICLICK_S3_2P5
|
||||
config BOARD_TYPE_MAGICLICK_2P5
|
||||
bool "神奇按钮 Magiclick_2.5"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_MAGICLICK_C3
|
||||
@ -233,88 +190,60 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_M5STACK_CORE_TAB5
|
||||
bool "M5Stack Tab5"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_M5STACK_ATOM_S3_ECHO_BASE
|
||||
bool "M5Stack AtomS3 + Echo Base"
|
||||
config BOARD_TYPE_ATOMS3_ECHO_BASE
|
||||
bool "AtomS3 + Echo Base"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_M5STACK_ATOM_S3R_ECHO_BASE
|
||||
bool "M5Stack AtomS3R + Echo Base"
|
||||
config BOARD_TYPE_ATOMS3R_ECHO_BASE
|
||||
bool "AtomS3R + Echo Base"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_M5STACK_ATOM_S3R_CAM_M12_ECHO_BASE
|
||||
bool "M5Stack AtomS3R CAM/M12 + Echo Base"
|
||||
config BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE
|
||||
bool "AtomS3R CAM/M12 + Echo Base"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_M5STACK_ATOM_ECHOS3R
|
||||
bool "M5Stack AtomEchoS3R"
|
||||
config BOARD_TYPE_ATOM_ECHOS3R
|
||||
bool "AtomEchoS3R"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_M5STACK_ATOM_MATRIX_ECHO_BASE
|
||||
bool "M5Stack AtomMatrix + Echo Base"
|
||||
config BOARD_TYPE_ATOMMATRIX_ECHO_BASE
|
||||
bool "AtomMatrix + Echo Base"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD
|
||||
config BOARD_TYPE_ESP32S3_AUDIO_BOARD
|
||||
bool "Waveshare ESP32-S3-Audio-Board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_8
|
||||
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06
|
||||
config BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-2.06"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_2_06
|
||||
bool "Waveshare ESP32-C6-Touch-AMOLED-2.06"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75
|
||||
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-1.75"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.83"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-4B"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85C
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_85C
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.85C"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_85
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.85"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_46
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_46
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.46"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_C6_LCD_1_69
|
||||
config BOARD_TYPE_ESP32C6_LCD_1_69
|
||||
bool "Waveshare ESP32-C6-LCD-1.69"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_WAVESHARE_C6_TOUCH_LCD_1_83
|
||||
bool "Waveshare ESP32-C6-Touch-LCD-1.83"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_43
|
||||
config BOARD_TYPE_ESP32C6_Touch_AMOLED_1_43
|
||||
bool "Waveshare ESP32-C6-Touch-AMOLOED-1.43"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_32
|
||||
bool "Waveshare ESP32-C6-Touch-AMOLOED-1.32"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_32
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLOED-1.32"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-3.49"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_3_5
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-3.5"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_ePaper_1_54
|
||||
bool "Waveshare ESP32-S3-ePaper-1.54"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_3_5B
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-3.5B"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_P4_NANO
|
||||
config BOARD_TYPE_ESP32P4_NANO
|
||||
bool "Waveshare ESP32-P4-NANO"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B
|
||||
config BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B
|
||||
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4B"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B
|
||||
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-7B"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC
|
||||
config BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC
|
||||
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C or ESP32-P4-WIFI6-Touch-LCD-4C"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_TUDOUZI
|
||||
@ -335,15 +264,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA_NO_BATTERY
|
||||
bool "LILYGO T-Display-S3-Pro-MVSRLora_No_Battery"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LILYGO_T_DISPLAY_P4
|
||||
bool "LILYGO T-Display-P4"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_MOVECALL_MOJI_ESP32S3
|
||||
bool "Movecall Moji 小智AI衍生版"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_MOVECALL_MOJI2_ESP32C5
|
||||
bool "Movecall Moji2.0 小智AI衍生版"
|
||||
depends on IDF_TARGET_ESP32C5
|
||||
config BOARD_TYPE_MOVECALL_CUICAN_ESP32S3
|
||||
bool "Movecall CuiCan 璀璨·AI吊坠"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@ -360,7 +283,7 @@ choice BOARD_TYPE
|
||||
bool "正点原子DNESP32S3-BOX2-WIFI"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATK_DNESP32S3_BOX2_4G
|
||||
bool "正点原子DNESP32S3-BOX2-4G"
|
||||
bool "正点原子DNESP32S3-BOX2-4G"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATK_DNESP32S3M_WIFI
|
||||
bool "正点原子DNESP32S3M-WIFI"
|
||||
@ -371,32 +294,29 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_DU_CHATX
|
||||
bool "嘟嘟开发板CHATX(wifi)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_TAIJI_PI_S3
|
||||
config BOARD_TYPE_ESP32S3_Taiji_Pi
|
||||
bool "太极小派esp32s3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_CUBE_0_85TFT_WIFI
|
||||
config BOARD_TYPE_XINGZHI_Cube_0_85TFT_WIFI
|
||||
bool "无名科技星智0.85(WIFI)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_CUBE_0_85TFT_ML307
|
||||
config BOARD_TYPE_XINGZHI_Cube_0_85TFT_ML307
|
||||
bool "无名科技星智0.85(ML307)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_CUBE_0_96OLED_WIFI
|
||||
config BOARD_TYPE_XINGZHI_Cube_0_96OLED_WIFI
|
||||
bool "无名科技星智0.96(WIFI)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_CUBE_0_96OLED_ML307
|
||||
config BOARD_TYPE_XINGZHI_Cube_0_96OLED_ML307
|
||||
bool "无名科技星智0.96(ML307)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_CUBE_1_54TFT_WIFI
|
||||
config BOARD_TYPE_XINGZHI_Cube_1_54TFT_WIFI
|
||||
bool "无名科技星智1.54(WIFI)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_CUBE_1_54TFT_ML307
|
||||
config BOARD_TYPE_XINGZHI_Cube_1_54TFT_ML307
|
||||
bool "无名科技星智1.54(ML307)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_XINGZHI_METAL_1_54_WIFI
|
||||
bool "无名科技星智1.54 METAL(wifi)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_SEEED_STUDIO_SENSECAP_WATCHER
|
||||
bool "Seeed Studio SenseCAP Watcher"
|
||||
config BOARD_TYPE_SENSECAP_WATCHER
|
||||
bool "SenseCAP Watcher"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_DOIT_S3_AIBOX
|
||||
bool "四博智联AI陪伴盒子"
|
||||
@ -422,68 +342,45 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_MINSI_K08_DUAL
|
||||
bool "敏思科技K08(DUAL)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_SPOTPEAR_ESP32_S3_1_54_MUMA
|
||||
config BOARD_TYPE_ESP32_S3_1_54_MUMA
|
||||
bool "Spotpear ESP32-S3-1.54-MUMA"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_SPOTPEAR_ESP32_S3_1_28_BOX
|
||||
config BOARD_TYPE_ESP32_S3_1_28_BOX
|
||||
bool "Spotpear ESP32-S3-1.28-BOX"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_OTTO_ROBOT
|
||||
bool "ottoRobot"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
select LV_USE_GIF
|
||||
select LV_GIF_CACHE_DECODE_DATA
|
||||
config BOARD_TYPE_ELECTRON_BOT
|
||||
bool "electronBot"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
select LV_USE_GIF
|
||||
select LV_GIF_CACHE_DECODE_DATA
|
||||
config BOARD_TYPE_JIUCHUAN
|
||||
bool "九川智能"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LABPLUS_MPYTHON_V3
|
||||
bool "labplus mpython_v3 board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LABPLUS_LEDONG_V2
|
||||
bool "labplus ledong_v2 board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_SURFER_C3_1_14TFT
|
||||
bool "Surfer-C3-1.14TFT"
|
||||
bool "Surfer-C3-1-14TFT"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_YUNLIAO_S3
|
||||
bool "小智云聊-S3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WIRELESS_TAG_WTP4C5MP07S
|
||||
bool "Wireless-Tag WTP4C5MP07S"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
config BOARD_TYPE_AIPI_LITE
|
||||
bool "AIPI-Lite"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_HU_087
|
||||
bool "HU-087"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
endchoice
|
||||
|
||||
choice
|
||||
depends on BOARD_TYPE_LILYGO_T_DISPLAY_P4
|
||||
prompt "Select the screen type"
|
||||
default SCREEN_TYPE_HI8561
|
||||
config SCREEN_TYPE_HI8561
|
||||
bool "HI8561"
|
||||
config SCREEN_TYPE_RM69A10
|
||||
bool "RM69A10"
|
||||
endchoice
|
||||
|
||||
choice
|
||||
depends on BOARD_TYPE_LILYGO_T_DISPLAY_P4
|
||||
prompt "Select the color format of the screen"
|
||||
default SCREEN_PIXEL_FORMAT_RGB565
|
||||
config SCREEN_PIXEL_FORMAT_RGB565
|
||||
bool "RGB565"
|
||||
config SCREEN_PIXEL_FORMAT_RGB888
|
||||
bool "RGB888"
|
||||
endchoice
|
||||
|
||||
choice ESP_S3_LCD_EV_Board_Version_TYPE
|
||||
depends on BOARD_TYPE_ESP_S3_LCD_EV_Board
|
||||
prompt "EV_BOARD Type"
|
||||
default ESP_S3_LCD_EV_Board_1p4
|
||||
help
|
||||
开发板硬件版本型号选择
|
||||
config ESP_S3_LCD_EV_Board_1p4
|
||||
bool "乐鑫ESP32_S3_LCD_EV_Board-MB_V1.4"
|
||||
config ESP_S3_LCD_EV_Board_1p5
|
||||
@ -491,55 +388,55 @@ choice ESP_S3_LCD_EV_Board_Version_TYPE
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_OLED_TYPE
|
||||
depends on BOARD_TYPE_BREAD_COMPACT_WIFI || BOARD_TYPE_BREAD_COMPACT_ML307 || BOARD_TYPE_BREAD_COMPACT_ESP32 || BOARD_TYPE_HU_087
|
||||
depends on BOARD_TYPE_BREAD_COMPACT_WIFI || BOARD_TYPE_BREAD_COMPACT_ML307 || BOARD_TYPE_BREAD_COMPACT_ESP32
|
||||
prompt "OLED Type"
|
||||
default OLED_SSD1306_128X32
|
||||
help
|
||||
OLED Monochrome Display Type
|
||||
OLED 屏幕类型选择
|
||||
config OLED_SSD1306_128X32
|
||||
bool "SSD1306 128*32"
|
||||
bool "SSD1306, 分辨率128*32"
|
||||
config OLED_SSD1306_128X64
|
||||
bool "SSD1306 128*64"
|
||||
bool "SSD1306, 分辨率128*64"
|
||||
config OLED_SH1106_128X64
|
||||
bool "SH1106 128*64"
|
||||
bool "SH1106, 分辨率128*64"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_LCD_TYPE
|
||||
depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_CGC || BOARD_TYPE_WAVESHARE_P4_NANO || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC || BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
|
||||
depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_ESP32_CGC || BOARD_TYPE_ESP32P4_NANO || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC || BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
|
||||
prompt "LCD Type"
|
||||
default LCD_ST7789_240X320
|
||||
help
|
||||
LCD Display Type
|
||||
屏幕类型选择
|
||||
config LCD_ST7789_240X320
|
||||
bool "ST7789 240*320, IPS"
|
||||
bool "ST7789, 分辨率240*320, IPS"
|
||||
config LCD_ST7789_240X320_NO_IPS
|
||||
bool "ST7789 240*320, Non-IPS"
|
||||
bool "ST7789, 分辨率240*320, 非IPS"
|
||||
config LCD_ST7789_170X320
|
||||
bool "ST7789 170*320"
|
||||
bool "ST7789, 分辨率170*320"
|
||||
config LCD_ST7789_172X320
|
||||
bool "ST7789 172*320"
|
||||
bool "ST7789, 分辨率172*320"
|
||||
config LCD_ST7789_240X280
|
||||
bool "ST7789 240*280"
|
||||
bool "ST7789, 分辨率240*280"
|
||||
config LCD_ST7789_240X240
|
||||
bool "ST7789 240*240"
|
||||
bool "ST7789, 分辨率240*240"
|
||||
config LCD_ST7789_240X240_7PIN
|
||||
bool "ST7789 240*240, 7PIN"
|
||||
bool "ST7789, 分辨率240*240, 7PIN"
|
||||
config LCD_ST7789_240X135
|
||||
bool "ST7789 240*135"
|
||||
bool "ST7789, 分辨率240*135"
|
||||
config LCD_ST7735_128X160
|
||||
bool "ST7735 128*160"
|
||||
bool "ST7735, 分辨率128*160"
|
||||
config LCD_ST7735_128X128
|
||||
bool "ST7735 128*128"
|
||||
bool "ST7735, 分辨率128*128"
|
||||
config LCD_ST7796_320X480
|
||||
bool "ST7796 320*480 IPS"
|
||||
bool "ST7796, 分辨率320*480 IPS"
|
||||
config LCD_ST7796_320X480_NO_IPS
|
||||
bool "ST7796 320*480, Non-IPS"
|
||||
bool "ST7796, 分辨率320*480, 非IPS"
|
||||
config LCD_ILI9341_240X320
|
||||
bool "ILI9341 240*320"
|
||||
bool "ILI9341, 分辨率240*320"
|
||||
config LCD_ILI9341_240X320_NO_IPS
|
||||
bool "ILI9341 240*320, Non-IPS"
|
||||
bool "ILI9341, 分辨率240*320, 非IPS"
|
||||
config LCD_GC9A01_240X240
|
||||
bool "GC9A01 240*240 Circle"
|
||||
bool "GC9A01, 分辨率240*240, 圆屏"
|
||||
config LCD_TYPE_800_1280_10_1_INCH
|
||||
bool "Waveshare 101M-8001280-IPS-CT-K Display"
|
||||
config LCD_TYPE_800_1280_10_1_INCH_A
|
||||
@ -549,97 +446,73 @@ choice DISPLAY_LCD_TYPE
|
||||
config LCD_TYPE_720_720_4_INCH
|
||||
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4C with 720*720 4inch round display"
|
||||
config LCD_CUSTOM
|
||||
bool "Custom LCD (自定义屏幕参数)"
|
||||
bool "自定义屏幕参数"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_ESP32S3_KORVO2_V3
|
||||
depends on BOARD_TYPE_ESP_KORVO2_V3
|
||||
depends on BOARD_TYPE_ESP32S3_KORVO2_V3
|
||||
prompt "ESP32S3_KORVO2_V3 LCD Type"
|
||||
default ESP32S3_KORVO2_V3_LCD_ST7789
|
||||
help
|
||||
LCD Display Type
|
||||
屏幕类型选择
|
||||
config ESP32S3_KORVO2_V3_LCD_ST7789
|
||||
bool "ST7789 240*280"
|
||||
bool "ST7789, 分辨率240*280"
|
||||
config ESP32S3_KORVO2_V3_LCD_ILI9341
|
||||
bool "ILI9341 240*320"
|
||||
bool "ILI9341, 分辨率240*320"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_ESP32S3_AUDIO_BOARD
|
||||
depends on BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD
|
||||
depends on BOARD_TYPE_ESP32S3_AUDIO_BOARD
|
||||
prompt "ESP32S3_AUDIO_BOARD LCD Type"
|
||||
default AUDIO_BOARD_LCD_JD9853
|
||||
help
|
||||
LCD Display Type
|
||||
屏幕类型选择
|
||||
config AUDIO_BOARD_LCD_JD9853
|
||||
bool "JD9853 320*172"
|
||||
bool "JD9853, 分辨率320*172"
|
||||
config AUDIO_BOARD_LCD_ST7789
|
||||
bool "ST7789 240*320"
|
||||
bool "ST7789, 分辨率240*320"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_STYLE
|
||||
prompt "Select display style"
|
||||
default USE_DEFAULT_MESSAGE_STYLE
|
||||
config USE_WECHAT_MESSAGE_STYLE
|
||||
bool "Enable WeChat Message Style"
|
||||
default n
|
||||
help
|
||||
Select display style for Xiaozhi device
|
||||
使用微信聊天界面风格
|
||||
|
||||
config USE_DEFAULT_MESSAGE_STYLE
|
||||
bool "Enable default message style"
|
||||
|
||||
config USE_WECHAT_MESSAGE_STYLE
|
||||
bool "Enable WeChat Message Style"
|
||||
|
||||
config USE_EMOTE_MESSAGE_STYLE
|
||||
bool "Emote animation style"
|
||||
depends on BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_3 \
|
||||
|| BOARD_TYPE_ECHOEAR || BOARD_TYPE_LICHUANG_DEV_S3 \
|
||||
|| BOARD_TYPE_ESP_SENSAIRSHUTTLE
|
||||
endchoice
|
||||
|
||||
choice WAKE_WORD_TYPE
|
||||
prompt "Wake Word Implementation Type"
|
||||
default USE_AFE_WAKE_WORD if (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
default WAKE_WORD_DISABLED
|
||||
config USE_ESP_WAKE_WORD
|
||||
bool "Enable Wake Word Detection (without AFE)"
|
||||
default n
|
||||
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || (IDF_TARGET_ESP32 && SPIRAM)
|
||||
help
|
||||
Choose the type of wake word implementation to use
|
||||
支持 ESP32 C3、ESP32 C5 与 ESP32 C6,增加ESP32支持(需要开启PSRAM)
|
||||
|
||||
config WAKE_WORD_DISABLED
|
||||
bool "Disabled"
|
||||
help
|
||||
Disable wake word detection
|
||||
|
||||
config USE_ESP_WAKE_WORD
|
||||
bool "Wakenet model without AFE"
|
||||
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || (IDF_TARGET_ESP32 && SPIRAM)
|
||||
help
|
||||
Support ESP32 C3、ESP32 C5 与 ESP32 C6, and (ESP32 with PSRAM)
|
||||
|
||||
config USE_AFE_WAKE_WORD
|
||||
bool "Wakenet model with AFE"
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
help
|
||||
Support AEC if available, requires ESP32 S3 and PSRAM
|
||||
|
||||
config USE_CUSTOM_WAKE_WORD
|
||||
bool "Multinet model (Custom Wake Word)"
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
help
|
||||
Requires ESP32 S3 and PSRAM
|
||||
|
||||
endchoice
|
||||
config USE_AFE_WAKE_WORD
|
||||
bool "Enable Wake Word Detection (AFE)"
|
||||
default y
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
help
|
||||
需要 ESP32 S3 与 PSRAM 支持
|
||||
|
||||
config USE_CUSTOM_WAKE_WORD
|
||||
bool "Enable Custom Wake Word Detection"
|
||||
default n
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM && (!USE_AFE_WAKE_WORD)
|
||||
help
|
||||
需要 ESP32 S3 与 PSRAM 支持
|
||||
|
||||
config CUSTOM_WAKE_WORD
|
||||
string "Custom Wake Word"
|
||||
default "xiao tu dou"
|
||||
depends on USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
Custom Wake Word, use pinyin for Chinese, separated by spaces
|
||||
自定义唤醒词,中文用拼音表示,每个字之间用空格隔开
|
||||
|
||||
config CUSTOM_WAKE_WORD_DISPLAY
|
||||
string "Custom Wake Word Display"
|
||||
default "小土豆"
|
||||
depends on USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
Greeting sent to the server after wake word detection
|
||||
唤醒后发送给服务器的问候语
|
||||
|
||||
config CUSTOM_WAKE_WORD_THRESHOLD
|
||||
int "Custom Wake Word Threshold (%)"
|
||||
@ -647,178 +520,64 @@ config CUSTOM_WAKE_WORD_THRESHOLD
|
||||
range 1 99
|
||||
depends on USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
Custom Wake Word Threshold, range 1-99, the smaller the more sensitive, default 20
|
||||
|
||||
config SEND_WAKE_WORD_DATA
|
||||
bool "Send Wake Word Data"
|
||||
default y
|
||||
depends on USE_AFE_WAKE_WORD || USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
Send wake word data to the server as the first message of the conversation and wait for response
|
||||
自定义唤醒词阈值,范围1-99,越小越敏感,默认10
|
||||
|
||||
config USE_AUDIO_PROCESSOR
|
||||
bool "Enable Audio Noise Reduction"
|
||||
default y
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
|
||||
help
|
||||
Requires ESP32 S3 and PSRAM
|
||||
需要 ESP32 S3 与 PSRAM 支持
|
||||
|
||||
config USE_DEVICE_AEC
|
||||
bool "Enable Device-Side AEC"
|
||||
default n
|
||||
depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE \
|
||||
|| BOARD_TYPE_LICHUANG_DEV_S3 || BOARD_TYPE_ESP_KORVO2_V3 || BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75 || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83\
|
||||
|| BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06 || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B \
|
||||
|| BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3 \
|
||||
|| BOARD_TYPE_ECHOEAR || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49)
|
||||
depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE || BOARD_TYPE_LICHUANG_DEV || BOARD_TYPE_ESP32S3_KORVO2_V3 || BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 || BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06 || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3)
|
||||
help
|
||||
To work properly, device-side AEC requires a clean output reference path from the speaker signal and physical acoustic isolation between the microphone and speaker.
|
||||
因为性能不够,不建议和微信聊天界面风格同时开启
|
||||
|
||||
config USE_SERVER_AEC
|
||||
bool "Enable Server-Side AEC (Unstable)"
|
||||
default n
|
||||
depends on USE_AUDIO_PROCESSOR
|
||||
help
|
||||
To work perperly, server-side AEC requires server support
|
||||
启用服务器端 AEC,需要服务器支持
|
||||
|
||||
config USE_AUDIO_DEBUGGER
|
||||
bool "Enable Audio Debugger"
|
||||
default n
|
||||
help
|
||||
Enable audio debugger, send audio data through UDP to the host machine
|
||||
启用音频调试功能,通过UDP发送音频数据
|
||||
|
||||
menu "WiFi Configuration Method"
|
||||
config USE_ACOUSTIC_WIFI_PROVISIONING
|
||||
bool "Enable Acoustic WiFi Provisioning"
|
||||
default n
|
||||
help
|
||||
WiFi Configuration Method Selection
|
||||
config USE_HOTSPOT_WIFI_PROVISIONING
|
||||
bool "Hotspot"
|
||||
default y
|
||||
help
|
||||
Use WiFi Hotspot to transmit WiFi configuration data
|
||||
config USE_ACOUSTIC_WIFI_PROVISIONING
|
||||
bool "Acoustic"
|
||||
help
|
||||
Use audio signal to transmit WiFi configuration data
|
||||
|
||||
config USE_ESP_BLUFI_WIFI_PROVISIONING
|
||||
bool "Esp Blufi"
|
||||
help
|
||||
Use esp blufi protocol to transmit WiFi configuration data
|
||||
select BT_ENABLED
|
||||
select BT_BLE_42_FEATURES_SUPPORTED
|
||||
select BT_BLE_BLUFI_ENABLE
|
||||
select MBEDTLS_DHM_C
|
||||
endmenu
|
||||
启用声波配网功能,使用音频信号传输 WiFi 配置数据
|
||||
|
||||
config AUDIO_DEBUG_UDP_SERVER
|
||||
string "Audio Debug UDP Server Address"
|
||||
default "192.168.2.100:8000"
|
||||
depends on USE_AUDIO_DEBUGGER
|
||||
help
|
||||
UDP server address, format: IP:PORT, used to receive audio debugging data
|
||||
UDP服务器地址,格式: IP:PORT,用于接收音频调试数据
|
||||
|
||||
config RECEIVE_CUSTOM_MESSAGE
|
||||
bool "Enable Custom Message Reception"
|
||||
default n
|
||||
help
|
||||
Enable custom message reception, allow the device to receive custom messages from the server (preferably through the MQTT protocol)
|
||||
启用接收自定义消息功能,允许设备接收来自服务器的自定义消息(最好通过 MQTT 协议)
|
||||
|
||||
menu "Camera Configuration"
|
||||
depends on !IDF_TARGET_ESP32
|
||||
|
||||
comment "Warning: Please read the help text before modifying these settings."
|
||||
|
||||
config XIAOZHI_CAMERA_ALLOW_JPEG_INPUT
|
||||
bool "Allow JPEG Input"
|
||||
default n
|
||||
help
|
||||
Allow JPEG Input format for the camera.
|
||||
|
||||
This option may need to be enabled when using a USB camera.
|
||||
|
||||
Not currently supported when used simultaneously with XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE.
|
||||
|
||||
config XIAOZHI_ENABLE_HARDWARE_JPEG_ENCODER
|
||||
bool "Enable Hardware JPEG Encoder"
|
||||
default y
|
||||
depends on SOC_JPEG_ENCODE_SUPPORTED
|
||||
help
|
||||
Use hardware JPEG encoder on ESP32-P4 to encode image to JPEG.
|
||||
See https://docs.espressif.com/projects/esp-idf/en/stable/esp32p4/api-reference/peripherals/jpeg.html for more details.
|
||||
|
||||
config XIAOZHI_ENABLE_HARDWARE_JPEG_DECODER
|
||||
bool "Enable Hardware JPEG Decoder"
|
||||
default n
|
||||
depends on SOC_JPEG_DECODE_SUPPORTED && XIAOZHI_CAMERA_ALLOW_JPEG_INPUT
|
||||
help
|
||||
Use hardware JPEG decoder on ESP32-P4 to decode JPEG to image.
|
||||
See https://docs.espressif.com/projects/esp-idf/en/stable/esp32p4/api-reference/peripherals/jpeg.html for more details.
|
||||
|
||||
config XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
bool "Enable Camera Debug Mode"
|
||||
default n
|
||||
help
|
||||
Enable camera debug mode, print camera debug information to the console.
|
||||
Only works on boards that support camera.
|
||||
|
||||
config XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP
|
||||
bool "Enable software camera buffer endianness swapping"
|
||||
default n
|
||||
depends on !CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER
|
||||
help
|
||||
This option treats the camera buffer as a uint16_t[] array and performs byte-swapping (endianness conversion) on each element.
|
||||
|
||||
Should only be modified by development board integration engineers.
|
||||
|
||||
**Incorrect usage may result in incorrect image colors!**
|
||||
|
||||
ATTENTION: If the option CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER is available for your sensor, please use that instead.
|
||||
|
||||
menuconfig XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
|
||||
bool "Enable Camera Image Rotation"
|
||||
default n
|
||||
depends on !XIAOZHI_CAMERA_ALLOW_JPEG_INPUT
|
||||
help
|
||||
Enable camera image rotation, rotate the camera image to the correct orientation.
|
||||
- On ESP32-P4, rotation is handled by PPA hardware.
|
||||
- On other chips, rotation is done in software with performance cost.
|
||||
- For 180° rotation, use HFlip + VFlip instead of this option.
|
||||
|
||||
Not currently supported when used simultaneously with XIAOZHI_CAMERA_ALLOW_JPEG_INPUT.
|
||||
|
||||
if XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
|
||||
choice XIAOZHI_CAMERA_IMAGE_ROTATION_ANGLE
|
||||
prompt "Camera Image Rotation Angle (clockwise)"
|
||||
default XIAOZHI_CAMERA_IMAGE_ROTATION_ANGLE_90
|
||||
help
|
||||
Camera image rotation angle.
|
||||
config XIAOZHI_CAMERA_IMAGE_ROTATION_ANGLE_90
|
||||
bool "90°"
|
||||
config XIAOZHI_CAMERA_IMAGE_ROTATION_ANGLE_270
|
||||
bool "270°"
|
||||
comment "For 180° rotation, use HFlip + VFlip instead of this option"
|
||||
endchoice
|
||||
endif
|
||||
endmenu
|
||||
|
||||
menu "TAIJIPAI_S3_CONFIG"
|
||||
depends on BOARD_TYPE_TAIJI_PI_S3
|
||||
choice I2S_TYPE_TAIJIPI_S3
|
||||
prompt "taiji-pi-S3 I2S Type"
|
||||
default TAIJIPAI_I2S_TYPE_STD
|
||||
help
|
||||
I2S 类型选择
|
||||
config TAIJIPAI_I2S_TYPE_STD
|
||||
bool "I2S Type STD"
|
||||
config TAIJIPAI_I2S_TYPE_PDM
|
||||
bool "I2S Type PDM"
|
||||
endchoice
|
||||
|
||||
config I2S_USE_2SLOT
|
||||
bool "Enable I2S 2 Slot"
|
||||
default y
|
||||
choice I2S_TYPE_TAIJIPI_S3
|
||||
depends on BOARD_TYPE_ESP32S3_Taiji_Pi
|
||||
prompt "taiji-pi-S3 I2S Type"
|
||||
default TAIJIPAI_I2S_TYPE_STD
|
||||
help
|
||||
启动双声道
|
||||
endmenu
|
||||
I2S 类型选择
|
||||
config TAIJIPAI_I2S_TYPE_STD
|
||||
bool "I2S Type STD"
|
||||
config TAIJIPAI_I2S_TYPE_PDM
|
||||
bool "I2S Type PDM"
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
1098
main/application.cc
1098
main/application.cc
File diff suppressed because it is too large
Load Diff
@ -14,23 +14,16 @@
|
||||
#include "protocol.h"
|
||||
#include "ota.h"
|
||||
#include "audio_service.h"
|
||||
#include "device_state.h"
|
||||
#include "device_state_machine.h"
|
||||
#include "device_state_event.h"
|
||||
|
||||
// Main event bits
|
||||
#define MAIN_EVENT_SCHEDULE (1 << 0)
|
||||
#define MAIN_EVENT_SEND_AUDIO (1 << 1)
|
||||
#define MAIN_EVENT_WAKE_WORD_DETECTED (1 << 2)
|
||||
#define MAIN_EVENT_VAD_CHANGE (1 << 3)
|
||||
#define MAIN_EVENT_ERROR (1 << 4)
|
||||
#define MAIN_EVENT_ACTIVATION_DONE (1 << 5)
|
||||
#define MAIN_EVENT_CLOCK_TICK (1 << 6)
|
||||
#define MAIN_EVENT_NETWORK_CONNECTED (1 << 7)
|
||||
#define MAIN_EVENT_NETWORK_DISCONNECTED (1 << 8)
|
||||
#define MAIN_EVENT_TOGGLE_CHAT (1 << 9)
|
||||
#define MAIN_EVENT_START_LISTENING (1 << 10)
|
||||
#define MAIN_EVENT_STOP_LISTENING (1 << 11)
|
||||
#define MAIN_EVENT_STATE_CHANGED (1 << 12)
|
||||
|
||||
#define MAIN_EVENT_SCHEDULE (1 << 0)
|
||||
#define MAIN_EVENT_SEND_AUDIO (1 << 1)
|
||||
#define MAIN_EVENT_WAKE_WORD_DETECTED (1 << 2)
|
||||
#define MAIN_EVENT_VAD_CHANGE (1 << 3)
|
||||
#define MAIN_EVENT_ERROR (1 << 4)
|
||||
#define MAIN_EVENT_CHECK_NEW_VERSION_DONE (1 << 5)
|
||||
#define MAIN_EVENT_CLOCK_TICK (1 << 6)
|
||||
|
||||
|
||||
enum AecMode {
|
||||
@ -45,80 +38,31 @@ public:
|
||||
static Application instance;
|
||||
return instance;
|
||||
}
|
||||
// Delete copy constructor and assignment operator
|
||||
// 删除拷贝构造函数和赋值运算符
|
||||
Application(const Application&) = delete;
|
||||
Application& operator=(const Application&) = delete;
|
||||
|
||||
/**
|
||||
* Initialize the application
|
||||
* This sets up display, audio, network callbacks, etc.
|
||||
* Network connection starts asynchronously.
|
||||
*/
|
||||
void Initialize();
|
||||
|
||||
/**
|
||||
* Run the main event loop
|
||||
* This function runs in the main task and never returns.
|
||||
* It handles all events including network, state changes, and user interactions.
|
||||
*/
|
||||
void Run();
|
||||
|
||||
DeviceState GetDeviceState() const { return state_machine_.GetState(); }
|
||||
void Start();
|
||||
void MainEventLoop();
|
||||
DeviceState GetDeviceState() const { return device_state_; }
|
||||
bool IsVoiceDetected() const { return audio_service_.IsVoiceDetected(); }
|
||||
|
||||
/**
|
||||
* Request state transition
|
||||
* Returns true if transition was successful
|
||||
*/
|
||||
bool SetDeviceState(DeviceState state);
|
||||
|
||||
/**
|
||||
* Schedule a callback to be executed in the main task
|
||||
*/
|
||||
void Schedule(std::function<void()>&& callback);
|
||||
|
||||
/**
|
||||
* Alert with status, message, emotion and optional sound
|
||||
*/
|
||||
void Schedule(std::function<void()> callback);
|
||||
void SetDeviceState(DeviceState state);
|
||||
void Alert(const char* status, const char* message, const char* emotion = "", const std::string_view& sound = "");
|
||||
void DismissAlert();
|
||||
|
||||
void AbortSpeaking(AbortReason reason);
|
||||
|
||||
/**
|
||||
* Toggle chat state (event-based, thread-safe)
|
||||
* Sends MAIN_EVENT_TOGGLE_CHAT to be handled in Run()
|
||||
*/
|
||||
void ToggleChatState();
|
||||
|
||||
/**
|
||||
* Start listening (event-based, thread-safe)
|
||||
* Sends MAIN_EVENT_START_LISTENING to be handled in Run()
|
||||
*/
|
||||
void StartListening();
|
||||
|
||||
/**
|
||||
* Stop listening (event-based, thread-safe)
|
||||
* Sends MAIN_EVENT_STOP_LISTENING to be handled in Run()
|
||||
*/
|
||||
void StopListening();
|
||||
|
||||
void Reboot();
|
||||
void WakeWordInvoke(const std::string& wake_word);
|
||||
bool UpgradeFirmware(const std::string& url, const std::string& version = "");
|
||||
bool UpgradeFirmware(Ota& ota, const std::string& url = "");
|
||||
bool CanEnterSleepMode();
|
||||
void SendMcpMessage(const std::string& payload);
|
||||
void SetAecMode(AecMode mode);
|
||||
AecMode GetAecMode() const { return aec_mode_; }
|
||||
void PlaySound(const std::string_view& sound);
|
||||
AudioService& GetAudioService() { return audio_service_; }
|
||||
|
||||
/**
|
||||
* Reset protocol resources (thread-safe)
|
||||
* Can be called from any task to release resources allocated after network connected
|
||||
* This includes closing audio channel, resetting protocol and ota objects
|
||||
*/
|
||||
void ResetProtocol();
|
||||
|
||||
private:
|
||||
Application();
|
||||
@ -129,43 +73,23 @@ private:
|
||||
std::unique_ptr<Protocol> protocol_;
|
||||
EventGroupHandle_t event_group_ = nullptr;
|
||||
esp_timer_handle_t clock_timer_handle_ = nullptr;
|
||||
DeviceStateMachine state_machine_;
|
||||
volatile DeviceState device_state_ = kDeviceStateUnknown;
|
||||
ListeningMode listening_mode_ = kListeningModeAutoStop;
|
||||
AecMode aec_mode_ = kAecOff;
|
||||
std::string last_error_message_;
|
||||
AudioService audio_service_;
|
||||
std::unique_ptr<Ota> ota_;
|
||||
|
||||
bool has_server_time_ = false;
|
||||
bool aborted_ = false;
|
||||
bool assets_version_checked_ = false;
|
||||
bool play_popup_on_listening_ = false; // Flag to play popup sound after state changes to listening
|
||||
int clock_ticks_ = 0;
|
||||
TaskHandle_t activation_task_handle_ = nullptr;
|
||||
TaskHandle_t check_new_version_task_handle_ = nullptr;
|
||||
TaskHandle_t main_event_loop_task_handle_ = nullptr;
|
||||
|
||||
|
||||
// Event handlers
|
||||
void HandleStateChangedEvent();
|
||||
void HandleToggleChatEvent();
|
||||
void HandleStartListeningEvent();
|
||||
void HandleStopListeningEvent();
|
||||
void HandleNetworkConnectedEvent();
|
||||
void HandleNetworkDisconnectedEvent();
|
||||
void HandleActivationDoneEvent();
|
||||
void HandleWakeWordDetectedEvent();
|
||||
|
||||
// Activation task (runs in background)
|
||||
void ActivationTask();
|
||||
|
||||
// Helper methods
|
||||
void OnWakeWordDetected();
|
||||
void CheckNewVersion(Ota& ota);
|
||||
void CheckAssetsVersion();
|
||||
void CheckNewVersion();
|
||||
void InitializeProtocol();
|
||||
void ShowActivationCode(const std::string& code, const std::string& message);
|
||||
void SetListeningMode(ListeningMode mode);
|
||||
|
||||
// State change handler called by state machine
|
||||
void OnStateChanged(DeviceState old_state, DeviceState new_state);
|
||||
};
|
||||
|
||||
|
||||
|
||||
300
main/assets.cc
300
main/assets.cc
@ -3,20 +3,14 @@
|
||||
#include "display.h"
|
||||
#include "application.h"
|
||||
#include "lvgl_theme.h"
|
||||
#include "emote_display.h"
|
||||
#include "expression_emote.h"
|
||||
#if HAVE_LVGL
|
||||
#include "display/lcd_display.h"
|
||||
#include <spi_flash_mmap.h>
|
||||
#endif
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <spi_flash_mmap.h>
|
||||
#include <esp_timer.h>
|
||||
#include <cbin_font.h>
|
||||
|
||||
|
||||
#define TAG "Assets"
|
||||
#define PARTITION_LABEL "assets"
|
||||
|
||||
struct mmap_assets_table {
|
||||
char asset_name[32]; /*!< Name of the asset */
|
||||
@ -26,99 +20,25 @@ struct mmap_assets_table {
|
||||
uint16_t asset_height; /*!< Height of the asset */
|
||||
};
|
||||
|
||||
Assets::Assets() {
|
||||
#if HAVE_LVGL
|
||||
strategy_ = std::make_unique<Assets::LvglStrategy>();
|
||||
#else
|
||||
strategy_ = std::make_unique<Assets::EmoteStrategy>();
|
||||
#endif
|
||||
|
||||
Assets::Assets(std::string default_assets_url) {
|
||||
if (default_assets_url.find("http") == 0) {
|
||||
default_assets_url_ = default_assets_url;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "The default assets url is not a http url: %s", default_assets_url.c_str());
|
||||
}
|
||||
|
||||
// Initialize the partition
|
||||
InitializePartition();
|
||||
}
|
||||
|
||||
Assets::~Assets() {
|
||||
UnApplyPartition();
|
||||
}
|
||||
|
||||
bool Assets::FindPartition(Assets* assets) {
|
||||
assets->partition_ = esp_partition_find_first(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, PARTITION_LABEL);
|
||||
if (assets->partition_ == nullptr) {
|
||||
ESP_LOGI(TAG, "No assets partition found");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Assets::Apply() {
|
||||
return strategy_ ? strategy_->Apply(this) : false;
|
||||
}
|
||||
|
||||
bool Assets::InitializePartition() {
|
||||
return strategy_ ? strategy_->InitializePartition(this) : false;
|
||||
}
|
||||
|
||||
void Assets::UnApplyPartition() {
|
||||
if (strategy_) {
|
||||
strategy_->UnApplyPartition(this);
|
||||
if (mmap_handle_ != 0) {
|
||||
esp_partition_munmap(mmap_handle_);
|
||||
}
|
||||
}
|
||||
|
||||
bool Assets::GetAssetData(const std::string& name, void*& ptr, size_t& size) {
|
||||
return strategy_ ? strategy_->GetAssetData(this, name, ptr, size) : false;
|
||||
}
|
||||
|
||||
bool Assets::LoadSrmodelsFromIndex(Assets* assets, cJSON* root) {
|
||||
void* ptr = nullptr;
|
||||
size_t size = 0;
|
||||
bool need_delete_root = false;
|
||||
|
||||
// If root is not provided, parse index.json
|
||||
if (root == nullptr) {
|
||||
if (!assets->GetAssetData("index.json", ptr, size)) {
|
||||
ESP_LOGE(TAG, "The index.json file is not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
root = cJSON_ParseWithLength(static_cast<char*>(ptr), size);
|
||||
if (root == nullptr) {
|
||||
ESP_LOGE(TAG, "The index.json file is not valid");
|
||||
return false;
|
||||
}
|
||||
need_delete_root = true;
|
||||
}
|
||||
|
||||
cJSON* srmodels = cJSON_GetObjectItem(root, "srmodels");
|
||||
if (cJSON_IsString(srmodels)) {
|
||||
std::string srmodels_file = srmodels->valuestring;
|
||||
if (assets->GetAssetData(srmodels_file, ptr, size)) {
|
||||
if (assets->models_list_ != nullptr) {
|
||||
esp_srmodel_deinit(assets->models_list_);
|
||||
assets->models_list_ = nullptr;
|
||||
}
|
||||
assets->models_list_ = srmodel_load(static_cast<uint8_t*>(ptr));
|
||||
if (assets->models_list_ != nullptr) {
|
||||
auto& app = Application::GetInstance();
|
||||
app.GetAudioService().SetModelsList(assets->models_list_);
|
||||
if (need_delete_root) {
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to load srmodels.bin");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "The srmodels file %s is not found", srmodels_file.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (need_delete_root) {
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if HAVE_LVGL
|
||||
uint32_t Assets::LvglStrategy::CalculateChecksum(const char* data, uint32_t length) {
|
||||
uint32_t Assets::CalculateChecksum(const char* data, uint32_t length) {
|
||||
uint32_t checksum = 0;
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
checksum += data[i];
|
||||
@ -126,37 +46,40 @@ uint32_t Assets::LvglStrategy::CalculateChecksum(const char* data, uint32_t leng
|
||||
return checksum & 0xFFFF;
|
||||
}
|
||||
|
||||
bool Assets::LvglStrategy::InitializePartition(Assets* assets) {
|
||||
assets->partition_valid_ = false;
|
||||
bool Assets::InitializePartition() {
|
||||
partition_valid_ = false;
|
||||
checksum_valid_ = false;
|
||||
assets_.clear();
|
||||
|
||||
if (!Assets::FindPartition(assets)) {
|
||||
partition_ = esp_partition_find_first(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, "assets");
|
||||
if (partition_ == nullptr) {
|
||||
ESP_LOGI(TAG, "No assets partition found");
|
||||
return false;
|
||||
}
|
||||
|
||||
int free_pages = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
|
||||
uint32_t storage_size = free_pages * 64 * 1024;
|
||||
ESP_LOGI(TAG, "The storage free size is %ld KB", storage_size / 1024);
|
||||
ESP_LOGI(TAG, "The partition size is %ld KB", assets->partition_->size / 1024);
|
||||
if (storage_size < assets->partition_->size) {
|
||||
ESP_LOGE(TAG, "The free size %ld KB is less than assets partition required %ld KB", storage_size / 1024, assets->partition_->size / 1024);
|
||||
ESP_LOGI(TAG, "The partition size is %ld KB", partition_->size / 1024);
|
||||
if (storage_size < partition_->size) {
|
||||
ESP_LOGE(TAG, "The free size %ld KB is less than assets partition required %ld KB", storage_size / 1024, partition_->size / 1024);
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_partition_mmap(assets->partition_, 0, assets->partition_->size, ESP_PARTITION_MMAP_DATA, (const void**)&mmap_root_, &mmap_handle_);
|
||||
esp_err_t err = esp_partition_mmap(partition_, 0, partition_->size, ESP_PARTITION_MMAP_DATA, (const void**)&mmap_root_, &mmap_handle_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to mmap assets partition: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
assets->partition_valid_ = true;
|
||||
partition_valid_ = true;
|
||||
|
||||
uint32_t stored_files = *(uint32_t*)(mmap_root_ + 0);
|
||||
uint32_t stored_chksum = *(uint32_t*)(mmap_root_ + 4);
|
||||
uint32_t stored_len = *(uint32_t*)(mmap_root_ + 8);
|
||||
|
||||
if (stored_len > assets->partition_->size - 12) {
|
||||
ESP_LOGD(TAG, "The stored_len (0x%lx) is greater than the partition size (0x%lx) - 12", stored_len, assets->partition_->size);
|
||||
if (stored_len > partition_->size - 12) {
|
||||
ESP_LOGD(TAG, "The stored_len (0x%lx) is greater than the partition size (0x%lx) - 12", stored_len, partition_->size);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -183,41 +106,13 @@ bool Assets::LvglStrategy::InitializePartition(Assets* assets) {
|
||||
return checksum_valid_;
|
||||
}
|
||||
|
||||
void Assets::LvglStrategy::UnApplyPartition(Assets* assets) {
|
||||
if (mmap_handle_ != 0) {
|
||||
esp_partition_munmap(mmap_handle_);
|
||||
mmap_handle_ = 0;
|
||||
mmap_root_ = nullptr;
|
||||
}
|
||||
checksum_valid_ = false;
|
||||
assets_.clear();
|
||||
(void)assets; // Unused parameter
|
||||
}
|
||||
|
||||
bool Assets::LvglStrategy::GetAssetData(Assets* assets, const std::string& name, void*& ptr, size_t& size) {
|
||||
auto asset = assets_.find(name);
|
||||
if (asset == assets_.end()) {
|
||||
return false;
|
||||
}
|
||||
auto data = (const char*)(mmap_root_ + asset->second.offset);
|
||||
if (data[0] != 'Z' || data[1] != 'Z') {
|
||||
ESP_LOGE(TAG, "The asset %s is not valid with magic %02x%02x", name.c_str(), data[0], data[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
ptr = static_cast<void*>(const_cast<char*>(data + 2));
|
||||
size = asset->second.size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
bool Assets::Apply() {
|
||||
void* ptr = nullptr;
|
||||
size_t size = 0;
|
||||
if (!assets->GetAssetData("index.json", ptr, size)) {
|
||||
if (!GetAssetData("index.json", ptr, size)) {
|
||||
ESP_LOGE(TAG, "The index.json file is not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
cJSON* root = cJSON_ParseWithLength(static_cast<char*>(ptr), size);
|
||||
if (root == nullptr) {
|
||||
ESP_LOGE(TAG, "The index.json file is not valid");
|
||||
@ -231,9 +126,28 @@ bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
cJSON* srmodels = cJSON_GetObjectItem(root, "srmodels");
|
||||
if (cJSON_IsString(srmodels)) {
|
||||
std::string srmodels_file = srmodels->valuestring;
|
||||
if (GetAssetData(srmodels_file, ptr, size)) {
|
||||
if (models_list_ != nullptr) {
|
||||
esp_srmodel_deinit(models_list_);
|
||||
models_list_ = nullptr;
|
||||
}
|
||||
models_list_ = srmodel_load(static_cast<uint8_t*>(ptr));
|
||||
if (models_list_ != nullptr) {
|
||||
auto& app = Application::GetInstance();
|
||||
app.GetAudioService().SetModelsList(models_list_);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to load srmodels.bin");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "The srmodels file %s is not found", srmodels_file.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Assets::LoadSrmodelsFromIndex(assets, root);
|
||||
|
||||
#ifdef HAVE_LVGL
|
||||
auto& theme_manager = LvglThemeManager::GetInstance();
|
||||
auto light_theme = theme_manager.GetTheme("light");
|
||||
auto dark_theme = theme_manager.GetTheme("dark");
|
||||
@ -241,7 +155,7 @@ bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
cJSON* font = cJSON_GetObjectItem(root, "text_font");
|
||||
if (cJSON_IsString(font)) {
|
||||
std::string fonts_text_file = font->valuestring;
|
||||
if (assets->GetAssetData(fonts_text_file, ptr, size)) {
|
||||
if (GetAssetData(fonts_text_file, ptr, size)) {
|
||||
auto text_font = std::make_shared<LvglCBinFont>(ptr);
|
||||
if (text_font->font() == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to load fonts.bin");
|
||||
@ -267,9 +181,8 @@ bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
if (cJSON_IsObject(emoji)) {
|
||||
cJSON* name = cJSON_GetObjectItem(emoji, "name");
|
||||
cJSON* file = cJSON_GetObjectItem(emoji, "file");
|
||||
cJSON* eaf = cJSON_GetObjectItem(emoji, "eaf");
|
||||
if (cJSON_IsString(name) && cJSON_IsString(file) && (NULL== eaf)) {
|
||||
if (!assets->GetAssetData(file->valuestring, ptr, size)) {
|
||||
if (cJSON_IsString(name) && cJSON_IsString(file)) {
|
||||
if (!GetAssetData(file->valuestring, ptr, size)) {
|
||||
ESP_LOGE(TAG, "Emoji %s image file %s is not found", name->valuestring, file->valuestring);
|
||||
continue;
|
||||
}
|
||||
@ -300,7 +213,7 @@ bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
light_theme->set_chat_background_color(LvglTheme::ParseColor(background_color->valuestring));
|
||||
}
|
||||
if (cJSON_IsString(background_image)) {
|
||||
if (!assets->GetAssetData(background_image->valuestring, ptr, size)) {
|
||||
if (!GetAssetData(background_image->valuestring, ptr, size)) {
|
||||
ESP_LOGE(TAG, "The background image file %s is not found", background_image->valuestring);
|
||||
return false;
|
||||
}
|
||||
@ -321,7 +234,7 @@ bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
dark_theme->set_chat_background_color(LvglTheme::ParseColor(background_color->valuestring));
|
||||
}
|
||||
if (cJSON_IsString(background_image)) {
|
||||
if (!assets->GetAssetData(background_image->valuestring, ptr, size)) {
|
||||
if (!GetAssetData(background_image->valuestring, ptr, size)) {
|
||||
ESP_LOGE(TAG, "The background image file %s is not found", background_image->valuestring);
|
||||
return false;
|
||||
}
|
||||
@ -330,6 +243,7 @@ bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
ESP_LOGI(TAG, "Refreshing display theme...");
|
||||
@ -338,95 +252,21 @@ bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
if (current_theme != nullptr) {
|
||||
display->SetTheme(current_theme);
|
||||
}
|
||||
|
||||
// Parse hide_subtitle configuration
|
||||
cJSON* hide_subtitle = cJSON_GetObjectItem(root, "hide_subtitle");
|
||||
if (cJSON_IsBool(hide_subtitle)) {
|
||||
bool hide = cJSON_IsTrue(hide_subtitle);
|
||||
auto lcd_display = dynamic_cast<LcdDisplay*>(display);
|
||||
if (lcd_display != nullptr) {
|
||||
lcd_display->SetHideSubtitle(hide);
|
||||
ESP_LOGI(TAG, "Set hide_subtitle to %s", hide ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(root);
|
||||
return true;
|
||||
}
|
||||
#endif // HAVE_LVGL
|
||||
|
||||
bool Assets::EmoteStrategy::InitializePartition(Assets* assets) {
|
||||
assets->partition_valid_ = false;
|
||||
|
||||
if (!Assets::FindPartition(assets)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t ret = ESP_ERR_INVALID_STATE;
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
auto* emote_display = dynamic_cast<emote::EmoteDisplay*>(display);
|
||||
if (emote_display && emote_display->GetEmoteHandle() != nullptr) {
|
||||
const emote_data_t data = {
|
||||
.type = EMOTE_SOURCE_PARTITION,
|
||||
.source = {
|
||||
.partition_label = PARTITION_LABEL,
|
||||
},
|
||||
.flags = {
|
||||
.mmap_enable = true, //must be true here!!!
|
||||
},
|
||||
};
|
||||
ret = emote_mount_assets(emote_display->GetEmoteHandle(), &data);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Emote display is not initialized");
|
||||
}
|
||||
assets->partition_valid_ = ((ret == ESP_OK) ? true : false);
|
||||
return assets->partition_valid_;
|
||||
}
|
||||
|
||||
void Assets::EmoteStrategy::UnApplyPartition(Assets* assets) {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
auto* emote_display = dynamic_cast<emote::EmoteDisplay*>(display);
|
||||
if (emote_display && emote_display->GetEmoteHandle() != nullptr) {
|
||||
emote_unmount_assets(emote_display->GetEmoteHandle());
|
||||
}
|
||||
(void)assets; // Unused parameter
|
||||
}
|
||||
|
||||
bool Assets::EmoteStrategy::GetAssetData(Assets* assets, const std::string& name, void*& ptr, size_t& size) {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
auto* emote_display = dynamic_cast<emote::EmoteDisplay*>(display);
|
||||
if (emote_display && emote_display->GetEmoteHandle() != nullptr) {
|
||||
const uint8_t* data = nullptr;
|
||||
size_t data_size = 0;
|
||||
if (ESP_OK == emote_get_asset_data_by_name(emote_display->GetEmoteHandle(), name.c_str(), &data, &data_size)) {
|
||||
ptr = const_cast<void*>(static_cast<const void*>(data));
|
||||
size = data_size;
|
||||
return true;
|
||||
}
|
||||
ESP_LOGE(TAG, "Failed to get asset data by name: %s", name.c_str());
|
||||
return false;
|
||||
}
|
||||
(void)assets; // Unused parameter
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Assets::EmoteStrategy::Apply(Assets* assets) {
|
||||
Assets::LoadSrmodelsFromIndex(assets);
|
||||
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
auto* emote_display = dynamic_cast<emote::EmoteDisplay*>(display);
|
||||
|
||||
if (emote_display && emote_display->GetEmoteHandle() != nullptr) {
|
||||
emote_load_assets(emote_display->GetEmoteHandle());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Assets::Download(std::string url, std::function<void(int progress, size_t speed)> progress_callback) {
|
||||
ESP_LOGI(TAG, "Downloading new version of assets from %s", url.c_str());
|
||||
|
||||
|
||||
// 取消当前资源分区的内存映射
|
||||
UnApplyPartition();
|
||||
if (mmap_handle_ != 0) {
|
||||
esp_partition_munmap(mmap_handle_);
|
||||
mmap_handle_ = 0;
|
||||
mmap_root_ = nullptr;
|
||||
}
|
||||
checksum_valid_ = false;
|
||||
assets_.clear();
|
||||
|
||||
// 下载新的资源文件
|
||||
auto network = Board::GetInstance().GetNetwork();
|
||||
@ -548,3 +388,19 @@ bool Assets::Download(std::string url, std::function<void(int progress, size_t s
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Assets::GetAssetData(const std::string& name, void*& ptr, size_t& size) {
|
||||
auto asset = assets_.find(name);
|
||||
if (asset == assets_.end()) {
|
||||
return false;
|
||||
}
|
||||
auto data = (const char*)(mmap_root_ + asset->second.offset);
|
||||
if (data[0] != 'Z' || data[1] != 'Z') {
|
||||
ESP_LOGE(TAG, "The asset %s is not valid with magic %02x%02x", name.c_str(), data[0], data[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
ptr = static_cast<void*>(const_cast<char*>(data + 2));
|
||||
size = asset->second.size;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,19 +1,31 @@
|
||||
#ifndef ASSETS_H
|
||||
#define ASSETS_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <esp_partition.h>
|
||||
#include <model_path.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#if HAVE_LVGL
|
||||
#include <spi_flash_mmap.h>
|
||||
#endif
|
||||
|
||||
// All combinations of wakenet_model, text_font, emoji_collection can be found from the following url:
|
||||
// https://github.com/78/xiaozhi-fonts/releases/tag/assets
|
||||
|
||||
#define ASSETS_PUHUI_COMMON_14_1 "none-font_puhui_common_14_1-none.bin"
|
||||
#define ASSETS_XIAOZHI_WAKENET "wn9_nihaoxiaozhi_tts-none-none.bin"
|
||||
#define ASSETS_XIAOZHI_WAKENET_SMALL "wn9s_nihaoxiaozhi-none-none.bin"
|
||||
#define ASSETS_XIAOZHI_PUHUI_COMMON_14_1 "wn9_nihaoxiaozhi_tts-font_puhui_common_14_1-none.bin"
|
||||
#define ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_32 "wn9_nihaoxiaozhi_tts-font_puhui_common_16_4-emojis_32.bin"
|
||||
#define ASSETS_XIAOZHI_PUHUI_COMMON_16_4_EMOJI_64 "wn9_nihaoxiaozhi_tts-font_puhui_common_16_4-emojis_64.bin"
|
||||
#define ASSETS_XIAOZHI_PUHUI_COMMON_20_4_EMOJI_64 "wn9_nihaoxiaozhi_tts-font_puhui_common_20_4-emojis_64.bin"
|
||||
#define ASSETS_XIAOZHI_PUHUI_COMMON_30_4_EMOJI_64 "wn9_nihaoxiaozhi_tts-font_puhui_common_30_4-emojis_64.bin"
|
||||
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_14_1 "wn9s_nihaoxiaozhi-font_puhui_common_14_1-none.bin"
|
||||
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_16_4_EMOJI_32 "wn9s_nihaoxiaozhi-font_puhui_common_16_4-emojis_32.bin"
|
||||
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_20_4_EMOJI_32 "wn9s_nihaoxiaozhi-font_puhui_common_20_4-emojis_32.bin"
|
||||
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_20_4_EMOJI_64 "wn9s_nihaoxiaozhi-font_puhui_common_20_4-emojis_64.bin"
|
||||
#define ASSETS_XIAOZHI_S_PUHUI_COMMON_30_4_EMOJI_64 "wn9s_nihaoxiaozhi-font_puhui_common_30_4-emojis_64.bin"
|
||||
|
||||
struct Asset {
|
||||
size_t size;
|
||||
@ -22,68 +34,32 @@ struct Asset {
|
||||
|
||||
class Assets {
|
||||
public:
|
||||
static Assets& GetInstance() {
|
||||
static Assets instance;
|
||||
return instance;
|
||||
}
|
||||
Assets(std::string default_assets_url);
|
||||
~Assets();
|
||||
|
||||
bool Download(std::string url, std::function<void(int progress, size_t speed)> progress_callback);
|
||||
bool Apply();
|
||||
bool GetAssetData(const std::string& name, void*& ptr, size_t& size);
|
||||
|
||||
inline bool partition_valid() const { return partition_valid_; }
|
||||
inline bool checksum_valid() const { return checksum_valid_; }
|
||||
inline std::string default_assets_url() const { return default_assets_url_; }
|
||||
|
||||
private:
|
||||
Assets();
|
||||
Assets(const Assets&) = delete;
|
||||
Assets& operator=(const Assets&) = delete;
|
||||
|
||||
bool InitializePartition();
|
||||
void UnApplyPartition();
|
||||
static bool FindPartition(Assets* assets);
|
||||
static bool LoadSrmodelsFromIndex(Assets* assets, cJSON* root = nullptr);
|
||||
|
||||
class AssetStrategy {
|
||||
public:
|
||||
virtual ~AssetStrategy() = default;
|
||||
virtual bool Apply(Assets* assets) = 0;
|
||||
virtual bool InitializePartition(Assets* assets) = 0;
|
||||
virtual void UnApplyPartition(Assets* assets) = 0;
|
||||
virtual bool GetAssetData(Assets* assets, const std::string& name, void*& ptr, size_t& size) = 0;
|
||||
};
|
||||
|
||||
class LvglStrategy : public AssetStrategy {
|
||||
public:
|
||||
bool Apply(Assets* assets) override;
|
||||
bool InitializePartition(Assets* assets) override;
|
||||
void UnApplyPartition(Assets* assets) override;
|
||||
bool GetAssetData(Assets* assets, const std::string& name, void*& ptr, size_t& size) override;
|
||||
private:
|
||||
static uint32_t CalculateChecksum(const char* data, uint32_t length);
|
||||
std::map<std::string, Asset> assets_;
|
||||
esp_partition_mmap_handle_t mmap_handle_ = 0;
|
||||
const char* mmap_root_ = nullptr;
|
||||
bool checksum_valid_ = false;
|
||||
};
|
||||
|
||||
class EmoteStrategy : public AssetStrategy {
|
||||
public:
|
||||
bool Apply(Assets* assets) override;
|
||||
bool InitializePartition(Assets* assets) override;
|
||||
void UnApplyPartition(Assets* assets) override;
|
||||
bool GetAssetData(Assets* assets, const std::string& name, void*& ptr, size_t& size) override;
|
||||
};
|
||||
|
||||
// Strategy instance
|
||||
std::unique_ptr<AssetStrategy> strategy_;
|
||||
uint32_t CalculateChecksum(const char* data, uint32_t length);
|
||||
bool GetAssetData(const std::string& name, void*& ptr, size_t& size);
|
||||
|
||||
protected:
|
||||
const esp_partition_t* partition_ = nullptr;
|
||||
esp_partition_mmap_handle_t mmap_handle_ = 0;
|
||||
const char* mmap_root_ = nullptr;
|
||||
bool partition_valid_ = false;
|
||||
bool checksum_valid_ = false;
|
||||
std::string default_assets_url_;
|
||||
srmodel_list_t* models_list_ = nullptr;
|
||||
std::map<std::string, Asset> assets_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,57 +0,0 @@
|
||||
{
|
||||
"language": {
|
||||
"type": "bg-BG"
|
||||
},
|
||||
"strings": {
|
||||
"WARNING": "Предупреждение",
|
||||
"INFO": "Информация",
|
||||
"ERROR": "Грешка",
|
||||
"VERSION": "Версия ",
|
||||
"LOADING_PROTOCOL": "Влизане в системата...",
|
||||
"INITIALIZING": "Инициализация...",
|
||||
"PIN_ERROR": "Моля, поставете SIM карта",
|
||||
"REG_ERROR": "Не може да се осъществи достъп до мрежата, моля проверете статуса на SIM картата",
|
||||
"DETECTING_MODULE": "Откриване на модул...",
|
||||
"REGISTERING_NETWORK": "Изчакване на мрежата...",
|
||||
"CHECKING_NEW_VERSION": "Проверка за нова версия...",
|
||||
"CHECK_NEW_VERSION_FAILED": "Проверката за нова версия е неуспешна, ще се опита отново след %d секунди: %s",
|
||||
"SWITCH_TO_WIFI_NETWORK": "Превключване към Wi-Fi...",
|
||||
"SWITCH_TO_4G_NETWORK": "Превключване към 4G...",
|
||||
"STANDBY": "Режим на готовност",
|
||||
"CONNECT_TO": "Свързване към ",
|
||||
"CONNECTING": "Свързване...",
|
||||
"CONNECTION_SUCCESSFUL": "Успешно свързване",
|
||||
"CONNECTED_TO": "Свързан към ",
|
||||
"LISTENING": "Слушане...",
|
||||
"SPEAKING": "Говорене...",
|
||||
"SERVER_NOT_FOUND": "Търсене на налична услуга",
|
||||
"SERVER_NOT_CONNECTED": "Не може да се свърже с услугата, моля опитайте по-късно",
|
||||
"SERVER_TIMEOUT": "Времето за изчакване на отговор изтече",
|
||||
"SERVER_ERROR": "Неуспешно изпращане, моля проверете мрежата",
|
||||
"CONNECT_TO_HOTSPOT": "Горещa точка: ",
|
||||
"ACCESS_VIA_BROWSER": " Конфигурационен URL: ",
|
||||
"WIFI_CONFIG_MODE": "Режим на конфигуриране на Wi-Fi",
|
||||
"ENTERING_WIFI_CONFIG_MODE": "Влизане в режим на конфигуриране на Wi-Fi...",
|
||||
"SCANNING_WIFI": "Сканиране на Wi-Fi...",
|
||||
"NEW_VERSION": "Нова версия ",
|
||||
"OTA_UPGRADE": "OTA надстройка",
|
||||
"UPGRADING": "Системата се надстройва...",
|
||||
"UPGRADE_FAILED": "Надстройката е неуспешна",
|
||||
"ACTIVATION": "Активация",
|
||||
"BATTERY_LOW": "Слаба батерия",
|
||||
"BATTERY_CHARGING": "Зарядна",
|
||||
"BATTERY_FULL": "Батерията е пълна",
|
||||
"BATTERY_NEED_CHARGE": "Слаба батерия, моля заредете",
|
||||
"VOLUME": "Сила на звука ",
|
||||
"MUTED": "Заглушено",
|
||||
"MAX_VOLUME": "Максимална сила на звука",
|
||||
"RTC_MODE_OFF": "AEC изключен",
|
||||
"RTC_MODE_ON": "AEC включен",
|
||||
"PLEASE_WAIT": "Моля, изчакайте...",
|
||||
"FOUND_NEW_ASSETS": "Намерени нови ресурси: %s",
|
||||
"DOWNLOAD_ASSETS_FAILED": "Неуспешно изтегляне на ресурси",
|
||||
"LOADING_ASSETS": "Зареждане на ресурси...",
|
||||
"HELLO_MY_FRIEND": "Здравей, мой приятел!"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,57 +0,0 @@
|
||||
{
|
||||
"language": {
|
||||
"type": "ca-ES"
|
||||
},
|
||||
"strings": {
|
||||
"WARNING": "Advertència",
|
||||
"INFO": "Informació",
|
||||
"ERROR": "Error",
|
||||
"VERSION": "Versió ",
|
||||
"LOADING_PROTOCOL": "Iniciant sessió...",
|
||||
"INITIALIZING": "Inicialitzant...",
|
||||
"PIN_ERROR": "Si us plau, inseriu la targeta SIM",
|
||||
"REG_ERROR": "No es pot accedir a la xarxa, si us plau comproveu l'estat de la targeta SIM",
|
||||
"DETECTING_MODULE": "Detectant mòdul...",
|
||||
"REGISTERING_NETWORK": "Esperant la xarxa...",
|
||||
"CHECKING_NEW_VERSION": "Comprovant nova versió...",
|
||||
"CHECK_NEW_VERSION_FAILED": "La comprovació de nova versió ha fallat, es tornarà a intentar en %d segons: %s",
|
||||
"SWITCH_TO_WIFI_NETWORK": "Canviant a Wi-Fi...",
|
||||
"SWITCH_TO_4G_NETWORK": "Canviant a 4G...",
|
||||
"STANDBY": "En espera",
|
||||
"CONNECT_TO": "Connectar a ",
|
||||
"CONNECTING": "Connectant...",
|
||||
"CONNECTION_SUCCESSFUL": "Connexió exitosa",
|
||||
"CONNECTED_TO": "Connectat a ",
|
||||
"LISTENING": "Escoltant...",
|
||||
"SPEAKING": "Parlant...",
|
||||
"SERVER_NOT_FOUND": "Buscant servei disponible",
|
||||
"SERVER_NOT_CONNECTED": "No es pot connectar al servei, si us plau intenteu-ho més tard",
|
||||
"SERVER_TIMEOUT": "Temps d'espera de resposta exhaurit",
|
||||
"SERVER_ERROR": "L'enviament ha fallat, si us plau comproveu la xarxa",
|
||||
"CONNECT_TO_HOTSPOT": "Punt d'accés: ",
|
||||
"ACCESS_VIA_BROWSER": " URL de configuració: ",
|
||||
"WIFI_CONFIG_MODE": "Mode de configuració Wi-Fi",
|
||||
"ENTERING_WIFI_CONFIG_MODE": "Entrant en mode de configuració Wi-Fi...",
|
||||
"SCANNING_WIFI": "Escanejant Wi-Fi...",
|
||||
"NEW_VERSION": "Nova versió ",
|
||||
"OTA_UPGRADE": "Actualització OTA",
|
||||
"UPGRADING": "El sistema s'està actualitzant...",
|
||||
"UPGRADE_FAILED": "L'actualització ha fallat",
|
||||
"ACTIVATION": "Activació",
|
||||
"BATTERY_LOW": "Bateria baixa",
|
||||
"BATTERY_CHARGING": "Carregant",
|
||||
"BATTERY_FULL": "Bateria plena",
|
||||
"BATTERY_NEED_CHARGE": "Bateria baixa, si us plau carregueu",
|
||||
"VOLUME": "Volum ",
|
||||
"MUTED": "Silenciat",
|
||||
"MAX_VOLUME": "Volum màxim",
|
||||
"RTC_MODE_OFF": "AEC desactivat",
|
||||
"RTC_MODE_ON": "AEC activat",
|
||||
"PLEASE_WAIT": "Si us plau, espereu...",
|
||||
"FOUND_NEW_ASSETS": "S'han trobat nous recursos: %s",
|
||||
"DOWNLOAD_ASSETS_FAILED": "No s'han pogut descarregar els recursos",
|
||||
"LOADING_ASSETS": "Carregant recursos...",
|
||||
"HELLO_MY_FRIEND": "Hola, amic meu!"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,57 +0,0 @@
|
||||
{
|
||||
"language": {
|
||||
"type": "da-DK"
|
||||
},
|
||||
"strings": {
|
||||
"WARNING": "Advarsel",
|
||||
"INFO": "Information",
|
||||
"ERROR": "Fejl",
|
||||
"VERSION": "Version ",
|
||||
"LOADING_PROTOCOL": "Logger ind...",
|
||||
"INITIALIZING": "Initialiserer...",
|
||||
"PIN_ERROR": "Indsæt venligst SIM-kort",
|
||||
"REG_ERROR": "Kan ikke få adgang til netværket, tjek venligst SIM-kortets status",
|
||||
"DETECTING_MODULE": "Detekterer modul...",
|
||||
"REGISTERING_NETWORK": "Venter på netværk...",
|
||||
"CHECKING_NEW_VERSION": "Tjekker for ny version...",
|
||||
"CHECK_NEW_VERSION_FAILED": "Tjek for ny version mislykkedes, prøver igen om %d sekunder: %s",
|
||||
"SWITCH_TO_WIFI_NETWORK": "Skifter til Wi-Fi...",
|
||||
"SWITCH_TO_4G_NETWORK": "Skifter til 4G...",
|
||||
"STANDBY": "Standby",
|
||||
"CONNECT_TO": "Forbind til ",
|
||||
"CONNECTING": "Forbinder...",
|
||||
"CONNECTION_SUCCESSFUL": "Forbindelse lykkedes",
|
||||
"CONNECTED_TO": "Forbundet til ",
|
||||
"LISTENING": "Lytter...",
|
||||
"SPEAKING": "Taler...",
|
||||
"SERVER_NOT_FOUND": "Søger efter tilgængelig tjeneste",
|
||||
"SERVER_NOT_CONNECTED": "Kan ikke forbinde til tjeneste, prøv venligst igen senere",
|
||||
"SERVER_TIMEOUT": "Timeout ved venten på svar",
|
||||
"SERVER_ERROR": "Afsendelse mislykkedes, tjek venligst netværket",
|
||||
"CONNECT_TO_HOTSPOT": "Hotspot: ",
|
||||
"ACCESS_VIA_BROWSER": " Konfigurations-URL: ",
|
||||
"WIFI_CONFIG_MODE": "Wi-Fi-konfigurationstilstand",
|
||||
"ENTERING_WIFI_CONFIG_MODE": "Går ind i Wi-Fi-konfigurationstilstand...",
|
||||
"SCANNING_WIFI": "Scanner Wi-Fi...",
|
||||
"NEW_VERSION": "Ny version ",
|
||||
"OTA_UPGRADE": "OTA-opgradering",
|
||||
"UPGRADING": "Systemet opgraderes...",
|
||||
"UPGRADE_FAILED": "Opgradering mislykkedes",
|
||||
"ACTIVATION": "Aktivering",
|
||||
"BATTERY_LOW": "Lavt batteri",
|
||||
"BATTERY_CHARGING": "Oplader",
|
||||
"BATTERY_FULL": "Batteriet er fuldt",
|
||||
"BATTERY_NEED_CHARGE": "Lavt batteri, oplad venligst",
|
||||
"VOLUME": "Lydstyrke ",
|
||||
"MUTED": "Lydløs",
|
||||
"MAX_VOLUME": "Maksimal lydstyrke",
|
||||
"RTC_MODE_OFF": "AEC slukket",
|
||||
"RTC_MODE_ON": "AEC tændt",
|
||||
"PLEASE_WAIT": "Vent venligst...",
|
||||
"FOUND_NEW_ASSETS": "Fandt nye ressourcer: %s",
|
||||
"DOWNLOAD_ASSETS_FAILED": "Download af ressourcer mislykkedes",
|
||||
"LOADING_ASSETS": "Indlæser ressourcer...",
|
||||
"HELLO_MY_FRIEND": "Hej, min ven!"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,57 +0,0 @@
|
||||
{
|
||||
"language": {
|
||||
"type": "el-GR"
|
||||
},
|
||||
"strings": {
|
||||
"WARNING": "Προειδοποίηση",
|
||||
"INFO": "Πληροφορίες",
|
||||
"ERROR": "Σφάλμα",
|
||||
"VERSION": "Έκδοση ",
|
||||
"LOADING_PROTOCOL": "Σύνδεση...",
|
||||
"INITIALIZING": "Αρχικοποίηση...",
|
||||
"PIN_ERROR": "Παρακαλώ εισαγάγετε κάρτα SIM",
|
||||
"REG_ERROR": "Αδυναμία πρόσβασης στο δίκτυο, ελέγξτε την κατάσταση της κάρτας SIM",
|
||||
"DETECTING_MODULE": "Ανίχνευση μονάδας...",
|
||||
"REGISTERING_NETWORK": "Αναμονή δικτύου...",
|
||||
"CHECKING_NEW_VERSION": "Έλεγχος για νέα έκδοση...",
|
||||
"CHECK_NEW_VERSION_FAILED": "Ο έλεγχος για νέα έκδοση απέτυχε, θα επαναληφθεί σε %d δευτερόλεπτα: %s",
|
||||
"SWITCH_TO_WIFI_NETWORK": "Μετάβαση σε Wi-Fi...",
|
||||
"SWITCH_TO_4G_NETWORK": "Μετάβαση σε 4G...",
|
||||
"STANDBY": "Αναμονή",
|
||||
"CONNECT_TO": "Σύνδεση σε ",
|
||||
"CONNECTING": "Σύνδεση...",
|
||||
"CONNECTION_SUCCESSFUL": "Επιτυχής σύνδεση",
|
||||
"CONNECTED_TO": "Συνδέθηκε σε ",
|
||||
"LISTENING": "Ακρόαση...",
|
||||
"SPEAKING": "Ομιλία...",
|
||||
"SERVER_NOT_FOUND": "Αναζήτηση διαθέσιμης υπηρεσίας",
|
||||
"SERVER_NOT_CONNECTED": "Αδυναμία σύνδεσης στην υπηρεσία, παρακαλώ δοκιμάστε αργότερα",
|
||||
"SERVER_TIMEOUT": "Λήξη χρόνου αναμονής απόκρισης",
|
||||
"SERVER_ERROR": "Η αποστολή απέτυχε, ελέγξτε το δίκτυο",
|
||||
"CONNECT_TO_HOTSPOT": "Σημείο πρόσβασης: ",
|
||||
"ACCESS_VIA_BROWSER": " URL διαμόρφωσης: ",
|
||||
"WIFI_CONFIG_MODE": "Λειτουργία διαμόρφωσης Wi-Fi",
|
||||
"ENTERING_WIFI_CONFIG_MODE": "Είσοδος σε λειτουργία διαμόρφωσης Wi-Fi...",
|
||||
"SCANNING_WIFI": "Σάρωση Wi-Fi...",
|
||||
"NEW_VERSION": "Νέα έκδοση ",
|
||||
"OTA_UPGRADE": "Αναβάθμιση OTA",
|
||||
"UPGRADING": "Το σύστημα αναβαθμίζεται...",
|
||||
"UPGRADE_FAILED": "Η αναβάθμιση απέτυχε",
|
||||
"ACTIVATION": "Ενεργοποίηση",
|
||||
"BATTERY_LOW": "Χαμηλή μπαταρία",
|
||||
"BATTERY_CHARGING": "Φόρτιση",
|
||||
"BATTERY_FULL": "Πλήρης μπαταρία",
|
||||
"BATTERY_NEED_CHARGE": "Χαμηλή μπαταρία, παρακαλώ φορτίστε",
|
||||
"VOLUME": "Ένταση ",
|
||||
"MUTED": "Σίγαση",
|
||||
"MAX_VOLUME": "Μέγιστη ένταση",
|
||||
"RTC_MODE_OFF": "AEC απενεργοποιημένο",
|
||||
"RTC_MODE_ON": "AEC ενεργοποιημένο",
|
||||
"PLEASE_WAIT": "Παρακαλώ περιμένετε...",
|
||||
"FOUND_NEW_ASSETS": "Βρέθηκαν νέοι πόροι: %s",
|
||||
"DOWNLOAD_ASSETS_FAILED": "Αποτυχία λήψης πόρων",
|
||||
"LOADING_ASSETS": "Φόρτωση πόρων...",
|
||||
"HELLO_MY_FRIEND": "Γεια σου, φίλε μου!"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,57 +0,0 @@
|
||||
{
|
||||
"language": {
|
||||
"type": "fa-IR"
|
||||
},
|
||||
"strings": {
|
||||
"WARNING": "هشدار",
|
||||
"INFO": "اطلاعات",
|
||||
"ERROR": "خطا",
|
||||
"VERSION": "نسخه ",
|
||||
"LOADING_PROTOCOL": "ورود به سیستم...",
|
||||
"INITIALIZING": "در حال راهاندازی...",
|
||||
"PIN_ERROR": "لطفاً سیم کارت را وارد کنید",
|
||||
"REG_ERROR": "عدم دسترسی به شبکه، لطفاً وضعیت سیم کارت را بررسی کنید",
|
||||
"DETECTING_MODULE": "شناسایی ماژول...",
|
||||
"REGISTERING_NETWORK": "در انتظار شبکه...",
|
||||
"CHECKING_NEW_VERSION": "بررسی نسخه جدید...",
|
||||
"CHECK_NEW_VERSION_FAILED": "بررسی نسخه جدید ناموفق بود، پس از %d ثانیه مجدداً تلاش میشود: %s",
|
||||
"SWITCH_TO_WIFI_NETWORK": "تغییر به Wi-Fi...",
|
||||
"SWITCH_TO_4G_NETWORK": "تغییر به 4G...",
|
||||
"STANDBY": "آماده به کار",
|
||||
"CONNECT_TO": "اتصال به ",
|
||||
"CONNECTING": "در حال اتصال...",
|
||||
"CONNECTION_SUCCESSFUL": "اتصال موفق",
|
||||
"CONNECTED_TO": "متصل به ",
|
||||
"LISTENING": "در حال گوش دادن...",
|
||||
"SPEAKING": "در حال صحبت...",
|
||||
"SERVER_NOT_FOUND": "جستجوی سرویس در دسترس",
|
||||
"SERVER_NOT_CONNECTED": "اتصال به سرویس برقرار نشد، لطفاً بعداً تلاش کنید",
|
||||
"SERVER_TIMEOUT": "زمان انتظار برای پاسخ به پایان رسید",
|
||||
"SERVER_ERROR": "ارسال ناموفق، لطفاً شبکه را بررسی کنید",
|
||||
"CONNECT_TO_HOTSPOT": "نقطه اتصال: ",
|
||||
"ACCESS_VIA_BROWSER": " آدرس پیکربندی: ",
|
||||
"WIFI_CONFIG_MODE": "حالت پیکربندی Wi-Fi",
|
||||
"ENTERING_WIFI_CONFIG_MODE": "ورود به حالت پیکربندی Wi-Fi...",
|
||||
"SCANNING_WIFI": "جستجوی Wi-Fi...",
|
||||
"NEW_VERSION": "نسخه جدید ",
|
||||
"OTA_UPGRADE": "بهروزرسانی OTA",
|
||||
"UPGRADING": "سیستم در حال بهروزرسانی است...",
|
||||
"UPGRADE_FAILED": "بهروزرسانی ناموفق بود",
|
||||
"ACTIVATION": "فعالسازی",
|
||||
"BATTERY_LOW": "شارژ باتری کم",
|
||||
"BATTERY_CHARGING": "در حال شارژ",
|
||||
"BATTERY_FULL": "باتری پر است",
|
||||
"BATTERY_NEED_CHARGE": "شارژ باتری کم، لطفاً شارژ کنید",
|
||||
"VOLUME": "صدا ",
|
||||
"MUTED": "بیصدا",
|
||||
"MAX_VOLUME": "حداکثر صدا",
|
||||
"RTC_MODE_OFF": "AEC خاموش",
|
||||
"RTC_MODE_ON": "AEC روشن",
|
||||
"PLEASE_WAIT": "لطفاً صبر کنید...",
|
||||
"FOUND_NEW_ASSETS": "منابع جدید یافت شد: %s",
|
||||
"DOWNLOAD_ASSETS_FAILED": "دانلود منابع ناموفق بود",
|
||||
"LOADING_ASSETS": "بارگذاری منابع...",
|
||||
"HELLO_MY_FRIEND": "سلام، دوست من!"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user