esphome 2025.6.3__py3-none-any.whl → 2025.7.0b2__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 (606) 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 +57 -21
  22. esphome/components/api/api_connection.cpp +344 -539
  23. esphome/components/api/api_connection.h +224 -141
  24. esphome/components/api/api_frame_helper.cpp +91 -127
  25. esphome/components/api/api_frame_helper.h +64 -54
  26. esphome/components/api/api_pb2.cpp +1837 -9044
  27. esphome/components/api/api_pb2.h +532 -685
  28. esphome/components/api/api_pb2_dump.cpp +4432 -0
  29. esphome/components/api/api_pb2_service.cpp +184 -425
  30. esphome/components/api/api_pb2_service.h +13 -6
  31. esphome/components/api/api_server.cpp +131 -167
  32. esphome/components/api/api_server.h +38 -10
  33. esphome/components/api/client.py +8 -2
  34. esphome/components/api/custom_api_device.h +8 -0
  35. esphome/components/api/list_entities.cpp +37 -104
  36. esphome/components/api/list_entities.h +33 -23
  37. esphome/components/api/proto.h +532 -26
  38. esphome/components/api/subscribe_state.cpp +23 -29
  39. esphome/components/api/subscribe_state.h +26 -19
  40. esphome/components/api/user_services.h +2 -0
  41. esphome/components/as5600/as5600.h +0 -1
  42. esphome/components/async_tcp/__init__.py +14 -5
  43. esphome/components/atc_mithermometer/atc_mithermometer.h +0 -1
  44. esphome/components/atm90e32/atm90e32.cpp +2 -1
  45. esphome/components/audio/audio_decoder.cpp +1 -1
  46. esphome/components/audio/audio_transfer_buffer.cpp +2 -2
  47. esphome/components/b_parasite/b_parasite.h +0 -1
  48. esphome/components/bedjet/bedjet_hub.cpp +5 -1
  49. esphome/components/bedjet/climate/bedjet_climate.cpp +5 -1
  50. esphome/components/beken_spi_led_strip/led_strip.cpp +4 -2
  51. esphome/components/bh1750/bh1750.cpp +5 -5
  52. esphome/components/binary_sensor/__init__.py +82 -5
  53. esphome/components/binary_sensor/automation.h +19 -1
  54. esphome/components/binary_sensor/binary_sensor.cpp +12 -30
  55. esphome/components/binary_sensor/binary_sensor.h +11 -25
  56. esphome/components/binary_sensor/filter.cpp +29 -24
  57. esphome/components/binary_sensor/filter.h +20 -10
  58. esphome/components/ble_client/output/ble_binary_output.h +0 -1
  59. esphome/components/ble_client/sensor/ble_rssi_sensor.cpp +5 -1
  60. esphome/components/ble_client/sensor/ble_rssi_sensor.h +0 -1
  61. esphome/components/ble_client/sensor/ble_sensor.cpp +5 -1
  62. esphome/components/ble_client/sensor/ble_sensor.h +0 -1
  63. esphome/components/ble_client/switch/ble_switch.h +0 -1
  64. esphome/components/ble_client/text_sensor/ble_text_sensor.cpp +5 -1
  65. esphome/components/ble_client/text_sensor/ble_text_sensor.h +0 -1
  66. esphome/components/ble_presence/ble_presence_device.h +0 -1
  67. esphome/components/ble_rssi/ble_rssi_sensor.h +0 -1
  68. esphome/components/ble_scanner/ble_scanner.h +0 -1
  69. esphome/components/bluetooth_proxy/bluetooth_connection.h +9 -2
  70. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +16 -6
  71. esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -2
  72. esphome/components/bme680/sensor.py +1 -1
  73. esphome/components/bmp581/bmp581.h +0 -2
  74. esphome/components/button/__init__.py +5 -2
  75. esphome/components/camera/__init__.py +1 -0
  76. esphome/components/camera/camera.cpp +22 -0
  77. esphome/components/camera/camera.h +80 -0
  78. esphome/components/canbus/__init__.py +1 -0
  79. esphome/components/cap1188/cap1188.h +0 -1
  80. esphome/components/captive_portal/__init__.py +12 -2
  81. esphome/components/captive_portal/captive_portal.cpp +12 -2
  82. esphome/components/captive_portal/captive_portal.h +5 -2
  83. esphome/components/ccs811/ccs811.h +0 -2
  84. esphome/components/climate/__init__.py +5 -2
  85. esphome/components/cm1106/sensor.py +2 -2
  86. esphome/components/const/__init__.py +2 -0
  87. esphome/components/copy/binary_sensor/copy_binary_sensor.h +0 -1
  88. esphome/components/copy/button/copy_button.h +0 -1
  89. esphome/components/copy/cover/copy_cover.h +0 -1
  90. esphome/components/copy/fan/copy_fan.h +0 -1
  91. esphome/components/copy/lock/copy_lock.h +0 -1
  92. esphome/components/copy/number/copy_number.h +0 -1
  93. esphome/components/copy/select/copy_select.h +0 -1
  94. esphome/components/copy/sensor/copy_sensor.h +0 -1
  95. esphome/components/copy/switch/copy_switch.h +0 -1
  96. esphome/components/copy/text/copy_text.h +0 -1
  97. esphome/components/copy/text_sensor/copy_text_sensor.h +0 -1
  98. esphome/components/cover/__init__.py +5 -2
  99. esphome/components/cs5460a/cs5460a.h +0 -1
  100. esphome/components/datetime/__init__.py +4 -2
  101. esphome/components/debug/__init__.py +20 -0
  102. esphome/components/debug/debug_esp32.cpp +2 -0
  103. esphome/components/deep_sleep/__init__.py +43 -9
  104. esphome/components/demo/__init__.py +2 -2
  105. esphome/components/display/display.cpp +4 -3
  106. esphome/components/display/display.h +0 -2
  107. esphome/components/display/display_buffer.cpp +1 -1
  108. esphome/components/ds2484/__init__.py +1 -0
  109. esphome/components/ds2484/ds2484.cpp +209 -0
  110. esphome/components/ds2484/ds2484.h +43 -0
  111. esphome/components/ds2484/one_wire.py +37 -0
  112. esphome/components/duty_time/duty_time_sensor.h +0 -1
  113. esphome/components/ens160_base/ens160_base.h +0 -1
  114. esphome/components/es7210/es7210.h +0 -1
  115. esphome/components/es7243e/es7243e.h +0 -1
  116. esphome/components/es8156/es8156.h +0 -1
  117. esphome/components/es8311/es8311.h +0 -1
  118. esphome/components/es8388/es8388.h +0 -1
  119. esphome/components/esp32/__init__.py +103 -135
  120. esphome/components/esp32/core.cpp +0 -4
  121. esphome/components/esp32/gpio.h +1 -1
  122. esphome/components/esp32/helpers.cpp +69 -0
  123. esphome/components/esp32_ble/ble.cpp +5 -6
  124. esphome/components/esp32_ble/ble.h +29 -14
  125. esphome/components/esp32_ble/ble_event.h +6 -6
  126. esphome/components/esp32_ble_client/ble_client_base.cpp +21 -6
  127. esphome/components/esp32_ble_client/ble_client_base.h +24 -9
  128. esphome/components/esp32_ble_tracker/__init__.py +2 -8
  129. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +5 -5
  130. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +11 -7
  131. esphome/components/esp32_camera/__init__.py +112 -98
  132. esphome/components/esp32_camera/esp32_camera.cpp +41 -31
  133. esphome/components/esp32_camera/esp32_camera.h +35 -30
  134. esphome/components/esp32_camera_web_server/__init__.py +2 -1
  135. esphome/components/esp32_camera_web_server/camera_web_server.cpp +8 -8
  136. esphome/components/esp32_camera_web_server/camera_web_server.h +3 -3
  137. esphome/components/esp32_hall/sensor.py +2 -21
  138. esphome/components/esp32_hosted/__init__.py +101 -0
  139. esphome/components/esp32_hosted/esp32_hosted.py.script +12 -0
  140. esphome/components/esp32_improv/esp32_improv_component.cpp +3 -0
  141. esphome/components/esp32_rmt/__init__.py +0 -58
  142. esphome/components/esp32_rmt_led_strip/led_strip.cpp +77 -63
  143. esphome/components/esp32_rmt_led_strip/led_strip.h +11 -17
  144. esphome/components/esp32_rmt_led_strip/light.py +14 -76
  145. esphome/components/esp32_touch/esp32_touch.h +174 -28
  146. esphome/components/esp32_touch/esp32_touch_common.cpp +162 -0
  147. esphome/components/esp32_touch/esp32_touch_v1.cpp +240 -0
  148. esphome/components/esp32_touch/esp32_touch_v2.cpp +397 -0
  149. esphome/components/esp8266/__init__.py +2 -0
  150. esphome/components/esp8266/gpio.cpp +10 -10
  151. esphome/components/esp8266/helpers.cpp +31 -0
  152. esphome/components/esphome/ota/__init__.py +1 -0
  153. esphome/components/esphome/ota/ota_esphome.cpp +24 -19
  154. esphome/components/ethernet/__init__.py +42 -23
  155. esphome/components/ethernet/esp_eth_phy_jl1101.c +0 -16
  156. esphome/components/ethernet/ethernet_component.cpp +69 -29
  157. esphome/components/ethernet/ethernet_component.h +18 -10
  158. esphome/components/event/__init__.py +5 -2
  159. esphome/components/ezo/ezo.h +0 -1
  160. esphome/components/ezo_pmp/ezo_pmp.h +0 -1
  161. esphome/components/fan/__init__.py +5 -2
  162. esphome/components/feedback/feedback_cover.h +0 -1
  163. esphome/components/font/__init__.py +92 -82
  164. esphome/components/font/font.cpp +9 -2
  165. esphome/components/font/font.h +20 -5
  166. esphome/components/fs3000/fs3000.h +0 -1
  167. esphome/components/gcja5/gcja5.h +0 -1
  168. esphome/components/gl_r01_i2c/__init__.py +0 -0
  169. esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +68 -0
  170. esphome/components/gl_r01_i2c/gl_r01_i2c.h +22 -0
  171. esphome/components/gl_r01_i2c/sensor.py +36 -0
  172. esphome/components/gp8403/gp8403.h +0 -1
  173. esphome/components/gpio/binary_sensor/__init__.py +17 -0
  174. esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +77 -3
  175. esphome/components/gpio/binary_sensor/gpio_binary_sensor.h +40 -0
  176. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +0 -2
  177. esphome/components/he60r/he60r.h +0 -1
  178. esphome/components/heatpumpir/climate.py +2 -1
  179. esphome/components/heatpumpir/heatpumpir.cpp +1 -0
  180. esphome/components/heatpumpir/heatpumpir.h +1 -0
  181. esphome/components/honeywellabp2_i2c/honeywellabp2.h +0 -1
  182. esphome/components/host/__init__.py +3 -1
  183. esphome/components/host/helpers.cpp +57 -0
  184. esphome/components/http_request/__init__.py +19 -1
  185. esphome/components/http_request/http_request.h +1 -1
  186. esphome/components/http_request/http_request_arduino.h +1 -0
  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 +421 -268
  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 +5 -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 +132 -47
  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 +34 -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 +2 -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 +0 -4
  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/usb_host/usb_host_client.cpp +10 -10
  477. esphome/components/usb_uart/cp210x.cpp +1 -1
  478. esphome/components/usb_uart/usb_uart.cpp +41 -44
  479. esphome/components/usb_uart/usb_uart.h +4 -3
  480. esphome/components/valve/__init__.py +5 -2
  481. esphome/components/vbus/vbus.h +0 -1
  482. esphome/components/veml3235/veml3235.h +0 -1
  483. esphome/components/veml7700/veml7700.h +0 -1
  484. esphome/components/vl53l0x/vl53l0x_sensor.h +0 -1
  485. esphome/components/voice_assistant/voice_assistant.cpp +4 -4
  486. esphome/components/watchdog/watchdog.cpp +0 -4
  487. esphome/components/waveshare_epaper/waveshare_epaper.cpp +6 -6
  488. esphome/components/web_server/__init__.py +34 -19
  489. esphome/components/web_server/ota/__init__.py +32 -0
  490. esphome/components/web_server/ota/ota_web_server.cpp +210 -0
  491. esphome/components/web_server/ota/ota_web_server.h +26 -0
  492. esphome/components/web_server/web_server.cpp +305 -427
  493. esphome/components/web_server/web_server.h +33 -23
  494. esphome/components/web_server/web_server_v1.cpp +4 -5
  495. esphome/components/web_server_base/__init__.py +5 -2
  496. esphome/components/web_server_base/web_server_base.cpp +2 -94
  497. esphome/components/web_server_base/web_server_base.h +5 -25
  498. esphome/components/web_server_idf/multipart.cpp +254 -0
  499. esphome/components/web_server_idf/multipart.h +86 -0
  500. esphome/components/web_server_idf/utils.cpp +32 -0
  501. esphome/components/web_server_idf/utils.h +10 -0
  502. esphome/components/web_server_idf/web_server_idf.cpp +162 -16
  503. esphome/components/web_server_idf/web_server_idf.h +11 -10
  504. esphome/components/wiegand/wiegand.cpp +2 -2
  505. esphome/components/wifi/__init__.py +18 -0
  506. esphome/components/wifi/wifi_component.cpp +17 -22
  507. esphome/components/wifi/wifi_component.h +27 -23
  508. esphome/components/wifi/wifi_component_esp32_arduino.cpp +52 -59
  509. esphome/components/wifi/wifi_component_esp8266.cpp +46 -46
  510. esphome/components/wifi/wifi_component_esp_idf.cpp +35 -36
  511. esphome/components/wifi/wifi_component_libretiny.cpp +26 -27
  512. esphome/components/wifi/wifi_component_pico_w.cpp +3 -3
  513. esphome/components/wifi_info/wifi_info_text_sensor.cpp +6 -6
  514. esphome/components/wireguard/__init__.py +2 -11
  515. esphome/components/xiaomi_ble/xiaomi_ble.cpp +13 -1
  516. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  517. esphome/components/xiaomi_cgd1/xiaomi_cgd1.h +0 -1
  518. esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h +0 -1
  519. esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +0 -1
  520. esphome/components/xiaomi_cgpr1/xiaomi_cgpr1.h +0 -1
  521. esphome/components/xiaomi_gcls002/xiaomi_gcls002.h +0 -1
  522. esphome/components/xiaomi_hhccjcy01/xiaomi_hhccjcy01.h +0 -1
  523. esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h +0 -1
  524. esphome/components/xiaomi_hhccpot002/xiaomi_hhccpot002.h +0 -1
  525. esphome/components/xiaomi_jqjcy01ym/xiaomi_jqjcy01ym.h +0 -1
  526. esphome/components/xiaomi_lywsd02/xiaomi_lywsd02.h +0 -1
  527. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +0 -1
  528. esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.h +0 -1
  529. esphome/components/xiaomi_lywsdcgq/xiaomi_lywsdcgq.h +0 -1
  530. esphome/components/xiaomi_mhoc303/xiaomi_mhoc303.h +0 -1
  531. esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.h +0 -1
  532. esphome/components/xiaomi_miscale/xiaomi_miscale.h +0 -1
  533. esphome/components/xiaomi_mjyd02yla/xiaomi_mjyd02yla.h +0 -1
  534. esphome/components/xiaomi_mue4094rt/xiaomi_mue4094rt.h +0 -1
  535. esphome/components/xiaomi_rtcgq02lm/xiaomi_rtcgq02lm.h +0 -1
  536. esphome/components/xiaomi_wx08zm/xiaomi_wx08zm.h +0 -1
  537. esphome/components/xiaomi_xmwsdj04mmc/__init__.py +0 -0
  538. esphome/components/xiaomi_xmwsdj04mmc/sensor.py +77 -0
  539. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.cpp +77 -0
  540. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.h +36 -0
  541. esphome/components/zio_ultrasonic/zio_ultrasonic.h +0 -2
  542. esphome/components/zyaura/zyaura.h +0 -1
  543. esphome/config.py +88 -22
  544. esphome/config_helpers.py +74 -1
  545. esphome/config_validation.py +12 -1
  546. esphome/const.py +65 -10
  547. esphome/core/__init__.py +18 -2
  548. esphome/core/application.cpp +163 -10
  549. esphome/core/application.h +145 -165
  550. esphome/core/area.h +19 -0
  551. esphome/core/automation.h +58 -9
  552. esphome/core/color.cpp +3 -5
  553. esphome/core/color.h +16 -16
  554. esphome/core/component.cpp +151 -18
  555. esphome/core/component.h +98 -4
  556. esphome/core/component_iterator.cpp +11 -9
  557. esphome/core/component_iterator.h +12 -10
  558. esphome/core/config.py +155 -6
  559. esphome/core/controller.cpp +4 -2
  560. esphome/core/controller.h +1 -1
  561. esphome/core/datatypes.h +2 -2
  562. esphome/core/defines.h +17 -2
  563. esphome/core/device.h +20 -0
  564. esphome/core/entity_base.cpp +20 -15
  565. esphome/core/entity_base.h +76 -0
  566. esphome/core/entity_helpers.py +168 -1
  567. esphome/core/event_pool.h +81 -0
  568. esphome/core/helpers.cpp +75 -230
  569. esphome/core/helpers.h +164 -104
  570. esphome/core/lock_free_queue.h +151 -0
  571. esphome/core/log.cpp +2 -2
  572. esphome/core/log.h +2 -0
  573. esphome/core/optional.h +5 -0
  574. esphome/core/ring_buffer.cpp +2 -2
  575. esphome/core/scheduler.cpp +275 -103
  576. esphome/core/scheduler.h +154 -17
  577. esphome/core/time.cpp +5 -5
  578. esphome/core/time.h +5 -5
  579. esphome/cpp_generator.py +17 -0
  580. esphome/cpp_helpers.py +0 -22
  581. esphome/cpp_types.py +3 -1
  582. esphome/dashboard/entries.py +1 -1
  583. esphome/dashboard/util/text.py +5 -21
  584. esphome/dashboard/web_server.py +9 -1
  585. esphome/helpers.py +47 -0
  586. esphome/loader.py +15 -1
  587. esphome/pins.py +14 -8
  588. esphome/wizard.py +17 -4
  589. esphome/writer.py +21 -3
  590. esphome/yaml_util.py +0 -2
  591. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/METADATA +10 -9
  592. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/RECORD +597 -538
  593. esphome/components/api/api_pb2_size.h +0 -361
  594. esphome/components/esp32_ble/ble_event_pool.h +0 -72
  595. esphome/components/esp32_ble/queue.h +0 -85
  596. esphome/components/esp32_hall/esp32_hall.cpp +0 -25
  597. esphome/components/esp32_hall/esp32_hall.h +0 -23
  598. esphome/components/esp32_touch/esp32_touch.cpp +0 -355
  599. esphome/components/ld2410/button/reset_button.cpp +0 -9
  600. esphome/components/ld2450/button/reset_button.cpp +0 -9
  601. esphome/components/openthread/tlv.py +0 -65
  602. /esphome/{dashboard/enum.py → enum.py} +0 -0
  603. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/WHEEL +0 -0
  604. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/entry_points.txt +0 -0
  605. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/licenses/LICENSE +0 -0
  606. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,7 @@
