

Hahahah. Awesome. Have fun! You just need a simple webserver. The builtin one will do and then you use the ota functions of the ESP IDF.
Hahahah. Awesome. Have fun! You just need a simple webserver. The builtin one will do and then you use the ota functions of the ESP IDF.
Back in school my friends all flashed their mcus with 4-8MB images over serial with 115200 baud. I set up ota updates over wifi. They were all fascinated by my speedy flashes. However when I offered to help them set it up, not one was interested because their setup was working as is and slow flashing is not a “bad” thing since it gave them an excuse to do other things.
We are talking minutes vs seconds here.
The teachers were surprised by my quick progress and iterations. When I told them my “trick” the gave me bonus points but also were not interested in learning how to do ota which was very easy. A simple 20 minute first time setup would have saved sooo much time during the year.
I don’t think the promise chain is really needed here.
I used this script:
Relevent code on the esp:
You can ignore my cpp stuff and just put this in the handler of the stock webserver.
auto ota = vfs->addHandler(makeDirectory("ota")); { ota->addHandler(makeDirect([](auto &con) { if (con.req->method != HTTP_POST) return HandlerReturn::UNHANDLED; // https://github.com/espressif/esp-idf/tree/master/examples/system/ota/native_ota_example/main // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/ota.html auto updatePartition = esp_ota_get_next_update_partition(nullptr); if (updatePartition == nullptr) return sendError(con,500, "No free ota partition found!"); esp_ota_handle_t otaHandle; auto err = esp_ota_begin(updatePartition, con.req->content_len, &otaHandle); if (err != ESP_OK) return sendError(con, 500, std::string{"Can't start ota update: "} + esp_err_to_name(err), true); int receivedBytes = 0; do { auto end = httpd_req_recv(con.req, buf.data(), buf.size()); // ESP_LOGE(TAG, "Received %d", receivedBytes); // hexDump("RECV:", buf.data(), end); if (end <= 0) { esp_ota_abort(otaHandle); return sendError(con, 500, "Error receiving", true); } err = esp_ota_write(otaHandle, buf.data(), end); if (err != ESP_OK) { esp_ota_abort(otaHandle); return sendError(con, 500, std::string{"Error writing: "} + esp_err_to_name(err), true); } receivedBytes += end; } while (receivedBytes < con.req->content_len); err = esp_ota_end(otaHandle); if (err != ESP_OK) return sendError(con, 500, std::string{"Failed to end: "} + esp_err_to_name(err), true); err = esp_ota_set_boot_partition(updatePartition); if (err != ESP_OK) return sendError(con, 500, std::string{"esp_ota_set_boot_partition failed: "} + esp_err_to_name(err), true); auto ret = sendOK(con); FactoryResetServiceCon().reboot(1000 / portTICK_PERIOD_MS); return ret; })); }
I also used a custom partition table for 2 partitions so that when my program crashes it can just go back to boot the previous version.
Here it is for reference:
partitions.csv
# Name, Type, SubType, Offset, Size, Flags # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild nvs, data, nvs, 0x011000, 0x006000, otadata, data, ota, 0x017000, 0x002000, phy_init, data, phy, 0x019000, 0x001000, ota_0, app, ota_0, 0x020000, 0x1F0000, ota_1, app, ota_1, 0x210000, 0x1F0000,
Note: This partition table is for a special model of the ESP32 though.
Also another disclaimer: This code does not represent my current coding abilities and may be outdated - it worked well though.