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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (457) hide show
  1. esphome/__main__.py +16 -14
  2. esphome/components/ac_dimmer/ac_dimmer.cpp +3 -2
  3. esphome/components/adc/__init__.py +51 -34
  4. esphome/components/airthings_wave_base/__init__.py +1 -1
  5. esphome/components/alarm_control_panel/__init__.py +37 -2
  6. esphome/components/am43/cover/__init__.py +4 -5
  7. esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp +6 -4
  8. esphome/components/analog_threshold/analog_threshold_binary_sensor.h +4 -5
  9. esphome/components/analog_threshold/binary_sensor.py +10 -8
  10. esphome/components/anova/climate.py +4 -5
  11. esphome/components/api/__init__.py +25 -8
  12. esphome/components/api/api_connection.cpp +416 -662
  13. esphome/components/api/api_connection.h +256 -57
  14. esphome/components/api/api_frame_helper.cpp +232 -177
  15. esphome/components/api/api_frame_helper.h +61 -8
  16. esphome/components/api/api_noise_context.h +13 -4
  17. esphome/components/api/api_pb2.cpp +1422 -1
  18. esphome/components/api/api_pb2.h +255 -1
  19. esphome/components/api/api_pb2_service.cpp +162 -49
  20. esphome/components/api/api_pb2_service.h +90 -51
  21. esphome/components/api/api_pb2_size.h +361 -0
  22. esphome/components/api/api_server.cpp +110 -34
  23. esphome/components/api/api_server.h +8 -0
  24. esphome/components/api/proto.h +86 -17
  25. esphome/components/as3935_i2c/as3935_i2c.h +0 -3
  26. esphome/components/as7341/as7341.h +1 -1
  27. esphome/components/at581x/at581x.h +4 -4
  28. esphome/components/atm90e32/__init__.py +1 -0
  29. esphome/components/atm90e32/atm90e32.cpp +576 -199
  30. esphome/components/atm90e32/atm90e32.h +128 -31
  31. esphome/components/atm90e32/atm90e32_reg.h +4 -2
  32. esphome/components/atm90e32/button/__init__.py +62 -10
  33. esphome/components/atm90e32/button/atm90e32_button.cpp +63 -4
  34. esphome/components/atm90e32/button/atm90e32_button.h +36 -4
  35. esphome/components/atm90e32/number/__init__.py +130 -0
  36. esphome/components/atm90e32/number/atm90e32_number.h +16 -0
  37. esphome/components/atm90e32/sensor.py +21 -4
  38. esphome/components/atm90e32/text_sensor/__init__.py +48 -0
  39. esphome/components/audio/__init__.py +96 -49
  40. esphome/components/audio/audio.h +48 -0
  41. esphome/components/audio/audio_decoder.cpp +1 -1
  42. esphome/components/audio/audio_resampler.cpp +2 -0
  43. esphome/components/audio/audio_resampler.h +1 -0
  44. esphome/components/ballu/climate.py +2 -9
  45. esphome/components/bang_bang/climate.py +5 -6
  46. esphome/components/bedjet/bedjet_hub.cpp +1 -0
  47. esphome/components/bedjet/climate/__init__.py +3 -8
  48. esphome/components/bedjet/fan/__init__.py +2 -11
  49. esphome/components/binary/fan/__init__.py +13 -16
  50. esphome/components/binary_sensor/__init__.py +13 -10
  51. esphome/components/bl0906/constants.h +16 -16
  52. esphome/components/ble_client/text_sensor/__init__.py +3 -5
  53. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +4 -6
  54. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +136 -21
  55. esphome/components/bluetooth_proxy/bluetooth_proxy.h +7 -0
  56. esphome/components/button/__init__.py +11 -8
  57. esphome/components/canbus/canbus.cpp +3 -0
  58. esphome/components/canbus/canbus.h +16 -0
  59. esphome/components/ccs811/sensor.py +9 -6
  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/cse7766/cse7766.cpp +2 -1
  76. esphome/components/cst226/binary_sensor/__init__.py +28 -0
  77. esphome/components/cst226/binary_sensor/cs226_button.h +22 -0
  78. esphome/components/cst226/binary_sensor/cstt6_button.cpp +19 -0
  79. esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +27 -5
  80. esphome/components/cst226/touchscreen/cst226_touchscreen.h +10 -10
  81. esphome/components/current_based/cover.py +37 -36
  82. esphome/components/current_based/current_based_cover.cpp +2 -1
  83. esphome/components/daikin/climate.py +2 -9
  84. esphome/components/daikin/daikin.cpp +15 -9
  85. esphome/components/daikin/daikin.h +5 -5
  86. esphome/components/daikin_arc/climate.py +2 -7
  87. esphome/components/daikin_brc/climate.py +3 -5
  88. esphome/components/dallas_temp/dallas_temp.cpp +17 -24
  89. esphome/components/dallas_temp/dallas_temp.h +0 -1
  90. esphome/components/daly_bms/daly_bms.cpp +2 -1
  91. esphome/components/debug/debug_component.cpp +6 -1
  92. esphome/components/debug/debug_component.h +8 -0
  93. esphome/components/debug/debug_esp32.cpp +109 -254
  94. esphome/components/debug/sensor.py +14 -0
  95. esphome/components/deep_sleep/deep_sleep_esp32.cpp +13 -1
  96. esphome/components/delonghi/climate.py +2 -9
  97. esphome/components/demo/__init__.py +18 -20
  98. esphome/components/dfrobot_sen0395/switch/__init__.py +21 -22
  99. esphome/components/display/rect.cpp +4 -9
  100. esphome/components/display/rect.h +1 -1
  101. esphome/components/dps310/sensor.py +6 -6
  102. esphome/components/ee895/sensor.py +9 -9
  103. esphome/components/emmeti/climate.py +2 -9
  104. esphome/components/endstop/cover.py +17 -16
  105. esphome/components/endstop/endstop_cover.cpp +2 -1
  106. esphome/components/ens160_base/__init__.py +12 -9
  107. esphome/components/esp32/__init__.py +60 -3
  108. esphome/components/esp32/core.cpp +11 -5
  109. esphome/components/esp32/gpio.cpp +86 -24
  110. esphome/components/esp32/gpio.py +15 -16
  111. esphome/components/esp32/gpio_esp32.py +1 -2
  112. esphome/components/esp32/gpio_esp32_c2.py +1 -1
  113. esphome/components/esp32/gpio_esp32_c3.py +1 -1
  114. esphome/components/esp32/gpio_esp32_c6.py +1 -1
  115. esphome/components/esp32/gpio_esp32_h2.py +1 -1
  116. esphome/components/esp32_ble/ble.cpp +1 -8
  117. esphome/components/esp32_ble/ble.h +5 -3
  118. esphome/components/esp32_ble/ble_advertising.cpp +2 -1
  119. esphome/components/esp32_ble/ble_advertising.h +1 -0
  120. esphome/components/esp32_ble_server/__init__.py +3 -0
  121. esphome/components/esp32_ble_tracker/__init__.py +7 -1
  122. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +192 -118
  123. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +29 -3
  124. esphome/components/esp32_camera/__init__.py +1 -1
  125. esphome/components/esp32_camera/esp32_camera.cpp +2 -10
  126. esphome/components/esp32_camera/esp32_camera.h +1 -1
  127. esphome/components/esp32_can/esp32_can.cpp +1 -1
  128. esphome/components/esp32_improv/esp32_improv_component.cpp +1 -1
  129. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  130. esphome/components/esp32_rmt_led_strip/led_strip.h +7 -5
  131. esphome/components/esp32_rmt_led_strip/light.py +9 -1
  132. esphome/components/esp32_touch/esp32_touch.cpp +1 -1
  133. esphome/components/esp8266/gpio.cpp +69 -8
  134. esphome/components/ethernet/ethernet_component.cpp +1 -1
  135. esphome/components/event/__init__.py +13 -10
  136. esphome/components/factory_reset/switch/__init__.py +7 -21
  137. esphome/components/fan/__init__.py +52 -5
  138. esphome/components/fastled_base/__init__.py +1 -4
  139. esphome/components/fastled_base/fastled_light.cpp +1 -1
  140. esphome/components/feedback/cover.py +38 -33
  141. esphome/components/feedback/feedback_cover.cpp +2 -1
  142. esphome/components/fujitsu_general/climate.py +2 -9
  143. esphome/components/gcja5/gcja5.cpp +2 -1
  144. esphome/components/gpio/one_wire/gpio_one_wire.cpp +45 -43
  145. esphome/components/gpio/one_wire/gpio_one_wire.h +2 -1
  146. esphome/components/gpio_expander/cached_gpio.h +22 -7
  147. esphome/components/gps/__init__.py +47 -17
  148. esphome/components/gps/gps.cpp +42 -23
  149. esphome/components/gps/gps.h +17 -13
  150. esphome/components/graph/__init__.py +1 -2
  151. esphome/components/gree/climate.py +4 -6
  152. esphome/components/gree/gree.cpp +16 -2
  153. esphome/components/gree/gree.h +2 -2
  154. esphome/components/growatt_solar/growatt_solar.cpp +2 -1
  155. esphome/components/haier/climate.py +37 -34
  156. esphome/components/hbridge/fan/__init__.py +19 -17
  157. esphome/components/he60r/cover.py +4 -5
  158. esphome/components/heatpumpir/climate.py +3 -6
  159. esphome/components/hitachi_ac344/climate.py +2 -9
  160. esphome/components/hitachi_ac424/climate.py +2 -9
  161. esphome/components/hlw8012/hlw8012.cpp +1 -1
  162. esphome/components/hm3301/hm3301.h +1 -1
  163. esphome/components/hte501/sensor.py +6 -6
  164. esphome/components/http_request/__init__.py +39 -6
  165. esphome/components/http_request/http_request.cpp +20 -0
  166. esphome/components/http_request/http_request.h +57 -15
  167. esphome/components/http_request/http_request_arduino.cpp +22 -6
  168. esphome/components/http_request/http_request_arduino.h +4 -3
  169. esphome/components/http_request/http_request_host.cpp +141 -0
  170. esphome/components/http_request/http_request_host.h +37 -0
  171. esphome/components/http_request/http_request_idf.cpp +35 -3
  172. esphome/components/http_request/http_request_idf.h +10 -3
  173. esphome/components/http_request/httplib.h +9691 -0
  174. esphome/components/http_request/update/__init__.py +11 -8
  175. esphome/components/hyt271/sensor.py +6 -6
  176. esphome/components/i2c/i2c.h +4 -0
  177. esphome/components/i2c/i2c_bus_esp_idf.cpp +1 -1
  178. esphome/components/i2s_audio/__init__.py +131 -22
  179. esphome/components/i2s_audio/i2s_audio.h +44 -4
  180. esphome/components/i2s_audio/media_player/__init__.py +19 -9
  181. esphome/components/i2s_audio/microphone/__init__.py +63 -5
  182. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +351 -61
  183. esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +40 -6
  184. esphome/components/i2s_audio/speaker/__init__.py +31 -5
  185. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +155 -19
  186. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +17 -4
  187. esphome/components/ili9xxx/ili9xxx_init.h +1 -1
  188. esphome/components/image/__init__.py +37 -17
  189. esphome/components/image/image.cpp +25 -8
  190. esphome/components/internal_temperature/internal_temperature.cpp +6 -4
  191. esphome/components/key_collector/__init__.py +35 -0
  192. esphome/components/key_collector/key_collector.cpp +8 -0
  193. esphome/components/key_collector/key_collector.h +10 -0
  194. esphome/components/kuntze/kuntze.cpp +2 -1
  195. esphome/components/ld2410/ld2410.h +1 -1
  196. esphome/components/ld2450/ld2450.h +1 -1
  197. esphome/components/light/__init__.py +57 -0
  198. esphome/components/lock/__init__.py +51 -4
  199. esphome/components/lock/automation.h +2 -13
  200. esphome/components/logger/__init__.py +22 -0
  201. esphome/components/logger/logger.cpp +154 -103
  202. esphome/components/logger/logger.h +211 -36
  203. esphome/components/logger/task_log_buffer.cpp +138 -0
  204. esphome/components/logger/task_log_buffer.h +69 -0
  205. esphome/components/lvgl/__init__.py +13 -5
  206. esphome/components/lvgl/automation.py +50 -1
  207. esphome/components/lvgl/defines.py +0 -1
  208. esphome/components/lvgl/lv_validation.py +10 -1
  209. esphome/components/lvgl/lvgl_esphome.cpp +5 -1
  210. esphome/components/lvgl/schemas.py +14 -14
  211. esphome/components/lvgl/text/__init__.py +1 -2
  212. esphome/components/lvgl/widgets/arc.py +7 -6
  213. esphome/components/lvgl/widgets/buttonmatrix.py +3 -3
  214. esphome/components/lvgl/widgets/checkbox.py +2 -2
  215. esphome/components/lvgl/widgets/dropdown.py +2 -1
  216. esphome/components/lvgl/widgets/img.py +15 -12
  217. esphome/components/mapping/__init__.py +134 -0
  218. esphome/components/matrix_keypad/matrix_keypad.cpp +2 -1
  219. esphome/components/max7219digit/max7219digit.cpp +28 -27
  220. esphome/components/mdns/__init__.py +11 -5
  221. esphome/components/mdns/mdns_component.cpp +11 -5
  222. esphome/components/mdns/mdns_component.h +3 -2
  223. esphome/components/mdns/mdns_esp32.cpp +4 -3
  224. esphome/components/mdns/mdns_esp8266.cpp +4 -2
  225. esphome/components/mdns/mdns_libretiny.cpp +4 -2
  226. esphome/components/mdns/mdns_rp2040.cpp +4 -2
  227. esphome/components/media_player/__init__.py +40 -6
  228. esphome/components/mhz19/sensor.py +11 -7
  229. esphome/components/micro_wake_word/__init__.py +99 -31
  230. esphome/components/micro_wake_word/automation.h +54 -0
  231. esphome/components/micro_wake_word/micro_wake_word.cpp +331 -319
  232. esphome/components/micro_wake_word/micro_wake_word.h +58 -105
  233. esphome/components/micro_wake_word/preprocessor_settings.h +19 -2
  234. esphome/components/micro_wake_word/streaming_model.cpp +158 -41
  235. esphome/components/micro_wake_word/streaming_model.h +85 -13
  236. esphome/components/microphone/__init__.py +139 -9
  237. esphome/components/microphone/automation.h +14 -2
  238. esphome/components/microphone/microphone.cpp +21 -0
  239. esphome/components/microphone/microphone.h +14 -5
  240. esphome/components/microphone/microphone_source.cpp +95 -0
  241. esphome/components/microphone/microphone_source.h +80 -0
  242. esphome/components/mics_4514/sensor.py +25 -14
  243. esphome/components/midea/climate.py +3 -4
  244. esphome/components/midea_ir/climate.py +3 -5
  245. esphome/components/mipi_spi/__init__.py +15 -0
  246. esphome/components/mipi_spi/display.py +474 -0
  247. esphome/components/mipi_spi/mipi_spi.cpp +481 -0
  248. esphome/components/mipi_spi/mipi_spi.h +171 -0
  249. esphome/components/mipi_spi/models/__init__.py +65 -0
  250. esphome/components/mipi_spi/models/amoled.py +72 -0
  251. esphome/components/mipi_spi/models/commands.py +82 -0
  252. esphome/components/mipi_spi/models/cyd.py +10 -0
  253. esphome/components/mipi_spi/models/ili.py +749 -0
  254. esphome/components/mipi_spi/models/jc.py +260 -0
  255. esphome/components/mipi_spi/models/lanbon.py +15 -0
  256. esphome/components/mipi_spi/models/lilygo.py +60 -0
  257. esphome/components/mipi_spi/models/waveshare.py +139 -0
  258. esphome/components/mitsubishi/climate.py +2 -5
  259. esphome/components/mitsubishi/mitsubishi.cpp +9 -9
  260. esphome/components/mixer/speaker/mixer_speaker.cpp +12 -22
  261. esphome/components/mixer/speaker/mixer_speaker.h +1 -3
  262. esphome/components/mlx90393/sensor.py +5 -0
  263. esphome/components/mlx90393/sensor_mlx90393.cpp +195 -13
  264. esphome/components/mlx90393/sensor_mlx90393.h +21 -4
  265. esphome/components/modbus/modbus.cpp +2 -1
  266. esphome/components/mqtt/__init__.py +1 -1
  267. esphome/components/mqtt/mqtt_client.cpp +6 -2
  268. esphome/components/mqtt/mqtt_const.h +4 -0
  269. esphome/components/mqtt/mqtt_fan.cpp +39 -0
  270. esphome/components/mqtt/mqtt_fan.h +2 -0
  271. esphome/components/ms5611/sensor.py +6 -6
  272. esphome/components/ms8607/sensor.py +3 -3
  273. esphome/components/network/__init__.py +1 -1
  274. esphome/components/nextion/base_component.py +17 -16
  275. esphome/components/nextion/display.py +11 -2
  276. esphome/components/nextion/nextion.cpp +39 -1
  277. esphome/components/nextion/nextion.h +50 -0
  278. esphome/components/noblex/climate.py +2 -9
  279. esphome/components/number/__init__.py +12 -9
  280. esphome/components/one_wire/one_wire_bus.cpp +14 -10
  281. esphome/components/one_wire/one_wire_bus.h +14 -8
  282. esphome/components/online_image/bmp_image.cpp +48 -11
  283. esphome/components/online_image/bmp_image.h +2 -0
  284. esphome/components/opentherm/binary_sensor/__init__.py +2 -4
  285. esphome/components/opentherm/number/__init__.py +11 -20
  286. esphome/components/opentherm/sensor/__init__.py +3 -3
  287. esphome/components/opentherm/switch/__init__.py +3 -5
  288. esphome/components/output/lock/__init__.py +11 -9
  289. esphome/components/packages/__init__.py +33 -31
  290. esphome/components/packet_transport/__init__.py +201 -0
  291. esphome/components/packet_transport/binary_sensor.py +19 -0
  292. esphome/components/packet_transport/packet_transport.cpp +534 -0
  293. esphome/components/packet_transport/packet_transport.h +154 -0
  294. esphome/components/packet_transport/sensor.py +19 -0
  295. esphome/components/pca9685/pca9685_output.cpp +2 -1
  296. esphome/components/pid/climate.py +2 -4
  297. esphome/components/pm2005/__init__.py +1 -0
  298. esphome/components/pm2005/pm2005.cpp +123 -0
  299. esphome/components/pm2005/pm2005.h +46 -0
  300. esphome/components/pm2005/sensor.py +86 -0
  301. esphome/components/pmsa003i/pmsa003i.cpp +43 -16
  302. esphome/components/pmsa003i/pmsa003i.h +25 -25
  303. esphome/components/pmsx003/pmsx003.cpp +195 -230
  304. esphome/components/pmsx003/pmsx003.h +51 -33
  305. esphome/components/pmsx003/sensor.py +21 -11
  306. esphome/components/pn7150/pn7150.h +2 -2
  307. esphome/components/pn7160/pn7160.h +2 -2
  308. esphome/components/prometheus/prometheus_handler.cpp +174 -0
  309. esphome/components/prometheus/prometheus_handler.h +17 -0
  310. esphome/components/psram/__init__.py +7 -5
  311. esphome/components/pulse_meter/pulse_meter_sensor.cpp +32 -12
  312. esphome/components/pulse_meter/pulse_meter_sensor.h +5 -5
  313. esphome/components/pzem004t/pzem004t.cpp +2 -1
  314. esphome/components/qspi_dbi/__init__.py +0 -1
  315. esphome/components/qspi_dbi/display.py +2 -1
  316. esphome/components/qspi_dbi/models.py +1 -2
  317. esphome/components/remote_base/__init__.py +91 -0
  318. esphome/components/remote_base/beo4_protocol.cpp +153 -0
  319. esphome/components/remote_base/beo4_protocol.h +43 -0
  320. esphome/components/remote_base/gobox_protocol.cpp +131 -0
  321. esphome/components/remote_base/gobox_protocol.h +54 -0
  322. esphome/components/remote_receiver/remote_receiver_esp32.cpp +16 -9
  323. esphome/components/resampler/speaker/resampler_speaker.cpp +12 -10
  324. esphome/components/resampler/speaker/resampler_speaker.h +1 -1
  325. esphome/components/rf_bridge/rf_bridge.cpp +2 -1
  326. esphome/components/scd30/sensor.py +2 -3
  327. esphome/components/scd4x/sensor.py +4 -5
  328. esphome/components/sdp3x/sensor.py +2 -1
  329. esphome/components/sds011/sds011.cpp +2 -1
  330. esphome/components/select/__init__.py +19 -20
  331. esphome/components/sen5x/sen5x.cpp +55 -36
  332. esphome/components/sen5x/sensor.py +1 -1
  333. esphome/components/senseair/sensor.py +3 -3
  334. esphome/components/sensor/__init__.py +158 -14
  335. esphome/components/sensor/filter.cpp +23 -0
  336. esphome/components/sensor/filter.h +22 -0
  337. esphome/components/sgp30/sensor.py +14 -16
  338. esphome/components/sgp4x/sensor.py +1 -1
  339. esphome/components/sht4x/sht4x.cpp +43 -22
  340. esphome/components/sht4x/sht4x.h +1 -1
  341. esphome/components/shtcx/sensor.py +6 -6
  342. esphome/components/slow_pwm/slow_pwm_output.cpp +2 -1
  343. esphome/components/sml/text_sensor/__init__.py +4 -6
  344. esphome/components/sound_level/__init__.py +0 -0
  345. esphome/components/sound_level/sensor.py +97 -0
  346. esphome/components/sound_level/sound_level.cpp +194 -0
  347. esphome/components/sound_level/sound_level.h +73 -0
  348. esphome/components/speaker/media_player/__init__.py +4 -8
  349. esphome/components/speaker/media_player/speaker_media_player.cpp +0 -18
  350. esphome/components/speaker/media_player/speaker_media_player.h +0 -11
  351. esphome/components/speaker/speaker.h +4 -7
  352. esphome/components/speed/fan/__init__.py +17 -16
  353. esphome/components/spi/spi.h +11 -1
  354. esphome/components/sprinkler/__init__.py +18 -19
  355. esphome/components/sprinkler/sprinkler.cpp +6 -5
  356. esphome/components/switch/__init__.py +32 -42
  357. esphome/components/syslog/__init__.py +41 -0
  358. esphome/components/syslog/esphome_syslog.cpp +49 -0
  359. esphome/components/syslog/esphome_syslog.h +27 -0
  360. esphome/components/t6615/sensor.py +3 -3
  361. esphome/components/t6615/t6615.cpp +2 -1
  362. esphome/components/tca9555/tca9555.cpp +11 -6
  363. esphome/components/tcl112/climate.py +2 -9
  364. esphome/components/template/alarm_control_panel/__init__.py +7 -6
  365. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +21 -17
  366. esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +2 -1
  367. esphome/components/template/cover/__init__.py +27 -21
  368. esphome/components/template/fan/__init__.py +14 -12
  369. esphome/components/template/lock/__init__.py +20 -25
  370. esphome/components/template/lock/automation.h +18 -0
  371. esphome/components/template/text/__init__.py +4 -3
  372. esphome/components/template/valve/__init__.py +32 -21
  373. esphome/components/template/valve/automation.h +24 -0
  374. esphome/components/text/__init__.py +32 -1
  375. esphome/components/text_sensor/__init__.py +24 -29
  376. esphome/components/thermostat/climate.py +5 -5
  377. esphome/components/time_based/cover.py +17 -16
  378. esphome/components/time_based/time_based_cover.cpp +2 -1
  379. esphome/components/tm1638/switch/__init__.py +10 -7
  380. esphome/components/tormatic/cover.py +4 -5
  381. esphome/components/toshiba/climate.py +3 -5
  382. esphome/components/touchscreen/touchscreen.cpp +3 -1
  383. esphome/components/tt21100/touchscreen/tt21100.cpp +1 -1
  384. esphome/components/tuya/climate/__init__.py +5 -6
  385. esphome/components/tuya/cover/__init__.py +6 -11
  386. esphome/components/tuya/select/__init__.py +15 -5
  387. esphome/components/tuya/select/tuya_select.cpp +6 -1
  388. esphome/components/tuya/select/tuya_select.h +5 -1
  389. esphome/components/uart/packet_transport/__init__.py +20 -0
  390. esphome/components/uart/packet_transport/uart_transport.cpp +88 -0
  391. esphome/components/uart/packet_transport/uart_transport.h +41 -0
  392. esphome/components/uart/switch/uart_switch.cpp +2 -1
  393. esphome/components/udp/__init__.py +126 -128
  394. esphome/components/udp/automation.h +40 -0
  395. esphome/components/udp/binary_sensor.py +3 -25
  396. esphome/components/udp/packet_transport/__init__.py +29 -0
  397. esphome/components/udp/packet_transport/udp_transport.cpp +36 -0
  398. esphome/components/udp/packet_transport/udp_transport.h +28 -0
  399. esphome/components/udp/sensor.py +3 -25
  400. esphome/components/udp/udp_component.cpp +26 -470
  401. esphome/components/udp/udp_component.h +21 -128
  402. esphome/components/update/__init__.py +31 -1
  403. esphome/components/uponor_smatrix/climate/__init__.py +4 -9
  404. esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +2 -1
  405. esphome/components/uponor_smatrix/uponor_smatrix.cpp +2 -1
  406. esphome/components/uptime/text_sensor/__init__.py +47 -7
  407. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +12 -7
  408. esphome/components/uptime/text_sensor/uptime_text_sensor.h +19 -0
  409. esphome/components/valve/__init__.py +34 -3
  410. esphome/components/valve/automation.h +1 -19
  411. esphome/components/vl53l0x/sensor.py +11 -0
  412. esphome/components/vl53l0x/vl53l0x_sensor.cpp +5 -1
  413. esphome/components/vl53l0x/vl53l0x_sensor.h +2 -1
  414. esphome/components/voice_assistant/__init__.py +36 -10
  415. esphome/components/voice_assistant/voice_assistant.cpp +170 -144
  416. esphome/components/voice_assistant/voice_assistant.h +26 -25
  417. esphome/components/waveshare_epaper/display.py +6 -0
  418. esphome/components/waveshare_epaper/waveshare_epaper.cpp +439 -37
  419. esphome/components/waveshare_epaper/waveshare_epaper.h +60 -11
  420. esphome/components/weikai/weikai.cpp +0 -52
  421. esphome/components/whirlpool/climate.py +3 -5
  422. esphome/components/whynter/climate.py +3 -5
  423. esphome/components/xpt2046/touchscreen/xpt2046.cpp +1 -1
  424. esphome/components/yashima/climate.py +6 -6
  425. esphome/components/zhlt01/climate.py +2 -7
  426. esphome/config.py +13 -13
  427. esphome/config_validation.py +38 -58
  428. esphome/const.py +15 -1
  429. esphome/core/__init__.py +2 -0
  430. esphome/core/application.cpp +27 -10
  431. esphome/core/application.h +9 -1
  432. esphome/core/automation.h +4 -3
  433. esphome/core/component.cpp +28 -7
  434. esphome/core/component.h +10 -1
  435. esphome/core/defines.h +23 -17
  436. esphome/core/doxygen.h +13 -0
  437. esphome/core/macros.h +4 -0
  438. esphome/core/scheduler.cpp +7 -1
  439. esphome/cpp_generator.py +6 -2
  440. esphome/dashboard/web_server.py +3 -3
  441. esphome/helpers.py +39 -0
  442. esphome/loader.py +4 -0
  443. esphome/log.py +15 -19
  444. esphome/mqtt.py +23 -10
  445. esphome/platformio_api.py +1 -1
  446. esphome/schema_extractors.py +0 -1
  447. esphome/voluptuous_schema.py +3 -1
  448. esphome/vscode.py +15 -0
  449. esphome/wizard.py +47 -37
  450. esphome/zeroconf.py +7 -3
  451. {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/METADATA +10 -11
  452. {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/RECORD +456 -396
  453. {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/WHEEL +1 -1
  454. esphome/components/esp32_ble/const_esp32c6.h +0 -74
  455. {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/entry_points.txt +0 -0
  456. {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/licenses/LICENSE +0 -0
  457. {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/top_level.txt +0 -0
@@ -5,33 +5,27 @@
5
5
  #include "preprocessor_settings.h"
6
6
  #include "streaming_model.h"
7
7
 
8
+ #include "esphome/components/microphone/microphone_source.h"
9
+
8
10
  #include "esphome/core/automation.h"
9
11
  #include "esphome/core/component.h"
10
12
  #include "esphome/core/ring_buffer.h"
11
13
 
12
- #include "esphome/components/microphone/microphone.h"
14
+ #include <freertos/event_groups.h>
13
15
 
16
+ #include <frontend.h>
14
17
  #include <frontend_util.h>
15
18
 
16
- #include <tensorflow/lite/core/c/common.h>
17
- #include <tensorflow/lite/micro/micro_interpreter.h>
18
- #include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
19
-
20
19
  namespace esphome {
21
20
  namespace micro_wake_word {
22
21
 
23
22
  enum State {
24
- IDLE,
25
- START_MICROPHONE,
26
- STARTING_MICROPHONE,
23
+ STARTING,
27
24
  DETECTING_WAKE_WORD,
28
- STOP_MICROPHONE,
29
- STOPPING_MICROPHONE,
25
+ STOPPING,
26
+ STOPPED,
30
27
  };
31
28
 
32
- // The number of audio slices to process before accepting a positive detection
33
- static const uint8_t MIN_SLICES_BEFORE_DETECTION = 74;
34
-
35
29
  class MicroWakeWord : public Component {
36
30
  public:
37
31
  void setup() override;
@@ -42,132 +36,91 @@ class MicroWakeWord : public Component {
42
36
  void start();
43
37
  void stop();
44
38
 
45
- bool is_running() const { return this->state_ != State::IDLE; }
39
+ bool is_running() const { return this->state_ != State::STOPPED; }
46
40
 
47
41
  void set_features_step_size(uint8_t step_size) { this->features_step_size_ = step_size; }
48
42
 
49
- void set_microphone(microphone::Microphone *microphone) { this->microphone_ = microphone; }
43
+ void set_microphone_source(microphone::MicrophoneSource *microphone_source) {
44
+ this->microphone_source_ = microphone_source;
45
+ }
46
+
47
+ void set_stop_after_detection(bool stop_after_detection) { this->stop_after_detection_ = stop_after_detection; }
50
48
 
51
49
  Trigger<std::string> *get_wake_word_detected_trigger() const { return this->wake_word_detected_trigger_; }
52
50
 
53
- void add_wake_word_model(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_average_size,
54
- const std::string &wake_word, size_t tensor_arena_size);
51
+ void add_wake_word_model(WakeWordModel *model);
55
52
 
56
53
  #ifdef USE_MICRO_WAKE_WORD_VAD
57
- void add_vad_model(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size,
54
+ void add_vad_model(const uint8_t *model_start, uint8_t probability_cutoff, size_t sliding_window_size,
58
55
  size_t tensor_arena_size);
56
+
57
+ // Intended for the voice assistant component to fetch VAD status
58
+ bool get_vad_state() { return this->vad_state_; }
59
59
  #endif
60
60
 
61
+ // Intended for the voice assistant component to access which wake words are available
62
+ // Since these are pointers to the WakeWordModel objects, the voice assistant component can enable or disable them
63
+ std::vector<WakeWordModel *> get_wake_words();
64
+
61
65
  protected:
62
- microphone::Microphone *microphone_{nullptr};
66
+ microphone::MicrophoneSource *microphone_source_{nullptr};
63
67
  Trigger<std::string> *wake_word_detected_trigger_ = new Trigger<std::string>();
64
- State state_{State::IDLE};
65
- HighFrequencyLoopRequester high_freq_;
68
+ State state_{State::STOPPED};
66
69
 
67
- std::unique_ptr<RingBuffer> ring_buffer_;
68
-
69
- std::vector<WakeWordModel> wake_word_models_;
70
+ std::weak_ptr<RingBuffer> ring_buffer_;
71
+ std::vector<WakeWordModel *> wake_word_models_;
70
72
 
71
73
  #ifdef USE_MICRO_WAKE_WORD_VAD
72
74
  std::unique_ptr<VADModel> vad_model_;
75
+ bool vad_state_{false};
73
76
  #endif
74
77
 
75
- tflite::MicroMutableOpResolver<20> streaming_op_resolver_;
78
+ bool pending_start_{false};
79
+ bool pending_stop_{false};
80
+
81
+ bool stop_after_detection_;
82
+
83
+ uint8_t features_step_size_;
76
84
 
77
85
  // Audio frontend handles generating spectrogram features
78
86
  struct FrontendConfig frontend_config_;
79
87
  struct FrontendState frontend_state_;
80
88
 
81
- // When the wake word detection first starts, we ignore this many audio
82
- // feature slices before accepting a positive detection
83
- int16_t ignore_windows_{-MIN_SLICES_BEFORE_DETECTION};
89
+ // Handles managing the stop/state of the inference task
90
+ EventGroupHandle_t event_group_;
84
91
 
85
- uint8_t features_step_size_;
92
+ // Used to send messages about the models' states to the main loop
93
+ QueueHandle_t detection_queue_;
86
94
 
87
- // Stores audio read from the microphone before being added to the ring buffer.
88
- int16_t *input_buffer_{nullptr};
89
- // Stores audio to be fed into the audio frontend for generating features.
90
- int16_t *preprocessor_audio_buffer_{nullptr};
95
+ static void inference_task(void *params);
96
+ TaskHandle_t inference_task_handle_{nullptr};
91
97
 
92
- bool detected_{false};
93
- std::string detected_wake_word_{""};
98
+ /// @brief Suspends the inference task
99
+ void suspend_task_();
100
+ /// @brief Resumes the inference task
101
+ void resume_task_();
94
102
 
95
103
  void set_state_(State state);
96
104
 
97
- /// @brief Tests if there are enough samples in the ring buffer to generate new features.
98
- /// @return True if enough samples, false otherwise.
99
- bool has_enough_samples_();
100
-
101
- /** Reads audio from microphone into the ring buffer
102
- *
103
- * Audio data (16000 kHz with int16 samples) is read into the input_buffer_.
104
- * Verifies the ring buffer has enough space for all audio data. If not, it logs
105
- * a warning and resets the ring buffer entirely.
106
- * @return Number of bytes written to the ring buffer
107
- */
108
- size_t read_microphone_();
105
+ /// @brief Generates spectrogram features from an input buffer of audio samples
106
+ /// @param audio_buffer (int16_t *) Buffer containing input audio samples
107
+ /// @param samples_available (size_t) Number of samples avaiable in the input buffer
108
+ /// @param features_buffer (int8_t *) Buffer to store generated features
109
+ /// @return (size_t) Number of samples processed from the input buffer
110
+ size_t generate_features_(int16_t *audio_buffer, size_t samples_available,
111
+ int8_t features_buffer[PREPROCESSOR_FEATURE_SIZE]);
109
112
 
110
- /// @brief Allocates memory for input_buffer_, preprocessor_audio_buffer_, and ring_buffer_
111
- /// @return True if successful, false otherwise
112
- bool allocate_buffers_();
113
+ /// @brief Processes any new probabilities for each model. If any wake word is detected, it will send a DetectionEvent
114
+ /// to the detection_queue_.
115
+ void process_probabilities_();
113
116
 
114
- /// @brief Frees memory allocated for input_buffer_ and preprocessor_audio_buffer_
115
- void deallocate_buffers_();
116
-
117
- /// @brief Loads streaming models and prepares the feature generation frontend
118
- /// @return True if successful, false otherwise
119
- bool load_models_();
120
-
121
- /// @brief Deletes each model's TFLite interpreters and frees tensor arena memory. Frees memory used by the feature
122
- /// generation frontend.
117
+ /// @brief Deletes each model's TFLite interpreters and frees tensor arena memory.
123
118
  void unload_models_();
124
119
 
125
- /** Performs inference with each configured model
126
- *
127
- * If enough audio samples are available, it will generate one slice of new features.
128
- * It then loops through and performs inference with each of the loaded models.
129
- */
130
- void update_model_probabilities_();
131
-
132
- /** Checks every model's recent probabilities to determine if the wake word has been predicted
133
- *
134
- * Verifies the models have processed enough new samples for accurate predictions.
135
- * Sets detected_wake_word_ to the wake word, if one is detected.
136
- * @return True if a wake word is predicted, false otherwise
137
- */
138
- bool detect_wake_words_();
139
-
140
- /** Generates features for a window of audio samples
141
- *
142
- * Reads samples from the ring buffer and feeds them into the preprocessor frontend.
143
- * Adapted from TFLite microspeech frontend.
144
- * @param features int8_t array to store the audio features
145
- * @return True if successful, false otherwise.
146
- */
147
- bool generate_features_for_window_(int8_t features[PREPROCESSOR_FEATURE_SIZE]);
148
-
149
- /// @brief Resets the ring buffer, ignore_windows_, and sliding window probabilities
150
- void reset_states_();
151
-
152
- /// @brief Returns true if successfully registered the streaming model's TensorFlow operations
153
- bool register_streaming_ops_(tflite::MicroMutableOpResolver<20> &op_resolver);
154
-
155
- inline uint16_t new_samples_to_get_() { return (this->features_step_size_ * (AUDIO_SAMPLE_FREQUENCY / 1000)); }
156
- };
157
-
158
- template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<MicroWakeWord> {
159
- public:
160
- void play(Ts... x) override { this->parent_->start(); }
161
- };
162
-
163
- template<typename... Ts> class StopAction : public Action<Ts...>, public Parented<MicroWakeWord> {
164
- public:
165
- void play(Ts... x) override { this->parent_->stop(); }
166
- };
167
-
168
- template<typename... Ts> class IsRunningCondition : public Condition<Ts...>, public Parented<MicroWakeWord> {
169
- public:
170
- bool check(Ts... x) override { return this->parent_->is_running(); }
120
+ /// @brief Runs an inference with each model using the new spectrogram features
121
+ /// @param audio_features (int8_t *) Buffer containing new spectrogram features
122
+ /// @return True if successful, false if any errors were encountered
123
+ bool update_model_probabilities_(const int8_t audio_features[PREPROCESSOR_FEATURE_SIZE]);
171
124
  };
172
125
 
173
126
  } // namespace micro_wake_word
@@ -7,13 +7,30 @@
7
7
  namespace esphome {
8
8
  namespace micro_wake_word {
9
9
 
10
+ // Settings for controlling the spectrogram feature generation by the preprocessor.
11
+ // These must match the settings used when training a particular model.
12
+ // All microWakeWord models have been trained with these specific paramters.
13
+
10
14
  // The number of features the audio preprocessor generates per slice
11
15
  static const uint8_t PREPROCESSOR_FEATURE_SIZE = 40;
12
16
  // Duration of each slice used as input into the preprocessor
13
17
  static const uint8_t FEATURE_DURATION_MS = 30;
14
- // Audio sample frequency in hertz
15
- static const uint16_t AUDIO_SAMPLE_FREQUENCY = 16000;
16
18
 
19
+ static const float FILTERBANK_LOWER_BAND_LIMIT = 125.0;
20
+ static const float FILTERBANK_UPPER_BAND_LIMIT = 7500.0;
21
+
22
+ static const uint8_t NOISE_REDUCTION_SMOOTHING_BITS = 10;
23
+ static const float NOISE_REDUCTION_EVEN_SMOOTHING = 0.025;
24
+ static const float NOISE_REDUCTION_ODD_SMOOTHING = 0.06;
25
+ static const float NOISE_REDUCTION_MIN_SIGNAL_REMAINING = 0.05;
26
+
27
+ static const bool PCAN_GAIN_CONTROL_ENABLE_PCAN = true;
28
+ static const float PCAN_GAIN_CONTROL_STRENGTH = 0.95;
29
+ static const float PCAN_GAIN_CONTROL_OFFSET = 80.0;
30
+ static const uint8_t PCAN_GAIN_CONTROL_GAIN_BITS = 21;
31
+
32
+ static const bool LOG_SCALE_ENABLE_LOG = true;
33
+ static const uint8_t LOG_SCALE_SCALE_SHIFT = 6;
17
34
  } // namespace micro_wake_word
18
35
  } // namespace esphome
19
36
 
@@ -1,8 +1,7 @@
1
- #ifdef USE_ESP_IDF
2
-
3
1
  #include "streaming_model.h"
4
2
 
5
- #include "esphome/core/hal.h"
3
+ #ifdef USE_ESP_IDF
4
+
6
5
  #include "esphome/core/helpers.h"
7
6
  #include "esphome/core/log.h"
8
7
 
@@ -13,18 +12,18 @@ namespace micro_wake_word {
13
12
 
14
13
  void WakeWordModel::log_model_config() {
15
14
  ESP_LOGCONFIG(TAG, " - Wake Word: %s", this->wake_word_.c_str());
16
- ESP_LOGCONFIG(TAG, " Probability cutoff: %.3f", this->probability_cutoff_);
15
+ ESP_LOGCONFIG(TAG, " Probability cutoff: %.2f", this->probability_cutoff_ / 255.0f);
17
16
  ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_size_);
18
17
  }
19
18
 
20
19
  void VADModel::log_model_config() {
21
20
  ESP_LOGCONFIG(TAG, " - VAD Model");
22
- ESP_LOGCONFIG(TAG, " Probability cutoff: %.3f", this->probability_cutoff_);
21
+ ESP_LOGCONFIG(TAG, " Probability cutoff: %.2f", this->probability_cutoff_ / 255.0f);
23
22
  ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_size_);
24
23
  }
25
24
 
26
- bool StreamingModel::load_model(tflite::MicroMutableOpResolver<20> &op_resolver) {
27
- ExternalRAMAllocator<uint8_t> arena_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
25
+ bool StreamingModel::load_model_() {
26
+ RAMAllocator<uint8_t> arena_allocator(RAMAllocator<uint8_t>::ALLOW_FAILURE);
28
27
 
29
28
  if (this->tensor_arena_ == nullptr) {
30
29
  this->tensor_arena_ = arena_allocator.allocate(this->tensor_arena_size_);
@@ -51,8 +50,9 @@ bool StreamingModel::load_model(tflite::MicroMutableOpResolver<20> &op_resolver)
51
50
  }
52
51
 
53
52
  if (this->interpreter_ == nullptr) {
54
- this->interpreter_ = make_unique<tflite::MicroInterpreter>(
55
- tflite::GetModel(this->model_start_), op_resolver, this->tensor_arena_, this->tensor_arena_size_, this->mrv_);
53
+ this->interpreter_ =
54
+ make_unique<tflite::MicroInterpreter>(tflite::GetModel(this->model_start_), this->streaming_op_resolver_,
55
+ this->tensor_arena_, this->tensor_arena_size_, this->mrv_);
56
56
  if (this->interpreter_->AllocateTensors() != kTfLiteOk) {
57
57
  ESP_LOGE(TAG, "Failed to allocate tensors for the streaming model");
58
58
  return false;
@@ -84,34 +84,55 @@ bool StreamingModel::load_model(tflite::MicroMutableOpResolver<20> &op_resolver)
84
84
  }
85
85
  }
86
86
 
87
+ this->loaded_ = true;
88
+ this->reset_probabilities();
87
89
  return true;
88
90
  }
89
91
 
90
92
  void StreamingModel::unload_model() {
91
93
  this->interpreter_.reset();
92
94
 
93
- ExternalRAMAllocator<uint8_t> arena_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
95
+ RAMAllocator<uint8_t> arena_allocator(RAMAllocator<uint8_t>::ALLOW_FAILURE);
96
+
97
+ if (this->tensor_arena_ != nullptr) {
98
+ arena_allocator.deallocate(this->tensor_arena_, this->tensor_arena_size_);
99
+ this->tensor_arena_ = nullptr;
100
+ }
101
+
102
+ if (this->var_arena_ != nullptr) {
103
+ arena_allocator.deallocate(this->var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
104
+ this->var_arena_ = nullptr;
105
+ }
94
106
 
95
- arena_allocator.deallocate(this->tensor_arena_, this->tensor_arena_size_);
96
- this->tensor_arena_ = nullptr;
97
- arena_allocator.deallocate(this->var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
98
- this->var_arena_ = nullptr;
107
+ this->loaded_ = false;
99
108
  }
100
109
 
101
110
  bool StreamingModel::perform_streaming_inference(const int8_t features[PREPROCESSOR_FEATURE_SIZE]) {
102
- if (this->interpreter_ != nullptr) {
111
+ if (this->enabled_ && !this->loaded_) {
112
+ // Model is enabled but isn't loaded
113
+ if (!this->load_model_()) {
114
+ return false;
115
+ }
116
+ }
117
+
118
+ if (!this->enabled_ && this->loaded_) {
119
+ // Model is disabled but still loaded
120
+ this->unload_model();
121
+ return true;
122
+ }
123
+
124
+ if (this->loaded_) {
103
125
  TfLiteTensor *input = this->interpreter_->input(0);
104
126
 
127
+ uint8_t stride = this->interpreter_->input(0)->dims->data[1];
128
+ this->current_stride_step_ = this->current_stride_step_ % stride;
129
+
105
130
  std::memmove(
106
131
  (int8_t *) (tflite::GetTensorData<int8_t>(input)) + PREPROCESSOR_FEATURE_SIZE * this->current_stride_step_,
107
132
  features, PREPROCESSOR_FEATURE_SIZE);
108
133
  ++this->current_stride_step_;
109
134
 
110
- uint8_t stride = this->interpreter_->input(0)->dims->data[1];
111
-
112
135
  if (this->current_stride_step_ >= stride) {
113
- this->current_stride_step_ = 0;
114
-
115
136
  TfLiteStatus invoke_status = this->interpreter_->Invoke();
116
137
  if (invoke_status != kTfLiteOk) {
117
138
  ESP_LOGW(TAG, "Streaming interpreter invoke failed");
@@ -124,65 +145,161 @@ bool StreamingModel::perform_streaming_inference(const int8_t features[PREPROCES
124
145
  if (this->last_n_index_ == this->sliding_window_size_)
125
146
  this->last_n_index_ = 0;
126
147
  this->recent_streaming_probabilities_[this->last_n_index_] = output->data.uint8[0]; // probability;
148
+ this->unprocessed_probability_status_ = true;
127
149
  }
128
- return true;
150
+ this->ignore_windows_ = std::min(this->ignore_windows_ + 1, 0);
129
151
  }
130
- ESP_LOGE(TAG, "Streaming interpreter is not initialized.");
131
- return false;
152
+ return true;
132
153
  }
133
154
 
134
155
  void StreamingModel::reset_probabilities() {
135
156
  for (auto &prob : this->recent_streaming_probabilities_) {
136
157
  prob = 0;
137
158
  }
159
+ this->ignore_windows_ = -MIN_SLICES_BEFORE_DETECTION;
138
160
  }
139
161
 
140
- WakeWordModel::WakeWordModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_average_size,
141
- const std::string &wake_word, size_t tensor_arena_size) {
162
+ WakeWordModel::WakeWordModel(const std::string &id, const uint8_t *model_start, uint8_t default_probability_cutoff,
163
+ size_t sliding_window_average_size, const std::string &wake_word, size_t tensor_arena_size,
164
+ bool default_enabled, bool internal_only) {
165
+ this->id_ = id;
142
166
  this->model_start_ = model_start;
143
- this->probability_cutoff_ = probability_cutoff;
167
+ this->default_probability_cutoff_ = default_probability_cutoff;
168
+ this->probability_cutoff_ = default_probability_cutoff;
144
169
  this->sliding_window_size_ = sliding_window_average_size;
145
170
  this->recent_streaming_probabilities_.resize(sliding_window_average_size, 0);
146
171
  this->wake_word_ = wake_word;
147
172
  this->tensor_arena_size_ = tensor_arena_size;
173
+ this->register_streaming_ops_(this->streaming_op_resolver_);
174
+ this->current_stride_step_ = 0;
175
+ this->internal_only_ = internal_only;
176
+
177
+ this->pref_ = global_preferences->make_preference<bool>(fnv1_hash(id));
178
+ bool enabled;
179
+ if (this->pref_.load(&enabled)) {
180
+ // Use the enabled state loaded from flash
181
+ this->enabled_ = enabled;
182
+ } else {
183
+ // If no state saved, then use the default
184
+ this->enabled_ = default_enabled;
185
+ }
148
186
  };
149
187
 
150
- bool WakeWordModel::determine_detected() {
188
+ void WakeWordModel::enable() {
189
+ this->enabled_ = true;
190
+ if (!this->internal_only_) {
191
+ this->pref_.save(&this->enabled_);
192
+ }
193
+ }
194
+
195
+ void WakeWordModel::disable() {
196
+ this->enabled_ = false;
197
+ if (!this->internal_only_) {
198
+ this->pref_.save(&this->enabled_);
199
+ }
200
+ }
201
+
202
+ DetectionEvent WakeWordModel::determine_detected() {
203
+ DetectionEvent detection_event;
204
+ detection_event.wake_word = &this->wake_word_;
205
+ detection_event.max_probability = 0;
206
+ detection_event.average_probability = 0;
207
+
208
+ if ((this->ignore_windows_ < 0) || !this->enabled_) {
209
+ detection_event.detected = false;
210
+ return detection_event;
211
+ }
212
+
151
213
  uint32_t sum = 0;
152
214
  for (auto &prob : this->recent_streaming_probabilities_) {
215
+ detection_event.max_probability = std::max(detection_event.max_probability, prob);
153
216
  sum += prob;
154
217
  }
155
218
 
156
- float sliding_window_average = static_cast<float>(sum) / static_cast<float>(255 * this->sliding_window_size_);
219
+ detection_event.average_probability = sum / this->sliding_window_size_;
220
+ detection_event.detected = sum > this->probability_cutoff_ * this->sliding_window_size_;
157
221
 
158
- // Detect the wake word if the sliding window average is above the cutoff
159
- if (sliding_window_average > this->probability_cutoff_) {
160
- ESP_LOGD(TAG, "The '%s' model sliding average probability is %.3f and most recent probability is %.3f",
161
- this->wake_word_.c_str(), sliding_window_average,
162
- this->recent_streaming_probabilities_[this->last_n_index_] / (255.0));
163
- return true;
164
- }
165
- return false;
222
+ this->unprocessed_probability_status_ = false;
223
+ return detection_event;
166
224
  }
167
225
 
168
- VADModel::VADModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size,
226
+ VADModel::VADModel(const uint8_t *model_start, uint8_t default_probability_cutoff, size_t sliding_window_size,
169
227
  size_t tensor_arena_size) {
170
228
  this->model_start_ = model_start;
171
- this->probability_cutoff_ = probability_cutoff;
229
+ this->default_probability_cutoff_ = default_probability_cutoff;
230
+ this->probability_cutoff_ = default_probability_cutoff;
172
231
  this->sliding_window_size_ = sliding_window_size;
173
232
  this->recent_streaming_probabilities_.resize(sliding_window_size, 0);
174
233
  this->tensor_arena_size_ = tensor_arena_size;
175
- };
234
+ this->register_streaming_ops_(this->streaming_op_resolver_);
235
+ }
236
+
237
+ DetectionEvent VADModel::determine_detected() {
238
+ DetectionEvent detection_event;
239
+ detection_event.max_probability = 0;
240
+ detection_event.average_probability = 0;
241
+
242
+ if (!this->enabled_) {
243
+ // We disabled the VAD model for some reason... so we shouldn't block wake words from being detected
244
+ detection_event.detected = true;
245
+ return detection_event;
246
+ }
176
247
 
177
- bool VADModel::determine_detected() {
178
248
  uint32_t sum = 0;
179
249
  for (auto &prob : this->recent_streaming_probabilities_) {
250
+ detection_event.max_probability = std::max(detection_event.max_probability, prob);
180
251
  sum += prob;
181
252
  }
182
253
 
183
- float sliding_window_average = static_cast<float>(sum) / static_cast<float>(255 * this->sliding_window_size_);
254
+ detection_event.average_probability = sum / this->sliding_window_size_;
255
+ detection_event.detected = sum > (this->probability_cutoff_ * this->sliding_window_size_);
256
+
257
+ return detection_event;
258
+ }
184
259
 
185
- return sliding_window_average > this->probability_cutoff_;
260
+ bool StreamingModel::register_streaming_ops_(tflite::MicroMutableOpResolver<20> &op_resolver) {
261
+ if (op_resolver.AddCallOnce() != kTfLiteOk)
262
+ return false;
263
+ if (op_resolver.AddVarHandle() != kTfLiteOk)
264
+ return false;
265
+ if (op_resolver.AddReshape() != kTfLiteOk)
266
+ return false;
267
+ if (op_resolver.AddReadVariable() != kTfLiteOk)
268
+ return false;
269
+ if (op_resolver.AddStridedSlice() != kTfLiteOk)
270
+ return false;
271
+ if (op_resolver.AddConcatenation() != kTfLiteOk)
272
+ return false;
273
+ if (op_resolver.AddAssignVariable() != kTfLiteOk)
274
+ return false;
275
+ if (op_resolver.AddConv2D() != kTfLiteOk)
276
+ return false;
277
+ if (op_resolver.AddMul() != kTfLiteOk)
278
+ return false;
279
+ if (op_resolver.AddAdd() != kTfLiteOk)
280
+ return false;
281
+ if (op_resolver.AddMean() != kTfLiteOk)
282
+ return false;
283
+ if (op_resolver.AddFullyConnected() != kTfLiteOk)
284
+ return false;
285
+ if (op_resolver.AddLogistic() != kTfLiteOk)
286
+ return false;
287
+ if (op_resolver.AddQuantize() != kTfLiteOk)
288
+ return false;
289
+ if (op_resolver.AddDepthwiseConv2D() != kTfLiteOk)
290
+ return false;
291
+ if (op_resolver.AddAveragePool2D() != kTfLiteOk)
292
+ return false;
293
+ if (op_resolver.AddMaxPool2D() != kTfLiteOk)
294
+ return false;
295
+ if (op_resolver.AddPad() != kTfLiteOk)
296
+ return false;
297
+ if (op_resolver.AddPack() != kTfLiteOk)
298
+ return false;
299
+ if (op_resolver.AddSplitV() != kTfLiteOk)
300
+ return false;
301
+
302
+ return true;
186
303
  }
187
304
 
188
305
  } // namespace micro_wake_word