esphome 2025.6.3__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 (599) 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 +8 -2
  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.h +1 -0
  185. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  186. esphome/components/http_request/update/http_request_update.cpp +28 -9
  187. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +3 -9
  188. esphome/components/hydreon_rgxx/sensor.py +1 -1
  189. esphome/components/i2c/__init__.py +23 -11
  190. esphome/components/i2c/i2c_bus.h +8 -1
  191. esphome/components/i2c/i2c_bus_arduino.cpp +4 -3
  192. esphome/components/i2c/i2c_bus_arduino.h +6 -3
  193. esphome/components/i2c/i2c_bus_esp_idf.h +5 -3
  194. esphome/components/i2c_device/i2c_device.h +0 -1
  195. esphome/components/i2s_audio/__init__.py +2 -10
  196. esphome/components/i2s_audio/i2s_audio.cpp +1 -5
  197. esphome/components/i2s_audio/media_player/__init__.py +2 -2
  198. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +2 -2
  199. esphome/components/iaqcore/iaqcore.h +0 -2
  200. esphome/components/image/__init__.py +123 -24
  201. esphome/components/improv_serial/improv_serial_component.cpp +0 -4
  202. esphome/components/ina219/ina219.cpp +7 -0
  203. esphome/components/ina219/ina219.h +1 -0
  204. esphome/components/ina260/ina260.h +0 -2
  205. esphome/components/inkbird_ibsth1_mini/inkbird_ibsth1_mini.h +0 -1
  206. esphome/components/inkplate6/display.py +15 -0
  207. esphome/components/inkplate6/inkplate.cpp +2 -2
  208. esphome/components/integration/integration_sensor.h +0 -1
  209. esphome/components/internal_temperature/internal_temperature.cpp +8 -27
  210. esphome/components/internal_temperature/sensor.py +0 -26
  211. esphome/components/interval/interval.h +0 -2
  212. esphome/components/ld2410/button/__init__.py +3 -3
  213. esphome/components/ld2410/button/factory_reset_button.cpp +9 -0
  214. esphome/components/ld2410/button/{reset_button.h → factory_reset_button.h} +2 -2
  215. esphome/components/ld2410/ld2410.cpp +430 -261
  216. esphome/components/ld2410/ld2410.h +44 -146
  217. esphome/components/ld2410/number/__init__.py +2 -2
  218. esphome/components/ld2410/sensor.py +1 -1
  219. esphome/components/ld2410/switch/__init__.py +1 -1
  220. esphome/components/ld2420/ld2420.cpp +196 -100
  221. esphome/components/ld2420/ld2420.h +46 -118
  222. esphome/components/ld2420/number/__init__.py +2 -2
  223. esphome/components/ld2420/sensor/__init__.py +6 -2
  224. esphome/components/ld2420/sensor/ld2420_sensor.h +1 -1
  225. esphome/components/ld2450/button/__init__.py +3 -3
  226. esphome/components/ld2450/button/factory_reset_button.cpp +9 -0
  227. esphome/components/ld2450/button/{reset_button.h → factory_reset_button.h} +2 -2
  228. esphome/components/ld2450/ld2450.cpp +384 -232
  229. esphome/components/ld2450/ld2450.h +60 -69
  230. esphome/components/ld2450/switch/__init__.py +1 -1
  231. esphome/components/ledc/ledc_output.cpp +1 -63
  232. esphome/components/libretiny/__init__.py +4 -3
  233. esphome/components/libretiny/const.py +5 -0
  234. esphome/components/libretiny/generate_components.py +1 -0
  235. esphome/components/libretiny/helpers.cpp +35 -0
  236. esphome/components/libretiny/lt_component.cpp +5 -3
  237. esphome/components/light/__init__.py +4 -2
  238. esphome/components/light/addressable_light.h +3 -3
  239. esphome/components/light/light_call.cpp +180 -243
  240. esphome/components/light/light_call.h +72 -20
  241. esphome/components/light/light_color_values.h +14 -14
  242. esphome/components/light/light_state.h +15 -13
  243. esphome/components/light/transformers.h +2 -2
  244. esphome/components/ln882x/__init__.py +52 -0
  245. esphome/components/ln882x/boards.py +285 -0
  246. esphome/components/lock/__init__.py +5 -2
  247. esphome/components/logger/__init__.py +40 -3
  248. esphome/components/logger/logger.cpp +47 -12
  249. esphome/components/logger/logger.h +80 -49
  250. esphome/components/logger/logger_esp32.cpp +3 -3
  251. esphome/components/lps22/__init__.py +0 -0
  252. esphome/components/lps22/lps22.cpp +75 -0
  253. esphome/components/lps22/lps22.h +27 -0
  254. esphome/components/lps22/sensor.py +58 -0
  255. esphome/components/ltr390/ltr390.h +0 -1
  256. esphome/components/ltr501/ltr501.h +0 -1
  257. esphome/components/ltr_als_ps/ltr_als_ps.h +0 -1
  258. esphome/components/lvgl/__init__.py +1 -1
  259. esphome/components/lvgl/schemas.py +66 -6
  260. esphome/components/lvgl/styles.py +24 -16
  261. esphome/components/lvgl/widgets/__init__.py +12 -2
  262. esphome/components/lvgl/widgets/lv_bar.py +40 -19
  263. esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +1 -1
  264. esphome/components/max9611/max9611.h +0 -1
  265. esphome/components/mcp23016/__init__.py +1 -1
  266. esphome/components/mcp23xxx_base/__init__.py +1 -1
  267. esphome/components/mcp4461/__init__.py +1 -1
  268. esphome/components/mcp4461/output/__init__.py +3 -2
  269. esphome/components/mcp9600/mcp9600.h +0 -2
  270. esphome/components/md5/md5.cpp +3 -3
  271. esphome/components/md5/md5.h +1 -6
  272. esphome/components/mdns/__init__.py +22 -11
  273. esphome/components/media_player/__init__.py +4 -3
  274. esphome/components/micro_wake_word/__init__.py +1 -5
  275. esphome/components/micro_wake_word/streaming_model.cpp +2 -2
  276. esphome/components/microphone/microphone.cpp +7 -9
  277. esphome/components/microphone/microphone.h +0 -2
  278. esphome/components/mipi_spi/display.py +1 -0
  279. esphome/components/mmc5603/mmc5603.cpp +1 -1
  280. esphome/components/modbus/modbus.cpp +33 -15
  281. esphome/components/modbus/modbus.h +9 -0
  282. esphome/components/modbus_controller/__init__.py +42 -10
  283. esphome/components/modbus_controller/modbus_controller.cpp +92 -11
  284. esphome/components/modbus_controller/modbus_controller.h +61 -7
  285. esphome/components/mopeka_pro_check/mopeka_pro_check.h +0 -1
  286. esphome/components/mopeka_std_check/mopeka_std_check.h +0 -1
  287. esphome/components/mpl3115a2/mpl3115a2.h +0 -2
  288. esphome/components/mqtt/__init__.py +16 -0
  289. esphome/components/mqtt/mqtt_backend.h +2 -1
  290. esphome/components/mqtt/mqtt_backend_esp32.cpp +126 -45
  291. esphome/components/mqtt/mqtt_backend_esp32.h +106 -4
  292. esphome/components/mqtt/mqtt_client.cpp +15 -9
  293. esphome/components/mqtt/mqtt_client.h +8 -3
  294. esphome/components/ms8607/ms8607.h +0 -1
  295. esphome/components/neopixelbus/light.py +4 -1
  296. esphome/components/neopixelbus/neopixelbus_light.h +1 -1
  297. esphome/components/network/__init__.py +4 -1
  298. esphome/components/network/ip_address.h +1 -0
  299. esphome/components/nextion/__init__.py +16 -0
  300. esphome/components/nextion/base_component.py +1 -0
  301. esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
  302. esphome/components/nextion/display.py +14 -4
  303. esphome/components/nextion/nextion.cpp +166 -101
  304. esphome/components/nextion/nextion.h +84 -53
  305. esphome/components/nextion/nextion_commands.cpp +11 -10
  306. esphome/components/nextion/nextion_component.cpp +28 -28
  307. esphome/components/nextion/nextion_component.h +53 -18
  308. esphome/components/nextion/nextion_component_base.h +3 -0
  309. esphome/components/nextion/nextion_upload.cpp +36 -0
  310. esphome/components/nextion/nextion_upload_arduino.cpp +10 -35
  311. esphome/components/nextion/nextion_upload_idf.cpp +9 -33
  312. esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
  313. esphome/components/nextion/switch/nextion_switch.cpp +1 -1
  314. esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
  315. esphome/components/nfc/nfc.cpp +3 -22
  316. esphome/components/nfc/nfc.h +3 -3
  317. esphome/components/number/__init__.py +5 -2
  318. esphome/components/online_image/__init__.py +5 -0
  319. esphome/components/online_image/online_image.cpp +6 -2
  320. esphome/components/online_image/online_image.h +4 -1
  321. esphome/components/opentherm/opentherm.cpp +7 -12
  322. esphome/components/openthread/__init__.py +47 -40
  323. esphome/components/openthread/const.py +1 -0
  324. esphome/components/openthread/openthread_esp.cpp +27 -5
  325. esphome/components/opt3001/__init__.py +0 -0
  326. esphome/components/opt3001/opt3001.cpp +122 -0
  327. esphome/components/opt3001/opt3001.h +27 -0
  328. esphome/components/opt3001/sensor.py +35 -0
  329. esphome/components/ota/__init__.py +17 -0
  330. esphome/components/ota/ota_backend.h +27 -1
  331. esphome/components/ota/ota_backend_arduino_esp32.cpp +12 -2
  332. esphome/components/ota/ota_backend_arduino_esp32.h +3 -0
  333. esphome/components/ota/ota_backend_arduino_esp8266.cpp +18 -4
  334. esphome/components/ota/ota_backend_arduino_esp8266.h +3 -0
  335. esphome/components/ota/ota_backend_arduino_libretiny.cpp +12 -2
  336. esphome/components/ota/ota_backend_arduino_libretiny.h +3 -0
  337. esphome/components/ota/ota_backend_arduino_rp2040.cpp +9 -2
  338. esphome/components/ota/ota_backend_arduino_rp2040.h +3 -0
  339. esphome/components/ota/ota_backend_esp_idf.cpp +10 -16
  340. esphome/components/ota/ota_backend_esp_idf.h +1 -0
  341. esphome/components/packages/__init__.py +5 -2
  342. esphome/components/packet_transport/binary_sensor.py +61 -4
  343. esphome/components/packet_transport/packet_transport.cpp +31 -1
  344. esphome/components/packet_transport/packet_transport.h +11 -5
  345. esphome/components/pcf8574/__init__.py +1 -1
  346. esphome/components/pi4ioe5v6408/__init__.py +84 -0
  347. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +171 -0
  348. esphome/components/pi4ioe5v6408/pi4ioe5v6408.h +70 -0
  349. esphome/components/pmsa003i/pmsa003i.h +0 -1
  350. esphome/components/pmsx003/pmsx003.h +0 -1
  351. esphome/components/pn7150/pn7150.cpp +7 -7
  352. esphome/components/pn7150/pn7150.h +0 -1
  353. esphome/components/pn7160/pn7160.cpp +7 -7
  354. esphome/components/pn7160/pn7160.h +0 -1
  355. esphome/components/preferences/syncer.h +2 -0
  356. esphome/components/prometheus/prometheus_handler.h +1 -1
  357. esphome/components/psram/psram.cpp +0 -20
  358. esphome/components/pulse_counter/pulse_counter_sensor.h +0 -1
  359. esphome/components/pulse_meter/pulse_meter_sensor.cpp +8 -4
  360. esphome/components/pulse_width/pulse_width.h +0 -1
  361. esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +0 -4
  362. esphome/components/pvvx_mithermometer/display/pvvx_display.h +0 -2
  363. esphome/components/pvvx_mithermometer/pvvx_mithermometer.h +0 -1
  364. esphome/components/qr_code/__init__.py +13 -10
  365. esphome/components/qwiic_pir/qwiic_pir.h +0 -1
  366. esphome/components/radon_eye_ble/radon_eye_listener.cpp +1 -1
  367. esphome/components/rc522/rc522.h +0 -1
  368. esphome/components/rdm6300/rdm6300.h +0 -2
  369. esphome/components/remote_base/__init__.py +7 -5
  370. esphome/components/remote_base/remote_base.cpp +24 -21
  371. esphome/components/remote_base/remote_base.h +3 -26
  372. esphome/components/remote_receiver/__init__.py +40 -46
  373. esphome/components/remote_receiver/remote_receiver.h +4 -18
  374. esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -87
  375. esphome/components/remote_receiver/remote_receiver_esp8266.cpp +1 -1
  376. esphome/components/remote_transmitter/__init__.py +42 -43
  377. esphome/components/remote_transmitter/remote_transmitter.h +2 -14
  378. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -77
  379. esphome/components/resistance/resistance_sensor.h +0 -1
  380. esphome/components/rp2040/__init__.py +1 -0
  381. esphome/components/rp2040/helpers.cpp +55 -0
  382. esphome/components/rp2040_pio_led_strip/led_strip.cpp +2 -2
  383. esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -4
  384. esphome/components/rtttl/__init__.py +4 -4
  385. esphome/components/rtttl/rtttl.cpp +10 -1
  386. esphome/components/ruuvitag/ruuvitag.h +0 -1
  387. esphome/components/safe_mode/safe_mode.cpp +2 -0
  388. esphome/components/safe_mode/safe_mode.h +4 -1
  389. esphome/components/scd30/scd30.h +0 -1
  390. esphome/components/scd30/sensor.py +2 -2
  391. esphome/components/scd4x/scd4x.cpp +61 -54
  392. esphome/components/scd4x/scd4x.h +17 -15
  393. esphome/components/scd4x/sensor.py +4 -4
  394. esphome/components/script/script.h +0 -2
  395. esphome/components/sdp3x/sensor.py +1 -1
  396. esphome/components/select/__init__.py +5 -2
  397. esphome/components/sen5x/sen5x.h +0 -1
  398. esphome/components/senseair/senseair.h +0 -1
  399. esphome/components/sensor/__init__.py +4 -2
  400. esphome/components/sensor/filter.cpp +1 -1
  401. esphome/components/sensor/sensor.cpp +12 -6
  402. esphome/components/sensor/sensor.h +13 -5
  403. esphome/components/servo/servo.h +0 -1
  404. esphome/components/sfa30/sfa30.h +0 -1
  405. esphome/components/sgp30/sgp30.h +0 -1
  406. esphome/components/sgp4x/sgp4x.h +0 -1
  407. esphome/components/shelly_dimmer/stm32flash.cpp +1 -2
  408. esphome/components/sht4x/sht4x.h +0 -1
  409. esphome/components/sm300d2/sm300d2.h +0 -2
  410. esphome/components/smt100/sensor.py +8 -4
  411. esphome/components/smt100/smt100.cpp +5 -5
  412. esphome/components/smt100/smt100.h +3 -3
  413. esphome/components/sn74hc595/__init__.py +1 -1
  414. esphome/components/sn74hc595/sn74hc595.cpp +5 -4
  415. esphome/components/sntp/sntp_component.cpp +9 -3
  416. esphome/components/sntp/time.py +2 -0
  417. esphome/components/socket/__init__.py +17 -0
  418. esphome/components/spi/__init__.py +27 -6
  419. esphome/components/spi/spi.cpp +3 -2
  420. esphome/components/spi/spi.h +9 -3
  421. esphome/components/spi/spi_arduino.cpp +3 -5
  422. esphome/components/spi/spi_esp_idf.cpp +40 -21
  423. esphome/components/spi_led_strip/spi_led_strip.cpp +1 -1
  424. esphome/components/sps30/sps30.h +0 -1
  425. esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
  426. esphome/components/st7701s/st7701s.cpp +0 -4
  427. esphome/components/status/status_binary_sensor.h +0 -2
  428. esphome/components/substitutions/__init__.py +76 -19
  429. esphome/components/substitutions/jinja.py +99 -0
  430. esphome/components/sun/sun.cpp +3 -4
  431. esphome/components/switch/__init__.py +5 -2
  432. esphome/components/switch/binary_sensor/switch_binary_sensor.h +0 -1
  433. esphome/components/sx126x/__init__.py +317 -0
  434. esphome/components/sx126x/automation.h +62 -0
  435. esphome/components/sx126x/packet_transport/__init__.py +26 -0
  436. esphome/components/sx126x/packet_transport/sx126x_transport.cpp +26 -0
  437. esphome/components/sx126x/packet_transport/sx126x_transport.h +25 -0
  438. esphome/components/sx126x/sx126x.cpp +523 -0
  439. esphome/components/sx126x/sx126x.h +140 -0
  440. esphome/components/sx126x/sx126x_reg.h +163 -0
  441. esphome/components/sx127x/__init__.py +325 -0
  442. esphome/components/sx127x/automation.h +62 -0
  443. esphome/components/sx127x/packet_transport/__init__.py +26 -0
  444. esphome/components/sx127x/packet_transport/sx127x_transport.cpp +26 -0
  445. esphome/components/sx127x/packet_transport/sx127x_transport.h +25 -0
  446. esphome/components/sx127x/sx127x.cpp +498 -0
  447. esphome/components/sx127x/sx127x.h +128 -0
  448. esphome/components/sx127x/sx127x_reg.h +295 -0
  449. esphome/components/syslog/esphome_syslog.cpp +5 -3
  450. esphome/components/syslog/esphome_syslog.h +1 -1
  451. esphome/components/tca9555/__init__.py +1 -1
  452. esphome/components/template/binary_sensor/template_binary_sensor.cpp +1 -9
  453. esphome/components/text/__init__.py +5 -2
  454. esphome/components/text_sensor/__init__.py +5 -2
  455. esphome/components/thermostat/thermostat_climate.cpp +34 -31
  456. esphome/components/thermostat/thermostat_climate.h +43 -39
  457. esphome/components/time/__init__.py +16 -2
  458. esphome/components/time/real_time_clock.cpp +4 -0
  459. esphome/components/time/real_time_clock.h +5 -1
  460. esphome/components/tlc5971/tlc5971.cpp +4 -1
  461. esphome/components/tmp1075/tmp1075.h +0 -2
  462. esphome/components/tof10120/tof10120_sensor.h +0 -1
  463. esphome/components/tormatic/tormatic_cover.h +0 -1
  464. esphome/components/total_daily_energy/total_daily_energy.h +0 -1
  465. esphome/components/tsl2591/tsl2591.cpp +1 -1
  466. esphome/components/ttp229_bsf/ttp229_bsf.h +0 -1
  467. esphome/components/ttp229_lsf/ttp229_lsf.h +0 -1
  468. esphome/components/tx20/tx20.cpp +2 -2
  469. esphome/components/uart/__init__.py +18 -0
  470. esphome/components/uart/uart_component_esp_idf.cpp +0 -4
  471. esphome/components/update/__init__.py +5 -2
  472. esphome/components/update/update_entity.h +8 -0
  473. esphome/components/usb_host/__init__.py +5 -2
  474. esphome/components/valve/__init__.py +5 -2
  475. esphome/components/vbus/vbus.h +0 -1
  476. esphome/components/veml3235/veml3235.h +0 -1
  477. esphome/components/veml7700/veml7700.h +0 -1
  478. esphome/components/vl53l0x/vl53l0x_sensor.h +0 -1
  479. esphome/components/voice_assistant/voice_assistant.cpp +4 -4
  480. esphome/components/watchdog/watchdog.cpp +0 -4
  481. esphome/components/waveshare_epaper/waveshare_epaper.cpp +6 -6
  482. esphome/components/web_server/__init__.py +34 -19
  483. esphome/components/web_server/ota/__init__.py +32 -0
  484. esphome/components/web_server/ota/ota_web_server.cpp +210 -0
  485. esphome/components/web_server/ota/ota_web_server.h +26 -0
  486. esphome/components/web_server/web_server.cpp +305 -427
  487. esphome/components/web_server/web_server.h +33 -23
  488. esphome/components/web_server/web_server_v1.cpp +4 -5
  489. esphome/components/web_server_base/__init__.py +5 -2
  490. esphome/components/web_server_base/web_server_base.cpp +2 -94
  491. esphome/components/web_server_base/web_server_base.h +5 -25
  492. esphome/components/web_server_idf/multipart.cpp +254 -0
  493. esphome/components/web_server_idf/multipart.h +86 -0
  494. esphome/components/web_server_idf/utils.cpp +32 -0
  495. esphome/components/web_server_idf/utils.h +10 -0
  496. esphome/components/web_server_idf/web_server_idf.cpp +162 -16
  497. esphome/components/web_server_idf/web_server_idf.h +11 -10
  498. esphome/components/wiegand/wiegand.cpp +2 -2
  499. esphome/components/wifi/__init__.py +18 -0
  500. esphome/components/wifi/wifi_component.cpp +17 -22
  501. esphome/components/wifi/wifi_component.h +27 -23
  502. esphome/components/wifi/wifi_component_esp32_arduino.cpp +52 -59
  503. esphome/components/wifi/wifi_component_esp8266.cpp +46 -46
  504. esphome/components/wifi/wifi_component_esp_idf.cpp +35 -36
  505. esphome/components/wifi/wifi_component_libretiny.cpp +26 -27
  506. esphome/components/wifi/wifi_component_pico_w.cpp +3 -3
  507. esphome/components/wifi_info/wifi_info_text_sensor.cpp +6 -6
  508. esphome/components/wireguard/__init__.py +2 -11
  509. esphome/components/xiaomi_ble/xiaomi_ble.cpp +13 -1
  510. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  511. esphome/components/xiaomi_cgd1/xiaomi_cgd1.h +0 -1
  512. esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h +0 -1
  513. esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +0 -1
  514. esphome/components/xiaomi_cgpr1/xiaomi_cgpr1.h +0 -1
  515. esphome/components/xiaomi_gcls002/xiaomi_gcls002.h +0 -1
  516. esphome/components/xiaomi_hhccjcy01/xiaomi_hhccjcy01.h +0 -1
  517. esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h +0 -1
  518. esphome/components/xiaomi_hhccpot002/xiaomi_hhccpot002.h +0 -1
  519. esphome/components/xiaomi_jqjcy01ym/xiaomi_jqjcy01ym.h +0 -1
  520. esphome/components/xiaomi_lywsd02/xiaomi_lywsd02.h +0 -1
  521. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +0 -1
  522. esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.h +0 -1
  523. esphome/components/xiaomi_lywsdcgq/xiaomi_lywsdcgq.h +0 -1
  524. esphome/components/xiaomi_mhoc303/xiaomi_mhoc303.h +0 -1
  525. esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.h +0 -1
  526. esphome/components/xiaomi_miscale/xiaomi_miscale.h +0 -1
  527. esphome/components/xiaomi_mjyd02yla/xiaomi_mjyd02yla.h +0 -1
  528. esphome/components/xiaomi_mue4094rt/xiaomi_mue4094rt.h +0 -1
  529. esphome/components/xiaomi_rtcgq02lm/xiaomi_rtcgq02lm.h +0 -1
  530. esphome/components/xiaomi_wx08zm/xiaomi_wx08zm.h +0 -1
  531. esphome/components/xiaomi_xmwsdj04mmc/__init__.py +0 -0
  532. esphome/components/xiaomi_xmwsdj04mmc/sensor.py +77 -0
  533. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.cpp +77 -0
  534. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.h +36 -0
  535. esphome/components/zio_ultrasonic/zio_ultrasonic.h +0 -2
  536. esphome/components/zyaura/zyaura.h +0 -1
  537. esphome/config.py +88 -22
  538. esphome/config_helpers.py +74 -1
  539. esphome/config_validation.py +12 -1
  540. esphome/const.py +65 -10
  541. esphome/core/__init__.py +18 -2
  542. esphome/core/application.cpp +163 -10
  543. esphome/core/application.h +145 -165
  544. esphome/core/area.h +19 -0
  545. esphome/core/automation.h +58 -9
  546. esphome/core/color.cpp +3 -5
  547. esphome/core/color.h +16 -16
  548. esphome/core/component.cpp +151 -18
  549. esphome/core/component.h +98 -4
  550. esphome/core/component_iterator.cpp +7 -7
  551. esphome/core/component_iterator.h +9 -7
  552. esphome/core/config.py +155 -6
  553. esphome/core/controller.cpp +4 -2
  554. esphome/core/controller.h +1 -1
  555. esphome/core/datatypes.h +2 -2
  556. esphome/core/defines.h +17 -2
  557. esphome/core/device.h +20 -0
  558. esphome/core/entity_base.cpp +20 -15
  559. esphome/core/entity_base.h +76 -0
  560. esphome/core/entity_helpers.py +162 -1
  561. esphome/core/event_pool.h +81 -0
  562. esphome/core/helpers.cpp +75 -230
  563. esphome/core/helpers.h +164 -104
  564. esphome/core/lock_free_queue.h +151 -0
  565. esphome/core/log.cpp +2 -2
  566. esphome/core/log.h +2 -0
  567. esphome/core/optional.h +5 -0
  568. esphome/core/ring_buffer.cpp +2 -2
  569. esphome/core/scheduler.cpp +278 -103
  570. esphome/core/scheduler.h +157 -17
  571. esphome/core/time.cpp +5 -5
  572. esphome/core/time.h +5 -5
  573. esphome/cpp_generator.py +17 -0
  574. esphome/cpp_helpers.py +0 -22
  575. esphome/cpp_types.py +3 -1
  576. esphome/dashboard/entries.py +1 -1
  577. esphome/dashboard/util/text.py +5 -21
  578. esphome/dashboard/web_server.py +9 -1
  579. esphome/helpers.py +47 -0
  580. esphome/loader.py +15 -1
  581. esphome/pins.py +14 -8
  582. esphome/wizard.py +16 -3
  583. esphome/writer.py +21 -3
  584. esphome/yaml_util.py +0 -2
  585. {esphome-2025.6.3.dist-info → esphome-2025.7.0b1.dist-info}/METADATA +10 -9
  586. {esphome-2025.6.3.dist-info → esphome-2025.7.0b1.dist-info}/RECORD +591 -531
  587. esphome/components/esp32_ble/ble_event_pool.h +0 -72
  588. esphome/components/esp32_ble/queue.h +0 -85
  589. esphome/components/esp32_hall/esp32_hall.cpp +0 -25
  590. esphome/components/esp32_hall/esp32_hall.h +0 -23
  591. esphome/components/esp32_touch/esp32_touch.cpp +0 -355
  592. esphome/components/ld2410/button/reset_button.cpp +0 -9
  593. esphome/components/ld2450/button/reset_button.cpp +0 -9
  594. esphome/components/openthread/tlv.py +0 -65
  595. /esphome/{dashboard/enum.py → enum.py} +0 -0
  596. {esphome-2025.6.3.dist-info → esphome-2025.7.0b1.dist-info}/WHEEL +0 -0
  597. {esphome-2025.6.3.dist-info → esphome-2025.7.0b1.dist-info}/entry_points.txt +0 -0
  598. {esphome-2025.6.3.dist-info → esphome-2025.7.0b1.dist-info}/licenses/LICENSE +0 -0
  599. {esphome-2025.6.3.dist-info → esphome-2025.7.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,35 @@
1
+ import esphome.codegen as cg
2
+ import esphome.config_validation as cv
3
+ from esphome.components import i2c, sensor
4
+ from esphome.const import (
5
+ DEVICE_CLASS_ILLUMINANCE,
6
+ STATE_CLASS_MEASUREMENT,
7
+ UNIT_LUX,
8
+ )
9
+
10
+ DEPENDENCIES = ["i2c"]
11
+ CODEOWNERS = ["@ccutrer"]
12
+
13
+ opt3001_ns = cg.esphome_ns.namespace("opt3001")
14
+
15
+ OPT3001Sensor = opt3001_ns.class_(
16
+ "OPT3001Sensor", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice
17
+ )
18
+
19
+ CONFIG_SCHEMA = (
20
+ sensor.sensor_schema(
21
+ OPT3001Sensor,
22
+ unit_of_measurement=UNIT_LUX,
23
+ accuracy_decimals=1,
24
+ device_class=DEVICE_CLASS_ILLUMINANCE,
25
+ state_class=STATE_CLASS_MEASUREMENT,
26
+ )
27
+ .extend(cv.polling_component_schema("60s"))
28
+ .extend(i2c.i2c_device_schema(0x44))
29
+ )
30
+
31
+
32
+ async def to_code(config):
33
+ var = await sensor.new_sensor(config)
34
+ await cg.register_component(var, config)
35
+ await i2c.register_i2c_device(var, config)
@@ -1,5 +1,6 @@
1
1
  from esphome import automation
2
2
  import esphome.codegen as cg
3
+ from esphome.config_helpers import filter_source_files_from_platform
3
4
  import esphome.config_validation as cv
4
5
  from esphome.const import (
5
6
  CONF_ESPHOME,
@@ -7,6 +8,7 @@ from esphome.const import (
7
8
  CONF_OTA,
8
9
  CONF_PLATFORM,
9
10
  CONF_TRIGGER_ID,
11
+ PlatformFramework,
10
12
  )
11
13
  from esphome.core import CORE, coroutine_with_priority
12
14
 
@@ -120,3 +122,18 @@ async def ota_to_code(var, config):
120
122
  use_state_callback = True
121
123
  if use_state_callback:
122
124
  cg.add_define("USE_OTA_STATE_CALLBACK")
125
+
126
+
127
+ FILTER_SOURCE_FILES = filter_source_files_from_platform(
128
+ {
129
+ "ota_backend_arduino_esp32.cpp": {PlatformFramework.ESP32_ARDUINO},
130
+ "ota_backend_esp_idf.cpp": {PlatformFramework.ESP32_IDF},
131
+ "ota_backend_arduino_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
132
+ "ota_backend_arduino_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
133
+ "ota_backend_arduino_libretiny.cpp": {
134
+ PlatformFramework.BK72XX_ARDUINO,
135
+ PlatformFramework.RTL87XX_ARDUINO,
136
+ PlatformFramework.LN882X_ARDUINO,
137
+ },
138
+ }
139
+ )
@@ -67,7 +67,28 @@ class OTAComponent : public Component {
67
67
  }
68
68
 
69
69
  protected:
70
- CallbackManager<void(ota::OTAState, float, uint8_t)> state_callback_{};
70
+ /** Extended callback manager with deferred call support.
71
+ *
72
+ * This adds a call_deferred() method for thread-safe execution from other tasks.
73
+ */
74
+ class StateCallbackManager : public CallbackManager<void(OTAState, float, uint8_t)> {
75
+ public:
76
+ StateCallbackManager(OTAComponent *component) : component_(component) {}
77
+
78
+ /** Call callbacks with deferral to main loop (for thread safety).
79
+ *
80
+ * This should be used by OTA implementations that run in separate tasks
81
+ * (like web_server OTA) to ensure callbacks execute in the main loop.
82
+ */
83
+ void call_deferred(ota::OTAState state, float progress, uint8_t error) {
84
+ component_->defer([this, state, progress, error]() { this->call(state, progress, error); });
85
+ }
86
+
87
+ private:
88
+ OTAComponent *component_;
89
+ };
90
+
91
+ StateCallbackManager state_callback_{this};
71
92
  #endif
72
93
  };
73
94
 
@@ -89,6 +110,11 @@ class OTAGlobalCallback {
89
110
 
90
111
  OTAGlobalCallback *get_global_ota_callback();
91
112
  void register_ota_platform(OTAComponent *ota_caller);
113
+
114
+ // OTA implementations should use:
115
+ // - state_callback_.call() when already in main loop (e.g., esphome OTA)
116
+ // - state_callback_.call_deferred() when in separate task (e.g., web_server OTA)
117
+ // This ensures proper callback execution in all contexts.
92
118
  #endif
93
119
  std::unique_ptr<ota::OTABackend> make_ota_backend();
94
120
 
@@ -15,6 +15,11 @@ static const char *const TAG = "ota.arduino_esp32";
15
15
  std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoESP32OTABackend>(); }
16
16
 
17
17
  OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) {
18
+ // Handle UPDATE_SIZE_UNKNOWN (0) which is used by web server OTA
19
+ // where the exact firmware size is unknown due to multipart encoding
20
+ if (image_size == 0) {
21
+ image_size = UPDATE_SIZE_UNKNOWN;
22
+ }
18
23
  bool ret = Update.begin(image_size, U_FLASH);
19
24
  if (ret) {
20
25
  return OTA_RESPONSE_OK;
@@ -29,7 +34,10 @@ OTAResponseTypes ArduinoESP32OTABackend::begin(size_t image_size) {
29
34
  return OTA_RESPONSE_ERROR_UNKNOWN;
30
35
  }
31
36
 
32
- void ArduinoESP32OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); }
37
+ void ArduinoESP32OTABackend::set_update_md5(const char *md5) {
38
+ Update.setMD5(md5);
39
+ this->md5_set_ = true;
40
+ }
33
41
 
