esphome 2024.9.1__py3-none-any.whl → 2024.10.0__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 (196) hide show
  1. esphome/components/aic3204/__init__.py +0 -0
  2. esphome/components/aic3204/aic3204.cpp +173 -0
  3. esphome/components/aic3204/aic3204.h +88 -0
  4. esphome/components/aic3204/audio_dac.py +52 -0
  5. esphome/components/aic3204/automation.h +23 -0
  6. esphome/components/alarm_control_panel/__init__.py +3 -4
  7. esphome/components/animation/__init__.py +16 -12
  8. esphome/components/api/api_connection.cpp +2 -0
  9. esphome/components/api/api_connection.h +3 -1
  10. esphome/components/api/api_frame_helper.cpp +2 -1
  11. esphome/components/api/api_frame_helper.h +2 -1
  12. esphome/components/api/api_server.cpp +2 -0
  13. esphome/components/api/api_server.h +3 -1
  14. esphome/components/api/custom_api_device.h +3 -2
  15. esphome/components/api/homeassistant_service.h +4 -3
  16. esphome/components/api/list_entities.cpp +2 -0
  17. esphome/components/api/list_entities.h +3 -2
  18. esphome/components/api/subscribe_state.cpp +2 -0
  19. esphome/components/api/subscribe_state.h +3 -2
  20. esphome/components/audio_dac/__init__.py +57 -0
  21. esphome/components/audio_dac/audio_dac.h +23 -0
  22. esphome/components/audio_dac/automation.h +43 -0
  23. esphome/components/bang_bang/bang_bang_climate.cpp +5 -2
  24. esphome/components/bedjet/bedjet_codec.cpp +4 -2
  25. esphome/components/binary_sensor/__init__.py +3 -4
  26. esphome/components/bl0906/sensor.py +3 -2
  27. esphome/components/button/__init__.py +3 -4
  28. esphome/components/ch422g/__init__.py +26 -17
  29. esphome/components/ch422g/ch422g.cpp +66 -49
  30. esphome/components/ch422g/ch422g.h +17 -19
  31. esphome/components/climate/__init__.py +3 -4
  32. esphome/components/cover/__init__.py +4 -5
  33. esphome/components/cse7766/cse7766.cpp +12 -1
  34. esphome/components/cse7766/cse7766.h +4 -0
  35. esphome/components/cse7766/sensor.py +13 -1
  36. esphome/components/cst816/touchscreen/__init__.py +7 -4
  37. esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +20 -19
  38. esphome/components/cst816/touchscreen/cst816_touchscreen.h +2 -0
  39. esphome/components/datetime/__init__.py +21 -14
  40. esphome/components/datetime/datetime_base.h +8 -1
  41. esphome/components/datetime/datetime_entity.cpp +2 -0
  42. esphome/components/datetime/datetime_entity.h +2 -0
  43. esphome/components/datetime/time_entity.cpp +2 -0
  44. esphome/components/datetime/time_entity.h +2 -0
  45. esphome/components/esp32/__init__.py +20 -4
  46. esphome/components/esp32_improv/__init__.py +82 -1
  47. esphome/components/esp32_improv/automation.h +72 -0
  48. esphome/components/esp32_improv/esp32_improv_component.cpp +13 -5
  49. esphome/components/esp32_improv/esp32_improv_component.h +15 -0
  50. esphome/components/ethernet/__init__.py +5 -0
  51. esphome/components/ethernet/ethernet_component.cpp +13 -0
  52. esphome/components/ethernet/ethernet_component.h +1 -0
  53. esphome/components/event/__init__.py +20 -12
  54. esphome/components/fan/__init__.py +3 -4
  55. esphome/components/gp2y1010au0f/__init__.py +0 -0
  56. esphome/components/gp2y1010au0f/gp2y1010au0f.cpp +67 -0
  57. esphome/components/gp2y1010au0f/gp2y1010au0f.h +52 -0
  58. esphome/components/gp2y1010au0f/sensor.py +61 -0
  59. esphome/components/gpio_expander/__init__.py +0 -0
  60. esphome/components/gpio_expander/cached_gpio.h +38 -0
  61. esphome/components/grove_gas_mc_v2/__init__.py +0 -0
  62. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +88 -0
  63. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +39 -0
  64. esphome/components/grove_gas_mc_v2/sensor.py +77 -0
  65. esphome/components/haier/climate.py +4 -3
  66. esphome/components/haier/haier_base.cpp +63 -8
  67. esphome/components/haier/haier_base.h +29 -3
  68. esphome/components/haier/hon_climate.cpp +122 -65
  69. esphome/components/haier/hon_climate.h +18 -2
  70. esphome/components/haier/smartair2_climate.cpp +21 -21
  71. esphome/components/haier/switch/__init__.py +91 -0
  72. esphome/components/haier/switch/beeper.cpp +14 -0
  73. esphome/components/haier/switch/beeper.h +18 -0
  74. esphome/components/haier/switch/display.cpp +14 -0
  75. esphome/components/haier/switch/display.h +18 -0
  76. esphome/components/haier/switch/health_mode.cpp +14 -0
  77. esphome/components/haier/switch/health_mode.h +18 -0
  78. esphome/components/haier/switch/quiet_mode.cpp +14 -0
  79. esphome/components/haier/switch/quiet_mode.h +18 -0
  80. esphome/components/hmac_md5/hmac_md5.cpp +2 -0
  81. esphome/components/hmac_md5/hmac_md5.h +2 -1
  82. esphome/components/i2s_audio/speaker/__init__.py +19 -0
  83. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
  84. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +2 -0
  85. esphome/components/ili9xxx/ili9xxx_display.h +1 -0
  86. esphome/components/image/__init__.py +12 -12
  87. esphome/components/image/image.cpp +44 -0
  88. esphome/components/image/image.h +17 -2
  89. esphome/components/inkplate6/display.py +2 -0
  90. esphome/components/inkplate6/inkplate.h +30 -2
  91. esphome/components/light/__init__.py +3 -4
  92. esphome/components/lock/__init__.py +3 -4
  93. esphome/components/lvgl/__init__.py +16 -5
  94. esphome/components/lvgl/defines.py +1 -0
  95. esphome/components/lvgl/hello_world.py +64 -0
  96. esphome/components/lvgl/lv_validation.py +159 -3
  97. esphome/components/lvgl/lvgl_esphome.cpp +0 -43
  98. esphome/components/lvgl/lvgl_esphome.h +0 -4
  99. esphome/components/lvgl/styles.py +3 -2
  100. esphome/components/lvgl/text/__init__.py +3 -3
  101. esphome/components/lvgl/widgets/__init__.py +2 -0
  102. esphome/components/lvgl/widgets/animimg.py +3 -4
  103. esphome/components/lvgl/widgets/dropdown.py +5 -1
  104. esphome/components/lvgl/widgets/meter.py +16 -11
  105. esphome/components/md5/__init__.py +6 -0
  106. esphome/components/md5/md5.cpp +2 -0
  107. esphome/components/md5/md5.h +2 -0
  108. esphome/components/micro_wake_word/__init__.py +7 -0
  109. esphome/components/mics_4514/sensor.py +11 -26
  110. esphome/components/modbus_controller/__init__.py +7 -5
  111. esphome/components/modbus_controller/binary_sensor/__init__.py +6 -6
  112. esphome/components/modbus_controller/number/__init__.py +5 -6
  113. esphome/components/modbus_controller/output/__init__.py +10 -14
  114. esphome/components/modbus_controller/select/__init__.py +1 -1
  115. esphome/components/modbus_controller/sensor/__init__.py +7 -7
  116. esphome/components/modbus_controller/switch/__init__.py +6 -7
  117. esphome/components/modbus_controller/text_sensor/__init__.py +8 -9
  118. esphome/components/mqtt/__init__.py +3 -0
  119. esphome/components/mqtt/mqtt_client.cpp +2 -0
  120. esphome/components/mqtt/mqtt_client.h +2 -0
  121. esphome/components/nau7802/__init__.py +0 -0
  122. esphome/components/nau7802/nau7802.cpp +323 -0
  123. esphome/components/nau7802/nau7802.h +121 -0
  124. esphome/components/nau7802/sensor.py +134 -0
  125. esphome/components/nextion/base_component.py +1 -0
  126. esphome/components/nextion/display.py +4 -0
  127. esphome/components/nextion/nextion.cpp +19 -4
  128. esphome/components/nextion/nextion.h +16 -0
  129. esphome/components/npi19/__init__.py +0 -0
  130. esphome/components/npi19/npi19.cpp +111 -0
  131. esphome/components/npi19/npi19.h +30 -0
  132. esphome/components/npi19/sensor.py +52 -0
  133. esphome/components/number/__init__.py +3 -5
  134. esphome/components/online_image/__init__.py +1 -1
  135. esphome/components/online_image/online_image.h +1 -2
  136. esphome/components/opentherm/__init__.py +57 -0
  137. esphome/components/opentherm/hub.cpp +277 -0
  138. esphome/components/opentherm/hub.h +110 -0
  139. esphome/components/opentherm/opentherm.cpp +568 -0
  140. esphome/components/opentherm/opentherm.h +347 -0
  141. esphome/components/pulse_counter/pulse_counter_sensor.cpp +8 -1
  142. esphome/components/pulse_counter/pulse_counter_sensor.h +1 -0
  143. esphome/components/radon_eye_ble/radon_eye_listener.cpp +10 -3
  144. esphome/components/remote_transmitter/__init__.py +18 -2
  145. esphome/components/remote_transmitter/remote_transmitter.h +6 -0
  146. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +2 -0
  147. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +2 -0
  148. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +2 -0
  149. esphome/components/rp2040/__init__.py +13 -14
  150. esphome/components/select/__init__.py +3 -4
  151. esphome/components/sensor/__init__.py +3 -4
  152. esphome/components/shelly_dimmer/shelly_dimmer.cpp +32 -32
  153. esphome/components/shelly_dimmer/shelly_dimmer.h +2 -0
  154. esphome/components/st7701s/st7701s.cpp +21 -8
  155. esphome/components/st7701s/st7701s.h +2 -0
  156. esphome/components/switch/__init__.py +3 -4
  157. esphome/components/tca9555/__init__.py +72 -0
  158. esphome/components/tca9555/tca9555.cpp +140 -0
  159. esphome/components/tca9555/tca9555.h +64 -0
  160. esphome/components/tcs34725/tcs34725.cpp +62 -64
  161. esphome/components/tem3200/__init__.py +0 -0
  162. esphome/components/tem3200/sensor.py +55 -0
  163. esphome/components/tem3200/tem3200.cpp +151 -0
  164. esphome/components/tem3200/tem3200.h +30 -0
  165. esphome/components/template/binary_sensor/__init__.py +19 -6
  166. esphome/components/text/__init__.py +3 -4
  167. esphome/components/text_sensor/__init__.py +3 -4
  168. esphome/components/thermostat/climate.py +11 -9
  169. esphome/components/thermostat/thermostat_climate.cpp +21 -15
  170. esphome/components/tm1638/binary_sensor/__init__.py +3 -2
  171. esphome/components/tm1638/display.py +5 -5
  172. esphome/components/tm1638/output/__init__.py +3 -2
  173. esphome/components/tm1638/switch/__init__.py +3 -2
  174. esphome/components/touchscreen/touchscreen.cpp +2 -2
  175. esphome/components/update/__init__.py +3 -4
  176. esphome/components/valve/__init__.py +3 -4
  177. esphome/components/web_server/__init__.py +78 -22
  178. esphome/components/web_server/server_index_v3.h +3989 -3979
  179. esphome/components/web_server/web_server.cpp +219 -34
  180. esphome/components/web_server/web_server.h +10 -1
  181. esphome/components/wifi/wifi_component_esp_idf.cpp +4 -5
  182. esphome/config_validation.py +1 -0
  183. esphome/const.py +12 -2
  184. esphome/core/defines.h +4 -2
  185. esphome/core/helpers.cpp +46 -10
  186. esphome/core/helpers.h +8 -0
  187. esphome/core/ring_buffer.cpp +12 -2
  188. esphome/core/ring_buffer.h +3 -0
  189. esphome/voluptuous_schema.py +3 -1
  190. esphome/wizard.py +0 -3
  191. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/METADATA +5 -3
  192. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/RECORD +196 -147
  193. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/LICENSE +0 -0
  194. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/WHEEL +0 -0
  195. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/entry_points.txt +0 -0
  196. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/top_level.txt +0 -0
