如何轻松掌握ESP32 OTA空中升级?原生API开发全解析!

一、概述与架构设计

1.1 OTA核心架构

ESP32的OTA功能建立在分层架构之上,确保升级过程的可靠性和安全性。

1.2 OTA工作流程详解

1.3 Flash分区结构深度解析

1.3.1 标准分区布局

分区名 类型 子类型 偏移地址 大小 作用描述
bootloader

bootloader

–

0x1000

28KB

引导加载程序

partition_table

data

–

0x8000

4KB

分区表

nvs

data

nvs

0x9000

16KB

非易失存储

otadata

data

ota

0xD000

8KB

OTA状态数据

phy_init

data

phy

0xF000

4KB

PHY初始化数据

factory

app

factory

0x10000

1.5MB

出厂固件

ota_0

app

ota_0

0x180000

1.5MB

OTA槽位0

ota_1

app

ota_1

0x300000

1.5MB

OTA槽位1

storage

data

spiffs

0x480000

1.0MB

文件系统

1.3.2 分区表配置对比

配置方案 分区数量 OTA槽位 Factory分区 适用场景
Factory + 2 OTA

8个

2个

保留

标准应用

Factory + 1 OTA

7个

1个

保留

空间受限

No Factory

7个

2个

无

纯OTA部署

自定义

可变

可配置

可选

特殊需求

1.4 OTA数据分区结构

otadata分区是OTA升级的关键,其数据结构如下:

字段 大小 描述 示例值
ota_seq

4字节

OTA序列号

0x00000001

crc

4字节

数据CRC校验

0x12345678

ota_state

1字节

OTA状态

0x03

ota_attempt

1字节

启动尝试次数

0x00

ota_partition

1字节

当前引导分区

0x00

reserved

29字节

保留字段

0x00

OTA状态码表:

状态码 名称 含义

0x00

ESP_OTA_IMG_PENDING_VERIFY

待验证

0x01

ESP_OTA_IMG_VALID

验证通过

0x02

ESP_OTA_IMG_INVALID

验证失败

0x03

ESP_OTA_IMG_ABORTED

已中止

0x04

ESP_OTA_IMG_NEW

新固件

二、原生API深度解析

2.1 核心API函数详解

2.1.1 esp_ota_begin() – 初始化OTA升级

函数原型:

esp_err_t esp_ota_begin(
    const esp_partition_t *partition,
    size_t image_size,
    esp_ota_handle_t *out_handle
)
;

参数说明:

参数 类型 输入/输出 描述

partition

const esp_partition_t*

输入

目标分区指针

image_size

size_t

输入

固件大小,未知填OTA_SIZE_UNKNOWN

out_handle

esp_ota_handle_t*

输出

OTA操作句柄

返回错误码:

错误码 值 描述 解决方案

ESP_OK

0

成功

–

ESP_ERR_INVALID_ARG

0x102

参数无效

检查分区指针

ESP_ERR_OTA_BASE

0x1500

OTA基础错误

查看具体错误

ESP_ERR_NO_MEM

0x101

内存不足

增大堆内存

ESP_ERR_OTA_PARTITION_CONFLICT

0x151

分区冲突

检查分区表

2.1.2 esp_ota_write() – 写入固件数据

优化参数配置:

// 优化配置建议
#define OTA_WRITE_BUFFER_SIZE  4096    // 4KB对齐,提升性能
#define OTA_WRITE_RETRY_COUNT  3       // 写入重试次数
#define OTA_WRITE_TIMEOUT_MS   5000    // 写入超时时间

// 高级写入函数(带重试机制)
esp_err_t ota_write_with_retry(
    esp_ota_handle_t handle, 
    const void *data, 
    size_t size,
    int max_retries
)
 {
    esp_err_t ret = ESP_FAIL;
    int retry_count = 0;
    
    while (retry_count < max_retries) {
        ret = esp_ota_write(handle, data, size);
        if (ret == ESP_OK) {
            break;
        }
        
        ESP_LOGE("OTA", "Write failed (attempt %d): %s", 
                retry_count + 1, esp_err_to_name(ret));
        
        vTaskDelay(pdMS_TO_TICKS(100 * (retry_count + 1))); // 退避延迟
        retry_count++;
    }
    
    return ret;
}

2.1.3 esp_ota_end() – 结束OTA升级

验证流程:

// 完整的OTA结束流程
esp_err_t complete_ota_update(esp_ota_handle_t handle, 
                             const esp_partition_t *target_partition)
 {
    esp_err_t err;
    
    // 1. 结束OTA写入
    err = esp_ota_end(handle);
    if (err != ESP_OK) {
        if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
            ESP_LOGE("OTA", "Firmware validation failed!");
            
            // 可选:记录验证失败到NVS
            nvs_handle_t nvs;
            nvs_open("ota_stats", NVS_READWRITE, &nvs);
            uint32_t fail_count = 0;
            nvs_get_u32(nvs, "validate_fails", &fail_count);
            nvs_set_u32(nvs, "validate_fails", fail_count + 1);
            nvs_commit(nvs);
            nvs_close(nvs);
        }
        
        esp_ota_abort(handle);  // 必须调用,释放资源
        return err;
    }
    
    // 2. 验证分区可引导性
    if (!esp_ota_check_rollback_is_possible(target_partition)) {
        ESP_LOGW("OTA", "Rollback may not be possible for this partition");
    }
    
    // 3. 设置引导分区
    err = esp_ota_set_boot_partition(target_partition);
    if (err != ESP_OK) {
        ESP_LOGE("OTA", "Failed to set boot partition: %s", 
                esp_err_to_name(err));
        return err;
    }
    
    // 4. 验证设置成功
    const esp_partition_t *boot_partition = esp_ota_get_boot_partition();
    if (boot_partition != target_partition) {
        ESP_LOGE("OTA", "Boot partition mismatch after setting!");
        return ESP_FAIL;
    }
    
    ESP_LOGI("OTA", "OTA update completed successfully");
    return ESP_OK;
}

2.2 辅助函数与工具集

2.2.1 分区管理函数

// 分区选择策略表
typedef enum {
    OTA_SELECT_NEXT = 0,      // 选择下一个空闲分区
    OTA_SELECT_SPECIFIC = 1,  // 选择指定分区
    OTA_SELECT_SAFEST = 2,    // 选择最安全的分区(验证通过)
    OTA_SELECT_ROLLBACK = 3// 选择回滚分区
} ota_selection_strategy_t;

// 智能分区选择函数
const esp_partition_t* select_ota_partition(ota_selection_strategy_t strategy, 
                                           int specific_slot)
 {
    const esp_partition_t *partition = NULL;
    
    switch(strategy) {
        case OTA_SELECT_NEXT:
            partition = esp_ota_get_next_update_partition(NULL);
            break;
            
        case OTA_SELECT_SPECIFIC:
            if (specific_slot == 0) {
                partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
                                                    ESP_PARTITION_SUBTYPE_APP_OTA_0,
                                                    NULL);
            } else if (specific_slot == 1) {
                partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
                                                    ESP_PARTITION_SUBTYPE_APP_OTA_1,
                                                    NULL);
            }
            break;
            
        case OTA_SELECT_SAFEST:
            // 检查两个OTA分区,选择已验证的
            partition = find_valid_ota_partition();
            break;
            
        case OTA_SELECT_ROLLBACK:
            // 选择前一个版本的分区
            partition = find_rollback_partition();
            break;
    }
    
    if (partition == NULL) {
        ESP_LOGE("OTA", "No suitable partition found with strategy %d", strategy);
    }
    
    return partition;
}

2.2.2 固件信息获取

// 获取固件详细信息的完整函数
void print_firmware_info(const esp_partition_t *partition) {
    esp_app_desc_t app_desc;
    
    if (esp_ota_get_partition_description(partition, &app_desc) == ESP_OK) {
        printf("=== Firmware Information ===\n");
        printf("Magic Word: 0x%08X\n", app_desc.magic_word);
        printf("Secure Version: %d\n", app_desc.secure_version);
        printf("Version: %s\n", app_desc.version);
        printf("Project Name: %s\n", app_desc.project_name);
        printf("Time: %s %s\n", app_desc.date, app_desc.time);
        printf("IDF Version: %s\n", app_desc.idf_ver);
        printf("App ELF SHA256: ");
        for (int i = 0; i < 32; i++) {
            printf("%02X", app_desc.app_elf_sha256[i]);
            if ((i + 1) % 8 == 0) printf(" ");
        }
        printf("\n");
        
        // 检查固件类型
        if (partition->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY) {
            printf("Type: Factory Image\n");
        } else if (partition->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_MIN &&
                   partition->subtype <= ESP_PARTITION_SUBTYPE_APP_OTA_MAX) {
            printf("Type: OTA Slot %d\n", 
                   partition->subtype - ESP_PARTITION_SUBTYPE_APP_OTA_MIN);
        }
    }
}

三、编程流程与优化实践

3.1 完整的OTA实现示例

// OTA管理器结构体
typedef struct {
    esp_ota_handle_t handle;
    const esp_partition_t *target_partition;
    uint32_t total_size;
    uint32_t written_size;
    uint8_t *buffer;
    size_t buffer_size;
    SemaphoreHandle_t mutex;
    TaskHandle_t task_handle;
    ota_state_t state;
    char firmware_url[256];
    char firmware_version[32];
    uint32_t crc32;
    time_t start_time;
    time_t end_time;
} ota_manager_t;

// OTA状态机
typedef enum {
    OTA_STATE_IDLE = 0,
    OTA_STATE_INITIALIZING,
    OTA_STATE_DOWNLOADING,
    OTA_STATE_WRITING,
    OTA_STATE_VALIDATING,
    OTA_STATE_COMPLETING,
    OTA_STATE_SUCCESS,
    OTA_STATE_FAILED,
    OTA_STATE_ABORTED
} ota_state_t;

// 主OTA任务函数
void ota_task(void *pvParameters) {
    ota_manager_t *manager = (ota_manager_t *)pvParameters;
    esp_err_t err = ESP_OK;
    
    manager->state = OTA_STATE_INITIALIZING;
    
    // 1. 初始化OTA
    ESP_LOGI("OTA", "Initializing OTA update");
    manager->target_partition = esp_ota_get_next_update_partition(NULL);
    if (manager->target_partition == NULL) {
        ESP_LOGE("OTA", "No OTA partition found");
        manager->state = OTA_STATE_FAILED;
        vTaskDelete(NULL);
        return;
    }
    
    // 2. 检查可用空间
    size_t free_size = manager->target_partition->size;
    if (free_size < manager->total_size) {
        ESP_LOGE("OTA", "Insufficient space: %d < %d", free_size, manager->total_size);
        manager->state = OTA_STATE_FAILED;
        vTaskDelete(NULL);
        return;
    }
    
    // 3. 开始OTA操作
    err = esp_ota_begin(manager->target_partition, 
                        manager->total_size, 
                        &manager->handle);
    if (err != ESP_OK) {
        ESP_LOGE("OTA", "esp_ota_begin failed: %s", esp_err_to_name(err));
        manager->state = OTA_STATE_FAILED;
        vTaskDelete(NULL);
        return;
    }
    
    manager->state = OTA_STATE_DOWNLOADING;
    
    // 4. 下载并写入数据(示例:HTTP下载)
    err = http_download_and_write(manager);
    if (err != ESP_OK) {
        ESP_LOGE("OTA", "Download/write failed: %s", esp_err_to_name(err));
        esp_ota_abort(manager->handle);
        manager->state = OTA_STATE_FAILED;
        vTaskDelete(NULL);
        return;
    }
    
    manager->state = OTA_STATE_VALIDATING;
    
    // 5. 完成OTA
    err = esp_ota_end(manager->handle);
    if (err != ESP_OK) {
        ESP_LOGE("OTA", "esp_ota_end failed: %s", esp_err_to_name(err));
        if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
            ESP_LOGE("OTA", "Firmware validation failed!");
        }
        manager->state = OTA_STATE_FAILED;
        vTaskDelete(NULL);
        return;
    }
    
    manager->state = OTA_STATE_COMPLETING;
    
    // 6. 设置引导分区
    err = esp_ota_set_boot_partition(manager->target_partition);
    if (err != ESP_OK) {
        ESP_LOGE("OTA", "esp_ota_set_boot_partition failed: %s", 
                esp_err_to_name(err));
        manager->state = OTA_STATE_FAILED;
        vTaskDelete(NULL);
        return;
    }
    
    manager->state = OTA_STATE_SUCCESS;
    manager->end_time = time(NULL);
    
    // 7. 记录升级信息
    log_ota_event(manager);
    
    // 8. 准备重启
    ESP_LOGI("OTA", "OTA update successful. Rebooting in 3 seconds...");
    vTaskDelay(pdMS_TO_TICKS(3000));
    esp_restart();
    
    vTaskDelete(NULL);
}

3.2 关键增强逻辑实现

3.2.1 版本控制与校验

// 版本比较函数
int compare_versions(const char *ver1, const char *ver2) {
    int major1, minor1, patch1;
    int major2, minor2, patch2;
    
    sscanf(ver1, "%d.%d.%d", &major1, &minor1, &patch1);
    sscanf(ver2, "%d.%d.%d", &major2, &minor2, &patch2);
    
    if (major1 != major2) return major1 - major2;
    if (minor1 != minor2) return minor1 - minor2;
    return patch1 - patch2;
}