34
42
  OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) {
35
43
  size_t written = Update.write(data, len);
@@ -44,7 +52,9 @@ OTAResponseTypes ArduinoESP32OTABackend::write(uint8_t *data, size_t len) {
44
52
  }
45
53
 
46
54
  OTAResponseTypes ArduinoESP32OTABackend::end() {
47
- if (Update.end()) {
55
+ // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
56
+ // This matches the behavior of the old web_server OTA implementation
57
+ if (Update.end(!this->md5_set_)) {
48
58
  return OTA_RESPONSE_OK;
49
59
  }
50
60
 
@@ -16,6 +16,9 @@ class ArduinoESP32OTABackend : public OTABackend {
16
16
  OTAResponseTypes end() override;
17
17
  void abort() override;
18
18
  bool supports_compression() override { return false; }
19
+
20
+ private:
21
+ bool md5_set_{false};
19
22
  };
20
23
 
21
24
  } // namespace ota
@@ -17,6 +17,11 @@ static const char *const TAG = "ota.arduino_esp8266";
17
17
  std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoESP8266OTABackend>(); }
18
18
 
19
19
  OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) {
20
+ // Handle UPDATE_SIZE_UNKNOWN (0) by calculating available space
21
+ if (image_size == 0) {
22
+ // NOLINTNEXTLINE(readability-static-accessed-through-instance)
23
+ image_size = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
24
+ }
20
25
  bool ret = Update.begin(image_size, U_FLASH);
21
26
  if (ret) {
22
27
  esp8266::preferences_prevent_write(true);
@@ -38,7 +43,10 @@ OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) {
38
43
  return OTA_RESPONSE_ERROR_UNKNOWN;
39
44
  }
40
45
 
41
- void ArduinoESP8266OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); }
46
+ void ArduinoESP8266OTABackend::set_update_md5(const char *md5) {
47
+ Update.setMD5(md5);
48
+ this->md5_set_ = true;
49
+ }
42
50
 
