feat: bridge_server livekit
This commit is contained in:
123
main/ota.cc
123
main/ota.cc
@ -1,30 +1,29 @@
|
||||
#include "ota.h"
|
||||
#include "system_info.h"
|
||||
#include "settings.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "settings.h"
|
||||
#include "system_info.h"
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <cJSON.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_partition.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <esp_app_format.h>
|
||||
#include <esp_efuse.h>
|
||||
#include <esp_efuse_table.h>
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <esp_partition.h>
|
||||
#include <cJSON.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#ifdef SOC_HMAC_SUPPORTED
|
||||
#include <esp_hmac.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#define TAG "Ota"
|
||||
|
||||
|
||||
Ota::Ota() {
|
||||
#ifdef ESP_EFUSE_BLOCK_USR_DATA
|
||||
// Read Serial Number from efuse user_data
|
||||
@ -40,8 +39,7 @@ Ota::Ota() {
|
||||
#endif
|
||||
}
|
||||
|
||||
Ota::~Ota() {
|
||||
}
|
||||
Ota::~Ota() {}
|
||||
|
||||
std::string Ota::GetCheckVersionUrl() {
|
||||
Settings settings("wifi", false);
|
||||
@ -62,7 +60,8 @@ std::unique_ptr<Http> Ota::SetupHttp() {
|
||||
http->SetHeader("Client-Id", board.GetUuid());
|
||||
if (has_serial_number_) {
|
||||
http->SetHeader("Serial-Number", serial_number_.c_str());
|
||||
ESP_LOGI(TAG, "Setup HTTP, User-Agent: %s, Serial-Number: %s", user_agent.c_str(), serial_number_.c_str());
|
||||
ESP_LOGI(TAG, "Setup HTTP, User-Agent: %s, Serial-Number: %s", user_agent.c_str(),
|
||||
serial_number_.c_str());
|
||||
}
|
||||
http->SetHeader("User-Agent", user_agent);
|
||||
http->SetHeader("Accept-Language", Lang::CODE);
|
||||
@ -71,7 +70,7 @@ std::unique_ptr<Http> Ota::SetupHttp() {
|
||||
return http;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Specification: https://ccnphfhqs21z.feishu.cn/wiki/FjW6wZmisimNBBkov6OcmfvknVd
|
||||
*/
|
||||
esp_err_t Ota::CheckVersion() {
|
||||
@ -112,8 +111,8 @@ esp_err_t Ota::CheckVersion() {
|
||||
// Response: { "firmware": { "version": "1.0.0", "url": "http://" } }
|
||||
// Parse the JSON response and check if the version is newer
|
||||
// If it is, set has_new_version_ to true and store the new version and URL
|
||||
|
||||
cJSON *root = cJSON_Parse(data.c_str());
|
||||
|
||||
cJSON* root = cJSON_Parse(data.c_str());
|
||||
if (root == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to parse JSON response");
|
||||
return ESP_ERR_INVALID_RESPONSE;
|
||||
@ -121,7 +120,7 @@ esp_err_t Ota::CheckVersion() {
|
||||
|
||||
has_activation_code_ = false;
|
||||
has_activation_challenge_ = false;
|
||||
cJSON *activation = cJSON_GetObjectItem(root, "activation");
|
||||
cJSON* activation = cJSON_GetObjectItem(root, "activation");
|
||||
if (cJSON_IsObject(activation)) {
|
||||
cJSON* message = cJSON_GetObjectItem(activation, "message");
|
||||
if (cJSON_IsString(message)) {
|
||||
@ -144,11 +143,11 @@ esp_err_t Ota::CheckVersion() {
|
||||
}
|
||||
|
||||
has_mqtt_config_ = false;
|
||||
cJSON *mqtt = cJSON_GetObjectItem(root, "mqtt");
|
||||
cJSON* mqtt = cJSON_GetObjectItem(root, "mqtt");
|
||||
if (cJSON_IsObject(mqtt)) {
|
||||
Settings settings("mqtt", true);
|
||||
cJSON *item = NULL;
|
||||
cJSON_ArrayForEach(item, mqtt) {
|
||||
cJSON* item = NULL;
|
||||
cJSON_ArrayForEach (item, mqtt) {
|
||||
if (cJSON_IsString(item)) {
|
||||
if (settings.GetString(item->string) != item->valuestring) {
|
||||
settings.SetString(item->string, item->valuestring);
|
||||
@ -159,17 +158,17 @@ esp_err_t Ota::CheckVersion() {
|
||||
}
|
||||
}
|
||||
}
|
||||
has_mqtt_config_ = true;
|
||||
has_mqtt_config_ = false;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "No mqtt section found !");
|
||||
}
|
||||
|
||||
has_websocket_config_ = false;
|
||||
cJSON *websocket = cJSON_GetObjectItem(root, "websocket");
|
||||
cJSON* websocket = cJSON_GetObjectItem(root, "websocket");
|
||||
if (cJSON_IsObject(websocket)) {
|
||||
Settings settings("websocket", true);
|
||||
cJSON *item = NULL;
|
||||
cJSON_ArrayForEach(item, websocket) {
|
||||
cJSON* item = NULL;
|
||||
cJSON_ArrayForEach (item, websocket) {
|
||||
if (cJSON_IsString(item)) {
|
||||
if (settings.GetString(item->string) != item->valuestring) {
|
||||
settings.SetString(item->string, item->valuestring);
|
||||
@ -185,23 +184,28 @@ esp_err_t Ota::CheckVersion() {
|
||||
ESP_LOGI(TAG, "No websocket section found!");
|
||||
}
|
||||
|
||||
has_server_time_ = false;
|
||||
cJSON *server_time = cJSON_GetObjectItem(root, "server_time");
|
||||
// [开发调试] 强制修改 WebSocket URL 指向本地 Bridge 服务
|
||||
// 请将下面的 IP 地址修改为你电脑的局域网 IP (例如 192.168.1.5)
|
||||
Settings settings("websocket", true);
|
||||
settings.SetString("url", "ws://10.6.80.130:8080");
|
||||
has_websocket_config_ = true;
|
||||
|
||||
cJSON* server_time = cJSON_GetObjectItem(root, "server_time");
|
||||
if (cJSON_IsObject(server_time)) {
|
||||
cJSON *timestamp = cJSON_GetObjectItem(server_time, "timestamp");
|
||||
cJSON *timezone_offset = cJSON_GetObjectItem(server_time, "timezone_offset");
|
||||
|
||||
cJSON* timestamp = cJSON_GetObjectItem(server_time, "timestamp");
|
||||
cJSON* timezone_offset = cJSON_GetObjectItem(server_time, "timezone_offset");
|
||||
|
||||
if (cJSON_IsNumber(timestamp)) {
|
||||
// 设置系统时间
|
||||
struct timeval tv;
|
||||
double ts = timestamp->valuedouble;
|
||||
|
||||
|
||||
// 如果有时区偏移,计算本地时间
|
||||
if (cJSON_IsNumber(timezone_offset)) {
|
||||
ts += (timezone_offset->valueint * 60 * 1000); // 转换分钟为毫秒
|
||||
ts += (timezone_offset->valueint * 60 * 1000); // 转换分钟为毫秒
|
||||
}
|
||||
|
||||
tv.tv_sec = (time_t)(ts / 1000); // 转换毫秒为秒
|
||||
|
||||
tv.tv_sec = (time_t)(ts / 1000); // 转换毫秒为秒
|
||||
tv.tv_usec = (suseconds_t)((long long)ts % 1000) * 1000; // 剩余的毫秒转换为微秒
|
||||
settimeofday(&tv, NULL);
|
||||
has_server_time_ = true;
|
||||
@ -211,13 +215,13 @@ esp_err_t Ota::CheckVersion() {
|
||||
}
|
||||
|
||||
has_new_version_ = false;
|
||||
cJSON *firmware = cJSON_GetObjectItem(root, "firmware");
|
||||
cJSON* firmware = cJSON_GetObjectItem(root, "firmware");
|
||||
if (cJSON_IsObject(firmware)) {
|
||||
cJSON *version = cJSON_GetObjectItem(firmware, "version");
|
||||
cJSON* version = cJSON_GetObjectItem(firmware, "version");
|
||||
if (cJSON_IsString(version)) {
|
||||
firmware_version_ = version->valuestring;
|
||||
}
|
||||
cJSON *url = cJSON_GetObjectItem(firmware, "url");
|
||||
cJSON* url = cJSON_GetObjectItem(firmware, "url");
|
||||
if (cJSON_IsString(url)) {
|
||||
firmware_url_ = url->valuestring;
|
||||
}
|
||||
@ -231,7 +235,7 @@ esp_err_t Ota::CheckVersion() {
|
||||
ESP_LOGI(TAG, "Current is the latest version");
|
||||
}
|
||||
// If the force flag is set to 1, the given version is forced to be installed
|
||||
cJSON *force = cJSON_GetObjectItem(firmware, "force");
|
||||
cJSON* force = cJSON_GetObjectItem(firmware, "force");
|
||||
if (cJSON_IsNumber(force) && force->valueint == 1) {
|
||||
has_new_version_ = true;
|
||||
}
|
||||
@ -264,7 +268,8 @@ void Ota::MarkCurrentVersionValid() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Ota::Upgrade(const std::string& firmware_url, std::function<void(int progress, size_t speed)> callback) {
|
||||
bool Ota::Upgrade(const std::string& firmware_url,
|
||||
std::function<void(int progress, size_t speed)> callback) {
|
||||
ESP_LOGI(TAG, "Upgrading firmware from %s", firmware_url.c_str());
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
auto update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
@ -273,7 +278,8 @@ bool Ota::Upgrade(const std::string& firmware_url, std::function<void(int progre
|
||||
return false;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Writing to partition %s at offset 0x%lx", update_partition->label, update_partition->address);
|
||||
ESP_LOGI(TAG, "Writing to partition %s at offset 0x%lx", update_partition->label,
|
||||
update_partition->address);
|
||||
bool image_header_checked = false;
|
||||
std::string image_header;
|
||||
|
||||
@ -319,7 +325,8 @@ bool Ota::Upgrade(const std::string& firmware_url, std::function<void(int progre
|
||||
buffer_offset += ret;
|
||||
if (esp_timer_get_time() - last_calc_time >= 1000000 || ret == 0) {
|
||||
size_t progress = total_read * 100 / content_length;
|
||||
ESP_LOGI(TAG, "Progress: %u%% (%u/%u), Speed: %uB/s", progress, total_read, content_length, recent_read);
|
||||
ESP_LOGI(TAG, "Progress: %u%% (%u/%u), Speed: %uB/s", progress, total_read,
|
||||
content_length, recent_read);
|
||||
if (callback) {
|
||||
callback(progress, recent_read);
|
||||
}
|
||||
@ -329,9 +336,14 @@ bool Ota::Upgrade(const std::string& firmware_url, std::function<void(int progre
|
||||
|
||||
if (!image_header_checked) {
|
||||
image_header.append(buffer, buffer_offset);
|
||||
if (image_header.size() >= sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
|
||||
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));
|
||||
memcpy(&new_app_info,
|
||||
image_header.data() + sizeof(esp_image_header_t) +
|
||||
sizeof(esp_image_segment_header_t),
|
||||
sizeof(esp_app_desc_t));
|
||||
|
||||
if (esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle)) {
|
||||
esp_ota_abort(update_handle);
|
||||
@ -390,23 +402,22 @@ bool Ota::StartUpgrade(std::function<void(int progress, size_t speed)> callback)
|
||||
return Upgrade(firmware_url_, callback);
|
||||
}
|
||||
|
||||
|
||||
std::vector<int> Ota::ParseVersion(const std::string& version) {
|
||||
std::vector<int> versionNumbers;
|
||||
std::stringstream ss(version);
|
||||
std::string segment;
|
||||
|
||||
|
||||
while (std::getline(ss, segment, '.')) {
|
||||
versionNumbers.push_back(std::stoi(segment));
|
||||
}
|
||||
|
||||
|
||||
return versionNumbers;
|
||||
}
|
||||
|
||||
bool Ota::IsNewVersionAvailable(const std::string& currentVersion, const std::string& newVersion) {
|
||||
std::vector<int> current = ParseVersion(currentVersion);
|
||||
std::vector<int> newer = ParseVersion(newVersion);
|
||||
|
||||
|
||||
for (size_t i = 0; i < std::min(current.size(), newer.size()); ++i) {
|
||||
if (newer[i] > current[i]) {
|
||||
return true;
|
||||
@ -414,7 +425,7 @@ bool Ota::IsNewVersionAvailable(const std::string& currentVersion, const std::st
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return newer.size() > current.size();
|
||||
}
|
||||
|
||||
@ -425,10 +436,11 @@ std::string Ota::GetActivationPayload() {
|
||||
|
||||
std::string hmac_hex;
|
||||
#ifdef SOC_HMAC_SUPPORTED
|
||||
uint8_t hmac_result[32]; // SHA-256 输出为32字节
|
||||
|
||||
uint8_t hmac_result[32]; // SHA-256 输出为32字节
|
||||
|
||||
// 使用Key0计算HMAC
|
||||
esp_err_t ret = esp_hmac_calculate(HMAC_KEY0, (uint8_t*)activation_challenge_.data(), activation_challenge_.size(), hmac_result);
|
||||
esp_err_t ret = esp_hmac_calculate(HMAC_KEY0, (uint8_t*)activation_challenge_.data(),
|
||||
activation_challenge_.size(), hmac_result);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "HMAC calculation failed: %s", esp_err_to_name(ret));
|
||||
return "{}";
|
||||
@ -441,7 +453,7 @@ std::string Ota::GetActivationPayload() {
|
||||
}
|
||||
#endif
|
||||
|
||||
cJSON *payload = cJSON_CreateObject();
|
||||
cJSON* payload = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(payload, "algorithm", "hmac-sha256");
|
||||
cJSON_AddStringToObject(payload, "serial_number", serial_number_.c_str());
|
||||
cJSON_AddStringToObject(payload, "challenge", activation_challenge_.c_str());
|
||||
@ -477,13 +489,14 @@ esp_err_t Ota::Activate() {
|
||||
ESP_LOGE(TAG, "Failed to open HTTP connection");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
auto status_code = http->GetStatusCode();
|
||||
if (status_code == 202) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
if (status_code != 200) {
|
||||
ESP_LOGE(TAG, "Failed to activate, code: %d, body: %s", status_code, http->ReadAll().c_str());
|
||||
ESP_LOGE(TAG, "Failed to activate, code: %d, body: %s", status_code,
|
||||
http->ReadAll().c_str());
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user