// 版本控制策略
typedef enum {
    VERSION_UPGRADE_ANY = 0,      // 允许任何版本升级
    VERSION_UPGRADE_HIGHER = 1,   // 只允许升级到更高版本
    VERSION_UPGRADE_SAME = 2,     // 允许相同版本(重新刷写)
    VERSION_UPGRADE_SPECIFIC = 3// 只允许特定版本
} version_upgrade_policy_t;

// 版本检查函数
bool check_version_compatibility(const char *current_ver, 
                                const char *new_ver,
                                version_upgrade_policy_t policy)
 {
    int comparison = compare_versions(current_ver, new_ver);
    
    switch(policy) {
        case VERSION_UPGRADE_ANY:
            return true;
            
        case VERSION_UPGRADE_HIGHER:
            return comparison < 0;  // 新版本 > 当前版本
            
        case VERSION_UPGRADE_SAME:
            return comparison == 0; // 版本相同
            
        case VERSION_UPGRADE_SPECIFIC:
            // 检查是否在允许的版本列表中
            return is_version_allowed(new_ver);
            
        default:
            return false;
    }
}

3.2.2 断电保护机制

// 断电保护上下文
typedef struct {
    uint32_t last_written_offset;
    uint32_t total_size;
    uint32_t crc32;
    uint8_t partition_slot;
    time_t timestamp;
    uint8_t retry_count;
} ota_backup_context_t;

// 保存OTA进度到NVS
esp_err_t save_ota_progress(ota_backup_context_t *ctx) {
    nvs_handle_t handle;
    esp_err_t err;
    
    err = nvs_open("ota_backup", NVS_READWRITE, &handle);
    if (err != ESP_OK) return err;
    
    err = nvs_set_blob(handle, "context", ctx, sizeof(ota_backup_context_t));
    if (err == ESP_OK) {
        err = nvs_commit(handle);
    }
    
    nvs_close(handle);
    return err;
}

// 恢复OTA进度
esp_err_t restore_ota_progress(ota_backup_context_t *ctx) {
    nvs_handle_t handle;
    esp_err_t err;
    size_t required_size = 0;
    
    err = nvs_open("ota_backup", NVS_READONLY, &handle);
    if (err != ESP_OK) return err;
    
    // 获取数据大小
    err = nvs_get_blob(handle, "context", NULL, &required_size);
    if (err != ESP_OK || required_size != sizeof(ota_backup_context_t)) {
        nvs_close(handle);
        return ESP_ERR_NVS_NOT_FOUND;
    }
    
    // 读取数据
    err = nvs_get_blob(handle, "context", ctx, &required_size);
    nvs_close(handle);
    
    return err;
}

// 断点续传实现
esp_err_t resume_ota_update(const char *url, ota_backup_context_t *ctx) {
    esp_err_t err;
    esp_ota_handle_t handle;
    const esp_partition_t *partition;
    
    // 根据保存的槽位找到分区
    partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
                                        ctx->partition_slot == 0 ? 
                                        ESP_PARTITION_SUBTYPE_APP_OTA_0 :
                                        ESP_PARTITION_SUBTYPE_APP_OTA_1,
                                        NULL);
    if (partition == NULL) {
        return ESP_ERR_NOT_FOUND;
    }
    
    // 从上次中断的位置继续
    err = esp_ota_begin(partition, ctx->total_size, &handle);
    if (err != ESP_OK) return err;
    
    // HTTP恢复下载(设置Range头)
    err = http_resume_download(url, ctx->last_written_offset, handle);
    if (err != ESP_OK) {
        esp_ota_abort(handle);
        return err;
    }
    
    // 完成OTA
    err = esp_ota_end(handle);
    if (err != ESP_OK) return err;
    
    // 清除备份数据
    nvs_erase_key(nvs_open("ota_backup", NVS_READWRITE, NULL), "context");
    
    return err;
}

3.2.3 回滚机制实现

// 回滚管理器
typedef struct {
    uint8_t max_rollback_attempts;
    uint8_t current_attempts;
    uint32_t rollback_timeout_ms;
    bool auto_rollback_enabled;
    bool manual_rollback_triggered;
    gpio_num_t rollback_gpio;
    uint8_t rollback_gpio_level;
} rollback_manager_t;

// 初始化回滚管理器
void init_rollback_manager(rollback_manager_t *mgr) {
    mgr->max_rollback_attempts = 3;
    mgr->current_attempts = 0;
    mgr->rollback_timeout_ms = 30000; // 30秒
    mgr->auto_rollback_enabled = true;
    mgr->manual_rollback_triggered = false;
    mgr->rollback_gpio = GPIO_NUM_0;
    mgr->rollback_gpio_level = 0;
    
    // 配置回滚GPIO
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << mgr->rollback_gpio),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&io_conf);
}

// 检查是否需要回滚
bool should_rollback(rollback_manager_t *mgr) {
    // 检查自动回滚条件
    if (mgr->auto_rollback_enabled) {
        // 检查启动失败计数器
        esp_ota_img_states_t ota_state;
        if (esp_ota_get_state_partition(esp_ota_get_running_partition(), 
                                        &ota_state) == ESP_OK) {
            if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
                mgr->current_attempts++;
                if (mgr->current_attempts >= mgr->max_rollback_attempts) {
                    return true;
                }
            }
        }
    }
    
    // 检查手动回滚触发
    if (mgr->manual_rollback_triggered) {
        return true;
    }
    
    // 检查GPIO触发
    if (gpio_get_level(mgr->rollback_gpio) == mgr->rollback_gpio_level) {
        vTaskDelay(pdMS_TO_TICKS(5000)); // 持续5秒
        if (gpio_get_level(mgr->rollback_gpio) == mgr->rollback_gpio_level) {
            return true;
        }
    }
    
    return false;
}

// 执行回滚操作
esp_err_t perform_rollback(rollback_manager_t *mgr) {
    ESP_LOGW("ROLLBACK", "Initiating rollback procedure");
    
    // 1. 标记当前固件为无效
    esp_err_t err = esp_ota_mark_app_invalid_rollback_and_reboot();
    if (err != ESP_OK) {
        ESP_LOGE("ROLLBACK", "Failed to mark app as invalid: %s", 
                esp_err_to_name(err));
        return err;
    }
    
    // 2. 获取回滚分区(上一个有效的OTA分区)
    const esp_partition_t *rollback_partition = NULL;
    const esp_partition_t *current = esp_ota_get_running_partition();
    
    if (current->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_0) {
        rollback_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
                                                     ESP_PARTITION_SUBTYPE_APP_OTA_1,
                                                     NULL);
    } else if (current->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_1) {
        rollback_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
                                                     ESP_PARTITION_SUBTYPE_APP_OTA_0,
                                                     NULL);
    }
    
    // 3. 如果没有可用的OTA分区,回退到工厂分区
    if (rollback_partition == NULL) {
        ESP_LOGW("ROLLBACK", "No OTA partition available, trying factory");
        rollback_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
                                                     ESP_PARTITION_SUBTYPE_APP_FACTORY,
                                                     NULL);
    }
    
    if (rollback_partition == NULL) {
        ESP_LOGE("ROLLBACK", "No valid rollback partition found");
        return ESP_FAIL;
    }
    
    // 4. 设置引导分区
    err = esp_ota_set_boot_partition(rollback_partition);
    if (err != ESP_OK) {
        ESP_LOGE("ROLLBACK", "Failed to set boot partition: %s", 
                esp_err_to_name(err));
        return err;
    }
    
    ESP_LOGI("ROLLBACK", "Rollback to partition %s scheduled", 
            rollback_partition->label);
    
    // 5. 重启设备
    vTaskDelay(pdMS_TO_TICKS(2000));
    esp_restart();
    
    return ESP_OK;
}

四、测试与故障排查

4.1 分区表配置深度解析

4.1.1 分区表生成与验证

# 分区表生成脚本示例
import os
import sys

def generate_partition_table(ota_slots=2, factory_enabled=True, custom_size=None):
    """生成自定义分区表"""
    
    partitions = []
    
    # 固定分区
    partitions.extend([
        ("bootloader", "0x1000", "0x7000"),
        ("partition_table", "0x8000", "0x1000"),
        ("nvs", "0x9000", "0x6000"),
        ("otadata", "0xd000", "0x2000"),
        ("phy_init", "0xf000", "0x1000"),
    ])
    
    offset = "0x10000"
    
    # 工厂分区(可选)
    if factory_enabled:
        partitions.append(("factory", "app", "factory", offset, "1M"))
        offset = hex(int(offset, 16) + 0x100000)  # 增加1MB
    
    # OTA分区
    for i in range(ota_slots):
        size = custom_size[i] if custom_size else "1M"
        partitions.append((f"ota_{i}", "app", f"ota_{i}", offset, size))
        offset = hex(int(offset, 16) + parse_size(size))
    
    # 文件系统分区(剩余空间)
    partitions.append(("storage", "data", "spiffs", offset, ""))
    
    # 生成CSV文件
    with open("partitions.csv", "w") as f:
        f.write("# Name, Type, SubType, Offset, Size, Flags\n")
        for part in partitions:
            f.write(",".join(str(x) for x in part) + "\n")
    
    return partitions

def parse_size(size_str):
    """解析大小字符串"""
    if size_str.endswith("K"):
        return int(size_str[:-1]) * 1024
    elif size_str.endswith("M"):
        return int(size_str[:-1]) * 1024 * 1024
    else:
        return int(size_str)

4.1.2 分区表验证工具

// 分区表验证函数
void validate_partition_table(void) {
    esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, 
                                                    ESP_PARTITION_SUBTYPE_ANY, 
                                                    NULL);
    
    printf("=== Partition Table Validation ===\n");
    printf("%-20s %-10s %-12s %-10s %-10s\n", 
           "Name", "Type", "Subtype", "Offset", "Size");
    printf("------------------------------------------------------------\n");
    
    bool factory_found = false;
    bool ota_0_found = false;
    bool ota_1_found = false;
    bool otadata_found = false;
    
    for (; it != NULL; it = esp_partition_next(it)) {
        const esp_partition_t *part = esp_partition_get(it);
        
        printf("%-20s 0x%02X      0x%02X        0x%08X 0x%08X\n",
               part->label, part->type, part->subtype, 
               part->address, part->size);
        
        // 检查关键分区
        if (part->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY) {
            factory_found = true;
        } else if (part->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_0) {
            ota_0_found = true;
        } else if (part->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_1) {
            ota_1_found = true;
        } else if (part->subtype == ESP_PARTITION_SUBTYPE_DATA_OTA) {
            otadata_found = true;
        }
    }
    
    esp_partition_iterator_release(it);
    
    printf("\n=== Validation Results ===\n");
    printf("Factory Partition: %s\n", factory_found ? "✓ Found" : "✗ Missing");
    printf("OTA_0 Partition: %s\n", ota_0_found ? "✓ Found" : "✗ Missing");
    printf("OTA_1 Partition: %s\n", ota_1_found ? "✓ Found" : "✗ Missing");
    printf("OTAData Partition: %s\n", otadata_found ? "✓ Found" : "✗ Missing");
    
    if (!ota_0_found || !ota_1_found) {
        ESP_LOGW("PARTITION", "OTA requires at least two OTA partitions");
    }
    
    if (!otadata_found) {
        ESP_LOGE("PARTITION", "otadata partition is required for OTA!");
    }
}

4.2 故障排查与诊断

4.2.1 常见错误代码解析

错误码 十六进制 常量名 原因分析 解决方案
0x101

0x00000101

ESP_ERR_NO_MEM

内存分配失败

增大堆内存,优化内存管理

0x102

0x00000102

ESP_ERR_INVALID_ARG

参数无效

检查API调用参数

0x103

0x00000103

ESP_ERR_NOT_FOUND

分区未找到

检查分区表配置

0x109

0x00000109

ESP_ERR_INVALID_SIZE

大小无效

验证固件大小

0x115

0x00000115

ESP_ERR_INVALID_STATE

状态无效

检查OTA操作顺序

0x1500

0x00001500

ESP_ERR_OTA_BASE

OTA基础错误

查看具体OTA错误

0x1501

0x00001501

ESP_ERR_OTA_PARTITION_CONFLICT

分区冲突

检查分区重叠

0x1502

0x00001502

ESP_ERR_OTA_SELECT_INFO_INVALID

OTA信息无效

重置otadata分区

0x1503

0x00001503

ESP_ERR_OTA_VALIDATE_FAILED

验证失败

检查签名和校验和

0x1504

0x00001504

ESP_ERR_OTA_SMALL_SEC_VER

安全版本过低

更新bootloader

0x1505

0x00001505

ESP_ERR_OTA_ROLLBACK_FAILED

回滚失败

检查回滚分区

4.2.2 诊断工具函数

