esphome 2025.5.0b2__py3-none-any.whl → 2025.5.0b4__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 (104) hide show
  1. esphome/__main__.py +16 -14
  2. esphome/components/api/api_connection.cpp +339 -652
  3. esphome/components/api/api_connection.h +251 -57
  4. esphome/components/api/api_frame_helper.cpp +136 -49
  5. esphome/components/api/api_frame_helper.h +49 -6
  6. esphome/components/api/proto.h +48 -8
  7. esphome/components/ballu/climate.py +1 -1
  8. esphome/components/bedjet/bedjet_hub.cpp +1 -0
  9. esphome/components/binary_sensor/binary_sensor.cpp +10 -6
  10. esphome/components/binary_sensor/binary_sensor.h +1 -1
  11. esphome/components/binary_sensor/filter.cpp +21 -21
  12. esphome/components/binary_sensor/filter.h +10 -10
  13. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -1
  14. esphome/components/ccs811/sensor.py +9 -6
  15. esphome/components/climate_ir/__init__.py +3 -3
  16. esphome/components/climate_ir_lg/climate.py +1 -1
  17. esphome/components/coolix/climate.py +1 -1
  18. esphome/components/cse7766/cse7766.cpp +2 -1
  19. esphome/components/current_based/current_based_cover.cpp +2 -1
  20. esphome/components/daikin/climate.py +1 -1
  21. esphome/components/daikin_arc/climate.py +1 -1
  22. esphome/components/daikin_brc/climate.py +1 -1
  23. esphome/components/daly_bms/daly_bms.cpp +2 -1
  24. esphome/components/debug/debug_component.cpp +1 -1
  25. esphome/components/delonghi/climate.py +1 -1
  26. esphome/components/dps310/sensor.py +6 -6
  27. esphome/components/ee895/sensor.py +9 -9
  28. esphome/components/emmeti/climate.py +1 -1
  29. esphome/components/endstop/endstop_cover.cpp +2 -1
  30. esphome/components/ens160_base/__init__.py +12 -9
  31. esphome/components/esp32_ble/ble_advertising.cpp +2 -1
  32. esphome/components/esp32_camera/__init__.py +1 -1
  33. esphome/components/esp32_camera/esp32_camera.cpp +2 -10
  34. esphome/components/esp32_camera/esp32_camera.h +1 -1
  35. esphome/components/esp32_improv/esp32_improv_component.cpp +1 -1
  36. esphome/components/esp32_touch/esp32_touch.cpp +1 -1
  37. esphome/components/ethernet/ethernet_component.cpp +1 -1
  38. esphome/components/feedback/feedback_cover.cpp +2 -1
  39. esphome/components/fujitsu_general/climate.py +1 -1
  40. esphome/components/gcja5/gcja5.cpp +2 -1
  41. esphome/components/gps/__init__.py +37 -16
  42. esphome/components/gps/gps.cpp +33 -17
  43. esphome/components/gps/gps.h +16 -15
  44. esphome/components/gree/climate.py +1 -1
  45. esphome/components/growatt_solar/growatt_solar.cpp +2 -1
  46. esphome/components/heatpumpir/climate.py +1 -1
  47. esphome/components/hitachi_ac344/climate.py +1 -1
  48. esphome/components/hitachi_ac424/climate.py +1 -1
  49. esphome/components/hte501/sensor.py +6 -6
  50. esphome/components/hyt271/sensor.py +6 -6
  51. esphome/components/kuntze/kuntze.cpp +2 -1
  52. esphome/components/logger/__init__.py +1 -0
  53. esphome/components/logger/logger.cpp +53 -32
  54. esphome/components/logger/logger.h +55 -5
  55. esphome/components/matrix_keypad/matrix_keypad.cpp +2 -1
  56. esphome/components/max7219digit/max7219digit.cpp +2 -1
  57. esphome/components/mhz19/sensor.py +11 -7
  58. esphome/components/midea_ir/climate.py +1 -1
  59. esphome/components/mitsubishi/climate.py +1 -1
  60. esphome/components/modbus/modbus.cpp +2 -1
  61. esphome/components/mqtt/mqtt_client.cpp +1 -1
  62. esphome/components/ms5611/sensor.py +6 -6
  63. esphome/components/ms8607/sensor.py +3 -3
  64. esphome/components/noblex/climate.py +1 -1
  65. esphome/components/pmsx003/pmsx003.cpp +2 -1
  66. esphome/components/pzem004t/pzem004t.cpp +2 -1
  67. esphome/components/rf_bridge/rf_bridge.cpp +2 -1
  68. esphome/components/sds011/sds011.cpp +2 -1
  69. esphome/components/sen5x/sen5x.cpp +55 -36
  70. esphome/components/senseair/sensor.py +3 -3
  71. esphome/components/sgp30/sensor.py +14 -16
  72. esphome/components/shtcx/sensor.py +6 -6
  73. esphome/components/slow_pwm/slow_pwm_output.cpp +2 -1
  74. esphome/components/sprinkler/sprinkler.cpp +6 -5
  75. esphome/components/t6615/sensor.py +3 -3
  76. esphome/components/t6615/t6615.cpp +2 -1
  77. esphome/components/tcl112/climate.py +1 -1
  78. esphome/components/time_based/time_based_cover.cpp +2 -1
  79. esphome/components/toshiba/climate.py +1 -1
  80. esphome/components/uart/switch/uart_switch.cpp +2 -1
  81. esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +2 -1
  82. esphome/components/uponor_smatrix/uponor_smatrix.cpp +2 -1
  83. esphome/components/weikai/weikai.cpp +0 -52
  84. esphome/components/whirlpool/climate.py +1 -1
  85. esphome/components/whynter/climate.py +1 -1
  86. esphome/components/zhlt01/climate.py +1 -1
  87. esphome/config.py +13 -13
  88. esphome/const.py +1 -1
  89. esphome/core/application.cpp +26 -10
  90. esphome/core/application.h +5 -1
  91. esphome/core/component.cpp +10 -5
  92. esphome/core/component.h +5 -1
  93. esphome/core/doxygen.h +13 -0
  94. esphome/core/scheduler.cpp +4 -1
  95. esphome/log.py +15 -19
  96. esphome/mqtt.py +2 -2
  97. esphome/voluptuous_schema.py +3 -1
  98. esphome/wizard.py +45 -35
  99. {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b4.dist-info}/METADATA +1 -1
  100. {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b4.dist-info}/RECORD +104 -103
  101. {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b4.dist-info}/WHEEL +0 -0
  102. {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b4.dist-info}/entry_points.txt +0 -0
  103. {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b4.dist-info}/licenses/LICENSE +0 -0
  104. {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b4.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,7 @@
8
8
  #include "esphome/core/hal.h"
9
9
  #include "esphome/core/log.h"
10
10
  #include "esphome/core/version.h"
11
+ #include "esphome/core/application.h"
11
12
 
12
13
  #ifdef USE_DEEP_SLEEP
13
14
  #include "esphome/components/deep_sleep/deep_sleep_component.h"
@@ -29,7 +30,7 @@ static const char *const TAG = "api.connection";
29
30
  static const int ESP32_CAMERA_STOP_STREAM = 5000;
30
31
 
31
32
  // 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
+ void DeferredMessageQueue::dmq_push_back_with_dedup_(void *source, send_message_t send_message) {
33
34
  DeferredMessage item(source, send_message);
34
35
 
35
36
  auto iter = std::find_if(this->deferred_queue_.begin(), this->deferred_queue_.end(),
@@ -45,7 +46,7 @@ void DeferredMessageQueue::dmq_push_back_with_dedup_(void *source, send_message_
45
46
  void DeferredMessageQueue::process_queue() {
46
47
  while (!deferred_queue_.empty()) {
47
48
  DeferredMessage &de = deferred_queue_.front();
48
- if (de.send_message_(this->api_connection_, de.source_)) {
49
+ if ((this->api_connection_->*(de.send_message_))(de.source_)) {
49
50
  // O(n) but memory efficiency is more important than speed here which is why std::vector was chosen
50
51
  deferred_queue_.erase(deferred_queue_.begin());
51
52
  } else {
@@ -54,7 +55,7 @@ void DeferredMessageQueue::process_queue() {
54
55
  }
55
56
  }
56
57
 
57
- void DeferredMessageQueue::defer(void *source, send_message_t *send_message) {
58
+ void DeferredMessageQueue::defer(void *source, send_message_t send_message) {
58
59
  this->dmq_push_back_with_dedup_(source, send_message);
59
60
  }
60
61
 
@@ -78,7 +79,11 @@ APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *pa
78
79
  #endif
79
80
  }
80
81
  void APIConnection::start() {
81
- this->last_traffic_ = millis();
82
+ this->last_traffic_ = App.get_loop_component_start_time();
83
+
84
+ // Set next_ping_retry_ to prevent immediate ping
85
+ // This ensures the first ping happens after the keepalive period
86
+ this->next_ping_retry_ = this->last_traffic_ + KEEPALIVE_TIMEOUT_MS;
82
87
 
83
88
  APIError err = this->helper_->init();
84
89
  if (err != APIError::OK) {
@@ -146,31 +151,32 @@ void APIConnection::loop() {
146
151
  }
147
152
  return;
148
153
  } else {
149
- this->last_traffic_ = millis();
154
+ this->last_traffic_ = App.get_loop_component_start_time();
150
155
  // read a packet
151
156
  this->read_message(buffer.data_len, buffer.type, &buffer.container[buffer.data_offset]);
152
157
  if (this->remove_)
153
158
  return;
154
159
  }
155
160
 
156
- this->deferred_message_queue_.process_queue();
161
+ if (!this->deferred_message_queue_.empty() && this->helper_->can_write_without_blocking()) {
162
+ this->deferred_message_queue_.process_queue();
163
+ }
157
164
 
158
165
  if (!this->list_entities_iterator_.completed())
159
166
  this->list_entities_iterator_.advance();
160
167
  if (!this->initial_state_iterator_.completed() && this->list_entities_iterator_.completed())
161
168
  this->initial_state_iterator_.advance();
162
169
 
163
- static uint32_t keepalive = 60000;
164
170
  static uint8_t max_ping_retries = 60;
165
171
  static uint16_t ping_retry_interval = 1000;
166
- const uint32_t now = millis();
172
+ const uint32_t now = App.get_loop_component_start_time();
167
173
  if (this->sent_ping_) {
168
174
  // Disconnect if not responded within 2.5*keepalive
169
- if (now - this->last_traffic_ > (keepalive * 5) / 2) {
175
+ if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) {
170
176
  on_fatal_error();
171
177
  ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_combined_info_.c_str());
172
178
  }
173
- } else if (now - this->last_traffic_ > keepalive && now > this->next_ping_retry_) {
179
+ } else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) {
174
180
  ESP_LOGVV(TAG, "Sending keepalive PING...");
175
181
  this->sent_ping_ = this->send_ping_request(PingRequest());
176
182
  if (!this->sent_ping_) {
@@ -267,96 +273,65 @@ void APIConnection::on_disconnect_response(const DisconnectResponse &value) {
267
273
 
268
274
  #ifdef USE_BINARY_SENSOR
269
275
  bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor, bool state) {
270
- if (!this->state_subscription_)
271
- return false;
272
-
273
- if (!APIConnection::try_send_binary_sensor_state(this, binary_sensor, state)) {
274
- this->deferred_message_queue_.defer(binary_sensor, try_send_binary_sensor_state);
275
- }
276
-
277
- return true;
276
+ return this->send_state_with_value_(binary_sensor, &APIConnection::try_send_binary_sensor_state_,
277
+ &APIConnection::try_send_binary_sensor_state_, state);
278
278
  }
279
279
  void APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor) {
280
- if (!APIConnection::try_send_binary_sensor_info(this, binary_sensor)) {
281
- this->deferred_message_queue_.defer(binary_sensor, try_send_binary_sensor_info);
282
- }
280
+ this->send_info_(static_cast<EntityBase *>(binary_sensor),
281
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_binary_sensor_info_));
283
282
  }
284
- bool APIConnection::try_send_binary_sensor_state(APIConnection *api, void *v_binary_sensor) {
285
- binary_sensor::BinarySensor *binary_sensor = reinterpret_cast<binary_sensor::BinarySensor *>(v_binary_sensor);
286
- return APIConnection::try_send_binary_sensor_state(api, binary_sensor, binary_sensor->state);
283
+ bool APIConnection::try_send_binary_sensor_state_(binary_sensor::BinarySensor *binary_sensor) {
284
+ return this->try_send_binary_sensor_state_(binary_sensor, binary_sensor->state);
287
285
  }
288
- bool APIConnection::try_send_binary_sensor_state(APIConnection *api, binary_sensor::BinarySensor *binary_sensor,
289
- bool state) {
290
- BinarySensorStateResponse resp;
291
- resp.key = binary_sensor->get_object_id_hash();
292
- resp.state = state;
293
- resp.missing_state = !binary_sensor->has_state();
294
- return api->send_binary_sensor_state_response(resp);
286
+ bool APIConnection::try_send_binary_sensor_state_(binary_sensor::BinarySensor *binary_sensor, bool state) {
287
+ BinarySensorStateResponse msg;
288
+ msg.state = state;
289
+ msg.missing_state = !binary_sensor->has_state();
290
+ msg.key = binary_sensor->get_object_id_hash();
291
+ return this->send_binary_sensor_state_response(msg);
295
292
  }
296
- bool APIConnection::try_send_binary_sensor_info(APIConnection *api, void *v_binary_sensor) {
297
- binary_sensor::BinarySensor *binary_sensor = reinterpret_cast<binary_sensor::BinarySensor *>(v_binary_sensor);
293
+ bool APIConnection::try_send_binary_sensor_info_(binary_sensor::BinarySensor *binary_sensor) {
298
294
  ListEntitiesBinarySensorResponse msg;
299
- msg.object_id = binary_sensor->get_object_id();
300
- msg.key = binary_sensor->get_object_id_hash();
301
- if (binary_sensor->has_own_name())
302
- msg.name = binary_sensor->get_name();
303
- msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor);
304
295
  msg.device_class = binary_sensor->get_device_class();
305
296
  msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor();
306
- msg.disabled_by_default = binary_sensor->is_disabled_by_default();
307
- msg.icon = binary_sensor->get_icon();
308
- msg.entity_category = static_cast<enums::EntityCategory>(binary_sensor->get_entity_category());
309
- return api->send_list_entities_binary_sensor_response(msg);
297
+ msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor);
298
+ return this->try_send_entity_info_(static_cast<EntityBase *>(binary_sensor), msg,
299
+ &APIConnection::send_list_entities_binary_sensor_response);
310
300
  }
311
301
  #endif
312
302
 
313
303
  #ifdef USE_COVER
314
304
  bool APIConnection::send_cover_state(cover::Cover *cover) {
315
- if (!this->state_subscription_)
316
- return false;
317
-
318
- if (!APIConnection::try_send_cover_state(this, cover)) {
319
- this->deferred_message_queue_.defer(cover, try_send_cover_state);
320
- }
321
-
322
- return true;
305
+ return this->send_state_(static_cast<EntityBase *>(cover),
306
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_cover_state_));
323
307
  }
324
308
  void APIConnection::send_cover_info(cover::Cover *cover) {
325
- if (!APIConnection::try_send_cover_info(this, cover)) {
326
- this->deferred_message_queue_.defer(cover, try_send_cover_info);
327
- }
309
+ this->send_info_(static_cast<EntityBase *>(cover),
310
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_cover_info_));
328
311
  }
329
- bool APIConnection::try_send_cover_state(APIConnection *api, void *v_cover) {
330
- cover::Cover *cover = reinterpret_cast<cover::Cover *>(v_cover);
312
+ bool APIConnection::try_send_cover_state_(cover::Cover *cover) {
313
+ CoverStateResponse msg;
331
314
  auto traits = cover->get_traits();
332
- CoverStateResponse resp{};
333
- resp.key = cover->get_object_id_hash();
334
- resp.legacy_state =
315
+ msg.legacy_state =
335
316
  (cover->position == cover::COVER_OPEN) ? enums::LEGACY_COVER_STATE_OPEN : enums::LEGACY_COVER_STATE_CLOSED;
336
- resp.position = cover->position;
317
+ msg.position = cover->position;
337
318
  if (traits.get_supports_tilt())
338
- resp.tilt = cover->tilt;
339
- resp.current_operation = static_cast<enums::CoverOperation>(cover->current_operation);
340
- return api->send_cover_state_response(resp);
319
+ msg.tilt = cover->tilt;
320
+ msg.current_operation = static_cast<enums::CoverOperation>(cover->current_operation);
321
+ msg.key = cover->get_object_id_hash();
322
+ return this->send_cover_state_response(msg);
341
323
  }
342
- bool APIConnection::try_send_cover_info(APIConnection *api, void *v_cover) {
343
- cover::Cover *cover = reinterpret_cast<cover::Cover *>(v_cover);
344
- auto traits = cover->get_traits();
324
+ bool APIConnection::try_send_cover_info_(cover::Cover *cover) {
345
325
  ListEntitiesCoverResponse msg;
346
- msg.key = cover->get_object_id_hash();
347
- msg.object_id = cover->get_object_id();
348
- if (cover->has_own_name())
349
- msg.name = cover->get_name();
350
- msg.unique_id = get_default_unique_id("cover", cover);
326
+ auto traits = cover->get_traits();
351
327
  msg.assumed_state = traits.get_is_assumed_state();
352
328
  msg.supports_position = traits.get_supports_position();
353
329
  msg.supports_tilt = traits.get_supports_tilt();
354
330
  msg.supports_stop = traits.get_supports_stop();
355
331
  msg.device_class = cover->get_device_class();
356
- msg.disabled_by_default = cover->is_disabled_by_default();
357
- msg.icon = cover->get_icon();
358
- msg.entity_category = static_cast<enums::EntityCategory>(cover->get_entity_category());
359
- return api->send_list_entities_cover_response(msg);
332
+ msg.unique_id = get_default_unique_id("cover", cover);
333
+ return this->try_send_entity_info_(static_cast<EntityBase *>(cover), msg,
334
+ &APIConnection::send_list_entities_cover_response);
360
335
  }
361
336
  void APIConnection::cover_command(const CoverCommandRequest &msg) {
362
337
  cover::Cover *cover = App.get_cover_by_key(msg.key);
@@ -389,56 +364,41 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) {
389
364
 
390
365
  #ifdef USE_FAN
391
366
  bool APIConnection::send_fan_state(fan::Fan *fan) {
392
- if (!this->state_subscription_)
393
- return false;
394
-
395
- if (!APIConnection::try_send_fan_state(this, fan)) {
396
- this->deferred_message_queue_.defer(fan, try_send_fan_state);
397
- }
398
-
399
- return true;
367
+ return this->send_state_(static_cast<EntityBase *>(fan),
368
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_fan_state_));
400
369
  }
401
370
  void APIConnection::send_fan_info(fan::Fan *fan) {
402
- if (!APIConnection::try_send_fan_info(this, fan)) {
403
- this->deferred_message_queue_.defer(fan, try_send_fan_info);
404
- }
371
+ this->send_info_(static_cast<EntityBase *>(fan),
372
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_fan_info_));
405
373
  }
406
- bool APIConnection::try_send_fan_state(APIConnection *api, void *v_fan) {
407
- fan::Fan *fan = reinterpret_cast<fan::Fan *>(v_fan);
374
+ bool APIConnection::try_send_fan_state_(fan::Fan *fan) {
375
+ FanStateResponse msg;
408
376
  auto traits = fan->get_traits();
409
- FanStateResponse resp{};
410
- resp.key = fan->get_object_id_hash();
411
- resp.state = fan->state;
377
+ msg.state = fan->state;
412
378
  if (traits.supports_oscillation())
413
- resp.oscillating = fan->oscillating;
379
+ msg.oscillating = fan->oscillating;
414
380
  if (traits.supports_speed()) {
415
- resp.speed_level = fan->speed;
381
+ msg.speed_level = fan->speed;
416
382
  }
417
383
  if (traits.supports_direction())
418
- resp.direction = static_cast<enums::FanDirection>(fan->direction);
384
+ msg.direction = static_cast<enums::FanDirection>(fan->direction);
419
385
  if (traits.supports_preset_modes())
420
- resp.preset_mode = fan->preset_mode;
421
- return api->send_fan_state_response(resp);
386
+ msg.preset_mode = fan->preset_mode;
387
+ msg.key = fan->get_object_id_hash();
388
+ return this->send_fan_state_response(msg);
422
389
  }
423
- bool APIConnection::try_send_fan_info(APIConnection *api, void *v_fan) {
424
- fan::Fan *fan = reinterpret_cast<fan::Fan *>(v_fan);
425
- auto traits = fan->get_traits();
390
+ bool APIConnection::try_send_fan_info_(fan::Fan *fan) {
426
391
  ListEntitiesFanResponse msg;
427
- msg.key = fan->get_object_id_hash();
428
- msg.object_id = fan->get_object_id();
429
- if (fan->has_own_name())
430
- msg.name = fan->get_name();
431
- msg.unique_id = get_default_unique_id("fan", fan);
392
+ auto traits = fan->get_traits();
432
393
  msg.supports_oscillation = traits.supports_oscillation();
433
394
  msg.supports_speed = traits.supports_speed();
434
395
  msg.supports_direction = traits.supports_direction();
435
396
  msg.supported_speed_count = traits.supported_speed_count();
436
397
  for (auto const &preset : traits.supported_preset_modes())
437
398
  msg.supported_preset_modes.push_back(preset);
438
- msg.disabled_by_default = fan->is_disabled_by_default();
439
- msg.icon = fan->get_icon();
440
- msg.entity_category = static_cast<enums::EntityCategory>(fan->get_entity_category());
441
- return api->send_list_entities_fan_response(msg);
399
+ msg.unique_id = get_default_unique_id("fan", fan);
400
+ return this->try_send_entity_info_(static_cast<EntityBase *>(fan), msg,
401
+ &APIConnection::send_list_entities_fan_response);
442
402
  }
443
403
  void APIConnection::fan_command(const FanCommandRequest &msg) {
444
404
  fan::Fan *fan = App.get_fan_by_key(msg.key);
@@ -464,28 +424,18 @@ void APIConnection::fan_command(const FanCommandRequest &msg) {
464
424
 
465
425
  #ifdef USE_LIGHT
466
426
  bool APIConnection::send_light_state(light::LightState *light) {
467
- if (!this->state_subscription_)
468
- return false;
469
-
470
- if (!APIConnection::try_send_light_state(this, light)) {
471
- this->deferred_message_queue_.defer(light, try_send_light_state);
472
- }
473
-
474
- return true;
427
+ return this->send_state_(static_cast<EntityBase *>(light),
428
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_light_state_));
475
429
  }
476
430
  void APIConnection::send_light_info(light::LightState *light) {
477
- if (!APIConnection::try_send_light_info(this, light)) {
478
- this->deferred_message_queue_.defer(light, try_send_light_info);
479
- }
431
+ this->send_info_(static_cast<EntityBase *>(light),
432
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_light_info_));
480
433
  }
481
- bool APIConnection::try_send_light_state(APIConnection *api, void *v_light) {
482
- light::LightState *light = reinterpret_cast<light::LightState *>(v_light);
434
+ bool APIConnection::try_send_light_state_(light::LightState *light) {
435
+ LightStateResponse resp;
483
436
  auto traits = light->get_traits();
484
437
  auto values = light->remote_values;
485
438
  auto color_mode = values.get_color_mode();
486
- LightStateResponse resp{};
487
-
488
- resp.key = light->get_object_id_hash();
489
439
  resp.state = values.is_on();
490
440
  resp.color_mode = static_cast<enums::ColorMode>(color_mode);
491
441
  resp.brightness = values.get_brightness();
@@ -499,25 +449,14 @@ bool APIConnection::try_send_light_state(APIConnection *api, void *v_light) {
499
449
  resp.warm_white = values.get_warm_white();
500
450
  if (light->supports_effects())
501
451
  resp.effect = light->get_effect_name();
502
- return api->send_light_state_response(resp);
452
+ resp.key = light->get_object_id_hash();
453
+ return this->send_light_state_response(resp);
503
454
  }
504
- bool APIConnection::try_send_light_info(APIConnection *api, void *v_light) {
505
- light::LightState *light = reinterpret_cast<light::LightState *>(v_light);
506
- auto traits = light->get_traits();
455
+ bool APIConnection::try_send_light_info_(light::LightState *light) {
507
456
  ListEntitiesLightResponse msg;
508
- msg.key = light->get_object_id_hash();
509
- msg.object_id = light->get_object_id();
510
- if (light->has_own_name())
511
- msg.name = light->get_name();
512
- msg.unique_id = get_default_unique_id("light", light);
513
-
514
- msg.disabled_by_default = light->is_disabled_by_default();
515
- msg.icon = light->get_icon();
516
- msg.entity_category = static_cast<enums::EntityCategory>(light->get_entity_category());
517
-
457
+ auto traits = light->get_traits();
518
458
  for (auto mode : traits.get_supported_color_modes())
519
459
  msg.supported_color_modes.push_back(static_cast<enums::ColorMode>(mode));
520
-
521
460
  msg.legacy_supports_brightness = traits.supports_color_capability(light::ColorCapability::BRIGHTNESS);
522
461
  msg.legacy_supports_rgb = traits.supports_color_capability(light::ColorCapability::RGB);
523
462
  msg.legacy_supports_white_value =
@@ -525,17 +464,19 @@ bool APIConnection::try_send_light_info(APIConnection *api, void *v_light) {
525
464
  traits.supports_color_capability(light::ColorCapability::COLD_WARM_WHITE));
526
465
  msg.legacy_supports_color_temperature = traits.supports_color_capability(light::ColorCapability::COLOR_TEMPERATURE) ||
527
466
  traits.supports_color_capability(light::ColorCapability::COLD_WARM_WHITE);
528
-
529
467
  if (msg.legacy_supports_color_temperature) {
530
468
  msg.min_mireds = traits.get_min_mireds();
531
469
  msg.max_mireds = traits.get_max_mireds();
532
470
  }
533
471
  if (light->supports_effects()) {
534
472
  msg.effects.emplace_back("None");
535
- for (auto *effect : light->get_effects())
473
+ for (auto *effect : light->get_effects()) {
536
474
  msg.effects.push_back(effect->get_name());
475
+ }
537
476
  }
538
- return api->send_list_entities_light_response(msg);
477
+ msg.unique_id = get_default_unique_id("light", light);
478
+ return this->try_send_entity_info_(static_cast<EntityBase *>(light), msg,
479
+ &APIConnection::send_list_entities_light_response);
539
480
  }
540
481
  void APIConnection::light_command(const LightCommandRequest &msg) {
541
482
  light::LightState *light = App.get_light_by_key(msg.key);
@@ -576,93 +517,65 @@ void APIConnection::light_command(const LightCommandRequest &msg) {
576
517
 
577
518
  #ifdef USE_SENSOR
578
519
  bool APIConnection::send_sensor_state(sensor::Sensor *sensor, float state) {
579
- if (!this->state_subscription_)
580
- return false;
581
-
582
- if (!APIConnection::try_send_sensor_state(this, sensor, state)) {
583
- this->deferred_message_queue_.defer(sensor, try_send_sensor_state);
584
- }
585
-
586
- return true;
520
+ return this->send_state_with_value_(sensor, &APIConnection::try_send_sensor_state_,
521
+ &APIConnection::try_send_sensor_state_, state);
587
522
  }
588
523
  void APIConnection::send_sensor_info(sensor::Sensor *sensor) {
589
- if (!APIConnection::try_send_sensor_info(this, sensor)) {
590
- this->deferred_message_queue_.defer(sensor, try_send_sensor_info);
591
- }
524
+ this->send_info_(static_cast<EntityBase *>(sensor),
525
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_sensor_info_));
592
526
  }
593
- bool APIConnection::try_send_sensor_state(APIConnection *api, void *v_sensor) {
594
- sensor::Sensor *sensor = reinterpret_cast<sensor::Sensor *>(v_sensor);
595
- return APIConnection::try_send_sensor_state(api, sensor, sensor->state);
527
+ bool APIConnection::try_send_sensor_state_(sensor::Sensor *sensor) {
528
+ return this->try_send_sensor_state_(sensor, sensor->state);
596
529
  }
597
- bool APIConnection::try_send_sensor_state(APIConnection *api, sensor::Sensor *sensor, float state) {
598
- SensorStateResponse resp{};
599
- resp.key = sensor->get_object_id_hash();
530
+ bool APIConnection::try_send_sensor_state_(sensor::Sensor *sensor, float state) {
531
+ SensorStateResponse resp;
600
532
  resp.state = state;
601
533
  resp.missing_state = !sensor->has_state();
602
- return api->send_sensor_state_response(resp);
534
+
535
+ resp.key = sensor->get_object_id_hash();
536
+ return this->send_sensor_state_response(resp);
603
537
  }
604
- bool APIConnection::try_send_sensor_info(APIConnection *api, void *v_sensor) {
605
- sensor::Sensor *sensor = reinterpret_cast<sensor::Sensor *>(v_sensor);
538
+ bool APIConnection::try_send_sensor_info_(sensor::Sensor *sensor) {
606
539
  ListEntitiesSensorResponse msg;
607
- msg.key = sensor->get_object_id_hash();
608
- msg.object_id = sensor->get_object_id();
609
- if (sensor->has_own_name())
610
- msg.name = sensor->get_name();
611
- msg.unique_id = sensor->unique_id();
612
- if (msg.unique_id.empty())
613
- msg.unique_id = get_default_unique_id("sensor", sensor);
614
- msg.icon = sensor->get_icon();
615
540
  msg.unit_of_measurement = sensor->get_unit_of_measurement();
616
541
  msg.accuracy_decimals = sensor->get_accuracy_decimals();
617
542
  msg.force_update = sensor->get_force_update();
618
543
  msg.device_class = sensor->get_device_class();
619
544
  msg.state_class = static_cast<enums::SensorStateClass>(sensor->get_state_class());
620
- msg.disabled_by_default = sensor->is_disabled_by_default();
621
- msg.entity_category = static_cast<enums::EntityCategory>(sensor->get_entity_category());
622
- return api->send_list_entities_sensor_response(msg);
545
+ msg.unique_id = sensor->unique_id();
546
+ if (msg.unique_id.empty())
547
+ msg.unique_id = get_default_unique_id("sensor", sensor);
548
+ return this->try_send_entity_info_(static_cast<EntityBase *>(sensor), msg,
549
+ &APIConnection::send_list_entities_sensor_response);
623
550
  }
624
551
  #endif
625
552
 
626
553
  #ifdef USE_SWITCH
627
554
  bool APIConnection::send_switch_state(switch_::Switch *a_switch, bool state) {
628
- if (!this->state_subscription_)
629
- return false;
630
-
631
- if (!APIConnection::try_send_switch_state(this, a_switch, state)) {
632
- this->deferred_message_queue_.defer(a_switch, try_send_switch_state);
633
- }
634
-
635
- return true;
555
+ return this->send_state_with_value_(a_switch, &APIConnection::try_send_switch_state_,
556
+ &APIConnection::try_send_switch_state_, state);
636
557
  }
637
558
  void APIConnection::send_switch_info(switch_::Switch *a_switch) {
638
- if (!APIConnection::try_send_switch_info(this, a_switch)) {
639
- this->deferred_message_queue_.defer(a_switch, try_send_switch_info);
640
- }
559
+ this->send_info_(static_cast<EntityBase *>(a_switch),
560
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_switch_info_));
641
561
  }
642
- bool APIConnection::try_send_switch_state(APIConnection *api, void *v_a_switch) {
643
- switch_::Switch *a_switch = reinterpret_cast<switch_::Switch *>(v_a_switch);
644
- return APIConnection::try_send_switch_state(api, a_switch, a_switch->state);
562
+ bool APIConnection::try_send_switch_state_(switch_::Switch *a_switch) {
563
+ return this->try_send_switch_state_(a_switch, a_switch->state);
645
564
  }
646
- bool APIConnection::try_send_switch_state(APIConnection *api, switch_::Switch *a_switch, bool state) {
647
- SwitchStateResponse resp{};
648
- resp.key = a_switch->get_object_id_hash();
565
+ bool APIConnection::try_send_switch_state_(switch_::Switch *a_switch, bool state) {
566
+ SwitchStateResponse resp;
649
567
  resp.state = state;
650
- return api->send_switch_state_response(resp);
568
+
569
+ resp.key = a_switch->get_object_id_hash();
570
+ return this->send_switch_state_response(resp);
651
571
  }
652
- bool APIConnection::try_send_switch_info(APIConnection *api, void *v_a_switch) {
653
- switch_::Switch *a_switch = reinterpret_cast<switch_::Switch *>(v_a_switch);
572
+ bool APIConnection::try_send_switch_info_(switch_::Switch *a_switch) {
654
573
  ListEntitiesSwitchResponse msg;
655
- msg.key = a_switch->get_object_id_hash();
656
- msg.object_id = a_switch->get_object_id();
657
- if (a_switch->has_own_name())
658
- msg.name = a_switch->get_name();
659
- msg.unique_id = get_default_unique_id("switch", a_switch);
660
- msg.icon = a_switch->get_icon();
661
574
  msg.assumed_state = a_switch->assumed_state();
662
- msg.disabled_by_default = a_switch->is_disabled_by_default();
663
- msg.entity_category = static_cast<enums::EntityCategory>(a_switch->get_entity_category());
664
575
  msg.device_class = a_switch->get_device_class();
665
- return api->send_list_entities_switch_response(msg);
576
+ msg.unique_id = get_default_unique_id("switch", a_switch);
577
+ return this->try_send_entity_info_(static_cast<EntityBase *>(a_switch), msg,
578
+ &APIConnection::send_list_entities_switch_response);
666
579
  }
667
580
  void APIConnection::switch_command(const SwitchCommandRequest &msg) {
668
581
  switch_::Switch *a_switch = App.get_switch_by_key(msg.key);
@@ -679,70 +592,48 @@ void APIConnection::switch_command(const SwitchCommandRequest &msg) {
679
592
 
680
593
  #ifdef USE_TEXT_SENSOR
681
594
  bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor, std::string state) {
682
- if (!this->state_subscription_)
683
- return false;
684
-
685
- if (!APIConnection::try_send_text_sensor_state(this, text_sensor, std::move(state))) {
686
- this->deferred_message_queue_.defer(text_sensor, try_send_text_sensor_state);
687
- }
688
-
689
- return true;
595
+ return this->send_state_with_value_(text_sensor, &APIConnection::try_send_text_sensor_state_,
596
+ &APIConnection::try_send_text_sensor_state_, std::move(state));
690
597
  }
691
598
  void APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor) {
692
- if (!APIConnection::try_send_text_sensor_info(this, text_sensor)) {
693
- this->deferred_message_queue_.defer(text_sensor, try_send_text_sensor_info);
694
- }
599
+ this->send_info_(static_cast<EntityBase *>(text_sensor),
600
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_text_sensor_info_));
695
601
  }
696
- bool APIConnection::try_send_text_sensor_state(APIConnection *api, void *v_text_sensor) {
697
- text_sensor::TextSensor *text_sensor = reinterpret_cast<text_sensor::TextSensor *>(v_text_sensor);
698
- return APIConnection::try_send_text_sensor_state(api, text_sensor, text_sensor->state);
602
+ bool APIConnection::try_send_text_sensor_state_(text_sensor::TextSensor *text_sensor) {
603
+ return this->try_send_text_sensor_state_(text_sensor, text_sensor->state);
699
604
  }
700
- bool APIConnection::try_send_text_sensor_state(APIConnection *api, text_sensor::TextSensor *text_sensor,
701
- std::string state) {
702
- TextSensorStateResponse resp{};
703
- resp.key = text_sensor->get_object_id_hash();
605
+ bool APIConnection::try_send_text_sensor_state_(text_sensor::TextSensor *text_sensor, std::string state) {
606
+ TextSensorStateResponse resp;
704
607
  resp.state = std::move(state);
705
608
  resp.missing_state = !text_sensor->has_state();
706
- return api->send_text_sensor_state_response(resp);
609
+
610
+ resp.key = text_sensor->get_object_id_hash();
611
+ return this->send_text_sensor_state_response(resp);
707
612
  }
708
- bool APIConnection::try_send_text_sensor_info(APIConnection *api, void *v_text_sensor) {
709
- text_sensor::TextSensor *text_sensor = reinterpret_cast<text_sensor::TextSensor *>(v_text_sensor);
613
+ bool APIConnection::try_send_text_sensor_info_(text_sensor::TextSensor *text_sensor) {
710
614
  ListEntitiesTextSensorResponse msg;
711
- msg.key = text_sensor->get_object_id_hash();
712
- msg.object_id = text_sensor->get_object_id();
713
- msg.name = text_sensor->get_name();
615
+ msg.device_class = text_sensor->get_device_class();
714
616
  msg.unique_id = text_sensor->unique_id();
715
617
  if (msg.unique_id.empty())
716
618
  msg.unique_id = get_default_unique_id("text_sensor", text_sensor);
717
- msg.icon = text_sensor->get_icon();
718
- msg.disabled_by_default = text_sensor->is_disabled_by_default();
719
- msg.entity_category = static_cast<enums::EntityCategory>(text_sensor->get_entity_category());
720
- msg.device_class = text_sensor->get_device_class();
721
- return api->send_list_entities_text_sensor_response(msg);
619
+ return this->try_send_entity_info_(static_cast<EntityBase *>(text_sensor), msg,
620
+ &APIConnection::send_list_entities_text_sensor_response);
722
621
  }
723
622
  #endif
724
623
 
725
624
  #ifdef USE_CLIMATE
726
625
  bool APIConnection::send_climate_state(climate::Climate *climate) {
727
- if (!this->state_subscription_)
728
- return false;
729
-
730
- if (!APIConnection::try_send_climate_state(this, climate)) {
731
- this->deferred_message_queue_.defer(climate, try_send_climate_state);
732
- }
733
-
734
- return true;
626
+ return this->send_state_(static_cast<EntityBase *>(climate),
627
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_climate_state_));
735
628
  }
736
629
  void APIConnection::send_climate_info(climate::Climate *climate) {
737
- if (!APIConnection::try_send_climate_info(this, climate)) {
738
- this->deferred_message_queue_.defer(climate, try_send_climate_info);
739
- }
630
+ this->send_info_(static_cast<EntityBase *>(climate),
631
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_climate_info_));
740
632
  }
741
- bool APIConnection::try_send_climate_state(APIConnection *api, void *v_climate) {
742
- climate::Climate *climate = reinterpret_cast<climate::Climate *>(v_climate);
743
- auto traits = climate->get_traits();
744
- ClimateStateResponse resp{};
633
+ bool APIConnection::try_send_climate_state_(climate::Climate *climate) {
634
+ ClimateStateResponse resp;
745
635
  resp.key = climate->get_object_id_hash();
636
+ auto traits = climate->get_traits();
746
637
  resp.mode = static_cast<enums::ClimateMode>(climate->mode);
747
638
  resp.action = static_cast<enums::ClimateAction>(climate->action);
748
639
  if (traits.get_supports_current_temperature())
@@ -768,40 +659,25 @@ bool APIConnection::try_send_climate_state(APIConnection *api, void *v_climate)
768
659
  resp.current_humidity = climate->current_humidity;
769
660
  if (traits.get_supports_target_humidity())
770
661
  resp.target_humidity = climate->target_humidity;
771
- return api->send_climate_state_response(resp);
662
+ return this->send_climate_state_response(resp);
772
663
  }
773
- bool APIConnection::try_send_climate_info(APIConnection *api, void *v_climate) {
774
- climate::Climate *climate = reinterpret_cast<climate::Climate *>(v_climate);
775
- auto traits = climate->get_traits();
664
+ bool APIConnection::try_send_climate_info_(climate::Climate *climate) {
776
665
  ListEntitiesClimateResponse msg;
777
- msg.key = climate->get_object_id_hash();
778
- msg.object_id = climate->get_object_id();
779
- if (climate->has_own_name())
780
- msg.name = climate->get_name();
781
- msg.unique_id = get_default_unique_id("climate", climate);
782
-
783
- msg.disabled_by_default = climate->is_disabled_by_default();
784
- msg.icon = climate->get_icon();
785
- msg.entity_category = static_cast<enums::EntityCategory>(climate->get_entity_category());
786
-
666
+ auto traits = climate->get_traits();
787
667
  msg.supports_current_temperature = traits.get_supports_current_temperature();
788
668
  msg.supports_current_humidity = traits.get_supports_current_humidity();
789
669
  msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature();
790
670
  msg.supports_target_humidity = traits.get_supports_target_humidity();
791
-
792
671
  for (auto mode : traits.get_supported_modes())
793
672
  msg.supported_modes.push_back(static_cast<enums::ClimateMode>(mode));
794
-
795
673
  msg.visual_min_temperature = traits.get_visual_min_temperature();
796
674
  msg.visual_max_temperature = traits.get_visual_max_temperature();
797
675
  msg.visual_target_temperature_step = traits.get_visual_target_temperature_step();
798
676
  msg.visual_current_temperature_step = traits.get_visual_current_temperature_step();
799
677
  msg.visual_min_humidity = traits.get_visual_min_humidity();
800
678
  msg.visual_max_humidity = traits.get_visual_max_humidity();
801
-
802
679
  msg.legacy_supports_away = traits.supports_preset(climate::CLIMATE_PRESET_AWAY);
803
680
  msg.supports_action = traits.get_supports_action();
804
-
805
681
  for (auto fan_mode : traits.get_supported_fan_modes())
806
682
  msg.supported_fan_modes.push_back(static_cast<enums::ClimateFanMode>(fan_mode));
807
683
  for (auto const &custom_fan_mode : traits.get_supported_custom_fan_modes())
@@ -812,7 +688,9 @@ bool APIConnection::try_send_climate_info(APIConnection *api, void *v_climate) {
812
688
  msg.supported_custom_presets.push_back(custom_preset);
813
689
  for (auto swing_mode : traits.get_supported_swing_modes())
814
690
  msg.supported_swing_modes.push_back(static_cast<enums::ClimateSwingMode>(swing_mode));
815
- return api->send_list_entities_climate_response(msg);
691
+ msg.unique_id = get_default_unique_id("climate", climate);
692
+ return this->try_send_entity_info_(static_cast<EntityBase *>(climate), msg,
693
+ &APIConnection::send_list_entities_climate_response);
816
694
  }
817
695
  void APIConnection::climate_command(const ClimateCommandRequest &msg) {
818
696
  climate::Climate *climate = App.get_climate_by_key(msg.key);
@@ -846,51 +724,35 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
846
724
 
847
725
  #ifdef USE_NUMBER
848
726
  bool APIConnection::send_number_state(number::Number *number, float state) {
849
- if (!this->state_subscription_)
850
- return false;
851
-
852
- if (!APIConnection::try_send_number_state(this, number, state)) {
853
- this->deferred_message_queue_.defer(number, try_send_number_state);
854
- }
855
-
856
- return true;
727
+ return this->send_state_with_value_(number, &APIConnection::try_send_number_state_,
728
+ &APIConnection::try_send_number_state_, state);
857
729
  }
858
730
  void APIConnection::send_number_info(number::Number *number) {
859
- if (!APIConnection::try_send_number_info(this, number)) {
860
- this->deferred_message_queue_.defer(number, try_send_number_info);
861
- }
731
+ this->send_info_(static_cast<EntityBase *>(number),
732
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_number_info_));
862
733
  }
863
- bool APIConnection::try_send_number_state(APIConnection *api, void *v_number) {
864
- number::Number *number = reinterpret_cast<number::Number *>(v_number);
865
- return APIConnection::try_send_number_state(api, number, number->state);
734
+ bool APIConnection::try_send_number_state_(number::Number *number) {
735
+ return this->try_send_number_state_(number, number->state);
866
736
  }
867
- bool APIConnection::try_send_number_state(APIConnection *api, number::Number *number, float state) {
868
- NumberStateResponse resp{};
869
- resp.key = number->get_object_id_hash();
737
+ bool APIConnection::try_send_number_state_(number::Number *number, float state) {
738
+ NumberStateResponse resp;
870
739
  resp.state = state;
871
740
  resp.missing_state = !number->has_state();
872
- return api->send_number_state_response(resp);
741
+
742
+ resp.key = number->get_object_id_hash();
743
+ return this->send_number_state_response(resp);
873
744
  }
874
- bool APIConnection::try_send_number_info(APIConnection *api, void *v_number) {
875
- number::Number *number = reinterpret_cast<number::Number *>(v_number);
745
+ bool APIConnection::try_send_number_info_(number::Number *number) {
876
746
  ListEntitiesNumberResponse msg;
877
- msg.key = number->get_object_id_hash();
878
- msg.object_id = number->get_object_id();
879
- if (number->has_own_name())
880
- msg.name = number->get_name();
881
- msg.unique_id = get_default_unique_id("number", number);
882
- msg.icon = number->get_icon();
883
- msg.disabled_by_default = number->is_disabled_by_default();
884
- msg.entity_category = static_cast<enums::EntityCategory>(number->get_entity_category());
885
747
  msg.unit_of_measurement = number->traits.get_unit_of_measurement();
886
748
  msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode());
887
749
  msg.device_class = number->traits.get_device_class();
888
-
889
750
  msg.min_value = number->traits.get_min_value();
890
751
  msg.max_value = number->traits.get_max_value();
891
752
  msg.step = number->traits.get_step();
892
-
893
- return api->send_list_entities_number_response(msg);
753
+ msg.unique_id = get_default_unique_id("number", number);
754
+ return this->try_send_entity_info_(static_cast<EntityBase *>(number), msg,
755
+ &APIConnection::send_list_entities_number_response);
894
756
  }
895
757
  void APIConnection::number_command(const NumberCommandRequest &msg) {
896
758
  number::Number *number = App.get_number_by_key(msg.key);
@@ -905,43 +767,28 @@ void APIConnection::number_command(const NumberCommandRequest &msg) {
905
767
 
906
768
  #ifdef USE_DATETIME_DATE
907
769
  bool APIConnection::send_date_state(datetime::DateEntity *date) {
908
- if (!this->state_subscription_)
909
- return false;
910
-
911
- if (!APIConnection::try_send_date_state(this, date)) {
912
- this->deferred_message_queue_.defer(date, try_send_date_state);
913
- }
914
-
915
- return true;
770
+ return this->send_state_(static_cast<EntityBase *>(date),
771
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_date_state_));
916
772
  }
917
773
  void APIConnection::send_date_info(datetime::DateEntity *date) {
918
- if (!APIConnection::try_send_date_info(this, date)) {
919
- this->deferred_message_queue_.defer(date, try_send_date_info);
920
- }
774
+ this->send_info_(static_cast<EntityBase *>(date),
775
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_date_info_));
921
776
  }
922
- bool APIConnection::try_send_date_state(APIConnection *api, void *v_date) {
923
- datetime::DateEntity *date = reinterpret_cast<datetime::DateEntity *>(v_date);
924
- DateStateResponse resp{};
925
- resp.key = date->get_object_id_hash();
777
+ bool APIConnection::try_send_date_state_(datetime::DateEntity *date) {
778
+ DateStateResponse resp;
926
779
  resp.missing_state = !date->has_state();
927
780
  resp.year = date->year;
928
781
  resp.month = date->month;
929
782
  resp.day = date->day;
930
- return api->send_date_state_response(resp);
783
+
784
+ resp.key = date->get_object_id_hash();
785
+ return this->send_date_state_response(resp);
931
786
  }
932
- bool APIConnection::try_send_date_info(APIConnection *api, void *v_date) {
933
- datetime::DateEntity *date = reinterpret_cast<datetime::DateEntity *>(v_date);
787
+ bool APIConnection::try_send_date_info_(datetime::DateEntity *date) {
934
788
  ListEntitiesDateResponse msg;
935
- msg.key = date->get_object_id_hash();
936
- msg.object_id = date->get_object_id();
937
- if (date->has_own_name())
938
- msg.name = date->get_name();
939
789
  msg.unique_id = get_default_unique_id("date", date);
940
- msg.icon = date->get_icon();
941
- msg.disabled_by_default = date->is_disabled_by_default();
942
- msg.entity_category = static_cast<enums::EntityCategory>(date->get_entity_category());
943
-
944
- return api->send_list_entities_date_response(msg);
790
+ return this->try_send_entity_info_(static_cast<EntityBase *>(date), msg,
791
+ &APIConnection::send_list_entities_date_response);
945
792
  }
946
793
  void APIConnection::date_command(const DateCommandRequest &msg) {
947
794
  datetime::DateEntity *date = App.get_date_by_key(msg.key);
@@ -956,43 +803,28 @@ void APIConnection::date_command(const DateCommandRequest &msg) {
956
803
 
957
804
  #ifdef USE_DATETIME_TIME
958
805
  bool APIConnection::send_time_state(datetime::TimeEntity *time) {
959
- if (!this->state_subscription_)
960
- return false;
961
-
962
- if (!APIConnection::try_send_time_state(this, time)) {
963
- this->deferred_message_queue_.defer(time, try_send_time_state);
964
- }
965
-
966
- return true;
806
+ return this->send_state_(static_cast<EntityBase *>(time),
807
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_time_state_));
967
808
  }
968
809
  void APIConnection::send_time_info(datetime::TimeEntity *time) {
969
- if (!APIConnection::try_send_time_info(this, time)) {
970
- this->deferred_message_queue_.defer(time, try_send_time_info);
971
- }
810
+ this->send_info_(static_cast<EntityBase *>(time),
811
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_time_info_));
972
812
  }
973
- bool APIConnection::try_send_time_state(APIConnection *api, void *v_time) {
974
- datetime::TimeEntity *time = reinterpret_cast<datetime::TimeEntity *>(v_time);
975
- TimeStateResponse resp{};
976
- resp.key = time->get_object_id_hash();
813
+ bool APIConnection::try_send_time_state_(datetime::TimeEntity *time) {
814
+ TimeStateResponse resp;
977
815
  resp.missing_state = !time->has_state();
978
816
  resp.hour = time->hour;
979
817
  resp.minute = time->minute;
980
818
  resp.second = time->second;
981
- return api->send_time_state_response(resp);
819
+
820
+ resp.key = time->get_object_id_hash();
821
+ return this->send_time_state_response(resp);
982
822
  }
983
- bool APIConnection::try_send_time_info(APIConnection *api, void *v_time) {
984
- datetime::TimeEntity *time = reinterpret_cast<datetime::TimeEntity *>(v_time);
823
+ bool APIConnection::try_send_time_info_(datetime::TimeEntity *time) {
985
824
  ListEntitiesTimeResponse msg;
986
- msg.key = time->get_object_id_hash();
987
- msg.object_id = time->get_object_id();
988
- if (time->has_own_name())
989
- msg.name = time->get_name();
990
825
  msg.unique_id = get_default_unique_id("time", time);
991
- msg.icon = time->get_icon();
992
- msg.disabled_by_default = time->is_disabled_by_default();
993
- msg.entity_category = static_cast<enums::EntityCategory>(time->get_entity_category());
994
-
995
- return api->send_list_entities_time_response(msg);
826
+ return this->try_send_entity_info_(static_cast<EntityBase *>(time), msg,
827
+ &APIConnection::send_list_entities_time_response);
996
828
  }
997
829
  void APIConnection::time_command(const TimeCommandRequest &msg) {
998
830
  datetime::TimeEntity *time = App.get_time_by_key(msg.key);
@@ -1007,44 +839,29 @@ void APIConnection::time_command(const TimeCommandRequest &msg) {
1007
839
 
1008
840
  #ifdef USE_DATETIME_DATETIME
1009
841
  bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) {
1010
- if (!this->state_subscription_)
1011
- return false;
1012
-
1013
- if (!APIConnection::try_send_datetime_state(this, datetime)) {
1014
- this->deferred_message_queue_.defer(datetime, try_send_datetime_state);
1015
- }
1016
-
1017
- return true;
842
+ return this->send_state_(static_cast<EntityBase *>(datetime),
843
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_datetime_state_));
1018
844
  }
1019
845
  void APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) {
1020
- if (!APIConnection::try_send_datetime_info(this, datetime)) {
1021
- this->deferred_message_queue_.defer(datetime, try_send_datetime_info);
1022
- }
846
+ this->send_info_(static_cast<EntityBase *>(datetime),
847
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_datetime_info_));
1023
848
  }
1024
- bool APIConnection::try_send_datetime_state(APIConnection *api, void *v_datetime) {
1025
- datetime::DateTimeEntity *datetime = reinterpret_cast<datetime::DateTimeEntity *>(v_datetime);
1026
- DateTimeStateResponse resp{};
1027
- resp.key = datetime->get_object_id_hash();
849
+ bool APIConnection::try_send_datetime_state_(datetime::DateTimeEntity *datetime) {
850
+ DateTimeStateResponse resp;
1028
851
  resp.missing_state = !datetime->has_state();
1029
852
  if (datetime->has_state()) {
1030
853
  ESPTime state = datetime->state_as_esptime();
1031
854
  resp.epoch_seconds = state.timestamp;
1032
855
  }
1033
- return api->send_date_time_state_response(resp);
856
+
857
+ resp.key = datetime->get_object_id_hash();
858
+ return this->send_date_time_state_response(resp);
1034
859
  }
1035
- bool APIConnection::try_send_datetime_info(APIConnection *api, void *v_datetime) {
1036
- datetime::DateTimeEntity *datetime = reinterpret_cast<datetime::DateTimeEntity *>(v_datetime);
860
+ bool APIConnection::try_send_datetime_info_(datetime::DateTimeEntity *datetime) {
1037
861
  ListEntitiesDateTimeResponse msg;
1038
- msg.key = datetime->get_object_id_hash();
1039
- msg.object_id = datetime->get_object_id();
1040
- if (datetime->has_own_name())
1041
- msg.name = datetime->get_name();
1042
862
  msg.unique_id = get_default_unique_id("datetime", datetime);
1043
- msg.icon = datetime->get_icon();
1044
- msg.disabled_by_default = datetime->is_disabled_by_default();
1045
- msg.entity_category = static_cast<enums::EntityCategory>(datetime->get_entity_category());
1046
-
1047
- return api->send_list_entities_date_time_response(msg);
863
+ return this->try_send_entity_info_(static_cast<EntityBase *>(datetime), msg,
864
+ &APIConnection::send_list_entities_date_time_response);
1048
865
  }
1049
866
  void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
1050
867
  datetime::DateTimeEntity *datetime = App.get_datetime_by_key(msg.key);
@@ -1059,47 +876,31 @@ void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
1059
876
 
1060
877
  #ifdef USE_TEXT
1061
878
  bool APIConnection::send_text_state(text::Text *text, std::string state) {
1062
- if (!this->state_subscription_)
1063
- return false;
1064
-
1065
- if (!APIConnection::try_send_text_state(this, text, std::move(state))) {
1066
- this->deferred_message_queue_.defer(text, try_send_text_state);
1067
- }
1068
-
1069
- return true;
879
+ return this->send_state_with_value_(text, &APIConnection::try_send_text_state_, &APIConnection::try_send_text_state_,
880
+ std::move(state));
1070
881
  }
1071
882
  void APIConnection::send_text_info(text::Text *text) {
1072
- if (!APIConnection::try_send_text_info(this, text)) {
1073
- this->deferred_message_queue_.defer(text, try_send_text_info);
1074
- }
883
+ this->send_info_(static_cast<EntityBase *>(text),
884
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_text_info_));
1075
885
  }
1076
- bool APIConnection::try_send_text_state(APIConnection *api, void *v_text) {
1077
- text::Text *text = reinterpret_cast<text::Text *>(v_text);
1078
- return APIConnection::try_send_text_state(api, text, text->state);
1079
- }
1080
- bool APIConnection::try_send_text_state(APIConnection *api, text::Text *text, std::string state) {
1081
- TextStateResponse resp{};
1082
- resp.key = text->get_object_id_hash();
886
+ bool APIConnection::try_send_text_state_(text::Text *text) { return this->try_send_text_state_(text, text->state); }
887
+ bool APIConnection::try_send_text_state_(text::Text *text, std::string state) {
888
+ TextStateResponse resp;
1083
889
  resp.state = std::move(state);
1084
890
  resp.missing_state = !text->has_state();
1085
- return api->send_text_state_response(resp);
891
+
892
+ resp.key = text->get_object_id_hash();
893
+ return this->send_text_state_response(resp);
1086
894
  }
1087
- bool APIConnection::try_send_text_info(APIConnection *api, void *v_text) {
1088
- text::Text *text = reinterpret_cast<text::Text *>(v_text);
895
+ bool APIConnection::try_send_text_info_(text::Text *text) {
1089
896
  ListEntitiesTextResponse msg;
1090
- msg.key = text->get_object_id_hash();
1091
- msg.object_id = text->get_object_id();
1092
- msg.name = text->get_name();
1093
- msg.icon = text->get_icon();
1094
- msg.disabled_by_default = text->is_disabled_by_default();
1095
- msg.entity_category = static_cast<enums::EntityCategory>(text->get_entity_category());
1096
897
  msg.mode = static_cast<enums::TextMode>(text->traits.get_mode());
1097
-
1098
898
  msg.min_length = text->traits.get_min_length();
1099
899
  msg.max_length = text->traits.get_max_length();
1100
900
  msg.pattern = text->traits.get_pattern();
1101
-
1102
- return api->send_list_entities_text_response(msg);
901
+ msg.unique_id = get_default_unique_id("text", text);
902
+ return this->try_send_entity_info_(static_cast<EntityBase *>(text), msg,
903
+ &APIConnection::send_list_entities_text_response);
1103
904
  }
1104
905
  void APIConnection::text_command(const TextCommandRequest &msg) {
1105
906
  text::Text *text = App.get_text_by_key(msg.key);
@@ -1114,47 +915,31 @@ void APIConnection::text_command(const TextCommandRequest &msg) {
1114
915
 
1115
916
  #ifdef USE_SELECT
1116
917
  bool APIConnection::send_select_state(select::Select *select, std::string state) {
1117
- if (!this->state_subscription_)
1118
- return false;
1119
-
1120
- if (!APIConnection::try_send_select_state(this, select, std::move(state))) {
1121
- this->deferred_message_queue_.defer(select, try_send_select_state);
1122
- }
1123
-
1124
- return true;
918
+ return this->send_state_with_value_(select, &APIConnection::try_send_select_state_,
919
+ &APIConnection::try_send_select_state_, std::move(state));
1125
920
  }
1126
921
  void APIConnection::send_select_info(select::Select *select) {
1127
- if (!APIConnection::try_send_select_info(this, select)) {
1128
- this->deferred_message_queue_.defer(select, try_send_select_info);
1129
- }
922
+ this->send_info_(static_cast<EntityBase *>(select),
923
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_select_info_));
1130
924
  }
1131
- bool APIConnection::try_send_select_state(APIConnection *api, void *v_select) {
1132
- select::Select *select = reinterpret_cast<select::Select *>(v_select);
1133
- return APIConnection::try_send_select_state(api, select, select->state);
925
+ bool APIConnection::try_send_select_state_(select::Select *select) {
926
+ return this->try_send_select_state_(select, select->state);
1134
927
  }
1135
- bool APIConnection::try_send_select_state(APIConnection *api, select::Select *select, std::string state) {
1136
- SelectStateResponse resp{};
1137
- resp.key = select->get_object_id_hash();
928
+ bool APIConnection::try_send_select_state_(select::Select *select, std::string state) {
929
+ SelectStateResponse resp;
1138
930
  resp.state = std::move(state);
1139
931
  resp.missing_state = !select->has_state();
1140
- return api->send_select_state_response(resp);
932
+
933
+ resp.key = select->get_object_id_hash();
934
+ return this->send_select_state_response(resp);
1141
935
  }
1142
- bool APIConnection::try_send_select_info(APIConnection *api, void *v_select) {
1143
- select::Select *select = reinterpret_cast<select::Select *>(v_select);
936
+ bool APIConnection::try_send_select_info_(select::Select *select) {
1144
937
  ListEntitiesSelectResponse msg;
1145
- msg.key = select->get_object_id_hash();
1146
- msg.object_id = select->get_object_id();
1147
- if (select->has_own_name())
1148
- msg.name = select->get_name();
1149
- msg.unique_id = get_default_unique_id("select", select);
1150
- msg.icon = select->get_icon();
1151
- msg.disabled_by_default = select->is_disabled_by_default();
1152
- msg.entity_category = static_cast<enums::EntityCategory>(select->get_entity_category());
1153
-
1154
938
  for (const auto &option : select->traits.get_options())
1155
939
  msg.options.push_back(option);
1156
-
1157
- return api->send_list_entities_select_response(msg);
940
+ msg.unique_id = get_default_unique_id("select", select);
941
+ return this->try_send_entity_info_(static_cast<EntityBase *>(select), msg,
942
+ &APIConnection::send_list_entities_select_response);
1158
943
  }
1159
944
  void APIConnection::select_command(const SelectCommandRequest &msg) {
1160
945
  select::Select *select = App.get_select_by_key(msg.key);
@@ -1168,26 +953,18 @@ void APIConnection::select_command(const SelectCommandRequest &msg) {
1168
953
  #endif
1169
954
 
1170
955
  #ifdef USE_BUTTON
1171
- void APIConnection::send_button_info(button::Button *button) {
1172
- if (!APIConnection::try_send_button_info(this, button)) {
1173
- this->deferred_message_queue_.defer(button, try_send_button_info);
1174
- }
956
+ void esphome::api::APIConnection::send_button_info(button::Button *button) {
957
+ this->send_info_(static_cast<EntityBase *>(button),
958
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_button_info_));
1175
959
  }
1176
- bool APIConnection::try_send_button_info(APIConnection *api, void *v_button) {
1177
- button::Button *button = reinterpret_cast<button::Button *>(v_button);
960
+ bool esphome::api::APIConnection::try_send_button_info_(button::Button *button) {
1178
961
  ListEntitiesButtonResponse msg;
1179
- msg.key = button->get_object_id_hash();
1180
- msg.object_id = button->get_object_id();
1181
- if (button->has_own_name())
1182
- msg.name = button->get_name();
1183
- msg.unique_id = get_default_unique_id("button", button);
1184
- msg.icon = button->get_icon();
1185
- msg.disabled_by_default = button->is_disabled_by_default();
1186
- msg.entity_category = static_cast<enums::EntityCategory>(button->get_entity_category());
1187
962
  msg.device_class = button->get_device_class();
1188
- return api->send_list_entities_button_response(msg);
963
+ msg.unique_id = get_default_unique_id("button", button);
964
+ return this->try_send_entity_info_(static_cast<EntityBase *>(button), msg,
965
+ &APIConnection::send_list_entities_button_response);
1189
966
  }
1190
- void APIConnection::button_command(const ButtonCommandRequest &msg) {
967
+ void esphome::api::APIConnection::button_command(const ButtonCommandRequest &msg) {
1191
968
  button::Button *button = App.get_button_by_key(msg.key);
1192
969
  if (button == nullptr)
1193
970
  return;
@@ -1198,45 +975,31 @@ void APIConnection::button_command(const ButtonCommandRequest &msg) {
1198
975
 
1199
976
  #ifdef USE_LOCK
1200
977
  bool APIConnection::send_lock_state(lock::Lock *a_lock, lock::LockState state) {
1201
- if (!this->state_subscription_)
1202
- return false;
1203
-
1204
- if (!APIConnection::try_send_lock_state(this, a_lock, state)) {
1205
- this->deferred_message_queue_.defer(a_lock, try_send_lock_state);
1206
- }
1207
-
1208
- return true;
978
+ return this->send_state_with_value_(a_lock, &APIConnection::try_send_lock_state_,
979
+ &APIConnection::try_send_lock_state_, state);
1209
980
  }
1210
981
  void APIConnection::send_lock_info(lock::Lock *a_lock) {
1211
- if (!APIConnection::try_send_lock_info(this, a_lock)) {
1212
- this->deferred_message_queue_.defer(a_lock, try_send_lock_info);
1213
- }
982
+ this->send_info_(static_cast<EntityBase *>(a_lock),
983
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_lock_info_));
1214
984
  }
1215
- bool APIConnection::try_send_lock_state(APIConnection *api, void *v_a_lock) {
1216
- lock::Lock *a_lock = reinterpret_cast<lock::Lock *>(v_a_lock);
1217
- return APIConnection::try_send_lock_state(api, a_lock, a_lock->state);
985
+ bool APIConnection::try_send_lock_state_(lock::Lock *a_lock) {
986
+ return this->try_send_lock_state_(a_lock, a_lock->state);
1218
987
  }
1219
- bool APIConnection::try_send_lock_state(APIConnection *api, lock::Lock *a_lock, lock::LockState state) {
1220
- LockStateResponse resp{};
1221
- resp.key = a_lock->get_object_id_hash();
988
+ bool APIConnection::try_send_lock_state_(lock::Lock *a_lock, lock::LockState state) {
989
+ LockStateResponse resp;
1222
990
  resp.state = static_cast<enums::LockState>(state);
1223
- return api->send_lock_state_response(resp);
991
+
992
+ resp.key = a_lock->get_object_id_hash();
993
+ return this->send_lock_state_response(resp);
1224
994
  }
1225
- bool APIConnection::try_send_lock_info(APIConnection *api, void *v_a_lock) {
1226
- lock::Lock *a_lock = reinterpret_cast<lock::Lock *>(v_a_lock);
995
+ bool APIConnection::try_send_lock_info_(lock::Lock *a_lock) {
1227
996
  ListEntitiesLockResponse msg;
1228
- msg.key = a_lock->get_object_id_hash();
1229
- msg.object_id = a_lock->get_object_id();
1230
- if (a_lock->has_own_name())
1231
- msg.name = a_lock->get_name();
1232
- msg.unique_id = get_default_unique_id("lock", a_lock);
1233
- msg.icon = a_lock->get_icon();
1234
997
  msg.assumed_state = a_lock->traits.get_assumed_state();
1235
- msg.disabled_by_default = a_lock->is_disabled_by_default();
1236
- msg.entity_category = static_cast<enums::EntityCategory>(a_lock->get_entity_category());
1237
998
  msg.supports_open = a_lock->traits.get_supports_open();
1238
999
  msg.requires_code = a_lock->traits.get_requires_code();
1239
- return api->send_list_entities_lock_response(msg);
1000
+ msg.unique_id = get_default_unique_id("lock", a_lock);
1001
+ return this->try_send_entity_info_(static_cast<EntityBase *>(a_lock), msg,
1002
+ &APIConnection::send_list_entities_lock_response);
1240
1003
  }
1241
1004
  void APIConnection::lock_command(const LockCommandRequest &msg) {
1242
1005
  lock::Lock *a_lock = App.get_lock_by_key(msg.key);
@@ -1259,45 +1022,31 @@ void APIConnection::lock_command(const LockCommandRequest &msg) {
1259
1022
 
1260
1023
  #ifdef USE_VALVE
1261
1024
  bool APIConnection::send_valve_state(valve::Valve *valve) {
1262
- if (!this->state_subscription_)
1263
- return false;
1264
-
1265
- if (!APIConnection::try_send_valve_state(this, valve)) {
1266
- this->deferred_message_queue_.defer(valve, try_send_valve_state);
1267
- }
1268
-
1269
- return true;
1025
+ return this->send_state_(static_cast<EntityBase *>(valve),
1026
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_valve_state_));
1270
1027
  }
1271
1028
  void APIConnection::send_valve_info(valve::Valve *valve) {
1272
- if (!APIConnection::try_send_valve_info(this, valve)) {
1273
- this->deferred_message_queue_.defer(valve, try_send_valve_info);
1274
- }
1029
+ this->send_info_(static_cast<EntityBase *>(valve),
1030
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_valve_info_));
1275
1031
  }
1276
- bool APIConnection::try_send_valve_state(APIConnection *api, void *v_valve) {
1277
- valve::Valve *valve = reinterpret_cast<valve::Valve *>(v_valve);
1278
- ValveStateResponse resp{};
1279
- resp.key = valve->get_object_id_hash();
1032
+ bool APIConnection::try_send_valve_state_(valve::Valve *valve) {
1033
+ ValveStateResponse resp;
1280
1034
  resp.position = valve->position;
1281
1035
  resp.current_operation = static_cast<enums::ValveOperation>(valve->current_operation);
1282
- return api->send_valve_state_response(resp);
1036
+
1037
+ resp.key = valve->get_object_id_hash();
1038
+ return this->send_valve_state_response(resp);
1283
1039
  }
1284
- bool APIConnection::try_send_valve_info(APIConnection *api, void *v_valve) {
1285
- valve::Valve *valve = reinterpret_cast<valve::Valve *>(v_valve);
1286
- auto traits = valve->get_traits();
1040
+ bool APIConnection::try_send_valve_info_(valve::Valve *valve) {
1287
1041
  ListEntitiesValveResponse msg;
1288
- msg.key = valve->get_object_id_hash();
1289
- msg.object_id = valve->get_object_id();
1290
- if (valve->has_own_name())
1291
- msg.name = valve->get_name();
1292
- msg.unique_id = get_default_unique_id("valve", valve);
1293
- msg.icon = valve->get_icon();
1294
- msg.disabled_by_default = valve->is_disabled_by_default();
1295
- msg.entity_category = static_cast<enums::EntityCategory>(valve->get_entity_category());
1042
+ auto traits = valve->get_traits();
1296
1043
  msg.device_class = valve->get_device_class();
1297
1044
  msg.assumed_state = traits.get_is_assumed_state();
1298
1045
  msg.supports_position = traits.get_supports_position();
1299
1046
  msg.supports_stop = traits.get_supports_stop();
1300
- return api->send_list_entities_valve_response(msg);
1047
+ msg.unique_id = get_default_unique_id("valve", valve);
1048
+ return this->try_send_entity_info_(static_cast<EntityBase *>(valve), msg,
1049
+ &APIConnection::send_list_entities_valve_response);
1301
1050
  }
1302
1051
  void APIConnection::valve_command(const ValveCommandRequest &msg) {
1303
1052
  valve::Valve *valve = App.get_valve_by_key(msg.key);
@@ -1315,48 +1064,29 @@ void APIConnection::valve_command(const ValveCommandRequest &msg) {
1315
1064
 
1316
1065
  #ifdef USE_MEDIA_PLAYER
1317
1066
  bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_player) {
1318
- if (!this->state_subscription_)
1319
- return false;
1320
-
1321
- if (!APIConnection::try_send_media_player_state(this, media_player)) {
1322
- this->deferred_message_queue_.defer(media_player, try_send_media_player_state);
1323
- }
1324
-
1325
- return true;
1067
+ return this->send_state_(static_cast<EntityBase *>(media_player),
1068
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_media_player_state_));
1326
1069
  }
1327
1070
  void APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) {
1328
- if (!APIConnection::try_send_media_player_info(this, media_player)) {
1329
- this->deferred_message_queue_.defer(media_player, try_send_media_player_info);
1330
- }
1071
+ this->send_info_(static_cast<EntityBase *>(media_player),
1072
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_media_player_info_));
1331
1073
  }
1332
- bool APIConnection::try_send_media_player_state(APIConnection *api, void *v_media_player) {
1333
- media_player::MediaPlayer *media_player = reinterpret_cast<media_player::MediaPlayer *>(v_media_player);
1334
- MediaPlayerStateResponse resp{};
1335
- resp.key = media_player->get_object_id_hash();
1336
-
1074
+ bool APIConnection::try_send_media_player_state_(media_player::MediaPlayer *media_player) {
1075
+ MediaPlayerStateResponse resp;
1337
1076
  media_player::MediaPlayerState report_state = media_player->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING
1338
1077
  ? media_player::MEDIA_PLAYER_STATE_PLAYING
1339
1078
  : media_player->state;
1340
1079
  resp.state = static_cast<enums::MediaPlayerState>(report_state);
1341
1080
  resp.volume = media_player->volume;
1342
1081
  resp.muted = media_player->is_muted();
1343
- return api->send_media_player_state_response(resp);
1082
+
1083
+ resp.key = media_player->get_object_id_hash();
1084
+ return this->send_media_player_state_response(resp);
1344
1085
  }
1345
- bool APIConnection::try_send_media_player_info(APIConnection *api, void *v_media_player) {
1346
- media_player::MediaPlayer *media_player = reinterpret_cast<media_player::MediaPlayer *>(v_media_player);
1086
+ bool APIConnection::try_send_media_player_info_(media_player::MediaPlayer *media_player) {
1347
1087
  ListEntitiesMediaPlayerResponse msg;
1348
- msg.key = media_player->get_object_id_hash();
1349
- msg.object_id = media_player->get_object_id();
1350
- if (media_player->has_own_name())
1351
- msg.name = media_player->get_name();
1352
- msg.unique_id = get_default_unique_id("media_player", media_player);
1353
- msg.icon = media_player->get_icon();
1354
- msg.disabled_by_default = media_player->is_disabled_by_default();
1355
- msg.entity_category = static_cast<enums::EntityCategory>(media_player->get_entity_category());
1356
-
1357
1088
  auto traits = media_player->get_traits();
1358
1089
  msg.supports_pause = traits.get_supports_pause();
1359
-
1360
1090
  for (auto &supported_format : traits.get_supported_formats()) {
1361
1091
  MediaPlayerSupportedFormat media_format;
1362
1092
  media_format.format = supported_format.format;
@@ -1366,8 +1096,9 @@ bool APIConnection::try_send_media_player_info(APIConnection *api, void *v_media
1366
1096
  media_format.sample_bytes = supported_format.sample_bytes;
1367
1097
  msg.supported_formats.push_back(media_format);
1368
1098
  }
1369
-
1370
- return api->send_list_entities_media_player_response(msg);
1099
+ msg.unique_id = get_default_unique_id("media_player", media_player);
1100
+ return this->try_send_entity_info_(static_cast<EntityBase *>(media_player), msg,
1101
+ &APIConnection::send_list_entities_media_player_response);
1371
1102
  }
1372
1103
  void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
1373
1104
  media_player::MediaPlayer *media_player = App.get_media_player_by_key(msg.key);
@@ -1402,22 +1133,14 @@ void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage>
1402
1133
  this->image_reader_.set_image(std::move(image));
1403
1134
  }
1404
1135
  void APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
1405
- if (!APIConnection::try_send_camera_info(this, camera)) {
1406
- this->deferred_message_queue_.defer(camera, try_send_camera_info);
1407
- }
1136
+ this->send_info_(static_cast<EntityBase *>(camera),
1137
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_camera_info_));
1408
1138
  }
1409
- bool APIConnection::try_send_camera_info(APIConnection *api, void *v_camera) {
1410
- esp32_camera::ESP32Camera *camera = reinterpret_cast<esp32_camera::ESP32Camera *>(v_camera);
1139
+ bool APIConnection::try_send_camera_info_(esp32_camera::ESP32Camera *camera) {
1411
1140
  ListEntitiesCameraResponse msg;
1412
- msg.key = camera->get_object_id_hash();
1413
- msg.object_id = camera->get_object_id();
1414
- if (camera->has_own_name())
1415
- msg.name = camera->get_name();
1416
1141
  msg.unique_id = get_default_unique_id("camera", camera);
1417
- msg.disabled_by_default = camera->is_disabled_by_default();
1418
- msg.icon = camera->get_icon();
1419
- msg.entity_category = static_cast<enums::EntityCategory>(camera->get_entity_category());
1420
- return api->send_list_entities_camera_response(msg);
1142
+ return this->try_send_entity_info_(static_cast<EntityBase *>(camera), msg,
1143
+ &APIConnection::send_list_entities_camera_response);
1421
1144
  }
1422
1145
  void APIConnection::camera_image(const CameraImageRequest &msg) {
1423
1146
  if (esp32_camera::global_esp32_camera == nullptr)
@@ -1606,43 +1329,28 @@ void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetCon
1606
1329
 
1607
1330
  #ifdef USE_ALARM_CONTROL_PANEL
1608
1331
  bool APIConnection::send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1609
- if (!this->state_subscription_)
1610
- return false;
1611
-
1612
- if (!APIConnection::try_send_alarm_control_panel_state(this, a_alarm_control_panel)) {
1613
- this->deferred_message_queue_.defer(a_alarm_control_panel, try_send_alarm_control_panel_state);
1614
- }
1615
-
1616
- return true;
1332
+ return this->send_state_(static_cast<EntityBase *>(a_alarm_control_panel),
1333
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_alarm_control_panel_state_));
1617
1334
  }
1618
1335
  void APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1619
- if (!APIConnection::try_send_alarm_control_panel_info(this, a_alarm_control_panel)) {
1620
- this->deferred_message_queue_.defer(a_alarm_control_panel, try_send_alarm_control_panel_info);
1621
- }
1336
+ this->send_info_(static_cast<EntityBase *>(a_alarm_control_panel),
1337
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_alarm_control_panel_info_));
1622
1338
  }
1623
- bool APIConnection::try_send_alarm_control_panel_state(APIConnection *api, void *v_a_alarm_control_panel) {
1624
- alarm_control_panel::AlarmControlPanel *a_alarm_control_panel =
1625
- reinterpret_cast<alarm_control_panel::AlarmControlPanel *>(v_a_alarm_control_panel);
1626
- AlarmControlPanelStateResponse resp{};
1627
- resp.key = a_alarm_control_panel->get_object_id_hash();
1339
+ bool APIConnection::try_send_alarm_control_panel_state_(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1340
+ AlarmControlPanelStateResponse resp;
1628
1341
  resp.state = static_cast<enums::AlarmControlPanelState>(a_alarm_control_panel->get_state());
1629
- return api->send_alarm_control_panel_state_response(resp);
1342
+
1343
+ resp.key = a_alarm_control_panel->get_object_id_hash();
1344
+ return this->send_alarm_control_panel_state_response(resp);
1630
1345
  }
1631
- bool APIConnection::try_send_alarm_control_panel_info(APIConnection *api, void *v_a_alarm_control_panel) {
1632
- alarm_control_panel::AlarmControlPanel *a_alarm_control_panel =
1633
- reinterpret_cast<alarm_control_panel::AlarmControlPanel *>(v_a_alarm_control_panel);
1346
+ bool APIConnection::try_send_alarm_control_panel_info_(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1634
1347
  ListEntitiesAlarmControlPanelResponse msg;
1635
- msg.key = a_alarm_control_panel->get_object_id_hash();
1636
- msg.object_id = a_alarm_control_panel->get_object_id();
1637
- msg.name = a_alarm_control_panel->get_name();
1638
- msg.unique_id = get_default_unique_id("alarm_control_panel", a_alarm_control_panel);
1639
- msg.icon = a_alarm_control_panel->get_icon();
1640
- msg.disabled_by_default = a_alarm_control_panel->is_disabled_by_default();
1641
- msg.entity_category = static_cast<enums::EntityCategory>(a_alarm_control_panel->get_entity_category());
1642
1348
  msg.supported_features = a_alarm_control_panel->get_supported_features();
1643
1349
  msg.requires_code = a_alarm_control_panel->get_requires_code();
1644
1350
  msg.requires_code_to_arm = a_alarm_control_panel->get_requires_code_to_arm();
1645
- return api->send_list_entities_alarm_control_panel_response(msg);
1351
+ msg.unique_id = get_default_unique_id("alarm_control_panel", a_alarm_control_panel);
1352
+ return this->try_send_entity_info_(static_cast<EntityBase *>(a_alarm_control_panel), msg,
1353
+ &APIConnection::send_list_entities_alarm_control_panel_response);
1646
1354
  }
1647
1355
  void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) {
1648
1356
  alarm_control_panel::AlarmControlPanel *a_alarm_control_panel = App.get_alarm_control_panel_by_key(msg.key);
@@ -1680,63 +1388,45 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe
1680
1388
 
1681
1389
  #ifdef USE_EVENT
1682
1390
  void APIConnection::send_event(event::Event *event, std::string event_type) {
1683
- if (!APIConnection::try_send_event(this, event, std::move(event_type))) {
1684
- this->deferred_message_queue_.defer(event, try_send_event);
1685
- }
1391
+ this->send_state_with_value_(event, &APIConnection::try_send_event_, &APIConnection::try_send_event_,
1392
+ std::move(event_type));
1686
1393
  }
1687
1394
  void APIConnection::send_event_info(event::Event *event) {
1688
- if (!APIConnection::try_send_event_info(this, event)) {
1689
- this->deferred_message_queue_.defer(event, try_send_event_info);
1690
- }
1395
+ this->send_info_(static_cast<EntityBase *>(event),
1396
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_event_info_));
1691
1397
  }
1692
- bool APIConnection::try_send_event(APIConnection *api, void *v_event) {
1693
- event::Event *event = reinterpret_cast<event::Event *>(v_event);
1694
- return APIConnection::try_send_event(api, event, *(event->last_event_type));
1398
+ bool APIConnection::try_send_event_(event::Event *event) {
1399
+ return this->try_send_event_(event, *(event->last_event_type));
1695
1400
  }
1696
- bool APIConnection::try_send_event(APIConnection *api, event::Event *event, std::string event_type) {
1697
- EventResponse resp{};
1698
- resp.key = event->get_object_id_hash();
1401
+ bool APIConnection::try_send_event_(event::Event *event, std::string event_type) {
1402
+ EventResponse resp;
1699
1403
  resp.event_type = std::move(event_type);
1700
- return api->send_event_response(resp);
1404
+
1405
+ resp.key = event->get_object_id_hash();
1406
+ return this->send_event_response(resp);
1701
1407
  }
1702
- bool APIConnection::try_send_event_info(APIConnection *api, void *v_event) {
1703
- event::Event *event = reinterpret_cast<event::Event *>(v_event);
1408
+ bool APIConnection::try_send_event_info_(event::Event *event) {
1704
1409
  ListEntitiesEventResponse msg;
1705
- msg.key = event->get_object_id_hash();
1706
- msg.object_id = event->get_object_id();
1707
- if (event->has_own_name())
1708
- msg.name = event->get_name();
1709
- msg.unique_id = get_default_unique_id("event", event);
1710
- msg.icon = event->get_icon();
1711
- msg.disabled_by_default = event->is_disabled_by_default();
1712
- msg.entity_category = static_cast<enums::EntityCategory>(event->get_entity_category());
1713
1410
  msg.device_class = event->get_device_class();
1714
1411
  for (const auto &event_type : event->get_event_types())
1715
1412
  msg.event_types.push_back(event_type);
1716
- return api->send_list_entities_event_response(msg);
1413
+ msg.unique_id = get_default_unique_id("event", event);
1414
+ return this->try_send_entity_info_(static_cast<EntityBase *>(event), msg,
1415
+ &APIConnection::send_list_entities_event_response);
1717
1416
  }
1718
1417
  #endif
1719
1418
 
1720
1419
  #ifdef USE_UPDATE
1721
1420
  bool APIConnection::send_update_state(update::UpdateEntity *update) {
1722
- if (!this->state_subscription_)
1723
- return false;
1724
-
1725
- if (!APIConnection::try_send_update_state(this, update)) {
1726
- this->deferred_message_queue_.defer(update, try_send_update_state);
1727
- }
1728
-
1729
- return true;
1421
+ return this->send_state_(static_cast<EntityBase *>(update),
1422
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_update_state_));
1730
1423
  }
1731
1424
  void APIConnection::send_update_info(update::UpdateEntity *update) {
1732
- if (!APIConnection::try_send_update_info(this, update)) {
1733
- this->deferred_message_queue_.defer(update, try_send_update_info);
1734
- }
1425
+ this->send_info_(static_cast<EntityBase *>(update),
1426
+ reinterpret_cast<send_message_t>(&APIConnection::try_send_update_info_));
1735
1427
  }
1736
- bool APIConnection::try_send_update_state(APIConnection *api, void *v_update) {
1737
- update::UpdateEntity *update = reinterpret_cast<update::UpdateEntity *>(v_update);
1738
- UpdateStateResponse resp{};
1739
- resp.key = update->get_object_id_hash();
1428
+ bool APIConnection::try_send_update_state_(update::UpdateEntity *update) {
1429
+ UpdateStateResponse resp;
1740
1430
  resp.missing_state = !update->has_state();
1741
1431
  if (update->has_state()) {
1742
1432
  resp.in_progress = update->state == update::UpdateState::UPDATE_STATE_INSTALLING;
@@ -1751,21 +1441,15 @@ bool APIConnection::try_send_update_state(APIConnection *api, void *v_update) {
1751
1441
  resp.release_url = update->update_info.release_url;
1752
1442
  }
1753
1443
 
1754
- return api->send_update_state_response(resp);
1444
+ resp.key = update->get_object_id_hash();
1445
+ return this->send_update_state_response(resp);
1755
1446
  }
1756
- bool APIConnection::try_send_update_info(APIConnection *api, void *v_update) {
1757
- update::UpdateEntity *update = reinterpret_cast<update::UpdateEntity *>(v_update);
1447
+ bool APIConnection::try_send_update_info_(update::UpdateEntity *update) {
1758
1448
  ListEntitiesUpdateResponse msg;
1759
- msg.key = update->get_object_id_hash();
1760
- msg.object_id = update->get_object_id();
1761
- if (update->has_own_name())
1762
- msg.name = update->get_name();
1763
- msg.unique_id = get_default_unique_id("update", update);
1764
- msg.icon = update->get_icon();
1765
- msg.disabled_by_default = update->is_disabled_by_default();
1766
- msg.entity_category = static_cast<enums::EntityCategory>(update->get_entity_category());
1767
1449
  msg.device_class = update->get_device_class();
1768
- return api->send_list_entities_update_response(msg);
1450
+ msg.unique_id = get_default_unique_id("update", update);
1451
+ return this->try_send_entity_info_(static_cast<EntityBase *>(update), msg,
1452
+ &APIConnection::send_list_entities_update_response);
1769
1453
  }
1770
1454
  void APIConnection::update_command(const UpdateCommandRequest &msg) {
1771
1455
  update::UpdateEntity *update = App.get_update_by_key(msg.key);
@@ -1939,29 +1623,32 @@ NoiseEncryptionSetKeyResponse APIConnection::noise_encryption_set_key(const Nois
1939
1623
  void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) {
1940
1624
  state_subs_at_ = 0;
1941
1625
  }
1942
- bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) {
1626
+ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
1943
1627
  if (this->remove_)
1944
1628
  return false;
1945
- if (!this->helper_->can_write_without_blocking()) {
1946
- delay(0);
1947
- APIError err = this->helper_->loop();
1948
- if (err != APIError::OK) {
1949
- on_fatal_error();
1950
- ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
1951
- api_error_to_str(err), errno);
1952
- return false;
1953
- }
1954
- if (!this->helper_->can_write_without_blocking()) {
1955
- // SubscribeLogsResponse
1956
- if (message_type != 29) {
1957
- ESP_LOGV(TAG, "Cannot send message because of TCP buffer space");
1958
- }
1959
- delay(0);
1960
- return false;
1961
- }
1629
+ if (this->helper_->can_write_without_blocking())
1630
+ return true;
1631
+ delay(0);
1632
+ APIError err = this->helper_->loop();
1633
+ if (err != APIError::OK) {
1634
+ on_fatal_error();
1635
+ ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
1636
+ api_error_to_str(err), errno);
1637
+ return false;
1638
+ }
1639
+ if (this->helper_->can_write_without_blocking())
1640
+ return true;
1641
+ if (log_out_of_space) {
1642
+ ESP_LOGV(TAG, "Cannot send message because of TCP buffer space");
1643
+ }
1644
+ return false;
1645
+ }
1646
+ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) {
1647
+ if (!this->try_to_clear_buffer(message_type != 29)) { // SubscribeLogsResponse
1648
+ return false;
1962
1649
  }
1963
1650
 
1964
- APIError err = this->helper_->write_packet(message_type, buffer.get_buffer()->data(), buffer.get_buffer()->size());
1651
+ APIError err = this->helper_->write_protobuf_packet(message_type, buffer);
1965
1652
  if (err == APIError::WOULD_BLOCK)
1966
1653
  return false;
1967
1654
  if (err != APIError::OK) {