43
51
  OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) {
44
52
  size_t written = Update.write(data, len);
@@ -53,13 +61,19 @@ OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) {
53
61
  }
54
62
 
55
63
  OTAResponseTypes ArduinoESP8266OTABackend::end() {
56
- if (Update.end()) {
64
+ // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
65
+ // This matches the behavior of the old web_server OTA implementation
66
+ bool success = Update.end(!this->md5_set_);
67
+
68
+ // On ESP8266, Update.end() might return false even with error code 0
69
+ // Check the actual error code to determine success
70
+ uint8_t error = Update.getError();
71
+
72
+ if (success || error == UPDATE_ERROR_OK) {
57
73
  return OTA_RESPONSE_OK;
58
74
  }
59
75
 
60
- uint8_t error = Update.getError();
61
76
  ESP_LOGE(TAG, "End error: %d", error);
62
-
63
77
  return OTA_RESPONSE_ERROR_UPDATE_END;
64
78
  }
65
79
 
@@ -21,6 +21,9 @@ class ArduinoESP8266OTABackend : public OTABackend {
21
21
  #else
22
22
  bool supports_compression() override { return false; }
23
23
  #endif
24
+
25
+ private:
26
+ bool md5_set_{false};
24
27
  };
25
28
 
26
29
  } // namespace ota
