esphome 2025.7.4__py3-none-any.whl → 2025.8.0b1__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.
Potentially problematic release.
This version of esphome might be problematic. Click here for more details.
- esphome/__main__.py +189 -82
- esphome/automation.py +2 -4
- esphome/build_gen/__init__.py +0 -0
- esphome/build_gen/platformio.py +102 -0
- esphome/components/a4988/a4988.cpp +0 -1
- esphome/components/absolute_humidity/absolute_humidity.cpp +0 -2
- esphome/components/absolute_humidity/sensor.py +2 -2
- esphome/components/adc/__init__.py +123 -85
- esphome/components/adc/adc_sensor.h +98 -35
- esphome/components/adc/adc_sensor_common.cpp +10 -4
- esphome/components/adc/adc_sensor_esp32.cpp +291 -123
- esphome/components/adc/adc_sensor_esp8266.cpp +1 -4
- esphome/components/adc/adc_sensor_libretiny.cpp +1 -2
- esphome/components/adc/adc_sensor_rp2040.cpp +1 -2
- esphome/components/adc/adc_sensor_zephyr.cpp +207 -0
- esphome/components/adc/sensor.py +61 -27
- esphome/components/adc128s102/adc128s102.cpp +1 -4
- esphome/components/ade7880/sensor.py +75 -49
- esphome/components/ads1115/ads1115.cpp +0 -1
- esphome/components/ads1118/ads1118.cpp +0 -1
- esphome/components/ags10/ags10.cpp +0 -4
- esphome/components/aht10/aht10.cpp +0 -4
- esphome/components/aic3204/aic3204.cpp +0 -2
- esphome/components/airthings_wave_plus/__init__.py +1 -1
- esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +22 -4
- esphome/components/airthings_wave_plus/airthings_wave_plus.h +10 -1
- esphome/components/airthings_wave_plus/sensor.py +55 -28
- esphome/components/alarm_control_panel/__init__.py +4 -9
- esphome/components/am2315c/am2315c.cpp +0 -2
- esphome/components/am2320/am2320.cpp +0 -1
- esphome/components/animation/__init__.py +14 -11
- esphome/components/apds9306/apds9306.cpp +0 -4
- esphome/components/apds9960/apds9960.cpp +0 -1
- esphome/components/api/__init__.py +29 -4
- esphome/components/api/api_connection.cpp +378 -401
- esphome/components/api/api_connection.h +112 -56
- esphome/components/api/api_frame_helper.cpp +69 -896
- esphome/components/api/api_frame_helper.h +31 -126
- esphome/components/api/api_frame_helper_noise.cpp +583 -0
- esphome/components/api/api_frame_helper_noise.h +68 -0
- esphome/components/api/api_frame_helper_plaintext.cpp +290 -0
- esphome/components/api/api_frame_helper_plaintext.h +53 -0
- esphome/components/api/api_noise_context.h +2 -4
- esphome/components/api/api_pb2.cpp +1601 -1808
- esphome/components/api/api_pb2.h +367 -323
- esphome/components/api/api_pb2_dump.cpp +1137 -3466
- esphome/components/api/api_pb2_includes.h +34 -0
- esphome/components/api/api_pb2_service.cpp +94 -105
- esphome/components/api/api_pb2_service.h +27 -16
- esphome/components/api/api_server.cpp +18 -17
- esphome/components/api/api_server.h +8 -5
- esphome/components/api/client.py +16 -8
- esphome/components/api/custom_api_device.h +68 -14
- esphome/components/api/homeassistant_service.h +24 -19
- esphome/components/api/list_entities.cpp +3 -5
- esphome/components/api/list_entities.h +2 -4
- esphome/components/api/proto.cpp +3 -5
- esphome/components/api/proto.h +239 -274
- esphome/components/api/subscribe_state.cpp +2 -4
- esphome/components/api/subscribe_state.h +2 -4
- esphome/components/api/user_services.cpp +2 -4
- esphome/components/api/user_services.h +8 -8
- esphome/components/as3935/as3935.cpp +0 -2
- esphome/components/as3935_spi/as3935_spi.cpp +0 -2
- esphome/components/as5600/__init__.py +1 -1
- esphome/components/as5600/as5600.cpp +0 -2
- esphome/components/as5600/sensor/__init__.py +0 -1
- esphome/components/as7341/as7341.cpp +0 -1
- esphome/components/async_tcp/__init__.py +1 -1
- esphome/components/at581x/at581x.cpp +1 -1
- esphome/components/atm90e26/atm90e26.cpp +0 -1
- esphome/components/atm90e32/atm90e32.cpp +488 -118
- esphome/components/atm90e32/atm90e32.h +44 -5
- esphome/components/audio/audio.h +2 -2
- esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +0 -2
- esphome/components/beken_spi_led_strip/led_strip.cpp +0 -2
- esphome/components/bh1750/bh1750.cpp +0 -1
- esphome/components/binary_sensor/__init__.py +14 -12
- esphome/components/ble_client/__init__.py +4 -7
- esphome/components/bluetooth_proxy/__init__.py +40 -3
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +387 -82
- esphome/components/bluetooth_proxy/bluetooth_connection.h +16 -5
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +102 -311
- esphome/components/bluetooth_proxy/bluetooth_proxy.h +30 -14
- esphome/components/bme280_base/bme280_base.cpp +15 -16
- esphome/components/bme680/bme680.cpp +2 -3
- esphome/components/bme680_bsec/bme680_bsec.cpp +0 -2
- esphome/components/bme68x_bsec2/bme68x_bsec2.cpp +0 -2
- esphome/components/bmi160/bmi160.cpp +0 -1
- esphome/components/bmp085/bmp085.cpp +0 -1
- esphome/components/bmp280_base/bmp280_base.cpp +13 -14
- esphome/components/bmp3xx_base/bmp3xx_base.cpp +0 -1
- esphome/components/bmp581/bmp581.cpp +0 -2
- esphome/components/bp1658cj/bp1658cj.cpp +0 -1
- esphome/components/bp5758d/bp5758d.cpp +0 -1
- esphome/components/button/__init__.py +0 -1
- esphome/components/canbus/__init__.py +2 -3
- esphome/components/canbus/canbus.cpp +0 -1
- esphome/components/cap1188/cap1188.cpp +0 -2
- esphome/components/captive_portal/__init__.py +1 -1
- esphome/components/cd74hc4067/cd74hc4067.cpp +0 -2
- esphome/components/ch422g/ch422g.cpp +0 -1
- esphome/components/chsc6x/chsc6x_touchscreen.cpp +0 -3
- esphome/components/climate/__init__.py +0 -1
- esphome/components/climate/climate_traits.h +24 -0
- esphome/components/cm1106/cm1106.cpp +0 -1
- esphome/components/const/__init__.py +6 -0
- esphome/components/cover/__init__.py +0 -1
- esphome/components/cover/cover.cpp +9 -13
- esphome/components/cs5460a/cs5460a.cpp +0 -2
- esphome/components/cse7761/cse7761.cpp +0 -1
- esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +0 -2
- esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +0 -2
- esphome/components/dac7678/dac7678_output.cpp +0 -2
- esphome/components/dallas_temp/dallas_temp.cpp +0 -1
- esphome/components/datetime/__init__.py +0 -2
- esphome/components/debug/__init__.py +15 -1
- esphome/components/debug/debug_zephyr.cpp +281 -0
- esphome/components/debug/sensor.py +2 -1
- esphome/components/deep_sleep/deep_sleep_component.cpp +0 -1
- esphome/components/deep_sleep/deep_sleep_esp32.cpp +20 -1
- esphome/components/dfrobot_sen0395/__init__.py +1 -2
- esphome/components/dht/dht.cpp +0 -1
- esphome/components/dht12/dht12.cpp +0 -1
- esphome/components/display/__init__.py +16 -3
- esphome/components/display_menu_base/__init__.py +1 -1
- esphome/components/dps310/dps310.cpp +0 -2
- esphome/components/ds1307/ds1307.cpp +0 -1
- esphome/components/ds2484/ds2484.cpp +0 -1
- esphome/components/duty_cycle/duty_cycle_sensor.cpp +0 -1
- esphome/components/ee895/ee895.cpp +0 -1
- esphome/components/ektf2232/touchscreen/ektf2232.cpp +0 -1
- esphome/components/emc2101/emc2101.cpp +0 -2
- esphome/components/ens160_base/ens160_base.cpp +0 -2
- esphome/components/ens210/ens210.cpp +0 -1
- esphome/components/es7210/es7210.cpp +0 -2
- esphome/components/es7243e/es7243e.cpp +0 -2
- esphome/components/es8156/es8156.cpp +0 -2
- esphome/components/es8311/es8311.cpp +0 -2
- esphome/components/es8388/es8388.cpp +0 -2
- esphome/components/esp32/__init__.py +199 -58
- esphome/components/esp32/boards.py +17 -0
- esphome/components/esp32/gpio.cpp +0 -1
- esphome/components/esp32/gpio.py +1 -2
- esphome/components/esp32/gpio_esp32_h2.py +2 -7
- esphome/components/esp32/gpio_esp32_p4.py +2 -7
- esphome/components/esp32/post_build.py.script +112 -61
- esphome/components/esp32_ble/__init__.py +40 -2
- esphome/components/esp32_ble/ble.cpp +12 -8
- esphome/components/esp32_ble/ble.h +18 -18
- esphome/components/esp32_ble/ble_advertising.cpp +5 -5
- esphome/components/esp32_ble/ble_advertising.h +7 -5
- esphome/components/esp32_ble/ble_event.h +2 -4
- esphome/components/esp32_ble/ble_scan_result.h +2 -4
- esphome/components/esp32_ble/ble_uuid.cpp +5 -5
- esphome/components/esp32_ble/ble_uuid.h +6 -5
- esphome/components/esp32_ble_beacon/__init__.py +4 -0
- esphome/components/esp32_ble_client/__init__.py +1 -1
- esphome/components/esp32_ble_client/ble_characteristic.cpp +4 -4
- esphome/components/esp32_ble_client/ble_characteristic.h +6 -4
- esphome/components/esp32_ble_client/ble_client_base.cpp +155 -104
- esphome/components/esp32_ble_client/ble_client_base.h +17 -6
- esphome/components/esp32_ble_client/ble_descriptor.h +6 -4
- esphome/components/esp32_ble_client/ble_service.cpp +4 -4
- esphome/components/esp32_ble_client/ble_service.h +6 -4
- esphome/components/esp32_ble_server/__init__.py +15 -12
- esphome/components/esp32_ble_tracker/__init__.py +79 -11
- esphome/components/esp32_ble_tracker/automation.h +4 -4
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +264 -261
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +103 -37
- esphome/components/esp32_camera/__init__.py +13 -1
- esphome/components/esp32_camera/esp32_camera.cpp +7 -2
- esphome/components/esp32_camera/esp32_camera.h +1 -0
- esphome/components/esp32_dac/esp32_dac.cpp +3 -19
- esphome/components/esp32_dac/esp32_dac.h +4 -8
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -6
- esphome/components/esp32_rmt_led_strip/light.py +1 -1
- esphome/components/esp32_touch/__init__.py +2 -3
- esphome/components/esp32_touch/esp32_touch.h +9 -6
- esphome/components/esp32_touch/esp32_touch_common.cpp +2 -0
- esphome/components/esp32_touch/esp32_touch_v1.cpp +7 -9
- esphome/components/esp32_touch/esp32_touch_v2.cpp +10 -6
- esphome/components/esp8266/__init__.py +3 -1
- esphome/components/esp8266_pwm/esp8266_pwm.cpp +0 -1
- esphome/components/esphome/ota/__init__.py +1 -2
- esphome/components/esphome/ota/ota_esphome.cpp +150 -77
- esphome/components/esphome/ota/ota_esphome.h +8 -1
- esphome/components/espnow/__init__.py +309 -0
- esphome/components/espnow/automation.h +175 -0
- esphome/components/espnow/espnow_component.cpp +468 -0
- esphome/components/espnow/espnow_component.h +183 -0
- esphome/components/espnow/espnow_err.h +19 -0
- esphome/components/espnow/espnow_packet.h +166 -0
- esphome/components/ethernet/__init__.py +7 -1
- esphome/components/ethernet/esp_eth_phy_jl1101.c +5 -0
- esphome/components/ethernet/ethernet_component.cpp +0 -1
- esphome/components/ethernet/ethernet_component.h +4 -0
- esphome/components/ethernet_info/ethernet_info_text_sensor.h +0 -3
- esphome/components/event/__init__.py +0 -1
- esphome/components/factory_reset/__init__.py +92 -0
- esphome/components/factory_reset/factory_reset.cpp +76 -0
- esphome/components/factory_reset/factory_reset.h +43 -0
- esphome/components/fan/__init__.py +0 -1
- esphome/components/fan/fan_traits.h +16 -0
- esphome/components/fastled_base/fastled_light.cpp +0 -1
- esphome/components/fastled_spi/light.py +1 -3
- esphome/components/fingerprint_grow/fingerprint_grow.cpp +0 -2
- esphome/components/font/__init__.py +9 -1
- esphome/components/fs3000/fs3000.cpp +0 -2
- esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp +0 -2
- esphome/components/ft63x6/ft63x6.cpp +0 -1
- esphome/components/gdk101/gdk101.cpp +0 -1
- esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +0 -1
- esphome/components/gl_r01_i2c/sensor.py +1 -1
- esphome/components/gpio/one_wire/gpio_one_wire.cpp +0 -1
- esphome/components/gpio/switch/gpio_switch.cpp +0 -2
- esphome/components/gpio_expander/cached_gpio.h +24 -15
- esphome/components/gps/__init__.py +6 -2
- esphome/components/gps/gps.cpp +50 -49
- esphome/components/gps/gps.h +4 -8
- esphome/components/gps/time/gps_time.cpp +3 -9
- esphome/components/gps/time/gps_time.h +4 -7
- esphome/components/graph/__init__.py +1 -1
- esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +0 -1
- esphome/components/grove_tb6612fng/grove_tb6612fng.cpp +0 -1
- esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +21 -12
- esphome/components/gt911/touchscreen/gt911_touchscreen.h +26 -2
- esphome/components/haier/climate.py +5 -10
- esphome/components/haier/haier_base.cpp +0 -1
- esphome/components/hbridge/switch/hbridge_switch.cpp +0 -2
- esphome/components/hdc1080/hdc1080.cpp +0 -2
- esphome/components/heatpumpir/climate.py +2 -2
- esphome/components/hlw8012/hlw8012.cpp +0 -1
- esphome/components/hm3301/hm3301.cpp +0 -1
- esphome/components/hmc5883l/hmc5883l.cpp +0 -1
- esphome/components/homeassistant/__init__.py +1 -0
- esphome/components/homeassistant/number/__init__.py +1 -0
- esphome/components/homeassistant/number/homeassistant_number.cpp +11 -7
- esphome/components/homeassistant/switch/__init__.py +1 -0
- esphome/components/homeassistant/switch/homeassistant_switch.cpp +9 -5
- esphome/components/honeywellabp/honeywellabp.cpp +1 -4
- esphome/components/host/__init__.py +2 -0
- esphome/components/hte501/hte501.cpp +0 -1
- esphome/components/http_request/__init__.py +2 -3
- esphome/components/http_request/http_request_idf.cpp +2 -2
- esphome/components/htu21d/htu21d.cpp +0 -2
- esphome/components/htu31d/htu31d.cpp +0 -2
- esphome/components/hx711/hx711.cpp +0 -1
- esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +0 -1
- esphome/components/hydreon_rgxx/sensor.py +4 -5
- esphome/components/i2c/i2c_bus.h +1 -1
- esphome/components/i2c/i2c_bus_arduino.cpp +1 -2
- esphome/components/i2c/i2c_bus_esp_idf.cpp +192 -17
- esphome/components/i2c/i2c_bus_esp_idf.h +11 -1
- esphome/components/i2s_audio/__init__.py +6 -5
- esphome/components/i2s_audio/i2s_audio.cpp +0 -2
- esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +1 -4
- esphome/components/i2s_audio/microphone/__init__.py +4 -6
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +46 -19
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +4 -3
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +273 -269
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +19 -34
- esphome/components/ili9xxx/display.py +4 -3
- esphome/components/ili9xxx/ili9xxx_display.cpp +0 -2
- esphome/components/image/__init__.py +123 -92
- esphome/components/improv_serial/__init__.py +7 -8
- esphome/components/ina219/ina219.cpp +0 -1
- esphome/components/ina226/ina226.cpp +0 -2
- esphome/components/ina260/ina260.cpp +0 -2
- esphome/components/ina2xx_base/__init__.py +2 -5
- esphome/components/ina2xx_base/ina2xx_base.cpp +0 -2
- esphome/components/ina3221/ina3221.cpp +0 -1
- esphome/components/internal_temperature/internal_temperature.cpp +0 -2
- esphome/components/interval/interval.h +5 -9
- esphome/components/json/__init__.py +1 -1
- esphome/components/kmeteriso/kmeteriso.cpp +0 -2
- esphome/components/lc709203f/lc709203f.cpp +0 -2
- esphome/components/lcd_gpio/display.py +1 -3
- esphome/components/lcd_gpio/gpio_lcd_display.cpp +0 -1
- esphome/components/lcd_pcf8574/pcf8574_display.cpp +0 -1
- esphome/components/ld2410/__init__.py +4 -6
- esphome/components/ld2410/binary_sensor.py +4 -0
- esphome/components/ld2410/ld2410.cpp +56 -100
- esphome/components/ld2410/ld2410.h +17 -15
- esphome/components/ld2410/sensor.py +24 -10
- esphome/components/ld2412/__init__.py +46 -0
- esphome/components/ld2412/binary_sensor.py +70 -0
- esphome/components/ld2412/button/__init__.py +74 -0
- esphome/components/ld2412/button/factory_reset_button.cpp +9 -0
- esphome/components/ld2412/button/factory_reset_button.h +18 -0
- esphome/components/ld2412/button/query_button.cpp +9 -0
- esphome/components/ld2412/button/query_button.h +18 -0
- esphome/components/ld2412/button/restart_button.cpp +9 -0
- esphome/components/ld2412/button/restart_button.h +18 -0
- esphome/components/ld2412/button/start_dynamic_background_correction_button.cpp +11 -0
- esphome/components/ld2412/button/start_dynamic_background_correction_button.h +18 -0
- esphome/components/ld2412/ld2412.cpp +861 -0
- esphome/components/ld2412/ld2412.h +141 -0
- esphome/components/ld2412/number/__init__.py +126 -0
- esphome/components/ld2412/number/gate_threshold_number.cpp +14 -0
- esphome/components/ld2412/number/gate_threshold_number.h +19 -0
- esphome/components/ld2412/number/light_threshold_number.cpp +12 -0
- esphome/components/ld2412/number/light_threshold_number.h +18 -0
- esphome/components/ld2412/number/max_distance_timeout_number.cpp +12 -0
- esphome/components/ld2412/number/max_distance_timeout_number.h +18 -0
- esphome/components/ld2412/select/__init__.py +82 -0
- esphome/components/ld2412/select/baud_rate_select.cpp +12 -0
- esphome/components/ld2412/select/baud_rate_select.h +18 -0
- esphome/components/ld2412/select/distance_resolution_select.cpp +12 -0
- esphome/components/ld2412/select/distance_resolution_select.h +18 -0
- esphome/components/ld2412/select/light_out_control_select.cpp +12 -0
- esphome/components/ld2412/select/light_out_control_select.h +18 -0
- esphome/components/ld2412/sensor.py +124 -0
- esphome/components/ld2412/switch/__init__.py +45 -0
- esphome/components/ld2412/switch/bluetooth_switch.cpp +12 -0
- esphome/components/ld2412/switch/bluetooth_switch.h +18 -0
- esphome/components/ld2412/switch/engineering_mode_switch.cpp +12 -0
- esphome/components/ld2412/switch/engineering_mode_switch.h +18 -0
- esphome/components/ld2412/text_sensor.py +34 -0
- esphome/components/ld2420/ld2420.cpp +0 -1
- esphome/components/ld2450/__init__.py +3 -4
- esphome/components/ld2450/binary_sensor.py +3 -0
- esphome/components/ld2450/ld2450.cpp +77 -165
- esphome/components/ld2450/ld2450.h +26 -54
- esphome/components/ld2450/sensor.py +120 -6
- esphome/components/ld2450/text_sensor.py +5 -4
- esphome/components/ld24xx/__init__.py +1 -0
- esphome/components/ld24xx/ld24xx.h +65 -0
- esphome/components/ledc/ledc_output.cpp +0 -1
- esphome/components/libretiny/__init__.py +2 -0
- esphome/components/light/__init__.py +0 -1
- esphome/components/light/effects.py +70 -45
- esphome/components/light/light_call.cpp +101 -66
- esphome/components/light/light_color_values.h +16 -11
- esphome/components/light/light_json_schema.cpp +46 -44
- esphome/components/light/light_state.cpp +8 -11
- esphome/components/light/light_traits.h +17 -0
- esphome/components/lightwaverf/lightwaverf.cpp +0 -2
- esphome/components/lilygo_t5_47/touchscreen/lilygo_t5_47_touchscreen.cpp +0 -1
- esphome/components/lock/__init__.py +0 -1
- esphome/components/logger/__init__.py +31 -9
- esphome/components/logger/logger.cpp +12 -7
- esphome/components/logger/logger.h +25 -14
- esphome/components/logger/logger_esp32.cpp +2 -7
- esphome/components/logger/logger_esp8266.cpp +2 -4
- esphome/components/logger/logger_host.cpp +2 -4
- esphome/components/logger/logger_libretiny.cpp +2 -4
- esphome/components/logger/logger_rp2040.cpp +2 -4
- esphome/components/logger/logger_zephyr.cpp +86 -0
- esphome/components/logger/select/logger_level_select.cpp +2 -4
- esphome/components/logger/select/logger_level_select.h +2 -4
- esphome/components/logger/task_log_buffer.cpp +2 -4
- esphome/components/logger/task_log_buffer.h +2 -4
- esphome/components/lps22/sensor.py +5 -5
- esphome/components/ltr390/ltr390.cpp +0 -2
- esphome/components/ltr501/ltr501.cpp +0 -1
- esphome/components/ltr_als_ps/ltr_als_ps.cpp +0 -1
- esphome/components/lvgl/__init__.py +14 -13
- esphome/components/lvgl/automation.py +2 -4
- esphome/components/lvgl/defines.py +0 -2
- esphome/components/lvgl/helpers.py +1 -1
- esphome/components/lvgl/lv_validation.py +7 -4
- esphome/components/lvgl/lvgl_esphome.cpp +2 -3
- esphome/components/lvgl/styles.py +2 -2
- esphome/components/lvgl/types.py +1 -1
- esphome/components/lvgl/widgets/__init__.py +2 -2
- esphome/components/lvgl/widgets/arc.py +14 -11
- esphome/components/lvgl/widgets/buttonmatrix.py +1 -1
- esphome/components/lvgl/widgets/qrcode.py +7 -7
- esphome/components/lvgl/widgets/spinner.py +6 -6
- esphome/components/lvgl/widgets/switch.py +2 -2
- esphome/components/lvgl/widgets/tabview.py +3 -3
- esphome/components/lvgl/widgets/tileview.py +15 -7
- esphome/components/m5stack_8angle/m5stack_8angle.cpp +0 -1
- esphome/components/matrix_keypad/__init__.py +4 -3
- esphome/components/max17043/max17043.cpp +0 -2
- esphome/components/max31855/max31855.cpp +1 -4
- esphome/components/max31856/max31856.cpp +0 -4
- esphome/components/max31865/max31865.cpp +0 -1
- esphome/components/max44009/max44009.cpp +0 -1
- esphome/components/max6675/max6675.cpp +1 -4
- esphome/components/max6956/max6956.cpp +0 -1
- esphome/components/max7219/max7219.cpp +0 -1
- esphome/components/max7219digit/display.py +1 -1
- esphome/components/max7219digit/max7219digit.cpp +0 -1
- esphome/components/max9611/max9611.cpp +0 -1
- esphome/components/mcp23008/__init__.py +1 -1
- esphome/components/mcp23008/mcp23008.cpp +0 -1
- esphome/components/mcp23016/mcp23016.cpp +0 -1
- esphome/components/mcp23017/__init__.py +1 -1
- esphome/components/mcp23017/mcp23017.cpp +0 -1
- esphome/components/mcp23s08/__init__.py +1 -1
- esphome/components/mcp23s08/mcp23s08.cpp +0 -1
- esphome/components/mcp23s17/__init__.py +1 -1
- esphome/components/mcp23s17/mcp23s17.cpp +0 -1
- esphome/components/mcp23x08_base/__init__.py +2 -0
- esphome/components/mcp23x08_base/mcp23x08_base.cpp +9 -7
- esphome/components/mcp23x08_base/mcp23x08_base.h +9 -4
- esphome/components/mcp23x17_base/__init__.py +2 -0
- esphome/components/mcp23x17_base/mcp23x17_base.cpp +20 -7
- esphome/components/mcp23x17_base/mcp23x17_base.h +9 -4
- esphome/components/mcp23xxx_base/__init__.py +11 -5
- esphome/components/mcp23xxx_base/mcp23xxx_base.cpp +15 -12
- esphome/components/mcp23xxx_base/mcp23xxx_base.h +8 -7
- esphome/components/mcp3008/mcp3008.cpp +1 -4
- esphome/components/mcp3204/mcp3204.cpp +1 -4
- esphome/components/mcp4461/mcp4461.cpp +0 -1
- esphome/components/mcp4725/mcp4725.cpp +0 -1
- esphome/components/mcp4728/mcp4728.cpp +0 -1
- esphome/components/mcp9600/mcp9600.cpp +0 -2
- esphome/components/mcp9808/mcp9808.cpp +0 -2
- esphome/components/mdns/__init__.py +3 -0
- esphome/components/mdns/mdns_component.cpp +2 -0
- esphome/components/mdns/mdns_component.h +4 -0
- esphome/components/media_player/__init__.py +40 -0
- esphome/components/media_player/automation.h +16 -0
- esphome/components/media_player/media_player.cpp +13 -0
- esphome/components/media_player/media_player.h +50 -3
- esphome/components/micro_wake_word/micro_wake_word.cpp +0 -3
- esphome/components/mics_4514/mics_4514.cpp +1 -6
- esphome/components/midea/ir_transmitter.h +4 -4
- esphome/components/mipi/__init__.py +416 -0
- esphome/components/mipi_dsi/__init__.py +5 -0
- esphome/components/mipi_dsi/display.py +233 -0
- esphome/components/mipi_dsi/mipi_dsi.cpp +379 -0
- esphome/components/mipi_dsi/mipi_dsi.h +123 -0
- esphome/components/mipi_dsi/models/__init__.py +0 -0
- esphome/components/mipi_dsi/models/guition.py +38 -0
- esphome/components/mipi_dsi/models/m5stack.py +57 -0
- esphome/components/mipi_dsi/models/waveshare.py +105 -0
- esphome/components/mipi_rgb/models/lilygo.py +0 -0
- esphome/components/mipi_spi/__init__.py +0 -9
- esphome/components/mipi_spi/display.py +220 -256
- esphome/components/mipi_spi/mipi_spi.cpp +1 -485
- esphome/components/mipi_spi/mipi_spi.h +556 -108
- esphome/components/mipi_spi/models/__init__.py +0 -65
- esphome/components/mipi_spi/models/adafruit.py +30 -0
- esphome/components/mipi_spi/models/amoled.py +41 -5
- esphome/components/mipi_spi/models/ili.py +5 -5
- esphome/components/mipi_spi/models/jc.py +1 -3
- esphome/components/mipi_spi/models/lilygo.py +1 -1
- esphome/components/mipi_spi/models/waveshare.py +16 -1
- esphome/components/mixer/speaker/__init__.py +4 -5
- esphome/components/mlx90393/sensor.py +7 -5
- esphome/components/mlx90393/sensor_mlx90393.cpp +0 -1
- esphome/components/mlx90614/mlx90614.cpp +0 -1
- esphome/components/mmc5603/mmc5603.cpp +0 -1
- esphome/components/mmc5983/mmc5983.cpp +0 -2
- esphome/components/mpl3115a2/mpl3115a2.cpp +0 -2
- esphome/components/mpr121/__init__.py +7 -6
- esphome/components/mpr121/mpr121.cpp +0 -1
- esphome/components/mpu6050/mpu6050.cpp +0 -1
- esphome/components/mpu6886/mpu6886.cpp +0 -1
- esphome/components/mqtt/__init__.py +1 -2
- esphome/components/mqtt/mqtt_button.cpp +1 -1
- esphome/components/mqtt/mqtt_client.cpp +0 -1
- esphome/components/mqtt/mqtt_component.cpp +8 -14
- esphome/components/mqtt/mqtt_component.h +0 -7
- esphome/components/mqtt/mqtt_sensor.cpp +0 -1
- esphome/components/mqtt/mqtt_sensor.h +0 -1
- esphome/components/mqtt/mqtt_text_sensor.cpp +0 -1
- esphome/components/mqtt/mqtt_text_sensor.h +0 -1
- esphome/components/ms5611/ms5611.cpp +0 -1
- esphome/components/ms8607/ms8607.cpp +0 -1
- esphome/components/msa3xx/msa3xx.cpp +0 -2
- esphome/components/my9231/my9231.cpp +0 -2
- esphome/components/nau7802/nau7802.cpp +0 -1
- esphome/components/neopixelbus/light.py +3 -0
- esphome/components/network/util.cpp +29 -0
- esphome/components/nextion/nextion.cpp +0 -1
- esphome/components/nfc/binary_sensor/{binary_sensor.cpp → nfc_binary_sensor.cpp} +1 -1
- esphome/components/npi19/npi19.cpp +0 -2
- esphome/components/nrf52/__init__.py +223 -0
- esphome/components/nrf52/boards.py +34 -0
- esphome/components/nrf52/const.py +18 -0
- esphome/components/nrf52/gpio.py +79 -0
- esphome/components/number/__init__.py +2 -1
- esphome/components/one_wire/__init__.py +1 -2
- esphome/components/one_wire/one_wire.cpp +0 -2
- esphome/components/one_wire/one_wire.h +0 -2
- esphome/components/opentherm/hub.cpp +0 -1
- esphome/components/opentherm/number/__init__.py +2 -2
- esphome/components/openthread/__init__.py +2 -3
- esphome/components/openthread/openthread.cpp +30 -13
- esphome/components/openthread/openthread.h +3 -0
- esphome/components/openthread/openthread_esp.cpp +3 -1
- esphome/components/opt3001/sensor.py +2 -6
- esphome/components/output/__init__.py +38 -0
- esphome/components/output/automation.h +24 -0
- esphome/components/output/switch/output_switch.cpp +0 -2
- esphome/components/packages/__init__.py +1 -2
- esphome/components/packet_transport/__init__.py +4 -3
- esphome/components/pca6416a/pca6416a.cpp +0 -1
- esphome/components/pca9554/pca9554.cpp +0 -1
- esphome/components/pca9685/pca9685_output.cpp +0 -2
- esphome/components/pcf85063/pcf85063.cpp +0 -1
- esphome/components/pcf8563/pcf8563.cpp +0 -1
- esphome/components/pcf8574/pcf8574.cpp +0 -1
- esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +0 -1
- esphome/components/pipsolar/sensor/__init__.py +1 -1
- esphome/components/pm2005/pm2005.cpp +0 -1
- esphome/components/pmsa003i/pmsa003i.cpp +0 -2
- esphome/components/pmwcs3/sensor.py +1 -2
- esphome/components/pn532/pn532.cpp +0 -2
- esphome/components/pn532_spi/pn532_spi.cpp +0 -2
- esphome/components/power_supply/power_supply.cpp +7 -10
- esphome/components/power_supply/power_supply.h +1 -1
- esphome/components/psram/__init__.py +2 -1
- esphome/components/pulse_counter/pulse_counter_sensor.cpp +0 -1
- esphome/components/pulse_counter/sensor.py +9 -6
- esphome/components/pylontech/pylontech.cpp +0 -1
- esphome/components/qmc5883l/qmc5883l.cpp +0 -1
- esphome/components/qmp6988/qmp6988.cpp +0 -2
- esphome/components/qspi_dbi/display.py +2 -3
- esphome/components/qspi_dbi/qspi_dbi.cpp +0 -2
- esphome/components/qwiic_pir/binary_sensor.py +2 -3
- esphome/components/qwiic_pir/qwiic_pir.cpp +0 -2
- esphome/components/rc522/rc522.cpp +9 -31
- esphome/components/rc522_spi/rc522_spi.cpp +0 -1
- esphome/components/remote_base/__init__.py +5 -6
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -1
- esphome/components/remote_receiver/remote_receiver_esp8266.cpp +0 -1
- esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -1
- esphome/components/remote_transmitter/__init__.py +26 -0
- esphome/components/remote_transmitter/automation.h +18 -0
- esphome/components/remote_transmitter/remote_transmitter.h +2 -1
- esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -1
- esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +2 -0
- esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +2 -0
- esphome/components/resampler/speaker/__init__.py +4 -5
- esphome/components/rf_bridge/__init__.py +4 -8
- esphome/components/rotary_encoder/rotary_encoder.cpp +0 -2
- esphome/components/rp2040/__init__.py +3 -1
- esphome/components/rp2040_pio_led_strip/led_strip.cpp +0 -2
- esphome/components/rp2040_pio_led_strip/light.py +1 -2
- esphome/components/rp2040_pwm/rp2040_pwm.cpp +1 -5
- esphome/components/rpi_dpi_rgb/display.py +13 -15
- esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -3
- esphome/components/runtime_stats/__init__.py +34 -0
- esphome/components/runtime_stats/runtime_stats.cpp +102 -0
- esphome/components/runtime_stats/runtime_stats.h +132 -0
- esphome/components/scd30/scd30.cpp +0 -2
- esphome/components/scd30/sensor.py +1 -2
- esphome/components/scd4x/scd4x.cpp +0 -1
- esphome/components/scd4x/sensor.py +1 -3
- esphome/components/sdl/display.py +3 -1
- esphome/components/sdl/sdl_esphome.cpp +0 -2
- esphome/components/sdp3x/sdp3x.cpp +0 -2
- esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp +0 -2
- esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp +0 -3
- esphome/components/select/__init__.py +2 -3
- esphome/components/select/select_traits.cpp +1 -1
- esphome/components/select/select_traits.h +1 -1
- esphome/components/sen0321/sen0321.cpp +0 -1
- esphome/components/sen5x/sen5x.cpp +0 -2
- esphome/components/sensor/__init__.py +36 -4
- esphome/components/sensor/filter.cpp +49 -10
- esphome/components/sensor/filter.h +22 -7
- esphome/components/sensor/sensor.cpp +0 -1
- esphome/components/sensor/sensor.h +0 -9
- esphome/components/sfa30/sfa30.cpp +0 -4
- esphome/components/sgp30/sgp30.cpp +0 -2
- esphome/components/sgp4x/sensor.py +1 -1
- esphome/components/sgp4x/sgp4x.cpp +0 -2
- esphome/components/shelly_dimmer/shelly_dimmer.cpp +0 -2
- esphome/components/sht3xd/sht3xd.cpp +0 -2
- esphome/components/sht4x/sht4x.cpp +0 -2
- esphome/components/shtcx/shtcx.cpp +0 -1
- esphome/components/sim800l/__init__.py +2 -4
- esphome/components/sm16716/sm16716.cpp +0 -1
- esphome/components/sm2135/sm2135.cpp +0 -1
- esphome/components/sm2235/sm2235.cpp +0 -1
- esphome/components/sm2335/sm2335.cpp +0 -1
- esphome/components/sn74hc165/sn74hc165.cpp +0 -1
- esphome/components/sn74hc595/sn74hc595.cpp +0 -1
- esphome/components/sntp/sntp_component.cpp +0 -1
- esphome/components/sound_level/sensor.py +1 -1
- esphome/components/speaker/media_player/__init__.py +21 -33
- esphome/components/speaker/media_player/audio_pipeline.cpp +4 -7
- esphome/components/spi/__init__.py +29 -13
- esphome/components/spi/spi.cpp +0 -2
- esphome/components/spi_device/spi_device.cpp +1 -4
- esphome/components/sprinkler/__init__.py +4 -4
- esphome/components/sps30/sps30.cpp +0 -1
- esphome/components/ssd1306_base/__init__.py +11 -11
- esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
- esphome/components/ssd1306_i2c/ssd1306_i2c.cpp +0 -1
- esphome/components/ssd1306_spi/ssd1306_spi.cpp +0 -1
- esphome/components/ssd1322_spi/ssd1322_spi.cpp +0 -1
- esphome/components/ssd1325_spi/ssd1325_spi.cpp +0 -1
- esphome/components/ssd1327_i2c/ssd1327_i2c.cpp +0 -1
- esphome/components/ssd1327_spi/ssd1327_spi.cpp +0 -1
- esphome/components/ssd1331_spi/ssd1331_spi.cpp +0 -1
- esphome/components/ssd1351_spi/ssd1351_spi.cpp +0 -1
- esphome/components/st7567_i2c/st7567_i2c.cpp +0 -1
- esphome/components/st7567_spi/st7567_spi.cpp +0 -1
- esphome/components/st7701s/display.py +10 -14
- esphome/components/st7701s/st7701s.cpp +0 -3
- esphome/components/st7735/st7735.cpp +0 -1
- esphome/components/st7789v/st7789v.cpp +0 -1
- esphome/components/st7920/st7920.cpp +0 -1
- esphome/components/status_led/light/status_led_light.cpp +0 -2
- esphome/components/status_led/status_led.cpp +0 -1
- esphome/components/stepper/__init__.py +2 -4
- esphome/components/sts3x/sts3x.cpp +0 -1
- esphome/components/substitutions/__init__.py +10 -16
- esphome/components/substitutions/jinja.py +24 -1
- esphome/components/sun/__init__.py +2 -3
- esphome/components/switch/__init__.py +31 -1
- esphome/components/switch/automation.h +24 -0
- esphome/components/switch/switch.cpp +8 -0
- esphome/components/switch/switch.h +8 -0
- esphome/components/sx126x/sx126x.cpp +0 -2
- esphome/components/sx127x/sx127x.cpp +0 -2
- esphome/components/sx1509/__init__.py +7 -5
- esphome/components/sx1509/output/sx1509_float_output.cpp +1 -1
- esphome/components/sx1509/sx1509.cpp +0 -2
- esphome/components/syslog/esphome_syslog.cpp +1 -1
- esphome/components/tc74/tc74.cpp +0 -1
- esphome/components/tca9548a/tca9548a.cpp +0 -1
- esphome/components/tca9555/tca9555.cpp +0 -1
- esphome/components/tcs34725/tcs34725.cpp +0 -1
- esphome/components/tee501/tee501.cpp +0 -1
- esphome/components/tem3200/tem3200.cpp +0 -2
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +0 -1
- esphome/components/template/cover/template_cover.cpp +0 -1
- esphome/components/template/select/template_select.cpp +0 -1
- esphome/components/template/text/template_text.cpp +0 -2
- esphome/components/template/valve/template_valve.cpp +0 -1
- esphome/components/text/__init__.py +0 -1
- esphome/components/text/text_traits.h +2 -0
- esphome/components/text_sensor/__init__.py +2 -1
- esphome/components/text_sensor/text_sensor.cpp +0 -2
- esphome/components/text_sensor/text_sensor.h +0 -8
- esphome/components/thermostat/climate.py +4 -4
- esphome/components/time/__init__.py +7 -4
- esphome/components/time/real_time_clock.cpp +16 -3
- esphome/components/tlc59208f/tlc59208f_output.cpp +0 -2
- esphome/components/tlc5947/tlc5947.cpp +0 -2
- esphome/components/tlc5971/tlc5971.cpp +0 -2
- esphome/components/tm1621/tm1621.cpp +0 -2
- esphome/components/tm1637/tm1637.cpp +0 -2
- esphome/components/tm1638/tm1638.cpp +0 -2
- esphome/components/tm1651/__init__.py +45 -48
- esphome/components/tm1651/tm1651.cpp +213 -47
- esphome/components/tm1651/tm1651.h +37 -32
- esphome/components/tmp117/tmp117.cpp +0 -2
- esphome/components/tsl2561/tsl2561.cpp +0 -1
- esphome/components/tsl2591/tsl2591.cpp +0 -1
- esphome/components/tt21100/touchscreen/tt21100.cpp +0 -2
- esphome/components/ttp229_bsf/ttp229_bsf.cpp +0 -1
- esphome/components/ttp229_lsf/ttp229_lsf.cpp +0 -1
- esphome/components/tuya/climate/__init__.py +9 -10
- esphome/components/tuya/number/__init__.py +8 -6
- esphome/components/tx20/tx20.cpp +0 -1
- esphome/components/uart/uart_component_esp32_arduino.cpp +0 -1
- esphome/components/uart/uart_component_esp8266.cpp +0 -1
- esphome/components/uart/uart_component_esp_idf.cpp +0 -2
- esphome/components/uart/uart_component_libretiny.cpp +0 -2
- esphome/components/uart/uart_component_rp2040.cpp +0 -2
- esphome/components/udp/__init__.py +1 -1
- esphome/components/ufire_ec/sensor.py +1 -2
- esphome/components/ufire_ec/ufire_ec.cpp +0 -2
- esphome/components/ufire_ise/sensor.py +1 -2
- esphome/components/ufire_ise/ufire_ise.cpp +0 -2
- esphome/components/ultrasonic/ultrasonic_sensor.cpp +0 -1
- esphome/components/update/__init__.py +0 -1
- esphome/components/uptime/sensor/uptime_seconds_sensor.cpp +0 -1
- esphome/components/uptime/sensor/uptime_seconds_sensor.h +0 -2
- esphome/components/usb_host/usb_host_client.cpp +0 -1
- esphome/components/usb_host/usb_host_component.cpp +0 -1
- esphome/components/valve/__init__.py +0 -1
- esphome/components/veml3235/veml3235.cpp +0 -3
- esphome/components/veml7700/veml7700.cpp +0 -2
- esphome/components/version/version_text_sensor.cpp +0 -1
- esphome/components/version/version_text_sensor.h +0 -1
- esphome/components/vl53l0x/vl53l0x_sensor.cpp +0 -4
- esphome/components/voice_assistant/voice_assistant.cpp +9 -8
- esphome/components/web_server/__init__.py +13 -0
- esphome/components/web_server/web_server.cpp +187 -352
- esphome/components/web_server/web_server.h +61 -1
- esphome/components/web_server_base/__init__.py +1 -1
- esphome/components/web_server_base/web_server_base.cpp +2 -0
- esphome/components/web_server_base/web_server_base.h +6 -0
- esphome/components/web_server_idf/web_server_idf.cpp +10 -8
- esphome/components/web_server_idf/web_server_idf.h +2 -0
- esphome/components/weikai_i2c/weikai_i2c.cpp +1 -2
- esphome/components/weikai_spi/weikai_spi.cpp +1 -1
- esphome/components/wifi/__init__.py +8 -43
- esphome/components/wifi/wifi_component.cpp +100 -36
- esphome/components/wifi/wifi_component.h +5 -1
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -0
- esphome/components/wifi/wifi_component_esp_idf.cpp +30 -0
- esphome/components/wifi_info/wifi_info_text_sensor.h +0 -6
- esphome/components/wifi_signal/wifi_signal_sensor.h +0 -1
- esphome/components/wireguard/wireguard.cpp +0 -2
- esphome/components/x9c/x9c.cpp +0 -2
- esphome/components/xgzp68xx/xgzp68xx.cpp +0 -1
- esphome/components/xl9535/xl9535.cpp +0 -2
- esphome/components/zephyr/__init__.py +252 -0
- esphome/components/zephyr/const.py +16 -0
- esphome/components/zephyr/core.cpp +90 -0
- esphome/components/zephyr/gpio.cpp +120 -0
- esphome/components/zephyr/gpio.h +38 -0
- esphome/components/zephyr/pre_build.py.script +4 -0
- esphome/components/zephyr/preferences.cpp +156 -0
- esphome/components/zephyr/preferences.h +13 -0
- esphome/config.py +38 -16
- esphome/config_helpers.py +1 -2
- esphome/config_validation.py +8 -15
- esphome/const.py +26 -1
- esphome/core/__init__.py +88 -51
- esphome/core/application.cpp +75 -21
- esphome/core/application.h +106 -171
- esphome/core/color.h +10 -0
- esphome/core/component.cpp +41 -25
- esphome/core/component.h +9 -6
- esphome/core/component_iterator.cpp +61 -261
- esphome/core/component_iterator.h +15 -0
- esphome/core/config.py +26 -11
- esphome/core/defines.h +40 -2
- esphome/core/entity_base.h +18 -0
- esphome/core/entity_helpers.py +41 -6
- esphome/core/helpers.cpp +8 -15
- esphome/core/helpers.h +60 -6
- esphome/core/lock_free_queue.h +1 -1
- esphome/core/scheduler.cpp +277 -74
- esphome/core/scheduler.h +89 -27
- esphome/cpp_generator.py +2 -6
- esphome/cpp_helpers.py +1 -1
- esphome/dashboard/dashboard.py +2 -3
- esphome/dashboard/dns.py +2 -8
- esphome/dashboard/web_server.py +34 -19
- esphome/espota2.py +1 -4
- esphome/git.py +3 -1
- esphome/helpers.py +23 -4
- esphome/log.py +3 -1
- esphome/mqtt.py +3 -5
- esphome/platformio_api.py +7 -4
- esphome/types.py +12 -0
- esphome/util.py +20 -8
- esphome/voluptuous_schema.py +4 -3
- esphome/vscode.py +1 -2
- esphome/wizard.py +1 -4
- esphome/writer.py +5 -107
- esphome/yaml_util.py +7 -5
- {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/METADATA +12 -13
- {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/RECORD +753 -673
- esphome/components/mipi_spi/models/commands.py +0 -82
- /esphome/components/nfc/binary_sensor/{binary_sensor.h → nfc_binary_sensor.h} +0 -0
- {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/WHEEL +0 -0
- {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/top_level.txt +0 -0
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#endif
|
|
10
10
|
|
|
11
11
|
#include "esphome/components/audio/audio.h"
|
|
12
|
+
#include "esphome/components/audio/audio_transfer_buffer.h"
|
|
12
13
|
|
|
13
14
|
#include "esphome/core/application.h"
|
|
14
15
|
#include "esphome/core/hal.h"
|
|
@@ -19,71 +20,32 @@
|
|
|
19
20
|
namespace esphome {
|
|
20
21
|
namespace i2s_audio {
|
|
21
22
|
|
|
22
|
-
static const
|
|
23
|
+
static const uint32_t DMA_BUFFER_DURATION_MS = 15;
|
|
23
24
|
static const size_t DMA_BUFFERS_COUNT = 4;
|
|
24
25
|
|
|
25
|
-
static const size_t TASK_DELAY_MS = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT / 2;
|
|
26
|
-
|
|
27
26
|
static const size_t TASK_STACK_SIZE = 4096;
|
|
28
|
-
static const ssize_t TASK_PRIORITY =
|
|
27
|
+
static const ssize_t TASK_PRIORITY = 19;
|
|
29
28
|
|
|
30
29
|
static const size_t I2S_EVENT_QUEUE_COUNT = DMA_BUFFERS_COUNT + 1;
|
|
31
30
|
|
|
32
31
|
static const char *const TAG = "i2s_audio.speaker";
|
|
33
32
|
|
|
34
33
|
enum SpeakerEventGroupBits : uint32_t {
|
|
35
|
-
COMMAND_START = (1 << 0), //
|
|
34
|
+
COMMAND_START = (1 << 0), // indicates loop should start speaker task
|
|
36
35
|
COMMAND_STOP = (1 << 1), // stops the speaker task
|
|
37
36
|
COMMAND_STOP_GRACEFULLY = (1 << 2), // Stops the speaker task once all data has been written
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ERR_ESP_NOT_SUPPORTED = (1 << 16),
|
|
45
|
-
ERR_ESP_INVALID_ARG = (1 << 17),
|
|
46
|
-
ERR_ESP_INVALID_SIZE = (1 << 18),
|
|
37
|
+
|
|
38
|
+
TASK_STARTING = (1 << 10),
|
|
39
|
+
TASK_RUNNING = (1 << 11),
|
|
40
|
+
TASK_STOPPING = (1 << 12),
|
|
41
|
+
TASK_STOPPED = (1 << 13),
|
|
42
|
+
|
|
47
43
|
ERR_ESP_NO_MEM = (1 << 19),
|
|
48
|
-
ERR_ESP_FAIL = (1 << 20),
|
|
49
|
-
ALL_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_NOT_SUPPORTED | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE |
|
|
50
|
-
ERR_ESP_NO_MEM | ERR_ESP_FAIL,
|
|
51
|
-
ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
|
|
52
|
-
};
|
|
53
44
|
|
|
54
|
-
|
|
55
|
-
static esp_err_t err_bit_to_esp_err(uint32_t bit) {
|
|
56
|
-
switch (bit) {
|
|
57
|
-
case SpeakerEventGroupBits::ERR_ESP_INVALID_STATE:
|
|
58
|
-
return ESP_ERR_INVALID_STATE;
|
|
59
|
-
case SpeakerEventGroupBits::ERR_ESP_INVALID_ARG:
|
|
60
|
-
return ESP_ERR_INVALID_ARG;
|
|
61
|
-
case SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE:
|
|
62
|
-
return ESP_ERR_INVALID_SIZE;
|
|
63
|
-
case SpeakerEventGroupBits::ERR_ESP_NO_MEM:
|
|
64
|
-
return ESP_ERR_NO_MEM;
|
|
65
|
-
case SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED:
|
|
66
|
-
return ESP_ERR_NOT_SUPPORTED;
|
|
67
|
-
default:
|
|
68
|
-
return ESP_FAIL;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
45
|
+
WARN_DROPPED_EVENT = (1 << 20),
|
|
71
46
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
/// Based on `dsps_mulc_s16_ansi` from the esp-dsp library:
|
|
75
|
-
/// https://github.com/espressif/esp-dsp/blob/master/modules/math/mulc/fixed/dsps_mulc_s16_ansi.c
|
|
76
|
-
/// (accessed on 2024-09-30).
|
|
77
|
-
/// @param input Array of Q15 numbers
|
|
78
|
-
/// @param output Array of Q15 numbers
|
|
79
|
-
/// @param len Length of array
|
|
80
|
-
/// @param c Q15 constant factor
|
|
81
|
-
static void q15_multiplication(const int16_t *input, int16_t *output, size_t len, int16_t c) {
|
|
82
|
-
for (int i = 0; i < len; i++) {
|
|
83
|
-
int32_t acc = (int32_t) input[i] * (int32_t) c;
|
|
84
|
-
output[i] = (int16_t) (acc >> 15);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
47
|
+
ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
|
|
48
|
+
};
|
|
87
49
|
|
|
88
50
|
// Lists the Q15 fixed point scaling factor for volume reduction.
|
|
89
51
|
// Has 100 values representing silence and a reduction [49, 48.5, ... 0.5, 0] dB.
|
|
@@ -99,8 +61,6 @@ static const std::vector<int16_t> Q15_VOLUME_SCALING_FACTORS = {
|
|
|
99
61
|
19508, 20665, 21891, 23189, 24565, 26022, 27566, 29201, 30933, 32767};
|
|
100
62
|
|
|
101
63
|
void I2SAudioSpeaker::setup() {
|
|
102
|
-
ESP_LOGCONFIG(TAG, "Running setup");
|
|
103
|
-
|
|
104
64
|
this->event_group_ = xEventGroupCreate();
|
|
105
65
|
|
|
106
66
|
if (this->event_group_ == nullptr) {
|
|
@@ -132,51 +92,80 @@ void I2SAudioSpeaker::dump_config() {
|
|
|
132
92
|
void I2SAudioSpeaker::loop() {
|
|
133
93
|
uint32_t event_group_bits = xEventGroupGetBits(this->event_group_);
|
|
134
94
|
|
|
135
|
-
if (event_group_bits & SpeakerEventGroupBits::
|
|
136
|
-
ESP_LOGD(TAG, "Starting");
|
|
95
|
+
if ((event_group_bits & SpeakerEventGroupBits::COMMAND_START) && (this->state_ == speaker::STATE_STOPPED)) {
|
|
137
96
|
this->state_ = speaker::STATE_STARTING;
|
|
138
|
-
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::
|
|
97
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::COMMAND_START);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Handle the task's state
|
|
101
|
+
if (event_group_bits & SpeakerEventGroupBits::TASK_STARTING) {
|
|
102
|
+
ESP_LOGD(TAG, "Starting");
|
|
103
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::TASK_STARTING);
|
|
139
104
|
}
|
|
140
|
-
if (event_group_bits & SpeakerEventGroupBits::
|
|
105
|
+
if (event_group_bits & SpeakerEventGroupBits::TASK_RUNNING) {
|
|
141
106
|
ESP_LOGD(TAG, "Started");
|
|
107
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::TASK_RUNNING);
|
|
142
108
|
this->state_ = speaker::STATE_RUNNING;
|
|
143
|
-
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
|
|
144
|
-
this->status_clear_warning();
|
|
145
|
-
this->status_clear_error();
|
|
146
109
|
}
|
|
147
|
-
if (event_group_bits & SpeakerEventGroupBits::
|
|
110
|
+
if (event_group_bits & SpeakerEventGroupBits::TASK_STOPPING) {
|
|
148
111
|
ESP_LOGD(TAG, "Stopping");
|
|
112
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::TASK_STOPPING);
|
|
149
113
|
this->state_ = speaker::STATE_STOPPING;
|
|
150
|
-
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
|
|
151
|
-
}
|
|
152
|
-
if (event_group_bits & SpeakerEventGroupBits::STATE_STOPPED) {
|
|
153
|
-
if (!this->task_created_) {
|
|
154
|
-
ESP_LOGD(TAG, "Stopped");
|
|
155
|
-
this->state_ = speaker::STATE_STOPPED;
|
|
156
|
-
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ALL_BITS);
|
|
157
|
-
this->speaker_task_handle_ = nullptr;
|
|
158
|
-
}
|
|
159
114
|
}
|
|
115
|
+
if (event_group_bits & SpeakerEventGroupBits::TASK_STOPPED) {
|
|
116
|
+
ESP_LOGD(TAG, "Stopped");
|
|
117
|
+
|
|
118
|
+
vTaskDelete(this->speaker_task_handle_);
|
|
119
|
+
this->speaker_task_handle_ = nullptr;
|
|
120
|
+
|
|
121
|
+
this->stop_i2s_driver_();
|
|
122
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ALL_BITS);
|
|
123
|
+
this->status_clear_error();
|
|
160
124
|
|
|
161
|
-
|
|
162
|
-
this->status_set_error("Failed to start task");
|
|
163
|
-
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
|
|
125
|
+
this->state_ = speaker::STATE_STOPPED;
|
|
164
126
|
}
|
|
165
127
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
this->
|
|
128
|
+
// Log any errors encounted by the task
|
|
129
|
+
if (event_group_bits & SpeakerEventGroupBits::ERR_ESP_NO_MEM) {
|
|
130
|
+
ESP_LOGE(TAG, "Not enough memory");
|
|
131
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
|
|
170
132
|
}
|
|
171
133
|
|
|
172
|
-
if
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
this->audio_stream_info_.get_bits_per_sample());
|
|
134
|
+
// Warn if any playback timestamp events are dropped, which drastically reduces synced playback accuracy
|
|
135
|
+
if (event_group_bits & SpeakerEventGroupBits::WARN_DROPPED_EVENT) {
|
|
136
|
+
ESP_LOGW(TAG, "Event dropped, synchronized playback accuracy is reduced");
|
|
137
|
+
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::WARN_DROPPED_EVENT);
|
|
177
138
|
}
|
|
178
139
|
|
|
179
|
-
|
|
140
|
+
// Handle the speaker's state
|
|
141
|
+
switch (this->state_) {
|
|
142
|
+
case speaker::STATE_STARTING:
|
|
143
|
+
if (this->status_has_error()) {
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (this->start_i2s_driver_(this->audio_stream_info_) != ESP_OK) {
|
|
148
|
+
ESP_LOGE(TAG, "Driver failed to start; retrying in 1 second");
|
|
149
|
+
this->status_momentary_error("driver-faiure", 1000);
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (this->speaker_task_handle_ == nullptr) {
|
|
154
|
+
xTaskCreate(I2SAudioSpeaker::speaker_task, "speaker_task", TASK_STACK_SIZE, (void *) this, TASK_PRIORITY,
|
|
155
|
+
&this->speaker_task_handle_);
|
|
156
|
+
|
|
157
|
+
if (this->speaker_task_handle_ == nullptr) {
|
|
158
|
+
ESP_LOGE(TAG, "Task failed to start, retrying in 1 second");
|
|
159
|
+
this->status_momentary_error("task-failure", 1000);
|
|
160
|
+
this->stop_i2s_driver_(); // Stops the driver to return the lock; will be reloaded in next attempt
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
case speaker::STATE_RUNNING: // Intentional fallthrough
|
|
165
|
+
case speaker::STATE_STOPPING: // Intentional fallthrough
|
|
166
|
+
case speaker::STATE_STOPPED:
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
180
169
|
}
|
|
181
170
|
|
|
182
171
|
void I2SAudioSpeaker::set_volume(float volume) {
|
|
@@ -227,83 +216,76 @@ size_t I2SAudioSpeaker::play(const uint8_t *data, size_t length, TickType_t tick
|
|
|
227
216
|
this->start();
|
|
228
217
|
}
|
|
229
218
|
|
|
230
|
-
if (
|
|
219
|
+
if (this->state_ != speaker::STATE_RUNNING) {
|
|
231
220
|
// Unable to write data to a running speaker, so delay the max amount of time so it can get ready
|
|
232
221
|
vTaskDelay(ticks_to_wait);
|
|
233
222
|
ticks_to_wait = 0;
|
|
234
223
|
}
|
|
235
224
|
|
|
236
225
|
size_t bytes_written = 0;
|
|
237
|
-
if (
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
bytes_written = temp_ring_buffer->write_without_replacement((void *) data, length, ticks_to_wait);
|
|
226
|
+
if (this->state_ == speaker::STATE_RUNNING) {
|
|
227
|
+
std::shared_ptr<RingBuffer> temp_ring_buffer = this->audio_ring_buffer_.lock();
|
|
228
|
+
if (temp_ring_buffer.use_count() == 2) {
|
|
229
|
+
// Only the speaker task and this temp_ring_buffer own the ring buffer, so its safe to write to
|
|
230
|
+
bytes_written = temp_ring_buffer->write_without_replacement((void *) data, length, ticks_to_wait);
|
|
231
|
+
}
|
|
244
232
|
}
|
|
245
233
|
|
|
246
234
|
return bytes_written;
|
|
247
235
|
}
|
|
248
236
|
|
|
249
237
|
bool I2SAudioSpeaker::has_buffered_data() const {
|
|
250
|
-
if (this->audio_ring_buffer_
|
|
251
|
-
|
|
238
|
+
if (this->audio_ring_buffer_.use_count() > 0) {
|
|
239
|
+
std::shared_ptr<RingBuffer> temp_ring_buffer = this->audio_ring_buffer_.lock();
|
|
240
|
+
return temp_ring_buffer->available() > 0;
|
|
252
241
|
}
|
|
253
242
|
return false;
|
|
254
243
|
}
|
|
255
244
|
|
|
256
245
|
void I2SAudioSpeaker::speaker_task(void *params) {
|
|
257
246
|
I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) params;
|
|
258
|
-
this_speaker->task_created_ = true;
|
|
259
|
-
|
|
260
|
-
uint32_t event_group_bits =
|
|
261
|
-
xEventGroupWaitBits(this_speaker->event_group_,
|
|
262
|
-
SpeakerEventGroupBits::COMMAND_START | SpeakerEventGroupBits::COMMAND_STOP |
|
|
263
|
-
SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY, // Bit message to read
|
|
264
|
-
pdTRUE, // Clear the bits on exit
|
|
265
|
-
pdFALSE, // Don't wait for all the bits,
|
|
266
|
-
portMAX_DELAY); // Block indefinitely until a bit is set
|
|
267
|
-
|
|
268
|
-
if (event_group_bits & (SpeakerEventGroupBits::COMMAND_STOP | SpeakerEventGroupBits::COMMAND_STOP_GRACEFULLY)) {
|
|
269
|
-
// Received a stop signal before the task was requested to start
|
|
270
|
-
this_speaker->delete_task_(0);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STARTING);
|
|
274
247
|
|
|
275
|
-
|
|
248
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::TASK_STARTING);
|
|
276
249
|
|
|
277
250
|
const uint32_t dma_buffers_duration_ms = DMA_BUFFER_DURATION_MS * DMA_BUFFERS_COUNT;
|
|
278
251
|
// Ensure ring buffer duration is at least the duration of all DMA buffers
|
|
279
252
|
const uint32_t ring_buffer_duration = std::max(dma_buffers_duration_ms, this_speaker->buffer_duration_ms_);
|
|
280
253
|
|
|
281
254
|
// The DMA buffers may have more bits per sample, so calculate buffer sizes based in the input audio stream info
|
|
282
|
-
const size_t
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
255
|
+
const size_t ring_buffer_size = this_speaker->current_stream_info_.ms_to_bytes(ring_buffer_duration);
|
|
256
|
+
|
|
257
|
+
const uint32_t frames_to_fill_single_dma_buffer =
|
|
258
|
+
this_speaker->current_stream_info_.ms_to_frames(DMA_BUFFER_DURATION_MS);
|
|
259
|
+
const size_t bytes_to_fill_single_dma_buffer =
|
|
260
|
+
this_speaker->current_stream_info_.frames_to_bytes(frames_to_fill_single_dma_buffer);
|
|
261
|
+
|
|
262
|
+
bool successful_setup = false;
|
|
263
|
+
std::unique_ptr<audio::AudioSourceTransferBuffer> transfer_buffer =
|
|
264
|
+
audio::AudioSourceTransferBuffer::create(bytes_to_fill_single_dma_buffer);
|
|
265
|
+
|
|
266
|
+
if (transfer_buffer != nullptr) {
|
|
267
|
+
std::shared_ptr<RingBuffer> temp_ring_buffer = RingBuffer::create(ring_buffer_size);
|
|
268
|
+
if (temp_ring_buffer.use_count() == 1) {
|
|
269
|
+
transfer_buffer->set_source(temp_ring_buffer);
|
|
270
|
+
this_speaker->audio_ring_buffer_ = temp_ring_buffer;
|
|
271
|
+
successful_setup = true;
|
|
272
|
+
}
|
|
291
273
|
}
|
|
292
274
|
|
|
293
|
-
if (!
|
|
294
|
-
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::
|
|
295
|
-
|
|
275
|
+
if (!successful_setup) {
|
|
276
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
|
|
277
|
+
} else {
|
|
296
278
|
bool stop_gracefully = false;
|
|
279
|
+
bool tx_dma_underflow = true;
|
|
280
|
+
|
|
281
|
+
uint32_t frames_written = 0;
|
|
297
282
|
uint32_t last_data_received_time = millis();
|
|
298
|
-
bool tx_dma_underflow = false;
|
|
299
283
|
|
|
300
|
-
this_speaker->
|
|
284
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::TASK_RUNNING);
|
|
301
285
|
|
|
302
|
-
// Keep looping if paused, there is no timeout configured, or data was received more recently than the configured
|
|
303
|
-
// timeout
|
|
304
286
|
while (this_speaker->pause_state_ || !this_speaker->timeout_.has_value() ||
|
|
305
287
|
(millis() - last_data_received_time) <= this_speaker->timeout_.value()) {
|
|
306
|
-
event_group_bits = xEventGroupGetBits(this_speaker->event_group_);
|
|
288
|
+
uint32_t event_group_bits = xEventGroupGetBits(this_speaker->event_group_);
|
|
307
289
|
|
|
308
290
|
if (event_group_bits & SpeakerEventGroupBits::COMMAND_STOP) {
|
|
309
291
|
xEventGroupClearBits(this_speaker->event_group_, SpeakerEventGroupBits::COMMAND_STOP);
|
|
@@ -314,7 +296,7 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|
|
314
296
|
stop_gracefully = true;
|
|
315
297
|
}
|
|
316
298
|
|
|
317
|
-
if (this_speaker->audio_stream_info_ !=
|
|
299
|
+
if (this_speaker->audio_stream_info_ != this_speaker->current_stream_info_) {
|
|
318
300
|
// Audio stream info changed, stop the speaker task so it will restart with the proper settings.
|
|
319
301
|
break;
|
|
320
302
|
}
|
|
@@ -326,36 +308,75 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|
|
326
308
|
}
|
|
327
309
|
}
|
|
328
310
|
#else
|
|
329
|
-
|
|
330
|
-
while (xQueueReceive(this_speaker->i2s_event_queue_, &
|
|
331
|
-
|
|
311
|
+
int64_t write_timestamp;
|
|
312
|
+
while (xQueueReceive(this_speaker->i2s_event_queue_, &write_timestamp, 0)) {
|
|
313
|
+
// Receives timing events from the I2S on_sent callback. If actual audio data was sent in this event, it passes
|
|
314
|
+
// on the timing info via the audio_output_callback.
|
|
315
|
+
uint32_t frames_sent = frames_to_fill_single_dma_buffer;
|
|
316
|
+
if (frames_to_fill_single_dma_buffer > frames_written) {
|
|
332
317
|
tx_dma_underflow = true;
|
|
318
|
+
frames_sent = frames_written;
|
|
319
|
+
const uint32_t frames_zeroed = frames_to_fill_single_dma_buffer - frames_written;
|
|
320
|
+
write_timestamp -= this_speaker->current_stream_info_.frames_to_microseconds(frames_zeroed);
|
|
321
|
+
} else {
|
|
322
|
+
tx_dma_underflow = false;
|
|
323
|
+
}
|
|
324
|
+
frames_written -= frames_sent;
|
|
325
|
+
if (frames_sent > 0) {
|
|
326
|
+
this_speaker->audio_output_callback_(frames_sent, write_timestamp);
|
|
333
327
|
}
|
|
334
328
|
}
|
|
335
329
|
#endif
|
|
336
330
|
|
|
337
331
|
if (this_speaker->pause_state_) {
|
|
338
332
|
// Pause state is accessed atomically, so thread safe
|
|
339
|
-
// Delay so the task
|
|
340
|
-
|
|
333
|
+
// Delay so the task yields, then skip transferring audio data
|
|
334
|
+
vTaskDelay(pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS));
|
|
341
335
|
continue;
|
|
342
336
|
}
|
|
343
337
|
|
|
344
|
-
|
|
345
|
-
|
|
338
|
+
// Wait half the duration of the data already written to the DMA buffers for new audio data
|
|
339
|
+
// The millisecond helper modifies the frames_written variable, so use the microsecond helper and divide by 1000
|
|
340
|
+
const uint32_t read_delay =
|
|
341
|
+
(this_speaker->current_stream_info_.frames_to_microseconds(frames_written) / 1000) / 2;
|
|
342
|
+
|
|
343
|
+
uint8_t *new_data = transfer_buffer->get_buffer_end(); // track start of any newly copied bytes
|
|
344
|
+
size_t bytes_read = transfer_buffer->transfer_data_from_source(pdMS_TO_TICKS(read_delay));
|
|
346
345
|
|
|
347
346
|
if (bytes_read > 0) {
|
|
348
|
-
if (
|
|
349
|
-
//
|
|
350
|
-
|
|
351
|
-
|
|
347
|
+
if (this_speaker->q15_volume_factor_ < INT16_MAX) {
|
|
348
|
+
// Apply the software volume adjustment by unpacking the sample into a Q31 fixed-point number, shifting it,
|
|
349
|
+
// multiplying by the volume factor, and packing the sample back into the original bytes per sample.
|
|
350
|
+
|
|
351
|
+
const size_t bytes_per_sample = this_speaker->current_stream_info_.samples_to_bytes(1);
|
|
352
|
+
const uint32_t len = bytes_read / bytes_per_sample;
|
|
353
|
+
|
|
354
|
+
// Use Q16 for samples with 1 or 2 bytes: shifted_sample * gain_factor is Q16 * Q15 -> Q31
|
|
355
|
+
int32_t shift = 15; // Q31 -> Q16
|
|
356
|
+
int32_t gain_factor = this_speaker->q15_volume_factor_; // Q15
|
|
357
|
+
|
|
358
|
+
if (bytes_per_sample >= 3) {
|
|
359
|
+
// Use Q23 for samples with 3 or 4 bytes: shifted_sample * gain_factor is Q23 * Q8 -> Q31
|
|
360
|
+
|
|
361
|
+
shift = 8; // Q31 -> Q23
|
|
362
|
+
gain_factor >>= 7; // Q15 -> Q8
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
for (uint32_t i = 0; i < len; ++i) {
|
|
366
|
+
int32_t sample =
|
|
367
|
+
audio::unpack_audio_sample_to_q31(&new_data[i * bytes_per_sample], bytes_per_sample); // Q31
|
|
368
|
+
sample >>= shift;
|
|
369
|
+
sample *= gain_factor; // Q31
|
|
370
|
+
audio::pack_q31_as_audio_sample(sample, &new_data[i * bytes_per_sample], bytes_per_sample);
|
|
371
|
+
}
|
|
352
372
|
}
|
|
353
373
|
|
|
354
374
|
#ifdef USE_ESP32_VARIANT_ESP32
|
|
355
375
|
// For ESP32 8/16 bit mono mode samples need to be switched.
|
|
356
|
-
if (
|
|
376
|
+
if (this_speaker->current_stream_info_.get_channels() == 1 &&
|
|
377
|
+
this_speaker->current_stream_info_.get_bits_per_sample() <= 16) {
|
|
357
378
|
size_t len = bytes_read / sizeof(int16_t);
|
|
358
|
-
int16_t *tmp_buf = (int16_t *)
|
|
379
|
+
int16_t *tmp_buf = (int16_t *) new_data;
|
|
359
380
|
for (int i = 0; i < len; i += 2) {
|
|
360
381
|
int16_t tmp = tmp_buf[i];
|
|
361
382
|
tmp_buf[i] = tmp_buf[i + 1];
|
|
@@ -363,62 +384,87 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|
|
363
384
|
}
|
|
364
385
|
}
|
|
365
386
|
#endif
|
|
366
|
-
|
|
367
|
-
// callback.
|
|
368
|
-
const uint32_t batches = (bytes_read + single_dma_buffer_input_size - 1) / single_dma_buffer_input_size;
|
|
369
|
-
|
|
370
|
-
for (uint32_t i = 0; i < batches; ++i) {
|
|
371
|
-
size_t bytes_written = 0;
|
|
372
|
-
size_t bytes_to_write = std::min(single_dma_buffer_input_size, bytes_read);
|
|
387
|
+
}
|
|
373
388
|
|
|
389
|
+
if (transfer_buffer->available() == 0) {
|
|
390
|
+
if (stop_gracefully && tx_dma_underflow) {
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
vTaskDelay(pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS / 2));
|
|
394
|
+
} else {
|
|
395
|
+
size_t bytes_written = 0;
|
|
374
396
|
#ifdef USE_I2S_LEGACY
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
397
|
+
if (this_speaker->current_stream_info_.get_bits_per_sample() == (uint8_t) this_speaker->bits_per_sample_) {
|
|
398
|
+
i2s_write(this_speaker->parent_->get_port(), transfer_buffer->get_buffer_start(),
|
|
399
|
+
transfer_buffer->available(), &bytes_written, pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS));
|
|
400
|
+
} else if (this_speaker->current_stream_info_.get_bits_per_sample() <
|
|
401
|
+
(uint8_t) this_speaker->bits_per_sample_) {
|
|
402
|
+
i2s_write_expand(this_speaker->parent_->get_port(), transfer_buffer->get_buffer_start(),
|
|
403
|
+
transfer_buffer->available(), this_speaker->current_stream_info_.get_bits_per_sample(),
|
|
404
|
+
this_speaker->bits_per_sample_, &bytes_written, pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS));
|
|
405
|
+
}
|
|
384
406
|
#else
|
|
385
|
-
|
|
386
|
-
|
|
407
|
+
if (tx_dma_underflow) {
|
|
408
|
+
// Temporarily disable channel and callback to reset the I2S driver's internal DMA buffer queue so timing
|
|
409
|
+
// callbacks are accurate. Preload the data.
|
|
410
|
+
i2s_channel_disable(this_speaker->tx_handle_);
|
|
411
|
+
const i2s_event_callbacks_t callbacks = {
|
|
412
|
+
.on_sent = nullptr,
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
i2s_channel_register_event_callback(this_speaker->tx_handle_, &callbacks, this_speaker);
|
|
416
|
+
i2s_channel_preload_data(this_speaker->tx_handle_, transfer_buffer->get_buffer_start(),
|
|
417
|
+
transfer_buffer->available(), &bytes_written);
|
|
418
|
+
} else {
|
|
419
|
+
// Audio is already playing, use regular I2S write to add to the DMA buffers
|
|
420
|
+
i2s_channel_write(this_speaker->tx_handle_, transfer_buffer->get_buffer_start(), transfer_buffer->available(),
|
|
421
|
+
&bytes_written, DMA_BUFFER_DURATION_MS);
|
|
422
|
+
}
|
|
387
423
|
#endif
|
|
424
|
+
if (bytes_written > 0) {
|
|
425
|
+
last_data_received_time = millis();
|
|
426
|
+
frames_written += this_speaker->current_stream_info_.bytes_to_frames(bytes_written);
|
|
427
|
+
transfer_buffer->decrease_buffer_length(bytes_written);
|
|
428
|
+
if (tx_dma_underflow) {
|
|
429
|
+
tx_dma_underflow = false;
|
|
430
|
+
#ifndef USE_I2S_LEGACY
|
|
431
|
+
// Reset the event queue timestamps
|
|
432
|
+
// Enable the on_sent callback to accurately track the timestamps of played audio
|
|
433
|
+
// Enable the I2S channel to start sending the preloaded audio
|
|
388
434
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
if (bytes_written != bytes_to_write) {
|
|
392
|
-
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE);
|
|
393
|
-
}
|
|
394
|
-
bytes_read -= bytes_written;
|
|
435
|
+
xQueueReset(this_speaker->i2s_event_queue_);
|
|
395
436
|
|
|
396
|
-
|
|
397
|
-
|
|
437
|
+
const i2s_event_callbacks_t callbacks = {
|
|
438
|
+
.on_sent = i2s_on_sent_cb,
|
|
439
|
+
};
|
|
440
|
+
i2s_channel_register_event_callback(this_speaker->tx_handle_, &callbacks, this_speaker);
|
|
398
441
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
442
|
+
i2s_channel_enable(this_speaker->tx_handle_);
|
|
443
|
+
#endif
|
|
444
|
+
}
|
|
445
|
+
#ifdef USE_I2S_LEGACY
|
|
446
|
+
// The legacy driver doesn't easily support the callback approach for timestamps, so fall back to a direct but
|
|
447
|
+
// less accurate approach.
|
|
448
|
+
this_speaker->audio_output_callback_(this_speaker->current_stream_info_.bytes_to_frames(bytes_written),
|
|
449
|
+
esp_timer_get_time() + dma_buffers_duration_ms * 1000);
|
|
450
|
+
#endif
|
|
406
451
|
}
|
|
407
452
|
}
|
|
408
453
|
}
|
|
454
|
+
}
|
|
409
455
|
|
|
410
|
-
|
|
411
|
-
#ifdef USE_I2S_LEGACY
|
|
412
|
-
i2s_driver_uninstall(this_speaker->parent_->get_port());
|
|
413
|
-
#else
|
|
414
|
-
i2s_channel_disable(this_speaker->tx_handle_);
|
|
415
|
-
i2s_del_channel(this_speaker->tx_handle_);
|
|
416
|
-
#endif
|
|
456
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::TASK_STOPPING);
|
|
417
457
|
|
|
418
|
-
|
|
458
|
+
if (transfer_buffer != nullptr) {
|
|
459
|
+
transfer_buffer.reset();
|
|
419
460
|
}
|
|
420
461
|
|
|
421
|
-
this_speaker->
|
|
462
|
+
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::TASK_STOPPED);
|
|
463
|
+
|
|
464
|
+
while (true) {
|
|
465
|
+
// Continuously delay until the loop method deletes the task
|
|
466
|
+
vTaskDelay(pdMS_TO_TICKS(10));
|
|
467
|
+
}
|
|
422
468
|
}
|
|
423
469
|
|
|
424
470
|
void I2SAudioSpeaker::start() {
|
|
@@ -427,16 +473,7 @@ void I2SAudioSpeaker::start() {
|
|
|
427
473
|
if ((this->state_ == speaker::STATE_STARTING) || (this->state_ == speaker::STATE_RUNNING))
|
|
428
474
|
return;
|
|
429
475
|
|
|
430
|
-
|
|
431
|
-
xTaskCreate(I2SAudioSpeaker::speaker_task, "speaker_task", TASK_STACK_SIZE, (void *) this, TASK_PRIORITY,
|
|
432
|
-
&this->speaker_task_handle_);
|
|
433
|
-
|
|
434
|
-
if (this->speaker_task_handle_ != nullptr) {
|
|
435
|
-
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_START);
|
|
436
|
-
} else {
|
|
437
|
-
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
476
|
+
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::COMMAND_START);
|
|
440
477
|
}
|
|
441
478
|
|
|
442
479
|
void I2SAudioSpeaker::stop() { this->stop_(false); }
|
|
@@ -456,61 +493,16 @@ void I2SAudioSpeaker::stop_(bool wait_on_empty) {
|
|
|
456
493
|
}
|
|
457
494
|
}
|
|
458
495
|
|
|
459
|
-
bool I2SAudioSpeaker::send_esp_err_to_event_group_(esp_err_t err) {
|
|
460
|
-
switch (err) {
|
|
461
|
-
case ESP_OK:
|
|
462
|
-
return false;
|
|
463
|
-
case ESP_ERR_INVALID_STATE:
|
|
464
|
-
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_STATE);
|
|
465
|
-
return true;
|
|
466
|
-
case ESP_ERR_INVALID_ARG:
|
|
467
|
-
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_ARG);
|
|
468
|
-
return true;
|
|
469
|
-
case ESP_ERR_INVALID_SIZE:
|
|
470
|
-
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE);
|
|
471
|
-
return true;
|
|
472
|
-
case ESP_ERR_NO_MEM:
|
|
473
|
-
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
|
|
474
|
-
return true;
|
|
475
|
-
case ESP_ERR_NOT_SUPPORTED:
|
|
476
|
-
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED);
|
|
477
|
-
return true;
|
|
478
|
-
default:
|
|
479
|
-
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_FAIL);
|
|
480
|
-
return true;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
esp_err_t I2SAudioSpeaker::allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size) {
|
|
485
|
-
if (this->data_buffer_ == nullptr) {
|
|
486
|
-
// Allocate data buffer for temporarily storing audio from the ring buffer before writing to the I2S bus
|
|
487
|
-
RAMAllocator<uint8_t> allocator;
|
|
488
|
-
this->data_buffer_ = allocator.allocate(data_buffer_size);
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
if (this->data_buffer_ == nullptr) {
|
|
492
|
-
return ESP_ERR_NO_MEM;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
if (this->audio_ring_buffer_.use_count() == 0) {
|
|
496
|
-
// Allocate ring buffer. Uses a shared_ptr to ensure it isn't improperly deallocated.
|
|
497
|
-
this->audio_ring_buffer_ = RingBuffer::create(ring_buffer_size);
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
if (this->audio_ring_buffer_ == nullptr) {
|
|
501
|
-
return ESP_ERR_NO_MEM;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
return ESP_OK;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
496
|
esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info) {
|
|
497
|
+
this->current_stream_info_ = audio_stream_info; // store the stream info settings the driver will use
|
|
498
|
+
|
|
508
499
|
#ifdef USE_I2S_LEGACY
|
|
509
500
|
if ((this->i2s_mode_ & I2S_MODE_SLAVE) && (this->sample_rate_ != audio_stream_info.get_sample_rate())) { // NOLINT
|
|
510
501
|
#else
|
|
511
502
|
if ((this->i2s_role_ & I2S_ROLE_SLAVE) && (this->sample_rate_ != audio_stream_info.get_sample_rate())) { // NOLINT
|
|
512
503
|
#endif
|
|
513
504
|
// Can't reconfigure I2S bus, so the sample rate must match the configured value
|
|
505
|
+
ESP_LOGE(TAG, "Audio stream settings are not compatible with this I2S configuration");
|
|
514
506
|
return ESP_ERR_NOT_SUPPORTED;
|
|
515
507
|
}
|
|
516
508
|
|
|
@@ -521,10 +513,12 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
|
521
513
|
(i2s_slot_bit_width_t) audio_stream_info.get_bits_per_sample() > this->slot_bit_width_) {
|
|
522
514
|
#endif
|
|
523
515
|
// Currently can't handle the case when the incoming audio has more bits per sample than the configured value
|
|
516
|
+
ESP_LOGE(TAG, "Audio streams with more bits per sample than the I2S speaker's configuration is not supported");
|
|
524
517
|
return ESP_ERR_NOT_SUPPORTED;
|
|
525
518
|
}
|
|
526
519
|
|
|
527
520
|
if (!this->parent_->try_lock()) {
|
|
521
|
+
ESP_LOGE(TAG, "Parent I2S bus not free");
|
|
528
522
|
return ESP_ERR_INVALID_STATE;
|
|
529
523
|
}
|
|
530
524
|
|
|
@@ -575,6 +569,7 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
|
575
569
|
esp_err_t err =
|
|
576
570
|
i2s_driver_install(this->parent_->get_port(), &config, I2S_EVENT_QUEUE_COUNT, &this->i2s_event_queue_);
|
|
577
571
|
if (err != ESP_OK) {
|
|
572
|
+
ESP_LOGE(TAG, "Failed to install I2S legacy driver");
|
|
578
573
|
// Failed to install the driver, so unlock the I2S port
|
|
579
574
|
this->parent_->unlock();
|
|
580
575
|
return err;
|
|
@@ -595,6 +590,7 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
|
595
590
|
|
|
596
591
|
if (err != ESP_OK) {
|
|
597
592
|
// Failed to set the data out pin, so uninstall the driver and unlock the I2S port
|
|
593
|
+
ESP_LOGE(TAG, "Failed to set the data out pin");
|
|
598
594
|
i2s_driver_uninstall(this->parent_->get_port());
|
|
599
595
|
this->parent_->unlock();
|
|
600
596
|
}
|
|
@@ -605,10 +601,12 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
|
605
601
|
.dma_desc_num = DMA_BUFFERS_COUNT,
|
|
606
602
|
.dma_frame_num = dma_buffer_length,
|
|
607
603
|
.auto_clear = true,
|
|
604
|
+
.intr_priority = 3,
|
|
608
605
|
};
|
|
609
606
|
/* Allocate a new TX channel and get the handle of this channel */
|
|
610
607
|
esp_err_t err = i2s_new_channel(&chan_cfg, &this->tx_handle_, NULL);
|
|
611
608
|
if (err != ESP_OK) {
|
|
609
|
+
ESP_LOGE(TAG, "Failed to allocate new I2S channel");
|
|
612
610
|
this->parent_->unlock();
|
|
613
611
|
return err;
|
|
614
612
|
}
|
|
@@ -652,7 +650,11 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
|
652
650
|
// per sample causes the audio to play too fast. Setting the ws_width to the configured slot bit width seems to
|
|
653
651
|
// make it play at the correct speed while sending more bits per slot.
|
|
654
652
|
if (this->slot_bit_width_ != I2S_SLOT_BIT_WIDTH_AUTO) {
|
|
655
|
-
|
|
653
|
+
uint32_t configured_bit_width = static_cast<uint32_t>(this->slot_bit_width_);
|
|
654
|
+
std_slot_cfg.ws_width = configured_bit_width;
|
|
655
|
+
if (configured_bit_width > 16) {
|
|
656
|
+
std_slot_cfg.msb_right = false;
|
|
657
|
+
}
|
|
656
658
|
}
|
|
657
659
|
#else
|
|
658
660
|
std_slot_cfg.slot_bit_width = this->slot_bit_width_;
|
|
@@ -670,53 +672,55 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
|
670
672
|
err = i2s_channel_init_std_mode(this->tx_handle_, &std_cfg);
|
|
671
673
|
|
|
672
674
|
if (err != ESP_OK) {
|
|
675
|
+
ESP_LOGE(TAG, "Failed to initialize channel");
|
|
673
676
|
i2s_del_channel(this->tx_handle_);
|
|
677
|
+
this->tx_handle_ = nullptr;
|
|
674
678
|
this->parent_->unlock();
|
|
675
679
|
return err;
|
|
676
680
|
}
|
|
677
681
|
if (this->i2s_event_queue_ == nullptr) {
|
|
678
|
-
this->i2s_event_queue_ = xQueueCreate(
|
|
682
|
+
this->i2s_event_queue_ = xQueueCreate(I2S_EVENT_QUEUE_COUNT, sizeof(int64_t));
|
|
679
683
|
}
|
|
680
|
-
const i2s_event_callbacks_t callbacks = {
|
|
681
|
-
.on_send_q_ovf = i2s_overflow_cb,
|
|
682
|
-
};
|
|
683
|
-
|
|
684
|
-
i2s_channel_register_event_callback(this->tx_handle_, &callbacks, this);
|
|
685
684
|
|
|
686
|
-
/* Before reading data, start the TX channel first */
|
|
687
685
|
i2s_channel_enable(this->tx_handle_);
|
|
688
|
-
if (err != ESP_OK) {
|
|
689
|
-
i2s_del_channel(this->tx_handle_);
|
|
690
|
-
this->parent_->unlock();
|
|
691
|
-
}
|
|
692
686
|
#endif
|
|
693
687
|
|
|
694
688
|
return err;
|
|
695
689
|
}
|
|
696
690
|
|
|
697
|
-
|
|
698
|
-
|
|
691
|
+
#ifndef USE_I2S_LEGACY
|
|
692
|
+
bool IRAM_ATTR I2SAudioSpeaker::i2s_on_sent_cb(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx) {
|
|
693
|
+
int64_t now = esp_timer_get_time();
|
|
694
|
+
|
|
695
|
+
BaseType_t need_yield1 = pdFALSE;
|
|
696
|
+
BaseType_t need_yield2 = pdFALSE;
|
|
697
|
+
BaseType_t need_yield3 = pdFALSE;
|
|
698
|
+
|
|
699
|
+
I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) user_ctx;
|
|
699
700
|
|
|
700
|
-
if (
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
701
|
+
if (xQueueIsQueueFullFromISR(this_speaker->i2s_event_queue_)) {
|
|
702
|
+
// Queue is full, so discard the oldest event and set the warning flag to inform the user
|
|
703
|
+
int64_t dummy;
|
|
704
|
+
xQueueReceiveFromISR(this_speaker->i2s_event_queue_, &dummy, &need_yield1);
|
|
705
|
+
xEventGroupSetBitsFromISR(this_speaker->event_group_, SpeakerEventGroupBits::WARN_DROPPED_EVENT, &need_yield2);
|
|
704
706
|
}
|
|
705
707
|
|
|
706
|
-
|
|
708
|
+
xQueueSendToBackFromISR(this_speaker->i2s_event_queue_, &now, &need_yield3);
|
|
707
709
|
|
|
708
|
-
|
|
709
|
-
vTaskDelete(nullptr);
|
|
710
|
+
return need_yield1 | need_yield2 | need_yield3;
|
|
710
711
|
}
|
|
712
|
+
#endif
|
|
711
713
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
714
|
+
void I2SAudioSpeaker::stop_i2s_driver_() {
|
|
715
|
+
#ifdef USE_I2S_LEGACY
|
|
716
|
+
i2s_driver_uninstall(this->parent_->get_port());
|
|
717
|
+
#else
|
|
718
|
+
i2s_channel_disable(this->tx_handle_);
|
|
719
|
+
i2s_del_channel(this->tx_handle_);
|
|
720
|
+
this->tx_handle_ = nullptr;
|
|
719
721
|
#endif
|
|
722
|
+
this->parent_->unlock();
|
|
723
|
+
}
|
|
720
724
|
|
|
721
725
|
} // namespace i2s_audio
|
|
722
726
|
} // namespace esphome
|