// OTA诊断工具
void diagnose_ota_issues(void) {
    ESP_LOGI("DIAGNOSE", "Starting OTA diagnostics...");
    
    // 1. 检查当前运行分区
    const esp_partition_t *running = esp_ota_get_running_partition();
    if (running) {
        ESP_LOGI("DIAGNOSE", "Running partition: %s (0x%08X)", 
                running->label, running->address);
    } else {
        ESP_LOGE("DIAGNOSE", "Cannot determine running partition!");
    }
    
    // 2. 检查引导分区
    const esp_partition_t *boot = esp_ota_get_boot_partition();
    if (boot) {
        ESP_LOGI("DIAGNOSE", "Boot partition: %s (0x%08X)", 
                boot->label, boot->address);
    }
    
    // 3. 检查分区一致性
    if (running && boot && running != boot) {
        ESP_LOGW("DIAGNOSE", "Warning: Running and boot partitions differ!");
    }
    
    // 4. 检查下一个更新分区
    const esp_partition_t *next = esp_ota_get_next_update_partition(NULL);
    if (next) {
        ESP_LOGI("DIAGNOSE", "Next update partition: %s", next->label);
    } else {
        ESP_LOGE("DIAGNOSE", "No available partition for update!");
    }
    
    // 5. 检查ota_data分区状态
    esp_ota_img_states_t ota_state;
    if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
        const char *state_str;
        switch(ota_state) {
            case ESP_OTA_IMG_PENDING_VERIFY: state_str = "Pending Verify"; break;
            case ESP_OTA_IMG_VALID: state_str = "Valid"; break;
            case ESP_OTA_IMG_INVALID: state_str = "Invalid"; break;
            case ESP_OTA_IMG_ABORTED: state_str = "Aborted"; break;
            case ESP_OTA_IMG_NEW: state_str = "New"; break;
            default: state_str = "Unknown";
        }
        ESP_LOGI("DIAGNOSE", "OTA state: %s", state_str);
    }
    
    // 6. 检查所有OTA分区状态
    esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP,
                                                    ESP_PARTITION_SUBTYPE_ANY,
                                                    NULL);
    for (; it != NULL; it = esp_partition_next(it)) {
        const esp_partition_t *p = esp_partition_get(it);
        
        if (p->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_MIN ||
            p->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY) {
            
            esp_app_desc_t app_desc;
            if (esp_ota_get_partition_description(p, &app_desc) == ESP_OK) {
                printf("  %-10s: v%s (%s %s)\n", 
                       p->label, app_desc.version, app_desc.date, app_desc.time);
                
                // 检查固件完整性
                if (check_firmware_crc(p) != ESP_OK) {
                    ESP_LOGW("DIAGNOSE", "  CRC check failed for %s", p->label);
                }
            }
        }
    }
    esp_partition_iterator_release(it);
    
    // 7. 检查可用闪存空间
    size_t total, used, free_space;
    if (esp_spiram_get_chip_size(&total) == ESP_OK) {
        // 简化估算
        free_space = total - (running ? running->address + running->size : 0);
        ESP_LOGI("DIAGNOSE", "Estimated free flash: %d KB", free_space / 1024);
    }
}

4.2.3 服务器配置与调试

# OTA服务器模拟器(Python)
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
import os
import json

class OTARequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        """处理固件下载请求"""
        if self.path == '/firmware.bin':
            firmware_path = 'firmware/firmware.bin'
            
            if not os.path.exists(firmware_path):
                self.send_error(404, "Firmware not found")
                return
            
            # 支持断点续传
            range_header = self.headers.get('Range')
            file_size = os.path.getsize(firmware_path)
            start_byte = 0
            end_byte = file_size - 1
            
            if range_header:
                # 解析Range头
                byte_range = range_header.replace('bytes=', '').split('-')
                start_byte = int(byte_range[0]) if byte_range[0] else 0
                end_byte = int(byte_range[1]) if byte_range[1] else file_size - 1
            
            content_length = end_byte - start_byte + 1
            
            self.send_response(206 if range_header else 200)
            self.send_header('Content-Type', 'application/octet-stream')
            self.send_header('Content-Length', str(content_length))
            self.send_header('Accept-Ranges', 'bytes')
            
            if range_header:
                self.send_header('Content-Range', 
                                f'bytes {start_byte}-{end_byte}/{file_size}')
            
            self.end_headers()
            
            # 发送固件数据
            with open(firmware_path, 'rb') as f:
                f.seek(start_byte)
                remaining = content_length
                while remaining > 0:
                    chunk = f.read(min(4096, remaining))
                    if not chunk:
                        break
                    self.wfile.write(chunk)
                    remaining -= len(chunk)
        
        elif self.path == '/version':
            # 提供版本信息
            version_info = {
                "version": "1.2.3",
                "url": "https://ota.server.com/firmware.bin",
                "size": os.path.getsize("firmware/firmware.bin"),
                "sha256": "abc123...",
                "release_notes": "Bug fixes and improvements",
                "mandatory": False,
                "min_hardware": "ESP32"
            }
            
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps(version_info).encode())
    
    def do_POST(self):
        """处理OTA状态上报"""
        if self.path == '/report':
            content_length = int(self.headers['Content-Length'])
            post_data = self.rfile.read(content_length)
            status = json.loads(post_data)
            
            # 记录状态
            with open('ota_log.txt', 'a') as f:
                f.write(f"{status['device_id']}: {status['status']}\n")
            
            self.send_response(200)
            self.end_headers()
    
    def log_message(self, format, *args):
        """自定义日志格式"""
        print(f"[OTA Server] {args[0]} - {args[1]}")

def run_ota_server(port=8070, use_ssl=False):
    """启动OTA服务器"""
    server_address = ('', port)
    httpd = HTTPServer(server_address, OTARequestHandler)
    
    if use_ssl:
        # 配置SSL
        httpd.socket = ssl.wrap_socket(
            httpd.socket,
            certfile='cert.pem',
            keyfile='key.pem',
            server_side=True
        )
        print(f"OTA HTTPS server running on port {port}")
    else:
        print(f"OTA HTTP server running on port {port}")
    
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("\nServer stopped")

# 生成自签名证书
def generate_self_signed_cert():
    import subprocess
    subprocess.run([
        'openssl', 'req', '-x509', '-newkey', 'rsa:2048',
        '-keyout', 'key.pem', '-out', 'cert.pem',
        '-days', '365', '-nodes', '-subj', '/CN=ota.local'
    ])

if __name__ == '__main__':
    # generate_self_signed_cert()  # 首次运行生成证书
    run_ota_server(port=8070, use_ssl=False)

五、高级应用场景

5.1 Web Server本地升级实现

// Web服务器OTA处理器
static esp_err_t ota_update_handler(httpd_req_t *req) {
    esp_err_t err = ESP_OK;
    ota_update_context_t ctx = {0};
    
    // 1. 检查请求方法
    if (req->method != HTTP_POST) {
        httpd_resp_send_err(req, HTTPD_405_METHOD_NOT_ALLOWED, NULL);
        return ESP_FAIL;
    }
    
    // 2. 获取Content-Length
    char content_length_str[32] = {0};
    if (httpd_req_get_hdr_value_len(req, "Content-Length") > 0) {
        httpd_req_get_hdr_value_str(req, "Content-Length", 
                                   content_length_str, sizeof(content_length_str));
        ctx.content_length = atoi(content_length_str);
    }
    
    if (ctx.content_length <= 0) {
        httpd_resp_send_err(req, HTTPD_411_LENGTH_REQUIRED, NULL);
        return ESP_FAIL;
    }
    
    // 3. 检查可用空间
    const esp_partition_t *target = esp_ota_get_next_update_partition(NULL);
    if (target == NULL || target->size < ctx.content_length) {
        httpd_resp_send_err(req, HTTPD_507_INSUFFICIENT_STORAGE, 
                           "Insufficient storage space");
        return ESP_FAIL;
    }
    
    // 4. 初始化OTA
    err = esp_ota_begin(target, ctx.content_length, &ctx.handle);
    if (err != ESP_OK) {
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, 
                           "OTA initialization failed");
        return err;
    }
    
    // 5. 接收并写入数据
    char buf[4096];
    int received;
    size_t total_received = 0;
    
    while (total_received < ctx.content_length) {
        // 接收数据块
        received = httpd_req_recv(req, buf, sizeof(buf));
        if (received <= 0) {
            if (received == HTTPD_SOCK_ERR_TIMEOUT) {
                continue;  // 重试
            }
            break;  // 错误或连接关闭
        }
        
        // 写入OTA分区
        err = esp_ota_write(ctx.handle, buf, received);
        if (err != ESP_OK) {
            esp_ota_abort(ctx.handle);
            httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, 
                               "OTA write failed");
            return err;
        }
        
        total_received += received;
        
        // 可选:发送进度更新
        if (total_received % (100 * 1024) == 0) {  // 每100KB
            ESP_LOGI("OTA", "Received %d/%d bytes (%.1f%%)", 
                    total_received, ctx.content_length,
                    (total_received * 100.0) / ctx.content_length);
        }
    }
    
    // 6. 完成OTA
    err = esp_ota_end(ctx.handle);
    if (err != ESP_OK) {
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, 
                           "OTA validation failed");
        return err;
    }
    
    // 7. 设置引导分区
    err = esp_ota_set_boot_partition(target);
    if (err != ESP_OK) {
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, 
                           "Failed to set boot partition");
        return err;
    }
    
    // 8. 返回成功响应
    httpd_resp_set_status(req, "200 OK");
    httpd_resp_set_type(req, "application/json");
    
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "status", "success");
    cJSON_AddNumberToObject(root, "bytes_received", total_received);
    cJSON_AddStringToObject(root, "partition", target->label);
    
    const char *json_str = cJSON_Print(root);
    httpd_resp_sendstr(req, json_str);
    free((void*)json_str);
    cJSON_Delete(root);
    
    // 9. 延迟重启
    ESP_LOGI("OTA", "Web OTA update successful. Rebooting in 5 seconds...");
    vTaskDelay(pdMS_TO_TICKS(5000));
    esp_restart();
    
    return ESP_OK;
}

// 注册Web OTA路由
void register_ota_web_handler(httpd_handle_t server) {
    httpd_uri_t ota_uri = {
        .uri       = "/update",
        .method    = HTTP_POST,
        .handler   = ota_update_handler,
        .user_ctx  = NULL
    };
    
    httpd_register_uri_handler(server, &ota_uri);
    
    // 添加版本查询接口
    httpd_uri_t version_uri = {
        .uri       = "/version",
        .method    = HTTP_GET,
        .handler   = version_info_handler,
        .user_ctx  = NULL
    };
    
    httpd_register_uri_handler(server, &version_uri);
}

5.2 MQTT批量升级系统

// MQTT OTA管理器
typedef struct {
    esp_mqtt_client_handle_t mqtt_client;
    char device_id[32];
    char group_id[32];
    char firmware_topic[128];
    char status_topic[128];
    char control_topic[128];
    ota_state_t state;
    uint32_t firmware_size;
    char firmware_url[256];
    char firmware_version[32];
    SemaphoreHandle_t mutex;
    TaskHandle_t ota_task;
} mqtt_ota_manager_t;

// MQTT OTA回调函数
static void mqtt_ota_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;
    mqtt_ota_manager_t *manager = (mqtt_ota_manager_t*)handler_args;
    
    switch (event->event_id) {
        case MQTT_EVENT_CONNECTED:
            ESP_LOGI("MQTT_OTA", "Connected to MQTT broker");
            
            // 订阅相关主题
            esp_mqtt_client_subscribe(manager->mqtt_client, 
                                     manager->control_topic, 1);
            esp_mqtt_client_subscribe(manager->mqtt_client, 
                                     "firmware/updates", 1);
            esp_mqtt_client_subscribe(manager->mqtt_client, 
                                     "firmware/commands", 1);
            
            // 发布设备上线消息
            publish_device_status(manager, "online");
            break;
            
        case MQTT_EVENT_DATA:
            // 处理接收到的消息
            handle_mqtt_message(manager, event->topic, event->data, event->data_len);
            break;
            
        case MQTT_EVENT_DISCONNECTED:
            ESP_LOGW("MQTT_OTA", "Disconnected from MQTT broker");
            manager->state = OTA_STATE_IDLE;
            break;
    }
}

// 处理MQTT消息
static void handle_mqtt_message(mqtt_ota_manager_t *manager, 
                               const char *topic, const char *data, int len)
 {
    cJSON *json = cJSON_ParseWithLength(data, len);
    if (json == NULL) return;
    
    // 解析消息类型
    cJSON *type_json = cJSON_GetObjectItem(json, "type");
    if (type_json == NULL) {
        cJSON_Delete(json);
        return;
    }
    
    const char *msg_type = type_json->valuestring;
    
    if (strcmp(msg_type, "firmware_update") == 0) {
        // 处理固件更新命令
        handle_firmware_update_cmd(manager, json);
        
    } else if (strcmp(msg_type, "ota_start") == 0) {
        // 开始OTA升级
        start_mqtt_ota_update(manager, json);
        
    } else if (strcmp(msg_type, "ota_status") == 0) {
        // 状态查询
        publish_ota_status(manager);
        
    } else if (strcmp(msg_type, "rollback") == 0) {
        // 回滚命令
        handle_rollback_cmd(manager, json);
    }
    
    cJSON_Delete(json);
}

