Basic OTA Support

This commit is contained in:
dark98
2026-09-03 01:59:06 +01:00
parent c926159a81
commit 7bde605438
2 changed files with 98 additions and 1 deletions
+97 -1
View File
@@ -6,6 +6,7 @@
#include "esp_http_server.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_ota_ops.h"
#include "esp_wifi.h"
#include "nvs.h"
#include "nvs_flash.h"
@@ -21,6 +22,13 @@ static httpd_handle_t s_http_server;
static char s_sta_ssid[33];
static char s_sta_password[65];
static void ota_reboot_task(void *arg)
{
(void)arg;
vTaskDelay(pdMS_TO_TICKS(1000));
esp_restart();
}
static void copy_wifi_string(uint8_t *destination, size_t destination_size, const char *source)
{
size_t length = strlen(source);
@@ -189,6 +197,86 @@ static esp_err_t provisioning_get(httpd_req_t *request)
return httpd_resp_send(request, page, HTTPD_RESP_USE_STRLEN);
}
static esp_err_t ota_get(httpd_req_t *request)
{
const char *page =
"<!doctype html><html><head><meta name=viewport content=\"width=device-width\">"
"<title>ABrobot OTA</title><style>body{font:16px sans-serif;max-width:480px;margin:2em auto;padding:0 1em}"
"input,button{font:inherit;padding:.6em;width:100%;box-sizing:border-box}button{margin-top:1em}"
"progress{width:100%;margin-top:1em}#message{margin-top:1em}</style></head><body>"
"<h1>Firmware update</h1><form id=form><input id=file type=file accept=\".bin,application/octet-stream\" required>"
"<button type=submit>Upload firmware</button></form><progress id=progress value=0 max=100 hidden></progress>"
"<p id=message></p><script>const form=document.getElementById('form'),file=document.getElementById('file'),"
"progress=document.getElementById('progress'),message=document.getElementById('message');"
"form.onsubmit=async event=>{event.preventDefault();if(!file.files.length)return;"
"let selected=file.files[0];progress.hidden=false;progress.value=0;message.textContent='Uploading...';"
"try{let response=await fetch('/ota',{method:'POST',headers:{'Content-Type':'application/octet-stream'},body:selected});"
"if(!response.ok)throw new Error(await response.text());progress.value=100;message.textContent='Update installed. Rebooting...';"
"}catch(error){message.textContent='Update failed: '+error.message;progress.hidden=true}};</script></body></html>";
httpd_resp_set_type(request, "text/html");
return httpd_resp_send(request, page, HTTPD_RESP_USE_STRLEN);
}
static esp_err_t ota_post(httpd_req_t *request)
{
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
if (!update_partition || request->content_len == 0 || request->content_len > update_partition->size) {
httpd_resp_send_err(request, HTTPD_400_BAD_REQUEST, "Firmware image is too large or unavailable");
return ESP_ERR_INVALID_SIZE;
}
esp_ota_handle_t ota_handle;
esp_err_t err = esp_ota_begin(update_partition, request->content_len, &ota_handle);
if (err != ESP_OK) {
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Could not begin firmware update");
return err;
}
uint8_t *buffer = malloc(4096);
if (!buffer) {
esp_ota_abort(ota_handle);
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Not enough memory for firmware update");
return ESP_ERR_NO_MEM;
}
size_t remaining = request->content_len;
while (remaining > 0) {
size_t chunk_size = remaining < 4096 ? remaining : 4096;
int received = httpd_req_recv(request, (char *)buffer, chunk_size);
if (received <= 0) {
free(buffer);
esp_ota_abort(ota_handle);
httpd_resp_send_err(request, HTTPD_400_BAD_REQUEST, "Firmware upload interrupted");
return ESP_FAIL;
}
err = esp_ota_write(ota_handle, buffer, received);
if (err != ESP_OK) {
free(buffer);
esp_ota_abort(ota_handle);
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Could not write firmware image");
return err;
}
remaining -= (size_t)received;
}
free(buffer);
err = esp_ota_end(ota_handle);
if (err != ESP_OK) {
httpd_resp_send_err(request, HTTPD_400_BAD_REQUEST, "Invalid firmware image");
return err;
}
err = esp_ota_set_boot_partition(update_partition);
if (err != ESP_OK) {
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Could not select new firmware");
return err;
}
httpd_resp_sendstr(request, "Firmware update installed. Rebooting.");
ESP_LOGI(TAG, "OTA image installed to %s; rebooting", update_partition->label);
xTaskCreate(ota_reboot_task, "ota_reboot", 2048, NULL, 5, NULL);
return ESP_OK;
}
static esp_err_t provisioning_post(httpd_req_t *request)
{
char body[160] = {0};
@@ -235,15 +323,21 @@ static esp_err_t provisioning_post(httpd_req_t *request)
static void start_provisioning_server(void)
{
if (s_http_server != NULL) return;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
if (httpd_start(&s_http_server, &config) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start provisioning web server");
return;
}
const httpd_uri_t get_uri = {.uri = "/", .method = HTTP_GET, .handler = provisioning_get};
const httpd_uri_t ota_get_uri = {.uri = "/ota", .method = HTTP_GET, .handler = ota_get};
const httpd_uri_t ota_post_uri = {.uri = "/ota", .method = HTTP_POST, .handler = ota_post};
const httpd_uri_t scan_uri = {.uri = "/scan", .method = HTTP_GET, .handler = provisioning_scan};
const httpd_uri_t post_uri = {.uri = "/configure", .method = HTTP_POST, .handler = provisioning_post};
httpd_register_uri_handler(s_http_server, &get_uri);
httpd_register_uri_handler(s_http_server, &ota_get_uri);
httpd_register_uri_handler(s_http_server, &ota_post_uri);
httpd_register_uri_handler(s_http_server, &scan_uri);
httpd_register_uri_handler(s_http_server, &post_uri);
}
@@ -286,7 +380,9 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t e
int8_t rssi = 0;
if (esp_wifi_sta_get_ap_info(&record) == ESP_OK) rssi = record.rssi;
set_status(WIFI_STATE_CONNECTED, rssi);
ESP_LOGI(TAG, "Wi-Fi connected");
start_provisioning_server();
const ip_event_got_ip_t *got_ip = (const ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG, "Wi-Fi connected, web server at http://" IPSTR, IP2STR(&got_ip->ip_info.ip));
}
}