AP menu
All checks were successful
ESP32 Build & Release / build (push) Successful in 6m40s

This commit is contained in:
2026-09-12 13:47:34 +02:00
parent d691febfe4
commit 3708674bbb
14 changed files with 289 additions and 120 deletions

View File

@@ -22,6 +22,7 @@
#include "nvs_flash.h"
#include "nvs.h"
#include "cJSON.h"
#include "wifi_manager.h"
#include "ota_manager.h"
static const char *TAG = "ota";
@@ -30,7 +31,42 @@ static const char *TAG = "ota";
#define GITEA_RELEASE_API_URL "https://git.rasmusbendtsen.dk/api/v1/repos/rasmus/MTGcompanion/releases/latest"
#define GITEA_FIRMWARE_FALLBACK_URL "https://git.rasmusbendtsen.dk/rasmus/MTGcompanion/releases/download/latest/mtg-rfid-companion.bin"
#define GITEA_API_BUF_SIZE (8192)
#define GITEA_API_BUF_SIZE (5120)
/* Let's Encrypt ISRG Root X1 CA Certificate (valid through 2035) */
static const char s_isrg_root_x1_pem[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n"
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n"
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n"
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n"
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n"
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n"
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n"
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n"
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n"
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB\n"
"5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n"
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n"
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n"
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n"
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n"
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n"
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n"
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n"
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n"
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n"
"NFtY2PwByVS5uCbMiogzihDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORA\n"
"zI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7UrTkX\n"
"WStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdCjNP\n"
"ElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVcoyi\n"
"3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4Rg\n"
"qsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRG\n"
"unUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demy\n"
"PxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n"
"-----END CERTIFICATE-----\n";
static SemaphoreHandle_t s_ota_mux = NULL;
static ota_status_t s_status = OTA_STATUS_IDLE;
@@ -215,6 +251,14 @@ static void ota_check_task(void *arg)
ESP_LOGI(TAG, "Querying Gitea release API: %s", GITEA_RELEASE_API_URL);
if (wifi_manager_acquire_net_lock(pdMS_TO_TICKS(15000)) != ESP_OK) {
ESP_LOGW(TAG, "Network lock busy, cannot start OTA check");
set_state(OTA_STATUS_FAILED, "Network busy");
s_ota_task_handle = NULL;
vTaskDelete(NULL);
return;
}
http_rx_buf_t rx = {
.buf = malloc(GITEA_API_BUF_SIZE),
.len = 0,
@@ -222,6 +266,7 @@ static void ota_check_task(void *arg)
};
if (!rx.buf) {
wifi_manager_release_net_lock();
set_state(OTA_STATUS_FAILED, "Out of memory");
s_ota_task_handle = NULL;
vTaskDelete(NULL);
@@ -232,15 +277,16 @@ static void ota_check_task(void *arg)
esp_http_client_config_t cfg = {
.url = GITEA_RELEASE_API_URL,
.transport_type = HTTP_TRANSPORT_OVER_SSL,
.timeout_ms = 10000,
.timeout_ms = 15000,
.event_handler = http_rx_event_handler,
.user_data = &rx,
.buffer_size = 2048,
.crt_bundle_attach = esp_crt_bundle_attach,
.buffer_size = 1024,
.cert_pem = s_isrg_root_x1_pem,
};
esp_http_client_handle_t client = esp_http_client_init(&cfg);
if (!client) {
wifi_manager_release_net_lock();
free(rx.buf);
set_state(OTA_STATUS_FAILED, "HTTP init failed");
s_ota_task_handle = NULL;
@@ -255,6 +301,8 @@ static void ota_check_task(void *arg)
esp_err_t ret = esp_http_client_perform(client);
int status_code = esp_http_client_get_status_code(client);
esp_http_client_cleanup(client);
wifi_manager_release_net_lock();
if (ret != ESP_OK || status_code != 200) {
char err_msg[64];
@@ -415,6 +463,14 @@ static void ota_download_task(void *arg)
s_bytes_read = 0;
s_total_bytes = s_release.binary_size;
if (wifi_manager_acquire_net_lock(pdMS_TO_TICKS(15000)) != ESP_OK) {
ESP_LOGW(TAG, "Network lock busy, cannot start OTA download");
set_state(OTA_STATUS_FAILED, "Network busy");
s_ota_task_handle = NULL;
vTaskDelete(NULL);
return;
}
set_state(OTA_STATUS_DOWNLOADING, "Starting download...");
ESP_LOGI(TAG, "Starting HTTPS OTA from: %s", s_release.download_url);
@@ -424,7 +480,7 @@ static void ota_download_task(void *arg)
.timeout_ms = 30000,
.keep_alive_enable = true,
.buffer_size = 2048,
.crt_bundle_attach = esp_crt_bundle_attach,
.cert_pem = s_isrg_root_x1_pem,
};
esp_https_ota_config_t ota_cfg = {
@@ -434,6 +490,7 @@ static void ota_download_task(void *arg)
esp_https_ota_handle_t ota_handle = NULL;
esp_err_t err = esp_https_ota_begin(&ota_cfg, &ota_handle);
if (err != ESP_OK || ota_handle == NULL) {
wifi_manager_release_net_lock();
ESP_LOGE(TAG, "esp_https_ota_begin failed: %s", esp_err_to_name(err));
set_state(OTA_STATUS_FAILED, "Failed to connect to image");
s_ota_task_handle = NULL;
@@ -448,6 +505,7 @@ static void ota_download_task(void *arg)
if (memcmp(new_app_info.app_elf_sha256, running->app_elf_sha256, sizeof(new_app_info.app_elf_sha256)) == 0) {
ESP_LOGW(TAG, "Incoming image has identical ELF SHA-256 as running app - aborting flash write");
esp_https_ota_abort(ota_handle);
wifi_manager_release_net_lock();
set_state(OTA_STATUS_UP_TO_DATE, "Firmware is already up to date");
s_ota_task_handle = NULL;
vTaskDelete(NULL);
@@ -459,6 +517,7 @@ static void ota_download_task(void *arg)
if (s_cancel_requested) {
ESP_LOGW(TAG, "OTA canceled by user");
esp_https_ota_abort(ota_handle);
wifi_manager_release_net_lock();
set_state(OTA_STATUS_IDLE, "Update canceled");
s_ota_task_handle = NULL;
vTaskDelete(NULL);
@@ -481,6 +540,7 @@ static void ota_download_task(void *arg)
if (err == ESP_OK) {
if (esp_https_ota_is_complete_data_received(ota_handle)) {
esp_err_t finish_err = esp_https_ota_finish(ota_handle);
wifi_manager_release_net_lock();
if (finish_err == ESP_OK) {
/* Store installed release hash in NVS */
nvs_handle_t nvs_h;
@@ -502,11 +562,13 @@ static void ota_download_task(void *arg)
}
} else {
esp_https_ota_abort(ota_handle);
wifi_manager_release_net_lock();
set_state(OTA_STATUS_FAILED, "Incomplete download");
}
} else {
ESP_LOGE(TAG, "esp_https_ota_perform failed: %s", esp_err_to_name(err));
esp_https_ota_abort(ota_handle);
wifi_manager_release_net_lock();
set_state(OTA_STATUS_FAILED, "Flash write failed");
}