1. 完成了ota功能的基本测试,测试通过

2. 封装了一个模板线程类,支持创建来自单例类的成员函数线程,普通类的线程,普通函数线程
3. 封装了一个Wifi模块类,支持Wifi的各种基本配置
This commit is contained in:
Misaki
2025-09-05 01:09:12 +08:00
parent 5d79f88918
commit 28ceb0caf5
24 changed files with 824 additions and 91 deletions
+87
View File
@@ -0,0 +1,87 @@
//
// Created by misaki on 2025/9/4.
//
#include "app_ota.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "freertos/task.h"
static const char *TAG = "app_ota";
#define DEFAULT_VERSION "0.0.1"
/* 本地版本号,编译时可由构建系统注入 */
#ifndef APP_FW_VERSION
#define APP_FW_VERSION DEFAULT_VERSION
#endif
static const char s_version[] = APP_FW_VERSION;
const char *app_ota_current_version(void)
{
return s_version;
}
/* 简单版本号比较:a.b.c 字符串比较即可 */
static bool need_update(const char *server_ver)
{
if (!server_ver) return false;
return strcmp(server_ver, s_version) > 0;
}
/* HTTP 事件回调,仅打印进度 */
static esp_err_t http_evt(esp_http_client_event_t *evt)
{
switch (evt->event_id) {
case HTTP_EVENT_ON_DATA:
/* 数据流直接走 OTA,这里不打印 */
break;
default:
break;
}
return ESP_OK;
}
static void ota_task(void *pv)
{
char url[256];
strncpy(url, (const char *)pv, sizeof(url) - 1);
url[sizeof(url) - 1] = '\0';
ESP_LOGI(TAG, "开始 OTAURL=%s", url);
esp_http_client_config_t http_cfg = {
.url = url,
.event_handler = http_evt,
.keep_alive_enable = true,
// 如用 https,把 cert_pem 打开即可
// .cert_pem = (const char *)server_cert_pem_start,
};
esp_https_ota_config_t ota_cfg = {
.http_config = &http_cfg,
};
/* 执行升级 */
esp_err_t ret = esp_https_ota(&ota_cfg);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "OTA 完成,准备重启");
esp_restart();
} else {
ESP_LOGE(TAG, "OTA 失败,err=%s", esp_err_to_name(ret));
}
vTaskDelete(NULL);
}
esp_err_t app_ota_start(const char *url)
{
if (!url) return ESP_ERR_INVALID_ARG;
/* 内部建 Task,栈 8 KB */
BaseType_t ok = xTaskCreate(ota_task, "ota_task", 8192, (void *)url, 5, NULL);
return ok == pdPASS ? ESP_OK : ESP_FAIL;
}
+13
View File
@@ -0,0 +1,13 @@
//
// Created by misaki on 2025/9/4.
//
#pragma once
#include "esp_err.h"
/* 一键启动 OTA(阻塞,内部建 Task) */
esp_err_t app_ota_start(const char *url);
/* 获取当前运行版本号(返回静态指针) */
const char *app_ota_current_version(void);
+97
View File
@@ -0,0 +1,97 @@
//
// Created by misaki on 2025/9/4.
//
#include "ota_ws.h"
#include "esp_log.h"
#include "esp_websocket_client.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "cJSON.h"
#include "esp_system.h"
#include "esp_mac.h"
static const char *TAG = "OTA_WS";
#define FW_VERSION "1.0.1" // ←每次发布修改这里
#define WS_URL_FMT "ws://%s:%d/ws?mac=%02X%02X%02X%02X%02X%02X"
static esp_websocket_client_handle_t ws = NULL;
static void ota_start(const char *url)
{
esp_http_client_config_t config = {
.url = url,
.keep_alive_enable = true,
};
esp_https_ota_config_t ota_cfg = { .http_config = &config };
ESP_LOGI(TAG, "开始下载固件...");
esp_err_t ret = esp_https_ota(&ota_cfg);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "下载完成,重启");
esp_restart();
} else {
ESP_LOGE(TAG, "OTA 失败:%s", esp_err_to_name(ret));
}
}
static void ws_event(void *arg, esp_event_base_t base, int32_t id, void *data)
{
esp_websocket_event_data_t *d = (esp_websocket_event_data_t *)data;
switch (id) {
case WEBSOCKET_EVENT_CONNECTED:
ESP_LOGI(TAG, "WebSocket 已连接");
break;
case WEBSOCKET_EVENT_DATA:
if (d->op_code == WS_TRANSPORT_OPCODES_TEXT) {
char *json = malloc(d->data_len + 1);
if (!json) break;
memcpy(json, d->data_ptr, d->data_len);
json[d->data_len] = 0;
cJSON *root = cJSON_Parse(json);
free(json);
if (root) {
cJSON *cmd = cJSON_GetObjectItem(root, "cmd");
if (cmd && strcmp(cmd->valuestring, "upgrade") == 0) {
const char *url = cJSON_GetObjectItem(root, "url")->valuestring;
ESP_LOGI(TAG, "收到升级指令,URL=%s", url);
ota_start(url);
}
cJSON_Delete(root);
}
}
break;
case WEBSOCKET_EVENT_DISCONNECTED:
ESP_LOGW(TAG, "WS 断开,5 秒后重连...");
vTaskDelay(pdMS_TO_TICKS(5000));
esp_websocket_client_start(ws);
break;
default:
break;
}
}
esp_err_t ota_ws_start(const char *server_ip, uint16_t port)
{
if (ws) return ESP_OK;
uint8_t mac[6];
esp_efuse_mac_get_default(mac);
char uri[128];
snprintf(uri, sizeof(uri), WS_URL_FMT,
server_ip, port, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
esp_websocket_client_config_t cfg = {
.uri = uri,
.ping_interval_sec = 30,
};
ws = esp_websocket_client_init(&cfg);
esp_websocket_register_events(ws, WEBSOCKET_EVENT_ANY, ws_event, NULL);
esp_websocket_client_start(ws);
return ESP_OK;
}
+23
View File
@@ -0,0 +1,23 @@
//
// Created by misaki on 2025/9/4.
//
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
/**
* @brief 启动 WebSocket 长连接,接收服务器推送的升级指令
* @param server_ip 服务器 IP 字符串,如 "192.168.1.100"
* @return esp_err_t
*/
esp_err_t ota_ws_start(const char *server_ip, uint16_t port);
#ifdef __cplusplus
}
#endif