Enhance device activation and OTA update process

- Add support for device activation with audio feedback
- Refactor OTA update flow to include activation code handling
- Update asset management for localized sound resources
- Improve error handling and device state management
- Reorganize binary asset includes and CMake configuration
This commit is contained in:
Terrence
2025-02-16 06:59:19 +08:00
parent 14a89cae33
commit 3a71c1e895
39 changed files with 220 additions and 86 deletions
+1 -1
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.1.2")
set(PROJECT_VER "1.1.9")
# Add this line to disable the specific warning
add_compile_options(-Wno-missing-field-initializers)
+9 -3
View File
@@ -13,8 +13,6 @@ set(SOURCES "audio_codecs/audio_codec.cc"
"display/ssd1306_display.cc"
"boards/lilygo-t-circle-s3/esp_lcd_gc9d01n.c"
"protocols/protocol.cc"
"protocols/mqtt_protocol.cc"
"protocols/websocket_protocol.cc"
"iot/thing.cc"
"iot/thing_manager.cc"
"system_info.cc"
@@ -107,6 +105,12 @@ endif()
file(GLOB BOARD_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc)
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_PROCESSING)
list(APPEND SOURCES "audio_processing/audio_processor.cc" "audio_processing/wake_word_detect.cc")
endif()
@@ -119,8 +123,10 @@ if(CONFIG_IDF_TARGET_ESP32)
"audio_codecs/es8388_audio_codec.cc")
endif()
file(GLOB ASSETS ${CMAKE_CURRENT_SOURCE_DIR}/assets/zh/*.p3)
idf_component_register(SRCS ${SOURCES}
EMBED_FILES "assets/err_reg.p3" "assets/err_pin.p3" "assets/wificonfig.p3" "assets/upgrade.p3"
EMBED_FILES ${ASSETS}
INCLUDE_DIRS ${INCLUDE_DIRS}
WHOLE_ARCHIVE
)
+78 -42
View File
@@ -8,6 +8,7 @@
#include "websocket_protocol.h"
#include "font_awesome_symbols.h"
#include "iot/thing_manager.h"
#include "assets/zh/binary.h"
#include <cstring>
#include <esp_log.h>
@@ -17,14 +18,6 @@
#define TAG "Application"
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");
static const char* const STATE_STRINGS[] = {
"unknown",
@@ -35,6 +28,7 @@ static const char* const STATE_STRINGS[] = {
"listening",
"speaking",
"upgrading",
"activating",
"fatal_error",
"invalid_state"
};
@@ -42,9 +36,6 @@ static const char* const STATE_STRINGS[] = {
Application::Application() {
event_group_ = xEventGroupCreate();
background_task_ = new BackgroundTask(4096 * 8);
ota_.SetCheckVersionUrl(CONFIG_OTA_VERSION_URL);
ota_.SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
}
Application::~Application() {
@@ -61,13 +52,9 @@ void Application::CheckNewVersion() {
ota_.SetPostData(board.GetJson());
while (true) {
bool success = ota_.CheckVersion();
if (ota_.HasActivationCode()) {
DisplayActivationCode();
}
if (success) {
if (ota_.CheckVersion()) {
if (ota_.HasNewVersion()) {
Alert("Info", "正在升级固件");
Alert("OTA 升级", "正在升级系统", "happy", std::string(p3_upgrade_start, p3_upgrade_end - p3_upgrade_start));
// Wait for the chat state to be idle
do {
vTaskDelay(pdMS_TO_TICKS(3000));
@@ -78,7 +65,7 @@ void Application::CheckNewVersion() {
SetDeviceState(kDeviceStateUpgrading);
display->SetIcon(FONT_AWESOME_DOWNLOAD);
display->SetStatus("新版本 " + ota_.GetFirmwareVersion());
display->SetChatMessage("system", "新版本 " + ota_.GetFirmwareVersion());
board.SetPowerSaveMode(false);
#if CONFIG_USE_AUDIO_PROCESSING
@@ -100,52 +87,83 @@ void Application::CheckNewVersion() {
ota_.StartUpgrade([display](int progress, size_t speed) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "%d%% %zuKB/s", progress, speed / 1024);
display->SetStatus(buffer);
display->SetChatMessage("system", buffer);
});
// If upgrade success, the device will reboot and never reach here
display->SetStatus("更新失败");
ESP_LOGI(TAG, "Firmware upgrade failed...");
vTaskDelay(pdMS_TO_TICKS(3000));
esp_restart();
Reboot();
});
} else {
ota_.MarkCurrentVersionValid();
display->ShowNotification("版本 " + ota_.GetCurrentVersion());
}
// Check if the activation code is valid
if (ota_.HasActivationCode()) {
SetDeviceState(kDeviceStateActivating);
ShowActivationCode();
} else {
SetDeviceState(kDeviceStateIdle);
display->SetChatMessage("system", "");
return;
}
}
}
// Check again in 60 seconds
vTaskDelay(pdMS_TO_TICKS(60000));
}
}
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::ShowActivationCode() {
auto& message = ota_.GetActivationMessage();
auto& code = ota_.GetActivationCode();
struct digit_sound {
char digit;
const char* sound_data_start;
const char* sound_data_end;
};
digit_sound digit_sounds[] = {
{'0', p3_0_start, p3_0_end},
{'1', p3_1_start, p3_1_end},
{'2', p3_2_start, p3_2_end},
{'3', p3_3_start, p3_3_end},
{'4', p3_4_start, p3_4_end},
{'5', p3_5_start, p3_5_end},
{'6', p3_6_start, p3_6_end},
{'7', p3_7_start, p3_7_end},
{'8', p3_8_start, p3_8_end},
{'9', p3_9_start, p3_9_end},
};
std::string sound = std::string(p3_activation_start, p3_activation_end - p3_activation_start);
for (const auto& digit : code) {
auto it = std::find_if(digit_sounds, digit_sounds + sizeof(digit_sounds) / sizeof(digit_sound),
[digit](const digit_sound& ds) { return ds.digit == digit; });
if (it != digit_sounds + sizeof(digit_sounds) / sizeof(digit_sound)) {
sound += std::string(it->sound_data_start, it->sound_data_end - it->sound_data_start);
}
}
Alert("激活设备", message, "happy", sound);
}
void Application::Alert(const std::string& title, const std::string& message) {
ESP_LOGW(TAG, "Alert: %s, %s", title.c_str(), message.c_str());
void Application::Alert(const std::string& status, const std::string& message, const std::string& emotion, const std::string& sound) {
ESP_LOGW(TAG, "Alert %s: %s [%s]", status.c_str(), message.c_str(), emotion.c_str());
auto display = Board::GetInstance().GetDisplay();
display->ShowNotification(message);
if (message == "进入配网模式") {
PlayLocalFile(p3_wificonfig_start, p3_wificonfig_end - p3_wificonfig_start);
} else if (message == "正在升级固件") {
PlayLocalFile(p3_upgrade_start, p3_upgrade_end - p3_upgrade_start);
} else if (message == "请插入SIM卡") {
PlayLocalFile(p3_err_pin_start, p3_err_pin_end - p3_err_pin_start);
} else if (message == "无法接入网络,请检查流量卡状态") {
PlayLocalFile(p3_err_reg_start, p3_err_reg_end - p3_err_reg_start);
display->SetStatus(status);
display->SetEmotion(emotion);
display->SetChatMessage("system", message);
if (!sound.empty()) {
PlayLocalFile(sound.data(), sound.size());
}
}
void Application::PlayLocalFile(const char* data, size_t size) {
ESP_LOGI(TAG, "PlayLocalFile: %zu bytes", size);
auto codec = Board::GetInstance().GetAudioCodec();
codec->EnableOutput(true);
SetDecodeSampleRate(16000);
for (const char* p = data; p < data + size; ) {
auto p3 = (BinaryProtocol3*)p;
@@ -164,6 +182,11 @@ void Application::PlayLocalFile(const char* data, size_t size) {
void Application::ToggleChatState() {
Schedule([this]() {
if (device_state_ == kDeviceStateActivating) {
Reboot();
return;
}
if (!protocol_) {
ESP_LOGE(TAG, "Protocol not initialized");
return;
@@ -172,7 +195,7 @@ void Application::ToggleChatState() {
if (device_state_ == kDeviceStateIdle) {
SetDeviceState(kDeviceStateConnecting);
if (!protocol_->OpenAudioChannel()) {
Alert("Error", "Failed to open audio channel");
Alert("ERROR", "无法建立音频通道");
SetDeviceState(kDeviceStateIdle);
return;
}
@@ -190,6 +213,11 @@ void Application::ToggleChatState() {
void Application::StartListening() {
Schedule([this]() {
if (device_state_ == kDeviceStateActivating) {
Reboot();
return;
}
if (!protocol_) {
ESP_LOGE(TAG, "Protocol not initialized");
return;
@@ -201,7 +229,7 @@ void Application::StartListening() {
SetDeviceState(kDeviceStateConnecting);
if (!protocol_->OpenAudioChannel()) {
SetDeviceState(kDeviceStateIdle);
Alert("Error", "Failed to open audio channel");
Alert("ERROR", "无法建立音频通道");
return;
}
}
@@ -275,14 +303,14 @@ void Application::Start() {
board.StartNetwork();
// Initialize the protocol
display->SetStatus("初始化协议");
display->SetStatus("加载协议...");
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
protocol_ = std::make_unique<WebsocketProtocol>();
#else
protocol_ = std::make_unique<MqttProtocol>();
#endif
protocol_->OnNetworkError([this](const std::string& message) {
Alert("Error", std::move(message));
Alert("ERROR", message);
});
protocol_->OnIncomingAudio([this](std::vector<uint8_t>&& data) {
std::lock_guard<std::mutex> lock(mutex_);
@@ -371,6 +399,9 @@ void Application::Start() {
});
// Check for new firmware version or get the MQTT broker address
ota_.SetCheckVersionUrl(CONFIG_OTA_VERSION_URL);
ota_.SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
ota_.SetHeader("Client-Id", board.GetUuid());
xTaskCreate([](void* arg) {
Application* app = (Application*)arg;
app->CheckNewVersion();
@@ -664,3 +695,8 @@ void Application::UpdateIotStates() {
protocol_->SendIotStates(states);
}
}
void Application::Reboot() {
ESP_LOGI(TAG, "Rebooting...");
esp_restart();
}
+4 -2
View File
@@ -35,6 +35,7 @@ enum DeviceState {
kDeviceStateListening,
kDeviceStateSpeaking,
kDeviceStateUpgrading,
kDeviceStateActivating,
kDeviceStateFatalError
};
@@ -55,12 +56,13 @@ public:
bool IsVoiceDetected() const { return voice_detected_; }
void Schedule(std::function<void()> callback);
void SetDeviceState(DeviceState state);
void Alert(const std::string& title, const std::string& message);
void Alert(const std::string& status, const std::string& message, const std::string& emotion = "", const std::string& sound = "");
void AbortSpeaking(AbortReason reason);
void ToggleChatState();
void StartListening();
void StopListening();
void UpdateIotStates();
void Reboot();
private:
Application();
@@ -100,7 +102,7 @@ private:
void ResetDecoder();
void SetDecodeSampleRate(int sample_rate);
void CheckNewVersion();
void DisplayActivationCode();
void ShowActivationCode();
void PlayLocalFile(const char* data, size_t size);
};
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.
+39
View File
@@ -0,0 +1,39 @@
#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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4 -1
View File
@@ -20,7 +20,10 @@ BackgroundTask::~BackgroundTask() {
void BackgroundTask::Schedule(std::function<void()> callback) {
std::lock_guard<std::mutex> lock(mutex_);
if (active_tasks_ >= 30) {
ESP_LOGW(TAG, "active_tasks_ == %u", active_tasks_.load());
int free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
if (free_sram < 10000) {
ESP_LOGW(TAG, "active_tasks_ == %u, free_sram == %u", active_tasks_.load(), free_sram);
}
}
active_tasks_++;
main_tasks_.emplace_back([this, cb = std::move(callback)]() {
+4 -3
View File
@@ -3,6 +3,7 @@
#include "application.h"
#include "display.h"
#include "font_awesome_symbols.h"
#include "assets/zh/binary.h"
#include <esp_log.h>
#include <esp_timer.h>
@@ -24,7 +25,7 @@ std::string Ml307Board::GetBoardType() {
void Ml307Board::StartNetwork() {
auto display = Board::GetInstance().GetDisplay();
display->SetStatus("初始化模块");
display->SetStatus("检测模组...");
modem_.SetDebug(false);
modem_.SetBaudRate(921600);
@@ -47,10 +48,10 @@ void Ml307Board::WaitForNetworkReady() {
display->SetStatus("等待网络...");
int result = modem_.WaitForNetworkReady();
if (result == -1) {
application.Alert("Error", "请插入SIM卡");
application.Alert("PIN_ERROR", "请插入SIM卡", "sad", std::string(p3_err_pin_start, p3_err_pin_end - p3_err_pin_start));
return;
} else if (result == -2) {
application.Alert("Error", "无法接入网络,请检查流量卡状态");
application.Alert("REG_ERROR", "无法接入网络,请检查流量卡状态", "sad", std::string(p3_err_reg_start, p3_err_reg_end - p3_err_reg_start));
return;
}
+4 -6
View File
@@ -5,6 +5,7 @@
#include "system_info.h"
#include "font_awesome_symbols.h"
#include "settings.h"
#include "assets/zh/binary.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
@@ -37,7 +38,6 @@ std::string WifiBoard::GetBoardType() {
void WifiBoard::EnterWifiConfigMode() {
auto& application = Application::GetInstance();
auto display = Board::GetInstance().GetDisplay();
application.SetDeviceState(kDeviceStateWifiConfiguring);
auto& wifi_ap = WifiConfigurationAp::GetInstance();
@@ -50,10 +50,8 @@ void WifiBoard::EnterWifiConfigMode() {
hint += ",然后打开浏览器访问 ";
hint += wifi_ap.GetWebServerUrl();
display->SetStatus(hint);
// 播报配置 WiFi 的提示
application.Alert("Info", "进入配网模式");
application.Alert("配网模式", hint, "", std::string(p3_wificonfig_start, p3_wificonfig_end - p3_wificonfig_start));
// Wait forever until reset after configuration
while (true) {
@@ -83,11 +81,11 @@ void WifiBoard::StartNetwork() {
auto& wifi_station = WifiStation::GetInstance();
wifi_station.OnScanBegin([this]() {
auto display = Board::GetInstance().GetDisplay();
display->ShowNotification("正在扫描 WiFi 网络", 30000);
display->ShowNotification("扫描 WiFi...", 30000);
});
wifi_station.OnConnect([this](const std::string& ssid) {
auto display = Board::GetInstance().GetDisplay();
display->ShowNotification(std::string("正在连接 ") + ssid, 30000);
display->ShowNotification(std::string("连接 ") + ssid + "...", 30000);
});
wifi_station.OnConnected([this](const std::string& ssid) {
auto display = Board::GetInstance().GetDisplay();
+5
View File
@@ -210,6 +210,11 @@ void Display::SetIcon(const char* icon) {
}
void Display::SetChatMessage(const std::string &role, const std::string &content) {
DisplayLockGuard lock(this);
if (chat_message_label_ == nullptr) {
return;
}
lv_label_set_text(chat_message_label_, content.c_str());
}
void Display::SetBacklight(uint8_t brightness) {
+1
View File
@@ -42,6 +42,7 @@ protected:
lv_obj_t *notification_label_ = nullptr;
lv_obj_t *mute_label_ = nullptr;
lv_obj_t *battery_label_ = nullptr;
lv_obj_t* chat_message_label_ = nullptr;
const char* battery_icon_ = nullptr;
const char* network_icon_ = nullptr;
bool muted_ = false;
-8
View File
@@ -274,14 +274,6 @@ void LcdDisplay::SetupUI() {
lv_obj_set_style_text_font(battery_label_, fonts_.icon_font, 0);
}
void LcdDisplay::SetChatMessage(const std::string &role, const std::string &content) {
DisplayLockGuard lock(this);
if (chat_message_label_ == nullptr) {
return;
}
lv_label_set_text(chat_message_label_, content.c_str());
}
void LcdDisplay::SetEmotion(const std::string &emotion) {
struct Emotion {
const char* icon;
-2
View File
@@ -26,7 +26,6 @@ protected:
lv_obj_t* content_ = nullptr;
lv_obj_t* container_ = nullptr;
lv_obj_t* side_bar_ = nullptr;
lv_obj_t* chat_message_label_ = nullptr;
DisplayFonts fonts_;
@@ -46,7 +45,6 @@ public:
DisplayFonts fonts);
~LcdDisplay();
virtual void SetChatMessage(const std::string &role, const std::string &content) override;
virtual void SetEmotion(const std::string &emotion) override;
virtual void SetIcon(const char* icon) override;
virtual void SetBacklight(uint8_t brightness) override;
+53 -11
View File
@@ -132,6 +132,20 @@ void Ssd1306Display::Unlock() {
lvgl_port_unlock();
}
void Ssd1306Display::SetChatMessage(const std::string &role, const std::string &content) {
DisplayLockGuard lock(this);
if (content_right_ == nullptr) {
lv_label_set_text(chat_message_label_, content.c_str());
} else {
if (content.empty()) {
lv_obj_add_flag(content_right_, LV_OBJ_FLAG_HIDDEN);
} else {
lv_label_set_text(chat_message_label_, content.c_str());
lv_obj_clear_flag(content_right_, LV_OBJ_FLAG_HIDDEN);
}
}
}
void Ssd1306Display::SetupUI_128x64() {
DisplayLockGuard lock(this);
@@ -149,20 +163,46 @@ void Ssd1306Display::SetupUI_128x64() {
/* Status bar */
status_bar_ = lv_obj_create(container_);
lv_obj_set_size(status_bar_, LV_HOR_RES, 18);
lv_obj_set_size(status_bar_, LV_HOR_RES, 16);
lv_obj_set_style_border_width(status_bar_, 0, 0);
lv_obj_set_style_pad_all(status_bar_, 0, 0);
lv_obj_set_style_radius(status_bar_, 0, 0);
/* Content */
content_ = lv_obj_create(container_);
lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF);
lv_obj_set_style_radius(status_bar_, 0, 0);
lv_obj_set_style_radius(content_, 0, 0);
lv_obj_set_style_pad_all(content_, 0, 0);
lv_obj_set_width(content_, LV_HOR_RES);
lv_obj_set_flex_grow(content_, 1);
lv_obj_set_flex_flow(content_, LV_FLEX_FLOW_ROW);
lv_obj_set_style_flex_main_place(content_, LV_FLEX_ALIGN_CENTER, 0);
emotion_label_ = lv_label_create(content_);
// 创建左侧固定宽度的容器
content_left_ = lv_obj_create(content_);
lv_obj_set_size(content_left_, 32, LV_SIZE_CONTENT); // 固定宽度32像素
lv_obj_set_style_pad_all(content_left_, 0, 0);
lv_obj_set_style_border_width(content_left_, 0, 0);
emotion_label_ = lv_label_create(content_left_);
lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_1, 0);
lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP);
lv_obj_center(emotion_label_);
lv_obj_set_style_pad_top(emotion_label_, 8, 0);
// 创建右侧可扩展的容器
content_right_ = lv_obj_create(content_);
lv_obj_set_size(content_right_, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(content_right_, 0, 0);
lv_obj_set_style_border_width(content_right_, 0, 0);
lv_obj_set_flex_grow(content_right_, 1);
lv_obj_add_flag(content_right_, LV_OBJ_FLAG_HIDDEN);
chat_message_label_ = lv_label_create(content_right_);
lv_label_set_text(chat_message_label_, "");
lv_label_set_long_mode(chat_message_label_, LV_LABEL_LONG_WRAP);
lv_obj_set_width(chat_message_label_, lv_pct(100));
lv_obj_set_style_text_align(chat_message_label_, LV_TEXT_ALIGN_LEFT, 0);
/* Status bar */
lv_obj_set_flex_flow(status_bar_, LV_FLEX_FLOW_ROW);
@@ -250,17 +290,19 @@ void Ssd1306Display::SetupUI_128x32() {
lv_label_set_text(battery_label_, "");
lv_obj_set_style_text_font(battery_label_, icon_font_, 0);
status_label_ = lv_label_create(side_bar_);
lv_obj_set_flex_grow(status_label_, 1);
lv_obj_set_width(status_label_, width_ - 32);
lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
status_label_ = lv_label_create(status_bar_);
lv_obj_set_style_pad_left(status_label_, 2, 0);
lv_label_set_text(status_label_, "正在初始化");
notification_label_ = lv_label_create(side_bar_);
lv_obj_set_flex_grow(notification_label_, 1);
lv_obj_set_width(notification_label_, width_ - 32);
lv_label_set_long_mode(notification_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
notification_label_ = lv_label_create(status_bar_);
lv_label_set_text(notification_label_, "通知");
lv_obj_set_style_pad_left(notification_label_, 2, 0);
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
chat_message_label_ = lv_label_create(side_bar_);
lv_obj_set_flex_grow(chat_message_label_, 1);
lv_obj_set_width(chat_message_label_, width_ - 32);
lv_label_set_long_mode(chat_message_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_label_set_text(chat_message_label_, "");
}
+4
View File
@@ -13,6 +13,8 @@ private:
lv_obj_t* status_bar_ = nullptr;
lv_obj_t* content_ = nullptr;
lv_obj_t* content_left_ = nullptr;
lv_obj_t* content_right_ = nullptr;
lv_obj_t* container_ = nullptr;
lv_obj_t* side_bar_ = nullptr;
@@ -29,6 +31,8 @@ public:
Ssd1306Display(void* i2c_master_handle, int width, int height, bool mirror_x, bool mirror_y,
const lv_font_t* text_font, const lv_font_t* icon_font);
~Ssd1306Display();
virtual void SetChatMessage(const std::string &role, const std::string &content);
};
#endif // SSD1306_DISPLAY_H
+6 -1
View File
@@ -211,8 +211,13 @@ void CircularStrip::OnStateChanged() {
Blink(color, 100);
break;
}
case kDeviceStateActivating: {
StripColor color = { LOW_BRIGHTNESS, DEFAULT_BRIGHTNESS, LOW_BRIGHTNESS };
Blink(color, 500);
break;
}
default:
ESP_LOGE(TAG, "Invalid led strip event: %d", device_state);
ESP_LOGW(TAG, "Unknown led strip event: %d", device_state);
return;
}
}
+5 -1
View File
@@ -151,8 +151,12 @@ void SingleLed::OnStateChanged() {
SetColor(0, DEFAULT_BRIGHTNESS, 0);
StartContinuousBlink(100);
break;
case kDeviceStateActivating:
SetColor(0, DEFAULT_BRIGHTNESS, 0);
StartContinuousBlink(500);
break;
default:
ESP_LOGE(TAG, "Invalid led strip event: %d", device_state);
ESP_LOGW(TAG, "Unknown led strip event: %d", device_state);
return;
}
}
+2
View File
@@ -71,6 +71,7 @@ bool Ota::CheckVersion() {
return false;
}
has_activation_code_ = false;
cJSON *activation = cJSON_GetObjectItem(root, "activation");
if (activation != NULL) {
cJSON* message = cJSON_GetObjectItem(activation, "message");
@@ -84,6 +85,7 @@ bool Ota::CheckVersion() {
has_activation_code_ = true;
}
has_mqtt_config_ = false;
cJSON *mqtt = cJSON_GetObjectItem(root, "mqtt");
if (mqtt != NULL) {
Settings settings("mqtt", true);
+1 -5
View File
@@ -10,8 +10,6 @@
#define TAG "WS"
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
WebsocketProtocol::WebsocketProtocol() {
event_group_handle_ = xEventGroupCreate();
}
@@ -61,7 +59,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_->SetHeader("Client-Id", Board::GetInstance().GetUuid().c_str());
websocket_->OnData([this](const char* data, size_t len, bool binary) {
if (binary) {
@@ -147,5 +145,3 @@ void WebsocketProtocol::ParseServerHello(const cJSON* root) {
xEventGroupSetBits(event_group_handle_, WEBSOCKET_PROTOCOL_SERVER_HELLO_EVENT);
}
#endif