@@ -105,6 +105,14 @@ void WebServer::setup() {
105
105
  // Configure reconnect timeout and send config
106
106
  client->send(this->get_config_json().c_str(), "ping", millis(), 30000);
107
107
 
108
+ for (auto &group : this->sorting_groups_) {
109
+ client->send(json::build_json([group](JsonObject root) {
110
+ root["name"] = group.second.name;
111
+ root["sorting_weight"] = group.second.weight;
112
+ }).c_str(),
113
+ "sorting_group");
114
+ }
115
+
108
116
  this->entities_iterator_.begin(this->include_internal_);
109
117
  });
110
118
 
@@ -219,9 +227,16 @@ void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlM
219
227
  for (sensor::Sensor *obj : App.get_sensors()) {
220
228
  if (obj->get_object_id() != match.id)
221
229
  continue;
222
- std::string data = this->sensor_json(obj, obj->state, DETAIL_STATE);
223
- request->send(200, "application/json", data.c_str());
224
- return;
230
+ if (request->method() == HTTP_GET && match.method.empty()) {
231
+ auto detail = DETAIL_STATE;
232
+ auto *param = request->getParam("detail");
233
+ if (param && param->value() == "all") {
234
+ detail = DETAIL_ALL;
235
+ }
236
+ std::string data = this->sensor_json(obj, obj->state, detail);
237
+ request->send(200, "application/json", data.c_str());
238
+ return;
239
+ }
225
240
  }
