ESP32学习笔记(基于IDF):基于OneNet的ESP32的OTA功能

目录

前言

本文是基于ESP32学习笔记(基于IDF):ESP32接入OneNET该片文章的延续,继成功接入OneNet后基于OneNet进行OTA的功能

一、相关知识

1、OTA框架

2、OTA分区

3、APP镜像

4、OTA流程

5、订阅、回复OTA升级通知消息格式

咱的ESP32需要订阅OneNet平台的升级topic,当需要升级时,平台会下发升级通知

这个是我们收到OneNet平台的升级通知后,设备进行应答回复的消息格式

6、MQTT协议和HTTP协议

HTTP :是为互联网内容(如网页、API)设计的请求-响应协议。

MQTT :是为物联网设备设计的发布-订阅协议。

特性 MQTT HTTP
通信模型 发布-订阅 请求-响应
工作方式 客户端连接到代理,订阅感兴趣的主题。当有客户端向该主题发布消息时,代理会将消息推送给所有订阅者。 客户端主动向服务器发起请求,服务器处理请求后返回一个响应。通信总是由客户端发起。
连接关系 多对多,通过代理解耦。发布者和订阅者不需要知道彼此的存在。 一对一,紧密耦合。客户端必须知道服务器的确切地址。

二、代码编写、操作流程

1、新建这两个文件,在里面写有关OTA的代码
2、在根目录的CMakeLists.txt文件下写入该语句,用来确认当前工程的版本

bash 复制代码
set(PROJECT_VER "1.0.0")

这样在编译的时候,构建系统就会把这个字符串(版本号)写入esp_app_desc_t这个结构体

3、启用APP的回滚功能,就是OTA后如果发现这个新程序不好使,则会自动返回运行OTA前的程序

在工程目录下,输入以下指令,开启工程配置

bash 复制代码
idf.py menuconfig

然后进到这个Bootloader 配置

然后启用这个APP回滚功能

4、在onenet_ota.c文件下写入如下代码

c 复制代码
#include "esp_ota_ops.h"   //引入 ESP32 OTA相关操作库
#include <stdio.h>
#include "esp_http_client.h"
#include "onenet_token.h"
#include "onenet_mqtt.h"
#include <string.h>
#include "cJSON.h"
#include "esp_https_ota.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

#define TAG  "onenet_ota"

#define TOKEN_VALID_TIMESTAMP   1791515811                //时间有效期

#define ONENET_OTA_URL    "http://iot-api.heclouds.com/fuse-ota"

static char target_version[32] = {0};
static int task_id = 0;
static bool ota_is_running = false;

const char* get_app_version()
{
    // 静态缓冲区,用于存储版本号(仅初始化一次,避免重复分配内存)
    static char app_version[32] = {0};
    // 如果缓冲区未初始化(首次调用),则读取版本信息
    if(app_version[0] == 0)
    {
        // 获取当前正在运行的固件分区(OTA 中可能有多个固件分区,这里定位当前激活的分区)
        const esp_partition_t * running = esp_ota_get_running_partition();
          // 存储固件描述信息的结构体(包含版本号、编译时间等)
        esp_app_desc_t app_desc;
        // 从当前运行的分区中读取固件描述信息(包括 version 字段)
        esp_ota_get_partition_description(running,&app_desc);
          // 将固件版本号(app_desc.version)复制到缓冲区中
        snprintf(app_version,sizeof(app_version),"%s",app_desc.version);
    }
    return app_version;
}

void set_app_valid(int valid)
{
     // 获取当前正在运行的固件分区
    const esp_partition_t * running = esp_ota_get_running_partition();
    esp_ota_img_states_t state; // 存储当前固件的状态(如:待验证、有效、无效等)
    // 获取当前固件分区的状态(检查是否处于"待验证"状态)
    if(esp_ota_get_state_partition(running,&state) == ESP_OK)
    {
        // 仅当固件处于"待验证"状态时,才执行标记操作
        // (OTA 升级后,新固件首次启动时会处于此状态,等待确认)
        if(state == ESP_OTA_IMG_PENDING_VERIFY)
        {
            if(valid)
            {
                 // 标记当前固件为有效,取消回滚(确认升级成功)
                esp_ota_mark_app_valid_cancel_rollback();
            }
            else
            {
                // 标记当前固件为无效,触发回滚到上一版本并重启(升级失败)
                esp_ota_mark_app_invalid_rollback_and_reboot();
            }
        }

    }
}