// 处理固件更新命令
static void handle_firmware_update_cmd(mqtt_ota_manager_t *manager, cJSON *json) {
    cJSON *version_json = cJSON_GetObjectItem(json, "version");
    cJSON *url_json = cJSON_GetObjectItem(json, "url");
    cJSON *size_json = cJSON_GetObjectItem(json, "size");
    cJSON *force_json = cJSON_GetObjectItem(json, "force");
    
    if (!version_json || !url_json || !size_json) {
        ESP_LOGE("MQTT_OTA", "Invalid firmware update command");
        return;
    }
    
    // 检查是否已经在更新中
    if (manager->state != OTA_STATE_IDLE && 
        !(force_json && cJSON_IsTrue(force_json))) {
        ESP_LOGW("MQTT_OTA", "OTA already in progress, ignoring update");
        return;
    }
    
    // 保存固件信息
    strlcpy(manager->firmware_version, version_json->valuestring,
           sizeof(manager->firmware_version));
    strlcpy(manager->firmware_url, url_json->valuestring,
           sizeof(manager->firmware_url));
    manager->firmware_size = (uint32_t)cJSON_GetNumberValue(size_json);
    
    // 检查版本
    esp_app_desc_t current_desc;
    esp_ota_get_partition_description(esp_ota_get_running_partition(), 
                                     &current_desc);
    
    if (strcmp(current_desc.version, manager->firmware_version) == 0) {
        ESP_LOGI("MQTT_OTA", "Already running version %s", 
                manager->firmware_version);
        return;
    }
    
    // 发布确认消息
    publish_ota_ack(manager, "update_received");
    
    // 开始OTA更新(在单独的任务中)
    xTaskCreate(mqtt_ota_update_task, "mqtt_ota", 8192, manager, 5, 
               &manager->ota_task);
}

// MQTT OTA更新任务
static void mqtt_ota_update_task(void *pvParameters) {
    mqtt_ota_manager_t *manager = (mqtt_ota_manager_t*)pvParameters;
    
    xSemaphoreTake(manager->mutex, portMAX_DELAY);
    manager->state = OTA_STATE_DOWNLOADING;
    xSemaphoreGive(manager->mutex);
    
    // 发布开始状态
    publish_ota_status(manager);
    
    // 执行OTA更新
    esp_err_t err = perform_http_ota_update(manager->firmware_url, 
                                           manager->firmware_size);
    
    xSemaphoreTake(manager->mutex, portMAX_DELAY);
    
    if (err == ESP_OK) {
        manager->state = OTA_STATE_SUCCESS;
        ESP_LOGI("MQTT_OTA", "OTA update completed successfully");
        
        // 发布成功状态
        publish_ota_status(manager);
        
        // 延迟重启
        vTaskDelay(pdMS_TO_TICKS(5000));
        esp_restart();
        
    } else {
        manager->state = OTA_STATE_FAILED;
        ESP_LOGE("MQTT_OTA", "OTA update failed: %s", esp_err_to_name(err));
        
        // 发布失败状态
        publish_ota_status(manager);
    }
    
    xSemaphoreGive(manager->mutex);
    vTaskDelete(NULL);
}

// 发布OTA状态
static void publish_ota_status(mqtt_ota_manager_t *manager) {
    cJSON *root = cJSON_CreateObject();
    
    cJSON_AddStringToObject(root, "device_id", manager->device_id);
    cJSON_AddStringToObject(root, "group_id", manager->group_id);
    
    const char *state_str;
    switch(manager->state) {
        case OTA_STATE_IDLE: state_str = "idle"; break;
        case OTA_STATE_DOWNLOADING: state_str = "downloading"; break;
        case OTA_STATE_SUCCESS: state_str = "success"; break;
        case OTA_STATE_FAILED: state_str = "failed"; break;
        default: state_str = "unknown";
    }
    cJSON_AddStringToObject(root, "ota_state", state_str);
    
    // 添加固件信息
    if (manager->firmware_version[0] != '\0') {
        cJSON_AddStringToObject(root, "target_version", 
                               manager->firmware_version);
    }
    
    // 添加当前版本
    esp_app_desc_t desc;
    if (esp_ota_get_partition_description(esp_ota_get_running_partition(), 
                                         &desc) == ESP_OK) {
        cJSON_AddStringToObject(root, "current_version", desc.version);
    }
    
    char *json_str = cJSON_PrintUnformatted(root);
    esp_mqtt_client_publish(manager->mqtt_client, manager->status_topic, 
                           json_str, 0, 1, 0);
    free(json_str);
    cJSON_Delete(root);
}

六、安全机制深度解析

6.1 安全启动配置

6.1.1 安全启动流程

graph TD     A[上电复位] --> B[ROM Bootloader]     B --> C[加载一级Bootloader]     C --> D[验证签名]     D --> E{签名有效?}     E -->|是| F[加载二级Bootloader]     E -->|否| G[停止启动<br>红灯闪烁]     F --> H[验证应用程序]     H --> I{应用程序有效?}     I -->|是| J[运行应用程序]     I -->|否| K[尝试备用分区]

6.1.2 安全启动配置步骤

# 1. 生成安全启动密钥
espsecure.py generate_signing_key --version 2 secure_boot_key.pem

# 2. 配置项目启用安全启动
idf.py menuconfig
# → Security features
#   → Enable flash encryption
#   → Enable Secure Boot
#   → Sign binaries during build

# 3. 烧写密钥到设备
espsecure.py burn_key --no-protect-key \
    flash_encryption_key.bin FLASH_CRYPT_CNT 1

# 4. 编译并签名固件
idf.py build
espsecure.py sign_data --version 2 \
    --keyfile secure_boot_key.pem \
    --output build/firmware_signed.bin \
    build/firmware.bin

# 5. 烧写固件
esptool.py write_flash 0x1000 build/bootloader/bootloader.bin
esptool.py write_flash 0x8000 build/partition_table/partition-table.bin
esptool.py write_flash 0x10000 build/firmware_signed.bin

6.2 加密通信实现

// HTTPS OTA实现
esp_err_t perform_https_ota_update(const char *url, const char *cert_pem) {
    esp_http_client_config_t config = {
        .url = url,
        .cert_pem = cert_pem,
        .timeout_ms = 30000,
        .keep_alive_enable = true,
        .disable_auto_redirect = false,
        .max_redirection_count = 5,
        .user_agent = "ESP32-HTTP-Client/1.0",
        .method = HTTP_METHOD_GET,
    };
    
    // 创建HTTPS OTA客户端
    esp_https_ota_config_t ota_config = {
        .http_config = &config,
        .http_client_init_cb = NULL,  // 可选的初始化回调
        .bulk_flash_erase = false,    // 是否批量擦除
        .partial_http_download = false, // 是否部分下载
        .max_http_request_size = 0,   // 0表示使用默认值
    };
    
    esp_https_ota_handle_t https_ota_handle = NULL;
    esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
    if (err != ESP_OK) {
        ESP_LOGE("HTTPS_OTA", "Failed to start HTTPS OTA");
        return err;
    }
    
    // 获取固件信息
    esp_app_desc_t app_desc;
    err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);
    if (err != ESP_OK) {
        ESP_LOGE("HTTPS_OTA", "Failed to get image description");
        esp_https_ota_abort(https_ota_handle);
        return err;
    }
    
    ESP_LOGI("HTTPS_OTA", "New firmware version: %s", app_desc.version);
    
    // 执行OTA升级
    while (1) {
        err = esp_https_ota_perform(https_ota_handle);
        if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
            break;
        }
        
        // 可选:报告下载进度
        int progress = esp_https_ota_get_image_len_read(https_ota_handle);
        int total = esp_https_ota_get_image_size(https_ota_handle);
        if (total > 0) {
            ESP_LOGI("HTTPS_OTA", "Download progress: %d/%d (%.1f%%)", 
                    progress, total, (progress * 100.0) / total);
        }
    }
    
    if (err == ESP_OK) {
        ESP_LOGI("HTTPS_OTA", "HTTPS OTA update successful");
        
        // 完成OTA
        esp_err_t ota_finish_err = esp_https_ota_finish(https_ota_handle);
        if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED) {
            ESP_LOGE("HTTPS_OTA", "Image validation failed");
            return ota_finish_err;
        }
        
        ESP_LOGI("HTTPS_OTA", "Rebooting in 3 seconds...");
        vTaskDelay(pdMS_TO_TICKS(3000));
        esp_restart();
        
    } else {
        ESP_LOGE("HTTPS_OTA", "HTTPS OTA update failed: %s", 
                esp_err_to_name(err));
        esp_https_ota_abort(https_ota_handle);
    }
    
    return err;
}

七、性能优化技巧

7.1 内存优化策略

7.1.1 双缓冲技术实现

// 双缓冲OTA写入器
typedef struct {
    uint8_t *buffer_a;
    uint8_t *buffer_b;
    size_t buffer_size;
    size_t buffer_a_used;
    size_t buffer_b_used;
    bool buffer_a_ready;
    bool buffer_b_ready;
    SemaphoreHandle_t buffer_mutex;
    TaskHandle_t fill_task;
    TaskHandle_t write_task;
    esp_ota_handle_t ota_handle;
} dual_buffer_writer_t;

// 初始化双缓冲
esp_err_t init_dual_buffer_writer(dual_buffer_writer_t *writer, 
                                 size_t buffer_size)
 {
    writer->buffer_a = (uint8_t*)malloc(buffer_size);
    writer->buffer_b = (uint8_t*)malloc(buffer_size);
    if (!writer->buffer_a || !writer->buffer_b) {
        free(writer->buffer_a);
        free(writer->buffer_b);
        return ESP_ERR_NO_MEM;
    }
    
    writer->buffer_size = buffer_size;
    writer->buffer_a_used = 0;
    writer->buffer_b_used = 0;
    writer->buffer_a_ready = false;
    writer->buffer_b_ready = false;
    writer->buffer_mutex = xSemaphoreCreateMutex();
    
    if (!writer->buffer_mutex) {
        free(writer->buffer_a);
        free(writer->buffer_b);
        return ESP_FAIL;
    }
    
    return ESP_OK;
}

// 填充缓冲区任务
void fill_buffer_task(void *pvParameters) {
    dual_buffer_writer_t *writer = (dual_buffer_writer_t*)pvParameters;
    
    while (1) {
        // 等待缓冲区可用
        xSemaphoreTake(writer->buffer_mutex, portMAX_DELAY);
        
        // 选择要填充的缓冲区
        uint8_t *target_buffer = NULL;
        bool *ready_flag = NULL;
        size_t *used_size = NULL;
        
        if (!writer->buffer_a_ready && writer->buffer_a_used < writer->buffer_size) {
            target_buffer = writer->buffer_a;
            ready_flag = &writer->buffer_a_ready;
            used_size = &writer->buffer_a_used;
        } else if (!writer->buffer_b_ready && writer->buffer_b_used < writer->buffer_size) {
            target_buffer = writer->buffer_b;
            ready_flag = &writer->buffer_b_ready;
            used_size = &writer->buffer_b_used;
        }
        
        xSemaphoreGive(writer->buffer_mutex);
        
        if (target_buffer) {
            // 从网络填充数据
            size_t fill_size = fill_from_network(target_buffer + *used_size, 
                                               writer->buffer_size - *used_size);
            
            if (fill_size > 0) {
                xSemaphoreTake(writer->buffer_mutex, portMAX_DELAY);
                *used_size += fill_size;
                
                // 如果缓冲区满了,标记为就绪
                if (*used_size == writer->buffer_size) {
                    *ready_flag = true;
                }
                
                xSemaphoreGive(writer->buffer_mutex);
            }
        } else {
            // 没有可用的缓冲区,短暂休眠
            vTaskDelay(pdMS_TO_TICKS(10));
        }
    }
}

// 写入缓冲区任务
void write_buffer_task(void *pvParameters) {
    dual_buffer_writer_t *writer = (dual_buffer_writer_t*)pvParameters;
    
    while (1) {
        // 检查哪个缓冲区就绪了
        uint8_t *write_buffer = NULL;
        size_t write_size = 0;
        
        xSemaphoreTake(writer->buffer_mutex, portMAX_DELAY);
        
        if (writer->buffer_a_ready) {
            write_buffer = writer->buffer_a;
            write_size = writer->buffer_a_used;
            writer->buffer_a_ready = false;
            writer->buffer_a_used = 0;
        } else if (writer->buffer_b_ready) {
            write_buffer = writer->buffer_b;
            write_size = writer->buffer_b_used;
            writer->buffer_b_ready = false;
            writer->buffer_b_used = 0;
        }
        
        xSemaphoreGive(writer->buffer_mutex);
        
        if (write_buffer && write_size > 0) {
            // 写入闪存
            esp_err_t err = esp_ota_write(writer->ota_handle, 
                                         write_buffer, write_size);
            if (err != ESP_OK) {
                ESP_LOGE("DUAL_BUFFER", "Write failed: %s", 
                        esp_err_to_name(err));
                break;
            }
        } else {
            // 没有就绪的缓冲区,短暂休眠
            vTaskDelay(pdMS_TO_TICKS(10));
        }
    }
}