226
241
  request->send(404);
227
242
  }
@@ -239,6 +254,9 @@ std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail
239
254
  if (start_config == DETAIL_ALL) {
240
255
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
241
256
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
257
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
258
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
259
+ }
242
260
  }
243
261
  if (!obj->get_unit_of_measurement().empty())
244
262
  root["uom"] = obj->get_unit_of_measurement();
@@ -257,9 +275,16 @@ void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const
257
275
  for (text_sensor::TextSensor *obj : App.get_text_sensors()) {
258
276
  if (obj->get_object_id() != match.id)
259
277
  continue;
260
- std::string data = this->text_sensor_json(obj, obj->state, DETAIL_STATE);
261
- request->send(200, "application/json", data.c_str());
262
- return;
278
+ if (request->method() == HTTP_GET && match.method.empty()) {
279
+ auto detail = DETAIL_STATE;
280
+ auto *param = request->getParam("detail");
281
+ if (param && param->value() == "all") {
282
+ detail = DETAIL_ALL;
283
+ }
284
+ std::string data = this->text_sensor_json(obj, obj->state, detail);
285
+ request->send(200, "application/json", data.c_str());
286
+ return;
287
+ }
263
288
  }
264
289
  request->send(404);
265
290
  }
@@ -270,6 +295,9 @@ std::string WebServer::text_sensor_json(text_sensor::TextSensor *obj, const std:
270
295
  if (start_config == DETAIL_ALL) {
271
296
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
272
297
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
298
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
299
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
300
+ }
273
301
  }