1
1
  #ifdef USE_ESP_IDF
2
2
  #include <memory>
3
+ #include <cstring>
4
+ #include <cctype>
3
5
  #include "esphome/core/helpers.h"
4
6
  #include "esphome/core/log.h"
5
7
  #include "http_parser.h"
@@ -88,6 +90,36 @@ optional<std::string> query_key_value(const std::string &query_url, const std::s
88
90
  return {val.get()};
89
91
  }
90
92
 
93
+ // Helper function for case-insensitive string region comparison
94
+ bool str_ncmp_ci(const char *s1, const char *s2, size_t n) {
95
+ for (size_t i = 0; i < n; i++) {
96
+ if (!char_equals_ci(s1[i], s2[i])) {
97
+ return false;
98
+ }
99
+ }
100
+ return true;
101
+ }
102
+
103
+ // Case-insensitive string search (like strstr but case-insensitive)
104
+ const char *stristr(const char *haystack, const char *needle) {
105
+ if (!haystack) {
106
+ return nullptr;
107
+ }
108
+
109
+ size_t needle_len = strlen(needle);
110
+ if (needle_len == 0) {
111
+ return haystack;
112
+ }
113
+
114
+ for (const char *p = haystack; *p; p++) {
115
+ if (str_ncmp_ci(p, needle, needle_len)) {
116
+ return p;
117
+ }
118
+ }
119
+
120
+ return nullptr;
121
+ }
122
+
91
123
  } // namespace web_server_idf