7.2 网络优化策略

// 网络优化配置
void configure_network_for_ota(void) {
    // 1. 配置TCP/IP参数
    esp_netif_init();
    
    // 2. 优化TCP窗口大小
    esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
    if (netif) {
        esp_netif_set_ip_info(netif, &(esp_netif_ip_info_t){
            .ip = { .addr = IPADDR_ANY },
            .gw = { .addr = IPADDR_ANY },
            .netmask = { .addr = IPADDR_ANY }
        });
    }
    
    // 3. 配置Wi-Fi为高性能模式
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = CONFIG_WIFI_SSID,
            .password = CONFIG_WIFI_PASSWORD,
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
            .pmf_cfg = {
                .capable = true,
                .required = false
            },
        },
    };
    
    esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
    
    // 4. 设置最大传输功率
    esp_wifi_set_max_tx_power(84);  // +20dBm
    
    // 5. 配置Wi-Fi速率
    esp_wifi_config_80211_tx_rate(WIFI_IF_STA, WIFI_PHY_RATE_MCS7_SGI);
    
    // 6. 禁用省电模式
    esp_wifi_set_ps(WIFI_PS_NONE);
    
    // 7. 配置LwIP参数
    tcpip_adapter_init();
    tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
    
    // 8. 优化TCP参数
    struct timeval tv;
    tv.tv_sec = 30;  // 30秒超时
    tv.tv_usec = 0;
    
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock >= 0) {
        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
        setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
        
        // 启用TCP_NODELAY(禁用Nagle算法)
        int flag = 1;
        setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
        
        close(sock);
    }
}

八、企业级部署方案

8.1 灰度发布实现

// 灰度发布管理器
typedef struct {
    uint8_t release_group;      // 发布组
    uint8_t release_percentage; // 发布百分比
    char release_version[32];   // 发布版本
    char release_url[256];      // 固件URL
    time_t release_time;        // 发布时间
    uint32_t device_seed;       // 设备种子(用于分组)
    bool force_update;          // 强制更新
} gray_release_manager_t;

// 检查设备是否在灰度发布组
bool is_device_in_gray_release(gray_release_manager_t *mgr) {
    // 使用设备ID或MAC地址生成确定性的分组
    uint8_t mac[6];
    esp_read_mac(mac, ESP_MAC_WIFI_STA);
    
    // 生成设备哈希值
    uint32_t device_hash = 0;
    for (int i = 0; i < 6; i++) {
        device_hash = (device_hash << 5) - device_hash + mac[i];
    }
    
    // 计算分组(0-99)
    uint8_t device_group = device_hash % 100;
    
    // 检查是否在发布组内
    return device_group < mgr->release_percentage;
}

// 灰度发布状态机
typedef enum {
    GRAY_STAGE_TESTING = 0,     // 测试阶段(内部)
    GRAY_STAGE_EARLY = 1,       // 早期阶段(10%)
    GRAY_STAGE_BROAD = 2,       // 广泛阶段(50%)
    GRAY_STAGE_FULL = 3,        // 全量阶段(100%)
    GRAY_STAGE_COMPLETE = 4// 完成阶段
} gray_release_stage_t;

// 执行灰度发布
void execute_gray_release(gray_release_manager_t *mgr) {
    gray_release_stage_t current_stage = get_current_release_stage(mgr);
    
    switch (current_stage) {
        case GRAY_STAGE_TESTING:
            mgr->release_percentage = 5;  // 内部测试5%
            break;
            
        case GRAY_STAGE_EARLY:
            mgr->release_percentage = 10; // 早期用户10%
            break;
            
        case GRAY_STAGE_BROAD:
            mgr->release_percentage = 50; // 广泛发布50%
            break;
            
        case GRAY_STAGE_FULL:
            mgr->release_percentage = 100; // 全量发布100%
            break;
            
        case GRAY_STAGE_COMPLETE:
            // 发布完成,清理状态
            cleanup_gray_release(mgr);
            return;
    }
    
    // 检查设备是否在发布组
    if (is_device_in_gray_release(mgr) || mgr->force_update) {
        ESP_LOGI("GRAY_RELEASE", "Device selected for gray release (group %d%%)", 
                mgr->release_percentage);
        
        // 执行OTA更新
        start_ota_update(mgr->release_url);
        
        // 上报状态
        report_gray_release_status(mgr, "updating");
        
    } else {
        ESP_LOGI("GRAY_RELEASE", "Device not in current release group (%d%%)", 
                mgr->release_percentage);
        
        // 可选:延迟检查
        schedule_next_gray_check(mgr, 3600); // 1小时后再次检查
    }
}

8.2 设备状态监控系统

// 设备状态监控器
typedef struct {
    char device_id[32];
    char group_id[32];
    char firmware_version[32];
    char hardware_version[16];
    uint32_t uptime;
    uint32_t free_heap;
    int8_t wifi_rssi;
    uint8_t battery_level;
    float temperature;
    ota_state_t ota_state;
    time_t last_report;
    uint32_t report_interval;
    esp_mqtt_client_handle_t mqtt_client;
} device_monitor_t;

// 收集设备状态
void collect_device_status(device_monitor_t *monitor) {
    // 1. 系统信息
    monitor->uptime = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000;
    monitor->free_heap = esp_get_free_heap_size();
    
    // 2. 固件信息
    esp_app_desc_t app_desc;
    esp_ota_get_partition_description(esp_ota_get_running_partition(), 
                                     &app_desc);
    strlcpy(monitor->firmware_version, app_desc.version,
           sizeof(monitor->firmware_version));
    
    // 3. Wi-Fi状态
    wifi_ap_record_t ap_info;
    if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
        monitor->wifi_rssi = ap_info.rssi;
    } else {
        monitor->wifi_rssi = 0;
    }
    
    // 4. 温度传感器(如果可用)
    #ifdef CONFIG_TEMPERATURE_SENSOR_ENABLED
    monitor->temperature = read_temperature();
    #else
    monitor->temperature = 0.0;
    #endif
    
    // 5. 电池电量(如果可用)
    #ifdef CONFIG_BATTERY_MONITOR_ENABLED
    monitor->battery_level = read_battery_level();
    #else
    monitor->battery_level = 100;
    #endif
    
    // 6. OTA状态
    monitor->ota_state = get_current_ota_state();
}

// 上报设备状态
void report_device_status(device_monitor_t *monitor) {
    cJSON *root = cJSON_CreateObject();
    
    // 基础信息
    cJSON_AddStringToObject(root, "device_id", monitor->device_id);
    cJSON_AddStringToObject(root, "group_id", monitor->group_id);
    cJSON_AddStringToObject(root, "firmware_version", monitor->firmware_version);
    cJSON_AddStringToObject(root, "hardware_version", monitor->hardware_version);
    
    // 系统状态
    cJSON_AddNumberToObject(root, "uptime", monitor->uptime);
    cJSON_AddNumberToObject(root, "free_heap", monitor->free_heap);
    cJSON_AddNumberToObject(root, "wifi_rssi", monitor->wifi_rssi);
    cJSON_AddNumberToObject(root, "battery_level", monitor->battery_level);
    cJSON_AddNumberToObject(root, "temperature", monitor->temperature);
    
    // OTA状态
    const char *ota_state_str;
    switch (monitor->ota_state) {
        case OTA_STATE_IDLE: ota_state_str = "idle"; break;
        case OTA_STATE_DOWNLOADING: ota_state_str = "downloading"; break;
        case OTA_STATE_SUCCESS: ota_state_str = "success"; break;
        case OTA_STATE_FAILED: ota_state_str = "failed"; break;
        default: ota_state_str = "unknown";
    }
    cJSON_AddStringToObject(root, "ota_state", ota_state_str);
    
    // 时间戳
    cJSON_AddNumberToObject(root, "timestamp", time(NULL));
    
    // 转换为JSON字符串
    char *json_str = cJSON_PrintUnformatted(root);
    
    // 发布到MQTT
    char topic[128];
    snprintf(topic, sizeof(topic), "devices/%s/status", monitor->device_id);
    
    esp_mqtt_client_publish(monitor->mqtt_client, topic, json_str, 
                           strlen(json_str), 1, 0);
    
    // 清理
    free(json_str);
    cJSON_Delete(root);
    
    // 更新最后上报时间
    monitor->last_report = time(NULL);
}

// 状态监控任务
void device_monitor_task(void *pvParameters) {
    device_monitor_t *monitor = (device_monitor_t*)pvParameters;
    
    while (1) {
        // 收集状态
        collect_device_status(monitor);
        
        // 检查是否需要上报
        time_t now = time(NULL);
        if (difftime(now, monitor->last_report) >= monitor->report_interval) {
            report_device_status(monitor);
        }
        
        // 检查是否需要OTA
        check_ota_updates(monitor);
        
        // 休眠
        vTaskDelay(pdMS_TO_TICKS(10000)); // 10秒
    }
}

九、深度故障恢复机制

9.1 三级回滚策略完整实现

// 回滚管理器完整实现
typedef struct {
    uint8_t max_boot_attempts;      // 最大启动尝试次数
    uint8_t current_boot_attempts;  // 当前启动尝试次数
    bool auto_rollback_enabled;     // 自动回滚启用
    bool manual_rollback_triggered; // 手动回滚触发
    gpio_num_t rollback_gpio;       // 回滚GPIO
    uint8_t rollback_gpio_level;    // 触发电平
    uint32_t rollback_timeout_ms;   // 回滚超时时间
    char rollback_reason[64];       // 回滚原因
    time_t rollback_timestamp;      // 回滚时间戳
} rollback_manager_v2_t;

// 初始化回滚管理器
void init_rollback_manager_v2(rollback_manager_v2_t *mgr) {
    memset(mgr, 0, sizeof(rollback_manager_v2_t));
    
    // 默认配置
    mgr->max_boot_attempts = 3;
    mgr->auto_rollback_enabled = true;
    mgr->manual_rollback_triggered = false;
    mgr->rollback_gpio = GPIO_NUM_0;
    mgr->rollback_gpio_level = 0;
    mgr->rollback_timeout_ms = 30000;
    
    // 从NVS加载配置
    nvs_handle_t nvs;
    if (nvs_open("rollback_cfg", NVS_READONLY, &nvs) == ESP_OK) {
        nvs_get_u8(nvs, "max_attempts", &mgr->max_boot_attempts);
        nvs_get_u8(nvs, "auto_enabled", (uint8_t*)&mgr->auto_rollback_enabled);
        nvs_get_u32(nvs, "timeout_ms", &mgr->rollback_timeout_ms);
        nvs_close(nvs);
    }
    
    // 配置GPIO
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << mgr->rollback_gpio),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&io_conf);
    
    // 检查启动状态
    check_boot_status(mgr);
}

// 检查启动状态
void check_boot_status(rollback_manager_v2_t *mgr) {
    esp_ota_img_states_t ota_state;
    const esp_partition_t *running = esp_ota_get_running_partition();
    
    if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
        if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
            // 新固件待验证
            
            // 从NVS读取尝试次数
            nvs_handle_t nvs;
            if (nvs_open("ota_stats", NVS_READWRITE, &nvs) == ESP_OK) {
                nvs_get_u8(nvs, "boot_attempts", &mgr->current_boot_attempts);
                mgr->current_boot_attempts++;
                nvs_set_u8(nvs, "boot_attempts", mgr->current_boot_attempts);
                nvs_commit(nvs);
                nvs_close(nvs);
            }
            
            ESP_LOGW("ROLLBACK", "Boot attempt %d/%d for new firmware", 
                    mgr->current_boot_attempts, mgr->max_boot_attempts);
            
            if (mgr->current_boot_attempts >= mgr->max_boot_attempts) {
                // 超过最大尝试次数,需要回滚
                strlcpy(mgr->rollback_reason, 
                       "Max boot attempts exceeded",
                       sizeof(mgr->rollback_reason));
                mgr->rollback_timestamp = time(NULL);
                
                // 执行回滚
                perform_rollback_v2(mgr);
            }
        } else if (ota_state == ESP_OTA_IMG_VALID) {
            // 固件验证通过,重置计数器
            nvs_handle_t nvs;
            if (nvs_open("ota_stats", NVS_READWRITE, &nvs) == ESP_OK) {
                nvs_set_u8(nvs, "boot_attempts", 0);
                nvs_commit(nvs);
                nvs_close(nvs);
            }
            
            // 标记固件为有效
            esp_ota_mark_app_valid_cancel_rollback();
        }
    }
}

