From bf1830c48c2d03d49b4ad0e2bbe13997bc775a50 Mon Sep 17 00:00:00 2001 From: reubenmiller Date: Tue, 10 Nov 2026 16:11:01 +1000 Subject: [PATCH 1/5] feat: set devices up over USB with tedge-onboard Builds with the thin-edge.io client now include tiny-edge's provisioning library (APP_TEDGE_PROVISIONING), so tedge-onboard, run on a computer the device is plugged into, can give it a Wi-Fi network and register it in Cumulocity: - net.c gains app_net_switch_network(). It tries a network through the normal reconnect path, and stores it only once the device has an address. Otherwise it goes back to the stored network, so a mistyped password cannot strand a device. - lib/common/prov_tedge.c provides the library's hooks: Wi-Fi through that switch, identify by flashing the status LED, the tiny-edge Zephyr port's scan, and the application's firmware name and version. - A device with no Wi-Fi network starts the client first and waits for the tool, instead of rebooting into the Wi-Fi provisioner (the button pattern still starts it). It then waits for a network for as long as it takes, and the reconnect loop no longer retries without credentials. tiny-edge is pinned to its serial-onboarding branch for now. Co-Authored-By: Claude Opus 5.5 --- apps/modbus-server/src/main.c | 18 +++++- apps/modbus-server/src/tedge_glue.c | 4 ++ apps/opcua-server/src/main.c | 16 +++++- apps/opcua-server/src/tedge_glue.c | 4 ++ apps/snmp-agent/src/main.c | 16 +++++- apps/snmp-agent/src/tedge_glue.c | 4 ++ apps/tedge-agent/src/main.c | 16 +++++- apps/tedge-agent/src/tedge_glue.c | 4 ++ lib/common/CMakeLists.txt | 1 + lib/common/Kconfig | 12 ++++ lib/common/net.c | 86 ++++++++++++++++++++++++++++- lib/common/net.h | 18 ++++++ lib/common/prov_tedge.c | 72 ++++++++++++++++++++++++ lib/common/prov_tedge.h | 9 +++ west.yml | 2 +- 15 files changed, 271 insertions(+), 11 deletions(-) create mode 100644 lib/common/prov_tedge.c create mode 100644 lib/common/prov_tedge.h diff --git a/apps/modbus-server/src/main.c b/apps/modbus-server/src/main.c index 7a1c522..37b9aef 100644 --- a/apps/modbus-server/src/main.c +++ b/apps/modbus-server/src/main.c @@ -37,8 +37,20 @@ int main(void) return 0; } + bool onboarding = false; + +#if defined(CONFIG_APP_TEDGE_PROVISIONING) + /* No Wi-Fi network yet: the client starts first, since its + * provisioning library is how the device gets one (tedge-onboard over + * USB). The rest waits for the network as long as that takes. */ + onboarding = !app_net_has_network(); + if (onboarding) { + (void)tedge_glue_start(); + } +#endif + LOG_INF("Waiting for network..."); - ret = app_net_wait_connected(K_SECONDS(60)); + ret = app_net_wait_connected(onboarding ? K_FOREVER : K_SECONDS(60)); if (ret) { LOG_ERR("Network did not come up in time (%d)", ret); display_status_stage(DISPLAY_STAGE_ERROR); @@ -55,7 +67,9 @@ int main(void) #if defined(CONFIG_TEDGE) /* Device management runs alongside the protocol server. */ - (void)tedge_glue_start(); + if (!onboarding) { + (void)tedge_glue_start(); + } #endif return 0; diff --git a/apps/modbus-server/src/tedge_glue.c b/apps/modbus-server/src/tedge_glue.c index e01c89f..ab33490 100644 --- a/apps/modbus-server/src/tedge_glue.c +++ b/apps/modbus-server/src/tedge_glue.c @@ -17,6 +17,7 @@ #include "identity.h" #if defined(CONFIG_APP_WIFI_CRED_STORE) #include "prov_c8y.h" +#include "prov_tedge.h" #endif #include "status_led.h" @@ -478,6 +479,9 @@ int tedge_glue_start(void) LOG_ERR("tedge_init failed (%d)", rc); return rc; } +#if defined(CONFIG_APP_TEDGE_PROVISIONING) + (void)app_prov_tedge_init(); +#endif #if defined(CONFIG_APP_WIFI_CRED_STORE) /* Tenant and one-time password from the ZTP provisioner, if it left * any. The external ID already came through app_identity_device_id(). */ diff --git a/apps/opcua-server/src/main.c b/apps/opcua-server/src/main.c index b2b5697..90f7877 100644 --- a/apps/opcua-server/src/main.c +++ b/apps/opcua-server/src/main.c @@ -40,8 +40,20 @@ int main(void) return 0; } + bool onboarding = false; + +#if defined(CONFIG_APP_TEDGE_PROVISIONING) + /* No Wi-Fi network yet: the client starts first, since its + * provisioning library is how the device gets one (tedge-onboard over + * USB). The rest waits for the network as long as that takes. */ + onboarding = !app_net_has_network(); + if (onboarding) { + (void)tedge_glue_start(); + } +#endif + LOG_INF("Waiting for network..."); - ret = app_net_wait_connected(K_SECONDS(60)); + ret = app_net_wait_connected(onboarding ? K_FOREVER : K_SECONDS(60)); if (ret) { LOG_ERR("Network did not come up in time (%d)", ret); display_status_stage(DISPLAY_STAGE_ERROR); @@ -63,7 +75,7 @@ int main(void) #if defined(CONFIG_TEDGE) /* Device management runs alongside the protocol server. */ - if (tedge_glue_start() == 0) { + if (onboarding || tedge_glue_start() == 0) { #if defined(CONFIG_TEDGE_TELEMETRY) tedge_glue_start_telemetry(); #endif diff --git a/apps/opcua-server/src/tedge_glue.c b/apps/opcua-server/src/tedge_glue.c index bd8a402..44b3531 100644 --- a/apps/opcua-server/src/tedge_glue.c +++ b/apps/opcua-server/src/tedge_glue.c @@ -20,6 +20,7 @@ #include "opcua_server.h" #if defined(CONFIG_APP_WIFI_CRED_STORE) #include "prov_c8y.h" +#include "prov_tedge.h" #endif #include "status_led.h" @@ -149,6 +150,9 @@ int tedge_glue_start(void) LOG_ERR("tedge_init failed (%d)", rc); return rc; } +#if defined(CONFIG_APP_TEDGE_PROVISIONING) + (void)app_prov_tedge_init(); +#endif #if defined(CONFIG_APP_WIFI_CRED_STORE) /* Tenant and one-time password from the ZTP provisioner, if it left * any. The external ID already came through app_identity_device_id(). */ diff --git a/apps/snmp-agent/src/main.c b/apps/snmp-agent/src/main.c index 8592bdc..1366e3f 100644 --- a/apps/snmp-agent/src/main.c +++ b/apps/snmp-agent/src/main.c @@ -38,8 +38,20 @@ int main(void) return 0; } + bool onboarding = false; + +#if defined(CONFIG_APP_TEDGE_PROVISIONING) + /* No Wi-Fi network yet: the client starts first, since its + * provisioning library is how the device gets one (tedge-onboard over + * USB). The rest waits for the network as long as that takes. */ + onboarding = !app_net_has_network(); + if (onboarding) { + (void)tedge_glue_start(); + } +#endif + LOG_INF("Waiting for network..."); - ret = app_net_wait_connected(K_SECONDS(60)); + ret = app_net_wait_connected(onboarding ? K_FOREVER : K_SECONDS(60)); if (ret) { LOG_ERR("Network did not come up in time (%d)", ret); display_status_stage(DISPLAY_STAGE_ERROR); @@ -56,7 +68,7 @@ int main(void) #if defined(CONFIG_TEDGE) /* Device management runs alongside the protocol agent. */ - if (tedge_glue_start() == 0) { + if (onboarding || tedge_glue_start() == 0) { #if defined(CONFIG_TEDGE_TELEMETRY) tedge_glue_start_telemetry(); #endif diff --git a/apps/snmp-agent/src/tedge_glue.c b/apps/snmp-agent/src/tedge_glue.c index 81ed4a4..96a2405 100644 --- a/apps/snmp-agent/src/tedge_glue.c +++ b/apps/snmp-agent/src/tedge_glue.c @@ -15,6 +15,7 @@ #include "identity.h" #if defined(CONFIG_APP_WIFI_CRED_STORE) #include "prov_c8y.h" +#include "prov_tedge.h" #endif #include "status_led.h" @@ -125,6 +126,9 @@ int tedge_glue_start(void) LOG_ERR("tedge_init failed (%d)", rc); return rc; } +#if defined(CONFIG_APP_TEDGE_PROVISIONING) + (void)app_prov_tedge_init(); +#endif #if defined(CONFIG_APP_WIFI_CRED_STORE) /* Tenant and one-time password from the ZTP provisioner, if it left * any. The external ID already came through app_identity_device_id(). */ diff --git a/apps/tedge-agent/src/main.c b/apps/tedge-agent/src/main.c index e2b593e..d0f2dfa 100644 --- a/apps/tedge-agent/src/main.c +++ b/apps/tedge-agent/src/main.c @@ -37,15 +37,27 @@ int main(void) return 0; } + bool onboarding = false; + +#if defined(CONFIG_APP_TEDGE_PROVISIONING) + /* No Wi-Fi network yet: the client starts first, since its + * provisioning library is how the device gets one (tedge-onboard over + * USB). The rest waits for the network as long as that takes. */ + onboarding = !app_net_has_network(); + if (onboarding) { + (void)tedge_glue_start(); + } +#endif + LOG_INF("Waiting for network..."); - ret = app_net_wait_connected(K_SECONDS(60)); + ret = app_net_wait_connected(onboarding ? K_FOREVER : K_SECONDS(60)); if (ret) { LOG_ERR("Network did not come up in time (%d)", ret); display_status_stage(DISPLAY_STAGE_ERROR); return 0; } - ret = tedge_glue_start(); + ret = onboarding ? 0 : tedge_glue_start(); if (ret) { LOG_ERR("Device management did not start (%d)", ret); display_status_stage(DISPLAY_STAGE_ERROR); diff --git a/apps/tedge-agent/src/tedge_glue.c b/apps/tedge-agent/src/tedge_glue.c index 0a1541d..9ed2ea6 100644 --- a/apps/tedge-agent/src/tedge_glue.c +++ b/apps/tedge-agent/src/tedge_glue.c @@ -21,6 +21,7 @@ #include "net.h" #if defined(CONFIG_APP_WIFI_CRED_STORE) #include "prov_c8y.h" +#include "prov_tedge.h" #endif #include "status_led.h" @@ -179,6 +180,9 @@ int tedge_glue_start(void) LOG_ERR("tedge_init failed (%d)", rc); return rc; } +#if defined(CONFIG_APP_TEDGE_PROVISIONING) + (void)app_prov_tedge_init(); +#endif #if defined(CONFIG_APP_WIFI_CRED_STORE) /* Tenant and one-time password from the ZTP provisioner, if it left * any. The external ID already came through app_identity_device_id(). */ diff --git a/lib/common/CMakeLists.txt b/lib/common/CMakeLists.txt index 1fb2b40..20b6117 100644 --- a/lib/common/CMakeLists.txt +++ b/lib/common/CMakeLists.txt @@ -29,6 +29,7 @@ zephyr_library_sources(status_led.c) zephyr_library_sources_ifdef(CONFIG_APP_BOOT_REQUEST boot_request.c) zephyr_library_sources_ifdef(CONFIG_APP_WIFI_CRED_STORE prov_identity.c prov_c8y.c) zephyr_library_sources_ifdef(CONFIG_APP_PROV_HANDOFF prov_handoff.c) +zephyr_library_sources_ifdef(CONFIG_APP_TEDGE_PROVISIONING prov_tedge.c) # Identify: `tedge identify` blinks the status LED, the sw0 identify pattern # sends an event. diff --git a/lib/common/Kconfig b/lib/common/Kconfig index b3e9a73..337019d 100644 --- a/lib/common/Kconfig +++ b/lib/common/Kconfig @@ -301,6 +301,18 @@ config APP_BOOT_REQUEST help The boot request record in bootreq_partition (boot_request.h). +config APP_TEDGE_PROVISIONING + bool "Set the device up over USB with tedge-onboard" + default y + depends on TEDGE && APP_WIFI_CRED_STORE && !APP_WIFI_PROVISIONER + select TEDGE_PROVISIONING + help + tiny-edge's provisioning library on the console (Improv Serial): + tedge-onboard, run on a computer the device is plugged into, gives it + the Wi-Fi network and registers it in Cumulocity. A device without a + Wi-Fi network then waits for it, rather than starting the Wi-Fi + provisioner image (the button pattern still starts that). + config APP_PROV_HANDOFF bool "Hand over to the Wi-Fi provisioner image" default y if BOOTLOADER_MCUBOOT && $(dt_nodelabel_exists,prov_partition) diff --git a/lib/common/net.c b/lib/common/net.c index 8a657d1..5b0e80e 100644 --- a/lib/common/net.c +++ b/lib/common/net.c @@ -430,8 +430,21 @@ static int stored_creds(struct app_wifi_creds *out) } #endif +#if defined(CONFIG_APP_WIFI_CRED_STORE) && !defined(CONFIG_APP_WIFI_PROVISIONER) +/* A network being tried (app_net_switch_network()): what every connect + * uses until the trial ends. */ +static struct app_wifi_creds switch_creds; +static atomic_t switching; +#endif + int app_wifi_creds_resolve(struct app_wifi_creds *out) { +#if defined(CONFIG_APP_WIFI_CRED_STORE) && !defined(CONFIG_APP_WIFI_PROVISIONER) + if (atomic_get(&switching)) { + *out = switch_creds; + return 0; + } +#endif #if defined(CONFIG_APP_WIFI_CRED_STORE) if (stored_creds(out) == 0) { return 0; @@ -456,6 +469,16 @@ int app_wifi_creds_resolve(struct app_wifi_creds *out) #endif } +bool app_net_has_network(void) +{ + struct app_wifi_creds creds; + bool have = app_wifi_creds_resolve(&creds) == 0; + + memset(&creds, 0, sizeof(creds)); + return have; +} + + #if defined(CONFIG_NET_NATIVE_OFFLOADED_SOCKETS) /* native_sim with host-offloaded sockets: the host provides connectivity, so @@ -605,7 +628,11 @@ static void reconnect_handler(struct k_work *work) struct app_wifi_creds creds; - (void)app_wifi_creds_resolve(&creds); + if (app_wifi_creds_resolve(&creds) != 0) { + /* No network yet (waiting for tedge-onboard): nothing to join, + * and nothing to retry until one is given. */ + return; + } int rc = wifi_connect(&creds); memset(&creds, 0, sizeof(creds)); @@ -792,7 +819,9 @@ int app_net_init(void) bool have_creds = app_wifi_creds_resolve(&creds) == 0; #if defined(CONFIG_APP_PROV_HANDOFF) - if (!have_creds) { + /* With tedge-onboard support the device waits for it on the console + * instead; the button pattern still starts the provisioner. */ + if (!have_creds && !IS_ENABLED(CONFIG_APP_TEDGE_PROVISIONING)) { /* Record the identity first: a factory-fresh device has never been * online, and without it the provisioner advertises — and a ZTP * server registers the device — under the provisioner's fallback @@ -806,6 +835,11 @@ int app_net_init(void) #endif if (!have_creds) { + if (IS_ENABLED(CONFIG_APP_TEDGE_PROVISIONING)) { + LOG_INF("No Wi-Fi network yet: set the device up over USB " + "with tedge-onboard"); + return 0; + } LOG_ERR("Wi-Fi SSID is empty — set APP_WIFI_SSID via a local " "overlay (see overlay-wifi-credentials.conf.example)"); return -EINVAL; @@ -823,6 +857,54 @@ struct k_work_q *app_net_workq(void) return &net_wq; } +#if defined(CONFIG_APP_WIFI_CRED_STORE) && !defined(CONFIG_APP_WIFI_PROVISIONER) +int app_net_switch_network(const struct app_wifi_creds *creds, + k_timeout_t timeout) +{ + struct net_if *iface = net_if_get_first_wifi(); + enum wifi_security_type security; + int rc; + + if (iface == NULL) { + return -ENODEV; + } + switch_creds = *creds; + atomic_set(&switching, 1); + k_sem_reset(&net_connected_sem); + /* Leave the current network; the reconnect path joins the new one, + * since app_wifi_creds_resolve() returns it while switching. */ + (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, iface, NULL, 0); + mark_connected(false); + net_wq_reschedule(&reconnect_work, K_MSEC(500)); + + rc = k_sem_take(&net_connected_sem, timeout) == 0 ? 0 : -ETIMEDOUT; + if (rc == 0) { + /* It works: keep it, and only it. */ + security = creds->psk_len ? WIFI_SECURITY_TYPE_PSK + : WIFI_SECURITY_TYPE_NONE; + (void)wifi_credentials_delete_all(); + rc = wifi_credentials_set_personal(creds->ssid, creds->ssid_len, + security, NULL, 0, creds->psk, + creds->psk_len, 0, 0, 0); + if (rc != 0) { + LOG_ERR("Joined \"%s\" but could not store it (%d)", + creds->ssid, rc); + } + } + atomic_set(&switching, 0); + memset(&switch_creds, 0, sizeof(switch_creds)); + if (rc == -ETIMEDOUT) { + /* Back to the stored network, if there is one. */ + LOG_WRN("Could not join \"%s\"; back to the stored network", + creds->ssid); + (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, iface, NULL, 0); + mark_connected(false); + net_wq_reschedule(&reconnect_work, K_MSEC(500)); + } + return rc; +} +#endif + #if defined(CONFIG_APP_WIFI_PROVISIONER) int app_net_try_credentials(const struct app_wifi_creds *creds, k_timeout_t timeout) diff --git a/lib/common/net.h b/lib/common/net.h index fed4053..f2e10d3 100644 --- a/lib/common/net.h +++ b/lib/common/net.h @@ -70,9 +70,27 @@ struct app_wifi_creds { */ int app_wifi_creds_resolve(struct app_wifi_creds *out); +/** @return true when the device has a Wi-Fi network to join (stored, or + * built in). */ +bool app_net_has_network(void); + /** The connectivity work queue (the sw0 monitors run on it). */ struct k_work_q *app_net_workq(void); +#if defined(CONFIG_APP_WIFI_CRED_STORE) && !defined(CONFIG_APP_WIFI_PROVISIONER) +/** + * Join another Wi-Fi network, and keep it only once it works: the device + * tries @p creds, and when it gets an address within @p timeout they replace + * the stored network. Otherwise it goes back to the stored network, so a + * mistyped password cannot strand a device. + * + * @return 0 once joined and stored; -ETIMEDOUT when the network could not be + * joined in time; -ENODEV without a Wi-Fi interface. + */ +int app_net_switch_network(const struct app_wifi_creds *creds, + k_timeout_t timeout); +#endif + #if defined(CONFIG_APP_WIFI_PROVISIONER) /** * Provisioner image: join with @p creds and wait for an IPv4 address. diff --git a/lib/common/prov_tedge.c b/lib/common/prov_tedge.c new file mode 100644 index 0000000..b0d8b75 --- /dev/null +++ b/lib/common/prov_tedge.c @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: Apache-2.0 + * + * Setting the device up over USB with tedge-onboard: the hooks of + * tiny-edge's provisioning library for these applications. The Wi-Fi + * network goes through net.c, which tries it before keeping it; identify + * flashes the status LED; the scan is the tiny-edge Zephyr port's. + */ + +#include "prov_tedge.h" + +#include "identity.h" +#include "net.h" +#include "status_led.h" + +#include +#include + +#include + +#include +#include + +LOG_MODULE_REGISTER(app_prov_tedge, CONFIG_LOG_DEFAULT_LEVEL); + +#define JOIN_TIMEOUT K_SECONDS(30) +#define IDENTIFY_MS 10000 + +static int wifi_connect(const char *ssid, const char *password, void *ctx) +{ + struct app_wifi_creds creds = { 0 }; + int rc; + + ARG_UNUSED(ctx); + creds.ssid_len = strlen(ssid); + creds.psk_len = strlen(password); + if (creds.ssid_len >= sizeof(creds.ssid) || + creds.psk_len >= sizeof(creds.psk)) { + return -EINVAL; + } + memcpy(creds.ssid, ssid, creds.ssid_len); + memcpy(creds.psk, password, creds.psk_len); + rc = app_net_switch_network(&creds, JOIN_TIMEOUT); + memset(&creds, 0, sizeof(creds)); + return rc; +} + +static void identify(void *ctx) +{ + ARG_UNUSED(ctx); + status_led_flash(STATUS_LED_IDENTIFY, IDENTIFY_MS); +} + +static struct tedge_provisioning_hooks hooks = { + .wifi_connect = wifi_connect, + .identify = identify, + .wifi_scan = tedge_provisioning_wifi_scan, + .chip = CONFIG_SOC, +}; + +int app_prov_tedge_init(void) +{ + int rc; + + hooks.firmware_name = app_identity_firmware_name(); + hooks.firmware_version = app_identity_firmware_version(); + rc = tedge_provisioning_init(&hooks); + + if (rc != 0) { + LOG_ERR("tedge-onboard support did not start (%d)", rc); + } + return rc; +} diff --git a/lib/common/prov_tedge.h b/lib/common/prov_tedge.h new file mode 100644 index 0000000..24e8c13 --- /dev/null +++ b/lib/common/prov_tedge.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +#ifndef APP_PROV_TEDGE_H_ +#define APP_PROV_TEDGE_H_ + +/** Start tedge-onboard support (CONFIG_APP_TEDGE_PROVISIONING): call after + * tedge_init(). @return 0, or a negative errno. */ +int app_prov_tedge_init(void); + +#endif /* APP_PROV_TEDGE_H_ */ diff --git a/west.yml b/west.yml index dfaab05..2987764 100644 --- a/west.yml +++ b/west.yml @@ -51,7 +51,7 @@ manifest: # CONFIG_TEDGE=y. Pin a release tag; move the pin to pick up a new one. - name: tiny-edge remote: thin-edge - revision: v0.2.0 + revision: e2cdf677978e70a190d810556e75a522246b24e3 path: modules/lib/tiny-edge self: From d7f53a359ca1d5729c0394e5d360d740a01bcdce Mon Sep 17 00:00:00 2001 From: reubenmiller Date: Tue, 10 Nov 2026 17:06:41 +1000 Subject: [PATCH 2/5] feat: set up over USB by default, BLE on the button pattern A tedge-* device with no Wi-Fi network waits for tedge-onboard, and shows the provisioning pattern on its status LED until it is set up. Pressing the button 3 times within 2 seconds still starts the Wi-Fi provisioner (Improv over BLE, or lab-ztp-provisioner). The README describes both. Co-Authored-By: Claude Opus 5.5 --- README.md | 27 ++++++++++++++++++++++++--- lib/common/net.c | 9 +++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 82d0d66..a9bc78f 100644 --- a/README.md +++ b/README.md @@ -73,8 +73,9 @@ bundle, checking first that the board has the flash it was laid out for. Verify downloads with `sha256sum -c SHA256SUMS`. Then provision the device: [Improv](#provisioning-a-device) for -`standalone`, [lab-ztp-provisioner](#provisioning-wi-fi-and-cumulocity-with-lab-ztp-provisioner) -for `tedge-*`. The security notes there apply to prebuilt images too. +`standalone`, and for `tedge-*` +[tedge-onboard over USB](#setting-a-device-up-over-usb-with-tedge-onboard) or +[lab-ztp-provisioner](#provisioning-wi-fi-and-cumulocity-with-lab-ztp-provisioner). The security notes there apply to prebuilt images too. > **Release images are signed with MCUboot's public development key** unless > a release says otherwise (its notes and every `flash.json` state the key). @@ -414,10 +415,30 @@ If you'd rather not bake credentials into the image, see the next section: on the ESP32-C6, the ESP32-S3 boards and the ESP32-WROOM-32 a device can be given its network over BLE after flashing. +## Setting a device up over USB with tedge-onboard + +The `tedge-*` builds are set up from a computer by default. Plug the device +into a computer with a USB data cable and run +[`tedge-onboard`](https://github.com/thin-edge/tiny-edge/tree/main/tools/onboard) +there. It finds the device, gives it the computer's Wi-Fi network (the one +the device can see), registers it in Cumulocity through your go-c8y-cli +session, and waits until it is connected. Download it from the +[tiny-edge releases](https://github.com/thin-edge/tiny-edge/releases). + +A `tedge-*` device with no Wi-Fi network waits for the tool: its status LED +shows the provisioning pattern (two short blinks, then a pause), and the log +says so. To provision it over BLE instead (Improv, or lab-ztp-provisioner), +**press the button 3 times within 2 seconds**: it reboots into the Wi-Fi +provisioner described below. + +The Wi-Fi network the tool sends is tried before it is stored: if the device +cannot join it, the device keeps its previous network. + ## Provisioning Wi-Fi over BLE On boards with a BLE radio the device can join any network without a rebuild. -A device with no credentials boots into the **Wi-Fi provisioner**: it advertises +A `standalone` device with no credentials boots into the **Wi-Fi provisioner** +(a `tedge-*` device does after the button pattern above): it advertises the [Improv Wi-Fi](https://www.improv-wifi.com/ble/) BLE service, a phone or laptop sends it an SSID and password, and the device checks them by actually joining the network, stores them, and reboots into the application. diff --git a/lib/common/net.c b/lib/common/net.c index 5b0e80e..d21831e 100644 --- a/lib/common/net.c +++ b/lib/common/net.c @@ -836,8 +836,17 @@ int app_net_init(void) if (!have_creds) { if (IS_ENABLED(CONFIG_APP_TEDGE_PROVISIONING)) { +#if defined(CONFIG_APP_PROV_HANDOFF) + LOG_INF("No Wi-Fi network yet: set the device up over USB " + "with tedge-onboard, or press the button %d times " + "for BLE provisioning", + CONFIG_APP_WIFI_PROV_PRESS_COUNT); +#else LOG_INF("No Wi-Fi network yet: set the device up over USB " "with tedge-onboard"); +#endif + /* "Needs setting up" on the LED until it is. */ + status_led_set_mode(STATUS_LED_PROVISIONING); return 0; } LOG_ERR("Wi-Fi SSID is empty — set APP_WIFI_SSID via a local " From 76e8ed7ae9e2babb79b43d9a6c353b5c9a423035 Mon Sep 17 00:00:00 2001 From: reubenmiller Date: Tue, 10 Nov 2026 17:26:00 +1000 Subject: [PATCH 3/5] refactor: use tiny-edge's provisioning defaults, one start-up helper lib/common/prov_tedge.c starts provisioning with tedge_provisioning_zephyr_init(). It passes only what these applications do their own way: Wi-Fi through net.c, which owns connecting; identify on the status LED; and the firmware name. The scan and the chip come from the tiny-edge Zephyr port. The start-up block that each of the four apps repeated, "no Wi-Fi yet: start the client first, wait for the network", is now one call, app_prov_tedge_start_unprovisioned(). In builds without the client it is a macro that names no client symbol. tiny-edge is pinned to the branch of thin-edge/tiny-edge#9 for now. Co-Authored-By: Claude Opus 5.5 --- apps/modbus-server/src/main.c | 15 ++++----------- apps/opcua-server/src/main.c | 15 ++++----------- apps/snmp-agent/src/main.c | 15 ++++----------- apps/tedge-agent/src/main.c | 15 ++++----------- lib/common/prov_tedge.c | 23 +++++++++++++++++------ lib/common/prov_tedge.h | 23 +++++++++++++++++++++-- west.yml | 2 +- 7 files changed, 55 insertions(+), 53 deletions(-) diff --git a/apps/modbus-server/src/main.c b/apps/modbus-server/src/main.c index 37b9aef..8ff7543 100644 --- a/apps/modbus-server/src/main.c +++ b/apps/modbus-server/src/main.c @@ -12,6 +12,7 @@ #include #include "net.h" +#include "prov_tedge.h" #include "display.h" #include "modbus_server.h" #if defined(CONFIG_TEDGE) @@ -37,17 +38,9 @@ int main(void) return 0; } - bool onboarding = false; - -#if defined(CONFIG_APP_TEDGE_PROVISIONING) - /* No Wi-Fi network yet: the client starts first, since its - * provisioning library is how the device gets one (tedge-onboard over - * USB). The rest waits for the network as long as that takes. */ - onboarding = !app_net_has_network(); - if (onboarding) { - (void)tedge_glue_start(); - } -#endif + /* No Wi-Fi network yet: the client starts first (tedge-onboard gives + * the device one), and the rest waits for the network. */ + bool onboarding = app_prov_tedge_start_unprovisioned(tedge_glue_start); LOG_INF("Waiting for network..."); ret = app_net_wait_connected(onboarding ? K_FOREVER : K_SECONDS(60)); diff --git a/apps/opcua-server/src/main.c b/apps/opcua-server/src/main.c index 90f7877..5b11261 100644 --- a/apps/opcua-server/src/main.c +++ b/apps/opcua-server/src/main.c @@ -12,6 +12,7 @@ #include #include "net.h" +#include "prov_tedge.h" #include "display.h" #if defined(CONFIG_APP_OPCUA_SERVER) @@ -40,17 +41,9 @@ int main(void) return 0; } - bool onboarding = false; - -#if defined(CONFIG_APP_TEDGE_PROVISIONING) - /* No Wi-Fi network yet: the client starts first, since its - * provisioning library is how the device gets one (tedge-onboard over - * USB). The rest waits for the network as long as that takes. */ - onboarding = !app_net_has_network(); - if (onboarding) { - (void)tedge_glue_start(); - } -#endif + /* No Wi-Fi network yet: the client starts first (tedge-onboard gives + * the device one), and the rest waits for the network. */ + bool onboarding = app_prov_tedge_start_unprovisioned(tedge_glue_start); LOG_INF("Waiting for network..."); ret = app_net_wait_connected(onboarding ? K_FOREVER : K_SECONDS(60)); diff --git a/apps/snmp-agent/src/main.c b/apps/snmp-agent/src/main.c index 1366e3f..f68010b 100644 --- a/apps/snmp-agent/src/main.c +++ b/apps/snmp-agent/src/main.c @@ -13,6 +13,7 @@ #include #include "net.h" +#include "prov_tedge.h" #include "display.h" #include "snmp_agent.h" #if defined(CONFIG_TEDGE) @@ -38,17 +39,9 @@ int main(void) return 0; } - bool onboarding = false; - -#if defined(CONFIG_APP_TEDGE_PROVISIONING) - /* No Wi-Fi network yet: the client starts first, since its - * provisioning library is how the device gets one (tedge-onboard over - * USB). The rest waits for the network as long as that takes. */ - onboarding = !app_net_has_network(); - if (onboarding) { - (void)tedge_glue_start(); - } -#endif + /* No Wi-Fi network yet: the client starts first (tedge-onboard gives + * the device one), and the rest waits for the network. */ + bool onboarding = app_prov_tedge_start_unprovisioned(tedge_glue_start); LOG_INF("Waiting for network..."); ret = app_net_wait_connected(onboarding ? K_FOREVER : K_SECONDS(60)); diff --git a/apps/tedge-agent/src/main.c b/apps/tedge-agent/src/main.c index d0f2dfa..80dcaa1 100644 --- a/apps/tedge-agent/src/main.c +++ b/apps/tedge-agent/src/main.c @@ -15,6 +15,7 @@ #include #include "net.h" +#include "prov_tedge.h" #include "display.h" #include "tedge_glue.h" @@ -37,17 +38,9 @@ int main(void) return 0; } - bool onboarding = false; - -#if defined(CONFIG_APP_TEDGE_PROVISIONING) - /* No Wi-Fi network yet: the client starts first, since its - * provisioning library is how the device gets one (tedge-onboard over - * USB). The rest waits for the network as long as that takes. */ - onboarding = !app_net_has_network(); - if (onboarding) { - (void)tedge_glue_start(); - } -#endif + /* No Wi-Fi network yet: the client starts first (tedge-onboard gives + * the device one), and the rest waits for the network. */ + bool onboarding = app_prov_tedge_start_unprovisioned(tedge_glue_start); LOG_INF("Waiting for network..."); ret = app_net_wait_connected(onboarding ? K_FOREVER : K_SECONDS(60)); diff --git a/lib/common/prov_tedge.c b/lib/common/prov_tedge.c index b0d8b75..07020cb 100644 --- a/lib/common/prov_tedge.c +++ b/lib/common/prov_tedge.c @@ -2,8 +2,9 @@ * * Setting the device up over USB with tedge-onboard: the hooks of * tiny-edge's provisioning library for these applications. The Wi-Fi - * network goes through net.c, which tries it before keeping it; identify - * flashes the status LED; the scan is the tiny-edge Zephyr port's. + * network goes through net.c, which owns connecting and tries a network + * before keeping it; identify flashes the status LED. The rest (the scan, + * the chip) are the tiny-edge Zephyr port's defaults. */ #include "prov_tedge.h" @@ -50,11 +51,11 @@ static void identify(void *ctx) status_led_flash(STATUS_LED_IDENTIFY, IDENTIFY_MS); } +/* What these applications do their own way; the scan and the chip are the + * tiny-edge Zephyr port's. */ static struct tedge_provisioning_hooks hooks = { .wifi_connect = wifi_connect, .identify = identify, - .wifi_scan = tedge_provisioning_wifi_scan, - .chip = CONFIG_SOC, }; int app_prov_tedge_init(void) @@ -63,10 +64,20 @@ int app_prov_tedge_init(void) hooks.firmware_name = app_identity_firmware_name(); hooks.firmware_version = app_identity_firmware_version(); - rc = tedge_provisioning_init(&hooks); - + rc = tedge_provisioning_zephyr_init(&hooks); if (rc != 0) { LOG_ERR("tedge-onboard support did not start (%d)", rc); } return rc; } + +bool app_prov_tedge_start_unprovisioned(int (*client_start)(void)) +{ + if (app_net_has_network()) { + return false; + } + /* No Wi-Fi network yet: the client starts first, since its + * provisioning library is how the device gets one. */ + (void)client_start(); + return true; +} diff --git a/lib/common/prov_tedge.h b/lib/common/prov_tedge.h index 24e8c13..2e1be59 100644 --- a/lib/common/prov_tedge.h +++ b/lib/common/prov_tedge.h @@ -2,8 +2,27 @@ #ifndef APP_PROV_TEDGE_H_ #define APP_PROV_TEDGE_H_ -/** Start tedge-onboard support (CONFIG_APP_TEDGE_PROVISIONING): call after - * tedge_init(). @return 0, or a negative errno. */ +#include + +#if defined(CONFIG_APP_TEDGE_PROVISIONING) + +/** Start tedge-onboard support: call after tedge_init(). + * @return 0, or a negative errno. */ int app_prov_tedge_init(void); +/** + * At start-up: when the device has no Wi-Fi network yet, start the client at + * once with @p client_start, since its provisioning library is how the + * device gets one, and return true. The application then waits for the + * network as long as that takes, and does not start the client again. + */ +bool app_prov_tedge_start_unprovisioned(int (*client_start)(void)); + +#else + +/* A macro, so builds without the client need no client_start symbol. */ +#define app_prov_tedge_start_unprovisioned(client_start) false + +#endif + #endif /* APP_PROV_TEDGE_H_ */ diff --git a/west.yml b/west.yml index 2987764..f580fe8 100644 --- a/west.yml +++ b/west.yml @@ -51,7 +51,7 @@ manifest: # CONFIG_TEDGE=y. Pin a release tag; move the pin to pick up a new one. - name: tiny-edge remote: thin-edge - revision: e2cdf677978e70a190d810556e75a522246b24e3 + revision: 8388bb6988952f556efc03f2b514785e679c0202 path: modules/lib/tiny-edge self: From a2baaab57e1a263277507fe98777b37bada28ab5 Mon Sep 17 00:00:00 2001 From: reubenmiller Date: Tue, 10 Nov 2026 18:56:09 +1000 Subject: [PATCH 4/5] chore(deps): move tiny-edge to v0.3.0 The release with the provisioning library, its Zephyr defaults (tedge_provisioning_zephyr_init()), tedge-onboard, and the code-scanning fixes. It replaces the pin to the pull request branch. Co-Authored-By: Claude Opus 5.5 --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index f580fe8..3217462 100644 --- a/west.yml +++ b/west.yml @@ -51,7 +51,7 @@ manifest: # CONFIG_TEDGE=y. Pin a release tag; move the pin to pick up a new one. - name: tiny-edge remote: thin-edge - revision: 8388bb6988952f556efc03f2b514785e679c0202 + revision: v0.3.0 path: modules/lib/tiny-edge self: From 6688ed0e8769c263d6ccbccc1a66ebe9ba32123f Mon Sep 17 00:00:00 2001 From: reubenmiller Date: Tue, 10 Nov 2026 21:01:44 +1000 Subject: [PATCH 5/5] chore(release): record sizes with the provisioning library Every build that runs the thin-edge.io client now carries tiny-edge's provisioning library. On the ESP32-S3 and C6, that adds about 1.2 KB of flash and 6.5 KB of static RAM, for the worker's stack and buffers. On the classic ESP32, it adds about 6 KB of flash and 6.4 KB of RAM. The standalone builds don't change. Two images move by a 64 KB alignment step: - modbus-server tedge-full on the C6 (content +8.5 KB). - snmp-agent tedge-full on the QT Py S3, which dropped by the same step in #18. Both are within their flash budgets. The sizes come from a CI run of every build (release workflow, run 42801580748), using the same size.py report that --write-baseline records. Co-Authored-By: Claude Opus 5.5 --- release/size-baseline.json | 410 ++++++++++++++++++------------------- 1 file changed, 205 insertions(+), 205 deletions(-) diff --git a/release/size-baseline.json b/release/size-baseline.json index c149a04..657b0ff 100644 --- a/release/size-baseline.json +++ b/release/size-baseline.json @@ -1,16 +1,16 @@ { "modbus-server-standalone-esp32-devkitc": { - "image": 590343, - "content": 590343, + "image": 590359, + "content": 590359, "ram": { "iram0_0_seg": 59648, - "dram0_0_seg": 97160, + "dram0_0_seg": 97280, "dram1_0_seg": 46904 }, - "arena": 99440, + "arena": 99320, "provisioner": { - "image": 740406, - "content": 740406, + "image": 740407, + "content": 740407, "ram": { "iram0_0_seg": 92928, "dram0_0_seg": 125664, @@ -20,16 +20,16 @@ } }, "modbus-server-standalone-esp32c6-devkitc": { - "image": 733898, - "content": 633058, + "image": 733900, + "content": 633044, "ram": { - "sram0_0_seg": 205788, + "sram0_0_seg": 205900, "lp_ram_seg": 36 }, - "arena": 303648, + "arena": 303536, "provisioner": { - "image": 943756, - "content": 863652, + "image": 943754, + "content": 863650, "ram": { "sram0_0_seg": 282472, "lp_ram_seg": 36 @@ -38,16 +38,16 @@ } }, "modbus-server-standalone-esp32s3-devkitc": { - "image": 583884, - "content": 583884, + "image": 583883, + "content": 583883, "ram": { "iram0_0_seg": 56672, - "dram0_0_seg": 196112 + "dram0_0_seg": 196224 }, - "arena": 202980, + "arena": 202868, "provisioner": { - "image": 662060, - "content": 662060, + "image": 662059, + "content": 662059, "ram": { "iram0_0_seg": 57688, "dram0_0_seg": 230760 @@ -56,16 +56,16 @@ } }, "modbus-server-standalone-qtpy-esp32s3": { - "image": 584026, - "content": 584026, + "image": 584012, + "content": 584012, "ram": { "iram0_0_seg": 56200, - "dram0_0_seg": 193508 + "dram0_0_seg": 193628 }, - "arena": 205580, + "arena": 205460, "provisioner": { - "image": 662220, - "content": 662220, + "image": 662203, + "content": 662203, "ram": { "iram0_0_seg": 57216, "dram0_0_seg": 228144 @@ -74,16 +74,16 @@ } }, "modbus-server-tedge-full-esp32c6-devkitc": { - "image": 892907, - "content": 830611, + "image": 959692, + "content": 839144, "ram": { - "sram0_0_seg": 428668, + "sram0_0_seg": 435312, "lp_ram_seg": 36 }, - "arena": 80768, + "arena": 74128, "provisioner": { - "image": 1013962, - "content": 909466, + "image": 1013963, + "content": 909467, "ram": { "sram0_0_seg": 302652, "lp_ram_seg": 36 @@ -95,16 +95,16 @@ } }, "modbus-server-tedge-full-esp32s3-devkitc": { - "image": 931115, - "content": 931115, + "image": 932332, + "content": 932332, "ram": { - "iram0_0_seg": 61332, - "dram0_0_seg": 339120 + "iram0_0_seg": 61420, + "dram0_0_seg": 345636 }, - "arena": 59972, + "arena": 53468, "provisioner": { - "image": 732124, - "content": 732124, + "image": 732123, + "content": 732123, "ram": { "iram0_0_seg": 57688, "dram0_0_seg": 250820 @@ -113,13 +113,13 @@ } }, "modbus-server-tedge-full-qtpy-esp32s3": { - "image": 931307, - "content": 931307, + "image": 932508, + "content": 932508, "ram": { - "iram0_0_seg": 60380, - "dram0_0_seg": 335508 + "iram0_0_seg": 60468, + "dram0_0_seg": 342048 }, - "arena": 63596, + "arena": 57052, "provisioner": { "image": 732284, "content": 732284, @@ -131,17 +131,17 @@ } }, "modbus-server-tedge-ota-esp32-cam": { - "image": 796232, - "content": 796232, + "image": 802247, + "content": 802247, "ram": { "iram0_0_seg": 65792, - "dram0_0_seg": 140952, - "dram1_0_seg": 79128 + "dram0_0_seg": 142924, + "dram1_0_seg": 83560 }, - "arena": 55648, + "arena": 53672, "provisioner": { - "image": 776472, - "content": 776472, + "image": 776471, + "content": 776471, "ram": { "iram0_0_seg": 92928, "dram0_0_seg": 126996, @@ -151,14 +151,14 @@ } }, "modbus-server-tedge-ota-esp32-devkitc": { - "image": 791640, - "content": 791640, + "image": 797688, + "content": 797688, "ram": { "iram0_0_seg": 60416, - "dram0_0_seg": 177416, - "dram1_0_seg": 81440 + "dram0_0_seg": 179392, + "dram1_0_seg": 85872 }, - "arena": 19184, + "arena": 17200, "provisioner": { "image": 776470, "content": 776470, @@ -171,13 +171,13 @@ } }, "modbus-server-tedge-ota-esp32c6-devkitc": { - "image": 887100, - "content": 804304, + "image": 888298, + "content": 812778, "ram": { - "sram0_0_seg": 394684, + "sram0_0_seg": 401368, "lp_ram_seg": 36 }, - "arena": 114752, + "arena": 108064, "provisioner": { "image": 1013963, "content": 909467, @@ -192,16 +192,16 @@ } }, "modbus-server-tedge-ota-esp32s3-devkitc": { - "image": 736059, - "content": 736059, + "image": 737211, + "content": 737211, "ram": { - "iram0_0_seg": 59280, - "dram0_0_seg": 289752 + "iram0_0_seg": 59368, + "dram0_0_seg": 296248 }, - "arena": 109332, + "arena": 102844, "provisioner": { - "image": 732124, - "content": 732124, + "image": 732122, + "content": 732122, "ram": { "iram0_0_seg": 57688, "dram0_0_seg": 250820 @@ -210,16 +210,16 @@ } }, "modbus-server-tedge-ota-qtpy-esp32s3": { - "image": 736203, - "content": 736203, + "image": 737338, + "content": 737338, "ram": { - "iram0_0_seg": 58328, - "dram0_0_seg": 286140 + "iram0_0_seg": 58416, + "dram0_0_seg": 292628 }, - "arena": 112940, + "arena": 106460, "provisioner": { - "image": 732284, - "content": 732284, + "image": 732283, + "content": 732283, "ram": { "iram0_0_seg": 57216, "dram0_0_seg": 248204 @@ -228,17 +228,17 @@ } }, "opcua-server-standalone-esp32-devkitc": { - "image": 750039, - "content": 750039, + "image": 750071, + "content": 750071, "ram": { "iram0_0_seg": 59904, - "dram0_0_seg": 101500, + "dram0_0_seg": 101612, "dram1_0_seg": 65656 }, - "arena": 95104, + "arena": 94992, "provisioner": { - "image": 740407, - "content": 740407, + "image": 740406, + "content": 740406, "ram": { "iram0_0_seg": 92928, "dram0_0_seg": 125664, @@ -248,13 +248,13 @@ } }, "opcua-server-standalone-esp32c6-devkitc": { - "image": 854154, - "content": 794130, + "image": 854155, + "content": 794115, "ram": { - "sram0_0_seg": 229844, + "sram0_0_seg": 229972, "lp_ram_seg": 36 }, - "arena": 279584, + "arena": 279456, "provisioner": { "image": 943755, "content": 863651, @@ -266,13 +266,13 @@ } }, "opcua-server-standalone-esp32s3-devkitc": { - "image": 768666, - "content": 768666, + "image": 768667, + "content": 768667, "ram": { "iram0_0_seg": 56924, - "dram0_0_seg": 219472 + "dram0_0_seg": 219592 }, - "arena": 179620, + "arena": 179500, "provisioner": { "image": 662058, "content": 662058, @@ -284,16 +284,16 @@ } }, "opcua-server-standalone-qtpy-esp32s3": { - "image": 768812, - "content": 768812, + "image": 768811, + "content": 768811, "ram": { "iram0_0_seg": 56452, - "dram0_0_seg": 216864 + "dram0_0_seg": 216984 }, - "arena": 182220, + "arena": 182100, "provisioner": { - "image": 662219, - "content": 662219, + "image": 662204, + "content": 662204, "ram": { "iram0_0_seg": 57216, "dram0_0_seg": 228144 @@ -302,13 +302,13 @@ } }, "opcua-server-tedge-ota-qtpy-esp32s3": { - "image": 920154, - "content": 920154, + "image": 921291, + "content": 921291, "ram": { - "iram0_0_seg": 58580, - "dram0_0_seg": 303036 + "iram0_0_seg": 58668, + "dram0_0_seg": 309540 }, - "arena": 96060, + "arena": 89556, "provisioner": { "image": 732283, "content": 732283, @@ -320,17 +320,17 @@ } }, "snmp-agent-standalone-esp32-devkitc": { - "image": 578792, - "content": 578792, + "image": 578808, + "content": 578808, "ram": { "iram0_0_seg": 59648, - "dram0_0_seg": 105608, + "dram0_0_seg": 105728, "dram1_0_seg": 45144 }, - "arena": 90992, + "arena": 90872, "provisioner": { - "image": 740406, - "content": 740406, + "image": 740407, + "content": 740407, "ram": { "iram0_0_seg": 92928, "dram0_0_seg": 125664, @@ -341,12 +341,12 @@ }, "snmp-agent-standalone-esp32c6-devkitc": { "image": 732010, - "content": 616738, + "content": 616722, "ram": { - "sram0_0_seg": 212352, + "sram0_0_seg": 212480, "lp_ram_seg": 36 }, - "arena": 297088, + "arena": 296960, "provisioner": { "image": 943755, "content": 863651, @@ -362,9 +362,9 @@ "content": 582427, "ram": { "iram0_0_seg": 56560, - "dram0_0_seg": 202696 + "dram0_0_seg": 202808 }, - "arena": 196388, + "arena": 196276, "provisioner": { "image": 662060, "content": 662060, @@ -376,16 +376,16 @@ } }, "snmp-agent-standalone-qtpy-esp32s3": { - "image": 582572, - "content": 582572, + "image": 582570, + "content": 582570, "ram": { "iram0_0_seg": 56088, - "dram0_0_seg": 200092 + "dram0_0_seg": 200212 }, - "arena": 198988, + "arena": 198868, "provisioner": { - "image": 662218, - "content": 662218, + "image": 662203, + "content": 662203, "ram": { "iram0_0_seg": 57216, "dram0_0_seg": 228144 @@ -394,13 +394,13 @@ } }, "snmp-agent-tedge-full-esp32c6-devkitc": { - "image": 890843, - "content": 820891, + "image": 892108, + "content": 829448, "ram": { - "sram0_0_seg": 440940, + "sram0_0_seg": 447608, "lp_ram_seg": 36 }, - "arena": 68496, + "arena": 61824, "provisioner": { "image": 1013963, "content": 909467, @@ -415,13 +415,13 @@ } }, "snmp-agent-tedge-full-esp32s3-devkitc": { - "image": 805420, - "content": 805420, + "image": 806636, + "content": 806636, "ram": { - "iram0_0_seg": 60032, - "dram0_0_seg": 336060 + "iram0_0_seg": 60120, + "dram0_0_seg": 342556 }, - "arena": 63028, + "arena": 56524, "provisioner": { "image": 732123, "content": 732123, @@ -433,16 +433,16 @@ } }, "snmp-agent-tedge-full-qtpy-esp32s3": { - "image": 740026, - "content": 740026, + "image": 806764, + "content": 806764, "ram": { - "iram0_0_seg": 59080, - "dram0_0_seg": 332448 + "iram0_0_seg": 59168, + "dram0_0_seg": 338928 }, - "arena": 66636, + "arena": 60164, "provisioner": { - "image": 732283, - "content": 732283, + "image": 732282, + "content": 732282, "ram": { "iram0_0_seg": 57216, "dram0_0_seg": 248204 @@ -451,14 +451,14 @@ } }, "snmp-agent-tedge-ota-esp32-cam": { - "image": 790567, - "content": 790567, + "image": 796600, + "content": 796600, "ram": { "iram0_0_seg": 65792, - "dram0_0_seg": 148992, - "dram1_0_seg": 83224 + "dram0_0_seg": 150960, + "dram1_0_seg": 87656 }, - "arena": 47608, + "arena": 45632, "provisioner": { "image": 776472, "content": 776472, @@ -471,16 +471,16 @@ } }, "snmp-agent-tedge-ota-esp32c6-devkitc": { - "image": 885739, - "content": 796559, + "image": 886956, + "content": 805044, "ram": { - "sram0_0_seg": 406996, + "sram0_0_seg": 413672, "lp_ram_seg": 36 }, - "arena": 102432, + "arena": 95760, "provisioner": { - "image": 1013964, - "content": 909468, + "image": 1013963, + "content": 909467, "ram": { "sram0_0_seg": 302652, "lp_ram_seg": 36 @@ -492,16 +492,16 @@ } }, "snmp-agent-tedge-ota-esp32s3-devkitc": { - "image": 735131, - "content": 735131, + "image": 736268, + "content": 736268, "ram": { - "iram0_0_seg": 59280, - "dram0_0_seg": 301920 + "iram0_0_seg": 59368, + "dram0_0_seg": 308424 }, - "arena": 97164, + "arena": 90668, "provisioner": { - "image": 732124, - "content": 732124, + "image": 732123, + "content": 732123, "ram": { "iram0_0_seg": 57688, "dram0_0_seg": 250820 @@ -510,13 +510,13 @@ } }, "snmp-agent-tedge-ota-qtpy-esp32s3": { - "image": 735259, - "content": 735259, + "image": 736395, + "content": 736395, "ram": { - "iram0_0_seg": 58328, - "dram0_0_seg": 298316 + "iram0_0_seg": 58416, + "dram0_0_seg": 304796 }, - "arena": 100764, + "arena": 94292, "provisioner": { "image": 732283, "content": 732283, @@ -528,16 +528,16 @@ } }, "tedge-agent-tedge-full-esp32c6-devkitc": { - "image": 889036, - "content": 806988, + "image": 890300, + "content": 815536, "ram": { - "sram0_0_seg": 423980, + "sram0_0_seg": 430640, "lp_ram_seg": 36 }, - "arena": 85456, + "arena": 78800, "provisioner": { - "image": 1013963, - "content": 909467, + "image": 1013962, + "content": 909466, "ram": { "sram0_0_seg": 302652, "lp_ram_seg": 36 @@ -549,16 +549,16 @@ } }, "tedge-agent-tedge-full-esp32s3-devkitc": { - "image": 927499, - "content": 927499, + "image": 928700, + "content": 928700, "ram": { - "iram0_0_seg": 61332, - "dram0_0_seg": 333940 + "iram0_0_seg": 61420, + "dram0_0_seg": 340456 }, - "arena": 65156, + "arena": 58636, "provisioner": { - "image": 732123, - "content": 732123, + "image": 732124, + "content": 732124, "ram": { "iram0_0_seg": 57688, "dram0_0_seg": 250820 @@ -567,16 +567,16 @@ } }, "tedge-agent-tedge-full-qtpy-esp32s3": { - "image": 927674, - "content": 927674, + "image": 928891, + "content": 928891, "ram": { - "iram0_0_seg": 60380, - "dram0_0_seg": 330328 + "iram0_0_seg": 60468, + "dram0_0_seg": 336868 }, - "arena": 68764, + "arena": 62220, "provisioner": { - "image": 732282, - "content": 732282, + "image": 732284, + "content": 732284, "ram": { "iram0_0_seg": 57216, "dram0_0_seg": 248204 @@ -585,14 +585,14 @@ } }, "tedge-agent-tedge-ota-esp32-cam": { - "image": 780518, - "content": 780518, + "image": 786631, + "content": 786631, "ram": { "iram0_0_seg": 65792, - "dram0_0_seg": 139460, - "dram1_0_seg": 76056 + "dram0_0_seg": 141428, + "dram1_0_seg": 80488 }, - "arena": 57136, + "arena": 55176, "provisioner": { "image": 776471, "content": 776471, @@ -605,17 +605,17 @@ } }, "tedge-agent-tedge-ota-esp32-devkitc": { - "image": 776152, - "content": 776152, + "image": 782278, + "content": 782278, "ram": { "iram0_0_seg": 60416, - "dram0_0_seg": 175924, - "dram1_0_seg": 78368 + "dram0_0_seg": 177892, + "dram1_0_seg": 82800 }, - "arena": 20672, + "arena": 18712, "provisioner": { - "image": 776472, - "content": 776472, + "image": 776470, + "content": 776470, "ram": { "iram0_0_seg": 92928, "dram0_0_seg": 126996, @@ -625,16 +625,16 @@ } }, "tedge-agent-tedge-ota-esp32c6-devkitc": { - "image": 884155, - "content": 783047, + "image": 885354, + "content": 791522, "ram": { - "sram0_0_seg": 390028, + "sram0_0_seg": 396712, "lp_ram_seg": 36 }, - "arena": 119408, + "arena": 112720, "provisioner": { - "image": 1013964, - "content": 909468, + "image": 1013963, + "content": 909467, "ram": { "sram0_0_seg": 302652, "lp_ram_seg": 36 @@ -646,16 +646,16 @@ } }, "tedge-agent-tedge-ota-esp32s3-devkitc": { - "image": 733658, - "content": 733658, + "image": 734794, + "content": 734794, "ram": { - "iram0_0_seg": 59280, - "dram0_0_seg": 285220 + "iram0_0_seg": 59368, + "dram0_0_seg": 291716 }, - "arena": 113860, + "arena": 107372, "provisioner": { - "image": 732124, - "content": 732124, + "image": 732122, + "content": 732122, "ram": { "iram0_0_seg": 57688, "dram0_0_seg": 250820 @@ -664,16 +664,16 @@ } }, "tedge-agent-tedge-ota-qtpy-esp32s3": { - "image": 733788, - "content": 733788, + "image": 734922, + "content": 734922, "ram": { - "iram0_0_seg": 58328, - "dram0_0_seg": 281608 + "iram0_0_seg": 58416, + "dram0_0_seg": 288096 }, - "arena": 117484, + "arena": 110988, "provisioner": { - "image": 732284, - "content": 732284, + "image": 732283, + "content": 732283, "ram": { "iram0_0_seg": 57216, "dram0_0_seg": 248204