forked from xiaozhi/xiaozhi-esp32
Add English system sounds
This commit is contained in:
@@ -115,6 +115,18 @@ if(CONFIG_USE_AUDIO_PROCESSING)
|
|||||||
list(APPEND SOURCES "audio_processing/audio_processor.cc" "audio_processing/wake_word_detect.cc")
|
list(APPEND SOURCES "audio_processing/audio_processor.cc" "audio_processing/wake_word_detect.cc")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# 根据Kconfig选择语言目录
|
||||||
|
if(CONFIG_LANGUAGE_ZH_CN)
|
||||||
|
set(LANG_DIR "zh-CN")
|
||||||
|
elseif(CONFIG_LANGUAGE_EN_US)
|
||||||
|
set(LANG_DIR "en-US")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# 定义生成路径
|
||||||
|
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/language.json")
|
||||||
|
set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
|
||||||
|
file(GLOB ASSETS ${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/*.p3)
|
||||||
|
|
||||||
# 如果目标芯片是 ESP32,则排除特定文件
|
# 如果目标芯片是 ESP32,则排除特定文件
|
||||||
if(CONFIG_IDF_TARGET_ESP32)
|
if(CONFIG_IDF_TARGET_ESP32)
|
||||||
# 排除 "audio_codecs/box_audio_codec.cc" 和 "audio_codecs/cores3_audio_codec.cc"
|
# 排除 "audio_codecs/box_audio_codec.cc" 和 "audio_codecs/cores3_audio_codec.cc"
|
||||||
@@ -123,8 +135,6 @@ if(CONFIG_IDF_TARGET_ESP32)
|
|||||||
"audio_codecs/es8388_audio_codec.cc")
|
"audio_codecs/es8388_audio_codec.cc")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(GLOB ASSETS ${CMAKE_CURRENT_SOURCE_DIR}/assets/zh/*.p3)
|
|
||||||
|
|
||||||
idf_component_register(SRCS ${SOURCES}
|
idf_component_register(SRCS ${SOURCES}
|
||||||
EMBED_FILES ${ASSETS}
|
EMBED_FILES ${ASSETS}
|
||||||
INCLUDE_DIRS ${INCLUDE_DIRS}
|
INCLUDE_DIRS ${INCLUDE_DIRS}
|
||||||
@@ -136,17 +146,6 @@ target_compile_definitions(${COMPONENT_LIB}
|
|||||||
PRIVATE BOARD_TYPE=\"${BOARD_TYPE}\"
|
PRIVATE BOARD_TYPE=\"${BOARD_TYPE}\"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 根据Kconfig选择语言目录
|
|
||||||
if(CONFIG_LANGUAGE_ZH)
|
|
||||||
set(LANG_DIR "zh")
|
|
||||||
elseif(CONFIG_LANGUAGE_EN)
|
|
||||||
set(LANG_DIR "en-US")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# 定义生成路径
|
|
||||||
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/language.json")
|
|
||||||
set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
|
|
||||||
|
|
||||||
# 添加生成规则
|
# 添加生成规则
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${LANG_HEADER}
|
OUTPUT ${LANG_HEADER}
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ config OTA_VERSION_URL
|
|||||||
|
|
||||||
choice
|
choice
|
||||||
prompt "语言选择"
|
prompt "语言选择"
|
||||||
default LANGUAGE_ZH
|
default LANGUAGE_ZH_CN
|
||||||
help
|
help
|
||||||
Select device display language
|
Select device display language
|
||||||
|
|
||||||
config LANGUAGE_ZH
|
config LANGUAGE_ZH_CN
|
||||||
bool "Chinese"
|
bool "Chinese"
|
||||||
config LANGUAGE_EN
|
config LANGUAGE_EN_US
|
||||||
bool "English"
|
bool "English"
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "ssd1306_display.h"
|
|
||||||
#include "system_info.h"
|
#include "system_info.h"
|
||||||
#include "ml307_ssl_transport.h"
|
#include "ml307_ssl_transport.h"
|
||||||
#include "audio_codec.h"
|
#include "audio_codec.h"
|
||||||
@@ -9,7 +8,6 @@
|
|||||||
#include "websocket_protocol.h"
|
#include "websocket_protocol.h"
|
||||||
#include "font_awesome_symbols.h"
|
#include "font_awesome_symbols.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "iot/thing_manager.h"
|
||||||
#include "assets/zh/binary.h"
|
|
||||||
#include "assets/lang_config.h"
|
#include "assets/lang_config.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -60,17 +58,17 @@ void Application::CheckNewVersion() {
|
|||||||
if (!ota_.CheckVersion()) {
|
if (!ota_.CheckVersion()) {
|
||||||
retry_count++;
|
retry_count++;
|
||||||
if (retry_count >= MAX_RETRY) {
|
if (retry_count >= MAX_RETRY) {
|
||||||
ESP_LOGE(TAG, "版本检查失败次数过多,退出检查");
|
ESP_LOGE(TAG, "Too many retries, exit version check");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ESP_LOGW(TAG, "版本检查失败,%d秒后重试 (%d/%d)", 60, retry_count, MAX_RETRY);
|
ESP_LOGW(TAG, "Check new version failed, retry in %d seconds (%d/%d)", 60, retry_count, MAX_RETRY);
|
||||||
vTaskDelay(pdMS_TO_TICKS(60000));
|
vTaskDelay(pdMS_TO_TICKS(60000));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
retry_count = 0;
|
retry_count = 0;
|
||||||
|
|
||||||
if (ota_.HasNewVersion()) {
|
if (ota_.HasNewVersion()) {
|
||||||
Alert("OTA 升级", "正在升级系统", "happy", std::string_view(p3_upgrade_start, p3_upgrade_end - p3_upgrade_start));
|
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "happy", Lang::Sounds::P3_UPGRADE);
|
||||||
// Wait for the chat state to be idle
|
// Wait for the chat state to be idle
|
||||||
do {
|
do {
|
||||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||||
@@ -81,7 +79,8 @@ void Application::CheckNewVersion() {
|
|||||||
SetDeviceState(kDeviceStateUpgrading);
|
SetDeviceState(kDeviceStateUpgrading);
|
||||||
|
|
||||||
display->SetIcon(FONT_AWESOME_DOWNLOAD);
|
display->SetIcon(FONT_AWESOME_DOWNLOAD);
|
||||||
display->SetChatMessage("system", "新版本 " + ota_.GetFirmwareVersion());
|
std::string message = std::string(Lang::Strings::NEW_VERSION) + ota_.GetFirmwareVersion();
|
||||||
|
display->SetChatMessage("system", message.c_str());
|
||||||
|
|
||||||
auto& board = Board::GetInstance();
|
auto& board = Board::GetInstance();
|
||||||
board.SetPowerSaveMode(false);
|
board.SetPowerSaveMode(false);
|
||||||
@@ -108,7 +107,7 @@ void Application::CheckNewVersion() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// If upgrade success, the device will reboot and never reach here
|
// If upgrade success, the device will reboot and never reach here
|
||||||
display->SetStatus("更新失败");
|
display->SetStatus(Lang::Strings::UPGRADE_FAILED);
|
||||||
ESP_LOGI(TAG, "Firmware upgrade failed...");
|
ESP_LOGI(TAG, "Firmware upgrade failed...");
|
||||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||||
Reboot();
|
Reboot();
|
||||||
@@ -119,7 +118,8 @@ void Application::CheckNewVersion() {
|
|||||||
|
|
||||||
// No new version, mark the current version as valid
|
// No new version, mark the current version as valid
|
||||||
ota_.MarkCurrentVersionValid();
|
ota_.MarkCurrentVersionValid();
|
||||||
display->ShowNotification(Lang::Strings::VERSION + " " + ota_.GetCurrentVersion());
|
std::string message = std::string(Lang::Strings::VERSION) + ota_.GetCurrentVersion();
|
||||||
|
display->ShowNotification(message.c_str());
|
||||||
|
|
||||||
if (ota_.HasActivationCode()) {
|
if (ota_.HasActivationCode()) {
|
||||||
// Activation code is valid
|
// Activation code is valid
|
||||||
@@ -144,24 +144,23 @@ void Application::ShowActivationCode() {
|
|||||||
|
|
||||||
struct digit_sound {
|
struct digit_sound {
|
||||||
char digit;
|
char digit;
|
||||||
const char* data;
|
const std::string_view& sound;
|
||||||
size_t size;
|
|
||||||
};
|
};
|
||||||
static const std::array<digit_sound, 10> digit_sounds{{
|
static const std::array<digit_sound, 10> digit_sounds{{
|
||||||
digit_sound{'0', p3_0_start, size_t(p3_0_end - p3_0_start)},
|
digit_sound{'0', Lang::Sounds::P3_0},
|
||||||
digit_sound{'1', p3_1_start, size_t(p3_1_end - p3_1_start)},
|
digit_sound{'1', Lang::Sounds::P3_1},
|
||||||
digit_sound{'2', p3_2_start, size_t(p3_2_end - p3_2_start)},
|
digit_sound{'2', Lang::Sounds::P3_2},
|
||||||
digit_sound{'3', p3_3_start, size_t(p3_3_end - p3_3_start)},
|
digit_sound{'3', Lang::Sounds::P3_3},
|
||||||
digit_sound{'4', p3_4_start, size_t(p3_4_end - p3_4_start)},
|
digit_sound{'4', Lang::Sounds::P3_4},
|
||||||
digit_sound{'5', p3_5_start, size_t(p3_5_end - p3_5_start)},
|
digit_sound{'5', Lang::Sounds::P3_5},
|
||||||
digit_sound{'6', p3_6_start, size_t(p3_6_end - p3_6_start)},
|
digit_sound{'6', Lang::Sounds::P3_6},
|
||||||
digit_sound{'7', p3_7_start, size_t(p3_7_end - p3_7_start)},
|
digit_sound{'7', Lang::Sounds::P3_7},
|
||||||
digit_sound{'8', p3_8_start, size_t(p3_8_end - p3_8_start)},
|
digit_sound{'8', Lang::Sounds::P3_8},
|
||||||
digit_sound{'9', p3_9_start, size_t(p3_9_end - p3_9_start)}
|
digit_sound{'9', Lang::Sounds::P3_9}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// This sentence uses 9KB of SRAM, so we need to wait for it to finish
|
// This sentence uses 9KB of SRAM, so we need to wait for it to finish
|
||||||
Alert("激活设备", message, "happy", std::string_view(p3_activation_start, p3_activation_end - p3_activation_start));
|
Alert(Lang::Strings::ACTIVATION, message.c_str(), "happy", Lang::Sounds::P3_ACTIVATION);
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
background_task_->WaitForCompletion();
|
background_task_->WaitForCompletion();
|
||||||
|
|
||||||
@@ -169,13 +168,13 @@ void Application::ShowActivationCode() {
|
|||||||
auto it = std::find_if(digit_sounds.begin(), digit_sounds.end(),
|
auto it = std::find_if(digit_sounds.begin(), digit_sounds.end(),
|
||||||
[digit](const digit_sound& ds) { return ds.digit == digit; });
|
[digit](const digit_sound& ds) { return ds.digit == digit; });
|
||||||
if (it != digit_sounds.end()) {
|
if (it != digit_sounds.end()) {
|
||||||
PlayLocalFile(it->data, it->size);
|
PlayLocalFile(it->sound.data(), it->sound.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::Alert(const std::string& status, const std::string& message, const std::string& emotion, const std::string_view& sound) {
|
void Application::Alert(const char* status, const char* message, const char* emotion, const std::string_view& sound) {
|
||||||
ESP_LOGW(TAG, "Alert %s: %s [%s]", status.c_str(), message.c_str(), emotion.c_str());
|
ESP_LOGW(TAG, "Alert %s: %s [%s]", status, message, emotion);
|
||||||
auto display = Board::GetInstance().GetDisplay();
|
auto display = Board::GetInstance().GetDisplay();
|
||||||
display->SetStatus(status);
|
display->SetStatus(status);
|
||||||
display->SetEmotion(emotion);
|
display->SetEmotion(emotion);
|
||||||
@@ -220,7 +219,7 @@ void Application::ToggleChatState() {
|
|||||||
if (device_state_ == kDeviceStateIdle) {
|
if (device_state_ == kDeviceStateIdle) {
|
||||||
SetDeviceState(kDeviceStateConnecting);
|
SetDeviceState(kDeviceStateConnecting);
|
||||||
if (!protocol_->OpenAudioChannel()) {
|
if (!protocol_->OpenAudioChannel()) {
|
||||||
Alert("ERROR", Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
|
Alert(Lang::Strings::ERROR, Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
|
||||||
SetDeviceState(kDeviceStateIdle);
|
SetDeviceState(kDeviceStateIdle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -254,7 +253,7 @@ void Application::StartListening() {
|
|||||||
SetDeviceState(kDeviceStateConnecting);
|
SetDeviceState(kDeviceStateConnecting);
|
||||||
if (!protocol_->OpenAudioChannel()) {
|
if (!protocol_->OpenAudioChannel()) {
|
||||||
SetDeviceState(kDeviceStateIdle);
|
SetDeviceState(kDeviceStateIdle);
|
||||||
Alert("ERROR", Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
|
Alert(Lang::Strings::ERROR, Lang::Strings::UNABLE_TO_ESTABLISH_AUDIO_CHANNEL, "sad");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,14 +327,14 @@ void Application::Start() {
|
|||||||
board.StartNetwork();
|
board.StartNetwork();
|
||||||
|
|
||||||
// Initialize the protocol
|
// Initialize the protocol
|
||||||
display->SetStatus(Lang::Strings::LOADING_PROTOCOL + "...");
|
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
|
||||||
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
|
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
|
||||||
protocol_ = std::make_unique<WebsocketProtocol>();
|
protocol_ = std::make_unique<WebsocketProtocol>();
|
||||||
#else
|
#else
|
||||||
protocol_ = std::make_unique<MqttProtocol>();
|
protocol_ = std::make_unique<MqttProtocol>();
|
||||||
#endif
|
#endif
|
||||||
protocol_->OnNetworkError([this](const std::string& message) {
|
protocol_->OnNetworkError([this](const std::string& message) {
|
||||||
Alert("ERROR", message, "sad");
|
Alert(Lang::Strings::ERROR, message.c_str(), "sad");
|
||||||
});
|
});
|
||||||
protocol_->OnIncomingAudio([this](std::vector<uint8_t>&& data) {
|
protocol_->OnIncomingAudio([this](std::vector<uint8_t>&& data) {
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
@@ -346,11 +345,11 @@ void Application::Start() {
|
|||||||
protocol_->OnAudioChannelOpened([this, codec, &board]() {
|
protocol_->OnAudioChannelOpened([this, codec, &board]() {
|
||||||
board.SetPowerSaveMode(false);
|
board.SetPowerSaveMode(false);
|
||||||
if (protocol_->server_sample_rate() != codec->output_sample_rate()) {
|
if (protocol_->server_sample_rate() != codec->output_sample_rate()) {
|
||||||
ESP_LOGW(TAG, "服务器的音频采样率 %d 与设备输出的采样率 %d 不一致,重采样后可能会失真",
|
ESP_LOGW(TAG, "Server sample rate %d does not match device output sample rate %d, resampling may cause distortion",
|
||||||
protocol_->server_sample_rate(), codec->output_sample_rate());
|
protocol_->server_sample_rate(), codec->output_sample_rate());
|
||||||
}
|
}
|
||||||
SetDecodeSampleRate(protocol_->server_sample_rate());
|
SetDecodeSampleRate(protocol_->server_sample_rate());
|
||||||
// 物联网设备描述符
|
// IoT device descriptors
|
||||||
last_iot_states_.clear();
|
last_iot_states_.clear();
|
||||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||||
protocol_->SendIotDescriptors(thing_manager.GetDescriptorsJson());
|
protocol_->SendIotDescriptors(thing_manager.GetDescriptorsJson());
|
||||||
@@ -392,7 +391,7 @@ void Application::Start() {
|
|||||||
if (text != NULL) {
|
if (text != NULL) {
|
||||||
ESP_LOGI(TAG, "<< %s", text->valuestring);
|
ESP_LOGI(TAG, "<< %s", text->valuestring);
|
||||||
Schedule([this, display, message = std::string(text->valuestring)]() {
|
Schedule([this, display, message = std::string(text->valuestring)]() {
|
||||||
display->SetChatMessage("assistant", message);
|
display->SetChatMessage("assistant", message.c_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,14 +400,14 @@ void Application::Start() {
|
|||||||
if (text != NULL) {
|
if (text != NULL) {
|
||||||
ESP_LOGI(TAG, ">> %s", text->valuestring);
|
ESP_LOGI(TAG, ">> %s", text->valuestring);
|
||||||
Schedule([this, display, message = std::string(text->valuestring)]() {
|
Schedule([this, display, message = std::string(text->valuestring)]() {
|
||||||
display->SetChatMessage("user", message);
|
display->SetChatMessage("user", message.c_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (strcmp(type->valuestring, "llm") == 0) {
|
} else if (strcmp(type->valuestring, "llm") == 0) {
|
||||||
auto emotion = cJSON_GetObjectItem(root, "emotion");
|
auto emotion = cJSON_GetObjectItem(root, "emotion");
|
||||||
if (emotion != NULL) {
|
if (emotion != NULL) {
|
||||||
Schedule([this, display, emotion_str = std::string(emotion->valuestring)]() {
|
Schedule([this, display, emotion_str = std::string(emotion->valuestring)]() {
|
||||||
display->SetEmotion(emotion_str);
|
display->SetEmotion(emotion_str.c_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (strcmp(type->valuestring, "iot") == 0) {
|
} else if (strcmp(type->valuestring, "iot") == 0) {
|
||||||
@@ -428,6 +427,8 @@ void Application::Start() {
|
|||||||
ota_.SetCheckVersionUrl(CONFIG_OTA_VERSION_URL);
|
ota_.SetCheckVersionUrl(CONFIG_OTA_VERSION_URL);
|
||||||
ota_.SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
|
ota_.SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
|
||||||
ota_.SetHeader("Client-Id", board.GetUuid());
|
ota_.SetHeader("Client-Id", board.GetUuid());
|
||||||
|
ota_.SetHeader("X-Language", Lang::CODE);
|
||||||
|
|
||||||
xTaskCreate([](void* arg) {
|
xTaskCreate([](void* arg) {
|
||||||
Application* app = (Application*)arg;
|
Application* app = (Application*)arg;
|
||||||
app->CheckNewVersion();
|
app->CheckNewVersion();
|
||||||
@@ -664,18 +665,18 @@ void Application::SetDeviceState(DeviceState state) {
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case kDeviceStateUnknown:
|
case kDeviceStateUnknown:
|
||||||
case kDeviceStateIdle:
|
case kDeviceStateIdle:
|
||||||
display->SetStatus(Lang::Strings::STANDING_BY);
|
display->SetStatus(Lang::Strings::STANDBY);
|
||||||
display->SetEmotion("neutral");
|
display->SetEmotion("neutral");
|
||||||
#ifdef CONFIG_USE_AUDIO_PROCESSING
|
#ifdef CONFIG_USE_AUDIO_PROCESSING
|
||||||
audio_processor_.Stop();
|
audio_processor_.Stop();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case kDeviceStateConnecting:
|
case kDeviceStateConnecting:
|
||||||
display->SetStatus(Lang::Strings::CONNECTING+"...");
|
display->SetStatus(Lang::Strings::CONNECTING);
|
||||||
display->SetChatMessage("system", "");
|
display->SetChatMessage("system", "");
|
||||||
break;
|
break;
|
||||||
case kDeviceStateListening:
|
case kDeviceStateListening:
|
||||||
display->SetStatus(Lang::Strings::LISTENING+"...");
|
display->SetStatus(Lang::Strings::LISTENING);
|
||||||
display->SetEmotion("neutral");
|
display->SetEmotion("neutral");
|
||||||
ResetDecoder();
|
ResetDecoder();
|
||||||
opus_encoder_->ResetState();
|
opus_encoder_->ResetState();
|
||||||
@@ -685,7 +686,7 @@ void Application::SetDeviceState(DeviceState state) {
|
|||||||
UpdateIotStates();
|
UpdateIotStates();
|
||||||
break;
|
break;
|
||||||
case kDeviceStateSpeaking:
|
case kDeviceStateSpeaking:
|
||||||
display->SetStatus(Lang::Strings::SPEAKING+"...");
|
display->SetStatus(Lang::Strings::SPEAKING);
|
||||||
ResetDecoder();
|
ResetDecoder();
|
||||||
codec->EnableOutput(true);
|
codec->EnableOutput(true);
|
||||||
#if CONFIG_USE_AUDIO_PROCESSING
|
#if CONFIG_USE_AUDIO_PROCESSING
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public:
|
|||||||
bool IsVoiceDetected() const { return voice_detected_; }
|
bool IsVoiceDetected() const { return voice_detected_; }
|
||||||
void Schedule(std::function<void()> callback);
|
void Schedule(std::function<void()> callback);
|
||||||
void SetDeviceState(DeviceState state);
|
void SetDeviceState(DeviceState state);
|
||||||
void Alert(const std::string& status, const std::string& message, const std::string& emotion = "", const std::string_view& sound = "");
|
void Alert(const char* status, const char* message, const char* emotion = "", const std::string_view& sound = "");
|
||||||
void AbortSpeaking(AbortReason reason);
|
void AbortSpeaking(AbortReason reason);
|
||||||
void ToggleChatState();
|
void ToggleChatState();
|
||||||
void StartListening();
|
void StartListening();
|
||||||
|
|||||||
BIN
main/assets/en-US/0.p3
Normal file
BIN
main/assets/en-US/0.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/1.p3
Normal file
BIN
main/assets/en-US/1.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/2.p3
Normal file
BIN
main/assets/en-US/2.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/3.p3
Normal file
BIN
main/assets/en-US/3.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/4.p3
Normal file
BIN
main/assets/en-US/4.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/5.p3
Normal file
BIN
main/assets/en-US/5.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/6.p3
Normal file
BIN
main/assets/en-US/6.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/7.p3
Normal file
BIN
main/assets/en-US/7.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/8.p3
Normal file
BIN
main/assets/en-US/8.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/9.p3
Normal file
BIN
main/assets/en-US/9.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/activation.p3
Normal file
BIN
main/assets/en-US/activation.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/err_pin.p3
Normal file
BIN
main/assets/en-US/err_pin.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/err_reg.p3
Normal file
BIN
main/assets/en-US/err_reg.p3
Normal file
Binary file not shown.
@@ -1,34 +1,44 @@
|
|||||||
{
|
{
|
||||||
"language": {
|
"language": {
|
||||||
"type" :"en"
|
"type": "en"
|
||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"VERSION": "Version",
|
"VERSION": "Ver ",
|
||||||
"LOADING_PROTOCOL":"Loading Protocol",
|
"LOADING_PROTOCOL": "Loading Protocol...",
|
||||||
"INITIALIZING":"Initializing",
|
"INITIALIZING": "Initializing...",
|
||||||
"NOTICE":"Notice",
|
"DETECTING_MODULE": "Detecting module...",
|
||||||
|
"REGISTERING_NETWORK": "Waiting for network...",
|
||||||
|
|
||||||
"STANDING_BY":"Standing By",
|
"ERROR": "Error",
|
||||||
"CONNECT":"Connect",
|
"PIN_ERROR": "Please insert SIM card",
|
||||||
"CONNECTING":"Connecting",
|
"REG_ERROR": "Unable to access network, please check SIM card status",
|
||||||
"CONNECTION_SUCCESSFUL":"Connection Successful",
|
|
||||||
|
|
||||||
"LISTENING":"Listening",
|
"STANDBY": "Standby",
|
||||||
"SPEAKING":"Speaking",
|
"CONNECT_TO": "Connect to ",
|
||||||
|
"CONNECTING": "Connecting...",
|
||||||
|
"CONNECTION_SUCCESSFUL": "Connection Successful",
|
||||||
|
"CONNECTED_TO": "Connected to ",
|
||||||
|
|
||||||
"UNABLE_TO_CONNECT_TO_SERVICE":"Unable to connect to service",
|
"LISTENING": "Listening...",
|
||||||
"WAITING_FOR_RESPONSE_TIMEOUT":"Waiting for response timeout",
|
"SPEAKING": "Speaking...",
|
||||||
"SENDING_FAILED_PLEASE_CHECK_THE_NETWORK":"Sending failed, please check the network",
|
|
||||||
|
|
||||||
|
"UNABLE_TO_CONNECT_TO_SERVICE": "Unable to connect to service",
|
||||||
|
"WAITING_FOR_RESPONSE_TIMEOUT": "Waiting for response timeout",
|
||||||
|
"SENDING_FAILED_PLEASE_CHECK_THE_NETWORK": "Sending failed, please check the network",
|
||||||
|
|
||||||
|
"CONNECT_TO_HOTSPOT": "Hotspot: ",
|
||||||
"CONNECT_MOBILE_PHONE_TO_HOTSPOT":"Connect mobile phone to hotspot",
|
"ACCESS_VIA_BROWSER": " Config URL: ",
|
||||||
"ACCESS_VIA_BROWSER":"Access via browser",
|
"WIFI_CONFIG_MODE": "Wi-Fi Configuration Mode",
|
||||||
"WIFI_CONFIGURATION_MODE":"Wi-Fi Configuration Mode",
|
"ENTERING_WIFI_CONFIG_MODE": "Entering Wi-Fi configuration mode...",
|
||||||
"SCANNING_WIFI":"Scanning Wi-Fi",
|
"SCANNING_WIFI": "Scanning Wi-Fi...",
|
||||||
|
|
||||||
"UNABLE_TO_ESTABLISH_AUDIO_CHANNEL": "Unable to establish audio channel",
|
"UNABLE_TO_ESTABLISH_AUDIO_CHANNEL": "Unable to establish audio channel",
|
||||||
"TEST":"Test"
|
"TEST": "Test",
|
||||||
|
|
||||||
|
"NEW_VERSION": "New version ",
|
||||||
|
"OTA_UPGRADE": "OTA Upgrade",
|
||||||
|
"UPGRADING": "System is upgrading...",
|
||||||
|
"UPGRADE_FAILED": "Upgrade failed",
|
||||||
|
"ACTIVATION": "Activation"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
main/assets/en-US/upgrade.p3
Normal file
BIN
main/assets/en-US/upgrade.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/welcome.p3
Normal file
BIN
main/assets/en-US/welcome.p3
Normal file
Binary file not shown.
BIN
main/assets/en-US/wificonfig.p3
Normal file
BIN
main/assets/en-US/wificonfig.p3
Normal file
Binary file not shown.
42
main/assets/zh-CN/language.json
Normal file
42
main/assets/zh-CN/language.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"language": {
|
||||||
|
"type" :"zh-CN"
|
||||||
|
},
|
||||||
|
"strings": {
|
||||||
|
"ERROR":"错误",
|
||||||
|
"VERSION": "版本 ",
|
||||||
|
"LOADING_PROTOCOL":"加载协议...",
|
||||||
|
"INITIALIZING":"正在初始化...",
|
||||||
|
"PIN_ERROR":"请插入 SIM 卡",
|
||||||
|
"REG_ERROR":"无法接入网络,请检查流量卡状态",
|
||||||
|
"DETECTING_MODULE":"检测模组...",
|
||||||
|
"REGISTERING_NETWORK":"等待网络...",
|
||||||
|
|
||||||
|
"STANDBY":"待命",
|
||||||
|
"CONNECT_TO":"连接 ",
|
||||||
|
"CONNECTING":"连接中...",
|
||||||
|
"CONNECTED_TO":"已连接 ",
|
||||||
|
|
||||||
|
"LISTENING":"聆听中...",
|
||||||
|
"SPEAKING":"说话中...",
|
||||||
|
|
||||||
|
"UNABLE_TO_CONNECT_TO_SERVICE":"无法连接服务",
|
||||||
|
"WAITING_FOR_RESPONSE_TIMEOUT":"等待响应超时",
|
||||||
|
"SENDING_FAILED_PLEASE_CHECK_THE_NETWORK":"发送失败,请检查网络",
|
||||||
|
|
||||||
|
"CONNECT_TO_HOTSPOT":"手机连接热点 ",
|
||||||
|
"ACCESS_VIA_BROWSER":",浏览器访问 ",
|
||||||
|
"WIFI_CONFIG_MODE":"配网模式",
|
||||||
|
"ENTERING_WIFI_CONFIG_MODE":"进入配网模式...",
|
||||||
|
"SCANNING_WIFI":"扫描 Wi-Fi...",
|
||||||
|
|
||||||
|
"UNABLE_TO_ESTABLISH_AUDIO_CHANNEL": "无法建立音频通道",
|
||||||
|
"TEST":"测试",
|
||||||
|
|
||||||
|
"NEW_VERSION": "新版本 ",
|
||||||
|
"OTA_UPGRADE":"OTA 升级",
|
||||||
|
"UPGRADING":"正在升级系统...",
|
||||||
|
"UPGRADE_FAILED":"升级失败",
|
||||||
|
"ACTIVATION":"激活设备"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#ifndef BINARY_H
|
|
||||||
#define BINARY_H
|
|
||||||
|
|
||||||
extern const char p3_err_reg_start[] asm("_binary_err_reg_p3_start");
|
|
||||||
extern const char p3_err_reg_end[] asm("_binary_err_reg_p3_end");
|
|
||||||
extern const char p3_err_pin_start[] asm("_binary_err_pin_p3_start");
|
|
||||||
extern const char p3_err_pin_end[] asm("_binary_err_pin_p3_end");
|
|
||||||
extern const char p3_wificonfig_start[] asm("_binary_wificonfig_p3_start");
|
|
||||||
extern const char p3_wificonfig_end[] asm("_binary_wificonfig_p3_end");
|
|
||||||
extern const char p3_upgrade_start[] asm("_binary_upgrade_p3_start");
|
|
||||||
extern const char p3_upgrade_end[] asm("_binary_upgrade_p3_end");
|
|
||||||
extern const char p3_activation_start[] asm("_binary_activation_p3_start");
|
|
||||||
extern const char p3_activation_end[] asm("_binary_activation_p3_end");
|
|
||||||
extern const char p3_welcome_start[] asm("_binary_welcome_p3_start");
|
|
||||||
extern const char p3_welcome_end[] asm("_binary_welcome_p3_end");
|
|
||||||
|
|
||||||
extern const char p3_0_start[] asm("_binary_0_p3_start");
|
|
||||||
extern const char p3_0_end[] asm("_binary_0_p3_end");
|
|
||||||
extern const char p3_1_start[] asm("_binary_1_p3_start");
|
|
||||||
extern const char p3_1_end[] asm("_binary_1_p3_end");
|
|
||||||
extern const char p3_2_start[] asm("_binary_2_p3_start");
|
|
||||||
extern const char p3_2_end[] asm("_binary_2_p3_end");
|
|
||||||
extern const char p3_3_start[] asm("_binary_3_p3_start");
|
|
||||||
extern const char p3_3_end[] asm("_binary_3_p3_end");
|
|
||||||
extern const char p3_4_start[] asm("_binary_4_p3_start");
|
|
||||||
extern const char p3_4_end[] asm("_binary_4_p3_end");
|
|
||||||
extern const char p3_5_start[] asm("_binary_5_p3_start");
|
|
||||||
extern const char p3_5_end[] asm("_binary_5_p3_end");
|
|
||||||
extern const char p3_6_start[] asm("_binary_6_p3_start");
|
|
||||||
extern const char p3_6_end[] asm("_binary_6_p3_end");
|
|
||||||
extern const char p3_7_start[] asm("_binary_7_p3_start");
|
|
||||||
extern const char p3_7_end[] asm("_binary_7_p3_end");
|
|
||||||
extern const char p3_8_start[] asm("_binary_8_p3_start");
|
|
||||||
extern const char p3_8_end[] asm("_binary_8_p3_end");
|
|
||||||
extern const char p3_9_start[] asm("_binary_9_p3_start");
|
|
||||||
extern const char p3_9_end[] asm("_binary_9_p3_end");
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"language": {
|
|
||||||
"type" :"zh"
|
|
||||||
},
|
|
||||||
"strings": {
|
|
||||||
"VERSION": "版本",
|
|
||||||
"LOADING_PROTOCOL":"加载协议",
|
|
||||||
"INITIALIZING":"正在初始化",
|
|
||||||
"NOTICE":"通知",
|
|
||||||
|
|
||||||
"STANDING_BY":"待命",
|
|
||||||
"CONNECT":"连接",
|
|
||||||
"CONNECTING":"连接中",
|
|
||||||
"CONNECTION_SUCCESSFUL":"连接成功",
|
|
||||||
|
|
||||||
"LISTENING":"聆听中",
|
|
||||||
"SPEAKING":"说话中",
|
|
||||||
|
|
||||||
"UNABLE_TO_CONNECT_TO_SERVICE":"无法连接服务",
|
|
||||||
"WAITING_FOR_RESPONSE_TIMEOUT":"等待响应超时",
|
|
||||||
"SENDING_FAILED_PLEASE_CHECK_THE_NETWORK":"发送失败,请检查网络",
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"CONNECT_MOBILE_PHONE_TO_HOTSPOT":"手机连接热点",
|
|
||||||
"ACCESS_VIA_BROWSER":"浏览器访问",
|
|
||||||
"WIFI_CONFIGURATION_MODE":"配网模式",
|
|
||||||
"SCANNING_WIFI":"扫描 WIFI",
|
|
||||||
|
|
||||||
"UNABLE_TO_ESTABLISH_AUDIO_CHANNEL": "无法建立音频通道",
|
|
||||||
"TEST":"测试"
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
|||||||
#include "wifi_board.h"
|
#include "wifi_board.h"
|
||||||
#include "audio_codecs/es8311_audio_codec.h"
|
#include "audio_codecs/es8311_audio_codec.h"
|
||||||
#include "display/lcd_display.h"
|
#include "display/lcd_display.h"
|
||||||
#include "display/no_display.h"
|
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "i2c_device.h"
|
#include "i2c_device.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "iot/thing_manager.h"
|
||||||
|
#include "assets/lang_config.h"
|
||||||
|
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <driver/i2c_master.h>
|
#include <driver/i2c_master.h>
|
||||||
@@ -110,9 +110,9 @@ private:
|
|||||||
InitializeSpi();
|
InitializeSpi();
|
||||||
InitializeGc9107Display();
|
InitializeGc9107Display();
|
||||||
InitializeButtons();
|
InitializeButtons();
|
||||||
display_->SetStatus("错误");
|
display_->SetStatus(Lang::Strings::ERROR);
|
||||||
display_->SetEmotion("sad");
|
display_->SetEmotion("sad");
|
||||||
display_->SetChatMessage("system", "Echo Base\n未连接");
|
display_->SetChatMessage("system", "Echo Base\nnot connected");
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ESP_LOGE(TAG, "Atomic Echo Base is disconnected");
|
ESP_LOGE(TAG, "Atomic Echo Base is disconnected");
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#include "wifi_board.h"
|
#include "wifi_board.h"
|
||||||
#include "audio_codecs/es8311_audio_codec.h"
|
#include "audio_codecs/es8311_audio_codec.h"
|
||||||
#include "display/lcd_display.h"
|
#include "display/lcd_display.h"
|
||||||
#include "display/no_display.h"
|
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "i2c_device.h"
|
#include "i2c_device.h"
|
||||||
#include "iot/thing_manager.h"
|
#include "iot/thing_manager.h"
|
||||||
|
#include "assets/lang_config.h"
|
||||||
|
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <driver/i2c_master.h>
|
#include <driver/i2c_master.h>
|
||||||
@@ -158,9 +158,10 @@ private:
|
|||||||
InitializeSpi();
|
InitializeSpi();
|
||||||
InitializeGc9107Display();
|
InitializeGc9107Display();
|
||||||
InitializeButtons();
|
InitializeButtons();
|
||||||
display_->SetStatus("错误");
|
|
||||||
|
display_->SetStatus(Lang::Strings::ERROR);
|
||||||
display_->SetEmotion("sad");
|
display_->SetEmotion("sad");
|
||||||
display_->SetChatMessage("system", "Echo Base\n未连接");
|
display_->SetChatMessage("system", "Echo Base\nnot connected");
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ESP_LOGE(TAG, "Atomic Echo Base is disconnected");
|
ESP_LOGE(TAG, "Atomic Echo Base is disconnected");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "system_info.h"
|
#include "system_info.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "display/no_display.h"
|
#include "display/no_display.h"
|
||||||
|
#include "assets/lang_config.h"
|
||||||
|
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <esp_ota_ops.h>
|
#include <esp_ota_ops.h>
|
||||||
@@ -99,6 +100,7 @@ std::string Board::GetJson() {
|
|||||||
*/
|
*/
|
||||||
std::string json = "{";
|
std::string json = "{";
|
||||||
json += "\"version\":2,";
|
json += "\"version\":2,";
|
||||||
|
json += "\"language\":\"" + std::string(Lang::CODE) + "\",";
|
||||||
json += "\"flash_size\":" + std::to_string(SystemInfo::GetFlashSize()) + ",";
|
json += "\"flash_size\":" + std::to_string(SystemInfo::GetFlashSize()) + ",";
|
||||||
json += "\"minimum_free_heap_size\":" + std::to_string(SystemInfo::GetMinimumFreeHeapSize()) + ",";
|
json += "\"minimum_free_heap_size\":" + std::to_string(SystemInfo::GetMinimumFreeHeapSize()) + ",";
|
||||||
json += "\"mac_address\":\"" + SystemInfo::GetMacAddress() + "\",";
|
json += "\"mac_address\":\"" + SystemInfo::GetMacAddress() + "\",";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "font_awesome_symbols.h"
|
#include "font_awesome_symbols.h"
|
||||||
#include "assets/zh/binary.h"
|
#include "assets/lang_config.h"
|
||||||
|
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <esp_timer.h>
|
#include <esp_timer.h>
|
||||||
@@ -25,7 +25,7 @@ std::string Ml307Board::GetBoardType() {
|
|||||||
|
|
||||||
void Ml307Board::StartNetwork() {
|
void Ml307Board::StartNetwork() {
|
||||||
auto display = Board::GetInstance().GetDisplay();
|
auto display = Board::GetInstance().GetDisplay();
|
||||||
display->SetStatus("检测模组...");
|
display->SetStatus(Lang::Strings::DETECTING_MODULE);
|
||||||
modem_.SetDebug(false);
|
modem_.SetDebug(false);
|
||||||
modem_.SetBaudRate(921600);
|
modem_.SetBaudRate(921600);
|
||||||
|
|
||||||
@@ -45,13 +45,13 @@ void Ml307Board::StartNetwork() {
|
|||||||
void Ml307Board::WaitForNetworkReady() {
|
void Ml307Board::WaitForNetworkReady() {
|
||||||
auto& application = Application::GetInstance();
|
auto& application = Application::GetInstance();
|
||||||
auto display = Board::GetInstance().GetDisplay();
|
auto display = Board::GetInstance().GetDisplay();
|
||||||
display->SetStatus("等待网络...");
|
display->SetStatus(Lang::Strings::REGISTERING_NETWORK);
|
||||||
int result = modem_.WaitForNetworkReady();
|
int result = modem_.WaitForNetworkReady();
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
application.Alert("PIN_ERROR", "请插入SIM卡", "sad", std::string_view(p3_err_pin_start, p3_err_pin_end - p3_err_pin_start));
|
application.Alert(Lang::Strings::ERROR, Lang::Strings::PIN_ERROR, "sad", Lang::Sounds::P3_ERR_PIN);
|
||||||
return;
|
return;
|
||||||
} else if (result == -2) {
|
} else if (result == -2) {
|
||||||
application.Alert("REG_ERROR", "无法接入网络,请检查流量卡状态", "sad", std::string_view(p3_err_reg_start, p3_err_reg_end - p3_err_reg_start));
|
application.Alert(Lang::Strings::ERROR, Lang::Strings::REG_ERROR, "sad", Lang::Sounds::P3_ERR_REG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include "system_info.h"
|
#include "system_info.h"
|
||||||
#include "font_awesome_symbols.h"
|
#include "font_awesome_symbols.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "assets/zh/binary.h"
|
#include "assets/lang_config.h"
|
||||||
|
|
||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
#include <wifi_station.h>
|
#include <wifi_station.h>
|
||||||
#include <wifi_configuration_ap.h>
|
#include <wifi_configuration_ap.h>
|
||||||
#include <ssid_manager.h>
|
#include <ssid_manager.h>
|
||||||
#include "assets/lang_config.h"
|
|
||||||
|
|
||||||
static const char *TAG = "WifiBoard";
|
static const char *TAG = "WifiBoard";
|
||||||
|
|
||||||
@@ -46,14 +45,14 @@ void WifiBoard::EnterWifiConfigMode() {
|
|||||||
wifi_ap.Start();
|
wifi_ap.Start();
|
||||||
|
|
||||||
// 显示 WiFi 配置 AP 的 SSID 和 Web 服务器 URL
|
// 显示 WiFi 配置 AP 的 SSID 和 Web 服务器 URL
|
||||||
std::string hint = Lang::Strings::CONNECT_MOBILE_PHONE_TO_HOTSPOT + " ";
|
std::string hint = Lang::Strings::CONNECT_TO_HOTSPOT;
|
||||||
hint += wifi_ap.GetSsid();
|
hint += wifi_ap.GetSsid();
|
||||||
hint += "\n"+ Lang::Strings::ACCESS_VIA_BROWSER + " ";
|
hint += Lang::Strings::ACCESS_VIA_BROWSER;
|
||||||
hint += wifi_ap.GetWebServerUrl();
|
hint += wifi_ap.GetWebServerUrl();
|
||||||
hint += "\n\n";
|
hint += "\n\n";
|
||||||
|
|
||||||
// 播报配置 WiFi 的提示
|
// 播报配置 WiFi 的提示
|
||||||
application.Alert(Lang::Strings::WIFI_CONFIGURATION_MODE, hint, "", std::string(p3_wificonfig_start, p3_wificonfig_end - p3_wificonfig_start));
|
application.Alert(Lang::Strings::WIFI_CONFIG_MODE, hint.c_str(), "", Lang::Sounds::P3_WIFICONFIG);
|
||||||
|
|
||||||
// Wait forever until reset after configuration
|
// Wait forever until reset after configuration
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -87,11 +86,16 @@ void WifiBoard::StartNetwork() {
|
|||||||
});
|
});
|
||||||
wifi_station.OnConnect([this](const std::string& ssid) {
|
wifi_station.OnConnect([this](const std::string& ssid) {
|
||||||
auto display = Board::GetInstance().GetDisplay();
|
auto display = Board::GetInstance().GetDisplay();
|
||||||
display->ShowNotification(std::string(Lang::Strings::CONNECT + " ") + ssid + "...", 30000);
|
std::string notification = Lang::Strings::CONNECT_TO;
|
||||||
|
notification += ssid;
|
||||||
|
notification += "...";
|
||||||
|
display->ShowNotification(notification.c_str(), 30000);
|
||||||
});
|
});
|
||||||
wifi_station.OnConnected([this](const std::string& ssid) {
|
wifi_station.OnConnected([this](const std::string& ssid) {
|
||||||
auto display = Board::GetInstance().GetDisplay();
|
auto display = Board::GetInstance().GetDisplay();
|
||||||
display->ShowNotification(std::string(Lang::Strings::CONNECTION_SUCCESSFUL) + ssid);
|
std::string notification = Lang::Strings::CONNECTED_TO;
|
||||||
|
notification += ssid;
|
||||||
|
display->ShowNotification(notification.c_str(), 30000);
|
||||||
});
|
});
|
||||||
wifi_station.Start();
|
wifi_station.Start();
|
||||||
|
|
||||||
@@ -167,12 +171,12 @@ void WifiBoard::SetPowerSaveMode(bool enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WifiBoard::ResetWifiConfiguration() {
|
void WifiBoard::ResetWifiConfiguration() {
|
||||||
// Reset the wifi station
|
// Set a flag and reboot the device to enter the network configuration mode
|
||||||
{
|
{
|
||||||
Settings settings("wifi", true);
|
Settings settings("wifi", true);
|
||||||
settings.SetInt("force_ap", 1);
|
settings.SetInt("force_ap", 1);
|
||||||
}
|
}
|
||||||
GetDisplay()->ShowNotification("Enter the network configuration mode...");
|
GetDisplay()->ShowNotification(Lang::Strings::ENTERING_WIFI_CONFIG_MODE);
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
// Reboot the device
|
// Reboot the device
|
||||||
esp_restart();
|
esp_restart();
|
||||||
|
|||||||
@@ -67,22 +67,26 @@ Display::~Display() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::SetStatus(const std::string &status) {
|
void Display::SetStatus(const char* status) {
|
||||||
DisplayLockGuard lock(this);
|
DisplayLockGuard lock(this);
|
||||||
if (status_label_ == nullptr) {
|
if (status_label_ == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lv_label_set_text(status_label_, status.c_str());
|
lv_label_set_text(status_label_, status);
|
||||||
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::ShowNotification(const std::string ¬ification, int duration_ms) {
|
void Display::ShowNotification(const std::string ¬ification, int duration_ms) {
|
||||||
|
ShowNotification(notification.c_str(), duration_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::ShowNotification(const char* notification, int duration_ms) {
|
||||||
DisplayLockGuard lock(this);
|
DisplayLockGuard lock(this);
|
||||||
if (notification_label_ == nullptr) {
|
if (notification_label_ == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lv_label_set_text(notification_label_, notification.c_str());
|
lv_label_set_text(notification_label_, notification);
|
||||||
lv_obj_clear_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_clear_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||||
lv_obj_add_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
@@ -154,7 +158,7 @@ void Display::Update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Display::SetEmotion(const std::string &emotion) {
|
void Display::SetEmotion(const char* emotion) {
|
||||||
struct Emotion {
|
struct Emotion {
|
||||||
const char* icon;
|
const char* icon;
|
||||||
const char* text;
|
const char* text;
|
||||||
@@ -185,8 +189,9 @@ void Display::SetEmotion(const std::string &emotion) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 查找匹配的表情
|
// 查找匹配的表情
|
||||||
|
std::string_view emotion_view(emotion);
|
||||||
auto it = std::find_if(emotions.begin(), emotions.end(),
|
auto it = std::find_if(emotions.begin(), emotions.end(),
|
||||||
[&emotion](const Emotion& e) { return e.text == emotion; });
|
[&emotion_view](const Emotion& e) { return e.text == emotion_view; });
|
||||||
|
|
||||||
DisplayLockGuard lock(this);
|
DisplayLockGuard lock(this);
|
||||||
if (emotion_label_ == nullptr) {
|
if (emotion_label_ == nullptr) {
|
||||||
@@ -209,12 +214,12 @@ void Display::SetIcon(const char* icon) {
|
|||||||
lv_label_set_text(emotion_label_, icon);
|
lv_label_set_text(emotion_label_, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::SetChatMessage(const std::string &role, const std::string &content) {
|
void Display::SetChatMessage(const char* role, const char* content) {
|
||||||
DisplayLockGuard lock(this);
|
DisplayLockGuard lock(this);
|
||||||
if (chat_message_label_ == nullptr) {
|
if (chat_message_label_ == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lv_label_set_text(chat_message_label_, content.c_str());
|
lv_label_set_text(chat_message_label_, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::SetBacklight(uint8_t brightness) {
|
void Display::SetBacklight(uint8_t brightness) {
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ public:
|
|||||||
Display();
|
Display();
|
||||||
virtual ~Display();
|
virtual ~Display();
|
||||||
|
|
||||||
virtual void SetStatus(const std::string &status);
|
virtual void SetStatus(const char* status);
|
||||||
|
virtual void ShowNotification(const char* notification, int duration_ms = 3000);
|
||||||
virtual void ShowNotification(const std::string ¬ification, int duration_ms = 3000);
|
virtual void ShowNotification(const std::string ¬ification, int duration_ms = 3000);
|
||||||
virtual void SetEmotion(const std::string &emotion);
|
virtual void SetEmotion(const char* emotion);
|
||||||
virtual void SetChatMessage(const std::string &role, const std::string &content);
|
virtual void SetChatMessage(const char* role, const char* content);
|
||||||
virtual void SetIcon(const char* icon);
|
virtual void SetIcon(const char* icon);
|
||||||
virtual void SetBacklight(uint8_t brightness);
|
virtual void SetBacklight(uint8_t brightness);
|
||||||
|
|
||||||
|
|||||||
@@ -257,15 +257,14 @@ void LcdDisplay::SetupUI() {
|
|||||||
notification_label_ = lv_label_create(status_bar_);
|
notification_label_ = lv_label_create(status_bar_);
|
||||||
lv_obj_set_flex_grow(notification_label_, 1);
|
lv_obj_set_flex_grow(notification_label_, 1);
|
||||||
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
|
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
lv_label_set_text(notification_label_, (Lang::Strings::NOTICE).c_str());
|
lv_label_set_text(notification_label_, "");
|
||||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
status_label_ = lv_label_create(status_bar_);
|
status_label_ = lv_label_create(status_bar_);
|
||||||
lv_obj_set_flex_grow(status_label_, 1);
|
lv_obj_set_flex_grow(status_label_, 1);
|
||||||
lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||||
lv_label_set_text(status_label_,(Lang::Strings::INITIALIZING + "...").c_str());
|
|
||||||
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
|
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
|
lv_label_set_text(status_label_, Lang::Strings::INITIALIZING);
|
||||||
mute_label_ = lv_label_create(status_bar_);
|
mute_label_ = lv_label_create(status_bar_);
|
||||||
lv_label_set_text(mute_label_, "");
|
lv_label_set_text(mute_label_, "");
|
||||||
lv_obj_set_style_text_font(mute_label_, fonts_.icon_font, 0);
|
lv_obj_set_style_text_font(mute_label_, fonts_.icon_font, 0);
|
||||||
@@ -275,7 +274,7 @@ void LcdDisplay::SetupUI() {
|
|||||||
lv_obj_set_style_text_font(battery_label_, fonts_.icon_font, 0);
|
lv_obj_set_style_text_font(battery_label_, fonts_.icon_font, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LcdDisplay::SetEmotion(const std::string &emotion) {
|
void LcdDisplay::SetEmotion(const char* emotion) {
|
||||||
struct Emotion {
|
struct Emotion {
|
||||||
const char* icon;
|
const char* icon;
|
||||||
const char* text;
|
const char* text;
|
||||||
@@ -306,8 +305,9 @@ void LcdDisplay::SetEmotion(const std::string &emotion) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 查找匹配的表情
|
// 查找匹配的表情
|
||||||
|
std::string_view emotion_view(emotion);
|
||||||
auto it = std::find_if(emotions.begin(), emotions.end(),
|
auto it = std::find_if(emotions.begin(), emotions.end(),
|
||||||
[&emotion](const Emotion& e) { return e.text == emotion; });
|
[&emotion_view](const Emotion& e) { return e.text == emotion_view; });
|
||||||
|
|
||||||
DisplayLockGuard lock(this);
|
DisplayLockGuard lock(this);
|
||||||
if (emotion_label_ == nullptr) {
|
if (emotion_label_ == nullptr) {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public:
|
|||||||
DisplayFonts fonts);
|
DisplayFonts fonts);
|
||||||
~LcdDisplay();
|
~LcdDisplay();
|
||||||
|
|
||||||
virtual void SetEmotion(const std::string &emotion) override;
|
virtual void SetEmotion(const char* emotion) override;
|
||||||
virtual void SetIcon(const char* icon) override;
|
virtual void SetIcon(const char* icon) override;
|
||||||
virtual void SetBacklight(uint8_t brightness) override;
|
virtual void SetBacklight(uint8_t brightness) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -221,12 +221,12 @@ void Ssd1306Display::SetupUI_128x64() {
|
|||||||
notification_label_ = lv_label_create(status_bar_);
|
notification_label_ = lv_label_create(status_bar_);
|
||||||
lv_obj_set_flex_grow(notification_label_, 1);
|
lv_obj_set_flex_grow(notification_label_, 1);
|
||||||
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
|
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
lv_label_set_text(notification_label_, (Lang::Strings::NOTICE).c_str());
|
lv_label_set_text(notification_label_, "");
|
||||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
status_label_ = lv_label_create(status_bar_);
|
status_label_ = lv_label_create(status_bar_);
|
||||||
lv_obj_set_flex_grow(status_label_, 1);
|
lv_obj_set_flex_grow(status_label_, 1);
|
||||||
lv_label_set_text(status_label_,(Lang::Strings::INITIALIZING + "...").c_str());
|
lv_label_set_text(status_label_, Lang::Strings::INITIALIZING);
|
||||||
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
|
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
|
|
||||||
mute_label_ = lv_label_create(status_bar_);
|
mute_label_ = lv_label_create(status_bar_);
|
||||||
@@ -296,10 +296,10 @@ void Ssd1306Display::SetupUI_128x32() {
|
|||||||
|
|
||||||
status_label_ = lv_label_create(status_bar_);
|
status_label_ = lv_label_create(status_bar_);
|
||||||
lv_obj_set_style_pad_left(status_label_, 2, 0);
|
lv_obj_set_style_pad_left(status_label_, 2, 0);
|
||||||
lv_label_set_text(status_label_,(Lang::Strings::INITIALIZING + "...").c_str());
|
lv_label_set_text(status_label_, Lang::Strings::INITIALIZING);
|
||||||
|
|
||||||
notification_label_ = lv_label_create(status_bar_);
|
notification_label_ = lv_label_create(status_bar_);
|
||||||
lv_label_set_text(notification_label_, (Lang::Strings::NOTICE).c_str());
|
lv_label_set_text(notification_label_, "");
|
||||||
lv_obj_set_style_pad_left(notification_label_, 2, 0);
|
lv_obj_set_style_pad_left(notification_label_, 2, 0);
|
||||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
|
|||||||
@@ -6,18 +6,20 @@ import os
|
|||||||
HEADER_TEMPLATE = """// Auto-generated language config
|
HEADER_TEMPLATE = """// Auto-generated language config
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
namespace Lang {{
|
namespace Lang {{
|
||||||
// 语言元数据
|
// 语言元数据
|
||||||
constexpr std::string_view CODE_VIEW = "{lang_code}";
|
constexpr const char* CODE = "{lang_code}";
|
||||||
const std::string CODE = std::string(CODE_VIEW);
|
|
||||||
|
|
||||||
// 字符串资源
|
// 字符串资源
|
||||||
namespace Strings {{
|
namespace Strings {{
|
||||||
{strings_view}
|
{strings}
|
||||||
{strings_string}
|
}}
|
||||||
|
|
||||||
|
// 音效资源
|
||||||
|
namespace Sounds {{
|
||||||
|
{sounds}
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
@@ -33,18 +35,29 @@ def generate_header(input_path, output_path):
|
|||||||
lang_code = data['language']['type']
|
lang_code = data['language']['type']
|
||||||
|
|
||||||
# 生成字符串常量
|
# 生成字符串常量
|
||||||
strings_view = []
|
strings = []
|
||||||
strings_string = []
|
sounds = []
|
||||||
for key, value in data['strings'].items():
|
for key, value in data['strings'].items():
|
||||||
value = value.replace('"', '\\"')
|
value = value.replace('"', '\\"')
|
||||||
strings_view.append(f' constexpr std::string_view {key.upper()}_VIEW = "{value}";')
|
strings.append(f' constexpr const char* {key.upper()} = "{value}";')
|
||||||
strings_string.append(f' const std::string {key.upper()} = std::string({key.upper()}_VIEW);')
|
|
||||||
|
# 生成音效常量
|
||||||
|
for file in os.listdir(os.path.dirname(input_path)):
|
||||||
|
if file.endswith('.p3'):
|
||||||
|
base_name = os.path.splitext(file)[0]
|
||||||
|
sounds.append(f'''
|
||||||
|
extern const char p3_{base_name}_start[] asm("_binary_{base_name}_p3_start");
|
||||||
|
extern const char p3_{base_name}_end[] asm("_binary_{base_name}_p3_end");
|
||||||
|
static const std::string_view P3_{base_name.upper()} {{
|
||||||
|
static_cast<const char*>(p3_{base_name}_start),
|
||||||
|
static_cast<size_t>(p3_{base_name}_end - p3_{base_name}_start)
|
||||||
|
}};''')
|
||||||
|
|
||||||
# 填充模板
|
# 填充模板
|
||||||
content = HEADER_TEMPLATE.format(
|
content = HEADER_TEMPLATE.format(
|
||||||
lang_code=lang_code,
|
lang_code=lang_code,
|
||||||
strings_view="\n".join(sorted(strings_view)),
|
strings="\n".join(sorted(strings)),
|
||||||
strings_string="\n".join(sorted(strings_string))
|
sounds="\n".join(sorted(sounds))
|
||||||
)
|
)
|
||||||
|
|
||||||
# 写入文件
|
# 写入文件
|
||||||
|
|||||||
Reference in New Issue
Block a user