// 执行回滚操作
esp_err_t perform_rollback_v2(rollback_manager_v2_t *mgr) {
    ESP_LOGW("ROLLBACK", "Initiating rollback: %s", mgr->rollback_reason);
    
    // 记录回滚事件
    log_rollback_event(mgr);
    
    // 1. 标记当前固件为无效
    esp_err_t err = esp_ota_mark_app_invalid_rollback_and_reboot();
    if (err != ESP_OK) {
        ESP_LOGE("ROLLBACK", "Failed to mark app as invalid: %s", 
                esp_err_to_name(err));
        return err;
    }
    
    // 2. 查找可回滚的分区
    const esp_partition_t *rollback_partition = find_rollback_partition_v2();
    if (rollback_partition == NULL) {
        ESP_LOGE("ROLLBACK", "No valid rollback partition found");
        return ESP_FAIL;
    }
    
    // 3. 设置引导分区
    err = esp_ota_set_boot_partition(rollback_partition);
    if (err != ESP_OK) {
        ESP_LOGE("ROLLBACK", "Failed to set boot partition: %s", 
                esp_err_to_name(err));
        return err;
    }
    
    // 4. 发送回滚通知(如果网络可用)
    if (is_network_available()) {
        send_rollback_notification(mgr, rollback_partition);
    }
    
    ESP_LOGI("ROLLBACK", "Rollback to %s scheduled. Rebooting...", 
            rollback_partition->label);
    
    // 5. 延迟重启
    vTaskDelay(pdMS_TO_TICKS(2000));
    esp_restart();
    
    return ESP_OK;
}

// 查找回滚分区
const esp_partition_t* find_rollback_partition_v2(void) {
    const esp_partition_t *partitions[3] = {NULL};
    int count = 0;
    
    // 查找所有可用的APP分区
    esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP,
                                                    ESP_PARTITION_SUBTYPE_ANY,
                                                    NULL);
    
    for (; it != NULL; it = esp_partition_next(it)) {
        const esp_partition_t *p = esp_partition_get(it);
        
        // 跳过当前运行的分区
        if (p == esp_ota_get_running_partition()) {
            continue;
        }
        
        // 检查分区状态
        esp_ota_img_states_t state;
        if (esp_ota_get_state_partition(p, &state) == ESP_OK) {
            if (state == ESP_OTA_IMG_VALID) {
                partitions[count++] = p;
                if (count >= 3) break;
            }
        }
    }
    esp_partition_iterator_release(it);
    
    // 选择回滚分区(优先选择最近的OTA分区)
    if (count > 0) {
        // 按类型排序:Factory > OTA_1 > OTA_0
        for (int i = 0; i < count; i++) {
            if (partitions[i]->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY) {
                return partitions[i];
            }
        }
        
        for (int i = 0; i < count; i++) {
            if (partitions[i]->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_1) {
                return partitions[i];
            }
        }
        
        return partitions[0];  // 返回第一个可用的
    }
    
    return NULL;
}

// 记录回滚事件
void log_rollback_event(rollback_manager_v2_t *mgr) {
    nvs_handle_t nvs;
    if (nvs_open("rollback_log", NVS_READWRITE, &nvs) == ESP_OK) {
        // 读取历史记录
        char log_key[16];
        uint8_t log_count = 0;
        nvs_get_u8(nvs, "count", &log_count);
        
        // 保存新记录
        snprintf(log_key, sizeof(log_key), "event_%d", log_count % 10);
        
        cJSON *event = cJSON_CreateObject();
        cJSON_AddStringToObject(event, "reason", mgr->rollback_reason);
        cJSON_AddNumberToObject(event, "timestamp", mgr->rollback_timestamp);
        cJSON_AddNumberToObject(event, "attempts", mgr->current_boot_attempts);
        
        char *event_str = cJSON_PrintUnformatted(event);
        nvs_set_str(nvs, log_key, event_str);
        free(event_str);
        cJSON_Delete(event);
        
        // 更新计数
        log_count++;
        nvs_set_u8(nvs, "count", log_count);
        nvs_commit(nvs);
        nvs_close(nvs);
    }
}

9.2 断点续传完整实现

// 断点续传管理器
typedef struct {
    char url[256];              // 下载URL
    uint32_t total_size;        // 文件总大小
    uint32_t downloaded_size;   // 已下载大小
    uint32_t file_crc32;        // 文件CRC32
    uint8_t partition_slot;     // 目标分区槽位
    time_t start_time;          // 开始时间
    time_t last_update;         // 最后更新时间
    char etag[64];              // ETag(用于验证)
    char last_modified[64];     // Last-Modified
    bool resume_supported;      // 是否支持断点续传
} resume_manager_t;

// 初始化断点续传
esp_err_t init_resume_download(const char *url, resume_manager_t *resume) {
    memset(resume, 0, sizeof(resume_manager_t));
    strlcpy(resume->url, url, sizeof(resume->url));
    
    // 从NVS加载之前的进度
    nvs_handle_t nvs;
    esp_err_t err = nvs_open("ota_resume", NVS_READWRITE, &nvs);
    if (err == ESP_OK) {
        // 检查是否有相同URL的进度
        char saved_url[256];
        size_t url_len = sizeof(saved_url);
        
        if (nvs_get_str(nvs, "url", saved_url, &url_len) == ESP_OK) {
            if (strcmp(saved_url, url) == 0) {
                // 恢复进度
                nvs_get_u32(nvs, "downloaded", &resume->downloaded_size);
                nvs_get_u32(nvs, "total", &resume->total_size);
                nvs_get_u8(nvs, "slot", &resume->partition_slot);
                nvs_get_u32(nvs, "crc32", &resume->file_crc32);
                
                size_t etag_len = sizeof(resume->etag);
                nvs_get_str(nvs, "etag", resume->etag, &etag_len);
                
                size_t mod_len = sizeof(resume->last_modified);
                nvs_get_str(nvs, "lastmod", resume->last_modified, &mod_len);
                
                ESP_LOGI("RESUME", "Resuming download from %u bytes", 
                        resume->downloaded_size);
            }
        }
        nvs_close(nvs);
    }
    
    // 检查服务器是否支持断点续传
    check_resume_support(resume);
    
    return ESP_OK;
}

// 检查服务器支持
bool check_resume_support(resume_manager_t *resume) {
    esp_http_client_config_t config = {
        .url = resume->url,
        .method = HTTP_METHOD_HEAD,
    };
    
    esp_http_client_handle_t client = esp_http_client_init(&config);
    if (!client) return false;
    
    // 设置超时
    esp_http_client_set_timeout_ms(client, 5000);
    
    // 执行HEAD请求
    esp_err_t err = esp_http_client_perform(client);
    
    if (err == ESP_OK) {
        // 检查Accept-Ranges头
        char accept_ranges[32] = {0};
        esp_http_client_get_header(client, "Accept-Ranges", 
                                  accept_ranges, sizeof(accept_ranges));
        
        if (strstr(accept_ranges, "bytes") != NULL) {
            resume->resume_supported = true;
        }
        
        // 获取文件大小
        char content_length[32] = {0};
        esp_http_client_get_header(client, "Content-Length", 
                                  content_length, sizeof(content_length));
        
        if (content_length[0] != '\0') {
            resume->total_size = atoi(content_length);
        }
        
        // 获取ETag和Last-Modified
        esp_http_client_get_header(client, "ETag", 
                                  resume->etag, sizeof(resume->etag));
        esp_http_client_get_header(client, "Last-Modified", 
                                  resume->last_modified, 
                                  sizeof(resume->last_modified));
    }
    
    esp_http_client_cleanup(client);
    return resume->resume_supported;
}

// 执行断点续传下载
esp_err_t perform_resume_download(resume_manager_t *resume, 
                                 esp_ota_handle_t ota_handle)
 {
    esp_http_client_config_t config = {
        .url = resume->url,
        .method = HTTP_METHOD_GET,
        .timeout_ms = 30000,
        .buffer_size = 4096,
        .buffer_size_tx = 4096,
    };
    
    esp_http_client_handle_t client = esp_http_client_init(&config);
    if (!client) return ESP_FAIL;
    
    // 设置Range头(如果需要)
    if (resume->resume_supported && resume->downloaded_size > 0) {
        char range_header[64];
        snprintf(range_header, sizeof(range_header), 
                "bytes=%u-", resume->downloaded_size);
        esp_http_client_set_header(client, "Range", range_header);
        
        ESP_LOGI("RESUME", "Resuming from byte %u", resume->downloaded_size);
    }
    
    // 执行请求
    esp_err_t err = esp_http_client_open(client, 0);
    if (err != ESP_OK) {
        esp_http_client_cleanup(client);
        return err;
    }
    
    // 读取响应头
    int status_code = esp_http_client_fetch_headers(client);
    
    if (status_code == 206) {  // Partial Content
        ESP_LOGI("RESUME", "Server supports partial content");
    } else if (status_code == 200) {  // OK (从头开始)
        if (resume->downloaded_size > 0) {
            ESP_LOGW("RESUME", "Server doesn't support resume, starting over");
            resume->downloaded_size = 0;
        }
    } else {
        ESP_LOGE("RESUME", "HTTP error: %d", status_code);
        esp_http_client_close(client);
        esp_http_client_cleanup(client);
        return ESP_FAIL;
    }
    
    // 下载数据
    uint8_t buffer[4096];
    int read_len;
    uint32_t total_downloaded = resume->downloaded_size;
    
    resume->start_time = time(NULL);
    
    while (1) {
        read_len = esp_http_client_read(client, (char*)buffer, sizeof(buffer));
        if (read_len <= 0) {
            break;
        }
        
        // 写入OTA分区
        err = esp_ota_write(ota_handle, buffer, read_len);
        if (err != ESP_OK) {
            ESP_LOGE("RESUME", "OTA write failed: %s", esp_err_to_name(err));
            break;
        }
        
        total_downloaded += read_len;
        
        // 定期保存进度
        if (total_downloaded % (1024 * 1024) == 0) {  // 每1MB
            save_download_progress(resume, total_downloaded, ota_handle);
            
            // 计算下载速度
            time_t now = time(NULL);
            double elapsed = difftime(now, resume->start_time);
            double speed = total_downloaded / elapsed / 1024;  // KB/s
            
            ESP_LOGI("RESUME", "Progress: %u/%u (%.1f%%) Speed: %.1f KB/s", 
                    total_downloaded, resume->total_size,
                    (total_downloaded * 100.0) / resume->total_size,
                    speed);
        }
    }
    
    // 检查下载完成
    if (total_downloaded >= resume->total_size) {
        ESP_LOGI("RESUME", "Download completed: %u bytes", total_downloaded);
        
        // 清除进度保存
        clear_download_progress();
        
        err = ESP_OK;
    } else {
        // 保存进度以便恢复
        save_download_progress(resume, total_downloaded, ota_handle);
        
        ESP_LOGW("RESUME", "Download interrupted at %u bytes", total_downloaded);
        err = ESP_FAIL;
    }
    
    esp_http_client_close(client);
    esp_http_client_cleanup(client);
    
    return err;
}

// 保存下载进度
void save_download_progress(resume_manager_t *resume, 
                           uint32_t downloaded, 
                           esp_ota_handle_t ota_handle)
 {
    nvs_handle_t nvs;
    if (nvs_open("ota_resume", NVS_READWRITE, &nvs) == ESP_OK) {
        // 保存基本信息
        nvs_set_str(nvs, "url", resume->url);
        nvs_set_u32(nvs, "downloaded", downloaded);
        nvs_set_u32(nvs, "total", resume->total_size);
        
        // 保存OTA句柄信息(分区槽位)
        const esp_partition_t *target = esp_ota_get_partition(ota_handle);
        if (target) {
            uint8_t slot = 0;
            if (target->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_0) slot = 0;
            else if (target->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_1) slot = 1;
            nvs_set_u8(nvs, "slot", slot);
        }
        
        // 保存验证信息
        if (resume->etag[0] != '\0') {
            nvs_set_str(nvs, "etag", resume->etag);
        }
        if (resume->last_modified[0] != '\0') {
            nvs_set_str(nvs, "lastmod", resume->last_modified);
        }
        
        // 保存CRC32(如果已计算)
        if (resume->file_crc32 != 0) {
            nvs_set_u32(nvs, "crc32", resume->file_crc32);
        }
        
        nvs_commit(nvs);
        nvs_close(nvs);
        
        resume->last_update = time(NULL);
    }
}

// 清除下载进度
void clear_download_progress(void) {
    nvs_handle_t nvs;
    if (nvs_open("ota_resume", NVS_READWRITE, &nvs) == ESP_OK) {
        // 删除所有相关键
        nvs_erase_key(nvs, "url");
        nvs_erase_key(nvs, "downloaded");
        nvs_erase_key(nvs, "total");
        nvs_erase_key(nvs, "slot");
        nvs_erase_key(nvs, "etag");
        nvs_erase_key(nvs, "lastmod");
        nvs_erase_key(nvs, "crc32");
        
        nvs_commit(nvs);
        nvs_close(nvs);
    }
}

十、射频敏感场景优化

10.1 Wi-Fi稳定性增强完整方案

// Wi-Fi优化管理器
typedef struct {
    wifi_config_t wifi_config;
    wifi_ps_type_t power_save_mode;
    int8_t tx_power;
    wifi_bandwidth_t bandwidth;
    wifi_second_chan_t second_channel;
    wifi_auth_mode_t auth_mode;
    wifi_cipher_type_t cipher_type;
    uint8_t retry_count;
    uint32_t reconnect_interval;
    time_t last_disconnect;
    uint32_t disconnect_count;
    bool static_ip_enabled;
    tcpip_adapter_ip_info_t static_ip;
} wifi_optimizer_t;

