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
@@ -18,14 +18,25 @@ static const char *const TAG = "voice_assistant";
18
18
  #endif
19
19
 
20
20
  static const size_t SAMPLE_RATE_HZ = 16000;
21
- static const size_t INPUT_BUFFER_SIZE = 32 * SAMPLE_RATE_HZ / 1000; // 32ms * 16kHz / 1000ms
22
- static const size_t BUFFER_SIZE = 512 * SAMPLE_RATE_HZ / 1000;
23
- static const size_t SEND_BUFFER_SIZE = INPUT_BUFFER_SIZE * sizeof(int16_t);
21
+
22
+ static const size_t RING_BUFFER_SAMPLES = 512 * SAMPLE_RATE_HZ / 1000; // 512 ms * 16 kHz/ 1000 ms
23
+ static const size_t RING_BUFFER_SIZE = RING_BUFFER_SAMPLES * sizeof(int16_t);
24
+ static const size_t SEND_BUFFER_SAMPLES = 32 * SAMPLE_RATE_HZ / 1000; // 32ms * 16kHz / 1000ms
25
+ static const size_t SEND_BUFFER_SIZE = SEND_BUFFER_SAMPLES * sizeof(int16_t);
24
26
  static const size_t RECEIVE_SIZE = 1024;
25
27
  static const size_t SPEAKER_BUFFER_SIZE = 16 * RECEIVE_SIZE;
26
28
 
27
29
  VoiceAssistant::VoiceAssistant() { global_voice_assistant = this; }
28
30
 
31
+ void VoiceAssistant::setup() {
32
+ this->mic_source_->add_data_callback([this](const std::vector<uint8_t> &data) {
33
+ std::shared_ptr<RingBuffer> temp_ring_buffer = this->ring_buffer_;
34
+ if (this->ring_buffer_.use_count() > 1) {
35
+ temp_ring_buffer->write((void *) data.data(), data.size());
36
+ }
37
+ });
38
+ }
39
+
29
40
  float VoiceAssistant::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
30
41
 