274
302
  }
275
303
  });
@@ -288,7 +316,12 @@ void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlM
288
316
  continue;
289
317
 
290
318
  if (request->method() == HTTP_GET && match.method.empty()) {
291
- std::string data = this->switch_json(obj, obj->state, DETAIL_STATE);
319
+ auto detail = DETAIL_STATE;
320
+ auto *param = request->getParam("detail");
321
+ if (param && param->value() == "all") {
322
+ detail = DETAIL_ALL;
323
+ }
324
+ std::string data = this->switch_json(obj, obj->state, detail);
292
325
  request->send(200, "application/json", data.c_str());
293
326
  } else if (match.method == "toggle") {
294
327
  this->schedule_([obj]() { obj->toggle(); });
@@ -313,6 +346,9 @@ std::string WebServer::switch_json(switch_::Switch *obj, bool value, JsonDetail
313
346
  root["assumed_state"] = obj->assumed_state();
314
347
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
315
348
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
349
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
350
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
351
+ }
316
352
  }
317
353
  }
318
354
  });
@@ -324,7 +360,15 @@ void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlM
324
360
  for (button::Button *obj : App.get_buttons()) {
325
361
  if (obj->get_object_id() != match.id)
326
362
  continue;
327
- if (match.method == "press") {
363
+ if (request->method() == HTTP_GET && match.method.empty()) {
364
+ auto detail = DETAIL_STATE;
365
+ auto *param = request->getParam("detail");
366
+ if (param && param->value() == "all") {
367
+ detail = DETAIL_ALL;
368
+ }
369
+ std::string data = this->button_json(obj, detail);
370
+ request->send(200, "application/json", data.c_str());
371
+ } else if (match.method == "press") {
328
372
  this->schedule_([obj]() { obj->press(); });
329
373
  request->send(200);
330
374
  return;
@@ -341,6 +385,9 @@ std::string WebServer::button_json(button::Button *obj, JsonDetail start_config)
341
385
  if (start_config == DETAIL_ALL) {
342
386
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
343
387
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
388
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
389
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
390
+ }
344
391
  }
345
392
  }
346
393
  });
@@ -357,9 +404,16 @@ void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, con
357
404
  for (binary_sensor::BinarySensor *obj : App.get_binary_sensors()) {
358
405
  if (obj->get_object_id() != match.id)
359
406
  continue;
360
- std::string data = this->binary_sensor_json(obj, obj->state, DETAIL_STATE);
361
- request->send(200, "application/json", data.c_str());
362
- return;
407
+ if (request->method() == HTTP_GET && match.method.empty()) {
408
+ auto detail = DETAIL_STATE;
409
+ auto *param = request->getParam("detail");
410
+ if (param && param->value() == "all") {
411
+ detail = DETAIL_ALL;
412
+ }
413
+ std::string data = this->binary_sensor_json(obj, obj->state, detail);
414
+ request->send(200, "application/json", data.c_str());
415
+ return;
416
+ }
363
417
  }
364
418
  request->send(404);
365
419
  }
@@ -370,6 +424,9 @@ std::string WebServer::binary_sensor_json(binary_sensor::BinarySensor *obj, bool
370
424
  if (start_config == DETAIL_ALL) {
371
425
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
372
426
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
427
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
428
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
429
+ }
373
430
  }
374
431
  }
375
432
  });
@@ -388,7 +445,12 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc
388
445
  continue;
