esphome 2025.4.2__py3-none-any.whl → 2025.5.0b3__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 (440) hide show
  1. esphome/__main__.py +16 -14
  2. esphome/components/ac_dimmer/ac_dimmer.cpp +3 -2
  3. esphome/components/adc/__init__.py +51 -34
  4. esphome/components/airthings_wave_base/__init__.py +1 -1
  5. esphome/components/alarm_control_panel/__init__.py +37 -2
  6. esphome/components/am43/cover/__init__.py +4 -5
  7. esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp +6 -4
  8. esphome/components/analog_threshold/analog_threshold_binary_sensor.h +4 -5
  9. esphome/components/analog_threshold/binary_sensor.py +10 -8
  10. esphome/components/anova/climate.py +4 -5
  11. esphome/components/api/__init__.py +25 -8
  12. esphome/components/api/api_connection.cpp +81 -13
  13. esphome/components/api/api_connection.h +13 -1
  14. esphome/components/api/api_frame_helper.cpp +232 -177
  15. esphome/components/api/api_frame_helper.h +61 -8
  16. esphome/components/api/api_noise_context.h +13 -4
  17. esphome/components/api/api_pb2.cpp +1422 -1
  18. esphome/components/api/api_pb2.h +255 -1
  19. esphome/components/api/api_pb2_service.cpp +162 -49
  20. esphome/components/api/api_pb2_service.h +90 -51
  21. esphome/components/api/api_pb2_size.h +361 -0
  22. esphome/components/api/api_server.cpp +110 -34
  23. esphome/components/api/api_server.h +8 -0
  24. esphome/components/api/proto.h +86 -17
  25. esphome/components/as7341/as7341.h +1 -1
  26. esphome/components/atm90e32/__init__.py +1 -0
  27. esphome/components/atm90e32/atm90e32.cpp +576 -199
  28. esphome/components/atm90e32/atm90e32.h +128 -31
  29. esphome/components/atm90e32/atm90e32_reg.h +4 -2
  30. esphome/components/atm90e32/button/__init__.py +62 -10
  31. esphome/components/atm90e32/button/atm90e32_button.cpp +63 -4
  32. esphome/components/atm90e32/button/atm90e32_button.h +36 -4
  33. esphome/components/atm90e32/number/__init__.py +130 -0
  34. esphome/components/atm90e32/number/atm90e32_number.h +16 -0
  35. esphome/components/atm90e32/sensor.py +21 -4
  36. esphome/components/atm90e32/text_sensor/__init__.py +48 -0
  37. esphome/components/audio/__init__.py +96 -49
  38. esphome/components/audio/audio.h +48 -0
  39. esphome/components/audio/audio_decoder.cpp +1 -1
  40. esphome/components/audio/audio_resampler.cpp +2 -0
  41. esphome/components/audio/audio_resampler.h +1 -0
  42. esphome/components/ballu/climate.py +2 -9
  43. esphome/components/bang_bang/climate.py +5 -6
  44. esphome/components/bedjet/bedjet_hub.cpp +1 -0
  45. esphome/components/bedjet/climate/__init__.py +3 -8
  46. esphome/components/bedjet/fan/__init__.py +2 -11
  47. esphome/components/binary/fan/__init__.py +13 -16
  48. esphome/components/binary_sensor/__init__.py +13 -10
  49. esphome/components/bl0906/constants.h +16 -16
  50. esphome/components/ble_client/text_sensor/__init__.py +3 -5
  51. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +4 -6
  52. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +136 -21
  53. esphome/components/bluetooth_proxy/bluetooth_proxy.h +7 -0
  54. esphome/components/button/__init__.py +11 -8
  55. esphome/components/canbus/canbus.cpp +3 -0
  56. esphome/components/canbus/canbus.h +16 -0
  57. esphome/components/ccs811/sensor.py +9 -6
  58. esphome/components/climate/__init__.py +35 -2
  59. esphome/components/climate/climate_mode.h +1 -1
  60. esphome/components/climate/climate_traits.h +63 -57
  61. esphome/components/climate_ir/__init__.py +57 -17
  62. esphome/components/climate_ir_lg/climate.py +2 -5
  63. esphome/components/climate_ir_lg/climate_ir_lg.cpp +7 -7
  64. esphome/components/climate_ir_lg/climate_ir_lg.h +1 -1
  65. esphome/components/color/__init__.py +2 -0
  66. esphome/components/const/__init__.py +5 -0
  67. esphome/components/coolix/climate.py +2 -9
  68. esphome/components/copy/cover/__init__.py +10 -9
  69. esphome/components/copy/fan/__init__.py +11 -9
  70. esphome/components/copy/lock/__init__.py +11 -9
  71. esphome/components/copy/text/__init__.py +9 -6
  72. esphome/components/cover/__init__.py +37 -2
  73. esphome/components/cse7766/cse7766.cpp +2 -1
  74. esphome/components/cst226/binary_sensor/__init__.py +28 -0
  75. esphome/components/cst226/binary_sensor/cs226_button.h +22 -0
  76. esphome/components/cst226/binary_sensor/cstt6_button.cpp +19 -0
  77. esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +27 -5
  78. esphome/components/cst226/touchscreen/cst226_touchscreen.h +10 -10
  79. esphome/components/current_based/cover.py +37 -36
  80. esphome/components/current_based/current_based_cover.cpp +2 -1
  81. esphome/components/daikin/climate.py +2 -9
  82. esphome/components/daikin/daikin.cpp +15 -9
  83. esphome/components/daikin/daikin.h +5 -5
  84. esphome/components/daikin_arc/climate.py +2 -7
  85. esphome/components/daikin_brc/climate.py +3 -5
  86. esphome/components/dallas_temp/dallas_temp.cpp +17 -24
  87. esphome/components/dallas_temp/dallas_temp.h +0 -1
  88. esphome/components/daly_bms/daly_bms.cpp +2 -1
  89. esphome/components/debug/debug_component.cpp +6 -1
  90. esphome/components/debug/debug_component.h +6 -0
  91. esphome/components/debug/debug_esp32.cpp +109 -254
  92. esphome/components/debug/sensor.py +14 -0
  93. esphome/components/deep_sleep/deep_sleep_esp32.cpp +13 -1
  94. esphome/components/delonghi/climate.py +2 -9
  95. esphome/components/demo/__init__.py +18 -20
  96. esphome/components/dfrobot_sen0395/switch/__init__.py +21 -22
  97. esphome/components/dps310/sensor.py +6 -6
  98. esphome/components/ee895/sensor.py +9 -9
  99. esphome/components/emmeti/climate.py +2 -9
  100. esphome/components/endstop/cover.py +17 -16
  101. esphome/components/endstop/endstop_cover.cpp +2 -1
  102. esphome/components/ens160_base/__init__.py +12 -9
  103. esphome/components/esp32/__init__.py +60 -3
  104. esphome/components/esp32/core.cpp +11 -5
  105. esphome/components/esp32/gpio.cpp +86 -24
  106. esphome/components/esp32/gpio.py +15 -16
  107. esphome/components/esp32/gpio_esp32.py +1 -2
  108. esphome/components/esp32/gpio_esp32_c2.py +1 -1
  109. esphome/components/esp32/gpio_esp32_c3.py +1 -1
  110. esphome/components/esp32/gpio_esp32_c6.py +1 -1
  111. esphome/components/esp32/gpio_esp32_h2.py +1 -1
  112. esphome/components/esp32_ble/ble.cpp +1 -0
  113. esphome/components/esp32_ble/ble.h +5 -3
  114. esphome/components/esp32_ble/ble_advertising.cpp +2 -1
  115. esphome/components/esp32_ble/ble_advertising.h +1 -0
  116. esphome/components/esp32_ble_server/__init__.py +3 -0
  117. esphome/components/esp32_ble_tracker/__init__.py +7 -1
  118. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +192 -118
  119. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +29 -3
  120. esphome/components/esp32_camera/esp32_camera.cpp +2 -1
  121. esphome/components/esp32_camera/esp32_camera.h +1 -1
  122. esphome/components/esp32_can/esp32_can.cpp +1 -1
  123. esphome/components/esp32_improv/esp32_improv_component.cpp +1 -1
  124. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  125. esphome/components/esp32_rmt_led_strip/led_strip.h +7 -5
  126. esphome/components/esp32_rmt_led_strip/light.py +9 -1
  127. esphome/components/esp32_touch/esp32_touch.cpp +1 -1
  128. esphome/components/esp8266/gpio.cpp +69 -8
  129. esphome/components/ethernet/ethernet_component.cpp +1 -1
  130. esphome/components/event/__init__.py +13 -10
  131. esphome/components/factory_reset/switch/__init__.py +7 -21
  132. esphome/components/fan/__init__.py +52 -5
  133. esphome/components/fastled_base/__init__.py +1 -4
  134. esphome/components/fastled_base/fastled_light.cpp +1 -1
  135. esphome/components/feedback/cover.py +38 -33
  136. esphome/components/feedback/feedback_cover.cpp +2 -1
  137. esphome/components/fujitsu_general/climate.py +2 -9
  138. esphome/components/gcja5/gcja5.cpp +2 -1
  139. esphome/components/gpio/one_wire/gpio_one_wire.cpp +45 -43
  140. esphome/components/gpio/one_wire/gpio_one_wire.h +2 -1
  141. esphome/components/gpio_expander/cached_gpio.h +22 -7
  142. esphome/components/gps/__init__.py +47 -17
  143. esphome/components/gps/gps.cpp +42 -23
  144. esphome/components/gps/gps.h +17 -13
  145. esphome/components/graph/__init__.py +1 -2
  146. esphome/components/gree/climate.py +4 -6
  147. esphome/components/gree/gree.cpp +16 -2
  148. esphome/components/gree/gree.h +2 -2
  149. esphome/components/growatt_solar/growatt_solar.cpp +2 -1
  150. esphome/components/haier/climate.py +37 -34
  151. esphome/components/hbridge/fan/__init__.py +19 -17
  152. esphome/components/he60r/cover.py +4 -5
  153. esphome/components/heatpumpir/climate.py +3 -6
  154. esphome/components/hitachi_ac344/climate.py +2 -9
  155. esphome/components/hitachi_ac424/climate.py +2 -9
  156. esphome/components/hm3301/hm3301.h +1 -1
  157. esphome/components/hte501/sensor.py +6 -6
  158. esphome/components/http_request/__init__.py +39 -6
  159. esphome/components/http_request/http_request.cpp +20 -0
  160. esphome/components/http_request/http_request.h +57 -15
  161. esphome/components/http_request/http_request_arduino.cpp +22 -6
  162. esphome/components/http_request/http_request_arduino.h +4 -3
  163. esphome/components/http_request/http_request_host.cpp +141 -0
  164. esphome/components/http_request/http_request_host.h +37 -0
  165. esphome/components/http_request/http_request_idf.cpp +35 -3
  166. esphome/components/http_request/http_request_idf.h +10 -3
  167. esphome/components/http_request/httplib.h +9691 -0
  168. esphome/components/http_request/update/__init__.py +11 -8
  169. esphome/components/hyt271/sensor.py +6 -6
  170. esphome/components/i2c/i2c.h +4 -0
  171. esphome/components/i2c/i2c_bus_esp_idf.cpp +1 -1
  172. esphome/components/i2s_audio/__init__.py +131 -22
  173. esphome/components/i2s_audio/i2s_audio.h +44 -4
  174. esphome/components/i2s_audio/media_player/__init__.py +19 -9
  175. esphome/components/i2s_audio/microphone/__init__.py +63 -5
  176. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +351 -61
  177. esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +40 -6
  178. esphome/components/i2s_audio/speaker/__init__.py +31 -5
  179. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +155 -19
  180. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +17 -4
  181. esphome/components/ili9xxx/ili9xxx_init.h +1 -1
  182. esphome/components/image/__init__.py +37 -17
  183. esphome/components/image/image.cpp +25 -8
  184. esphome/components/internal_temperature/internal_temperature.cpp +6 -4
  185. esphome/components/key_collector/__init__.py +35 -0
  186. esphome/components/key_collector/key_collector.cpp +8 -0
  187. esphome/components/key_collector/key_collector.h +10 -0
  188. esphome/components/kuntze/kuntze.cpp +2 -1
  189. esphome/components/ld2410/ld2410.h +1 -1
  190. esphome/components/ld2450/ld2450.h +1 -1
  191. esphome/components/light/__init__.py +57 -0
  192. esphome/components/lock/__init__.py +51 -4
  193. esphome/components/lock/automation.h +2 -13
  194. esphome/components/logger/__init__.py +22 -0
  195. esphome/components/logger/logger.cpp +154 -103
  196. esphome/components/logger/logger.h +211 -36
  197. esphome/components/logger/task_log_buffer.cpp +138 -0
  198. esphome/components/logger/task_log_buffer.h +69 -0
  199. esphome/components/lvgl/__init__.py +13 -5
  200. esphome/components/lvgl/automation.py +50 -1
  201. esphome/components/lvgl/defines.py +0 -1
  202. esphome/components/lvgl/lvgl_esphome.cpp +5 -1
  203. esphome/components/lvgl/text/__init__.py +1 -2
  204. esphome/components/mapping/__init__.py +134 -0
  205. esphome/components/matrix_keypad/matrix_keypad.cpp +2 -1
  206. esphome/components/max7219digit/max7219digit.cpp +28 -27
  207. esphome/components/mdns/__init__.py +11 -5
  208. esphome/components/mdns/mdns_component.cpp +11 -5
  209. esphome/components/mdns/mdns_component.h +3 -2
  210. esphome/components/mdns/mdns_esp32.cpp +4 -3
  211. esphome/components/mdns/mdns_esp8266.cpp +4 -2
  212. esphome/components/mdns/mdns_libretiny.cpp +4 -2
  213. esphome/components/mdns/mdns_rp2040.cpp +4 -2
  214. esphome/components/media_player/__init__.py +33 -1
  215. esphome/components/mhz19/sensor.py +11 -7
  216. esphome/components/micro_wake_word/__init__.py +99 -31
  217. esphome/components/micro_wake_word/automation.h +54 -0
  218. esphome/components/micro_wake_word/micro_wake_word.cpp +331 -319
  219. esphome/components/micro_wake_word/micro_wake_word.h +58 -105
  220. esphome/components/micro_wake_word/preprocessor_settings.h +19 -2
  221. esphome/components/micro_wake_word/streaming_model.cpp +158 -41
  222. esphome/components/micro_wake_word/streaming_model.h +85 -13
  223. esphome/components/microphone/__init__.py +139 -9
  224. esphome/components/microphone/automation.h +14 -2
  225. esphome/components/microphone/microphone.cpp +21 -0
  226. esphome/components/microphone/microphone.h +14 -5
  227. esphome/components/microphone/microphone_source.cpp +95 -0
  228. esphome/components/microphone/microphone_source.h +80 -0
  229. esphome/components/mics_4514/sensor.py +25 -14
  230. esphome/components/midea/climate.py +3 -4
  231. esphome/components/midea_ir/climate.py +3 -5
  232. esphome/components/mipi_spi/__init__.py +15 -0
  233. esphome/components/mipi_spi/display.py +474 -0
  234. esphome/components/mipi_spi/mipi_spi.cpp +481 -0
  235. esphome/components/mipi_spi/mipi_spi.h +171 -0
  236. esphome/components/mipi_spi/models/__init__.py +65 -0
  237. esphome/components/mipi_spi/models/amoled.py +72 -0
  238. esphome/components/mipi_spi/models/commands.py +82 -0
  239. esphome/components/mipi_spi/models/cyd.py +10 -0
  240. esphome/components/mipi_spi/models/ili.py +749 -0
  241. esphome/components/mipi_spi/models/jc.py +260 -0
  242. esphome/components/mipi_spi/models/lanbon.py +15 -0
  243. esphome/components/mipi_spi/models/lilygo.py +60 -0
  244. esphome/components/mipi_spi/models/waveshare.py +139 -0
  245. esphome/components/mitsubishi/climate.py +2 -5
  246. esphome/components/mitsubishi/mitsubishi.cpp +9 -9
  247. esphome/components/mixer/speaker/mixer_speaker.cpp +12 -22
  248. esphome/components/mixer/speaker/mixer_speaker.h +1 -3
  249. esphome/components/mlx90393/sensor.py +5 -0
  250. esphome/components/mlx90393/sensor_mlx90393.cpp +195 -13
  251. esphome/components/mlx90393/sensor_mlx90393.h +21 -4
  252. esphome/components/modbus/modbus.cpp +2 -1
  253. esphome/components/mqtt/__init__.py +1 -1
  254. esphome/components/mqtt/mqtt_client.cpp +6 -2
  255. esphome/components/mqtt/mqtt_const.h +4 -0
  256. esphome/components/mqtt/mqtt_fan.cpp +39 -0
  257. esphome/components/mqtt/mqtt_fan.h +2 -0
  258. esphome/components/ms5611/sensor.py +6 -6
  259. esphome/components/ms8607/sensor.py +3 -3
  260. esphome/components/network/__init__.py +1 -1
  261. esphome/components/nextion/base_component.py +17 -16
  262. esphome/components/nextion/display.py +11 -2
  263. esphome/components/nextion/nextion.cpp +39 -1
  264. esphome/components/nextion/nextion.h +50 -0
  265. esphome/components/noblex/climate.py +2 -9
  266. esphome/components/number/__init__.py +12 -9
  267. esphome/components/one_wire/one_wire_bus.cpp +14 -10
  268. esphome/components/one_wire/one_wire_bus.h +14 -8
  269. esphome/components/online_image/bmp_image.cpp +48 -11
  270. esphome/components/online_image/bmp_image.h +2 -0
  271. esphome/components/opentherm/binary_sensor/__init__.py +2 -4
  272. esphome/components/opentherm/number/__init__.py +11 -20
  273. esphome/components/opentherm/sensor/__init__.py +3 -3
  274. esphome/components/opentherm/switch/__init__.py +3 -5
  275. esphome/components/output/lock/__init__.py +11 -9
  276. esphome/components/packages/__init__.py +33 -31
  277. esphome/components/packet_transport/__init__.py +201 -0
  278. esphome/components/packet_transport/binary_sensor.py +19 -0
  279. esphome/components/packet_transport/packet_transport.cpp +534 -0
  280. esphome/components/packet_transport/packet_transport.h +154 -0
  281. esphome/components/packet_transport/sensor.py +19 -0
  282. esphome/components/pca9685/pca9685_output.cpp +2 -1
  283. esphome/components/pid/climate.py +2 -4
  284. esphome/components/pm2005/__init__.py +1 -0
  285. esphome/components/pm2005/pm2005.cpp +123 -0
  286. esphome/components/pm2005/pm2005.h +46 -0
  287. esphome/components/pm2005/sensor.py +86 -0
  288. esphome/components/pmsa003i/pmsa003i.cpp +43 -16
  289. esphome/components/pmsa003i/pmsa003i.h +25 -25
  290. esphome/components/pmsx003/pmsx003.cpp +195 -230
  291. esphome/components/pmsx003/pmsx003.h +51 -33
  292. esphome/components/pmsx003/sensor.py +21 -11
  293. esphome/components/pn7150/pn7150.h +2 -2
  294. esphome/components/pn7160/pn7160.h +2 -2
  295. esphome/components/prometheus/prometheus_handler.cpp +174 -0
  296. esphome/components/prometheus/prometheus_handler.h +17 -0
  297. esphome/components/psram/__init__.py +7 -5
  298. esphome/components/pulse_meter/pulse_meter_sensor.cpp +32 -12
  299. esphome/components/pulse_meter/pulse_meter_sensor.h +5 -5
  300. esphome/components/pzem004t/pzem004t.cpp +2 -1
  301. esphome/components/qspi_dbi/__init__.py +0 -1
  302. esphome/components/qspi_dbi/display.py +2 -1
  303. esphome/components/qspi_dbi/models.py +1 -2
  304. esphome/components/remote_base/__init__.py +91 -0
  305. esphome/components/remote_base/beo4_protocol.cpp +153 -0
  306. esphome/components/remote_base/beo4_protocol.h +43 -0
  307. esphome/components/remote_base/gobox_protocol.cpp +131 -0
  308. esphome/components/remote_base/gobox_protocol.h +54 -0
  309. esphome/components/remote_receiver/remote_receiver_esp32.cpp +16 -9
  310. esphome/components/resampler/speaker/resampler_speaker.cpp +12 -10
  311. esphome/components/resampler/speaker/resampler_speaker.h +1 -1
  312. esphome/components/rf_bridge/rf_bridge.cpp +2 -1
  313. esphome/components/scd30/sensor.py +2 -3
  314. esphome/components/scd4x/sensor.py +4 -5
  315. esphome/components/sdp3x/sensor.py +2 -1
  316. esphome/components/sds011/sds011.cpp +2 -1
  317. esphome/components/select/__init__.py +19 -20
  318. esphome/components/sen5x/sen5x.cpp +55 -36
  319. esphome/components/sen5x/sensor.py +1 -1
  320. esphome/components/senseair/sensor.py +3 -3
  321. esphome/components/sensor/__init__.py +158 -14
  322. esphome/components/sensor/filter.cpp +23 -0
  323. esphome/components/sensor/filter.h +22 -0
  324. esphome/components/sgp30/sensor.py +14 -16
  325. esphome/components/sgp4x/sensor.py +1 -1
  326. esphome/components/sht4x/sht4x.cpp +43 -22
  327. esphome/components/sht4x/sht4x.h +1 -1
  328. esphome/components/shtcx/sensor.py +6 -6
  329. esphome/components/slow_pwm/slow_pwm_output.cpp +2 -1
  330. esphome/components/sml/text_sensor/__init__.py +4 -6
  331. esphome/components/sound_level/__init__.py +0 -0
  332. esphome/components/sound_level/sensor.py +97 -0
  333. esphome/components/sound_level/sound_level.cpp +194 -0
  334. esphome/components/sound_level/sound_level.h +73 -0
  335. esphome/components/speaker/media_player/__init__.py +4 -8
  336. esphome/components/speaker/media_player/speaker_media_player.cpp +0 -18
  337. esphome/components/speaker/media_player/speaker_media_player.h +0 -11
  338. esphome/components/speaker/speaker.h +4 -7
  339. esphome/components/speed/fan/__init__.py +17 -16
  340. esphome/components/spi/spi.h +11 -1
  341. esphome/components/sprinkler/__init__.py +18 -19
  342. esphome/components/sprinkler/sprinkler.cpp +6 -5
  343. esphome/components/switch/__init__.py +32 -42
  344. esphome/components/syslog/__init__.py +41 -0
  345. esphome/components/syslog/esphome_syslog.cpp +49 -0
  346. esphome/components/syslog/esphome_syslog.h +27 -0
  347. esphome/components/t6615/sensor.py +3 -3
  348. esphome/components/t6615/t6615.cpp +2 -1
  349. esphome/components/tca9555/tca9555.cpp +11 -6
  350. esphome/components/tcl112/climate.py +2 -9
  351. esphome/components/template/alarm_control_panel/__init__.py +7 -6
  352. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +21 -17
  353. esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +2 -1
  354. esphome/components/template/cover/__init__.py +27 -21
  355. esphome/components/template/fan/__init__.py +14 -12
  356. esphome/components/template/lock/__init__.py +20 -25
  357. esphome/components/template/lock/automation.h +18 -0
  358. esphome/components/template/text/__init__.py +4 -3
  359. esphome/components/template/valve/__init__.py +32 -21
  360. esphome/components/template/valve/automation.h +24 -0
  361. esphome/components/text/__init__.py +32 -1
  362. esphome/components/text_sensor/__init__.py +24 -29
  363. esphome/components/thermostat/climate.py +5 -5
  364. esphome/components/time_based/cover.py +17 -16
  365. esphome/components/time_based/time_based_cover.cpp +2 -1
  366. esphome/components/tm1638/switch/__init__.py +10 -7
  367. esphome/components/tormatic/cover.py +4 -5
  368. esphome/components/toshiba/climate.py +3 -5
  369. esphome/components/touchscreen/touchscreen.cpp +3 -1
  370. esphome/components/tuya/climate/__init__.py +5 -6
  371. esphome/components/tuya/cover/__init__.py +6 -11
  372. esphome/components/tuya/select/__init__.py +15 -5
  373. esphome/components/tuya/select/tuya_select.cpp +6 -1
  374. esphome/components/tuya/select/tuya_select.h +5 -1
  375. esphome/components/uart/packet_transport/__init__.py +20 -0
  376. esphome/components/uart/packet_transport/uart_transport.cpp +88 -0
  377. esphome/components/uart/packet_transport/uart_transport.h +41 -0
  378. esphome/components/uart/switch/uart_switch.cpp +2 -1
  379. esphome/components/udp/__init__.py +126 -128
  380. esphome/components/udp/automation.h +40 -0
  381. esphome/components/udp/binary_sensor.py +3 -25
  382. esphome/components/udp/packet_transport/__init__.py +29 -0
  383. esphome/components/udp/packet_transport/udp_transport.cpp +36 -0
  384. esphome/components/udp/packet_transport/udp_transport.h +28 -0
  385. esphome/components/udp/sensor.py +3 -25
  386. esphome/components/udp/udp_component.cpp +26 -470
  387. esphome/components/udp/udp_component.h +21 -128
  388. esphome/components/update/__init__.py +31 -1
  389. esphome/components/uponor_smatrix/climate/__init__.py +4 -9
  390. esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +2 -1
  391. esphome/components/uponor_smatrix/uponor_smatrix.cpp +2 -1
  392. esphome/components/uptime/text_sensor/__init__.py +47 -7
  393. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +12 -7
  394. esphome/components/uptime/text_sensor/uptime_text_sensor.h +19 -0
  395. esphome/components/valve/__init__.py +34 -3
  396. esphome/components/valve/automation.h +1 -19
  397. esphome/components/vl53l0x/sensor.py +11 -0
  398. esphome/components/vl53l0x/vl53l0x_sensor.cpp +5 -1
  399. esphome/components/vl53l0x/vl53l0x_sensor.h +2 -1
  400. esphome/components/voice_assistant/__init__.py +36 -10
  401. esphome/components/voice_assistant/voice_assistant.cpp +170 -144
  402. esphome/components/voice_assistant/voice_assistant.h +26 -25
  403. esphome/components/waveshare_epaper/display.py +6 -0
  404. esphome/components/waveshare_epaper/waveshare_epaper.cpp +439 -37
  405. esphome/components/waveshare_epaper/waveshare_epaper.h +60 -11
  406. esphome/components/whirlpool/climate.py +3 -5
  407. esphome/components/whynter/climate.py +3 -5
  408. esphome/components/xpt2046/touchscreen/xpt2046.cpp +1 -1
  409. esphome/components/yashima/climate.py +6 -6
  410. esphome/components/zhlt01/climate.py +2 -7
  411. esphome/config.py +13 -13
  412. esphome/config_validation.py +38 -58
  413. esphome/const.py +15 -1
  414. esphome/core/__init__.py +2 -0
  415. esphome/core/application.cpp +23 -10
  416. esphome/core/application.h +9 -1
  417. esphome/core/automation.h +4 -3
  418. esphome/core/component.cpp +28 -7
  419. esphome/core/component.h +10 -1
  420. esphome/core/defines.h +23 -17
  421. esphome/core/macros.h +4 -0
  422. esphome/core/scheduler.cpp +7 -1
  423. esphome/cpp_generator.py +6 -2
  424. esphome/dashboard/web_server.py +3 -3
  425. esphome/helpers.py +39 -0
  426. esphome/loader.py +4 -0
  427. esphome/log.py +15 -19
  428. esphome/mqtt.py +23 -10
  429. esphome/platformio_api.py +1 -1
  430. esphome/schema_extractors.py +0 -1
  431. esphome/voluptuous_schema.py +3 -1
  432. esphome/vscode.py +15 -0
  433. esphome/wizard.py +47 -37
  434. esphome/zeroconf.py +7 -3
  435. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/METADATA +10 -11
  436. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/RECORD +440 -380
  437. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/WHEEL +1 -1
  438. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/entry_points.txt +0 -0
  439. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/licenses/LICENSE +0 -0
  440. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/top_level.txt +0 -0