#define OTA_BUFF_LEN  1024
static uint8_t ota_data_buff[OTA_BUFF_LEN];
static int ota_data_size = 0;

esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    switch(evt->event_id) {
        case HTTP_EVENT_ERROR:
            ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
            break;
        case HTTP_EVENT_ON_DATA:
        {
            ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
            printf("HTTP_EVENT_ON_DATA data=%.*s\r\n",evt->data_len,(char*)evt->data);
            int copy_len = 0;
            if(evt->data_len > OTA_BUFF_LEN - ota_data_size)
            {
                copy_len = OTA_BUFF_LEN - ota_data_size;
            }
            else
            {
                copy_len = evt->data_len;
            }
            memcpy(&ota_data_buff,evt->data,copy_len);
            ota_data_size += copy_len;
            break;
        }
            break;
        case HTTP_EVENT_ON_FINISH:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
            break;
        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
            break;
        case HTTP_EVENT_REDIRECT:
            ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
            break;
        default:break;
    }
    return ESP_OK;
}



static esp_err_t onenet_ota_http_connect(const char *url,esp_http_client_method_t method,const char* payload)
{
    esp_http_client_config_t config = {
        .url = url,
        .event_handler = _http_event_handler,
    };
    esp_http_client_handle_t client = esp_http_client_init(&config);

    char *token = (char*)malloc(256);
    memset(token,0,256);
    dev_token_generate(token,SIG_METHOD_SHA256,TOKEN_VALID_TIMESTAMP,ONENET_PRODUCT_ID,NULL,ONENET_PRODUCT_ACCESS_KEY);
    ESP_LOGI(TAG,"ota token:%s",token);
    // POST
    esp_http_client_set_method(client, method);
    esp_http_client_set_header(client, "Content-Type", "application/json");
    esp_http_client_set_header(client,"host","iot-api.heclouds.com");
    esp_http_client_set_header(client,"Authorization",token);
    if(payload)
    {
        ESP_LOGI(TAG,"post data:%s",payload);
        esp_http_client_set_post_field(client, payload, strlen(payload));
    }
    memset(ota_data_buff,0,sizeof(ota_data_buff));
    ota_data_size = 0;
    esp_err_t err = esp_http_client_perform(client);
    free(token);
    esp_http_client_cleanup(client);
    return err;
}

//检测升级任务
esp_err_t onenet_ota_check_task(const char* type,const char* version)
{
    char url[128];
    esp_err_t ret = ESP_FAIL;
    snprintf(url,256,ONENET_OTA_URL"/%s/%s/check?type=%s&version=%s",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME,type,version);
    if(ESP_OK == onenet_ota_http_connect(url,HTTP_METHOD_GET,NULL))
    {
        cJSON *root = cJSON_Parse((const char*)ota_data_buff);
        if(root)
        {
            cJSON* code_js = cJSON_GetObjectItem(root,"code");
            cJSON* data_js = cJSON_GetObjectItem(root,"data");
            cJSON* target_js = cJSON_GetObjectItem(data_js,"target");
            cJSON* tid_js = cJSON_GetObjectItem(data_js,"tid");
            if(code_js && cJSON_GetNumberValue(code_js) == 0)
            {
                if(target_js && tid_js)
                {
                    snprintf(target_version,sizeof(target_version),"%s",cJSON_GetStringValue(target_js));
                    task_id = cJSON_GetNumberValue(tid_js);
                    ret = ESP_OK;
                }
                
            }
            else
            {
                ESP_LOGI(TAG,"check ota task invalid code");
            }
            cJSON_Delete(root);
        }
    }
    return ret;
}


//上报版本号给OneNet
esp_err_t onenet_ota_upload_version(void)
{
    char url[128];
    char version_info[128];
    esp_err_t ret = ESP_FAIL;
    const char* version = get_app_version();
    snprintf(version_info,sizeof(version_info),"{\"s_version\":\"%s\", \"f_version\": \"%s\"}",version,version);
    snprintf(url,256,ONENET_OTA_URL"/%s/%s/version",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME);
    if(ESP_OK == onenet_ota_http_connect(url,HTTP_METHOD_POST,version_info))
    {
        cJSON *root = cJSON_Parse((const char*)ota_data_buff);
        if(root)
        {
            cJSON* code_js = cJSON_GetObjectItem(root,"code");
            if(code_js && cJSON_GetNumberValue(code_js) == 0)
            {
                ret = ESP_OK;
            }
            cJSON_Delete(root);
        }
    }
    else
    {
        ESP_LOGI(TAG,"Upload version fail!");
        return ret;
    }
    return ret;
}