389
446
 
390
447
  if (request->method() == HTTP_GET && match.method.empty()) {
391
- std::string data = this->fan_json(obj, DETAIL_STATE);
448
+ auto detail = DETAIL_STATE;
449
+ auto *param = request->getParam("detail");
450
+ if (param && param->value() == "all") {
451
+ detail = DETAIL_ALL;
452
+ }
453
+ std::string data = this->fan_json(obj, detail);
392
454
  request->send(200, "application/json", data.c_str());
393
455
  } else if (match.method == "toggle") {
394
456
  this->schedule_([obj]() { obj->toggle().perform(); });
@@ -448,6 +510,9 @@ std::string WebServer::fan_json(fan::Fan *obj, JsonDetail start_config) {
448
510
  if (start_config == DETAIL_ALL) {
449
511
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
450
512
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
513
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
514
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
515
+ }
451
516
  }
452
517
  }
453
518
  });
@@ -466,7 +531,12 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa
466
531
  continue;
467
532
 
468
533
  if (request->method() == HTTP_GET && match.method.empty()) {
469
- std::string data = this->light_json(obj, DETAIL_STATE);
534
+ auto detail = DETAIL_STATE;
535
+ auto *param = request->getParam("detail");
536
+ if (param && param->value() == "all") {
537
+ detail = DETAIL_ALL;
538
+ }
539
+ std::string data = this->light_json(obj, detail);
470
540
  request->send(200, "application/json", data.c_str());
471
541
  } else if (match.method == "toggle") {
472
542
  this->schedule_([obj]() { obj->toggle().perform(); });
@@ -559,6 +629,9 @@ std::string WebServer::light_json(light::LightState *obj, JsonDetail start_confi
559
629
  }
560
630
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
561
631
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
632
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
633
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
634
+ }
562
635
  }
563
636
  }
564
637
  });
@@ -577,9 +650,14 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa
577
650
  continue;
578
651
 
579
652
  if (request->method() == HTTP_GET && match.method.empty()) {
580
- std::string data = this->cover_json(obj, DETAIL_STATE);
653
+ auto detail = DETAIL_STATE;
654
+ auto *param = request->getParam("detail");
655
+ if (param && param->value() == "all") {
656
+ detail = DETAIL_ALL;
657
+ }
658
+ std::string data = this->cover_json(obj, detail);
581
659
  request->send(200, "application/json", data.c_str());
582
- continue;
660
+ return;
583
661
  }
584
662
 
585
663
  auto call = obj->make_call();
@@ -635,6 +713,9 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) {
635
713
  if (start_config == DETAIL_ALL) {
636
714
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
637
715
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
716
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
717
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
718
+ }
638
719
  }
639
720
  }
640
721
  });
@@ -653,7 +734,12 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM
653
734
  continue;
654
735
 
655
736
  if (request->method() == HTTP_GET && match.method.empty()) {
656
- std::string data = this->number_json(obj, obj->state, DETAIL_STATE);
737
+ auto detail = DETAIL_STATE;
738
+ auto *param = request->getParam("detail");
739
+ if (param && param->value() == "all") {
740
+ detail = DETAIL_ALL;
741
+ }
742
+ std::string data = this->number_json(obj, obj->state, detail);
657
743
  request->send(200, "application/json", data.c_str());
658
744
  return;
659
745
  }
@@ -691,6 +777,9 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail
691
777
  root["uom"] = obj->traits.get_unit_of_measurement();
692
778
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
693
779
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
780
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
781
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
782
+ }
694
783
  }
695
784
  }
696
785
  if (std::isnan(value)) {
@@ -717,8 +806,13 @@ void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMat
717
806
  for (auto *obj : App.get_dates()) {
718
807
  if (obj->get_object_id() != match.id)
719
808
  continue;
720
- if (request->method() == HTTP_GET) {
721
- std::string data = this->date_json(obj, DETAIL_STATE);
809
+ if (request->method() == HTTP_GET && match.method.empty()) {
810
+ auto detail = DETAIL_STATE;
811
+ auto *param = request->getParam("detail");
812
+ if (param && param->value() == "all") {
813
+ detail = DETAIL_ALL;
814
+ }
815
+ std::string data = this->date_json(obj, detail);
722
816
  request->send(200, "application/json", data.c_str());
723
817
  return;
724
818
  }
@@ -755,6 +849,9 @@ std::string WebServer::date_json(datetime::DateEntity *obj, JsonDetail start_con
755
849
  if (start_config == DETAIL_ALL) {
756
850
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
757
851
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
852
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
853
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
854
+ }
758
855
  }
759
856
  }
760
857
  });
@@ -772,7 +869,12 @@ void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMat
772
869
  if (obj->get_object_id() != match.id)
