OTA (Over-the-Air Firmware Update)
The Ota class is a transport-agnostic OTA firmware update engine wrapping
ESP-IDF’s esp_ota_ops: a single mutex-serialized update session
(begin() -> write() … -> finish() / abort()) with all
failures reported via std::error_code. It performs no I/O itself — feed it
image bytes from any transport and it streams them into the next OTA app
partition. The first chunk is validated against the ESP image magic byte
(0xE9) and the incoming application descriptor (project name, version, build
date) is extracted, logged and exposed; finish() runs the full image
validation (including the appended SHA-256) and sets the boot partition, while
the restart is a separate explicit restart() call.
Rollback helpers (is_pending_verify(), mark_app_valid(),
mark_app_invalid_and_rollback()) integrate with the bootloader’s app
rollback support (CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE): an app booted
pending-verify must call mark_app_valid() after its own health checks or
the bootloader rolls back to the previous image on the next reset.
For OTA over a raw byte stream (such as the
usb_device vendor / WebUSB interface), the header
detail/ota_stream_protocol.hpp provides a host-testable framed protocol —
CRC-32-verified little-endian frames (BEGIN / DATA / FINISH /
ABORT and OK / ERROR / PROGRESS replies) with an incremental,
resynchronizing parser and a bounded 4096-byte maximum payload. The hosted
espp OTA Console web
app speaks this protocol over WebUSB directly from a Chromium browser.
The frame codec itself lives in the reusable Stream Frame APIs
component (detail/ota_stream_protocol.hpp re-exports it and layers the OTA
message types on top); to run OTA alongside other protocols (crash-dump, CAN,
…) on one stream, register it as a module with the
Dispatcher APIs — the ota example does exactly this (OTA is
module id 0).
Command line: build → OTA
The ota component ships a project_include.cmake and a pure-Python host
tool (components/ota/python/espp_ota), so any project using it can build and
OTA-flash over USB in one step — the OTA counterpart to idf.py flash:
pip install pyusb # once (needs a libusb backend)
idf.py ota-usb # builds the app, then OTAs it over USB
The tool draws a live progress bar (percent, size, transfer speed, ETA) and
colorizes its output. Because idf.py captures the target’s output, the bar is
drawn straight to the controlling terminal so it still animates in place:
For full control (a specific serial, chunk size, discovery probe) run it directly
with python -m espp_ota flash build/<app>.bin — see
components/ota/python/README.md.
API Reference
Header File
Classes
-
class Ota : public espp::BaseComponent
Transport-agnostic OTA (over-the-air) firmware update engine.
Wraps ESP-IDF’s `esp_ota_ops` in an idiomatic espp API: no exceptions, all failures reported via `std::error_code`, and a single mutex-serialized update session (`begin()` -> `write()`… -> `finish()` / `abort()`). The component performs no I/O of its own — feed it image bytes from ANY transport (USB vendor / WebUSB stream, HTTP request body, TCP socket, UART, SD card, …) and it streams them into the next OTA app partition.
On the first chunk of `write()` the image is sanity-checked (the ESP image magic byte 0xE9) and the embedded application descriptor (`esp_app_desc_t`: project name, version, build date) is extracted, logged and exposed via `incoming_app_description()`; with `Config::reject_same_version` set, an image whose version matches the running app is rejected. `finish()` runs the full image validation (including the appended SHA-256) via `esp_ota_end()` and sets the boot partition, but does NOT restart — call `restart()` when the application is ready to reboot into the new image.
Rollback
The rollback helpers (`is_pending_verify()`, `mark_app_valid()`, `mark_app_invalid_and_rollback()`) require the bootloader rollback support to be compiled in (`CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y`). With rollback enabled, a freshly-updated app boots in the `ESP_OTA_IMG_PENDING_VERIFY` state and MUST call `mark_app_valid()` after its own health checks pass — otherwise the bootloader rolls back to the previous image on the next reset. Call `mark_app_invalid_and_rollback()` to actively reject the new image and reboot into the previous one.
OTA Example (USB / WebUSB + WiFi / Ethernet HTTP)
namespace proto = espp::detail::ota_stream; // --- The OTA engine (transport-agnostic) ----------------------------------- espp::Ota ota({.reject_same_version = false, .progress_callback = [&logger](size_t written, size_t total) { // log every ~64 KiB so a big image doesn't spam the log if (total > 0 && (written % (64 * 1024)) < 4096) logger.info("OTA progress: {} / {} bytes", written, total); }, .log_level = espp::Logger::Verbosity::INFO}); const auto running = ota.running_app_description(); logger.info("Running '{}' version '{}' (built {} {}) from partition '{}' ({} bytes)", running.project_name, running.version, running.date, running.time, ota.running_partition_label(), ota.running_partition_size()); logger.info("Next update will target partition '{}' ({} bytes)", ota.update_partition_label(), ota.update_partition_size()); // --- Rollback handling ------------------------------------------------------ // With CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE, an app booted right after an // OTA update is in the PENDING_VERIFY state: it will ROLL BACK to the previous // image on the next reset unless it is confirmed. This example demonstrates // HOST-DRIVEN confirmation: it deliberately does NOT mark itself valid here. // Instead it stays pending and lets the host confirm it (MARK_VALID over the // OTA protocol) once the host has verified the device is healthy — a broken // build could otherwise self-validate right before failing. The ota-console web // app / `espp-ota` CLI do this after reconnecting. // // (If your own product prefers device self-validation, run your health checks // here and call ota.mark_app_valid() / ota.mark_app_invalid_and_rollback().) if (ota.is_pending_verify()) { logger.warn("This image is PENDING VERIFY (first boot after an OTA update). Waiting for the " "host to confirm it (MARK_VALID); it rolls back on the next reset if not."); } // --- Transport 1: USB vendor / WebUSB (espp::UsbDevice) -------------------- // The vendor interface carries the framed OTA stream protocol (see // detail/ota_stream_protocol.hpp); the hosted web app // https://esp-cpp.github.io/espp/apps/ota_console.html speaks it in the // browser. RX bytes arrive in the TinyUSB task context, so they are queued // and dispatched from a worker task below (esp_ota_begin's flash erase can // take seconds and must not block the USB stack). espp::UsbDevice::Config usb_cfg; usb_cfg.manufacturer = "espp"; usb_cfg.product = "espp OTA"; usb_cfg.log_level = espp::Logger::Verbosity::INFO; espp::UsbDevice::VendorFunction vendor; vendor.interface_name = "espp OTA (WebUSB)"; vendor.webusb = true; // advertise BOS / WebUSB / MS OS 2.0 descriptors vendor.landing_page_url = "esp-cpp.github.io/espp/apps/ota_console.html"; usb_cfg.vendor = vendor; // Add a CDC-ACM function so the SAME native USB cable also carries the log // console. `route_console = true` makes UsbDevice redirect the ESP console // (stdout: printf / ESP_LOG / espp::Logger) to this CDC interface at the end of // initialize(), teeing to the UART0 console so `idf.py monitor` still works. So // one native USB cable carries both the OTA vendor stream and the logs -- no // manual VFS plumbing in the app. CDC uses 1 interrupt IN + 1 bulk IN + 1 bulk // OUT; with the vendor function's bulk IN + OUT that is 3 IN / 2 OUT endpoints, // within the ESP32-S3 budget. espp::UsbDevice::CdcFunction cdc; cdc.interface_name = "espp OTA console"; cdc.route_console = true; // redirect the console to this CDC interface (tee to UART0) usb_cfg.cdc = cdc; espp::UsbDevice usb(usb_cfg); std::mutex usb_rx_mutex; std::condition_variable usb_rx_cv; std::deque<std::vector<uint8_t>> usb_rx_queue; size_t usb_rx_queued_bytes = 0; bool usb_rx_overflow = false; // The protocol is one-frame-in-flight (the host waits for OK/ERROR before // the next DATA), so a well-behaved host queues at most ~one frame while the // worker is busy. Cap the queue anyway: the worker can legitimately block // for seconds inside esp_ota_begin()/end() (flash erase / SHA validation), // and a misbehaving host that pipelines OUT transfers must not be able to // exhaust device RAM. 8 max-size frames of headroom is far more than the // protocol ever needs. static constexpr size_t kMaxQueuedRxBytes = 8 * espp::detail::ota_stream::kMaxFrameSize; usb.set_vendor_receive_callback([&](std::span<const uint8_t> data) { // TinyUSB task context: just queue the bytes and wake the worker. { std::lock_guard<std::mutex> lock(usb_rx_mutex); if (usb_rx_queued_bytes + data.size() > kMaxQueuedRxBytes) { // Overflow: drop everything (partial frames are useless once bytes // are missing) and let the worker abort + resynchronize + reply. usb_rx_queue.clear(); usb_rx_queued_bytes = 0; usb_rx_overflow = true; } else { usb_rx_queue.emplace_back(data.begin(), data.end()); usb_rx_queued_bytes += data.size(); } } usb_rx_cv.notify_one(); }); std::error_code usb_ec; if (!usb.initialize(usb_ec)) logger.error("Failed to initialize USB device: {}", usb_ec.message()); // On success the console is now on USB-CDC (cdc.route_console above), teed to // UART0 -- this and later logs travel over the native USB cable and UART0. // Route the vendor stream through a Dispatcher: OTA occupies module id 0 (its // opcodes are 0x0X). Other protocols (e.g. a crash-dump service on module 4) // could register alongside on the same stream and would be routed // independently; frames for unregistered modules are ignored rather than // mis-handled as malformed OTA frames. espp::Dispatcher dispatcher; bool restart_pending = false; // The OTA engine serializes sessions across ALL transports, but that alone // is not enough here: without ownership tracking a USB DATA/FINISH/ABORT // could append to / activate / cancel a session that HTTP started. Set only // after a successful USB BEGIN; cleared on every terminal path (FINISH and // ABORT end the session in all outcomes, and a failed write() aborts it). // If the host unplugs mid-session the flag stays set, so a reconnecting // host's ABORT is still honored (BEGIN would correctly fail busy first). bool usb_owns_session = false; auto handle_usb_frame = [&](const proto::Frame &frame) { // The device only handles requests; OTA replies (OK/ERROR/PROGRESS) share // module 0, so ignore any reply-flagged frame (e.g. a loopback echo) rather // than treating it as an unknown request. if (frame.is_reply()) return; std::error_code ec; auto reply_error = [&](const std::error_code &err, const std::string &context) { usb.write_vendor( proto::make_error(static_cast<uint32_t>(err.value()), context + ": " + err.message())); }; switch (static_cast<proto::MessageType>(frame.type)) { case proto::MessageType::Begin: { const auto image_size = proto::parse_u32_payload(frame); if (!image_size.has_value()) { reply_error(std::make_error_code(std::errc::invalid_argument), "malformed BEGIN"); break; } if (ota.begin(*image_size, ec)) { usb_owns_session = true; usb.write_vendor(proto::make_ok(0)); } else { // busy = another transport's session; ownership stays false reply_error(ec, "begin failed"); } break; } case proto::MessageType::Data: if (!usb_owns_session) { reply_error(std::make_error_code(std::errc::operation_not_permitted), "no USB-owned update session (send BEGIN first)"); break; } if (ota.write(frame.payload, ec)) { usb.write_vendor(proto::make_ok(static_cast<uint32_t>(ota.bytes_written()))); } else { usb_owns_session = false; // write() aborted the session on failure reply_error(ec, "write failed"); } break; case proto::MessageType::Finish: { if (!usb_owns_session) { reply_error(std::make_error_code(std::errc::operation_not_permitted), "no USB-owned update session (send BEGIN first)"); break; } const auto written = static_cast<uint32_t>(ota.bytes_written()); usb_owns_session = false; // finish() ends the session in all outcomes if (ota.finish(ec)) { usb.write_vendor(proto::make_ok(written)); restart_pending = true; // reply first; the worker restarts shortly } else { reply_error(ec, "finish (validate/activate) failed"); } break; } case proto::MessageType::Abort: { if (!usb_owns_session) { reply_error(std::make_error_code(std::errc::operation_not_permitted), "no USB-owned update session to abort"); break; } const auto written = static_cast<uint32_t>(ota.bytes_written()); usb_owns_session = false; // session over either way if (ota.abort(ec)) usb.write_vendor(proto::make_ok(written)); else reply_error(ec, "abort failed"); break; } case proto::MessageType::GetStatus: { // Report rollback status + the running firmware (so the host can show what // is now running before confirming it). Session-independent (no BEGIN). uint8_t flags = 0; #if defined(CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE) flags |= proto::kStatusRollbackSupported; if (ota.is_pending_verify()) flags |= proto::kStatusPendingVerify; #endif const auto desc = ota.running_app_description(); usb.write_vendor(proto::make_status(flags, desc.version, desc.project_name)); break; } case proto::MessageType::MarkValid: // The HOST confirms the running image after its own health checks — the app // must not confirm itself. Cancels the pending rollback. if (ota.mark_app_valid(ec)) usb.write_vendor(proto::make_ok(0)); else reply_error(ec, "mark valid failed"); break; case proto::MessageType::MarkInvalid: // Reject the running image: roll back to the previous app and reboot. // mark_app_invalid_and_rollback() does NOT return on success (the device // reboots), so DON'T pre-send OK: the reboot / USB disconnect IS the // success signal to the host. It only returns on *failure* (e.g. no valid // image to roll back to), so the reply below is reached only then and an // ERROR is the sole reply. Sending OK first would let the host report // success even when rollback was refused, leaving a stale ERROR on the // stream. ota.mark_app_invalid_and_rollback(ec); reply_error(ec, "rollback failed"); // only reached on failure break; default: reply_error(std::make_error_code(std::errc::not_supported), "unknown message type"); break; } }; // OTA is module id 0. The Dispatcher routes each frame for that module here. // Advertise it (name / web app / description) so the browser Device Hub can // discover and link it, and answer discovery queries over the vendor stream. dispatcher.register_module( proto::kModule, [&](const proto::Frame &frame) { handle_usb_frame(frame); }, {.name = "OTA", .app = "ota_console.html", .description = "Firmware update over USB"}); dispatcher.set_device_info(usb_cfg.product); dispatcher.serve_discovery([&](std::span<const uint8_t> frame) { usb.write_vendor(frame); }); espp::Task usb_task( {.callback = [&](std::mutex &, std::condition_variable &) -> bool { std::vector<std::vector<uint8_t>> chunks; bool overflowed = false; { std::unique_lock<std::mutex> lock(usb_rx_mutex); usb_rx_cv.wait_for(lock, 100ms, [&] { return !usb_rx_queue.empty() || usb_rx_overflow; }); chunks.assign(std::make_move_iterator(usb_rx_queue.begin()), std::make_move_iterator(usb_rx_queue.end())); usb_rx_queue.clear(); usb_rx_queued_bytes = 0; overflowed = usb_rx_overflow; usb_rx_overflow = false; } if (overflowed) { // Bytes were dropped: any in-flight frame/image is // unusable. Abort a USB-owned session, resync the // parser, and tell the host to start over. if (usb_owns_session) { std::error_code abort_ec; ota.abort(abort_ec); usb_owns_session = false; } dispatcher.reset(); usb.write_vendor(proto::make_error( static_cast<uint32_t>(std::make_error_code(std::errc::no_buffer_space).value()), "RX overflow: frames dropped; transfer aborted -- wait for OK " "replies between frames and restart the update")); return false; // dropped chunks are gone; skip parse } for (const auto &chunk : chunks) dispatcher.feed(chunk); if (restart_pending) { // give the final OK reply time to reach the host std::this_thread::sleep_for(750ms); ota.restart(); } return false; // don't stop the task }, .task_config = {.name = "ota_usb", .stack_size_bytes = 8192}}); usb_task.start(); // --- Transports 2 & 3: WiFi (or Ethernet) + HTTP push ----------------------- // NVS is required by the WiFi stack. esp_err_t nvs_err = nvs_flash_init(); if (nvs_err == ESP_ERR_NVS_NO_FREE_PAGES || nvs_err == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); nvs_err = nvs_flash_init(); } ESP_ERROR_CHECK(nvs_err); espp::WifiSta wifi_sta({.ssid = CONFIG_ESP_WIFI_SSID, .password = CONFIG_ESP_WIFI_PASSWORD, .num_connect_retries = CONFIG_ESP_MAXIMUM_RETRY, .on_connected = nullptr, .on_disconnected = nullptr, .on_got_ip = [&logger](ip_event_got_ip_t *eventdata) { logger.info("got IP: {}.{}.{}.{}", IP2STR(&eventdata->ip_info.ip)); logger.info(" browser upload page: http://{}.{}.{}.{}/ota", IP2STR(&eventdata->ip_info.ip)); logger.info(" curl --data-binary @build/ota_example.bin " "http://{}.{}.{}.{}/ota", IP2STR(&eventdata->ip_info.ip)); }, .log_level = espp::Logger::Verbosity::WARN}); // The HTTP server binds to every netif, so this exact same code serves OTA // over the espp `ethernet` component as well -- to use Ethernet, simply // bring up its netif (see the ethernet example) instead of WifiSta above. httpd_handle_t http_server = nullptr; httpd_config_t http_cfg = HTTPD_DEFAULT_CONFIG(); http_cfg.stack_size = 8192; // OTA handler streams through a 4 KiB buffer if (httpd_start(&http_server, &http_cfg) == ESP_OK) { const httpd_uri_t get_uri = { .uri = "/ota", .method = HTTP_GET, .handler = ota_get_handler, .user_ctx = nullptr}; const httpd_uri_t post_uri = { .uri = "/ota", .method = HTTP_POST, .handler = ota_post_handler, .user_ctx = &ota}; // Status + host-driven rollback endpoints backing the upload page's status // card (running firmware, pending-verify state, mark-valid / rollback). const httpd_uri_t status_uri = { .uri = "/status", .method = HTTP_GET, .handler = ota_status_handler, .user_ctx = &ota}; const httpd_uri_t mark_valid_uri = {.uri = "/mark-valid", .method = HTTP_POST, .handler = ota_mark_valid_handler, .user_ctx = &ota}; const httpd_uri_t rollback_uri = { .uri = "/rollback", .method = HTTP_POST, .handler = ota_rollback_handler, .user_ctx = &ota}; httpd_register_uri_handler(http_server, &get_uri); httpd_register_uri_handler(http_server, &post_uri); httpd_register_uri_handler(http_server, &status_uri); httpd_register_uri_handler(http_server, &mark_valid_uri); httpd_register_uri_handler(http_server, &rollback_uri); logger.info("HTTP OTA server ready: GET /ota (upload page + status), POST /ota (raw image), " "GET /status, POST /mark-valid, POST /rollback"); if constexpr (sizeof(CONFIG_EXAMPLE_OTA_HTTP_TOKEN) <= 1) { logger.warn("POST /ota is UNAUTHENTICATED (demo default): any peer that can reach this " "device can install structurally-valid firmware. Set EXAMPLE_OTA_HTTP_TOKEN in " "menuconfig to require a bearer token, and enable secure boot / signed images " "for real deployments."); } } else { logger.error("Failed to start HTTP server"); }
Public Types
-
using progress_callback_fn = std::function<void(size_t written, size_t total)>
Progress callback, invoked (with the session mutex held, so keep it short) after every successful write().
- Param written:
Total bytes written to the update partition so far.
- Param total:
Total expected image size in bytes (0 if unknown / streaming).
Public Functions
-
inline explicit Ota(const Config &config)
Construct the OTA engine. Does not touch the flash until begin().
- Parameters:
config – Configuration parameters.
-
inline ~Ota()
Aborts any still-active update session.
-
inline bool begin(size_t image_size, std::error_code &ec)
Start an update session targeting the next OTA app partition (esp_ota_get_next_update_partition()).
- Parameters:
image_size – Expected image size in bytes, or 0 if unknown / streaming (OTA_SIZE_UNKNOWN — the WHOLE update partition is erased up front, which can take several seconds; with a known size only the required range is erased).
ec – [out] Set on failure: a session is already active (device_or_resource_busy), no OTA partition exists (no_such_device), the image is larger than the partition (no_space_on_device), or the flash erase failed (io_error).
- Returns:
true if the session started, false otherwise (ec is set).
-
inline bool write(std::span<const uint8_t> data, std::error_code &ec)
Stream image bytes into the update partition.
The first chunk(s) are additionally used to validate the ESP image magic byte (0xE9) and — once enough bytes have arrived — to extract and log the incoming `esp_app_desc_t` (see incoming_app_description()). On ANY failure the session is aborted (a partially-written image is useless), so after an error the caller may simply start over with begin().
- Parameters:
data – Image bytes (any chunk size; empty is a no-op).
ec – [out] Set on failure: no active session (operation_not_permitted), bad image magic (illegal_byte_sequence), same-version rejection (file_exists, when Config::reject_same_version is set), the chunk crossing a declared image size (file_too_large — only that range was erased by begin()), or a flash write failure (io_error).
- Returns:
true if the bytes were written, false otherwise (ec is set).
-
inline bool finish(std::error_code &ec)
Finish the update: validate the complete image (esp_ota_end() checks the image structure and its appended SHA-256, plus the signature when secure boot is enabled) and set it as the boot partition.
Does NOT restart the device — call restart() when ready, so the application controls the timing (e.g. after flushing a reply to the host). The session is over after this call, whether it succeeds or fails.
- Parameters:
ec – [out] Set on failure: no active session (operation_not_permitted), image validation failed (illegal_byte_sequence), or setting the boot partition failed (io_error).
- Returns:
true if the new image is validated and set to boot, false otherwise.
-
inline bool abort(std::error_code &ec)
Abort the active update session (esp_ota_abort()) and reset the session state. Idempotent: succeeds as a no-op if no session is active.
- Parameters:
ec – [out] Set on failure (io_error if esp_ota_abort() fails).
- Returns:
true on success (or no-op), false otherwise (ec is set).
-
inline void restart()
Restart the device (esp_restart()); does not return. Call after a successful finish() to boot the new image.
-
inline bool is_pending_verify() const
Whether the RUNNING app is in the ESP_OTA_IMG_PENDING_VERIFY state, i.e. it was just installed by an OTA update and must call mark_app_valid() after its health checks, or the bootloader will roll back on the next reset.
Note
Only meaningful with CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y; without it this always returns false.
-
inline bool mark_app_valid(std::error_code &ec)
Mark the running app valid and cancel a pending rollback (esp_ota_mark_app_valid_cancel_rollback()). An app booted in the pending-verify state must call this once its own health checks pass.
- Parameters:
ec – [out] Set on failure (io_error).
- Returns:
true on success, false otherwise (ec is set).
-
inline bool mark_app_invalid_and_rollback(std::error_code &ec)
Mark the running app invalid and reboot into the previous image (esp_ota_mark_app_invalid_rollback_and_reboot()). Does not return on success.
- Parameters:
ec – [out] Set on failure (io_error, e.g. no valid app to roll back to or rollback support not enabled).
- Returns:
false (only returns on failure; ec is set).
-
inline std::string running_partition_label() const
Label of the partition the current app is running from (”” if unknown).
-
inline size_t running_partition_size() const
Size in bytes of the partition the current app is running from (0 if unknown).
-
inline std::string boot_partition_label() const
Label of the currently-configured BOOT partition (”” if unknown). After a successful finish() this is the just-written partition.
-
inline std::string update_partition_label() const
Label of the partition the next update session will (or the active one does) target (”” if the partition table has no OTA slot).
-
inline size_t update_partition_size() const
Size in bytes of the update target partition (0 if none) — the maximum image size an update can carry.
-
inline AppDescription running_app_description() const
Description (project name / version / build date) of the RUNNING app.
-
inline std::optional<AppDescription> incoming_app_description() const
Description of the INCOMING image, available once enough of the image (the first 288 bytes) has been written in the current / latest session; std::nullopt before then or if the image carries no valid app descriptor.
-
inline bool session_active() const
Whether an update session is active (begin() succeeded and neither finish() nor abort() has ended it).
-
inline size_t bytes_written() const
Bytes written to the update partition in the current session.
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns:
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters:
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns:
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters:
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters:
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns:
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters:
rate_limit – The rate limit to use for the logger
-
struct AppDescription
Application description extracted from an app image’s `esp_app_desc_t`.
-
struct Config
Configuration for the Ota engine.
Public Members
-
bool reject_same_version = {false}
Reject an incoming image whose `esp_app_desc_t` version string matches the running app’s version (checked on the first chunk of write()).
-
progress_callback_fn progress_callback = {nullptr}
Optional progress callback (see progress_callback_fn).
-
bool reject_same_version = {false}
-
using progress_callback_fn = std::function<void(size_t written, size_t total)>