From 7136204faf8e3e41a7ebcfecd072a2fa846fa6a3 Mon Sep 17 00:00:00 2001 From: mcuw <112967559+mcuw@users.noreply.github.com> Date: Wed, 26 Aug 2026 01:11:57 +0200 Subject: [PATCH] fix: the TBR has a working auto-joiner even on client factory-reset --- .../ot_br_web_api/ot_br_web_api_handlers.c | 39 ++++++----- .../ot_br_web_api/ot_br_web_api_setup_mode.c | 66 ++++++++++++++----- 2 files changed, 71 insertions(+), 34 deletions(-) diff --git a/ot_br/components/ot_br_web_api/ot_br_web_api_handlers.c b/ot_br/components/ot_br_web_api/ot_br_web_api_handlers.c index 8be4892..cf467c8 100644 --- a/ot_br/components/ot_br_web_api/ot_br_web_api_handlers.c +++ b/ot_br/components/ot_br_web_api/ot_br_web_api_handlers.c @@ -30,10 +30,12 @@ // CoAP Light Control #include "ot_br_web_api_coap_client.h" -// static const char *TAG = "ot_br_web_handlers"; +static const char *TAG = "ot_br_web_api_handlers"; extern bool ot_br_web_api_check_auth(httpd_req_t *req); +static SemaphoreHandle_t s_commissioner_active_sem = NULL; + // -------- Helpers -------- void send_json(httpd_req_t *req, cJSON *json) @@ -545,6 +547,14 @@ static esp_err_t setup_complete_handler(httpd_req_t *req) return ESP_OK; } + +static void commissioner_state_callback(otCommissionerState state, void *context) +{ + if (state == OT_COMMISSIONER_STATE_ACTIVE) { + xSemaphoreGive(s_commissioner_active_sem); + } +} + // POST /api/thread/commissioner/open // Body: {"pskd": "J01NME"} // Fuehrt Stop+Start+Joiner-Add in EINEM atomaren Aufruf aus - verhindert @@ -578,33 +588,28 @@ static esp_err_t commissioner_open_handler(httpd_req_t *req) pskd[sizeof(pskd) - 1] = '\0'; cJSON_Delete(json); + if (!s_commissioner_active_sem) { + s_commissioner_active_sem = xSemaphoreCreateBinary(); + } + xSemaphoreTake(s_commissioner_active_sem, 0); // evtl. Altsignal verwerfen + otInstance *instance = otInstanceInitSingle(); esp_openthread_lock_acquire(portMAX_DELAY); - // Workaround fuer bekannten ESP-IDF-Bug (Issue #18075): - // Stop-vor-Start behebt "Failed to process Discovery Request: Security" otCommissionerStop(instance); - otError start_err = otCommissionerStart(instance, NULL, NULL, NULL); + otError start_err = otCommissionerStart(instance, commissioner_state_callback, NULL, NULL); esp_openthread_lock_release(); otError joiner_err = OT_ERROR_INVALID_STATE; if (start_err == OT_ERROR_NONE) { - // Commissioner braucht einen Moment fuer den Uebergang - // petitioning -> active, bevor AddJoiner erfolgreich sein kann - for (int i = 0; i < 20; i++) { // max. 2 Sekunden warten + // Waiting, until the State-Callback returns ACTIVE instead of Polling + if (xSemaphoreTake(s_commissioner_active_sem, pdMS_TO_TICKS(5000)) == pdTRUE) { esp_openthread_lock_acquire(portMAX_DELAY); - otCommissionerState state = otCommissionerGetState(instance); + joiner_err = otCommissionerAddJoiner(instance, NULL, pskd, 600); esp_openthread_lock_release(); - - if (state == OT_COMMISSIONER_STATE_ACTIVE) { - break; - } - vTaskDelay(pdMS_TO_TICKS(100)); + } else { + ESP_LOGW(TAG, "Timeout while waiting on the ACTIVE-state"); } - - esp_openthread_lock_acquire(portMAX_DELAY); - joiner_err = otCommissionerAddJoiner(instance, NULL, pskd, 0); - esp_openthread_lock_release(); } if (start_err != OT_ERROR_NONE || joiner_err != OT_ERROR_NONE) { diff --git a/ot_br/components/ot_br_web_api/ot_br_web_api_setup_mode.c b/ot_br/components/ot_br_web_api/ot_br_web_api_setup_mode.c index c95b9a1..87fc2c4 100644 --- a/ot_br/components/ot_br_web_api/ot_br_web_api_setup_mode.c +++ b/ot_br/components/ot_br_web_api/ot_br_web_api_setup_mode.c @@ -17,18 +17,59 @@ static const char *TAG = "ot_br_setup_mode"; static volatile bool s_setup_mode_active = false; static int64_t s_setup_mode_started_at = 0; +static void commissioner_state_callback(otCommissionerState aState, void *aContext) +{ + switch (aState) + { + case OT_COMMISSIONER_STATE_ACTIVE: + ESP_LOGI(TAG, "Commissioner ACTIVE"); + break; + + case OT_COMMISSIONER_STATE_PETITION: + ESP_LOGI(TAG, "Commissioner PETITION"); + break; + + case OT_COMMISSIONER_STATE_DISABLED: + ESP_LOGI(TAG, "Commissioner DISABLED"); + break; + + default: + ESP_LOGI(TAG, "Commissioner state: %d", aState); + break; + } +} static void auto_open_commissioning(void) { otInstance *instance = esp_openthread_get_instance(); esp_openthread_lock_acquire(portMAX_DELAY); - otCommissionerStop(instance); - otError err = otCommissionerStart(instance, NULL, NULL, NULL); + + otError err; + + if (otCommissionerGetState(instance) != OT_COMMISSIONER_STATE_DISABLED) + { + ESP_LOGW(TAG, "Commissioner already active - stopping first"); + + err = otCommissionerStop(instance); + + ESP_LOGI(TAG, "otCommissionerStop: %s (%d)", + otThreadErrorToString(err), err); + } + + err = otCommissionerStart(instance, commissioner_state_callback, NULL, NULL); + ESP_LOGI(TAG, "otCommissionerStart: %s (%d)", + otThreadErrorToString(err), err); + if (err == OT_ERROR_NONE) { - // Timeout = 600s (10 Minuten) - deckt exakt das Setup-Fenster ab, - // kein periodisches Nachtragen noetig - otCommissionerAddJoiner(instance, NULL, JOINER_PSKD, 600); - ESP_LOGI(TAG, "Open commissioning automatically for 10 minutes"); + err = otCommissionerAddJoiner(instance, NULL, JOINER_PSKD, 600); + ESP_LOGI(TAG, "otCommissionerAddJoiner: %s (%d)", + otThreadErrorToString(err), err); + + if (err == OT_ERROR_NONE) + { + ESP_LOGI(TAG, + "Open commissioning enabled for 600 seconds"); + } } esp_openthread_lock_release(); } @@ -46,15 +87,6 @@ static void button_task(void *arg) bool was_pressed = false; while (1) { - // uncomment for debug the button state - // - // static int64_t last_log = 0; - // int64_t now = esp_timer_get_time() / 1000; - // if (now - last_log > 1000) { - // ESP_LOGD(TAG, "GPIO0 state: %d", gpio_get_level(BUTTON_GPIO)); - // last_log = now; - // } - bool pressed = (gpio_get_level(BUTTON_GPIO) == 0); // Active-Low if (pressed && !was_pressed) { @@ -72,12 +104,12 @@ static void button_task(void *arg) } was_pressed = pressed; - // Zeitfenster automatisch ablaufen lassen + // let the timeframe expire automatically if (s_setup_mode_active) { int64_t elapsed = (esp_timer_get_time() / 1000) - s_setup_mode_started_at; if (elapsed > SETUP_WINDOW_MS) { s_setup_mode_active = false; - ESP_LOGI(TAG, "Setup-Modus abgelaufen"); + ESP_LOGI(TAG, "Setup-Modus is expired"); } }