esphome 2025.7.4__py3-none-any.whl → 2025.8.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 (758) hide show
  1. esphome/__main__.py +190 -83
  2. esphome/automation.py +2 -4
  3. esphome/build_gen/__init__.py +0 -0
  4. esphome/build_gen/platformio.py +102 -0
  5. esphome/components/a4988/a4988.cpp +0 -1
  6. esphome/components/absolute_humidity/absolute_humidity.cpp +0 -2
  7. esphome/components/absolute_humidity/sensor.py +2 -2
  8. esphome/components/adc/__init__.py +123 -85
  9. esphome/components/adc/adc_sensor.h +98 -35
  10. esphome/components/adc/adc_sensor_common.cpp +10 -4
  11. esphome/components/adc/adc_sensor_esp32.cpp +291 -123
  12. esphome/components/adc/adc_sensor_esp8266.cpp +1 -4
  13. esphome/components/adc/adc_sensor_libretiny.cpp +1 -2
  14. esphome/components/adc/adc_sensor_rp2040.cpp +1 -2
  15. esphome/components/adc/adc_sensor_zephyr.cpp +207 -0
  16. esphome/components/adc/sensor.py +61 -27
  17. esphome/components/adc128s102/adc128s102.cpp +1 -4
  18. esphome/components/ade7880/sensor.py +75 -49
  19. esphome/components/ads1115/ads1115.cpp +0 -1
  20. esphome/components/ads1118/ads1118.cpp +0 -1
  21. esphome/components/ags10/ags10.cpp +0 -4
  22. esphome/components/aht10/aht10.cpp +0 -4
  23. esphome/components/aic3204/aic3204.cpp +0 -2
  24. esphome/components/airthings_wave_plus/__init__.py +1 -1
  25. esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +22 -4
  26. esphome/components/airthings_wave_plus/airthings_wave_plus.h +10 -1
  27. esphome/components/airthings_wave_plus/sensor.py +55 -28
  28. esphome/components/alarm_control_panel/__init__.py +4 -9
  29. esphome/components/am2315c/am2315c.cpp +0 -2
  30. esphome/components/am2320/am2320.cpp +0 -1
  31. esphome/components/animation/__init__.py +14 -11
  32. esphome/components/apds9306/apds9306.cpp +0 -4
  33. esphome/components/apds9960/apds9960.cpp +0 -1
  34. esphome/components/api/__init__.py +29 -4
  35. esphome/components/api/api_connection.cpp +378 -401
  36. esphome/components/api/api_connection.h +112 -56
  37. esphome/components/api/api_frame_helper.cpp +69 -896
  38. esphome/components/api/api_frame_helper.h +31 -126
  39. esphome/components/api/api_frame_helper_noise.cpp +583 -0
  40. esphome/components/api/api_frame_helper_noise.h +68 -0
  41. esphome/components/api/api_frame_helper_plaintext.cpp +290 -0
  42. esphome/components/api/api_frame_helper_plaintext.h +53 -0
  43. esphome/components/api/api_noise_context.h +2 -4
  44. esphome/components/api/api_pb2.cpp +1601 -1808
  45. esphome/components/api/api_pb2.h +367 -323
  46. esphome/components/api/api_pb2_dump.cpp +1137 -3466
  47. esphome/components/api/api_pb2_includes.h +34 -0
  48. esphome/components/api/api_pb2_service.cpp +94 -105
  49. esphome/components/api/api_pb2_service.h +27 -16
  50. esphome/components/api/api_server.cpp +18 -17
  51. esphome/components/api/api_server.h +8 -5
  52. esphome/components/api/client.py +16 -8
  53. esphome/components/api/custom_api_device.h +68 -14
  54. esphome/components/api/homeassistant_service.h +24 -19
  55. esphome/components/api/list_entities.cpp +3 -5
  56. esphome/components/api/list_entities.h +2 -4
  57. esphome/components/api/proto.cpp +3 -5
  58. esphome/components/api/proto.h +239 -274
  59. esphome/components/api/subscribe_state.cpp +2 -4
  60. esphome/components/api/subscribe_state.h +2 -4
  61. esphome/components/api/user_services.cpp +2 -4
  62. esphome/components/api/user_services.h +8 -8
  63. esphome/components/as3935/as3935.cpp +0 -2
  64. esphome/components/as3935_spi/as3935_spi.cpp +0 -2
  65. esphome/components/as5600/__init__.py +1 -1
  66. esphome/components/as5600/as5600.cpp +0 -2
  67. esphome/components/as5600/sensor/__init__.py +0 -1
  68. esphome/components/as7341/as7341.cpp +0 -1
  69. esphome/components/async_tcp/__init__.py +1 -1
  70. esphome/components/at581x/at581x.cpp +1 -1
  71. esphome/components/atm90e26/atm90e26.cpp +0 -1
  72. esphome/components/atm90e32/atm90e32.cpp +475 -116
  73. esphome/components/atm90e32/atm90e32.h +43 -5
  74. esphome/components/audio/audio.h +2 -2
  75. esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +0 -2
  76. esphome/components/beken_spi_led_strip/led_strip.cpp +0 -2
  77. esphome/components/bh1750/bh1750.cpp +0 -1
  78. esphome/components/binary_sensor/__init__.py +14 -12
  79. esphome/components/ble_client/__init__.py +4 -7
  80. esphome/components/bluetooth_proxy/__init__.py +40 -3
  81. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +392 -81
  82. esphome/components/bluetooth_proxy/bluetooth_connection.h +16 -5
  83. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +102 -311
  84. esphome/components/bluetooth_proxy/bluetooth_proxy.h +30 -14
  85. esphome/components/bme280_base/bme280_base.cpp +15 -16
  86. esphome/components/bme680/bme680.cpp +2 -3
  87. esphome/components/bme680_bsec/bme680_bsec.cpp +0 -2
  88. esphome/components/bme68x_bsec2/bme68x_bsec2.cpp +0 -2
  89. esphome/components/bmi160/bmi160.cpp +0 -1
  90. esphome/components/bmp085/bmp085.cpp +0 -1
  91. esphome/components/bmp280_base/bmp280_base.cpp +13 -14
  92. esphome/components/bmp3xx_base/bmp3xx_base.cpp +0 -1
  93. esphome/components/bmp581/bmp581.cpp +0 -2
  94. esphome/components/bp1658cj/bp1658cj.cpp +0 -1
  95. esphome/components/bp5758d/bp5758d.cpp +0 -1
  96. esphome/components/button/__init__.py +0 -1
  97. esphome/components/canbus/__init__.py +2 -3
  98. esphome/components/canbus/canbus.cpp +0 -1
  99. esphome/components/cap1188/cap1188.cpp +0 -2
  100. esphome/components/captive_portal/__init__.py +1 -1
  101. esphome/components/cd74hc4067/cd74hc4067.cpp +0 -2
  102. esphome/components/ch422g/ch422g.cpp +0 -1
  103. esphome/components/chsc6x/chsc6x_touchscreen.cpp +0 -3
  104. esphome/components/climate/__init__.py +0 -1
  105. esphome/components/climate/climate_traits.h +24 -0
  106. esphome/components/cm1106/cm1106.cpp +0 -1
  107. esphome/components/const/__init__.py +6 -0
  108. esphome/components/cover/__init__.py +0 -1
  109. esphome/components/cover/cover.cpp +9 -13
  110. esphome/components/cs5460a/cs5460a.cpp +0 -2
  111. esphome/components/cse7761/cse7761.cpp +0 -1
  112. esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +0 -2
  113. esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +0 -2
  114. esphome/components/dac7678/dac7678_output.cpp +0 -2
  115. esphome/components/dallas_temp/dallas_temp.cpp +0 -1
  116. esphome/components/datetime/__init__.py +0 -2
  117. esphome/components/debug/__init__.py +15 -1
  118. esphome/components/debug/debug_zephyr.cpp +281 -0
  119. esphome/components/debug/sensor.py +2 -1
  120. esphome/components/deep_sleep/deep_sleep_component.cpp +0 -1
  121. esphome/components/deep_sleep/deep_sleep_esp32.cpp +20 -1
  122. esphome/components/dfrobot_sen0395/__init__.py +1 -2
  123. esphome/components/dht/dht.cpp +0 -1
  124. esphome/components/dht12/dht12.cpp +0 -1
  125. esphome/components/display/__init__.py +16 -3
  126. esphome/components/display_menu_base/__init__.py +1 -1
  127. esphome/components/dps310/dps310.cpp +0 -2
  128. esphome/components/ds1307/ds1307.cpp +0 -1
  129. esphome/components/ds2484/ds2484.cpp +0 -1
  130. esphome/components/duty_cycle/duty_cycle_sensor.cpp +0 -1
  131. esphome/components/ee895/ee895.cpp +0 -1
  132. esphome/components/ektf2232/touchscreen/ektf2232.cpp +0 -1
  133. esphome/components/emc2101/emc2101.cpp +0 -2
  134. esphome/components/ens160_base/ens160_base.cpp +0 -2
  135. esphome/components/ens210/ens210.cpp +0 -1
  136. esphome/components/es7210/es7210.cpp +0 -2
  137. esphome/components/es7243e/es7243e.cpp +0 -2
  138. esphome/components/es8156/es8156.cpp +0 -2
  139. esphome/components/es8311/es8311.cpp +0 -2
  140. esphome/components/es8388/es8388.cpp +0 -2
  141. esphome/components/esp32/__init__.py +203 -60
  142. esphome/components/esp32/boards.py +17 -0
  143. esphome/components/esp32/gpio.cpp +0 -1
  144. esphome/components/esp32/gpio.py +1 -2
  145. esphome/components/esp32/gpio_esp32_h2.py +2 -7
  146. esphome/components/esp32/gpio_esp32_p4.py +2 -7
  147. esphome/components/esp32/post_build.py.script +112 -61
  148. esphome/components/esp32_ble/__init__.py +41 -2
  149. esphome/components/esp32_ble/ble.cpp +14 -10
  150. esphome/components/esp32_ble/ble.h +18 -18
  151. esphome/components/esp32_ble/ble_advertising.cpp +5 -5
  152. esphome/components/esp32_ble/ble_advertising.h +7 -5
  153. esphome/components/esp32_ble/ble_event.h +139 -73
  154. esphome/components/esp32_ble/ble_scan_result.h +2 -4
  155. esphome/components/esp32_ble/ble_uuid.cpp +5 -5
  156. esphome/components/esp32_ble/ble_uuid.h +6 -5
  157. esphome/components/esp32_ble_beacon/__init__.py +4 -0
  158. esphome/components/esp32_ble_client/__init__.py +1 -1
  159. esphome/components/esp32_ble_client/ble_characteristic.cpp +4 -4
  160. esphome/components/esp32_ble_client/ble_characteristic.h +6 -4
  161. esphome/components/esp32_ble_client/ble_client_base.cpp +155 -104
  162. esphome/components/esp32_ble_client/ble_client_base.h +17 -6
  163. esphome/components/esp32_ble_client/ble_descriptor.h +6 -4
  164. esphome/components/esp32_ble_client/ble_service.cpp +4 -4
  165. esphome/components/esp32_ble_client/ble_service.h +6 -4
  166. esphome/components/esp32_ble_server/__init__.py +15 -12
  167. esphome/components/esp32_ble_tracker/__init__.py +79 -11
  168. esphome/components/esp32_ble_tracker/automation.h +4 -4
  169. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +264 -261
  170. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +103 -37
  171. esphome/components/esp32_camera/__init__.py +13 -1
  172. esphome/components/esp32_camera/esp32_camera.cpp +7 -2
  173. esphome/components/esp32_camera/esp32_camera.h +1 -0
  174. esphome/components/esp32_dac/esp32_dac.cpp +3 -19
  175. esphome/components/esp32_dac/esp32_dac.h +4 -8
  176. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -6
  177. esphome/components/esp32_rmt_led_strip/light.py +1 -1
  178. esphome/components/esp32_touch/__init__.py +2 -3
  179. esphome/components/esp32_touch/esp32_touch.h +9 -6
  180. esphome/components/esp32_touch/esp32_touch_common.cpp +2 -0
  181. esphome/components/esp32_touch/esp32_touch_v1.cpp +7 -9
  182. esphome/components/esp32_touch/esp32_touch_v2.cpp +10 -6
  183. esphome/components/esp8266/__init__.py +3 -1
  184. esphome/components/esp8266_pwm/esp8266_pwm.cpp +0 -1
  185. esphome/components/esphome/ota/__init__.py +1 -2
  186. esphome/components/esphome/ota/ota_esphome.cpp +150 -77
  187. esphome/components/esphome/ota/ota_esphome.h +8 -1
  188. esphome/components/espnow/__init__.py +309 -0
  189. esphome/components/espnow/automation.h +175 -0
  190. esphome/components/espnow/espnow_component.cpp +468 -0
  191. esphome/components/espnow/espnow_component.h +183 -0
  192. esphome/components/espnow/espnow_err.h +19 -0
  193. esphome/components/espnow/espnow_packet.h +166 -0
  194. esphome/components/ethernet/__init__.py +7 -1
  195. esphome/components/ethernet/esp_eth_phy_jl1101.c +5 -0
  196. esphome/components/ethernet/ethernet_component.cpp +0 -1
  197. esphome/components/ethernet/ethernet_component.h +4 -0
  198. esphome/components/ethernet_info/ethernet_info_text_sensor.h +0 -3
  199. esphome/components/event/__init__.py +0 -1
  200. esphome/components/factory_reset/__init__.py +92 -0
  201. esphome/components/factory_reset/factory_reset.cpp +76 -0
  202. esphome/components/factory_reset/factory_reset.h +43 -0
  203. esphome/components/fan/__init__.py +0 -1
  204. esphome/components/fan/fan_traits.h +16 -0
  205. esphome/components/fastled_base/fastled_light.cpp +0 -1
  206. esphome/components/fastled_spi/light.py +1 -3
  207. esphome/components/fingerprint_grow/fingerprint_grow.cpp +0 -2
  208. esphome/components/font/__init__.py +9 -1
  209. esphome/components/fs3000/fs3000.cpp +0 -2
  210. esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp +0 -2
  211. esphome/components/ft63x6/ft63x6.cpp +0 -1
  212. esphome/components/gdk101/gdk101.cpp +0 -1
  213. esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +0 -1
  214. esphome/components/gl_r01_i2c/sensor.py +1 -1
  215. esphome/components/gpio/one_wire/gpio_one_wire.cpp +0 -1
  216. esphome/components/gpio/switch/gpio_switch.cpp +0 -2
  217. esphome/components/gpio_expander/cached_gpio.h +24 -15
  218. esphome/components/gps/__init__.py +6 -2
  219. esphome/components/gps/gps.cpp +50 -49
  220. esphome/components/gps/gps.h +4 -8
  221. esphome/components/gps/time/gps_time.cpp +3 -9
  222. esphome/components/gps/time/gps_time.h +4 -7
  223. esphome/components/graph/__init__.py +1 -1
  224. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +0 -1
  225. esphome/components/grove_tb6612fng/grove_tb6612fng.cpp +0 -1
  226. esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +21 -12
  227. esphome/components/gt911/touchscreen/gt911_touchscreen.h +26 -2
  228. esphome/components/haier/climate.py +5 -10
  229. esphome/components/haier/haier_base.cpp +0 -1
  230. esphome/components/hbridge/switch/hbridge_switch.cpp +0 -2
  231. esphome/components/hdc1080/hdc1080.cpp +0 -2
  232. esphome/components/heatpumpir/climate.py +2 -2
  233. esphome/components/hlw8012/hlw8012.cpp +0 -1
  234. esphome/components/hm3301/hm3301.cpp +0 -1
  235. esphome/components/hmc5883l/hmc5883l.cpp +0 -1
  236. esphome/components/homeassistant/__init__.py +1 -0
  237. esphome/components/homeassistant/number/__init__.py +1 -0
  238. esphome/components/homeassistant/number/homeassistant_number.cpp +11 -7
  239. esphome/components/homeassistant/switch/__init__.py +1 -0
  240. esphome/components/homeassistant/switch/homeassistant_switch.cpp +9 -5
  241. esphome/components/honeywellabp/honeywellabp.cpp +1 -4
  242. esphome/components/host/__init__.py +2 -0
  243. esphome/components/hte501/hte501.cpp +0 -1
  244. esphome/components/http_request/__init__.py +2 -3
  245. esphome/components/http_request/http_request_idf.cpp +2 -2
  246. esphome/components/htu21d/htu21d.cpp +0 -2
  247. esphome/components/htu31d/htu31d.cpp +0 -2
  248. esphome/components/hx711/hx711.cpp +0 -1
  249. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +0 -1
  250. esphome/components/hydreon_rgxx/sensor.py +4 -5
  251. esphome/components/i2c/i2c_bus.h +1 -1
  252. esphome/components/i2c/i2c_bus_arduino.cpp +1 -2
  253. esphome/components/i2c/i2c_bus_esp_idf.cpp +192 -17
  254. esphome/components/i2c/i2c_bus_esp_idf.h +11 -1
  255. esphome/components/i2s_audio/__init__.py +6 -5
  256. esphome/components/i2s_audio/i2s_audio.cpp +0 -2
  257. esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +1 -4
  258. esphome/components/i2s_audio/microphone/__init__.py +4 -6
  259. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +46 -19
  260. esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +4 -3
  261. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +273 -269
  262. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +19 -34
  263. esphome/components/ili9xxx/display.py +4 -3
  264. esphome/components/ili9xxx/ili9xxx_display.cpp +0 -2
  265. esphome/components/image/__init__.py +123 -92
  266. esphome/components/improv_serial/__init__.py +7 -8
  267. esphome/components/ina219/ina219.cpp +0 -1
  268. esphome/components/ina226/ina226.cpp +0 -2
  269. esphome/components/ina260/ina260.cpp +0 -2
  270. esphome/components/ina2xx_base/__init__.py +2 -5
  271. esphome/components/ina2xx_base/ina2xx_base.cpp +0 -2
  272. esphome/components/ina3221/ina3221.cpp +0 -1
  273. esphome/components/internal_temperature/internal_temperature.cpp +0 -2
  274. esphome/components/interval/interval.h +5 -9
  275. esphome/components/json/__init__.py +1 -1
  276. esphome/components/kmeteriso/kmeteriso.cpp +0 -2
  277. esphome/components/lc709203f/lc709203f.cpp +0 -2
  278. esphome/components/lcd_gpio/display.py +1 -3
  279. esphome/components/lcd_gpio/gpio_lcd_display.cpp +0 -1
  280. esphome/components/lcd_pcf8574/pcf8574_display.cpp +0 -1
  281. esphome/components/ld2410/__init__.py +4 -6
  282. esphome/components/ld2410/binary_sensor.py +4 -0
  283. esphome/components/ld2410/ld2410.cpp +56 -100
  284. esphome/components/ld2410/ld2410.h +17 -15
  285. esphome/components/ld2410/sensor.py +24 -10
  286. esphome/components/ld2412/__init__.py +46 -0
  287. esphome/components/ld2412/binary_sensor.py +70 -0
  288. esphome/components/ld2412/button/__init__.py +74 -0
  289. esphome/components/ld2412/button/factory_reset_button.cpp +9 -0
  290. esphome/components/ld2412/button/factory_reset_button.h +18 -0
  291. esphome/components/ld2412/button/query_button.cpp +9 -0
  292. esphome/components/ld2412/button/query_button.h +18 -0
  293. esphome/components/ld2412/button/restart_button.cpp +9 -0
  294. esphome/components/ld2412/button/restart_button.h +18 -0
  295. esphome/components/ld2412/button/start_dynamic_background_correction_button.cpp +11 -0
  296. esphome/components/ld2412/button/start_dynamic_background_correction_button.h +18 -0
  297. esphome/components/ld2412/ld2412.cpp +861 -0
  298. esphome/components/ld2412/ld2412.h +141 -0
  299. esphome/components/ld2412/number/__init__.py +126 -0
  300. esphome/components/ld2412/number/gate_threshold_number.cpp +14 -0
  301. esphome/components/ld2412/number/gate_threshold_number.h +19 -0
  302. esphome/components/ld2412/number/light_threshold_number.cpp +12 -0
  303. esphome/components/ld2412/number/light_threshold_number.h +18 -0
  304. esphome/components/ld2412/number/max_distance_timeout_number.cpp +12 -0
  305. esphome/components/ld2412/number/max_distance_timeout_number.h +18 -0
  306. esphome/components/ld2412/select/__init__.py +82 -0
  307. esphome/components/ld2412/select/baud_rate_select.cpp +12 -0
  308. esphome/components/ld2412/select/baud_rate_select.h +18 -0
  309. esphome/components/ld2412/select/distance_resolution_select.cpp +12 -0
  310. esphome/components/ld2412/select/distance_resolution_select.h +18 -0
  311. esphome/components/ld2412/select/light_out_control_select.cpp +12 -0
  312. esphome/components/ld2412/select/light_out_control_select.h +18 -0
  313. esphome/components/ld2412/sensor.py +124 -0
  314. esphome/components/ld2412/switch/__init__.py +45 -0
  315. esphome/components/ld2412/switch/bluetooth_switch.cpp +12 -0
  316. esphome/components/ld2412/switch/bluetooth_switch.h +18 -0
  317. esphome/components/ld2412/switch/engineering_mode_switch.cpp +12 -0
  318. esphome/components/ld2412/switch/engineering_mode_switch.h +18 -0
  319. esphome/components/ld2412/text_sensor.py +34 -0
  320. esphome/components/ld2420/ld2420.cpp +0 -1
  321. esphome/components/ld2450/__init__.py +3 -4
  322. esphome/components/ld2450/binary_sensor.py +3 -0
  323. esphome/components/ld2450/ld2450.cpp +77 -165
  324. esphome/components/ld2450/ld2450.h +26 -54
  325. esphome/components/ld2450/sensor.py +120 -6
  326. esphome/components/ld2450/text_sensor.py +5 -4
  327. esphome/components/ld24xx/__init__.py +1 -0
  328. esphome/components/ld24xx/ld24xx.h +65 -0
  329. esphome/components/ledc/ledc_output.cpp +0 -1
  330. esphome/components/libretiny/__init__.py +2 -0
  331. esphome/components/light/__init__.py +0 -1
  332. esphome/components/light/effects.py +70 -45
  333. esphome/components/light/light_call.cpp +101 -66
  334. esphome/components/light/light_color_values.h +16 -11
  335. esphome/components/light/light_json_schema.cpp +46 -44
  336. esphome/components/light/light_state.cpp +8 -11
  337. esphome/components/light/light_traits.h +17 -0
  338. esphome/components/lightwaverf/lightwaverf.cpp +0 -2
  339. esphome/components/lilygo_t5_47/touchscreen/lilygo_t5_47_touchscreen.cpp +0 -1
  340. esphome/components/lock/__init__.py +0 -1
  341. esphome/components/logger/__init__.py +31 -9
  342. esphome/components/logger/logger.cpp +12 -7
  343. esphome/components/logger/logger.h +25 -14
  344. esphome/components/logger/logger_esp32.cpp +2 -7
  345. esphome/components/logger/logger_esp8266.cpp +2 -4
  346. esphome/components/logger/logger_host.cpp +2 -4
  347. esphome/components/logger/logger_libretiny.cpp +2 -4
  348. esphome/components/logger/logger_rp2040.cpp +2 -4
  349. esphome/components/logger/logger_zephyr.cpp +86 -0
  350. esphome/components/logger/select/logger_level_select.cpp +2 -4
  351. esphome/components/logger/select/logger_level_select.h +2 -4
  352. esphome/components/logger/task_log_buffer.cpp +2 -4
  353. esphome/components/logger/task_log_buffer.h +2 -4
  354. esphome/components/lps22/sensor.py +5 -5
  355. esphome/components/ltr390/ltr390.cpp +0 -2
  356. esphome/components/ltr501/ltr501.cpp +0 -1
  357. esphome/components/ltr_als_ps/ltr_als_ps.cpp +0 -1
  358. esphome/components/lvgl/__init__.py +14 -13
  359. esphome/components/lvgl/automation.py +2 -4
  360. esphome/components/lvgl/defines.py +0 -2
  361. esphome/components/lvgl/helpers.py +1 -1
  362. esphome/components/lvgl/lv_validation.py +7 -4
  363. esphome/components/lvgl/lvgl_esphome.cpp +2 -3
  364. esphome/components/lvgl/styles.py +2 -2
  365. esphome/components/lvgl/types.py +1 -1
  366. esphome/components/lvgl/widgets/__init__.py +2 -2
  367. esphome/components/lvgl/widgets/arc.py +14 -11
  368. esphome/components/lvgl/widgets/buttonmatrix.py +1 -1
  369. esphome/components/lvgl/widgets/qrcode.py +7 -7
  370. esphome/components/lvgl/widgets/spinner.py +6 -6
  371. esphome/components/lvgl/widgets/switch.py +2 -2
  372. esphome/components/lvgl/widgets/tabview.py +3 -3
  373. esphome/components/lvgl/widgets/tileview.py +15 -7
  374. esphome/components/m5stack_8angle/m5stack_8angle.cpp +0 -1
  375. esphome/components/matrix_keypad/__init__.py +4 -3
  376. esphome/components/max17043/max17043.cpp +0 -2
  377. esphome/components/max31855/max31855.cpp +1 -4
  378. esphome/components/max31856/max31856.cpp +0 -4
  379. esphome/components/max31865/max31865.cpp +0 -1
  380. esphome/components/max44009/max44009.cpp +0 -1
  381. esphome/components/max6675/max6675.cpp +1 -4
  382. esphome/components/max6956/max6956.cpp +0 -1
  383. esphome/components/max7219/max7219.cpp +0 -1
  384. esphome/components/max7219digit/display.py +1 -1
  385. esphome/components/max7219digit/max7219digit.cpp +0 -1
  386. esphome/components/max9611/max9611.cpp +0 -1
  387. esphome/components/mcp23008/__init__.py +1 -1
  388. esphome/components/mcp23008/mcp23008.cpp +0 -1
  389. esphome/components/mcp23016/mcp23016.cpp +0 -1
  390. esphome/components/mcp23017/__init__.py +1 -1
  391. esphome/components/mcp23017/mcp23017.cpp +0 -1
  392. esphome/components/mcp23s08/__init__.py +1 -1
  393. esphome/components/mcp23s08/mcp23s08.cpp +0 -1
  394. esphome/components/mcp23s17/__init__.py +1 -1
  395. esphome/components/mcp23s17/mcp23s17.cpp +0 -1
  396. esphome/components/mcp23x08_base/__init__.py +2 -0
  397. esphome/components/mcp23x08_base/mcp23x08_base.cpp +9 -7
  398. esphome/components/mcp23x08_base/mcp23x08_base.h +9 -4
  399. esphome/components/mcp23x17_base/__init__.py +2 -0
  400. esphome/components/mcp23x17_base/mcp23x17_base.cpp +20 -7
  401. esphome/components/mcp23x17_base/mcp23x17_base.h +9 -4
  402. esphome/components/mcp23xxx_base/__init__.py +11 -5
  403. esphome/components/mcp23xxx_base/mcp23xxx_base.cpp +15 -12
  404. esphome/components/mcp23xxx_base/mcp23xxx_base.h +8 -7
  405. esphome/components/mcp3008/mcp3008.cpp +1 -4
  406. esphome/components/mcp3204/mcp3204.cpp +1 -4
  407. esphome/components/mcp4461/mcp4461.cpp +0 -1
  408. esphome/components/mcp4725/mcp4725.cpp +0 -1
  409. esphome/components/mcp4728/mcp4728.cpp +0 -1
  410. esphome/components/mcp9600/mcp9600.cpp +0 -2
  411. esphome/components/mcp9808/mcp9808.cpp +0 -2
  412. esphome/components/mdns/__init__.py +3 -0
  413. esphome/components/mdns/mdns_component.cpp +2 -0
  414. esphome/components/mdns/mdns_component.h +4 -0
  415. esphome/components/media_player/__init__.py +40 -0
  416. esphome/components/media_player/automation.h +16 -0
  417. esphome/components/media_player/media_player.cpp +13 -0
  418. esphome/components/media_player/media_player.h +50 -3
  419. esphome/components/micro_wake_word/micro_wake_word.cpp +0 -3
  420. esphome/components/mics_4514/mics_4514.cpp +1 -6
  421. esphome/components/midea/ir_transmitter.h +4 -4
  422. esphome/components/mipi/__init__.py +416 -0
  423. esphome/components/mipi_dsi/__init__.py +5 -0
  424. esphome/components/mipi_dsi/display.py +233 -0
  425. esphome/components/mipi_dsi/mipi_dsi.cpp +379 -0
  426. esphome/components/mipi_dsi/mipi_dsi.h +123 -0
  427. esphome/components/mipi_dsi/models/__init__.py +0 -0
  428. esphome/components/mipi_dsi/models/guition.py +38 -0
  429. esphome/components/mipi_dsi/models/m5stack.py +57 -0
  430. esphome/components/mipi_dsi/models/waveshare.py +105 -0
  431. esphome/components/mipi_rgb/models/lilygo.py +0 -0
  432. esphome/components/mipi_spi/__init__.py +0 -9
  433. esphome/components/mipi_spi/display.py +220 -256
  434. esphome/components/mipi_spi/mipi_spi.cpp +1 -485
  435. esphome/components/mipi_spi/mipi_spi.h +556 -108
  436. esphome/components/mipi_spi/models/__init__.py +0 -65
  437. esphome/components/mipi_spi/models/adafruit.py +30 -0
  438. esphome/components/mipi_spi/models/amoled.py +41 -5
  439. esphome/components/mipi_spi/models/ili.py +5 -5
  440. esphome/components/mipi_spi/models/jc.py +1 -3
  441. esphome/components/mipi_spi/models/lilygo.py +1 -1
  442. esphome/components/mipi_spi/models/waveshare.py +16 -1
  443. esphome/components/mixer/speaker/__init__.py +4 -5
  444. esphome/components/mlx90393/sensor.py +7 -5
  445. esphome/components/mlx90393/sensor_mlx90393.cpp +0 -1
  446. esphome/components/mlx90614/mlx90614.cpp +0 -1
  447. esphome/components/mmc5603/mmc5603.cpp +0 -1
  448. esphome/components/mmc5983/mmc5983.cpp +0 -2
  449. esphome/components/mpl3115a2/mpl3115a2.cpp +0 -2
  450. esphome/components/mpr121/__init__.py +7 -6
  451. esphome/components/mpr121/mpr121.cpp +0 -1
  452. esphome/components/mpu6050/mpu6050.cpp +0 -1
  453. esphome/components/mpu6886/mpu6886.cpp +0 -1
  454. esphome/components/mqtt/__init__.py +1 -2
  455. esphome/components/mqtt/mqtt_button.cpp +1 -1
  456. esphome/components/mqtt/mqtt_client.cpp +0 -1
  457. esphome/components/mqtt/mqtt_component.cpp +8 -14
  458. esphome/components/mqtt/mqtt_component.h +0 -7
  459. esphome/components/mqtt/mqtt_sensor.cpp +0 -1
  460. esphome/components/mqtt/mqtt_sensor.h +0 -1
  461. esphome/components/mqtt/mqtt_text_sensor.cpp +0 -1
  462. esphome/components/mqtt/mqtt_text_sensor.h +0 -1
  463. esphome/components/ms5611/ms5611.cpp +0 -1
  464. esphome/components/ms8607/ms8607.cpp +0 -1
  465. esphome/components/msa3xx/msa3xx.cpp +0 -2
  466. esphome/components/my9231/my9231.cpp +0 -2
  467. esphome/components/nau7802/nau7802.cpp +0 -1
  468. esphome/components/neopixelbus/light.py +3 -0
  469. esphome/components/network/util.cpp +29 -0
  470. esphome/components/nextion/nextion.cpp +2 -2
  471. esphome/components/nfc/binary_sensor/{binary_sensor.cpp → nfc_binary_sensor.cpp} +1 -1
  472. esphome/components/npi19/npi19.cpp +0 -2
  473. esphome/components/nrf52/__init__.py +223 -0
  474. esphome/components/nrf52/boards.py +34 -0
  475. esphome/components/nrf52/const.py +18 -0
  476. esphome/components/nrf52/gpio.py +79 -0
  477. esphome/components/number/__init__.py +2 -1
  478. esphome/components/one_wire/__init__.py +1 -2
  479. esphome/components/one_wire/one_wire.cpp +0 -2
  480. esphome/components/one_wire/one_wire.h +0 -2
  481. esphome/components/opentherm/hub.cpp +0 -1
  482. esphome/components/opentherm/number/__init__.py +2 -2
  483. esphome/components/openthread/__init__.py +2 -3
  484. esphome/components/openthread/openthread.cpp +30 -13
  485. esphome/components/openthread/openthread.h +3 -0
  486. esphome/components/openthread/openthread_esp.cpp +3 -1
  487. esphome/components/opt3001/sensor.py +2 -6
  488. esphome/components/output/__init__.py +38 -0
  489. esphome/components/output/automation.h +24 -0
  490. esphome/components/output/switch/output_switch.cpp +0 -2
  491. esphome/components/packages/__init__.py +1 -2
  492. esphome/components/packet_transport/__init__.py +4 -3
  493. esphome/components/pca6416a/pca6416a.cpp +0 -1
  494. esphome/components/pca9554/pca9554.cpp +0 -1
  495. esphome/components/pca9685/pca9685_output.cpp +0 -2
  496. esphome/components/pcf85063/pcf85063.cpp +0 -1
  497. esphome/components/pcf8563/pcf8563.cpp +0 -1
  498. esphome/components/pcf8574/pcf8574.cpp +0 -1
  499. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +0 -1
  500. esphome/components/pipsolar/pipsolar.cpp +54 -42
  501. esphome/components/pipsolar/pipsolar.h +5 -4
  502. esphome/components/pipsolar/sensor/__init__.py +1 -1
  503. esphome/components/pm2005/pm2005.cpp +0 -1
  504. esphome/components/pmsa003i/pmsa003i.cpp +0 -2
  505. esphome/components/pmwcs3/sensor.py +1 -2
  506. esphome/components/pn532/pn532.cpp +0 -2
  507. esphome/components/pn532_spi/pn532_spi.cpp +0 -2
  508. esphome/components/power_supply/power_supply.cpp +7 -10
  509. esphome/components/power_supply/power_supply.h +1 -1
  510. esphome/components/psram/__init__.py +6 -1
  511. esphome/components/pulse_counter/pulse_counter_sensor.cpp +0 -1
  512. esphome/components/pulse_counter/sensor.py +9 -6
  513. esphome/components/pylontech/pylontech.cpp +0 -1
  514. esphome/components/qmc5883l/qmc5883l.cpp +0 -1
  515. esphome/components/qmp6988/qmp6988.cpp +0 -2
  516. esphome/components/qspi_dbi/display.py +2 -3
  517. esphome/components/qspi_dbi/qspi_dbi.cpp +0 -2
  518. esphome/components/qwiic_pir/binary_sensor.py +2 -3
  519. esphome/components/qwiic_pir/qwiic_pir.cpp +0 -2
  520. esphome/components/rc522/rc522.cpp +9 -31
  521. esphome/components/rc522_spi/rc522_spi.cpp +0 -1
  522. esphome/components/remote_base/__init__.py +5 -6
  523. esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -1
  524. esphome/components/remote_receiver/remote_receiver_esp8266.cpp +0 -1
  525. esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -1
  526. esphome/components/remote_transmitter/__init__.py +26 -0
  527. esphome/components/remote_transmitter/automation.h +18 -0
  528. esphome/components/remote_transmitter/remote_transmitter.h +2 -1
  529. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -1
  530. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +2 -0
  531. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +2 -0
  532. esphome/components/resampler/speaker/__init__.py +4 -5
  533. esphome/components/rf_bridge/__init__.py +4 -8
  534. esphome/components/rotary_encoder/rotary_encoder.cpp +0 -2
  535. esphome/components/rp2040/__init__.py +3 -1
  536. esphome/components/rp2040_pio_led_strip/led_strip.cpp +0 -2
  537. esphome/components/rp2040_pio_led_strip/light.py +1 -2
  538. esphome/components/rp2040_pwm/rp2040_pwm.cpp +1 -5
  539. esphome/components/rpi_dpi_rgb/display.py +13 -15
  540. esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -3
  541. esphome/components/runtime_stats/__init__.py +34 -0
  542. esphome/components/runtime_stats/runtime_stats.cpp +102 -0
  543. esphome/components/runtime_stats/runtime_stats.h +132 -0
  544. esphome/components/scd30/scd30.cpp +0 -2
  545. esphome/components/scd30/sensor.py +1 -2
  546. esphome/components/scd4x/scd4x.cpp +0 -1
  547. esphome/components/scd4x/sensor.py +1 -3
  548. esphome/components/sdl/display.py +3 -1
  549. esphome/components/sdl/sdl_esphome.cpp +0 -2
  550. esphome/components/sdp3x/sdp3x.cpp +0 -2
  551. esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp +0 -2
  552. esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp +0 -3
  553. esphome/components/select/__init__.py +2 -3
  554. esphome/components/select/select_traits.cpp +1 -1
  555. esphome/components/select/select_traits.h +1 -1
  556. esphome/components/sen0321/sen0321.cpp +0 -1
  557. esphome/components/sen5x/sen5x.cpp +0 -2
  558. esphome/components/senseair/senseair.cpp +7 -3
  559. esphome/components/senseair/senseair.h +11 -0
  560. esphome/components/sensor/__init__.py +36 -4
  561. esphome/components/sensor/filter.cpp +49 -10
  562. esphome/components/sensor/filter.h +22 -7
  563. esphome/components/sensor/sensor.cpp +0 -1
  564. esphome/components/sensor/sensor.h +0 -9
  565. esphome/components/sfa30/sfa30.cpp +0 -4
  566. esphome/components/sgp30/sgp30.cpp +0 -2
  567. esphome/components/sgp4x/sensor.py +1 -1
  568. esphome/components/sgp4x/sgp4x.cpp +0 -2
  569. esphome/components/shelly_dimmer/shelly_dimmer.cpp +0 -2
  570. esphome/components/sht3xd/sht3xd.cpp +0 -2
  571. esphome/components/sht4x/sht4x.cpp +0 -2
  572. esphome/components/shtcx/shtcx.cpp +0 -1
  573. esphome/components/sim800l/__init__.py +2 -4
  574. esphome/components/sm16716/sm16716.cpp +0 -1
  575. esphome/components/sm2135/sm2135.cpp +0 -1
  576. esphome/components/sm2235/sm2235.cpp +0 -1
  577. esphome/components/sm2335/sm2335.cpp +0 -1
  578. esphome/components/sn74hc165/sn74hc165.cpp +0 -1
  579. esphome/components/sn74hc595/sn74hc595.cpp +0 -1
  580. esphome/components/sntp/sntp_component.cpp +0 -1
  581. esphome/components/sound_level/sensor.py +1 -1
  582. esphome/components/speaker/media_player/__init__.py +21 -33
  583. esphome/components/speaker/media_player/audio_pipeline.cpp +4 -7
  584. esphome/components/spi/__init__.py +29 -13
  585. esphome/components/spi/spi.cpp +0 -2
  586. esphome/components/spi_device/spi_device.cpp +1 -4
  587. esphome/components/sprinkler/__init__.py +4 -4
  588. esphome/components/sps30/sps30.cpp +0 -1
  589. esphome/components/ssd1306_base/__init__.py +11 -11
  590. esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
  591. esphome/components/ssd1306_i2c/ssd1306_i2c.cpp +0 -1
  592. esphome/components/ssd1306_spi/ssd1306_spi.cpp +0 -1
  593. esphome/components/ssd1322_spi/ssd1322_spi.cpp +0 -1
  594. esphome/components/ssd1325_spi/ssd1325_spi.cpp +0 -1
  595. esphome/components/ssd1327_i2c/ssd1327_i2c.cpp +0 -1
  596. esphome/components/ssd1327_spi/ssd1327_spi.cpp +0 -1
  597. esphome/components/ssd1331_spi/ssd1331_spi.cpp +0 -1
  598. esphome/components/ssd1351_spi/ssd1351_spi.cpp +0 -1
  599. esphome/components/st7567_i2c/st7567_i2c.cpp +0 -1
  600. esphome/components/st7567_spi/st7567_spi.cpp +0 -1
  601. esphome/components/st7701s/display.py +10 -14
  602. esphome/components/st7701s/st7701s.cpp +0 -3
  603. esphome/components/st7735/st7735.cpp +0 -1
  604. esphome/components/st7789v/st7789v.cpp +0 -1
  605. esphome/components/st7920/st7920.cpp +0 -1
  606. esphome/components/status_led/light/status_led_light.cpp +0 -2
  607. esphome/components/status_led/status_led.cpp +0 -1
  608. esphome/components/stepper/__init__.py +2 -4
  609. esphome/components/sts3x/sts3x.cpp +0 -1
  610. esphome/components/substitutions/__init__.py +10 -16
  611. esphome/components/substitutions/jinja.py +24 -1
  612. esphome/components/sun/__init__.py +2 -3
  613. esphome/components/switch/__init__.py +31 -1
  614. esphome/components/switch/automation.h +24 -0
  615. esphome/components/switch/switch.cpp +8 -0
  616. esphome/components/switch/switch.h +8 -0
  617. esphome/components/sx126x/sx126x.cpp +0 -2
  618. esphome/components/sx127x/sx127x.cpp +0 -2
  619. esphome/components/sx1509/__init__.py +7 -5
  620. esphome/components/sx1509/output/sx1509_float_output.cpp +1 -1
  621. esphome/components/sx1509/sx1509.cpp +0 -2
  622. esphome/components/syslog/esphome_syslog.cpp +1 -1
  623. esphome/components/tc74/tc74.cpp +0 -1
  624. esphome/components/tca9548a/tca9548a.cpp +0 -1
  625. esphome/components/tca9555/tca9555.cpp +0 -1
  626. esphome/components/tcs34725/tcs34725.cpp +0 -1
  627. esphome/components/tee501/tee501.cpp +0 -1
  628. esphome/components/tem3200/tem3200.cpp +0 -2
  629. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +0 -1
  630. esphome/components/template/cover/template_cover.cpp +0 -1
  631. esphome/components/template/select/template_select.cpp +0 -1
  632. esphome/components/template/text/template_text.cpp +0 -2
  633. esphome/components/template/valve/template_valve.cpp +0 -1
  634. esphome/components/text/__init__.py +0 -1
  635. esphome/components/text/text_traits.h +2 -0
  636. esphome/components/text_sensor/__init__.py +2 -1
  637. esphome/components/text_sensor/text_sensor.cpp +0 -2
  638. esphome/components/text_sensor/text_sensor.h +0 -8
  639. esphome/components/thermostat/climate.py +4 -4
  640. esphome/components/time/__init__.py +7 -4
  641. esphome/components/time/real_time_clock.cpp +16 -3
  642. esphome/components/tlc59208f/tlc59208f_output.cpp +0 -2
  643. esphome/components/tlc5947/tlc5947.cpp +0 -2
  644. esphome/components/tlc5971/tlc5971.cpp +0 -2
  645. esphome/components/tm1621/tm1621.cpp +0 -2
  646. esphome/components/tm1637/tm1637.cpp +0 -2
  647. esphome/components/tm1638/tm1638.cpp +0 -2
  648. esphome/components/tm1651/__init__.py +45 -48
  649. esphome/components/tm1651/tm1651.cpp +213 -47
  650. esphome/components/tm1651/tm1651.h +37 -32
  651. esphome/components/tmp117/tmp117.cpp +0 -2
  652. esphome/components/tsl2561/tsl2561.cpp +0 -1
  653. esphome/components/tsl2591/tsl2591.cpp +0 -1
  654. esphome/components/tt21100/touchscreen/tt21100.cpp +0 -2
  655. esphome/components/ttp229_bsf/ttp229_bsf.cpp +0 -1
  656. esphome/components/ttp229_lsf/ttp229_lsf.cpp +0 -1
  657. esphome/components/tuya/climate/__init__.py +9 -10
  658. esphome/components/tuya/number/__init__.py +8 -6
  659. esphome/components/tx20/tx20.cpp +0 -1
  660. esphome/components/uart/uart_component_esp32_arduino.cpp +0 -1
  661. esphome/components/uart/uart_component_esp8266.cpp +0 -1
  662. esphome/components/uart/uart_component_esp_idf.cpp +0 -2
  663. esphome/components/uart/uart_component_libretiny.cpp +0 -2
  664. esphome/components/uart/uart_component_rp2040.cpp +0 -2
  665. esphome/components/udp/__init__.py +1 -1
  666. esphome/components/ufire_ec/sensor.py +1 -2
  667. esphome/components/ufire_ec/ufire_ec.cpp +0 -2
  668. esphome/components/ufire_ise/sensor.py +1 -2
  669. esphome/components/ufire_ise/ufire_ise.cpp +0 -2
  670. esphome/components/ultrasonic/ultrasonic_sensor.cpp +0 -1
  671. esphome/components/update/__init__.py +0 -1
  672. esphome/components/uptime/sensor/uptime_seconds_sensor.cpp +0 -1
  673. esphome/components/uptime/sensor/uptime_seconds_sensor.h +0 -2
  674. esphome/components/usb_host/usb_host_client.cpp +0 -1
  675. esphome/components/usb_host/usb_host_component.cpp +0 -1
  676. esphome/components/valve/__init__.py +0 -1
  677. esphome/components/veml3235/veml3235.cpp +0 -3
  678. esphome/components/veml7700/veml7700.cpp +0 -2
  679. esphome/components/version/version_text_sensor.cpp +0 -1
  680. esphome/components/version/version_text_sensor.h +0 -1
  681. esphome/components/vl53l0x/vl53l0x_sensor.cpp +0 -4
  682. esphome/components/voice_assistant/voice_assistant.cpp +9 -8
  683. esphome/components/web_server/__init__.py +13 -0
  684. esphome/components/web_server/web_server.cpp +188 -353
  685. esphome/components/web_server/web_server.h +61 -1
  686. esphome/components/web_server_base/__init__.py +1 -1
  687. esphome/components/web_server_base/web_server_base.cpp +2 -0
  688. esphome/components/web_server_base/web_server_base.h +6 -0
  689. esphome/components/web_server_idf/web_server_idf.cpp +10 -8
  690. esphome/components/web_server_idf/web_server_idf.h +2 -0
  691. esphome/components/weikai_i2c/weikai_i2c.cpp +1 -2
  692. esphome/components/weikai_spi/weikai_spi.cpp +1 -1
  693. esphome/components/wifi/__init__.py +17 -43
  694. esphome/components/wifi/wifi_component.cpp +100 -36
  695. esphome/components/wifi/wifi_component.h +5 -1
  696. esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -0
  697. esphome/components/wifi/wifi_component_esp_idf.cpp +30 -0
  698. esphome/components/wifi_info/wifi_info_text_sensor.h +0 -6
  699. esphome/components/wifi_signal/wifi_signal_sensor.h +0 -1
  700. esphome/components/wireguard/wireguard.cpp +0 -2
  701. esphome/components/x9c/x9c.cpp +0 -2
  702. esphome/components/xgzp68xx/xgzp68xx.cpp +0 -1
  703. esphome/components/xl9535/xl9535.cpp +0 -2
  704. esphome/components/zephyr/__init__.py +252 -0
  705. esphome/components/zephyr/const.py +16 -0
  706. esphome/components/zephyr/core.cpp +90 -0
  707. esphome/components/zephyr/gpio.cpp +120 -0
  708. esphome/components/zephyr/gpio.h +38 -0
  709. esphome/components/zephyr/pre_build.py.script +4 -0
  710. esphome/components/zephyr/preferences.cpp +156 -0
  711. esphome/components/zephyr/preferences.h +13 -0
  712. esphome/config.py +38 -16
  713. esphome/config_helpers.py +1 -2
  714. esphome/config_validation.py +12 -16
  715. esphome/const.py +26 -1
  716. esphome/core/__init__.py +92 -51
  717. esphome/core/application.cpp +75 -21
  718. esphome/core/application.h +106 -171
  719. esphome/core/color.h +10 -0
  720. esphome/core/component.cpp +41 -25
  721. esphome/core/component.h +9 -6
  722. esphome/core/component_iterator.cpp +61 -261
  723. esphome/core/component_iterator.h +15 -0
  724. esphome/core/config.py +26 -11
  725. esphome/core/defines.h +40 -2
  726. esphome/core/entity_base.h +18 -0
  727. esphome/core/entity_helpers.py +45 -10
  728. esphome/core/helpers.cpp +8 -15
  729. esphome/core/helpers.h +60 -6
  730. esphome/core/lock_free_queue.h +1 -1
  731. esphome/core/scheduler.cpp +311 -77
  732. esphome/core/scheduler.h +141 -28
  733. esphome/cpp_generator.py +2 -6
  734. esphome/cpp_helpers.py +1 -1
  735. esphome/dashboard/dashboard.py +2 -3
  736. esphome/dashboard/dns.py +2 -8
  737. esphome/dashboard/web_server.py +34 -19
  738. esphome/espota2.py +1 -4
  739. esphome/git.py +3 -1
  740. esphome/helpers.py +23 -4
  741. esphome/log.py +3 -1
  742. esphome/mqtt.py +3 -5
  743. esphome/platformio_api.py +7 -4
  744. esphome/types.py +12 -0
  745. esphome/util.py +20 -8
  746. esphome/voluptuous_schema.py +4 -3
  747. esphome/vscode.py +1 -2
  748. esphome/wizard.py +1 -4
  749. esphome/writer.py +16 -108
  750. esphome/yaml_util.py +7 -5
  751. {esphome-2025.7.4.dist-info → esphome-2025.8.0.dist-info}/METADATA +13 -14
  752. {esphome-2025.7.4.dist-info → esphome-2025.8.0.dist-info}/RECORD +757 -677
  753. esphome/components/mipi_spi/models/commands.py +0 -82
  754. /esphome/components/nfc/binary_sensor/{binary_sensor.h → nfc_binary_sensor.h} +0 -0
  755. {esphome-2025.7.4.dist-info → esphome-2025.8.0.dist-info}/WHEEL +0 -0
  756. {esphome-2025.7.4.dist-info → esphome-2025.8.0.dist-info}/entry_points.txt +0 -0
  757. {esphome-2025.7.4.dist-info → esphome-2025.8.0.dist-info}/licenses/LICENSE +0 -0
  758. {esphome-2025.7.4.dist-info → esphome-2025.8.0.dist-info}/top_level.txt +0 -0
