esphome 2025.8.0b1__py3-none-any.whl → 2025.8.0b3__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.

Potentially problematic release.


This version of esphome might be problematic. Click here for more details.

esphome/__main__.py CHANGED
@@ -476,7 +476,7 @@ def show_logs(config: ConfigType, args: ArgsProtocol, devices: list[str]) -> int
476
476
  from esphome.components.api.client import run_logs
477
477
 
478
478
  return run_logs(config, addresses_to_use)
479
- if get_port_type(port) == "MQTT" and "mqtt" in config:
479
+ if get_port_type(port) in ("NETWORK", "MQTT") and "mqtt" in config:
480
480
  from esphome import mqtt
481
481
 
482
482
  return mqtt.show_logs(
@@ -133,7 +133,7 @@ void BluetoothConnection::loop() {
133
133
 
134
134
  // Check if we should disable the loop
135
135
  // - For V3_WITH_CACHE: Services are never sent, disable after INIT state
136
- // - For other connections: Disable only after service discovery is complete
136
+ // - For V3_WITHOUT_CACHE: Disable only after service discovery is complete
137
137
  // (send_service_ == DONE_SENDING_SERVICES, which is only set after services are sent)
138
138
  if (this->state_ != espbt::ClientState::INIT && (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
139
139
  this->send_service_ == DONE_SENDING_SERVICES)) {
@@ -160,10 +160,7 @@ void BluetoothConnection::send_service_for_discovery_() {
160
160
  if (this->send_service_ >= this->service_count_) {
161
161
  this->send_service_ = DONE_SENDING_SERVICES;
162
162
  this->proxy_->send_gatt_services_done(this->address_);
163
- if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
164
- this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
165
- this->release_services();
166
- }
163
+ this->release_services();
167
164
  return;
168
165
  }
169
166
 
@@ -824,8 +824,9 @@ async def to_code(config):
824
824
  cg.set_cpp_standard("gnu++20")
825
825
  cg.add_build_flag("-DUSE_ESP32")
826
826
  cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
827
- cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{config[CONF_VARIANT]}")
828
- cg.add_define("ESPHOME_VARIANT", VARIANT_FRIENDLY[config[CONF_VARIANT]])
827
+ variant = config[CONF_VARIANT]
828
+ cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{variant}")
829
+ cg.add_define("ESPHOME_VARIANT", VARIANT_FRIENDLY[variant])
829
830
  cg.add_define(ThreadModel.MULTI_ATOMICS)
830
831
 
831
832
  cg.add_platformio_option("lib_ldf_mode", "off")
@@ -859,6 +860,7 @@ async def to_code(config):
859
860
  cg.add_platformio_option(
860
861
  "platform_packages", ["espressif/toolchain-esp32ulp@2.35.0-20220830"]
861
862
  )
863
+ add_idf_sdkconfig_option(f"CONFIG_IDF_TARGET_{variant}", True)
862
864
  add_idf_sdkconfig_option(
863
865
  f"CONFIG_ESPTOOLPY_FLASHSIZE_{config[CONF_FLASH_SIZE]}", True
864
866
  )
@@ -294,6 +294,7 @@ async def to_code(config):
294
294
 
295
295
  if config[CONF_ADVERTISING]:
296
296
  cg.add_define("USE_ESP32_BLE_ADVERTISING")
297
+ cg.add_define("USE_ESP32_BLE_UUID")
297
298
 
298
299
 
299
300
  @automation.register_condition("ble.enabled", BLEEnabledCondition, cv.Schema({}))
@@ -306,7 +306,7 @@ void ESP32BLE::loop() {
306
306
  case BLEEvent::GATTS: {
307
307
  esp_gatts_cb_event_t event = ble_event->event_.gatts.gatts_event;
308
308
  esp_gatt_if_t gatts_if = ble_event->event_.gatts.gatts_if;
309
- esp_ble_gatts_cb_param_t *param = ble_event->event_.gatts.gatts_param;
309
+ esp_ble_gatts_cb_param_t *param = &ble_event->event_.gatts.gatts_param;
310
310
  ESP_LOGV(TAG, "gatts_event [esp_gatt_if: %d] - %d", gatts_if, event);
311
311
  for (auto *gatts_handler : this->gatts_event_handlers_) {
312
312
  gatts_handler->gatts_event_handler(event, gatts_if, param);
@@ -316,7 +316,7 @@ void ESP32BLE::loop() {
316
316
  case BLEEvent::GATTC: {
317
317
  esp_gattc_cb_event_t event = ble_event->event_.gattc.gattc_event;
318
318
  esp_gatt_if_t gattc_if = ble_event->event_.gattc.gattc_if;
319
- esp_ble_gattc_cb_param_t *param = ble_event->event_.gattc.gattc_param;
319
+ esp_ble_gattc_cb_param_t *param = &ble_event->event_.gattc.gattc_param;
320
320
  ESP_LOGV(TAG, "gattc_event [esp_gatt_if: %d] - %d", gattc_if, event);
321
321
  for (auto *gattc_handler : this->gattc_event_handlers_) {
322
322
  gattc_handler->gattc_event_handler(event, gattc_if, param);
@@ -3,8 +3,7 @@
3
3
  #ifdef USE_ESP32
4
4
 
5
5
  #include <cstddef> // for offsetof
6
- #include <vector>
7
-
6
+ #include <cstring> // for memcpy
8
7
  #include <esp_gap_ble_api.h>
9
8
  #include <esp_gattc_api.h>
10
9
  #include <esp_gatts_api.h>
@@ -62,10 +61,24 @@ static_assert(offsetof(esp_ble_gap_cb_param_t, read_rssi_cmpl.rssi) == sizeof(es
62
61
  static_assert(offsetof(esp_ble_gap_cb_param_t, read_rssi_cmpl.remote_addr) == sizeof(esp_bt_status_t) + sizeof(int8_t),
63
62
  "remote_addr must follow rssi in read_rssi_cmpl");
64
63
 
64
+ // Param struct sizes on ESP32
65
+ static constexpr size_t GATTC_PARAM_SIZE = 28;
66
+ static constexpr size_t GATTS_PARAM_SIZE = 32;
67
+
68
+ // Maximum size for inline storage of data
69
+ // GATTC: 80 - 28 (param) - 8 (other fields) = 44 bytes for data
70
+ // GATTS: 80 - 32 (param) - 8 (other fields) = 40 bytes for data
71
+ static constexpr size_t GATTC_INLINE_DATA_SIZE = 44;
72
+ static constexpr size_t GATTS_INLINE_DATA_SIZE = 40;
73
+
74
+ // Verify param struct sizes
75
+ static_assert(sizeof(esp_ble_gattc_cb_param_t) == GATTC_PARAM_SIZE, "GATTC param size unexpected");
76
+ static_assert(sizeof(esp_ble_gatts_cb_param_t) == GATTS_PARAM_SIZE, "GATTS param size unexpected");
77
+
65
78
  // Received GAP, GATTC and GATTS events are only queued, and get processed in the main loop().
66
79
  // This class stores each event with minimal memory usage.
67
- // GAP events (99% of traffic) don't have the vector overhead.
68
- // GATTC/GATTS events use heap allocation for their param and data.
80
+ // GAP events (99% of traffic) don't have the heap allocation overhead.
81
+ // GATTC/GATTS events use heap allocation for their param and inline storage for small data.
69
82
  //
70
83
  // Event flow:
71
84
  // 1. ESP-IDF BLE stack calls our static handlers in the BLE task context
@@ -112,21 +125,21 @@ class BLEEvent {
112
125
  this->init_gap_data_(e, p);
113
126
  }
114
127
 
115
- // Constructor for GATTC events - uses heap allocation
116
- // IMPORTANT: The heap allocation is REQUIRED and must not be removed as an optimization.
117
- // The param pointer from ESP-IDF is only valid during the callback execution.
118
- // Since BLE events are processed asynchronously in the main loop, we must create
119
- // our own copy to ensure the data remains valid until the event is processed.
128
+ // Constructor for GATTC events - param stored inline, data may use heap
129
+ // IMPORTANT: We MUST copy the param struct because the pointer from ESP-IDF
130
+ // is only valid during the callback execution. Since BLE events are processed
131
+ // asynchronously in the main loop, we store our own copy inline to ensure
132
+ // the data remains valid until the event is processed.
120
133
  BLEEvent(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
121
134
  this->type_ = GATTC;
122
135
  this->init_gattc_data_(e, i, p);
123
136
  }
124
137
 
125
- // Constructor for GATTS events - uses heap allocation
126
- // IMPORTANT: The heap allocation is REQUIRED and must not be removed as an optimization.
127
- // The param pointer from ESP-IDF is only valid during the callback execution.
128
- // Since BLE events are processed asynchronously in the main loop, we must create
129
- // our own copy to ensure the data remains valid until the event is processed.
138
+ // Constructor for GATTS events - param stored inline, data may use heap
139
+ // IMPORTANT: We MUST copy the param struct because the pointer from ESP-IDF
140
+ // is only valid during the callback execution. Since BLE events are processed
141
+ // asynchronously in the main loop, we store our own copy inline to ensure
142
+ // the data remains valid until the event is processed.
130
143
  BLEEvent(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
131
144
  this->type_ = GATTS;
132
145
  this->init_gatts_data_(e, i, p);
@@ -136,25 +149,32 @@ class BLEEvent {
136
149
  ~BLEEvent() { this->release(); }
137
150
 
138
151
  // Default constructor for pre-allocation in pool
139
- BLEEvent() : type_(GAP) {}
152
+ BLEEvent() : event_{}, type_(GAP) {}
140
153
 
141
154
  // Invoked on return to EventPool - clean up any heap-allocated data
142
155
  void release() {
143
- if (this->type_ == GAP) {
144
- return;
145
- }
146
- if (this->type_ == GATTC) {
147
- delete this->event_.gattc.gattc_param;
148
- delete this->event_.gattc.data;
149
- this->event_.gattc.gattc_param = nullptr;
150
- this->event_.gattc.data = nullptr;
151
- return;
152
- }
153
- if (this->type_ == GATTS) {
154
- delete this->event_.gatts.gatts_param;
155
- delete this->event_.gatts.data;
156
- this->event_.gatts.gatts_param = nullptr;
157
- this->event_.gatts.data = nullptr;
156
+ switch (this->type_) {
157
+ case GAP:
158
+ // GAP events don't have heap allocations
159
+ break;
160
+ case GATTC:
161
+ // Param is now stored inline, only delete heap data if it was heap-allocated
162
+ if (!this->event_.gattc.is_inline && this->event_.gattc.data.heap_data != nullptr) {
163
+ delete[] this->event_.gattc.data.heap_data;
164
+ }
165
+ // Clear critical fields to prevent issues if type changes
166
+ this->event_.gattc.is_inline = false;
167
+ this->event_.gattc.data.heap_data = nullptr;
168
+ break;
169
+ case GATTS:
170
+ // Param is now stored inline, only delete heap data if it was heap-allocated
171
+ if (!this->event_.gatts.is_inline && this->event_.gatts.data.heap_data != nullptr) {
172
+ delete[] this->event_.gatts.data.heap_data;
173
+ }
174
+ // Clear critical fields to prevent issues if type changes
175
+ this->event_.gatts.is_inline = false;
176
+ this->event_.gatts.data.heap_data = nullptr;
177
+ break;
158
178
  }
159
179
  }
160
180
 
@@ -206,20 +226,30 @@ class BLEEvent {
206
226
 
207
227
  // NOLINTNEXTLINE(readability-identifier-naming)
208
228
  struct gattc_event {
209
- esp_gattc_cb_event_t gattc_event;
210
- esp_gatt_if_t gattc_if;
211
- esp_ble_gattc_cb_param_t *gattc_param; // Heap-allocated
212
- std::vector<uint8_t> *data; // Heap-allocated
213
- } gattc; // 16 bytes (pointers only)
229
+ esp_ble_gattc_cb_param_t gattc_param; // Stored inline (28 bytes)
230
+ esp_gattc_cb_event_t gattc_event; // 4 bytes
231
+ union {
232
+ uint8_t *heap_data; // 4 bytes when heap-allocated
233
+ uint8_t inline_data[GATTC_INLINE_DATA_SIZE]; // 44 bytes when stored inline
234
+ } data; // 44 bytes total
235
+ uint16_t data_len; // 2 bytes
236
+ esp_gatt_if_t gattc_if; // 1 byte
237
+ bool is_inline; // 1 byte - true when data is stored inline
238
+ } gattc; // Total: 80 bytes
214
239
 
215
240
  // NOLINTNEXTLINE(readability-identifier-naming)
216
241
  struct gatts_event {
217
- esp_gatts_cb_event_t gatts_event;
218
- esp_gatt_if_t gatts_if;
219
- esp_ble_gatts_cb_param_t *gatts_param; // Heap-allocated
220
- std::vector<uint8_t> *data; // Heap-allocated
221
- } gatts; // 16 bytes (pointers only)
222
- } event_; // 80 bytes
242
+ esp_ble_gatts_cb_param_t gatts_param; // Stored inline (32 bytes)
243
+ esp_gatts_cb_event_t gatts_event; // 4 bytes
244
+ union {
245
+ uint8_t *heap_data; // 4 bytes when heap-allocated
246
+ uint8_t inline_data[GATTS_INLINE_DATA_SIZE]; // 40 bytes when stored inline
247
+ } data; // 40 bytes total
248
+ uint16_t data_len; // 2 bytes
249
+ esp_gatt_if_t gatts_if; // 1 byte
250
+ bool is_inline; // 1 byte - true when data is stored inline
251
+ } gatts; // Total: 80 bytes
252
+ } event_; // 80 bytes
223
253
 
224
254
  ble_event_t type_;
225
255
 
@@ -233,6 +263,29 @@ class BLEEvent {
233
263
  const esp_ble_sec_t &security() const { return event_.gap.security; }
234
264
 
235
265
  private:
266
+ // Helper to copy data with inline storage optimization
267
+ template<typename EventStruct, size_t InlineSize>
268
+ void copy_data_with_inline_storage_(EventStruct &event, const uint8_t *src_data, uint16_t len,
269
+ uint8_t **param_value_ptr) {
270
+ event.data_len = len;
271
+ if (len > 0) {
272
+ if (len <= InlineSize) {
273
+ event.is_inline = true;
274
+ memcpy(event.data.inline_data, src_data, len);
275
+ *param_value_ptr = event.data.inline_data;
276
+ } else {
277
+ event.is_inline = false;
278
+ event.data.heap_data = new uint8_t[len];
279
+ memcpy(event.data.heap_data, src_data, len);
280
+ *param_value_ptr = event.data.heap_data;
281
+ }
282
+ } else {
283
+ event.is_inline = false;
284
+ event.data.heap_data = nullptr;
285
+ *param_value_ptr = nullptr;
286
+ }
287
+ }
288
+
236
289
  // Initialize GAP event data
237
290
  void init_gap_data_(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) {
238
291
  this->event_.gap.gap_event = e;
@@ -317,35 +370,38 @@ class BLEEvent {
317
370
  this->event_.gattc.gattc_if = i;
318
371
 
319
372
  if (p == nullptr) {
320
- this->event_.gattc.gattc_param = nullptr;
321
- this->event_.gattc.data = nullptr;
373
+ // Zero out the param struct when null
374
+ memset(&this->event_.gattc.gattc_param, 0, sizeof(this->event_.gattc.gattc_param));
375
+ this->event_.gattc.is_inline = false;
376
+ this->event_.gattc.data.heap_data = nullptr;
377
+ this->event_.gattc.data_len = 0;
322
378
  return; // Invalid event, but we can't log in header file
323
379
  }
324
380
 
325
- // Heap-allocate param and data
326
- // Heap allocation is used because GATTC/GATTS events are rare (<1% of events)
327
- // while GAP events (99%) are stored inline to minimize memory usage
328
- // IMPORTANT: This heap allocation provides clear ownership semantics:
329
- // - The BLEEvent owns the allocated memory for its lifetime
330
- // - The data remains valid from the BLE callback context until processed in the main loop
331
- // - Without this copy, we'd have use-after-free bugs as ESP-IDF reuses the callback memory
332
- this->event_.gattc.gattc_param = new esp_ble_gattc_cb_param_t(*p);
381
+ // Copy param struct inline (no heap allocation!)
382
+ // GATTC/GATTS events are rare (<1% of events) but we can still store them inline
383
+ // along with small data payloads, eliminating all heap allocations for typical BLE operations
384
+ // CRITICAL: This copy is REQUIRED for memory safety - the ESP-IDF param pointer
385
+ // is only valid during the callback and will be reused/freed after we return
386
+ this->event_.gattc.gattc_param = *p;
333
387
 
334
388
  // Copy data for events that need it
335
389
  // The param struct contains pointers (e.g., notify.value) that point to temporary buffers.
336
390
  // We must copy this data to ensure it remains valid when the event is processed later.
337
391
  switch (e) {
338
392
  case ESP_GATTC_NOTIFY_EVT:
339
- this->event_.gattc.data = new std::vector<uint8_t>(p->notify.value, p->notify.value + p->notify.value_len);
340
- this->event_.gattc.gattc_param->notify.value = this->event_.gattc.data->data();
393
+ copy_data_with_inline_storage_<decltype(this->event_.gattc), GATTC_INLINE_DATA_SIZE>(
394
+ this->event_.gattc, p->notify.value, p->notify.value_len, &this->event_.gattc.gattc_param.notify.value);
341
395
  break;
342
396
  case ESP_GATTC_READ_CHAR_EVT:
343
397
  case ESP_GATTC_READ_DESCR_EVT:
344
- this->event_.gattc.data = new std::vector<uint8_t>(p->read.value, p->read.value + p->read.value_len);
345
- this->event_.gattc.gattc_param->read.value = this->event_.gattc.data->data();
398
+ copy_data_with_inline_storage_<decltype(this->event_.gattc), GATTC_INLINE_DATA_SIZE>(
399
+ this->event_.gattc, p->read.value, p->read.value_len, &this->event_.gattc.gattc_param.read.value);
346
400
  break;
347
401
  default:
348
- this->event_.gattc.data = nullptr;
402
+ this->event_.gattc.is_inline = false;
403
+ this->event_.gattc.data.heap_data = nullptr;
404
+ this->event_.gattc.data_len = 0;
349
405
  break;
350
406
  }
351
407
  }
@@ -356,30 +412,33 @@ class BLEEvent {
356
412
  this->event_.gatts.gatts_if = i;
357
413
 
358
414
  if (p == nullptr) {
359
- this->event_.gatts.gatts_param = nullptr;
360
- this->event_.gatts.data = nullptr;
415
+ // Zero out the param struct when null
416
+ memset(&this->event_.gatts.gatts_param, 0, sizeof(this->event_.gatts.gatts_param));
417
+ this->event_.gatts.is_inline = false;
418
+ this->event_.gatts.data.heap_data = nullptr;
419
+ this->event_.gatts.data_len = 0;
361
420
  return; // Invalid event, but we can't log in header file
362
421
  }
363
422
 
364
- // Heap-allocate param and data
365
- // Heap allocation is used because GATTC/GATTS events are rare (<1% of events)
366
- // while GAP events (99%) are stored inline to minimize memory usage
367
- // IMPORTANT: This heap allocation provides clear ownership semantics:
368
- // - The BLEEvent owns the allocated memory for its lifetime
369
- // - The data remains valid from the BLE callback context until processed in the main loop
370
- // - Without this copy, we'd have use-after-free bugs as ESP-IDF reuses the callback memory
371
- this->event_.gatts.gatts_param = new esp_ble_gatts_cb_param_t(*p);
423
+ // Copy param struct inline (no heap allocation!)
424
+ // GATTC/GATTS events are rare (<1% of events) but we can still store them inline
425
+ // along with small data payloads, eliminating all heap allocations for typical BLE operations
426
+ // CRITICAL: This copy is REQUIRED for memory safety - the ESP-IDF param pointer
427
+ // is only valid during the callback and will be reused/freed after we return
428
+ this->event_.gatts.gatts_param = *p;
372
429
 
373
430
  // Copy data for events that need it
374
431
  // The param struct contains pointers (e.g., write.value) that point to temporary buffers.
375
432
  // We must copy this data to ensure it remains valid when the event is processed later.
376
433
  switch (e) {
377
434
  case ESP_GATTS_WRITE_EVT:
378
- this->event_.gatts.data = new std::vector<uint8_t>(p->write.value, p->write.value + p->write.len);
379
- this->event_.gatts.gatts_param->write.value = this->event_.gatts.data->data();
435
+ copy_data_with_inline_storage_<decltype(this->event_.gatts), GATTS_INLINE_DATA_SIZE>(
436
+ this->event_.gatts, p->write.value, p->write.len, &this->event_.gatts.gatts_param.write.value);
380
437
  break;
381
438
  default:
382
- this->event_.gatts.data = nullptr;
439
+ this->event_.gatts.is_inline = false;
440
+ this->event_.gatts.data.heap_data = nullptr;
441
+ this->event_.gatts.data_len = 0;
383
442
  break;
384
443
  }
385
444
  }
@@ -389,6 +448,15 @@ class BLEEvent {
389
448
  // The gap member in the union should be 80 bytes (including the gap_event enum)
390
449
  static_assert(sizeof(decltype(((BLEEvent *) nullptr)->event_.gap)) <= 80, "gap_event struct has grown beyond 80 bytes");
391
450
 
451
+ // Verify GATTC and GATTS structs don't exceed GAP struct size
452
+ // This ensures the union size is determined by GAP (the most common event type)
453
+ static_assert(sizeof(decltype(((BLEEvent *) nullptr)->event_.gattc)) <=
454
+ sizeof(decltype(((BLEEvent *) nullptr)->event_.gap)),
455
+ "gattc_event struct exceeds gap_event size - union size would increase");
456
+ static_assert(sizeof(decltype(((BLEEvent *) nullptr)->event_.gatts)) <=
457
+ sizeof(decltype(((BLEEvent *) nullptr)->event_.gap)),
458
+ "gatts_event struct exceeds gap_event size - union size would increase");
459
+
392
460
  // Verify esp_ble_sec_t fits within our union
393
461
  static_assert(sizeof(esp_ble_sec_t) <= 73, "esp_ble_sec_t is larger than BLEScanResult");
394
462
 
@@ -208,11 +208,11 @@ void ESPNowComponent::enable_() {
208
208
  esp_wifi_connectionless_module_set_wake_interval(CONFIG_ESPNOW_WAKE_INTERVAL);
209
209
  #endif
210
210
 
211
+ this->state_ = ESPNOW_STATE_ENABLED;
212
+
211
213
  for (auto peer : this->peers_) {
212
214
  this->add_peer(peer.address);
213
215
  }
214
-
215
- this->state_ = ESPNOW_STATE_ENABLED;
216
216
  }
217
217
 
218
218
  void ESPNowComponent::disable() {
@@ -407,7 +407,7 @@ esp_err_t ESPNowComponent::add_peer(const uint8_t *peer) {
407
407
  }
408
408
 
409
409
  if (memcmp(peer, this->own_address_, ESP_NOW_ETH_ALEN) == 0) {
410
- this->mark_failed();
410
+ this->status_momentary_warning("peer-add-failed");
411
411
  return ESP_ERR_INVALID_MAC;
412
412
  }
413
413
 
@@ -764,7 +764,8 @@ void Nextion::process_nextion_commands_() {
764
764
  variable_name = to_process.substr(0, index);
765
765
  ++index;
766
766
 
767
- text_value = to_process.substr(index);
767
+ // Get variable value without terminating NUL byte. Length check above ensures substr len >= 0.
768
+ text_value = to_process.substr(index, to_process_length - index - 1);
768
769
 
769
770
  ESP_LOGN(TAG, "Text sensor: %s='%s'", variable_name.c_str(), text_value.c_str());
770
771
 
@@ -16,6 +16,7 @@ from esphome.components.esp32.const import (
16
16
  import esphome.config_validation as cv
17
17
  from esphome.const import (
18
18
  CONF_ADVANCED,
19
+ CONF_DISABLED,
19
20
  CONF_FRAMEWORK,
20
21
  CONF_ID,
21
22
  CONF_MODE,
@@ -102,6 +103,7 @@ def get_config_schema(config):
102
103
  cv.Optional(CONF_MODE, default=modes[0]): cv.one_of(*modes, lower=True),
103
104
  cv.Optional(CONF_ENABLE_ECC, default=False): cv.boolean,
104
105
  cv.Optional(CONF_SPEED, default=speeds[0]): cv.one_of(*speeds, upper=True),
106
+ cv.Optional(CONF_DISABLED, default=False): cv.boolean,
105
107
  }
106
108
  )(config)
107
109
 
@@ -112,6 +114,8 @@ FINAL_VALIDATE_SCHEMA = validate_psram_mode
112
114
 
113
115
 
114
116
  async def to_code(config):
117
+ if config[CONF_DISABLED]:
118
+ return
115
119
  if CORE.using_arduino:
116
120
  cg.add_build_flag("-DBOARD_HAS_PSRAM")
117
121
  if config[CONF_MODE] == TYPE_OCTAL:
@@ -53,10 +53,14 @@ void SenseAirComponent::update() {
53
53
 
54
54
  this->status_clear_warning();
55
55
  const uint8_t length = response[2];
56
- const uint16_t status = (uint16_t(response[3]) << 8) | response[4];
57
- const int16_t ppm = int16_t((response[length + 1] << 8) | response[length + 2]);
56
+ const uint16_t status = encode_uint16(response[3], response[4]);
57
+ const uint16_t ppm = encode_uint16(response[length + 1], response[length + 2]);
58
58
 
59
- ESP_LOGD(TAG, "SenseAir Received CO₂=%dppm Status=0x%02X", ppm, status);
59
+ ESP_LOGD(TAG, "SenseAir Received CO₂=%uppm Status=0x%02X", ppm, status);
60
+ if (ppm == 0 && (status & SenseAirStatus::OUT_OF_RANGE_ERROR) != 0) {
61
+ ESP_LOGD(TAG, "Discarding 0 ppm reading with out-of-range status.");
62
+ return;
63
+ }
60
64
  if (this->co2_sensor_ != nullptr)
61
65
  this->co2_sensor_->publish_state(ppm);
62
66
  }
@@ -8,6 +8,17 @@
8
8
  namespace esphome {
9
9
  namespace senseair {
10
10
 
11
+ enum SenseAirStatus : uint8_t {
12
+ FATAL_ERROR = 1 << 0,
13
+ OFFSET_ERROR = 1 << 1,
14
+ ALGORITHM_ERROR = 1 << 2,
15
+ OUTPUT_ERROR = 1 << 3,
16
+ SELF_DIAGNOSTIC_ERROR = 1 << 4,
17
+ OUT_OF_RANGE_ERROR = 1 << 5,
18
+ MEMORY_ERROR = 1 << 6,
19
+ RESERVED = 1 << 7
20
+ };
21
+
11
22
  class SenseAirComponent : public PollingComponent, public uart::UARTDevice {
12
23
  public:
13
24
  void set_co2_sensor(sensor::Sensor *co2_sensor) { co2_sensor_ = co2_sensor; }
@@ -813,7 +813,7 @@ std::string WebServer::cover_state_json_generator(WebServer *web_server, void *s
813
813
  return web_server->cover_json((cover::Cover *) (source), DETAIL_STATE);
814
814
  }
815
815
  std::string WebServer::cover_all_json_generator(WebServer *web_server, void *source) {
816
- return web_server->cover_json((cover::Cover *) (source), DETAIL_STATE);
816
+ return web_server->cover_json((cover::Cover *) (source), DETAIL_ALL);
817
817
  }
818
818
  std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) {
819
819
  return json::build_json([this, obj, start_config](JsonObject root) {
@@ -375,11 +375,16 @@ async def to_code(config):
375
375
  var = cg.new_Pvariable(config[CONF_ID])
376
376
  cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))
377
377
 
378
+ # Track if any network uses Enterprise authentication
379
+ has_eap = False
380
+
378
381
  def add_sta(ap, network):
379
382
  ip_config = network.get(CONF_MANUAL_IP, config.get(CONF_MANUAL_IP))
380
383
  cg.add(var.add_sta(wifi_network(network, ap, ip_config)))
381
384
 
382
385
  for network in config.get(CONF_NETWORKS, []):
386
+ if CONF_EAP in network:
387
+ has_eap = True
383
388
  cg.with_local_variable(network[CONF_ID], WiFiAP(), add_sta, network)
384
389
 
385
390
  if CONF_AP in config:
@@ -396,6 +401,10 @@ async def to_code(config):
396
401
  add_idf_sdkconfig_option("CONFIG_ESP_WIFI_SOFTAP_SUPPORT", False)
397
402
  add_idf_sdkconfig_option("CONFIG_LWIP_DHCPS", False)
398
403
 
404
+ # Disable Enterprise WiFi support if no EAP is configured
405
+ if CORE.is_esp32 and CORE.using_esp_idf and not has_eap:
406
+ add_idf_sdkconfig_option("CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT", False)
407
+
399
408
  cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
400
409
  cg.add(var.set_power_save_mode(config[CONF_POWER_SAVE_MODE]))
401
410
  cg.add(var.set_fast_connect(config[CONF_FAST_CONNECT]))
@@ -393,10 +393,13 @@ def icon(value):
393
393
  )
394
394
 
395
395
 
396
- def sub_device_id(value: str | None) -> core.ID:
396
+ def sub_device_id(value: str | None) -> core.ID | None:
397
397
  # Lazy import to avoid circular imports
398
398
  from esphome.core.config import Device
399
399
 
400
+ if not value:
401
+ return None
402
+
400
403
  return use_id(Device)(value)
401
404
 
402
405
 
esphome/const.py CHANGED
@@ -4,7 +4,7 @@ from enum import Enum
4
4
 
5
5
  from esphome.enum import StrEnum
6
6
 
7
- __version__ = "2025.8.0b1"
7
+ __version__ = "2025.8.0b3"
8
8
 
9
9
  ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
10
10
  VALID_SUBSTITUTIONS_CHARACTERS = (
esphome/core/__init__.py CHANGED
@@ -803,6 +803,10 @@ class EsphomeCore:
803
803
  raise TypeError(
804
804
  f"Library {library} must be instance of Library, not {type(library)}"
805
805
  )
806
+
807
+ if not library.name:
808
+ raise ValueError(f"The library for {library.repository} must have a name")
809
+
806
810
  short_name = (
807
811
  library.name if "/" not in library.name else library.name.split("/")[-1]
808
812
  )
@@ -77,8 +77,8 @@ async def setup_entity(var: MockObj, config: ConfigType, platform: str) -> None:
77
77
  """
78
78
  # Get device info
79
79
  device_name: str | None = None
80
- if CONF_DEVICE_ID in config:
81
- device_id_obj: ID = config[CONF_DEVICE_ID]
80
+ device_id_obj: ID | None
81
+ if device_id_obj := config.get(CONF_DEVICE_ID):
82
82
  device: MockObj = await get_variable(device_id_obj)
83
83
  add(var.set_device(device))
84
84
  # Get device name for object ID calculation
@@ -199,8 +199,8 @@ def entity_duplicate_validator(platform: str) -> Callable[[ConfigType], ConfigTy
199
199
  # Get device name if entity is on a sub-device
200
200
  device_name = None
201
201
  device_id = "" # Empty string for main device
202
- if CONF_DEVICE_ID in config:
203
- device_id_obj = config[CONF_DEVICE_ID]
202
+ device_id_obj: ID | None
203
+ if device_id_obj := config.get(CONF_DEVICE_ID):
204
204
  device_name = device_id_obj.id
205
205
  # Use the device ID string directly for uniqueness
206
206
  device_id = device_id_obj.id
@@ -82,7 +82,13 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
82
82
  item->set_name(name_cstr, !is_static_string);
83
83
  item->type = type;
84
84
  item->callback = std::move(func);
85
+ // Initialize remove to false (though it should already be from constructor)
86
+ // Not using mark_item_removed_ helper since we're setting to false, not true
87
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
88
+ item->remove.store(false, std::memory_order_relaxed);
89
+ #else
85
90
  item->remove = false;
91
+ #endif
86
92
  item->is_retry = is_retry;
87
93
 
88
94
  #ifndef ESPHOME_THREAD_SINGLE
@@ -398,6 +404,31 @@ void HOT Scheduler::call(uint32_t now) {
398
404
  this->pop_raw_();
399
405
  continue;
400
406
  }
407
+
408
+ // Check if item is marked for removal
409
+ // This handles two cases:
410
+ // 1. Item was marked for removal after cleanup_() but before we got here
411
+ // 2. Item is marked for removal but wasn't at the front of the heap during cleanup_()
412
+ #ifdef ESPHOME_THREAD_MULTI_NO_ATOMICS
413
+ // Multi-threaded platforms without atomics: must take lock to safely read remove flag
414
+ {
415
+ LockGuard guard{this->lock_};
416
+ if (is_item_removed_(item.get())) {
417
+ this->pop_raw_();
418
+ this->to_remove_--;
419
+ continue;
420
+ }
421
+ }
422
+ #else
423
+ // Single-threaded or multi-threaded with atomics: can check without lock
424
+ if (is_item_removed_(item.get())) {
425
+ LockGuard guard{this->lock_};
426
+ this->pop_raw_();
427
+ this->to_remove_--;
428
+ continue;
429
+ }
430
+ #endif
431
+
401
432
  #ifdef ESPHOME_DEBUG_SCHEDULER
402
433
  const char *item_name = item->get_name();
403
434
  ESP_LOGV(TAG, "Running %s '%s/%s' with interval=%" PRIu32 " next_execution=%" PRIu64 " (now=%" PRIu64 ")",
@@ -518,7 +549,7 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_c
518
549
  if (type == SchedulerItem::TIMEOUT) {
519
550
  for (auto &item : this->defer_queue_) {
520
551
  if (this->matches_item_(item, component, name_cstr, type, match_retry)) {
521
- item->remove = true;
552
+ this->mark_item_removed_(item.get());
522
553
  total_cancelled++;
523
554
  }
524
555
  }
@@ -528,7 +559,7 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_c
528
559
  // Cancel items in the main heap
529
560
  for (auto &item : this->items_) {
530
561
  if (this->matches_item_(item, component, name_cstr, type, match_retry)) {
531
- item->remove = true;
562
+ this->mark_item_removed_(item.get());
532
563
  total_cancelled++;
533
564
  this->to_remove_++; // Track removals for heap items
534
565
  }
@@ -537,7 +568,7 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_c
537
568
  // Cancel items in to_add_
538
569
  for (auto &item : this->to_add_) {
539
570
  if (this->matches_item_(item, component, name_cstr, type, match_retry)) {
540
- item->remove = true;
571
+ this->mark_item_removed_(item.get());
541
572
  total_cancelled++;
542
573
  // Don't track removals for to_add_ items
543
574
  }
esphome/core/scheduler.h CHANGED
@@ -97,22 +97,42 @@ class Scheduler {
97
97
 
98
98
  std::function<void()> callback;
99
99
 
100
- // Bit-packed fields to minimize padding
100
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
101
+ // Multi-threaded with atomics: use atomic for lock-free access
102
+ // Place atomic<bool> separately since it can't be packed with bit fields
103
+ std::atomic<bool> remove{false};
104
+
105
+ // Bit-packed fields (3 bits used, 5 bits padding in 1 byte)
106
+ enum Type : uint8_t { TIMEOUT, INTERVAL } type : 1;
107
+ bool name_is_dynamic : 1; // True if name was dynamically allocated (needs delete[])
108
+ bool is_retry : 1; // True if this is a retry timeout
109
+ // 5 bits padding
110
+ #else
111
+ // Single-threaded or multi-threaded without atomics: can pack all fields together
112
+ // Bit-packed fields (4 bits used, 4 bits padding in 1 byte)
101
113
  enum Type : uint8_t { TIMEOUT, INTERVAL } type : 1;
102
114
  bool remove : 1;
103
115
  bool name_is_dynamic : 1; // True if name was dynamically allocated (needs delete[])
104
116
  bool is_retry : 1; // True if this is a retry timeout
105
- // 4 bits padding
117
+ // 4 bits padding
118
+ #endif
106
119
 
107
120
  // Constructor
108
121
  SchedulerItem()
109
122
  : component(nullptr),
110
123
  interval(0),
111
124
  next_execution_(0),
125
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
126
+ // remove is initialized in the member declaration as std::atomic<bool>{false}
127
+ type(TIMEOUT),
128
+ name_is_dynamic(false),
129
+ is_retry(false) {
130
+ #else
112
131
  type(TIMEOUT),
113
132
  remove(false),
114
133
  name_is_dynamic(false),
115
134
  is_retry(false) {
135
+ #endif
116
136
  name_.static_name = nullptr;
117
137
  }
118
138
 
@@ -219,6 +239,37 @@ class Scheduler {
219
239
  return item->remove || (item->component != nullptr && item->component->is_failed());
220
240
  }
221
241
 
242
+ // Helper to check if item is marked for removal (platform-specific)
243
+ // Returns true if item should be skipped, handles platform-specific synchronization
244
+ // For ESPHOME_THREAD_MULTI_NO_ATOMICS platforms, the caller must hold the scheduler lock before calling this
245
+ // function.
246
+ bool is_item_removed_(SchedulerItem *item) const {
247
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
248
+ // Multi-threaded with atomics: use atomic load for lock-free access
249
+ return item->remove.load(std::memory_order_acquire);
250
+ #else
251
+ // Single-threaded (ESPHOME_THREAD_SINGLE) or
252
+ // multi-threaded without atomics (ESPHOME_THREAD_MULTI_NO_ATOMICS): direct read
253
+ // For ESPHOME_THREAD_MULTI_NO_ATOMICS, caller MUST hold lock!
254
+ return item->remove;
255
+ #endif
256
+ }
257
+
258
+ // Helper to mark item for removal (platform-specific)
259
+ // For ESPHOME_THREAD_MULTI_NO_ATOMICS platforms, the caller must hold the scheduler lock before calling this
260
+ // function.
261
+ void mark_item_removed_(SchedulerItem *item) {
262
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
263
+ // Multi-threaded with atomics: use atomic store
264
+ item->remove.store(true, std::memory_order_release);
265
+ #else
266
+ // Single-threaded (ESPHOME_THREAD_SINGLE) or
267
+ // multi-threaded without atomics (ESPHOME_THREAD_MULTI_NO_ATOMICS): direct write
268
+ // For ESPHOME_THREAD_MULTI_NO_ATOMICS, caller MUST hold lock!
269
+ item->remove = true;
270
+ #endif
271
+ }
272
+
222
273
  // Template helper to check if any item in a container matches our criteria
223
274
  template<typename Container>
224
275
  bool has_cancelled_timeout_in_container_(const Container &container, Component *component, const char *name_cstr,
esphome/writer.py CHANGED
@@ -80,13 +80,16 @@ def replace_file_content(text, pattern, repl):
80
80
  return content_new, count
81
81
 
82
82
 
83
- def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool:
83
+ def storage_should_clean(old: StorageJSON | None, new: StorageJSON) -> bool:
84
84
  if old is None:
85
85
  return True
86
86
 
87
87
  if old.src_version != new.src_version:
88
88
  return True
89
- return old.build_path != new.build_path
89
+ if old.build_path != new.build_path:
90
+ return True
91
+ # Check if any components have been removed
92
+ return bool(old.loaded_integrations - new.loaded_integrations)
90
93
 
91
94
 
92
95
  def storage_should_update_cmake_cache(old: StorageJSON, new: StorageJSON) -> bool:
@@ -100,7 +103,7 @@ def storage_should_update_cmake_cache(old: StorageJSON, new: StorageJSON) -> boo
100
103
  return False
101
104
 
102
105
 
103
- def update_storage_json():
106
+ def update_storage_json() -> None:
104
107
  path = storage_path()
105
108
  old = StorageJSON.load(path)
106
109
  new = StorageJSON.from_esphome_core(CORE, old)
@@ -108,7 +111,14 @@ def update_storage_json():
108
111
  return
109
112
 
110
113
  if storage_should_clean(old, new):
111
- _LOGGER.info("Core config, version changed, cleaning build files...")
114
+ if old is not None and old.loaded_integrations - new.loaded_integrations:
115
+ removed = old.loaded_integrations - new.loaded_integrations
116
+ _LOGGER.info(
117
+ "Components removed (%s), cleaning build files...",
118
+ ", ".join(sorted(removed)),
119
+ )
120
+ else:
121
+ _LOGGER.info("Core config or version changed, cleaning build files...")
112
122
  clean_build()
113
123
  elif storage_should_update_cmake_cache(old, new):
114
124
  _LOGGER.info("Integrations changed, cleaning cmake cache...")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: esphome
3
- Version: 2025.8.0b1
3
+ Version: 2025.8.0b3
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
@@ -36,8 +36,8 @@ Requires-Dist: pyserial==3.5
36
36
  Requires-Dist: platformio==6.1.18
37
37
  Requires-Dist: esptool==5.0.2
38
38
  Requires-Dist: click==8.1.7
39
- Requires-Dist: esphome-dashboard==20250514.0
40
- Requires-Dist: aioesphomeapi==38.2.1
39
+ Requires-Dist: esphome-dashboard==20250814.0
40
+ Requires-Dist: aioesphomeapi==39.0.0
41
41
  Requires-Dist: zeroconf==0.147.0
42
42
  Requires-Dist: puremagic==1.30
43
43
  Requires-Dist: ruamel.yaml==0.18.14
@@ -1,11 +1,11 @@
1
1
  esphome/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- esphome/__main__.py,sha256=m-wU3QjBMaJ1Y7wqDcuMbvWQPjDa558Z5OWn6vzisoo,37200
2
+ esphome/__main__.py,sha256=Roc55A-6CX8SLiNURtPs73_ACfZ8uVZRWtV6r3zPu7U,37213
3
3
  esphome/automation.py,sha256=gK_oTzOSb3X-0O82bZNYk4XjAzSecpSdvHQGcY79Rcc,15661
4
4
  esphome/codegen.py,sha256=H_WB4rj0uEowvlhEb31EjJQwutLQ5CQkJIsNgDK-wx8,1917
5
5
  esphome/config.py,sha256=74-Y3XKtlB9h__fsu-Zvj6PanDWufVGo1-W4jlG-8cg,43172
6
6
  esphome/config_helpers.py,sha256=E0UO0khX9JW-br_NSsDlLH3VuE-YwMQ99_pzEQVupDc,5391
7
- esphome/config_validation.py,sha256=ylrgF9ZwGBAyb4gGX2FTZ2ut_PyvP2XTh1RpHdYD8sM,64794
8
- esphome/const.py,sha256=PpKS8OB3x8Mvk9O65BLOXFSqmBTHichskvdKChwiuT8,44162
7
+ esphome/config_validation.py,sha256=iYkDothyN3eT011IndUD-kEMke9ymZXKSsEjQjnwjSo,64840
8
+ esphome/const.py,sha256=aZXZI3c0Gmsb-JkZx3bBJEso3cziE7nAK2Wa-zEdMaw,44162
9
9
  esphome/coroutine.py,sha256=HNBqqhaTbpvsOI19bTXltxJCMVtoeqZPe4qTf4CKkAc,9309
10
10
  esphome/cpp_generator.py,sha256=j5FQMC8wzHDwXnZ9uii5t6wXA7ZwjwHI2SUWghTsCuE,31869
11
11
  esphome/cpp_helpers.py,sha256=xDR-Gz5ZTmW-Qp7coa0AF77_ac6fDJEBV7gpGBlZGRw,4003
@@ -28,7 +28,7 @@ esphome/util.py,sha256=5YSJgdrS5hjiiH2YXOquh5rBRitrSj3W7_xvyoNRPfg,11093
28
28
  esphome/voluptuous_schema.py,sha256=EKm4CIP5-e6wY6L1_RleMGCDYbFOWTK_Sa_oO94Advc,9529
29
29
  esphome/vscode.py,sha256=Zg6ToHy7holnMswcSUGm6-89mRsf88owU2kr864eTP0,4241
30
30
  esphome/wizard.py,sha256=KZX8_WHEYCVDzkbUUaGz0E76Owix5XIBbqq6zBuJOfA,15830
31
- esphome/writer.py,sha256=1bmDRAX7RFi8mvCj1XP4dtvi8ySG5p4ZZiQTtxVAEXg,9686
31
+ esphome/writer.py,sha256=nu4S019t563LCigqmDceweOxjy9g_PRgFve56QFSxdQ,10159
32
32
  esphome/yaml_util.py,sha256=_NKLTaGK9rqjV3r3i-5d_HfZoPBtbtqIvZZ86qMt-oI,23166
33
33
  esphome/zeroconf.py,sha256=dy3aWh1Lf4Sh5e7Izlq30FkdzAKWA6IGvZkXuxYrxFE,6511
34
34
  esphome/build_gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -391,7 +391,7 @@ esphome/components/ble_scanner/ble_scanner.cpp,sha256=4NvPhE7_RkLprMCD9hZOk4po32
391
391
  esphome/components/ble_scanner/ble_scanner.h,sha256=r43KWVPdMgJxyNiapqc4IPmEaJ8MX8ZIEUsvRcoA8T0,1028
392
392
  esphome/components/ble_scanner/text_sensor.py,sha256=yOB-AMBbNwJ0K9zYXh3ZedA42Os8884RbLsiZyQao9s,717
393
393
  esphome/components/bluetooth_proxy/__init__.py,sha256=1vRwcv_xHe1yIM9jNSZRvBRrCRVwEdO6WgpQZjtc_7w,5168
394
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp,sha256=R_tQWFlxfVKl6tL5ZXf_JPx6e3JW08QPUmmusxVilnM,25321
394
+ esphome/components/bluetooth_proxy/bluetooth_connection.cpp,sha256=MbJFkrlDGXJThiLDTpiGGCdJdbtUwN35Gqe8ftSKX5M,25161
395
395
  esphome/components/bluetooth_proxy/bluetooth_connection.h,sha256=VHTD2S-QzvdT9k6BPiQeIxXN8M4svX3QEevhfL71PqA,2079
396
396
  esphome/components/bluetooth_proxy/bluetooth_proxy.cpp,sha256=fdtHt85viaXNPMcqQfn2PDDD02cn_oN2Gt35xmq12mo,17268
397
397
  esphome/components/bluetooth_proxy/bluetooth_proxy.h,sha256=lAZySpUTjCr7KAVeglQW1keK_Nt6KhKXUlDbCRICUrs,6509
@@ -836,7 +836,7 @@ esphome/components/es8388/select/adc_input_mic_select.cpp,sha256=xBlweJHP_BHSvwP
836
836
  esphome/components/es8388/select/adc_input_mic_select.h,sha256=1Wf54OGjnrj9vFe7WuIU10qraRAJX7HM1qEcCTTSlvc,336
837
837
  esphome/components/es8388/select/dac_output_select.cpp,sha256=FDOC7NHBaR34BqzzsPrmzBIzY_4o_YkF3_wSs_A9LC8,302
838
838
  esphome/components/es8388/select/dac_output_select.h,sha256=u00z0jHqKmqsaKht3b3k7aGtYudU0cCJRTOw1Zh-mbw,334
839
- esphome/components/esp32/__init__.py,sha256=xoxrvg3VZ5BLLG8QBzYCw1TFLsmdFXIGp6er_qXdsYo,41632
839
+ esphome/components/esp32/__init__.py,sha256=DfxBh_7LPo8o1jPu_FL4oiPgwLj94FnKTl-mh0juKRQ,41712
840
840
  esphome/components/esp32/boards.py,sha256=c3G-Ai5zlslngaW0efkQtyuJ4w4r1j-ueg4SNoBQ0m4,55695
841
841
  esphome/components/esp32/const.py,sha256=3sPibOKzbGgtSUIn7PfTQJRyob6x1vUtxagKCGS9CyY,1130
842
842
  esphome/components/esp32/core.cpp,sha256=7zSi6LBjWUV1qMNdCTs3R4LRLkg6Xnl8a7bsTGy-f8Q,2747
@@ -856,12 +856,12 @@ esphome/components/esp32/helpers.cpp,sha256=j0V0-kI4Ww04BH5N5EfyRgQHks0q_OoH8mPJ
856
856
  esphome/components/esp32/post_build.py.script,sha256=W0ovnULShEdSMYJbQfbXwlsYvIA_5VZZeg_xlIykfs8,4729
857
857
  esphome/components/esp32/preferences.cpp,sha256=WpEG6PenHwrAIonuoV_chdDJriJXF5dcpIbuYfmaUCQ,6229
858
858
  esphome/components/esp32/preferences.h,sha256=9HIy-BOgjOXJiEgOizZ_Qb8-l6K4eb3VSPW8Y8ffuWM,165
859
- esphome/components/esp32_ble/__init__.py,sha256=HkW0KPQ971XqTGw3RDKKVwgnYRNbQc3CVvNz10daeaE,11477
860
- esphome/components/esp32_ble/ble.cpp,sha256=jvS20rgL76hGcBj1-JsDbCY4AR8FanpQeNcx0gp3oNE,18056
859
+ esphome/components/esp32_ble/__init__.py,sha256=oS-nr_7uWa8vXd1sIWhoqmXWX5gjjUadapQ_nziJA4o,11521
860
+ esphome/components/esp32_ble/ble.cpp,sha256=v61I_viLjEdzeDtZC56ms_GluryUPMt37FPn3pv3Az0,18058
861
861
  esphome/components/esp32_ble/ble.h,sha256=FrziF-BDOhAMDji2rBOlN41Yog5Pu6EdACdsbUupCKs,6636
862
862
  esphome/components/esp32_ble/ble_advertising.cpp,sha256=OTPdELtn7q60zl2cua6tllF7U_uLsm4NIGePOG17PH8,6162
863
863
  esphome/components/esp32_ble/ble_advertising.h,sha256=h3SRhv6ZQ0VrrOyGvsuJ9_qsW8cOHWaofudIDusIdWM,1669
864
- esphome/components/esp32_ble/ble_event.h,sha256=_0wO24VY2c3zJ0wc3Scmw-Dc1xbYoQDuhPaDG6uolxM,18258
864
+ esphome/components/esp32_ble/ble_event.h,sha256=bgABmZzSEXlu8uy7cnN4I964WcGhtrpWjwVDFHO_X1A,21966
865
865
  esphome/components/esp32_ble/ble_scan_result.h,sha256=_vUaGDJkt3agdNdz7DA1dofJHooDFvtjaQVVO-a3V1A,520
866
866
  esphome/components/esp32_ble/ble_uuid.cpp,sha256=WAv4ULcteJDfigD_YHaEYPVQawHrwU5HvFAF39RVMMY,6211
867
867
  esphome/components/esp32_ble/ble_uuid.h,sha256=3VEsXyMLY2R545p2GHQbxWNzqSxPharuUaWbgEqel_4,994
@@ -950,7 +950,7 @@ esphome/components/esphome/ota/ota_esphome.cpp,sha256=wjSpISw66rKAQIeVuL_-LdOvY3
950
950
  esphome/components/esphome/ota/ota_esphome.h,sha256=M59XzEEM9b4MtTtS0tsS_hdiRHPXAlJUrGfwgUgPuAQ,1397
951
951
  esphome/components/espnow/__init__.py,sha256=ZMz0wyAmx4VW8dewtRhvSu3-TiCMbjVswF8_PvgxcvA,9780
952
952
  esphome/components/espnow/automation.h,sha256=nR-WJEfKRLpbkd1xbX2sKPId-M1TPdFrA5CD_C7LXwU,5776
953
- esphome/components/espnow/espnow_component.cpp,sha256=O7DCbKGUjCzDlKAjumLncPNU7aV9zp6xuwLGBZjuBXU,15021
953
+ esphome/components/espnow/espnow_component.cpp,sha256=cVGDLhpyYV33P0B5U__M9HUJTXmkHig6PoWwK8OYrPQ,15051
954
954
  esphome/components/espnow/espnow_component.h,sha256=wQpUgP7vnQ8quScoOxdfEyyDQ77B4i1ryhSiwbNnqSI,6971
955
955
  esphome/components/espnow/espnow_err.h,sha256=XpcviJ6_EdTPdJ7f_DX3pWcKsm9FVfLtczO-JeGMoRg,649
956
956
  esphome/components/espnow/espnow_packet.h,sha256=zZGNt5qGWWcq9Sfwmc685VgLH4AEmYYzxZBF0uHrvMM,5692
@@ -2102,7 +2102,7 @@ esphome/components/nextion/__init__.py,sha256=ozHEIgLsTp_S7g2jI_JGwi_qR9c7HstX4a
2102
2102
  esphome/components/nextion/automation.h,sha256=baaMGf6qTWI2OILZvkIkiKiW_pM21YZqTNbeggVXeXw,4555
2103
2103
  esphome/components/nextion/base_component.py,sha256=09AVYuXDHlGlK95nVyjBRpys7JYjkkd37hSjvXfkfXA,4333
2104
2104
  esphome/components/nextion/display.py,sha256=oYrIEnRQjIxphZyBgbNwVmkLiQ6TS0LzZ2dxROR5KAU,8341
2105
- esphome/components/nextion/nextion.cpp,sha256=z1xypVF7lgAEpjS5fxNCofLXurcmzKH9yKNXmzdemXg,45976
2105
+ esphome/components/nextion/nextion.cpp,sha256=e8Jd00sRcxFVJ36is3X3FmhmW4knMU56_MPmlVoLDWg,46112
2106
2106
  esphome/components/nextion/nextion.h,sha256=UbwolEuER3Olc_20C43YKQ1r5zT_Snd7QSs6sYv9UZA,53663
2107
2107
  esphome/components/nextion/nextion_base.h,sha256=3v9nuHpvpFxMKutV4bzuu1OB_uj26PRDaDc5gTv_2rc,2416
2108
2108
  esphome/components/nextion/nextion_commands.cpp,sha256=0JUOsd_k6JLYZr7ZT_obxoHrSTdT3gP0-hVq7USYg-k,17935
@@ -2377,7 +2377,7 @@ esphome/components/preferences/syncer.h,sha256=AaSl8_J86_P6bZFVx2j7I8cXz8VGeSdGC
2377
2377
  esphome/components/prometheus/__init__.py,sha256=nDE6iM3mGGovPVT74EOrDgXKv4yq0kQaK2UUbEbSllg,1697
2378
2378
  esphome/components/prometheus/prometheus_handler.cpp,sha256=dTvIT7QbsLDLM6VERKH0ipEKMY5oiamnNy6Eg7AVVuo,39091
2379
2379
  esphome/components/prometheus/prometheus_handler.h,sha256=oohyR_wpYfb2I7s6zWV3rO-zO9ZsQ3ybxEJSsvdbeEY,7834
2380
- esphome/components/psram/__init__.py,sha256=u059-e7Da5hVoTI0fq_tC7V5d-5dH5p2NWjyLZHfVnc,4918
2380
+ esphome/components/psram/__init__.py,sha256=1SWqKgYP0KZq8iAuZDndKKXpkobn3MSTyBBG5RmpzTI,5049
2381
2381
  esphome/components/psram/psram.cpp,sha256=ILopiIgTMmmb4mD431OuaZMEPU6v24u9Pn9K9Du1dgw,637
2382
2382
  esphome/components/psram/psram.h,sha256=LdElwxbKK68o4J9sdmMX8RZn5D94lXhCCSDm83Ge2jc,239
2383
2383
  esphome/components/pulse_counter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -2750,8 +2750,8 @@ esphome/components/sen5x/sen5x.cpp,sha256=NaUbTAIajZ_9kD6KgjZ8kipc-b_IEocR35qjGX
2750
2750
  esphome/components/sen5x/sen5x.h,sha256=B99SUzUVMVHfF0iwCWggTaBp2ZG0s932i2vp1fdwuBs,5381
2751
2751
  esphome/components/sen5x/sensor.py,sha256=xdH2NGxyQ1xZyQZ8FtSwVxpuZWogmmf4SmPjiLAe02U,8881
2752
2752
  esphome/components/senseair/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2753
- esphome/components/senseair/senseair.cpp,sha256=Ptorun-BQYADdkWC_t-EwTdRlWogwZnP7owATbu6R8U,6551
2754
- esphome/components/senseair/senseair.h,sha256=2V0MNq8liklRv6NpmJrFEZy2nopkRyNhOSKIoFCbyvs,2315
2753
+ esphome/components/senseair/senseair.cpp,sha256=t3_W_MjQDNg3iwF8h7YGZh7mytidyIEMq8cW7BSanTM,6708
2754
+ esphome/components/senseair/senseair.h,sha256=Eb5KT5Yyhz8ctqvM15TdUPlYDxGxsPMG7Kyhoyix_UM,2563
2755
2755
  esphome/components/senseair/sensor.py,sha256=922zXA1BMk2O-qbZNaP6BCs05kXd6Ktyx84UACHf6xU,2853
2756
2756
  esphome/components/sensirion_common/__init__.py,sha256=qxluYFMHWL6gSh-lUsnt-0N9tsBYzI6Pgv2bbqnYVko,245
2757
2757
  esphome/components/sensirion_common/i2c_sensirion.cpp,sha256=kJt5twbac4ThpnYZUGxsQaMOkScGJFp9onmDZxew0nA,3766
@@ -3464,7 +3464,7 @@ esphome/components/web_server/list_entities.cpp,sha256=yQ3skDSDFnnKsEpLdkyjzySmX
3464
3464
  esphome/components/web_server/list_entities.h,sha256=afeebykHFeV1rLpywOSZqaPqfL-K-MkLByfJWrkrb-M,2561
3465
3465
  esphome/components/web_server/server_index_v2.h,sha256=cVFZzhvmwcUzN815XwYnx2L9zf5lH-MAZjolRearXdw,74968
3466
3466
  esphome/components/web_server/server_index_v3.h,sha256=5SZfSHDG4xAyXNBxUqs8-jSVwocgfRbNbTSMwzVl1io,476640
3467
- esphome/components/web_server/web_server.cpp,sha256=7g33xeUaggv3sMfOcj9KNS65LvL13rSfg_jxFhJwi5E,69023
3467
+ esphome/components/web_server/web_server.cpp,sha256=_esKbsAhaXqarCfiQ5K2sj6RbF32QSXwAnApj2upG2E,69021
3468
3468
  esphome/components/web_server/web_server.h,sha256=OG0MpnGUaZGI6DY3_OyDm8Yuso8P5RcgThnTEFWFTM0,23991
3469
3469
  esphome/components/web_server/web_server_v1.cpp,sha256=ZnFV1J2YAzAT2mtR-eeVgG1TSVpy953EF1yVKYdTcTg,7409
3470
3470
  esphome/components/web_server/ota/__init__.py,sha256=w4Ufe8mN-5r0913AODCjl9LlCKMpWRTFMSCEmLgRzxE,1018
@@ -3501,7 +3501,7 @@ esphome/components/whynter/whynter.h,sha256=S9Psg1t7acdsWyaEJvTwwEnXwXcBgnGXlhVL
3501
3501
  esphome/components/wiegand/__init__.py,sha256=omQlVAU2D_tLx1sO8Mr_lBfAlhi9mrPsJJUrM1gihFk,2633
3502
3502
  esphome/components/wiegand/wiegand.cpp,sha256=K7XAflWGKzb4_qp32dnVHglnV3dH_OvLtPvhp7b9IhM,3816
3503
3503
  esphome/components/wiegand/wiegand.h,sha256=gyg5szEK0okoeLBQR284k84xy-ln19kNIkeOTe-CX-Y,1658
3504
- esphome/components/wifi/__init__.py,sha256=uMMTA05-oADZfV73WEiQH0LbXqO8mqC32YrO3XdZwi4,17880
3504
+ esphome/components/wifi/__init__.py,sha256=rBuHuSmhncruw9EvPNRYDYxeufaKroPU87gqVrrBOSc,18220
3505
3505
  esphome/components/wifi/wifi_component.cpp,sha256=u37YI4d-tswpIY_PbITPByxppMRiy_tmaWVKL44ZADk,31055
3506
3506
  esphome/components/wifi/wifi_component.h,sha256=x4yX4b1Jyt3QyPrlLKmm6hjLTnjMZdRcG-sgf7fdkl8,15884
3507
3507
  esphome/components/wifi/wifi_component_esp32_arduino.cpp,sha256=lqzdvTN1FzvqwCnErx03R2DDC_JwfJrt6BsW_oSktus,28822
@@ -3672,7 +3672,7 @@ esphome/components/zyaura/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
3672
3672
  esphome/components/zyaura/sensor.py,sha256=cSmO4ozYdi4ZD7NK4lmYjswWVmJoDvEruU1HhGrZSE0,2476
3673
3673
  esphome/components/zyaura/zyaura.cpp,sha256=F7WM8XAZ5MYuCD3eERm2_IA-O7sP1i-A-yF5TV4PqX8,3679
3674
3674
  esphome/components/zyaura/zyaura.h,sha256=7O3EGFIopUEfBp3A5sBC0l4zx2mesRxDWa_MBdGtPKQ,2307
3675
- esphome/core/__init__.py,sha256=d6MfXS3rJso9i5ntG8kfSmqwTZqs935qJVYMe7P7MdU,29790
3675
+ esphome/core/__init__.py,sha256=LtYxFisX_WLZxoECaIokSHi-vTnubke286K68enEHs4,29908
3676
3676
  esphome/core/application.cpp,sha256=Q-ZZmKRTjD6MbXwCqUa9v5hO6bIM1DzVK2_XZax8BeY,21289
3677
3677
  esphome/core/application.h,sha256=HpXLMQk5NckiDTvDnUAsUv3xyMKof6yz1Gl6IKmm8u0,20187
3678
3678
  esphome/core/area.h,sha256=mtFxmuv8fC2hArcey3cZ0F6hMXSO2QpFZ9Xv49z4rvk,393
@@ -3693,7 +3693,7 @@ esphome/core/device.h,sha256=mYTwRg92-BU8uTTzmrufH-KkHCMLKsKWnvM-mjzw6I0,531
3693
3693
  esphome/core/doxygen.h,sha256=9fAJ2T-1z96-NYnj63vQhsnKthHBrh3EqBnY0h3ZN-A,439
3694
3694
  esphome/core/entity_base.cpp,sha256=4JMAGN8w3bMW-kTchQxlbA-zS43NOdYhT1Fo0Celx78,2453
3695
3695
  esphome/core/entity_base.h,sha256=BSy0wKv8I1CvrbH86REV-yRN-YCPv5ZUF3FCsv5d02g,7198
3696
- esphome/core/entity_helpers.py,sha256=cbCG91EeBgiIw4R4TsO39ukTJQRKKRUPnUjZnSBrRD8,9761
3696
+ esphome/core/entity_helpers.py,sha256=XqeVCGPX1BeOFlyrtV3m5CxVedO3BVmnvfuqZHGMdFI,9759
3697
3697
  esphome/core/event_pool.h,sha256=X8_-72rODgpG9P_dSjezkJjFaaFvXy0cV42o6X-Vv1Q,2405
3698
3698
  esphome/core/gpio.h,sha256=kLkCnPxu4_1CsLR4BI_Baj1lDGoRIh8uubbwsIkJPIA,2575
3699
3699
  esphome/core/hal.h,sha256=Le0-vtdDylYCaE9i4yvrv5-Y5PB5xoL3PM2FfMJsIeA,970
@@ -3708,8 +3708,8 @@ esphome/core/optional.h,sha256=uKMzglliXSA5eC3ujwrADmyt8m7X4WkBQcOL6p3ET7E,7144
3708
3708
  esphome/core/preferences.h,sha256=RxgWuAi-uo6SZiK8UKX4KTwVfIMnaaLvrZP2rqTn_mE,1959
3709
3709
  esphome/core/ring_buffer.cpp,sha256=6vOoKNjO4dSLYfqJYM8AXclpKgQOH6C79CqocwTSv-k,3526
3710
3710
  esphome/core/ring_buffer.h,sha256=4SeN2DYZLCHrLIjSPDsiAynIjwOoItiRUDO-u1wjq-o,2997
3711
- esphome/core/scheduler.cpp,sha256=mlr_K8MAlmOvdE4wQ9pVOkPIRCvtYpMSx3RDlHmuEBY,30282
3712
- esphome/core/scheduler.h,sha256=wt1m4zXWIC7imCtAeOMhoQ0OVeLfzayhPY1arv5ggQc,11443
3711
+ esphome/core/scheduler.cpp,sha256=J_DLLEXaEkRzkTgB5gfDxTJElBwFvMuN7GnlpkcN3TY,31421
3712
+ esphome/core/scheduler.h,sha256=2oFr6l8oXHydmyzaGaieSftPk76R-bHb2H8dJkedaUM,13735
3713
3713
  esphome/core/string_ref.cpp,sha256=of1TYMY6t3t4HjjPLSiItuPSa62AMG0lK_CU2HS1RvM,242
3714
3714
  esphome/core/string_ref.h,sha256=Rd8HVBiUZrPA3TkPCwuAxGw91VX-e3Fky812OCNhNvA,5227
3715
3715
  esphome/core/time.cpp,sha256=ML3sAvlSgDaUkhbPmBkUkSFhGM78j0d7cL8CHAIgfow,7667
@@ -3735,9 +3735,9 @@ esphome/dashboard/util/itertools.py,sha256=8eLrWEWmICLtXNxkKdYPQV0c_N4GEz8m9Npnb
3735
3735
  esphome/dashboard/util/password.py,sha256=cQz3b9B-ijTe7zS6BeCW0hc3pWv6JjC78jmnycYYAh8,321
3736
3736
  esphome/dashboard/util/subprocess.py,sha256=T8EW6dbU4LPd2DG1dRrdh8li71tt6J1isn411poMhkk,1022
3737
3737
  esphome/dashboard/util/text.py,sha256=wwFtORlvHjsYkqb68IT-772LHAhWxT4OtnkIcPICQB0,317
3738
- esphome-2025.8.0b1.dist-info/licenses/LICENSE,sha256=HzEjkBInJe44L4WvAOPfhPJJDNj6YbnqFyvGWRzArGM,36664
3739
- esphome-2025.8.0b1.dist-info/METADATA,sha256=Fx2vOfXLjiT1dHcygMtzeI145tBREaLdN-3if4Z0I4o,3633
3740
- esphome-2025.8.0b1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
3741
- esphome-2025.8.0b1.dist-info/entry_points.txt,sha256=mIxVNuWtbYzeEcaWCl-AQ-97aBOWbnYBAK8nbF6P4M0,50
3742
- esphome-2025.8.0b1.dist-info/top_level.txt,sha256=0GSXEW3cnITpgG3qnsSMz0qoqJHAFyfw7Y8MVtEf1Yk,8
3743
- esphome-2025.8.0b1.dist-info/RECORD,,
3738
+ esphome-2025.8.0b3.dist-info/licenses/LICENSE,sha256=HzEjkBInJe44L4WvAOPfhPJJDNj6YbnqFyvGWRzArGM,36664
3739
+ esphome-2025.8.0b3.dist-info/METADATA,sha256=EGfyUjV_6wRqxq45uj41r05Uq4BBcdkF5kmY2Kils34,3633
3740
+ esphome-2025.8.0b3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
3741
+ esphome-2025.8.0b3.dist-info/entry_points.txt,sha256=mIxVNuWtbYzeEcaWCl-AQ-97aBOWbnYBAK8nbF6P4M0,50
3742
+ esphome-2025.8.0b3.dist-info/top_level.txt,sha256=0GSXEW3cnITpgG3qnsSMz0qoqJHAFyfw7Y8MVtEf1Yk,8
3743
+ esphome-2025.8.0b3.dist-info/RECORD,,