esphome/__main__.py CHANGED
@@ -43,7 +43,7 @@ from esphome.const import (
43
43
  )
44
44
  from esphome.core import CORE, EsphomeError, coroutine
45
45
  from esphome.helpers import get_bool_env, indent, is_ip_address
46
- from esphome.log import Fore, color, setup_log
46
+ from esphome.log import AnsiFore, color, setup_log
47
47
  from esphome.util import (
48
48
  get_serial_ports,
49
49
  list_yaml_files,
@@ -83,7 +83,7 @@ def choose_prompt(options, purpose: str = None):
83
83
  raise ValueError
84
84
  break
85
85
  except ValueError:
86
- safe_print(color(Fore.RED, f"Invalid option: '{opt}'"))
86
+ safe_print(color(AnsiFore.RED, f"Invalid option: '{opt}'"))
87
87
  return options[opt - 1][1]
88
88
 
89
89
 
@@ -596,30 +596,30 @@ def command_update_all(args):
596
596
  click.echo(f"{half_line}{middle_text}{half_line}")
597
597
 
598
598
  for f in files:
599
- print(f"Updating {color(Fore.CYAN, f)}")
599
+ print(f"Updating {color(AnsiFore.CYAN, f)}")
600
600
  print("-" * twidth)
601
601
  print()
602
602
  rc = run_external_process(
603
603
  "esphome", "--dashboard", "run", f, "--no-logs", "--device", "OTA"
604
604
  )
605
605
  if rc == 0:
606
- print_bar(f"[{color(Fore.BOLD_GREEN, 'SUCCESS')}] {f}")
606
+ print_bar(f"[{color(AnsiFore.BOLD_GREEN, 'SUCCESS')}] {f}")
607
607
  success[f] = True
608
608
  else:
609
- print_bar(f"[{color(Fore.BOLD_RED, 'ERROR')}] {f}")
609
+ print_bar(f"[{color(AnsiFore.BOLD_RED, 'ERROR')}] {f}")
610
610
  success[f] = False
611
611
 
612
612
  print()
613
613
  print()
614
614
  print()
615
615
 
616
- print_bar(f"[{color(Fore.BOLD_WHITE, 'SUMMARY')}]")
616
+ print_bar(f"[{color(AnsiFore.BOLD_WHITE, 'SUMMARY')}]")
617
617
  failed = 0
618
618
  for f in files:
619
619
  if success[f]:
620
- print(f" - {f}: {color(Fore.GREEN, 'SUCCESS')}")
620
+ print(f" - {f}: {color(AnsiFore.GREEN, 'SUCCESS')}")
621
621
  else:
622
- print(f" - {f}: {color(Fore.BOLD_RED, 'FAILED')}")
622
+ print(f" - {f}: {color(AnsiFore.BOLD_RED, 'FAILED')}")
623
623
  failed += 1
624
624
  return failed
625
625
 
@@ -645,7 +645,7 @@ def command_rename(args, config):
645
645
  if c not in ALLOWED_NAME_CHARS:
646
646
  print(
647
647
  color(
648
- Fore.BOLD_RED,
648
+ AnsiFore.BOLD_RED,
649
649
  f"'{c}' is an invalid character for names. Valid characters are: "
650
650
  f"{ALLOWED_NAME_CHARS} (lowercase, no spaces)",
651
651
  )
@@ -658,7 +658,9 @@ def command_rename(args, config):
658
658
  yaml = yaml_util.load_yaml(CORE.config_path)
659
659
  if CONF_ESPHOME not in yaml or CONF_NAME not in yaml[CONF_ESPHOME]:
660
660
  print(
661
- color(Fore.BOLD_RED, "Complex YAML files cannot be automatically renamed.")
661
+ color(
662
+ AnsiFore.BOLD_RED, "Complex YAML files cannot be automatically renamed."
663
+ )
662
664
  )
663
665
  return 1
664
666
  old_name = yaml[CONF_ESPHOME][CONF_NAME]
@@ -681,7 +683,7 @@ def command_rename(args, config):
681
683
  )
682
684
  > 1
683
685
  ):