773
870
  continue;
774
871
  if (request->method() == HTTP_GET && match.method.empty()) {
775
- std::string data = this->time_json(obj, DETAIL_STATE);
872
+ auto detail = DETAIL_STATE;
873
+ auto *param = request->getParam("detail");
874
+ if (param && param->value() == "all") {
875
+ detail = DETAIL_ALL;
876
+ }
877
+ std::string data = this->time_json(obj, detail);
776
878
  request->send(200, "application/json", data.c_str());
777
879
  return;
778
880
  }
@@ -808,6 +910,9 @@ std::string WebServer::time_json(datetime::TimeEntity *obj, JsonDetail start_con
808
910
  if (start_config == DETAIL_ALL) {
809
911
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
810
912
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
913
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
914
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
915
+ }
811
916
  }
812
917
  }
813
918
  });
@@ -825,7 +930,12 @@ void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const Ur
825
930
  if (obj->get_object_id() != match.id)
826
931
  continue;
827
932
  if (request->method() == HTTP_GET && match.method.empty()) {
828
- std::string data = this->datetime_json(obj, DETAIL_STATE);
933
+ auto detail = DETAIL_STATE;
934
+ auto *param = request->getParam("detail");
935
+ if (param && param->value() == "all") {
936
+ detail = DETAIL_ALL;
937
+ }
938
+ std::string data = this->datetime_json(obj, detail);
829
939
  request->send(200, "application/json", data.c_str());
830
940
  return;
831
941
  }
@@ -862,6 +972,9 @@ std::string WebServer::datetime_json(datetime::DateTimeEntity *obj, JsonDetail s
862
972
  if (start_config == DETAIL_ALL) {
863
973
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
864
974
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
975
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
976
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
977
+ }
865
978
  }
866
979
  }
867
980
  });
@@ -880,8 +993,13 @@ void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMat
880
993
  continue;
881
994
 
882
995
  if (request->method() == HTTP_GET && match.method.empty()) {
883
- std::string data = this->text_json(obj, obj->state, DETAIL_STATE);
884
- request->send(200, "text/json", data.c_str());
996
+ auto detail = DETAIL_STATE;
997
+ auto *param = request->getParam("detail");
998
+ if (param && param->value() == "all") {
999
+ detail = DETAIL_ALL;
1000
+ }
1001
+ std::string data = this->text_json(obj, obj->state, detail);
1002
+ request->send(200, "application/json", data.c_str());
885
1003
  return;
886
1004
  }
887
1005
  if (match.method != "set") {
@@ -918,6 +1036,9 @@ std::string WebServer::text_json(text::Text *obj, const std::string &value, Json
918
1036
  root["mode"] = (int) obj->traits.get_mode();
919
1037
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
920
1038
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
1039
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
1040
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
1041
+ }
921
1042
  }
922
1043
  }
923
1044
  });
@@ -974,6 +1095,9 @@ std::string WebServer::select_json(select::Select *obj, const std::string &value
974
1095
  }
975
1096
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
976
1097
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
1098
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
1099
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
1100
+ }
977
1101
  }
978
1102
  }
979
1103
  });
@@ -995,11 +1119,15 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url
995
1119
  continue;
996
1120
 
997
1121
  if (request->method() == HTTP_GET && match.method.empty()) {
998
- std::string data = this->climate_json(obj, DETAIL_STATE);
1122
+ auto detail = DETAIL_STATE;
1123
+ auto *param = request->getParam("detail");
1124
+ if (param && param->value() == "all") {
1125
+ detail = DETAIL_ALL;
1126
+ }
1127
+ std::string data = this->climate_json(obj, detail);
999
1128
  request->send(200, "application/json", data.c_str());
1000
1129
  return;
1001
1130
  }
1002
-
1003
1131
  if (match.method != "set") {
1004
1132
  request->send(404);
1005
1133
  return;
@@ -1012,6 +1140,16 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url
1012
1140
  call.set_mode(mode.c_str());
1013
1141
  }
1014
1142
 
1143
+ if (request->hasParam("fan_mode")) {
1144
+ auto mode = request->getParam("fan_mode")->value();
1145
+ call.set_fan_mode(mode.c_str());
1146
+ }
1147
+
1148
+ if (request->hasParam("swing_mode")) {
1149
+ auto mode = request->getParam("swing_mode")->value();
1150
+ call.set_swing_mode(mode.c_str());
1151
+ }
1152
+
1015
1153
  if (request->hasParam("target_temperature_high")) {
1016
1154
  auto target_temperature_high = parse_number<float>(request->getParam("target_temperature_high")->value().c_str());
1017
1155
  if (target_temperature_high.has_value())
@@ -1076,6 +1214,9 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf
1076
1214
  }