//上报固件下载进度
esp_err_t onenet_ota_upload_status(int tid,int step)
{
    char url[128];
    char payload[16];
    esp_err_t ret = ESP_FAIL;
    snprintf(url,sizeof(url),ONENET_OTA_URL"/%s/%s/%d/status",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME,tid);
    snprintf(payload,sizeof(payload),"{\"step\":%d} ",step);
    if(ESP_OK == onenet_ota_http_connect(url,HTTP_METHOD_POST,payload))
    {
        cJSON *root = cJSON_Parse((const char*)ota_data_buff);
        if(root)
        {
            cJSON* code_js = cJSON_GetObjectItem(root,"code");
            if(code_js && cJSON_GetNumberValue(code_js) == 0)
            {
                ret = ESP_OK;
            }
            cJSON_Delete(root);
        }
    }
    if(ret != ESP_OK)
    {
        ESP_LOGI(TAG,"Upload task status fail!");
    }
    return ret;
}


esp_err_t onenet_ota_init_cb(esp_http_client_handle_t client)
{
    static char token[256];
    memset(token,0,256);
    dev_token_generate(token,SIG_METHOD_SHA256,TOKEN_VALID_TIMESTAMP,ONENET_PRODUCT_ID,NULL,ONENET_PRODUCT_ACCESS_KEY);
    // POST
    esp_http_client_set_method(client, HTTP_METHOD_GET);
    esp_http_client_set_header(client, "Content-Type", "application/json");
    esp_http_client_set_header(client,"host","iot-api.heclouds.com");
    esp_http_client_set_header(client,"Authorization",token);
    return ESP_OK;
}

//下载固件
esp_err_t onenet_ota_download(int tid)
{
    char url[128];
    snprintf(url,sizeof(url),"http://iot-api.heclouds.com/fuse-ota/%s/%s/%d/download",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME,tid);
    esp_http_client_config_t http_cfg = 
    {
        .url = url,
    }; 
    esp_https_ota_config_t ota_cfg = 
    {
        .http_config = &http_cfg,
        .http_client_init_cb = onenet_ota_init_cb,
    };
    esp_err_t ota_ret = ESP_FAIL;
    ota_ret = esp_https_ota(&ota_cfg);
    if(ota_ret == ESP_OK)
    {
        ESP_LOGI(TAG,"Upgrade successful...");
    }
    else
    {
        ESP_LOGI(TAG,"Upgrade fail! Code:%d",ota_ret);
    }
    return ota_ret;
}

static void onenet_ota_task(void* param)
{
    esp_err_t ret = ESP_FAIL;
    //上报版本号
    ret = onenet_ota_upload_version();
    if(ret != ESP_OK)
    {
        ESP_LOGE(TAG,"Upload version fail!");
        goto delete_ota_task;
    }
    //检测升级任务
    ret = onenet_ota_check_task("1",get_app_version());
        if(ret != ESP_OK)
    {
        ESP_LOGE(TAG,"Check task fail!");
        goto delete_ota_task;
    }
    //上报任务升级状态 10%
    ret = onenet_ota_upload_status(task_id,10);
        if(ret != ESP_OK)
    {
        ESP_LOGE(TAG,"Upload status fail!");
        goto delete_ota_task;
    }
    //进行HTTP下载
    ret = onenet_ota_download(task_id);
        if(ret != ESP_OK)
    {
        ESP_LOGE(TAG,"download fail!");
        goto delete_ota_task;
    }
    //上报任务升级状态 100%
    ret = onenet_ota_upload_status(task_id,100);
        if(ret != ESP_OK)
    {
        ESP_LOGE(TAG,"Upload status fail!");
        goto delete_ota_task;
    }
    //重启
    esp_restart();
delete_ota_task:
    ota_is_running = false;
    vTaskDelete(NULL);
}

