esphome 2025.4.2__py3-none-any.whl → 2025.5.0b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +81 -13
- esphome/components/api/api_connection.h +13 -1
- 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/as7341/as7341.h +1 -1
- 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 +6 -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/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 -0
- 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/esp32_camera.cpp +2 -1
- 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/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/lvgl_esphome.cpp +5 -1
- esphome/components/lvgl/text/__init__.py +1 -2
- 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 +33 -1
- 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/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/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 +23 -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/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.2.dist-info → esphome-2025.5.0b3.dist-info}/METADATA +10 -11
- {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/RECORD +440 -380
- {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/WHEEL +1 -1
- {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/entry_points.txt +0 -0
- {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
from esphome import automation
|
2
2
|
from esphome.automation import register_action, register_condition
|
3
3
|
import esphome.codegen as cg
|
4
|
-
from esphome.components import media_player, microphone, speaker
|
4
|
+
from esphome.components import media_player, micro_wake_word, microphone, speaker
|
5
5
|
import esphome.config_validation as cv
|
6
6
|
from esphome.const import (
|
7
7
|
CONF_ID,
|
@@ -41,6 +41,7 @@ CONF_AUTO_GAIN = "auto_gain"
|
|
41
41
|
CONF_NOISE_SUPPRESSION_LEVEL = "noise_suppression_level"
|
42
42
|
CONF_VOLUME_MULTIPLIER = "volume_multiplier"
|
43
43
|
|
44
|
+
CONF_MICRO_WAKE_WORD = "micro_wake_word"
|
44
45
|
CONF_WAKE_WORD = "wake_word"
|
45
46
|
|
46
47
|
CONF_CONVERSATION_TIMEOUT = "conversation_timeout"
|
@@ -88,14 +89,22 @@ CONFIG_SCHEMA = cv.All(
|
|
88
89
|
cv.Schema(
|
89
90
|
{
|
90
91
|
cv.GenerateID(): cv.declare_id(VoiceAssistant),
|
91
|
-
cv.
|
92
|
-
|
92
|
+
cv.Optional(
|
93
|
+
CONF_MICROPHONE, default={}
|
94
|
+
): microphone.microphone_source_schema(
|
95
|
+
min_bits_per_sample=16,
|
96
|
+
max_bits_per_sample=16,
|
97
|
+
min_channels=1,
|
98
|
+
max_channels=1,
|
99
|
+
),
|
93
100
|
cv.Exclusive(CONF_MEDIA_PLAYER, "output"): cv.use_id(
|
94
101
|
media_player.MediaPlayer
|
95
102
|
),
|
103
|
+
cv.Exclusive(CONF_SPEAKER, "output"): cv.use_id(speaker.Speaker),
|
96
104
|
cv.Optional(CONF_USE_WAKE_WORD, default=False): cv.boolean,
|
97
|
-
cv.Optional(
|
98
|
-
|
105
|
+
cv.Optional(CONF_MICRO_WAKE_WORD): cv.use_id(micro_wake_word.MicroWakeWord),
|
106
|
+
cv.Optional(CONF_VAD_THRESHOLD): cv.invalid(
|
107
|
+
"VAD threshold is no longer supported, as it requires the deprecated esp_adf external component. Use an i2s_audio microphone/speaker instead. Additionally, you may need to configure the audio_adc and audio_dac components depending on your hardware."
|
99
108
|
),
|
100
109
|
cv.Optional(CONF_NOISE_SUPPRESSION_LEVEL, default=0): cv.int_range(0, 4),
|
101
110
|
cv.Optional(CONF_AUTO_GAIN, default="0dBFS"): cv.All(
|
@@ -163,22 +172,39 @@ CONFIG_SCHEMA = cv.All(
|
|
163
172
|
tts_stream_validate,
|
164
173
|
)
|
165
174
|
|
175
|
+
FINAL_VALIDATE_SCHEMA = cv.All(
|
176
|
+
cv.Schema(
|
177
|
+
{
|
178
|
+
cv.Optional(
|
179
|
+
CONF_MICROPHONE
|
180
|
+
): microphone.final_validate_microphone_source_schema(
|
181
|
+
"voice_assistant", sample_rate=16000
|
182
|
+
),
|
183
|
+
},
|
184
|
+
extra=cv.ALLOW_EXTRA,
|
185
|
+
),
|
186
|
+
)
|
187
|
+
|
166
188
|
|
167
189
|
async def to_code(config):
|
168
190
|
var = cg.new_Pvariable(config[CONF_ID])
|
169
191
|
await cg.register_component(var, config)
|
170
192
|
|
171
|
-
|
172
|
-
cg.add(var.
|
193
|
+
mic_source = await microphone.microphone_source_to_code(config[CONF_MICROPHONE])
|
194
|
+
cg.add(var.set_microphone_source(mic_source))
|
173
195
|
|
174
|
-
if
|
175
|
-
|
176
|
-
cg.add(var.
|
196
|
+
if CONF_MICRO_WAKE_WORD in config:
|
197
|
+
mww = await cg.get_variable(config[CONF_MICRO_WAKE_WORD])
|
198
|
+
cg.add(var.set_micro_wake_word(mww))
|
177
199
|
|
178
200
|
if CONF_MEDIA_PLAYER in config:
|
179
201
|
mp = await cg.get_variable(config[CONF_MEDIA_PLAYER])
|
180
202
|
cg.add(var.set_media_player(mp))
|
181
203
|
|
204
|
+
if CONF_SPEAKER in config:
|
205
|
+
spkr = await cg.get_variable(config[CONF_SPEAKER])
|
206
|
+
cg.add(var.set_speaker(spkr))
|
207
|
+
|
182
208
|
cg.add(var.set_use_wake_word(config[CONF_USE_WAKE_WORD]))
|
183
209
|
|
184
210
|
if (vad_threshold := config.get(CONF_VAD_THRESHOLD)) is not None:
|
@@ -18,14 +18,25 @@ static const char *const TAG = "voice_assistant";
|
|
18
18
|
#endif
|
19
19
|
|
20
20
|
static const size_t SAMPLE_RATE_HZ = 16000;
|
21
|
-
|
22
|
-
static const size_t
|
23
|
-
static const size_t
|
21
|
+
|
22
|
+
static const size_t RING_BUFFER_SAMPLES = 512 * SAMPLE_RATE_HZ / 1000; // 512 ms * 16 kHz/ 1000 ms
|
23
|
+
static const size_t RING_BUFFER_SIZE = RING_BUFFER_SAMPLES * sizeof(int16_t);
|
24
|
+
static const size_t SEND_BUFFER_SAMPLES = 32 * SAMPLE_RATE_HZ / 1000; // 32ms * 16kHz / 1000ms
|
25
|
+
static const size_t SEND_BUFFER_SIZE = SEND_BUFFER_SAMPLES * sizeof(int16_t);
|
24
26
|
static const size_t RECEIVE_SIZE = 1024;
|
25
27
|
static const size_t SPEAKER_BUFFER_SIZE = 16 * RECEIVE_SIZE;
|
26
28
|
|
27
29
|
VoiceAssistant::VoiceAssistant() { global_voice_assistant = this; }
|
28
30
|
|
31
|
+
void VoiceAssistant::setup() {
|
32
|
+
this->mic_source_->add_data_callback([this](const std::vector<uint8_t> &data) {
|
33
|
+
std::shared_ptr<RingBuffer> temp_ring_buffer = this->ring_buffer_;
|
34
|
+
if (this->ring_buffer_.use_count() > 1) {
|
35
|
+
temp_ring_buffer->write((void *) data.data(), data.size());
|
36
|
+
}
|
37
|
+
});
|
38
|
+
}
|
39
|
+
|
29
40
|
float VoiceAssistant::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
|
30
41
|
|
31
42
|
bool VoiceAssistant::start_udp_socket_() {
|
@@ -72,12 +83,8 @@ bool VoiceAssistant::start_udp_socket_() {
|
|
72
83
|
}
|
73
84
|
|
74
85
|
bool VoiceAssistant::allocate_buffers_() {
|
75
|
-
if (this->send_buffer_ != nullptr) {
|
76
|
-
return true; // Already allocated
|
77
|
-
}
|
78
|
-
|
79
86
|
#ifdef USE_SPEAKER
|
80
|
-
if (this->speaker_ != nullptr) {
|
87
|
+
if ((this->speaker_ != nullptr) && (this->speaker_buffer_ == nullptr)) {
|
81
88
|
ExternalRAMAllocator<uint8_t> speaker_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
82
89
|
this->speaker_buffer_ = speaker_allocator.allocate(SPEAKER_BUFFER_SIZE);
|
83
90
|
if (this->speaker_buffer_ == nullptr) {
|
@@ -87,28 +94,21 @@ bool VoiceAssistant::allocate_buffers_() {
|
|
87
94
|
}
|
88
95
|
#endif
|
89
96
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
#ifdef USE_ESP_ADF
|
98
|
-
this->vad_instance_ = vad_create(VAD_MODE_4);
|
99
|
-
#endif
|
100
|
-
|
101
|
-
this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t));
|
102
|
-
if (this->ring_buffer_ == nullptr) {
|
103
|
-
ESP_LOGW(TAG, "Could not allocate ring buffer");
|
104
|
-
return false;
|
97
|
+
if (this->ring_buffer_.use_count() == 0) {
|
98
|
+
this->ring_buffer_ = RingBuffer::create(RING_BUFFER_SIZE);
|
99
|
+
if (this->ring_buffer_.use_count() == 0) {
|
100
|
+
ESP_LOGE(TAG, "Could not allocate ring buffer");
|
101
|
+
return false;
|
102
|
+
}
|
105
103
|
}
|
106
104
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
105
|
+
if (this->send_buffer_ == nullptr) {
|
106
|
+
ExternalRAMAllocator<uint8_t> send_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
107
|
+
this->send_buffer_ = send_allocator.allocate(SEND_BUFFER_SIZE);
|
108
|
+
if (send_buffer_ == nullptr) {
|
109
|
+
ESP_LOGW(TAG, "Could not allocate send buffer");
|
110
|
+
return false;
|
111
|
+
}
|
112
112
|
}
|
113
113
|
|
114
114
|
return true;
|
@@ -119,10 +119,6 @@ void VoiceAssistant::clear_buffers_() {
|
|
119
119
|
memset(this->send_buffer_, 0, SEND_BUFFER_SIZE);
|
120
120
|
}
|
121
121
|
|
122
|
-
if (this->input_buffer_ != nullptr) {
|
123
|
-
memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t));
|
124
|
-
}
|
125
|
-
|
126
122
|
if (this->ring_buffer_ != nullptr) {
|
127
123
|
this->ring_buffer_->reset();
|
128
124
|
}
|
@@ -139,25 +135,15 @@ void VoiceAssistant::clear_buffers_() {
|
|
139
135
|
}
|
140
136
|
|
141
137
|
void VoiceAssistant::deallocate_buffers_() {
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
if (this->ring_buffer_ != nullptr) {
|
147
|
-
this->ring_buffer_.reset();
|
148
|
-
this->ring_buffer_ = nullptr;
|
138
|
+
if (this->send_buffer_ != nullptr) {
|
139
|
+
ExternalRAMAllocator<uint8_t> send_deallocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
140
|
+
send_deallocator.deallocate(this->send_buffer_, SEND_BUFFER_SIZE);
|
141
|
+
this->send_buffer_ = nullptr;
|
149
142
|
}
|
150
143
|
|
151
|
-
|
152
|
-
|
153
|
-
vad_destroy(this->vad_instance_);
|
154
|
-
this->vad_instance_ = nullptr;
|
144
|
+
if (this->ring_buffer_.use_count() > 0) {
|
145
|
+
this->ring_buffer_.reset();
|
155
146
|
}
|
156
|
-
#endif
|
157
|
-
|
158
|
-
ExternalRAMAllocator<int16_t> input_deallocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE);
|
159
|
-
input_deallocator.deallocate(this->input_buffer_, INPUT_BUFFER_SIZE);
|
160
|
-
this->input_buffer_ = nullptr;
|
161
147
|
|
162
148
|
#ifdef USE_SPEAKER
|
163
149
|
if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) {
|
@@ -173,26 +159,10 @@ void VoiceAssistant::reset_conversation_id() {
|
|
173
159
|
ESP_LOGD(TAG, "reset conversation ID");
|
174
160
|
}
|
175
161
|
|
176
|
-
int VoiceAssistant::read_microphone_() {
|
177
|
-
size_t bytes_read = 0;
|
178
|
-
if (this->mic_->is_running()) { // Read audio into input buffer
|
179
|
-
bytes_read = this->mic_->read(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t));
|
180
|
-
if (bytes_read == 0) {
|
181
|
-
memset(this->input_buffer_, 0, INPUT_BUFFER_SIZE * sizeof(int16_t));
|
182
|
-
return 0;
|
183
|
-
}
|
184
|
-
// Write audio into ring buffer
|
185
|
-
this->ring_buffer_->write((void *) this->input_buffer_, bytes_read);
|
186
|
-
} else {
|
187
|
-
ESP_LOGD(TAG, "microphone not running");
|
188
|
-
}
|
189
|
-
return bytes_read;
|
190
|
-
}
|
191
|
-
|
192
162
|
void VoiceAssistant::loop() {
|
193
163
|
if (this->api_client_ == nullptr && this->state_ != State::IDLE && this->state_ != State::STOP_MICROPHONE &&
|
194
164
|
this->state_ != State::STOPPING_MICROPHONE) {
|
195
|
-
if (this->
|
165
|
+
if (this->mic_source_->is_running() || this->state_ == State::STARTING_MICROPHONE) {
|
196
166
|
this->set_state_(State::STOP_MICROPHONE, State::IDLE);
|
197
167
|
} else {
|
198
168
|
this->set_state_(State::IDLE, State::IDLE);
|
@@ -206,16 +176,9 @@ void VoiceAssistant::loop() {
|
|
206
176
|
case State::IDLE: {
|
207
177
|
if (this->continuous_ && this->desired_state_ == State::IDLE) {
|
208
178
|
this->idle_trigger_->trigger();
|
209
|
-
|
210
|
-
if (this->use_wake_word_) {
|
211
|
-
this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD);
|
212
|
-
} else
|
213
|
-
#endif
|
214
|
-
{
|
215
|
-
this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
|
216
|
-
}
|
179
|
+
this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
|
217
180
|
} else {
|
218
|
-
this->
|
181
|
+
this->deallocate_buffers_();
|
219
182
|
}
|
220
183
|
break;
|
221
184
|
}
|
@@ -230,53 +193,20 @@ void VoiceAssistant::loop() {
|
|
230
193
|
}
|
231
194
|
this->clear_buffers_();
|
232
195
|
|
233
|
-
this->
|
234
|
-
this->high_freq_.start();
|
196
|
+
this->mic_source_->start();
|
235
197
|
this->set_state_(State::STARTING_MICROPHONE);
|
236
198
|
break;
|
237
199
|
}
|
238
200
|
case State::STARTING_MICROPHONE: {
|
239
|
-
if (this->
|
201
|
+
if (this->mic_source_->is_running()) {
|
240
202
|
this->set_state_(this->desired_state_);
|
241
203
|
}
|
242
204
|
break;
|
243
205
|
}
|
244
|
-
#ifdef USE_ESP_ADF
|
245
|
-
case State::WAIT_FOR_VAD: {
|
246
|
-
this->read_microphone_();
|
247
|
-
ESP_LOGD(TAG, "Waiting for speech...");
|
248
|
-
this->set_state_(State::WAITING_FOR_VAD);
|
249
|
-
break;
|
250
|
-
}
|
251
|
-
case State::WAITING_FOR_VAD: {
|
252
|
-
size_t bytes_read = this->read_microphone_();
|
253
|
-
if (bytes_read > 0) {
|
254
|
-
vad_state_t vad_state =
|
255
|
-
vad_process(this->vad_instance_, this->input_buffer_, SAMPLE_RATE_HZ, VAD_FRAME_LENGTH_MS);
|
256
|
-
if (vad_state == VAD_SPEECH) {
|
257
|
-
if (this->vad_counter_ < this->vad_threshold_) {
|
258
|
-
this->vad_counter_++;
|
259
|
-
} else {
|
260
|
-
ESP_LOGD(TAG, "VAD detected speech");
|
261
|
-
this->set_state_(State::START_PIPELINE, State::STREAMING_MICROPHONE);
|
262
|
-
|
263
|
-
// Reset for next time
|
264
|
-
this->vad_counter_ = 0;
|
265
|
-
}
|
266
|
-
} else {
|
267
|
-
if (this->vad_counter_ > 0) {
|
268
|
-
this->vad_counter_--;
|
269
|
-
}
|
270
|
-
}
|
271
|
-
}
|
272
|
-
break;
|
273
|
-
}
|
274
|
-
#endif
|
275
206
|
case State::START_PIPELINE: {
|
276
|
-
this->read_microphone_();
|
277
207
|
ESP_LOGD(TAG, "Requesting start...");
|
278
208
|
uint32_t flags = 0;
|
279
|
-
if (this->use_wake_word_)
|
209
|
+
if (!this->continue_conversation_ && this->use_wake_word_)
|
280
210
|
flags |= api::enums::VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD;
|
281
211
|
if (this->silence_detection_)
|
282
212
|
flags |= api::enums::VOICE_ASSISTANT_REQUEST_USE_VAD;
|
@@ -306,11 +236,9 @@ void VoiceAssistant::loop() {
|
|
306
236
|
break;
|
307
237
|
}
|
308
238
|
case State::STARTING_PIPELINE: {
|
309
|
-
this->read_microphone_();
|
310
239
|
break; // State changed when udp server port received
|
311
240
|
}
|
312
241
|
case State::STREAMING_MICROPHONE: {
|
313
|
-
this->read_microphone_();
|
314
242
|
size_t available = this->ring_buffer_->available();
|
315
243
|
while (available >= SEND_BUFFER_SIZE) {
|
316
244
|
size_t read_bytes = this->ring_buffer_->read((void *) this->send_buffer_, SEND_BUFFER_SIZE, 0);
|
@@ -334,8 +262,8 @@ void VoiceAssistant::loop() {
|
|
334
262
|
break;
|
335
263
|
}
|
336
264
|
case State::STOP_MICROPHONE: {
|
337
|
-
if (this->
|
338
|
-
this->
|
265
|
+
if (this->mic_source_->is_running()) {
|
266
|
+
this->mic_source_->stop();
|
339
267
|
this->set_state_(State::STOPPING_MICROPHONE);
|
340
268
|
} else {
|
341
269
|
this->set_state_(this->desired_state_);
|
@@ -343,7 +271,7 @@ void VoiceAssistant::loop() {
|
|
343
271
|
break;
|
344
272
|
}
|
345
273
|
case State::STOPPING_MICROPHONE: {
|
346
|
-
if (this->
|
274
|
+
if (this->mic_source_->is_stopped()) {
|
347
275
|
this->set_state_(this->desired_state_);
|
348
276
|
}
|
349
277
|
break;
|
@@ -387,6 +315,25 @@ void VoiceAssistant::loop() {
|
|
387
315
|
#ifdef USE_MEDIA_PLAYER
|
388
316
|
if (this->media_player_ != nullptr) {
|
389
317
|
playing = (this->media_player_->state == media_player::MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING);
|
318
|
+
|
319
|
+
if (playing && this->media_player_wait_for_announcement_start_) {
|
320
|
+
// Announcement has started playing, wait for it to finish
|
321
|
+
this->media_player_wait_for_announcement_start_ = false;
|
322
|
+
this->media_player_wait_for_announcement_end_ = true;
|
323
|
+
}
|
324
|
+
|
325
|
+
if (!playing && this->media_player_wait_for_announcement_end_) {
|
326
|
+
// Announcement has finished playing
|
327
|
+
this->media_player_wait_for_announcement_end_ = false;
|
328
|
+
this->cancel_timeout("playing");
|
329
|
+
ESP_LOGD(TAG, "Announcement finished playing");
|
330
|
+
this->set_state_(State::RESPONSE_FINISHED, State::RESPONSE_FINISHED);
|
331
|
+
|
332
|
+
api::VoiceAssistantAnnounceFinished msg;
|
333
|
+
msg.success = true;
|
334
|
+
this->api_client_->send_voice_assistant_announce_finished(msg);
|
335
|
+
break;
|
336
|
+
}
|
390
337
|
}
|
391
338
|
#endif
|
392
339
|
if (playing) {
|
@@ -417,7 +364,11 @@ void VoiceAssistant::loop() {
|
|
417
364
|
this->tts_stream_end_trigger_->trigger();
|
418
365
|
}
|
419
366
|
#endif
|
420
|
-
this->
|
367
|
+
if (this->continue_conversation_) {
|
368
|
+
this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
|
369
|
+
} else {
|
370
|
+
this->set_state_(State::IDLE, State::IDLE);
|
371
|
+
}
|
421
372
|
break;
|
422
373
|
}
|
423
374
|
default:
|
@@ -527,7 +478,7 @@ void VoiceAssistant::start_streaming() {
|
|
527
478
|
ESP_LOGD(TAG, "Client started, streaming microphone");
|
528
479
|
this->audio_mode_ = AUDIO_MODE_API;
|
529
480
|
|
530
|
-
if (this->
|
481
|
+
if (this->mic_source_->is_running()) {
|
531
482
|
this->set_state_(State::STREAMING_MICROPHONE, State::STREAMING_MICROPHONE);
|
532
483
|
} else {
|
533
484
|
this->set_state_(State::START_MICROPHONE, State::STREAMING_MICROPHONE);
|
@@ -557,7 +508,7 @@ void VoiceAssistant::start_streaming(struct sockaddr_storage *addr, uint16_t por
|
|
557
508
|
return;
|
558
509
|
}
|
559
510
|
|
560
|
-
if (this->
|
511
|
+
if (this->mic_source_->is_running()) {
|
561
512
|
this->set_state_(State::STREAMING_MICROPHONE, State::STREAMING_MICROPHONE);
|
562
513
|
} else {
|
563
514
|
this->set_state_(State::START_MICROPHONE, State::STREAMING_MICROPHONE);
|
@@ -574,19 +525,14 @@ void VoiceAssistant::request_start(bool continuous, bool silence_detection) {
|
|
574
525
|
if (this->state_ == State::IDLE) {
|
575
526
|
this->continuous_ = continuous;
|
576
527
|
this->silence_detection_ = silence_detection;
|
577
|
-
|
578
|
-
|
579
|
-
this->set_state_(State::START_MICROPHONE, State::WAIT_FOR_VAD);
|
580
|
-
} else
|
581
|
-
#endif
|
582
|
-
{
|
583
|
-
this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
|
584
|
-
}
|
528
|
+
|
529
|
+
this->set_state_(State::START_MICROPHONE, State::START_PIPELINE);
|
585
530
|
}
|
586
531
|
}
|
587
532
|
|
588
533
|
void VoiceAssistant::request_stop() {
|
589
534
|
this->continuous_ = false;
|
535
|
+
this->continue_conversation_ = false;
|
590
536
|
|
591
537
|
switch (this->state_) {
|
592
538
|
case State::IDLE:
|
@@ -611,6 +557,16 @@ void VoiceAssistant::request_stop() {
|
|
611
557
|
this->signal_stop_();
|
612
558
|
break;
|
613
559
|
case State::STREAMING_RESPONSE:
|
560
|
+
#ifdef USE_MEDIA_PLAYER
|
561
|
+
// Stop any ongoing media player announcement
|
562
|
+
if (this->media_player_ != nullptr) {
|
563
|
+
this->media_player_->make_call()
|
564
|
+
.set_command(media_player::MEDIA_PLAYER_COMMAND_STOP)
|
565
|
+
.set_announcement(true)
|
566
|
+
.perform();
|
567
|
+
}
|
568
|
+
#endif
|
569
|
+
break;
|
614
570
|
case State::RESPONSE_FINISHED:
|
615
571
|
break; // Let the incoming audio stream finish then it will go to idle.
|
616
572
|
}
|
@@ -628,9 +584,9 @@ void VoiceAssistant::signal_stop_() {
|
|
628
584
|
}
|
629
585
|
|
630
586
|
void VoiceAssistant::start_playback_timeout_() {
|
631
|
-
this->set_timeout("playing",
|
587
|
+
this->set_timeout("playing", 2000, [this]() {
|
632
588
|
this->cancel_timeout("speaker-timeout");
|
633
|
-
this->set_state_(State::
|
589
|
+
this->set_state_(State::RESPONSE_FINISHED, State::RESPONSE_FINISHED);
|
634
590
|
|
635
591
|
api::VoiceAssistantAnnounceFinished msg;
|
636
592
|
msg.success = true;
|
@@ -679,6 +635,8 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
|
679
635
|
for (auto arg : msg.data) {
|
680
636
|
if (arg.name == "conversation_id") {
|
681
637
|
this->conversation_id_ = std::move(arg.value);
|
638
|
+
} else if (arg.name == "continue_conversation") {
|
639
|
+
this->continue_conversation_ = (arg.value == "1");
|
682
640
|
}
|
683
641
|
}
|
684
642
|
this->defer([this]() { this->intent_end_trigger_->trigger(); });
|
@@ -722,6 +680,9 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
|
722
680
|
#ifdef USE_MEDIA_PLAYER
|
723
681
|
if (this->media_player_ != nullptr) {
|
724
682
|
this->media_player_->make_call().set_media_url(url).set_announcement(true).perform();
|
683
|
+
|
684
|
+
this->media_player_wait_for_announcement_start_ = true;
|
685
|
+
this->media_player_wait_for_announcement_end_ = false;
|
725
686
|
// Start the playback timeout, as the media player state isn't immediately updated
|
726
687
|
this->start_playback_timeout_();
|
727
688
|
}
|
@@ -734,21 +695,13 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
|
734
695
|
}
|
735
696
|
case api::enums::VOICE_ASSISTANT_RUN_END: {
|
736
697
|
ESP_LOGD(TAG, "Assist Pipeline ended");
|
737
|
-
if ((this->state_ == State::
|
738
|
-
|
739
|
-
//
|
698
|
+
if ((this->state_ == State::START_PIPELINE) || (this->state_ == State::STARTING_PIPELINE) ||
|
699
|
+
(this->state_ == State::STREAMING_MICROPHONE)) {
|
700
|
+
// Microphone is running, stop it
|
701
|
+
this->set_state_(State::STOP_MICROPHONE, State::IDLE);
|
702
|
+
} else if (this->state_ == State::AWAITING_RESPONSE) {
|
703
|
+
// No TTS start event ("nevermind")
|
740
704
|
this->set_state_(State::IDLE, State::IDLE);
|
741
|
-
} else if (this->state_ == State::STREAMING_MICROPHONE) {
|
742
|
-
this->ring_buffer_->reset();
|
743
|
-
#ifdef USE_ESP_ADF
|
744
|
-
if (this->use_wake_word_) {
|
745
|
-
// No need to stop the microphone since we didn't use the speaker
|
746
|
-
this->set_state_(State::WAIT_FOR_VAD, State::WAITING_FOR_VAD);
|
747
|
-
} else
|
748
|
-
#endif
|
749
|
-
{
|
750
|
-
this->set_state_(State::IDLE, State::IDLE);
|
751
|
-
}
|
752
705
|
}
|
753
706
|
this->defer([this]() { this->end_trigger_->trigger(); });
|
754
707
|
break;
|
@@ -888,14 +841,87 @@ void VoiceAssistant::on_announce(const api::VoiceAssistantAnnounceRequest &msg)
|
|
888
841
|
#ifdef USE_MEDIA_PLAYER
|
889
842
|
if (this->media_player_ != nullptr) {
|
890
843
|
this->tts_start_trigger_->trigger(msg.text);
|
891
|
-
|
892
|
-
|
844
|
+
if (!msg.preannounce_media_id.empty()) {
|
845
|
+
this->media_player_->make_call().set_media_url(msg.preannounce_media_id).set_announcement(true).perform();
|
846
|
+
}
|
847
|
+
// Enqueueing a URL with an empty playlist will still play the file immediately
|
848
|
+
this->media_player_->make_call()
|
849
|
+
.set_command(media_player::MEDIA_PLAYER_COMMAND_ENQUEUE)
|
850
|
+
.set_media_url(msg.media_id)
|
851
|
+
.set_announcement(true)
|
852
|
+
.perform();
|
853
|
+
this->continue_conversation_ = msg.start_conversation;
|
854
|
+
|
855
|
+
this->media_player_wait_for_announcement_start_ = true;
|
856
|
+
this->media_player_wait_for_announcement_end_ = false;
|
857
|
+
// Start the playback timeout, as the media player state isn't immediately updated
|
858
|
+
this->start_playback_timeout_();
|
859
|
+
|
860
|
+
if (this->continuous_) {
|
861
|
+
this->set_state_(State::STOP_MICROPHONE, State::STREAMING_RESPONSE);
|
862
|
+
} else {
|
863
|
+
this->set_state_(State::STREAMING_RESPONSE, State::STREAMING_RESPONSE);
|
864
|
+
}
|
865
|
+
|
893
866
|
this->tts_end_trigger_->trigger(msg.media_id);
|
894
867
|
this->end_trigger_->trigger();
|
895
868
|
}
|
896
869
|
#endif
|
897
870
|
}
|
898
871
|
|
872
|
+
void VoiceAssistant::on_set_configuration(const std::vector<std::string> &active_wake_words) {
|
873
|
+
#ifdef USE_MICRO_WAKE_WORD
|
874
|
+
if (this->micro_wake_word_) {
|
875
|
+
// Disable all wake words first
|
876
|
+
for (auto &model : this->micro_wake_word_->get_wake_words()) {
|
877
|
+
model->disable();
|
878
|
+
}
|
879
|
+
|
880
|
+
// Enable only active wake words
|
881
|
+
for (auto ww_id : active_wake_words) {
|
882
|
+
for (auto &model : this->micro_wake_word_->get_wake_words()) {
|
883
|
+
if (model->get_id() == ww_id) {
|
884
|
+
model->enable();
|
885
|
+
ESP_LOGD(TAG, "Enabled wake word: %s (id=%s)", model->get_wake_word().c_str(), model->get_id().c_str());
|
886
|
+
}
|
887
|
+
}
|
888
|
+
}
|
889
|
+
}
|
890
|
+
#endif
|
891
|
+
};
|
892
|
+
|
893
|
+
const Configuration &VoiceAssistant::get_configuration() {
|
894
|
+
this->config_.available_wake_words.clear();
|
895
|
+
this->config_.active_wake_words.clear();
|
896
|
+
|
897
|
+
#ifdef USE_MICRO_WAKE_WORD
|
898
|
+
if (this->micro_wake_word_) {
|
899
|
+
this->config_.max_active_wake_words = 1;
|
900
|
+
|
901
|
+
for (auto &model : this->micro_wake_word_->get_wake_words()) {
|
902
|
+
if (model->is_enabled()) {
|
903
|
+
this->config_.active_wake_words.push_back(model->get_id());
|
904
|
+
}
|
905
|
+
|
906
|
+
WakeWord wake_word;
|
907
|
+
wake_word.id = model->get_id();
|
908
|
+
wake_word.wake_word = model->get_wake_word();
|
909
|
+
for (const auto &lang : model->get_trained_languages()) {
|
910
|
+
wake_word.trained_languages.push_back(lang);
|
911
|
+
}
|
912
|
+
this->config_.available_wake_words.push_back(std::move(wake_word));
|
913
|
+
}
|
914
|
+
} else {
|
915
|
+
#endif
|
916
|
+
// No microWakeWord
|
917
|
+
this->config_.max_active_wake_words = 0;
|
918
|
+
#ifdef USE_MICRO_WAKE_WORD
|
919
|
+
}
|
920
|
+
#endif
|
921
|
+
|
922
|
+
return this->config_;
|
923
|
+
};
|
924
|
+
|
899
925
|
VoiceAssistant *global_voice_assistant = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
900
926
|
|
901
927
|
} // namespace voice_assistant
|