更新Wi-Fi组件版本,从OTA接口读取Websocket服务器

This commit is contained in:
Terrence
2025-04-21 15:12:52 +08:00
parent c380617cca
commit 3404180a77
15 changed files with 67 additions and 58 deletions

View File

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

View File

@@ -13,7 +13,7 @@
2. **建立 WebSocket 连接** 2. **建立 WebSocket 连接**
- 当设备需要开始语音会话时(例如用户唤醒、手动按键触发等),调用 `OpenAudioChannel()` - 当设备需要开始语音会话时(例如用户唤醒、手动按键触发等),调用 `OpenAudioChannel()`
- 根据编译配置获取 WebSocket URL`CONFIG_WEBSOCKET_URL` - 根据配置获取 WebSocket URL
- 设置若干请求头(`Authorization`, `Protocol-Version`, `Device-Id`, `Client-Id` - 设置若干请求头(`Authorization`, `Protocol-Version`, `Device-Id`, `Client-Id`
- 调用 `Connect()` 与服务器建立 WebSocket 连接 - 调用 `Connect()` 与服务器建立 WebSocket 连接

View File

@@ -11,6 +11,8 @@ set(SOURCES "audio_codecs/audio_codec.cc"
"display/lcd_display.cc" "display/lcd_display.cc"
"display/oled_display.cc" "display/oled_display.cc"
"protocols/protocol.cc" "protocols/protocol.cc"
"protocols/mqtt_protocol.cc"
"protocols/websocket_protocol.cc"
"iot/thing.cc" "iot/thing.cc"
"iot/thing_manager.cc" "iot/thing_manager.cc"
"system_info.cc" "system_info.cc"
@@ -148,12 +150,6 @@ file(GLOB BOARD_SOURCES
) )
list(APPEND SOURCES ${BOARD_SOURCES}) list(APPEND SOURCES ${BOARD_SOURCES})
if(CONFIG_CONNECTION_TYPE_MQTT_UDP)
list(APPEND SOURCES "protocols/mqtt_protocol.cc")
elseif(CONFIG_CONNECTION_TYPE_WEBSOCKET)
list(APPEND SOURCES "protocols/websocket_protocol.cc")
endif()
if(CONFIG_USE_AUDIO_PROCESSOR) if(CONFIG_USE_AUDIO_PROCESSOR)
list(APPEND SOURCES "audio_processing/audio_processor.cc") list(APPEND SOURCES "audio_processing/audio_processor.cc")
endif() endif()

View File

@@ -1,10 +1,10 @@
menu "Xiaozhi Assistant" menu "Xiaozhi Assistant"
config OTA_VERSION_URL config OTA_URL
string "OTA Version URL" string "Default OTA URL"
default "https://api.tenclass.net/xiaozhi/ota/" default "https://api.tenclass.net/xiaozhi/ota/"
help help
The application will access this URL to check for updates. The application will access this URL to check for new firmwares and server address.
choice choice
@@ -23,32 +23,6 @@ choice
bool "Japanese" bool "Japanese"
endchoice endchoice
choice CONNECTION_TYPE
prompt "Connection Type"
default CONNECTION_TYPE_MQTT_UDP
help
网络数据传输协议
config CONNECTION_TYPE_MQTT_UDP
bool "MQTT + UDP"
config CONNECTION_TYPE_WEBSOCKET
bool "Websocket"
endchoice
config WEBSOCKET_URL
depends on CONNECTION_TYPE_WEBSOCKET
string "Websocket URL"
default "wss://api.tenclass.net/xiaozhi/v1/"
help
Communication with the server through websocket after wake up.
config WEBSOCKET_ACCESS_TOKEN
depends on CONNECTION_TYPE_WEBSOCKET
string "Websocket Access Token"
default "test-token"
help
Access token for websocket communication.
choice BOARD_TYPE choice BOARD_TYPE
prompt "Board Type" prompt "Board Type"
default BOARD_TYPE_BREAD_COMPACT_WIFI default BOARD_TYPE_BREAD_COMPACT_WIFI

View File

@@ -78,6 +78,11 @@ void Application::CheckNewVersion() {
ESP_LOGE(TAG, "Too many retries, exit version check"); ESP_LOGE(TAG, "Too many retries, exit version check");
return; return;
} }
char buffer[128];
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);
ESP_LOGW(TAG, "Check new version failed, retry in %d seconds (%d/%d)", retry_delay, retry_count, MAX_RETRY); 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++) { for (int i = 0; i < retry_delay; i++) {
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(1000));
@@ -372,11 +377,16 @@ void Application::Start() {
// Initialize the protocol // Initialize the protocol
display->SetStatus(Lang::Strings::LOADING_PROTOCOL); display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
protocol_ = std::make_unique<WebsocketProtocol>(); if (ota_.HasMqttConfig()) {
#else protocol_ = std::make_unique<MqttProtocol>();
protocol_ = std::make_unique<MqttProtocol>(); } else if (ota_.HasWebsocketConfig()) {
#endif protocol_ = std::make_unique<WebsocketProtocol>();
} else {
ESP_LOGW(TAG, "No protocol specified in the OTA config, using MQTT");
protocol_ = std::make_unique<MqttProtocol>();
}
protocol_->OnNetworkError([this](const std::string& message) { protocol_->OnNetworkError([this](const std::string& message) {
SetDeviceState(kDeviceStateIdle); SetDeviceState(kDeviceStateIdle);
Alert(Lang::Strings::ERROR, message.c_str(), "sad", Lang::Sounds::P3_EXCLAMATION); Alert(Lang::Strings::ERROR, message.c_str(), "sad", Lang::Sounds::P3_EXCLAMATION);
@@ -529,7 +539,7 @@ void Application::Start() {
SetDeviceState(kDeviceStateConnecting); SetDeviceState(kDeviceStateConnecting);
wake_word_detect_.EncodeWakeWordData(); wake_word_detect_.EncodeWakeWordData();
if (!protocol_->OpenAudioChannel()) { if (!protocol_ || !protocol_->OpenAudioChannel()) {
wake_word_detect_.StartDetection(); wake_word_detect_.StartDetection();
return; return;
} }

View File

@@ -8,12 +8,13 @@
"ERROR": "Error", "ERROR": "Error",
"VERSION": "Ver ", "VERSION": "Ver ",
"LOADING_PROTOCOL": "Logging in...", "LOADING_PROTOCOL": "Logging in...",
"CHECKING_NEW_VERSION": "Checking for new version...",
"INITIALIZING": "Initializing...", "INITIALIZING": "Initializing...",
"PIN_ERROR": "Please insert SIM card", "PIN_ERROR": "Please insert SIM card",
"REG_ERROR": "Unable to access network, please check SIM card status", "REG_ERROR": "Unable to access network, please check SIM card status",
"DETECTING_MODULE": "Detecting module...", "DETECTING_MODULE": "Detecting module...",
"REGISTERING_NETWORK": "Waiting for network...", "REGISTERING_NETWORK": "Waiting for network...",
"CHECKING_NEW_VERSION": "Checking for new version...",
"CHECK_NEW_VERSION_FAILED": "Check for new version failed, will retry in %d seconds: %s",
"STANDBY": "Standby", "STANDBY": "Standby",
"CONNECT_TO": "Connect to ", "CONNECT_TO": "Connect to ",

View File

@@ -14,6 +14,7 @@
"DETECTING_MODULE": "モジュールを検出中...", "DETECTING_MODULE": "モジュールを検出中...",
"REGISTERING_NETWORK": "ネットワーク接続待機中...", "REGISTERING_NETWORK": "ネットワーク接続待機中...",
"CHECKING_NEW_VERSION": "新しいバージョンを確認中...", "CHECKING_NEW_VERSION": "新しいバージョンを確認中...",
"CHECK_NEW_VERSION_FAILED": "更新確認に失敗しました。%d 秒後に再試行します: %s",
"STANDBY": "待機中", "STANDBY": "待機中",
"CONNECT_TO": "接続先 ", "CONNECT_TO": "接続先 ",

View File

@@ -14,6 +14,7 @@
"DETECTING_MODULE":"检测模组...", "DETECTING_MODULE":"检测模组...",
"REGISTERING_NETWORK":"等待网络...", "REGISTERING_NETWORK":"等待网络...",
"CHECKING_NEW_VERSION":"检查新版本...", "CHECKING_NEW_VERSION":"检查新版本...",
"CHECK_NEW_VERSION_FAILED":"检查新版本失败,将在 %d 秒后重试:%s",
"STANDBY":"待命", "STANDBY":"待命",
"CONNECT_TO":"连接 ", "CONNECT_TO":"连接 ",

View File

@@ -14,6 +14,7 @@
"DETECTING_MODULE": "檢測模組...", "DETECTING_MODULE": "檢測模組...",
"REGISTERING_NETWORK": "等待網絡...", "REGISTERING_NETWORK": "等待網絡...",
"CHECKING_NEW_VERSION": "檢查新版本...", "CHECKING_NEW_VERSION": "檢查新版本...",
"CHECK_NEW_VERSION_FAILED": "檢查新版本失敗,將在 %d 秒後重試:%s",
"STANDBY": "待命", "STANDBY": "待命",
"CONNECT_TO": "連接 ", "CONNECT_TO": "連接 ",

View File

@@ -114,14 +114,13 @@ Http* WifiBoard::CreateHttp() {
} }
WebSocket* WifiBoard::CreateWebSocket() { WebSocket* WifiBoard::CreateWebSocket() {
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET Settings settings("websocket", false);
std::string url = CONFIG_WEBSOCKET_URL; std::string url = settings.GetString("url");
if (url.find("wss://") == 0) { if (url.find("wss://") == 0) {
return new WebSocket(new TlsTransport()); return new WebSocket(new TlsTransport());
} else { } else {
return new WebSocket(new TcpTransport()); return new WebSocket(new TcpTransport());
} }
#endif
return nullptr; return nullptr;
} }

View File

@@ -8,13 +8,13 @@ dependencies:
espressif/esp_io_expander_tca9554: "==2.0.0" espressif/esp_io_expander_tca9554: "==2.0.0"
espressif/esp_lcd_panel_io_additions: "^1.0.1" espressif/esp_lcd_panel_io_additions: "^1.0.1"
78/esp_lcd_nv3023: "~1.0.0" 78/esp_lcd_nv3023: "~1.0.0"
78/esp-wifi-connect: "~2.3.2" 78/esp-wifi-connect: "~2.4.1"
78/esp-opus-encoder: "~2.3.1" 78/esp-opus-encoder: "~2.3.1"
78/esp-ml307: "~1.9.0" 78/esp-ml307: "~1.9.0"
78/xiaozhi-fonts: "~1.3.2" 78/xiaozhi-fonts: "~1.3.2"
espressif/led_strip: "^2.4.1" espressif/led_strip: "^2.4.1"
espressif/esp_codec_dev: "~1.3.2" espressif/esp_codec_dev: "~1.3.2"
espressif/esp-sr: "^2.0.3" espressif/esp-sr: "^2.0.5"
espressif/button: "^3.3.1" espressif/button: "^3.3.1"
espressif/knob: "^1.0.0" espressif/knob: "^1.0.0"
lvgl/lvgl: "~9.2.2" lvgl/lvgl: "~9.2.2"

View File

@@ -23,7 +23,13 @@
Ota::Ota() { Ota::Ota() {
SetCheckVersionUrl(CONFIG_OTA_VERSION_URL); {
Settings settings("wifi", false);
check_version_url_ = settings.GetString("ota_url");
if (check_version_url_.empty()) {
check_version_url_ = CONFIG_OTA_URL;
}
}
#ifdef ESP_EFUSE_BLOCK_USR_DATA #ifdef ESP_EFUSE_BLOCK_USR_DATA
// Read Serial Number from efuse user_data // Read Serial Number from efuse user_data
@@ -42,10 +48,6 @@ Ota::Ota() {
Ota::~Ota() { Ota::~Ota() {
} }
void Ota::SetCheckVersionUrl(std::string check_version_url) {
check_version_url_ = check_version_url;
}
void Ota::SetHeader(const std::string& key, const std::string& value) { void Ota::SetHeader(const std::string& key, const std::string& value) {
headers_[key] = value; headers_[key] = value;
} }
@@ -144,6 +146,19 @@ bool Ota::CheckVersion() {
has_mqtt_config_ = true; has_mqtt_config_ = true;
} }
has_websocket_config_ = false;
cJSON *websocket = cJSON_GetObjectItem(root, "websocket");
if (websocket != NULL) {
Settings settings("websocket", true);
cJSON *item = NULL;
cJSON_ArrayForEach(item, websocket) {
if (item->type == cJSON_String) {
settings.SetString(item->string, item->valuestring);
}
}
has_websocket_config_ = true;
}
has_server_time_ = false; has_server_time_ = false;
cJSON *server_time = cJSON_GetObjectItem(root, "server_time"); cJSON *server_time = cJSON_GetObjectItem(root, "server_time");
if (server_time != NULL) { if (server_time != NULL) {

View File

@@ -13,13 +13,13 @@ public:
Ota(); Ota();
~Ota(); ~Ota();
void SetCheckVersionUrl(std::string check_version_url);
void SetHeader(const std::string& key, const std::string& value); void SetHeader(const std::string& key, const std::string& value);
bool CheckVersion(); bool CheckVersion();
esp_err_t Activate(); esp_err_t Activate();
bool HasActivationChallenge() { return has_activation_challenge_; } bool HasActivationChallenge() { return has_activation_challenge_; }
bool HasNewVersion() { return has_new_version_; } bool HasNewVersion() { return has_new_version_; }
bool HasMqttConfig() { return has_mqtt_config_; } bool HasMqttConfig() { return has_mqtt_config_; }
bool HasWebsocketConfig() { return has_websocket_config_; }
bool HasActivationCode() { return has_activation_code_; } bool HasActivationCode() { return has_activation_code_; }
bool HasServerTime() { return has_server_time_; } bool HasServerTime() { return has_server_time_; }
void StartUpgrade(std::function<void(int progress, size_t speed)> callback); void StartUpgrade(std::function<void(int progress, size_t speed)> callback);
@@ -29,6 +29,7 @@ public:
const std::string& GetCurrentVersion() const { return current_version_; } const std::string& GetCurrentVersion() const { return current_version_; }
const std::string& GetActivationMessage() const { return activation_message_; } const std::string& GetActivationMessage() const { return activation_message_; }
const std::string& GetActivationCode() const { return activation_code_; } const std::string& GetActivationCode() const { return activation_code_; }
const std::string& GetCheckVersionUrl() const { return check_version_url_; }
private: private:
std::string check_version_url_; std::string check_version_url_;
@@ -36,6 +37,7 @@ private:
std::string activation_code_; std::string activation_code_;
bool has_new_version_ = false; bool has_new_version_ = false;
bool has_mqtt_config_ = false; bool has_mqtt_config_ = false;
bool has_websocket_config_ = false;
bool has_server_time_ = false; bool has_server_time_ = false;
bool has_activation_code_ = false; bool has_activation_code_ = false;
bool has_serial_number_ = false; bool has_serial_number_ = false;

View File

@@ -2,6 +2,7 @@
#include "board.h" #include "board.h"
#include "system_info.h" #include "system_info.h"
#include "application.h" #include "application.h"
#include "settings.h"
#include <cstring> #include <cstring>
#include <cJSON.h> #include <cJSON.h>
@@ -67,10 +68,18 @@ bool WebsocketProtocol::OpenAudioChannel() {
delete websocket_; delete websocket_;
} }
Settings settings("websocket", false);
std::string url = settings.GetString("url");
std::string token = settings.GetString("token");
busy_sending_audio_ = false; busy_sending_audio_ = false;
error_occurred_ = false; error_occurred_ = false;
std::string url = CONFIG_WEBSOCKET_URL;
std::string token = "Bearer " + std::string(CONFIG_WEBSOCKET_ACCESS_TOKEN); // If token not starts with "Bearer " or "bearer ", add it
if (token.empty() || (token.find("Bearer ") != 0 && token.find("bearer ") != 0)) {
token = "Bearer " + token;
}
websocket_ = Board::GetInstance().CreateWebSocket(); websocket_ = Board::GetInstance().CreateWebSocket();
websocket_->SetHeader("Authorization", token.c_str()); websocket_->SetHeader("Authorization", token.c_str());
websocket_->SetHeader("Protocol-Version", "1"); websocket_->SetHeader("Protocol-Version", "1");
@@ -109,6 +118,7 @@ bool WebsocketProtocol::OpenAudioChannel() {
} }
}); });
ESP_LOGI(TAG, "Connecting to websocket server: %s with token: %s", url.c_str(), token.c_str());
if (!websocket_->Connect(url.c_str())) { if (!websocket_->Connect(url.c_str())) {
ESP_LOGE(TAG, "Failed to connect to websocket server"); ESP_LOGE(TAG, "Failed to connect to websocket server");
SetError(Lang::Strings::SERVER_NOT_FOUND); SetError(Lang::Strings::SERVER_NOT_FOUND);

View File

@@ -8,7 +8,6 @@ CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=4096 CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=4096
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=49152 CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=49152
CONFIG_SPIRAM_MEMTEST=n CONFIG_SPIRAM_MEMTEST=n
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y