esphome 2025.4.1__py3-none-any.whl → 2025.5.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (412) hide show
  1. esphome/components/ac_dimmer/ac_dimmer.cpp +3 -2
  2. esphome/components/adc/__init__.py +51 -34
  3. esphome/components/airthings_wave_base/__init__.py +1 -1
  4. esphome/components/alarm_control_panel/__init__.py +37 -2
  5. esphome/components/am43/cover/__init__.py +4 -5
  6. esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp +6 -4
  7. esphome/components/analog_threshold/analog_threshold_binary_sensor.h +4 -5
  8. esphome/components/analog_threshold/binary_sensor.py +10 -8
  9. esphome/components/anova/climate.py +4 -5
  10. esphome/components/api/__init__.py +25 -8
  11. esphome/components/api/api_connection.cpp +77 -10
  12. esphome/components/api/api_connection.h +6 -1
  13. esphome/components/api/api_frame_helper.cpp +98 -130
  14. esphome/components/api/api_frame_helper.h +12 -2
  15. esphome/components/api/api_noise_context.h +13 -4
  16. esphome/components/api/api_pb2.cpp +1422 -1
  17. esphome/components/api/api_pb2.h +255 -1
  18. esphome/components/api/api_pb2_service.cpp +162 -49
  19. esphome/components/api/api_pb2_service.h +90 -51
  20. esphome/components/api/api_pb2_size.h +361 -0
  21. esphome/components/api/api_server.cpp +110 -34
  22. esphome/components/api/api_server.h +8 -0
  23. esphome/components/api/proto.h +38 -9
  24. esphome/components/as3935_i2c/as3935_i2c.h +0 -3
  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/climate/__init__.py +3 -8
  45. esphome/components/bedjet/fan/__init__.py +2 -11
  46. esphome/components/binary/fan/__init__.py +13 -16
  47. esphome/components/binary_sensor/__init__.py +13 -10
  48. esphome/components/binary_sensor/binary_sensor.cpp +6 -10
  49. esphome/components/binary_sensor/binary_sensor.h +1 -1
  50. esphome/components/binary_sensor/filter.cpp +21 -21
  51. esphome/components/binary_sensor/filter.h +10 -10
  52. esphome/components/bl0906/constants.h +16 -16
  53. esphome/components/ble_client/text_sensor/__init__.py +3 -5
  54. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +4 -6
  55. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +135 -21
  56. esphome/components/bluetooth_proxy/bluetooth_proxy.h +7 -0
  57. esphome/components/button/__init__.py +11 -8
  58. esphome/components/canbus/canbus.cpp +3 -0
  59. esphome/components/canbus/canbus.h +16 -0
  60. esphome/components/climate/__init__.py +35 -2
  61. esphome/components/climate/climate_mode.h +1 -1
  62. esphome/components/climate/climate_traits.h +63 -57
  63. esphome/components/climate_ir/__init__.py +57 -17
  64. esphome/components/climate_ir_lg/climate.py +2 -5
  65. esphome/components/climate_ir_lg/climate_ir_lg.cpp +7 -7
  66. esphome/components/climate_ir_lg/climate_ir_lg.h +1 -1
  67. esphome/components/color/__init__.py +2 -0
  68. esphome/components/const/__init__.py +5 -0
  69. esphome/components/coolix/climate.py +2 -9
  70. esphome/components/copy/cover/__init__.py +10 -9
  71. esphome/components/copy/fan/__init__.py +11 -9
  72. esphome/components/copy/lock/__init__.py +11 -9
  73. esphome/components/copy/text/__init__.py +9 -6
  74. esphome/components/cover/__init__.py +37 -2
  75. esphome/components/cst226/binary_sensor/__init__.py +28 -0
  76. esphome/components/cst226/binary_sensor/cs226_button.h +22 -0
  77. esphome/components/cst226/binary_sensor/cstt6_button.cpp +19 -0
  78. esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +27 -5
  79. esphome/components/cst226/touchscreen/cst226_touchscreen.h +10 -10
  80. esphome/components/current_based/cover.py +37 -36
  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/debug/debug_component.cpp +5 -0
  89. esphome/components/debug/debug_component.h +6 -0
  90. esphome/components/debug/debug_esp32.cpp +109 -254
  91. esphome/components/debug/sensor.py +14 -0
  92. esphome/components/deep_sleep/deep_sleep_esp32.cpp +13 -1
  93. esphome/components/delonghi/climate.py +2 -9
  94. esphome/components/demo/__init__.py +18 -20
  95. esphome/components/dfrobot_sen0395/switch/__init__.py +21 -22
  96. esphome/components/display/rect.cpp +4 -9
  97. esphome/components/display/rect.h +1 -1
  98. esphome/components/emmeti/climate.py +2 -9
  99. esphome/components/endstop/cover.py +17 -16
  100. esphome/components/esp32/__init__.py +60 -3
  101. esphome/components/esp32/core.cpp +11 -5
  102. esphome/components/esp32/gpio.cpp +86 -24
  103. esphome/components/esp32/gpio.py +15 -16
  104. esphome/components/esp32/gpio_esp32.py +1 -2
  105. esphome/components/esp32/gpio_esp32_c2.py +1 -1
  106. esphome/components/esp32/gpio_esp32_c3.py +1 -1
  107. esphome/components/esp32/gpio_esp32_c6.py +1 -1
  108. esphome/components/esp32/gpio_esp32_h2.py +1 -1
  109. esphome/components/esp32_ble/ble.cpp +1 -8
  110. esphome/components/esp32_ble/ble.h +5 -3
  111. esphome/components/esp32_ble/ble_advertising.h +1 -0
  112. esphome/components/esp32_ble_server/__init__.py +3 -0
  113. esphome/components/esp32_ble_tracker/__init__.py +7 -1
  114. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +192 -118
  115. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +29 -3
  116. esphome/components/esp32_can/esp32_can.cpp +1 -1
  117. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  118. esphome/components/esp32_rmt_led_strip/led_strip.h +7 -5
  119. esphome/components/esp32_rmt_led_strip/light.py +9 -1
  120. esphome/components/esp8266/gpio.cpp +69 -8
  121. esphome/components/event/__init__.py +13 -10
  122. esphome/components/factory_reset/switch/__init__.py +7 -21
  123. esphome/components/fan/__init__.py +52 -5
  124. esphome/components/fastled_base/__init__.py +1 -4
  125. esphome/components/fastled_base/fastled_light.cpp +1 -1
  126. esphome/components/feedback/cover.py +38 -33
  127. esphome/components/fujitsu_general/climate.py +2 -9
  128. esphome/components/gpio/one_wire/gpio_one_wire.cpp +45 -43
  129. esphome/components/gpio/one_wire/gpio_one_wire.h +2 -1
  130. esphome/components/gpio_expander/cached_gpio.h +22 -7
  131. esphome/components/gps/__init__.py +11 -2
  132. esphome/components/gps/gps.cpp +11 -8
  133. esphome/components/gps/gps.h +9 -6
  134. esphome/components/graph/__init__.py +1 -2
  135. esphome/components/gree/climate.py +4 -6
  136. esphome/components/gree/gree.cpp +16 -2
  137. esphome/components/gree/gree.h +2 -2
  138. esphome/components/haier/climate.py +37 -34
  139. esphome/components/hbridge/fan/__init__.py +19 -17
  140. esphome/components/he60r/cover.py +4 -5
  141. esphome/components/heatpumpir/climate.py +3 -6
  142. esphome/components/hitachi_ac344/climate.py +2 -9
  143. esphome/components/hitachi_ac424/climate.py +2 -9
  144. esphome/components/hlw8012/hlw8012.cpp +1 -1
  145. esphome/components/hm3301/hm3301.h +1 -1
  146. esphome/components/http_request/__init__.py +39 -6
  147. esphome/components/http_request/http_request.cpp +20 -0
  148. esphome/components/http_request/http_request.h +57 -15
  149. esphome/components/http_request/http_request_arduino.cpp +22 -6
  150. esphome/components/http_request/http_request_arduino.h +4 -3
  151. esphome/components/http_request/http_request_host.cpp +141 -0
  152. esphome/components/http_request/http_request_host.h +37 -0
  153. esphome/components/http_request/http_request_idf.cpp +35 -3
  154. esphome/components/http_request/http_request_idf.h +10 -3
  155. esphome/components/http_request/httplib.h +9691 -0
  156. esphome/components/http_request/update/__init__.py +11 -8
  157. esphome/components/i2c/i2c.h +4 -0
  158. esphome/components/i2c/i2c_bus_esp_idf.cpp +1 -1
  159. esphome/components/i2s_audio/__init__.py +131 -22
  160. esphome/components/i2s_audio/i2s_audio.h +44 -4
  161. esphome/components/i2s_audio/media_player/__init__.py +19 -9
  162. esphome/components/i2s_audio/microphone/__init__.py +63 -5
  163. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +351 -61
  164. esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +40 -6
  165. esphome/components/i2s_audio/speaker/__init__.py +31 -5
  166. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +155 -19
  167. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +17 -4
  168. esphome/components/ili9xxx/ili9xxx_init.h +1 -1
  169. esphome/components/image/__init__.py +37 -17
  170. esphome/components/image/image.cpp +25 -8
  171. esphome/components/internal_temperature/internal_temperature.cpp +6 -4
  172. esphome/components/key_collector/__init__.py +35 -0
  173. esphome/components/key_collector/key_collector.cpp +8 -0
  174. esphome/components/key_collector/key_collector.h +10 -0
  175. esphome/components/ld2410/ld2410.h +1 -1
  176. esphome/components/ld2450/ld2450.h +1 -1
  177. esphome/components/light/__init__.py +57 -0
  178. esphome/components/lock/__init__.py +51 -4
  179. esphome/components/lock/automation.h +2 -13
  180. esphome/components/logger/__init__.py +21 -0
  181. esphome/components/logger/logger.cpp +125 -95
  182. esphome/components/logger/logger.h +160 -35
  183. esphome/components/logger/task_log_buffer.cpp +138 -0
  184. esphome/components/logger/task_log_buffer.h +69 -0
  185. esphome/components/lvgl/__init__.py +13 -5
  186. esphome/components/lvgl/automation.py +50 -1
  187. esphome/components/lvgl/defines.py +0 -1
  188. esphome/components/lvgl/lv_validation.py +10 -1
  189. esphome/components/lvgl/lvgl_esphome.cpp +5 -1
  190. esphome/components/lvgl/schemas.py +14 -14
  191. esphome/components/lvgl/text/__init__.py +1 -2
  192. esphome/components/lvgl/widgets/arc.py +7 -6
  193. esphome/components/lvgl/widgets/buttonmatrix.py +3 -3
  194. esphome/components/lvgl/widgets/checkbox.py +2 -2
  195. esphome/components/lvgl/widgets/dropdown.py +2 -1
  196. esphome/components/lvgl/widgets/img.py +15 -12
  197. esphome/components/mapping/__init__.py +134 -0
  198. esphome/components/max7219digit/max7219digit.cpp +27 -27
  199. esphome/components/mdns/__init__.py +11 -5
  200. esphome/components/mdns/mdns_component.cpp +11 -5
  201. esphome/components/mdns/mdns_component.h +3 -2
  202. esphome/components/mdns/mdns_esp32.cpp +4 -3
  203. esphome/components/mdns/mdns_esp8266.cpp +4 -2
  204. esphome/components/mdns/mdns_libretiny.cpp +4 -2
  205. esphome/components/mdns/mdns_rp2040.cpp +4 -2
  206. esphome/components/media_player/__init__.py +40 -6
  207. esphome/components/micro_wake_word/__init__.py +99 -31
  208. esphome/components/micro_wake_word/automation.h +54 -0
  209. esphome/components/micro_wake_word/micro_wake_word.cpp +331 -319
  210. esphome/components/micro_wake_word/micro_wake_word.h +58 -105
  211. esphome/components/micro_wake_word/preprocessor_settings.h +19 -2
  212. esphome/components/micro_wake_word/streaming_model.cpp +158 -41
  213. esphome/components/micro_wake_word/streaming_model.h +85 -13
  214. esphome/components/microphone/__init__.py +139 -9
  215. esphome/components/microphone/automation.h +14 -2
  216. esphome/components/microphone/microphone.cpp +21 -0
  217. esphome/components/microphone/microphone.h +14 -5
  218. esphome/components/microphone/microphone_source.cpp +95 -0
  219. esphome/components/microphone/microphone_source.h +80 -0
  220. esphome/components/mics_4514/sensor.py +25 -14
  221. esphome/components/midea/climate.py +3 -4
  222. esphome/components/midea_ir/climate.py +3 -5
  223. esphome/components/mipi_spi/__init__.py +15 -0
  224. esphome/components/mipi_spi/display.py +474 -0
  225. esphome/components/mipi_spi/mipi_spi.cpp +481 -0
  226. esphome/components/mipi_spi/mipi_spi.h +171 -0
  227. esphome/components/mipi_spi/models/__init__.py +65 -0
  228. esphome/components/mipi_spi/models/amoled.py +72 -0
  229. esphome/components/mipi_spi/models/commands.py +82 -0
  230. esphome/components/mipi_spi/models/cyd.py +10 -0
  231. esphome/components/mipi_spi/models/ili.py +749 -0
  232. esphome/components/mipi_spi/models/jc.py +260 -0
  233. esphome/components/mipi_spi/models/lanbon.py +15 -0
  234. esphome/components/mipi_spi/models/lilygo.py +60 -0
  235. esphome/components/mipi_spi/models/waveshare.py +139 -0
  236. esphome/components/mitsubishi/climate.py +2 -5
  237. esphome/components/mitsubishi/mitsubishi.cpp +9 -9
  238. esphome/components/mixer/speaker/mixer_speaker.cpp +12 -22
  239. esphome/components/mixer/speaker/mixer_speaker.h +1 -3
  240. esphome/components/mlx90393/sensor.py +5 -0
  241. esphome/components/mlx90393/sensor_mlx90393.cpp +195 -13
  242. esphome/components/mlx90393/sensor_mlx90393.h +21 -4
  243. esphome/components/mqtt/__init__.py +1 -1
  244. esphome/components/mqtt/mqtt_client.cpp +5 -1
  245. esphome/components/mqtt/mqtt_const.h +4 -0
  246. esphome/components/mqtt/mqtt_fan.cpp +39 -0
  247. esphome/components/mqtt/mqtt_fan.h +2 -0
  248. esphome/components/network/__init__.py +1 -1
  249. esphome/components/nextion/base_component.py +17 -16
  250. esphome/components/nextion/display.py +11 -2
  251. esphome/components/nextion/nextion.cpp +39 -1
  252. esphome/components/nextion/nextion.h +50 -0
  253. esphome/components/noblex/climate.py +2 -9
  254. esphome/components/number/__init__.py +12 -9
  255. esphome/components/one_wire/one_wire_bus.cpp +14 -10
  256. esphome/components/one_wire/one_wire_bus.h +14 -8
  257. esphome/components/online_image/bmp_image.cpp +48 -11
  258. esphome/components/online_image/bmp_image.h +2 -0
  259. esphome/components/opentherm/binary_sensor/__init__.py +2 -4
  260. esphome/components/opentherm/number/__init__.py +11 -20
  261. esphome/components/opentherm/sensor/__init__.py +3 -3
  262. esphome/components/opentherm/switch/__init__.py +3 -5
  263. esphome/components/output/lock/__init__.py +11 -9
  264. esphome/components/packages/__init__.py +33 -31
  265. esphome/components/packet_transport/__init__.py +201 -0
  266. esphome/components/packet_transport/binary_sensor.py +19 -0
  267. esphome/components/packet_transport/packet_transport.cpp +534 -0
  268. esphome/components/packet_transport/packet_transport.h +154 -0
  269. esphome/components/packet_transport/sensor.py +19 -0
  270. esphome/components/pca9685/pca9685_output.cpp +2 -1
  271. esphome/components/pid/climate.py +2 -4
  272. esphome/components/pm2005/__init__.py +1 -0
  273. esphome/components/pm2005/pm2005.cpp +123 -0
  274. esphome/components/pm2005/pm2005.h +46 -0
  275. esphome/components/pm2005/sensor.py +86 -0
  276. esphome/components/pmsa003i/pmsa003i.cpp +43 -16
  277. esphome/components/pmsa003i/pmsa003i.h +25 -25
  278. esphome/components/pmsx003/pmsx003.cpp +193 -229
  279. esphome/components/pmsx003/pmsx003.h +51 -33
  280. esphome/components/pmsx003/sensor.py +21 -11
  281. esphome/components/pn7150/pn7150.h +2 -2
  282. esphome/components/pn7160/pn7160.h +2 -2
  283. esphome/components/prometheus/prometheus_handler.cpp +174 -0
  284. esphome/components/prometheus/prometheus_handler.h +17 -0
  285. esphome/components/psram/__init__.py +7 -5
  286. esphome/components/pulse_meter/pulse_meter_sensor.cpp +32 -12
  287. esphome/components/pulse_meter/pulse_meter_sensor.h +5 -5
  288. esphome/components/qspi_dbi/__init__.py +0 -1
  289. esphome/components/qspi_dbi/display.py +2 -1
  290. esphome/components/qspi_dbi/models.py +1 -2
  291. esphome/components/remote_base/__init__.py +91 -0
  292. esphome/components/remote_base/beo4_protocol.cpp +153 -0
  293. esphome/components/remote_base/beo4_protocol.h +43 -0
  294. esphome/components/remote_base/gobox_protocol.cpp +131 -0
  295. esphome/components/remote_base/gobox_protocol.h +54 -0
  296. esphome/components/remote_receiver/remote_receiver_esp32.cpp +16 -9
  297. esphome/components/resampler/speaker/resampler_speaker.cpp +12 -10
  298. esphome/components/resampler/speaker/resampler_speaker.h +1 -1
  299. esphome/components/scd30/sensor.py +2 -3
  300. esphome/components/scd4x/sensor.py +4 -5
  301. esphome/components/sdp3x/sensor.py +2 -1
  302. esphome/components/select/__init__.py +19 -20
  303. esphome/components/sen5x/sensor.py +1 -1
  304. esphome/components/sensor/__init__.py +158 -14
  305. esphome/components/sensor/filter.cpp +23 -0
  306. esphome/components/sensor/filter.h +22 -0
  307. esphome/components/sgp4x/sensor.py +1 -1
  308. esphome/components/sht4x/sht4x.cpp +43 -22
  309. esphome/components/sht4x/sht4x.h +1 -1
  310. esphome/components/sml/text_sensor/__init__.py +4 -6
  311. esphome/components/sound_level/__init__.py +0 -0
  312. esphome/components/sound_level/sensor.py +97 -0
  313. esphome/components/sound_level/sound_level.cpp +194 -0
  314. esphome/components/sound_level/sound_level.h +73 -0
  315. esphome/components/speaker/media_player/__init__.py +4 -8
  316. esphome/components/speaker/media_player/speaker_media_player.cpp +0 -18
  317. esphome/components/speaker/media_player/speaker_media_player.h +0 -11
  318. esphome/components/speaker/speaker.h +4 -7
  319. esphome/components/speed/fan/__init__.py +17 -16
  320. esphome/components/spi/spi.h +11 -1
  321. esphome/components/sprinkler/__init__.py +18 -19
  322. esphome/components/switch/__init__.py +32 -42
  323. esphome/components/syslog/__init__.py +41 -0
  324. esphome/components/syslog/esphome_syslog.cpp +49 -0
  325. esphome/components/syslog/esphome_syslog.h +27 -0
  326. esphome/components/tca9555/tca9555.cpp +11 -6
  327. esphome/components/tcl112/climate.py +2 -9
  328. esphome/components/template/alarm_control_panel/__init__.py +7 -6
  329. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +21 -17
  330. esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +2 -1
  331. esphome/components/template/cover/__init__.py +27 -21
  332. esphome/components/template/fan/__init__.py +14 -12
  333. esphome/components/template/lock/__init__.py +20 -25
  334. esphome/components/template/lock/automation.h +18 -0
  335. esphome/components/template/text/__init__.py +4 -3
  336. esphome/components/template/valve/__init__.py +32 -21
  337. esphome/components/template/valve/automation.h +24 -0
  338. esphome/components/text/__init__.py +32 -1
  339. esphome/components/text_sensor/__init__.py +24 -29
  340. esphome/components/thermostat/climate.py +5 -5
  341. esphome/components/time_based/cover.py +17 -16
  342. esphome/components/tm1638/switch/__init__.py +10 -7
  343. esphome/components/tormatic/cover.py +4 -5
  344. esphome/components/toshiba/climate.py +3 -5
  345. esphome/components/touchscreen/touchscreen.cpp +3 -1
  346. esphome/components/tt21100/touchscreen/tt21100.cpp +1 -1
  347. esphome/components/tuya/climate/__init__.py +5 -6
  348. esphome/components/tuya/cover/__init__.py +6 -11
  349. esphome/components/tuya/select/__init__.py +15 -5
  350. esphome/components/tuya/select/tuya_select.cpp +6 -1
  351. esphome/components/tuya/select/tuya_select.h +5 -1
  352. esphome/components/uart/packet_transport/__init__.py +20 -0
  353. esphome/components/uart/packet_transport/uart_transport.cpp +88 -0
  354. esphome/components/uart/packet_transport/uart_transport.h +41 -0
  355. esphome/components/udp/__init__.py +126 -128
  356. esphome/components/udp/automation.h +40 -0
  357. esphome/components/udp/binary_sensor.py +3 -25
  358. esphome/components/udp/packet_transport/__init__.py +29 -0
  359. esphome/components/udp/packet_transport/udp_transport.cpp +36 -0
  360. esphome/components/udp/packet_transport/udp_transport.h +28 -0
  361. esphome/components/udp/sensor.py +3 -25
  362. esphome/components/udp/udp_component.cpp +26 -470
  363. esphome/components/udp/udp_component.h +21 -128
  364. esphome/components/update/__init__.py +31 -1
  365. esphome/components/uponor_smatrix/climate/__init__.py +4 -9
  366. esphome/components/uptime/text_sensor/__init__.py +47 -7
  367. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +12 -7
  368. esphome/components/uptime/text_sensor/uptime_text_sensor.h +19 -0
  369. esphome/components/valve/__init__.py +34 -3
  370. esphome/components/valve/automation.h +1 -19
  371. esphome/components/vl53l0x/sensor.py +11 -0
  372. esphome/components/vl53l0x/vl53l0x_sensor.cpp +5 -1
  373. esphome/components/vl53l0x/vl53l0x_sensor.h +2 -1
  374. esphome/components/voice_assistant/__init__.py +36 -10
  375. esphome/components/voice_assistant/voice_assistant.cpp +170 -144
  376. esphome/components/voice_assistant/voice_assistant.h +26 -25
  377. esphome/components/waveshare_epaper/display.py +6 -0
  378. esphome/components/waveshare_epaper/waveshare_epaper.cpp +439 -37
  379. esphome/components/waveshare_epaper/waveshare_epaper.h +60 -11
  380. esphome/components/whirlpool/climate.py +3 -5
  381. esphome/components/whynter/climate.py +3 -5
  382. esphome/components/xpt2046/touchscreen/xpt2046.cpp +1 -1
  383. esphome/components/yashima/climate.py +6 -6
  384. esphome/components/zhlt01/climate.py +2 -7
  385. esphome/config_validation.py +38 -58
  386. esphome/const.py +15 -1
  387. esphome/core/__init__.py +2 -0
  388. esphome/core/application.cpp +1 -0
  389. esphome/core/application.h +4 -0
  390. esphome/core/automation.h +4 -3
  391. esphome/core/component.cpp +19 -3
  392. esphome/core/component.h +5 -0
  393. esphome/core/defines.h +23 -17
  394. esphome/core/macros.h +4 -0
  395. esphome/core/scheduler.cpp +3 -0
  396. esphome/cpp_generator.py +6 -2
  397. esphome/dashboard/web_server.py +3 -3
  398. esphome/helpers.py +39 -0
  399. esphome/loader.py +4 -0
  400. esphome/mqtt.py +21 -8
  401. esphome/platformio_api.py +1 -1
  402. esphome/schema_extractors.py +0 -1
  403. esphome/vscode.py +15 -0
  404. esphome/wizard.py +2 -2
  405. esphome/zeroconf.py +7 -3
  406. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/METADATA +10 -11
  407. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/RECORD +411 -352
  408. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/WHEEL +1 -1
  409. esphome/components/esp32_ble/const_esp32c6.h +0 -74
  410. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/entry_points.txt +0 -0
  411. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/licenses/LICENSE +0 -0
  412. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  import math
