esphome 2025.2.2__py3-none-any.whl → 2025.3.0b1__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.
Files changed (135) hide show
  1. esphome/__main__.py +9 -1
  2. esphome/components/api/api_connection.cpp +426 -70
  3. esphome/components/api/api_connection.h +117 -25
  4. esphome/components/api/api_pb2.cpp +9 -0
  5. esphome/components/api/api_pb2.h +1 -0
  6. esphome/components/api/api_server.cpp +2 -2
  7. esphome/components/api/list_entities.cpp +76 -22
  8. esphome/components/api/list_entities.h +1 -0
  9. esphome/components/api/subscribe_state.h +2 -0
  10. esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -0
  11. esphome/components/bmp085/bmp085.cpp +1 -1
  12. esphome/components/chsc6x/__init__.py +2 -0
  13. esphome/components/chsc6x/chsc6x_touchscreen.cpp +47 -0
  14. esphome/components/chsc6x/chsc6x_touchscreen.h +34 -0
  15. esphome/components/chsc6x/touchscreen.py +33 -0
  16. esphome/components/climate/__init__.py +0 -1
  17. esphome/components/cst816/binary_sensor/__init__.py +2 -25
  18. esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +3 -14
  19. esphome/components/cst816/touchscreen/cst816_touchscreen.h +0 -4
  20. esphome/components/esp32_ble_beacon/__init__.py +3 -1
  21. esphome/components/esp8266/gpio.py +1 -2
  22. esphome/components/font/__init__.py +185 -185
  23. esphome/components/font/font.cpp +4 -4
  24. esphome/components/font/font.h +1 -0
  25. esphome/components/haier/climate.py +11 -10
  26. esphome/components/hbridge/switch/hbridge_switch.cpp +2 -2
  27. esphome/components/heatpumpir/climate.py +2 -1
  28. esphome/components/heatpumpir/heatpumpir.cpp +1 -0
  29. esphome/components/heatpumpir/heatpumpir.h +1 -0
  30. esphome/components/i2c/__init__.py +6 -6
  31. esphome/components/i2c/i2c_bus_esp_idf.cpp +6 -2
  32. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
  33. esphome/components/ili9xxx/display.py +1 -0
  34. esphome/components/ili9xxx/ili9xxx_display.h +5 -0
  35. esphome/components/ili9xxx/ili9xxx_init.h +59 -0
  36. esphome/components/ld2450/__init__.py +51 -0
  37. esphome/components/ld2450/binary_sensor.py +47 -0
  38. esphome/components/ld2450/button/__init__.py +45 -0
  39. esphome/components/ld2450/button/reset_button.cpp +9 -0
  40. esphome/components/ld2450/button/reset_button.h +18 -0
  41. esphome/components/ld2450/button/restart_button.cpp +9 -0
  42. esphome/components/ld2450/button/restart_button.h +18 -0
  43. esphome/components/ld2450/ld2450.cpp +876 -0
  44. esphome/components/ld2450/ld2450.h +234 -0
  45. esphome/components/ld2450/number/__init__.py +121 -0
  46. esphome/components/ld2450/number/presence_timeout_number.cpp +12 -0
  47. esphome/components/ld2450/number/presence_timeout_number.h +18 -0
  48. esphome/components/ld2450/number/zone_coordinate_number.cpp +14 -0
  49. esphome/components/ld2450/number/zone_coordinate_number.h +19 -0
  50. esphome/components/ld2450/select/__init__.py +56 -0
  51. esphome/components/ld2450/select/baud_rate_select.cpp +12 -0
  52. esphome/components/ld2450/select/baud_rate_select.h +18 -0
  53. esphome/components/ld2450/select/zone_type_select.cpp +12 -0
  54. esphome/components/ld2450/select/zone_type_select.h +18 -0
  55. esphome/components/ld2450/sensor.py +156 -0
  56. esphome/components/ld2450/switch/__init__.py +45 -0
  57. esphome/components/ld2450/switch/bluetooth_switch.cpp +12 -0
  58. esphome/components/ld2450/switch/bluetooth_switch.h +18 -0
  59. esphome/components/ld2450/switch/multi_target_switch.cpp +12 -0
  60. esphome/components/ld2450/switch/multi_target_switch.h +18 -0
  61. esphome/components/ld2450/text_sensor.py +62 -0
  62. esphome/components/lvgl/defines.py +0 -2
  63. esphome/components/lvgl/font.cpp +1 -1
  64. esphome/components/lvgl/lvgl_esphome.cpp +27 -19
  65. esphome/components/lvgl/widgets/img.py +1 -3
  66. esphome/components/mcp2515/mcp2515.cpp +1 -0
  67. esphome/components/mlx90393/sensor.py +53 -33
  68. esphome/components/mlx90393/sensor_mlx90393.cpp +4 -0
  69. esphome/components/mlx90393/sensor_mlx90393.h +8 -3
  70. esphome/components/mqtt/__init__.py +2 -2
  71. esphome/components/msa3xx/__init__.py +189 -0
  72. esphome/components/msa3xx/binary_sensor.py +40 -0
  73. esphome/components/msa3xx/msa3xx.cpp +417 -0
  74. esphome/components/msa3xx/msa3xx.h +311 -0
  75. esphome/components/msa3xx/sensor.py +42 -0
  76. esphome/components/msa3xx/text_sensor.py +38 -0
  77. esphome/components/nfc/binary_sensor/__init__.py +4 -4
  78. esphome/components/opentherm/binary_sensor/__init__.py +4 -4
  79. esphome/components/opentherm/generate.py +6 -6
  80. esphome/components/opentherm/sensor/__init__.py +5 -6
  81. esphome/components/packages/__init__.py +35 -11
  82. esphome/components/pn532/binary_sensor.py +4 -4
  83. esphome/components/rc522/binary_sensor.py +4 -4
  84. esphome/components/socket/bsd_sockets_impl.cpp +1 -0
  85. esphome/components/socket/lwip_sockets_impl.cpp +1 -0
  86. esphome/components/socket/socket.h +3 -1
  87. esphome/components/ssd1306_base/__init__.py +7 -7
  88. esphome/components/thermostat/climate.py +1 -1
  89. esphome/components/tmp1075/tmp1075.cpp +7 -11
  90. esphome/components/tmp1075/tmp1075.h +1 -2
  91. esphome/components/tormatic/__init__.py +1 -0
  92. esphome/components/tormatic/cover.py +47 -0
  93. esphome/components/tormatic/tormatic_cover.cpp +355 -0
  94. esphome/components/tormatic/tormatic_cover.h +60 -0
  95. esphome/components/tormatic/tormatic_protocol.h +211 -0
  96. esphome/components/touchscreen/binary_sensor/__init__.py +3 -0
  97. esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp +7 -1
  98. esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h +3 -1
  99. esphome/components/touchscreen/touchscreen.cpp +3 -4
  100. esphome/components/udp/udp_component.h +4 -1
  101. esphome/components/web_server/list_entities.cpp +70 -66
  102. esphome/components/web_server/list_entities.h +43 -22
  103. esphome/components/web_server/web_server.cpp +345 -68
  104. esphome/components/web_server/web_server.h +138 -6
  105. esphome/components/web_server_base/__init__.py +1 -1
  106. esphome/components/web_server_idf/__init__.py +2 -0
  107. esphome/components/web_server_idf/web_server_idf.cpp +177 -30
  108. esphome/components/web_server_idf/web_server_idf.h +53 -4
  109. esphome/config_validation.py +23 -125
  110. esphome/const.py +5 -1
  111. esphome/core/config.py +12 -4
  112. esphome/core/defines.h +1 -1
  113. esphome/core/helpers.h +5 -3
  114. esphome/core/time.cpp +1 -0
  115. esphome/cpp_generator.py +3 -3
  116. esphome/dashboard/core.py +30 -21
  117. esphome/dashboard/dns.py +7 -1
  118. esphome/dashboard/entries.py +83 -16
  119. esphome/dashboard/settings.py +0 -4
  120. esphome/dashboard/status/mdns.py +43 -14
  121. esphome/dashboard/status/mqtt.py +22 -9
  122. esphome/dashboard/status/ping.py +54 -10
  123. esphome/dashboard/web_server.py +56 -24
  124. esphome/storage_json.py +4 -0
  125. esphome/wizard.py +13 -17
  126. esphome/writer.py +1 -3
  127. esphome/yaml_util.py +36 -33
  128. esphome/zeroconf.py +9 -21
  129. {esphome-2025.2.2.dist-info → esphome-2025.3.0b1.dist-info}/METADATA +5 -5
  130. {esphome-2025.2.2.dist-info → esphome-2025.3.0b1.dist-info}/RECORD +134 -94
  131. esphome/components/cst816/binary_sensor/cst816_button.h +0 -27
  132. {esphome-2025.2.2.dist-info → esphome-2025.3.0b1.dist-info}/LICENSE +0 -0
  133. {esphome-2025.2.2.dist-info → esphome-2025.3.0b1.dist-info}/WHEEL +0 -0
  134. {esphome-2025.2.2.dist-info → esphome-2025.3.0b1.dist-info}/entry_points.txt +0 -0
  135. {esphome-2025.2.2.dist-info → esphome-2025.3.0b1.dist-info}/top_level.txt +0 -0