esphome/core/scheduler.h CHANGED
@@ -1,9 +1,13 @@
1
1
  #pragma once
2
2
 
3
+ #include "esphome/core/defines.h"
3
4
  #include <vector>
4
5
  #include <memory>
5
6
  #include <cstring>
6
7
  #include <deque>
8
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
9
+ #include <atomic>
10
+ #endif
7
11
 
8
12
  #include "esphome/core/component.h"
9
13
  #include "esphome/core/helpers.h"
@@ -11,8 +15,15 @@
11
15
  namespace esphome {
12
16
 
13
17
  class Component;
18
+ struct RetryArgs;
19
+
20
+ // Forward declaration of retry_handler - needs to be non-static for friend declaration
21
+ void retry_handler(const std::shared_ptr<RetryArgs> &args);
14
22
 
15
23
  class Scheduler {
24
+ // Allow retry_handler to access protected members
25
+ friend void ::esphome::retry_handler(const std::shared_ptr<RetryArgs> &args);
26
+
16
27
  public:
17
28
  // Public API - accepts std::string for backward compatibility
18
29
  void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function<void()> func);
@@ -50,11 +61,21 @@ class Scheduler {
50
61
  bool cancel_interval(Component *component, const char *name);
51
62
  void set_retry(Component *component, const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts,
52
63
  std::function<RetryResult(uint8_t)> func, float backoff_increase_factor = 1.0f);
64
+ void set_retry(Component *component, const char *name, uint32_t initial_wait_time, uint8_t max_attempts,
65
+ std::function<RetryResult(uint8_t)> func, float backoff_increase_factor = 1.0f);
53
66
  bool cancel_retry(Component *component, const std::string &name);
67
+ bool cancel_retry(Component *component, const char *name);
54
68
 
55
- optional<uint32_t> next_schedule_in();
69
+ // Calculate when the next scheduled item should run
70
+ // @param now Fresh timestamp from millis() - must not be stale/cached
71
+ // Returns the time in milliseconds until the next scheduled item, or nullopt if no items
72
+ // This method performs cleanup of removed items before checking the schedule
73
+ // IMPORTANT: This method should only be called from the main thread (loop task).
74
+ optional<uint32_t> next_schedule_in(uint32_t now);
56
75
 
57
- void call();
76
+ // Execute all scheduled items that are ready
77
+ // @param now Fresh timestamp from millis() - must not be stale/cached
78
+ void call(uint32_t now);
58
79
 
59
80
  void process_to_add();
60
81
 
@@ -76,15 +97,42 @@ class Scheduler {
76
97
 
77
98
  std::function<void()> callback;
78
99
 
79
- // Bit-packed fields to minimize padding
100
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
101
+ // Multi-threaded with atomics: use atomic for lock-free access
102
+ // Place atomic<bool> separately since it can't be packed with bit fields
103
+ std::atomic<bool> remove{false};
104
+
105
+ // Bit-packed fields (3 bits used, 5 bits padding in 1 byte)
106
+ enum Type : uint8_t { TIMEOUT, INTERVAL } type : 1;
107
+ bool name_is_dynamic : 1; // True if name was dynamically allocated (needs delete[])
108
+ bool is_retry : 1; // True if this is a retry timeout
109
+ // 5 bits padding
110
+ #else
111
+ // Single-threaded or multi-threaded without atomics: can pack all fields together
112
+ // Bit-packed fields (4 bits used, 4 bits padding in 1 byte)
80
113
  enum Type : uint8_t { TIMEOUT, INTERVAL } type : 1;
81
114
  bool remove : 1;
82
115
  bool name_is_dynamic : 1; // True if name was dynamically allocated (needs delete[])
83
- // 5 bits padding
116
+ bool is_retry : 1; // True if this is a retry timeout
117
+ // 4 bits padding
118
+ #endif
84
119
 
85
120
  // Constructor
86
121
  SchedulerItem()
87
- : component(nullptr), interval(0), next_execution_(0), type(TIMEOUT), remove(false), name_is_dynamic(false) {
122
+ : component(nullptr),
123
+ interval(0),
124
+ next_execution_(0),
125
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
126
+ // remove is initialized in the member declaration as std::atomic<bool>{false}
127
+ type(TIMEOUT),
128
+ name_is_dynamic(false),
129
+ is_retry(false) {
130
+ #else
131
+ type(TIMEOUT),
132
+ remove(false),
133
+ name_is_dynamic(false),
134
+ is_retry(false) {
135
+ #endif
88
136
  name_.static_name = nullptr;
89
137
  }
90
138
 
@@ -136,15 +184,22 @@ class Scheduler {
136
184
 
137
185
  // Common implementation for both timeout and interval
138
186
  void set_timer_common_(Component *component, SchedulerItem::Type type, bool is_static_string, const void *name_ptr,
139
- uint32_t delay, std::function<void()> func);
187
+ uint32_t delay, std::function<void()> func, bool is_retry = false);
140
188
 
141
- uint64_t millis_();
142
- void cleanup_();
189
+ // Common implementation for retry
190
+ void set_retry_common_(Component *component, bool is_static_string, const void *name_ptr, uint32_t initial_wait_time,
191
+ uint8_t max_attempts, std::function<RetryResult(uint8_t)> func, float backoff_increase_factor);
192
+
193
+ uint64_t millis_64_(uint32_t now);
194
+ // Cleanup logically deleted items from the scheduler
195
+ // Returns the number of items remaining after cleanup
196
+ // IMPORTANT: This method should only be called from the main thread (loop task).
197
+ size_t cleanup_();
143
198
  void pop_raw_();
144
199
 
145
200
  private:
146
201
  // Helper to cancel items by name - must be called with lock held
147
- bool cancel_item_locked_(Component *component, const char *name, SchedulerItem::Type type);
202
+ bool cancel_item_locked_(Component *component, const char *name, SchedulerItem::Type type, bool match_retry = false);
148
203
 
149
204
  // Helper to extract name as const char* from either static string or std::string
150
205
  inline const char *get_name_cstr_(bool is_static_string, const void *name_ptr) {
@@ -156,8 +211,9 @@ class Scheduler {
156
211
 
157
212
  // Helper function to check if item matches criteria for cancellation
158
213
  inline bool HOT matches_item_(const std::unique_ptr<SchedulerItem> &item, Component *component, const char *name_cstr,
159
- SchedulerItem::Type type) {
160
- if (item->component != component || item->type != type || item->remove) {
214
+ SchedulerItem::Type type, bool match_retry, bool skip_removed = true) const {
215
+ if (item->component != component || item->type != type || (skip_removed && item->remove) ||
216
+ (match_retry && !item->is_retry)) {
161
217
  return false;
162
218
  }
163
219
  const char *item_name = item->get_name();
@@ -176,37 +232,94 @@ class Scheduler {
176
232
  }
177
233
 
178
234
  // Helper to execute a scheduler item
179
- void execute_item_(SchedulerItem *item);
235
+ void execute_item_(SchedulerItem *item, uint32_t now);
180
236
 
181
237
  // Helper to check if item should be skipped
182
238
  bool should_skip_item_(const SchedulerItem *item) const {
183
239
  return item->remove || (item->component != nullptr && item->component->is_failed());
184
240
  }
185
241
 
186
- // Check if the scheduler has no items.
187
- // IMPORTANT: This method should only be called from the main thread (loop task).
188
- // It performs cleanup of removed items and checks if the queue is empty.
189
- // The items_.empty() check at the end is done without a lock for performance,
190
- // which is safe because this is only called from the main thread while other
191
- // threads only add items (never remove them).
192
- bool empty_() {
193
- this->cleanup_();
194
- return this->items_.empty();
242
+ // Helper to check if item is marked for removal (platform-specific)
243
+ // Returns true if item should be skipped, handles platform-specific synchronization
244
+ // For ESPHOME_THREAD_MULTI_NO_ATOMICS platforms, the caller must hold the scheduler lock before calling this
245
+ // function.
246
+ bool is_item_removed_(SchedulerItem *item) const {
247
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
248
+ // Multi-threaded with atomics: use atomic load for lock-free access
249
+ return item->remove.load(std::memory_order_acquire);
250
+ #else
251
+ // Single-threaded (ESPHOME_THREAD_SINGLE) or
252
+ // multi-threaded without atomics (ESPHOME_THREAD_MULTI_NO_ATOMICS): direct read
253
+ // For ESPHOME_THREAD_MULTI_NO_ATOMICS, caller MUST hold lock!
254
+ return item->remove;
255
+ #endif
256
+ }
257
+
258
+ // Helper to mark item for removal (platform-specific)
259
+ // For ESPHOME_THREAD_MULTI_NO_ATOMICS platforms, the caller must hold the scheduler lock before calling this
260
+ // function.
261
+ void mark_item_removed_(SchedulerItem *item) {
262
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
263
+ // Multi-threaded with atomics: use atomic store
264
+ item->remove.store(true, std::memory_order_release);
265
+ #else
266
+ // Single-threaded (ESPHOME_THREAD_SINGLE) or
267
+ // multi-threaded without atomics (ESPHOME_THREAD_MULTI_NO_ATOMICS): direct write
268
+ // For ESPHOME_THREAD_MULTI_NO_ATOMICS, caller MUST hold lock!
269
+ item->remove = true;
270
+ #endif
271
+ }
272
+
273
+ // Template helper to check if any item in a container matches our criteria
274
+ template<typename Container>
275
+ bool has_cancelled_timeout_in_container_(const Container &container, Component *component, const char *name_cstr,
276
+ bool match_retry) const {
277
+ for (const auto &item : container) {
278
+ if (item->remove && this->matches_item_(item, component, name_cstr, SchedulerItem::TIMEOUT, match_retry,
279
+ /* skip_removed= */ false)) {
280
+ return true;
281
+ }
282
+ }
283
+ return false;
195
284
  }
196
285
 
197
286
  Mutex lock_;
198
287
  std::vector<std::unique_ptr<SchedulerItem>> items_;
199
288
  std::vector<std::unique_ptr<SchedulerItem>> to_add_;
200
- #if !defined(USE_ESP8266) && !defined(USE_RP2040)
201
- // ESP8266 and RP2040 don't need the defer queue because:
202
- // ESP8266: Single-core with no preemptive multitasking
203
- // RP2040: Currently has empty mutex implementation in ESPHome
204
- // Both platforms save 40 bytes of RAM by excluding this
289
+ #ifndef ESPHOME_THREAD_SINGLE
290
+ // Single-core platforms don't need the defer queue and save 40 bytes of RAM
205
291
  std::deque<std::unique_ptr<SchedulerItem>> defer_queue_; // FIFO queue for defer() calls
206
- #endif
292
+ #endif /* ESPHOME_THREAD_SINGLE */
293
+ uint32_t to_remove_{0};
294
+
295
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
296
+ /*
297
+ * Multi-threaded platforms with atomic support: last_millis_ needs atomic for lock-free updates
298
+ *
299
+ * MEMORY-ORDERING NOTE
300
+ * --------------------
301
+ * `last_millis_` and `millis_major_` form a single 64-bit timestamp split in half.
302
+ * Writers publish `last_millis_` with memory_order_release and readers use
303
+ * memory_order_acquire. This ensures that once a reader sees the new low word,
304
+ * it also observes the corresponding increment of `millis_major_`.
305
+ */
306
+ std::atomic<uint32_t> last_millis_{0};
307
+ #else /* not ESPHOME_THREAD_MULTI_ATOMICS */
308
+ // Platforms without atomic support or single-threaded platforms
207
309
  uint32_t last_millis_{0};
310
+ #endif /* else ESPHOME_THREAD_MULTI_ATOMICS */
311
+
312
+ /*
313
+ * Upper 16 bits of the 64-bit millis counter. Incremented only while holding
314
+ * `lock_`; read concurrently. Atomic (relaxed) avoids a formal data race.
315
+ * Ordering relative to `last_millis_` is provided by its release store and the
316
+ * corresponding acquire loads.
317
+ */
318
+ #ifdef ESPHOME_THREAD_MULTI_ATOMICS
319
+ std::atomic<uint16_t> millis_major_{0};
320
+ #else /* not ESPHOME_THREAD_MULTI_ATOMICS */
208
321
  uint16_t millis_major_{0};
209
- uint32_t to_remove_{0};
322
+ #endif /* else ESPHOME_THREAD_MULTI_ATOMICS */
210
323
  };
211
324
 
212
325
  } // namespace esphome
esphome/cpp_generator.py CHANGED
@@ -771,8 +771,7 @@ class MockObj(Expression):
771
771
  if attr.startswith("P") and self.op not in ["::", ""]:
772
772
  attr = attr[1:]
773
773
  next_op = "->"
774
- if attr.startswith("_"):
775
- attr = attr[1:]
774
+ attr = attr.removeprefix("_")
776
775
  return MockObj(f"{self.base}{self.op}{attr}", next_op)
777
776
 
778
777
  def __call__(self, *args: SafeExpType) -> "MockObj":
@@ -1037,10 +1036,7 @@ class MockObjClass(MockObj):
1037
1036
  def inherits_from(self, other: "MockObjClass") -> bool:
1038
1037
  if str(self) == str(other):
1039
1038
  return True
1040
- for parent in self._parents:
1041
- if str(parent) == str(other):
1042
- return True
1043
- return False
1039
+ return any(str(parent) == str(other) for parent in self._parents)
1044
1040
 
1045
1041
  def template(self, *args: SafeExpType) -> "MockObjClass":
1046
1042
  if len(args) != 1 or not isinstance(args[0], TemplateArguments):
esphome/cpp_helpers.py CHANGED
@@ -115,7 +115,7 @@ async def build_registry_list(registry, config):
115
115
 
116
116
  async def past_safe_mode():
117
117
  if CONF_SAFE_MODE not in CORE.config:
118
- return
118
+ return None
119
119
 
120
120
  def _safe_mode_generator():
121
121
  while True:
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  from asyncio import events
5
5
  from concurrent.futures import ThreadPoolExecutor
6
+ import contextlib
6
7
  import logging
7
8
  import os
8
9
  import socket
@@ -125,10 +126,8 @@ def start_dashboard(args) -> None:
125
126
 
126
127
  asyncio.set_event_loop_policy(DashboardEventLoopPolicy(settings.verbose))
127
128
 
128
- try:
129
+ with contextlib.suppress(KeyboardInterrupt):
129
130
  asyncio.run(async_start(args))
130
- except KeyboardInterrupt:
131
- pass
132
131
 
133
132
 
134
133
  async def async_start(args) -> None:
esphome/dashboard/dns.py CHANGED
@@ -3,15 +3,9 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  from contextlib import suppress
5
5
  from ipaddress import ip_address
6
- import sys
7
6
 
8
7
  from icmplib import NameLookupError, async_resolve
9
8
 
10
- if sys.version_info >= (3, 11):
11
- from asyncio import timeout as async_timeout
12
- else:
13
- from async_timeout import timeout as async_timeout
14
-
15
9
  RESOLVE_TIMEOUT = 3.0
16
10
 
17
11
 
@@ -20,9 +14,9 @@ async def _async_resolve_wrapper(hostname: str) -> list[str] | Exception:
20
14
  with suppress(ValueError):
21
15
  return [str(ip_address(hostname))]
22
16
  try:
23
- async with async_timeout(RESOLVE_TIMEOUT):
17
+ async with asyncio.timeout(RESOLVE_TIMEOUT):
24
18
  return await async_resolve(hostname)
25
- except (asyncio.TimeoutError, NameLookupError, UnicodeError) as ex:
19
+ except (TimeoutError, NameLookupError, UnicodeError) as ex:
26
20
  return ex
27
21
 
28
22
 
@@ -144,7 +144,7 @@ def websocket_class(cls):
144
144
  if not hasattr(cls, "_message_handlers"):
145
145
  cls._message_handlers = {}
146
146
 
147
- for _, method in cls.__dict__.items():
147
+ for method in cls.__dict__.values():
148
148
  if hasattr(method, "_message_handler"):
149
149
  cls._message_handlers[method._message_handler] = method
150
150
 
@@ -229,6 +229,7 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
229
229
  stdin=subprocess.PIPE,
230
230
  stdout=subprocess.PIPE,
231
231
  stderr=subprocess.STDOUT,
232
+ close_fds=False,
232
233
  )
233
234
  stdout_thread = threading.Thread(target=self._stdout_thread)
234
235
  stdout_thread.daemon = True
@@ -324,39 +325,53 @@ class EsphomePortCommandWebSocket(EsphomeCommandWebSocket):
324
325
  configuration = json_message["configuration"]
325
326
  config_file = settings.rel_path(configuration)
326
327
  port = json_message["port"]
328
+ addresses: list[str] = []
327
329
  if (
328
330
  port == "OTA" # pylint: disable=too-many-boolean-expressions
329
331
  and (entry := entries.get(config_file))
330
332
  and entry.loaded_integrations
331
333
  and "api" in entry.loaded_integrations
332
334
  ):
333
- if (mdns := dashboard.mdns_status) and (
334
- address_list := await mdns.async_resolve_host(entry.name)
335
- ):
336
- # Use the IP address if available but only
337
- # if the API is loaded and the device is online
338
- # since MQTT logging will not work otherwise
339
- port = sort_ip_addresses(address_list)[0]
340
- elif (
341
- entry.address
335
+ # First priority: entry.address AKA use_address
336
+ if (
337
+ (use_address := entry.address)
342
338
  and (
343
339
  address_list := await dashboard.dns_cache.async_resolve(
344
- entry.address, time.monotonic()
340
+ use_address, time.monotonic()
345
341
  )
346
342
  )
347
343
  and not isinstance(address_list, Exception)
348
344
  ):
349
- # If mdns is not available, try to use the DNS cache
350
- port = sort_ip_addresses(address_list)[0]
345
+ addresses.extend(sort_ip_addresses(address_list))
351
346
 
352
- return [
353
- *DASHBOARD_COMMAND,
354
- *args,
355
- config_file,
356
- "--device",
357
- port,
347
+ # Second priority: mDNS
348
+ if (
349
+ (mdns := dashboard.mdns_status)
350
+ and (address_list := await mdns.async_resolve_host(entry.name))
351
+ and (
352
+ new_addresses := [
353
+ addr for addr in address_list if addr not in addresses
354
+ ]
355
+ )
356
+ ):
357
+ # Use the IP address if available but only
358
+ # if the API is loaded and the device is online
359
+ # since MQTT logging will not work otherwise
360
+ addresses.extend(sort_ip_addresses(new_addresses))
361
+
362
+ if not addresses:
363
+ # If no address was found, use the port directly
364
+ # as otherwise they will get the chooser which
365
+ # does not work with the dashboard as there is no
366
+ # interactive way to get keyboard input
367
+ addresses = [port]
368
+
369
+ device_args: list[str] = [
370
+ arg for address in addresses for arg in ("--device", address)
358
371
  ]
359
372
 
373
+ return [*DASHBOARD_COMMAND, *args, config_file, *device_args]
374
+
360
375
 
361
376
  class EsphomeLogsHandler(EsphomePortCommandWebSocket):
362
377
  async def build_command(self, json_message: dict[str, Any]) -> list[str]:
esphome/espota2.py CHANGED
@@ -88,10 +88,7 @@ def recv_decode(sock, amount, decode=True):
88
88
 
89
89
 
90
90
  def receive_exactly(sock, amount, msg, expect, decode=True):
91
- if decode:
92
- data = []
93
- else:
94
- data = b""
91
+ data = [] if decode else b""
95
92
 
96
93
  try:
97
94
  data += recv_decode(sock, 1, decode=decode)
esphome/git.py CHANGED
@@ -17,7 +17,9 @@ _LOGGER = logging.getLogger(__name__)
17
17
  def run_git_command(cmd, cwd=None) -> str:
18
18
  _LOGGER.debug("Running git command: %s", " ".join(cmd))
19
19
  try:
20
- ret = subprocess.run(cmd, cwd=cwd, capture_output=True, check=False)
20
+ ret = subprocess.run(
21
+ cmd, cwd=cwd, capture_output=True, check=False, close_fds=False
22
+ )
21
23
  except FileNotFoundError as err:
22
24
  raise cv.Invalid(
23
25
  "git is not installed but required for external_components.\n"
esphome/helpers.py CHANGED
@@ -9,6 +9,8 @@ import re
9
9
  import tempfile
10
10
  from urllib.parse import urlparse
11
11
 
12
+ from esphome.const import __version__ as ESPHOME_VERSION
13
+
12
14
  _LOGGER = logging.getLogger(__name__)
13
15
 
14
16
  IS_MACOS = platform.system() == "Darwin"
@@ -96,9 +98,7 @@ def cpp_string_escape(string, encoding="utf-8"):
96
98
  def _should_escape(byte: int) -> bool:
97
99
  if not 32 <= byte < 127:
98
100
  return True
99
- if byte in (ord("\\"), ord('"')):
100
- return True
101
- return False
101
+ return byte in (ord("\\"), ord('"'))
102
102
 
103
103
  if isinstance(string, str):
104
104
  string = string.encode(encoding)
@@ -114,7 +114,9 @@ def cpp_string_escape(string, encoding="utf-8"):
114
114
  def run_system_command(*args):
115
115
  import subprocess
116
116
 
117
- with subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
117
+ with subprocess.Popen(
118
+ args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False
119
+ ) as p:
118
120
  stdout, stderr = p.communicate()
119
121
  rc = p.returncode
120
122
  return rc, stdout, stderr
@@ -505,3 +507,20 @@ _DISALLOWED_CHARS = re.compile(r"[^a-zA-Z0-9-_]")
505
507
  def sanitize(value):
506
508
  """Same behaviour as `helpers.cpp` method `str_sanitize`."""
507
509
  return _DISALLOWED_CHARS.sub("_", value)
510
+
511
+
512
+ def docs_url(path: str) -> str:
513
+ """Return the URL to the documentation for a given path."""
514
+ # Local import to avoid circular import
515
+ from esphome.config_validation import Version
516
+
517
+ version = Version.parse(ESPHOME_VERSION)
518
+ if version.is_beta:
519
+ docs_format = "https://beta.esphome.io/{path}"
520
+ elif version.is_dev:
521
+ docs_format = "https://next.esphome.io/{path}"
522
+ else:
523
+ docs_format = "https://esphome.io/{path}"
524
+
525
+ path = path.removeprefix("/")
526
+ return docs_format.format(path=path)
esphome/log.py CHANGED
@@ -37,6 +37,8 @@ class AnsiStyle(Enum):
37
37
 
38
38
 
39
39
  def color(col: AnsiFore, msg: str, reset: bool = True) -> str:
40
+ if col == AnsiFore.KEEP:
41
+ return msg
40
42
  s = col.value + msg
41
43
  if reset and col:
42
44
  s += AnsiStyle.RESET_ALL.value
@@ -61,7 +63,7 @@ class ESPHomeLogFormatter(logging.Formatter):
61
63
  }.get(record.levelname, "")
62
64
  message = f"{prefix}{formatted}{AnsiStyle.RESET_ALL.value}"
63
65
  if CORE.dashboard:
64
- try:
66
+ try: # noqa: SIM105
65
67
  message = message.replace("\033", "\\033")
66
68
  except UnicodeEncodeError:
67
69
  pass
esphome/mqtt.py CHANGED
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  from datetime import datetime
2
3
  import hashlib
3
4
  import json
@@ -35,7 +36,7 @@ _LOGGER = logging.getLogger(__name__)
35
36
 
36
37
 
37
38
  def config_from_env():
38
- config = {
39
+ return {
39
40
  CONF_MQTT: {
40
41
  CONF_USERNAME: get_str_env("ESPHOME_DASHBOARD_MQTT_USERNAME"),
41
42
  CONF_PASSWORD: get_str_env("ESPHOME_DASHBOARD_MQTT_PASSWORD"),
@@ -43,7 +44,6 @@ def config_from_env():
43
44
  CONF_PORT: get_int_env("ESPHOME_DASHBOARD_MQTT_PORT", 1883),
44
45
  },
45
46
  }
46
- return config
47
47
 
48
48
 
49
49
  def initialize(
@@ -52,10 +52,8 @@ def initialize(
52
52
  client = prepare(
53
53
  config, subscriptions, on_message, on_connect, username, password, client_id
54
54
  )
55
- try:
55
+ with contextlib.suppress(KeyboardInterrupt):
56
56
  client.loop_forever()
57
- except KeyboardInterrupt:
58
- pass
59
57
  return 0
60
58
 
61
59
 
esphome/platformio_api.py CHANGED
@@ -61,6 +61,7 @@ FILTER_PLATFORMIO_LINES = [
61
61
  r"Advanced Memory Usage is available via .*",
62
62
  r"Merged .* ELF section",
63
63
  r"esptool.py v.*",
64
+ r"esptool v.*",
64
65
  r"Checking size .*",
65
66
  r"Retrieving maximum program size .*",
66
67
  r"PLATFORM: .*",
@@ -131,9 +132,11 @@ def _load_idedata(config):
131
132
  temp_idedata = Path(CORE.relative_internal_path("idedata", f"{CORE.name}.json"))
132
133
 
133
134
  changed = False
134
- if not platformio_ini.is_file() or not temp_idedata.is_file():
135
- changed = True
136
- elif platformio_ini.stat().st_mtime >= temp_idedata.stat().st_mtime:
135
+ if (
136
+ not platformio_ini.is_file()
137
+ or not temp_idedata.is_file()
138
+ or platformio_ini.stat().st_mtime >= temp_idedata.stat().st_mtime
139
+ ):
137
140
  changed = True
138
141
 
139
142
  if not changed:
@@ -208,7 +211,7 @@ def _decode_pc(config, addr):
208
211
  return
209
212
  command = [idedata.addr2line_path, "-pfiaC", "-e", idedata.firmware_elf_path, addr]
210
213
  try:
211
- translation = subprocess.check_output(command).decode().strip()
214
+ translation = subprocess.check_output(command, close_fds=False).decode().strip()
212
215
  except Exception: # pylint: disable=broad-except
213
216
  _LOGGER.debug("Caught exception for command %s", command, exc_info=1)
214
217
  return
esphome/types.py CHANGED
@@ -1,5 +1,7 @@
1
1
  """This helper module tracks commonly used types in the esphome python codebase."""
2
2
 
3
+ from typing import TypedDict
4
+
3
5
  from esphome.core import ID, EsphomeCore, Lambda
4
6
 
5
7
  ConfigFragmentType = (
@@ -16,3 +18,13 @@ ConfigFragmentType = (
16
18
  ConfigType = dict[str, ConfigFragmentType]
17
19
  CoreType = EsphomeCore
18
20
  ConfigPathType = str | int
21
+
22
+
23
+ class EntityMetadata(TypedDict):
24
+ """Metadata stored for each entity to help with duplicate detection."""
25
+
26
+ name: str
27
+ device_id: str
28
+ platform: str
29
+ entity_id: str
30
+ component: str