esphome 2025.4.1__py3-none-any.whl → 2025.5.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +77 -10
- esphome/components/api/api_connection.h +6 -1
- esphome/components/api/api_frame_helper.cpp +98 -130
- esphome/components/api/api_frame_helper.h +12 -2
- 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 +38 -9
- esphome/components/as3935_i2c/as3935_i2c.h +0 -3
- 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/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/binary_sensor/binary_sensor.cpp +6 -10
- esphome/components/binary_sensor/binary_sensor.h +1 -1
- esphome/components/binary_sensor/filter.cpp +21 -21
- esphome/components/binary_sensor/filter.h +10 -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 +135 -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/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/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/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/debug/debug_component.cpp +5 -0
- 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/display/rect.cpp +4 -9
- esphome/components/display/rect.h +1 -1
- esphome/components/emmeti/climate.py +2 -9
- esphome/components/endstop/cover.py +17 -16
- 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.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_can/esp32_can.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/esp8266/gpio.cpp +69 -8
- 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/fujitsu_general/climate.py +2 -9
- 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 +11 -2
- esphome/components/gps/gps.cpp +11 -8
- esphome/components/gps/gps.h +9 -6
- 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/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/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/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/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 +21 -0
- esphome/components/logger/logger.cpp +125 -95
- esphome/components/logger/logger.h +160 -35
- 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/max7219digit/max7219digit.cpp +27 -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/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/mqtt/__init__.py +1 -1
- esphome/components/mqtt/mqtt_client.cpp +5 -1
- 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/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 +193 -229
- 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/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/scd30/sensor.py +2 -3
- esphome/components/scd4x/sensor.py +4 -5
- esphome/components/sdp3x/sensor.py +2 -1
- esphome/components/select/__init__.py +19 -20
- esphome/components/sen5x/sensor.py +1 -1
- esphome/components/sensor/__init__.py +158 -14
- esphome/components/sensor/filter.cpp +23 -0
- esphome/components/sensor/filter.h +22 -0
- esphome/components/sgp4x/sensor.py +1 -1
- esphome/components/sht4x/sht4x.cpp +43 -22
- esphome/components/sht4x/sht4x.h +1 -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/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/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/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/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/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_validation.py +38 -58
- esphome/const.py +15 -1
- esphome/core/__init__.py +2 -0
- esphome/core/application.cpp +1 -0
- esphome/core/application.h +4 -0
- esphome/core/automation.h +4 -3
- esphome/core/component.cpp +19 -3
- esphome/core/component.h +5 -0
- esphome/core/defines.h +23 -17
- esphome/core/macros.h +4 -0
- esphome/core/scheduler.cpp +3 -0
- esphome/cpp_generator.py +6 -2
- esphome/dashboard/web_server.py +3 -3
- esphome/helpers.py +39 -0
- esphome/loader.py +4 -0
- esphome/mqtt.py +21 -8
- esphome/platformio_api.py +1 -1
- esphome/schema_extractors.py +0 -1
- esphome/vscode.py +15 -0
- esphome/wizard.py +2 -2
- esphome/zeroconf.py +7 -3
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/METADATA +10 -11
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/RECORD +411 -352
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/WHEEL +1 -1
- esphome/components/esp32_ble/const_esp32c6.h +0 -74
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/entry_points.txt +0 -0
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/top_level.txt +0 -0
@@ -18,14 +18,25 @@ static const char *const TAG = "voice_assistant";
|
|
18
18
|
#endif
|
19
19
|
|
20
20
|
static const size_t SAMPLE_RATE_HZ = 16000;
|
21
|
-
|
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
|
@@ -11,18 +11,17 @@
|
|
11
11
|
|
12
12
|
#include "esphome/components/api/api_connection.h"
|
13
13
|
#include "esphome/components/api/api_pb2.h"
|
14
|
-
#include "esphome/components/microphone/
|
15
|
-
#ifdef USE_SPEAKER
|
16
|
-
#include "esphome/components/speaker/speaker.h"
|
17
|
-
#endif
|
14
|
+
#include "esphome/components/microphone/microphone_source.h"
|
18
15
|
#ifdef USE_MEDIA_PLAYER
|
19
16
|
#include "esphome/components/media_player/media_player.h"
|
20
17
|
#endif
|
21
|
-
#
|
22
|
-
|
23
|
-
#
|
24
|
-
#
|
18
|
+
#ifdef USE_MICRO_WAKE_WORD
|
19
|
+
#include "esphome/components/micro_wake_word/micro_wake_word.h"
|
20
|
+
#endif
|
21
|
+
#ifdef USE_SPEAKER
|
22
|
+
#include "esphome/components/speaker/speaker.h"
|
25
23
|
#endif
|
24
|
+
#include "esphome/components/socket/socket.h"
|
26
25
|
|
27
26
|
#include <unordered_map>
|
28
27
|
#include <vector>
|
@@ -41,6 +40,7 @@ enum VoiceAssistantFeature : uint32_t {
|
|
41
40
|
FEATURE_API_AUDIO = 1 << 2,
|
42
41
|
FEATURE_TIMERS = 1 << 3,
|
43
42
|
FEATURE_ANNOUNCE = 1 << 4,
|
43
|
+
FEATURE_START_CONVERSATION = 1 << 5,
|
44
44
|
};
|
45
45
|
|
46
46
|
enum class State {
|
@@ -95,12 +95,16 @@ class VoiceAssistant : public Component {
|
|
95
95
|
VoiceAssistant();
|
96
96
|
|
97
97
|
void loop() override;
|
98
|
+
void setup() override;
|
98
99
|
float get_setup_priority() const override;
|
99
100
|
void start_streaming();
|
100
101
|
void start_streaming(struct sockaddr_storage *addr, uint16_t port);
|
101
102
|
void failed_to_start();
|
102
103
|
|
103
|
-
void
|
104
|
+
void set_microphone_source(microphone::MicrophoneSource *mic_source) { this->mic_source_ = mic_source; }
|
105
|
+
#ifdef USE_MICRO_WAKE_WORD
|
106
|
+
void set_micro_wake_word(micro_wake_word::MicroWakeWord *mww) { this->micro_wake_word_ = mww; }
|
107
|
+
#endif
|
104
108
|
#ifdef USE_SPEAKER
|
105
109
|
void set_speaker(speaker::Speaker *speaker) {
|
106
110
|
this->speaker_ = speaker;
|
@@ -140,6 +144,7 @@ class VoiceAssistant : public Component {
|
|
140
144
|
#ifdef USE_MEDIA_PLAYER
|
141
145
|
if (this->media_player_ != nullptr) {
|
142
146
|
flags |= VoiceAssistantFeature::FEATURE_ANNOUNCE;
|
147
|
+
flags |= VoiceAssistantFeature::FEATURE_START_CONVERSATION;
|
143
148
|
}
|
144
149
|
#endif
|
145
150
|
|
@@ -153,17 +158,14 @@ class VoiceAssistant : public Component {
|
|
153
158
|
void on_audio(const api::VoiceAssistantAudio &msg);
|
154
159
|
void on_timer_event(const api::VoiceAssistantTimerEventResponse &msg);
|
155
160
|
void on_announce(const api::VoiceAssistantAnnounceRequest &msg);
|
156
|
-
void on_set_configuration(const std::vector<std::string> &active_wake_words)
|
157
|
-
const Configuration &get_configuration()
|
161
|
+
void on_set_configuration(const std::vector<std::string> &active_wake_words);
|
162
|
+
const Configuration &get_configuration();
|
158
163
|
|
159
164
|
bool is_running() const { return this->state_ != State::IDLE; }
|
160
165
|
void set_continuous(bool continuous) { this->continuous_ = continuous; }
|
161
166
|
bool is_continuous() const { return this->continuous_; }
|
162
167
|
|
163
168
|
void set_use_wake_word(bool use_wake_word) { this->use_wake_word_ = use_wake_word; }
|
164
|
-
#ifdef USE_ESP_ADF
|
165
|
-
void set_vad_threshold(uint8_t vad_threshold) { this->vad_threshold_ = vad_threshold; }
|
166
|
-
#endif
|
167
169
|
|
168
170
|
void set_noise_suppression_level(uint8_t noise_suppression_level) {
|
169
171
|
this->noise_suppression_level_ = noise_suppression_level;
|
@@ -212,7 +214,6 @@ class VoiceAssistant : public Component {
|
|
212
214
|
void clear_buffers_();
|
213
215
|
void deallocate_buffers_();
|
214
216
|
|
215
|
-
int read_microphone_();
|
216
217
|
void set_state_(State state);
|
217
218
|
void set_state_(State state, State desired_state);
|
218
219
|
void signal_stop_();
|
@@ -254,7 +255,7 @@ class VoiceAssistant : public Component {
|
|
254
255
|
bool has_timers_{false};
|
255
256
|
bool timer_tick_running_{false};
|
256
257
|
|
257
|
-
microphone::
|
258
|
+
microphone::MicrophoneSource *mic_source_{nullptr};
|
258
259
|
#ifdef USE_SPEAKER
|
259
260
|
void write_speaker_();
|
260
261
|
speaker::Speaker *speaker_{nullptr};
|
@@ -267,6 +268,8 @@ class VoiceAssistant : public Component {
|
|
267
268
|
#endif
|
268
269
|
#ifdef USE_MEDIA_PLAYER
|
269
270
|
media_player::MediaPlayer *media_player_{nullptr};
|
271
|
+
bool media_player_wait_for_announcement_start_{false};
|
272
|
+
bool media_player_wait_for_announcement_end_{false};
|
270
273
|
#endif
|
271
274
|
|
272
275
|
bool local_output_{false};
|
@@ -275,14 +278,7 @@ class VoiceAssistant : public Component {
|
|
275
278
|
|
276
279
|
std::string wake_word_{""};
|
277
280
|
|
278
|
-
|
279
|
-
|
280
|
-
#ifdef USE_ESP_ADF
|
281
|
-
vad_handle_t vad_instance_;
|
282
|
-
uint8_t vad_threshold_{5};
|
283
|
-
uint8_t vad_counter_{0};
|
284
|
-
#endif
|
285
|
-
std::unique_ptr<RingBuffer> ring_buffer_;
|
281
|
+
std::shared_ptr<RingBuffer> ring_buffer_;
|
286
282
|
|
287
283
|
bool use_wake_word_;
|
288
284
|
uint8_t noise_suppression_level_;
|
@@ -291,11 +287,12 @@ class VoiceAssistant : public Component {
|
|
291
287
|
uint32_t conversation_timeout_;
|
292
288
|
|
293
289
|
uint8_t *send_buffer_{nullptr};
|
294
|
-
int16_t *input_buffer_{nullptr};
|
295
290
|
|
296
291
|
bool continuous_{false};
|
297
292
|
bool silence_detection_;
|
298
293
|
|
294
|
+
bool continue_conversation_{false};
|
295
|
+
|
299
296
|
State state_{State::IDLE};
|
300
297
|
State desired_state_{State::IDLE};
|
301
298
|
|
@@ -304,6 +301,10 @@ class VoiceAssistant : public Component {
|
|
304
301
|
bool start_udp_socket_();
|
305
302
|
|
306
303
|
Configuration config_{};
|
304
|
+
|
305
|
+
#ifdef USE_MICRO_WAKE_WORD
|
306
|
+
micro_wake_word::MicroWakeWord *micro_wake_word_{nullptr};
|
307
|
+
#endif
|
307
308
|
};
|
308
309
|
|
309
310
|
template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<VoiceAssistant> {
|
@@ -70,12 +70,16 @@ WaveshareEPaper4P2InBV2 = waveshare_epaper_ns.class_(
|
|
70
70
|
WaveshareEPaper4P2InBV2BWR = waveshare_epaper_ns.class_(
|
71
71
|
"WaveshareEPaper4P2InBV2BWR", WaveshareEPaperBWR
|
72
72
|
)
|
73
|
+
WaveshareEPaper5P65InF = waveshare_epaper_ns.class_(
|
74
|
+
"WaveshareEPaper5P65InF", WaveshareEPaper7C
|
75
|
+
)
|
73
76
|
WaveshareEPaper5P8In = waveshare_epaper_ns.class_(
|
74
77
|
"WaveshareEPaper5P8In", WaveshareEPaper
|
75
78
|
)
|
76
79
|
WaveshareEPaper5P8InV2 = waveshare_epaper_ns.class_(
|
77
80
|
"WaveshareEPaper5P8InV2", WaveshareEPaper
|
78
81
|
)
|
82
|
+
GDEY0583T81 = waveshare_epaper_ns.class_("GDEY0583T81", WaveshareEPaper)
|
79
83
|
WaveshareEPaper7P3InF = waveshare_epaper_ns.class_(
|
80
84
|
"WaveshareEPaper7P3InF", WaveshareEPaper7C
|
81
85
|
)
|
@@ -150,8 +154,10 @@ MODELS = {
|
|
150
154
|
"4.20in": ("b", WaveshareEPaper4P2In),
|
151
155
|
"4.20in-bv2": ("b", WaveshareEPaper4P2InBV2),
|
152
156
|
"4.20in-bv2-bwr": ("b", WaveshareEPaper4P2InBV2BWR),
|
157
|
+
"5.65in-f": ("b", WaveshareEPaper5P65InF),
|
153
158
|
"5.83in": ("b", WaveshareEPaper5P8In),
|
154
159
|
"5.83inv2": ("b", WaveshareEPaper5P8InV2),
|
160
|
+
"gdey0583t81": ("c", GDEY0583T81),
|
155
161
|
"7.30in-f": ("b", WaveshareEPaper7P3InF),
|
156
162
|
"7.50in": ("b", WaveshareEPaper7P5In),
|
157
163
|
"7.50in-bv2": ("b", WaveshareEPaper7P5InBV2),
|