Skip to content

Commit 19077d9

Browse files
committed
feat(esp32): throttle Wi-Fi TX during Matter BDX OTA (#12); bump v1.1.5
The #12 brownout mitigation (drop TX power for the concurrent flash-write + Wi-Fi-TX window of an OTA) only covered the HTTP break-glass path; the PRIMARY Matter (BDX) OTA path ran at the full 20 dBm ceiling. Swap in a HisenseOTARequestorDriver that lowers TX on idle-exit (update starting) and restores it on idle-enter (back to idle on any path: done/abort/timeout), registered via esp_matter_ota_requestor_set_config right after esp_matter::start(). Capture-once + restore-on-every-idle-enter so the node never sticks at 10 dBm. Not a substitute for the bulk cap; it lowers brownout probability during the OTA window (node-35 phy_init brownout). PROJECT_VER 1.1.4 -> 1.1.5 (int 10105). Built + delta-OTA flashed to node 35, verified live: 1.1.5, subscribable, diagnostics reading (CompressorHz, Features1/Faults1 valid). Assisted-by: AI
1 parent e03e64e commit 19077d9

3 files changed

Lines changed: 55 additions & 3 deletions

File tree

firmware/esp32-matter/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# . ~/esp/esp-idf-v5.5.4/export.sh && . $ESP_MATTER_PATH/export.sh
33
# idf.py set-target esp32 && idf.py build flash monitor
44
cmake_minimum_required(VERSION 3.16)
5-
set(PROJECT_VER "1.1.4")
5+
set(PROJECT_VER "1.1.5")
66

77
# Unified versioning (issue #77): the Matter softwareVersion INT is DERIVED from PROJECT_VER --
88
# MAJOR*10000+MINOR*100+PATCH -> a readable, strictly-monotonic uint32. This keeps the human

firmware/esp32-matter/main/app_main.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include <esp_matter.h>
3232
#include <esp_matter_endpoint.h>
33+
#include <esp_matter_ota.h> // BDX-OTA TX-power throttle (#12): custom OTA requestor driver
3334

3435
#include <app/server/Server.h> // Server / FabricTable / commissioning window (F1 "77")
3536
#include <app/server/CommissioningWindowManager.h>
@@ -932,6 +933,44 @@ static void on_recommission_cancel(void)
932933
#define HISENSE_OTA_TX_POWER_QDBM 40 /* 10 dBm, quarter-dBm units. Plenty for a LAN hop. */
933934
#define HISENSE_OTA_CHUNK_YIELD_MS 8 /* breathing room between flash writes */
934935

936+
/* #12 brownout mitigation, Matter (BDX) OTA path. The stock esp-matter OTA requestor runs the
937+
* whole download+apply at the full 20 dBm TX ceiling, so on this marginal A/C rail the concurrent
938+
* flash-write (300-500 mA) + Wi-Fi TX peak is exactly the combination that hung a node mid-OTA.
939+
* The HTTP break-glass path (https_ota_task, below) already drops TX for its duration; this brings
940+
* the SAME throttle to the PRIMARY Matter path by swapping in a driver that lowers TX on idle-exit
941+
* (an update is starting) and restores it on idle-enter (back to idle on ANY path: done / abort /
942+
* timeout). Capture-once + restore-on-every-idle-enter mirrors the save/restore-on-every-branch
943+
* discipline of the HTTP path, so the node is never left stuck at 10 dBm. Not a substitute for the
944+
* bulk cap; it only lowers the probability of a brownout during the OTA window. */
945+
class HisenseOTARequestorDriver : public chip::DeviceLayer::ExtendedOTARequestorDriver {
946+
public:
947+
void HandleIdleStateExit() override
948+
{
949+
if (!m_tx_saved) { // capture the live ceiling ONCE, on the first exit-from-idle
950+
m_tx_saved = (esp_wifi_get_max_tx_power(&m_saved_tx) == ESP_OK);
951+
if (m_tx_saved) {
952+
esp_wifi_set_max_tx_power(HISENSE_OTA_TX_POWER_QDBM);
953+
ESP_LOGW(TAG, "Matter OTA: Wi-Fi TX power %d -> %d (quarter-dBm) to cut the current peak",
954+
(int) m_saved_tx, HISENSE_OTA_TX_POWER_QDBM);
955+
}
956+
}
957+
chip::DeviceLayer::ExtendedOTARequestorDriver::HandleIdleStateExit();
958+
}
959+
void HandleIdleStateEnter(chip::IdleStateReason reason) override
960+
{
961+
chip::DeviceLayer::ExtendedOTARequestorDriver::HandleIdleStateEnter(reason);
962+
if (m_tx_saved) { // restore on ANY return to idle (success / abort / timeout)
963+
esp_wifi_set_max_tx_power(m_saved_tx);
964+
ESP_LOGW(TAG, "Matter OTA: Wi-Fi TX power restored to %d (quarter-dBm)", (int) m_saved_tx);
965+
m_tx_saved = false;
966+
}
967+
}
968+
private:
969+
int8_t m_saved_tx = 0;
970+
bool m_tx_saved = false;
971+
};
972+
static HisenseOTARequestorDriver s_hisense_ota_driver;
973+
935974
static void https_ota_task(void *arg)
936975
{
937976
ESP_LOGW(TAG, "HTTPS-OTA: fetching %s", HISENSE_OTA_URL);
@@ -1452,6 +1491,19 @@ extern "C" void app_main()
14521491

14531492
esp_matter::start(NULL); // brings up Wi-Fi/Matter + commissioning
14541493

1494+
// #12 brownout mitigation: swap in the TX-throttling OTA requestor driver for the Matter (BDX)
1495+
// path. Must run AFTER esp_matter::start() (esp_matter_ota_requestor_init() has executed) and
1496+
// BEFORE the async kDnssdInitialized event fires esp_matter_ota_requestor_start(), which is what
1497+
// consumes this driver. Timeout fields left 0 -> set_config keeps the esp-matter defaults (it
1498+
// guards each with `if`). Only the driver pointer is captured, so the config structs are locals.
1499+
{
1500+
esp_matter_ota_requestor_impl_t ota_impl = {};
1501+
ota_impl.driver = &s_hisense_ota_driver;
1502+
esp_matter_ota_config_t ota_cfg = {};
1503+
ota_cfg.impl = &ota_impl;
1504+
esp_matter_ota_requestor_set_config(ota_cfg);
1505+
}
1506+
14551507
// HA entity labels (UserLabel key "ha_entitylabel") -> distinguishable same-type entities.
14561508
// start() has returned (Server::Init done, endpoints exist); take the stack lock since we
14571509
// run on a different task than the Matter event loop. Read live by the UserLabel cluster.

firmware/esp32-matter/sdkconfig.defaults

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ CONFIG_CUSTOM_DEVICE_INFO_PROVIDER=y
4646
# so it (and the fallback NUMBER) MUST stay equal to PROJECT_VER or the device reports a stale
4747
# softwareVersionString. Edit PROJECT_VER in CMakeLists.txt, then update both lines below.
4848
# esp32-lint.sh enforces this equality (fails the commit/CI if they drift).
49-
CONFIG_DEVICE_SOFTWARE_VERSION_NUMBER=10104
50-
CONFIG_DEVICE_SOFTWARE_VERSION_STRING="1.1.4"
49+
CONFIG_DEVICE_SOFTWARE_VERSION_NUMBER=10105
50+
CONFIG_DEVICE_SOFTWARE_VERSION_STRING="1.1.5"
5151
# --- OTA hardening (faster + reliable on marginal Wi-Fi) ---
5252
# Delta OTA: ship a diff (tens of KB) instead of the full ~1.5MB image over BDX.
5353
CONFIG_ENABLE_DELTA_OTA=y

0 commit comments

Comments
 (0)