void onenet_ota_start(void)
{
    if(ota_is_running)
    {
        return;
    }
    ota_is_running = true;
    ESP_LOGI(TAG,"Start OTA");
    xTaskCreatePinnedToCore(onenet_ota_task,"onenet_ota",8192,NULL,2,NULL,0);
}

5、在onenet_ota.h文件下,写入如下代码

c 复制代码
#ifndef _ONENET_OTA_H_
#define _ONENET_OTA_H_
#include "esp_err.h"

const char* get_app_version(void);

void set_app_valid(int valid);

esp_err_t onenet_ota_upload_version(void);

void onenet_ota_start(void);

#endif

6、在onenet_mqtt.c文件下写入如下代码

c 复制代码
#include "onenet_mqtt.h"
#include "onenet_token.h"
#include "mqtt_client.h"
#include "esp_log.h"
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "cJSON.h"
#include "onenet_dm.h"
#include "onenet_ota.h"

#define TAG "onenet"

static esp_mqtt_client_handle_t mqtt_handle = NULL;

static void onenet_property_ack(const char* id,int code,const char* msg);

static void onenet_ota_ack(const char* id, int code, const char* msg);

static void onenet_subscribe(void);

static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    esp_mqtt_event_handle_t event = event_data;
    switch ((esp_mqtt_event_id_t)event_id) {
    case MQTT_EVENT_CONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
        onenet_subscribe();
        cJSON* property_js = onenet_property_upload();
        char* data = cJSON_PrintUnformatted(property_js);
        onenet_post_property_data(data);
        onenet_ota_upload_version();//上报版本号
        set_app_valid(true);   //设置当前程序是合法的
        cJSON_free(data);
        cJSON_Delete(property_js);
        break;
    case MQTT_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
        break;

    case MQTT_EVENT_SUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_UNSUBSCRIBED:
        ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_PUBLISHED:
        ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
        break;
    case MQTT_EVENT_DATA:
        ESP_LOGI(TAG, "MQTT_EVENT_DATA");
        printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
        printf("DATA=%.*s\r\n", event->data_len, event->data);
        if(strstr(event->topic,"property/set"))
        {
            cJSON* property = cJSON_Parse(event->data);
            cJSON* id_js = cJSON_GetObjectItem(property,"id");
            onenet_property_handle(property);
            onenet_property_ack(cJSON_GetStringValue(id_js),200,"success");
            cJSON_Delete(property);
        }
        else if(strstr(event->topic,"ota/inform"))
        {
            cJSON* ota_js = cJSON_Parse(event->data);
            cJSON* id_js = cJSON_GetObjectItem(ota_js,"id");

            onenet_ota_ack(cJSON_GetStringValue(id_js),200,"success");
            cJSON_Delete(ota_js);

            //开始OTA升级流程
            onenet_ota_start();
        }
        break;
    case MQTT_EVENT_ERROR:
        ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
        break;
    default:
        ESP_LOGI(TAG, "Other event id:%d", event->event_id);
        break;
    }
}
  
esp_err_t onenet_start(void)
{
    esp_mqtt_client_config_t mqtt_config;
    memset(&mqtt_config,0,sizeof(esp_mqtt_client_config_t));
    mqtt_config.broker.address.uri = "mqtt://mqtts.heclouds.com";
    mqtt_config.broker.address.port = 1883;

    mqtt_config.credentials.client_id = ONENET_DEVICE_NAME;
    mqtt_config.credentials.username = ONENET_PRODUCT_ID;
       
    static char token[256];
    dev_token_generate(token,SIG_METHOD_SHA256,2232933411,ONENET_PRODUCT_ID,NULL,ONENET_PRODUCT_ACCESS_KEY);
    mqtt_config.credentials.authentication.password = token;
    //将鉴权信息打印出来
    ESP_LOGI(TAG,"onenet connect->clientId:%s,username:%s,password:%s",
        mqtt_config.credentials.client_id,mqtt_config.credentials.username,
        mqtt_config.credentials.authentication.password);
    mqtt_handle = esp_mqtt_client_init(&mqtt_config);
    esp_mqtt_client_register_event(mqtt_handle,ESP_EVENT_ANY_ID,mqtt_event_handler,NULL);
    return esp_mqtt_client_start(mqtt_handle);
}

