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.
- esphome/__main__.py +16 -14
- esphome/components/ac_dimmer/ac_dimmer.cpp +3 -2
- esphome/components/adc/__init__.py +51 -34
- esphome/components/airthings_wave_base/__init__.py +1 -1
- esphome/components/alarm_control_panel/__init__.py +37 -2
- esphome/components/am43/cover/__init__.py +4 -5
- esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp +6 -4
- esphome/components/analog_threshold/analog_threshold_binary_sensor.h +4 -5
- esphome/components/analog_threshold/binary_sensor.py +10 -8
- esphome/components/anova/climate.py +4 -5
- esphome/components/api/__init__.py +25 -8
- esphome/components/api/api_connection.cpp +416 -662
- esphome/components/api/api_connection.h +256 -57
- esphome/components/api/api_frame_helper.cpp +232 -177
- esphome/components/api/api_frame_helper.h +61 -8
- esphome/components/api/api_noise_context.h +13 -4
- esphome/components/api/api_pb2.cpp +1422 -1
- esphome/components/api/api_pb2.h +255 -1
- esphome/components/api/api_pb2_service.cpp +162 -49
- esphome/components/api/api_pb2_service.h +90 -51
- esphome/components/api/api_pb2_size.h +361 -0
- esphome/components/api/api_server.cpp +110 -34
- esphome/components/api/api_server.h +8 -0
- esphome/components/api/proto.h +86 -17
- esphome/components/as3935_i2c/as3935_i2c.h +0 -3
- esphome/components/as7341/as7341.h +1 -1
- esphome/components/at581x/at581x.h +4 -4
- esphome/components/atm90e32/__init__.py +1 -0
- esphome/components/atm90e32/atm90e32.cpp +576 -199
- esphome/components/atm90e32/atm90e32.h +128 -31
- esphome/components/atm90e32/atm90e32_reg.h +4 -2
- esphome/components/atm90e32/button/__init__.py +62 -10
- esphome/components/atm90e32/button/atm90e32_button.cpp +63 -4
- esphome/components/atm90e32/button/atm90e32_button.h +36 -4
- esphome/components/atm90e32/number/__init__.py +130 -0
- esphome/components/atm90e32/number/atm90e32_number.h +16 -0
- esphome/components/atm90e32/sensor.py +21 -4
- esphome/components/atm90e32/text_sensor/__init__.py +48 -0
- esphome/components/audio/__init__.py +96 -49
- esphome/components/audio/audio.h +48 -0
- esphome/components/audio/audio_decoder.cpp +1 -1
- esphome/components/audio/audio_resampler.cpp +2 -0
- esphome/components/audio/audio_resampler.h +1 -0
- esphome/components/ballu/climate.py +2 -9
- esphome/components/bang_bang/climate.py +5 -6
- esphome/components/bedjet/bedjet_hub.cpp +1 -0
- esphome/components/bedjet/climate/__init__.py +3 -8
- esphome/components/bedjet/fan/__init__.py +2 -11
- esphome/components/binary/fan/__init__.py +13 -16
- esphome/components/binary_sensor/__init__.py +13 -10
- esphome/components/bl0906/constants.h +16 -16
- esphome/components/ble_client/text_sensor/__init__.py +3 -5
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +4 -6
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +136 -21
- esphome/components/bluetooth_proxy/bluetooth_proxy.h +7 -0
- esphome/components/button/__init__.py +11 -8
- esphome/components/canbus/canbus.cpp +3 -0
- esphome/components/canbus/canbus.h +16 -0
- esphome/components/ccs811/sensor.py +9 -6
- esphome/components/climate/__init__.py +35 -2
- esphome/components/climate/climate_mode.h +1 -1
- esphome/components/climate/climate_traits.h +63 -57
- esphome/components/climate_ir/__init__.py +57 -17
- esphome/components/climate_ir_lg/climate.py +2 -5
- esphome/components/climate_ir_lg/climate_ir_lg.cpp +7 -7
- esphome/components/climate_ir_lg/climate_ir_lg.h +1 -1
- esphome/components/color/__init__.py +2 -0
- esphome/components/const/__init__.py +5 -0
- esphome/components/coolix/climate.py +2 -9
- esphome/components/copy/cover/__init__.py +10 -9
- esphome/components/copy/fan/__init__.py +11 -9
- esphome/components/copy/lock/__init__.py +11 -9
- esphome/components/copy/text/__init__.py +9 -6
- esphome/components/cover/__init__.py +37 -2
- esphome/components/cse7766/cse7766.cpp +2 -1
- esphome/components/cst226/binary_sensor/__init__.py +28 -0
- esphome/components/cst226/binary_sensor/cs226_button.h +22 -0
- esphome/components/cst226/binary_sensor/cstt6_button.cpp +19 -0
- esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +27 -5
- esphome/components/cst226/touchscreen/cst226_touchscreen.h +10 -10
- esphome/components/current_based/cover.py +37 -36
- esphome/components/current_based/current_based_cover.cpp +2 -1
- esphome/components/daikin/climate.py +2 -9
- esphome/components/daikin/daikin.cpp +15 -9
- esphome/components/daikin/daikin.h +5 -5
- esphome/components/daikin_arc/climate.py +2 -7
- esphome/components/daikin_brc/climate.py +3 -5
- esphome/components/dallas_temp/dallas_temp.cpp +17 -24
- esphome/components/dallas_temp/dallas_temp.h +0 -1
- esphome/components/daly_bms/daly_bms.cpp +2 -1
- esphome/components/debug/debug_component.cpp +6 -1
- esphome/components/debug/debug_component.h +8 -0
- esphome/components/debug/debug_esp32.cpp +109 -254
- esphome/components/debug/sensor.py +14 -0
- esphome/components/deep_sleep/deep_sleep_esp32.cpp +13 -1
- esphome/components/delonghi/climate.py +2 -9
- esphome/components/demo/__init__.py +18 -20
- esphome/components/dfrobot_sen0395/switch/__init__.py +21 -22
- esphome/components/display/rect.cpp +4 -9
- esphome/components/display/rect.h +1 -1
- esphome/components/dps310/sensor.py +6 -6
- esphome/components/ee895/sensor.py +9 -9
- esphome/components/emmeti/climate.py +2 -9
- esphome/components/endstop/cover.py +17 -16
- esphome/components/endstop/endstop_cover.cpp +2 -1
- esphome/components/ens160_base/__init__.py +12 -9
- esphome/components/esp32/__init__.py +60 -3
- esphome/components/esp32/core.cpp +11 -5
- esphome/components/esp32/gpio.cpp +86 -24
- esphome/components/esp32/gpio.py +15 -16
- esphome/components/esp32/gpio_esp32.py +1 -2
- esphome/components/esp32/gpio_esp32_c2.py +1 -1
- esphome/components/esp32/gpio_esp32_c3.py +1 -1
- esphome/components/esp32/gpio_esp32_c6.py +1 -1
- esphome/components/esp32/gpio_esp32_h2.py +1 -1
- esphome/components/esp32_ble/ble.cpp +1 -8
- esphome/components/esp32_ble/ble.h +5 -3
- esphome/components/esp32_ble/ble_advertising.cpp +2 -1
- esphome/components/esp32_ble/ble_advertising.h +1 -0
- esphome/components/esp32_ble_server/__init__.py +3 -0
- esphome/components/esp32_ble_tracker/__init__.py +7 -1
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +192 -118
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +29 -3
- esphome/components/esp32_camera/__init__.py +1 -1
- esphome/components/esp32_camera/esp32_camera.cpp +2 -10
- esphome/components/esp32_camera/esp32_camera.h +1 -1
- esphome/components/esp32_can/esp32_can.cpp +1 -1
- esphome/components/esp32_improv/esp32_improv_component.cpp +1 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
- esphome/components/esp32_rmt_led_strip/led_strip.h +7 -5
- esphome/components/esp32_rmt_led_strip/light.py +9 -1
- esphome/components/esp32_touch/esp32_touch.cpp +1 -1
- esphome/components/esp8266/gpio.cpp +69 -8
- esphome/components/ethernet/ethernet_component.cpp +1 -1
- esphome/components/event/__init__.py +13 -10
- esphome/components/factory_reset/switch/__init__.py +7 -21
- esphome/components/fan/__init__.py +52 -5
- esphome/components/fastled_base/__init__.py +1 -4
- esphome/components/fastled_base/fastled_light.cpp +1 -1
- esphome/components/feedback/cover.py +38 -33
- esphome/components/feedback/feedback_cover.cpp +2 -1
- esphome/components/fujitsu_general/climate.py +2 -9
- esphome/components/gcja5/gcja5.cpp +2 -1
- esphome/components/gpio/one_wire/gpio_one_wire.cpp +45 -43
- esphome/components/gpio/one_wire/gpio_one_wire.h +2 -1
- esphome/components/gpio_expander/cached_gpio.h +22 -7
- esphome/components/gps/__init__.py +47 -17
- esphome/components/gps/gps.cpp +42 -23
- esphome/components/gps/gps.h +17 -13
- esphome/components/graph/__init__.py +1 -2
- esphome/components/gree/climate.py +4 -6
- esphome/components/gree/gree.cpp +16 -2
- esphome/components/gree/gree.h +2 -2
- esphome/components/growatt_solar/growatt_solar.cpp +2 -1
- esphome/components/haier/climate.py +37 -34
- esphome/components/hbridge/fan/__init__.py +19 -17
- esphome/components/he60r/cover.py +4 -5
- esphome/components/heatpumpir/climate.py +3 -6
- esphome/components/hitachi_ac344/climate.py +2 -9
- esphome/components/hitachi_ac424/climate.py +2 -9
- esphome/components/hlw8012/hlw8012.cpp +1 -1
- esphome/components/hm3301/hm3301.h +1 -1
- esphome/components/hte501/sensor.py +6 -6
- esphome/components/http_request/__init__.py +39 -6
- esphome/components/http_request/http_request.cpp +20 -0
- esphome/components/http_request/http_request.h +57 -15
- esphome/components/http_request/http_request_arduino.cpp +22 -6
- esphome/components/http_request/http_request_arduino.h +4 -3
- esphome/components/http_request/http_request_host.cpp +141 -0
- esphome/components/http_request/http_request_host.h +37 -0
- esphome/components/http_request/http_request_idf.cpp +35 -3
- esphome/components/http_request/http_request_idf.h +10 -3
- esphome/components/http_request/httplib.h +9691 -0
- esphome/components/http_request/update/__init__.py +11 -8
- esphome/components/hyt271/sensor.py +6 -6
- esphome/components/i2c/i2c.h +4 -0
- esphome/components/i2c/i2c_bus_esp_idf.cpp +1 -1
- esphome/components/i2s_audio/__init__.py +131 -22
- esphome/components/i2s_audio/i2s_audio.h +44 -4
- esphome/components/i2s_audio/media_player/__init__.py +19 -9
- esphome/components/i2s_audio/microphone/__init__.py +63 -5
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +351 -61
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +40 -6
- esphome/components/i2s_audio/speaker/__init__.py +31 -5
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +155 -19
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +17 -4
- esphome/components/ili9xxx/ili9xxx_init.h +1 -1
- esphome/components/image/__init__.py +37 -17
- esphome/components/image/image.cpp +25 -8
- esphome/components/internal_temperature/internal_temperature.cpp +6 -4
- esphome/components/key_collector/__init__.py +35 -0
- esphome/components/key_collector/key_collector.cpp +8 -0
- esphome/components/key_collector/key_collector.h +10 -0
- esphome/components/kuntze/kuntze.cpp +2 -1
- esphome/components/ld2410/ld2410.h +1 -1
- esphome/components/ld2450/ld2450.h +1 -1
- esphome/components/light/__init__.py +57 -0
- esphome/components/lock/__init__.py +51 -4
- esphome/components/lock/automation.h +2 -13
- esphome/components/logger/__init__.py +22 -0
- esphome/components/logger/logger.cpp +154 -103
- esphome/components/logger/logger.h +211 -36
- esphome/components/logger/task_log_buffer.cpp +138 -0
- esphome/components/logger/task_log_buffer.h +69 -0
- esphome/components/lvgl/__init__.py +13 -5
- esphome/components/lvgl/automation.py +50 -1
- esphome/components/lvgl/defines.py +0 -1
- esphome/components/lvgl/lv_validation.py +10 -1
- esphome/components/lvgl/lvgl_esphome.cpp +5 -1
- esphome/components/lvgl/schemas.py +14 -14
- esphome/components/lvgl/text/__init__.py +1 -2
- esphome/components/lvgl/widgets/arc.py +7 -6
- esphome/components/lvgl/widgets/buttonmatrix.py +3 -3
- esphome/components/lvgl/widgets/checkbox.py +2 -2
- esphome/components/lvgl/widgets/dropdown.py +2 -1
- esphome/components/lvgl/widgets/img.py +15 -12
- esphome/components/mapping/__init__.py +134 -0
- esphome/components/matrix_keypad/matrix_keypad.cpp +2 -1
- esphome/components/max7219digit/max7219digit.cpp +28 -27
- esphome/components/mdns/__init__.py +11 -5
- esphome/components/mdns/mdns_component.cpp +11 -5
- esphome/components/mdns/mdns_component.h +3 -2
- esphome/components/mdns/mdns_esp32.cpp +4 -3
- esphome/components/mdns/mdns_esp8266.cpp +4 -2
- esphome/components/mdns/mdns_libretiny.cpp +4 -2
- esphome/components/mdns/mdns_rp2040.cpp +4 -2
- esphome/components/media_player/__init__.py +40 -6
- esphome/components/mhz19/sensor.py +11 -7
- esphome/components/micro_wake_word/__init__.py +99 -31
- esphome/components/micro_wake_word/automation.h +54 -0
- esphome/components/micro_wake_word/micro_wake_word.cpp +331 -319
- esphome/components/micro_wake_word/micro_wake_word.h +58 -105
- esphome/components/micro_wake_word/preprocessor_settings.h +19 -2
- esphome/components/micro_wake_word/streaming_model.cpp +158 -41
- esphome/components/micro_wake_word/streaming_model.h +85 -13
- esphome/components/microphone/__init__.py +139 -9
- esphome/components/microphone/automation.h +14 -2
- esphome/components/microphone/microphone.cpp +21 -0
- esphome/components/microphone/microphone.h +14 -5
- esphome/components/microphone/microphone_source.cpp +95 -0
- esphome/components/microphone/microphone_source.h +80 -0
- esphome/components/mics_4514/sensor.py +25 -14
- esphome/components/midea/climate.py +3 -4
- esphome/components/midea_ir/climate.py +3 -5
- esphome/components/mipi_spi/__init__.py +15 -0
- esphome/components/mipi_spi/display.py +474 -0
- esphome/components/mipi_spi/mipi_spi.cpp +481 -0
- esphome/components/mipi_spi/mipi_spi.h +171 -0
- esphome/components/mipi_spi/models/__init__.py +65 -0
- esphome/components/mipi_spi/models/amoled.py +72 -0
- esphome/components/mipi_spi/models/commands.py +82 -0
- esphome/components/mipi_spi/models/cyd.py +10 -0
- esphome/components/mipi_spi/models/ili.py +749 -0
- esphome/components/mipi_spi/models/jc.py +260 -0
- esphome/components/mipi_spi/models/lanbon.py +15 -0
- esphome/components/mipi_spi/models/lilygo.py +60 -0
- esphome/components/mipi_spi/models/waveshare.py +139 -0
- esphome/components/mitsubishi/climate.py +2 -5
- esphome/components/mitsubishi/mitsubishi.cpp +9 -9
- esphome/components/mixer/speaker/mixer_speaker.cpp +12 -22
- esphome/components/mixer/speaker/mixer_speaker.h +1 -3
- esphome/components/mlx90393/sensor.py +5 -0
- esphome/components/mlx90393/sensor_mlx90393.cpp +195 -13
- esphome/components/mlx90393/sensor_mlx90393.h +21 -4
- esphome/components/modbus/modbus.cpp +2 -1
- esphome/components/mqtt/__init__.py +1 -1
- esphome/components/mqtt/mqtt_client.cpp +6 -2
- esphome/components/mqtt/mqtt_const.h +4 -0
- esphome/components/mqtt/mqtt_fan.cpp +39 -0
- esphome/components/mqtt/mqtt_fan.h +2 -0
- esphome/components/ms5611/sensor.py +6 -6
- esphome/components/ms8607/sensor.py +3 -3
- esphome/components/network/__init__.py +1 -1
- esphome/components/nextion/base_component.py +17 -16
- esphome/components/nextion/display.py +11 -2
- esphome/components/nextion/nextion.cpp +39 -1
- esphome/components/nextion/nextion.h +50 -0
- esphome/components/noblex/climate.py +2 -9
- esphome/components/number/__init__.py +12 -9
- esphome/components/one_wire/one_wire_bus.cpp +14 -10
- esphome/components/one_wire/one_wire_bus.h +14 -8
- esphome/components/online_image/bmp_image.cpp +48 -11
- esphome/components/online_image/bmp_image.h +2 -0
- esphome/components/opentherm/binary_sensor/__init__.py +2 -4
- esphome/components/opentherm/number/__init__.py +11 -20
- esphome/components/opentherm/sensor/__init__.py +3 -3
- esphome/components/opentherm/switch/__init__.py +3 -5
- esphome/components/output/lock/__init__.py +11 -9
- esphome/components/packages/__init__.py +33 -31
- esphome/components/packet_transport/__init__.py +201 -0
- esphome/components/packet_transport/binary_sensor.py +19 -0
- esphome/components/packet_transport/packet_transport.cpp +534 -0
- esphome/components/packet_transport/packet_transport.h +154 -0
- esphome/components/packet_transport/sensor.py +19 -0
- esphome/components/pca9685/pca9685_output.cpp +2 -1
- esphome/components/pid/climate.py +2 -4
- esphome/components/pm2005/__init__.py +1 -0
- esphome/components/pm2005/pm2005.cpp +123 -0
- esphome/components/pm2005/pm2005.h +46 -0
- esphome/components/pm2005/sensor.py +86 -0
- esphome/components/pmsa003i/pmsa003i.cpp +43 -16
- esphome/components/pmsa003i/pmsa003i.h +25 -25
- esphome/components/pmsx003/pmsx003.cpp +195 -230
- esphome/components/pmsx003/pmsx003.h +51 -33
- esphome/components/pmsx003/sensor.py +21 -11
- esphome/components/pn7150/pn7150.h +2 -2
- esphome/components/pn7160/pn7160.h +2 -2
- esphome/components/prometheus/prometheus_handler.cpp +174 -0
- esphome/components/prometheus/prometheus_handler.h +17 -0
- esphome/components/psram/__init__.py +7 -5
- esphome/components/pulse_meter/pulse_meter_sensor.cpp +32 -12
- esphome/components/pulse_meter/pulse_meter_sensor.h +5 -5
- esphome/components/pzem004t/pzem004t.cpp +2 -1
- esphome/components/qspi_dbi/__init__.py +0 -1
- esphome/components/qspi_dbi/display.py +2 -1
- esphome/components/qspi_dbi/models.py +1 -2
- esphome/components/remote_base/__init__.py +91 -0
- esphome/components/remote_base/beo4_protocol.cpp +153 -0
- esphome/components/remote_base/beo4_protocol.h +43 -0
- esphome/components/remote_base/gobox_protocol.cpp +131 -0
- esphome/components/remote_base/gobox_protocol.h +54 -0
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +16 -9
- esphome/components/resampler/speaker/resampler_speaker.cpp +12 -10
- esphome/components/resampler/speaker/resampler_speaker.h +1 -1
- esphome/components/rf_bridge/rf_bridge.cpp +2 -1
- esphome/components/scd30/sensor.py +2 -3
- esphome/components/scd4x/sensor.py +4 -5
- esphome/components/sdp3x/sensor.py +2 -1
- esphome/components/sds011/sds011.cpp +2 -1
- esphome/components/select/__init__.py +19 -20
- esphome/components/sen5x/sen5x.cpp +55 -36
- esphome/components/sen5x/sensor.py +1 -1
- esphome/components/senseair/sensor.py +3 -3
- esphome/components/sensor/__init__.py +158 -14
- esphome/components/sensor/filter.cpp +23 -0
- esphome/components/sensor/filter.h +22 -0
- esphome/components/sgp30/sensor.py +14 -16
- esphome/components/sgp4x/sensor.py +1 -1
- esphome/components/sht4x/sht4x.cpp +43 -22
- esphome/components/sht4x/sht4x.h +1 -1
- esphome/components/shtcx/sensor.py +6 -6
- esphome/components/slow_pwm/slow_pwm_output.cpp +2 -1
- esphome/components/sml/text_sensor/__init__.py +4 -6
- esphome/components/sound_level/__init__.py +0 -0
- esphome/components/sound_level/sensor.py +97 -0
- esphome/components/sound_level/sound_level.cpp +194 -0
- esphome/components/sound_level/sound_level.h +73 -0
- esphome/components/speaker/media_player/__init__.py +4 -8
- esphome/components/speaker/media_player/speaker_media_player.cpp +0 -18
- esphome/components/speaker/media_player/speaker_media_player.h +0 -11
- esphome/components/speaker/speaker.h +4 -7
- esphome/components/speed/fan/__init__.py +17 -16
- esphome/components/spi/spi.h +11 -1
- esphome/components/sprinkler/__init__.py +18 -19
- esphome/components/sprinkler/sprinkler.cpp +6 -5
- esphome/components/switch/__init__.py +32 -42
- esphome/components/syslog/__init__.py +41 -0
- esphome/components/syslog/esphome_syslog.cpp +49 -0
- esphome/components/syslog/esphome_syslog.h +27 -0
- esphome/components/t6615/sensor.py +3 -3
- esphome/components/t6615/t6615.cpp +2 -1
- esphome/components/tca9555/tca9555.cpp +11 -6
- esphome/components/tcl112/climate.py +2 -9
- esphome/components/template/alarm_control_panel/__init__.py +7 -6
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +21 -17
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +2 -1
- esphome/components/template/cover/__init__.py +27 -21
- esphome/components/template/fan/__init__.py +14 -12
- esphome/components/template/lock/__init__.py +20 -25
- esphome/components/template/lock/automation.h +18 -0
- esphome/components/template/text/__init__.py +4 -3
- esphome/components/template/valve/__init__.py +32 -21
- esphome/components/template/valve/automation.h +24 -0
- esphome/components/text/__init__.py +32 -1
- esphome/components/text_sensor/__init__.py +24 -29
- esphome/components/thermostat/climate.py +5 -5
- esphome/components/time_based/cover.py +17 -16
- esphome/components/time_based/time_based_cover.cpp +2 -1
- esphome/components/tm1638/switch/__init__.py +10 -7
- esphome/components/tormatic/cover.py +4 -5
- esphome/components/toshiba/climate.py +3 -5
- esphome/components/touchscreen/touchscreen.cpp +3 -1
- esphome/components/tt21100/touchscreen/tt21100.cpp +1 -1
- esphome/components/tuya/climate/__init__.py +5 -6
- esphome/components/tuya/cover/__init__.py +6 -11
- esphome/components/tuya/select/__init__.py +15 -5
- esphome/components/tuya/select/tuya_select.cpp +6 -1
- esphome/components/tuya/select/tuya_select.h +5 -1
- esphome/components/uart/packet_transport/__init__.py +20 -0
- esphome/components/uart/packet_transport/uart_transport.cpp +88 -0
- esphome/components/uart/packet_transport/uart_transport.h +41 -0
- esphome/components/uart/switch/uart_switch.cpp +2 -1
- esphome/components/udp/__init__.py +126 -128
- esphome/components/udp/automation.h +40 -0
- esphome/components/udp/binary_sensor.py +3 -25
- esphome/components/udp/packet_transport/__init__.py +29 -0
- esphome/components/udp/packet_transport/udp_transport.cpp +36 -0
- esphome/components/udp/packet_transport/udp_transport.h +28 -0
- esphome/components/udp/sensor.py +3 -25
- esphome/components/udp/udp_component.cpp +26 -470
- esphome/components/udp/udp_component.h +21 -128
- esphome/components/update/__init__.py +31 -1
- esphome/components/uponor_smatrix/climate/__init__.py +4 -9
- esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +2 -1
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +2 -1
- esphome/components/uptime/text_sensor/__init__.py +47 -7
- esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +12 -7
- esphome/components/uptime/text_sensor/uptime_text_sensor.h +19 -0
- esphome/components/valve/__init__.py +34 -3
- esphome/components/valve/automation.h +1 -19
- esphome/components/vl53l0x/sensor.py +11 -0
- esphome/components/vl53l0x/vl53l0x_sensor.cpp +5 -1
- esphome/components/vl53l0x/vl53l0x_sensor.h +2 -1
- esphome/components/voice_assistant/__init__.py +36 -10
- esphome/components/voice_assistant/voice_assistant.cpp +170 -144
- esphome/components/voice_assistant/voice_assistant.h +26 -25
- esphome/components/waveshare_epaper/display.py +6 -0
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +439 -37
- esphome/components/waveshare_epaper/waveshare_epaper.h +60 -11
- esphome/components/weikai/weikai.cpp +0 -52
- esphome/components/whirlpool/climate.py +3 -5
- esphome/components/whynter/climate.py +3 -5
- esphome/components/xpt2046/touchscreen/xpt2046.cpp +1 -1
- esphome/components/yashima/climate.py +6 -6
- esphome/components/zhlt01/climate.py +2 -7
- esphome/config.py +13 -13
- esphome/config_validation.py +38 -58
- esphome/const.py +15 -1
- esphome/core/__init__.py +2 -0
- esphome/core/application.cpp +27 -10
- esphome/core/application.h +9 -1
- esphome/core/automation.h +4 -3
- esphome/core/component.cpp +28 -7
- esphome/core/component.h +10 -1
- esphome/core/defines.h +23 -17
- esphome/core/doxygen.h +13 -0
- esphome/core/macros.h +4 -0
- esphome/core/scheduler.cpp +7 -1
- esphome/cpp_generator.py +6 -2
- esphome/dashboard/web_server.py +3 -3
- esphome/helpers.py +39 -0
- esphome/loader.py +4 -0
- esphome/log.py +15 -19
- esphome/mqtt.py +23 -10
- esphome/platformio_api.py +1 -1
- esphome/schema_extractors.py +0 -1
- esphome/voluptuous_schema.py +3 -1
- esphome/vscode.py +15 -0
- esphome/wizard.py +47 -37
- esphome/zeroconf.py +7 -3
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/METADATA +10 -11
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/RECORD +456 -396
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/WHEEL +1 -1
- esphome/components/esp32_ble/const_esp32c6.h +0 -74
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/entry_points.txt +0 -0
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/licenses/LICENSE +0 -0
- {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
|
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
|
-
|
25
|
-
START_MICROPHONE,
|
26
|
-
STARTING_MICROPHONE,
|
23
|
+
STARTING,
|
27
24
|
DETECTING_WAKE_WORD,
|
28
|
-
|
29
|
-
|
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::
|
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
|
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(
|
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,
|
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::
|
66
|
+
microphone::MicrophoneSource *microphone_source_{nullptr};
|
63
67
|
Trigger<std::string> *wake_word_detected_trigger_ = new Trigger<std::string>();
|
64
|
-
State state_{State::
|
65
|
-
HighFrequencyLoopRequester high_freq_;
|
68
|
+
State state_{State::STOPPED};
|
66
69
|
|
67
|
-
std::
|
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
|
-
|
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
|
-
//
|
82
|
-
|
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
|
-
|
92
|
+
// Used to send messages about the models' states to the main loop
|
93
|
+
QueueHandle_t detection_queue_;
|
86
94
|
|
87
|
-
|
88
|
-
|
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
|
-
|
93
|
-
|
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
|
98
|
-
/// @
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
111
|
-
///
|
112
|
-
|
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
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
#
|
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: %.
|
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: %.
|
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::
|
27
|
-
|
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_ =
|
55
|
-
tflite::GetModel(this->model_start_),
|
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
|
-
|
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
|
-
|
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->
|
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
|
-
|
150
|
+
this->ignore_windows_ = std::min(this->ignore_windows_ + 1, 0);
|
129
151
|
}
|
130
|
-
|
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,
|
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->
|
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
|
-
|
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
|
-
|
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
|
-
|
159
|
-
|
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,
|
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->
|
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
|
-
|
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
|
-
|
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
|