1077
1215
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
1078
1216
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
1217
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
1218
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
1219
+ }
1079
1220
  }
1080
1221
  }
1081
1222
 
@@ -1139,7 +1280,12 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat
1139
1280
  continue;
1140
1281
 
1141
1282
  if (request->method() == HTTP_GET && match.method.empty()) {
1142
- std::string data = this->lock_json(obj, obj->state, DETAIL_STATE);
1283
+ auto detail = DETAIL_STATE;
1284
+ auto *param = request->getParam("detail");
1285
+ if (param && param->value() == "all") {
1286
+ detail = DETAIL_ALL;
1287
+ }
1288
+ std::string data = this->lock_json(obj, obj->state, detail);
1143
1289
  request->send(200, "application/json", data.c_str());
1144
1290
  } else if (match.method == "lock") {
1145
1291
  this->schedule_([obj]() { obj->lock(); });
@@ -1164,6 +1310,9 @@ std::string WebServer::lock_json(lock::Lock *obj, lock::LockState value, JsonDet
1164
1310
  if (start_config == DETAIL_ALL) {
1165
1311
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
1166
1312
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
1313
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
1314
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
1315
+ }
1167
1316
  }
1168
1317
  }
1169
1318
  });
@@ -1182,9 +1331,14 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa
1182
1331
  continue;
1183
1332
 
1184
1333
  if (request->method() == HTTP_GET && match.method.empty()) {
1185
- std::string data = this->valve_json(obj, DETAIL_STATE);
1334
+ auto detail = DETAIL_STATE;
1335
+ auto *param = request->getParam("detail");
1336
+ if (param && param->value() == "all") {
1337
+ detail = DETAIL_ALL;
1338
+ }
1339
+ std::string data = this->valve_json(obj, detail);
1186
1340
  request->send(200, "application/json", data.c_str());
1187
- continue;
1341
+ return;
1188
1342
  }
1189
1343
 
1190
1344
  auto call = obj->make_call();
@@ -1228,8 +1382,13 @@ std::string WebServer::valve_json(valve::Valve *obj, JsonDetail start_config) {
1228
1382
 
1229
1383
  if (obj->get_traits().get_supports_position())
1230
1384
  root["position"] = obj->position;
1231
- if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
1232
- root["sorting_weight"] = this->sorting_entitys_[obj].weight;
1385
+ if (start_config == DETAIL_ALL) {
1386
+ if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
1387
+ root["sorting_weight"] = this->sorting_entitys_[obj].weight;
1388
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
1389
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
1390
+ }
1391
+ }
1233
1392
  }
1234
1393
  });
1235
1394
  }
@@ -1247,7 +1406,12 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques
1247
1406
  continue;
1248
1407
 
1249
1408
  if (request->method() == HTTP_GET && match.method.empty()) {
1250
- std::string data = this->alarm_control_panel_json(obj, obj->get_state(), DETAIL_STATE);
1409
+ auto detail = DETAIL_STATE;
1410
+ auto *param = request->getParam("detail");
1411
+ if (param && param->value() == "all") {
1412
+ detail = DETAIL_ALL;
1413
+ }
1414
+ std::string data = this->alarm_control_panel_json(obj, obj->get_state(), detail);
1251
1415
  request->send(200, "application/json", data.c_str());
1252
1416
  return;
1253
1417
  }
@@ -1264,6 +1428,9 @@ std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmContro
1264
1428
  if (start_config == DETAIL_ALL) {
1265
1429
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
1266
1430
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
1431
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
1432
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
1433
+ }
1267
1434
  }
1268
1435
  }
1269
1436
  });
@@ -1276,7 +1443,7 @@ void WebServer::on_event(event::Event *obj, const std::string &event_type) {
1276
1443
  }
1277
1444
 
1278
1445
  std::string WebServer::event_json(event::Event *obj, const std::string &event_type, JsonDetail start_config) {
1279
- return json::build_json([obj, event_type, start_config](JsonObject root) {
1446
+ return json::build_json([this, obj, event_type, start_config](JsonObject root) {
1280
1447
  set_json_id(root, obj, "event-" + obj->get_object_id(), start_config);
1281
1448
  if (!event_type.empty()) {
1282
1449
  root["event_type"] = event_type;
@@ -1287,6 +1454,12 @@ std::string WebServer::event_json(event::Event *obj, const std::string &event_ty
1287
1454
  event_types.add(event_type);
1288
1455
  }
1289
1456
  root["device_class"] = obj->get_device_class();
1457
+ if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
1458
+ root["sorting_weight"] = this->sorting_entitys_[obj].weight;
1459
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
1460
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
1461
+ }
1462
+ }
1290
1463
  }
1291
1464
  });
1292
1465
  }