@@ -15,6 +15,11 @@ static const char *const TAG = "ota.arduino_libretiny";
15
15
  std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoLibreTinyOTABackend>(); }
16
16
 
17
17
  OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) {
18
+ // Handle UPDATE_SIZE_UNKNOWN (0) which is used by web server OTA
19
+ // where the exact firmware size is unknown due to multipart encoding
20
+ if (image_size == 0) {
21
+ image_size = UPDATE_SIZE_UNKNOWN;
22
+ }
18
23
  bool ret = Update.begin(image_size, U_FLASH);
19
24
  if (ret) {
20
25
  return OTA_RESPONSE_OK;
@@ -29,7 +34,10 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) {
29
34
  return OTA_RESPONSE_ERROR_UNKNOWN;
30
35
  }
31
36
 
32
- void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); }
37
+ void ArduinoLibreTinyOTABackend::set_update_md5(const char *md5) {
38
+ Update.setMD5(md5);
39
+ this->md5_set_ = true;
40
+ }
33
41
 
34
42
  OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) {
35
43
  size_t written = Update.write(data, len);
@@ -44,7 +52,9 @@ OTAResponseTypes ArduinoLibreTinyOTABackend::write(uint8_t *data, size_t len) {
44
52
  }
45
53
 
46
54
  OTAResponseTypes ArduinoLibreTinyOTABackend::end() {
47
- if (Update.end()) {
55
+ // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
56
+ // This matches the behavior of the old web_server OTA implementation
57
+ if (Update.end(!this->md5_set_)) {
48
58
  return OTA_RESPONSE_OK;
49
59
  }
50
60
 
@@ -15,6 +15,9 @@ class ArduinoLibreTinyOTABackend : public OTABackend {
15
15
  OTAResponseTypes end() override;
16
16
  void abort() override;
17
17
  bool supports_compression() override { return false; }
18
+
19
+ private:
20
+ bool md5_set_{false};
18
21
  };
19
22
 
20
23
  } // namespace ota
@@ -17,6 +17,8 @@ static const char *const TAG = "ota.arduino_rp2040";
17
17
  std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoRP2040OTABackend>(); }
18
18
 
19
19
  OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) {
20
+ // OTA size of 0 is not currently handled, but
21
+ // web_server is not supported for RP2040, so this is not an issue.
20
22
  bool ret = Update.begin(image_size, U_FLASH);
21
23
  if (ret) {
22
24
  rp2040::preferences_prevent_write(true);
@@ -38,7 +40,10 @@ OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) {
38
40
  return OTA_RESPONSE_ERROR_UNKNOWN;
39
41
  }
40
42
 
41
- void ArduinoRP2040OTABackend::set_update_md5(const char *md5) { Update.setMD5(md5); }
43
+ void ArduinoRP2040OTABackend::set_update_md5(const char *md5) {
44
+ Update.setMD5(md5);
45
+ this->md5_set_ = true;
46
+ }
42
47
 
43
48
  OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) {
44
49
  size_t written = Update.write(data, len);
@@ -53,7 +58,9 @@ OTAResponseTypes ArduinoRP2040OTABackend::write(uint8_t *data, size_t len) {
53
58
  }
54
59
 
55
60
  OTAResponseTypes ArduinoRP2040OTABackend::end() {
56
- if (Update.end()) {
61
+ // Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
62
+ // This matches the behavior of the old web_server OTA implementation
63
+ if (Update.end(!this->md5_set_)) {
57
64
  return OTA_RESPONSE_OK;
58
65
  }
59
66
 
@@ -17,6 +17,9 @@ class ArduinoRP2040OTABackend : public OTABackend {
17
17
  OTAResponseTypes end() override;
18
18
  void abort() override;
19
19
  bool supports_compression() override { return false; }
20
+
21
+ private:
22
+ bool md5_set_{false};
20
23
  };
21
24
 
22
25
  } // namespace ota
@@ -6,10 +6,7 @@
6
6
 
7
7
  #include <esp_ota_ops.h>
8
8
  #include <esp_task_wdt.h>
9
-
10
- #if ESP_IDF_VERSION_MAJOR >= 5
11
9
  #include <spi_flash_mmap.h>
12
- #endif
13
10
 
14
11
  namespace esphome {
15
12
  namespace ota {
@@ -24,7 +21,6 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) {
24
21
 
25
22
  #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15
26
23
  // The following function takes longer than the 5 seconds timeout of WDT
27
- #if ESP_IDF_VERSION_MAJOR >= 5
28
24
  esp_task_wdt_config_t wdtc;
29
25
  wdtc.idle_core_mask = 0;
30
26
  #if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
@@ -36,21 +32,14 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) {
36
32
  wdtc.timeout_ms = 15000;
37
33
  wdtc.trigger_panic = false;
38
34
  esp_task_wdt_reconfigure(&wdtc);
39
- #else
40
- esp_task_wdt_init(15, false);
41
- #endif
42
35
  #endif
43
36
 
44
37
  esp_err_t err = esp_ota_begin(this->partition_, image_size, &this->update_handle_);
45
38
 
46
39
  #if CONFIG_ESP_TASK_WDT_TIMEOUT_S < 15
47
40
  // Set the WDT back to the configured timeout
48
- #if ESP_IDF_VERSION_MAJOR >= 5
49
41
  wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000;
50
42
  esp_task_wdt_reconfigure(&wdtc);
51
- #else
52
- esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false);
53
- #endif
54
43
  #endif
55
44
 
56
45
  if (err != ESP_OK) {
@@ -67,7 +56,10 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) {
67
56
  return OTA_RESPONSE_OK;
68
57
  }
69
58
 
70
- void IDFOTABackend::set_update_md5(const char *expected_md5) { memcpy(this->expected_bin_md5_, expected_md5, 32); }
59
+ void IDFOTABackend::set_update_md5(const char *expected_md5) {
60
+ memcpy(this->expected_bin_md5_, expected_md5, 32);
61
+ this->md5_set_ = true;
62
+ }
71
63
 
72
64
  OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) {
73
65
  esp_err_t err = esp_ota_write(this->update_handle_, data, len);
@@ -84,10 +76,12 @@ OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) {
84
76
  }
85
77
 
86
78
  OTAResponseTypes IDFOTABackend::end() {
87
- this->md5_.calculate();
88
- if (!this->md5_.equals_hex(this->expected_bin_md5_)) {
89
- this->abort();
90
- return OTA_RESPONSE_ERROR_MD5_MISMATCH;
79
+ if (this->md5_set_) {
80
+ this->md5_.calculate();
81
+ if (!this->md5_.equals_hex(this->expected_bin_md5_)) {
82
+ this->abort();
83
+ return OTA_RESPONSE_ERROR_MD5_MISMATCH;
84
+ }
91
85
  }
92
86
  esp_err_t err = esp_ota_end(this->update_handle_);
93
87
  this->update_handle_ = 0;
@@ -24,6 +24,7 @@ class IDFOTABackend : public OTABackend {
24
24
  const esp_partition_t *partition_;
25
25
  md5::MD5Digest md5_{};
26
26
  char expected_bin_md5_[32];
27
+ bool md5_set_{false};
27
28
  };
28
29
 
29
30
  } // namespace ota
@@ -63,6 +63,7 @@ BASE_SCHEMA = cv.All(
63
63
  cv.Schema(
64
64
  {
65
65
  cv.Required(CONF_URL): cv.url,
66
+ cv.Optional(CONF_PATH): cv.string,
66
67
  cv.Optional(CONF_USERNAME): cv.string,
67
68
  cv.Optional(CONF_PASSWORD): cv.string,
68
69
  cv.Exclusive(CONF_FILE, CONF_FILES): validate_yaml_filename,
@@ -74,7 +75,7 @@ BASE_SCHEMA = cv.All(
74
75
  {
75
76
  cv.Required(CONF_PATH): validate_yaml_filename,
76
77
  cv.Optional(CONF_VARS, default={}): cv.Schema(
77
- {cv.string: cv.string}
78
+ {cv.string: object}
78
79
  ),
79
80
  }
80
81
  ),
@@ -116,6 +117,9 @@ def _process_base_package(config: dict) -> dict:
116
117
  )
117
118
  files = []
118
119
 
120
+ if base_path := config.get(CONF_PATH):
121
+ repo_dir = repo_dir / base_path
122
+
119
123
  for file in config[CONF_FILES]:
120
124
  if isinstance(file, str):
121
125
  files.append({CONF_PATH: file, CONF_VARS: {}})
@@ -148,7 +152,6 @@ def _process_base_package(config: dict) -> dict:
148
152
  raise cv.Invalid(
149
153
  f"Current ESPHome Version is too old to use this package: {ESPHOME_VERSION} < {min_version}"
150
154
  )
151
- vars = {k: str(v) for k, v in vars.items()}
152
155
  new_yaml = yaml_util.substitute_vars(new_yaml, vars)
153
156
  packages[f"{filename}{idx}"] = new_yaml
154
157
  except EsphomeError as e:
@@ -1,19 +1,76 @@
1
1
  import esphome.codegen as cg
2
2
  from esphome.components import binary_sensor
3
- from esphome.const import CONF_ID
3
+ import esphome.config_validation as cv
4
+ from esphome.const import (
5
+ CONF_DATA,
6
+ CONF_ID,
7
+ CONF_NAME,
8
+ CONF_STATUS,
9
+ CONF_TYPE,
10
+ DEVICE_CLASS_CONNECTIVITY,
11
+ ENTITY_CATEGORY_DIAGNOSTIC,
12
+ )
13
+ import esphome.final_validate as fv
4
14
 
5
15
  from . import (
16
+ CONF_ENCRYPTION,
17
+ CONF_PING_PONG_ENABLE,
6
18
  CONF_PROVIDER,
19
+ CONF_PROVIDERS,
7
20
  CONF_REMOTE_ID,
8
21
  CONF_TRANSPORT_ID,
22
+ PacketTransport,
9
23
  packet_transport_sensor_schema,
24
+ provider_name_validate,
25
+ )
26
+
27
+ STATUS_SENSOR_SCHEMA = binary_sensor.binary_sensor_schema(
28
+ device_class=DEVICE_CLASS_CONNECTIVITY,
29
+ entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
30
+ ).extend(
31
+ {
32
+ cv.GenerateID(CONF_TRANSPORT_ID): cv.use_id(PacketTransport),
33
+ cv.Required(CONF_PROVIDER): provider_name_validate,
34
+ }
35
+ )
36
+
37
+ CONFIG_SCHEMA = cv.typed_schema(
38
+ {
39
+ CONF_DATA: packet_transport_sensor_schema(binary_sensor.binary_sensor_schema()),
40
+ CONF_STATUS: STATUS_SENSOR_SCHEMA,
41
+ },
42
+ key=CONF_TYPE,
43
+ default_type=CONF_DATA,
10
44
  )
11
45
 
12
- CONFIG_SCHEMA = packet_transport_sensor_schema(binary_sensor.binary_sensor_schema())
46
+
47
+ def _final_validate(config):
48
+ if config[CONF_TYPE] != CONF_STATUS:
49
+ # Only run this validation if a status sensor is being configured
50
+ return config
51
+ full_config = fv.full_config.get()
52
+ transport_path = full_config.get_path_for_id(config[CONF_TRANSPORT_ID])[:-1]
53
+ transport_config = full_config.get_config_for_path(transport_path)
54
+ if transport_config[CONF_PING_PONG_ENABLE] and any(
55
+ CONF_ENCRYPTION in p
56
+ for p in transport_config[CONF_PROVIDERS]
57
+ if p[CONF_NAME] == config[CONF_PROVIDER]
58
+ ):
59
+ return config
60
+ raise cv.Invalid(
61
+ "Status sensor requires ping-pong to be enabled and the nominated provider to use encryption."
62
+ )
63
+
64
+
65
+ FINAL_VALIDATE_SCHEMA = _final_validate
13
66
 
14
67
 
15
68
  async def to_code(config):
16
69
  var = await binary_sensor.new_binary_sensor(config)
17
70
  comp = await cg.get_variable(config[CONF_TRANSPORT_ID])
18
- remote_id = str(config.get(CONF_REMOTE_ID) or config.get(CONF_ID))
19
- cg.add(comp.add_remote_binary_sensor(config[CONF_PROVIDER], remote_id, var))
71
+ if config[CONF_TYPE] == CONF_STATUS:
72
+ cg.add(comp.set_provider_status_sensor(config[CONF_PROVIDER], var))
73
+ cg.add_define("USE_STATUS_SENSOR")
74
+ else: # CONF_DATA is default
75
+ remote_id = str(config.get(CONF_REMOTE_ID) or config.get(CONF_ID))
76
+ cg.add(comp.add_remote_binary_sensor(config[CONF_PROVIDER], remote_id, var))
@@ -317,8 +317,37 @@ void PacketTransport::update() {
317
317
  auto now = millis() / 1000;
318
318
  if (this->last_key_time_ + this->ping_pong_recyle_time_ < now) {
319
319
  this->resend_ping_key_ = this->ping_pong_enable_;
320
+ ESP_LOGV(TAG, "Ping request, age %u", now - this->last_key_time_);
320
321
  this->last_key_time_ = now;
321
322
  }
323
+ for (const auto &provider : this->providers_) {
324
+ uint32_t key_response_age = now - provider.second.last_key_response_time;
325
+ if (key_response_age > (this->ping_pong_recyle_time_ * 2u)) {
326
+ #ifdef USE_STATUS_SENSOR
327
+ if (provider.second.status_sensor != nullptr && provider.second.status_sensor->state) {
328
+ ESP_LOGI(TAG, "Ping status for %s timeout at %u with age %u", provider.first.c_str(), now, key_response_age);
329
+ provider.second.status_sensor->publish_state(false);
330
+ }
331
+ #endif
332
+ #ifdef USE_SENSOR
333
+ for (auto &sensor : this->remote_sensors_[provider.first]) {
334
+ sensor.second->publish_state(NAN);
335
+ }
336
+ #endif
337
+ #ifdef USE_BINARY_SENSOR
338
+ for (auto &sensor : this->remote_binary_sensors_[provider.first]) {
339
+ sensor.second->invalidate_state();
340
+ }
341
+ #endif
342
+ } else {
343
+ #ifdef USE_STATUS_SENSOR
344
+ if (provider.second.status_sensor != nullptr && !provider.second.status_sensor->state) {
345
+ ESP_LOGI(TAG, "Ping status for %s restored at %u with age %u", provider.first.c_str(), now, key_response_age);
346
+ provider.second.status_sensor->publish_state(true);
347
+ }
348
+ #endif
349
+ }
350
+ }
322
351
  }
323
352
 
324
353
  void PacketTransport::add_key_(const char *name, uint32_t key) {
@@ -437,7 +466,8 @@ void PacketTransport::process_(const std::vector<uint8_t> &data) {
437
466
  if (decoder.decode(PING_KEY, key) == DECODE_OK) {
438
467
  if (key == this->ping_key_) {
439
468
  ping_key_seen = true;
440
- ESP_LOGV(TAG, "Found good ping key %X", (unsigned) key);
469
+ provider.last_key_response_time = millis() / 1000;
470
+ ESP_LOGV(TAG, "Found good ping key %X at timestamp %" PRIu32, (unsigned) key, provider.last_key_response_time);
441
471
  } else {
442
472
  ESP_LOGV(TAG, "Unknown ping key %X", (unsigned) key);
443
473
  }
@@ -8,7 +8,7 @@
8
8
  #ifdef USE_BINARY_SENSOR
9
9
  #include "esphome/components/binary_sensor/binary_sensor.h"
10
10
  #endif
11
- #
11
+
12
12
  #include <vector>
13
13
  #include <map>
14
14
 
@@ -27,6 +27,10 @@ struct Provider {
27
27
  std::vector<uint8_t> encryption_key;
28
28
  const char *name;
29
29
  uint32_t last_code[2];
30
+ uint32_t last_key_response_time;
31
+ #ifdef USE_STATUS_SENSOR
32
+ binary_sensor::BinarySensor *status_sensor{nullptr};
33
+ #endif
30
34
  };
31
35
 
32
36
  #ifdef USE_SENSOR
@@ -75,10 +79,7 @@ class PacketTransport : public PollingComponent {
75
79
 
76
80
  void add_provider(const char *hostname) {
77
81
  if (this->providers_.count(hostname) == 0) {
78
- Provider provider;
79
- provider.encryption_key = std::vector<uint8_t>{};
80
- provider.last_code[0] = 0;
81
- provider.last_code[1] = 0;
82
+ Provider provider{};
82
83
  provider.name = hostname;
83
84
  this->providers_[hostname] = provider;
84
85
  #ifdef USE_SENSOR
@@ -97,6 +98,11 @@ class PacketTransport : public PollingComponent {
97
98
  void set_provider_encryption(const char *name, std::vector<uint8_t> key) {
98
99
  this->providers_[name].encryption_key = std::move(key);
99
100
  }
101
+ #ifdef USE_STATUS_SENSOR
102
+ void set_provider_status_sensor(const char *name, binary_sensor::BinarySensor *sensor) {
103
+ this->providers_[name].status_sensor = sensor;
104
+ }
105
+ #endif
100
106
  void set_platform_name(const char *name) { this->platform_name_ = name; }
101
107
 
102
108
  protected:
@@ -53,7 +53,7 @@ PCF8574_PIN_SCHEMA = pins.gpio_base_schema(
53
53
  cv.int_range(min=0, max=17),
54
54
  modes=[CONF_INPUT, CONF_OUTPUT],
55
55
  mode_validator=validate_mode,
56
- invertable=True,
56
+ invertible=True,
57
57
  ).extend(
58
58
  {
59
59
  cv.Required(CONF_PCF8574): cv.use_id(PCF8574Component),