esphome 2025.6.2__py3-none-any.whl → 2025.7.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (601) hide show
  1. esphome/__main__.py +1 -3
  2. esphome/codegen.py +2 -0
  3. esphome/components/ac_dimmer/ac_dimmer.cpp +6 -6
  4. esphome/components/adc/__init__.py +25 -1
  5. esphome/components/adc/adc_sensor.h +11 -11
  6. esphome/components/adc/adc_sensor_common.cpp +1 -1
  7. esphome/components/adc/adc_sensor_esp32.cpp +16 -8
  8. esphome/components/ade7880/ade7880.h +0 -2
  9. esphome/components/ads1115/ads1115.h +0 -1
  10. esphome/components/ads1118/ads1118.h +0 -1
  11. esphome/components/ags10/ags10.h +0 -2
  12. esphome/components/aic3204/aic3204.h +0 -1
  13. esphome/components/alarm_control_panel/__init__.py +5 -2
  14. esphome/components/alpha3/alpha3.h +0 -1
  15. esphome/components/am43/cover/am43_cover.h +0 -1
  16. esphome/components/am43/sensor/am43_sensor.h +0 -1
  17. esphome/components/analog_threshold/analog_threshold_binary_sensor.h +0 -2
  18. esphome/components/anova/anova.cpp +5 -1
  19. esphome/components/anova/anova.h +0 -1
  20. esphome/components/apds9960/apds9960.cpp +1 -1
  21. esphome/components/api/__init__.py +42 -20
  22. esphome/components/api/api_connection.cpp +318 -391
  23. esphome/components/api/api_connection.h +206 -126
  24. esphome/components/api/api_frame_helper.cpp +89 -124
  25. esphome/components/api/api_frame_helper.h +57 -45
  26. esphome/components/api/api_pb2.cpp +414 -4350
  27. esphome/components/api/api_pb2.h +287 -198
  28. esphome/components/api/api_pb2_dump.cpp +4333 -0
  29. esphome/components/api/api_pb2_service.cpp +180 -425
  30. esphome/components/api/api_pb2_service.h +7 -6
  31. esphome/components/api/api_pb2_size.h +2 -4
  32. esphome/components/api/api_server.cpp +138 -167
  33. esphome/components/api/api_server.h +66 -12
  34. esphome/components/api/client.py +10 -4
  35. esphome/components/api/list_entities.cpp +36 -105
  36. esphome/components/api/list_entities.h +31 -23
  37. esphome/components/api/proto.h +26 -3
  38. esphome/components/api/subscribe_state.cpp +23 -29
  39. esphome/components/api/subscribe_state.h +26 -19
  40. esphome/components/as5600/as5600.h +0 -1
  41. esphome/components/async_tcp/__init__.py +14 -5
  42. esphome/components/atc_mithermometer/atc_mithermometer.h +0 -1
  43. esphome/components/atm90e32/atm90e32.cpp +2 -1
  44. esphome/components/audio/audio_decoder.cpp +1 -1
  45. esphome/components/audio/audio_transfer_buffer.cpp +2 -2
  46. esphome/components/b_parasite/b_parasite.h +0 -1
  47. esphome/components/bedjet/bedjet_hub.cpp +5 -1
  48. esphome/components/bedjet/climate/bedjet_climate.cpp +5 -1
  49. esphome/components/beken_spi_led_strip/led_strip.cpp +4 -2
  50. esphome/components/bh1750/bh1750.cpp +5 -5
  51. esphome/components/binary_sensor/__init__.py +82 -5
  52. esphome/components/binary_sensor/automation.h +19 -1
  53. esphome/components/binary_sensor/binary_sensor.cpp +12 -30
  54. esphome/components/binary_sensor/binary_sensor.h +11 -25
  55. esphome/components/binary_sensor/filter.cpp +29 -24
  56. esphome/components/binary_sensor/filter.h +20 -10
  57. esphome/components/ble_client/output/ble_binary_output.h +0 -1
  58. esphome/components/ble_client/sensor/ble_rssi_sensor.cpp +5 -1
  59. esphome/components/ble_client/sensor/ble_rssi_sensor.h +0 -1
  60. esphome/components/ble_client/sensor/ble_sensor.cpp +5 -1
  61. esphome/components/ble_client/sensor/ble_sensor.h +0 -1
  62. esphome/components/ble_client/switch/ble_switch.h +0 -1
  63. esphome/components/ble_client/text_sensor/ble_text_sensor.cpp +5 -1
  64. esphome/components/ble_client/text_sensor/ble_text_sensor.h +0 -1
  65. esphome/components/ble_presence/ble_presence_device.h +0 -1
  66. esphome/components/ble_rssi/ble_rssi_sensor.h +0 -1
  67. esphome/components/ble_scanner/ble_scanner.h +0 -1
  68. esphome/components/bluetooth_proxy/bluetooth_connection.h +9 -2
  69. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +16 -6
  70. esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -2
  71. esphome/components/bme680/sensor.py +1 -1
  72. esphome/components/bmp581/bmp581.h +0 -2
  73. esphome/components/button/__init__.py +5 -2
  74. esphome/components/camera/__init__.py +1 -0
  75. esphome/components/camera/camera.cpp +22 -0
  76. esphome/components/camera/camera.h +80 -0
  77. esphome/components/canbus/__init__.py +1 -0
  78. esphome/components/cap1188/cap1188.h +0 -1
  79. esphome/components/captive_portal/__init__.py +12 -2
  80. esphome/components/captive_portal/captive_portal.cpp +12 -2
  81. esphome/components/captive_portal/captive_portal.h +5 -2
  82. esphome/components/ccs811/ccs811.h +0 -2
  83. esphome/components/climate/__init__.py +5 -2
  84. esphome/components/cm1106/sensor.py +2 -2
  85. esphome/components/const/__init__.py +2 -0
  86. esphome/components/copy/binary_sensor/copy_binary_sensor.h +0 -1
  87. esphome/components/copy/button/copy_button.h +0 -1
  88. esphome/components/copy/cover/copy_cover.h +0 -1
  89. esphome/components/copy/fan/copy_fan.h +0 -1
  90. esphome/components/copy/lock/copy_lock.h +0 -1
  91. esphome/components/copy/number/copy_number.h +0 -1
  92. esphome/components/copy/select/copy_select.h +0 -1
  93. esphome/components/copy/sensor/copy_sensor.h +0 -1
  94. esphome/components/copy/switch/copy_switch.h +0 -1
  95. esphome/components/copy/text/copy_text.h +0 -1
  96. esphome/components/copy/text_sensor/copy_text_sensor.h +0 -1
  97. esphome/components/cover/__init__.py +5 -2
  98. esphome/components/cs5460a/cs5460a.h +0 -1
  99. esphome/components/datetime/__init__.py +4 -2
  100. esphome/components/debug/__init__.py +20 -0
  101. esphome/components/deep_sleep/__init__.py +43 -9
  102. esphome/components/demo/__init__.py +2 -2
  103. esphome/components/display/display.cpp +4 -3
  104. esphome/components/display/display.h +0 -2
  105. esphome/components/display/display_buffer.cpp +1 -1
  106. esphome/components/ds2484/__init__.py +1 -0
  107. esphome/components/ds2484/ds2484.cpp +209 -0
  108. esphome/components/ds2484/ds2484.h +43 -0
  109. esphome/components/ds2484/one_wire.py +37 -0
  110. esphome/components/duty_time/duty_time_sensor.h +0 -1
  111. esphome/components/ens160_base/ens160_base.h +0 -1
  112. esphome/components/es7210/es7210.h +0 -1
  113. esphome/components/es7243e/es7243e.h +0 -1
  114. esphome/components/es8156/es8156.h +0 -1
  115. esphome/components/es8311/es8311.h +0 -1
  116. esphome/components/es8388/es8388.h +0 -1
  117. esphome/components/esp32/__init__.py +102 -135
  118. esphome/components/esp32/core.cpp +0 -4
  119. esphome/components/esp32/gpio.h +1 -1
  120. esphome/components/esp32/helpers.cpp +69 -0
  121. esphome/components/esp32_ble/ble.cpp +5 -6
  122. esphome/components/esp32_ble/ble.h +29 -14
  123. esphome/components/esp32_ble/ble_event.h +6 -6
  124. esphome/components/esp32_ble_client/ble_client_base.cpp +21 -6
  125. esphome/components/esp32_ble_client/ble_client_base.h +24 -9
  126. esphome/components/esp32_ble_tracker/__init__.py +2 -8
  127. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +5 -5
  128. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +11 -7
  129. esphome/components/esp32_camera/__init__.py +111 -97
  130. esphome/components/esp32_camera/esp32_camera.cpp +41 -31
  131. esphome/components/esp32_camera/esp32_camera.h +35 -30
  132. esphome/components/esp32_camera_web_server/__init__.py +2 -1
  133. esphome/components/esp32_camera_web_server/camera_web_server.cpp +8 -8
  134. esphome/components/esp32_camera_web_server/camera_web_server.h +3 -3
  135. esphome/components/esp32_hall/sensor.py +2 -21
  136. esphome/components/esp32_hosted/__init__.py +101 -0
  137. esphome/components/esp32_hosted/esp32_hosted.py.script +12 -0
  138. esphome/components/esp32_improv/esp32_improv_component.cpp +3 -0
  139. esphome/components/esp32_rmt/__init__.py +0 -58
  140. esphome/components/esp32_rmt_led_strip/led_strip.cpp +77 -63
  141. esphome/components/esp32_rmt_led_strip/led_strip.h +11 -17
  142. esphome/components/esp32_rmt_led_strip/light.py +14 -76
  143. esphome/components/esp32_touch/esp32_touch.h +174 -28
  144. esphome/components/esp32_touch/esp32_touch_common.cpp +162 -0
  145. esphome/components/esp32_touch/esp32_touch_v1.cpp +238 -0
  146. esphome/components/esp32_touch/esp32_touch_v2.cpp +397 -0
  147. esphome/components/esp8266/__init__.py +1 -0
  148. esphome/components/esp8266/gpio.cpp +10 -10
  149. esphome/components/esp8266/helpers.cpp +31 -0
  150. esphome/components/esphome/ota/__init__.py +1 -0
  151. esphome/components/esphome/ota/ota_esphome.cpp +24 -19
  152. esphome/components/ethernet/__init__.py +42 -23
  153. esphome/components/ethernet/esp_eth_phy_jl1101.c +0 -16
  154. esphome/components/ethernet/ethernet_component.cpp +69 -29
  155. esphome/components/ethernet/ethernet_component.h +18 -10
  156. esphome/components/event/__init__.py +5 -2
  157. esphome/components/ezo/ezo.h +0 -1
  158. esphome/components/ezo_pmp/ezo_pmp.h +0 -1
  159. esphome/components/fan/__init__.py +5 -2
  160. esphome/components/feedback/feedback_cover.h +0 -1
  161. esphome/components/font/__init__.py +92 -82
  162. esphome/components/font/font.cpp +9 -2
  163. esphome/components/font/font.h +20 -5
  164. esphome/components/fs3000/fs3000.h +0 -1
  165. esphome/components/gcja5/gcja5.h +0 -1
  166. esphome/components/gl_r01_i2c/__init__.py +0 -0
  167. esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +68 -0
  168. esphome/components/gl_r01_i2c/gl_r01_i2c.h +22 -0
  169. esphome/components/gl_r01_i2c/sensor.py +36 -0
  170. esphome/components/gp8403/gp8403.h +0 -1
  171. esphome/components/gpio/binary_sensor/__init__.py +17 -0
  172. esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +77 -3
  173. esphome/components/gpio/binary_sensor/gpio_binary_sensor.h +40 -0
  174. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +0 -2
  175. esphome/components/he60r/he60r.h +0 -1
  176. esphome/components/heatpumpir/climate.py +2 -1
  177. esphome/components/heatpumpir/heatpumpir.cpp +1 -0
  178. esphome/components/heatpumpir/heatpumpir.h +1 -0
  179. esphome/components/honeywellabp2_i2c/honeywellabp2.h +0 -1
  180. esphome/components/host/__init__.py +2 -1
  181. esphome/components/host/helpers.cpp +57 -0
  182. esphome/components/http_request/__init__.py +19 -1
  183. esphome/components/http_request/http_request.h +1 -1
  184. esphome/components/http_request/http_request_arduino.cpp +0 -1
  185. esphome/components/http_request/http_request_arduino.h +1 -0
  186. esphome/components/http_request/http_request_idf.cpp +0 -1
  187. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  188. esphome/components/http_request/update/http_request_update.cpp +28 -9
  189. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +3 -9
  190. esphome/components/hydreon_rgxx/sensor.py +1 -1
  191. esphome/components/i2c/__init__.py +23 -11
  192. esphome/components/i2c/i2c_bus.h +8 -1
  193. esphome/components/i2c/i2c_bus_arduino.cpp +4 -3
  194. esphome/components/i2c/i2c_bus_arduino.h +6 -3
  195. esphome/components/i2c/i2c_bus_esp_idf.h +5 -3
  196. esphome/components/i2c_device/i2c_device.h +0 -1
  197. esphome/components/i2s_audio/__init__.py +2 -10
  198. esphome/components/i2s_audio/i2s_audio.cpp +1 -5
  199. esphome/components/i2s_audio/media_player/__init__.py +2 -2
  200. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +2 -2
  201. esphome/components/iaqcore/iaqcore.h +0 -2
  202. esphome/components/image/__init__.py +123 -24
  203. esphome/components/improv_serial/improv_serial_component.cpp +0 -4
  204. esphome/components/ina219/ina219.cpp +7 -0
  205. esphome/components/ina219/ina219.h +1 -0
  206. esphome/components/ina260/ina260.h +0 -2
  207. esphome/components/inkbird_ibsth1_mini/inkbird_ibsth1_mini.h +0 -1
  208. esphome/components/inkplate6/display.py +15 -0
  209. esphome/components/inkplate6/inkplate.cpp +2 -2
  210. esphome/components/integration/integration_sensor.h +0 -1
  211. esphome/components/internal_temperature/internal_temperature.cpp +8 -27
  212. esphome/components/internal_temperature/sensor.py +0 -26
  213. esphome/components/interval/interval.h +0 -2
  214. esphome/components/ld2410/button/__init__.py +3 -3
  215. esphome/components/ld2410/button/factory_reset_button.cpp +9 -0
  216. esphome/components/ld2410/button/{reset_button.h → factory_reset_button.h} +2 -2
  217. esphome/components/ld2410/ld2410.cpp +430 -261
  218. esphome/components/ld2410/ld2410.h +44 -146
  219. esphome/components/ld2410/number/__init__.py +2 -2
  220. esphome/components/ld2410/sensor.py +1 -1
  221. esphome/components/ld2410/switch/__init__.py +1 -1
  222. esphome/components/ld2420/ld2420.cpp +196 -100
  223. esphome/components/ld2420/ld2420.h +46 -118
  224. esphome/components/ld2420/number/__init__.py +2 -2
  225. esphome/components/ld2420/sensor/__init__.py +6 -2
  226. esphome/components/ld2420/sensor/ld2420_sensor.h +1 -1
  227. esphome/components/ld2450/button/__init__.py +3 -3
  228. esphome/components/ld2450/button/factory_reset_button.cpp +9 -0
  229. esphome/components/ld2450/button/{reset_button.h → factory_reset_button.h} +2 -2
  230. esphome/components/ld2450/ld2450.cpp +384 -232
  231. esphome/components/ld2450/ld2450.h +60 -69
  232. esphome/components/ld2450/switch/__init__.py +1 -1
  233. esphome/components/ledc/ledc_output.cpp +1 -63
  234. esphome/components/libretiny/__init__.py +4 -3
  235. esphome/components/libretiny/const.py +5 -0
  236. esphome/components/libretiny/generate_components.py +1 -0
  237. esphome/components/libretiny/helpers.cpp +35 -0
  238. esphome/components/libretiny/lt_component.cpp +5 -3
  239. esphome/components/light/__init__.py +4 -2
  240. esphome/components/light/addressable_light.h +3 -3
  241. esphome/components/light/light_call.cpp +180 -243
  242. esphome/components/light/light_call.h +72 -20
  243. esphome/components/light/light_color_values.h +14 -14
  244. esphome/components/light/light_state.h +15 -13
  245. esphome/components/light/transformers.h +2 -2
  246. esphome/components/ln882x/__init__.py +52 -0
  247. esphome/components/ln882x/boards.py +285 -0
  248. esphome/components/lock/__init__.py +5 -2
  249. esphome/components/logger/__init__.py +40 -3
  250. esphome/components/logger/logger.cpp +47 -12
  251. esphome/components/logger/logger.h +80 -49
  252. esphome/components/logger/logger_esp32.cpp +3 -3
  253. esphome/components/lps22/__init__.py +0 -0
  254. esphome/components/lps22/lps22.cpp +75 -0
  255. esphome/components/lps22/lps22.h +27 -0
  256. esphome/components/lps22/sensor.py +58 -0
  257. esphome/components/ltr390/ltr390.h +0 -1
  258. esphome/components/ltr501/ltr501.h +0 -1
  259. esphome/components/ltr_als_ps/ltr_als_ps.h +0 -1
  260. esphome/components/lvgl/__init__.py +1 -1
  261. esphome/components/lvgl/schemas.py +66 -6
  262. esphome/components/lvgl/styles.py +24 -16
  263. esphome/components/lvgl/widgets/__init__.py +12 -2
  264. esphome/components/lvgl/widgets/lv_bar.py +40 -19
  265. esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +1 -1
  266. esphome/components/max9611/max9611.h +0 -1
  267. esphome/components/mcp23016/__init__.py +1 -1
  268. esphome/components/mcp23xxx_base/__init__.py +1 -1
  269. esphome/components/mcp4461/__init__.py +1 -1
  270. esphome/components/mcp4461/output/__init__.py +3 -2
  271. esphome/components/mcp9600/mcp9600.h +0 -2
  272. esphome/components/md5/md5.cpp +3 -3
  273. esphome/components/md5/md5.h +1 -6
  274. esphome/components/mdns/__init__.py +22 -11
  275. esphome/components/media_player/__init__.py +4 -3
  276. esphome/components/micro_wake_word/__init__.py +1 -5
  277. esphome/components/micro_wake_word/streaming_model.cpp +2 -2
  278. esphome/components/microphone/microphone.cpp +7 -9
  279. esphome/components/microphone/microphone.h +0 -2
  280. esphome/components/mipi_spi/display.py +1 -0
  281. esphome/components/mmc5603/mmc5603.cpp +1 -1
  282. esphome/components/modbus/modbus.cpp +33 -15
  283. esphome/components/modbus/modbus.h +9 -0
  284. esphome/components/modbus_controller/__init__.py +42 -10
  285. esphome/components/modbus_controller/modbus_controller.cpp +92 -11
  286. esphome/components/modbus_controller/modbus_controller.h +61 -7
  287. esphome/components/mopeka_pro_check/mopeka_pro_check.h +0 -1
  288. esphome/components/mopeka_std_check/mopeka_std_check.h +0 -1
  289. esphome/components/mpl3115a2/mpl3115a2.h +0 -2
  290. esphome/components/mqtt/__init__.py +16 -0
  291. esphome/components/mqtt/mqtt_backend.h +2 -1
  292. esphome/components/mqtt/mqtt_backend_esp32.cpp +126 -45
  293. esphome/components/mqtt/mqtt_backend_esp32.h +106 -4
  294. esphome/components/mqtt/mqtt_client.cpp +15 -9
  295. esphome/components/mqtt/mqtt_client.h +8 -3
  296. esphome/components/ms8607/ms8607.h +0 -1
  297. esphome/components/neopixelbus/light.py +4 -1
  298. esphome/components/neopixelbus/neopixelbus_light.h +1 -1
  299. esphome/components/network/__init__.py +4 -1
  300. esphome/components/network/ip_address.h +1 -0
  301. esphome/components/nextion/__init__.py +16 -0
  302. esphome/components/nextion/base_component.py +1 -0
  303. esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
  304. esphome/components/nextion/display.py +14 -4
  305. esphome/components/nextion/nextion.cpp +166 -101
  306. esphome/components/nextion/nextion.h +84 -53
  307. esphome/components/nextion/nextion_commands.cpp +11 -10
  308. esphome/components/nextion/nextion_component.cpp +28 -28
  309. esphome/components/nextion/nextion_component.h +53 -18
  310. esphome/components/nextion/nextion_component_base.h +3 -0
  311. esphome/components/nextion/nextion_upload.cpp +36 -0
  312. esphome/components/nextion/nextion_upload_arduino.cpp +10 -35
  313. esphome/components/nextion/nextion_upload_idf.cpp +9 -33
  314. esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
  315. esphome/components/nextion/switch/nextion_switch.cpp +1 -1
  316. esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
  317. esphome/components/nfc/nfc.cpp +3 -22
  318. esphome/components/nfc/nfc.h +3 -3
  319. esphome/components/number/__init__.py +5 -2
  320. esphome/components/online_image/__init__.py +5 -0
  321. esphome/components/online_image/online_image.cpp +6 -2
  322. esphome/components/online_image/online_image.h +4 -1
  323. esphome/components/opentherm/opentherm.cpp +7 -12
  324. esphome/components/openthread/__init__.py +47 -40
  325. esphome/components/openthread/const.py +1 -0
  326. esphome/components/openthread/openthread_esp.cpp +27 -5
  327. esphome/components/opt3001/__init__.py +0 -0
  328. esphome/components/opt3001/opt3001.cpp +122 -0
  329. esphome/components/opt3001/opt3001.h +27 -0
  330. esphome/components/opt3001/sensor.py +35 -0
  331. esphome/components/ota/__init__.py +17 -0
  332. esphome/components/ota/ota_backend.h +27 -1
  333. esphome/components/ota/ota_backend_arduino_esp32.cpp +12 -2
  334. esphome/components/ota/ota_backend_arduino_esp32.h +3 -0
  335. esphome/components/ota/ota_backend_arduino_esp8266.cpp +18 -4
  336. esphome/components/ota/ota_backend_arduino_esp8266.h +3 -0
  337. esphome/components/ota/ota_backend_arduino_libretiny.cpp +12 -2
  338. esphome/components/ota/ota_backend_arduino_libretiny.h +3 -0
  339. esphome/components/ota/ota_backend_arduino_rp2040.cpp +9 -2
  340. esphome/components/ota/ota_backend_arduino_rp2040.h +3 -0
  341. esphome/components/ota/ota_backend_esp_idf.cpp +10 -16
  342. esphome/components/ota/ota_backend_esp_idf.h +1 -0
  343. esphome/components/packages/__init__.py +5 -2
  344. esphome/components/packet_transport/binary_sensor.py +61 -4
  345. esphome/components/packet_transport/packet_transport.cpp +31 -1
  346. esphome/components/packet_transport/packet_transport.h +11 -5
  347. esphome/components/pcf8574/__init__.py +1 -1
  348. esphome/components/pi4ioe5v6408/__init__.py +84 -0
  349. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +171 -0
  350. esphome/components/pi4ioe5v6408/pi4ioe5v6408.h +70 -0
  351. esphome/components/pmsa003i/pmsa003i.h +0 -1
  352. esphome/components/pmsx003/pmsx003.h +0 -1
  353. esphome/components/pn7150/pn7150.cpp +7 -7
  354. esphome/components/pn7150/pn7150.h +0 -1
  355. esphome/components/pn7160/pn7160.cpp +7 -7
  356. esphome/components/pn7160/pn7160.h +0 -1
  357. esphome/components/preferences/syncer.h +2 -0
  358. esphome/components/prometheus/prometheus_handler.h +1 -1
  359. esphome/components/psram/psram.cpp +0 -20
  360. esphome/components/pulse_counter/pulse_counter_sensor.h +0 -1
  361. esphome/components/pulse_meter/pulse_meter_sensor.cpp +8 -4
  362. esphome/components/pulse_width/pulse_width.h +0 -1
  363. esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +0 -4
  364. esphome/components/pvvx_mithermometer/display/pvvx_display.h +0 -2
  365. esphome/components/pvvx_mithermometer/pvvx_mithermometer.h +0 -1
  366. esphome/components/qr_code/__init__.py +13 -10
  367. esphome/components/qwiic_pir/qwiic_pir.h +0 -1
  368. esphome/components/radon_eye_ble/radon_eye_listener.cpp +1 -1
  369. esphome/components/rc522/rc522.h +0 -1
  370. esphome/components/rdm6300/rdm6300.h +0 -2
  371. esphome/components/remote_base/__init__.py +7 -5
  372. esphome/components/remote_base/remote_base.cpp +24 -21
  373. esphome/components/remote_base/remote_base.h +3 -26
  374. esphome/components/remote_receiver/__init__.py +40 -46
  375. esphome/components/remote_receiver/remote_receiver.h +4 -18
  376. esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -87
  377. esphome/components/remote_receiver/remote_receiver_esp8266.cpp +1 -1
  378. esphome/components/remote_transmitter/__init__.py +42 -43
  379. esphome/components/remote_transmitter/remote_transmitter.h +2 -14
  380. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -77
  381. esphome/components/resistance/resistance_sensor.h +0 -1
  382. esphome/components/rp2040/__init__.py +1 -0
  383. esphome/components/rp2040/helpers.cpp +55 -0
  384. esphome/components/rp2040_pio_led_strip/led_strip.cpp +2 -2
  385. esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -4
  386. esphome/components/rtttl/__init__.py +4 -4
  387. esphome/components/rtttl/rtttl.cpp +10 -1
  388. esphome/components/ruuvitag/ruuvitag.h +0 -1
  389. esphome/components/safe_mode/safe_mode.cpp +2 -0
  390. esphome/components/safe_mode/safe_mode.h +4 -1
  391. esphome/components/scd30/scd30.h +0 -1
  392. esphome/components/scd30/sensor.py +2 -2
  393. esphome/components/scd4x/scd4x.cpp +61 -54
  394. esphome/components/scd4x/scd4x.h +17 -15
  395. esphome/components/scd4x/sensor.py +4 -4
  396. esphome/components/script/script.h +0 -2
  397. esphome/components/sdp3x/sensor.py +1 -1
  398. esphome/components/select/__init__.py +5 -2
  399. esphome/components/sen5x/sen5x.h +0 -1
  400. esphome/components/senseair/senseair.h +0 -1
  401. esphome/components/sensor/__init__.py +4 -2
  402. esphome/components/sensor/filter.cpp +1 -1
  403. esphome/components/sensor/sensor.cpp +12 -6
  404. esphome/components/sensor/sensor.h +13 -5
  405. esphome/components/servo/servo.h +0 -1
  406. esphome/components/sfa30/sfa30.h +0 -1
  407. esphome/components/sgp30/sgp30.h +0 -1
  408. esphome/components/sgp4x/sgp4x.h +0 -1
  409. esphome/components/shelly_dimmer/stm32flash.cpp +1 -2
  410. esphome/components/sht4x/sht4x.h +0 -1
  411. esphome/components/sm300d2/sm300d2.h +0 -2
  412. esphome/components/smt100/sensor.py +8 -4
  413. esphome/components/smt100/smt100.cpp +5 -5
  414. esphome/components/smt100/smt100.h +3 -3
  415. esphome/components/sn74hc595/__init__.py +1 -1
  416. esphome/components/sn74hc595/sn74hc595.cpp +5 -4
  417. esphome/components/sntp/sntp_component.cpp +9 -3
  418. esphome/components/sntp/time.py +2 -0
  419. esphome/components/socket/__init__.py +17 -0
  420. esphome/components/spi/__init__.py +27 -6
  421. esphome/components/spi/spi.cpp +3 -2
  422. esphome/components/spi/spi.h +9 -3
  423. esphome/components/spi/spi_arduino.cpp +3 -5
  424. esphome/components/spi/spi_esp_idf.cpp +40 -21
  425. esphome/components/spi_led_strip/spi_led_strip.cpp +1 -1
  426. esphome/components/sps30/sps30.h +0 -1
  427. esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
  428. esphome/components/st7701s/st7701s.cpp +0 -4
  429. esphome/components/status/status_binary_sensor.h +0 -2
  430. esphome/components/substitutions/__init__.py +76 -19
  431. esphome/components/substitutions/jinja.py +99 -0
  432. esphome/components/sun/sun.cpp +3 -4
  433. esphome/components/switch/__init__.py +5 -2
  434. esphome/components/switch/binary_sensor/switch_binary_sensor.h +0 -1
  435. esphome/components/sx126x/__init__.py +317 -0
  436. esphome/components/sx126x/automation.h +62 -0
  437. esphome/components/sx126x/packet_transport/__init__.py +26 -0
  438. esphome/components/sx126x/packet_transport/sx126x_transport.cpp +26 -0
  439. esphome/components/sx126x/packet_transport/sx126x_transport.h +25 -0
  440. esphome/components/sx126x/sx126x.cpp +523 -0
  441. esphome/components/sx126x/sx126x.h +140 -0
  442. esphome/components/sx126x/sx126x_reg.h +163 -0
  443. esphome/components/sx127x/__init__.py +325 -0
  444. esphome/components/sx127x/automation.h +62 -0
  445. esphome/components/sx127x/packet_transport/__init__.py +26 -0
  446. esphome/components/sx127x/packet_transport/sx127x_transport.cpp +26 -0
  447. esphome/components/sx127x/packet_transport/sx127x_transport.h +25 -0
  448. esphome/components/sx127x/sx127x.cpp +498 -0
  449. esphome/components/sx127x/sx127x.h +128 -0
  450. esphome/components/sx127x/sx127x_reg.h +295 -0
  451. esphome/components/syslog/esphome_syslog.cpp +5 -3
  452. esphome/components/syslog/esphome_syslog.h +1 -1
  453. esphome/components/tca9555/__init__.py +1 -1
  454. esphome/components/template/binary_sensor/template_binary_sensor.cpp +1 -9
  455. esphome/components/text/__init__.py +5 -2
  456. esphome/components/text_sensor/__init__.py +5 -2
  457. esphome/components/thermostat/thermostat_climate.cpp +34 -31
  458. esphome/components/thermostat/thermostat_climate.h +43 -39
  459. esphome/components/time/__init__.py +16 -2
  460. esphome/components/time/real_time_clock.cpp +4 -0
  461. esphome/components/time/real_time_clock.h +5 -1
  462. esphome/components/tlc5971/tlc5971.cpp +4 -1
  463. esphome/components/tmp1075/tmp1075.h +0 -2
  464. esphome/components/tof10120/tof10120_sensor.h +0 -1
  465. esphome/components/tormatic/tormatic_cover.h +0 -1
  466. esphome/components/total_daily_energy/total_daily_energy.h +0 -1
  467. esphome/components/tsl2591/tsl2591.cpp +1 -1
  468. esphome/components/ttp229_bsf/ttp229_bsf.h +0 -1
  469. esphome/components/ttp229_lsf/ttp229_lsf.h +0 -1
  470. esphome/components/tx20/tx20.cpp +2 -2
  471. esphome/components/uart/__init__.py +18 -0
  472. esphome/components/uart/uart_component_esp_idf.cpp +1 -5
  473. esphome/components/update/__init__.py +5 -2
  474. esphome/components/update/update_entity.h +8 -0
  475. esphome/components/usb_host/__init__.py +5 -2
  476. esphome/components/valve/__init__.py +5 -2
  477. esphome/components/vbus/vbus.h +0 -1
  478. esphome/components/veml3235/veml3235.h +0 -1
  479. esphome/components/veml7700/veml7700.h +0 -1
  480. esphome/components/vl53l0x/vl53l0x_sensor.h +0 -1
  481. esphome/components/voice_assistant/voice_assistant.cpp +4 -4
  482. esphome/components/watchdog/watchdog.cpp +0 -4
  483. esphome/components/waveshare_epaper/waveshare_epaper.cpp +6 -6
  484. esphome/components/web_server/__init__.py +34 -19
  485. esphome/components/web_server/ota/__init__.py +32 -0
  486. esphome/components/web_server/ota/ota_web_server.cpp +210 -0
  487. esphome/components/web_server/ota/ota_web_server.h +26 -0
  488. esphome/components/web_server/web_server.cpp +311 -430
  489. esphome/components/web_server/web_server.h +33 -23
  490. esphome/components/web_server/web_server_v1.cpp +4 -5
  491. esphome/components/web_server_base/__init__.py +5 -2
  492. esphome/components/web_server_base/web_server_base.cpp +2 -94
  493. esphome/components/web_server_base/web_server_base.h +5 -25
  494. esphome/components/web_server_idf/multipart.cpp +254 -0
  495. esphome/components/web_server_idf/multipart.h +86 -0
  496. esphome/components/web_server_idf/utils.cpp +32 -0
  497. esphome/components/web_server_idf/utils.h +10 -0
  498. esphome/components/web_server_idf/web_server_idf.cpp +162 -16
  499. esphome/components/web_server_idf/web_server_idf.h +11 -10
  500. esphome/components/wiegand/wiegand.cpp +2 -2
  501. esphome/components/wifi/__init__.py +18 -0
  502. esphome/components/wifi/wifi_component.cpp +17 -22
  503. esphome/components/wifi/wifi_component.h +27 -23
  504. esphome/components/wifi/wifi_component_esp32_arduino.cpp +52 -59
  505. esphome/components/wifi/wifi_component_esp8266.cpp +46 -46
  506. esphome/components/wifi/wifi_component_esp_idf.cpp +35 -36
  507. esphome/components/wifi/wifi_component_libretiny.cpp +26 -27
  508. esphome/components/wifi/wifi_component_pico_w.cpp +3 -3
  509. esphome/components/wifi_info/wifi_info_text_sensor.cpp +6 -6
  510. esphome/components/wireguard/__init__.py +2 -11
  511. esphome/components/xiaomi_ble/xiaomi_ble.cpp +13 -1
  512. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  513. esphome/components/xiaomi_cgd1/xiaomi_cgd1.h +0 -1
  514. esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h +0 -1
  515. esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +0 -1
  516. esphome/components/xiaomi_cgpr1/xiaomi_cgpr1.h +0 -1
  517. esphome/components/xiaomi_gcls002/xiaomi_gcls002.h +0 -1
  518. esphome/components/xiaomi_hhccjcy01/xiaomi_hhccjcy01.h +0 -1
  519. esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h +0 -1
  520. esphome/components/xiaomi_hhccpot002/xiaomi_hhccpot002.h +0 -1
  521. esphome/components/xiaomi_jqjcy01ym/xiaomi_jqjcy01ym.h +0 -1
  522. esphome/components/xiaomi_lywsd02/xiaomi_lywsd02.h +0 -1
  523. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +0 -1
  524. esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.h +0 -1
  525. esphome/components/xiaomi_lywsdcgq/xiaomi_lywsdcgq.h +0 -1
  526. esphome/components/xiaomi_mhoc303/xiaomi_mhoc303.h +0 -1
  527. esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.h +0 -1
  528. esphome/components/xiaomi_miscale/xiaomi_miscale.h +0 -1
  529. esphome/components/xiaomi_mjyd02yla/xiaomi_mjyd02yla.h +0 -1
  530. esphome/components/xiaomi_mue4094rt/xiaomi_mue4094rt.h +0 -1
  531. esphome/components/xiaomi_rtcgq02lm/xiaomi_rtcgq02lm.h +0 -1
  532. esphome/components/xiaomi_wx08zm/xiaomi_wx08zm.h +0 -1
  533. esphome/components/xiaomi_xmwsdj04mmc/__init__.py +0 -0
  534. esphome/components/xiaomi_xmwsdj04mmc/sensor.py +77 -0
  535. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.cpp +77 -0
  536. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.h +36 -0
  537. esphome/components/zio_ultrasonic/zio_ultrasonic.h +0 -2
  538. esphome/components/zyaura/zyaura.h +0 -1
  539. esphome/config.py +88 -22
  540. esphome/config_helpers.py +74 -1
  541. esphome/config_validation.py +12 -1
  542. esphome/const.py +65 -10
  543. esphome/core/__init__.py +18 -2
  544. esphome/core/application.cpp +163 -10
  545. esphome/core/application.h +145 -165
  546. esphome/core/area.h +19 -0
  547. esphome/core/automation.h +58 -9
  548. esphome/core/color.cpp +3 -5
  549. esphome/core/color.h +16 -16
  550. esphome/core/component.cpp +151 -18
  551. esphome/core/component.h +98 -4
  552. esphome/core/component_iterator.cpp +7 -7
  553. esphome/core/component_iterator.h +9 -7
  554. esphome/core/config.py +155 -6
  555. esphome/core/controller.cpp +4 -2
  556. esphome/core/controller.h +1 -1
  557. esphome/core/datatypes.h +2 -2
  558. esphome/core/defines.h +17 -2
  559. esphome/core/device.h +20 -0
  560. esphome/core/entity_base.cpp +20 -15
  561. esphome/core/entity_base.h +76 -0
  562. esphome/core/entity_helpers.py +162 -1
  563. esphome/core/event_pool.h +81 -0
  564. esphome/core/helpers.cpp +75 -230
  565. esphome/core/helpers.h +164 -104
  566. esphome/core/lock_free_queue.h +151 -0
  567. esphome/core/log.cpp +2 -2
  568. esphome/core/log.h +2 -0
  569. esphome/core/optional.h +5 -0
  570. esphome/core/ring_buffer.cpp +2 -2
  571. esphome/core/scheduler.cpp +278 -103
  572. esphome/core/scheduler.h +157 -17
  573. esphome/core/time.cpp +5 -5
  574. esphome/core/time.h +5 -5
  575. esphome/cpp_generator.py +17 -0
  576. esphome/cpp_helpers.py +0 -22
  577. esphome/cpp_types.py +3 -1
  578. esphome/dashboard/entries.py +1 -1
  579. esphome/dashboard/util/text.py +5 -21
  580. esphome/dashboard/web_server.py +9 -1
  581. esphome/helpers.py +47 -0
  582. esphome/loader.py +15 -1
  583. esphome/pins.py +14 -8
  584. esphome/wizard.py +16 -3
  585. esphome/writer.py +21 -3
  586. esphome/yaml_util.py +0 -2
  587. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/METADATA +10 -9
  588. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/RECORD +593 -533
  589. esphome/components/esp32_ble/ble_event_pool.h +0 -72
  590. esphome/components/esp32_ble/queue.h +0 -85
  591. esphome/components/esp32_hall/esp32_hall.cpp +0 -25
  592. esphome/components/esp32_hall/esp32_hall.h +0 -23
  593. esphome/components/esp32_touch/esp32_touch.cpp +0 -355
  594. esphome/components/ld2410/button/reset_button.cpp +0 -9
  595. esphome/components/ld2450/button/reset_button.cpp +0 -9
  596. esphome/components/openthread/tlv.py +0 -65
  597. /esphome/{dashboard/enum.py → enum.py} +0 -0
  598. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/WHEEL +0 -0
  599. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/entry_points.txt +0 -0
  600. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/licenses/LICENSE +0 -0
  601. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/top_level.txt +0 -0