31
42
  bool VoiceAssistant::start_udp_socket_() {
@@ -72,12 +83,8 @@ bool VoiceAssistant::start_udp_socket_() {
72
83
  }
73
84
 
74
85
  bool VoiceAssistant::allocate_buffers_() {
75
- if (this->send_buffer_ != nullptr) {
76
- return true; // Already allocated
77
- }
78
-
79
86
  #ifdef USE_SPEAKER
80
- if (this->speaker_ != nullptr) {
87
+ if ((this->speaker_ != nullptr) && (this->speaker_buffer_ == nullptr)) {
81
88
  ExternalRAMAllocator<uint8_t> speaker_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
82
89
  this->speaker_buffer_ = speaker_allocator.allocate(SPEAKER_BUFFER_SIZE);
83
90
  if (this->speaker_buffer_ == nullptr) {
@@ -87,28 +94,21 @@ bool VoiceAssistant::allocate_buffers_() {
87
94
  }
88
95
  #endif
89
96
 
90
- ExternalRAMAllocator<int16_t> allocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE);
91
- this->input_buffer_ = allocator.allocate(INPUT_BUFFER_SIZE);
92
- if (this->input_buffer_ == nullptr) {
93
- ESP_LOGW(TAG, "Could not allocate input buffer");
94
- return false;
95
- }
96
-
97
- #ifdef USE_ESP_ADF
98
- this->vad_instance_ = vad_create(VAD_MODE_4);
99
- #endif
100
-
101
- this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t));
102
- if (this->ring_buffer_ == nullptr) {
103
- ESP_LOGW(TAG, "Could not allocate ring buffer");
104
- return false;
97
+ if (this->ring_buffer_.use_count() == 0) {
98
+ this->ring_buffer_ = RingBuffer::create(RING_BUFFER_SIZE);
99
+ if (this->ring_buffer_.use_count() == 0) {
100
+ ESP_LOGE(TAG, "Could not allocate ring buffer");
101
+ return false;
102
+ }
105
103
  }
106
104
 
107
- ExternalRAMAllocator<uint8_t> send_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
108
- this->send_buffer_ = send_allocator.allocate(SEND_BUFFER_SIZE);
109
- if (send_buffer_ == nullptr) {
110
- ESP_LOGW(TAG, "Could not allocate send buffer");
111
- return false;
105
+ if (this->send_buffer_ == nullptr) {
106
+ ExternalRAMAllocator<uint8_t> send_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
107
+ this->send_buffer_ = send_allocator.allocate(SEND_BUFFER_SIZE);
108
+ if (send_buffer_ == nullptr) {
109
+ ESP_LOGW(TAG, "Could not allocate send buffer");
110
+ return false;
111
+ }
112
112
  }
113
113
 
114
114
  return true;
@@ -119,10 +119,6 @@ void VoiceAssistant::clear_buffers_() {
119
119
  memset(this->send_buffer_, 0, SEND_BUFFER_SIZE);
120
120
  }
121
121
 
122
- if (this->input_buffer_ != nullptr) {
123
- memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t));
124
- }
125
-
126
122
  if (this->ring_buffer_ != nullptr) {
127
123
  this->ring_buffer_->reset();
128
124
  }
@@ -139,25 +135,15 @@ void VoiceAssistant::clear_buffers_() {
139
135
  }
140
136
 
141
137
  void VoiceAssistant::deallocate_buffers_() {
142
- ExternalRAMAllocator<uint8_t> send_deallocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
143
- send_deallocator.deallocate(this->send_buffer_, SEND_BUFFER_SIZE);
144
- this->send_buffer_ = nullptr;
145
-
146
- if (this->ring_buffer_ != nullptr) {
147
- this->ring_buffer_.reset();
148
- this->ring_buffer_ = nullptr;
138
+ if (this->send_buffer_ != nullptr) {
139
+ ExternalRAMAllocator<uint8_t> send_deallocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
140
+ send_deallocator.deallocate(this->send_buffer_, SEND_BUFFER_SIZE);
141
+ this->send_buffer_ = nullptr;
149
142
  }
150
143
 
151
- #ifdef USE_ESP_ADF
152
- if (this->vad_instance_ != nullptr) {
153
- vad_destroy(this->vad_instance_);
154
- this->vad_instance_ = nullptr;
144
+ if (this->ring_buffer_.use_count() > 0) {
145
+ this->ring_buffer_.reset();
155
146
  }
156
- #endif
157
-
158
- ExternalRAMAllocator<int16_t> input_deallocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE);
159
- input_deallocator.deallocate(this->input_buffer_, INPUT_BUFFER_SIZE);
160
- this->input_buffer_ = nullptr;
161
147
 
162
148
  #ifdef USE_SPEAKER
163
149
  if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) {
@@ -173,26 +159,10 @@ void VoiceAssistant::reset_conversation_id() {
173
159
  ESP_LOGD(TAG, "reset conversation ID");
174
160
  }
175
161
 
176
- int VoiceAssistant::read_microphone_() {
177
- size_t bytes_read = 0;
178
- if (this->mic_->is_running()) { // Read audio into input buffer
179
- bytes_read = this->mic_->read(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t));
180
- if (bytes_read == 0) {
181
- memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t));
182
- return 0;
183
- }
184
- // Write audio into ring buffer
185
- this->ring_buffer_->write((void *) this->input_buffer_, bytes_read);
186
- } else {
187
- ESP_LOGD(TAG, "microphone not running");
188
- }
189
- return bytes_read;
190
- }
191
-
192
162
  void VoiceAssistant::loop() {
193
163
  if (this->api_client_ == nullptr && this->state_ != State::IDLE && this->state_ != State::STOP_MICROPHONE &&
194
164
  this->state_ != State::STOPPING_MICROPHONE) {
195
- if (this->mic_->is_running() || this->state_ == State::STARTING_MICROPHONE) {
165
+ if (this->mic_source_->is_running() || this->state_ == State::STARTING_MICROPHONE) {
196
166
  this->set_state_(State::STOP_MICROPHONE, State::IDLE);
197
167
  } else {
198
168
  this->set_state_(State::IDLE, State::IDLE);
@@ -206,16 +176,9 @@ void VoiceAssistant::loop() {
206
176
  case State::IDLE: {
207
177
  if (this->continuous_ && this->desired_state_ == State::IDLE) {
208
178
  this->idle_trigger_->trigger();
209
- #ifdef USE_ESP_ADF
210
- if (this->use_wake_word_) {
211
- this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD);
212
- } else
213
- #endif
214
- {
215
- this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
216
- }
179
+ this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
217
180
  } else {
218
- this->high_freq_.stop();
181
+ this->deallocate_buffers_();
219
182
  }
220
183
  break;
221
184
  }
@@ -230,53 +193,20 @@ void VoiceAssistant::loop() {
230
193
  }
231
194
  this->clear_buffers_();
232
195
 
233
- this->mic_->start();
234
- this->high_freq_.start();
196
+ this->mic_source_->start();
235
197
  this->set_state_(State::STARTING_MICROPHONE);
236
198
  break;
237
199
  }
238
200
  case State::STARTING_MICROPHONE: {
239
- if (this->mic_->is_running()) {
201
+ if (this->mic_source_->is_running()) {
240
202
  this->set_state_(this->desired_state_);
241
203
  }
242
204
  break;
243
205
  }
244
- #ifdef USE_ESP_ADF
245
- case State::WAIT_FOR_VAD: {
246
- this->read_microphone_();
247
- ESP_LOGD(TAG, "Waiting for speech...");
248
- this->set_state_(State::WAITING_FOR_VAD);
249
- break;
250
- }
251
- case State::WAITING_FOR_VAD: {
252
- size_t bytes_read = this->read_microphone_();
253
- if (bytes_read > 0) {
254
- vad_state_t vad_state =
255
- vad_process(this->vad_instance_, this->input_buffer_, SAMPLE_RATE_HZ, VAD_FRAME_LENGTH_MS);
256
- if (vad_state == VAD_SPEECH) {
257
- if (this->vad_counter_ < this->vad_threshold_) {
258
- this->vad_counter_++;
259
- } else {
260
- ESP_LOGD(TAG, "VAD detected speech");
261
- this->set_state_(State::START_PIPELINE, State::STREAMING_MICROPHONE);
262
-
263
- // Reset for next time
264
- this->vad_counter_ = 0;
265
- }
266
- } else {
267
- if (this->vad_counter_ > 0) {
268
- this->vad_counter_--;
269
- }
270
- }
271
- }
272
- break;
273
- }
274
- #endif
275
206
  case State::START_PIPELINE: {
276
- this->read_microphone_();
277
207
  ESP_LOGD(TAG, "Requesting start...");
278
208
  uint32_t flags = 0;
279
- if (this->use_wake_word_)
209
+ if (!this->continue_conversation_ && this->use_wake_word_)
280
210
  flags |= api::enums::VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD;
281
211
  if (this->silence_detection_)
282
212
  flags |= api::enums::VOICE_ASSISTANT_REQUEST_USE_VAD;
@@ -306,11 +236,9 @@ void VoiceAssistant::loop() {
306
236
  break;
307
237
  }
308
238
  case State::STARTING_PIPELINE: {
309
- this->read_microphone_();
310
239
  break; // State changed when udp server port received
311
240
  }
312
241
  case State::STREAMING_MICROPHONE: {
313
- this->read_microphone_();
314
242
  size_t available = this->ring_buffer_->available();
315
243
  while (available >= SEND_BUFFER_SIZE) {
316
244
  size_t read_bytes = this->ring_buffer_->read((void *) this->send_buffer_, SEND_BUFFER_SIZE, 0);
@@ -334,8 +262,8 @@ void VoiceAssistant::loop() {
334
262
  break;
335
263
  }
336
264
  case State::STOP_MICROPHONE: {
337
- if (this->mic_->is_running()) {
338
- this->mic_->stop();
265
+ if (this->mic_source_->is_running()) {
266
+ this->mic_source_->stop();
339
267
  this->set_state_(State::STOPPING_MICROPHONE);
340
268
  } else {
341
269
  this->set_state_(this->desired_state_);
@@ -343,7 +271,7 @@ void VoiceAssistant::loop() {
343
271
  break;
344
272
  }
345
273
  case State::STOPPING_MICROPHONE: {
346
- if (this->mic_->is_stopped()) {
274
+ if (this->mic_source_->is_stopped()) {
347
275
  this->set_state_(this->desired_state_);
348
276
  }
349
277
  break;
@@ -387,6 +315,25 @@ void VoiceAssistant::loop() {
387
315
  #ifdef USE_MEDIA_PLAYER
388
316
  if (this->media_player_ != nullptr) {
389
317
  playing = (this->media_player_->state == media_player::MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING);
318
+
319
+ if (playing && this->media_player_wait_for_announcement_start_) {
320
+ // Announcement has started playing, wait for it to finish
321
+ this->media_player_wait_for_announcement_start_ = false;
322
+ this->media_player_wait_for_announcement_end_ = true;
323
+ }
324
+
325
+ if (!playing && this->media_player_wait_for_announcement_end_) {
326
+ // Announcement has finished playing
327
+ this->media_player_wait_for_announcement_end_ = false;
328
+ this->cancel_timeout("playing");
329
+ ESP_LOGD(TAG, "Announcement finished playing");
330
+ this->set_state_(State::RESPONSE_FINISHED, State::RESPONSE_FINISHED);
331
+
332
+ api::VoiceAssistantAnnounceFinished msg;
333
+ msg.success = true;
334
+ this->api_client_->send_voice_assistant_announce_finished(msg);
335
+ break;
336
+ }
390
337
  }
391
338
  #endif
392
339
  if (playing) {
@@ -417,7 +364,11 @@ void VoiceAssistant::loop() {
417
364
  this->tts_stream_end_trigger_->trigger();
418
365
  }
419
366
  #endif
420
- this->set_state_(State::IDLE, State::IDLE);
367
+ if (this->continue_conversation_) {
368
+ this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
369
+ } else {
370
+ this->set_state_(State::IDLE, State::IDLE);
371
+ }
421
372
  break;
422
373
  }
423
374
  default:
@@ -527,7 +478,7 @@ void VoiceAssistant::start_streaming() {
527
478
  ESP_LOGD(TAG, "Client started, streaming microphone");
528
479
  this->audio_mode_ = AUDIO_MODE_API;
529
480
 
530
- if (this->mic_->is_running()) {
481
+ if (this->mic_source_->is_running()) {
531
482
  this->set_state_(State::STREAMING_MICROPHONE, State::STREAMING_MICROPHONE);
532
483
  } else {
533
484
  this->set_state_(State::START_MICROPHONE, State::STREAMING_MICROPHONE);
@@ -557,7 +508,7 @@ void VoiceAssistant::start_streaming(struct sockaddr_storage *addr, uint16_t por
557
508
  return;
558
509
  }
559
510
 
560
- if (this->mic_->is_running()) {
511
+ if (this->mic_source_->is_running()) {
561
512
  this->set_state_(State::STREAMING_MICROPHONE, State::STREAMING_MICROPHONE);
562
513
  } else {
563
514
  this->set_state_(State::START_MICROPHONE, State::STREAMING_MICROPHONE);
@@ -574,19 +525,14 @@ void VoiceAssistant::request_start(bool continuous, bool silence_detection) {
574
525
  if (this->state_ == State::IDLE) {
575
526
  this->continuous_ = continuous;
576
527
  this->silence_detection_ = silence_detection;
577
- #ifdef USE_ESP_ADF
578
- if (this->use_wake_word_) {
579
- this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD);
580
- } else
581
- #endif
582
- {
583
- this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
584
- }
528
+
529
+ this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
585
530
  }
586
531
  }
587
532
 
588
533
  void VoiceAssistant::request_stop() {
589
534
  this->continuous_ = false;
535
+ this->continue_conversation_ = false;
590
536
 
591
537
  switch (this->state_) {
592
538
  case State::IDLE:
@@ -611,6 +557,16 @@ void VoiceAssistant::request_stop() {
611
557
  this->signal_stop_();
612
558
  break;
613
559
  case State::STREAMING_RESPONSE:
560
+ #ifdef USE_MEDIA_PLAYER
561
+ // Stop any ongoing media player announcement
562
+ if (this->media_player_ != nullptr) {
563
+ this->media_player_->make_call()
564
+ .set_command(media_player::MEDIA_PLAYER_COMMAND_STOP)
565
+ .set_announcement(true)
566
+ .perform();
567
+ }
568
+ #endif
569
+ break;
614
570
  case State::RESPONSE_FINISHED:
615
571
  break; // Let the incoming audio stream finish then it will go to idle.
616
572
  }
@@ -628,9 +584,9 @@ void VoiceAssistant::signal_stop_() {
628
584
  }
629
585
 
630
586
  void VoiceAssistant::start_playback_timeout_() {
631
- this->set_timeout("playing", 100, [this]() {
587
+ this->set_timeout("playing", 2000, [this]() {
632
588
  this->cancel_timeout("speaker-timeout");
633
- this->set_state_(State::IDLE, State::IDLE);
589
+ this->set_state_(State::RESPONSE_FINISHED, State::RESPONSE_FINISHED);
634
590
 
635
591
  api::VoiceAssistantAnnounceFinished msg;
636
592
  msg.success = true;
@@ -679,6 +635,8 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
679
635
  for (auto arg : msg.data) {
680
636
  if (arg.name == "conversation_id") {
681
637
  this->conversation_id_ = std::move(arg.value);
638
+ } else if (arg.name == "continue_conversation") {
639
+ this->continue_conversation_ = (arg.value == "1");
682
640
  }
683
641
  }
684
642
  this->defer([this]() { this->intent_end_trigger_->trigger(); });
@@ -722,6 +680,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
722
680
  #ifdef USE_MEDIA_PLAYER
723
681
  if (this->media_player_ != nullptr) {
724
682
  this->media_player_->make_call().set_media_url(url).set_announcement(true).perform();
683
+
684
+ this->media_player_wait_for_announcement_start_ = true;
685
+ this->media_player_wait_for_announcement_end_ = false;
725
686
  // Start the playback timeout, as the media player state isn't immediately updated
726
687
  this->start_playback_timeout_();
727
688
  }
@@ -734,21 +695,13 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
734
695
  }
735
696
  case api::enums::VOICE_ASSISTANT_RUN_END: {
736
697
  ESP_LOGD(TAG, "Assist Pipeline ended");
737
- if ((this->state_ == State::STARTING_PIPELINE) || (this->state_ == State::AWAITING_RESPONSE)) {
738
- // Pipeline ended before starting microphone
739
- // Or there wasn't a TTS start event ("nevermind")
698
+ if ((this->state_ == State::START_PIPELINE) || (this->state_ == State::STARTING_PIPELINE) ||
699
+ (this->state_ == State::STREAMING_MICROPHONE)) {
700
+ // Microphone is running, stop it
701
+ this->set_state_(State::STOP_MICROPHONE, State::IDLE);
702
+ } else if (this->state_ == State::AWAITING_RESPONSE) {
703
+ // No TTS start event ("nevermind")
740
704
  this->set_state_(State::IDLE, State::IDLE);
741
- } else if (this->state_ == State::STREAMING_MICROPHONE) {
742
- this->ring_buffer_->reset();
743
- #ifdef USE_ESP_ADF
744
- if (this->use_wake_word_) {
745
- // No need to stop the microphone since we didn't use the speaker
746
- this->set_state_(State::WAIT_FOR_VAD, State::WAITING_FOR_VAD);
747
- } else
748
- #endif
749
- {
750
- this->set_state_(State::IDLE, State::IDLE);
751
- }
752
705
  }
753
706
  this->defer([this]() { this->end_trigger_->trigger(); });
754
707
  break;
@@ -888,14 +841,87 @@ void VoiceAssistant::on_announce(const api::VoiceAssistantAnnounceRequest &msg)
888
841
  #ifdef USE_MEDIA_PLAYER
889
842
  if (this->media_player_ != nullptr) {
890
843
  this->tts_start_trigger_->trigger(msg.text);
891
- this->media_player_->make_call().set_media_url(msg.media_id).set_announcement(true).perform();
892
- this->set_state_(State::STREAMING_RESPONSE, State::STREAMING_RESPONSE);
844
+ if (!msg.preannounce_media_id.empty()) {
845
+ this->media_player_->make_call().set_media_url(msg.preannounce_media_id).set_announcement(true).perform();
846
+ }
847
+ // Enqueueing a URL with an empty playlist will still play the file immediately
848
+ this->media_player_->make_call()
849
+ .set_command(media_player::MEDIA_PLAYER_COMMAND_ENQUEUE)
850
+ .set_media_url(msg.media_id)
851
+ .set_announcement(true)
852
+ .perform();
853
+ this->continue_conversation_ = msg.start_conversation;
854
+
855
+ this->media_player_wait_for_announcement_start_ = true;
856
+ this->media_player_wait_for_announcement_end_ = false;
857
+ // Start the playback timeout, as the media player state isn't immediately updated
858
+ this->start_playback_timeout_();
859
+
860
+ if (this->continuous_) {
861
+ this->set_state_(State::STOP_MICROPHONE, State::STREAMING_RESPONSE);
862
+ } else {
863
+ this->set_state_(State::STREAMING_RESPONSE, State::STREAMING_RESPONSE);
864
+ }
865
+
893
866
  this->tts_end_trigger_->trigger(msg.media_id);
894
867
  this->end_trigger_->trigger();
895
868
  }
896
869
  #endif
897
870
  }
898
871
 
872
+ void VoiceAssistant::on_set_configuration(const std::vector<std::string> &active_wake_words) {
873
+ #ifdef USE_MICRO_WAKE_WORD
874
+ if (this->micro_wake_word_) {
875
+ // Disable all wake words first
876
+ for (auto &model : this->micro_wake_word_->get_wake_words()) {
877
+ model->disable();
878
+ }
879
+
880
+ // Enable only active wake words
881
+ for (auto ww_id : active_wake_words) {
882
+ for (auto &model : this->micro_wake_word_->get_wake_words()) {
883
+ if (model->get_id() == ww_id) {
884
+ model->enable();
885
+ ESP_LOGD(TAG, "Enabled wake word: %s (id=%s)", model->get_wake_word().c_str(), model->get_id().c_str());
886
+ }
887
+ }
888
+ }
889
+ }
890
+ #endif
891
+ };
892
+
893
+ const Configuration &VoiceAssistant::get_configuration() {
894
+ this->config_.available_wake_words.clear();
895
+ this->config_.active_wake_words.clear();
896
+
897
+ #ifdef USE_MICRO_WAKE_WORD
898
+ if (this->micro_wake_word_) {
899
+ this->config_.max_active_wake_words = 1;
900
+
901
+ for (auto &model : this->micro_wake_word_->get_wake_words()) {
902
+ if (model->is_enabled()) {
903
+ this->config_.active_wake_words.push_back(model->get_id());
904
+ }
905
+
906
+ WakeWord wake_word;
907
+ wake_word.id = model->get_id();
908
+ wake_word.wake_word = model->get_wake_word();
909
+ for (const auto &lang : model->get_trained_languages()) {
910
+ wake_word.trained_languages.push_back(lang);
911
+ }
912
+ this->config_.available_wake_words.push_back(std::move(wake_word));
913
+ }
914
+ } else {
915
+ #endif
916
+ // No microWakeWord
917
+ this->config_.max_active_wake_words = 0;
918
+ #ifdef USE_MICRO_WAKE_WORD
919
+ }
920
+ #endif
921
+
922
+ return this->config_;
923
+ };
924
+
899
925
  VoiceAssistant *global_voice_assistant = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
900
926
 
901
927
  } // namespace voice_assistant
@@ -11,18 +11,17 @@
11
11
 
12
12
  #include "esphome/components/api/api_connection.h"
13
13
  #include "esphome/components/api/api_pb2.h"
14
- #include "esphome/components/microphone/microphone.h"
15
- #ifdef USE_SPEAKER
16
- #include "esphome/components/speaker/speaker.h"
17
- #endif
14
+ #include "esphome/components/microphone/microphone_source.h"
18
15
  #ifdef USE_MEDIA_PLAYER
19
16
  #include "esphome/components/media_player/media_player.h"
20
17
  #endif
21
- #include "esphome/components/socket/socket.h"
22
-
23
- #ifdef USE_ESP_ADF
24
- #include <esp_vad.h>
18
+ #ifdef USE_MICRO_WAKE_WORD
19
+ #include "esphome/components/micro_wake_word/micro_wake_word.h"
20
+ #endif
21
+ #ifdef USE_SPEAKER
22
+ #include "esphome/components/speaker/speaker.h"
25
23
  #endif
24
+ #include "esphome/components/socket/socket.h"
26
25
 
27
26
  #include <unordered_map>
28
27
  #include <vector>
@@ -41,6 +40,7 @@ enum VoiceAssistantFeature : uint32_t {
41
40
  FEATURE_API_AUDIO = 1 << 2,
42
41
  FEATURE_TIMERS = 1 << 3,
43
42
  FEATURE_ANNOUNCE = 1 << 4,
43
+ FEATURE_START_CONVERSATION = 1 << 5,
44
44
  };
45
45
 
46
46
  enum class State {
@@ -95,12 +95,16 @@ class VoiceAssistant : public Component {
95
95
  VoiceAssistant();
96
96
 
97
97
  void loop() override;
98
+ void setup() override;
98
99
  float get_setup_priority() const override;
99
100
  void start_streaming();
100
101
  void start_streaming(struct sockaddr_storage *addr, uint16_t port);
101
102
  void failed_to_start();
102
103
 
103
- void set_microphone(microphone::Microphone *mic) { this->mic_ = mic; }
104
+ void set_microphone_source(microphone::MicrophoneSource *mic_source) { this->mic_source_ = mic_source; }
105
+ #ifdef USE_MICRO_WAKE_WORD
106
+ void set_micro_wake_word(micro_wake_word::MicroWakeWord *mww) { this->micro_wake_word_ = mww; }
107
+ #endif
104
108
  #ifdef USE_SPEAKER
105
109
  void set_speaker(speaker::Speaker *speaker) {
106
110
  this->speaker_ = speaker;
@@ -140,6 +144,7 @@ class VoiceAssistant : public Component {
140
144
  #ifdef USE_MEDIA_PLAYER
141
145
  if (this->media_player_ != nullptr) {
142
146
  flags |= VoiceAssistantFeature::FEATURE_ANNOUNCE;
147
+ flags |= VoiceAssistantFeature::FEATURE_START_CONVERSATION;
143
148
  }
144
149
  #endif
145
150
 
@@ -153,17 +158,14 @@ class VoiceAssistant : public Component {
153
158
  void on_audio(const api::VoiceAssistantAudio &msg);
154
159
  void on_timer_event(const api::VoiceAssistantTimerEventResponse &msg);
155
160
  void on_announce(const api::VoiceAssistantAnnounceRequest &msg);
156
- void on_set_configuration(const std::vector<std::string> &active_wake_words){};
157
- const Configuration &get_configuration() { return this->config_; };
161
+ void on_set_configuration(const std::vector<std::string> &active_wake_words);
162
+ const Configuration &get_configuration();
158
163
 
159
164
  bool is_running() const { return this->state_ != State::IDLE; }
160
165
  void set_continuous(bool continuous) { this->continuous_ = continuous; }
161
166
  bool is_continuous() const { return this->continuous_; }
162
167
 
163
168
  void set_use_wake_word(bool use_wake_word) { this->use_wake_word_ = use_wake_word; }
164
- #ifdef USE_ESP_ADF
165
- void set_vad_threshold(uint8_t vad_threshold) { this->vad_threshold_ = vad_threshold; }
166
- #endif
167
169
 
168
170
  void set_noise_suppression_level(uint8_t noise_suppression_level) {
169
171
  this->noise_suppression_level_ = noise_suppression_level;
@@ -212,7 +214,6 @@ class VoiceAssistant : public Component {
212
214
  void clear_buffers_();
213
215
  void deallocate_buffers_();
214
216
 
215
- int read_microphone_();
216
217
  void set_state_(State state);
217
218
  void set_state_(State state, State desired_state);
218
219
  void signal_stop_();
@@ -254,7 +255,7 @@ class VoiceAssistant : public Component {
254
255
  bool has_timers_{false};
255
256
  bool timer_tick_running_{false};
256
257
 
257
- microphone::Microphone *mic_{nullptr};
258
+ microphone::MicrophoneSource *mic_source_{nullptr};
258
259
  #ifdef USE_SPEAKER
259
260
  void write_speaker_();
260
261
  speaker::Speaker *speaker_{nullptr};
@@ -267,6 +268,8 @@ class VoiceAssistant : public Component {
267
268
  #endif
268
269
  #ifdef USE_MEDIA_PLAYER
269
270
  media_player::MediaPlayer *media_player_{nullptr};
271
+ bool media_player_wait_for_announcement_start_{false};
272
+ bool media_player_wait_for_announcement_end_{false};
270
273
  #endif
271
274
 
272
275
  bool local_output_{false};
@@ -275,14 +278,7 @@ class VoiceAssistant : public Component {
275
278
 
276
279
  std::string wake_word_{""};
277
280
 
278
- HighFrequencyLoopRequester high_freq_;
279
-
280
- #ifdef USE_ESP_ADF
281
- vad_handle_t vad_instance_;
282
- uint8_t vad_threshold_{5};
283
- uint8_t vad_counter_{0};
284
- #endif
285
- std::unique_ptr<RingBuffer> ring_buffer_;
281
+ std::shared_ptr<RingBuffer> ring_buffer_;
286
282
 
287
283
  bool use_wake_word_;
288
284
  uint8_t noise_suppression_level_;
@@ -291,11 +287,12 @@ class VoiceAssistant : public Component {
291
287
  uint32_t conversation_timeout_;
292
288
 
293
289
  uint8_t *send_buffer_{nullptr};
294
- int16_t *input_buffer_{nullptr};
295
290
 
296
291
  bool continuous_{false};
297
292
  bool silence_detection_;
298
293
 
294
+ bool continue_conversation_{false};
295
+
299
296
  State state_{State::IDLE};
300
297
  State desired_state_{State::IDLE};
301
298
 
@@ -304,6 +301,10 @@ class VoiceAssistant : public Component {
304
301
  bool start_udp_socket_();
305
302
 
306
303
  Configuration config_{};
304
+
305
+ #ifdef USE_MICRO_WAKE_WORD
306
+ micro_wake_word::MicroWakeWord *micro_wake_word_{nullptr};
307
+ #endif
307
308
  };
308
309
 
309
310
  template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<VoiceAssistant> {
@@ -70,12 +70,16 @@ WaveshareEPaper4P2InBV2 = waveshare_epaper_ns.class_(
70
70
  WaveshareEPaper4P2InBV2BWR = waveshare_epaper_ns.class_(
71
71
  "WaveshareEPaper4P2InBV2BWR", WaveshareEPaperBWR
72
72
  )
73
+ WaveshareEPaper5P65InF = waveshare_epaper_ns.class_(
74
+ "WaveshareEPaper5P65InF", WaveshareEPaper7C
75
+ )
73
76
  WaveshareEPaper5P8In = waveshare_epaper_ns.class_(
74
77
  "WaveshareEPaper5P8In", WaveshareEPaper
75
78
  )
76
79
  WaveshareEPaper5P8InV2 = waveshare_epaper_ns.class_(
77
80
  "WaveshareEPaper5P8InV2", WaveshareEPaper
78
81
  )
82
+ GDEY0583T81 = waveshare_epaper_ns.class_("GDEY0583T81", WaveshareEPaper)
79
83
  WaveshareEPaper7P3InF = waveshare_epaper_ns.class_(
80
84
  "WaveshareEPaper7P3InF", WaveshareEPaper7C
81
85
  )
@@ -150,8 +154,10 @@ MODELS = {
150
154
  "4.20in": ("b", WaveshareEPaper4P2In),
151
155
  "4.20in-bv2": ("b", WaveshareEPaper4P2InBV2),
152
156
  "4.20in-bv2-bwr": ("b", WaveshareEPaper4P2InBV2BWR),
157
+ "5.65in-f": ("b", WaveshareEPaper5P65InF),
153
158
  "5.83in": ("b", WaveshareEPaper5P8In),
154
159
  "5.83inv2": ("b", WaveshareEPaper5P8InV2),
160
+ "gdey0583t81": ("c", GDEY0583T81),
155
161
  "7.30in-f": ("b", WaveshareEPaper7P3InF),
156
162
  "7.50in": ("b", WaveshareEPaper7P5In),
157
163
  "7.50in-bv2": ("b", WaveshareEPaper7P5InBV2),