Compare commits

..

32 Commits

Author SHA1 Message Date
Terrence
cc5d724506 Support ogg files frame duration <= 60 2025-08-09 14:41:37 +08:00
Terrence
bba26ef69c fix building echoear 2025-08-09 14:39:31 +08:00
Terrence
7fcd40dbe7 feat: Add locales with OGG sounds 2025-08-09 07:57:52 +08:00
Terrence
48a1c5da29 xmin-c3 share MCP tool and sleep mode can be disabled 2025-08-09 03:07:09 +08:00
Xiaoxia
2a02dd65be fix ReadAudioData frame duration (#1051) 2025-08-08 21:50:28 +08:00
virgil
845b760db3 fix: Delete the esp_jpeg_simd component to resolve function conflicts (#1049) 2025-08-08 21:00:34 +08:00
Xiaoxia
f86637cf1c fix: codec unexpectedly closed by timer after open (#1046)
Co-authored-by: Xiaoxia <terrence.huang@tenclass.com>
2025-08-08 15:39:12 +08:00
Xiaoxia
363073658a fix: OTA buffer overflow caused by slow SetChatMessage (#1031) 2025-08-06 01:16:52 +08:00
laride
da228f2582 fix: ci idf.py not found (#1030) 2025-08-05 22:18:28 +08:00
laride
36476f05cd feat: add build CI (#1028) 2025-08-05 20:03:37 +08:00
flying1425
90602d3802 waveshare-c6-lcd-1.69 新增电池电量显示功能及电池供电状态下的PWR按键开关机功能。 (#1020)
* 新增电池电量显示功能及电池供电状态下的PWR按键开关机功能。

* 代码风格优化

---------

Co-authored-by: flyingtjy <flyingtjy@gmail.com>
2025-08-04 22:38:13 +08:00
Zxczzzzzzz
b2e1c5bb5c 添加了一个声波配网的HTML界面 (#996)
* Add HTML page for sonic-based Wi-Fi provisioning

* Add HTML page for sonic-based Wi-Fi provisioning

* Add soundwave provisioning UI and fix bugs

* Add soundwave provisioning UI and fix bugs

* Move sonic_wifi_config.html to the docs folder

---------

Co-authored-by: luyuhan <xiaolumylove@icloud.com>
2025-08-02 14:13:35 +08:00
Terrence
d58d55cfe7 Bump to 1.8.5 2025-08-02 01:27:14 +08:00
espressif2022
cd23e0f155 feat: add emote_gfx UI for EchoEar (#1022)
* feat: add emote_gfx UI for EchoEar

* feat: delete local assets
2025-08-01 18:07:13 +08:00
Xiaoxia
26d9ff283f Fix custom wakeword for dual mic (#1018) 2025-08-01 13:30:17 +08:00
Xiaoxia
fb85019c3c change bread-compact-wifi-s3cam test gpio num (#1017) 2025-08-01 05:28:27 +08:00
HonestQiao
4859d57fea 修复esp32-p4配网客户端无法连接、连接获取不到ip或者无法打开配置页面的问题 (#1012) 2025-07-31 05:14:17 +08:00
Xiaoxia
03394fe38d update the sleep time of xmini-c3 with wake word to 300s (#1007) 2025-07-30 15:25:39 +08:00
jake12355
e0e12450c5 jiuchuan-s3修改按键定义取消不对话自动关机修复屏幕显示不全 (#997)
* jiuchuan-s3修改按键定义取消不对话自动关机修复屏幕显示不全

* jiuchuan-s3修改按键定义取消不对话自动关机修复屏幕显示不全
2025-07-29 17:28:40 +08:00
Xiaoxia
e5ac40aac8 fix audio pm (#1004) 2025-07-29 15:25:40 +08:00
Xiaoxia
345c8be467 Add custom wakeword threshold option (#1003) 2025-07-29 10:56:52 +08:00
香草味的纳西妲喵
def6301292 增加其他分辨率表情转换选项 (#987)
* Create requirements.txt

* Update README.md

* add: 增加其他尺寸表情选项
2025-07-26 02:31:09 +08:00
Xiaoxia
df7cbdfcb6 fix esp-hi crashing in esp_codec_dev_close() (#984) 2025-07-25 10:36:56 +08:00
Terrence
d38763d5ef Reduce SRAM usage of audio tasks 2025-07-25 08:27:12 +08:00
LILYGO_L
e90e540933 增强T-CameraPlus-S3麦克风接收音量 (#958)
* Adapt for LilyGO-T-Circle-S3 device

* Adapt for LilyGO-T-Circle-S3 device

* Remove comments and modify the size of the lilygo-t-circle-s3 image

* Modify the code style and format to Google C++

* Modify the code style and format to Google C++

* Fixed bugs in the LILYGO T-Circle-S3 board and added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Merge branch 'main' of https://github.com/Llgok/xiaozhi-esp32

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Added support for two new boards: LILYGO T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Fix the color display issue for T-Display-S3-Pro-MVSRLora and LILYGO T-Display-S3-Pro-MVSRLora_NO_BATTERY.

* Update T-CameraPlus-S3_V1.2 Version Xiaozhi Example

* Resolve the issue where the camera on the T-CameraPlus-S3_V1.2 board cannot be used normally.

* Enhance microphone reception volume

* fix the issue where voice wake-up is not working

* fix the issue where voice wake-up is not working
2025-07-23 23:02:45 +08:00
Ky1eYang
656bf3c7fa FIX: 修复双声道声波配网失效, 添加屏幕打印SSID/密码 (#971)
* debug: 添加声波配网的log打印点display

* fix: 修复双声道下声波配网失效的问题

* fix: codec可能为nullptr的问题(需要从单例board获取)

* Update afsk_demod.cc

fix coding style

---------

Co-authored-by: yangkaiyue <yangkaiyue1@tenclass.com>
Co-authored-by: Xiaoxia <terrence@tenclass.com>
2025-07-23 22:59:07 +08:00
Y1hsiaochunnn
ca35b0761b Update README.md (#968)
The README text description is incorrect. It needs to be corrected.
2025-07-23 22:47:19 +08:00
Terrence
b031a829c0 Bump to 1.8.2 2025-07-22 22:43:41 +08:00
Xiaoxia
3c11cceb43 增加自定义唤醒词启动失败的提升 (#965) 2025-07-22 18:57:25 +08:00
Y1hsiaochunnn
15f233e773 Add compatibility for Waveshare ESP32-S3-Touch-AMOLED-2.06 (#960)
* Add Waveshare ESP32-S3-Touch-AMOLED-2.06

* Update some configuration settings

* Add configuration to the configuration file

* Fix the abnormal areas
2025-07-22 18:02:31 +08:00
Forairaaaaa
721b58f8c7 Fix atoms3 backlight control (#959) 2025-07-22 17:55:33 +08:00
Xiaoxia
eb0bba2c89 Update LICENSE 2025-07-22 10:06:11 +08:00
550 changed files with 3955 additions and 1071 deletions

View File

@@ -1,32 +1,106 @@
name: Build and Test
name: Build Boards
on:
push:
branches:
- main
- ci/* # for ci test
pull_request:
branches:
- main
permissions:
contents: read
jobs:
build:
prepare:
name: Determine boards to build
runs-on: ubuntu-latest
outputs:
boards: ${{ steps.select.outputs.boards }}
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Espressif IoT Development Framework (ESP-IDF)
# You may pin to the exact commit or the version.
# uses: espressif/esp-idf-ci-action@8cd22ae10042fadc37890e81e9988a9113e7b506
uses: espressif/esp-idf-ci-action@v1.1.0
- name: Checkout
uses: actions/checkout@v4
with:
# Relative path under $GITHUB_WORKSPACE to place the repository
#path: # optional, default is
# Version of ESP-IDF docker image to use
esp_idf_version: release-v5.4
# ESP32 variant to build for
target: esp32s3
# Command to run inside the docker container (default: builds the project)
# command: # optional, default is idf.py build
fetch-depth: 0
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- id: list
name: Get all board list
run: |
echo "all_boards=$(python scripts/release.py --list-boards --json)" >> $GITHUB_OUTPUT
- id: select
name: Select boards based on changes
env:
ALL_BOARDS: ${{ steps.list.outputs.all_boards }}
run: |
EVENT_NAME="${{ github.event_name }}"
# For push to main branch, build all boards
if [[ "$EVENT_NAME" == "push" ]]; then
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
exit 0
fi
# 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 "Changed files:\n$CHANGED"
NEED_ALL=0
declare -A AFFECTED
while IFS= read -r file; do
if [[ "$file" == main/* && "$file" != main/boards/* ]]; then
NEED_ALL=1
fi
if [[ "$file" == main/boards/* ]]; then
board=$(echo "$file" | cut -d '/' -f3)
AFFECTED[$board]=1
fi
done <<< "$CHANGED"
if [[ "$NEED_ALL" -eq 1 ]]; then
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
else
if [[ ${#AFFECTED[@]} -eq 0 ]]; then
echo "boards=[]" >> $GITHUB_OUTPUT
else
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.board }}
needs: prepare
if: ${{ needs.prepare.outputs.boards != '[]' }}
strategy:
fail-fast: false # 单个 board 失败不影响其它 board
matrix:
board: ${{ fromJson(needs.prepare.outputs.boards) }}
runs-on: ubuntu-latest
container:
image: espressif/idf:release-v5.4
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build current board
shell: bash
run: |
source $IDF_PATH/export.sh
python scripts/release.py ${{ matrix.board }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: xiaozhi_${{ matrix.board }}_${{ github.sha }}.bin
path: build/merged-binary.bin
if-no-files-found: error

3
.gitignore vendored
View File

@@ -15,4 +15,5 @@ main/mmap_generate_emoji.h
.cache
main/mmap_generate_emoji.h
*.pyc
*.bin
*.bin
mmap_generate_*.h

View File

@@ -4,7 +4,7 @@
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
set(PROJECT_VER "1.8.1")
set(PROJECT_VER "1.8.6")
# Add this line to disable the specific warning
add_compile_options(-Wno-missing-field-initializers)

View File

@@ -1,6 +1,7 @@
MIT License
Copyright (c) 2024 Xiaoxia
Copyright (c) 2025 Shenzhen Xinzhi Future Technology Co., Ltd.
Copyright (c) 2025 Project Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

208
docs/sonic_wifi_config.html Normal file
View File

@@ -0,0 +1,208 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>小智声波配网</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
font-family: "Segoe UI", "PingFang SC", sans-serif;
background: #f0f2f5;
margin: 0;
padding: 2rem 1rem;
display: flex;
justify-content: center;
}
.card {
background: #fff;
padding: 2rem 1.5rem;
border-radius: 16px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
max-width: 400px;
width: 100%;
}
h2 {
text-align: center;
margin-bottom: 2rem;
}
label {
font-weight: bold;
display: block;
margin: 1rem 0 0.3rem;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 0.75rem;
font-size: 1rem;
border-radius: 8px;
border: 1px solid #ccc;
box-sizing: border-box;
}
input[type="checkbox"] {
margin-right: 0.5rem;
}
.checkbox-container {
margin-top: 1rem;
font-size: 0.95rem;
}
button {
width: 100%;
margin-top: 1rem;
padding: 0.8rem;
font-size: 1rem;
border: none;
border-radius: 8px;
background-color: #4a90e2;
color: #fff;
cursor: pointer;
transition: background-color 0.2s;
}
button:hover {
background-color: #357ab8;
}
button:active {
background-color: #2f6ea2;
}
audio {
margin-top: 1.5rem;
width: 100%;
outline: none;
}
</style>
</head>
<body>
<div class="card">
<h2>📶 小智声波配网</h2>
<label for="ssid">WiFi 名称</label>
<input id="ssid" type="text" value="" placeholder="请输入 WiFi 名称" />
<label for="pwd">WiFi 密码</label>
<input id="pwd" type="password" value="" placeholder="请输入 WiFi 密码" />
<div class="checkbox-container">
<label><input type="checkbox" id="loopCheck" checked /> 自动循环播放声波</label>
</div>
<button onclick="generate()">🎵 生成并播放声波</button>
<button onclick="stopPlay()">⏹️ 停止播放</button>
<audio id="player" controls></audio>
</div>
<script>
const MARK = 1800;
const SPACE = 1500;
const SAMPLE_RATE = 44100;
const BIT_RATE = 100;
const START_BYTES = [0x01, 0x02];
const END_BYTES = [0x03, 0x04];
let loopTimer = null;
function checksum(data) {
return data.reduce((sum, b) => (sum + b) & 0xff, 0);
}
function toBits(byte) {
const bits = [];
for (let i = 7; i >= 0; i--) bits.push((byte >> i) & 1);
return bits;
}
function afskModulate(bits) {
const samplesPerBit = SAMPLE_RATE / BIT_RATE;
const totalSamples = Math.floor(bits.length * samplesPerBit);
const buffer = new Float32Array(totalSamples);
for (let i = 0; i < bits.length; i++) {
const freq = bits[i] ? MARK : SPACE;
for (let j = 0; j < samplesPerBit; j++) {
const t = (i * samplesPerBit + j) / SAMPLE_RATE;
buffer[i * samplesPerBit + j] = Math.sin(2 * Math.PI * freq * t);
}
}
return buffer;
}
function floatTo16BitPCM(floatSamples) {
const buffer = new Uint8Array(floatSamples.length * 2);
for (let i = 0; i < floatSamples.length; i++) {
const s = Math.max(-1, Math.min(1, floatSamples[i]));
const val = s < 0 ? s * 0x8000 : s * 0x7fff;
buffer[i * 2] = val & 0xff;
buffer[i * 2 + 1] = (val >> 8) & 0xff;
}
return buffer;
}
function buildWav(pcm) {
const wavHeader = new Uint8Array(44);
const dataLen = pcm.length;
const fileLen = 36 + dataLen;
const writeStr = (offset, str) => {
for (let i = 0; i < str.length; i++) wavHeader[offset + i] = str.charCodeAt(i);
};
const write32 = (offset, value) => {
wavHeader[offset] = value & 0xff;
wavHeader[offset + 1] = (value >> 8) & 0xff;
wavHeader[offset + 2] = (value >> 16) & 0xff;
wavHeader[offset + 3] = (value >> 24) & 0xff;
};
const write16 = (offset, value) => {
wavHeader[offset] = value & 0xff;
wavHeader[offset + 1] = (value >> 8) & 0xff;
};
writeStr(0, 'RIFF');
write32(4, fileLen);
writeStr(8, 'WAVE');
writeStr(12, 'fmt ');
write32(16, 16);
write16(20, 1);
write16(22, 1);
write32(24, SAMPLE_RATE);
write32(28, SAMPLE_RATE * 2);
write16(32, 2);
write16(34, 16);
writeStr(36, 'data');
write32(40, dataLen);
return new Blob([wavHeader, pcm], { type: 'audio/wav' });
}
function generate() {
stopPlay();
const ssid = document.getElementById('ssid').value.trim();
const pwd = document.getElementById('pwd').value.trim();
const dataStr = ssid + '\n' + pwd;
const textBytes = Array.from(new TextEncoder().encode(dataStr));
const fullBytes = [...START_BYTES, ...textBytes, checksum(textBytes), ...END_BYTES];
let bits = [];
fullBytes.forEach((b) => (bits = bits.concat(toBits(b))));
const floatBuf = afskModulate(bits);
const pcmBuf = floatTo16BitPCM(floatBuf);
const wavBlob = buildWav(pcmBuf);
const audio = document.getElementById('player');
audio.src = URL.createObjectURL(wavBlob);
audio.load();
audio.play();
// 修改了这里:使用 'ended' 事件来实现循环播放
if (document.getElementById('loopCheck').checked) {
audio.onended = function() {
audio.currentTime = 0; // 从头开始
audio.play(); // 重新播放
};
}
}
function stopPlay() {
const audio = document.getElementById('player');
audio.pause();
audio.onended = null; // 清除事件监听
}
</script>
</body>
</html>

View File

@@ -106,6 +106,8 @@ elseif(CONFIG_BOARD_TYPE_ECHOEAR)
set(BOARD_TYPE "echoear")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8)
set(BOARD_TYPE "esp32-s3-touch-amoled-1.8")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06)
set(BOARD_TYPE "waveshare-s3-touch-amoled-2.06")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75)
set(BOARD_TYPE "waveshare-s3-touch-amoled-1.75")
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_85C)
@@ -243,18 +245,55 @@ elseif(CONFIG_LANGUAGE_EN_US)
set(LANG_DIR "en-US")
elseif(CONFIG_LANGUAGE_JA_JP)
set(LANG_DIR "ja-JP")
elseif(CONFIG_LANGUAGE_KO_KR)
set(LANG_DIR "ko-KR")
elseif(CONFIG_LANGUAGE_VI_VN)
set(LANG_DIR "vi-VN")
elseif(CONFIG_LANGUAGE_TH_TH)
set(LANG_DIR "th-TH")
elseif(CONFIG_LANGUAGE_DE_DE)
set(LANG_DIR "de-DE")
elseif(CONFIG_LANGUAGE_FR_FR)
set(LANG_DIR "fr-FR")
elseif(CONFIG_LANGUAGE_ES_ES)
set(LANG_DIR "es-ES")
elseif(CONFIG_LANGUAGE_IT_IT)
set(LANG_DIR "it-IT")
elseif(CONFIG_LANGUAGE_RU_RU)
set(LANG_DIR "ru-RU")
elseif(CONFIG_LANGUAGE_AR_SA)
set(LANG_DIR "ar-SA")
elseif(CONFIG_LANGUAGE_HI_IN)
set(LANG_DIR "hi-IN")
elseif(CONFIG_LANGUAGE_PT_PT)
set(LANG_DIR "pt-PT")
elseif(CONFIG_LANGUAGE_PL_PL)
set(LANG_DIR "pl-PL")
elseif(CONFIG_LANGUAGE_CS_CZ)
set(LANG_DIR "cs-CZ")
elseif(CONFIG_LANGUAGE_FI_FI)
set(LANG_DIR "fi-FI")
elseif(CONFIG_LANGUAGE_TR_TR)
set(LANG_DIR "tr-TR")
elseif(CONFIG_LANGUAGE_ID_ID)
set(LANG_DIR "id-ID")
elseif(CONFIG_LANGUAGE_UK_UA)
set(LANG_DIR "uk-UA")
elseif(CONFIG_LANGUAGE_RO_RO)
set(LANG_DIR "ro-RO")
endif()
# 定义生成路径
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/language.json")
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/locales/${LANG_DIR}/language.json")
set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
file(GLOB LANG_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/*.p3)
file(GLOB COMMON_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/common/*.p3)
file(GLOB LANG_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/locales/${LANG_DIR}/*.ogg)
file(GLOB COMMON_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/common/*.ogg)
# 如果目标芯片是 ESP32则排除特定文件
if(CONFIG_IDF_TARGET_ESP32)
list(REMOVE_ITEM SOURCES "audio/codecs/box_audio_codec.cc"
"audio/codecs/es8388_audio_codec.cc"
"audio/codecs/es8389_audio_codec.cc"
"led/gpio_led.cc"
)
endif()
@@ -278,7 +317,7 @@ target_compile_definitions(${COMPONENT_LIB}
add_custom_command(
OUTPUT ${LANG_HEADER}
COMMAND python ${PROJECT_DIR}/scripts/gen_lang.py
--input "${LANG_JSON}"
--language "${LANG_DIR}"
--output "${LANG_HEADER}"
DEPENDS
${LANG_JSON}
@@ -332,4 +371,25 @@ spiffs_create_partition_assets(
FLASH_IN_PROJECT
MMAP_FILE_SUPPORT_FORMAT ".aaf"
)
endif()
if(CONFIG_BOARD_TYPE_ECHOEAR)
idf_build_get_property(build_components BUILD_COMPONENTS)
foreach(COMPONENT ${build_components})
if(COMPONENT MATCHES "esp_emote_gfx" OR COMPONENT MATCHES "espressif2022__esp_emote_gfx")
set(EMOTE_GFX_COMPONENT ${COMPONENT})
idf_component_get_property(EMOTE_GFX_COMPONENT_PATH ${EMOTE_GFX_COMPONENT} COMPONENT_DIR)
set(SPIFFS_DIR "${EMOTE_GFX_COMPONENT_PATH}/emoji_normal")
break()
endif()
endforeach()
spiffs_create_partition_assets(
assets_A
${SPIFFS_DIR}
FLASH_IN_PROJECT
MMAP_FILE_SUPPORT_FORMAT ".aaf, ttf, bin"
IMPORT_INC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}
)
endif()

View File

@@ -21,6 +21,42 @@ choice
bool "English"
config LANGUAGE_JA_JP
bool "Japanese"
config LANGUAGE_KO_KR
bool "Korean"
config LANGUAGE_VI_VN
bool "Vietnamese"
config LANGUAGE_TH_TH
bool "Thai"
config LANGUAGE_DE_DE
bool "German"
config LANGUAGE_FR_FR
bool "French"
config LANGUAGE_ES_ES
bool "Spanish"
config LANGUAGE_IT_IT
bool "Italian"
config LANGUAGE_RU_RU
bool "Russian"
config LANGUAGE_AR_SA
bool "Arabic"
config LANGUAGE_HI_IN
bool "Hindi"
config LANGUAGE_PT_PT
bool "Portuguese"
config LANGUAGE_PL_PL
bool "Polish"
config LANGUAGE_CS_CZ
bool "Czech"
config LANGUAGE_FI_FI
bool "Finnish"
config LANGUAGE_TR_TR
bool "Turkish"
config LANGUAGE_ID_ID
bool "Indonesian"
config LANGUAGE_UK_UA
bool "Ukrainian"
config LANGUAGE_RO_RO
bool "Romanian"
endchoice
choice BOARD_TYPE
@@ -148,6 +184,8 @@ choice BOARD_TYPE
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06
bool "Waveshare ESP32-S3-Touch-AMOLED-2.06"
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75
bool "Waveshare ESP32-S3-Touch-AMOLED-1.75"
depends on IDF_TARGET_ESP32S3
@@ -419,19 +457,26 @@ config USE_CUSTOM_WAKE_WORD
config CUSTOM_WAKE_WORD
string "Custom Wake Word"
default "ni hao xiao zhi"
default "xiao tu dou"
depends on USE_CUSTOM_WAKE_WORD
help
自定义唤醒词,用汉语拼音表示
自定义唤醒词,中文用拼音表示,每个字之间用空格隔开
config CUSTOM_WAKE_WORD_DISPLAY
string "Custom Wake Word Display"
default "你好小智"
default "小土豆"
depends on USE_CUSTOM_WAKE_WORD
help
自定义唤醒词对应问候语
唤醒后发送给服务器的问候语
config CUSTOM_WAKE_WORD_THRESHOLD
int "Custom Wake Word Threshold (%)"
default 20
range 1 99
depends on USE_CUSTOM_WAKE_WORD
help
自定义唤醒词阈值范围1-99越小越敏感默认10
config USE_AUDIO_PROCESSOR
bool "Enable Audio Noise Reduction"
default y
@@ -442,7 +487,7 @@ config USE_AUDIO_PROCESSOR
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 || BOARD_TYPE_ESP32S3_KORVO2_V3 || BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC)
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)
help
因为性能不够,不建议和微信聊天界面风格同时开启

View File

@@ -85,9 +85,9 @@ void Application::CheckNewVersion(Ota& ota) {
return;
}
char buffer[128];
char buffer[256];
snprintf(buffer, sizeof(buffer), Lang::Strings::CHECK_NEW_VERSION_FAILED, retry_delay, ota.GetCheckVersionUrl().c_str());
Alert(Lang::Strings::ERROR, buffer, "sad", Lang::Sounds::P3_EXCLAMATION);
Alert(Lang::Strings::ERROR, buffer, "sad", Lang::Sounds::OGG_EXCLAMATION);
ESP_LOGW(TAG, "Check new version failed, retry in %d seconds (%d/%d)", retry_delay, retry_count, MAX_RETRY);
for (int i = 0; i < retry_delay; i++) {
@@ -103,7 +103,7 @@ void Application::CheckNewVersion(Ota& ota) {
retry_delay = 10; // 重置重试延迟时间
if (ota.HasNewVersion()) {
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "happy", Lang::Sounds::P3_UPGRADE);
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "happy", Lang::Sounds::OGG_UPGRADE);
vTaskDelay(pdMS_TO_TICKS(3000));
@@ -118,9 +118,11 @@ void Application::CheckNewVersion(Ota& ota) {
vTaskDelay(pdMS_TO_TICKS(1000));
bool upgrade_success = ota.StartUpgrade([display](int progress, size_t speed) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "%d%% %uKB/s", progress, speed / 1024);
display->SetChatMessage("system", buffer);
std::thread([display, progress, speed]() {
char buffer[32];
snprintf(buffer, sizeof(buffer), "%d%% %uKB/s", progress, speed / 1024);
display->SetChatMessage("system", buffer);
}).detach();
});
if (!upgrade_success) {
@@ -128,7 +130,7 @@ void Application::CheckNewVersion(Ota& ota) {
ESP_LOGE(TAG, "Firmware upgrade failed, restarting audio service and continuing operation...");
audio_service_.Start(); // Restart audio service
board.SetPowerSaveMode(true); // Restore power save mode
Alert(Lang::Strings::ERROR, Lang::Strings::UPGRADE_FAILED, "sad", Lang::Sounds::P3_EXCLAMATION);
Alert(Lang::Strings::ERROR, Lang::Strings::UPGRADE_FAILED, "sad", Lang::Sounds::OGG_EXCLAMATION);
vTaskDelay(pdMS_TO_TICKS(3000));
// Continue to normal operation (don't break, just fall through)
} else {
@@ -180,20 +182,20 @@ void Application::ShowActivationCode(const std::string& code, const std::string&
const std::string_view& sound;
};
static const std::array<digit_sound, 10> digit_sounds{{
digit_sound{'0', Lang::Sounds::P3_0},
digit_sound{'1', Lang::Sounds::P3_1},
digit_sound{'2', Lang::Sounds::P3_2},
digit_sound{'3', Lang::Sounds::P3_3},
digit_sound{'4', Lang::Sounds::P3_4},
digit_sound{'5', Lang::Sounds::P3_5},
digit_sound{'6', Lang::Sounds::P3_6},
digit_sound{'7', Lang::Sounds::P3_7},
digit_sound{'8', Lang::Sounds::P3_8},
digit_sound{'9', Lang::Sounds::P3_9}
digit_sound{'0', Lang::Sounds::OGG_0},
digit_sound{'1', Lang::Sounds::OGG_1},
digit_sound{'2', Lang::Sounds::OGG_2},
digit_sound{'3', Lang::Sounds::OGG_3},
digit_sound{'4', Lang::Sounds::OGG_4},
digit_sound{'5', Lang::Sounds::OGG_5},
digit_sound{'6', Lang::Sounds::OGG_6},
digit_sound{'7', Lang::Sounds::OGG_7},
digit_sound{'8', Lang::Sounds::OGG_8},
digit_sound{'9', Lang::Sounds::OGG_9}
}};
// This sentence uses 9KB of SRAM, so we need to wait for it to finish
Alert(Lang::Strings::ACTIVATION, message.c_str(), "happy", Lang::Sounds::P3_ACTIVATION);
Alert(Lang::Strings::ACTIVATION, message.c_str(), "happy", Lang::Sounds::OGG_ACTIVATION);
for (const auto& digit : code) {
auto it = std::find_if(digit_sounds.begin(), digit_sounds.end(),
@@ -469,7 +471,7 @@ void Application::Start() {
auto message = cJSON_GetObjectItem(root, "message");
auto emotion = cJSON_GetObjectItem(root, "emotion");
if (cJSON_IsString(status) && cJSON_IsString(message) && cJSON_IsString(emotion)) {
Alert(status->valuestring, message->valuestring, emotion->valuestring, Lang::Sounds::P3_VIBRATION);
Alert(status->valuestring, message->valuestring, emotion->valuestring, Lang::Sounds::OGG_VIBRATION);
} else {
ESP_LOGW(TAG, "Alert command requires status, message and emotion");
}
@@ -499,14 +501,11 @@ void Application::Start() {
display->ShowNotification(message.c_str());
display->SetChatMessage("system", "");
// Play the success sound to indicate the device is ready
audio_service_.PlaySound(Lang::Sounds::P3_SUCCESS);
audio_service_.PlaySound(Lang::Sounds::OGG_SUCCESS);
}
// Print heap stats
SystemInfo::PrintHeapStats();
// Enter the main event loop
MainEventLoop();
}
void Application::OnClockTimer() {
@@ -547,7 +546,7 @@ void Application::MainEventLoop() {
MAIN_EVENT_ERROR, pdTRUE, pdFALSE, portMAX_DELAY);
if (bits & MAIN_EVENT_ERROR) {
SetDeviceState(kDeviceStateIdle);
Alert(Lang::Strings::ERROR, last_error_message_.c_str(), "sad", Lang::Sounds::P3_EXCLAMATION);
Alert(Lang::Strings::ERROR, last_error_message_.c_str(), "sad", Lang::Sounds::OGG_EXCLAMATION);
}
if (bits & MAIN_EVENT_SEND_AUDIO) {
@@ -609,7 +608,7 @@ void Application::OnWakeWordDetected() {
#else
SetListeningMode(aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime);
// Play the pop up sound to indicate the wake word is detected
audio_service_.PlaySound(Lang::Sounds::P3_POPUP);
audio_service_.PlaySound(Lang::Sounds::OGG_POPUP);
#endif
} else if (device_state_ == kDeviceStateSpeaking) {
AbortSpeaking(kAbortReasonWakeWordDetected);

View File

@@ -41,6 +41,7 @@ public:
Application& operator=(const Application&) = delete;
void Start();
void MainEventLoop();
DeviceState GetDeviceState() const { return device_state_; }
bool IsVoiceDetected() const { return audio_service_.IsVoiceDetected(); }
void Schedule(std::function<void()> callback);
@@ -80,7 +81,6 @@ private:
int clock_ticks_ = 0;
TaskHandle_t check_new_version_task_handle_ = nullptr;
void MainEventLoop();
void OnWakeWordDetected();
void CheckNewVersion(Ota& ota);
void ShowActivationCode(const std::string& code, const std::string& message);

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.

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.

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.

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.

View File

@@ -0,0 +1,58 @@
{
"language": {
"type" :"ar-SA"
},
"strings": {
"WARNING":"تحذير",
"INFO":"معلومات",
"ERROR":"خطأ",
"VERSION": "الإصدار ",
"LOADING_PROTOCOL":"الاتصال بالخادم...",
"INITIALIZING":"التهيئة...",
"PIN_ERROR":"يرجى إدخال بطاقة SIM",
"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":"جاري الاتصال...",
"CONNECTED_TO":"متصل بـ ",
"LISTENING":"الاستماع...",
"SPEAKING":"التحدث...",
"SERVER_NOT_FOUND":"البحث عن خدمة متاحة",
"SERVER_NOT_CONNECTED":"لا يمكن الاتصال بالخدمة، يرجى المحاولة لاحقاً",
"SERVER_TIMEOUT":"انتهت مهلة الاستجابة",
"SERVER_ERROR":"فشل الإرسال، يرجى التحقق من الشبكة",
"CONNECT_TO_HOTSPOT":"اتصل الهاتف بنقطة الاتصال ",
"ACCESS_VIA_BROWSER":"،الوصول عبر المتصفح ",
"WIFI_CONFIG_MODE":"وضع تكوين الشبكة",
"ENTERING_WIFI_CONFIG_MODE":"الدخول في وضع تكوين الشبكة...",
"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 مُشغل"
}
}

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.

View File

@@ -0,0 +1,58 @@
{
"language": {
"type" :"cs-CZ"
},
"strings": {
"WARNING":"Varování",
"INFO":"Informace",
"ERROR":"Chyba",
"VERSION": "Verze ",
"LOADING_PROTOCOL":"Připojování k serveru...",
"INITIALIZING":"Inicializace...",
"PIN_ERROR":"Prosím vložte SIM kartu",
"REG_ERROR":"Nelze se připojit k síti, zkontrolujte stav datové karty",
"DETECTING_MODULE":"Detekce modulu...",
"REGISTERING_NETWORK":"Čekání na síť...",
"CHECKING_NEW_VERSION":"Kontrola nové verze...",
"CHECK_NEW_VERSION_FAILED":"Kontrola nové verze selhala, opakování za %d sekund: %s",
"SWITCH_TO_WIFI_NETWORK":"Přepínání na Wi-Fi...",
"SWITCH_TO_4G_NETWORK":"Přepínání na 4G...",
"STANDBY":"Pohotovost",
"CONNECT_TO":"Připojit k ",
"CONNECTING":"Připojování...",
"CONNECTED_TO":"Připojeno k ",
"LISTENING":"Naslouchání...",
"SPEAKING":"Mluvení...",
"SERVER_NOT_FOUND":"Hledání dostupné služby",
"SERVER_NOT_CONNECTED":"Nelze se připojit ke službě, zkuste to později",
"SERVER_TIMEOUT":"Čas odpovědi vypršel",
"SERVER_ERROR":"Odeslání selhalo, zkontrolujte síť",
"CONNECT_TO_HOTSPOT":"Připojte telefon k hotspotu ",
"ACCESS_VIA_BROWSER":"přístup přes prohlížeč ",
"WIFI_CONFIG_MODE":"Režim konfigurace sítě",
"ENTERING_WIFI_CONFIG_MODE":"Vstup do režimu konfigurace sítě...",
"SCANNING_WIFI":"Skenování Wi-Fi...",
"NEW_VERSION": "Nová verze ",
"OTA_UPGRADE":"OTA upgrade",
"UPGRADING":"Aktualizace systému...",
"UPGRADE_FAILED":"Upgrade selhal",
"ACTIVATION":"Aktivace zařízení",
"BATTERY_LOW":"Slabá baterie",
"BATTERY_CHARGING":"Nabíjení",
"BATTERY_FULL":"Baterie plná",
"BATTERY_NEED_CHARGE":"Slabá baterie, prosím nabijte",
"VOLUME":"Hlasitost ",
"MUTED":"Ztlumeno",
"MAX_VOLUME":"Maximální hlasitost",
"RTC_MODE_OFF":"AEC vypnuto",
"RTC_MODE_ON":"AEC zapnuto"
}
}

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.

View File

@@ -0,0 +1,58 @@
{
"language": {
"type" :"de-DE"
},
"strings": {
"WARNING":"Warnung",
"INFO":"Information",
"ERROR":"Fehler",
"VERSION": "Version ",
"LOADING_PROTOCOL":"Verbindung zum Server...",
"INITIALIZING":"Initialisierung...",
"PIN_ERROR":"Bitte SIM-Karte einlegen",
"REG_ERROR":"Netzwerkverbindung fehlgeschlagen, bitte Datenkartenstatus prüfen",
"DETECTING_MODULE":"Modul erkennen...",
"REGISTERING_NETWORK":"Auf Netzwerk warten...",
"CHECKING_NEW_VERSION":"Neue Version prüfen...",
"CHECK_NEW_VERSION_FAILED":"Neue Version prüfen fehlgeschlagen, Wiederholung in %d Sekunden: %s",
"SWITCH_TO_WIFI_NETWORK":"Zu Wi-Fi wechseln...",
"SWITCH_TO_4G_NETWORK":"Zu 4G wechseln...",
"STANDBY":"Bereitschaft",
"CONNECT_TO":"Verbinden zu ",
"CONNECTING":"Verbindung wird hergestellt...",
"CONNECTED_TO":"Verbunden mit ",
"LISTENING":"Zuhören...",
"SPEAKING":"Sprechen...",
"SERVER_NOT_FOUND":"Verfügbaren Service suchen",
"SERVER_NOT_CONNECTED":"Service-Verbindung fehlgeschlagen, bitte später versuchen",
"SERVER_TIMEOUT":"Antwort-Timeout",
"SERVER_ERROR":"Senden fehlgeschlagen, bitte Netzwerk prüfen",
"CONNECT_TO_HOTSPOT":"Handy mit Hotspot verbinden ",
"ACCESS_VIA_BROWSER":"Browser öffnen ",
"WIFI_CONFIG_MODE":"Netzwerkkonfigurationsmodus",
"ENTERING_WIFI_CONFIG_MODE":"Netzwerkkonfigurationsmodus eingeben...",
"SCANNING_WIFI":"Wi-Fi scannen...",
"NEW_VERSION": "Neue Version ",
"OTA_UPGRADE":"OTA-Upgrade",
"UPGRADING":"System wird aktualisiert...",
"UPGRADE_FAILED":"Upgrade fehlgeschlagen",
"ACTIVATION":"Gerät aktivieren",
"BATTERY_LOW":"Niedriger Batteriestand",
"BATTERY_CHARGING":"Wird geladen",
"BATTERY_FULL":"Batterie voll",
"BATTERY_NEED_CHARGE":"Niedriger Batteriestand, bitte aufladen",
"VOLUME":"Lautstärke ",
"MUTED":"Stummgeschaltet",
"MAX_VOLUME":"Maximale Lautstärke",
"RTC_MODE_OFF":"AEC aus",
"RTC_MODE_ON":"AEC ein"
}
}

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More