diff --git a/main/application.cc b/main/application.cc index dfd8bdcf..75452d69 100644 --- a/main/application.cc +++ b/main/application.cc @@ -61,7 +61,11 @@ void Application::CheckNewVersion() { ota_.SetPostData(board.GetJson()); while (true) { - if (ota_.CheckVersion()) { + bool success = ota_.CheckVersion(); + if (ota_.HasActivationCode()) { + DisplayActivationCode(); + } + if (success) { if (ota_.HasNewVersion()) { Alert("Info", "正在升级固件"); // Wait for the chat state to be idle @@ -115,6 +119,13 @@ void Application::CheckNewVersion() { } } +void Application::DisplayActivationCode() { + ESP_LOGW(TAG, "Activation Message: %s", ota_.GetActivationMessage().c_str()); + ESP_LOGW(TAG, "Activation Code: %s", ota_.GetActivationCode().c_str()); + auto display = Board::GetInstance().GetDisplay(); + display->ShowNotification(ota_.GetActivationMessage(), 30000); +} + void Application::Alert(const std::string& title, const std::string& message) { ESP_LOGW(TAG, "Alert: %s, %s", title.c_str(), message.c_str()); auto display = Board::GetInstance().GetDisplay(); diff --git a/main/application.h b/main/application.h index 8546946f..2b8552e7 100644 --- a/main/application.h +++ b/main/application.h @@ -100,6 +100,7 @@ private: void ResetDecoder(); void SetDecodeSampleRate(int sample_rate); void CheckNewVersion(); + void DisplayActivationCode(); void PlayLocalFile(const char* data, size_t size); }; diff --git a/main/boards/common/board.cc b/main/boards/common/board.cc index b0f61829..a3e67a69 100644 --- a/main/boards/common/board.cc +++ b/main/boards/common/board.cc @@ -1,14 +1,46 @@ #include "board.h" #include "system_info.h" +#include "settings.h" #include "display/no_display.h" #include #include #include +#include #define TAG "Board" Board::Board() { + Settings settings("board", true); + uuid_ = settings.GetString("uuid"); + if (uuid_.empty()) { + uuid_ = GenerateUuid(); + settings.SetString("uuid", uuid_); + } + ESP_LOGI(TAG, "UUID: %s", uuid_.c_str()); +} + +std::string Board::GenerateUuid() { + // UUID v4 需要 16 字节的随机数据 + uint8_t uuid[16]; + + // 使用 ESP32 的硬件随机数生成器 + esp_fill_random(uuid, sizeof(uuid)); + + // 设置版本 (版本 4) 和变体位 + uuid[6] = (uuid[6] & 0x0F) | 0x40; // 版本 4 + uuid[8] = (uuid[8] & 0x3F) | 0x80; // 变体 1 + + // 将字节转换为标准的 UUID 字符串格式 + char uuid_str[37]; + snprintf(uuid_str, sizeof(uuid_str), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + + return std::string(uuid_str); } bool Board::GetBatteryLevel(int &level, bool& charging) { @@ -28,10 +60,12 @@ Led* Board::GetLed() { std::string Board::GetJson() { /* { + "version": 2, "flash_size": 4194304, "psram_size": 0, "minimum_free_heap_size": 123456, "mac_address": "00:00:00:00:00:00", + "uuid": "00000000-0000-0000-0000-000000000000", "chip_model_name": "esp32s3", "chip_info": { "model": 1, @@ -57,13 +91,18 @@ std::string Board::GetJson() { ], "ota": { "label": "ota_0" + }, + "board": { + ... } } */ std::string json = "{"; + json += "\"version\":2,"; json += "\"flash_size\":" + std::to_string(SystemInfo::GetFlashSize()) + ","; json += "\"minimum_free_heap_size\":" + std::to_string(SystemInfo::GetMinimumFreeHeapSize()) + ","; json += "\"mac_address\":\"" + SystemInfo::GetMacAddress() + "\","; + json += "\"uuid\":\"" + uuid_ + "\","; json += "\"chip_model_name\":\"" + SystemInfo::GetChipModelName() + "\","; json += "\"chip_info\":{"; diff --git a/main/boards/common/board.h b/main/boards/common/board.h index c3f2689f..f1504b7c 100644 --- a/main/boards/common/board.h +++ b/main/boards/common/board.h @@ -20,6 +20,10 @@ private: protected: Board(); + std::string GenerateUuid(); + + // 软件生成的设备唯一标识 + std::string uuid_; public: static Board& GetInstance() { @@ -29,6 +33,7 @@ public: virtual ~Board() = default; virtual std::string GetBoardType() = 0; + virtual std::string GetUuid() { return uuid_; } virtual Led* GetLed(); virtual AudioCodec* GetAudioCodec() = 0; virtual Display* GetDisplay(); diff --git a/main/ota.cc b/main/ota.cc index c9aa98aa..1181eb98 100644 --- a/main/ota.cc +++ b/main/ota.cc @@ -71,6 +71,19 @@ bool Ota::CheckVersion() { return false; } + cJSON *activation = cJSON_GetObjectItem(root, "activation"); + if (activation != NULL) { + cJSON* message = cJSON_GetObjectItem(activation, "message"); + if (message != NULL) { + activation_message_ = message->valuestring; + } + cJSON* code = cJSON_GetObjectItem(activation, "code"); + if (code != NULL) { + activation_code_ = code->valuestring; + } + has_activation_code_ = true; + } + cJSON *mqtt = cJSON_GetObjectItem(root, "mqtt"); if (mqtt != NULL) { Settings settings("mqtt", true); diff --git a/main/ota.h b/main/ota.h index 2901606f..96f6aa91 100644 --- a/main/ota.h +++ b/main/ota.h @@ -16,16 +16,22 @@ public: bool CheckVersion(); bool HasNewVersion() { return has_new_version_; } bool HasMqttConfig() { return has_mqtt_config_; } + bool HasActivationCode() { return has_activation_code_; } void StartUpgrade(std::function callback); void MarkCurrentVersionValid(); const std::string& GetFirmwareVersion() const { return firmware_version_; } const std::string& GetCurrentVersion() const { return current_version_; } + const std::string& GetActivationMessage() const { return activation_message_; } + const std::string& GetActivationCode() const { return activation_code_; } private: std::string check_version_url_; + std::string activation_message_; + std::string activation_code_; bool has_new_version_ = false; bool has_mqtt_config_ = false; + bool has_activation_code_ = false; std::string current_version_; std::string firmware_version_; std::string firmware_url_; diff --git a/main/protocols/websocket_protocol.cc b/main/protocols/websocket_protocol.cc index 5b965103..9e625803 100644 --- a/main/protocols/websocket_protocol.cc +++ b/main/protocols/websocket_protocol.cc @@ -61,6 +61,7 @@ bool WebsocketProtocol::OpenAudioChannel() { websocket_->SetHeader("Authorization", token.c_str()); websocket_->SetHeader("Protocol-Version", "1"); websocket_->SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str()); + websocket_->SetHeader("X-Uuid", Board::GetInstance().GetUuid().c_str()); websocket_->OnData([this](const char* data, size_t len, bool binary) { if (binary) {