static void onenet_property_ack(const char* id, int code, const char* msg)
{
    char topic[128];
    snprintf(topic,128,"$sys/%s/%s/thing/property/set_reply",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME);
    cJSON* reply_js = cJSON_CreateObject();
    cJSON_AddStringToObject(reply_js,"id",id);
    cJSON_AddNumberToObject(reply_js,"code",code);
    cJSON_AddStringToObject(reply_js,"msg",msg);
    char* data = cJSON_PrintUnformatted(reply_js);
    esp_mqtt_client_publish(mqtt_handle,topic,data,strlen(data),1,0);
    cJSON_free(data);
    cJSON_Delete(reply_js);
}


static void onenet_ota_ack(const char* id, int code, const char* msg)
{
    char topic[128];
    snprintf(topic,128,"$sys/%s/%s/thing/ota/inform_reply",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME);
    cJSON* reply_js = cJSON_CreateObject();
    cJSON_AddStringToObject(reply_js,"id",id);
    cJSON_AddNumberToObject(reply_js,"code",code);
    cJSON_AddStringToObject(reply_js,"msg",msg);
    char* data = cJSON_PrintUnformatted(reply_js);
    esp_mqtt_client_publish(mqtt_handle,topic,data,strlen(data),1,0);
    cJSON_free(data);
    cJSON_Delete(reply_js);
}



static void onenet_subscribe(void)
{
    char topic[128];
    sniprintf(topic,128,"$sys/%s/%s/thing/property/post/reply",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME);
    esp_mqtt_client_subscribe_single(mqtt_handle,topic,1);
    //订阅属性设置主题
    sniprintf(topic,128,"$sys/%s/%s/thing/property/set",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME);
    esp_mqtt_client_subscribe_single(mqtt_handle,topic,1);
    //订阅OTA升级通知主题
    sniprintf(topic,128,"$sys/%s/%s/ota/inform",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME);
    esp_mqtt_client_subscribe_single(mqtt_handle,topic,1);
}

esp_err_t onenet_post_property_data(const char* data)
{
    char topic[128];
    snprintf(topic,128,"$sys/%s/%s/thing/property/post",ONENET_PRODUCT_ID,ONENET_DEVICE_NAME);
    ESP_LOGI(TAG,"Upload topic:%s,payload:%s",topic,data);
    return esp_mqtt_client_publish(mqtt_handle,topic,data,strlen(data),1,0);
}

7、在onenet_mqtt.h文件下写入如下代码

c 复制代码
#ifndef _ONENET_MQTT_H_
#define _ONENET_MQTT_H_
#include "esp_err.h"

//产品ID
#define ONENET_PRODUCT_ID            "E3Sgq5fGjC"  
//产品密钥
#define ONENET_PRODUCT_ACCESS_KEY    "a82bv2/LWRePdSfT+cmRDw2Jt+8bl3NZJxOxbdN3O6M="
//设备名称                  
#define ONENET_DEVICE_NAME           "esp32led01"

esp_err_t onenet_start(void);

esp_err_t onenet_post_property_data(const char* data);

#endif

8、在onenet.c文件下写入如下代码

c 复制代码
#include <stdio.h>
#include "onenet_mqtt.h"
#include "wifi_manager.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "onenet_dm.h"
#include "esp_log.h"

static EventGroupHandle_t wifi_ev = NULL;
#define WIFI_CONNECT_BIT   BIT0
#define TAG "app_main"
/**
 * wifi事件回调函数
 * @param ev wifi事件
 * @return 无
 */
static void wifi_state_callback(WIFI_STATE state)
{
    if(state == WIFI_STATE_CONNECTED)
    {
        xEventGroupSetBits(wifi_ev,WIFI_CONNECT_BIT);
    }
}