@@ -2,9 +2,10 @@
2
2
  // See script/api_protobuf/api_protobuf.py
3
3
  #pragma once
4
4
 
5
- #include "api_pb2.h"
6
5
  #include "esphome/core/defines.h"
7
6
 
7
+ #include "api_pb2.h"
8
+
8
9
  namespace esphome {
9
10
  namespace api {
10
11
 
@@ -19,7 +20,7 @@ class APIServerConnectionBase : public ProtoService {
19
20
 
20
21
  template<typename T> bool send_message(const T &msg) {
21
22
  #ifdef HAS_PROTO_MESSAGE_DUMP
22
- this->log_send_message_(T::message_name(), msg.dump());
23
+ this->log_send_message_(msg.message_name(), msg.dump());
23
24
  #endif
24
25
  return this->send_message_(msg, T::MESSAGE_TYPE);
25
26
  }
@@ -70,7 +71,7 @@ class APIServerConnectionBase : public ProtoService {
70
71
 
71
72
  virtual void on_execute_service_request(const ExecuteServiceRequest &value){};
72
73
 
73
- #ifdef USE_ESP32_CAMERA
74
+ #ifdef USE_CAMERA
74
75
  virtual void on_camera_image_request(const CameraImageRequest &value){};
75
76
  #endif
76
77
 
@@ -199,7 +200,7 @@ class APIServerConnectionBase : public ProtoService {
199
200
  virtual void on_update_command_request(const UpdateCommandRequest &value){};
200
201
  #endif
201
202
  protected:
202
- bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
203
+ void read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
203
204
  };
204
205
 
205
206
  class APIServerConnection : public APIServerConnectionBase {
@@ -222,7 +223,7 @@ class APIServerConnection : public APIServerConnectionBase {
222
223
  #ifdef USE_BUTTON
223
224
  virtual void button_command(const ButtonCommandRequest &msg) = 0;
224
225
  #endif
225
- #ifdef USE_ESP32_CAMERA
226
+ #ifdef USE_CAMERA
226
227
  virtual void camera_image(const CameraImageRequest &msg) = 0;
227
228
  #endif
228
229
  #ifdef USE_CLIMATE
@@ -339,7 +340,7 @@ class APIServerConnection : public APIServerConnectionBase {
339
340
  #ifdef USE_BUTTON
340
341
  void on_button_command_request(const ButtonCommandRequest &msg) override;
341
342
  #endif
342
- #ifdef USE_ESP32_CAMERA
343
+ #ifdef USE_CAMERA
343
344
  void on_camera_image_request(const CameraImageRequest &msg) override;
344
345
  #endif
345
346
  #ifdef USE_CLIMATE
@@ -316,15 +316,13 @@ class ProtoSize {
316
316
  /**
317
317
  * @brief Calculates and adds the size of a nested message field to the total message size
318
318
  *
319
- * This templated version directly takes a message object, calculates its size internally,
319
+ * This version takes a ProtoMessage object, calculates its size internally,
320
320
  * and updates the total_size reference. This eliminates the need for a temporary variable
321
321
  * at the call site.
322
322
  *
323
- * @tparam MessageType The type of the nested message (inferred from parameter)
324
323
  * @param message The nested message object
325
324
  */
326
- template<typename MessageType>
327
- static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const MessageType &message,
325
+ static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const ProtoMessage &message,
328
326
  bool force = false) {
329
327
  uint32_t nested_size = 0;
330
328
  message.calculate_size(nested_size);
@@ -24,6 +24,14 @@ static const char *const TAG = "api";
24
24
  // APIServer
25
25
  APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
26
26
 
27
+ #ifndef USE_API_YAML_SERVICES
28
+ // Global empty vector to avoid guard variables (saves 8 bytes)
29
+ // This is initialized at program startup before any threads
30
+ static const std::vector<UserServiceDescriptor *> empty_user_services{};
31
+
32
+ const std::vector<UserServiceDescriptor *> &get_empty_user_services_instance() { return empty_user_services; }
33
+ #endif
34
+
27
35
  APIServer::APIServer() {
28
36
  global_api_server = this;
29
37
  // Pre-allocate shared write buffer
@@ -47,6 +55,11 @@ void APIServer::setup() {
47
55
  }
48
56
  #endif
49
57
 
58
+ // Schedule reboot if no clients connect within timeout
59
+ if (this->reboot_timeout_ != 0) {
60
+ this->schedule_reboot_timeout_();
61
+ }
62
+
50
63
  this->socket_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0); // monitored for incoming connections
51
64
  if (this->socket_ == nullptr) {
52
65
  ESP_LOGW(TAG, "Could not create socket");
@@ -91,34 +104,42 @@ void APIServer::setup() {
91
104
 
92
105
  #ifdef USE_LOGGER
93
106
  if (logger::global_logger != nullptr) {
94
- logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) {
95
- if (this->shutting_down_) {
96
- // Don't try to send logs during shutdown
97
- // as it could result in a recursion and
98
- // we would be filling a buffer we are trying to clear
99
- return;
100
- }
107
+ logger::global_logger->add_on_log_callback(
108
+ [this](int level, const char *tag, const char *message, size_t message_len) {
109
+ if (this->shutting_down_) {
110
+ // Don't try to send logs during shutdown
111
+ // as it could result in a recursion and
112
+ // we would be filling a buffer we are trying to clear
113
+ return;
114
+ }
115
+ for (auto &c : this->clients_) {
116
+ if (!c->flags_.remove)
117
+ c->try_send_log_message(level, tag, message, message_len);
118
+ }
119
+ });
120
+ }
121
+ #endif
122
+
123
+ #ifdef USE_CAMERA
124
+ if (camera::Camera::instance() != nullptr && !camera::Camera::instance()->is_internal()) {
125
+ camera::Camera::instance()->add_image_callback([this](const std::shared_ptr<camera::CameraImage> &image) {
101
126
  for (auto &c : this->clients_) {
102
- if (!c->remove_)
103
- c->try_send_log_message(level, tag, message);
127
+ if (!c->flags_.remove)
128
+ c->set_camera_state(image);
104
129
  }
105
130
  });
106
131
  }
107
132
  #endif
133
+ }
108
134
 
109
- this->last_connected_ = millis();
110
-
111
- #ifdef USE_ESP32_CAMERA
112
- if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) {
113
- esp32_camera::global_esp32_camera->add_image_callback(
114
- [this](const std::shared_ptr<esp32_camera::CameraImage> &image) {
115
- for (auto &c : this->clients_) {
116
- if (!c->remove_)
117
- c->set_camera_state(image);
118
- }
119
- });
120
- }
121
- #endif
135
+ void APIServer::schedule_reboot_timeout_() {
136
+ this->status_set_warning();
137
+ this->set_timeout("api_reboot", this->reboot_timeout_, []() {
138
+ if (!global_api_server->is_connected()) {
139
+ ESP_LOGE(TAG, "No clients; rebooting");
140
+ App.reboot();
141
+ }
142
+ });
122
143
  }
123
144
 
124
145
  void APIServer::loop() {
@@ -130,51 +151,63 @@ void APIServer::loop() {
130
151
  auto sock = this->socket_->accept_loop_monitored((struct sockaddr *) &source_addr, &addr_len);
131
152
  if (!sock)
132
153
  break;
133
- ESP_LOGD(TAG, "Accepted %s", sock->getpeername().c_str());
154
+ ESP_LOGD(TAG, "Accept %s", sock->getpeername().c_str());
134
155
 
135
156
  auto *conn = new APIConnection(std::move(sock), this);
136
157
  this->clients_.emplace_back(conn);
137
158
  conn->start();
159
+
160
+ // Clear warning status and cancel reboot when first client connects
161
+ if (this->clients_.size() == 1 && this->reboot_timeout_ != 0) {
162
+ this->status_clear_warning();
163
+ this->cancel_timeout("api_reboot");
164
+ }
138
165
  }
139
166
  }
140
167
 
168
+ if (this->clients_.empty()) {
169
+ return;
170
+ }
171
+
141
172
  // Process clients and remove disconnected ones in a single pass
142
- if (!this->clients_.empty()) {
143
- size_t client_index = 0;
144
- while (client_index < this->clients_.size()) {
145
- auto &client = this->clients_[client_index];
146
-
147
- if (client->remove_) {
148
- // Handle disconnection
149
- this->client_disconnected_trigger_->trigger(client->client_info_, client->client_peername_);
150
- ESP_LOGV(TAG, "Removing connection to %s", client->client_info_.c_str());
151
-
152
- // Swap with the last element and pop (avoids expensive vector shifts)
153
- if (client_index < this->clients_.size() - 1) {
154
- std::swap(this->clients_[client_index], this->clients_.back());
155
- }
156
- this->clients_.pop_back();
157
- // Don't increment client_index since we need to process the swapped element
158
- } else {
159
- // Process active client
160
- client->loop();
161
- client_index++; // Move to next client
162
- }
173
+ // Check network connectivity once for all clients
174
+ if (!network::is_connected()) {
175
+ // Network is down - disconnect all clients
176
+ for (auto &client : this->clients_) {
177
+ client->on_fatal_error();
178
+ ESP_LOGW(TAG, "%s: Network down; disconnect", client->get_client_combined_info().c_str());
163
179
  }
180
+ // Continue to process and clean up the clients below
164
181
  }
165
182
 
166
- if (this->reboot_timeout_ != 0) {
167
- const uint32_t now = millis();
168
- if (!this->is_connected()) {
169
- if (now - this->last_connected_ > this->reboot_timeout_) {
170
- ESP_LOGE(TAG, "No client connected; rebooting");
171
- App.reboot();
172
- }
173
- this->status_set_warning();
174
- } else {
175
- this->last_connected_ = now;
176
- this->status_clear_warning();
183
+ size_t client_index = 0;
184
+ while (client_index < this->clients_.size()) {
185
+ auto &client = this->clients_[client_index];
186
+
187
+ if (!client->flags_.remove) {
188
+ // Common case: process active client
189
+ client->loop();
190
+ client_index++;
191
+ continue;
192
+ }
193
+
194
+ // Rare case: handle disconnection
195
+ #ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
196
+ this->client_disconnected_trigger_->trigger(client->client_info_, client->client_peername_);
197
+ #endif
198
+ ESP_LOGV(TAG, "Remove connection %s", client->client_info_.c_str());
199
+
200
+ // Swap with the last element and pop (avoids expensive vector shifts)
201
+ if (client_index < this->clients_.size() - 1) {
202
+ std::swap(this->clients_[client_index], this->clients_.back());
203
+ }
204
+ this->clients_.pop_back();
205
+
206
+ // Schedule reboot when last client disconnects
207
+ if (this->clients_.empty() && this->reboot_timeout_ != 0) {
208
+ this->schedule_reboot_timeout_();
177
209
  }
210
+ // Don't increment client_index since we need to process the swapped element
178
211
  }
179
212
  }
180
213
 
@@ -193,6 +226,7 @@ void APIServer::dump_config() {
193
226
  #endif
194
227
  }
195
228
 
229
+ #ifdef USE_API_PASSWORD
196
230
  bool APIServer::uses_password() const { return !this->password_.empty(); }
197
231
 
198
232
  bool APIServer::check_password(const std::string &password) const {
@@ -223,192 +257,129 @@ bool APIServer::check_password(const std::string &password) const {
223
257
 
224
258
  return result == 0;
225
259
  }
260
+ #endif
226
261
 
227
262
  void APIServer::handle_disconnect(APIConnection *conn) {}
228
263
 
264
+ // Macro for entities without extra parameters
265
+ #define API_DISPATCH_UPDATE(entity_type, entity_name) \
266
+ void APIServer::on_##entity_name##_update(entity_type *obj) { /* NOLINT(bugprone-macro-parentheses) */ \
267
+ if (obj->is_internal()) \
268
+ return; \
269
+ for (auto &c : this->clients_) \
270
+ c->send_##entity_name##_state(obj); \
271
+ }
272
+
273
+ // Macro for entities with extra parameters (but parameters not used in send)
274
+ #define API_DISPATCH_UPDATE_IGNORE_PARAMS(entity_type, entity_name, ...) \
275
+ void APIServer::on_##entity_name##_update(entity_type *obj, __VA_ARGS__) { /* NOLINT(bugprone-macro-parentheses) */ \
276
+ if (obj->is_internal()) \
277
+ return; \
278
+ for (auto &c : this->clients_) \
279
+ c->send_##entity_name##_state(obj); \
280
+ }
281
+
229
282
  #ifdef USE_BINARY_SENSOR
230
- void APIServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) {
231
- if (obj->is_internal())
232
- return;
233
- for (auto &c : this->clients_)
234
- c->send_binary_sensor_state(obj);
235
- }
283
+ API_DISPATCH_UPDATE(binary_sensor::BinarySensor, binary_sensor)
236
284
  #endif
237
285
 
238
286
  #ifdef USE_COVER
239
- void APIServer::on_cover_update(cover::Cover *obj) {
240
- if (obj->is_internal())
241
- return;
242
- for (auto &c : this->clients_)
243
- c->send_cover_state(obj);
244
- }
287
+ API_DISPATCH_UPDATE(cover::Cover, cover)
245
288
  #endif
246
289
 
247
290
  #ifdef USE_FAN
248
- void APIServer::on_fan_update(fan::Fan *obj) {
249
- if (obj->is_internal())
250
- return;
251
- for (auto &c : this->clients_)
252
- c->send_fan_state(obj);
253
- }
291
+ API_DISPATCH_UPDATE(fan::Fan, fan)
254
292
  #endif
255
293
 
256
294
  #ifdef USE_LIGHT
257
- void APIServer::on_light_update(light::LightState *obj) {
258
- if (obj->is_internal())
259
- return;
260
- for (auto &c : this->clients_)
261
- c->send_light_state(obj);
262
- }
295
+ API_DISPATCH_UPDATE(light::LightState, light)
263
296
  #endif
264
297
 
265
298
  #ifdef USE_SENSOR
266
- void APIServer::on_sensor_update(sensor::Sensor *obj, float state) {
267
- if (obj->is_internal())
268
- return;
269
- for (auto &c : this->clients_)
270
- c->send_sensor_state(obj);
271
- }
299
+ API_DISPATCH_UPDATE_IGNORE_PARAMS(sensor::Sensor, sensor, float state)
272
300
  #endif
273
301
 
274
302
  #ifdef USE_SWITCH
275
- void APIServer::on_switch_update(switch_::Switch *obj, bool state) {
276
- if (obj->is_internal())
277
- return;
278
- for (auto &c : this->clients_)
279
- c->send_switch_state(obj);
280
- }
303
+ API_DISPATCH_UPDATE_IGNORE_PARAMS(switch_::Switch, switch, bool state)
281
304
  #endif
282
305
 
283
306
  #ifdef USE_TEXT_SENSOR
284
- void APIServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) {
285
- if (obj->is_internal())
286
- return;
287
- for (auto &c : this->clients_)
288
- c->send_text_sensor_state(obj);
289
- }
307
+ API_DISPATCH_UPDATE_IGNORE_PARAMS(text_sensor::TextSensor, text_sensor, const std::string &state)
290
308
  #endif
291
309
 
292
310
  #ifdef USE_CLIMATE
293
- void APIServer::on_climate_update(climate::Climate *obj) {
294
- if (obj->is_internal())
295
- return;
296
- for (auto &c : this->clients_)
297
- c->send_climate_state(obj);
298
- }
311
+ API_DISPATCH_UPDATE(climate::Climate, climate)
299
312
  #endif
300
313
 
301
314
  #ifdef USE_NUMBER
302
- void APIServer::on_number_update(number::Number *obj, float state) {
303
- if (obj->is_internal())
304
- return;
305
- for (auto &c : this->clients_)
306
- c->send_number_state(obj);
307
- }
315
+ API_DISPATCH_UPDATE_IGNORE_PARAMS(number::Number, number, float state)
308
316
  #endif
309
317
 
310
318
  #ifdef USE_DATETIME_DATE
311
- void APIServer::on_date_update(datetime::DateEntity *obj) {
312
- if (obj->is_internal())
313
- return;
314
- for (auto &c : this->clients_)
315
- c->send_date_state(obj);
316
- }
319
+ API_DISPATCH_UPDATE(datetime::DateEntity, date)
317
320
  #endif
318
321
 
319
322
  #ifdef USE_DATETIME_TIME
320
- void APIServer::on_time_update(datetime::TimeEntity *obj) {
321
- if (obj->is_internal())
322
- return;
323
- for (auto &c : this->clients_)
324
- c->send_time_state(obj);
325
- }
323
+ API_DISPATCH_UPDATE(datetime::TimeEntity, time)
326
324
  #endif
327
325
 
328
326
  #ifdef USE_DATETIME_DATETIME
329
- void APIServer::on_datetime_update(datetime::DateTimeEntity *obj) {
330
- if (obj->is_internal())
331
- return;
332
- for (auto &c : this->clients_)
333
- c->send_datetime_state(obj);
334
- }
327
+ API_DISPATCH_UPDATE(datetime::DateTimeEntity, datetime)
335
328
  #endif
336
329
 
337
330
  #ifdef USE_TEXT
338
- void APIServer::on_text_update(text::Text *obj, const std::string &state) {
339
- if (obj->is_internal())
340
- return;
341
- for (auto &c : this->clients_)
342
- c->send_text_state(obj);
343
- }
331
+ API_DISPATCH_UPDATE_IGNORE_PARAMS(text::Text, text, const std::string &state)
344
332
  #endif
345
333
 
346
334
  #ifdef USE_SELECT
347
- void APIServer::on_select_update(select::Select *obj, const std::string &state, size_t index) {
348
- if (obj->is_internal())
349
- return;
350
- for (auto &c : this->clients_)
351
- c->send_select_state(obj);
352
- }
335
+ API_DISPATCH_UPDATE_IGNORE_PARAMS(select::Select, select, const std::string &state, size_t index)
353
336
  #endif
354
337
 
355
338
  #ifdef USE_LOCK
356
- void APIServer::on_lock_update(lock::Lock *obj) {
357
- if (obj->is_internal())
358
- return;
359
- for (auto &c : this->clients_)
360
- c->send_lock_state(obj);
361
- }
339
+ API_DISPATCH_UPDATE(lock::Lock, lock)
362
340
  #endif
363
341
 
364
342
  #ifdef USE_VALVE
365
- void APIServer::on_valve_update(valve::Valve *obj) {
366
- if (obj->is_internal())
367
- return;
368
- for (auto &c : this->clients_)
369
- c->send_valve_state(obj);
370
- }
343
+ API_DISPATCH_UPDATE(valve::Valve, valve)
371
344
  #endif
372
345
 
373
346
  #ifdef USE_MEDIA_PLAYER
374
- void APIServer::on_media_player_update(media_player::MediaPlayer *obj) {
375
- if (obj->is_internal())
376
- return;
377
- for (auto &c : this->clients_)
378
- c->send_media_player_state(obj);
379
- }
347
+ API_DISPATCH_UPDATE(media_player::MediaPlayer, media_player)
380
348
  #endif
381
349
 
382
350
  #ifdef USE_EVENT
351
+ // Event is a special case - it's the only entity that passes extra parameters to the send method
383
352
  void APIServer::on_event(event::Event *obj, const std::string &event_type) {
353
+ if (obj->is_internal())
354
+ return;
384
355
  for (auto &c : this->clients_)
385
356
  c->send_event(obj, event_type);
386
357
  }
387
358
  #endif
388
359
 
389
360
  #ifdef USE_UPDATE
361
+ // Update is a special case - the method is called on_update, not on_update_update
390
362
  void APIServer::on_update(update::UpdateEntity *obj) {
363
+ if (obj->is_internal())
364
+ return;
391
365
  for (auto &c : this->clients_)
392
366
  c->send_update_state(obj);
393
367
  }
394
368
  #endif
395
369
 
396
370
  #ifdef USE_ALARM_CONTROL_PANEL
397
- void APIServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) {
398
- if (obj->is_internal())
399
- return;
400
- for (auto &c : this->clients_)
401
- c->send_alarm_control_panel_state(obj);
402
- }
371
+ API_DISPATCH_UPDATE(alarm_control_panel::AlarmControlPanel, alarm_control_panel)
403
372
  #endif
404
373
 
405
374
  float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
406
375
 
407
376
  void APIServer::set_port(uint16_t port) { this->port_ = port; }
408
377
 
378
+ #ifdef USE_API_PASSWORD
409
379
  void APIServer::set_password(const std::string &password) { this->password_ = password; }
380
+ #endif
410
381
 
411
- void APIServer::set_batch_delay(uint32_t batch_delay) { this->batch_delay_ = batch_delay; }
382
+ void APIServer::set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; }
412
383
 
413
384
  void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
414
385
  for (auto &client : this->clients_) {
@@ -479,7 +450,7 @@ bool APIServer::save_noise_psk(psk_t psk, bool make_active) {
479
450
  #ifdef USE_HOMEASSISTANT_TIME
480
451
  void APIServer::request_time() {
481
452
  for (auto &client : this->clients_) {
482
- if (!client->remove_ && client->is_authenticated())
453
+ if (!client->flags_.remove && client->is_authenticated())
483
454
  client->send_time_request();
484
455
  }
485
456
  }
@@ -503,8 +474,8 @@ void APIServer::on_shutdown() {
503
474
  for (auto &c : this->clients_) {
504
475
  if (!c->send_message(DisconnectRequest())) {
505
476
  // If we can't send the disconnect request directly (tx_buffer full),
506
- // schedule it in the batch so it will be sent with the 5ms timer
507
- c->schedule_message_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE);
477
+ // schedule it at the front of the batch so it will be sent with priority
478
+ c->schedule_message_front_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE);
508
479
  }
509
480
  }
510
481
  }
@@ -25,6 +25,11 @@ struct SavedNoisePsk {
25
25
  } PACKED; // NOLINT
26
26
  #endif
27
27
 
28
+ #ifndef USE_API_YAML_SERVICES
29
+ // Forward declaration of helper function
30
+ const std::vector<UserServiceDescriptor *> &get_empty_user_services_instance();
31
+ #endif
32
+
28
33
  class APIServer : public Component, public Controller {
29
34
  public:
30
35
  APIServer();
@@ -35,13 +40,15 @@ class APIServer : public Component, public Controller {
35
40
  void dump_config() override;
36
41
  void on_shutdown() override;
37
42
  bool teardown() override;
43
+ #ifdef USE_API_PASSWORD
38
44
  bool check_password(const std::string &password) const;
39
45
  bool uses_password() const;
40
- void set_port(uint16_t port);
41
46
  void set_password(const std::string &password);
47
+ #endif
48
+ void set_port(uint16_t port);
42
49
  void set_reboot_timeout(uint32_t reboot_timeout);
43
- void set_batch_delay(uint32_t batch_delay);
44
- uint32_t get_batch_delay() const { return batch_delay_; }
50
+ void set_batch_delay(uint16_t batch_delay);
51
+ uint16_t get_batch_delay() const { return batch_delay_; }
45
52
 
46
53
  // Get reference to shared buffer for API connections
47
54
  std::vector<uint8_t> &get_shared_buffer_ref() { return shared_write_buffer_; }
@@ -54,7 +61,7 @@ class APIServer : public Component, public Controller {
54
61
 
55
62
  void handle_disconnect(APIConnection *conn);
56
63
  #ifdef USE_BINARY_SENSOR
57
- void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override;
64
+ void on_binary_sensor_update(binary_sensor::BinarySensor *obj) override;
58
65
  #endif
59
66
  #ifdef USE_COVER
60
67
  void on_cover_update(cover::Cover *obj) override;
@@ -105,7 +112,18 @@ class APIServer : public Component, public Controller {
105
112
  void on_media_player_update(media_player::MediaPlayer *obj) override;
106
113
  #endif
107
114
  void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
108
- void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
115
+ void register_user_service(UserServiceDescriptor *descriptor) {
116
+ #ifdef USE_API_YAML_SERVICES
117
+ // Vector is pre-allocated when services are defined in YAML
118
+ this->user_services_.push_back(descriptor);
119
+ #else
120
+ // Lazy allocate vector on first use for CustomAPIDevice
121
+ if (!this->user_services_) {
122
+ this->user_services_ = std::make_unique<std::vector<UserServiceDescriptor *>>();
123
+ }
124
+ this->user_services_->push_back(descriptor);
125
+ #endif
126
+ }
109
127
  #ifdef USE_HOMEASSISTANT_TIME
110
128
  void request_time();
111
129
  #endif
@@ -134,27 +152,63 @@ class APIServer : public Component, public Controller {
134
152
  void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
135
153
  std::function<void(std::string)> f);
136
154
  const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
137
- const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
155
+ const std::vector<UserServiceDescriptor *> &get_user_services() const {
156
+ #ifdef USE_API_YAML_SERVICES
157
+ return this->user_services_;
158
+ #else
159
+ if (this->user_services_) {
160
+ return *this->user_services_;
161
+ }
162
+ // Return reference to global empty instance (no guard needed)
163
+ return get_empty_user_services_instance();
164
+ #endif
165
+ }
138
166
 
167
+ #ifdef USE_API_CLIENT_CONNECTED_TRIGGER
139
168
  Trigger<std::string, std::string> *get_client_connected_trigger() const { return this->client_connected_trigger_; }
169
+ #endif
170
+ #ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
140
171
  Trigger<std::string, std::string> *get_client_disconnected_trigger() const {
141
172
  return this->client_disconnected_trigger_;
142
173
  }
174
+ #endif
143
175
 
144
176
  protected:
145
- bool shutting_down_ = false;
177
+ void schedule_reboot_timeout_();
178
+ // Pointers and pointer-like types first (4 bytes each)
146
179
  std::unique_ptr<socket::Socket> socket_ = nullptr;
147
- uint16_t port_{6053};
180
+ #ifdef USE_API_CLIENT_CONNECTED_TRIGGER
181
+ Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>();
182
+ #endif
183
+ #ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
184
+ Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>();
185
+ #endif
186
+
187
+ // 4-byte aligned types
148
188
  uint32_t reboot_timeout_{300000};
149
- uint32_t batch_delay_{100};
150
- uint32_t last_connected_{0};
189
+
190
+ // Vectors and strings (12 bytes each on 32-bit)
151
191
  std::vector<std::unique_ptr<APIConnection>> clients_;
192
+ #ifdef USE_API_PASSWORD
152
193
  std::string password_;
194
+ #endif
153
195
  std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections
154
196
  std::vector<HomeAssistantStateSubscription> state_subs_;
197
+ #ifdef USE_API_YAML_SERVICES
198
+ // When services are defined in YAML, we know at compile time that services will be registered
155
199
  std::vector<UserServiceDescriptor *> user_services_;
156
- Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>();
157
- Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>();
200
+ #else
201
+ // Services can still be registered at runtime by CustomAPIDevice components even when not
202
+ // defined in YAML. Using unique_ptr allows lazy allocation, saving 12 bytes in the common
203
+ // case where no services (YAML or custom) are used.
204
+ std::unique_ptr<std::vector<UserServiceDescriptor *>> user_services_;
205
+ #endif
206
+
207
+ // Group smaller types together
208
+ uint16_t port_{6053};
209
+ uint16_t batch_delay_{100};
210
+ bool shutting_down_ = false;
211
+ // 5 bytes used, 3 bytes padding
158
212
 
159
213
  #ifdef USE_API_NOISE
160
214
  std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>();