From 3404180a776b5473531fbb9658add706155e32a8 Mon Sep 17 00:00:00 2001 From: Terrence Date: Mon, 21 Apr 2025 15:12:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0Wi-Fi=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=89=88=E6=9C=AC=EF=BC=8C=E4=BB=8EOTA=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=AF=BB=E5=8F=96Websocket=E6=9C=8D=E5=8A=A1=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- docs/websocket.md | 2 +- main/CMakeLists.txt | 8 ++----- main/Kconfig.projbuild | 32 +++------------------------- main/application.cc | 22 +++++++++++++------ main/assets/en-US/language.json | 3 ++- main/assets/ja-JP/language.json | 1 + main/assets/zh-CN/language.json | 1 + main/assets/zh-TW/language.json | 1 + main/boards/common/wifi_board.cc | 5 ++--- main/idf_component.yml | 4 ++-- main/ota.cc | 25 +++++++++++++++++----- main/ota.h | 4 +++- main/protocols/websocket_protocol.cc | 14 ++++++++++-- sdkconfig.defaults.esp32s3 | 1 - 15 files changed, 67 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d1200039..a844d1c5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # CMakeLists in this exact order for cmake to work correctly 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_compile_options(-Wno-missing-field-initializers) diff --git a/docs/websocket.md b/docs/websocket.md index bad6ea19..b9769532 100644 --- a/docs/websocket.md +++ b/docs/websocket.md @@ -13,7 +13,7 @@ 2. **建立 WebSocket 连接** - 当设备需要开始语音会话时(例如用户唤醒、手动按键触发等),调用 `OpenAudioChannel()`: - - 根据编译配置获取 WebSocket URL(`CONFIG_WEBSOCKET_URL`) + - 根据配置获取 WebSocket URL - 设置若干请求头(`Authorization`, `Protocol-Version`, `Device-Id`, `Client-Id`) - 调用 `Connect()` 与服务器建立 WebSocket 连接 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index a832818f..2e93df74 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -11,6 +11,8 @@ set(SOURCES "audio_codecs/audio_codec.cc" "display/lcd_display.cc" "display/oled_display.cc" "protocols/protocol.cc" + "protocols/mqtt_protocol.cc" + "protocols/websocket_protocol.cc" "iot/thing.cc" "iot/thing_manager.cc" "system_info.cc" @@ -148,12 +150,6 @@ file(GLOB 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) list(APPEND SOURCES "audio_processing/audio_processor.cc") endif() diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 631cde6b..67d2a12d 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -1,10 +1,10 @@ menu "Xiaozhi Assistant" -config OTA_VERSION_URL - string "OTA Version URL" +config OTA_URL + string "Default OTA URL" default "https://api.tenclass.net/xiaozhi/ota/" 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 @@ -23,32 +23,6 @@ choice bool "Japanese" 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 prompt "Board Type" default BOARD_TYPE_BREAD_COMPACT_WIFI diff --git a/main/application.cc b/main/application.cc index a0cab784..45faf2a1 100644 --- a/main/application.cc +++ b/main/application.cc @@ -78,6 +78,11 @@ void Application::CheckNewVersion() { ESP_LOGE(TAG, "Too many retries, exit version check"); 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); for (int i = 0; i < retry_delay; i++) { vTaskDelay(pdMS_TO_TICKS(1000)); @@ -372,11 +377,16 @@ void Application::Start() { // Initialize the protocol display->SetStatus(Lang::Strings::LOADING_PROTOCOL); -#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET - protocol_ = std::make_unique(); -#else - protocol_ = std::make_unique(); -#endif + + if (ota_.HasMqttConfig()) { + protocol_ = std::make_unique(); + } else if (ota_.HasWebsocketConfig()) { + protocol_ = std::make_unique(); + } else { + ESP_LOGW(TAG, "No protocol specified in the OTA config, using MQTT"); + protocol_ = std::make_unique(); + } + protocol_->OnNetworkError([this](const std::string& message) { SetDeviceState(kDeviceStateIdle); Alert(Lang::Strings::ERROR, message.c_str(), "sad", Lang::Sounds::P3_EXCLAMATION); @@ -529,7 +539,7 @@ void Application::Start() { SetDeviceState(kDeviceStateConnecting); wake_word_detect_.EncodeWakeWordData(); - if (!protocol_->OpenAudioChannel()) { + if (!protocol_ || !protocol_->OpenAudioChannel()) { wake_word_detect_.StartDetection(); return; } diff --git a/main/assets/en-US/language.json b/main/assets/en-US/language.json index e255d0d5..eef77c69 100644 --- a/main/assets/en-US/language.json +++ b/main/assets/en-US/language.json @@ -8,12 +8,13 @@ "ERROR": "Error", "VERSION": "Ver ", "LOADING_PROTOCOL": "Logging in...", - "CHECKING_NEW_VERSION": "Checking for new version...", "INITIALIZING": "Initializing...", "PIN_ERROR": "Please insert SIM card", "REG_ERROR": "Unable to access network, please check SIM card status", "DETECTING_MODULE": "Detecting module...", "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", "CONNECT_TO": "Connect to ", diff --git a/main/assets/ja-JP/language.json b/main/assets/ja-JP/language.json index b69dbf10..e333cd99 100644 --- a/main/assets/ja-JP/language.json +++ b/main/assets/ja-JP/language.json @@ -14,6 +14,7 @@ "DETECTING_MODULE": "モジュールを検出中...", "REGISTERING_NETWORK": "ネットワーク接続待機中...", "CHECKING_NEW_VERSION": "新しいバージョンを確認中...", + "CHECK_NEW_VERSION_FAILED": "更新確認に失敗しました。%d 秒後に再試行します: %s", "STANDBY": "待機中", "CONNECT_TO": "接続先 ", diff --git a/main/assets/zh-CN/language.json b/main/assets/zh-CN/language.json index d057be78..7e929e73 100644 --- a/main/assets/zh-CN/language.json +++ b/main/assets/zh-CN/language.json @@ -14,6 +14,7 @@ "DETECTING_MODULE":"检测模组...", "REGISTERING_NETWORK":"等待网络...", "CHECKING_NEW_VERSION":"检查新版本...", + "CHECK_NEW_VERSION_FAILED":"检查新版本失败,将在 %d 秒后重试:%s", "STANDBY":"待命", "CONNECT_TO":"连接 ", diff --git a/main/assets/zh-TW/language.json b/main/assets/zh-TW/language.json index 45e9eb55..7aef168b 100644 --- a/main/assets/zh-TW/language.json +++ b/main/assets/zh-TW/language.json @@ -14,6 +14,7 @@ "DETECTING_MODULE": "檢測模組...", "REGISTERING_NETWORK": "等待網絡...", "CHECKING_NEW_VERSION": "檢查新版本...", + "CHECK_NEW_VERSION_FAILED": "檢查新版本失敗,將在 %d 秒後重試:%s", "STANDBY": "待命", "CONNECT_TO": "連接 ", diff --git a/main/boards/common/wifi_board.cc b/main/boards/common/wifi_board.cc index 1c353800..569d6b4a 100644 --- a/main/boards/common/wifi_board.cc +++ b/main/boards/common/wifi_board.cc @@ -114,14 +114,13 @@ Http* WifiBoard::CreateHttp() { } WebSocket* WifiBoard::CreateWebSocket() { -#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET - std::string url = CONFIG_WEBSOCKET_URL; + Settings settings("websocket", false); + std::string url = settings.GetString("url"); if (url.find("wss://") == 0) { return new WebSocket(new TlsTransport()); } else { return new WebSocket(new TcpTransport()); } -#endif return nullptr; } diff --git a/main/idf_component.yml b/main/idf_component.yml index 2a27208f..e773012c 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -8,13 +8,13 @@ dependencies: espressif/esp_io_expander_tca9554: "==2.0.0" espressif/esp_lcd_panel_io_additions: "^1.0.1" 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-ml307: "~1.9.0" 78/xiaozhi-fonts: "~1.3.2" espressif/led_strip: "^2.4.1" 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/knob: "^1.0.0" lvgl/lvgl: "~9.2.2" diff --git a/main/ota.cc b/main/ota.cc index 6760791a..f40335ad 100644 --- a/main/ota.cc +++ b/main/ota.cc @@ -23,7 +23,13 @@ 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 // Read Serial Number from efuse user_data @@ -42,10 +48,6 @@ 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) { headers_[key] = value; } @@ -144,6 +146,19 @@ bool Ota::CheckVersion() { 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; cJSON *server_time = cJSON_GetObjectItem(root, "server_time"); if (server_time != NULL) { diff --git a/main/ota.h b/main/ota.h index d7aedd1d..3d019595 100644 --- a/main/ota.h +++ b/main/ota.h @@ -13,13 +13,13 @@ public: Ota(); ~Ota(); - void SetCheckVersionUrl(std::string check_version_url); void SetHeader(const std::string& key, const std::string& value); bool CheckVersion(); esp_err_t Activate(); bool HasActivationChallenge() { return has_activation_challenge_; } bool HasNewVersion() { return has_new_version_; } bool HasMqttConfig() { return has_mqtt_config_; } + bool HasWebsocketConfig() { return has_websocket_config_; } bool HasActivationCode() { return has_activation_code_; } bool HasServerTime() { return has_server_time_; } void StartUpgrade(std::function callback); @@ -29,6 +29,7 @@ public: const std::string& GetCurrentVersion() const { return current_version_; } const std::string& GetActivationMessage() const { return activation_message_; } const std::string& GetActivationCode() const { return activation_code_; } + const std::string& GetCheckVersionUrl() const { return check_version_url_; } private: std::string check_version_url_; @@ -36,6 +37,7 @@ private: std::string activation_code_; bool has_new_version_ = false; bool has_mqtt_config_ = false; + bool has_websocket_config_ = false; bool has_server_time_ = false; bool has_activation_code_ = false; bool has_serial_number_ = false; diff --git a/main/protocols/websocket_protocol.cc b/main/protocols/websocket_protocol.cc index 50b234a4..b08f5b69 100644 --- a/main/protocols/websocket_protocol.cc +++ b/main/protocols/websocket_protocol.cc @@ -2,6 +2,7 @@ #include "board.h" #include "system_info.h" #include "application.h" +#include "settings.h" #include #include @@ -67,10 +68,18 @@ bool WebsocketProtocol::OpenAudioChannel() { delete websocket_; } + Settings settings("websocket", false); + std::string url = settings.GetString("url"); + std::string token = settings.GetString("token"); + busy_sending_audio_ = 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_->SetHeader("Authorization", token.c_str()); 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())) { ESP_LOGE(TAG, "Failed to connect to websocket server"); SetError(Lang::Strings::SERVER_NOT_FOUND); diff --git a/sdkconfig.defaults.esp32s3 b/sdkconfig.defaults.esp32s3 index 021d39f7..c9bc1b68 100644 --- a/sdkconfig.defaults.esp32s3 +++ b/sdkconfig.defaults.esp32s3 @@ -8,7 +8,6 @@ CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_SPEED_80M=y CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=4096 -CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=49152 CONFIG_SPIRAM_MEMTEST=n CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y