forked from xiaozhi/xiaozhi-esp32
feat: add manual upgrade firmware
This commit is contained in:
@@ -164,43 +164,10 @@ void Application::CheckNewVersion(Ota& ota) {
|
||||
retry_delay = 10; // 重置重试延迟时间
|
||||
|
||||
if (ota.HasNewVersion()) {
|
||||
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "download", Lang::Sounds::OGG_UPGRADE);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
|
||||
SetDeviceState(kDeviceStateUpgrading);
|
||||
|
||||
std::string message = std::string(Lang::Strings::NEW_VERSION) + ota.GetFirmwareVersion();
|
||||
display->SetChatMessage("system", message.c_str());
|
||||
|
||||
board.SetPowerSaveMode(false);
|
||||
audio_service_.Stop();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
bool upgrade_success = ota.StartUpgrade([display](int progress, size_t speed) {
|
||||
std::thread([display, progress, speed]() {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%d%% %uKB/s", progress, speed / 1024);
|
||||
display->SetChatMessage("system", buffer);
|
||||
}).detach();
|
||||
});
|
||||
|
||||
if (!upgrade_success) {
|
||||
// Upgrade failed, restart audio service and continue running
|
||||
ESP_LOGE(TAG, "Firmware upgrade failed, restarting audio service and continuing operation...");
|
||||
audio_service_.Start(); // Restart audio service
|
||||
board.SetPowerSaveMode(true); // Restore power save mode
|
||||
Alert(Lang::Strings::ERROR, Lang::Strings::UPGRADE_FAILED, "circle_xmark", Lang::Sounds::OGG_EXCLAMATION);
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
// Continue to normal operation (don't break, just fall through)
|
||||
} else {
|
||||
// Upgrade success, reboot immediately
|
||||
ESP_LOGI(TAG, "Firmware upgrade successful, rebooting...");
|
||||
display->SetChatMessage("system", "Upgrade successful, rebooting...");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000)); // Brief pause to show message
|
||||
Reboot();
|
||||
if (UpgradeFirmware(ota)) {
|
||||
return; // This line will never be reached after reboot
|
||||
}
|
||||
// If upgrade failed, continue to normal operation (don't break, just fall through)
|
||||
}
|
||||
|
||||
// No new version, mark the current version as valid
|
||||
@@ -768,9 +735,64 @@ void Application::Reboot() {
|
||||
}
|
||||
protocol_.reset();
|
||||
audio_service_.Stop();
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
bool Application::UpgradeFirmware(Ota& ota, const std::string& url) {
|
||||
auto& board = Board::GetInstance();
|
||||
auto display = board.GetDisplay();
|
||||
|
||||
// Use provided URL or get from OTA object
|
||||
std::string upgrade_url = url.empty() ? ota.GetFirmwareUrl() : url;
|
||||
std::string version_info = url.empty() ? ota.GetFirmwareVersion() : "(Manual upgrade)";
|
||||
|
||||
// Close audio channel if it's open
|
||||
if (protocol_ && protocol_->IsAudioChannelOpened()) {
|
||||
ESP_LOGI(TAG, "Closing audio channel before firmware upgrade");
|
||||
protocol_->CloseAudioChannel();
|
||||
}
|
||||
ESP_LOGI(TAG, "Starting firmware upgrade from URL: %s", upgrade_url.c_str());
|
||||
|
||||
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "download", Lang::Sounds::OGG_UPGRADE);
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
|
||||
SetDeviceState(kDeviceStateUpgrading);
|
||||
|
||||
std::string message = std::string(Lang::Strings::NEW_VERSION) + version_info;
|
||||
display->SetChatMessage("system", message.c_str());
|
||||
|
||||
board.SetPowerSaveMode(false);
|
||||
audio_service_.Stop();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
bool upgrade_success = ota.StartUpgradeFromUrl(upgrade_url, [display](int progress, size_t speed) {
|
||||
std::thread([display, progress, speed]() {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%d%% %uKB/s", progress, speed / 1024);
|
||||
display->SetChatMessage("system", buffer);
|
||||
}).detach();
|
||||
});
|
||||
|
||||
if (!upgrade_success) {
|
||||
// Upgrade failed, restart audio service and continue running
|
||||
ESP_LOGE(TAG, "Firmware upgrade failed, restarting audio service and continuing operation...");
|
||||
audio_service_.Start(); // Restart audio service
|
||||
board.SetPowerSaveMode(true); // Restore power save mode
|
||||
Alert(Lang::Strings::ERROR, Lang::Strings::UPGRADE_FAILED, "circle_xmark", Lang::Sounds::OGG_EXCLAMATION);
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
return false;
|
||||
} else {
|
||||
// Upgrade success, reboot immediately
|
||||
ESP_LOGI(TAG, "Firmware upgrade successful, rebooting...");
|
||||
display->SetChatMessage("system", "Upgrade successful, rebooting...");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000)); // Brief pause to show message
|
||||
Reboot();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Application::WakeWordInvoke(const std::string& wake_word) {
|
||||
if (device_state_ == kDeviceStateIdle) {
|
||||
ToggleChatState();
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
void StopListening();
|
||||
void Reboot();
|
||||
void WakeWordInvoke(const std::string& wake_word);
|
||||
bool UpgradeFirmware(Ota& ota, const std::string& url = "");
|
||||
bool CanEnterSleepMode();
|
||||
void SendMcpMessage(const std::string& payload);
|
||||
void SetAecMode(AecMode mode);
|
||||
|
||||
@@ -161,8 +161,12 @@ bool Assets::Apply() {
|
||||
ESP_LOGE(TAG, "Failed to load fonts.bin");
|
||||
return false;
|
||||
}
|
||||
light_theme->set_text_font(text_font);
|
||||
dark_theme->set_text_font(text_font);
|
||||
if (light_theme != nullptr) {
|
||||
light_theme->set_text_font(text_font);
|
||||
}
|
||||
if (dark_theme != nullptr) {
|
||||
dark_theme->set_text_font(text_font);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "The font file %s is not found", fonts_text_file.c_str());
|
||||
}
|
||||
@@ -186,14 +190,18 @@ bool Assets::Apply() {
|
||||
}
|
||||
}
|
||||
}
|
||||
light_theme->set_emoji_collection(custom_emoji_collection);
|
||||
dark_theme->set_emoji_collection(custom_emoji_collection);
|
||||
if (light_theme != nullptr) {
|
||||
light_theme->set_emoji_collection(custom_emoji_collection);
|
||||
}
|
||||
if (dark_theme != nullptr) {
|
||||
dark_theme->set_emoji_collection(custom_emoji_collection);
|
||||
}
|
||||
}
|
||||
|
||||
cJSON* skin = cJSON_GetObjectItem(root, "skin");
|
||||
if (cJSON_IsObject(skin)) {
|
||||
cJSON* light_skin = cJSON_GetObjectItem(skin, "light");
|
||||
if (cJSON_IsObject(light_skin)) {
|
||||
if (cJSON_IsObject(light_skin) && light_theme != nullptr) {
|
||||
cJSON* text_color = cJSON_GetObjectItem(light_skin, "text_color");
|
||||
cJSON* background_color = cJSON_GetObjectItem(light_skin, "background_color");
|
||||
cJSON* background_image = cJSON_GetObjectItem(light_skin, "background_image");
|
||||
@@ -214,7 +222,7 @@ bool Assets::Apply() {
|
||||
}
|
||||
}
|
||||
cJSON* dark_skin = cJSON_GetObjectItem(skin, "dark");
|
||||
if (cJSON_IsObject(dark_skin)) {
|
||||
if (cJSON_IsObject(dark_skin) && dark_theme != nullptr) {
|
||||
cJSON* text_color = cJSON_GetObjectItem(dark_skin, "text_color");
|
||||
cJSON* background_color = cJSON_GetObjectItem(dark_skin, "background_color");
|
||||
cJSON* background_image = cJSON_GetObjectItem(dark_skin, "background_image");
|
||||
@@ -239,7 +247,11 @@ bool Assets::Apply() {
|
||||
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
ESP_LOGI(TAG, "Refreshing display theme...");
|
||||
display->SetTheme(display->GetTheme());
|
||||
|
||||
auto current_theme = display->GetTheme();
|
||||
if (current_theme != nullptr) {
|
||||
display->SetTheme(current_theme);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
return true;
|
||||
}
|
||||
@@ -253,7 +265,6 @@ bool Assets::Download(std::string url, std::function<void(int progress, size_t s
|
||||
mmap_handle_ = 0;
|
||||
mmap_root_ = nullptr;
|
||||
}
|
||||
partition_valid_ = false;
|
||||
checksum_valid_ = false;
|
||||
assets_.clear();
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "oled_display.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "lvgl_theme.h"
|
||||
#include "lvgl_font.h"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
@@ -20,8 +22,19 @@ OledDisplay::OledDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handl
|
||||
: panel_io_(panel_io), panel_(panel) {
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
text_font_ = &LVGL_TEXT_FONT;
|
||||
icon_font_ = &LVGL_ICON_FONT;
|
||||
|
||||
auto text_font = std::make_shared<LvglBuiltInFont>(&LVGL_TEXT_FONT);
|
||||
auto icon_font = std::make_shared<LvglBuiltInFont>(&LVGL_ICON_FONT);
|
||||
auto large_icon_font = std::make_shared<LvglBuiltInFont>(&font_awesome_30_1);
|
||||
|
||||
auto dark_theme = new LvglTheme("dark");
|
||||
dark_theme->set_text_font(text_font);
|
||||
dark_theme->set_icon_font(icon_font);
|
||||
dark_theme->set_large_icon_font(large_icon_font);
|
||||
|
||||
auto& theme_manager = LvglThemeManager::GetInstance();
|
||||
theme_manager.RegisterTheme("dark", dark_theme);
|
||||
current_theme_ = dark_theme;
|
||||
|
||||
ESP_LOGI(TAG, "Initialize LVGL");
|
||||
lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
@@ -123,8 +136,13 @@ void OledDisplay::SetChatMessage(const char* role, const char* content) {
|
||||
void OledDisplay::SetupUI_128x64() {
|
||||
DisplayLockGuard lock(this);
|
||||
|
||||
auto lvgl_theme = static_cast<LvglTheme*>(current_theme_);
|
||||
auto text_font = lvgl_theme->text_font()->font();
|
||||
auto icon_font = lvgl_theme->icon_font()->font();
|
||||
auto large_icon_font = lvgl_theme->large_icon_font()->font();
|
||||
|
||||
auto screen = lv_screen_active();
|
||||
lv_obj_set_style_text_font(screen, text_font_, 0);
|
||||
lv_obj_set_style_text_font(screen, text_font, 0);
|
||||
lv_obj_set_style_text_color(screen, lv_color_black(), 0);
|
||||
|
||||
/* Container */
|
||||
@@ -159,7 +177,7 @@ void OledDisplay::SetupUI_128x64() {
|
||||
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_obj_set_style_text_font(emotion_label_, large_icon_font, 0);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_MICROCHIP_AI);
|
||||
lv_obj_center(emotion_label_);
|
||||
lv_obj_set_style_pad_top(emotion_label_, 8, 0);
|
||||
@@ -195,7 +213,7 @@ void OledDisplay::SetupUI_128x64() {
|
||||
|
||||
network_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(network_label_, "");
|
||||
lv_obj_set_style_text_font(network_label_, icon_font_, 0);
|
||||
lv_obj_set_style_text_font(network_label_, icon_font, 0);
|
||||
|
||||
notification_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_flex_grow(notification_label_, 1);
|
||||
@@ -210,15 +228,15 @@ void OledDisplay::SetupUI_128x64() {
|
||||
|
||||
mute_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(mute_label_, "");
|
||||
lv_obj_set_style_text_font(mute_label_, icon_font_, 0);
|
||||
lv_obj_set_style_text_font(mute_label_, icon_font, 0);
|
||||
|
||||
battery_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(battery_label_, "");
|
||||
lv_obj_set_style_text_font(battery_label_, icon_font_, 0);
|
||||
lv_obj_set_style_text_font(battery_label_, icon_font, 0);
|
||||
|
||||
low_battery_popup_ = lv_obj_create(screen);
|
||||
lv_obj_set_scrollbar_mode(low_battery_popup_, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_obj_set_size(low_battery_popup_, LV_HOR_RES * 0.9, text_font_->line_height * 2);
|
||||
lv_obj_set_size(low_battery_popup_, LV_HOR_RES * 0.9, text_font->line_height * 2);
|
||||
lv_obj_align(low_battery_popup_, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||
lv_obj_set_style_bg_color(low_battery_popup_, lv_color_black(), 0);
|
||||
lv_obj_set_style_radius(low_battery_popup_, 10, 0);
|
||||
@@ -232,8 +250,13 @@ void OledDisplay::SetupUI_128x64() {
|
||||
void OledDisplay::SetupUI_128x32() {
|
||||
DisplayLockGuard lock(this);
|
||||
|
||||
auto lvgl_theme = static_cast<LvglTheme*>(current_theme_);
|
||||
auto text_font = lvgl_theme->text_font()->font();
|
||||
auto icon_font = lvgl_theme->icon_font()->font();
|
||||
auto large_icon_font = lvgl_theme->large_icon_font()->font();
|
||||
|
||||
auto screen = lv_screen_active();
|
||||
lv_obj_set_style_text_font(screen, text_font_, 0);
|
||||
lv_obj_set_style_text_font(screen, text_font, 0);
|
||||
|
||||
/* Container */
|
||||
container_ = lv_obj_create(screen);
|
||||
@@ -251,7 +274,7 @@ void OledDisplay::SetupUI_128x32() {
|
||||
lv_obj_set_style_radius(content_, 0, 0);
|
||||
|
||||
emotion_label_ = lv_label_create(content_);
|
||||
lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_1, 0);
|
||||
lv_obj_set_style_text_font(emotion_label_, large_icon_font, 0);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_MICROCHIP_AI);
|
||||
lv_obj_center(emotion_label_);
|
||||
|
||||
@@ -286,15 +309,15 @@ void OledDisplay::SetupUI_128x32() {
|
||||
|
||||
mute_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(mute_label_, "");
|
||||
lv_obj_set_style_text_font(mute_label_, icon_font_, 0);
|
||||
lv_obj_set_style_text_font(mute_label_, icon_font, 0);
|
||||
|
||||
network_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(network_label_, "");
|
||||
lv_obj_set_style_text_font(network_label_, icon_font_, 0);
|
||||
lv_obj_set_style_text_font(network_label_, icon_font, 0);
|
||||
|
||||
battery_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(battery_label_, "");
|
||||
lv_obj_set_style_text_font(battery_label_, icon_font_, 0);
|
||||
lv_obj_set_style_text_font(battery_label_, icon_font, 0);
|
||||
|
||||
chat_message_label_ = lv_label_create(side_bar_);
|
||||
lv_obj_set_size(chat_message_label_, width_ - 32, LV_SIZE_CONTENT);
|
||||
@@ -323,3 +346,13 @@ void OledDisplay::SetEmotion(const char* emotion) {
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_NEUTRAL);
|
||||
}
|
||||
}
|
||||
|
||||
void OledDisplay::SetTheme(Theme* theme) {
|
||||
DisplayLockGuard lock(this);
|
||||
|
||||
auto lvgl_theme = static_cast<LvglTheme*>(theme);
|
||||
auto text_font = lvgl_theme->text_font()->font();
|
||||
|
||||
auto screen = lv_screen_active();
|
||||
lv_obj_set_style_text_font(screen, text_font, 0);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ private:
|
||||
lv_obj_t* side_bar_ = nullptr;
|
||||
lv_obj_t *emotion_label_ = nullptr;
|
||||
lv_obj_t* chat_message_label_ = nullptr;
|
||||
const lv_font_t* text_font_ = nullptr;
|
||||
const lv_font_t* icon_font_ = nullptr;
|
||||
|
||||
virtual bool Lock(int timeout_ms = 0) override;
|
||||
virtual void Unlock() override;
|
||||
@@ -35,6 +33,7 @@ public:
|
||||
|
||||
virtual void SetChatMessage(const char* role, const char* content) override;
|
||||
virtual void SetEmotion(const char* emotion) override;
|
||||
virtual void SetTheme(Theme* theme) override;
|
||||
};
|
||||
|
||||
#endif // OLED_DISPLAY_H
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "application.h"
|
||||
#include "display.h"
|
||||
#include "oled_display.h"
|
||||
#include "board.h"
|
||||
#include "settings.h"
|
||||
#include "lvgl_theme.h"
|
||||
@@ -136,12 +137,36 @@ void McpServer::AddUserOnlyTools() {
|
||||
AddUserOnlyTool("self.reboot", "Reboot the system",
|
||||
PropertyList(),
|
||||
[this](const PropertyList& properties) -> ReturnValue {
|
||||
std::thread([]() {
|
||||
auto& app = Application::GetInstance();
|
||||
app.Schedule([]() {
|
||||
ESP_LOGW(TAG, "User requested reboot");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
auto& app = Application::GetInstance();
|
||||
app.Reboot();
|
||||
}).detach();
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
// Firmware upgrade
|
||||
AddUserOnlyTool("self.upgrade_firmware", "Upgrade firmware from a specific URL. This will download and install the firmware, then reboot the device.",
|
||||
PropertyList({
|
||||
Property("url", kPropertyTypeString, "The URL of the firmware binary file to download and install")
|
||||
}),
|
||||
[this](const PropertyList& properties) -> ReturnValue {
|
||||
auto url = properties["url"].value<std::string>();
|
||||
ESP_LOGI(TAG, "User requested firmware upgrade from URL: %s", url.c_str());
|
||||
|
||||
auto& app = Application::GetInstance();
|
||||
app.Schedule([url]() {
|
||||
auto& app = Application::GetInstance();
|
||||
auto ota = std::make_unique<Ota>();
|
||||
|
||||
bool success = app.UpgradeFirmware(*ota, url);
|
||||
if (!success) {
|
||||
ESP_LOGE(TAG, "Firmware upgrade failed");
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -155,6 +180,11 @@ void McpServer::AddUserOnlyTools() {
|
||||
cJSON *json = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(json, "width", display->width());
|
||||
cJSON_AddNumberToObject(json, "height", display->height());
|
||||
if (dynamic_cast<OledDisplay*>(display)) {
|
||||
cJSON_AddBoolToObject(json, "monochrome", true);
|
||||
} else {
|
||||
cJSON_AddBoolToObject(json, "monochrome", false);
|
||||
}
|
||||
return json;
|
||||
});
|
||||
|
||||
|
||||
13
main/ota.cc
13
main/ota.cc
@@ -325,13 +325,9 @@ bool Ota::Upgrade(const std::string& firmware_url) {
|
||||
if (image_header.size() >= sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
|
||||
esp_app_desc_t new_app_info;
|
||||
memcpy(&new_app_info, image_header.data() + sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t), sizeof(esp_app_desc_t));
|
||||
ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);
|
||||
|
||||
|
||||
auto current_version = esp_app_get_description()->version;
|
||||
if (memcmp(new_app_info.version, current_version, sizeof(new_app_info.version)) == 0) {
|
||||
ESP_LOGE(TAG, "Firmware version is the same, skipping upgrade");
|
||||
return false;
|
||||
}
|
||||
ESP_LOGI(TAG, "Current version: %s, New version: %s", current_version, new_app_info.version);
|
||||
|
||||
if (esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle)) {
|
||||
esp_ota_abort(update_handle);
|
||||
@@ -377,6 +373,11 @@ bool Ota::StartUpgrade(std::function<void(int progress, size_t speed)> callback)
|
||||
return Upgrade(firmware_url_);
|
||||
}
|
||||
|
||||
bool Ota::StartUpgradeFromUrl(const std::string& url, std::function<void(int progress, size_t speed)> callback) {
|
||||
upgrade_callback_ = callback;
|
||||
return Upgrade(url);
|
||||
}
|
||||
|
||||
std::vector<int> Ota::ParseVersion(const std::string& version) {
|
||||
std::vector<int> versionNumbers;
|
||||
std::stringstream ss(version);
|
||||
|
||||
@@ -21,10 +21,12 @@ public:
|
||||
bool HasActivationCode() { return has_activation_code_; }
|
||||
bool HasServerTime() { return has_server_time_; }
|
||||
bool StartUpgrade(std::function<void(int progress, size_t speed)> callback);
|
||||
bool StartUpgradeFromUrl(const std::string& url, std::function<void(int progress, size_t speed)> callback);
|
||||
void MarkCurrentVersionValid();
|
||||
|
||||
const std::string& GetFirmwareVersion() const { return firmware_version_; }
|
||||
const std::string& GetCurrentVersion() const { return current_version_; }
|
||||
const std::string& GetFirmwareUrl() const { return firmware_url_; }
|
||||
const std::string& GetActivationMessage() const { return activation_message_; }
|
||||
const std::string& GetActivationCode() const { return activation_code_; }
|
||||
std::string GetCheckVersionUrl();
|
||||
|
||||
@@ -36,6 +36,10 @@ MqttProtocol::~MqttProtocol() {
|
||||
esp_timer_stop(reconnect_timer_);
|
||||
esp_timer_delete(reconnect_timer_);
|
||||
}
|
||||
|
||||
udp_.reset();
|
||||
mqtt_.reset();
|
||||
|
||||
if (event_group_handle_ != nullptr) {
|
||||
vEventGroupDelete(event_group_handle_);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user