esphome 2025.6.0b3__py3-none-any.whl → 2025.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/components/api/api_pb2.cpp +2 -0
- esphome/components/api/api_pb2.h +1 -0
- esphome/components/esp32_ble/ble.cpp +108 -46
- esphome/components/esp32_ble/ble.h +2 -0
- esphome/components/esp32_ble/ble_event.h +242 -75
- esphome/components/esp32_ble/ble_event_pool.h +72 -0
- esphome/components/esp32_ble/queue.h +14 -11
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +1 -0
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +4 -0
- esphome/components/nextion/nextion.cpp +2 -10
- esphome/components/openthread/__init__.py +5 -5
- esphome/components/openthread/openthread.cpp +3 -3
- esphome/components/openthread/tlv.py +7 -0
- esphome/config_validation.py +44 -1
- esphome/const.py +1 -1
- esphome/yaml_util.py +2 -1
- {esphome-2025.6.0b3.dist-info → esphome-2025.6.1.dist-info}/METADATA +1 -1
- {esphome-2025.6.0b3.dist-info → esphome-2025.6.1.dist-info}/RECORD +22 -21
- {esphome-2025.6.0b3.dist-info → esphome-2025.6.1.dist-info}/WHEEL +0 -0
- {esphome-2025.6.0b3.dist-info → esphome-2025.6.1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.6.0b3.dist-info → esphome-2025.6.1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.6.0b3.dist-info → esphome-2025.6.1.dist-info}/top_level.txt +0 -0
@@ -516,6 +516,8 @@ template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::V
|
|
516
516
|
return "VOICE_ASSISTANT_TTS_STREAM_START";
|
517
517
|
case enums::VOICE_ASSISTANT_TTS_STREAM_END:
|
518
518
|
return "VOICE_ASSISTANT_TTS_STREAM_END";
|
519
|
+
case enums::VOICE_ASSISTANT_INTENT_PROGRESS:
|
520
|
+
return "VOICE_ASSISTANT_INTENT_PROGRESS";
|
519
521
|
default:
|
520
522
|
return "UNKNOWN";
|
521
523
|
}
|
esphome/components/api/api_pb2.h
CHANGED
@@ -208,6 +208,7 @@ enum VoiceAssistantEvent : uint32_t {
|
|
208
208
|
VOICE_ASSISTANT_STT_VAD_END = 12,
|
209
209
|
VOICE_ASSISTANT_TTS_STREAM_START = 98,
|
210
210
|
VOICE_ASSISTANT_TTS_STREAM_END = 99,
|
211
|
+
VOICE_ASSISTANT_INTENT_PROGRESS = 100,
|
211
212
|
};
|
212
213
|
enum VoiceAssistantTimerEvent : uint32_t {
|
213
214
|
VOICE_ASSISTANT_TIMER_STARTED = 0,
|
@@ -1,6 +1,7 @@
|
|
1
1
|
#ifdef USE_ESP32
|
2
2
|
|
3
3
|
#include "ble.h"
|
4
|
+
#include "ble_event_pool.h"
|
4
5
|
|
5
6
|
#include "esphome/core/application.h"
|
6
7
|
#include "esphome/core/log.h"
|
@@ -23,9 +24,6 @@ namespace esp32_ble {
|
|
23
24
|
|
24
25
|
static const char *const TAG = "esp32_ble";
|
25
26
|
|
26
|
-
static RAMAllocator<BLEEvent> EVENT_ALLOCATOR( // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
27
|
-
RAMAllocator<BLEEvent>::ALLOW_FAILURE | RAMAllocator<BLEEvent>::ALLOC_INTERNAL);
|
28
|
-
|
29
27
|
void ESP32BLE::setup() {
|
30
28
|
global_ble = this;
|
31
29
|
ESP_LOGCONFIG(TAG, "Running setup");
|
@@ -326,32 +324,77 @@ void ESP32BLE::loop() {
|
|
326
324
|
}
|
327
325
|
case BLEEvent::GAP: {
|
328
326
|
esp_gap_ble_cb_event_t gap_event = ble_event->event_.gap.gap_event;
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
scan_handler->
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
//
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
327
|
+
switch (gap_event) {
|
328
|
+
case ESP_GAP_BLE_SCAN_RESULT_EVT:
|
329
|
+
// Use the new scan event handler - no memcpy!
|
330
|
+
for (auto *scan_handler : this->gap_scan_event_handlers_) {
|
331
|
+
scan_handler->gap_scan_event_handler(ble_event->scan_result());
|
332
|
+
}
|
333
|
+
break;
|
334
|
+
|
335
|
+
// Scan complete events
|
336
|
+
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
|
337
|
+
case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
|
338
|
+
case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
|
339
|
+
// All three scan complete events have the same structure with just status
|
340
|
+
// The scan_complete struct matches ESP-IDF's layout exactly, so this reinterpret_cast is safe
|
341
|
+
// This is verified at compile-time by static_assert checks in ble_event.h
|
342
|
+
// The struct already contains our copy of the status (copied in BLEEvent constructor)
|
343
|
+
ESP_LOGV(TAG, "gap_event_handler - %d", gap_event);
|
344
|
+
for (auto *gap_handler : this->gap_event_handlers_) {
|
345
|
+
gap_handler->gap_event_handler(
|
346
|
+
gap_event, reinterpret_cast<esp_ble_gap_cb_param_t *>(&ble_event->event_.gap.scan_complete));
|
347
|
+
}
|
348
|
+
break;
|
349
|
+
|
350
|
+
// Advertising complete events
|
351
|
+
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
|
352
|
+
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
|
353
|
+
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
|
354
|
+
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
|
355
|
+
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
|
356
|
+
// All advertising complete events have the same structure with just status
|
357
|
+
ESP_LOGV(TAG, "gap_event_handler - %d", gap_event);
|
358
|
+
for (auto *gap_handler : this->gap_event_handlers_) {
|
359
|
+
gap_handler->gap_event_handler(
|
360
|
+
gap_event, reinterpret_cast<esp_ble_gap_cb_param_t *>(&ble_event->event_.gap.adv_complete));
|
361
|
+
}
|
362
|
+
break;
|
363
|
+
|
364
|
+
// RSSI complete event
|
365
|
+
case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
|
366
|
+
ESP_LOGV(TAG, "gap_event_handler - %d", gap_event);
|
367
|
+
for (auto *gap_handler : this->gap_event_handlers_) {
|
368
|
+
gap_handler->gap_event_handler(
|
369
|
+
gap_event, reinterpret_cast<esp_ble_gap_cb_param_t *>(&ble_event->event_.gap.read_rssi_complete));
|
370
|
+
}
|
371
|
+
break;
|
372
|
+
|
373
|
+
// Security events
|
374
|
+
case ESP_GAP_BLE_AUTH_CMPL_EVT:
|
375
|
+
case ESP_GAP_BLE_SEC_REQ_EVT:
|
376
|
+
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:
|
377
|
+
case ESP_GAP_BLE_PASSKEY_REQ_EVT:
|
378
|
+
case ESP_GAP_BLE_NC_REQ_EVT:
|
379
|
+
ESP_LOGV(TAG, "gap_event_handler - %d", gap_event);
|
380
|
+
for (auto *gap_handler : this->gap_event_handlers_) {
|
381
|
+
gap_handler->gap_event_handler(
|
382
|
+
gap_event, reinterpret_cast<esp_ble_gap_cb_param_t *>(&ble_event->event_.gap.security));
|
383
|
+
}
|
384
|
+
break;
|
385
|
+
|
386
|
+
default:
|
387
|
+
// Unknown/unhandled event
|
388
|
+
ESP_LOGW(TAG, "Unhandled GAP event type in loop: %d", gap_event);
|
389
|
+
break;
|
346
390
|
}
|
347
391
|
break;
|
348
392
|
}
|
349
393
|
default:
|
350
394
|
break;
|
351
395
|
}
|
352
|
-
//
|
353
|
-
ble_event
|
354
|
-
EVENT_ALLOCATOR.deallocate(ble_event, 1);
|
396
|
+
// Return the event to the pool
|
397
|
+
this->ble_event_pool_.release(ble_event);
|
355
398
|
ble_event = this->ble_events_.pop();
|
356
399
|
}
|
357
400
|
if (this->advertising_ != nullptr) {
|
@@ -359,37 +402,41 @@ void ESP32BLE::loop() {
|
|
359
402
|
}
|
360
403
|
|
361
404
|
// Log dropped events periodically
|
362
|
-
|
405
|
+
uint16_t dropped = this->ble_events_.get_and_reset_dropped_count();
|
363
406
|
if (dropped > 0) {
|
364
|
-
ESP_LOGW(TAG, "Dropped %
|
407
|
+
ESP_LOGW(TAG, "Dropped %u BLE events due to buffer overflow", dropped);
|
365
408
|
}
|
366
409
|
}
|
367
410
|
|
411
|
+
// Helper function to load new event data based on type
|
412
|
+
void load_ble_event(BLEEvent *event, esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) {
|
413
|
+
event->load_gap_event(e, p);
|
414
|
+
}
|
415
|
+
|
416
|
+
void load_ble_event(BLEEvent *event, esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
|
417
|
+
event->load_gattc_event(e, i, p);
|
418
|
+
}
|
419
|
+
|
420
|
+
void load_ble_event(BLEEvent *event, esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
|
421
|
+
event->load_gatts_event(e, i, p);
|
422
|
+
}
|
423
|
+
|
368
424
|
template<typename... Args> void enqueue_ble_event(Args... args) {
|
369
|
-
//
|
370
|
-
|
371
|
-
|
425
|
+
// Allocate an event from the pool
|
426
|
+
BLEEvent *event = global_ble->ble_event_pool_.allocate();
|
427
|
+
if (event == nullptr) {
|
428
|
+
// No events available - queue is full or we're out of memory
|
372
429
|
global_ble->ble_events_.increment_dropped_count();
|
373
430
|
return;
|
374
431
|
}
|
375
432
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
// Push the event - since we're the only producer and we checked full() above,
|
385
|
-
// this should always succeed unless we have a bug
|
386
|
-
if (!global_ble->ble_events_.push(new_event)) {
|
387
|
-
// This should not happen in SPSC queue with single producer
|
388
|
-
ESP_LOGE(TAG, "BLE queue push failed unexpectedly");
|
389
|
-
new_event->~BLEEvent();
|
390
|
-
EVENT_ALLOCATOR.deallocate(new_event, 1);
|
391
|
-
}
|
392
|
-
} // NOLINT(clang-analyzer-unix.Malloc)
|
433
|
+
// Load new event data (replaces previous event)
|
434
|
+
load_ble_event(event, args...);
|
435
|
+
|
436
|
+
// Push the event to the queue
|
437
|
+
global_ble->ble_events_.push(event);
|
438
|
+
// Push always succeeds because we're the only producer and the pool ensures we never exceed queue size
|
439
|
+
}
|
393
440
|
|
394
441
|
// Explicit template instantiations for the friend function
|
395
442
|
template void enqueue_ble_event(esp_gap_ble_cb_event_t, esp_ble_gap_cb_param_t *);
|
@@ -398,11 +445,26 @@ template void enqueue_ble_event(esp_gattc_cb_event_t, esp_gatt_if_t, esp_ble_gat
|
|
398
445
|
|
399
446
|
void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
400
447
|
switch (event) {
|
401
|
-
//
|
448
|
+
// Queue GAP events that components need to handle
|
449
|
+
// Scanning events - used by esp32_ble_tracker
|
402
450
|
case ESP_GAP_BLE_SCAN_RESULT_EVT:
|
403
451
|
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
|
404
452
|
case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
|
405
453
|
case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
|
454
|
+
// Advertising events - used by esp32_ble_beacon and esp32_ble server
|
455
|
+
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
|
456
|
+
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
|
457
|
+
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
|
458
|
+
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
|
459
|
+
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
|
460
|
+
// Connection events - used by ble_client
|
461
|
+
case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
|
462
|
+
// Security events - used by ble_client and bluetooth_proxy
|
463
|
+
case ESP_GAP_BLE_AUTH_CMPL_EVT:
|
464
|
+
case ESP_GAP_BLE_SEC_REQ_EVT:
|
465
|
+
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:
|
466
|
+
case ESP_GAP_BLE_PASSKEY_REQ_EVT:
|
467
|
+
case ESP_GAP_BLE_NC_REQ_EVT:
|
406
468
|
enqueue_ble_event(event, param);
|
407
469
|
return;
|
408
470
|
|
@@ -12,6 +12,7 @@
|
|
12
12
|
#include "esphome/core/helpers.h"
|
13
13
|
|
14
14
|
#include "ble_event.h"
|
15
|
+
#include "ble_event_pool.h"
|
15
16
|
#include "queue.h"
|
16
17
|
|
17
18
|
#ifdef USE_ESP32
|
@@ -148,6 +149,7 @@ class ESP32BLE : public Component {
|
|
148
149
|
BLEComponentState state_{BLE_COMPONENT_STATE_OFF};
|
149
150
|
|
150
151
|
LockFreeQueue<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_events_;
|
152
|
+
BLEEventPool<MAX_BLE_QUEUE_SIZE> ble_event_pool_;
|
151
153
|
BLEAdvertising *advertising_{};
|
152
154
|
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE};
|
153
155
|
uint32_t advertising_cycle_time_{};
|
@@ -24,16 +24,45 @@ static_assert(sizeof(esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param) == si
|
|
24
24
|
"ESP-IDF scan_stop_cmpl structure has unexpected size");
|
25
25
|
|
26
26
|
// Verify the status field is at offset 0 (first member)
|
27
|
-
static_assert(offsetof(esp_ble_gap_cb_param_t, scan_param_cmpl.status) ==
|
28
|
-
offsetof(esp_ble_gap_cb_param_t, scan_param_cmpl),
|
27
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, scan_param_cmpl.status) == 0,
|
29
28
|
"status must be first member of scan_param_cmpl");
|
30
|
-
static_assert(offsetof(esp_ble_gap_cb_param_t, scan_start_cmpl.status) ==
|
31
|
-
offsetof(esp_ble_gap_cb_param_t, scan_start_cmpl),
|
29
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, scan_start_cmpl.status) == 0,
|
32
30
|
"status must be first member of scan_start_cmpl");
|
33
|
-
static_assert(offsetof(esp_ble_gap_cb_param_t, scan_stop_cmpl.status) ==
|
34
|
-
offsetof(esp_ble_gap_cb_param_t, scan_stop_cmpl),
|
31
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, scan_stop_cmpl.status) == 0,
|
35
32
|
"status must be first member of scan_stop_cmpl");
|
36
33
|
|
34
|
+
// Compile-time verification for advertising complete events
|
35
|
+
static_assert(sizeof(esp_ble_gap_cb_param_t::ble_adv_data_cmpl_evt_param) == sizeof(esp_bt_status_t),
|
36
|
+
"ESP-IDF adv_data_cmpl structure has unexpected size");
|
37
|
+
static_assert(sizeof(esp_ble_gap_cb_param_t::ble_scan_rsp_data_cmpl_evt_param) == sizeof(esp_bt_status_t),
|
38
|
+
"ESP-IDF scan_rsp_data_cmpl structure has unexpected size");
|
39
|
+
static_assert(sizeof(esp_ble_gap_cb_param_t::ble_adv_data_raw_cmpl_evt_param) == sizeof(esp_bt_status_t),
|
40
|
+
"ESP-IDF adv_data_raw_cmpl structure has unexpected size");
|
41
|
+
static_assert(sizeof(esp_ble_gap_cb_param_t::ble_adv_start_cmpl_evt_param) == sizeof(esp_bt_status_t),
|
42
|
+
"ESP-IDF adv_start_cmpl structure has unexpected size");
|
43
|
+
static_assert(sizeof(esp_ble_gap_cb_param_t::ble_adv_stop_cmpl_evt_param) == sizeof(esp_bt_status_t),
|
44
|
+
"ESP-IDF adv_stop_cmpl structure has unexpected size");
|
45
|
+
|
46
|
+
// Verify the status field is at offset 0 for advertising events
|
47
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, adv_data_cmpl.status) == 0,
|
48
|
+
"status must be first member of adv_data_cmpl");
|
49
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, scan_rsp_data_cmpl.status) == 0,
|
50
|
+
"status must be first member of scan_rsp_data_cmpl");
|
51
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, adv_data_raw_cmpl.status) == 0,
|
52
|
+
"status must be first member of adv_data_raw_cmpl");
|
53
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, adv_start_cmpl.status) == 0,
|
54
|
+
"status must be first member of adv_start_cmpl");
|
55
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, adv_stop_cmpl.status) == 0,
|
56
|
+
"status must be first member of adv_stop_cmpl");
|
57
|
+
|
58
|
+
// Compile-time verification for RSSI complete event structure
|
59
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, read_rssi_cmpl.status) == 0,
|
60
|
+
"status must be first member of read_rssi_cmpl");
|
61
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, read_rssi_cmpl.rssi) == sizeof(esp_bt_status_t),
|
62
|
+
"rssi must immediately follow status in read_rssi_cmpl");
|
63
|
+
static_assert(offsetof(esp_ble_gap_cb_param_t, read_rssi_cmpl.remote_addr) == sizeof(esp_bt_status_t) + sizeof(int8_t),
|
64
|
+
"remote_addr must follow rssi in read_rssi_cmpl");
|
65
|
+
|
37
66
|
// Received GAP, GATTC and GATTS events are only queued, and get processed in the main loop().
|
38
67
|
// This class stores each event with minimal memory usage.
|
39
68
|
// GAP events (99% of traffic) don't have the vector overhead.
|
@@ -51,6 +80,13 @@ static_assert(offsetof(esp_ble_gap_cb_param_t, scan_stop_cmpl.status) ==
|
|
51
80
|
// - GATTC/GATTS events: We heap-allocate and copy the entire param struct, ensuring
|
52
81
|
// the data remains valid even after the BLE callback returns. The original
|
53
82
|
// param pointer from ESP-IDF is only valid during the callback.
|
83
|
+
//
|
84
|
+
// CRITICAL DESIGN NOTE:
|
85
|
+
// The heap allocations for GATTC/GATTS events are REQUIRED for memory safety.
|
86
|
+
// DO NOT attempt to optimize by removing these allocations or storing pointers
|
87
|
+
// to the original ESP-IDF data. The ESP-IDF callback data has a different lifetime
|
88
|
+
// than our event processing, and accessing it after the callback returns would
|
89
|
+
// result in use-after-free bugs and crashes.
|
54
90
|
class BLEEvent {
|
55
91
|
public:
|
56
92
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
@@ -60,19 +96,155 @@ class BLEEvent {
|
|
60
96
|
GATTS,
|
61
97
|
};
|
62
98
|
|
99
|
+
// Type definitions for cleaner method signatures
|
100
|
+
struct StatusOnlyData {
|
101
|
+
esp_bt_status_t status;
|
102
|
+
};
|
103
|
+
|
104
|
+
struct RSSICompleteData {
|
105
|
+
esp_bt_status_t status;
|
106
|
+
int8_t rssi;
|
107
|
+
esp_bd_addr_t remote_addr;
|
108
|
+
};
|
109
|
+
|
63
110
|
// Constructor for GAP events - no external allocations needed
|
64
111
|
BLEEvent(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) {
|
65
112
|
this->type_ = GAP;
|
113
|
+
this->init_gap_data_(e, p);
|
114
|
+
}
|
115
|
+
|
116
|
+
// Constructor for GATTC events - uses heap allocation
|
117
|
+
// IMPORTANT: The heap allocation is REQUIRED and must not be removed as an optimization.
|
118
|
+
// The param pointer from ESP-IDF is only valid during the callback execution.
|
119
|
+
// Since BLE events are processed asynchronously in the main loop, we must create
|
120
|
+
// our own copy to ensure the data remains valid until the event is processed.
|
121
|
+
BLEEvent(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
|
122
|
+
this->type_ = GATTC;
|
123
|
+
this->init_gattc_data_(e, i, p);
|
124
|
+
}
|
125
|
+
|
126
|
+
// Constructor for GATTS events - uses heap allocation
|
127
|
+
// IMPORTANT: The heap allocation is REQUIRED and must not be removed as an optimization.
|
128
|
+
// The param pointer from ESP-IDF is only valid during the callback execution.
|
129
|
+
// Since BLE events are processed asynchronously in the main loop, we must create
|
130
|
+
// our own copy to ensure the data remains valid until the event is processed.
|
131
|
+
BLEEvent(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
|
132
|
+
this->type_ = GATTS;
|
133
|
+
this->init_gatts_data_(e, i, p);
|
134
|
+
}
|
135
|
+
|
136
|
+
// Destructor to clean up heap allocations
|
137
|
+
~BLEEvent() { this->cleanup_heap_data(); }
|
138
|
+
|
139
|
+
// Default constructor for pre-allocation in pool
|
140
|
+
BLEEvent() : type_(GAP) {}
|
141
|
+
|
142
|
+
// Clean up any heap-allocated data
|
143
|
+
void cleanup_heap_data() {
|
144
|
+
if (this->type_ == GAP) {
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
if (this->type_ == GATTC) {
|
148
|
+
delete this->event_.gattc.gattc_param;
|
149
|
+
delete this->event_.gattc.data;
|
150
|
+
this->event_.gattc.gattc_param = nullptr;
|
151
|
+
this->event_.gattc.data = nullptr;
|
152
|
+
return;
|
153
|
+
}
|
154
|
+
if (this->type_ == GATTS) {
|
155
|
+
delete this->event_.gatts.gatts_param;
|
156
|
+
delete this->event_.gatts.data;
|
157
|
+
this->event_.gatts.gatts_param = nullptr;
|
158
|
+
this->event_.gatts.data = nullptr;
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
// Load new event data for reuse (replaces previous event data)
|
163
|
+
void load_gap_event(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) {
|
164
|
+
this->cleanup_heap_data();
|
165
|
+
this->type_ = GAP;
|
166
|
+
this->init_gap_data_(e, p);
|
167
|
+
}
|
168
|
+
|
169
|
+
void load_gattc_event(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
|
170
|
+
this->cleanup_heap_data();
|
171
|
+
this->type_ = GATTC;
|
172
|
+
this->init_gattc_data_(e, i, p);
|
173
|
+
}
|
174
|
+
|
175
|
+
void load_gatts_event(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
|
176
|
+
this->cleanup_heap_data();
|
177
|
+
this->type_ = GATTS;
|
178
|
+
this->init_gatts_data_(e, i, p);
|
179
|
+
}
|
180
|
+
|
181
|
+
// Disable copy to prevent double-delete
|
182
|
+
BLEEvent(const BLEEvent &) = delete;
|
183
|
+
BLEEvent &operator=(const BLEEvent &) = delete;
|
184
|
+
|
185
|
+
union {
|
186
|
+
// NOLINTNEXTLINE(readability-identifier-naming)
|
187
|
+
struct gap_event {
|
188
|
+
esp_gap_ble_cb_event_t gap_event;
|
189
|
+
union {
|
190
|
+
BLEScanResult scan_result; // 73 bytes - Used by: esp32_ble_tracker
|
191
|
+
// This matches ESP-IDF's scan complete event structures
|
192
|
+
// All three (scan_param_cmpl, scan_start_cmpl, scan_stop_cmpl) have identical layout
|
193
|
+
// Used by: esp32_ble_tracker
|
194
|
+
StatusOnlyData scan_complete; // 1 byte
|
195
|
+
// Advertising complete events all have same structure
|
196
|
+
// Used by: esp32_ble_beacon, esp32_ble server components
|
197
|
+
// ADV_DATA_SET, SCAN_RSP_DATA_SET, ADV_DATA_RAW_SET, ADV_START, ADV_STOP
|
198
|
+
StatusOnlyData adv_complete; // 1 byte
|
199
|
+
// RSSI complete event
|
200
|
+
// Used by: ble_client (ble_rssi_sensor component)
|
201
|
+
RSSICompleteData read_rssi_complete; // 8 bytes
|
202
|
+
// Security events - we store the full security union
|
203
|
+
// Used by: ble_client (automation), bluetooth_proxy, esp32_ble_client
|
204
|
+
esp_ble_sec_t security; // Variable size, but fits within scan_result size
|
205
|
+
};
|
206
|
+
} gap; // 80 bytes total
|
207
|
+
|
208
|
+
// NOLINTNEXTLINE(readability-identifier-naming)
|
209
|
+
struct gattc_event {
|
210
|
+
esp_gattc_cb_event_t gattc_event;
|
211
|
+
esp_gatt_if_t gattc_if;
|
212
|
+
esp_ble_gattc_cb_param_t *gattc_param; // Heap-allocated
|
213
|
+
std::vector<uint8_t> *data; // Heap-allocated
|
214
|
+
} gattc; // 16 bytes (pointers only)
|
215
|
+
|
216
|
+
// NOLINTNEXTLINE(readability-identifier-naming)
|
217
|
+
struct gatts_event {
|
218
|
+
esp_gatts_cb_event_t gatts_event;
|
219
|
+
esp_gatt_if_t gatts_if;
|
220
|
+
esp_ble_gatts_cb_param_t *gatts_param; // Heap-allocated
|
221
|
+
std::vector<uint8_t> *data; // Heap-allocated
|
222
|
+
} gatts; // 16 bytes (pointers only)
|
223
|
+
} event_; // 80 bytes
|
224
|
+
|
225
|
+
ble_event_t type_;
|
226
|
+
|
227
|
+
// Helper methods to access event data
|
228
|
+
ble_event_t type() const { return type_; }
|
229
|
+
esp_gap_ble_cb_event_t gap_event_type() const { return event_.gap.gap_event; }
|
230
|
+
const BLEScanResult &scan_result() const { return event_.gap.scan_result; }
|
231
|
+
esp_bt_status_t scan_complete_status() const { return event_.gap.scan_complete.status; }
|
232
|
+
esp_bt_status_t adv_complete_status() const { return event_.gap.adv_complete.status; }
|
233
|
+
const RSSICompleteData &read_rssi_complete() const { return event_.gap.read_rssi_complete; }
|
234
|
+
const esp_ble_sec_t &security() const { return event_.gap.security; }
|
235
|
+
|
236
|
+
private:
|
237
|
+
// Initialize GAP event data
|
238
|
+
void init_gap_data_(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) {
|
66
239
|
this->event_.gap.gap_event = e;
|
67
240
|
|
68
241
|
if (p == nullptr) {
|
69
242
|
return; // Invalid event, but we can't log in header file
|
70
243
|
}
|
71
244
|
|
72
|
-
//
|
245
|
+
// Copy data based on event type
|
73
246
|
switch (e) {
|
74
247
|
case ESP_GAP_BLE_SCAN_RESULT_EVT:
|
75
|
-
// Copy only the fields we use from scan results
|
76
248
|
memcpy(this->event_.gap.scan_result.bda, p->scan_rst.bda, sizeof(esp_bd_addr_t));
|
77
249
|
this->event_.gap.scan_result.ble_addr_type = p->scan_rst.ble_addr_type;
|
78
250
|
this->event_.gap.scan_result.rssi = p->scan_rst.rssi;
|
@@ -95,16 +267,53 @@ class BLEEvent {
|
|
95
267
|
this->event_.gap.scan_complete.status = p->scan_stop_cmpl.status;
|
96
268
|
break;
|
97
269
|
|
270
|
+
// Advertising complete events - all have same structure with just status
|
271
|
+
// Used by: esp32_ble_beacon, esp32_ble server components
|
272
|
+
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
|
273
|
+
this->event_.gap.adv_complete.status = p->adv_data_cmpl.status;
|
274
|
+
break;
|
275
|
+
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
|
276
|
+
this->event_.gap.adv_complete.status = p->scan_rsp_data_cmpl.status;
|
277
|
+
break;
|
278
|
+
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: // Used by: esp32_ble_beacon
|
279
|
+
this->event_.gap.adv_complete.status = p->adv_data_raw_cmpl.status;
|
280
|
+
break;
|
281
|
+
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: // Used by: esp32_ble_beacon
|
282
|
+
this->event_.gap.adv_complete.status = p->adv_start_cmpl.status;
|
283
|
+
break;
|
284
|
+
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: // Used by: esp32_ble_beacon
|
285
|
+
this->event_.gap.adv_complete.status = p->adv_stop_cmpl.status;
|
286
|
+
break;
|
287
|
+
|
288
|
+
// RSSI complete event
|
289
|
+
// Used by: ble_client (ble_rssi_sensor)
|
290
|
+
case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT:
|
291
|
+
this->event_.gap.read_rssi_complete.status = p->read_rssi_cmpl.status;
|
292
|
+
this->event_.gap.read_rssi_complete.rssi = p->read_rssi_cmpl.rssi;
|
293
|
+
memcpy(this->event_.gap.read_rssi_complete.remote_addr, p->read_rssi_cmpl.remote_addr, sizeof(esp_bd_addr_t));
|
294
|
+
break;
|
295
|
+
|
296
|
+
// Security events - copy the entire security union
|
297
|
+
// Used by: ble_client, bluetooth_proxy, esp32_ble_client
|
298
|
+
case ESP_GAP_BLE_AUTH_CMPL_EVT: // Used by: bluetooth_proxy, esp32_ble_client
|
299
|
+
case ESP_GAP_BLE_SEC_REQ_EVT: // Used by: esp32_ble_client
|
300
|
+
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: // Used by: ble_client automation
|
301
|
+
case ESP_GAP_BLE_PASSKEY_REQ_EVT: // Used by: ble_client automation
|
302
|
+
case ESP_GAP_BLE_NC_REQ_EVT: // Used by: ble_client automation
|
303
|
+
memcpy(&this->event_.gap.security, &p->ble_security, sizeof(esp_ble_sec_t));
|
304
|
+
break;
|
305
|
+
|
98
306
|
default:
|
99
|
-
// We only
|
307
|
+
// We only store data for GAP events that components currently use
|
308
|
+
// Unknown events still get queued and logged in ble.cpp:375 as
|
309
|
+
// "Unhandled GAP event type in loop" - this helps identify new events
|
310
|
+
// that components might need in the future
|
100
311
|
break;
|
101
312
|
}
|
102
313
|
}
|
103
314
|
|
104
|
-
//
|
105
|
-
|
106
|
-
BLEEvent(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
|
107
|
-
this->type_ = GATTC;
|
315
|
+
// Initialize GATTC event data
|
316
|
+
void init_gattc_data_(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
|
108
317
|
this->event_.gattc.gattc_event = e;
|
109
318
|
this->event_.gattc.gattc_if = i;
|
110
319
|
|
@@ -117,9 +326,15 @@ class BLEEvent {
|
|
117
326
|
// Heap-allocate param and data
|
118
327
|
// Heap allocation is used because GATTC/GATTS events are rare (<1% of events)
|
119
328
|
// while GAP events (99%) are stored inline to minimize memory usage
|
329
|
+
// IMPORTANT: This heap allocation provides clear ownership semantics:
|
330
|
+
// - The BLEEvent owns the allocated memory for its lifetime
|
331
|
+
// - The data remains valid from the BLE callback context until processed in the main loop
|
332
|
+
// - Without this copy, we'd have use-after-free bugs as ESP-IDF reuses the callback memory
|
120
333
|
this->event_.gattc.gattc_param = new esp_ble_gattc_cb_param_t(*p);
|
121
334
|
|
122
335
|
// Copy data for events that need it
|
336
|
+
// The param struct contains pointers (e.g., notify.value) that point to temporary buffers.
|
337
|
+
// We must copy this data to ensure it remains valid when the event is processed later.
|
123
338
|
switch (e) {
|
124
339
|
case ESP_GATTC_NOTIFY_EVT:
|
125
340
|
this->event_.gattc.data = new std::vector<uint8_t>(p->notify.value, p->notify.value + p->notify.value_len);
|
@@ -136,10 +351,8 @@ class BLEEvent {
|
|
136
351
|
}
|
137
352
|
}
|
138
353
|
|
139
|
-
//
|
140
|
-
|
141
|
-
BLEEvent(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
|
142
|
-
this->type_ = GATTS;
|
354
|
+
// Initialize GATTS event data
|
355
|
+
void init_gatts_data_(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
|
143
356
|
this->event_.gatts.gatts_event = e;
|
144
357
|
this->event_.gatts.gatts_if = i;
|
145
358
|
|
@@ -152,9 +365,15 @@ class BLEEvent {
|
|
152
365
|
// Heap-allocate param and data
|
153
366
|
// Heap allocation is used because GATTC/GATTS events are rare (<1% of events)
|
154
367
|
// while GAP events (99%) are stored inline to minimize memory usage
|
368
|
+
// IMPORTANT: This heap allocation provides clear ownership semantics:
|
369
|
+
// - The BLEEvent owns the allocated memory for its lifetime
|
370
|
+
// - The data remains valid from the BLE callback context until processed in the main loop
|
371
|
+
// - Without this copy, we'd have use-after-free bugs as ESP-IDF reuses the callback memory
|
155
372
|
this->event_.gatts.gatts_param = new esp_ble_gatts_cb_param_t(*p);
|
156
373
|
|
157
374
|
// Copy data for events that need it
|
375
|
+
// The param struct contains pointers (e.g., write.value) that point to temporary buffers.
|
376
|
+
// We must copy this data to ensure it remains valid when the event is processed later.
|
158
377
|
switch (e) {
|
159
378
|
case ESP_GATTS_WRITE_EVT:
|
160
379
|
this->event_.gatts.data = new std::vector<uint8_t>(p->write.value, p->write.value + p->write.len);
|
@@ -165,66 +384,14 @@ class BLEEvent {
|
|
165
384
|
break;
|
166
385
|
}
|
167
386
|
}
|
387
|
+
};
|
168
388
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
case GATTC:
|
173
|
-
delete this->event_.gattc.gattc_param;
|
174
|
-
delete this->event_.gattc.data;
|
175
|
-
break;
|
176
|
-
case GATTS:
|
177
|
-
delete this->event_.gatts.gatts_param;
|
178
|
-
delete this->event_.gatts.data;
|
179
|
-
break;
|
180
|
-
default:
|
181
|
-
break;
|
182
|
-
}
|
183
|
-
}
|
184
|
-
|
185
|
-
// Disable copy to prevent double-delete
|
186
|
-
BLEEvent(const BLEEvent &) = delete;
|
187
|
-
BLEEvent &operator=(const BLEEvent &) = delete;
|
188
|
-
|
189
|
-
union {
|
190
|
-
// NOLINTNEXTLINE(readability-identifier-naming)
|
191
|
-
struct gap_event {
|
192
|
-
esp_gap_ble_cb_event_t gap_event;
|
193
|
-
union {
|
194
|
-
BLEScanResult scan_result; // 73 bytes
|
195
|
-
// This matches ESP-IDF's scan complete event structures
|
196
|
-
// All three (scan_param_cmpl, scan_start_cmpl, scan_stop_cmpl) have identical layout
|
197
|
-
struct {
|
198
|
-
esp_bt_status_t status;
|
199
|
-
} scan_complete; // 1 byte
|
200
|
-
};
|
201
|
-
} gap; // 80 bytes total
|
202
|
-
|
203
|
-
// NOLINTNEXTLINE(readability-identifier-naming)
|
204
|
-
struct gattc_event {
|
205
|
-
esp_gattc_cb_event_t gattc_event;
|
206
|
-
esp_gatt_if_t gattc_if;
|
207
|
-
esp_ble_gattc_cb_param_t *gattc_param; // Heap-allocated
|
208
|
-
std::vector<uint8_t> *data; // Heap-allocated
|
209
|
-
} gattc; // 16 bytes (pointers only)
|
210
|
-
|
211
|
-
// NOLINTNEXTLINE(readability-identifier-naming)
|
212
|
-
struct gatts_event {
|
213
|
-
esp_gatts_cb_event_t gatts_event;
|
214
|
-
esp_gatt_if_t gatts_if;
|
215
|
-
esp_ble_gatts_cb_param_t *gatts_param; // Heap-allocated
|
216
|
-
std::vector<uint8_t> *data; // Heap-allocated
|
217
|
-
} gatts; // 16 bytes (pointers only)
|
218
|
-
} event_; // 80 bytes
|
219
|
-
|
220
|
-
ble_event_t type_;
|
389
|
+
// Verify the gap_event struct hasn't grown beyond expected size
|
390
|
+
// The gap member in the union should be 80 bytes (including the gap_event enum)
|
391
|
+
static_assert(sizeof(decltype(((BLEEvent *) nullptr)->event_.gap)) <= 80, "gap_event struct has grown beyond 80 bytes");
|
221
392
|
|
222
|
-
|
223
|
-
|
224
|
-
esp_gap_ble_cb_event_t gap_event_type() const { return event_.gap.gap_event; }
|
225
|
-
const BLEScanResult &scan_result() const { return event_.gap.scan_result; }
|
226
|
-
esp_bt_status_t scan_complete_status() const { return event_.gap.scan_complete.status; }
|
227
|
-
};
|
393
|
+
// Verify esp_ble_sec_t fits within our union
|
394
|
+
static_assert(sizeof(esp_ble_sec_t) <= 73, "esp_ble_sec_t is larger than BLEScanResult");
|
228
395
|
|
229
396
|
// BLEEvent total size: 84 bytes (80 byte union + 1 byte type + 3 bytes padding)
|
230
397
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#ifdef USE_ESP32
|
4
|
+
|
5
|
+
#include <atomic>
|
6
|
+
#include <cstddef>
|
7
|
+
#include "ble_event.h"
|
8
|
+
#include "queue.h"
|
9
|
+
#include "esphome/core/helpers.h"
|
10
|
+
|
11
|
+
namespace esphome {
|
12
|
+
namespace esp32_ble {
|
13
|
+
|
14
|
+
// BLE Event Pool - On-demand pool of BLEEvent objects to avoid heap fragmentation
|
15
|
+
// Events are allocated on first use and reused thereafter, growing to peak usage
|
16
|
+
template<uint8_t SIZE> class BLEEventPool {
|
17
|
+
public:
|
18
|
+
BLEEventPool() : total_created_(0) {}
|
19
|
+
|
20
|
+
~BLEEventPool() {
|
21
|
+
// Clean up any remaining events in the free list
|
22
|
+
BLEEvent *event;
|
23
|
+
while ((event = this->free_list_.pop()) != nullptr) {
|
24
|
+
delete event;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
// Allocate an event from the pool
|
29
|
+
// Returns nullptr if pool is full
|
30
|
+
BLEEvent *allocate() {
|
31
|
+
// Try to get from free list first
|
32
|
+
BLEEvent *event = this->free_list_.pop();
|
33
|
+
if (event != nullptr)
|
34
|
+
return event;
|
35
|
+
|
36
|
+
// Need to create a new event
|
37
|
+
if (this->total_created_ >= SIZE) {
|
38
|
+
// Pool is at capacity
|
39
|
+
return nullptr;
|
40
|
+
}
|
41
|
+
|
42
|
+
// Use internal RAM for better performance
|
43
|
+
RAMAllocator<BLEEvent> allocator(RAMAllocator<BLEEvent>::ALLOC_INTERNAL);
|
44
|
+
event = allocator.allocate(1);
|
45
|
+
|
46
|
+
if (event == nullptr) {
|
47
|
+
// Memory allocation failed
|
48
|
+
return nullptr;
|
49
|
+
}
|
50
|
+
|
51
|
+
// Placement new to construct the object
|
52
|
+
new (event) BLEEvent();
|
53
|
+
this->total_created_++;
|
54
|
+
return event;
|
55
|
+
}
|
56
|
+
|
57
|
+
// Return an event to the pool for reuse
|
58
|
+
void release(BLEEvent *event) {
|
59
|
+
if (event != nullptr) {
|
60
|
+
this->free_list_.push(event);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
private:
|
65
|
+
LockFreeQueue<BLEEvent, SIZE> free_list_; // Free events ready for reuse
|
66
|
+
uint8_t total_created_; // Total events created (high water mark)
|
67
|
+
};
|
68
|
+
|
69
|
+
} // namespace esp32_ble
|
70
|
+
} // namespace esphome
|
71
|
+
|
72
|
+
#endif
|
@@ -18,7 +18,7 @@
|
|
18
18
|
namespace esphome {
|
19
19
|
namespace esp32_ble {
|
20
20
|
|
21
|
-
template<class T,
|
21
|
+
template<class T, uint8_t SIZE> class LockFreeQueue {
|
22
22
|
public:
|
23
23
|
LockFreeQueue() : head_(0), tail_(0), dropped_count_(0) {}
|
24
24
|
|
@@ -26,8 +26,8 @@ template<class T, size_t SIZE> class LockFreeQueue {
|
|
26
26
|
if (element == nullptr)
|
27
27
|
return false;
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
uint8_t current_tail = tail_.load(std::memory_order_relaxed);
|
30
|
+
uint8_t next_tail = (current_tail + 1) % SIZE;
|
31
31
|
|
32
32
|
if (next_tail == head_.load(std::memory_order_acquire)) {
|
33
33
|
// Buffer full
|
@@ -41,7 +41,7 @@ template<class T, size_t SIZE> class LockFreeQueue {
|
|
41
41
|
}
|
42
42
|
|
43
43
|
T *pop() {
|
44
|
-
|
44
|
+
uint8_t current_head = head_.load(std::memory_order_relaxed);
|
45
45
|
|
46
46
|
if (current_head == tail_.load(std::memory_order_acquire)) {
|
47
47
|
return nullptr; // Empty
|
@@ -53,27 +53,30 @@ template<class T, size_t SIZE> class LockFreeQueue {
|
|
53
53
|
}
|
54
54
|
|
55
55
|
size_t size() const {
|
56
|
-
|
57
|
-
|
56
|
+
uint8_t tail = tail_.load(std::memory_order_acquire);
|
57
|
+
uint8_t head = head_.load(std::memory_order_acquire);
|
58
58
|
return (tail - head + SIZE) % SIZE;
|
59
59
|
}
|
60
60
|
|
61
|
-
|
61
|
+
uint16_t get_and_reset_dropped_count() { return dropped_count_.exchange(0, std::memory_order_relaxed); }
|
62
62
|
|
63
63
|
void increment_dropped_count() { dropped_count_.fetch_add(1, std::memory_order_relaxed); }
|
64
64
|
|
65
65
|
bool empty() const { return head_.load(std::memory_order_acquire) == tail_.load(std::memory_order_acquire); }
|
66
66
|
|
67
67
|
bool full() const {
|
68
|
-
|
68
|
+
uint8_t next_tail = (tail_.load(std::memory_order_relaxed) + 1) % SIZE;
|
69
69
|
return next_tail == head_.load(std::memory_order_acquire);
|
70
70
|
}
|
71
71
|
|
72
72
|
protected:
|
73
73
|
T *buffer_[SIZE];
|
74
|
-
|
75
|
-
std::atomic<
|
76
|
-
|
74
|
+
// Atomic: written by producer (push/increment), read+reset by consumer (get_and_reset)
|
75
|
+
std::atomic<uint16_t> dropped_count_; // 65535 max - more than enough for drop tracking
|
76
|
+
// Atomic: written by consumer (pop), read by producer (push) to check if full
|
77
|
+
std::atomic<uint8_t> head_;
|
78
|
+
// Atomic: written by producer (push), read by consumer (pop) to check if empty
|
79
|
+
std::atomic<uint8_t> tail_;
|
77
80
|
};
|
78
81
|
|
79
82
|
} // namespace esp32_ble
|
@@ -522,6 +522,7 @@ optional<ESPBLEiBeacon> ESPBLEiBeacon::from_manufacturer_data(const ServiceData
|
|
522
522
|
}
|
523
523
|
|
524
524
|
void ESPBTDevice::parse_scan_rst(const BLEScanResult &scan_result) {
|
525
|
+
this->scan_result_ = &scan_result;
|
525
526
|
for (uint8_t i = 0; i < ESP_BD_ADDR_LEN; i++)
|
526
527
|
this->address_[i] = scan_result.bda[i];
|
527
528
|
this->address_type_ = static_cast<esp_ble_addr_type_t>(scan_result.ble_addr_type);
|
@@ -85,6 +85,9 @@ class ESPBTDevice {
|
|
85
85
|
|
86
86
|
const std::vector<ServiceData> &get_service_datas() const { return service_datas_; }
|
87
87
|
|
88
|
+
// Exposed through a function for use in lambdas
|
89
|
+
const BLEScanResult &get_scan_result() const { return *scan_result_; }
|
90
|
+
|
88
91
|
bool resolve_irk(const uint8_t *irk) const;
|
89
92
|
|
90
93
|
optional<ESPBLEiBeacon> get_ibeacon() const {
|
@@ -111,6 +114,7 @@ class ESPBTDevice {
|
|
111
114
|
std::vector<ESPBTUUID> service_uuids_{};
|
112
115
|
std::vector<ServiceData> manufacturer_datas_{};
|
113
116
|
std::vector<ServiceData> service_datas_{};
|
117
|
+
const BLEScanResult *scan_result_{nullptr};
|
114
118
|
};
|
115
119
|
|
116
120
|
class ESP32BLETracker;
|
@@ -33,6 +33,7 @@ bool Nextion::send_command_(const std::string &command) {
|
|
33
33
|
|
34
34
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
35
35
|
if (!this->ignore_is_setup_ && !this->command_pacer_.can_send()) {
|
36
|
+
ESP_LOGN(TAG, "Command spacing: delaying command '%s'", command.c_str());
|
36
37
|
return false;
|
37
38
|
}
|
38
39
|
#endif // USE_NEXTION_COMMAND_SPACING
|
@@ -43,10 +44,6 @@ bool Nextion::send_command_(const std::string &command) {
|
|
43
44
|
const uint8_t to_send[3] = {0xFF, 0xFF, 0xFF};
|
44
45
|
this->write_array(to_send, sizeof(to_send));
|
45
46
|
|
46
|
-
#ifdef USE_NEXTION_COMMAND_SPACING
|
47
|
-
this->command_pacer_.mark_sent();
|
48
|
-
#endif // USE_NEXTION_COMMAND_SPACING
|
49
|
-
|
50
47
|
return true;
|
51
48
|
}
|
52
49
|
|
@@ -377,12 +374,6 @@ void Nextion::process_nextion_commands_() {
|
|
377
374
|
size_t commands_processed = 0;
|
378
375
|
#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP
|
379
376
|
|
380
|
-
#ifdef USE_NEXTION_COMMAND_SPACING
|
381
|
-
if (!this->command_pacer_.can_send()) {
|
382
|
-
return; // Will try again in next loop iteration
|
383
|
-
}
|
384
|
-
#endif
|
385
|
-
|
386
377
|
size_t to_process_length = 0;
|
387
378
|
std::string to_process;
|
388
379
|
|
@@ -430,6 +421,7 @@ void Nextion::process_nextion_commands_() {
|
|
430
421
|
}
|
431
422
|
#ifdef USE_NEXTION_COMMAND_SPACING
|
432
423
|
this->command_pacer_.mark_sent(); // Here is where we should mark the command as sent
|
424
|
+
ESP_LOGN(TAG, "Command spacing: marked command sent at %u ms", millis());
|
433
425
|
#endif
|
434
426
|
break;
|
435
427
|
case 0x02: // invalid Component ID or name was used
|
@@ -46,7 +46,7 @@ def set_sdkconfig_options(config):
|
|
46
46
|
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PANID", config[CONF_PAN_ID])
|
47
47
|
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_CHANNEL", config[CONF_CHANNEL])
|
48
48
|
add_idf_sdkconfig_option(
|
49
|
-
"CONFIG_OPENTHREAD_NETWORK_MASTERKEY", f"{config[CONF_NETWORK_KEY]:X}"
|
49
|
+
"CONFIG_OPENTHREAD_NETWORK_MASTERKEY", f"{config[CONF_NETWORK_KEY]:X}".lower()
|
50
50
|
)
|
51
51
|
|
52
52
|
if network_name := config.get(CONF_NETWORK_NAME):
|
@@ -54,14 +54,14 @@ def set_sdkconfig_options(config):
|
|
54
54
|
|
55
55
|
if (ext_pan_id := config.get(CONF_EXT_PAN_ID)) is not None:
|
56
56
|
add_idf_sdkconfig_option(
|
57
|
-
"CONFIG_OPENTHREAD_NETWORK_EXTPANID", f"{ext_pan_id:X}"
|
57
|
+
"CONFIG_OPENTHREAD_NETWORK_EXTPANID", f"{ext_pan_id:X}".lower()
|
58
58
|
)
|
59
59
|
if (mesh_local_prefix := config.get(CONF_MESH_LOCAL_PREFIX)) is not None:
|
60
60
|
add_idf_sdkconfig_option(
|
61
|
-
"CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX", f"{mesh_local_prefix
|
61
|
+
"CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX", f"{mesh_local_prefix}".lower()
|
62
62
|
)
|
63
63
|
if (pskc := config.get(CONF_PSKC)) is not None:
|
64
|
-
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PSKC", f"{pskc:X}")
|
64
|
+
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PSKC", f"{pskc:X}".lower())
|
65
65
|
|
66
66
|
if CONF_FORCE_DATASET in config:
|
67
67
|
if config[CONF_FORCE_DATASET]:
|
@@ -98,7 +98,7 @@ _CONNECTION_SCHEMA = cv.Schema(
|
|
98
98
|
cv.Optional(CONF_EXT_PAN_ID): cv.hex_int,
|
99
99
|
cv.Optional(CONF_NETWORK_NAME): cv.string_strict,
|
100
100
|
cv.Optional(CONF_PSKC): cv.hex_int,
|
101
|
-
cv.Optional(CONF_MESH_LOCAL_PREFIX): cv.
|
101
|
+
cv.Optional(CONF_MESH_LOCAL_PREFIX): cv.ipv6network,
|
102
102
|
}
|
103
103
|
)
|
104
104
|
|
@@ -137,7 +137,7 @@ void OpenThreadSrpComponent::setup() {
|
|
137
137
|
// Copy the mdns services to our local instance so that the c_str pointers remain valid for the lifetime of this
|
138
138
|
// component
|
139
139
|
this->mdns_services_ = this->mdns_->get_services();
|
140
|
-
|
140
|
+
ESP_LOGD(TAG, "Setting up SRP services. count = %d\n", this->mdns_services_.size());
|
141
141
|
for (const auto &service : this->mdns_services_) {
|
142
142
|
otSrpClientBuffersServiceEntry *entry = otSrpClientBuffersAllocateService(instance);
|
143
143
|
if (!entry) {
|
@@ -185,11 +185,11 @@ void OpenThreadSrpComponent::setup() {
|
|
185
185
|
if (error != OT_ERROR_NONE) {
|
186
186
|
ESP_LOGW(TAG, "Failed to add service: %s", otThreadErrorToString(error));
|
187
187
|
}
|
188
|
-
|
188
|
+
ESP_LOGD(TAG, "Added service: %s", full_service.c_str());
|
189
189
|
}
|
190
190
|
|
191
191
|
otSrpClientEnableAutoStartMode(instance, srp_start_callback, nullptr);
|
192
|
-
|
192
|
+
ESP_LOGD(TAG, "Finished SRP setup");
|
193
193
|
}
|
194
194
|
|
195
195
|
void *OpenThreadSrpComponent::pool_alloc_(size_t size) {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# Sourced from https://gist.github.com/agners/0338576e0003318b63ec1ea75adc90f9
|
2
2
|
import binascii
|
3
|
+
import ipaddress
|
3
4
|
|
4
5
|
from esphome.const import CONF_CHANNEL
|
5
6
|
|
@@ -37,6 +38,12 @@ def parse_tlv(tlv) -> dict:
|
|
37
38
|
if tag in TLV_TYPES:
|
38
39
|
if tag == 3:
|
39
40
|
output[TLV_TYPES[tag]] = val.decode("utf-8")
|
41
|
+
elif tag == 7:
|
42
|
+
mesh_local_prefix = binascii.hexlify(val).decode("utf-8")
|
43
|
+
mesh_local_prefix_str = f"{mesh_local_prefix}0000000000000000"
|
44
|
+
ipv6_bytes = bytes.fromhex(mesh_local_prefix_str)
|
45
|
+
ipv6_address = ipaddress.IPv6Address(ipv6_bytes)
|
46
|
+
output[TLV_TYPES[tag]] = f"{ipv6_address}/64"
|
40
47
|
else:
|
41
48
|
output[TLV_TYPES[tag]] = int.from_bytes(val)
|
42
49
|
return output
|
esphome/config_validation.py
CHANGED
@@ -3,7 +3,15 @@
|
|
3
3
|
from contextlib import contextmanager
|
4
4
|
from dataclasses import dataclass
|
5
5
|
from datetime import datetime
|
6
|
-
from ipaddress import
|
6
|
+
from ipaddress import (
|
7
|
+
AddressValueError,
|
8
|
+
IPv4Address,
|
9
|
+
IPv4Network,
|
10
|
+
IPv6Address,
|
11
|
+
IPv6Network,
|
12
|
+
ip_address,
|
13
|
+
ip_network,
|
14
|
+
)
|
7
15
|
import logging
|
8
16
|
import os
|
9
17
|
import re
|
@@ -1176,6 +1184,14 @@ def ipv4address(value):
|
|
1176
1184
|
return address
|
1177
1185
|
|
1178
1186
|
|
1187
|
+
def ipv6address(value):
|
1188
|
+
try:
|
1189
|
+
address = IPv6Address(value)
|
1190
|
+
except AddressValueError as exc:
|
1191
|
+
raise Invalid(f"{value} is not a valid IPv6 address") from exc
|
1192
|
+
return address
|
1193
|
+
|
1194
|
+
|
1179
1195
|
def ipv4address_multi_broadcast(value):
|
1180
1196
|
address = ipv4address(value)
|
1181
1197
|
if not (address.is_multicast or (address == IPv4Address("255.255.255.255"))):
|
@@ -1193,6 +1209,33 @@ def ipaddress(value):
|
|
1193
1209
|
return address
|
1194
1210
|
|
1195
1211
|
|
1212
|
+
def ipv4network(value):
|
1213
|
+
"""Validate that the value is a valid IPv4 network."""
|
1214
|
+
try:
|
1215
|
+
network = IPv4Network(value, strict=False)
|
1216
|
+
except ValueError as exc:
|
1217
|
+
raise Invalid(f"{value} is not a valid IPv4 network") from exc
|
1218
|
+
return network
|
1219
|
+
|
1220
|
+
|
1221
|
+
def ipv6network(value):
|
1222
|
+
"""Validate that the value is a valid IPv6 network."""
|
1223
|
+
try:
|
1224
|
+
network = IPv6Network(value, strict=False)
|
1225
|
+
except ValueError as exc:
|
1226
|
+
raise Invalid(f"{value} is not a valid IPv6 network") from exc
|
1227
|
+
return network
|
1228
|
+
|
1229
|
+
|
1230
|
+
def ipnetwork(value):
|
1231
|
+
"""Validate that the value is a valid IP network."""
|
1232
|
+
try:
|
1233
|
+
network = ip_network(value, strict=False)
|
1234
|
+
except ValueError as exc:
|
1235
|
+
raise Invalid(f"{value} is not a valid IP network") from exc
|
1236
|
+
return network
|
1237
|
+
|
1238
|
+
|
1196
1239
|
def _valid_topic(value):
|
1197
1240
|
"""Validate that this is a valid topic name/filter."""
|
1198
1241
|
if value is None: # Used to disable publishing and subscribing
|
esphome/const.py
CHANGED
esphome/yaml_util.py
CHANGED
@@ -5,7 +5,7 @@ import fnmatch
|
|
5
5
|
import functools
|
6
6
|
import inspect
|
7
7
|
from io import BytesIO, TextIOBase, TextIOWrapper
|
8
|
-
from ipaddress import _BaseAddress
|
8
|
+
from ipaddress import _BaseAddress, _BaseNetwork
|
9
9
|
import logging
|
10
10
|
import math
|
11
11
|
import os
|
@@ -621,6 +621,7 @@ ESPHomeDumper.add_multi_representer(str, ESPHomeDumper.represent_stringify)
|
|
621
621
|
ESPHomeDumper.add_multi_representer(int, ESPHomeDumper.represent_int)
|
622
622
|
ESPHomeDumper.add_multi_representer(float, ESPHomeDumper.represent_float)
|
623
623
|
ESPHomeDumper.add_multi_representer(_BaseAddress, ESPHomeDumper.represent_stringify)
|
624
|
+
ESPHomeDumper.add_multi_representer(_BaseNetwork, ESPHomeDumper.represent_stringify)
|
624
625
|
ESPHomeDumper.add_multi_representer(MACAddress, ESPHomeDumper.represent_stringify)
|
625
626
|
ESPHomeDumper.add_multi_representer(TimePeriod, ESPHomeDumper.represent_stringify)
|
626
627
|
ESPHomeDumper.add_multi_representer(Lambda, ESPHomeDumper.represent_lambda)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: esphome
|
3
|
-
Version: 2025.6.
|
3
|
+
Version: 2025.6.1
|
4
4
|
Summary: ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems.
|
5
5
|
Author-email: The ESPHome Authors <esphome@openhomefoundation.org>
|
6
6
|
License: MIT
|
@@ -4,8 +4,8 @@ esphome/automation.py,sha256=9xmW3AmWDd2oKB7zF-UITYIiSci8ys8qiylK-rcU7Rg,15689
|
|
4
4
|
esphome/codegen.py,sha256=GePHUM7xdXb_Pil59SHVsXg2F4VBPgkH-Fz2PDX8Z54,1873
|
5
5
|
esphome/config.py,sha256=GsKqzNb4OBxA92eltdGYtP7e9fgtk80QsquhnUesb50,39948
|
6
6
|
esphome/config_helpers.py,sha256=MKf_wzO35nn41FvigXE0iYKDslPgL2ruf8R-EPtTT2I,3256
|
7
|
-
esphome/config_validation.py,sha256=
|
8
|
-
esphome/const.py,sha256=
|
7
|
+
esphome/config_validation.py,sha256=Nt8rQegT0VRAcWumtI0rJ92kW0milKMv3b443ZUzcfY,63437
|
8
|
+
esphome/const.py,sha256=QgR3DaFz_YxZhrNTslTHOqnNYmKGGGhf1OEEUyyynR4,41815
|
9
9
|
esphome/coroutine.py,sha256=HNBqqhaTbpvsOI19bTXltxJCMVtoeqZPe4qTf4CKkAc,9309
|
10
10
|
esphome/cpp_generator.py,sha256=2MbyMVt9hg7cFD0X8885IiJfFNjdqkqjis3P-0oa5L0,31346
|
11
11
|
esphome/cpp_helpers.py,sha256=6C2vNbOIhZKi43xRVlk5hp9GfshfBn-rc5D_ZFUEYaE,4801
|
@@ -28,7 +28,7 @@ esphome/voluptuous_schema.py,sha256=tQUOLvVec6v4pxfWpa8CMgXqBqomuqUUYEJqCJOPhNs,
|
|
28
28
|
esphome/vscode.py,sha256=pKBx_9jmQlRJB1xiqjWq2-pFhXae8VNSFGYoqxRBMkw,4279
|
29
29
|
esphome/wizard.py,sha256=mru5jCpYTNrgaure7bP6fTkZ-1OfoUmqsowYuFBWRdU,15377
|
30
30
|
esphome/writer.py,sha256=qxT5CJOIXEJlqJy490layWc-47QLPFBWUpKOsy8FQvQ,11040
|
31
|
-
esphome/yaml_util.py,sha256=
|
31
|
+
esphome/yaml_util.py,sha256=k1zp-z1lpjIpRFbnzk6I3mwJouU2_9EtjNpgJdMA2eo,23239
|
32
32
|
esphome/zeroconf.py,sha256=dy3aWh1Lf4Sh5e7Izlq30FkdzAKWA6IGvZkXuxYrxFE,6511
|
33
33
|
esphome/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
34
|
esphome/components/a01nyub/__init__.py,sha256=d_xNluCS0T63CxdXJGuw7raK7G9vAEwXNJpnA9GthzA,34
|
@@ -187,8 +187,8 @@ esphome/components/api/api_connection.h,sha256=oZhcUrl6RByGhtLENp41-5b6CC0NXgbTu
|
|
187
187
|
esphome/components/api/api_frame_helper.cpp,sha256=KCHNw9HQ_Id3TirJytskB_1AO4tZz5NtZVZ9DCl3zPM,38965
|
188
188
|
esphome/components/api/api_frame_helper.h,sha256=gytvsuTbh4beQ2lGgGy-Crf-gQSCDU2z3plEa6EbgX8,9944
|
189
189
|
esphome/components/api/api_noise_context.h,sha256=y_3hWMKXtKxyCwZ8cKQjn3gQqenaAX5DhcCFQ6kBiPc,606
|
190
|
-
esphome/components/api/api_pb2.cpp,sha256=
|
191
|
-
esphome/components/api/api_pb2.h,sha256=
|
190
|
+
esphome/components/api/api_pb2.cpp,sha256=Es5qQLWZnKYurq9d9Gxp6eakh4Cne7cV2_lrE1j5sUM,319391
|
191
|
+
esphome/components/api/api_pb2.h,sha256=RIJPU96qJ7uT4enMyXJKnA931Scr73vrZKMlACJiiwg,106904
|
192
192
|
esphome/components/api/api_pb2_service.cpp,sha256=6K191Ols2tcmccr0leWTGgyJljPyfzOAJdF4Ep9TIrY,32073
|
193
193
|
esphome/components/api/api_pb2_service.h,sha256=CiUQWqbEIWSTN_Ku8RgA1UoVHUT2EWKjOUw9g28rYDc,16444
|
194
194
|
esphome/components/api/api_pb2_size.h,sha256=i9wFf675YrfJy9Em_vZLPJ9osRHRNkOb7DMd1LpK3YM,13430
|
@@ -839,15 +839,16 @@ esphome/components/esp32/post_build.py.script,sha256=ZBsPNunx2BH4ZiRyXnjTP7D7eN2
|
|
839
839
|
esphome/components/esp32/preferences.cpp,sha256=WpEG6PenHwrAIonuoV_chdDJriJXF5dcpIbuYfmaUCQ,6229
|
840
840
|
esphome/components/esp32/preferences.h,sha256=9HIy-BOgjOXJiEgOizZ_Qb8-l6K4eb3VSPW8Y8ffuWM,165
|
841
841
|
esphome/components/esp32_ble/__init__.py,sha256=aShI9hnF7NU0M8GrIYgOFqF4N2QL96Iuhzrh8SV1pus,9598
|
842
|
-
esphome/components/esp32_ble/ble.cpp,sha256=
|
843
|
-
esphome/components/esp32_ble/ble.h,sha256=
|
842
|
+
esphome/components/esp32_ble/ble.cpp,sha256=Trg51D750u2AsKTCpktiGMF26BHOQSvzxzKW-etuJBU,17932
|
843
|
+
esphome/components/esp32_ble/ble.h,sha256=eRr_nTLqWzkKn_Po4i4wuA_AQsiHduUu_8uBQjtRF80,5878
|
844
844
|
esphome/components/esp32_ble/ble_advertising.cpp,sha256=LFrrx7xMjXAf7pt7Q43XzlwwcE1YKKulE3Zbuqow6JU,6104
|
845
845
|
esphome/components/esp32_ble/ble_advertising.h,sha256=tbN2CN1CqlosOvnG0NlMHC_0JPMZ2ugTzIIOSmQl30s,1576
|
846
|
-
esphome/components/esp32_ble/ble_event.h,sha256=
|
846
|
+
esphome/components/esp32_ble/ble_event.h,sha256=3Zuq6mkPwBLg6AR4Q_7aebxLh7EWAlb4rLDmOL3DWIc,18301
|
847
|
+
esphome/components/esp32_ble/ble_event_pool.h,sha256=HWGuDfX34P-CgMtB5yzie2Y53dWtX-Cq-Scp0cXGMlo,1758
|
847
848
|
esphome/components/esp32_ble/ble_scan_result.h,sha256=3hpnLDvy9Fr7sMuophP_db4GcF76qWSZKOn_ZljYoME,546
|
848
849
|
esphome/components/esp32_ble/ble_uuid.cpp,sha256=2go_q78xgFlQRH_ZpM4tdsDJqyqe_3Ssn2PJFkpjlfI,6167
|
849
850
|
esphome/components/esp32_ble/ble_uuid.h,sha256=6OL7GrNP-pxIqANnLlsd4IWCRnVzRD3Zx20pD4uGymA,916
|
850
|
-
esphome/components/esp32_ble/queue.h,sha256=
|
851
|
+
esphome/components/esp32_ble/queue.h,sha256=11OyhJYHxuY5UTuJZawxWCoeHsGkig9uiZ3oVhN1j2M,2625
|
851
852
|
esphome/components/esp32_ble_beacon/__init__.py,sha256=ts8d3ZFLBH_QE6cW748AZUXaK_yCqg3rzlJcObTGkAQ,3190
|
852
853
|
esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp,sha256=Y1xsFMHU306rZ8ZU7Y0UmhU22gXYe_28o7jg1t5e3Ms,4202
|
853
854
|
esphome/components/esp32_ble_beacon/esp32_ble_beacon.h,sha256=tDM9fy5VLIrCp45bqgsqHAm6FTsn7ixoOZkuTugZqqw,1868
|
@@ -874,8 +875,8 @@ esphome/components/esp32_ble_server/ble_service.cpp,sha256=cLJpq-eEFNXV4tlkSHXQW
|
|
874
875
|
esphome/components/esp32_ble_server/ble_service.h,sha256=BvKpr2fsUlNnviH9gdokI7IcuTBu0C7bNFT0vvIuN1Y,2306
|
875
876
|
esphome/components/esp32_ble_tracker/__init__.py,sha256=cWHciy2tEUDNBC_bUqE-1hPSSGecbat3-8HUBitjOqQ,15170
|
876
877
|
esphome/components/esp32_ble_tracker/automation.h,sha256=0pDA6EX__f14sT0KJwcnqg7UOsueKjjegHPznQj9biw,3795
|
877
|
-
esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp,sha256
|
878
|
-
esphome/components/esp32_ble_tracker/esp32_ble_tracker.h,sha256=
|
878
|
+
esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp,sha256=VLZ9egEuses6lxLIQJQ43YDg2VYYlQVNYjgQSRrecxk,33205
|
879
|
+
esphome/components/esp32_ble_tracker/esp32_ble_tracker.h,sha256=bhbPLtxVvW0rwQWUXBzcby0SwyvER0KLmEucXawfuSQ,10849
|
879
880
|
esphome/components/esp32_camera/__init__.py,sha256=3M3EhzV9jPpWMiAHPaVWbYUW3D_uEM_6Je4Gd2EGhNg,12631
|
880
881
|
esphome/components/esp32_camera/esp32_camera.cpp,sha256=Q7QjA1DBd_dnQkB6xos7STKZPhSDM0C09m1YvO7E1U4,16685
|
881
882
|
esphome/components/esp32_camera/esp32_camera.h,sha256=bCDwl44XrornN6_KHe8htnrUJOoFlE-KMipggt3NWa8,7590
|
@@ -2015,7 +2016,7 @@ esphome/components/nextion/__init__.py,sha256=1f1kBHOUMvvwSjeIgY6cWSS_cAuRILmgs7
|
|
2015
2016
|
esphome/components/nextion/automation.h,sha256=baaMGf6qTWI2OILZvkIkiKiW_pM21YZqTNbeggVXeXw,4555
|
2016
2017
|
esphome/components/nextion/base_component.py,sha256=4O2S8GLPQerIbYlIYX7O3hEkHN7unn7u9pcRCkcBlIo,4290
|
2017
2018
|
esphome/components/nextion/display.py,sha256=GszSWhlTFnGYlw-fj8oH3vxtaTdpMHK1JEltSs1dCO8,7977
|
2018
|
-
esphome/components/nextion/nextion.cpp,sha256=
|
2019
|
+
esphome/components/nextion/nextion.cpp,sha256=814O1mFUe9SozcaVsIxzmxsSLsNKxCvV43JYMbGaW1g,42214
|
2019
2020
|
esphome/components/nextion/nextion.h,sha256=SQvZnSQx1gMH9b76sIOEh-IK5mjAxPffBrQNWi0uA5Y,51539
|
2020
2021
|
esphome/components/nextion/nextion_base.h,sha256=3v9nuHpvpFxMKutV4bzuu1OB_uj26PRDaDc5gTv_2rc,2416
|
2021
2022
|
esphome/components/nextion/nextion_commands.cpp,sha256=XjTHKSw7UHf0fujti5u_keUFGtYIAlrrTKNACSxnE60,17716
|
@@ -2120,12 +2121,12 @@ esphome/components/opentherm/sensor/__init__.py,sha256=uNb3f8CaWk7HE97GEKb_Jw61j
|
|
2120
2121
|
esphome/components/opentherm/switch/__init__.py,sha256=rgirLZntBuvFQ_7T0WEfhC6pPE6dXdIXV37-DZq3yIE,1136
|
2121
2122
|
esphome/components/opentherm/switch/switch.cpp,sha256=UurvOy-U1IEmNxWMCCpkPCueR-POh-FBI8fBjWWc64o,820
|
2122
2123
|
esphome/components/opentherm/switch/switch.h,sha256=JhJFaXrJi3orbavFDc4llzmmHwU0yN2v_VuwJx3r7FU,410
|
2123
|
-
esphome/components/openthread/__init__.py,sha256=
|
2124
|
+
esphome/components/openthread/__init__.py,sha256=lZ5TETobR61V1-jAEm0gEOnNCzRqci9Ni-4dKy-001w,5108
|
2124
2125
|
esphome/components/openthread/const.py,sha256=jJvW1yrA2naAIuhZ4aGH9WEFm8MNvsbTcUJqrJR8CfM,288
|
2125
|
-
esphome/components/openthread/openthread.cpp,sha256=
|
2126
|
+
esphome/components/openthread/openthread.cpp,sha256=SrMt0cNvPMpHk0eZDf9DPE8GGIuDpTfevjItX_87qGQ,7121
|
2126
2127
|
esphome/components/openthread/openthread.h,sha256=0FpY2swy0Dpvk51doFcX1IbKfKPO7CaFWFmS1hTeQD8,1855
|
2127
2128
|
esphome/components/openthread/openthread_esp.cpp,sha256=I8bbPhwJQDfnd8RqhpZJqezJXayZztv1ZnnlLIB_KqU,4714
|
2128
|
-
esphome/components/openthread/tlv.py,sha256=
|
2129
|
+
esphome/components/openthread/tlv.py,sha256=hYi_WM0Ja2Eo2gFR_8xIzcMY6En4g12JpolLBIb12LQ,1620
|
2129
2130
|
esphome/components/openthread_info/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2130
2131
|
esphome/components/openthread_info/openthread_info_text_sensor.cpp,sha256=M2kQAgRn2uRsjsJF96lEHtD39HTAhCp5bn2gLDARR34,1113
|
2131
2132
|
esphome/components/openthread_info/openthread_info_text_sensor.h,sha256=nLnWZBLkq3Dvnr1Rg8Lnj7bO3EhqSfYfRiQkYOQSmPg,6932
|
@@ -3595,9 +3596,9 @@ esphome/dashboard/util/itertools.py,sha256=8eLrWEWmICLtXNxkKdYPQV0c_N4GEz8m9Npnb
|
|
3595
3596
|
esphome/dashboard/util/password.py,sha256=cQz3b9B-ijTe7zS6BeCW0hc3pWv6JjC78jmnycYYAh8,321
|
3596
3597
|
esphome/dashboard/util/subprocess.py,sha256=T8EW6dbU4LPd2DG1dRrdh8li71tt6J1isn411poMhkk,1022
|
3597
3598
|
esphome/dashboard/util/text.py,sha256=ENDnfN4O0NdA3CKVJjQYabFbwbrsIhVKrAMQe53qYu4,534
|
3598
|
-
esphome-2025.6.
|
3599
|
-
esphome-2025.6.
|
3600
|
-
esphome-2025.6.
|
3601
|
-
esphome-2025.6.
|
3602
|
-
esphome-2025.6.
|
3603
|
-
esphome-2025.6.
|
3599
|
+
esphome-2025.6.1.dist-info/licenses/LICENSE,sha256=HzEjkBInJe44L4WvAOPfhPJJDNj6YbnqFyvGWRzArGM,36664
|
3600
|
+
esphome-2025.6.1.dist-info/METADATA,sha256=YHEkqz_qYmFQhk5PdKCeT3WQyl3ukyRrK4sFTarKYWg,3678
|
3601
|
+
esphome-2025.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
3602
|
+
esphome-2025.6.1.dist-info/entry_points.txt,sha256=mIxVNuWtbYzeEcaWCl-AQ-97aBOWbnYBAK8nbF6P4M0,50
|
3603
|
+
esphome-2025.6.1.dist-info/top_level.txt,sha256=0GSXEW3cnITpgG3qnsSMz0qoqJHAFyfw7Y8MVtEf1Yk,8
|
3604
|
+
esphome-2025.6.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|