esphome 2025.9.3__py3-none-any.whl → 2025.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. esphome/__main__.py +103 -37
  2. esphome/address_cache.py +142 -0
  3. esphome/automation.py +130 -32
  4. esphome/build_gen/platformio.py +1 -3
  5. esphome/codegen.py +1 -0
  6. esphome/components/animation/animation.cpp +2 -2
  7. esphome/components/api/__init__.py +166 -3
  8. esphome/components/api/api_connection.cpp +84 -41
  9. esphome/components/api/api_connection.h +22 -16
  10. esphome/components/api/api_frame_helper.cpp +33 -19
  11. esphome/components/api/api_frame_helper.h +19 -4
  12. esphome/components/api/api_frame_helper_noise.cpp +41 -53
  13. esphome/components/api/api_frame_helper_noise.h +1 -1
  14. esphome/components/api/api_frame_helper_plaintext.cpp +22 -31
  15. esphome/components/api/api_frame_helper_plaintext.h +1 -1
  16. esphome/components/api/api_pb2.cpp +189 -15
  17. esphome/components/api/api_pb2.h +132 -20
  18. esphome/components/api/api_pb2_dump.cpp +97 -9
  19. esphome/components/api/api_pb2_service.cpp +118 -160
  20. esphome/components/api/api_pb2_service.h +31 -3
  21. esphome/components/api/api_server.cpp +68 -10
  22. esphome/components/api/api_server.h +32 -4
  23. esphome/components/api/custom_api_device.h +8 -8
  24. esphome/components/api/homeassistant_service.h +123 -6
  25. esphome/components/api/proto.h +6 -2
  26. esphome/components/api/user_services.h +2 -2
  27. esphome/components/as7341/sensor.py +1 -1
  28. esphome/components/audio/__init__.py +1 -1
  29. esphome/components/audio/audio.cpp +1 -1
  30. esphome/components/audio/audio_decoder.cpp +9 -9
  31. esphome/components/bl0906/bl0906.cpp +2 -2
  32. esphome/components/bl0942/bl0942.cpp +2 -2
  33. esphome/components/ble_client/__init__.py +1 -1
  34. esphome/components/bluetooth_proxy/__init__.py +4 -30
  35. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +11 -4
  36. esphome/components/bluetooth_proxy/bluetooth_connection.h +2 -2
  37. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
  38. esphome/components/camera_encoder/__init__.py +2 -4
  39. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +4 -2
  40. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +3 -1
  41. esphome/components/canbus/canbus.cpp +7 -5
  42. esphome/components/canbus/canbus.h +7 -7
  43. esphome/components/captive_portal/__init__.py +18 -1
  44. esphome/components/captive_portal/captive_portal.cpp +40 -46
  45. esphome/components/captive_portal/captive_portal.h +20 -22
  46. esphome/components/captive_portal/dns_server_esp32_idf.cpp +205 -0
  47. esphome/components/captive_portal/dns_server_esp32_idf.h +27 -0
  48. esphome/components/ccs811/ccs811.cpp +1 -1
  49. esphome/components/climate/climate.cpp +10 -7
  50. esphome/components/cm1106/cm1106.cpp +1 -1
  51. esphome/components/copy/lock/copy_lock.cpp +1 -1
  52. esphome/components/cover/cover.cpp +1 -0
  53. esphome/components/daikin_arc/daikin_arc.cpp +19 -12
  54. esphome/components/dashboard_import/dashboard_import.cpp +1 -1
  55. esphome/components/dashboard_import/dashboard_import.h +1 -1
  56. esphome/components/deep_sleep/__init__.py +9 -2
  57. esphome/components/deep_sleep/deep_sleep_component.h +11 -9
  58. esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
  59. esphome/components/ektf2232/touchscreen/__init__.py +8 -5
  60. esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
  61. esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
  62. esphome/components/epaper_spi/__init__.py +1 -0
  63. esphome/components/epaper_spi/display.py +80 -0
  64. esphome/components/epaper_spi/epaper_spi.cpp +227 -0
  65. esphome/components/epaper_spi/epaper_spi.h +93 -0
  66. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
  67. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
  68. esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
  69. esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
  70. esphome/components/es7210/es7210.cpp +3 -3
  71. esphome/components/esp32/__init__.py +256 -340
  72. esphome/components/esp32/boards.py +81 -0
  73. esphome/components/esp32/preferences.cpp +23 -17
  74. esphome/components/esp32_ble/__init__.py +167 -44
  75. esphome/components/esp32_ble/ble.cpp +47 -3
  76. esphome/components/esp32_ble/ble.h +18 -0
  77. esphome/components/esp32_ble/ble_advertising.cpp +7 -3
  78. esphome/components/esp32_ble/ble_advertising.h +4 -0
  79. esphome/components/esp32_ble/ble_uuid.cpp +16 -42
  80. esphome/components/esp32_ble_beacon/__init__.py +3 -4
  81. esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +0 -4
  82. esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
  83. esphome/components/esp32_ble_server/__init__.py +28 -14
  84. esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
  85. esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
  86. esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
  87. esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
  88. esphome/components/esp32_ble_server/ble_server.cpp +59 -24
  89. esphome/components/esp32_ble_server/ble_server.h +38 -20
  90. esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
  91. esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
  92. esphome/components/esp32_ble_tracker/__init__.py +25 -80
  93. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -8
  94. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
  95. esphome/components/esp32_camera/__init__.py +1 -3
  96. esphome/components/esp32_can/esp32_can.cpp +22 -4
  97. esphome/components/esp32_can/esp32_can.h +3 -0
  98. esphome/components/esp32_hosted/__init__.py +2 -1
  99. esphome/components/esp32_improv/esp32_improv_component.cpp +135 -65
  100. esphome/components/esp32_improv/esp32_improv_component.h +7 -1
  101. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  102. esphome/components/esp8266/__init__.py +3 -3
  103. esphome/components/esphome/ota/__init__.py +21 -2
  104. esphome/components/esphome/ota/ota_esphome.cpp +456 -146
  105. esphome/components/esphome/ota/ota_esphome.h +49 -2
  106. esphome/components/ethernet/__init__.py +39 -22
  107. esphome/components/ethernet/ethernet_component.cpp +28 -5
  108. esphome/components/ethernet/ethernet_component.h +5 -1
  109. esphome/components/external_components/__init__.py +8 -6
  110. esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
  111. esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
  112. esphome/components/font/__init__.py +5 -5
  113. esphome/components/graph/graph.cpp +1 -1
  114. esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
  115. esphome/components/haier/hon_climate.cpp +2 -2
  116. esphome/components/haier/hon_climate.h +1 -1
  117. esphome/components/hdc1080/hdc1080.cpp +42 -34
  118. esphome/components/hdc1080/hdc1080.h +1 -3
  119. esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
  120. esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
  121. esphome/components/http_request/__init__.py +3 -3
  122. esphome/components/htu21d/htu21d.cpp +13 -18
  123. esphome/components/htu21d/htu21d.h +1 -1
  124. esphome/components/i2s_audio/__init__.py +1 -2
  125. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
  126. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
  127. esphome/components/improv_serial/improv_serial_component.cpp +12 -15
  128. esphome/components/improv_serial/improv_serial_component.h +6 -8
  129. esphome/components/json/json_util.cpp +42 -44
  130. esphome/components/json/json_util.h +57 -0
  131. esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
  132. esphome/components/key_collector/key_collector.h +4 -4
  133. esphome/components/libretiny/__init__.py +6 -6
  134. esphome/components/libretiny/preferences.cpp +23 -16
  135. esphome/components/light/light_call.cpp +98 -120
  136. esphome/components/light/light_call.h +17 -7
  137. esphome/components/lm75b/__init__.py +0 -0
  138. esphome/components/lm75b/lm75b.cpp +39 -0
  139. esphome/components/lm75b/lm75b.h +19 -0
  140. esphome/components/lm75b/sensor.py +34 -0
  141. esphome/components/lock/lock.h +12 -6
  142. esphome/components/logger/__init__.py +15 -27
  143. esphome/components/logger/logger.cpp +10 -20
  144. esphome/components/logger/logger.h +105 -62
  145. esphome/components/logger/logger_esp32.cpp +0 -48
  146. esphome/components/logger/logger_zephyr.cpp +2 -3
  147. esphome/components/logger/select/logger_level_select.cpp +6 -7
  148. esphome/components/logger/select/logger_level_select.h +7 -0
  149. esphome/components/ltr501/ltr501.cpp +7 -6
  150. esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
  151. esphome/components/matrix_keypad/matrix_keypad.h +4 -4
  152. esphome/components/max7219digit/max7219digit.cpp +1 -1
  153. esphome/components/mcp23xxx_base/mcp23xxx_base.h +3 -3
  154. esphome/components/mcp2515/mcp2515.cpp +31 -3
  155. esphome/components/mcp2515/mcp2515_defs.h +3 -1
  156. esphome/components/md5/md5.cpp +0 -26
  157. esphome/components/md5/md5.h +10 -20
  158. esphome/components/mdns/__init__.py +93 -19
  159. esphome/components/mdns/mdns_component.cpp +57 -94
  160. esphome/components/mdns/mdns_component.h +35 -11
  161. esphome/components/mdns/mdns_esp32.cpp +7 -13
  162. esphome/components/mdns/mdns_esp8266.cpp +7 -7
  163. esphome/components/mdns/mdns_libretiny.cpp +3 -4
  164. esphome/components/mdns/mdns_rp2040.cpp +3 -4
  165. esphome/components/mipi/__init__.py +1 -5
  166. esphome/components/mipi_dsi/models/waveshare.py +27 -36
  167. esphome/components/mipi_spi/display.py +24 -8
  168. esphome/components/mipi_spi/mipi_spi.h +3 -3
  169. esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
  170. esphome/components/mmc5603/mmc5603.cpp +3 -3
  171. esphome/components/modbus/modbus.cpp +27 -13
  172. esphome/components/modbus/modbus.h +5 -3
  173. esphome/components/modbus/modbus_definitions.h +86 -0
  174. esphome/components/modbus_controller/__init__.py +29 -1
  175. esphome/components/modbus_controller/const.py +4 -0
  176. esphome/components/modbus_controller/modbus_controller.cpp +38 -13
  177. esphome/components/modbus_controller/modbus_controller.h +18 -29
  178. esphome/components/mpr121/mpr121.cpp +41 -42
  179. esphome/components/mpr121/mpr121.h +0 -1
  180. esphome/components/nau7802/nau7802.cpp +2 -2
  181. esphome/components/network/__init__.py +7 -3
  182. esphome/components/nextion/display.py +4 -4
  183. esphome/components/nextion/nextion.cpp +8 -8
  184. esphome/components/number/__init__.py +2 -0
  185. esphome/components/number/number_call.cpp +23 -12
  186. esphome/components/number/number_call.h +5 -0
  187. esphome/components/online_image/bmp_image.cpp +2 -1
  188. esphome/components/online_image/jpeg_image.cpp +4 -2
  189. esphome/components/opentherm/opentherm.cpp +5 -5
  190. esphome/components/opentherm/opentherm.h +3 -3
  191. esphome/components/openthread/openthread.cpp +11 -10
  192. esphome/components/openthread/openthread.h +0 -1
  193. esphome/components/ota/ota_backend.h +1 -0
  194. esphome/components/packages/__init__.py +10 -8
  195. esphome/components/packet_transport/packet_transport.cpp +2 -0
  196. esphome/components/pid/pid_controller.cpp +1 -1
  197. esphome/components/prometheus/prometheus_handler.cpp +239 -239
  198. esphome/components/psram/__init__.py +32 -28
  199. esphome/components/qmc5883l/qmc5883l.cpp +15 -0
  200. esphome/components/qmc5883l/qmc5883l.h +3 -0
  201. esphome/components/qmc5883l/sensor.py +31 -12
  202. esphome/components/remote_base/gobox_protocol.cpp +3 -3
  203. esphome/components/remote_receiver/__init__.py +14 -2
  204. esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
  205. esphome/components/remote_receiver/remote_receiver.h +4 -0
  206. esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
  207. esphome/components/remote_transmitter/__init__.py +2 -2
  208. esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
  209. esphome/components/rp2040/__init__.py +11 -11
  210. esphome/components/rtttl/rtttl.cpp +2 -2
  211. esphome/components/scd30/sensor.py +1 -1
  212. esphome/components/script/__init__.py +1 -1
  213. esphome/components/script/script.h +7 -7
  214. esphome/components/select/select.cpp +5 -4
  215. esphome/components/select/select_call.cpp +1 -1
  216. esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
  217. esphome/components/sensor/__init__.py +2 -0
  218. esphome/components/sha256/__init__.py +22 -0
  219. esphome/components/sha256/sha256.cpp +116 -0
  220. esphome/components/sha256/sha256.h +60 -0
  221. esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
  222. esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
  223. esphome/components/speaker/media_player/__init__.py +16 -3
  224. esphome/components/spi/__init__.py +0 -3
  225. esphome/components/split_buffer/__init__.py +5 -0
  226. esphome/components/split_buffer/split_buffer.cpp +133 -0
  227. esphome/components/split_buffer/split_buffer.h +40 -0
  228. esphome/components/sps30/sps30.cpp +14 -10
  229. esphome/components/sps30/sps30.h +2 -0
  230. esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
  231. esphome/components/st7789v/st7789v.cpp +3 -2
  232. esphome/components/statsd/statsd.cpp +1 -1
  233. esphome/components/substitutions/__init__.py +3 -1
  234. esphome/components/substitutions/jinja.py +13 -3
  235. esphome/components/sx126x/__init__.py +16 -0
  236. esphome/components/sx126x/sx126x.cpp +15 -1
  237. esphome/components/sx126x/sx126x.h +9 -1
  238. esphome/components/sx126x/sx126x_reg.h +2 -0
  239. esphome/components/text_sensor/text_sensor.cpp +16 -0
  240. esphome/components/text_sensor/text_sensor.h +3 -10
  241. esphome/components/tormatic/tormatic_cover.cpp +1 -1
  242. esphome/components/tuya/select/tuya_select.cpp +1 -1
  243. esphome/components/tuya/tuya.cpp +29 -4
  244. esphome/components/uart/__init__.py +37 -27
  245. esphome/components/uart/uart.h +6 -0
  246. esphome/components/uart/uart_component.cpp +8 -0
  247. esphome/components/uart/uart_component.h +28 -0
  248. esphome/components/uart/uart_component_esp_idf.cpp +64 -10
  249. esphome/components/uart/uart_component_esp_idf.h +5 -2
  250. esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
  251. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
  252. esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
  253. esphome/components/usb_host/__init__.py +12 -2
  254. esphome/components/usb_host/usb_host.h +89 -14
  255. esphome/components/usb_host/usb_host_client.cpp +157 -22
  256. esphome/components/usb_host/usb_host_component.cpp +1 -1
  257. esphome/components/usb_uart/__init__.py +0 -1
  258. esphome/components/usb_uart/ch34x.cpp +4 -4
  259. esphome/components/usb_uart/cp210x.cpp +3 -3
  260. esphome/components/usb_uart/usb_uart.cpp +88 -32
  261. esphome/components/usb_uart/usb_uart.h +30 -6
  262. esphome/components/valve/valve.cpp +1 -0
  263. esphome/components/veml7700/veml7700.cpp +7 -6
  264. esphome/components/version/version_text_sensor.cpp +2 -1
  265. esphome/components/voice_assistant/voice_assistant.cpp +3 -2
  266. esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
  267. esphome/components/web_server/list_entities.cpp +3 -4
  268. esphome/components/web_server/list_entities.h +8 -10
  269. esphome/components/web_server/ota/__init__.py +1 -1
  270. esphome/components/web_server/ota/ota_web_server.cpp +9 -3
  271. esphome/components/web_server/web_server.cpp +509 -404
  272. esphome/components/web_server/web_server.h +5 -6
  273. esphome/components/web_server/web_server_v1.cpp +21 -19
  274. esphome/components/web_server_base/__init__.py +5 -2
  275. esphome/components/web_server_base/web_server_base.h +27 -7
  276. esphome/components/web_server_idf/__init__.py +1 -1
  277. esphome/components/web_server_idf/multipart.cpp +2 -2
  278. esphome/components/web_server_idf/multipart.h +2 -2
  279. esphome/components/web_server_idf/utils.cpp +2 -2
  280. esphome/components/web_server_idf/utils.h +2 -2
  281. esphome/components/web_server_idf/web_server_idf.cpp +118 -26
  282. esphome/components/web_server_idf/web_server_idf.h +12 -10
  283. esphome/components/wifi/__init__.py +13 -11
  284. esphome/components/wifi/wifi_component.cpp +74 -56
  285. esphome/components/wifi/wifi_component.h +4 -4
  286. esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
  287. esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
  288. esphome/components/wireguard/__init__.py +1 -1
  289. esphome/components/wts01/__init__.py +0 -0
  290. esphome/components/wts01/sensor.py +41 -0
  291. esphome/components/wts01/wts01.cpp +91 -0
  292. esphome/components/wts01/wts01.h +27 -0
  293. esphome/components/zephyr/__init__.py +5 -5
  294. esphome/components/zwave_proxy/__init__.py +43 -0
  295. esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
  296. esphome/components/zwave_proxy/zwave_proxy.h +93 -0
  297. esphome/config.py +79 -24
  298. esphome/config_validation.py +13 -15
  299. esphome/const.py +9 -2
  300. esphome/core/__init__.py +33 -22
  301. esphome/core/component.cpp +28 -18
  302. esphome/core/component_iterator.h +2 -1
  303. esphome/core/config.py +15 -15
  304. esphome/core/defines.h +21 -0
  305. esphome/core/entity_helpers.py +9 -6
  306. esphome/core/hash_base.h +56 -0
  307. esphome/core/helpers.cpp +19 -3
  308. esphome/core/helpers.h +26 -0
  309. esphome/core/scheduler.cpp +5 -21
  310. esphome/core/scheduler.h +19 -8
  311. esphome/core/string_ref.h +1 -1
  312. esphome/core/time.cpp +5 -5
  313. esphome/cpp_generator.py +4 -29
  314. esphome/dashboard/const.py +21 -4
  315. esphome/dashboard/core.py +10 -8
  316. esphome/dashboard/dns.py +15 -0
  317. esphome/dashboard/entries.py +15 -21
  318. esphome/dashboard/models.py +76 -0
  319. esphome/dashboard/settings.py +7 -7
  320. esphome/dashboard/status/mdns.py +46 -2
  321. esphome/dashboard/web_server.py +367 -93
  322. esphome/espota2.py +112 -32
  323. esphome/external_files.py +6 -7
  324. esphome/git.py +8 -0
  325. esphome/helpers.py +124 -77
  326. esphome/loader.py +8 -9
  327. esphome/pins.py +2 -2
  328. esphome/platformio_api.py +56 -18
  329. esphome/storage_json.py +26 -21
  330. esphome/types.py +30 -2
  331. esphome/util.py +32 -16
  332. esphome/vscode.py +8 -8
  333. esphome/wizard.py +10 -10
  334. esphome/writer.py +57 -15
  335. esphome/yaml_util.py +37 -31
  336. esphome/zeroconf.py +12 -3
  337. {esphome-2025.9.3.dist-info → esphome-2025.10.0.dist-info}/METADATA +12 -12
  338. {esphome-2025.9.3.dist-info → esphome-2025.10.0.dist-info}/RECORD +342 -322
  339. esphome/components/event_emitter/__init__.py +0 -5
  340. esphome/components/event_emitter/event_emitter.cpp +0 -14
  341. esphome/components/event_emitter/event_emitter.h +0 -63
  342. esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
  343. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
  344. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
  345. esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
  346. esphome/components/uart/uart_component_esp32_arduino.h +0 -60
  347. esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
  348. esphome/core/string_ref.cpp +0 -12
  349. esphome/dashboard/util/file.py +0 -63
  350. {esphome-2025.9.3.dist-info → esphome-2025.10.0.dist-info}/WHEEL +0 -0
  351. {esphome-2025.9.3.dist-info → esphome-2025.10.0.dist-info}/entry_points.txt +0 -0
  352. {esphome-2025.9.3.dist-info → esphome-2025.10.0.dist-info}/licenses/LICENSE +0 -0
  353. {esphome-2025.9.3.dist-info → esphome-2025.10.0.dist-info}/top_level.txt +0 -0
