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
@@ -14,11 +14,6 @@
14
14
  #include <string>
15
15
  #include <utility>
16
16
  #include <vector>
17
- #ifdef USE_ESP32
18
- #include <freertos/FreeRTOS.h>
19
- #include <freertos/semphr.h>
20
- #include <deque>
21
- #endif
22
17
 
23
18
  #if USE_WEBSERVER_VERSION >= 2
24
19
  extern const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM;
@@ -40,12 +35,31 @@ namespace web_server {
40
35
 
41
36
  /// Internal helper struct that is used to parse incoming URLs
42
37
  struct UrlMatch {
43
- std::string domain; ///< The domain of the component, for example "sensor"
44
- std::string id; ///< The id of the device that's being accessed, for example "living_room_fan"
45
- std::string method; ///< The method that's being called, for example "turn_on"
38
+ const char *domain; ///< Pointer to domain within URL, for example "sensor"
39
+ const char *id; ///< Pointer to id within URL, for example "living_room_fan"
40
+ const char *method; ///< Pointer to method within URL, for example "turn_on"
41
+ uint8_t domain_len; ///< Length of domain string
42
+ uint8_t id_len; ///< Length of id string
43
+ uint8_t method_len; ///< Length of method string
46
44
  bool valid; ///< Whether this match is valid
45
+
46
+ // Helper methods for string comparisons
47
+ bool domain_equals(const char *str) const {
48
+ return domain && domain_len == strlen(str) && memcmp(domain, str, domain_len) == 0;
49
+ }
50
+
51
+ bool id_equals(const std::string &str) const {
52
+ return id && id_len == str.length() && memcmp(id, str.c_str(), id_len) == 0;
53
+ }
54
+
55
+ bool method_equals(const char *str) const {
56
+ return method && method_len == strlen(str) && memcmp(method, str, method_len) == 0;
57
+ }
58
+
59
+ bool method_empty() const { return method_len == 0; }
47
60
  };
48
61
 
62
+ #ifdef USE_WEBSERVER_SORTING
49
63
  struct SortingComponents {
50
64
  float weight;
51
65
  uint64_t group_id;
@@ -55,6 +69,7 @@ struct SortingGroup {
55
69
  std::string name;
56
70
  float weight;
57
71
  };
72
+ #endif
58
73
 
59
74
  enum JsonDetail { DETAIL_ALL, DETAIL_STATE };
60
75
 
@@ -99,13 +114,15 @@ class DeferredUpdateEventSource : public AsyncEventSource {
99
114
  protected:
100
115
  // surface a couple methods from the base class
101
116
  using AsyncEventSource::handleRequest;
102
- using AsyncEventSource::try_send;
117
+ using AsyncEventSource::send;
103
118
 
104
119
  ListEntitiesIterator entities_iterator_;
105
120
  // vector is used very specifically for its zero memory overhead even though items are popped from the front (memory
106
121
  // footprint is more important than speed here)
107
122
  std::vector<DeferredEvent> deferred_queue_;
108
123
  WebServer *web_server_;
124
+ uint16_t consecutive_send_failures_{0};
125
+ static constexpr uint16_t MAX_CONSECUTIVE_SEND_FAILURES = 2500; // ~20 seconds at 125Hz loop rate
109
126
 
110
127
  // helper for allowing only unique entries in the queue
111
128
  void deq_push_back_with_dedup_(void *source, message_generator_t *message_generator);
@@ -192,11 +209,6 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
192
209
  * @param include_internal Whether internal components should be displayed.
193
210
  */
194
211
  void set_include_internal(bool include_internal) { include_internal_ = include_internal; }
195
- /** Set whether or not the webserver should expose the OTA form and handler.
196
- *
197
- * @param allow_ota.
198
- */
199
- void set_allow_ota(bool allow_ota) { this->allow_ota_ = allow_ota; }
200
212
  /** Set whether or not the webserver should expose the Log.
201
213
  *
202
214
  * @param expose_log.
@@ -269,7 +281,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
269
281
  #endif
270
282
 
271
283
  #ifdef USE_BINARY_SENSOR
272
- void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override;
284
+ void on_binary_sensor_update(binary_sensor::BinarySensor *obj) override;
273
285
 
274
286
  /// Handle a binary sensor request under '/binary_sensor/<id>'.
275
287
  void handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match);
@@ -468,21 +480,24 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
468
480
  #endif
469
481
 
470
482
  /// Override the web handler's canHandle method.
471
- bool canHandle(AsyncWebServerRequest *request) override;
483
+ bool canHandle(AsyncWebServerRequest *request) const override;
472
484
  /// Override the web handler's handleRequest method.
473
485
  void handleRequest(AsyncWebServerRequest *request) override;
474
486
  /// This web handle is not trivial.
475
- bool isRequestHandlerTrivial() override; // NOLINT(readability-identifier-naming)
487
+ bool isRequestHandlerTrivial() const override; // NOLINT(readability-identifier-naming)
476
488
 
489
+ #ifdef USE_WEBSERVER_SORTING
477
490
  void add_entity_config(EntityBase *entity, float weight, uint64_t group);
478
491
  void add_sorting_group(uint64_t group_id, const std::string &group_name, float weight);
479
492
 
480
493
  std::map<EntityBase *, SortingComponents> sorting_entitys_;
481
494
  std::map<uint64_t, SortingGroup> sorting_groups_;
495
+ #endif
496
+
482
497
  bool include_internal_{false};
483
498
 
484
499
  protected:
485
- void schedule_(std::function<void()> &&f);
500
+ void add_sorting_info_(JsonObject &root, EntityBase *entity);
486
501
  web_server_base::WebServerBase *base_;
487
502
  #ifdef USE_ARDUINO
488
503
  DeferredUpdateEventSourceList events_;
@@ -501,12 +516,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
501
516
  #ifdef USE_WEBSERVER_JS_INCLUDE
502
517
  const char *js_include_{nullptr};
503
518
  #endif
504
- bool allow_ota_{true};
505
519
  bool expose_log_{true};
506
- #ifdef USE_ESP32
507
- std::deque<std::function<void()>> to_schedule_;
508
- SemaphoreHandle_t to_schedule_lock_;
509
- #endif
510
520
  };
511
521
 
512
522
  } // namespace web_server
@@ -192,11 +192,10 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) {
192
192
 
193
193
  stream->print(F("</tbody></table><p>See <a href=\"https://esphome.io/web-api/index.html\">ESPHome Web API</a> for "
194
194
  "REST API documentation.</p>"));
195
- if (this->allow_ota_) {
196
- stream->print(
197
- F("<h2>OTA Update</h2><form method=\"POST\" action=\"/update\" enctype=\"multipart/form-data\"><input "
198
- "type=\"file\" name=\"update\"><input type=\"submit\" value=\"Update\"></form>"));
199
- }
195
+ #ifdef USE_WEBSERVER_OTA
196
+ stream->print(F("<h2>OTA Update</h2><form method=\"POST\" action=\"/update\" enctype=\"multipart/form-data\"><input "
197
+ "type=\"file\" name=\"update\"><input type=\"submit\" value=\"Update\"></form>"));
198
+ #endif
200
199
  stream->print(F("<h2>Debug Log</h2><pre id=\"log\"></pre>"));
201
200
  #ifdef USE_WEBSERVER_JS_INCLUDE
202
201
  if (this->js_include_ != nullptr) {
@@ -30,11 +30,14 @@ CONFIG_SCHEMA = cv.Schema(
30
30
  async def to_code(config):
31
31
  var = cg.new_Pvariable(config[CONF_ID])
32
32
  await cg.register_component(var, config)
33
+ cg.add(cg.RawExpression(f"{web_server_base_ns}::global_web_server_base = {var}"))
33
34
 
34
35
  if CORE.using_arduino:
35
36
  if CORE.is_esp32:
36
37
  cg.add_library("WiFi", None)
37
38
  cg.add_library("FS", None)
38
39
  cg.add_library("Update", None)
39
- # https://github.com/esphome/ESPAsyncWebServer/blob/master/library.json
40
- cg.add_library("esphome/ESPAsyncWebServer-esphome", "3.3.0")
40
+ if CORE.is_esp8266:
41
+ cg.add_library("ESP8266WiFi", None)
42
+ # https://github.com/ESP32Async/ESPAsyncWebServer/blob/main/library.json
43
+ cg.add_library("ESP32Async/ESPAsyncWebServer", "3.7.8")
@@ -4,21 +4,13 @@
4
4
  #include "esphome/core/helpers.h"
5
5
  #include "esphome/core/log.h"
6
6
 
7
- #ifdef USE_ARDUINO
8
- #include <StreamString.h>
9
- #if defined(USE_ESP32) || defined(USE_LIBRETINY)
10
- #include <Update.h>
11
- #endif
12
- #ifdef USE_ESP8266
13
- #include <Updater.h>
14
- #endif
15
- #endif
16
-
17
7
  namespace esphome {
18
8
  namespace web_server_base {
19
9
 
20
10
  static const char *const TAG = "web_server_base";
21
11
 
12
+ WebServerBase *global_web_server_base = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
13
+
22
14
  void WebServerBase::add_handler(AsyncWebHandler *handler) {
23
15
  // remove all handlers
24
16
 
@@ -31,90 +23,6 @@ void WebServerBase::add_handler(AsyncWebHandler *handler) {
31
23
  }
32
24
  }
33
25
 
34
- void report_ota_error() {
35
- #ifdef USE_ARDUINO
36
- StreamString ss;
37
- Update.printError(ss);
38
- ESP_LOGW(TAG, "OTA Update failed! Error: %s", ss.c_str());
39
- #endif
40
- }
41
-
42
- void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index,
43
- uint8_t *data, size_t len, bool final) {
44
- #ifdef USE_ARDUINO
45
- bool success;
46
- if (index == 0) {
47
- ESP_LOGI(TAG, "OTA Update Start: %s", filename.c_str());
48
- this->ota_read_length_ = 0;
49
- #ifdef USE_ESP8266
50
- Update.runAsync(true);
51
- // NOLINTNEXTLINE(readability-static-accessed-through-instance)
52
- success = Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
53
- #endif
54
- #if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_LIBRETINY)
55
- if (Update.isRunning()) {
56
- Update.abort();
57
- }
58
- success = Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH);
59
- #endif
60
- if (!success) {
61
- report_ota_error();
62
- return;
63
- }
64
- } else if (Update.hasError()) {
65
- // don't spam logs with errors if something failed at start
66
- return;
67
- }
68
-
69
- success = Update.write(data, len) == len;
70
- if (!success) {
71
- report_ota_error();
72
- return;
73
- }
74
- this->ota_read_length_ += len;
75
-
76
- const uint32_t now = millis();
77
- if (now - this->last_ota_progress_ > 1000) {
78
- if (request->contentLength() != 0) {
79
- float percentage = (this->ota_read_length_ * 100.0f) / request->contentLength();
80
- ESP_LOGD(TAG, "OTA in progress: %0.1f%%", percentage);
81
- } else {
82
- ESP_LOGD(TAG, "OTA in progress: %u bytes read", this->ota_read_length_);
83
- }
84
- this->last_ota_progress_ = now;
85
- }
86
-
87
- if (final) {
88
- if (Update.end(true)) {
89
- ESP_LOGI(TAG, "OTA update successful!");
90
- this->parent_->set_timeout(100, []() { App.safe_reboot(); });
91
- } else {
92
- report_ota_error();
93
- }
94
- }
95
- #endif
96
- }
97
- void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) {
98
- #ifdef USE_ARDUINO
99
- AsyncWebServerResponse *response;
100
- if (!Update.hasError()) {
101
- response = request->beginResponse(200, "text/plain", "Update Successful!");
102
- } else {
103
- StreamString ss;
104
- ss.print("Update Failed: ");
105
- Update.printError(ss);
106
- response = request->beginResponse(200, "text/plain", ss);
107
- }
108
- response->addHeader("Connection", "close");
109
- request->send(response);
110
- #endif
111
- }
112
-
113
- void WebServerBase::add_ota_handler() {
114
- #ifdef USE_ARDUINO
115
- this->add_handler(new OTARequestHandler(this)); // NOLINT
116
- #endif
117
- }
118
26
  float WebServerBase::get_setup_priority() const {
119
27
  // Before WiFi (captive portal)
120
28
  return setup_priority::WIFI + 2.0f;
@@ -17,13 +17,16 @@
17
17
  namespace esphome {
18
18
  namespace web_server_base {
19
19
 
20
+ class WebServerBase;
21
+ extern WebServerBase *global_web_server_base; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
22
+
20
23
  namespace internal {
21
24
 
22
25
  class MiddlewareHandler : public AsyncWebHandler {
23
26
  public:
24
27
  MiddlewareHandler(AsyncWebHandler *next) : next_(next) {}
25
28
 
26
- bool canHandle(AsyncWebServerRequest *request) override { return next_->canHandle(request); }
29
+ bool canHandle(AsyncWebServerRequest *request) const override { return next_->canHandle(request); }
27
30
  void handleRequest(AsyncWebServerRequest *request) override { next_->handleRequest(request); }
28
31
  void handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len,
29
32
  bool final) override {
@@ -32,7 +35,7 @@ class MiddlewareHandler : public AsyncWebHandler {
32
35
  void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override {
33
36
  next_->handleBody(request, data, len, index, total);
34
37
  }
35
- bool isRequestHandlerTrivial() override { return next_->isRequestHandlerTrivial(); }
38
+ bool isRequestHandlerTrivial() const override { return next_->isRequestHandlerTrivial(); }
36
39
 
37
40
  protected:
38
41
  AsyncWebHandler *next_;
@@ -110,14 +113,10 @@ class WebServerBase : public Component {
110
113
 
111
114
  void add_handler(AsyncWebHandler *handler);
112
115
 
113
- void add_ota_handler();
114
-
115
116
  void set_port(uint16_t port) { port_ = port; }
116
117
  uint16_t get_port() const { return port_; }
117
118
 
118
119
  protected:
119
- friend class OTARequestHandler;
120
-
121
120
  int initialized_{0};
122
121
  uint16_t port_{80};
123
122
  std::shared_ptr<AsyncWebServer> server_{nullptr};
@@ -125,25 +124,6 @@ class WebServerBase : public Component {
125
124
  internal::Credentials credentials_;
126
125
  };
127
126
 
128
- class OTARequestHandler : public AsyncWebHandler {
129
- public:
130
- OTARequestHandler(WebServerBase *parent) : parent_(parent) {}
131
- void handleRequest(AsyncWebServerRequest *request) override;
132
- void handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len,
133
- bool final) override;
134
- bool canHandle(AsyncWebServerRequest *request) override {
135
- return request->url() == "/update" && request->method() == HTTP_POST;
136
- }
137
-
138
- // NOLINTNEXTLINE(readability-identifier-naming)
139
- bool isRequestHandlerTrivial() override { return false; }
140
-
141
- protected:
142
- uint32_t last_ota_progress_{0};
143
- uint32_t ota_read_length_{0};
144
- WebServerBase *parent_;
145
- };
146
-
147
127
  } // namespace web_server_base
148
128
  } // namespace esphome
149
129
  #endif
@@ -0,0 +1,254 @@
1
+ #include "esphome/core/defines.h"
2
+ #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
3
+ #include "multipart.h"
4
+ #include "utils.h"
5
+ #include "esphome/core/log.h"
6
+ #include <cstring>
7
+ #include "multipart_parser.h"
8
+
9
+ namespace esphome {
10
+ namespace web_server_idf {
11
+
12
+ static const char *const TAG = "multipart";
13
+
14
+ // ========== MultipartReader Implementation ==========
15
+
16
+ MultipartReader::MultipartReader(const std::string &boundary) {
17
+ // Initialize settings with callbacks
18
+ memset(&settings_, 0, sizeof(settings_));
19
+ settings_.on_header_field = on_header_field;
20
+ settings_.on_header_value = on_header_value;
21
+ settings_.on_part_data = on_part_data;
22
+ settings_.on_part_data_end = on_part_data_end;
23
+
24
+ ESP_LOGV(TAG, "Initializing multipart parser with boundary: '%s' (len: %zu)", boundary.c_str(), boundary.length());
25
+
26
+ // Create parser with boundary
27
+ parser_ = multipart_parser_init(boundary.c_str(), &settings_);
28
+ if (parser_) {
29
+ multipart_parser_set_data(parser_, this);
30
+ } else {
31
+ ESP_LOGE(TAG, "Failed to initialize multipart parser");
32
+ }
33
+ }
34
+
35
+ MultipartReader::~MultipartReader() {
36
+ if (parser_) {
37
+ multipart_parser_free(parser_);
38
+ }
39
+ }
40
+
41
+ size_t MultipartReader::parse(const char *data, size_t len) {
42
+ if (!parser_) {
43
+ ESP_LOGE(TAG, "Parser not initialized");
44
+ return 0;
45
+ }
46
+
47
+ size_t parsed = multipart_parser_execute(parser_, data, len);
48
+
49
+ if (parsed != len) {
50
+ ESP_LOGW(TAG, "Parser consumed %zu of %zu bytes - possible error", parsed, len);
51
+ }
52
+
53
+ return parsed;
54
+ }
55
+
56
+ void MultipartReader::process_header_(const char *value, size_t length) {
57
+ // Process the completed header (field + value pair)
58
+ std::string value_str(value, length);
59
+
60
+ if (str_startswith_case_insensitive(current_header_field_, "content-disposition")) {
61
+ // Parse name and filename from Content-Disposition
62
+ current_part_.name = extract_header_param(value_str, "name");
63
+ current_part_.filename = extract_header_param(value_str, "filename");
64
+ } else if (str_startswith_case_insensitive(current_header_field_, "content-type")) {
65
+ current_part_.content_type = str_trim(value_str);
66
+ }
67
+
68
+ // Clear field for next header
69
+ current_header_field_.clear();
70
+ }
71
+
72
+ int MultipartReader::on_header_field(multipart_parser *parser, const char *at, size_t length) {
73
+ MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
74
+ reader->current_header_field_.assign(at, length);
75
+ return 0;
76
+ }
77
+
78
+ int MultipartReader::on_header_value(multipart_parser *parser, const char *at, size_t length) {
79
+ MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
80
+ reader->process_header_(at, length);
81
+ return 0;
82
+ }
83
+
84
+ int MultipartReader::on_part_data(multipart_parser *parser, const char *at, size_t length) {
85
+ MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
86
+ // Only process file uploads
87
+ if (reader->has_file() && reader->data_callback_) {
88
+ // IMPORTANT: The 'at' pointer points to data within the parser's input buffer.
89
+ // This data is only valid during this callback. The callback handler MUST
90
+ // process or copy the data immediately - it cannot store the pointer for
91
+ // later use as the buffer will be overwritten.
92
+ reader->data_callback_(reinterpret_cast<const uint8_t *>(at), length);
93
+ }
94
+ return 0;
95
+ }
96
+
97
+ int MultipartReader::on_part_data_end(multipart_parser *parser) {
98
+ MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
99
+ ESP_LOGV(TAG, "Part data end");
100
+ if (reader->part_complete_callback_) {
101
+ reader->part_complete_callback_();
102
+ }
103
+ // Clear part info for next part
104
+ reader->current_part_ = Part{};
105
+ return 0;
106
+ }
107
+
108
+ // ========== Utility Functions ==========
109
+
110
+ // Case-insensitive string prefix check
111
+ bool str_startswith_case_insensitive(const std::string &str, const std::string &prefix) {
112
+ if (str.length() < prefix.length()) {
113
+ return false;
114
+ }
115
+ return str_ncmp_ci(str.c_str(), prefix.c_str(), prefix.length());
116
+ }
117
+
118
+ // Extract a parameter value from a header line
119
+ // Handles both quoted and unquoted values
120
+ std::string extract_header_param(const std::string &header, const std::string &param) {
121
+ size_t search_pos = 0;
122
+
123
+ while (search_pos < header.length()) {
124
+ // Look for param name
125
+ const char *found = stristr(header.c_str() + search_pos, param.c_str());
126
+ if (!found) {
127
+ return "";
128
+ }
129
+ size_t pos = found - header.c_str();
130
+
131
+ // Check if this is a word boundary (not part of another parameter)
132
+ if (pos > 0 && header[pos - 1] != ' ' && header[pos - 1] != ';' && header[pos - 1] != '\t') {
133
+ search_pos = pos + 1;
134
+ continue;
135
+ }
136
+
137
+ // Move past param name
138
+ pos += param.length();
139
+
140
+ // Skip whitespace and find '='
141
+ while (pos < header.length() && (header[pos] == ' ' || header[pos] == '\t')) {
142
+ pos++;
143
+ }
144
+
145
+ if (pos >= header.length() || header[pos] != '=') {
146
+ search_pos = pos;
147
+ continue;
148
+ }
149
+
150
+ pos++; // Skip '='
151
+
152
+ // Skip whitespace after '='
153
+ while (pos < header.length() && (header[pos] == ' ' || header[pos] == '\t')) {
154
+ pos++;
155
+ }
156
+
157
+ if (pos >= header.length()) {
158
+ return "";
159
+ }
160
+
161
+ // Check if value is quoted
162
+ if (header[pos] == '"') {
163
+ pos++;
164
+ size_t end = header.find('"', pos);
165
+ if (end != std::string::npos) {
166
+ return header.substr(pos, end - pos);
167
+ }
168
+ // Malformed - no closing quote
169
+ return "";
170
+ }
171
+
172
+ // Unquoted value - find the end (semicolon, comma, or end of string)
173
+ size_t end = pos;
174
+ while (end < header.length() && header[end] != ';' && header[end] != ',' && header[end] != ' ' &&
175
+ header[end] != '\t') {
176
+ end++;
177
+ }
178
+
179
+ return header.substr(pos, end - pos);
180
+ }
181
+
182
+ return "";
183
+ }
184
+
185
+ // Parse boundary from Content-Type header
186
+ // Returns true if boundary found, false otherwise
187
+ // boundary_start and boundary_len will point to the boundary value
188
+ bool parse_multipart_boundary(const char *content_type, const char **boundary_start, size_t *boundary_len) {
189
+ if (!content_type) {
190
+ return false;
191
+ }
192
+
193
+ // Check for multipart/form-data (case-insensitive)
194
+ if (!stristr(content_type, "multipart/form-data")) {
195
+ return false;
196
+ }
197
+
198
+ // Look for boundary parameter
199
+ const char *b = stristr(content_type, "boundary=");
200
+ if (!b) {
201
+ return false;
202
+ }
203
+
204
+ const char *start = b + 9; // Skip "boundary="
205
+
206
+ // Skip whitespace
207
+ while (*start == ' ' || *start == '\t') {
208
+ start++;
209
+ }
210
+
211
+ if (!*start) {
212
+ return false;
213
+ }
214
+
215
+ // Find end of boundary
216
+ const char *end = start;
217
+ if (*end == '"') {
218
+ // Quoted boundary
219
+ start++;
220
+ end++;
221
+ while (*end && *end != '"') {
222
+ end++;
223
+ }
224
+ *boundary_len = end - start;
225
+ } else {
226
+ // Unquoted boundary
227
+ while (*end && *end != ' ' && *end != ';' && *end != '\r' && *end != '\n' && *end != '\t') {
228
+ end++;
229
+ }
230
+ *boundary_len = end - start;
231
+ }
232
+
233
+ if (*boundary_len == 0) {
234
+ return false;
235
+ }
236
+
237
+ *boundary_start = start;
238
+
239
+ return true;
240
+ }
241
+
242
+ // Trim whitespace from both ends of a string
243
+ std::string str_trim(const std::string &str) {
244
+ size_t start = str.find_first_not_of(" \t\r\n");
245
+ if (start == std::string::npos) {
246
+ return "";
247
+ }
248
+ size_t end = str.find_last_not_of(" \t\r\n");
249
+ return str.substr(start, end - start + 1);
250
+ }
251
+
252
+ } // namespace web_server_idf
253
+ } // namespace esphome
254
+ #endif // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
@@ -0,0 +1,86 @@
1
+ #pragma once
2
+ #include "esphome/core/defines.h"
3
+ #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
4
+
5
+ #include <cctype>
6
+ #include <cstring>
7
+ #include <esp_http_server.h>
8
+ #include <functional>
9
+ #include <multipart_parser.h>
10
+ #include <string>
11
+ #include <utility>
12
+
13
+ namespace esphome {
14
+ namespace web_server_idf {
15
+
16
+ // Wrapper around zorxx/multipart-parser for ESP-IDF OTA uploads
17
+ class MultipartReader {
18
+ public:
19
+ struct Part {
20
+ std::string name;
21
+ std::string filename;
22
+ std::string content_type;
23
+ };
24
+
25
+ // IMPORTANT: The data pointer in DataCallback is only valid during the callback!
26
+ // The multipart parser passes pointers to its internal buffer which will be
27
+ // overwritten after the callback returns. Callbacks MUST process or copy the
28
+ // data immediately - storing the pointer for deferred processing will result
29
+ // in use-after-free bugs.
30
+ using DataCallback = std::function<void(const uint8_t *data, size_t len)>;
31
+ using PartCompleteCallback = std::function<void()>;
32
+
33
+ explicit MultipartReader(const std::string &boundary);
34
+ ~MultipartReader();
35
+
36
+ // Set callbacks for handling data
37
+ void set_data_callback(DataCallback callback) { data_callback_ = std::move(callback); }
38
+ void set_part_complete_callback(PartCompleteCallback callback) { part_complete_callback_ = std::move(callback); }
39
+
40
+ // Parse incoming data
41
+ size_t parse(const char *data, size_t len);
42
+
43
+ // Get current part info
44
+ const Part &get_current_part() const { return current_part_; }
45
+
46
+ // Check if we found a file upload
47
+ bool has_file() const { return !current_part_.filename.empty(); }
48
+
49
+ private:
50
+ static int on_header_field(multipart_parser *parser, const char *at, size_t length);
51
+ static int on_header_value(multipart_parser *parser, const char *at, size_t length);
52
+ static int on_part_data(multipart_parser *parser, const char *at, size_t length);
53
+ static int on_part_data_end(multipart_parser *parser);
54
+
55
+ multipart_parser *parser_{nullptr};
56
+ multipart_parser_settings settings_{};
57
+
58
+ Part current_part_;
59
+ std::string current_header_field_;
60
+
61
+ DataCallback data_callback_;
62
+ PartCompleteCallback part_complete_callback_;
63
+
64
+ void process_header_(const char *value, size_t length);
65
+ };
66
+
67
+ // ========== Utility Functions ==========
68
+
69
+ // Case-insensitive string prefix check
70
+ bool str_startswith_case_insensitive(const std::string &str, const std::string &prefix);
71
+
72
+ // Extract a parameter value from a header line
73
+ // Handles both quoted and unquoted values
74
+ std::string extract_header_param(const std::string &header, const std::string &param);
75
+
76
+ // Parse boundary from Content-Type header
77
+ // Returns true if boundary found, false otherwise
78
+ // boundary_start and boundary_len will point to the boundary value
79
+ bool parse_multipart_boundary(const char *content_type, const char **boundary_start, size_t *boundary_len);
80
+
81
+ // Trim whitespace from both ends of a string
82
+ std::string str_trim(const std::string &str);
83
+
84
+ } // namespace web_server_idf
85
+ } // namespace esphome
86
+ #endif // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)