@@ -28,8 +28,38 @@ namespace api {
28
28
  static const char *const TAG = "api.connection";
29
29
  static const int ESP32_CAMERA_STOP_STREAM = 5000;
30
30
 
31
+ // helper for allowing only unique entries in the queue
32
+ void DeferredMessageQueue::dmq_push_back_with_dedup_(void *source, send_message_t *send_message) {
33
+ DeferredMessage item(source, send_message);
34
+
35
+ auto iter = std::find_if(this->deferred_queue_.begin(), this->deferred_queue_.end(),
36
+ [&item](const DeferredMessage &test) -> bool { return test == item; });
37
+
38
+ if (iter != this->deferred_queue_.end()) {
39
+ (*iter) = item;
40
+ } else {
41
+ this->deferred_queue_.push_back(item);
42
+ }
43
+ }
44
+
45
+ void DeferredMessageQueue::process_queue() {
46
+ while (!deferred_queue_.empty()) {
47
+ DeferredMessage &de = deferred_queue_.front();
48
+ if (de.send_message_(this->api_connection_, de.source_)) {
49
+ // O(n) but memory efficiency is more important than speed here which is why std::vector was chosen
50
+ deferred_queue_.erase(deferred_queue_.begin());
51
+ } else {
52
+ break;
53
+ }
54
+ }
55
+ }
56
+
57
+ void DeferredMessageQueue::defer(void *source, send_message_t *send_message) {
58
+ this->dmq_push_back_with_dedup_(source, send_message);
59
+ }
60
+
31
61
  APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
32
- : parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) {
62
+ : parent_(parent), deferred_message_queue_(this), initial_state_iterator_(this), list_entities_iterator_(this) {
33
63
  this->proto_write_buffer_.reserve(64);
34
64
 
35
65
  #if defined(USE_API_PLAINTEXT)
@@ -116,8 +146,12 @@ void APIConnection::loop() {
116
146
  return;
117
147
  }
118
148
 
119
- this->list_entities_iterator_.advance();
120
- this->initial_state_iterator_.advance();
149
+ this->deferred_message_queue_.process_queue();
150
+
151
+ if (!this->list_entities_iterator_.completed())
152
+ this->list_entities_iterator_.advance();
153
+ if (!this->initial_state_iterator_.completed() && this->list_entities_iterator_.completed())
154
+ this->initial_state_iterator_.advance();
121
155
 
122
156
  static uint32_t keepalive = 60000;
123
157
  static uint8_t max_ping_retries = 60;
@@ -210,13 +244,31 @@ bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary
210
244
  if (!this->state_subscription_)
211
245
  return false;
212
246
 
247
+ if (!APIConnection::try_send_binary_sensor_state(this, binary_sensor, state)) {
248
+ this->deferred_message_queue_.defer(binary_sensor, try_send_binary_sensor_state);
249
+ }
250
+
251
+ return true;
252
+ }
253
+ void APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor) {
254
+ if (!APIConnection::try_send_binary_sensor_info(this, binary_sensor)) {
255
+ this->deferred_message_queue_.defer(binary_sensor, try_send_binary_sensor_info);
256
+ }
257
+ }
258
+ bool APIConnection::try_send_binary_sensor_state(APIConnection *api, void *v_binary_sensor) {
259
+ binary_sensor::BinarySensor *binary_sensor = reinterpret_cast<binary_sensor::BinarySensor *>(v_binary_sensor);
260
+ return APIConnection::try_send_binary_sensor_state(api, binary_sensor, binary_sensor->state);
261
+ }
262
+ bool APIConnection::try_send_binary_sensor_state(APIConnection *api, binary_sensor::BinarySensor *binary_sensor,
263
+ bool state) {
213
264
  BinarySensorStateResponse resp;
214
265
  resp.key = binary_sensor->get_object_id_hash();
215
266
  resp.state = state;
216
267
  resp.missing_state = !binary_sensor->has_state();
217
- return this->send_binary_sensor_state_response(resp);
268
+ return api->send_binary_sensor_state_response(resp);
218
269
  }