// 初始化Wi-Fi优化
void init_wifi_optimizer(wifi_optimizer_t *optimizer) {
    memset(optimizer, 0, sizeof(wifi_optimizer_t));
    
    // 默认配置
    optimizer->power_save_mode = WIFI_PS_NONE;  // 禁用省电模式
    optimizer->tx_power = 84;                  // +20dBm
    optimizer->bandwidth = WIFI_BW_HT40;       // 40MHz带宽
    optimizer->retry_count = 5;                // 重试次数
    optimizer->reconnect_interval = 5000;      // 5秒重连间隔
    
    // 静态IP配置(可选)
    optimizer->static_ip_enabled = false;
    IP4_ADDR(&optimizer->static_ip.ip, 192, 168, 1, 100);
    IP4_ADDR(&optimizer->static_ip.gw, 192, 168, 1, 1);
    IP4_ADDR(&optimizer->static_ip.netmask, 255, 255, 255, 0);
    
    // 从NVS加载配置
    load_wifi_config_from_nvs(optimizer);
}

// 应用Wi-Fi优化配置
void apply_wifi_optimization(wifi_optimizer_t *optimizer) {
    ESP_LOGI("WIFI_OPT", "Applying Wi-Fi optimization settings");
    
    // 1. 配置电源模式
    esp_wifi_set_ps(optimizer->power_save_mode);
    
    // 2. 设置发射功率
    esp_wifi_set_max_tx_power(optimizer->tx_power);
    
    // 3. 配置带宽
    esp_wifi_set_bandwidth(ESP_IF_WIFI_STA, optimizer->bandwidth);
    
    // 4. 配置重传机制
    wifi_sta_config_t *sta_config = &optimizer->wifi_config.sta;
    sta_config->listen_interval = 3;  // 监听间隔
    sta_config->threshold.authmode = optimizer->auth_mode;
    
    // 5. 配置快速扫描
    wifi_scan_config_t scan_config = {
        .ssid = NULL,
        .bssid = NULL,
        .channel = 0,
        .show_hidden = true,
        .scan_type = WIFI_SCAN_TYPE_ACTIVE,
        .scan_time.active.min = 100,
        .scan_time.active.max = 300,
    };
    esp_wifi_scan_start(&scan_config, false);
    
    // 6. 配置LwIP参数
    if (optimizer->static_ip_enabled) {
        tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
        tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &optimizer->static_ip);
    }
    
    // 7. 配置TCP窗口大小
    optimize_tcp_parameters();
    
    // 8. 启用Wi-Fi事件监控
    register_wifi_event_handlers(optimizer);
}

// 优化TCP参数
void optimize_tcp_parameters(void) {
    // 调整LwIP内存池大小
    #ifdef CONFIG_LWIP_TCP
    // 增加TCP窗口大小
    #define TCP_WND 32768
    #define TCP_MSS 1460
    
    // 调整TCP缓冲池
    #define MEM_SIZE 16000
    #define PBUF_POOL_SIZE 16
    #define PBUF_POOL_BUFSIZE 1700
    #endif
    
    // 配置TCP重传参数
    struct timeval tv;
    tv.tv_sec = 30;
    tv.tv_usec = 0;
    
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock >= 0) {
        // 设置套接字选项
        int keep_alive = 1;
        int keep_idle = 5;      // 5秒后开始发送保活包
        int keep_interval = 5;  // 5秒发送一次
        int keep_count = 3;     // 最多3次
        
        setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keep_alive, sizeof(int));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keep_idle, sizeof(int));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval, sizeof(int));
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keep_count, sizeof(int));
        
        // 禁用Nagle算法
        int no_delay = 1;
        setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &no_delay, sizeof(int));
        
        close(sock);
    }
}

// Wi-Fi事件处理器
static void wifi_event_handler(void* arg, esp_event_base_t event_base, 
                              int32_t event_id, void* event_data)
 {
    wifi_optimizer_t *optimizer = (wifi_optimizer_t*)arg;
    
    switch (event_id) {
        case WIFI_EVENT_STA_START:
            ESP_LOGI("WIFI", "Wi-Fi STA started");
            break;
            
        case WIFI_EVENT_STA_CONNECTED:
            ESP_LOGI("WIFI", "Connected to AP");
            optimizer->disconnect_count = 0;
            break;
            
        case WIFI_EVENT_STA_DISCONNECTED: {
            wifi_event_sta_disconnected_t* event = 
                (wifi_event_sta_disconnected_t*) event_data;
            
            optimizer->last_disconnect = time(NULL);
            optimizer->disconnect_count++;
            
            ESP_LOGW("WIFI", "Disconnected from AP (reason: %d)", event->reason);
            
            // 根据断开原因调整策略
            switch (event->reason) {
                case WIFI_REASON_AUTH_EXPIRE:
                case WIFI_REASON_AUTH_FAIL:
                    // 认证问题,可能需要重新配置
                    ESP_LOGW("WIFI", "Authentication issue, checking credentials");
                    break;
                    
                case WIFI_REASON_ASSOC_LEAVE:
                    // 正常离开
                    break;
                    
                default:
                    // 其他原因,尝试重连
                    if (optimizer->disconnect_count < optimizer->retry_count) {
                        ESP_LOGI("WIFI", "Reconnecting in %d ms...", 
                                optimizer->reconnect_interval);
                        vTaskDelay(pdMS_TO_TICKS(optimizer->reconnect_interval));
                        esp_wifi_connect();
                    } else {
                        ESP_LOGE("WIFI", "Max reconnection attempts reached");
                    }
            }
            break;
        }
            
        case WIFI_EVENT_STA_AUTHMODE_CHANGE:
            ESP_LOGI("WIFI", "Auth mode changed");
            break;
    }
}

// 动态调整Wi-Fi参数
void dynamic_wifi_adjustment(wifi_optimizer_t *optimizer, int8_t rssi) {
    // 根据RSSI动态调整参数
    if (rssi > -50) {
        // 信号强,可以使用高性能模式
        optimizer->tx_power = 78;  // +19dBm
        optimizer->bandwidth = WIFI_BW_HT40;
        
    } else if (rssi > -70) {
        // 信号中等
        optimizer->tx_power = 82;  // +20dBm
        optimizer->bandwidth = WIFI_BW_HT20;
        
    } else {
        // 信号弱,使用保守设置
        optimizer->tx_power = 84;  // +20dBm(最大)
        optimizer->bandwidth = WIFI_BW_HT20;
        optimizer->retry_count = 8;  // 增加重试次数
    }
    
    // 应用调整
    esp_wifi_set_max_tx_power(optimizer->tx_power);
    esp_wifi_set_bandwidth(ESP_IF_WIFI_STA, optimizer->bandwidth);
    
    ESP_LOGD("WIFI_ADJUST", "RSSI: %d, TX Power: %d, BW: %d", 
            rssi, optimizer->tx_power, optimizer->bandwidth);
}

// Wi-Fi健康检查
bool check_wifi_health(wifi_optimizer_t *optimizer) {
    wifi_ap_record_t ap_info;
    if (esp_wifi_sta_get_ap_info(&ap_info) != ESP_OK) {
        return false;
    }
    
    // 检查RSSI
    if (ap_info.rssi < -80) {
        ESP_LOGW("WIFI_HEALTH", "Weak signal: %d dBm", ap_info.rssi);
        return false;
    }
    
    // 检查信噪比(如果有)
    if (ap_info.primary > 0 && ap_info.primary <= 14) {
        // 2.4GHz频段,检查干扰
        if (ap_info.rssi > -60 && ap_info.rssi - ap_info.noise < 20) {
            ESP_LOGW("WIFI_HEALTH", "Poor SNR: %d dB", 
                    ap_info.rssi - ap_info.noise);
            return false;
        }
    }
    
    // 检查连接稳定性
    time_t now = time(NULL);
    if (optimizer->disconnect_count > 3 && 
        difftime(now, optimizer->last_disconnect) < 300) {
        ESP_LOGW("WIFI_HEALTH", "Unstable connection (%d disconnects)", 
                optimizer->disconnect_count);
        return false;
    }
    
    return true;
}

10.2 分时段升级策略实现

// 分时段升级调度器
typedef struct {
    uint8_t upgrade_window_start;  // 升级窗口开始时间(小时)
    uint8_t upgrade_window_end;    // 升级窗口结束时间(小时)
    uint8_t max_duration_hours;    // 最大升级时长(小时)
    bool weekend_enabled;          // 是否允许周末升级
    bool holiday_excluded;         // 是否排除节假日
    char timezone[32];             // 时区
    struct tm last_upgrade_time;// 上次升级时间
    struct tm next_upgrade_time;// 下次计划升级时间
    uint32_t upgrade_count;        // 升级次数统计
    SemaphoreHandle_t mutex;       // 互斥锁
} upgrade_scheduler_t;

// 初始化升级调度器
void init_upgrade_scheduler(upgrade_scheduler_t *scheduler) {
    memset(scheduler, 0, sizeof(upgrade_scheduler_t));
    
    // 默认配置:凌晨1点到5点
    scheduler->upgrade_window_start = 1;
    scheduler->upgrade_window_end = 5;
    scheduler->max_duration_hours = 2;
    scheduler->weekend_enabled = true;
    scheduler->holiday_excluded = true;
    strlcpy(scheduler->timezone, "CST-8", sizeof(scheduler->timezone));
    
    // 从NVS加载配置
    nvs_handle_t nvs;
    if (nvs_open("upgrade_sched", NVS_READONLY, &nvs) == ESP_OK) {
        nvs_get_u8(nvs, "window_start", &scheduler->upgrade_window_start);
        nvs_get_u8(nvs, "window_end", &scheduler->upgrade_window_end);
        nvs_get_u8(nvs, "max_duration", &scheduler->max_duration_hours);
        nvs_get_u8(nvs, "weekend_enabled", (uint8_t*)&scheduler->weekend_enabled);
        nvs_get_u8(nvs, "holiday_excluded", (uint8_t*)&scheduler->holiday_excluded);
        nvs_close(nvs);
    }
    
    scheduler->mutex = xSemaphoreCreateMutex();
    
    // 初始化时间
    initialize_system_time(scheduler->timezone);
    
    // 计算下次升级时间
    calculate_next_upgrade_time(scheduler);
}

// 检查当前是否在升级窗口内
bool is_in_upgrade_window(upgrade_scheduler_t *scheduler) {
    struct tm timeinfo;
    if (!get_local_time(&timeinfo, scheduler->timezone)) {
        return false;
    }
    
    // 检查是否在允许的时间窗口内
    int current_hour = timeinfo.tm_hour;
    if (current_hour < scheduler->upgrade_window_start || 
        current_hour >= scheduler->upgrade_window_end) {
        return false;
    }
    
    // 检查周末是否允许
    if (!scheduler->weekend_enabled) {
        // 0=周日, 6=周六
        if (timeinfo.tm_wday == 0 || timeinfo.tm_wday == 6) {
            return false;
        }
    }
    
    // 检查节假日(如果有节假日数据)
    if (scheduler->holiday_excluded && is_holiday(&timeinfo)) {
        return false;
    }
    
    // 检查设备是否空闲
    if (!is_device_idle()) {
        return false;
    }
    
    // 检查网络条件
    if (!is_network_good_for_upgrade()) {
        return false;
    }
    
    return true;
}

// 计算下次升级时间
void calculate_next_upgrade_time(upgrade_scheduler_t *scheduler) {
    struct tm timeinfo;
    get_local_time(&timeinfo, scheduler->timezone);
    
    // 默认设置为明天的升级窗口开始时间
    struct tm next_time = timeinfo;
    next_time.tm_mday += 1;
    next_time.tm_hour = scheduler->upgrade_window_start;
    next_time.tm_min = 0;
    next_time.tm_sec = 0;
    
    // 调整周末和节假日
    mktime(&next_time);
    
    while (1) {
        // 检查周末
        if (!scheduler->weekend_enabled && 
            (next_time.tm_wday == 0 || next_time.tm_wday == 6)) {
            next_time.tm_mday += 1;
            mktime(&next_time);
            continue;
        }
        
        // 检查节假日
        if (scheduler->holiday_excluded && is_holiday(&next_time)) {
            next_time.tm_mday += 1;
            mktime(&next_time);
            continue;
        }
        
        break;
    }
    
    scheduler->next_upgrade_time = next_time;
    
    ESP_LOGI("UPGRADE_SCHED", "Next upgrade scheduled for: %04d-%02d-%02d %02d:%02d",
            next_time.tm_year + 1900, next_time.tm_mon + 1, next_time.tm_mday,
            next_time.tm_hour, next_time.tm_min);
}