92
124
  } // namespace esphome
93
125
  #endif // USE_ESP_IDF
@@ -2,6 +2,7 @@
2
2
  #ifdef USE_ESP_IDF
3
3
 
4
4
  #include <esp_http_server.h>
5
+ #include <string>
5
6
  #include "esphome/core/helpers.h"
6
7
 
7
8
  namespace esphome {
@@ -12,6 +13,15 @@ optional<std::string> request_get_header(httpd_req_t *req, const char *name);
12
13
  optional<std::string> request_get_url_query(httpd_req_t *req);
13
14
  optional<std::string> query_key_value(const std::string &query_url, const std::string &key);
14
15
 
16
+ // Helper function for case-insensitive character comparison
17
+ inline bool char_equals_ci(char a, char b) { return ::tolower(a) == ::tolower(b); }
18
+
19
+ // Helper function for case-insensitive string region comparison
20
+ bool str_ncmp_ci(const char *s1, const char *s2, size_t n);
21
+
22
+ // Case-insensitive string search (like strstr but case-insensitive)
23
+ const char *stristr(const char *haystack, const char *needle);
24
+
15
25
  } // namespace web_server_idf
16
26
  } // namespace esphome
17
27
  #endif // USE_ESP_IDF
@@ -1,16 +1,25 @@
1
1
  #ifdef USE_ESP_IDF
