esphome 2024.12.3__py3-none-any.whl → 2025.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/__main__.py +16 -3
- esphome/components/adc/__init__.py +17 -11
- esphome/components/adc/adc_sensor.h +17 -0
- esphome/components/adc/adc_sensor_common.cpp +55 -0
- esphome/components/adc/adc_sensor_esp32.cpp +8 -5
- esphome/components/adc/adc_sensor_esp8266.cpp +10 -6
- esphome/components/adc/adc_sensor_libretiny.cpp +11 -6
- esphome/components/adc/adc_sensor_rp2040.cpp +13 -10
- esphome/components/adc/sensor.py +9 -3
- esphome/components/ads1115/ads1115.cpp +56 -7
- esphome/components/ads1115/ads1115.h +13 -1
- esphome/components/ads1115/sensor/__init__.py +16 -0
- esphome/components/ads1115/sensor/ads1115_sensor.cpp +2 -1
- esphome/components/ads1115/sensor/ads1115_sensor.h +2 -0
- esphome/components/animation/__init__.py +23 -261
- esphome/components/animation/animation.cpp +2 -2
- esphome/components/animation/animation.h +2 -1
- esphome/components/api/api_pb2.cpp +14 -0
- esphome/components/api/api_pb2.h +1 -0
- esphome/components/api/client.py +8 -3
- esphome/components/audio/__init__.py +112 -0
- esphome/components/audio/audio.cpp +67 -0
- esphome/components/audio/audio.h +125 -7
- esphome/components/audio/audio_decoder.cpp +361 -0
- esphome/components/audio/audio_decoder.h +135 -0
- esphome/components/audio/audio_reader.cpp +308 -0
- esphome/components/audio/audio_reader.h +85 -0
- esphome/components/audio/audio_resampler.cpp +159 -0
- esphome/components/audio/audio_resampler.h +101 -0
- esphome/components/audio/audio_transfer_buffer.cpp +165 -0
- esphome/components/audio/audio_transfer_buffer.h +139 -0
- esphome/components/audio_adc/__init__.py +41 -0
- esphome/components/audio_adc/audio_adc.h +17 -0
- esphome/components/audio_adc/automation.h +23 -0
- esphome/components/bk72xx/__init__.py +1 -0
- esphome/components/ble_client/ble_client.cpp +1 -2
- esphome/components/ble_client/sensor/__init__.py +1 -1
- esphome/components/ble_client/text_sensor/__init__.py +1 -1
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +5 -0
- esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -0
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +5 -0
- esphome/components/ch422g/ch422g.h +2 -0
- esphome/components/climate/__init__.py +1 -1
- esphome/components/climate_ir/climate_ir.cpp +2 -1
- esphome/components/coolix/coolix.cpp +2 -1
- esphome/components/cse7766/cse7766.cpp +8 -16
- esphome/components/custom/__init__.py +0 -3
- esphome/components/custom/binary_sensor/__init__.py +2 -28
- esphome/components/custom/climate/__init__.py +2 -27
- esphome/components/custom/cover/__init__.py +2 -27
- esphome/components/custom/light/__init__.py +2 -27
- esphome/components/custom/output/__init__.py +2 -58
- esphome/components/custom/sensor/__init__.py +2 -24
- esphome/components/custom/switch/__init__.py +2 -24
- esphome/components/custom/text_sensor/__init__.py +2 -29
- esphome/components/custom_component/__init__.py +3 -27
- esphome/components/daly_bms/daly_bms.cpp +6 -0
- esphome/components/daly_bms/daly_bms.h +2 -0
- esphome/components/daly_bms/sensor.py +6 -0
- esphome/components/debug/debug_component.cpp +4 -0
- esphome/components/debug/debug_component.h +14 -0
- esphome/components/debug/debug_esp32.cpp +154 -74
- esphome/components/dfplayer/dfplayer.cpp +15 -2
- esphome/components/dfrobot_sen0395/dfrobot_sen0395.cpp +2 -1
- esphome/components/dht/dht.cpp +4 -2
- esphome/components/dht/sensor.py +1 -1
- esphome/components/display/__init__.py +18 -5
- esphome/components/display/display.cpp +16 -3
- esphome/components/display/rect.cpp +2 -1
- esphome/components/es7210/__init__.py +0 -0
- esphome/components/es7210/audio_adc.py +51 -0
- esphome/components/es7210/es7210.cpp +228 -0
- esphome/components/es7210/es7210.h +62 -0
- esphome/components/es7210/es7210_const.h +129 -0
- esphome/components/es7243e/__init__.py +0 -0
- esphome/components/es7243e/audio_adc.py +34 -0
- esphome/components/es7243e/es7243e.cpp +125 -0
- esphome/components/es7243e/es7243e.h +37 -0
- esphome/components/es7243e/es7243e_const.h +54 -0
- esphome/components/es8156/__init__.py +0 -0
- esphome/components/es8156/audio_dac.py +27 -0
- esphome/components/es8156/es8156.cpp +87 -0
- esphome/components/es8156/es8156.h +51 -0
- esphome/components/es8156/es8156_const.h +68 -0
- esphome/components/es8311/audio_dac.py +1 -2
- esphome/components/esp32/__init__.py +1 -0
- esphome/components/esp32/core.cpp +5 -1
- esphome/components/esp32/gpio.h +2 -0
- esphome/components/esp32_ble/__init__.py +39 -0
- esphome/components/esp32_ble/queue.h +4 -4
- esphome/components/esp32_ble_client/ble_client_base.cpp +46 -0
- esphome/components/esp32_ble_client/ble_client_base.h +2 -0
- esphome/components/esp32_ble_server/__init__.py +582 -12
- esphome/components/esp32_ble_server/ble_characteristic.cpp +48 -60
- esphome/components/esp32_ble_server/ble_characteristic.h +24 -17
- esphome/components/esp32_ble_server/ble_descriptor.cpp +21 -9
- esphome/components/esp32_ble_server/ble_descriptor.h +17 -6
- esphome/components/esp32_ble_server/ble_server.cpp +62 -67
- esphome/components/esp32_ble_server/ble_server.h +28 -32
- esphome/components/esp32_ble_server/ble_server_automations.cpp +77 -0
- esphome/components/esp32_ble_server/ble_server_automations.h +115 -0
- esphome/components/esp32_ble_server/ble_service.cpp +17 -15
- esphome/components/esp32_ble_server/ble_service.h +10 -14
- esphome/components/esp32_ble_tracker/__init__.py +6 -39
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +33 -10
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +8 -4
- esphome/components/esp32_dac/esp32_dac.cpp +16 -7
- esphome/components/esp32_dac/esp32_dac.h +8 -0
- esphome/components/esp32_dac/output.py +16 -4
- esphome/components/esp32_improv/__init__.py +2 -8
- esphome/components/esp32_improv/esp32_improv_component.cpp +21 -20
- esphome/components/esp32_improv/esp32_improv_component.h +3 -4
- esphome/components/esp32_rmt/__init__.py +28 -3
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +73 -6
- esphome/components/esp32_rmt_led_strip/led_strip.h +21 -3
- esphome/components/esp32_rmt_led_strip/light.py +72 -7
- esphome/components/esp32_touch/esp32_touch.cpp +5 -0
- esphome/components/esp8266/__init__.py +1 -0
- esphome/components/esp8266/gpio.h +1 -0
- esphome/components/ethernet/__init__.py +10 -10
- esphome/components/event/event.cpp +4 -2
- esphome/components/event/event.h +2 -0
- esphome/components/event_emitter/__init__.py +5 -0
- esphome/components/event_emitter/event_emitter.cpp +14 -0
- esphome/components/event_emitter/event_emitter.h +63 -0
- esphome/components/font/__init__.py +1 -1
- esphome/components/gcja5/gcja5.cpp +2 -1
- esphome/components/graph/graph.cpp +4 -9
- esphome/components/haier/haier_base.cpp +2 -1
- esphome/components/haier/hon_climate.cpp +2 -1
- esphome/components/heatpumpir/heatpumpir.cpp +2 -1
- esphome/components/host/__init__.py +1 -0
- esphome/components/host/gpio.h +1 -0
- esphome/components/http_request/http_request.h +2 -2
- esphome/components/http_request/http_request_arduino.cpp +1 -1
- esphome/components/http_request/http_request_idf.cpp +1 -1
- esphome/components/i2c/i2c_bus_esp_idf.cpp +4 -0
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +7 -5
- esphome/components/i2s_audio/speaker/__init__.py +53 -6
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +92 -46
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -0
- esphome/components/ili9xxx/display.py +29 -11
- esphome/components/ili9xxx/ili9xxx_display.cpp +2 -5
- esphome/components/ili9xxx/ili9xxx_display.h +2 -1
- esphome/components/image/__init__.py +443 -255
- esphome/components/image/image.cpp +115 -61
- esphome/components/image/image.h +15 -24
- esphome/components/json/json_util.cpp +8 -34
- esphome/components/libretiny/__init__.py +1 -0
- esphome/components/libretiny/gpio_arduino.h +1 -0
- esphome/components/light/light_color_values.h +1 -1
- esphome/components/logger/__init__.py +45 -9
- esphome/components/logger/logger.cpp +16 -14
- esphome/components/logger/logger.h +11 -7
- esphome/components/logger/select/__init__.py +29 -0
- esphome/components/logger/select/logger_level_select.cpp +27 -0
- esphome/components/logger/select/logger_level_select.h +15 -0
- esphome/components/lvgl/__init__.py +96 -73
- esphome/components/lvgl/automation.py +39 -7
- esphome/components/lvgl/defines.py +8 -2
- esphome/components/lvgl/lvgl_esphome.cpp +8 -15
- esphome/components/lvgl/lvgl_esphome.h +20 -5
- esphome/components/lvgl/schemas.py +25 -14
- esphome/components/lvgl/trigger.py +27 -3
- esphome/components/lvgl/widgets/dropdown.py +1 -1
- esphome/components/lvgl/widgets/keyboard.py +8 -1
- esphome/components/lvgl/widgets/meter.py +2 -1
- esphome/components/lvgl/widgets/msgbox.py +1 -1
- esphome/components/lvgl/widgets/obj.py +1 -12
- esphome/components/lvgl/widgets/page.py +37 -2
- esphome/components/lvgl/widgets/tabview.py +1 -1
- esphome/components/max6956/max6956.h +2 -0
- esphome/components/mcp23016/mcp23016.h +2 -0
- esphome/components/mcp23xxx_base/mcp23xxx_base.h +2 -0
- esphome/components/mdns/__init__.py +1 -1
- esphome/components/media_player/__init__.py +37 -8
- esphome/components/media_player/automation.h +11 -2
- esphome/components/media_player/media_player.cpp +8 -0
- esphome/components/media_player/media_player.h +8 -4
- esphome/components/micronova/switch/micronova_switch.cpp +4 -2
- esphome/components/midea/ac_automations.h +3 -1
- esphome/components/midea/air_conditioner.cpp +7 -5
- esphome/components/midea/air_conditioner.h +1 -1
- esphome/components/midea/climate.py +4 -2
- esphome/components/midea/ir_transmitter.h +36 -5
- esphome/components/mixer/__init__.py +0 -0
- esphome/components/mixer/speaker/__init__.py +172 -0
- esphome/components/mixer/speaker/automation.h +19 -0
- esphome/components/mixer/speaker/mixer_speaker.cpp +624 -0
- esphome/components/mixer/speaker/mixer_speaker.h +207 -0
- esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp +7 -13
- esphome/components/mpr121/mpr121.h +2 -0
- esphome/components/mqtt/__init__.py +1 -1
- esphome/components/mqtt/mqtt_client.cpp +7 -1
- esphome/components/mqtt/mqtt_client.h +1 -1
- esphome/components/mqtt/mqtt_climate.cpp +2 -2
- esphome/components/network/ip_address.h +2 -0
- esphome/components/nextion/automation.h +17 -0
- esphome/components/nextion/display.py +42 -17
- esphome/components/nextion/nextion.cpp +4 -10
- esphome/components/nextion/nextion.h +89 -82
- esphome/components/nextion/nextion_commands.cpp +10 -10
- esphome/components/ntc/sensor.py +2 -4
- esphome/components/online_image/__init__.py +98 -46
- esphome/components/online_image/bmp_image.cpp +101 -0
- esphome/components/online_image/bmp_image.h +40 -0
- esphome/components/online_image/image_decoder.cpp +31 -2
- esphome/components/online_image/image_decoder.h +24 -15
- esphome/components/online_image/jpeg_image.cpp +92 -0
- esphome/components/online_image/jpeg_image.h +34 -0
- esphome/components/online_image/online_image.cpp +118 -58
- esphome/components/online_image/online_image.h +39 -9
- esphome/components/online_image/png_image.cpp +7 -3
- esphome/components/online_image/png_image.h +2 -1
- esphome/components/opentherm/__init__.py +73 -7
- esphome/components/opentherm/automation.h +25 -0
- esphome/components/opentherm/const.py +1 -0
- esphome/components/opentherm/generate.py +39 -6
- esphome/components/opentherm/hub.cpp +117 -79
- esphome/components/opentherm/hub.h +31 -15
- esphome/components/opentherm/opentherm.cpp +47 -23
- esphome/components/opentherm/opentherm.h +27 -6
- esphome/components/opentherm/opentherm_macros.h +11 -0
- esphome/components/opentherm/schema.py +78 -1
- esphome/components/opentherm/validate.py +7 -2
- esphome/components/pca6416a/pca6416a.h +2 -0
- esphome/components/pca9554/pca9554.h +2 -0
- esphome/components/pcf8574/pcf8574.h +2 -0
- esphome/components/preferences/__init__.py +2 -4
- esphome/components/preferences/syncer.h +10 -3
- esphome/components/prometheus/prometheus_handler.cpp +313 -0
- esphome/components/prometheus/prometheus_handler.h +48 -7
- esphome/components/psram/psram.cpp +8 -1
- esphome/components/pulse_counter/pulse_counter_sensor.cpp +14 -9
- esphome/components/pulse_counter/pulse_counter_sensor.h +4 -4
- esphome/components/pulse_meter/pulse_meter_sensor.cpp +2 -0
- esphome/components/qspi_dbi/__init__.py +3 -0
- esphome/components/qspi_dbi/display.py +74 -47
- esphome/components/qspi_dbi/models.py +245 -2
- esphome/components/qspi_dbi/qspi_dbi.cpp +9 -16
- esphome/components/qspi_dbi/qspi_dbi.h +2 -2
- esphome/components/remote_base/__init__.py +77 -25
- esphome/components/remote_base/remote_base.cpp +1 -1
- esphome/components/remote_base/remote_base.h +20 -2
- esphome/components/remote_base/toto_protocol.cpp +100 -0
- esphome/components/remote_base/toto_protocol.h +45 -0
- esphome/components/remote_receiver/__init__.py +55 -10
- esphome/components/remote_receiver/remote_receiver.h +36 -3
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +145 -6
- esphome/components/remote_transmitter/__init__.py +62 -4
- esphome/components/remote_transmitter/remote_transmitter.h +21 -2
- esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +140 -4
- esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +3 -3
- esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +3 -3
- esphome/components/resampler/__init__.py +0 -0
- esphome/components/resampler/speaker/__init__.py +103 -0
- esphome/components/resampler/speaker/resampler_speaker.cpp +318 -0
- esphome/components/resampler/speaker/resampler_speaker.h +107 -0
- esphome/components/resistance/resistance_sensor.h +2 -3
- esphome/components/resistance/sensor.py +2 -9
- esphome/components/rotary_encoder/rotary_encoder.cpp +8 -4
- esphome/components/rp2040/__init__.py +1 -0
- esphome/components/rp2040/gpio.h +1 -0
- esphome/components/rtl87xx/__init__.py +2 -0
- esphome/components/scd30/sensor.py +1 -1
- esphome/components/sdl/binary_sensor.py +270 -0
- esphome/components/sdl/sdl_esphome.cpp +16 -0
- esphome/components/sdl/sdl_esphome.h +9 -0
- esphome/components/seeed_mr60bha2/binary_sensor.py +25 -0
- esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +26 -2
- esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +9 -20
- esphome/components/seeed_mr60bha2/sensor.py +9 -1
- esphome/components/sn74hc165/sn74hc165.h +3 -0
- esphome/components/sn74hc595/sn74hc595.h +3 -0
- esphome/components/speaker/__init__.py +5 -4
- esphome/components/speaker/media_player/__init__.py +458 -0
- esphome/components/speaker/media_player/audio_pipeline.cpp +568 -0
- esphome/components/speaker/media_player/audio_pipeline.h +159 -0
- esphome/components/speaker/media_player/automation.h +26 -0
- esphome/components/speaker/media_player/speaker_media_player.cpp +577 -0
- esphome/components/speaker/media_player/speaker_media_player.h +160 -0
- esphome/components/speaker/speaker.h +20 -0
- esphome/components/spi/__init__.py +1 -5
- esphome/components/spi/spi.cpp +7 -1
- esphome/components/spi/spi.h +21 -2
- esphome/components/spi_led_strip/light.py +3 -5
- esphome/components/spi_led_strip/spi_led_strip.cpp +67 -0
- esphome/components/spi_led_strip/spi_led_strip.h +8 -60
- esphome/components/sprinkler/sprinkler.cpp +3 -1
- esphome/components/sx1509/sx1509_gpio_pin.h +2 -0
- esphome/components/tca9555/tca9555.h +2 -0
- esphome/components/toshiba/toshiba.cpp +2 -1
- esphome/components/tuya/light/tuya_light.cpp +4 -2
- esphome/components/uart/uart_component_esp32_arduino.cpp +2 -2
- esphome/components/uart/uart_component_esp_idf.cpp +2 -2
- esphome/components/udp/__init__.py +8 -2
- esphome/components/udp/udp_component.cpp +25 -56
- esphome/components/udp/udp_component.h +3 -0
- esphome/components/uponor_smatrix/sensor/__init__.py +14 -4
- esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +5 -0
- esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.h +1 -0
- esphome/components/uptime/text_sensor/__init__.py +19 -0
- esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +63 -0
- esphome/components/uptime/text_sensor/uptime_text_sensor.h +25 -0
- esphome/components/voice_assistant/voice_assistant.cpp +24 -14
- esphome/components/voice_assistant/voice_assistant.h +8 -0
- esphome/components/waveshare_epaper/display.py +22 -1
- esphome/components/waveshare_epaper/waveshare_213v3.cpp +9 -3
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +1155 -44
- esphome/components/waveshare_epaper/waveshare_epaper.h +208 -7
- esphome/components/web_server/web_server.cpp +28 -6
- esphome/components/weikai/weikai.h +2 -0
- esphome/components/wifi/__init__.py +6 -6
- esphome/components/wifi/wifi_component.cpp +1 -1
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -1
- esphome/components/wireguard/__init__.py +2 -2
- esphome/components/xl9535/xl9535.h +2 -0
- esphome/components/xxtea/__init__.py +3 -0
- esphome/components/xxtea/xxtea.cpp +46 -0
- esphome/components/xxtea/xxtea.h +26 -0
- esphome/components/yashima/yashima.cpp +2 -1
- esphome/config.py +9 -5
- esphome/config_validation.py +55 -17
- esphome/const.py +7 -10
- esphome/core/__init__.py +6 -13
- esphome/core/base_automation.h +1 -0
- esphome/core/config.py +59 -72
- esphome/core/defines.h +9 -1
- esphome/core/gpio.h +7 -0
- esphome/core/helpers.cpp +19 -15
- esphome/core/helpers.h +57 -8
- esphome/core/log.h +9 -7
- esphome/cpp_generator.py +2 -2
- esphome/dashboard/web_server.py +1 -1
- esphome/espota2.py +3 -2
- esphome/loader.py +12 -4
- esphome/log.py +5 -7
- esphome/yaml_util.py +2 -2
- {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/METADATA +14 -9
- {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/RECORD +349 -300
- esphome/components/custom/binary_sensor/custom_binary_sensor.cpp +0 -16
- esphome/components/custom/binary_sensor/custom_binary_sensor.h +0 -26
- esphome/components/custom/climate/custom_climate.h +0 -22
- esphome/components/custom/cover/custom_cover.h +0 -21
- esphome/components/custom/light/custom_light_output.h +0 -24
- esphome/components/custom/output/custom_output.h +0 -37
- esphome/components/custom/sensor/custom_sensor.cpp +0 -16
- esphome/components/custom/sensor/custom_sensor.h +0 -24
- esphome/components/custom/switch/custom_switch.cpp +0 -16
- esphome/components/custom/switch/custom_switch.h +0 -24
- esphome/components/custom/text_sensor/custom_text_sensor.cpp +0 -16
- esphome/components/custom/text_sensor/custom_text_sensor.h +0 -26
- esphome/components/custom_component/custom_component.h +0 -28
- esphome/components/esp32_ble_server/ble_2901.cpp +0 -18
- esphome/components/esp32_ble_server/ble_2901.h +0 -19
- esphome/components/resistance_sampler/__init__.py +0 -6
- esphome/components/resistance_sampler/resistance_sampler.h +0 -10
- esphome/components/uptime/{sensor.py → sensor/__init__.py} +3 -3
- /esphome/components/uptime/{uptime_seconds_sensor.cpp → sensor/uptime_seconds_sensor.cpp} +0 -0
- /esphome/components/uptime/{uptime_seconds_sensor.h → sensor/uptime_seconds_sensor.h} +0 -0
- /esphome/components/uptime/{uptime_timestamp_sensor.cpp → sensor/uptime_timestamp_sensor.cpp} +0 -0
- /esphome/components/uptime/{uptime_timestamp_sensor.h → sensor/uptime_timestamp_sensor.h} +0 -0
- {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/LICENSE +0 -0
- {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/WHEEL +0 -0
- {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/entry_points.txt +0 -0
- {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/top_level.txt +0 -0
@@ -3,19 +3,29 @@
|
|
3
3
|
#include "esphome/core/application.h"
|
4
4
|
|
5
5
|
#ifdef USE_ESP32
|
6
|
+
#include <driver/gpio.h>
|
6
7
|
|
7
8
|
namespace esphome {
|
8
9
|
namespace remote_transmitter {
|
9
10
|
|
10
11
|
static const char *const TAG = "remote_transmitter";
|
11
12
|
|
12
|
-
void RemoteTransmitterComponent::setup() {
|
13
|
+
void RemoteTransmitterComponent::setup() {
|
14
|
+
ESP_LOGCONFIG(TAG, "Setting up Remote Transmitter...");
|
15
|
+
this->inverted_ = this->pin_->is_inverted();
|
16
|
+
this->configure_rmt_();
|
17
|
+
}
|
13
18
|
|
14
19
|
void RemoteTransmitterComponent::dump_config() {
|
15
|
-
ESP_LOGCONFIG(TAG, "Remote Transmitter
|
20
|
+
ESP_LOGCONFIG(TAG, "Remote Transmitter:");
|
21
|
+
#if ESP_IDF_VERSION_MAJOR >= 5
|
22
|
+
ESP_LOGCONFIG(TAG, " Clock resolution: %" PRIu32 " hz", this->clock_resolution_);
|
23
|
+
ESP_LOGCONFIG(TAG, " RMT symbols: %" PRIu32, this->rmt_symbols_);
|
24
|
+
#else
|
16
25
|
ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_);
|
17
26
|
ESP_LOGCONFIG(TAG, " RMT memory blocks: %d", this->mem_block_num_);
|
18
27
|
ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_);
|
28
|
+
#endif
|
19
29
|
LOG_PIN(" Pin: ", this->pin_);
|
20
30
|
|
21
31
|
if (this->current_carrier_frequency_ != 0 && this->carrier_duty_percent_ != 100) {
|
@@ -28,7 +38,105 @@ void RemoteTransmitterComponent::dump_config() {
|
|
28
38
|
}
|
29
39
|
}
|
30
40
|
|
41
|
+
#if ESP_IDF_VERSION_MAJOR >= 5
|
42
|
+
void RemoteTransmitterComponent::digital_write(bool value) {
|
43
|
+
rmt_symbol_word_t symbol = {
|
44
|
+
.duration0 = 1,
|
45
|
+
.level0 = value,
|
46
|
+
.duration1 = 0,
|
47
|
+
.level1 = value,
|
48
|
+
};
|
49
|
+
rmt_transmit_config_t config;
|
50
|
+
memset(&config, 0, sizeof(config));
|
51
|
+
config.loop_count = 0;
|
52
|
+
config.flags.eot_level = value;
|
53
|
+
esp_err_t error = rmt_transmit(this->channel_, this->encoder_, &symbol, sizeof(symbol), &config);
|
54
|
+
if (error != ESP_OK) {
|
55
|
+
ESP_LOGW(TAG, "rmt_transmit failed: %s", esp_err_to_name(error));
|
56
|
+
this->status_set_warning();
|
57
|
+
}
|
58
|
+
error = rmt_tx_wait_all_done(this->channel_, -1);
|
59
|
+
if (error != ESP_OK) {
|
60
|
+
ESP_LOGW(TAG, "rmt_tx_wait_all_done failed: %s", esp_err_to_name(error));
|
61
|
+
this->status_set_warning();
|
62
|
+
}
|
63
|
+
}
|
64
|
+
#endif
|
65
|
+
|
31
66
|
void RemoteTransmitterComponent::configure_rmt_() {
|
67
|
+
#if ESP_IDF_VERSION_MAJOR >= 5
|
68
|
+
esp_err_t error;
|
69
|
+
|
70
|
+
if (!this->initialized_) {
|
71
|
+
bool open_drain = (this->pin_->get_flags() & gpio::FLAG_OPEN_DRAIN) != 0;
|
72
|
+
rmt_tx_channel_config_t channel;
|
73
|
+
memset(&channel, 0, sizeof(channel));
|
74
|
+
channel.clk_src = RMT_CLK_SRC_DEFAULT;
|
75
|
+
channel.resolution_hz = this->clock_resolution_;
|
76
|
+
channel.gpio_num = gpio_num_t(this->pin_->get_pin());
|
77
|
+
channel.mem_block_symbols = this->rmt_symbols_;
|
78
|
+
channel.trans_queue_depth = 1;
|
79
|
+
channel.flags.io_loop_back = open_drain;
|
80
|
+
channel.flags.io_od_mode = open_drain;
|
81
|
+
channel.flags.invert_out = 0;
|
82
|
+
channel.flags.with_dma = this->with_dma_;
|
83
|
+
channel.intr_priority = 0;
|
84
|
+
error = rmt_new_tx_channel(&channel, &this->channel_);
|
85
|
+
if (error != ESP_OK) {
|
86
|
+
this->error_code_ = error;
|
87
|
+
if (error == ESP_ERR_NOT_FOUND) {
|
88
|
+
this->error_string_ = "out of RMT symbol memory";
|
89
|
+
} else {
|
90
|
+
this->error_string_ = "in rmt_new_tx_channel";
|
91
|
+
}
|
92
|
+
this->mark_failed();
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
if (this->pin_->get_flags() & gpio::FLAG_PULLUP) {
|
96
|
+
gpio_pullup_en(gpio_num_t(this->pin_->get_pin()));
|
97
|
+
} else {
|
98
|
+
gpio_pullup_dis(gpio_num_t(this->pin_->get_pin()));
|
99
|
+
}
|
100
|
+
|
101
|
+
rmt_copy_encoder_config_t encoder;
|
102
|
+
memset(&encoder, 0, sizeof(encoder));
|
103
|
+
error = rmt_new_copy_encoder(&encoder, &this->encoder_);
|
104
|
+
if (error != ESP_OK) {
|
105
|
+
this->error_code_ = error;
|
106
|
+
this->error_string_ = "in rmt_new_copy_encoder";
|
107
|
+
this->mark_failed();
|
108
|
+
return;
|
109
|
+
}
|
110
|
+
|
111
|
+
error = rmt_enable(this->channel_);
|
112
|
+
if (error != ESP_OK) {
|
113
|
+
this->error_code_ = error;
|
114
|
+
this->error_string_ = "in rmt_enable";
|
115
|
+
this->mark_failed();
|
116
|
+
return;
|
117
|
+
}
|
118
|
+
this->digital_write(open_drain || this->inverted_);
|
119
|
+
this->initialized_ = true;
|
120
|
+
}
|
121
|
+
|
122
|
+
if (this->current_carrier_frequency_ == 0 || this->carrier_duty_percent_ == 100) {
|
123
|
+
error = rmt_apply_carrier(this->channel_, nullptr);
|
124
|
+
} else {
|
125
|
+
rmt_carrier_config_t carrier;
|
126
|
+
memset(&carrier, 0, sizeof(carrier));
|
127
|
+
carrier.frequency_hz = this->current_carrier_frequency_;
|
128
|
+
carrier.duty_cycle = (float) this->carrier_duty_percent_ / 100.0f;
|
129
|
+
carrier.flags.polarity_active_low = this->inverted_;
|
130
|
+
carrier.flags.always_on = 1;
|
131
|
+
error = rmt_apply_carrier(this->channel_, &carrier);
|
132
|
+
}
|
133
|
+
if (error != ESP_OK) {
|
134
|
+
this->error_code_ = error;
|
135
|
+
this->error_string_ = "in rmt_apply_carrier";
|
136
|
+
this->mark_failed();
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
#else
|
32
140
|
rmt_config_t c{};
|
33
141
|
|
34
142
|
this->config_rmt(c);
|
@@ -45,13 +153,12 @@ void RemoteTransmitterComponent::configure_rmt_() {
|
|
45
153
|
}
|
46
154
|
|
47
155
|
c.tx_config.idle_output_en = true;
|
48
|
-
if (!this->
|
156
|
+
if (!this->inverted_) {
|
49
157
|
c.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
|
50
158
|
c.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
|
51
159
|
} else {
|
52
160
|
c.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
|
53
161
|
c.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH;
|
54
|
-
this->inverted_ = true;
|
55
162
|
}
|
56
163
|
|
57
164
|
esp_err_t error = rmt_config(&c);
|
@@ -76,6 +183,7 @@ void RemoteTransmitterComponent::configure_rmt_() {
|
|
76
183
|
}
|
77
184
|
this->initialized_ = true;
|
78
185
|
}
|
186
|
+
#endif
|
79
187
|
}
|
80
188
|
|
81
189
|
void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) {
|
@@ -90,7 +198,11 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
|
|
90
198
|
this->rmt_temp_.clear();
|
91
199
|
this->rmt_temp_.reserve((this->temp_.get_data().size() + 1) / 2);
|
92
200
|
uint32_t rmt_i = 0;
|
201
|
+
#if ESP_IDF_VERSION_MAJOR >= 5
|
202
|
+
rmt_symbol_word_t rmt_item;
|
203
|
+
#else
|
93
204
|
rmt_item32_t rmt_item;
|
205
|
+
#endif
|
94
206
|
|
95
207
|
for (int32_t val : this->temp_.get_data()) {
|
96
208
|
bool level = val >= 0;
|
@@ -125,6 +237,29 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
|
|
125
237
|
return;
|
126
238
|
}
|
127
239
|
this->transmit_trigger_->trigger();
|
240
|
+
#if ESP_IDF_VERSION_MAJOR >= 5
|
241
|
+
for (uint32_t i = 0; i < send_times; i++) {
|
242
|
+
rmt_transmit_config_t config;
|
243
|
+
memset(&config, 0, sizeof(config));
|
244
|
+
config.loop_count = 0;
|
245
|
+
config.flags.eot_level = this->eot_level_;
|
246
|
+
esp_err_t error = rmt_transmit(this->channel_, this->encoder_, this->rmt_temp_.data(),
|
247
|
+
this->rmt_temp_.size() * sizeof(rmt_symbol_word_t), &config);
|
248
|
+
if (error != ESP_OK) {
|
249
|
+
ESP_LOGW(TAG, "rmt_transmit failed: %s", esp_err_to_name(error));
|
250
|
+
this->status_set_warning();
|
251
|
+
} else {
|
252
|
+
this->status_clear_warning();
|
253
|
+
}
|
254
|
+
error = rmt_tx_wait_all_done(this->channel_, -1);
|
255
|
+
if (error != ESP_OK) {
|
256
|
+
ESP_LOGW(TAG, "rmt_tx_wait_all_done failed: %s", esp_err_to_name(error));
|
257
|
+
this->status_set_warning();
|
258
|
+
}
|
259
|
+
if (i + 1 < send_times)
|
260
|
+
delayMicroseconds(send_wait);
|
261
|
+
}
|
262
|
+
#else
|
128
263
|
for (uint32_t i = 0; i < send_times; i++) {
|
129
264
|
esp_err_t error = rmt_write_items(this->channel_, this->rmt_temp_.data(), this->rmt_temp_.size(), true);
|
130
265
|
if (error != ESP_OK) {
|
@@ -136,6 +271,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
|
|
136
271
|
if (i + 1 < send_times)
|
137
272
|
delayMicroseconds(send_wait);
|
138
273
|
}
|
274
|
+
#endif
|
139
275
|
this->complete_trigger_->trigger();
|
140
276
|
}
|
141
277
|
|
@@ -37,7 +37,7 @@ void RemoteTransmitterComponent::await_target_time_() {
|
|
37
37
|
const uint32_t current_time = micros();
|
38
38
|
if (this->target_time_ == 0) {
|
39
39
|
this->target_time_ = current_time;
|
40
|
-
} else if (this->target_time_
|
40
|
+
} else if ((int32_t) (this->target_time_ - current_time) > 0) {
|
41
41
|
delayMicroseconds(this->target_time_ - current_time);
|
42
42
|
}
|
43
43
|
}
|
@@ -50,13 +50,13 @@ void RemoteTransmitterComponent::mark_(uint32_t on_time, uint32_t off_time, uint
|
|
50
50
|
if (this->carrier_duty_percent_ < 100 && (on_time > 0 || off_time > 0)) {
|
51
51
|
while (true) { // Modulate with carrier frequency
|
52
52
|
this->target_time_ += on_time;
|
53
|
-
if (this->target_time_
|
53
|
+
if ((int32_t) (this->target_time_ - target) >= 0)
|
54
54
|
break;
|
55
55
|
this->await_target_time_();
|
56
56
|
this->pin_->digital_write(false);
|
57
57
|
|
58
58
|
this->target_time_ += off_time;
|
59
|
-
if (this->target_time_
|
59
|
+
if ((int32_t) (this->target_time_ - target) >= 0)
|
60
60
|
break;
|
61
61
|
this->await_target_time_();
|
62
62
|
this->pin_->digital_write(true);
|
@@ -38,7 +38,7 @@ void RemoteTransmitterComponent::await_target_time_() {
|
|
38
38
|
if (this->target_time_ == 0) {
|
39
39
|
this->target_time_ = current_time;
|
40
40
|
} else {
|
41
|
-
while (this->target_time_
|
41
|
+
while ((int32_t) (this->target_time_ - micros()) > 0) {
|
42
42
|
// busy loop that ensures micros is constantly called
|
43
43
|
}
|
44
44
|
}
|
@@ -52,13 +52,13 @@ void RemoteTransmitterComponent::mark_(uint32_t on_time, uint32_t off_time, uint
|
|
52
52
|
if (this->carrier_duty_percent_ < 100 && (on_time > 0 || off_time > 0)) {
|
53
53
|
while (true) { // Modulate with carrier frequency
|
54
54
|
this->target_time_ += on_time;
|
55
|
-
if (this->target_time_
|
55
|
+
if ((int32_t) (this->target_time_ - target) >= 0)
|
56
56
|
break;
|
57
57
|
this->await_target_time_();
|
58
58
|
this->pin_->digital_write(false);
|
59
59
|
|
60
60
|
this->target_time_ += off_time;
|
61
|
-
if (this->target_time_
|
61
|
+
if ((int32_t) (this->target_time_ - target) >= 0)
|
62
62
|
break;
|
63
63
|
this->await_target_time_();
|
64
64
|
this->pin_->digital_write(true);
|
File without changes
|
@@ -0,0 +1,103 @@
|
|
1
|
+
import esphome.codegen as cg
|
2
|
+
from esphome.components import audio, esp32, speaker
|
3
|
+
import esphome.config_validation as cv
|
4
|
+
from esphome.const import (
|
5
|
+
CONF_BITS_PER_SAMPLE,
|
6
|
+
CONF_BUFFER_DURATION,
|
7
|
+
CONF_FILTERS,
|
8
|
+
CONF_ID,
|
9
|
+
CONF_NUM_CHANNELS,
|
10
|
+
CONF_OUTPUT_SPEAKER,
|
11
|
+
CONF_SAMPLE_RATE,
|
12
|
+
CONF_TASK_STACK_IN_PSRAM,
|
13
|
+
PLATFORM_ESP32,
|
14
|
+
)
|
15
|
+
from esphome.core.entity_helpers import inherit_property_from
|
16
|
+
|
17
|
+
AUTO_LOAD = ["audio"]
|
18
|
+
CODEOWNERS = ["@kahrendt"]
|
19
|
+
|
20
|
+
resampler_ns = cg.esphome_ns.namespace("resampler")
|
21
|
+
ResamplerSpeaker = resampler_ns.class_(
|
22
|
+
"ResamplerSpeaker", cg.Component, speaker.Speaker
|
23
|
+
)
|
24
|
+
|
25
|
+
CONF_TAPS = "taps"
|
26
|
+
|
27
|
+
|
28
|
+
def _set_stream_limits(config):
|
29
|
+
audio.set_stream_limits(
|
30
|
+
min_bits_per_sample=16,
|
31
|
+
max_bits_per_sample=32,
|
32
|
+
)(config)
|
33
|
+
|
34
|
+
return config
|
35
|
+
|
36
|
+
|
37
|
+
def _validate_audio_compatability(config):
|
38
|
+
inherit_property_from(CONF_BITS_PER_SAMPLE, CONF_OUTPUT_SPEAKER)(config)
|
39
|
+
inherit_property_from(CONF_NUM_CHANNELS, CONF_OUTPUT_SPEAKER)(config)
|
40
|
+
inherit_property_from(CONF_SAMPLE_RATE, CONF_OUTPUT_SPEAKER)(config)
|
41
|
+
|
42
|
+
audio.final_validate_audio_schema(
|
43
|
+
"source_speaker",
|
44
|
+
audio_device=CONF_OUTPUT_SPEAKER,
|
45
|
+
bits_per_sample=config.get(CONF_BITS_PER_SAMPLE),
|
46
|
+
channels=config.get(CONF_NUM_CHANNELS),
|
47
|
+
sample_rate=config.get(CONF_SAMPLE_RATE),
|
48
|
+
)(config)
|
49
|
+
|
50
|
+
|
51
|
+
def _validate_taps(taps):
|
52
|
+
value = cv.int_range(min=16, max=128)(taps)
|
53
|
+
if value % 4 != 0:
|
54
|
+
raise cv.Invalid("Number of taps must be divisible by 4")
|
55
|
+
return value
|
56
|
+
|
57
|
+
|
58
|
+
CONFIG_SCHEMA = cv.All(
|
59
|
+
speaker.SPEAKER_SCHEMA.extend(
|
60
|
+
{
|
61
|
+
cv.GenerateID(): cv.declare_id(ResamplerSpeaker),
|
62
|
+
cv.Required(CONF_OUTPUT_SPEAKER): cv.use_id(speaker.Speaker),
|
63
|
+
cv.Optional(
|
64
|
+
CONF_BUFFER_DURATION, default="100ms"
|
65
|
+
): cv.positive_time_period_milliseconds,
|
66
|
+
cv.SplitDefault(CONF_TASK_STACK_IN_PSRAM, esp32_idf=False): cv.All(
|
67
|
+
cv.boolean, cv.only_with_esp_idf
|
68
|
+
),
|
69
|
+
cv.Optional(CONF_FILTERS, default=16): cv.int_range(min=2, max=1024),
|
70
|
+
cv.Optional(CONF_TAPS, default=16): _validate_taps,
|
71
|
+
}
|
72
|
+
).extend(cv.COMPONENT_SCHEMA),
|
73
|
+
cv.only_on([PLATFORM_ESP32]),
|
74
|
+
_set_stream_limits,
|
75
|
+
)
|
76
|
+
|
77
|
+
|
78
|
+
FINAL_VALIDATE_SCHEMA = _validate_audio_compatability
|
79
|
+
|
80
|
+
|
81
|
+
async def to_code(config):
|
82
|
+
var = cg.new_Pvariable(config[CONF_ID])
|
83
|
+
await cg.register_component(var, config)
|
84
|
+
await speaker.register_speaker(var, config)
|
85
|
+
|
86
|
+
output_spkr = await cg.get_variable(config[CONF_OUTPUT_SPEAKER])
|
87
|
+
cg.add(var.set_output_speaker(output_spkr))
|
88
|
+
|
89
|
+
cg.add(var.set_buffer_duration(config[CONF_BUFFER_DURATION]))
|
90
|
+
|
91
|
+
if task_stack_in_psram := config.get(CONF_TASK_STACK_IN_PSRAM):
|
92
|
+
cg.add(var.set_task_stack_in_psram(task_stack_in_psram))
|
93
|
+
if task_stack_in_psram:
|
94
|
+
if config[CONF_TASK_STACK_IN_PSRAM]:
|
95
|
+
esp32.add_idf_sdkconfig_option(
|
96
|
+
"CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY", True
|
97
|
+
)
|
98
|
+
|
99
|
+
cg.add(var.set_target_bits_per_sample(config[CONF_BITS_PER_SAMPLE]))
|
100
|
+
cg.add(var.set_target_sample_rate(config[CONF_SAMPLE_RATE]))
|
101
|
+
|
102
|
+
cg.add(var.set_filters(config[CONF_FILTERS]))
|
103
|
+
cg.add(var.set_taps(config[CONF_TAPS]))
|
@@ -0,0 +1,318 @@
|
|
1
|
+
#include "resampler_speaker.h"
|
2
|
+
|
3
|
+
#ifdef USE_ESP32
|
4
|
+
|
5
|
+
#include "esphome/components/audio/audio_resampler.h"
|
6
|
+
|
7
|
+
#include "esphome/core/helpers.h"
|
8
|
+
#include "esphome/core/log.h"
|
9
|
+
|
10
|
+
#include <algorithm>
|
11
|
+
#include <cstring>
|
12
|
+
|
13
|
+
namespace esphome {
|
14
|
+
namespace resampler {
|
15
|
+
|
16
|
+
static const UBaseType_t RESAMPLER_TASK_PRIORITY = 1;
|
17
|
+
|
18
|
+
static const uint32_t TRANSFER_BUFFER_DURATION_MS = 50;
|
19
|
+
|
20
|
+
static const uint32_t TASK_DELAY_MS = 20;
|
21
|
+
static const uint32_t TASK_STACK_SIZE = 3072;
|
22
|
+
|
23
|
+
static const char *const TAG = "resampler_speaker";
|
24
|
+
|
25
|
+
enum ResamplingEventGroupBits : uint32_t {
|
26
|
+
COMMAND_STOP = (1 << 0), // stops the resampler task
|
27
|
+
STATE_STARTING = (1 << 10),
|
28
|
+
STATE_RUNNING = (1 << 11),
|
29
|
+
STATE_STOPPING = (1 << 12),
|
30
|
+
STATE_STOPPED = (1 << 13),
|
31
|
+
ERR_ESP_NO_MEM = (1 << 19),
|
32
|
+
ERR_ESP_NOT_SUPPORTED = (1 << 20),
|
33
|
+
ERR_ESP_FAIL = (1 << 21),
|
34
|
+
ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
|
35
|
+
};
|
36
|
+
|
37
|
+
void ResamplerSpeaker::setup() {
|
38
|
+
this->event_group_ = xEventGroupCreate();
|
39
|
+
|
40
|
+
if (this->event_group_ == nullptr) {
|
41
|
+
ESP_LOGE(TAG, "Failed to create event group");
|
42
|
+
this->mark_failed();
|
43
|
+
return;
|
44
|
+
}
|
45
|
+
|
46
|
+
this->output_speaker_->add_audio_output_callback(
|
47
|
+
[this](uint32_t new_playback_ms, uint32_t remainder_us, uint32_t pending_ms, uint32_t write_timestamp) {
|
48
|
+
int32_t adjustment = this->playback_differential_ms_;
|
49
|
+
this->playback_differential_ms_ -= adjustment;
|
50
|
+
int32_t adjusted_playback_ms = static_cast<int32_t>(new_playback_ms) + adjustment;
|
51
|
+
this->audio_output_callback_(adjusted_playback_ms, remainder_us, pending_ms, write_timestamp);
|
52
|
+
});
|
53
|
+
}
|
54
|
+
|
55
|
+
void ResamplerSpeaker::loop() {
|
56
|
+
uint32_t event_group_bits = xEventGroupGetBits(this->event_group_);
|
57
|
+
|
58
|
+
if (event_group_bits & ResamplingEventGroupBits::STATE_STARTING) {
|
59
|
+
ESP_LOGD(TAG, "Starting resampler task");
|
60
|
+
xEventGroupClearBits(this->event_group_, ResamplingEventGroupBits::STATE_STARTING);
|
61
|
+
}
|
62
|
+
|
63
|
+
if (event_group_bits & ResamplingEventGroupBits::ERR_ESP_NO_MEM) {
|
64
|
+
this->status_set_error("Resampler task failed to allocate the internal buffers");
|
65
|
+
xEventGroupClearBits(this->event_group_, ResamplingEventGroupBits::ERR_ESP_NO_MEM);
|
66
|
+
this->state_ = speaker::STATE_STOPPING;
|
67
|
+
}
|
68
|
+
if (event_group_bits & ResamplingEventGroupBits::ERR_ESP_NOT_SUPPORTED) {
|
69
|
+
this->status_set_error("Cannot resample due to an unsupported audio stream");
|
70
|
+
xEventGroupClearBits(this->event_group_, ResamplingEventGroupBits::ERR_ESP_NOT_SUPPORTED);
|
71
|
+
this->state_ = speaker::STATE_STOPPING;
|
72
|
+
}
|
73
|
+
if (event_group_bits & ResamplingEventGroupBits::ERR_ESP_FAIL) {
|
74
|
+
this->status_set_error("Resampler task failed");
|
75
|
+
xEventGroupClearBits(this->event_group_, ResamplingEventGroupBits::ERR_ESP_FAIL);
|
76
|
+
this->state_ = speaker::STATE_STOPPING;
|
77
|
+
}
|
78
|
+
|
79
|
+
if (event_group_bits & ResamplingEventGroupBits::STATE_RUNNING) {
|
80
|
+
ESP_LOGD(TAG, "Started resampler task");
|
81
|
+
this->status_clear_error();
|
82
|
+
xEventGroupClearBits(this->event_group_, ResamplingEventGroupBits::STATE_RUNNING);
|
83
|
+
}
|
84
|
+
if (event_group_bits & ResamplingEventGroupBits::STATE_STOPPING) {
|
85
|
+
ESP_LOGD(TAG, "Stopping resampler task");
|
86
|
+
xEventGroupClearBits(this->event_group_, ResamplingEventGroupBits::STATE_STOPPING);
|
87
|
+
}
|
88
|
+
if (event_group_bits & ResamplingEventGroupBits::STATE_STOPPED) {
|
89
|
+
if (this->delete_task_() == ESP_OK) {
|
90
|
+
ESP_LOGD(TAG, "Stopped resampler task");
|
91
|
+
xEventGroupClearBits(this->event_group_, ResamplingEventGroupBits::ALL_BITS);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
switch (this->state_) {
|
96
|
+
case speaker::STATE_STARTING: {
|
97
|
+
esp_err_t err = this->start_();
|
98
|
+
if (err == ESP_OK) {
|
99
|
+
this->status_clear_error();
|
100
|
+
this->state_ = speaker::STATE_RUNNING;
|
101
|
+
} else {
|
102
|
+
switch (err) {
|
103
|
+
case ESP_ERR_INVALID_STATE:
|
104
|
+
this->status_set_error("Failed to start resampler: resampler task failed to start");
|
105
|
+
break;
|
106
|
+
case ESP_ERR_NO_MEM:
|
107
|
+
this->status_set_error("Failed to start resampler: not enough memory for task stack");
|
108
|
+
default:
|
109
|
+
this->status_set_error("Failed to start resampler");
|
110
|
+
break;
|
111
|
+
}
|
112
|
+
|
113
|
+
this->state_ = speaker::STATE_STOPPING;
|
114
|
+
}
|
115
|
+
break;
|
116
|
+
}
|
117
|
+
case speaker::STATE_RUNNING:
|
118
|
+
if (this->output_speaker_->is_stopped()) {
|
119
|
+
this->state_ = speaker::STATE_STOPPING;
|
120
|
+
}
|
121
|
+
|
122
|
+
break;
|
123
|
+
case speaker::STATE_STOPPING:
|
124
|
+
this->stop_();
|
125
|
+
this->state_ = speaker::STATE_STOPPED;
|
126
|
+
break;
|
127
|
+
case speaker::STATE_STOPPED:
|
128
|
+
break;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
size_t ResamplerSpeaker::play(const uint8_t *data, size_t length, TickType_t ticks_to_wait) {
|
133
|
+
if (this->is_stopped()) {
|
134
|
+
this->start();
|
135
|
+
}
|
136
|
+
|
137
|
+
size_t bytes_written = 0;
|
138
|
+
if ((this->output_speaker_->is_running()) && (!this->requires_resampling_())) {
|
139
|
+
bytes_written = this->output_speaker_->play(data, length, ticks_to_wait);
|
140
|
+
} else {
|
141
|
+
if (this->ring_buffer_.use_count() == 1) {
|
142
|
+
std::shared_ptr<RingBuffer> temp_ring_buffer = this->ring_buffer_.lock();
|
143
|
+
bytes_written = temp_ring_buffer->write_without_replacement(data, length, ticks_to_wait);
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
return bytes_written;
|
148
|
+
}
|
149
|
+
|
150
|
+
void ResamplerSpeaker::start() { this->state_ = speaker::STATE_STARTING; }
|
151
|
+
|
152
|
+
esp_err_t ResamplerSpeaker::start_() {
|
153
|
+
this->target_stream_info_ = audio::AudioStreamInfo(
|
154
|
+
this->target_bits_per_sample_, this->audio_stream_info_.get_channels(), this->target_sample_rate_);
|
155
|
+
|
156
|
+
this->output_speaker_->set_audio_stream_info(this->target_stream_info_);
|
157
|
+
this->output_speaker_->start();
|
158
|
+
|
159
|
+
if (this->requires_resampling_()) {
|
160
|
+
// Start the resampler task to handle converting sample rates
|
161
|
+
return this->start_task_();
|
162
|
+
}
|
163
|
+
|
164
|
+
return ESP_OK;
|
165
|
+
}
|
166
|
+
|
167
|
+
esp_err_t ResamplerSpeaker::start_task_() {
|
168
|
+
if (this->task_stack_buffer_ == nullptr) {
|
169
|
+
if (this->task_stack_in_psram_) {
|
170
|
+
RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_EXTERNAL);
|
171
|
+
this->task_stack_buffer_ = stack_allocator.allocate(TASK_STACK_SIZE);
|
172
|
+
} else {
|
173
|
+
RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_INTERNAL);
|
174
|
+
this->task_stack_buffer_ = stack_allocator.allocate(TASK_STACK_SIZE);
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
if (this->task_stack_buffer_ == nullptr) {
|
179
|
+
return ESP_ERR_NO_MEM;
|
180
|
+
}
|
181
|
+
|
182
|
+
if (this->task_handle_ == nullptr) {
|
183
|
+
this->task_handle_ = xTaskCreateStatic(resample_task, "sample", TASK_STACK_SIZE, (void *) this,
|
184
|
+
RESAMPLER_TASK_PRIORITY, this->task_stack_buffer_, &this->task_stack_);
|
185
|
+
}
|
186
|
+
|
187
|
+
if (this->task_handle_ == nullptr) {
|
188
|
+
return ESP_ERR_INVALID_STATE;
|
189
|
+
}
|
190
|
+
|
191
|
+
return ESP_OK;
|
192
|
+
}
|
193
|
+
|
194
|
+
void ResamplerSpeaker::stop() { this->state_ = speaker::STATE_STOPPING; }
|
195
|
+
|
196
|
+
void ResamplerSpeaker::stop_() {
|
197
|
+
if (this->task_handle_ != nullptr) {
|
198
|
+
xEventGroupSetBits(this->event_group_, ResamplingEventGroupBits::COMMAND_STOP);
|
199
|
+
}
|
200
|
+
this->output_speaker_->stop();
|
201
|
+
}
|
202
|
+
|
203
|
+
esp_err_t ResamplerSpeaker::delete_task_() {
|
204
|
+
if (!this->task_created_) {
|
205
|
+
this->task_handle_ = nullptr;
|
206
|
+
|
207
|
+
if (this->task_stack_buffer_ != nullptr) {
|
208
|
+
if (this->task_stack_in_psram_) {
|
209
|
+
RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_EXTERNAL);
|
210
|
+
stack_allocator.deallocate(this->task_stack_buffer_, TASK_STACK_SIZE);
|
211
|
+
} else {
|
212
|
+
RAMAllocator<StackType_t> stack_allocator(RAMAllocator<StackType_t>::ALLOC_INTERNAL);
|
213
|
+
stack_allocator.deallocate(this->task_stack_buffer_, TASK_STACK_SIZE);
|
214
|
+
}
|
215
|
+
|
216
|
+
this->task_stack_buffer_ = nullptr;
|
217
|
+
}
|
218
|
+
|
219
|
+
return ESP_OK;
|
220
|
+
}
|
221
|
+
|
222
|
+
return ESP_ERR_INVALID_STATE;
|
223
|
+
}
|
224
|
+
|
225
|
+
void ResamplerSpeaker::finish() { this->output_speaker_->finish(); }
|
226
|
+
|
227
|
+
bool ResamplerSpeaker::has_buffered_data() const {
|
228
|
+
bool has_ring_buffer_data = false;
|
229
|
+
if (this->requires_resampling_() && (this->ring_buffer_.use_count() > 0)) {
|
230
|
+
has_ring_buffer_data = (this->ring_buffer_.lock()->available() > 0);
|
231
|
+
}
|
232
|
+
return (has_ring_buffer_data || this->output_speaker_->has_buffered_data());
|
233
|
+
}
|
234
|
+
|
235
|
+
void ResamplerSpeaker::set_mute_state(bool mute_state) {
|
236
|
+
this->mute_state_ = mute_state;
|
237
|
+
this->output_speaker_->set_mute_state(mute_state);
|
238
|
+
}
|
239
|
+
|
240
|
+
void ResamplerSpeaker::set_volume(float volume) {
|
241
|
+
this->volume_ = volume;
|
242
|
+
this->output_speaker_->set_volume(volume);
|
243
|
+
}
|
244
|
+
|
245
|
+
bool ResamplerSpeaker::requires_resampling_() const {
|
246
|
+
return (this->audio_stream_info_.get_sample_rate() != this->target_sample_rate_) ||
|
247
|
+
(this->audio_stream_info_.get_bits_per_sample() != this->target_bits_per_sample_);
|
248
|
+
}
|
249
|
+
|
250
|
+
void ResamplerSpeaker::resample_task(void *params) {
|
251
|
+
ResamplerSpeaker *this_resampler = (ResamplerSpeaker *) params;
|
252
|
+
|
253
|
+
this_resampler->task_created_ = true;
|
254
|
+
xEventGroupSetBits(this_resampler->event_group_, ResamplingEventGroupBits::STATE_STARTING);
|
255
|
+
|
256
|
+
std::unique_ptr<audio::AudioResampler> resampler =
|
257
|
+
make_unique<audio::AudioResampler>(this_resampler->audio_stream_info_.ms_to_bytes(TRANSFER_BUFFER_DURATION_MS),
|
258
|
+
this_resampler->target_stream_info_.ms_to_bytes(TRANSFER_BUFFER_DURATION_MS));
|
259
|
+
|
260
|
+
esp_err_t err = resampler->start(this_resampler->audio_stream_info_, this_resampler->target_stream_info_,
|
261
|
+
this_resampler->taps_, this_resampler->filters_);
|
262
|
+
|
263
|
+
if (err == ESP_OK) {
|
264
|
+
std::shared_ptr<RingBuffer> temp_ring_buffer =
|
265
|
+
RingBuffer::create(this_resampler->audio_stream_info_.ms_to_bytes(this_resampler->buffer_duration_ms_));
|
266
|
+
|
267
|
+
if (temp_ring_buffer.use_count() == 0) {
|
268
|
+
err = ESP_ERR_NO_MEM;
|
269
|
+
} else {
|
270
|
+
this_resampler->ring_buffer_ = temp_ring_buffer;
|
271
|
+
resampler->add_source(this_resampler->ring_buffer_);
|
272
|
+
|
273
|
+
this_resampler->output_speaker_->set_audio_stream_info(this_resampler->target_stream_info_);
|
274
|
+
resampler->add_sink(this_resampler->output_speaker_);
|
275
|
+
}
|
276
|
+
}
|
277
|
+
|
278
|
+
if (err == ESP_OK) {
|
279
|
+
xEventGroupSetBits(this_resampler->event_group_, ResamplingEventGroupBits::STATE_RUNNING);
|
280
|
+
} else if (err == ESP_ERR_NO_MEM) {
|
281
|
+
xEventGroupSetBits(this_resampler->event_group_, ResamplingEventGroupBits::ERR_ESP_NO_MEM);
|
282
|
+
} else if (err == ESP_ERR_NOT_SUPPORTED) {
|
283
|
+
xEventGroupSetBits(this_resampler->event_group_, ResamplingEventGroupBits::ERR_ESP_NOT_SUPPORTED);
|
284
|
+
}
|
285
|
+
|
286
|
+
this_resampler->playback_differential_ms_ = 0;
|
287
|
+
while (err == ESP_OK) {
|
288
|
+
uint32_t event_bits = xEventGroupGetBits(this_resampler->event_group_);
|
289
|
+
|
290
|
+
if (event_bits & ResamplingEventGroupBits::COMMAND_STOP) {
|
291
|
+
break;
|
292
|
+
}
|
293
|
+
|
294
|
+
// Stop gracefully if the decoder is done
|
295
|
+
int32_t ms_differential = 0;
|
296
|
+
audio::AudioResamplerState resampler_state = resampler->resample(false, &ms_differential);
|
297
|
+
|
298
|
+
this_resampler->playback_differential_ms_ += ms_differential;
|
299
|
+
|
300
|
+
if (resampler_state == audio::AudioResamplerState::FINISHED) {
|
301
|
+
break;
|
302
|
+
} else if (resampler_state == audio::AudioResamplerState::FAILED) {
|
303
|
+
xEventGroupSetBits(this_resampler->event_group_, ResamplingEventGroupBits::ERR_ESP_FAIL);
|
304
|
+
break;
|
305
|
+
}
|
306
|
+
}
|
307
|
+
|
308
|
+
xEventGroupSetBits(this_resampler->event_group_, ResamplingEventGroupBits::STATE_STOPPING);
|
309
|
+
resampler.reset();
|
310
|
+
xEventGroupSetBits(this_resampler->event_group_, ResamplingEventGroupBits::STATE_STOPPED);
|
311
|
+
this_resampler->task_created_ = false;
|
312
|
+
vTaskDelete(nullptr);
|
313
|
+
}
|
314
|
+
|
315
|
+
} // namespace resampler
|
316
|
+
} // namespace esphome
|
317
|
+
|
318
|
+
#endif
|