// 升级调度任务
void upgrade_scheduler_task(void *pvParameters) {
    upgrade_scheduler_t *scheduler = (upgrade_scheduler_t*)pvParameters;
    
    while (1) {
        // 检查是否有待处理的升级
        bool pending_upgrade = check_pending_upgrade();
        
        if (pending_upgrade) {
            // 检查是否在升级窗口内
            if (is_in_upgrade_window(scheduler)) {
                ESP_LOGI("UPGRADE_SCHED", "Starting scheduled upgrade");
                
                // 执行升级
                perform_scheduled_upgrade(scheduler);
                
                // 更新统计
                xSemaphoreTake(scheduler->mutex, portMAX_DELAY);
                scheduler->upgrade_count++;
                scheduler->last_upgrade_time = get_current_time();
                xSemaphoreGive(scheduler->mutex);
                
                // 计算下次升级时间
                calculate_next_upgrade_time(scheduler);
                
            } else {
                // 不在升级窗口内,计算等待时间
                time_t now = time(NULL);
                struct tm *next_tm = &scheduler->next_upgrade_time;
                time_t next_time = mktime(next_tm);
                
                double seconds_to_wait = difftime(next_time, now);
                
                if (seconds_to_wait > 0) {
                    ESP_LOGI("UPGRADE_SCHED", "Waiting %.0f seconds for next upgrade window", 
                            seconds_to_wait);
                    
                    // 休眠到升级窗口
                    vTaskDelay(pdMS_TO_TICKS((uint32_t)(seconds_to_wait * 1000)));
                } else {
                    // 已经过了计划时间,立即检查
                    vTaskDelay(pdMS_TO_TICKS(60000)); // 1分钟后重试
                }
            }
        } else {
            // 没有待处理的升级,定期检查
            vTaskDelay(pdMS_TO_TICKS(300000)); // 5分钟
        }
    }
}

// 执行计划升级
void perform_scheduled_upgrade(upgrade_scheduler_t *scheduler) {
    // 记录开始时间
    time_t start_time = time(NULL);
    
    // 获取升级信息
    upgrade_info_t upgrade_info;
    if (!get_upgrade_info(&upgrade_info)) {
        ESP_LOGE("UPGRADE_SCHED", "Failed to get upgrade info");
        return;
    }
    
    // 检查固件大小
    if (upgrade_info.firmware_size > get_available_space()) {
        ESP_LOGE("UPGRADE_SCHED", "Insufficient space for upgrade");
        return;
    }
    
    // 执行升级
    esp_err_t err = perform_ota_update(upgrade_info.url, 
                                       upgrade_info.firmware_size);
    
    // 检查升级时长
    time_t end_time = time(NULL);
    double duration_hours = difftime(end_time, start_time) / 3600.0;
    
    if (duration_hours > scheduler->max_duration_hours) {
        ESP_LOGW("UPGRADE_SCHED", "Upgrade took %.1f hours, exceeding limit of %d hours", 
                duration_hours, scheduler->max_duration_hours);
        
        // 记录超时事件
        log_upgrade_timeout(duration_hours);
    }
    
    if (err == ESP_OK) {
        ESP_LOGI("UPGRADE_SCHED", "Scheduled upgrade completed successfully");
        
        // 上报成功
        report_upgrade_result("success", upgrade_info.version, duration_hours);
        
    } else {
        ESP_LOGE("UPGRADE_SCHED", "Scheduled upgrade failed: %s", 
                esp_err_to_name(err));
        
        // 上报失败
        report_upgrade_result("failed", upgrade_info.version, duration_hours);
        
        // 检查是否需要重试
        if (should_retry_upgrade(err)) {
            schedule_upgrade_retry(scheduler);
        }
    }
}

// 检查设备是否空闲
bool is_device_idle(void) {
    // 检查CPU使用率
    uint32_t idle_time = xTaskGetIdleRunTimeCounter();
    uint32_t total_time = xTaskGetTickCount() * portTICK_PERIOD_MS;
    
    double cpu_usage = 100.0 - ((idle_time * 100.0) / total_time);
    
    if (cpu_usage > 30.0) {  // CPU使用率超过30%
        ESP_LOGD("DEVICE_IDLE", "CPU usage too high: %.1f%%", cpu_usage);
        return false;
    }
    
    // 检查内存使用
    uint32_t free_heap = esp_get_free_heap_size();
    uint32_t min_heap = esp_get_minimum_free_heap_size();
    
    if (free_heap < 20000) {  // 空闲堆内存小于20KB
        ESP_LOGD("DEVICE_IDLE", "Free heap too low: %u bytes", free_heap);
        return false;
    }
    
    // 检查网络活动
    if (is_network_busy()) {
        ESP_LOGD("DEVICE_IDLE", "Network is busy");
        return false;
    }
    
    // 检查业务逻辑(如果有)
    #ifdef CONFIG_BUSINESS_LOGIC_ENABLED
    if (is_business_critical_operation()) {
        ESP_LOGD("DEVICE_IDLE", "Business critical operation in progress");
        return false;
    }
    #endif
    
    return true;
}

// 检查网络条件
bool is_network_good_for_upgrade(void) {
    wifi_ap_record_t ap_info;
    if (esp_wifi_sta_get_ap_info(&ap_info) != ESP_OK) {
        return false;
    }
    
    // 检查信号强度
    if (ap_info.rssi < -75) {  // RSSI小于-75dBm
        ESP_LOGD("NETWORK_CHECK", "Signal too weak: %d dBm", ap_info.rssi);
        return false;
    }
    
    // 检查网络延迟(简单ping测试)
    if (!ping_test("8.8.8.8", 3, 1000)) {
        ESP_LOGD("NETWORK_CHECK", "Network latency too high");
        return false;
    }
    
    // 检查下载速度(如果可能)
    if (!check_download_speed(1000000)) {  // 需要至少1Mbps
        ESP_LOGD("NETWORK_CHECK", "Download speed too low");
        return false;
    }
    
    return true;
}

十一、行业最佳实践

11.1 企业级OTA架构设计

11.2 能耗敏感设备优化

// 低功耗OTA管理器
typedef struct {
    uint8_t battery_level;          // 电池电量
    uint8_t battery_threshold;      // 升级电量阈值
    bool charging;                  // 是否在充电
    uint32_t download_chunk_size;   // 下载分块大小
    uint32_t sleep_interval;        // 休眠间隔
    wifi_ps_type_t wifi_power_save; // Wi-Fi省电模式
    uint32_t max_download_time;     // 最大下载时间
    time_t optimal_upgrade_time;    // 最佳升级时间
    bool scheduled_upgrade;         // 是否计划升级
} low_power_ota_manager_t;

// 初始化低功耗OTA
void init_low_power_ota(low_power_ota_manager_t *manager) {
    memset(manager, 0, sizeof(low_power_ota_manager_t));
    
    // 默认配置
    manager->battery_threshold = 30;      // 30%电量阈值
    manager->download_chunk_size = 65536; // 64KB分块
    manager->sleep_interval = 1000;       // 1秒休眠
    manager->wifi_power_save = WIFI_PS_MIN_MODEM; // 最小省电模式
    manager->max_download_time = 300;     // 5分钟最大下载时间
    
    // 检测电池状态
    manager->battery_level = read_battery_level();
    manager->charging = is_charging();
    
    ESP_LOGI("LOW_POWER_OTA", "Battery: %d%%%s", 
            manager->battery_level, 
            manager->charging ? " (Charging)" : "");
}

// 检查是否可以执行低功耗OTA
bool can_perform_low_power_ota(low_power_ota_manager_t *manager) {
    // 检查电池电量
    if (!manager->charging && manager->battery_level < manager->battery_threshold) {
        ESP_LOGW("LOW_POWER_OTA", "Battery too low for OTA: %d%%", 
                manager->battery_level);
        return false;
    }
    
    // 检查充电状态(如果电量低但正在充电,可以等待)
    if (manager->battery_level < manager->battery_threshold && manager->charging) {
        ESP_LOGI("LOW_POWER_OTA", "Waiting for battery to charge...");
        
        // 等待充电到阈值
        while (manager->battery_level < manager->battery_threshold) {
            vTaskDelay(pdMS_TO_TICKS(60000)); // 每分钟检查一次
            manager->battery_level = read_battery_level();
        }
    }
    
    // 检查网络连接
    if (!is_wifi_connected()) {
        ESP_LOGW("LOW_POWER_OTA", "Wi-Fi not connected");
        return false;
    }
    
    // 检查固件大小(估算下载时间)
    uint32_t firmware_size = get_firmware_size();
    uint32_t estimated_time = firmware_size / 50000; // 假设50KB/s速度
    
    if (estimated_time > manager->max_download_time) {
        ESP_LOGW("LOW_POWER_OTA", "Estimated download time too long: %d seconds", 
                estimated_time);
        return false;
    }
    
    return true;
}

// 执行低功耗OTA
esp_err_t perform_low_power_ota(low_power_ota_manager_t *manager, 
                               const char *firmware_url)
 {
    ESP_LOGI("LOW_POWER_OTA", "Starting low-power OTA update");
    
    // 1. 配置低功耗Wi-Fi模式
    esp_wifi_set_ps(manager->wifi_power_save);
    
    // 2. 获取固件信息
    uint32_t firmware_size = get_remote_file_size(firmware_url);
    if (firmware_size == 0) {
        return ESP_FAIL;
    }
    
    // 3. 分块下载
    esp_err_t err = ESP_OK;
    uint32_t downloaded = 0;
    uint8_t *buffer = (uint8_t*)malloc(manager->download_chunk_size);
    
    if (!buffer) {
        return ESP_ERR_NO_MEM;
    }
    
    // 4. 分块下载循环
    while (downloaded < firmware_size) {
        // 检查电池电量(如果在执行过程中电量下降)
        if (!manager->charging) {
            manager->battery_level = read_battery_level();
            if (manager->battery_level < 10) {  // 紧急阈值
                ESP_LOGE("LOW_POWER_OTA", "Battery critical, aborting OTA");
                err = ESP_FAIL;
                break;
            }
        }
        
        // 计算本次下载的大小
        uint32_t chunk_size = manager->download_chunk_size;
        if (downloaded + chunk_size > firmware_size) {
            chunk_size = firmware_size - downloaded;
        }
        
        // 下载数据块
        err = download_chunk(firmware_url, downloaded, chunk_size, buffer);
        if (err != ESP_OK) {
            break;
        }
        
        // 写入OTA分区
        // ... OTA写入代码 ...
        
        downloaded += chunk_size;
        
        // 休眠以节省功耗
        vTaskDelay(pdMS_TO_TICKS(manager->sleep_interval));
        
        // 可选:进入轻睡眠
        #ifdef CONFIG_PM_ENABLE
        esp_light_sleep_start();
        #endif
    }
    
    free(buffer);
    
    // 恢复Wi-Fi模式
    esp_wifi_set_ps(WIFI_PS_NONE);
    
    return err;
}

// 智能充电检测
void smart_charging_detection(low_power_ota_manager_t *manager) {
    // 检测充电器类型
    charging_type_t charger_type = detect_charger_type();
    
    switch (charger_type) {
        case CHARGER_TYPE_SLOW:
            // 慢速充电,使用更保守的策略
            manager->battery_threshold = 50;
            manager->download_chunk_size = 32768;  // 32KB
            break;
            
        case CHARGER_TYPE_FAST:
            // 快速充电,可以使用更激进的策略
            manager->battery_threshold = 20;
            manager->download_chunk_size = 131072; // 128KB
            break;
            
        case CHARGER_TYPE_WIRELESS:
            // 无线充电,考虑效率
            manager->battery_threshold = 40;
            manager->download_chunk_size = 65536;  // 64KB
            break;
            
        default:
            // 未知充电器,使用保守策略
            manager->battery_threshold = 50;
            manager->download_chunk_size = 32768;
            break;
    }
    
    ESP_LOGI("LOW_POWER_OTA", "Charger type: %d, threshold: %d%%, chunk: %dKB", 
            charger_type, manager->battery_threshold, 
            manager->download_chunk_size / 1024);
}

11.3 大规模部署建议

// 大规模部署配置
typedef struct {
    uint32_t device_count;           // 设备总数
    uint32_t batch_size;             // 批次大小
    uint32_t batch_interval;         // 批次间隔(秒)
    char cdn_url[256];               // CDN URL
    char regional_cdn[5][256];       // 区域CDN
    bool load_balancing;             // 是否负载均衡
    bool geolocation_routing;        // 是否地理位置路由
    uint32_t retry_policy;           // 重试策略
    uint32_t timeout_policy;         // 超时策略
    char monitoring_url[256];        // 监控URL
    char analytics_url[256];         // 分析URL
} mass_deployment_config_t;

// 大规模OTA调度
void mass_ota_scheduler(mass_deployment_config_t *config, 
                       const char *firmware_version)
 {
    ESP_LOGI("MASS_DEPLOY", "Starting mass deployment of version %s", 
            firmware_version);
    
    // 1. 计算批次
    uint32_t total_batches = (config->device_count + config->batch_size - 1) / 
                            config->batch_size;
    
    ESP_LOGI("MASS_DEPLOY", "Total devices: %d, Batch size: %d, Batches: %d", 
            config->device_count, config->batch_size, total_batches);
    
    // 2. 分批执行
    for (uint32_t batch = 0; batch < total_batches; batch++) {
        uint32_t start_device = batch * config->batch_size;
        uint32_t end_device = min((batch + 1) * config->batch_size, 
                                 config->device_count);
        
        ESP_LOGI("MASS_DEPLOY", "Starting batch %d (devices %d-%d)", 
                batch + 1, start_device + 1, end_device);
        
        // 3. 通知本批次设备开始升级
        notify_devices_for_upgrade(start_device, end_device, firmware_version);
        
        // 4. 监控本批次升级进度

发表评论