2
2
 
3
3
  #include <cstdarg>
4
+ #include <memory>
5
+ #include <cstring>
6
+ #include <cctype>
4
7
 
5
8
  #include "esphome/core/helpers.h"
6
9
  #include "esphome/core/log.h"
7
10
 
8
11
  #include "esp_tls_crypto.h"
12
+ #include <freertos/FreeRTOS.h>
13
+ #include <freertos/task.h>
9
14
 
10
15
  #include "utils.h"
11
-
12
16
  #include "web_server_idf.h"
13
17
 
18
+ #ifdef USE_WEBSERVER_OTA
19
+ #include <multipart_parser.h>
20
+ #include "multipart.h" // For parse_multipart_boundary and other utils
21
+ #endif
22
+
14
23
  #ifdef USE_WEBSERVER
15
24
  #include "esphome/components/web_server/web_server.h"
16
25
  #include "esphome/components/web_server/list_entities.h"
@@ -28,6 +37,15 @@ namespace web_server_idf {
28
37
 
29
38
  static const char *const TAG = "web_server_idf";
30
39
 
40
+ // Global instance to avoid guard variable (saves 8 bytes)
41
+ // This is initialized at program startup before any threads
42
+ namespace {
43
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
44
+ DefaultHeaders default_headers_instance;
45
+ } // namespace
46
+
47
+ DefaultHeaders &DefaultHeaders::Instance() { return default_headers_instance; }
48
+
31
49
  void AsyncWebServer::end() {
32
50
  if (this->server_) {
33
51
  httpd_stop(this->server_);
@@ -72,18 +90,32 @@ void AsyncWebServer::begin() {
72
90
  esp_err_t AsyncWebServer::request_post_handler(httpd_req_t *r) {
73
91
  ESP_LOGVV(TAG, "Enter AsyncWebServer::request_post_handler. uri=%s", r->uri);
74
92
  auto content_type = request_get_header(r, "Content-Type");
75
- if (content_type.has_value() && *content_type != "application/x-www-form-urlencoded") {
76
- ESP_LOGW(TAG, "Only application/x-www-form-urlencoded supported for POST request");
77
- // fallback to get handler to support backward compatibility
78
- return AsyncWebServer::request_handler(r);
79
- }
80
93
 
81
94
  if (!request_has_header(r, "Content-Length")) {
82
- ESP_LOGW(TAG, "Content length is requred for post: %s", r->uri);
95
+ ESP_LOGW(TAG, "Content length is required for post: %s", r->uri);
83
96
  httpd_resp_send_err(r, HTTPD_411_LENGTH_REQUIRED, nullptr);
84
97
  return ESP_OK;
85
98
  }
86
99
 
100
+ if (content_type.has_value()) {
101
+ const char *content_type_char = content_type.value().c_str();
102
+
103
+ // Check most common case first
104
+ if (stristr(content_type_char, "application/x-www-form-urlencoded") != nullptr) {
105
+ // Normal form data - proceed with regular handling
106
+ #ifdef USE_WEBSERVER_OTA
107
+ } else if (stristr(content_type_char, "multipart/form-data") != nullptr) {
108
+ auto *server = static_cast<AsyncWebServer *>(r->user_ctx);
109
+ return server->handle_multipart_upload_(r, content_type_char);
110
+ #endif
111
+ } else {
112
+ ESP_LOGW(TAG, "Unsupported content type for POST: %s", content_type_char);
113
+ // fallback to get handler to support backward compatibility
114
+ return AsyncWebServer::request_handler(r);
115
+ }
116
+ }
117
+
118
+ // Handle regular form data
87
119
  if (r->content_len > HTTPD_MAX_REQ_HDR_LEN) {
88
120
  ESP_LOGW(TAG, "Request size is to big: %zu", r->content_len);
89
121
  httpd_resp_send_err(r, HTTPD_400_BAD_REQUEST, nullptr);
@@ -292,21 +324,38 @@ void AsyncEventSource::handleRequest(AsyncWebServerRequest *request) {
292
324
  }
293
325
 
294
326
  void AsyncEventSource::loop() {
295
- for (auto *ses : this->sessions_) {
296
- ses->loop();
327
+ // Clean up dead sessions safely
328
+ // This follows the ESP-IDF pattern where free_ctx marks resources as dead
329
+ // and the main loop handles the actual cleanup to avoid race conditions
330
+ auto it = this->sessions_.begin();
331
+ while (it != this->sessions_.end()) {
332
+ auto *ses = *it;
333
+ // If the session has a dead socket (marked by destroy callback)
334
+ if (ses->fd_.load() == 0) {
335
+ ESP_LOGD(TAG, "Removing dead event source session");
336
+ it = this->sessions_.erase(it);
337
+ delete ses; // NOLINT(cppcoreguidelines-owning-memory)
338
+ } else {
339
+ ses->loop();
340
+ ++it;
341
+ }
297
342
  }
298
343
  }
299
344
 
300
345
  void AsyncEventSource::try_send_nodefer(const char *message, const char *event, uint32_t id, uint32_t reconnect) {
301
346
  for (auto *ses : this->sessions_) {
302
- ses->try_send_nodefer(message, event, id, reconnect);
347
+ if (ses->fd_.load() != 0) { // Skip dead sessions
348
+ ses->try_send_nodefer(message, event, id, reconnect);
349
+ }
303
350
  }
304
351
  }
305
352
 
306
353
  void AsyncEventSource::deferrable_send_state(void *source, const char *event_type,
307
354
  message_generator_t *message_generator) {
308
355
  for (auto *ses : this->sessions_) {
309
- ses->deferrable_send_state(source, event_type, message_generator);
356
+ if (ses->fd_.load() != 0) { // Skip dead sessions
357
+ ses->deferrable_send_state(source, event_type, message_generator);
358
+ }
310
359
  }
311
360
  }
312
361
 
@@ -331,13 +380,14 @@ AsyncEventSourceResponse::AsyncEventSourceResponse(const AsyncWebServerRequest *
331
380
  req->free_ctx = AsyncEventSourceResponse::destroy;
332
381
 
333
382
  this->hd_ = req->handle;
334
- this->fd_ = httpd_req_to_sockfd(req);
383
+ this->fd_.store(httpd_req_to_sockfd(req));
335
384
 
336
385
  // Configure reconnect timeout and send config
337
386
  // this should always go through since the tcp send buffer is empty on connect
338
387
  std::string message = ws->get_config_json();
339
388
  this->try_send_nodefer(message.c_str(), "ping", millis(), 30000);
340
389
 
390
+ #ifdef USE_WEBSERVER_SORTING
341
391
  for (auto &group : ws->sorting_groups_) {
342
392
  message = json::build_json([group](JsonObject root) {
343
393
  root["name"] = group.second.name;
@@ -348,6 +398,7 @@ AsyncEventSourceResponse::AsyncEventSourceResponse(const AsyncWebServerRequest *
348
398
  // since the only thing in the send buffer at this point is the initial ping/config
349
399
  this->try_send_nodefer(message.c_str(), "sorting_group");
350
400
  }
401
+ #endif
351
402
 
352
403
  this->entities_iterator_->begin(ws->include_internal_);
353
404
 
@@ -360,8 +411,10 @@ AsyncEventSourceResponse::AsyncEventSourceResponse(const AsyncWebServerRequest *
360
411
 
361
412
  void AsyncEventSourceResponse::destroy(void *ptr) {
362
413
  auto *rsp = static_cast<AsyncEventSourceResponse *>(ptr);
363
- rsp->server_->sessions_.erase(rsp);
364
- delete rsp; // NOLINT(cppcoreguidelines-owning-memory)
414
+ ESP_LOGD(TAG, "Event source connection closed (fd: %d)", rsp->fd_.load());
415
+ // Mark as dead by setting fd to 0 - will be cleaned up in the main loop
416
+ rsp->fd_.store(0);
417
+ // Note: We don't delete or remove from set here to avoid race conditions
365
418
  }
366
419
 
367
420
  // helper for allowing only unique entries in the queue
@@ -401,9 +454,11 @@ void AsyncEventSourceResponse::process_buffer_() {
401
454
  return;
402
455
  }
403
456
 
404
- int bytes_sent = httpd_socket_send(this->hd_, this->fd_, event_buffer_.c_str() + event_bytes_sent_,
457
+ int bytes_sent = httpd_socket_send(this->hd_, this->fd_.load(), event_buffer_.c_str() + event_bytes_sent_,
405
458
  event_buffer_.size() - event_bytes_sent_, 0);
406
459
  if (bytes_sent == HTTPD_SOCK_ERR_TIMEOUT || bytes_sent == HTTPD_SOCK_ERR_FAIL) {
460
+ // Socket error - just return, the connection will be closed by httpd
461
+ // and our destroy callback will be called
407
462
  return;
408
463
  }
409
464
  event_bytes_sent_ += bytes_sent;
@@ -423,7 +478,7 @@ void AsyncEventSourceResponse::loop() {
423
478
 
424
479
  bool AsyncEventSourceResponse::try_send_nodefer(const char *message, const char *event, uint32_t id,
425
480
  uint32_t reconnect) {
426
- if (this->fd_ == 0) {
481
+ if (this->fd_.load() == 0) {
427
482
  return false;
428
483
  }
429
484
 
@@ -516,6 +571,97 @@ void AsyncEventSourceResponse::deferrable_send_state(void *source, const char *e
516
571
  }
517
572
  #endif
518
573
 
574
+ #ifdef USE_WEBSERVER_OTA
575
+ esp_err_t AsyncWebServer::handle_multipart_upload_(httpd_req_t *r, const char *content_type) {
576
+ static constexpr size_t MULTIPART_CHUNK_SIZE = 1460; // Match Arduino AsyncWebServer buffer size
577
+ static constexpr size_t YIELD_INTERVAL_BYTES = 16 * 1024; // Yield every 16KB to prevent watchdog
578
+
579
+ // Parse boundary and create reader
580
+ const char *boundary_start;
581
+ size_t boundary_len;
582
+ if (!parse_multipart_boundary(content_type, &boundary_start, &boundary_len)) {
583
+ ESP_LOGE(TAG, "Failed to parse multipart boundary");
584
+ httpd_resp_send_err(r, HTTPD_400_BAD_REQUEST, nullptr);
585
+ return ESP_FAIL;
586
+ }
587
+
588
+ AsyncWebServerRequest req(r);
589
+ AsyncWebHandler *handler = nullptr;
590
+ for (auto *h : this->handlers_) {
591
+ if (h->canHandle(&req)) {
592
+ handler = h;
593
+ break;
594
+ }
595
+ }
596
+
597
+ if (!handler) {
598
+ ESP_LOGW(TAG, "No handler found for OTA request");
599
+ httpd_resp_send_err(r, HTTPD_404_NOT_FOUND, nullptr);
600
+ return ESP_OK;
601
+ }
602
+
603
+ // Upload state
604
+ std::string filename;
605
+ size_t index = 0;
606
+ // Create reader on heap to reduce stack usage
607
+ auto reader = std::make_unique<MultipartReader>("--" + std::string(boundary_start, boundary_len));
608
+
609
+ // Configure callbacks
610
+ reader->set_data_callback([&](const uint8_t *data, size_t len) {
611
+ if (!reader->has_file() || !len)
612
+ return;
613
+
614
+ if (filename.empty()) {
615
+ filename = reader->get_current_part().filename;
616
+ ESP_LOGV(TAG, "Processing file: '%s'", filename.c_str());
617
+ handler->handleUpload(&req, filename, 0, nullptr, 0, false); // Start
618
+ }
619
+
620
+ handler->handleUpload(&req, filename, index, const_cast<uint8_t *>(data), len, false);
621
+ index += len;
622
+ });
623
+
624
+ reader->set_part_complete_callback([&]() {
625
+ if (index > 0) {
626
+ handler->handleUpload(&req, filename, index, nullptr, 0, true); // End
627
+ filename.clear();
628
+ index = 0;
629
+ }
630
+ });
631
+
632
+ // Process data
633
+ std::unique_ptr<char[]> buffer(new char[MULTIPART_CHUNK_SIZE]);
634
+ size_t bytes_since_yield = 0;
635
+
636
+ for (size_t remaining = r->content_len; remaining > 0;) {
637
+ int recv_len = httpd_req_recv(r, buffer.get(), std::min(remaining, MULTIPART_CHUNK_SIZE));
638
+
639
+ if (recv_len <= 0) {
640
+ httpd_resp_send_err(r, recv_len == HTTPD_SOCK_ERR_TIMEOUT ? HTTPD_408_REQ_TIMEOUT : HTTPD_400_BAD_REQUEST,
641
+ nullptr);
642
+ return recv_len == HTTPD_SOCK_ERR_TIMEOUT ? ESP_ERR_TIMEOUT : ESP_FAIL;
643
+ }
644
+
645
+ if (reader->parse(buffer.get(), recv_len) != static_cast<size_t>(recv_len)) {
646
+ ESP_LOGW(TAG, "Multipart parser error");
647
+ httpd_resp_send_err(r, HTTPD_400_BAD_REQUEST, nullptr);
648
+ return ESP_FAIL;
649
+ }
650
+
651
+ remaining -= recv_len;
652
+ bytes_since_yield += recv_len;
653
+
654
+ if (bytes_since_yield > YIELD_INTERVAL_BYTES) {
655
+ vTaskDelay(1);
656
+ bytes_since_yield = 0;
657
+ }
658
+ }
659
+
660
+ handler->handleRequest(&req);
661
+ return ESP_OK;
662
+ }
663
+ #endif // USE_WEBSERVER_OTA
664
+
519
665
  } // namespace web_server_idf
520
666
  } // namespace esphome
521
667
 
@@ -4,6 +4,7 @@
4
4
  #include "esphome/core/defines.h"
5
5
  #include <esp_http_server.h>
6
6
 
7
+ #include <atomic>
7
8
  #include <functional>
8
9
  #include <list>
9
10
  #include <map>
@@ -135,8 +136,8 @@ class AsyncWebServerRequest {
135
136
  return res;
136
137
  }
137
138
  // NOLINTNEXTLINE(readability-identifier-naming)
138
- AsyncWebServerResponse *beginResponse_P(int code, const char *content_type, const uint8_t *data,
139
- const size_t data_size) {
139
+ AsyncWebServerResponse *beginResponse(int code, const char *content_type, const uint8_t *data,
140
+ const size_t data_size) {
140
141
  auto *res = new AsyncWebServerResponseProgmem(this, data, data_size); // NOLINT(cppcoreguidelines-owning-memory)
141
142
  this->init_response_(res, code, content_type);
142
143
  return res;
@@ -203,6 +204,9 @@ class AsyncWebServer {
203
204
  static esp_err_t request_handler(httpd_req_t *r);
204
205
  static esp_err_t request_post_handler(httpd_req_t *r);
205
206
  esp_err_t request_handler_(AsyncWebServerRequest *request) const;
207
+ #ifdef USE_WEBSERVER_OTA
208
+ esp_err_t handle_multipart_upload_(httpd_req_t *r, const char *content_type);
209
+ #endif
206
210
  std::vector<AsyncWebHandler *> handlers_;
207
211
  std::function<void(AsyncWebServerRequest *request)> on_not_found_{};
208
212
  };
@@ -211,7 +215,7 @@ class AsyncWebHandler {
211
215
  public:
212
216
  virtual ~AsyncWebHandler() {}
213
217
  // NOLINTNEXTLINE(readability-identifier-naming)
214
- virtual bool canHandle(AsyncWebServerRequest *request) { return false; }
218
+ virtual bool canHandle(AsyncWebServerRequest *request) const { return false; }
215
219
  // NOLINTNEXTLINE(readability-identifier-naming)
216
220
  virtual void handleRequest(AsyncWebServerRequest *request) {}
217
221
  // NOLINTNEXTLINE(readability-identifier-naming)
@@ -220,7 +224,7 @@ class AsyncWebHandler {
220
224
  // NOLINTNEXTLINE(readability-identifier-naming)
221
225
  virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {}
222
226
  // NOLINTNEXTLINE(readability-identifier-naming)
223
- virtual bool isRequestHandlerTrivial() { return true; }
227
+ virtual bool isRequestHandlerTrivial() const { return true; }
224
228
  };
225
229
 
226
230
  #ifdef USE_WEBSERVER
@@ -271,7 +275,7 @@ class AsyncEventSourceResponse {
271
275
  static void destroy(void *p);
272
276
  AsyncEventSource *server_;
273
277
  httpd_handle_t hd_{};
274
- int fd_{};
278
+ std::atomic<int> fd_{};
275
279
  std::vector<DeferredEvent> deferred_queue_;
276
280
  esphome::web_server::WebServer *web_server_;
277
281
  std::unique_ptr<esphome::web_server::ListEntitiesIterator> entities_iterator_;
@@ -290,7 +294,7 @@ class AsyncEventSource : public AsyncWebHandler {
290
294
  ~AsyncEventSource() override;
291
295
 
292
296
  // NOLINTNEXTLINE(readability-identifier-naming)
293
- bool canHandle(AsyncWebServerRequest *request) override {
297
+ bool canHandle(AsyncWebServerRequest *request) const override {
294
298
  return request->method() == HTTP_GET && request->url() == this->url_;
295
299
  }
296
300
  // NOLINTNEXTLINE(readability-identifier-naming)
@@ -324,10 +328,7 @@ class DefaultHeaders {
324
328
  void addHeader(const char *name, const char *value) { this->headers_.emplace_back(name, value); }
325
329
 
326
330
  // NOLINTNEXTLINE(readability-identifier-naming)
327
- static DefaultHeaders &Instance() {
328
- static DefaultHeaders instance;
329
- return instance;
330
- }
331
+ static DefaultHeaders &Instance();
331
332
 
332
333
  protected:
333
334
  std::vector<std::pair<std::string, std::string>> headers_;
@@ -11,7 +11,7 @@ static const char *const KEYS = "0123456789*#";
11
11
  void IRAM_ATTR HOT WiegandStore::d0_gpio_intr(WiegandStore *arg) {
12
12
  if (arg->d0.digital_read())
13
13
  return;
14
- arg->count++;
14
+ arg->count++; // NOLINT(clang-diagnostic-deprecated-volatile)
15
15
  arg->value <<= 1;
16
16
  arg->last_bit_time = millis();
17
17
  arg->done = false;
@@ -20,7 +20,7 @@ void IRAM_ATTR HOT WiegandStore::d0_gpio_intr(WiegandStore *arg) {
20
20
  void IRAM_ATTR HOT WiegandStore::d1_gpio_intr(WiegandStore *arg) {
21
21
  if (arg->d1.digital_read())
22
22
  return;
23
- arg->count++;
23
+ arg->count++; // NOLINT(clang-diagnostic-deprecated-volatile)
24
24
  arg->value = (arg->value << 1) | 1;
25
25
  arg->last_bit_time = millis();
26
26
  arg->done = false;
@@ -3,6 +3,7 @@ from esphome.automation import Condition
3
3
  import esphome.codegen as cg
4
4
  from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant
5
5
  from esphome.components.network import IPAddress
6
+ from esphome.config_helpers import filter_source_files_from_platform
6
7
  import esphome.config_validation as cv
7
8
  from esphome.const import (
8
9
  CONF_AP,
@@ -39,6 +40,7 @@ from esphome.const import (
39
40
  CONF_TTLS_PHASE_2,
40
41
  CONF_USE_ADDRESS,
41
42
  CONF_USERNAME,
43
+ PlatformFramework,
42
44
  )
43
45
  from esphome.core import CORE, HexInt, coroutine_with_priority
44
46
  import esphome.final_validate as fv
@@ -309,6 +311,7 @@ CONFIG_SCHEMA = cv.All(
309
311
  rp2040="light",
310
312
  bk72xx="none",
311
313
  rtl87xx="none",
314
+ ln882x="light",
312
315
  ): cv.enum(WIFI_POWER_SAVE_MODES, upper=True),
313
316
  cv.Optional(CONF_FAST_CONNECT, default=False): cv.boolean,
314
317
  cv.Optional(CONF_USE_ADDRESS): cv.string_strict,
@@ -525,3 +528,18 @@ async def wifi_set_sta_to_code(config, action_id, template_arg, args):
525
528
  await automation.build_automation(var.get_error_trigger(), [], on_error_config)
526
529
  await cg.register_component(var, config)
527
530
  return var
531
+
532
+
533
+ FILTER_SOURCE_FILES = filter_source_files_from_platform(
534
+ {
535
+ "wifi_component_esp32_arduino.cpp": {PlatformFramework.ESP32_ARDUINO},
536
+ "wifi_component_esp_idf.cpp": {PlatformFramework.ESP32_IDF},
537
+ "wifi_component_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
538
+ "wifi_component_libretiny.cpp": {
539
+ PlatformFramework.BK72XX_ARDUINO,
540
+ PlatformFramework.RTL87XX_ARDUINO,
541
+ PlatformFramework.LN882X_ARDUINO,
542
+ },
543
+ "wifi_component_pico_w.cpp": {PlatformFramework.RP2040_ARDUINO},
544
+ }
545
+ )
@@ -73,7 +73,7 @@ void WiFiComponent::start() {
73
73
 
74
74
  SavedWifiSettings save{};
75
75
  if (this->pref_.load(&save)) {
76
- ESP_LOGD(TAG, "Loaded saved settings: %s", save.ssid);
76
+ ESP_LOGD(TAG, "Loaded settings: %s", save.ssid);
77
77
 
78
78
  WiFiAP sta{};
79
79
  sta.set_ssid(save.ssid);
@@ -84,11 +84,11 @@ void WiFiComponent::start() {
84
84
  if (this->has_sta()) {
85
85
  this->wifi_sta_pre_setup_();
86
86
  if (this->output_power_.has_value() && !this->wifi_apply_output_power_(*this->output_power_)) {
87
- ESP_LOGV(TAG, "Setting Output Power Option failed!");
87
+ ESP_LOGV(TAG, "Setting Output Power Option failed");
88
88
  }
89
89
 
90
90
  if (!this->wifi_apply_power_save_()) {
91
- ESP_LOGV(TAG, "Setting Power Save Option failed!");
91
+ ESP_LOGV(TAG, "Setting Power Save Option failed");
92
92
  }
93
93
 
94
94
  if (this->fast_connect_) {
@@ -102,7 +102,7 @@ void WiFiComponent::start() {
102
102
  } else if (this->has_ap()) {
103
103
  this->setup_ap_config_();
104
104
  if (this->output_power_.has_value() && !this->wifi_apply_output_power_(*this->output_power_)) {
105
- ESP_LOGV(TAG, "Setting Output Power Option failed!");
105
+ ESP_LOGV(TAG, "Setting Output Power Option failed");
106
106
  }
107
107
  #ifdef USE_CAPTIVE_PORTAL
108
108
  if (captive_portal::global_captive_portal != nullptr) {
@@ -181,7 +181,7 @@ void WiFiComponent::loop() {
181
181
  #ifdef USE_WIFI_AP
182
182
  if (this->has_ap() && !this->ap_setup_) {
183
183
  if (this->ap_timeout_ != 0 && (now - this->last_connected_ > this->ap_timeout_)) {
184
- ESP_LOGI(TAG, "Starting fallback AP!");
184
+ ESP_LOGI(TAG, "Starting fallback AP");
185
185
  this->setup_ap_config_();
186
186
  #ifdef USE_CAPTIVE_PORTAL
187
187
  if (captive_portal::global_captive_portal != nullptr)
@@ -359,7 +359,7 @@ void WiFiComponent::start_connecting(const WiFiAP &ap, bool two) {
359
359
  if (ap.get_channel().has_value()) {
360
360
  ESP_LOGV(TAG, " Channel: %u", *ap.get_channel());
361
361
  } else {
362
- ESP_LOGV(TAG, " Channel: Not Set");
362
+ ESP_LOGV(TAG, " Channel not set");
363
363
  }
364
364
  if (ap.get_manual_ip().has_value()) {
365
365
  ManualIP m = *ap.get_manual_ip();
@@ -372,7 +372,7 @@ void WiFiComponent::start_connecting(const WiFiAP &ap, bool two) {
372
372
  #endif
373
373
 
374
374
  if (!this->wifi_sta_connect_(ap)) {
375
- ESP_LOGE(TAG, "wifi_sta_connect_ failed!");
375
+ ESP_LOGE(TAG, "wifi_sta_connect_ failed");
376
376
  this->retry_connect();
377
377
  return;
378
378
  }
@@ -500,20 +500,20 @@ void WiFiComponent::start_scanning() {
500
500
  void WiFiComponent::check_scanning_finished() {
501
501
  if (!this->scan_done_) {
502
502
  if (millis() - this->action_started_ > 30000) {
503
- ESP_LOGE(TAG, "Scan timeout!");
503
+ ESP_LOGE(TAG, "Scan timeout");
504
504
  this->retry_connect();
505
505
  }
506
506
  return;
507
507
  }
508
508
  this->scan_done_ = false;
509
509
 
510
- ESP_LOGD(TAG, "Found networks:");
511
510
  if (this->scan_result_.empty()) {
512
- ESP_LOGD(TAG, " No network found!");
511
+ ESP_LOGW(TAG, "No networks found");
513
512
  this->retry_connect();
514
513
  return;
515
514
  }
516
515
 
516
+ ESP_LOGD(TAG, "Found networks:");
517
517
  for (auto &res : this->scan_result_) {
518
518
  for (auto &ap : this->sta_) {
519
519
  if (res.matches(ap)) {
@@ -561,7 +561,7 @@ void WiFiComponent::check_scanning_finished() {
561
561
  }
562
562
 
563
563
  if (!this->scan_result_[0].get_matches()) {
564
- ESP_LOGW(TAG, "No matching network found!");
564
+ ESP_LOGW(TAG, "No matching network found");
565
565
  this->retry_connect();
566
566
  return;
567
567
  }
@@ -619,7 +619,7 @@ void WiFiComponent::check_connecting_finished() {
619
619
 
620
620
  if (status == WiFiSTAConnectStatus::CONNECTED) {
621
621
  if (wifi_ssid().empty()) {
622
- ESP_LOGW(TAG, "Incomplete connection.");
622
+ ESP_LOGW(TAG, "Connection incomplete");
623
623
  this->retry_connect();
624
624
  return;
625
625
  }
@@ -663,7 +663,7 @@ void WiFiComponent::check_connecting_finished() {
663
663
  }
664
664
 
665
665
  if (this->error_from_callback_) {
666
- ESP_LOGW(TAG, "Error while connecting to network.");
666
+ ESP_LOGW(TAG, "Connecting to network failed");
667
667
  this->retry_connect();
668
668
  return;
669
669
  }
@@ -679,7 +679,7 @@ void WiFiComponent::check_connecting_finished() {
679
679
  }
680
680
 
681
681
  if (status == WiFiSTAConnectStatus::ERROR_CONNECT_FAILED) {
682
- ESP_LOGW(TAG, "Connection failed. Check credentials");
682
+ ESP_LOGW(TAG, "Connecting to network failed");
683
683
  this->retry_connect();
684
684
  return;
685
685
  }
@@ -700,7 +700,7 @@ void WiFiComponent::retry_connect() {
700
700
  (this->num_retried_ > 3 || this->error_from_callback_)) {
701
701
  if (this->num_retried_ > 5) {
702
702
  // If retry failed for more than 5 times, let's restart STA
703
- ESP_LOGW(TAG, "Restarting WiFi adapter");
703
+ ESP_LOGW(TAG, "Restarting adapter");
704
704
  this->wifi_mode_(false, {});
705
705
  delay(100); // NOLINT
706
706
  this->num_retried_ = 0;
@@ -741,11 +741,6 @@ void WiFiComponent::set_power_save_mode(WiFiPowerSaveMode power_save) { this->po
741
741
 
742
742
  void WiFiComponent::set_passive_scan(bool passive) { this->passive_scan_ = passive; }
743
743
 
744
- std::string WiFiComponent::format_mac_addr(const uint8_t *mac) {
745
- char buf[20];
746
- sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
747
- return buf;
748
- }
749
744
  bool WiFiComponent::is_captive_portal_active_() {
750
745
  #ifdef USE_CAPTIVE_PORTAL
751
746
  return captive_portal::global_captive_portal != nullptr && captive_portal::global_captive_portal->is_active();
@@ -770,7 +765,7 @@ void WiFiComponent::load_fast_connect_settings_() {
770
765
  this->selected_ap_.set_bssid(bssid);
771
766
  this->selected_ap_.set_channel(fast_connect_save.channel);
772
767
 
773
- ESP_LOGD(TAG, "Loaded saved fast_connect wifi settings");
768
+ ESP_LOGD(TAG, "Loaded fast_connect settings");
774
769
  }
775
770
  }
776
771
 
@@ -786,7 +781,7 @@ void WiFiComponent::save_fast_connect_settings_() {
786
781
 
787
782
  this->fast_connect_pref_.save(&fast_connect_save);
788
783
 
789
- ESP_LOGD(TAG, "Saved fast_connect wifi settings");
784
+ ESP_LOGD(TAG, "Saved fast_connect settings");
790
785
  }
791
786
  }
792
787