@@ -1304,7 +1477,12 @@ void WebServer::handle_update_request(AsyncWebServerRequest *request, const UrlM
1304
1477
  continue;
1305
1478
 
1306
1479
  if (request->method() == HTTP_GET && match.method.empty()) {
1307
- std::string data = this->update_json(obj, DETAIL_STATE);
1480
+ auto detail = DETAIL_STATE;
1481
+ auto *param = request->getParam("detail");
1482
+ if (param && param->value() == "all") {
1483
+ detail = DETAIL_ALL;
1484
+ }
1485
+ std::string data = this->update_json(obj, detail);
1308
1486
  request->send(200, "application/json", data.c_str());
1309
1487
  return;
1310
1488
  }
@@ -1345,6 +1523,9 @@ std::string WebServer::update_json(update::UpdateEntity *obj, JsonDetail start_c
1345
1523
  root["release_url"] = obj->update_info.release_url;
1346
1524
  if (this->sorting_entitys_.find(obj) != this->sorting_entitys_.end()) {
1347
1525
  root["sorting_weight"] = this->sorting_entitys_[obj].weight;
1526
+ if (this->sorting_groups_.find(this->sorting_entitys_[obj].group_id) != this->sorting_groups_.end()) {
1527
+ root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[obj].group_id].name;
1528
+ }
1348
1529
  }
1349
1530
  }
1350
1531
  });
@@ -1643,8 +1824,12 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) {
1643
1824
 
1644
1825
  bool WebServer::isRequestHandlerTrivial() { return false; }
1645
1826
 
1646
- void WebServer::add_entity_to_sorting_list(EntityBase *entity, float weight) {
1647
- this->sorting_entitys_[entity] = SortingComponents{weight};
1827
+ void WebServer::add_entity_config(EntityBase *entity, float weight, uint64_t group) {
1828
+ this->sorting_entitys_[entity] = SortingComponents{weight, group};
1829
+ }
1830
+
1831
+ void WebServer::add_sorting_group(uint64_t group_id, const std::string &group_name, float weight) {
1832
+ this->sorting_groups_[group_id] = SortingGroup{group_name, weight};
1648
1833
  }
1649
1834
 
1650
1835
  void WebServer::schedule_(std::function<void()> &&f) {
@@ -44,6 +44,12 @@ struct UrlMatch {
44
44
 
45
45
  struct SortingComponents {
46
46
  float weight;
47
+ uint64_t group_id;
48
+ };
49
+
50
+ struct SortingGroup {
51
+ std::string name;
52
+ float weight;
47
53
  };
48
54
 
49
55
  enum JsonDetail { DETAIL_ALL, DETAIL_STATE };
@@ -337,7 +343,8 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
337
343
  /// This web handle is not trivial.
338
344
  bool isRequestHandlerTrivial() override; // NOLINT(readability-identifier-naming)
339
345
 
340
- void add_entity_to_sorting_list(EntityBase *entity, float weight);
346
+ void add_entity_config(EntityBase *entity, float weight, uint64_t group);
347
+ void add_sorting_group(uint64_t group_id, const std::string &group_name, float weight);
341
348
 
342
349
  protected:
343
350
  void schedule_(std::function<void()> &&f);
@@ -346,6 +353,8 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
346
353
  AsyncEventSource events_{"/events"};
347
354
  ListEntitiesIterator entities_iterator_;
348
355
  std::map<EntityBase *, SortingComponents> sorting_entitys_;
356
+ std::map<uint64_t, SortingGroup> sorting_groups_;
357
+
349
358
  #if USE_WEBSERVER_VERSION == 1
350
359
  const char *css_url_{nullptr};
351
360
  const char *js_url_{nullptr};
@@ -130,12 +130,11 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi
130
130
  }
131
131
 
132
132
  void WiFiComponent::wifi_pre_setup_() {
133
- #ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC
134
133
  uint8_t mac[6];
135
- get_mac_address_raw(mac);
136
- set_mac_address(mac);
137
- ESP_LOGV(TAG, "Use EFuse MAC without checking CRC: %s", get_mac_address_pretty().c_str());
138
- #endif
134
+ if (has_custom_mac_address()) {
135
+ get_mac_address_raw(mac);
136
+ set_mac_address(mac);
137
+ }
139
138
  esp_err_t err = esp_netif_init();
140
139
  if (err != ERR_OK) {
141
140
  ESP_LOGE(TAG, "esp_netif_init failed: %s", esp_err_to_name(err));
@@ -750,6 +750,7 @@ def time_period_str_unit(value):
750
750
  "ns": "nanoseconds",
751
751
  "nanoseconds": "nanoseconds",
752
752
  "us": "microseconds",
753
+ "µs": "microseconds",
753
754
  "microseconds": "microseconds",
754
755
  "ms": "milliseconds",
755
756
  "milliseconds": "milliseconds",