首页 > 解决方案 > 适用于来自 AWS 的深度睡眠设备的 FreeRTOS OTA

问题描述

背景

我有一个在 freeRTOS 上运行的小型电池供电系统。根据任何适当的互联网连接设备,我需要定期运行 OTA 更新。问题在于,在电池供电的情况下,该设备 99.9% 的寿命都处于深度睡眠状态。

当设备唤醒时,可以通过发布到设备的 OTA/更新主题从 AWS 发布 OTA 更新。从控制台,您只能使用 QOS = 0。但从内部,比如 lambda,我相信可以使用 QOS = 1。

{
"state": {
        "desired": {
            "ota_url":"https://s3-ap-southeast-2.amazonaws.com/my.awesome.bucket/signed_binary_v21.bin"
        }
    }
}

问题

  1. 如何修改此方法以成功更新一次睡眠 15 分钟并唤醒可能 10 秒的设备。在唤醒期间,它会发送一条消息。是否有某种方法可以将所需的 OTA/更新隐藏在 AWS 的响应中以某种方式包含在内。我还没有弄清楚阴影是如何真正起作用的。或者你可以指定一个重试周期和时间来继续尝试吗?
  2. 从安全角度来看,这种方法是否与最新的最佳实践基本一致:签名二进制、加密闪存和安全启动等。

非常感谢。

标签: mqttesp32aws-iotfreertosesp-idf

解决方案


IDF 附带了一个非常简单的 OTA 示例。正如您对问题的评论中所建议的那样,该示例下载固件更新,如果更新版本存在导致重置的错误,它将自动恢复到以前的图像。这是示例的操作部分:

extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");
esp_err_t _ota_http_event_handler(esp_http_client_event_t* evt);
#define FIRMWARE_UPGRADE_URL "https://yourserver.com/somefolder/somefirmware.bin"

void simple_ota_task(void* pvParameter)
{
    esp_http_client_config_t config = {
        .url = FIRMWARE_UPGRADE_URL,
        .cert_pem = (char*)server_cert_pem_start,
        .event_handler = _ota_http_event_handler,
    };
    esp_err_t ret = esp_https_ota(&config);
    if (ret == ESP_OK)
        ESP_LOGW("ota", "Upgrade success");
    else 
        ESP_LOGE(TAG, "Upgrade failure");

    esp_restart();
}

void foo()
{
    // after initializing WiFi, create a task to execute OTA:
    //
    xTaskCreate(&simple_ota_task, "ota_task", 8192, NULL, 5, NULL);
}

// event handler callback referenced above, it has no functional purpose
// just dumps info log output
esp_err_t _ota_http_event_handler(esp_http_client_event_t* evt)
{
    switch (evt->event_id) {
    case HTTP_EVENT_ERROR:
        ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
        break;
    case HTTP_EVENT_ON_DATA:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
        break;
    case HTTP_EVENT_ON_FINISH:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
        break;
    case HTTP_EVENT_DISCONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
        break;
    }
    return ESP_OK;
}

要设置嵌入证书,请通过检查 bin 文件所在站点的 SSL 证书来获取公钥,使用 Web 浏览器保存它,然后将其转换为 Base64,即 PEM 格式。(我使用了一些网页。)在我的例子中,我创建了一个与 /main 目录相同级别的目录,称为 /server_certs,并将 Base64 转换保存在该目录中作为 ca_cert.pem。(这也太迂腐了吧?)

然后将这些行添加到 /main 目录中的 CMakeFiles.txt 中:

# Embed the server root certificate into the final binary
set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem)
register_component()

我不清楚的是如何确定是否有更新的版本可用,如果有一个我无法辨别的内置方式,并且不想无缘无故下载更新,永远。所以我推出了自己的版本,在固件中嵌入了一个版本字符串,在我的服务器上创建了一个返回当前版本的 WebAPI 入口点(两者都是手工维护的,直到我能想到更好的方法......我想实现)和当字符串不匹配时调用 OTA 功能。它看起来很像这样:

// The WebAPI returns data in JSON format, 
// so if a method returns a string it is quoted.
#define FW_VERSION "\"00.09.015\""

// the HTTP request has just completed, payload stored in recv_buf
//
// tack a null terminator using an index maintained by the HTTP transfer
recv_buf[pos + 1] = 0;
// test for success
if (strncmp(recv_buf, "HTTP/1.1 200 OK", 15) == 0)
{
    // find the end of the headers
    char *p = strstr(recv_buf, "\r\n\r\n");
    if (p)
    {
        ESP_LOGI("***", "version: %s  content %s", FW_VERSION, (p + 4));
        if (strcmp((p + 4), FW_VERSION) > 0)
        {
            // execute OTA task
            foo();
        }
        else
        {
            // Assumes the new version has run far enough to be 
            // considered working, commits the update.  It doesn't
            // hurt anything to call this any number of times.
            esp_ota_mark_app_valid_cancel_rollback();
        }
    }
}

如果您不使用 CMake/Ninja 构建工具,请考虑检查一下,它比基于 MingW32 的工具集快得多。


推荐阅读