void app_main(void)
{
    esp_err_t ret;

        // 1. 初始化 NVS 闪存(必须处理返回值!)
    ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        // NVS 分区满了或版本不兼容,尝试擦除后重新初始化
        ESP_LOGE(TAG, "NVS init failed, try to erase...");
        ret = nvs_flash_erase();
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "NVS erase failed: %s", esp_err_to_name(ret));
            return; // 无法修复,直接退出
        }
        ret = nvs_flash_init(); // 重新初始化
    }
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "NVS init failed: %s", esp_err_to_name(ret));
        return; // NVS 初始化失败,无法继续
    }
    ESP_LOGI(TAG, "NVS init success");

    // 2. 创建事件组(用于同步 Wi-Fi 连接状态)
    // 事件组是 FreeRTOS 提供的同步机制,这里用于标记 Wi-Fi 是否连接成功
    wifi_ev = xEventGroupCreate();
    // 3. 初始化 Wi-Fi 管理器,并注册状态回调函数
    // wifi_manager_init:初始化 Wi-Fi 相关资源(如配置 Wi-Fi 模式、注册事件处理等)
    // wifi_state_callback:自定义回调函数,用于接收 Wi-Fi 连接/断开等状态通知
    onenet_dm_init();
    wifi_manager_init(wifi_state_callback);
    // 4. 调用 Wi-Fi 管理器连接指定的 Wi-Fi 热点
    // 参数:Wi-Fi 热点名称(SSID)为 "Lymow",密码为 "1415926535"
    wifi_manager_connect("Lymow","1415926535");//连接的WIFI用户名跟密码
    EventBits_t ev;
    while(1)
    {
        //等待WIFI连接成功,然后才开始连接onenet
        ev = xEventGroupWaitBits(wifi_ev,WIFI_CONNECT_BIT,pdTRUE,pdFALSE,pdMS_TO_TICKS(10*1000));
        if(ev & WIFI_CONNECT_BIT)
        {
            // Wi-Fi 已就绪,启动 OneNet 平台连接(如 MQTT 连接)
            onenet_start();
        }
    }
}

9、输入以下指令进入配置菜单

10、在这个路径下,选择第三个选项,一个出厂默认固件+两个OTA分区

11、在这个路径下,打开HTTP之中OTA的功能,不过正式产品的开发不能用HTTP来OTA,得用HTTPS,因为HTTP是不加密的,很危险,这个只能用来在本地测试OTA流程是否跑通

12、flash这里选择4M,因为我的C3芯片模组的FLAH最大是4M

13、主频选择160M,根据自己的芯片选择最大即可

14、在CMakeLists文件下写入如下代码

bash 复制代码
idf_component_register(SRCS "iot/onenet_dm.c" "iot/onenet_token.c" "iot/wifi_manager.c" "iot/onenet_mqtt.c" "iot/onenet_ota.c" "onenet.c"
                    INCLUDE_DIRS "." "iot")

15、在终端,使用以下指令对工程进行编译

bash 复制代码
idf.py build

16、编译成功

17、使用以下指令把程序下载进板子,并打开监控

bash 复制代码
idf.py flash monitor

18、可以看到程序跑起来了,上报版本号之后,OneNet平台进行了回复

19、我们把软件版本改成1.0.1,然后重新编译一个固件

20、我们在OneNet平台点击添加升级包

21、这里填一下,然后上传固件

22、点这个验证升级

23、这里填一下,然后开始验证

24、升级成功

25、可以看到平台这边也显示验证成功了

相关推荐
Smartdaili China2 小时前
掌握Java网页抓取:技术与示例完整指南
java·网络·学习·指南·网页·住宅ip·爬虫api
自不量力的A同学2 小时前
OpenNJet v3.3.1.3
笔记
charlie1145141913 小时前
如何快速在 VS2026 上使用 C++ 模块 — 完整上手指南
开发语言·c++·笔记·学习·现代c++
可信计算4 小时前
【算法随想】一种基于“视觉表征图”拓扑变化的NLP序列预测新范式
人工智能·笔记·python·算法·自然语言处理
历程里程碑4 小时前
C++ 9 stack_queue:数据结构的核心奥秘
java·开发语言·数据结构·c++·windows·笔记·算法
炽烈小老头5 小时前
【每天学习一点算法 2025/12/15】环形链表
学习·算法·链表
叶帆5 小时前
【睿擎派】云端一体,多种通信协议构建机械臂运动控制系统
物联网·mqtt·rt-thread·modbus·工业通信·ethercat·睿擎派
同聘云6 小时前
阿里云国际站服务器gpu服务器与cpu服务器的区别,gpu服务器如何使用?
服务器·前端·阿里云·云计算
tianyuanwo6 小时前
DPU驱动的云服务器革命:性能飙升与成本重构的商业技术双赢
服务器·云计算·dpu
usrcnusrcn6 小时前
告别PoE管理盲区:有人物联网工业交换机如何以智能供电驱动工业未来
大数据·网络·人工智能·物联网·自动化