From fd64585f99fe47e749606823231020915d6fa75e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:50:06 -0500 Subject: [PATCH 1/5] Bump github/codeql-action from 4.31.0 to 4.31.2 (#11626) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6b940eed8a..ab938b3436 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -58,7 +58,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -86,6 +86,6 @@ jobs: exit 1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0 + uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: category: "/language:${{matrix.language}}" From 59736f25e9f7bc15971ecf39c2d212a9a8835dc3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 30 Oct 2025 17:43:45 -0500 Subject: [PATCH 2/5] wip --- esphome/components/esp32_ble/ble.cpp | 89 +++++++++++++++++----------- esphome/components/esp32_ble/ble.h | 3 + 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 5bbd5fe9ed..b881211a26 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -335,6 +335,58 @@ bool ESP32BLE::ble_dismantle_() { return true; } +#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT +inline void ESP32BLE::dispatch_gap_event_(esp_gap_ble_cb_event_t gap_event, BLEEvent *ble_event) { + // Determine which union member to use based on event type. + // All event structures are properly laid out in memory per ESP-IDF. + // The reinterpret_cast operations are safe because: + // 1. Structure sizes match ESP-IDF expectations (verified by static_assert in ble_event.h) + // 2. Status fields are at offset 0 (verified by static_assert in ble_event.h) + // 3. The struct already contains our copy of the data (copied in BLEEvent constructor) + esp_ble_gap_cb_param_t *param; + + switch (gap_event) { + // Scan complete events - all have same structure with just status + case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: + case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: + case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: + param = reinterpret_cast(&ble_event->event_.gap.scan_complete); + break; + + // Advertising complete events - all have same structure with just status + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: + case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: + case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: + param = reinterpret_cast(&ble_event->event_.gap.adv_complete); + break; + + // RSSI complete event + case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: + param = reinterpret_cast(&ble_event->event_.gap.read_rssi_complete); + break; + + // Security events + case ESP_GAP_BLE_AUTH_CMPL_EVT: + case ESP_GAP_BLE_SEC_REQ_EVT: + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: + case ESP_GAP_BLE_PASSKEY_REQ_EVT: + case ESP_GAP_BLE_NC_REQ_EVT: + param = reinterpret_cast(&ble_event->event_.gap.security); + break; + + default: + return; // Shouldn't happen - all cases covered by loop() switch + } + + // Dispatch to all registered handlers + for (auto *gap_handler : this->gap_event_handlers_) { + gap_handler->gap_event_handler(gap_event, param); + } +} +#endif + void ESP32BLE::loop() { switch (this->state_) { case BLE_COMPONENT_STATE_OFF: @@ -417,46 +469,14 @@ void ESP32BLE::loop() { case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: - // All three scan complete events have the same structure with just status - // The scan_complete struct matches ESP-IDF's layout exactly, so this reinterpret_cast is safe - // This is verified at compile-time by static_assert checks in ble_event.h - // The struct already contains our copy of the status (copied in BLEEvent constructor) - ESP_LOGV(TAG, "gap_event_handler - %d", gap_event); -#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT - for (auto *gap_handler : this->gap_event_handlers_) { - gap_handler->gap_event_handler( - gap_event, reinterpret_cast(&ble_event->event_.gap.scan_complete)); - } -#endif - break; - // Advertising complete events case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: - // All advertising complete events have the same structure with just status - ESP_LOGV(TAG, "gap_event_handler - %d", gap_event); -#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT - for (auto *gap_handler : this->gap_event_handlers_) { - gap_handler->gap_event_handler( - gap_event, reinterpret_cast(&ble_event->event_.gap.adv_complete)); - } -#endif - break; - // RSSI complete event case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: - ESP_LOGV(TAG, "gap_event_handler - %d", gap_event); -#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT - for (auto *gap_handler : this->gap_event_handlers_) { - gap_handler->gap_event_handler( - gap_event, reinterpret_cast(&ble_event->event_.gap.read_rssi_complete)); - } -#endif - break; - // Security events case ESP_GAP_BLE_AUTH_CMPL_EVT: case ESP_GAP_BLE_SEC_REQ_EVT: @@ -465,10 +485,7 @@ void ESP32BLE::loop() { case ESP_GAP_BLE_NC_REQ_EVT: ESP_LOGV(TAG, "gap_event_handler - %d", gap_event); #ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT - for (auto *gap_handler : this->gap_event_handlers_) { - gap_handler->gap_event_handler( - gap_event, reinterpret_cast(&ble_event->event_.gap.security)); - } + this->dispatch_gap_event_(gap_event, ble_event); #endif break; diff --git a/esphome/components/esp32_ble/ble.h b/esphome/components/esp32_ble/ble.h index dc973f0e82..8c2954d571 100644 --- a/esphome/components/esp32_ble/ble.h +++ b/esphome/components/esp32_ble/ble.h @@ -161,6 +161,9 @@ class ESP32BLE : public Component { #ifdef USE_ESP32_BLE_ADVERTISING void advertising_init_(); #endif +#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT + void dispatch_gap_event_(esp_gap_ble_cb_event_t gap_event, BLEEvent *ble_event); +#endif private: template friend void enqueue_ble_event(Args... args); From 1905bbd8984fb727cd17cc945c53192089e60ed9 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 30 Oct 2025 17:49:20 -0500 Subject: [PATCH 3/5] dry --- esphome/components/esp32_ble/ble.cpp | 80 ++++++++++++---------------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index b881211a26..9d7b471be8 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -31,6 +31,26 @@ namespace esphome::esp32_ble { static const char *const TAG = "esp32_ble"; +// GAP event groups for deduplication across gap_event_handler and dispatch_gap_event_ +#define GAP_SCAN_COMPLETE_EVENTS \ + case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: \ + case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: \ + case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT + +#define GAP_ADV_COMPLETE_EVENTS \ + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: \ + case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: \ + case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: \ + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: \ + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT + +#define GAP_SECURITY_EVENTS \ + case ESP_GAP_BLE_AUTH_CMPL_EVT: \ + case ESP_GAP_BLE_SEC_REQ_EVT: \ + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: \ + case ESP_GAP_BLE_PASSKEY_REQ_EVT: \ + case ESP_GAP_BLE_NC_REQ_EVT + void ESP32BLE::setup() { global_ble = this; if (!ble_pre_setup_()) { @@ -346,21 +366,15 @@ inline void ESP32BLE::dispatch_gap_event_(esp_gap_ble_cb_event_t gap_event, BLEE esp_ble_gap_cb_param_t *param; switch (gap_event) { - // Scan complete events - all have same structure with just status - case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: - case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: - case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: - param = reinterpret_cast(&ble_event->event_.gap.scan_complete); - break; + // Scan complete events - all have same structure with just status + GAP_SCAN_COMPLETE_EVENTS: + param = reinterpret_cast(&ble_event->event_.gap.scan_complete); + break; - // Advertising complete events - all have same structure with just status - case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: - case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: - case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: - case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: - case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: - param = reinterpret_cast(&ble_event->event_.gap.adv_complete); - break; + // Advertising complete events - all have same structure with just status + GAP_ADV_COMPLETE_EVENTS: + param = reinterpret_cast(&ble_event->event_.gap.adv_complete); + break; // RSSI complete event case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: @@ -368,11 +382,7 @@ inline void ESP32BLE::dispatch_gap_event_(esp_gap_ble_cb_event_t gap_event, BLEE break; // Security events - case ESP_GAP_BLE_AUTH_CMPL_EVT: - case ESP_GAP_BLE_SEC_REQ_EVT: - case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: - case ESP_GAP_BLE_PASSKEY_REQ_EVT: - case ESP_GAP_BLE_NC_REQ_EVT: + GAP_SECURITY_EVENTS: param = reinterpret_cast(&ble_event->event_.gap.security); break; @@ -466,23 +476,13 @@ void ESP32BLE::loop() { break; // Scan complete events - case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: - case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: - case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: + GAP_SCAN_COMPLETE_EVENTS: // Advertising complete events - case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: - case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: - case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: - case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: - case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: + GAP_ADV_COMPLETE_EVENTS: // RSSI complete event case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: // Security events - case ESP_GAP_BLE_AUTH_CMPL_EVT: - case ESP_GAP_BLE_SEC_REQ_EVT: - case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: - case ESP_GAP_BLE_PASSKEY_REQ_EVT: - case ESP_GAP_BLE_NC_REQ_EVT: + GAP_SECURITY_EVENTS: ESP_LOGV(TAG, "gap_event_handler - %d", gap_event); #ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT this->dispatch_gap_event_(gap_event, ble_event); @@ -564,23 +564,13 @@ void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_pa // Queue GAP events that components need to handle // Scanning events - used by esp32_ble_tracker case ESP_GAP_BLE_SCAN_RESULT_EVT: - case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: - case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: - case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: + GAP_SCAN_COMPLETE_EVENTS: // Advertising events - used by esp32_ble_beacon and esp32_ble server - case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: - case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: - case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: - case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: - case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: + GAP_ADV_COMPLETE_EVENTS: // Connection events - used by ble_client case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: // Security events - used by ble_client and bluetooth_proxy - case ESP_GAP_BLE_AUTH_CMPL_EVT: - case ESP_GAP_BLE_SEC_REQ_EVT: - case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: - case ESP_GAP_BLE_PASSKEY_REQ_EVT: - case ESP_GAP_BLE_NC_REQ_EVT: + GAP_SECURITY_EVENTS: enqueue_ble_event(event, param); return; From 1925cd03795743947d852584d066df66e1d5e214 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 30 Oct 2025 17:53:34 -0500 Subject: [PATCH 4/5] dry --- esphome/components/esp32_ble/ble.cpp | 74 ++++++++++++---------------- esphome/components/esp32_ble/ble.h | 3 -- 2 files changed, 31 insertions(+), 46 deletions(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 9d7b471be8..117f489777 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -355,48 +355,6 @@ bool ESP32BLE::ble_dismantle_() { return true; } -#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT -inline void ESP32BLE::dispatch_gap_event_(esp_gap_ble_cb_event_t gap_event, BLEEvent *ble_event) { - // Determine which union member to use based on event type. - // All event structures are properly laid out in memory per ESP-IDF. - // The reinterpret_cast operations are safe because: - // 1. Structure sizes match ESP-IDF expectations (verified by static_assert in ble_event.h) - // 2. Status fields are at offset 0 (verified by static_assert in ble_event.h) - // 3. The struct already contains our copy of the data (copied in BLEEvent constructor) - esp_ble_gap_cb_param_t *param; - - switch (gap_event) { - // Scan complete events - all have same structure with just status - GAP_SCAN_COMPLETE_EVENTS: - param = reinterpret_cast(&ble_event->event_.gap.scan_complete); - break; - - // Advertising complete events - all have same structure with just status - GAP_ADV_COMPLETE_EVENTS: - param = reinterpret_cast(&ble_event->event_.gap.adv_complete); - break; - - // RSSI complete event - case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: - param = reinterpret_cast(&ble_event->event_.gap.read_rssi_complete); - break; - - // Security events - GAP_SECURITY_EVENTS: - param = reinterpret_cast(&ble_event->event_.gap.security); - break; - - default: - return; // Shouldn't happen - all cases covered by loop() switch - } - - // Dispatch to all registered handlers - for (auto *gap_handler : this->gap_event_handlers_) { - gap_handler->gap_event_handler(gap_event, param); - } -} -#endif - void ESP32BLE::loop() { switch (this->state_) { case BLE_COMPONENT_STATE_OFF: @@ -485,7 +443,37 @@ void ESP32BLE::loop() { GAP_SECURITY_EVENTS: ESP_LOGV(TAG, "gap_event_handler - %d", gap_event); #ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT - this->dispatch_gap_event_(gap_event, ble_event); + { + // Determine which union member to use based on event type. + // All event structures are properly laid out in memory per ESP-IDF. + // The reinterpret_cast operations are safe because: + // 1. Structure sizes match ESP-IDF expectations (verified by static_assert in ble_event.h) + // 2. Status fields are at offset 0 (verified by static_assert in ble_event.h) + // 3. The struct already contains our copy of the data (copied in BLEEvent constructor) + esp_ble_gap_cb_param_t *param; + // clang-format off + switch (gap_event) { + GAP_SCAN_COMPLETE_EVENTS: + param = reinterpret_cast(&ble_event->event_.gap.scan_complete); + break; + GAP_ADV_COMPLETE_EVENTS: + param = reinterpret_cast(&ble_event->event_.gap.adv_complete); + break; + case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: + param = reinterpret_cast(&ble_event->event_.gap.read_rssi_complete); + break; + GAP_SECURITY_EVENTS: + param = reinterpret_cast(&ble_event->event_.gap.security); + break; + default: + break; + } + // clang-format on + // Dispatch to all registered handlers + for (auto *gap_handler : this->gap_event_handlers_) { + gap_handler->gap_event_handler(gap_event, param); + } + } #endif break; diff --git a/esphome/components/esp32_ble/ble.h b/esphome/components/esp32_ble/ble.h index 8c2954d571..dc973f0e82 100644 --- a/esphome/components/esp32_ble/ble.h +++ b/esphome/components/esp32_ble/ble.h @@ -161,9 +161,6 @@ class ESP32BLE : public Component { #ifdef USE_ESP32_BLE_ADVERTISING void advertising_init_(); #endif -#ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT - void dispatch_gap_event_(esp_gap_ble_cb_event_t gap_event, BLEEvent *ble_event); -#endif private: template friend void enqueue_ble_event(Args... args); From d848cc33d7fd4d197f9697590234099c3f6dd5ba Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 30 Oct 2025 17:54:35 -0500 Subject: [PATCH 5/5] dry --- esphome/components/esp32_ble/ble.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 117f489777..69e317ff6d 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -444,27 +444,30 @@ void ESP32BLE::loop() { ESP_LOGV(TAG, "gap_event_handler - %d", gap_event); #ifdef ESPHOME_ESP32_BLE_GAP_EVENT_HANDLER_COUNT { - // Determine which union member to use based on event type. - // All event structures are properly laid out in memory per ESP-IDF. - // The reinterpret_cast operations are safe because: - // 1. Structure sizes match ESP-IDF expectations (verified by static_assert in ble_event.h) - // 2. Status fields are at offset 0 (verified by static_assert in ble_event.h) - // 3. The struct already contains our copy of the data (copied in BLEEvent constructor) esp_ble_gap_cb_param_t *param; // clang-format off switch (gap_event) { + // All three scan complete events have the same structure with just status + // The scan_complete struct matches ESP-IDF's layout exactly, so this reinterpret_cast is safe + // This is verified at compile-time by static_assert checks in ble_event.h + // The struct already contains our copy of the status (copied in BLEEvent constructor) GAP_SCAN_COMPLETE_EVENTS: param = reinterpret_cast(&ble_event->event_.gap.scan_complete); break; + + // All advertising complete events have the same structure with just status GAP_ADV_COMPLETE_EVENTS: param = reinterpret_cast(&ble_event->event_.gap.adv_complete); break; + case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: param = reinterpret_cast(&ble_event->event_.gap.read_rssi_complete); break; + GAP_SECURITY_EVENTS: param = reinterpret_cast(&ble_event->event_.gap.security); break; + default: break; }