esphome/writer.py CHANGED
@@ -15,6 +15,8 @@ from esphome.const import (
15
15
  from esphome.core import CORE, EsphomeError
16
16
  from esphome.helpers import (
17
17
  copy_file_if_changed,
18
+ get_str_env,
19
+ is_ha_addon,
18
20
  read_file,
19
21
  walk_files,
20
22
  write_file_if_changed,
@@ -266,7 +268,7 @@ def generate_version_h():
266
268
 
267
269
  def write_cpp(code_s):
268
270
  path = CORE.relative_src_path("main.cpp")
269
- if os.path.isfile(path):
271
+ if path.is_file():
270
272
  text = read_file(path)
271
273
  code_format = find_begin_end(
272
274
  text, CPP_AUTO_GENERATE_BEGIN, CPP_AUTO_GENERATE_END
@@ -292,43 +294,84 @@ def write_cpp(code_s):
292
294
 
293
295
  def clean_cmake_cache():
294
296
  pioenvs = CORE.relative_pioenvs_path()
295
- if os.path.isdir(pioenvs):
296
- pioenvs_cmake_path = CORE.relative_pioenvs_path(CORE.name, "CMakeCache.txt")
297
- if os.path.isfile(pioenvs_cmake_path):
297
+ if pioenvs.is_dir():
298
+ pioenvs_cmake_path = pioenvs / CORE.name / "CMakeCache.txt"
299
+ if pioenvs_cmake_path.is_file():
298
300
  _LOGGER.info("Deleting %s", pioenvs_cmake_path)
299
- os.remove(pioenvs_cmake_path)
301
+ pioenvs_cmake_path.unlink()
300
302
 
301
303
 
302
304
  def clean_build():
303
305
  import shutil
304
306
 
307
+ # Allow skipping cache cleaning for integration tests
308
+ if os.environ.get("ESPHOME_SKIP_CLEAN_BUILD"):
309
+ _LOGGER.warning("Skipping build cleaning (ESPHOME_SKIP_CLEAN_BUILD set)")
310
+ return
311
+
305
312
  pioenvs = CORE.relative_pioenvs_path()
306
- if os.path.isdir(pioenvs):
313
+ if pioenvs.is_dir():
307
314
  _LOGGER.info("Deleting %s", pioenvs)
308
315
  shutil.rmtree(pioenvs)
309
316
  piolibdeps = CORE.relative_piolibdeps_path()
310
- if os.path.isdir(piolibdeps):
317
+ if piolibdeps.is_dir():
311
318
  _LOGGER.info("Deleting %s", piolibdeps)
312
319
  shutil.rmtree(piolibdeps)
313
320
  dependencies_lock = CORE.relative_build_path("dependencies.lock")
314
- if os.path.isfile(dependencies_lock):
321
+ if dependencies_lock.is_file():
315
322
  _LOGGER.info("Deleting %s", dependencies_lock)
316
- os.remove(dependencies_lock)
323
+ dependencies_lock.unlink()
317
324
 
318
325
  # Clean PlatformIO cache to resolve CMake compiler detection issues
319
326
  # This helps when toolchain paths change or get corrupted
320
327
  try:
321
- from platformio.project.helpers import get_project_cache_dir
328
+ from platformio.project.config import ProjectConfig
322
329
  except ImportError:
323
330
  # PlatformIO is not available, skip cache cleaning
324
331
  pass
325
332
  else:
326
- cache_dir = get_project_cache_dir()
327
- if cache_dir and cache_dir.strip() and os.path.isdir(cache_dir):
333
+ config = ProjectConfig.get_instance()
334
+ cache_dir = Path(config.get("platformio", "cache_dir"))
335
+ if cache_dir.is_dir():
328
336
  _LOGGER.info("Deleting PlatformIO cache %s", cache_dir)
329
337
  shutil.rmtree(cache_dir)
330
338
 
331
339
 
340
+ def clean_all(configuration: list[str]):
341
+ import shutil
342
+
343
+ data_dirs = [Path(dir) / ".esphome" for dir in configuration]
344
+ if is_ha_addon():
345
+ data_dirs.append(Path("/data"))
346
+ if "ESPHOME_DATA_DIR" in os.environ:
347
+ data_dirs.append(Path(get_str_env("ESPHOME_DATA_DIR", None)))
348
+
349
+ # Clean build dir
350
+ for dir in data_dirs:
351
+ if dir.is_dir():
352
+ _LOGGER.info("Cleaning %s", dir)
353
+ # Don't remove storage or .json files which are needed by the dashboard
354
+ for item in dir.iterdir():
355
+ if item.is_file() and not item.name.endswith(".json"):
356
+ item.unlink()
357
+ elif item.is_dir() and item.name != "storage":
358
+ shutil.rmtree(item)
359
+
360
+ # Clean PlatformIO project files
361
+ try:
362
+ from platformio.project.config import ProjectConfig
363
+ except ImportError:
364
+ # PlatformIO is not available, skip cleaning
365
+ pass
366
+ else:
367
+ config = ProjectConfig.get_instance()
368
+ for pio_dir in ["cache_dir", "packages_dir", "platforms_dir", "core_dir"]:
369
+ path = Path(config.get("platformio", pio_dir))
370
+ if path.is_dir():
371
+ _LOGGER.info("Deleting PlatformIO %s %s", pio_dir, path)
372
+ shutil.rmtree(path)
373
+
374
+
332
375
  GITIGNORE_CONTENT = """# Gitignore settings for ESPHome
333
376
  # This is an example and may include too much for your use-case.
334
377
  # You can modify this file to suit your needs.
@@ -339,6 +382,5 @@ GITIGNORE_CONTENT = """# Gitignore settings for ESPHome
339
382
 
340
383
  def write_gitignore():
341
384
  path = CORE.relative_config_path(".gitignore")
342
- if not os.path.isfile(path):
343
- with open(file=path, mode="w", encoding="utf-8") as f:
344
- f.write(GITIGNORE_CONTENT)
385
+ if not path.is_file():
386
+ path.write_text(GITIGNORE_CONTENT, encoding="utf-8")
esphome/yaml_util.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from collections.abc import Callable
4
- import fnmatch
5
4
  import functools
6
5
  import inspect
7
6
  from io import BytesIO, TextIOBase, TextIOWrapper
@@ -9,6 +8,7 @@ from ipaddress import _BaseAddress, _BaseNetwork
9
8
  import logging
10
9
  import math
11
10
  import os
11
+ from pathlib import Path
12
12
  from typing import Any
13
13
  import uuid
14
14
 
@@ -69,7 +69,7 @@ class ESPHomeDataBase:
69
69
  self._content_offset = database.content_offset
70
70
 
71
71
 
72
- class ESPForceValue:
72
+ class ESPLiteralValue:
73
73
  pass
74
74
 
75
75
 
@@ -109,7 +109,9 @@ def _add_data_ref(fn):
109
109
  class ESPHomeLoaderMixin:
110
110
  """Loader class that keeps track of line numbers."""
111
111
 
112
- def __init__(self, name: str, yaml_loader: Callable[[str], dict[str, Any]]) -> None:
112
+ def __init__(
113
+ self, name: Path, yaml_loader: Callable[[Path], dict[str, Any]]
114
+ ) -> None:
113
115
  """Initialize the loader."""
114
116
  self.name = name
115
117
  self.yaml_loader = yaml_loader
@@ -254,12 +256,8 @@ class ESPHomeLoaderMixin:
254
256
  f"Environment variable '{node.value}' not defined", node.start_mark
255
257
  )
256
258
 
257
- @property
258
- def _directory(self) -> str:
259
- return os.path.dirname(self.name)
260
-
261
- def _rel_path(self, *args: str) -> str:
262
- return os.path.join(self._directory, *args)
259
+ def _rel_path(self, *args: str) -> Path:
260
+ return self.name.parent / Path(*args)
263
261
 
264
262
  @_add_data_ref
265
263
  def construct_secret(self, node: yaml.Node) -> str:
@@ -269,8 +267,8 @@ class ESPHomeLoaderMixin:
269
267
  if self.name == CORE.config_path:
270
268
  raise e
271
269
  try:
272
- main_config_dir = os.path.dirname(CORE.config_path)
273
- main_secret_yml = os.path.join(main_config_dir, SECRET_YAML)
270
+ main_config_dir = CORE.config_path.parent
271
+ main_secret_yml = main_config_dir / SECRET_YAML
274
272
  secrets = self.yaml_loader(main_secret_yml)
275
273
  except EsphomeError as er:
276
274
  raise EsphomeError(f"{e}\n{er}") from er
@@ -329,7 +327,7 @@ class ESPHomeLoaderMixin:
329
327
  files = filter_yaml_files(_find_files(self._rel_path(node.value), "*.yaml"))
330
328
  mapping = OrderedDict()
331
329
  for fname in files:
332
- filename = os.path.splitext(os.path.basename(fname))[0]
330
+ filename = fname.stem
333
331
  mapping[filename] = self.yaml_loader(fname)
334
332
  return mapping
335
333
 
@@ -350,9 +348,15 @@ class ESPHomeLoaderMixin:
350
348
  return Lambda(str(node.value))
351
349
 
352
350
  @_add_data_ref
353
- def construct_force(self, node: yaml.Node) -> ESPForceValue:
354
- obj = self.construct_scalar(node)
355
- return add_class_to_obj(obj, ESPForceValue)
351
+ def construct_literal(self, node: yaml.Node) -> ESPLiteralValue:
352
+ obj = None
353
+ if isinstance(node, yaml.ScalarNode):
354
+ obj = self.construct_scalar(node)
355
+ elif isinstance(node, yaml.SequenceNode):
356
+ obj = self.construct_sequence(node)
357
+ elif isinstance(node, yaml.MappingNode):
358
+ obj = self.construct_mapping(node)
359
+ return add_class_to_obj(obj, ESPLiteralValue)
356
360
 
357
361
  @_add_data_ref
358
362
  def construct_extend(self, node: yaml.Node) -> Extend:
@@ -369,8 +373,8 @@ class ESPHomeLoader(ESPHomeLoaderMixin, FastestAvailableSafeLoader):
369
373
  def __init__(
370
374
  self,
371
375
  stream: TextIOBase | BytesIO,
372
- name: str,
373
- yaml_loader: Callable[[str], dict[str, Any]],
376
+ name: Path,
377
+ yaml_loader: Callable[[Path], dict[str, Any]],
374
378
  ) -> None:
375
379
  FastestAvailableSafeLoader.__init__(self, stream)
376
380
  ESPHomeLoaderMixin.__init__(self, name, yaml_loader)
@@ -382,8 +386,8 @@ class ESPHomePurePythonLoader(ESPHomeLoaderMixin, PurePythonLoader):
382
386
  def __init__(
383
387
  self,
384
388
  stream: TextIOBase | BytesIO,
385
- name: str,
386
- yaml_loader: Callable[[str], dict[str, Any]],
389
+ name: Path,
390
+ yaml_loader: Callable[[Path], dict[str, Any]],
387
391
  ) -> None:
388
392
  PurePythonLoader.__init__(self, stream)
389
393
  ESPHomeLoaderMixin.__init__(self, name, yaml_loader)
@@ -409,29 +413,29 @@ for _loader in (ESPHomeLoader, ESPHomePurePythonLoader):
409
413
  "!include_dir_merge_named", _loader.construct_include_dir_merge_named
410
414
  )
411
415
  _loader.add_constructor("!lambda", _loader.construct_lambda)
412
- _loader.add_constructor("!force", _loader.construct_force)
416
+ _loader.add_constructor("!literal", _loader.construct_literal)
413
417
  _loader.add_constructor("!extend", _loader.construct_extend)
414
418
  _loader.add_constructor("!remove", _loader.construct_remove)
415
419
 
416
420
 
417
- def load_yaml(fname: str, clear_secrets: bool = True) -> Any:
421
+ def load_yaml(fname: Path, clear_secrets: bool = True) -> Any:
418
422
  if clear_secrets:
419
423
  _SECRET_VALUES.clear()
420
424
  _SECRET_CACHE.clear()
421
425
  return _load_yaml_internal(fname)
422
426
 
423
427
 
424
- def _load_yaml_internal(fname: str) -> Any:
428
+ def _load_yaml_internal(fname: Path) -> Any:
425
429
  """Load a YAML file."""
426
430
  try:
427
- with open(fname, encoding="utf-8") as f_handle:
431
+ with fname.open(encoding="utf-8") as f_handle:
428
432
  return parse_yaml(fname, f_handle)
429
433
  except (UnicodeDecodeError, OSError) as err:
430
434
  raise EsphomeError(f"Error reading file {fname}: {err}") from err
431
435
 
432
436
 
433
437
  def parse_yaml(
434
- file_name: str, file_handle: TextIOWrapper, yaml_loader=_load_yaml_internal
438
+ file_name: Path, file_handle: TextIOWrapper, yaml_loader=_load_yaml_internal
435
439
  ) -> Any:
436
440
  """Parse a YAML file."""
437
441
  try:
@@ -483,9 +487,9 @@ def substitute_vars(config, vars):
483
487
 
484
488
  def _load_yaml_internal_with_type(
485
489
  loader_type: type[ESPHomeLoader] | type[ESPHomePurePythonLoader],
486
- fname: str,
490
+ fname: Path,
487
491
  content: TextIOWrapper,
488
- yaml_loader: Any,
492
+ yaml_loader: Callable[[Path], dict[str, Any]],
489
493
  ) -> Any:
490
494
  """Load a YAML file."""
491
495
  loader = loader_type(content, fname, yaml_loader)
@@ -512,13 +516,14 @@ def _is_file_valid(name: str) -> bool:
512
516
  return not name.startswith(".")
513
517
 
514
518
 
515
- def _find_files(directory, pattern):
519
+ def _find_files(directory: Path, pattern):
516
520
  """Recursively load files in a directory."""
517
- for root, dirs, files in os.walk(directory, topdown=True):
521
+ for root, dirs, files in os.walk(directory):
518
522
  dirs[:] = [d for d in dirs if _is_file_valid(d)]
519
- for basename in files:
520
- if _is_file_valid(basename) and fnmatch.fnmatch(basename, pattern):
521
- filename = os.path.join(root, basename)
523
+ for f in files:
524
+ filename = Path(f)
525
+ if _is_file_valid(f) and filename.match(pattern):
526
+ filename = Path(root) / filename
522
527
  yield filename
523
528
 
524
529
 
@@ -627,3 +632,4 @@ ESPHomeDumper.add_multi_representer(TimePeriod, ESPHomeDumper.represent_stringif
627
632
  ESPHomeDumper.add_multi_representer(Lambda, ESPHomeDumper.represent_lambda)
628
633
  ESPHomeDumper.add_multi_representer(core.ID, ESPHomeDumper.represent_id)
629
634
  ESPHomeDumper.add_multi_representer(uuid.UUID, ESPHomeDumper.represent_stringify)
635
+ ESPHomeDumper.add_multi_representer(Path, ESPHomeDumper.represent_stringify)
esphome/zeroconf.py CHANGED
@@ -68,8 +68,11 @@ class DashboardBrowser(AsyncServiceBrowser):
68
68
 
69
69
 
70
70
  class DashboardImportDiscovery:
71
- def __init__(self) -> None:
71
+ def __init__(
72
+ self, on_update: Callable[[str, DiscoveredImport | None], None] | None = None
73
+ ) -> None:
72
74
  self.import_state: dict[str, DiscoveredImport] = {}
75
+ self.on_update = on_update
73
76
 
74
77
  def browser_callback(
75
78
  self,
@@ -85,7 +88,9 @@ class DashboardImportDiscovery:
85
88
  state_change,
86
89
  )
87
90
  if state_change == ServiceStateChange.Removed:
88
- self.import_state.pop(name, None)
91
+ removed = self.import_state.pop(name, None)
92
+ if removed and self.on_update:
93
+ self.on_update(name, None)
89
94
  return
90
95
 
91
96
  if state_change == ServiceStateChange.Updated and name not in self.import_state:
@@ -139,7 +144,7 @@ class DashboardImportDiscovery:
139
144
  if friendly_name is not None:
140
145
  friendly_name = friendly_name.decode()
141
146
 
142
- self.import_state[name] = DiscoveredImport(
147
+ discovered = DiscoveredImport(
143
148
  friendly_name=friendly_name,
144
149
  device_name=node_name,
145
150
  package_import_url=import_url,
@@ -147,6 +152,10 @@ class DashboardImportDiscovery:
147
152
  project_version=project_version,
148
153
  network=network,
149
154
  )
155
+ is_new = name not in self.import_state
156
+ self.import_state[name] = discovered
157
+ if is_new and self.on_update:
158
+ self.on_update(name, discovered)
150
159
 
151
160
  def update_device_mdns(self, node_name: str, version: str):
152
161
  storage_path = ext_storage_path(node_name + ".yaml")
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: esphome
3
- Version: 2025.9.3
3
+ Version: 2025.10.0
4
4
  Summary: ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems.
5
5
  Author-email: The ESPHome Authors <esphome@openhomefoundation.org>
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Documentation, https://esphome.io
8
8
  Project-URL: Source Code, https://github.com/esphome/esphome
9
9
  Project-URL: Bug Tracker, https://github.com/esphome/esphome/issues
@@ -16,7 +16,6 @@ Platform: any
16
16
  Classifier: Environment :: Console
17
17
  Classifier: Intended Audience :: Developers
18
18
  Classifier: Intended Audience :: End Users/Desktop
19
- Classifier: License :: OSI Approved :: MIT License
20
19
  Classifier: Programming Language :: C++
21
20
  Classifier: Programming Language :: Python :: 3
22
21
  Classifier: Topic :: Home Automation
@@ -25,7 +24,7 @@ Description-Content-Type: text/markdown
25
24
  License-File: LICENSE
26
25
  Requires-Dist: cryptography==45.0.1
27
26
  Requires-Dist: voluptuous==0.15.2
28
- Requires-Dist: PyYAML==6.0.2
27
+ Requires-Dist: PyYAML==6.0.3
29
28
  Requires-Dist: paho-mqtt==1.6.1
30
29
  Requires-Dist: colorama==0.4.6
31
30
  Requires-Dist: icmplib==3.0.4
@@ -34,13 +33,14 @@ Requires-Dist: tzlocal==5.3.1
34
33
  Requires-Dist: tzdata>=2021.1
35
34
  Requires-Dist: pyserial==3.5
36
35
  Requires-Dist: platformio==6.1.18
37
- Requires-Dist: esptool==5.0.2
36
+ Requires-Dist: esptool==5.1.0
38
37
  Requires-Dist: click==8.1.7
39
- Requires-Dist: esphome-dashboard==20250904.0
40
- Requires-Dist: aioesphomeapi==40.2.1
41
- Requires-Dist: zeroconf==0.147.2
38
+ Requires-Dist: esphome-dashboard==20251013.0
39
+ Requires-Dist: aioesphomeapi==41.16.1
40
+ Requires-Dist: zeroconf==0.148.0
42
41
  Requires-Dist: puremagic==1.30
43
42
  Requires-Dist: ruamel.yaml==0.18.15
43
+ Requires-Dist: ruamel.yaml.clib==0.2.12
44
44
  Requires-Dist: esphome-glyphsets==0.2.0
45
45
  Requires-Dist: pillow==10.4.0
46
46
  Requires-Dist: cairosvg==2.8.2
@@ -54,15 +54,15 @@ Requires-Dist: clang-format==13.0.1; extra == "dev"
54
54
  Requires-Dist: clang-tidy==18.1.8; extra == "dev"
55
55
  Requires-Dist: yamllint==1.37.1; extra == "dev"
56
56
  Provides-Extra: test
57
- Requires-Dist: pylint==3.3.8; extra == "test"
57
+ Requires-Dist: pylint==3.3.9; extra == "test"
58
58
  Requires-Dist: flake8==7.3.0; extra == "test"
59
- Requires-Dist: ruff==0.12.12; extra == "test"
59
+ Requires-Dist: ruff==0.14.0; extra == "test"
60
60
  Requires-Dist: pyupgrade==3.20.0; extra == "test"
61
61
  Requires-Dist: pre-commit; extra == "test"
62
62
  Requires-Dist: pytest==8.4.2; extra == "test"
63
63
  Requires-Dist: pytest-cov==7.0.0; extra == "test"
64
- Requires-Dist: pytest-mock==3.15.0; extra == "test"
65
- Requires-Dist: pytest-asyncio==1.1.0; extra == "test"
64
+ Requires-Dist: pytest-mock==3.15.1; extra == "test"
65
+ Requires-Dist: pytest-asyncio==1.2.0; extra == "test"
66
66
  Requires-Dist: pytest-xdist==3.8.0; extra == "test"
67
67
  Requires-Dist: asyncmock==0.4.2; extra == "test"
68
68
  Requires-Dist: hypothesis==6.92.1; extra == "test"