|
30 | 30 |
|
31 | 31 | #include <esp_matter.h> |
32 | 32 | #include <esp_matter_endpoint.h> |
| 33 | +#include <esp_matter_ota.h> // BDX-OTA TX-power throttle (#12): custom OTA requestor driver |
33 | 34 |
|
34 | 35 | #include <app/server/Server.h> // Server / FabricTable / commissioning window (F1 "77") |
35 | 36 | #include <app/server/CommissioningWindowManager.h> |
@@ -932,6 +933,44 @@ static void on_recommission_cancel(void) |
932 | 933 | #define HISENSE_OTA_TX_POWER_QDBM 40 /* 10 dBm, quarter-dBm units. Plenty for a LAN hop. */ |
933 | 934 | #define HISENSE_OTA_CHUNK_YIELD_MS 8 /* breathing room between flash writes */ |
934 | 935 |
|
| 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 | + |
935 | 974 | static void https_ota_task(void *arg) |
936 | 975 | { |
937 | 976 | ESP_LOGW(TAG, "HTTPS-OTA: fetching %s", HISENSE_OTA_URL); |
@@ -1452,6 +1491,19 @@ extern "C" void app_main() |
1452 | 1491 |
|
1453 | 1492 | esp_matter::start(NULL); // brings up Wi-Fi/Matter + commissioning |
1454 | 1493 |
|
| 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 | + |
1455 | 1507 | // HA entity labels (UserLabel key "ha_entitylabel") -> distinguishable same-type entities. |
1456 | 1508 | // start() has returned (Server::Init done, endpoints exist); take the stack lock since we |
1457 | 1509 | // run on a different task than the Matter event loop. Read live by the UserLabel cluster. |
|
0 commit comments