219
- bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor) {
270
+ bool APIConnection::try_send_binary_sensor_info(APIConnection *api, void *v_binary_sensor) {
271
+ binary_sensor::BinarySensor *binary_sensor = reinterpret_cast<binary_sensor::BinarySensor *>(v_binary_sensor);
220
272
  ListEntitiesBinarySensorResponse msg;
221
273
  msg.object_id = binary_sensor->get_object_id();
222
274
  msg.key = binary_sensor->get_object_id_hash();
@@ -228,7 +280,7 @@ bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_
228
280
  msg.disabled_by_default = binary_sensor->is_disabled_by_default();
229
281
  msg.icon = binary_sensor->get_icon();
230
282
  msg.entity_category = static_cast<enums::EntityCategory>(binary_sensor->get_entity_category());
231
- return this->send_list_entities_binary_sensor_response(msg);
283
+ return api->send_list_entities_binary_sensor_response(msg);
232
284
  }
233
285
  #endif
234
286
 
@@ -237,6 +289,19 @@ bool APIConnection::send_cover_state(cover::Cover *cover) {
237
289
  if (!this->state_subscription_)
238
290
  return false;
239
291
 
292
+ if (!APIConnection::try_send_cover_state(this, cover)) {
293
+ this->deferred_message_queue_.defer(cover, try_send_cover_state);
294
+ }
295
+
296
+ return true;
297
+ }
298
+ void APIConnection::send_cover_info(cover::Cover *cover) {
299
+ if (!APIConnection::try_send_cover_info(this, cover)) {
300
+ this->deferred_message_queue_.defer(cover, try_send_cover_info);
301
+ }
302
+ }
303
+ bool APIConnection::try_send_cover_state(APIConnection *api, void *v_cover) {
304
+ cover::Cover *cover = reinterpret_cast<cover::Cover *>(v_cover);
240
305
  auto traits = cover->get_traits();
241
306
  CoverStateResponse resp{};
242
307
  resp.key = cover->get_object_id_hash();
@@ -246,9 +311,10 @@ bool APIConnection::send_cover_state(cover::Cover *cover) {
246
311
  if (traits.get_supports_tilt())
247
312
  resp.tilt = cover->tilt;
248
313
  resp.current_operation = static_cast<enums::CoverOperation>(cover->current_operation);
249
- return this->send_cover_state_response(resp);
314
+ return api->send_cover_state_response(resp);
250
315
  }
251
- bool APIConnection::send_cover_info(cover::Cover *cover) {
316
+ bool APIConnection::try_send_cover_info(APIConnection *api, void *v_cover) {
317
+ cover::Cover *cover = reinterpret_cast<cover::Cover *>(v_cover);
252
318
  auto traits = cover->get_traits();
253
319
  ListEntitiesCoverResponse msg;
254
320
  msg.key = cover->get_object_id_hash();
@@ -264,7 +330,7 @@ bool APIConnection::send_cover_info(cover::Cover *cover) {
264
330
  msg.disabled_by_default = cover->is_disabled_by_default();
265
331
  msg.icon = cover->get_icon();
266
332
  msg.entity_category = static_cast<enums::EntityCategory>(cover->get_entity_category());
267
- return this->send_list_entities_cover_response(msg);
333
+ return api->send_list_entities_cover_response(msg);
268
334
  }
269
335
  void APIConnection::cover_command(const CoverCommandRequest &msg) {
270
336
  cover::Cover *cover = App.get_cover_by_key(msg.key);
@@ -300,6 +366,19 @@ bool APIConnection::send_fan_state(fan::Fan *fan) {
300
366
  if (!this->state_subscription_)
301
367
  return false;
302
368
 
369
+ if (!APIConnection::try_send_fan_state(this, fan)) {
370
+ this->deferred_message_queue_.defer(fan, try_send_fan_state);
371
+ }
372
+
373
+ return true;
374
+ }
375
+ void APIConnection::send_fan_info(fan::Fan *fan) {
376
+ if (!APIConnection::try_send_fan_info(this, fan)) {
377
+ this->deferred_message_queue_.defer(fan, try_send_fan_info);
378
+ }
379
+ }
380
+ bool APIConnection::try_send_fan_state(APIConnection *api, void *v_fan) {
381
+ fan::Fan *fan = reinterpret_cast<fan::Fan *>(v_fan);
303
382
  auto traits = fan->get_traits();
304
383
  FanStateResponse resp{};
305
384
  resp.key = fan->get_object_id_hash();
@@ -313,9 +392,10 @@ bool APIConnection::send_fan_state(fan::Fan *fan) {
313
392
  resp.direction = static_cast<enums::FanDirection>(fan->direction);
314
393
  if (traits.supports_preset_modes())
315
394
  resp.preset_mode = fan->preset_mode;
316
- return this->send_fan_state_response(resp);
395
+ return api->send_fan_state_response(resp);
317
396
  }
318
- bool APIConnection::send_fan_info(fan::Fan *fan) {
397
+ bool APIConnection::try_send_fan_info(APIConnection *api, void *v_fan) {
398
+ fan::Fan *fan = reinterpret_cast<fan::Fan *>(v_fan);
319
399
  auto traits = fan->get_traits();
320
400
  ListEntitiesFanResponse msg;
321
401
  msg.key = fan->get_object_id_hash();
@@ -332,7 +412,7 @@ bool APIConnection::send_fan_info(fan::Fan *fan) {
332
412
  msg.disabled_by_default = fan->is_disabled_by_default();
333
413
  msg.icon = fan->get_icon();
334
414
  msg.entity_category = static_cast<enums::EntityCategory>(fan->get_entity_category());
335
- return this->send_list_entities_fan_response(msg);
415
+ return api->send_list_entities_fan_response(msg);
336
416
  }
337
417
  void APIConnection::fan_command(const FanCommandRequest &msg) {
338
418
  fan::Fan *fan = App.get_fan_by_key(msg.key);
@@ -361,6 +441,19 @@ bool APIConnection::send_light_state(light::LightState *light) {
361
441
  if (!this->state_subscription_)
362
442
  return false;
363
443
 
444
+ if (!APIConnection::try_send_light_state(this, light)) {
445
+ this->deferred_message_queue_.defer(light, try_send_light_state);
446
+ }
447
+
448
+ return true;
449
+ }
450
+ void APIConnection::send_light_info(light::LightState *light) {
451
+ if (!APIConnection::try_send_light_info(this, light)) {
452
+ this->deferred_message_queue_.defer(light, try_send_light_info);
453
+ }
454
+ }
455
+ bool APIConnection::try_send_light_state(APIConnection *api, void *v_light) {
456
+ light::LightState *light = reinterpret_cast<light::LightState *>(v_light);
364
457
  auto traits = light->get_traits();
365
458
  auto values = light->remote_values;
366
459
  auto color_mode = values.get_color_mode();
@@ -380,9 +473,10 @@ bool APIConnection::send_light_state(light::LightState *light) {
380
473
  resp.warm_white = values.get_warm_white();
381
474
  if (light->supports_effects())
382
475
  resp.effect = light->get_effect_name();
383
- return this->send_light_state_response(resp);
476
+ return api->send_light_state_response(resp);
384
477
  }
385
- bool APIConnection::send_light_info(light::LightState *light) {
478
+ bool APIConnection::try_send_light_info(APIConnection *api, void *v_light) {
479
+ light::LightState *light = reinterpret_cast<light::LightState *>(v_light);
386
480
  auto traits = light->get_traits();
387
481
  ListEntitiesLightResponse msg;
388
482
  msg.key = light->get_object_id_hash();
@@ -415,7 +509,7 @@ bool APIConnection::send_light_info(light::LightState *light) {
415
509
  for (auto *effect : light->get_effects())
416
510
  msg.effects.push_back(effect->get_name());
417
511
  }
418
- return this->send_list_entities_light_response(msg);
512
+ return api->send_list_entities_light_response(msg);
419
513
  }
420
514
  void APIConnection::light_command(const LightCommandRequest &msg) {
421
515
  light::LightState *light = App.get_light_by_key(msg.key);
@@ -459,13 +553,30 @@ bool APIConnection::send_sensor_state(sensor::Sensor *sensor, float state) {
459
553
  if (!this->state_subscription_)
460
554
  return false;
461
555
 
556
+ if (!APIConnection::try_send_sensor_state(this, sensor, state)) {
557
+ this->deferred_message_queue_.defer(sensor, try_send_sensor_state);
558
+ }
559
+
560
+ return true;
561
+ }
562
+ void APIConnection::send_sensor_info(sensor::Sensor *sensor) {
563
+ if (!APIConnection::try_send_sensor_info(this, sensor)) {
564
+ this->deferred_message_queue_.defer(sensor, try_send_sensor_info);
565
+ }
566
+ }
567
+ bool APIConnection::try_send_sensor_state(APIConnection *api, void *v_sensor) {
568
+ sensor::Sensor *sensor = reinterpret_cast<sensor::Sensor *>(v_sensor);
569
+ return APIConnection::try_send_sensor_state(api, sensor, sensor->state);
570
+ }
571
+ bool APIConnection::try_send_sensor_state(APIConnection *api, sensor::Sensor *sensor, float state) {
462
572
  SensorStateResponse resp{};
463
573
  resp.key = sensor->get_object_id_hash();
464
574
  resp.state = state;
465
575
  resp.missing_state = !sensor->has_state();
466
- return this->send_sensor_state_response(resp);
576
+ return api->send_sensor_state_response(resp);
467
577
  }
468
- bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
578
+ bool APIConnection::try_send_sensor_info(APIConnection *api, void *v_sensor) {
579
+ sensor::Sensor *sensor = reinterpret_cast<sensor::Sensor *>(v_sensor);
469
580
  ListEntitiesSensorResponse msg;
470
581
  msg.key = sensor->get_object_id_hash();
471
582
  msg.object_id = sensor->get_object_id();
@@ -482,7 +593,7 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
482
593
  msg.state_class = static_cast<enums::SensorStateClass>(sensor->get_state_class());
483
594
  msg.disabled_by_default = sensor->is_disabled_by_default();
484
595
  msg.entity_category = static_cast<enums::EntityCategory>(sensor->get_entity_category());
485
- return this->send_list_entities_sensor_response(msg);
596
+ return api->send_list_entities_sensor_response(msg);
486
597
  }
487
598
  #endif
488
599
 
@@ -491,12 +602,29 @@ bool APIConnection::send_switch_state(switch_::Switch *a_switch, bool state) {
491
602
  if (!this->state_subscription_)
492
603
  return false;
493
604
 
605
+ if (!APIConnection::try_send_switch_state(this, a_switch, state)) {
606
+ this->deferred_message_queue_.defer(a_switch, try_send_switch_state);
607
+ }
608
+
609
+ return true;
610
+ }
611
+ void APIConnection::send_switch_info(switch_::Switch *a_switch) {
612
+ if (!APIConnection::try_send_switch_info(this, a_switch)) {
613
+ this->deferred_message_queue_.defer(a_switch, try_send_switch_info);
614
+ }
615
+ }
616
+ bool APIConnection::try_send_switch_state(APIConnection *api, void *v_a_switch) {
617
+ switch_::Switch *a_switch = reinterpret_cast<switch_::Switch *>(v_a_switch);
618
+ return APIConnection::try_send_switch_state(api, a_switch, a_switch->state);
619
+ }
620
+ bool APIConnection::try_send_switch_state(APIConnection *api, switch_::Switch *a_switch, bool state) {
494
621
  SwitchStateResponse resp{};
495
622
  resp.key = a_switch->get_object_id_hash();
496
623
  resp.state = state;
497
- return this->send_switch_state_response(resp);
624
+ return api->send_switch_state_response(resp);
498
625
  }
499
- bool APIConnection::send_switch_info(switch_::Switch *a_switch) {
626
+ bool APIConnection::try_send_switch_info(APIConnection *api, void *v_a_switch) {
627
+ switch_::Switch *a_switch = reinterpret_cast<switch_::Switch *>(v_a_switch);
500
628
  ListEntitiesSwitchResponse msg;
501
629
  msg.key = a_switch->get_object_id_hash();
502
630
  msg.object_id = a_switch->get_object_id();
@@ -508,7 +636,7 @@ bool APIConnection::send_switch_info(switch_::Switch *a_switch) {
508
636
  msg.disabled_by_default = a_switch->is_disabled_by_default();
509
637
  msg.entity_category = static_cast<enums::EntityCategory>(a_switch->get_entity_category());
510
638
  msg.device_class = a_switch->get_device_class();
511
- return this->send_list_entities_switch_response(msg);
639
+ return api->send_list_entities_switch_response(msg);
512
640
  }
513
641
  void APIConnection::switch_command(const SwitchCommandRequest &msg) {
514
642
  switch_::Switch *a_switch = App.get_switch_by_key(msg.key);
@@ -528,13 +656,31 @@ bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor,
528
656
  if (!this->state_subscription_)
529
657
  return false;
530
658
 
659
+ if (!APIConnection::try_send_text_sensor_state(this, text_sensor, std::move(state))) {
660
+ this->deferred_message_queue_.defer(text_sensor, try_send_text_sensor_state);
661
+ }
662
+
663
+ return true;
664
+ }
665
+ void APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor) {
666
+ if (!APIConnection::try_send_text_sensor_info(this, text_sensor)) {
667
+ this->deferred_message_queue_.defer(text_sensor, try_send_text_sensor_info);
668
+ }
669
+ }
670
+ bool APIConnection::try_send_text_sensor_state(APIConnection *api, void *v_text_sensor) {
671
+ text_sensor::TextSensor *text_sensor = reinterpret_cast<text_sensor::TextSensor *>(v_text_sensor);
672
+ return APIConnection::try_send_text_sensor_state(api, text_sensor, text_sensor->state);
673
+ }
674
+ bool APIConnection::try_send_text_sensor_state(APIConnection *api, text_sensor::TextSensor *text_sensor,
675
+ std::string state) {
531
676
  TextSensorStateResponse resp{};
532
677
  resp.key = text_sensor->get_object_id_hash();
533
678
  resp.state = std::move(state);
534
679
  resp.missing_state = !text_sensor->has_state();
535
- return this->send_text_sensor_state_response(resp);
680
+ return api->send_text_sensor_state_response(resp);
536
681
  }
537
- bool APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor) {
682
+ bool APIConnection::try_send_text_sensor_info(APIConnection *api, void *v_text_sensor) {
683
+ text_sensor::TextSensor *text_sensor = reinterpret_cast<text_sensor::TextSensor *>(v_text_sensor);
538
684
  ListEntitiesTextSensorResponse msg;
539
685
  msg.key = text_sensor->get_object_id_hash();
540
686
  msg.object_id = text_sensor->get_object_id();
@@ -546,7 +692,7 @@ bool APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor)
546
692
  msg.disabled_by_default = text_sensor->is_disabled_by_default();
547
693
  msg.entity_category = static_cast<enums::EntityCategory>(text_sensor->get_entity_category());
548
694
  msg.device_class = text_sensor->get_device_class();
549
- return this->send_list_entities_text_sensor_response(msg);
695
+ return api->send_list_entities_text_sensor_response(msg);
550
696
  }
551
697
  #endif
552
698
 
@@ -555,6 +701,19 @@ bool APIConnection::send_climate_state(climate::Climate *climate) {
555
701
  if (!this->state_subscription_)
556
702
  return false;
557
703
 
704
+ if (!APIConnection::try_send_climate_state(this, climate)) {
705
+ this->deferred_message_queue_.defer(climate, try_send_climate_state);
706
+ }
707
+
708
+ return true;
709
+ }
710
+ void APIConnection::send_climate_info(climate::Climate *climate) {
711
+ if (!APIConnection::try_send_climate_info(this, climate)) {
712
+ this->deferred_message_queue_.defer(climate, try_send_climate_info);
713
+ }
714
+ }
715
+ bool APIConnection::try_send_climate_state(APIConnection *api, void *v_climate) {
716
+ climate::Climate *climate = reinterpret_cast<climate::Climate *>(v_climate);
558
717
  auto traits = climate->get_traits();
559
718
  ClimateStateResponse resp{};
560
719
  resp.key = climate->get_object_id_hash();
@@ -583,9 +742,10 @@ bool APIConnection::send_climate_state(climate::Climate *climate) {
583
742
  resp.current_humidity = climate->current_humidity;
584
743
  if (traits.get_supports_target_humidity())
585
744
  resp.target_humidity = climate->target_humidity;
586
- return this->send_climate_state_response(resp);
745
+ return api->send_climate_state_response(resp);
587
746
  }
588
- bool APIConnection::send_climate_info(climate::Climate *climate) {
747
+ bool APIConnection::try_send_climate_info(APIConnection *api, void *v_climate) {
748
+ climate::Climate *climate = reinterpret_cast<climate::Climate *>(v_climate);
589
749
  auto traits = climate->get_traits();
590
750
  ListEntitiesClimateResponse msg;
591
751
  msg.key = climate->get_object_id_hash();
@@ -626,7 +786,7 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
626
786
  msg.supported_custom_presets.push_back(custom_preset);
627
787
  for (auto swing_mode : traits.get_supported_swing_modes())
628
788
  msg.supported_swing_modes.push_back(static_cast<enums::ClimateSwingMode>(swing_mode));
629
- return this->send_list_entities_climate_response(msg);
789
+ return api->send_list_entities_climate_response(msg);
630
790
  }
631
791
  void APIConnection::climate_command(const ClimateCommandRequest &msg) {
632
792
  climate::Climate *climate = App.get_climate_by_key(msg.key);
@@ -663,13 +823,30 @@ bool APIConnection::send_number_state(number::Number *number, float state) {
663
823
  if (!this->state_subscription_)
664
824
  return false;
665
825
 
826
+ if (!APIConnection::try_send_number_state(this, number, state)) {
827
+ this->deferred_message_queue_.defer(number, try_send_number_state);
828
+ }
829
+
830
+ return true;
831
+ }
832
+ void APIConnection::send_number_info(number::Number *number) {
833
+ if (!APIConnection::try_send_number_info(this, number)) {
834
+ this->deferred_message_queue_.defer(number, try_send_number_info);
835
+ }
836
+ }
837
+ bool APIConnection::try_send_number_state(APIConnection *api, void *v_number) {
838
+ number::Number *number = reinterpret_cast<number::Number *>(v_number);
839
+ return APIConnection::try_send_number_state(api, number, number->state);
840
+ }
841
+ bool APIConnection::try_send_number_state(APIConnection *api, number::Number *number, float state) {
666
842
  NumberStateResponse resp{};
667
843
  resp.key = number->get_object_id_hash();
668
844
  resp.state = state;
669
845
  resp.missing_state = !number->has_state();
670
- return this->send_number_state_response(resp);
846
+ return api->send_number_state_response(resp);
671
847
  }
672
- bool APIConnection::send_number_info(number::Number *number) {
848
+ bool APIConnection::try_send_number_info(APIConnection *api, void *v_number) {
849
+ number::Number *number = reinterpret_cast<number::Number *>(v_number);
673
850
  ListEntitiesNumberResponse msg;
674
851
  msg.key = number->get_object_id_hash();
675
852
  msg.object_id = number->get_object_id();
@@ -687,7 +864,7 @@ bool APIConnection::send_number_info(number::Number *number) {
687
864
  msg.max_value = number->traits.get_max_value();
688
865
  msg.step = number->traits.get_step();
689
866
 
690
- return this->send_list_entities_number_response(msg);
867
+ return api->send_list_entities_number_response(msg);
691
868
  }
692
869
  void APIConnection::number_command(const NumberCommandRequest &msg) {
693
870
  number::Number *number = App.get_number_by_key(msg.key);
@@ -705,15 +882,29 @@ bool APIConnection::send_date_state(datetime::DateEntity *date) {
705
882
  if (!this->state_subscription_)
706
883
  return false;
707
884
 
885
+ if (!APIConnection::try_send_date_state(this, date)) {
886
+ this->deferred_message_queue_.defer(date, try_send_date_state);
887
+ }
888
+
889
+ return true;
890
+ }
891
+ void APIConnection::send_date_info(datetime::DateEntity *date) {
892
+ if (!APIConnection::try_send_date_info(this, date)) {
893
+ this->deferred_message_queue_.defer(date, try_send_date_info);
894
+ }
895
+ }
896
+ bool APIConnection::try_send_date_state(APIConnection *api, void *v_date) {
897
+ datetime::DateEntity *date = reinterpret_cast<datetime::DateEntity *>(v_date);
708
898
  DateStateResponse resp{};
709
899
  resp.key = date->get_object_id_hash();
710
900
  resp.missing_state = !date->has_state();
711
901
  resp.year = date->year;
712
902
  resp.month = date->month;
713
903
  resp.day = date->day;
714
- return this->send_date_state_response(resp);
904
+ return api->send_date_state_response(resp);
715
905
  }
716
- bool APIConnection::send_date_info(datetime::DateEntity *date) {
906
+ bool APIConnection::try_send_date_info(APIConnection *api, void *v_date) {
907
+ datetime::DateEntity *date = reinterpret_cast<datetime::DateEntity *>(v_date);
717
908
  ListEntitiesDateResponse msg;
718
909
  msg.key = date->get_object_id_hash();
719
910
  msg.object_id = date->get_object_id();
@@ -724,7 +915,7 @@ bool APIConnection::send_date_info(datetime::DateEntity *date) {
724
915
  msg.disabled_by_default = date->is_disabled_by_default();
725
916
  msg.entity_category = static_cast<enums::EntityCategory>(date->get_entity_category());
726
917
 
727
- return this->send_list_entities_date_response(msg);
918
+ return api->send_list_entities_date_response(msg);
728
919
  }
729
920
  void APIConnection::date_command(const DateCommandRequest &msg) {
730
921
  datetime::DateEntity *date = App.get_date_by_key(msg.key);
@@ -742,15 +933,29 @@ bool APIConnection::send_time_state(datetime::TimeEntity *time) {
742
933
  if (!this->state_subscription_)
743
934
  return false;
744
935
 
936
+ if (!APIConnection::try_send_time_state(this, time)) {
937
+ this->deferred_message_queue_.defer(time, try_send_time_state);
938
+ }
939
+
940
+ return true;
941
+ }
942
+ void APIConnection::send_time_info(datetime::TimeEntity *time) {
943
+ if (!APIConnection::try_send_time_info(this, time)) {
944
+ this->deferred_message_queue_.defer(time, try_send_time_info);
945
+ }
946
+ }
947
+ bool APIConnection::try_send_time_state(APIConnection *api, void *v_time) {
948
+ datetime::TimeEntity *time = reinterpret_cast<datetime::TimeEntity *>(v_time);
745
949
  TimeStateResponse resp{};
746
950
  resp.key = time->get_object_id_hash();
747
951
  resp.missing_state = !time->has_state();
748
952
  resp.hour = time->hour;
749
953
  resp.minute = time->minute;
750
954
  resp.second = time->second;
751
- return this->send_time_state_response(resp);
955
+ return api->send_time_state_response(resp);
752
956
  }
753
- bool APIConnection::send_time_info(datetime::TimeEntity *time) {
957
+ bool APIConnection::try_send_time_info(APIConnection *api, void *v_time) {
958
+ datetime::TimeEntity *time = reinterpret_cast<datetime::TimeEntity *>(v_time);
754
959
  ListEntitiesTimeResponse msg;
755
960
  msg.key = time->get_object_id_hash();
756
961
  msg.object_id = time->get_object_id();
@@ -761,7 +966,7 @@ bool APIConnection::send_time_info(datetime::TimeEntity *time) {
761
966
  msg.disabled_by_default = time->is_disabled_by_default();
762
967
  msg.entity_category = static_cast<enums::EntityCategory>(time->get_entity_category());
763
968
 
764
- return this->send_list_entities_time_response(msg);
969
+ return api->send_list_entities_time_response(msg);
765
970
  }
766
971
  void APIConnection::time_command(const TimeCommandRequest &msg) {
767
972
  datetime::TimeEntity *time = App.get_time_by_key(msg.key);
@@ -779,6 +984,19 @@ bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) {
779
984
  if (!this->state_subscription_)
780
985
  return false;
781
986
 
987
+ if (!APIConnection::try_send_datetime_state(this, datetime)) {
988
+ this->deferred_message_queue_.defer(datetime, try_send_datetime_state);
989
+ }
990
+
991
+ return true;
992
+ }
993
+ void APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) {
994
+ if (!APIConnection::try_send_datetime_info(this, datetime)) {
995
+ this->deferred_message_queue_.defer(datetime, try_send_datetime_info);
996
+ }
997
+ }
998
+ bool APIConnection::try_send_datetime_state(APIConnection *api, void *v_datetime) {
999
+ datetime::DateTimeEntity *datetime = reinterpret_cast<datetime::DateTimeEntity *>(v_datetime);
782
1000
  DateTimeStateResponse resp{};
783
1001
  resp.key = datetime->get_object_id_hash();
784
1002
  resp.missing_state = !datetime->has_state();
@@ -786,9 +1004,10 @@ bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) {
786
1004
  ESPTime state = datetime->state_as_esptime();
787
1005
  resp.epoch_seconds = state.timestamp;
788
1006
  }
789
- return this->send_date_time_state_response(resp);
1007
+ return api->send_date_time_state_response(resp);
790
1008
  }
791
- bool APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) {
1009
+ bool APIConnection::try_send_datetime_info(APIConnection *api, void *v_datetime) {
1010
+ datetime::DateTimeEntity *datetime = reinterpret_cast<datetime::DateTimeEntity *>(v_datetime);
792
1011
  ListEntitiesDateTimeResponse msg;
793
1012
  msg.key = datetime->get_object_id_hash();
794
1013
  msg.object_id = datetime->get_object_id();
@@ -799,7 +1018,7 @@ bool APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) {
799
1018
  msg.disabled_by_default = datetime->is_disabled_by_default();
800
1019
  msg.entity_category = static_cast<enums::EntityCategory>(datetime->get_entity_category());
801
1020
 
802
- return this->send_list_entities_date_time_response(msg);
1021
+ return api->send_list_entities_date_time_response(msg);
803
1022
  }
804
1023
  void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
805
1024
  datetime::DateTimeEntity *datetime = App.get_datetime_by_key(msg.key);
@@ -817,13 +1036,30 @@ bool APIConnection::send_text_state(text::Text *text, std::string state) {
817
1036
  if (!this->state_subscription_)
818
1037
  return false;
819
1038
 
1039
+ if (!APIConnection::try_send_text_state(this, text, std::move(state))) {
1040
+ this->deferred_message_queue_.defer(text, try_send_text_state);
1041
+ }
1042
+
1043
+ return true;
1044
+ }
1045
+ void APIConnection::send_text_info(text::Text *text) {
1046
+ if (!APIConnection::try_send_text_info(this, text)) {
1047
+ this->deferred_message_queue_.defer(text, try_send_text_info);
1048
+ }
1049
+ }
1050
+ bool APIConnection::try_send_text_state(APIConnection *api, void *v_text) {
1051
+ text::Text *text = reinterpret_cast<text::Text *>(v_text);
1052
+ return APIConnection::try_send_text_state(api, text, text->state);
1053
+ }
1054
+ bool APIConnection::try_send_text_state(APIConnection *api, text::Text *text, std::string state) {
820
1055
  TextStateResponse resp{};
821
1056
  resp.key = text->get_object_id_hash();
822
1057
  resp.state = std::move(state);
823
1058
  resp.missing_state = !text->has_state();
824
- return this->send_text_state_response(resp);
1059
+ return api->send_text_state_response(resp);
825
1060
  }
826
- bool APIConnection::send_text_info(text::Text *text) {
1061
+ bool APIConnection::try_send_text_info(APIConnection *api, void *v_text) {
1062
+ text::Text *text = reinterpret_cast<text::Text *>(v_text);
827
1063
  ListEntitiesTextResponse msg;
828
1064
  msg.key = text->get_object_id_hash();
829
1065
  msg.object_id = text->get_object_id();
@@ -837,7 +1073,7 @@ bool APIConnection::send_text_info(text::Text *text) {
837
1073
  msg.max_length = text->traits.get_max_length();
838
1074
  msg.pattern = text->traits.get_pattern();
839
1075
 
840
- return this->send_list_entities_text_response(msg);
1076
+ return api->send_list_entities_text_response(msg);
841
1077
  }
842
1078
  void APIConnection::text_command(const TextCommandRequest &msg) {
843
1079
  text::Text *text = App.get_text_by_key(msg.key);
@@ -855,13 +1091,30 @@ bool APIConnection::send_select_state(select::Select *select, std::string state)
855
1091
  if (!this->state_subscription_)
856
1092
  return false;
857
1093
 
1094
+ if (!APIConnection::try_send_select_state(this, select, std::move(state))) {
1095
+ this->deferred_message_queue_.defer(select, try_send_select_state);
1096
+ }
1097
+
1098
+ return true;
1099
+ }
1100
+ void APIConnection::send_select_info(select::Select *select) {
1101
+ if (!APIConnection::try_send_select_info(this, select)) {
1102
+ this->deferred_message_queue_.defer(select, try_send_select_info);
1103
+ }
1104
+ }
1105
+ bool APIConnection::try_send_select_state(APIConnection *api, void *v_select) {
1106
+ select::Select *select = reinterpret_cast<select::Select *>(v_select);
1107
+ return APIConnection::try_send_select_state(api, select, select->state);
1108
+ }
1109
+ bool APIConnection::try_send_select_state(APIConnection *api, select::Select *select, std::string state) {
858
1110
  SelectStateResponse resp{};
859
1111
  resp.key = select->get_object_id_hash();
860
1112
  resp.state = std::move(state);
861
1113
  resp.missing_state = !select->has_state();
862
- return this->send_select_state_response(resp);
1114
+ return api->send_select_state_response(resp);
863
1115
  }
864
- bool APIConnection::send_select_info(select::Select *select) {
1116
+ bool APIConnection::try_send_select_info(APIConnection *api, void *v_select) {
1117
+ select::Select *select = reinterpret_cast<select::Select *>(v_select);
865
1118
  ListEntitiesSelectResponse msg;
866
1119
  msg.key = select->get_object_id_hash();
867
1120
  msg.object_id = select->get_object_id();
@@ -875,7 +1128,7 @@ bool APIConnection::send_select_info(select::Select *select) {
875
1128
  for (const auto &option : select->traits.get_options())
876
1129
  msg.options.push_back(option);
877
1130
 
878
- return this->send_list_entities_select_response(msg);
1131
+ return api->send_list_entities_select_response(msg);
879
1132
  }
880
1133
  void APIConnection::select_command(const SelectCommandRequest &msg) {
881
1134
  select::Select *select = App.get_select_by_key(msg.key);
@@ -889,7 +1142,13 @@ void APIConnection::select_command(const SelectCommandRequest &msg) {
889
1142
  #endif
890
1143
 
891
1144
  #ifdef USE_BUTTON
892
- bool APIConnection::send_button_info(button::Button *button) {
1145
+ void APIConnection::send_button_info(button::Button *button) {
1146
+ if (!APIConnection::try_send_button_info(this, button)) {
1147
+ this->deferred_message_queue_.defer(button, try_send_button_info);
1148
+ }
1149
+ }
1150
+ bool APIConnection::try_send_button_info(APIConnection *api, void *v_button) {
1151
+ button::Button *button = reinterpret_cast<button::Button *>(v_button);
893
1152
  ListEntitiesButtonResponse msg;
894
1153
  msg.key = button->get_object_id_hash();
895
1154
  msg.object_id = button->get_object_id();
@@ -900,7 +1159,7 @@ bool APIConnection::send_button_info(button::Button *button) {
900
1159
  msg.disabled_by_default = button->is_disabled_by_default();
901
1160
  msg.entity_category = static_cast<enums::EntityCategory>(button->get_entity_category());
902
1161
  msg.device_class = button->get_device_class();
903
- return this->send_list_entities_button_response(msg);
1162
+ return api->send_list_entities_button_response(msg);
904
1163
  }
905
1164
  void APIConnection::button_command(const ButtonCommandRequest &msg) {
906
1165
  button::Button *button = App.get_button_by_key(msg.key);
@@ -916,12 +1175,29 @@ bool APIConnection::send_lock_state(lock::Lock *a_lock, lock::LockState state) {
916
1175
  if (!this->state_subscription_)
917
1176
  return false;
918
1177
 
1178
+ if (!APIConnection::try_send_lock_state(this, a_lock, state)) {
1179
+ this->deferred_message_queue_.defer(a_lock, try_send_lock_state);
1180
+ }
1181
+
1182
+ return true;
1183
+ }
1184
+ void APIConnection::send_lock_info(lock::Lock *a_lock) {
1185
+ if (!APIConnection::try_send_lock_info(this, a_lock)) {
1186
+ this->deferred_message_queue_.defer(a_lock, try_send_lock_info);
1187
+ }
1188
+ }
1189
+ bool APIConnection::try_send_lock_state(APIConnection *api, void *v_a_lock) {
1190
+ lock::Lock *a_lock = reinterpret_cast<lock::Lock *>(v_a_lock);
1191
+ return APIConnection::try_send_lock_state(api, a_lock, a_lock->state);
1192
+ }
1193
+ bool APIConnection::try_send_lock_state(APIConnection *api, lock::Lock *a_lock, lock::LockState state) {
919
1194
  LockStateResponse resp{};
920
1195
  resp.key = a_lock->get_object_id_hash();
921
1196
  resp.state = static_cast<enums::LockState>(state);
922
- return this->send_lock_state_response(resp);
1197
+ return api->send_lock_state_response(resp);
923
1198
  }
924
- bool APIConnection::send_lock_info(lock::Lock *a_lock) {
1199
+ bool APIConnection::try_send_lock_info(APIConnection *api, void *v_a_lock) {
1200
+ lock::Lock *a_lock = reinterpret_cast<lock::Lock *>(v_a_lock);
925
1201
  ListEntitiesLockResponse msg;
926
1202
  msg.key = a_lock->get_object_id_hash();
927
1203
  msg.object_id = a_lock->get_object_id();
@@ -934,7 +1210,7 @@ bool APIConnection::send_lock_info(lock::Lock *a_lock) {
934
1210
  msg.entity_category = static_cast<enums::EntityCategory>(a_lock->get_entity_category());
935
1211
  msg.supports_open = a_lock->traits.get_supports_open();
936
1212
  msg.requires_code = a_lock->traits.get_requires_code();
937
- return this->send_list_entities_lock_response(msg);
1213
+ return api->send_list_entities_lock_response(msg);
938
1214
  }
939
1215
  void APIConnection::lock_command(const LockCommandRequest &msg) {
940
1216
  lock::Lock *a_lock = App.get_lock_by_key(msg.key);
@@ -960,13 +1236,27 @@ bool APIConnection::send_valve_state(valve::Valve *valve) {
960
1236
  if (!this->state_subscription_)
961
1237
  return false;
962
1238
 
1239
+ if (!APIConnection::try_send_valve_state(this, valve)) {
1240
+ this->deferred_message_queue_.defer(valve, try_send_valve_state);
1241
+ }
1242
+
1243
+ return true;
1244
+ }
1245
+ void APIConnection::send_valve_info(valve::Valve *valve) {
1246
+ if (!APIConnection::try_send_valve_info(this, valve)) {
1247
+ this->deferred_message_queue_.defer(valve, try_send_valve_info);
1248
+ }
1249
+ }
1250
+ bool APIConnection::try_send_valve_state(APIConnection *api, void *v_valve) {
1251
+ valve::Valve *valve = reinterpret_cast<valve::Valve *>(v_valve);
963
1252
  ValveStateResponse resp{};
964
1253
  resp.key = valve->get_object_id_hash();
965
1254
  resp.position = valve->position;
966
1255
  resp.current_operation = static_cast<enums::ValveOperation>(valve->current_operation);
967
- return this->send_valve_state_response(resp);
1256
+ return api->send_valve_state_response(resp);
968
1257
  }
969
- bool APIConnection::send_valve_info(valve::Valve *valve) {
1258
+ bool APIConnection::try_send_valve_info(APIConnection *api, void *v_valve) {
1259
+ valve::Valve *valve = reinterpret_cast<valve::Valve *>(v_valve);
970
1260
  auto traits = valve->get_traits();
971
1261
  ListEntitiesValveResponse msg;
972
1262
  msg.key = valve->get_object_id_hash();
@@ -981,7 +1271,7 @@ bool APIConnection::send_valve_info(valve::Valve *valve) {
981
1271
  msg.assumed_state = traits.get_is_assumed_state();
982
1272
  msg.supports_position = traits.get_supports_position();
983
1273
  msg.supports_stop = traits.get_supports_stop();
984
- return this->send_list_entities_valve_response(msg);
1274
+ return api->send_list_entities_valve_response(msg);
985
1275
  }
986
1276
  void APIConnection::valve_command(const ValveCommandRequest &msg) {
987
1277
  valve::Valve *valve = App.get_valve_by_key(msg.key);
@@ -1002,6 +1292,19 @@ bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_pla
1002
1292
  if (!this->state_subscription_)
1003
1293
  return false;
1004
1294
 
1295
+ if (!APIConnection::try_send_media_player_state(this, media_player)) {
1296
+ this->deferred_message_queue_.defer(media_player, try_send_media_player_state);
1297
+ }
1298
+
1299
+ return true;
1300
+ }
1301
+ void APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) {
1302
+ if (!APIConnection::try_send_media_player_info(this, media_player)) {
1303
+ this->deferred_message_queue_.defer(media_player, try_send_media_player_info);
1304
+ }
1305
+ }
1306
+ bool APIConnection::try_send_media_player_state(APIConnection *api, void *v_media_player) {
1307
+ media_player::MediaPlayer *media_player = reinterpret_cast<media_player::MediaPlayer *>(v_media_player);
1005
1308
  MediaPlayerStateResponse resp{};
1006
1309
  resp.key = media_player->get_object_id_hash();
1007
1310
 
@@ -1011,9 +1314,10 @@ bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_pla
1011
1314
  resp.state = static_cast<enums::MediaPlayerState>(report_state);
1012
1315
  resp.volume = media_player->volume;
1013
1316
  resp.muted = media_player->is_muted();
1014
- return this->send_media_player_state_response(resp);
1317
+ return api->send_media_player_state_response(resp);
1015
1318
  }
1016
- bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) {
1319
+ bool APIConnection::try_send_media_player_info(APIConnection *api, void *v_media_player) {
1320
+ media_player::MediaPlayer *media_player = reinterpret_cast<media_player::MediaPlayer *>(v_media_player);
1017
1321
  ListEntitiesMediaPlayerResponse msg;
1018
1322
  msg.key = media_player->get_object_id_hash();
1019
1323
  msg.object_id = media_player->get_object_id();
@@ -1037,7 +1341,7 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play
1037
1341
  msg.supported_formats.push_back(media_format);
1038
1342
  }
1039
1343
 
1040
- return this->send_list_entities_media_player_response(msg);
1344
+ return api->send_list_entities_media_player_response(msg);
1041
1345
  }
1042
1346
  void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
1043
1347
  media_player::MediaPlayer *media_player = App.get_media_player_by_key(msg.key);
@@ -1062,7 +1366,7 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
1062
1366
  #endif
1063
1367
 
1064
1368
  #ifdef USE_ESP32_CAMERA
1065
- void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
1369
+ void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
1066
1370
  if (!this->state_subscription_)
1067
1371
  return;
1068
1372
  if (this->image_reader_.available())
@@ -1071,7 +1375,13 @@ void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage>
1071
1375
  image->was_requested_by(esphome::esp32_camera::IDLE))
1072
1376
  this->image_reader_.set_image(std::move(image));
1073
1377
  }
1074
- bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
1378
+ void APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
1379
+ if (!APIConnection::try_send_camera_info(this, camera)) {
1380
+ this->deferred_message_queue_.defer(camera, try_send_camera_info);
1381
+ }
1382
+ }
1383
+ bool APIConnection::try_send_camera_info(APIConnection *api, void *v_camera) {
1384
+ esp32_camera::ESP32Camera *camera = reinterpret_cast<esp32_camera::ESP32Camera *>(v_camera);
1075
1385
  ListEntitiesCameraResponse msg;
1076
1386
  msg.key = camera->get_object_id_hash();
1077
1387
  msg.object_id = camera->get_object_id();
@@ -1081,7 +1391,7 @@ bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
1081
1391
  msg.disabled_by_default = camera->is_disabled_by_default();
1082
1392
  msg.icon = camera->get_icon();
1083
1393
  msg.entity_category = static_cast<enums::EntityCategory>(camera->get_entity_category());
1084
- return this->send_list_entities_camera_response(msg);
1394
+ return api->send_list_entities_camera_response(msg);
1085
1395
  }
1086
1396
  void APIConnection::camera_image(const CameraImageRequest &msg) {
1087
1397
  if (esp32_camera::global_esp32_camera == nullptr)
@@ -1268,12 +1578,28 @@ bool APIConnection::send_alarm_control_panel_state(alarm_control_panel::AlarmCon
1268
1578
  if (!this->state_subscription_)
1269
1579
  return false;
1270
1580
 
1581
+ if (!APIConnection::try_send_alarm_control_panel_state(this, a_alarm_control_panel)) {
1582
+ this->deferred_message_queue_.defer(a_alarm_control_panel, try_send_alarm_control_panel_state);
1583
+ }
1584
+
1585
+ return true;
1586
+ }
1587
+ void APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1588
+ if (!APIConnection::try_send_alarm_control_panel_info(this, a_alarm_control_panel)) {
1589
+ this->deferred_message_queue_.defer(a_alarm_control_panel, try_send_alarm_control_panel_info);
1590
+ }
1591
+ }
1592
+ bool APIConnection::try_send_alarm_control_panel_state(APIConnection *api, void *v_a_alarm_control_panel) {
1593
+ alarm_control_panel::AlarmControlPanel *a_alarm_control_panel =
1594
+ reinterpret_cast<alarm_control_panel::AlarmControlPanel *>(v_a_alarm_control_panel);
1271
1595
  AlarmControlPanelStateResponse resp{};
1272
1596
  resp.key = a_alarm_control_panel->get_object_id_hash();
1273
1597
  resp.state = static_cast<enums::AlarmControlPanelState>(a_alarm_control_panel->get_state());
1274
- return this->send_alarm_control_panel_state_response(resp);
1598
+ return api->send_alarm_control_panel_state_response(resp);
1275
1599
  }
1276
- bool APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1600
+ bool APIConnection::try_send_alarm_control_panel_info(APIConnection *api, void *v_a_alarm_control_panel) {
1601
+ alarm_control_panel::AlarmControlPanel *a_alarm_control_panel =
1602
+ reinterpret_cast<alarm_control_panel::AlarmControlPanel *>(v_a_alarm_control_panel);
1277
1603
  ListEntitiesAlarmControlPanelResponse msg;
1278
1604
  msg.key = a_alarm_control_panel->get_object_id_hash();
1279
1605
  msg.object_id = a_alarm_control_panel->get_object_id();
@@ -1285,7 +1611,7 @@ bool APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmCont
1285
1611
  msg.supported_features = a_alarm_control_panel->get_supported_features();
1286
1612
  msg.requires_code = a_alarm_control_panel->get_requires_code();
1287
1613
  msg.requires_code_to_arm = a_alarm_control_panel->get_requires_code_to_arm();
1288
- return this->send_list_entities_alarm_control_panel_response(msg);
1614
+ return api->send_list_entities_alarm_control_panel_response(msg);
1289
1615
  }
1290
1616
  void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) {
1291
1617
  alarm_control_panel::AlarmControlPanel *a_alarm_control_panel = App.get_alarm_control_panel_by_key(msg.key);
@@ -1322,13 +1648,28 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe
1322
1648
  #endif
1323
1649
 
1324
1650
  #ifdef USE_EVENT
1325
- bool APIConnection::send_event(event::Event *event, std::string event_type) {
1651
+ void APIConnection::send_event(event::Event *event, std::string event_type) {
1652
+ if (!APIConnection::try_send_event(this, event, std::move(event_type))) {
1653
+ this->deferred_message_queue_.defer(event, try_send_event);
1654
+ }
1655
+ }
1656
+ void APIConnection::send_event_info(event::Event *event) {
1657
+ if (!APIConnection::try_send_event_info(this, event)) {
1658
+ this->deferred_message_queue_.defer(event, try_send_event_info);
1659
+ }
1660
+ }
1661
+ bool APIConnection::try_send_event(APIConnection *api, void *v_event) {
1662
+ event::Event *event = reinterpret_cast<event::Event *>(v_event);
1663
+ return APIConnection::try_send_event(api, event, *(event->last_event_type));
1664
+ }
1665
+ bool APIConnection::try_send_event(APIConnection *api, event::Event *event, std::string event_type) {
1326
1666
  EventResponse resp{};
1327
1667
  resp.key = event->get_object_id_hash();
1328
1668
  resp.event_type = std::move(event_type);
1329
- return this->send_event_response(resp);
1669
+ return api->send_event_response(resp);
1330
1670
  }
1331
- bool APIConnection::send_event_info(event::Event *event) {
1671
+ bool APIConnection::try_send_event_info(APIConnection *api, void *v_event) {
1672
+ event::Event *event = reinterpret_cast<event::Event *>(v_event);
1332
1673
  ListEntitiesEventResponse msg;
1333
1674
  msg.key = event->get_object_id_hash();
1334
1675
  msg.object_id = event->get_object_id();
@@ -1341,7 +1682,7 @@ bool APIConnection::send_event_info(event::Event *event) {
1341
1682
  msg.device_class = event->get_device_class();
1342
1683
  for (const auto &event_type : event->get_event_types())
1343
1684
  msg.event_types.push_back(event_type);
1344
- return this->send_list_entities_event_response(msg);
1685
+ return api->send_list_entities_event_response(msg);
1345
1686
  }
1346
1687
  #endif
1347
1688
 
@@ -1350,6 +1691,19 @@ bool APIConnection::send_update_state(update::UpdateEntity *update) {
1350
1691
  if (!this->state_subscription_)
1351
1692
  return false;
1352
1693
 
1694
+ if (!APIConnection::try_send_update_state(this, update)) {
1695
+ this->deferred_message_queue_.defer(update, try_send_update_state);
1696
+ }
1697
+
1698
+ return true;
1699
+ }
1700
+ void APIConnection::send_update_info(update::UpdateEntity *update) {
1701
+ if (!APIConnection::try_send_update_info(this, update)) {
1702
+ this->deferred_message_queue_.defer(update, try_send_update_info);
1703
+ }
1704
+ }
1705
+ bool APIConnection::try_send_update_state(APIConnection *api, void *v_update) {
1706
+ update::UpdateEntity *update = reinterpret_cast<update::UpdateEntity *>(v_update);
1353
1707
  UpdateStateResponse resp{};
1354
1708
  resp.key = update->get_object_id_hash();
1355
1709
  resp.missing_state = !update->has_state();
@@ -1366,9 +1720,10 @@ bool APIConnection::send_update_state(update::UpdateEntity *update) {
1366
1720
  resp.release_url = update->update_info.release_url;
1367
1721
  }
1368
1722
 
1369
- return this->send_update_state_response(resp);
1723
+ return api->send_update_state_response(resp);
1370
1724
  }
1371
- bool APIConnection::send_update_info(update::UpdateEntity *update) {
1725
+ bool APIConnection::try_send_update_info(APIConnection *api, void *v_update) {
1726
+ update::UpdateEntity *update = reinterpret_cast<update::UpdateEntity *>(v_update);
1372
1727
  ListEntitiesUpdateResponse msg;
1373
1728
  msg.key = update->get_object_id_hash();
1374
1729
  msg.object_id = update->get_object_id();
@@ -1379,7 +1734,7 @@ bool APIConnection::send_update_info(update::UpdateEntity *update) {
1379
1734
  msg.disabled_by_default = update->is_disabled_by_default();
1380
1735
  msg.entity_category = static_cast<enums::EntityCategory>(update->get_entity_category());
1381
1736
  msg.device_class = update->get_device_class();
1382
- return this->send_list_entities_update_response(msg);
1737
+ return api->send_list_entities_update_response(msg);
1383
1738
  }
1384
1739
  void APIConnection::update_command(const UpdateCommandRequest &msg) {
1385
1740
  update::UpdateEntity *update = App.get_update_by_key(msg.key);
@@ -1403,7 +1758,7 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) {
1403
1758
  }
1404
1759
  #endif
1405
1760
 
1406
- bool APIConnection::send_log_message(int level, const char *tag, const char *line) {
1761
+ bool APIConnection::try_send_log_message(int level, const char *tag, const char *line) {
1407
1762
  if (this->log_subscription_ < level)
1408
1763
  return false;
1409
1764
 
@@ -1488,6 +1843,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
1488
1843
  #ifdef USE_BLUETOOTH_PROXY
1489
1844
  resp.legacy_bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->get_legacy_version();
1490
1845
  resp.bluetooth_proxy_feature_flags = bluetooth_proxy::global_bluetooth_proxy->get_feature_flags();
1846
+ resp.bluetooth_mac_address = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_mac_address_pretty();
1491
1847
  #endif
1492
1848
  #ifdef USE_VOICE_ASSISTANT
1493
1849
  resp.legacy_voice_assistant_version = voice_assistant::global_voice_assistant->get_legacy_version();