2
3
 
3
4
  from esphome import automation
@@ -9,6 +10,7 @@ from esphome.const import (
9
10
  CONF_ACCURACY_DECIMALS,
10
11
  CONF_ALPHA,
11
12
  CONF_BELOW,
13
+ CONF_CALIBRATION,
12
14
  CONF_DEVICE_CLASS,
13
15
  CONF_ENTITY_CATEGORY,
14
16
  CONF_EXPIRE_AFTER,
@@ -30,6 +32,7 @@ from esphome.const import (
30
32
  CONF_SEND_EVERY,
31
33
  CONF_SEND_FIRST_AT,
32
34
  CONF_STATE_CLASS,
35
+ CONF_TEMPERATURE,
33
36
  CONF_TIMEOUT,
34
37
  CONF_TO,
35
38
  CONF_TRIGGER_ID,
@@ -153,6 +156,8 @@ DEVICE_CLASSES = [
153
156
  DEVICE_CLASS_WIND_SPEED,
154
157
  ]
155
158
 
159
+ _LOGGER = logging.getLogger(__name__)
160
+
156
161
  sensor_ns = cg.esphome_ns.namespace("sensor")
157
162
  StateClasses = sensor_ns.enum("StateClass")
158
163
  STATE_CLASSES = {
@@ -246,6 +251,8 @@ HeartbeatFilter = sensor_ns.class_("HeartbeatFilter", Filter, cg.Component)
246
251
  DeltaFilter = sensor_ns.class_("DeltaFilter", Filter)
247
252
  OrFilter = sensor_ns.class_("OrFilter", Filter)
248
253
  CalibrateLinearFilter = sensor_ns.class_("CalibrateLinearFilter", Filter)
254
+ ToNTCResistanceFilter = sensor_ns.class_("ToNTCResistanceFilter", Filter)
255
+ ToNTCTemperatureFilter = sensor_ns.class_("ToNTCTemperatureFilter", Filter)
249
256
  CalibratePolynomialFilter = sensor_ns.class_("CalibratePolynomialFilter", Filter)
250
257
  SensorInRangeCondition = sensor_ns.class_("SensorInRangeCondition", Filter)
251
258
  ClampFilter = sensor_ns.class_("ClampFilter", Filter)
@@ -257,7 +264,7 @@ validate_accuracy_decimals = cv.int_
257
264
  validate_icon = cv.icon
258
265
  validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
259
266
 
260
- SENSOR_SCHEMA = (
267
+ _SENSOR_SCHEMA = (
261
268
  cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
262
269
  .extend(cv.MQTT_COMPONENT_SCHEMA)
263
270
  .extend(
@@ -302,22 +309,20 @@ SENSOR_SCHEMA = (
302
309
  )
303
310
  )
304
311
 
305
- _UNDEF = object()
306
-
307
312
 
308
313
  def sensor_schema(
309
- class_: MockObjClass = _UNDEF,
314
+ class_: MockObjClass = cv.UNDEFINED,
310
315
  *,
311
- unit_of_measurement: str = _UNDEF,
312
- icon: str = _UNDEF,
313
- accuracy_decimals: int = _UNDEF,
314
- device_class: str = _UNDEF,
315
- state_class: str = _UNDEF,
316
- entity_category: str = _UNDEF,
316
+ unit_of_measurement: str = cv.UNDEFINED,
317
+ icon: str = cv.UNDEFINED,
318
+ accuracy_decimals: int = cv.UNDEFINED,
319
+ device_class: str = cv.UNDEFINED,
320
+ state_class: str = cv.UNDEFINED,
321
+ entity_category: str = cv.UNDEFINED,
317
322
  ) -> cv.Schema:
318
323
  schema = {}
319
324
 
320
- if class_ is not _UNDEF:
325
+ if class_ is not cv.UNDEFINED:
321
326
  # Not optional.
322
327
  schema[cv.GenerateID()] = cv.declare_id(class_)
323
328
 
@@ -329,10 +334,15 @@ def sensor_schema(
329
334
  (CONF_STATE_CLASS, state_class, validate_state_class),
330
335
  (CONF_ENTITY_CATEGORY, entity_category, sensor_entity_category),
331
336
  ]:
332
- if default is not _UNDEF:
337
+ if default is not cv.UNDEFINED:
333
338
  schema[cv.Optional(key, default=default)] = validator
334
339
 
335
- return SENSOR_SCHEMA.extend(schema)
340
+ return _SENSOR_SCHEMA.extend(schema)
341
+
342
+
343
+ # Remove before 2025.11.0
344
+ SENSOR_SCHEMA = sensor_schema()
345
+ SENSOR_SCHEMA.add_extra(cv.deprecated_schema_constant("sensor"))
336
346
 
337
347
 
338
348
  @FILTER_REGISTRY.register("offset", OffsetFilter, cv.templatable(cv.float_))
@@ -804,7 +814,9 @@ async def setup_sensor_core_(var, config):
804
814
  mqtt_ = cg.new_Pvariable(mqtt_id, var)
805
815
  await mqtt.register_mqtt_component(mqtt_, config)
806
816
 
807
- if (expire_after := config.get(CONF_EXPIRE_AFTER, _UNDEF)) is not _UNDEF:
817
+ if (
818
+ expire_after := config.get(CONF_EXPIRE_AFTER, cv.UNDEFINED)
819
+ ) is not cv.UNDEFINED:
808
820
  if expire_after is None:
809
821
  cg.add(mqtt_.disable_expire_after())
810
822
  else:
@@ -852,6 +864,138 @@ async def sensor_in_range_to_code(config, condition_id, template_arg, args):
852
864
  return var
853
865
 
854
866
 
867
+ def validate_ntc_calibration_parameter(value):
868
+ if isinstance(value, dict):
869
+ return cv.Schema(
870
+ {
871
+ cv.Required(CONF_TEMPERATURE): cv.temperature,
872
+ cv.Required(CONF_VALUE): cv.resistance,
873
+ }
874
+ )(value)
875
+
876
+ value = cv.string(value)
877
+ parts = value.split("->")
878
+ if len(parts) != 2:
879
+ raise cv.Invalid("Calibration parameter must be of form 3000 -> 23°C")
880
+ resistance = cv.resistance(parts[0].strip())
881
+ temperature = cv.temperature(parts[1].strip())
882
+ return validate_ntc_calibration_parameter(
883
+ {
884
+ CONF_TEMPERATURE: temperature,
885
+ CONF_VALUE: resistance,
886
+ }
887
+ )
888
+
889
+
890
+ CONF_A = "a"
891
+ CONF_B = "b"
892
+ CONF_C = "c"
893
+ ZERO_POINT = 273.15
894
+
895
+
896
+ def ntc_calc_steinhart_hart(value):
897
+ r1 = value[0][CONF_VALUE]
898
+ r2 = value[1][CONF_VALUE]
899
+ r3 = value[2][CONF_VALUE]
900
+ t1 = value[0][CONF_TEMPERATURE] + ZERO_POINT
901
+ t2 = value[1][CONF_TEMPERATURE] + ZERO_POINT
902
+ t3 = value[2][CONF_TEMPERATURE] + ZERO_POINT
903
+
904
+ l1 = math.log(r1)
905
+ l2 = math.log(r2)
906
+ l3 = math.log(r3)
907
+
908
+ y1 = 1 / t1
909
+ y2 = 1 / t2
910
+ y3 = 1 / t3
911
+
912
+ g2 = (y2 - y1) / (l2 - l1)
913
+ g3 = (y3 - y1) / (l3 - l1)
914
+
915
+ c = (g3 - g2) / (l3 - l2) * 1 / (l1 + l2 + l3)
916
+ b = g2 - c * (l1 * l1 + l1 * l2 + l2 * l2)
917
+ a = y1 - (b + l1 * l1 * c) * l1
918
+ return a, b, c
919
+
920
+
921
+ def ntc_get_abc(value):
922
+ a = value[CONF_A]
923
+ b = value[CONF_B]
924
+ c = value[CONF_C]
925
+ return a, b, c
926
+
927
+
928
+ def ntc_process_calibration(value):
929
+ if isinstance(value, dict):
930
+ value = cv.Schema(
931
+ {
932
+ cv.Required(CONF_A): cv.float_,
933
+ cv.Required(CONF_B): cv.float_,
934
+ cv.Required(CONF_C): cv.float_,
935
+ }
936
+ )(value)
937
+ a, b, c = ntc_get_abc(value)
938
+ elif isinstance(value, list):
939
+ if len(value) != 3:
940
+ raise cv.Invalid(
941
+ "Steinhart–Hart Calibration must consist of exactly three values"
942
+ )
943
+ value = cv.Schema([validate_ntc_calibration_parameter])(value)
944
+ a, b, c = ntc_calc_steinhart_hart(value)
945
+ else:
946
+ raise cv.Invalid(
947
+ f"Calibration parameter accepts either a list for steinhart-hart calibration, or mapping for b-constant calibration, not {type(value)}"
948
+ )
949
+ _LOGGER.info("Coefficient: a:%s, b:%s, c:%s", a, b, c)
950
+ return {
951
+ CONF_A: a,
952
+ CONF_B: b,
953
+ CONF_C: c,
954
+ }
955
+
956
+
957
+ @FILTER_REGISTRY.register(
958
+ "to_ntc_resistance",
959
+ ToNTCResistanceFilter,
960
+ cv.All(
961
+ cv.Schema(
962
+ {
963
+ cv.Required(CONF_CALIBRATION): ntc_process_calibration,
964
+ }
965
+ ),
966
+ ),
967
+ )
968
+ async def calibrate_ntc_resistance_filter_to_code(config, filter_id):
969
+ calib = config[CONF_CALIBRATION]
970
+ return cg.new_Pvariable(
971
+ filter_id,
972
+ calib[CONF_A],
973
+ calib[CONF_B],
974
+ calib[CONF_C],
975
+ )
976
+
977
+
978
+ @FILTER_REGISTRY.register(
979
+ "to_ntc_temperature",
980
+ ToNTCTemperatureFilter,
981
+ cv.All(
982
+ cv.Schema(
983
+ {
984
+ cv.Required(CONF_CALIBRATION): ntc_process_calibration,
985
+ }
986
+ ),
987
+ ),
988
+ )
989
+ async def calibrate_ntc_temperature_filter_to_code(config, filter_id):
990
+ calib = config[CONF_CALIBRATION]
991
+ return cg.new_Pvariable(
992
+ filter_id,
993
+ calib[CONF_A],
994
+ calib[CONF_B],
995
+ calib[CONF_C],
996
+ )
997
+
998
+
855
999
  def _mean(xs):
856
1000
  return sum(xs) / len(xs)
857
1001
 
@@ -481,5 +481,28 @@ optional<float> RoundMultipleFilter::new_value(float value) {
481
481
  return value;
482
482
  }
483
483
 
484
+ optional<float> ToNTCResistanceFilter::new_value(float value) {
485
+ if (!std::isfinite(value)) {
486
+ return NAN;
487
+ }
488
+ double k = 273.15;
489
+ // https://de.wikipedia.org/wiki/Steinhart-Hart-Gleichung#cite_note-stein2_s4-3
490
+ double t = value + k;
491
+ double y = (this->a_ - 1 / (t)) / (2 * this->c_);
492
+ double x = sqrt(pow(this->b_ / (3 * this->c_), 3) + y * y);
493
+ double resistance = exp(pow(x - y, 1 / 3.0) - pow(x + y, 1 / 3.0));
494
+ return resistance;
495
+ }
496
+
497
+ optional<float> ToNTCTemperatureFilter::new_value(float value) {
498
+ if (!std::isfinite(value)) {
499
+ return NAN;
500
+ }
501
+ double lr = log(double(value));
502
+ double v = this->a_ + this->b_ * lr + this->c_ * lr * lr * lr;
503
+ double temp = float(1.0 / v - 273.15);
504
+ return temp;
505
+ }
506
+
484
507
  } // namespace sensor
485
508
  } // namespace esphome
@@ -439,5 +439,27 @@ class RoundMultipleFilter : public Filter {
439
439
  float multiple_;
440
440
  };
441
441
 
442
+ class ToNTCResistanceFilter : public Filter {
443
+ public:
444
+ ToNTCResistanceFilter(double a, double b, double c) : a_(a), b_(b), c_(c) {}
445
+ optional<float> new_value(float value) override;
446
+
447
+ protected:
448
+ double a_;
449
+ double b_;
450
+ double c_;
451
+ };
452
+
453
+ class ToNTCTemperatureFilter : public Filter {
454
+ public:
455
+ ToNTCTemperatureFilter(double a, double b, double c) : a_(a), b_(b), c_(c) {}
456
+ optional<float> new_value(float value) override;
457
+
458
+ protected:
459
+ double a_;
460
+ double b_;
461
+ double c_;
462
+ };
463
+
442
464
  } // namespace sensor
443
465
  } // namespace esphome
@@ -3,6 +3,7 @@ from esphome.components import i2c, sensirion_common, sensor
3
3
  import esphome.config_validation as cv
4
4
  from esphome.const import (
5
5
  CONF_COMPENSATION,
6
+ CONF_GAIN_FACTOR,
6
7
  CONF_ID,
7
8
  CONF_STORE_BASELINE,
8
9
  CONF_TEMPERATURE_SOURCE,
@@ -24,7 +25,6 @@ SGP4xComponent = sgp4x_ns.class_(
24
25
  )
25
26
 
26
27
  CONF_ALGORITHM_TUNING = "algorithm_tuning"
27
- CONF_GAIN_FACTOR = "gain_factor"
28
28
  CONF_GATING_MAX_DURATION_MINUTES = "gating_max_duration_minutes"
29
29
  CONF_HUMIDITY_SOURCE = "humidity_source"
30
30
  CONF_INDEX_OFFSET = "index_offset"
@@ -12,14 +12,22 @@ void SHT4XComponent::start_heater_() {
12
12
  uint8_t cmd[] = {MEASURECOMMANDS[this->heater_command_]};
13
13
 
14
14
  ESP_LOGD(TAG, "Heater turning on");
15
- this->write(cmd, 1);
15
+ if (this->write(cmd, 1) != i2c::ERROR_OK) {
16
+ this->status_set_error("Failed to turn on heater");
17
+ }
16
18
  }
17
19
 
18
20
  void SHT4XComponent::setup() {
19
21
  ESP_LOGCONFIG(TAG, "Setting up sht4x...");
20
22
 
21
- if (this->duty_cycle_ > 0.0) {
22
- uint32_t heater_interval = (uint32_t) (this->heater_time_ / this->duty_cycle_);
23
+ auto err = this->write(nullptr, 0);
24
+ if (err != i2c::ERROR_OK) {
25
+ this->mark_failed();
26
+ return;
27
+ }
28
+
29
+ if (std::isfinite(this->duty_cycle_) && this->duty_cycle_ > 0.0f) {
30
+ uint32_t heater_interval = static_cast<uint32_t>(static_cast<uint16_t>(this->heater_time_) / this->duty_cycle_);
23
31
  ESP_LOGD(TAG, "Heater interval: %" PRIu32, heater_interval);
24
32
 
25
33
  if (this->heater_power_ == SHT4X_HEATERPOWER_HIGH) {
@@ -47,37 +55,50 @@ void SHT4XComponent::setup() {
47
55
  }
48
56
  }
49
57
 
50
- void SHT4XComponent::dump_config() { LOG_I2C_DEVICE(this); }
58
+ void SHT4XComponent::dump_config() {
59
+ ESP_LOGCONFIG(TAG, "SHT4x:");
60
+ LOG_I2C_DEVICE(this);
61
+ if (this->is_failed()) {
62
+ ESP_LOGE(TAG, "Communication with SHT4x failed!");
63
+ }
64
+ }
51
65
 
52
66
  void SHT4XComponent::update() {
53
67
  // Send command
54
- this->write_command(MEASURECOMMANDS[this->precision_]);
68
+ if (!this->write_command(MEASURECOMMANDS[this->precision_])) {
69
+ // Warning will be printed only if warning status is not set yet
70
+ this->status_set_warning("Failed to send measurement command");
71
+ return;
72
+ }
55
73
 
56
74
  this->set_timeout(10, [this]() {
57
75
  uint16_t buffer[2];
58
76
 
59
77
  // Read measurement
60
- bool read_status = this->read_data(buffer, 2);
78
+ if (!this->read_data(buffer, 2)) {
79
+ // Using ESP_LOGW to force the warning to be printed
80
+ ESP_LOGW(TAG, "Sensor read failed");
81
+ this->status_set_warning();
82
+ return;
83
+ }
61
84
 
62
- if (read_status) {
63
- // Evaluate and publish measurements
64
- if (this->temp_sensor_ != nullptr) {
65
- // Temp is contained in the first result word
66
- float sensor_value_temp = buffer[0];
67
- float temp = -45 + 175 * sensor_value_temp / 65535;
85
+ this->status_clear_warning();
68
86
 
69
- this->temp_sensor_->publish_state(temp);
70
- }
87
+ // Evaluate and publish measurements
88
+ if (this->temp_sensor_ != nullptr) {
89
+ // Temp is contained in the first result word
90
+ float sensor_value_temp = buffer[0];
91
+ float temp = -45 + 175 * sensor_value_temp / 65535;
92
+
93
+ this->temp_sensor_->publish_state(temp);
94
+ }
71
95
 
72
- if (this->humidity_sensor_ != nullptr) {
73
- // Relative humidity is in the second result word
74
- float sensor_value_rh = buffer[1];
75
- float rh = -6 + 125 * sensor_value_rh / 65535;
96
+ if (this->humidity_sensor_ != nullptr) {
97
+ // Relative humidity is in the second result word
98
+ float sensor_value_rh = buffer[1];
99
+ float rh = -6 + 125 * sensor_value_rh / 65535;
76
100
 
77
- this->humidity_sensor_->publish_state(rh);
78
- }
79
- } else {
80
- ESP_LOGD(TAG, "Sensor read failed");
101
+ this->humidity_sensor_->publish_state(rh);
81
102
  }
82
103
  });
83
104
  }
@@ -13,7 +13,7 @@ enum SHT4XPRECISION { SHT4X_PRECISION_HIGH = 0, SHT4X_PRECISION_MED, SHT4X_PRECI
13
13
 
14
14
  enum SHT4XHEATERPOWER { SHT4X_HEATERPOWER_HIGH, SHT4X_HEATERPOWER_MED, SHT4X_HEATERPOWER_LOW };
15
15
 
16
- enum SHT4XHEATERTIME { SHT4X_HEATERTIME_LONG = 1100, SHT4X_HEATERTIME_SHORT = 110 };
16
+ enum SHT4XHEATERTIME : uint16_t { SHT4X_HEATERTIME_LONG = 1100, SHT4X_HEATERTIME_SHORT = 110 };
17
17
 
18
18
  class SHT4XComponent : public PollingComponent, public sensirion_common::SensirionI2CDevice {
19
19
  public:
@@ -1,7 +1,7 @@
1
1
  import esphome.codegen as cg
2
2
  from esphome.components import text_sensor
3
3
  import esphome.config_validation as cv
4
- from esphome.const import CONF_FORMAT, CONF_ID
4
+ from esphome.const import CONF_FORMAT
5
5
 
6
6
  from .. import CONF_OBIS_CODE, CONF_SERVER_ID, CONF_SML_ID, Sml, obis_code, sml_ns
7
7
 
@@ -19,9 +19,8 @@ SML_TYPES = {
19
19
 
20
20
  SmlTextSensor = sml_ns.class_("SmlTextSensor", text_sensor.TextSensor, cg.Component)
21
21
 
22
- CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend(
22
+ CONFIG_SCHEMA = text_sensor.text_sensor_schema(SmlTextSensor).extend(
23
23
  {
24
- cv.GenerateID(): cv.declare_id(SmlTextSensor),
25
24
  cv.GenerateID(CONF_SML_ID): cv.use_id(Sml),
26
25
  cv.Required(CONF_OBIS_CODE): obis_code,
27
26
  cv.Optional(CONF_SERVER_ID, default=""): cv.string,
@@ -31,13 +30,12 @@ CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend(
31
30
 
32
31
 
33
32
  async def to_code(config):
34
- var = cg.new_Pvariable(
35
- config[CONF_ID],
33
+ var = await text_sensor.new_text_sensor(
34
+ config,
36
35
  config[CONF_SERVER_ID],
37
36
  config[CONF_OBIS_CODE],
38
37
  config[CONF_FORMAT],
39
38
  )
40
39
  await cg.register_component(var, config)
41
- await text_sensor.register_text_sensor(var, config)
42
40
  sml = await cg.get_variable(config[CONF_SML_ID])
43
41
  cg.add(sml.register_sml_listener(var))
File without changes
@@ -0,0 +1,97 @@
1
+ from esphome import automation
2
+ import esphome.codegen as cg
3
+ from esphome.components import microphone, sensor
4
+ import esphome.config_validation as cv
5
+ from esphome.const import (
6
+ CONF_ID,
7
+ CONF_MEASUREMENT_DURATION,
8
+ CONF_MICROPHONE,
9
+ DEVICE_CLASS_SOUND_PRESSURE,
10
+ PLATFORM_ESP32,
11
+ STATE_CLASS_MEASUREMENT,
12
+ UNIT_DECIBEL,
13
+ )
14
+
15
+ AUTOLOAD = ["audio"]
16
+ CODEOWNERS = ["@kahrendt"]
17
+ DEPENDENCIES = ["microphone"]
18
+
19
+
20
+ CONF_PASSIVE = "passive"
21
+ CONF_PEAK = "peak"
22
+ CONF_RMS = "rms"
23
+
24
+ sound_level_ns = cg.esphome_ns.namespace("sound_level")
25
+ SoundLevelComponent = sound_level_ns.class_("SoundLevelComponent", cg.Component)
26
+
27
+ StartAction = sound_level_ns.class_("StartAction", automation.Action)
28
+ StopAction = sound_level_ns.class_("StopAction", automation.Action)
29
+
30
+ CONFIG_SCHEMA = cv.All(
31
+ cv.Schema(
32
+ {
33
+ cv.GenerateID(): cv.declare_id(SoundLevelComponent),
34
+ cv.Optional(CONF_MEASUREMENT_DURATION, default="1000ms"): cv.All(
35
+ cv.positive_time_period_milliseconds,
36
+ cv.Range(
37
+ min=cv.TimePeriod(milliseconds=50),
38
+ max=cv.TimePeriod(seconds=60),
39
+ ),
40
+ ),
41
+ cv.Optional(
42
+ CONF_MICROPHONE, default={}
43
+ ): microphone.microphone_source_schema(
44
+ min_bits_per_sample=16,
45
+ max_bits_per_sample=16,
46
+ ),
47
+ cv.Required(CONF_PASSIVE): cv.boolean,
48
+ cv.Optional(CONF_PEAK): sensor.sensor_schema(
49
+ unit_of_measurement=UNIT_DECIBEL,
50
+ accuracy_decimals=1,
51
+ device_class=DEVICE_CLASS_SOUND_PRESSURE,
52
+ state_class=STATE_CLASS_MEASUREMENT,
53
+ ),
54
+ cv.Optional(CONF_RMS): sensor.sensor_schema(
55
+ unit_of_measurement=UNIT_DECIBEL,
56
+ accuracy_decimals=1,
57
+ device_class=DEVICE_CLASS_SOUND_PRESSURE,
58
+ state_class=STATE_CLASS_MEASUREMENT,
59
+ ),
60
+ }
61
+ ).extend(cv.COMPONENT_SCHEMA),
62
+ cv.only_on([PLATFORM_ESP32]),
63
+ )
64
+
65
+
66
+ async def to_code(config):
67
+ var = cg.new_Pvariable(config[CONF_ID])
68
+ await cg.register_component(var, config)
69
+
70
+ mic_source = await microphone.microphone_source_to_code(
71
+ config[CONF_MICROPHONE], passive=config[CONF_PASSIVE]
72
+ )
73
+ cg.add(var.set_microphone_source(mic_source))
74
+
75
+ cg.add(var.set_measurement_duration(config[CONF_MEASUREMENT_DURATION]))
76
+
77
+ if peak_config := config.get(CONF_PEAK):
78
+ sens = await sensor.new_sensor(peak_config)
79
+ cg.add(var.set_peak_sensor(sens))
80
+ if rms_config := config.get(CONF_RMS):
81
+ sens = await sensor.new_sensor(rms_config)
82
+ cg.add(var.set_rms_sensor(sens))
83
+
84
+
85
+ SOUND_LEVEL_ACTION_SCHEMA = automation.maybe_simple_id(
86
+ {
87
+ cv.GenerateID(): cv.use_id(SoundLevelComponent),
88
+ }
89
+ )
90
+
91
+
92
+ @automation.register_action("sound_level.start", StartAction, SOUND_LEVEL_ACTION_SCHEMA)
93
+ @automation.register_action("sound_level.stop", StopAction, SOUND_LEVEL_ACTION_SCHEMA)
94
+ async def sound_level_action_to_code(config, action_id, template_arg, args):
95
+ var = cg.new_Pvariable(action_id, template_arg)
96
+ await cg.register_parented(var, config[CONF_ID])
97
+ return var