684
- print(color(Fore.BOLD_RED, "Too many matches in YAML to safely rename"))
686
+ print(color(AnsiFore.BOLD_RED, "Too many matches in YAML to safely rename"))
685
687
  return 1
686
688
 
687
689
  new_raw = re.sub(
@@ -693,7 +695,7 @@ def command_rename(args, config):
693
695
 
694
696
  new_path = os.path.join(CORE.config_dir, args.name + ".yaml")
695
697
  print(
696
- f"Updating {color(Fore.CYAN, CORE.config_path)} to {color(Fore.CYAN, new_path)}"
698
+ f"Updating {color(AnsiFore.CYAN, CORE.config_path)} to {color(AnsiFore.CYAN, new_path)}"
697
699
  )
698
700
  print()
699
701
 
@@ -702,7 +704,7 @@ def command_rename(args, config):
702
704
 
703
705
  rc = run_external_process("esphome", "config", new_path)
704
706
  if rc != 0:
705
- print(color(Fore.BOLD_RED, "Rename failed. Reverting changes."))
707
+ print(color(AnsiFore.BOLD_RED, "Rename failed. Reverting changes."))
706
708
  os.remove(new_path)
707
709
  return 1
708
710
 
@@ -728,7 +730,7 @@ def command_rename(args, config):
728
730
  if CORE.config_path != new_path:
729
731
  os.remove(CORE.config_path)
730
732
 
731
- print(color(Fore.BOLD_GREEN, "SUCCESS"))
733
+ print(color(AnsiFore.BOLD_GREEN, "SUCCESS"))
732
734
  print()
733
735
  return 0
734
736
 
@@ -114,13 +114,14 @@ void IRAM_ATTR HOT AcDimmerDataStore::gpio_intr() {
114
114
  // fully off, disable output immediately
115
115
  this->gate_pin.digital_write(false);
116
116
  } else {
117
+ auto min_us = this->cycle_time_us * this->min_power / 1000;
117
118
  if (this->method == DIM_METHOD_TRAILING) {
118
119
  this->enable_time_us = 1; // cannot be 0
119
- this->disable_time_us = std::max((uint32_t) 10, this->value * this->cycle_time_us / 65535);
120
+ // calculate time until disable in µs with integer arithmetic and take into account min_power
121
+ this->disable_time_us = std::max((uint32_t) 10, this->value * (this->cycle_time_us - min_us) / 65535 + min_us);
120
122
  } else {
121
123
  // calculate time until enable in µs: (1.0-value)*cycle_time, but with integer arithmetic
122
124
  // also take into account min_power
123
- auto min_us = this->cycle_time_us * this->min_power / 1000;
124
125
  this->enable_time_us = std::max((uint32_t) 1, ((65535 - this->value) * (this->cycle_time_us - min_us)) / 65535);
125
126
 
126
127
  if (this->method == DIM_METHOD_LEADING_PULSE) {
@@ -47,9 +47,10 @@ SAMPLING_MODES = {
47
47
  adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
48
48
  adc2_channel_t = cg.global_ns.enum("adc2_channel_t")
49
49
 
50
- # From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h
51
50
  # pin to adc1 channel mapping
51
+ # https://github.com/espressif/esp-idf/blob/v4.4.8/components/driver/include/driver/adc.h
52
52
  ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
53
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/adc_channel.h
53
54
  VARIANT_ESP32: {
54
55
  36: adc1_channel_t.ADC1_CHANNEL_0,
55
56
  37: adc1_channel_t.ADC1_CHANNEL_1,
@@ -60,44 +61,23 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
60
61
  34: adc1_channel_t.ADC1_CHANNEL_6,
61
62
  35: adc1_channel_t.ADC1_CHANNEL_7,
62
63
  },
63
- VARIANT_ESP32S2: {
64
- 1: adc1_channel_t.ADC1_CHANNEL_0,
65
- 2: adc1_channel_t.ADC1_CHANNEL_1,
66
- 3: adc1_channel_t.ADC1_CHANNEL_2,
67
- 4: adc1_channel_t.ADC1_CHANNEL_3,
68
- 5: adc1_channel_t.ADC1_CHANNEL_4,
69
- 6: adc1_channel_t.ADC1_CHANNEL_5,
70
- 7: adc1_channel_t.ADC1_CHANNEL_6,
71
- 8: adc1_channel_t.ADC1_CHANNEL_7,
72
- 9: adc1_channel_t.ADC1_CHANNEL_8,
73
- 10: adc1_channel_t.ADC1_CHANNEL_9,
74
- },
75
- VARIANT_ESP32S3: {
76
- 1: adc1_channel_t.ADC1_CHANNEL_0,
77
- 2: adc1_channel_t.ADC1_CHANNEL_1,
78
- 3: adc1_channel_t.ADC1_CHANNEL_2,
79
- 4: adc1_channel_t.ADC1_CHANNEL_3,
80
- 5: adc1_channel_t.ADC1_CHANNEL_4,
81
- 6: adc1_channel_t.ADC1_CHANNEL_5,
82
- 7: adc1_channel_t.ADC1_CHANNEL_6,
83
- 8: adc1_channel_t.ADC1_CHANNEL_7,
84
- 9: adc1_channel_t.ADC1_CHANNEL_8,
85
- 10: adc1_channel_t.ADC1_CHANNEL_9,
86
- },
87
- VARIANT_ESP32C3: {
64
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c2/include/soc/adc_channel.h
65
+ VARIANT_ESP32C2: {
88
66
  0: adc1_channel_t.ADC1_CHANNEL_0,
89
67
  1: adc1_channel_t.ADC1_CHANNEL_1,
90
68
  2: adc1_channel_t.ADC1_CHANNEL_2,
91
69
  3: adc1_channel_t.ADC1_CHANNEL_3,
92
70
  4: adc1_channel_t.ADC1_CHANNEL_4,
93
71
  },
94
- VARIANT_ESP32C2: {
72
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c3/include/soc/adc_channel.h
73
+ VARIANT_ESP32C3: {
95
74
  0: adc1_channel_t.ADC1_CHANNEL_0,
96
75
  1: adc1_channel_t.ADC1_CHANNEL_1,
97
76
  2: adc1_channel_t.ADC1_CHANNEL_2,
98
77
  3: adc1_channel_t.ADC1_CHANNEL_3,
99
78
  4: adc1_channel_t.ADC1_CHANNEL_4,
100
79
  },
80
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c6/include/soc/adc_channel.h
101
81
  VARIANT_ESP32C6: {
102
82
  0: adc1_channel_t.ADC1_CHANNEL_0,
103
83
  1: adc1_channel_t.ADC1_CHANNEL_1,
@@ -107,6 +87,7 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
107
87
  5: adc1_channel_t.ADC1_CHANNEL_5,
108
88
  6: adc1_channel_t.ADC1_CHANNEL_6,
109
89
  },
90
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32h2/include/soc/adc_channel.h
110
91
  VARIANT_ESP32H2: {
111
92
  1: adc1_channel_t.ADC1_CHANNEL_0,
112
93
  2: adc1_channel_t.ADC1_CHANNEL_1,
@@ -114,10 +95,38 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
114
95
  4: adc1_channel_t.ADC1_CHANNEL_3,
115
96
  5: adc1_channel_t.ADC1_CHANNEL_4,
116
97
  },
98
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
99
+ VARIANT_ESP32S2: {
100
+ 1: adc1_channel_t.ADC1_CHANNEL_0,
101
+ 2: adc1_channel_t.ADC1_CHANNEL_1,
102
+ 3: adc1_channel_t.ADC1_CHANNEL_2,
103
+ 4: adc1_channel_t.ADC1_CHANNEL_3,
104
+ 5: adc1_channel_t.ADC1_CHANNEL_4,
105
+ 6: adc1_channel_t.ADC1_CHANNEL_5,
106
+ 7: adc1_channel_t.ADC1_CHANNEL_6,
107
+ 8: adc1_channel_t.ADC1_CHANNEL_7,
108
+ 9: adc1_channel_t.ADC1_CHANNEL_8,
109
+ 10: adc1_channel_t.ADC1_CHANNEL_9,
110
+ },
111
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s3/include/soc/adc_channel.h
112
+ VARIANT_ESP32S3: {
113
+ 1: adc1_channel_t.ADC1_CHANNEL_0,
114
+ 2: adc1_channel_t.ADC1_CHANNEL_1,
115
+ 3: adc1_channel_t.ADC1_CHANNEL_2,
116
+ 4: adc1_channel_t.ADC1_CHANNEL_3,
117
+ 5: adc1_channel_t.ADC1_CHANNEL_4,
118
+ 6: adc1_channel_t.ADC1_CHANNEL_5,
119
+ 7: adc1_channel_t.ADC1_CHANNEL_6,
120
+ 8: adc1_channel_t.ADC1_CHANNEL_7,
121
+ 9: adc1_channel_t.ADC1_CHANNEL_8,
122
+ 10: adc1_channel_t.ADC1_CHANNEL_9,
123
+ },
117
124
  }
118
125
 
126
+ # pin to adc2 channel mapping
127
+ # https://github.com/espressif/esp-idf/blob/v4.4.8/components/driver/include/driver/adc.h
119
128
  ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
120
- # TODO: add other variants
129
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/adc_channel.h
121
130
  VARIANT_ESP32: {
122
131
  4: adc2_channel_t.ADC2_CHANNEL_0,
123
132
  0: adc2_channel_t.ADC2_CHANNEL_1,
@@ -130,6 +139,19 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
130
139
  25: adc2_channel_t.ADC2_CHANNEL_8,
131
140
  26: adc2_channel_t.ADC2_CHANNEL_9,
132
141
  },
142
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c2/include/soc/adc_channel.h
143
+ VARIANT_ESP32C2: {
144
+ 5: adc2_channel_t.ADC2_CHANNEL_0,
145
+ },
146
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c3/include/soc/adc_channel.h
147
+ VARIANT_ESP32C3: {
148
+ 5: adc2_channel_t.ADC2_CHANNEL_0,
149
+ },
150
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c6/include/soc/adc_channel.h
151
+ VARIANT_ESP32C6: {}, # no ADC2
152
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32h2/include/soc/adc_channel.h
153
+ VARIANT_ESP32H2: {}, # no ADC2
154
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
133
155
  VARIANT_ESP32S2: {
134
156
  11: adc2_channel_t.ADC2_CHANNEL_0,
135
157
  12: adc2_channel_t.ADC2_CHANNEL_1,
@@ -142,6 +164,7 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
142
164
  19: adc2_channel_t.ADC2_CHANNEL_8,
143
165
  20: adc2_channel_t.ADC2_CHANNEL_9,
144
166
  },
167
+ # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s3/include/soc/adc_channel.h
145
168
  VARIANT_ESP32S3: {
146
169
  11: adc2_channel_t.ADC2_CHANNEL_0,
147
170
  12: adc2_channel_t.ADC2_CHANNEL_1,
@@ -154,12 +177,6 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
154
177
  19: adc2_channel_t.ADC2_CHANNEL_8,
155
178
  20: adc2_channel_t.ADC2_CHANNEL_9,
156
179
  },
157
- VARIANT_ESP32C3: {
158
- 5: adc2_channel_t.ADC2_CHANNEL_0,
159
- },
160
- VARIANT_ESP32C2: {},
161
- VARIANT_ESP32C6: {},
162
- VARIANT_ESP32H2: {},
163
180
  }
164
181
 
165
182
 
@@ -34,7 +34,7 @@ AirthingsWaveBase = airthings_wave_base_ns.class_(
34
34
 
35
35
 
36
36
  BASE_SCHEMA = (
37
- sensor.SENSOR_SCHEMA.extend(
37
+ cv.Schema(
38
38
  {
39
39
  cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
40
40
  unit_of_measurement=UNIT_PERCENT,
@@ -5,6 +5,8 @@ from esphome.components import mqtt, web_server
5
5
  import esphome.config_validation as cv
6
6
  from esphome.const import (
7
7
  CONF_CODE,
8
+ CONF_ENTITY_CATEGORY,
9
+ CONF_ICON,
8
10
  CONF_ID,
9
11
  CONF_MQTT_ID,
10
12
  CONF_ON_STATE,
@@ -12,6 +14,7 @@ from esphome.const import (
12
14
  CONF_WEB_SERVER,
13
15
  )
14
16
  from esphome.core import CORE, coroutine_with_priority
17
+ from esphome.cpp_generator import MockObjClass
15
18
  from esphome.cpp_helpers import setup_entity
16
19
 
17
20
  CODEOWNERS = ["@grahambrown11", "@hwstar"]
@@ -78,12 +81,11 @@ AlarmControlPanelCondition = alarm_control_panel_ns.class_(
78
81
  "AlarmControlPanelCondition", automation.Condition
79
82
  )
80
83
 
81
- ALARM_CONTROL_PANEL_SCHEMA = (
84
+ _ALARM_CONTROL_PANEL_SCHEMA = (
82
85
  cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
83
86
  .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
84
87
  .extend(
85
88
  {
86
- cv.GenerateID(): cv.declare_id(AlarmControlPanel),
87
89
  cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
88
90
  mqtt.MQTTAlarmControlPanelComponent
89
91
  ),
@@ -146,6 +148,33 @@ ALARM_CONTROL_PANEL_SCHEMA = (
146
148
  )
147
149
  )
148
150
 
151
+
152
+ def alarm_control_panel_schema(
153
+ class_: MockObjClass,
154
+ *,
155
+ entity_category: str = cv.UNDEFINED,
156
+ icon: str = cv.UNDEFINED,
157
+ ) -> cv.Schema:
158
+ schema = {
159
+ cv.GenerateID(): cv.declare_id(class_),
160
+ }
161
+
162
+ for key, default, validator in [
163
+ (CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
164
+ (CONF_ICON, icon, cv.icon),
165
+ ]:
166
+ if default is not cv.UNDEFINED:
167
+ schema[cv.Optional(key, default=default)] = validator
168
+
169
+ return _ALARM_CONTROL_PANEL_SCHEMA.extend(schema)
170
+
171
+
172
+ # Remove before 2025.11.0
173
+ ALARM_CONTROL_PANEL_SCHEMA = alarm_control_panel_schema(AlarmControlPanel)
174
+ ALARM_CONTROL_PANEL_SCHEMA.add_extra(
175
+ cv.deprecated_schema_constant("alarm_control_panel")
176
+ )
177
+
149
178
  ALARM_CONTROL_PANEL_ACTION_SCHEMA = maybe_simple_id(
150
179
  {
151
180
  cv.GenerateID(): cv.use_id(AlarmControlPanel),
@@ -209,6 +238,12 @@ async def register_alarm_control_panel(var, config):
209
238
  await setup_alarm_control_panel_core_(var, config)
210
239
 
211
240
 
241
+ async def new_alarm_control_panel(config, *args):
242
+ var = cg.new_Pvariable(config[CONF_ID], *args)
243
+ await register_alarm_control_panel(var, config)
244
+ return var
245
+
246
+
212
247
  @automation.register_action(
213
248
  "alarm_control_panel.arm_away", ArmAwayAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA
214
249
  )
@@ -1,7 +1,7 @@
1
1
  import esphome.codegen as cg
2
2
  from esphome.components import ble_client, cover
3
3
  import esphome.config_validation as cv
4
- from esphome.const import CONF_ID, CONF_PIN
4
+ from esphome.const import CONF_PIN
5
5
 
6
6
  CODEOWNERS = ["@buxtronix"]
7
7
  DEPENDENCIES = ["ble_client"]
@@ -15,9 +15,9 @@ Am43Component = am43_ns.class_(
15
15
  )
16
16
 
17
17
  CONFIG_SCHEMA = (
18
- cover.COVER_SCHEMA.extend(
18
+ cover.cover_schema(Am43Component)
19
+ .extend(
19
20
  {
20
- cv.GenerateID(): cv.declare_id(Am43Component),
21
21
  cv.Optional(CONF_PIN, default=8888): cv.int_range(min=0, max=0xFFFF),
22
22
  cv.Optional(CONF_INVERT_POSITION, default=False): cv.boolean,
23
23
  }
@@ -28,9 +28,8 @@ CONFIG_SCHEMA = (
28
28
 
29
29
 
30
30
  async def to_code(config):
31
- var = cg.new_Pvariable(config[CONF_ID])
31
+ var = await cover.new_cover(config)
32
32
  cg.add(var.set_pin(config[CONF_PIN]))
33
33
  cg.add(var.set_invert_position(config[CONF_INVERT_POSITION]))
34
34
  await cg.register_component(var, config)
35
- await cover.register_cover(var, config)
36
35
  await ble_client.register_ble_node(var, config)
@@ -14,7 +14,8 @@ void AnalogThresholdBinarySensor::setup() {
14
14
  if (std::isnan(sensor_value)) {
15
15
  this->publish_initial_state(false);
16
16
  } else {
17
- this->publish_initial_state(sensor_value >= (this->lower_threshold_ + this->upper_threshold_) / 2.0f);
17
+ this->publish_initial_state(sensor_value >=
18
+ (this->lower_threshold_.value() + this->upper_threshold_.value()) / 2.0f);
18
19
  }
19
20
  }
20
21
 
@@ -24,7 +25,8 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
24
25
  this->sensor_->add_on_state_callback([this](float sensor_value) {
25
26
  // if there is an invalid sensor reading, ignore the change and keep the current state
26
27
  if (!std::isnan(sensor_value)) {
27
- this->publish_state(sensor_value >= (this->state ? this->lower_threshold_ : this->upper_threshold_));
28
+ this->publish_state(sensor_value >=
29
+ (this->state ? this->lower_threshold_.value() : this->upper_threshold_.value()));
28
30
  }
29
31
  });
30
32
  }
@@ -32,8 +34,8 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
32
34
  void AnalogThresholdBinarySensor::dump_config() {
33
35
  LOG_BINARY_SENSOR("", "Analog Threshold Binary Sensor", this);
34
36
  LOG_SENSOR(" ", "Sensor", this->sensor_);
35
- ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_);
36
- ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_);
37
+ ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_.value());
38
+ ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_.value());
37
39
  }
38
40
 
39
41
  } // namespace analog_threshold
@@ -15,14 +15,13 @@ class AnalogThresholdBinarySensor : public Component, public binary_sensor::Bina
15
15
  float get_setup_priority() const override { return setup_priority::DATA; }
16
16
 
17
17
  void set_sensor(sensor::Sensor *analog_sensor);
18
- void set_upper_threshold(float threshold) { this->upper_threshold_ = threshold; }
19
- void set_lower_threshold(float threshold) { this->lower_threshold_ = threshold; }
18
+ template<typename T> void set_upper_threshold(T upper_threshold) { this->upper_threshold_ = upper_threshold; }
19
+ template<typename T> void set_lower_threshold(T lower_threshold) { this->lower_threshold_ = lower_threshold; }
20
20
 
21
21
  protected:
22
22
  sensor::Sensor *sensor_{nullptr};
23
-
24
- float upper_threshold_;
25
- float lower_threshold_;
23
+ TemplatableValue<float> upper_threshold_{};
24
+ TemplatableValue<float> lower_threshold_{};
26
25
  };
27
26
 
28
27
  } // namespace analog_threshold
@@ -18,11 +18,11 @@ CONFIG_SCHEMA = (
18
18
  {
19
19
  cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
20
20
  cv.Required(CONF_THRESHOLD): cv.Any(
21
- cv.float_,
21
+ cv.templatable(cv.float_),
22
22
  cv.Schema(
23
23
  {
24
- cv.Required(CONF_UPPER): cv.float_,
25
- cv.Required(CONF_LOWER): cv.float_,
24
+ cv.Required(CONF_UPPER): cv.templatable(cv.float_),
25
+ cv.Required(CONF_LOWER): cv.templatable(cv.float_),
26
26
  }
27
27
  ),
28
28
  ),
@@ -39,9 +39,11 @@ async def to_code(config):
39
39
  sens = await cg.get_variable(config[CONF_SENSOR_ID])
40
40
  cg.add(var.set_sensor(sens))
41
41
 
42
- if isinstance(config[CONF_THRESHOLD], float):
43
- cg.add(var.set_upper_threshold(config[CONF_THRESHOLD]))
44
- cg.add(var.set_lower_threshold(config[CONF_THRESHOLD]))
42
+ if isinstance(config[CONF_THRESHOLD], dict):
43
+ lower = await cg.templatable(config[CONF_THRESHOLD][CONF_LOWER], [], float)
44
+ upper = await cg.templatable(config[CONF_THRESHOLD][CONF_UPPER], [], float)
45
45
  else:
46
- cg.add(var.set_upper_threshold(config[CONF_THRESHOLD][CONF_UPPER]))
47
- cg.add(var.set_lower_threshold(config[CONF_THRESHOLD][CONF_LOWER]))
46
+ lower = await cg.templatable(config[CONF_THRESHOLD], [], float)
47
+ upper = lower
48
+ cg.add(var.set_upper_threshold(upper))
49
+ cg.add(var.set_lower_threshold(lower))
@@ -1,7 +1,7 @@
1
1
  import esphome.codegen as cg
2
2
  from esphome.components import ble_client, climate
3
3
  import esphome.config_validation as cv
4
- from esphome.const import CONF_ID, CONF_UNIT_OF_MEASUREMENT
4
+ from esphome.const import CONF_UNIT_OF_MEASUREMENT
5
5
 
6
6
  UNITS = {
7
7
  "f": "f",
@@ -17,9 +17,9 @@ Anova = anova_ns.class_(
17
17
  )
18
18
 
19
19
  CONFIG_SCHEMA = (
20
- climate.CLIMATE_SCHEMA.extend(
20
+ climate.climate_schema(Anova)
21
+ .extend(
21
22
  {
22
- cv.GenerateID(): cv.declare_id(Anova),
23
23
  cv.Required(CONF_UNIT_OF_MEASUREMENT): cv.enum(UNITS),
24
24
  }
25
25
  )
@@ -29,8 +29,7 @@ CONFIG_SCHEMA = (
29
29
 
30
30
 
31
31
  async def to_code(config):
32
- var = cg.new_Pvariable(config[CONF_ID])
32
+ var = await climate.new_climate(config)
33
33
  await cg.register_component(var, config)
34
- await climate.register_climate(var, config)
35
34
  await ble_client.register_ble_node(var, config)
36
35
  cg.add(var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT]))
@@ -82,6 +82,19 @@ ACTIONS_SCHEMA = automation.validate_automation(
82
82
  ),
83
83
  )
84
84
 
85
+ ENCRYPTION_SCHEMA = cv.Schema(
86
+ {
87
+ cv.Optional(CONF_KEY): validate_encryption_key,
88
+ }
89
+ )
90
+
91
+
92
+ def _encryption_schema(config):
93
+ if config is None:
94
+ config = {}
95
+ return ENCRYPTION_SCHEMA(config)
96
+
97
+
85
98
  CONFIG_SCHEMA = cv.All(
86
99
  cv.Schema(
87
100
  {
@@ -95,11 +108,7 @@ CONFIG_SCHEMA = cv.All(
95
108
  CONF_SERVICES, group_of_exclusion=CONF_ACTIONS
96
109
  ): ACTIONS_SCHEMA,
97
110
  cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA,
98
- cv.Optional(CONF_ENCRYPTION): cv.Schema(
99
- {
100
- cv.Required(CONF_KEY): validate_encryption_key,
101
- }
102
- ),
111
+ cv.Optional(CONF_ENCRYPTION): _encryption_schema,
103
112
  cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
104
113
  single=True
105
114
  ),
@@ -151,9 +160,17 @@ async def to_code(config):
151
160
  config[CONF_ON_CLIENT_DISCONNECTED],
152
161
  )
153
162
 
154
- if encryption_config := config.get(CONF_ENCRYPTION):
155
- decoded = base64.b64decode(encryption_config[CONF_KEY])
156
- cg.add(var.set_noise_psk(list(decoded)))
163
+ if (encryption_config := config.get(CONF_ENCRYPTION, None)) is not None:
164
+ if key := encryption_config.get(CONF_KEY):
165
+ decoded = base64.b64decode(key)
166
+ cg.add(var.set_noise_psk(list(decoded)))
167
+ else:
168
+ # No key provided, but encryption desired
169
+ # This will allow a plaintext client to provide a noise key,
170
+ # send it to the device, and then switch to noise.
171
+ # The key will be saved in flash and used for future connections
172
+ # and plaintext disabled. Only a factory reset can remove it.
173
+ cg.add_define("USE_API_PLAINTEXT")
157
174
  cg.add_define("USE_API_NOISE")
158
175
  cg.add_library("esphome/noise-c", "0.1.6")
159
176
  else: