esphome 2024.12.4__py3-none-any.whl → 2025.2.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. esphome/__main__.py +16 -3
  2. esphome/components/adc/__init__.py +17 -11
  3. esphome/components/adc/adc_sensor.h +17 -0
  4. esphome/components/adc/adc_sensor_common.cpp +55 -0
  5. esphome/components/adc/adc_sensor_esp32.cpp +8 -5
  6. esphome/components/adc/adc_sensor_esp8266.cpp +10 -6
  7. esphome/components/adc/adc_sensor_libretiny.cpp +11 -6
  8. esphome/components/adc/adc_sensor_rp2040.cpp +13 -10
  9. esphome/components/adc/sensor.py +9 -3
  10. esphome/components/ads1115/ads1115.cpp +56 -7
  11. esphome/components/ads1115/ads1115.h +13 -1
  12. esphome/components/ads1115/sensor/__init__.py +16 -0
  13. esphome/components/ads1115/sensor/ads1115_sensor.cpp +2 -1
  14. esphome/components/ads1115/sensor/ads1115_sensor.h +2 -0
  15. esphome/components/animation/__init__.py +23 -261
  16. esphome/components/animation/animation.cpp +2 -2
  17. esphome/components/animation/animation.h +2 -1
  18. esphome/components/api/api_pb2.cpp +14 -0
  19. esphome/components/api/api_pb2.h +1 -0
  20. esphome/components/audio/__init__.py +112 -0
  21. esphome/components/audio/audio.cpp +67 -0
  22. esphome/components/audio/audio.h +125 -7
  23. esphome/components/audio/audio_decoder.cpp +361 -0
  24. esphome/components/audio/audio_decoder.h +135 -0
  25. esphome/components/audio/audio_reader.cpp +308 -0
  26. esphome/components/audio/audio_reader.h +85 -0
  27. esphome/components/audio/audio_resampler.cpp +159 -0
  28. esphome/components/audio/audio_resampler.h +101 -0
  29. esphome/components/audio/audio_transfer_buffer.cpp +165 -0
  30. esphome/components/audio/audio_transfer_buffer.h +139 -0
  31. esphome/components/audio_adc/__init__.py +41 -0
  32. esphome/components/audio_adc/audio_adc.h +17 -0
  33. esphome/components/audio_adc/automation.h +23 -0
  34. esphome/components/bk72xx/__init__.py +1 -0
  35. esphome/components/ble_client/ble_client.cpp +1 -2
  36. esphome/components/ble_client/sensor/__init__.py +1 -1
  37. esphome/components/ble_client/text_sensor/__init__.py +1 -1
  38. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +5 -0
  39. esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -0
  40. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +5 -0
  41. esphome/components/ch422g/ch422g.h +2 -0
  42. esphome/components/climate/__init__.py +1 -1
  43. esphome/components/climate_ir/climate_ir.cpp +2 -1
  44. esphome/components/coolix/coolix.cpp +2 -1
  45. esphome/components/cse7766/cse7766.cpp +8 -16
  46. esphome/components/custom/__init__.py +0 -3
  47. esphome/components/custom/binary_sensor/__init__.py +2 -28
  48. esphome/components/custom/climate/__init__.py +2 -27
  49. esphome/components/custom/cover/__init__.py +2 -27
  50. esphome/components/custom/light/__init__.py +2 -27
  51. esphome/components/custom/output/__init__.py +2 -58
  52. esphome/components/custom/sensor/__init__.py +2 -24
  53. esphome/components/custom/switch/__init__.py +2 -24
  54. esphome/components/custom/text_sensor/__init__.py +2 -29
  55. esphome/components/custom_component/__init__.py +3 -27
  56. esphome/components/daly_bms/daly_bms.cpp +6 -0
  57. esphome/components/daly_bms/daly_bms.h +2 -0
  58. esphome/components/daly_bms/sensor.py +6 -0
  59. esphome/components/debug/debug_component.cpp +4 -0
  60. esphome/components/debug/debug_component.h +14 -0
  61. esphome/components/debug/debug_esp32.cpp +154 -74
  62. esphome/components/dfplayer/dfplayer.cpp +15 -2
  63. esphome/components/dfrobot_sen0395/dfrobot_sen0395.cpp +2 -1
  64. esphome/components/dht/dht.cpp +2 -1
  65. esphome/components/display/__init__.py +18 -5
  66. esphome/components/display/display.cpp +2 -1
  67. esphome/components/display/rect.cpp +2 -1
  68. esphome/components/es7210/__init__.py +0 -0
  69. esphome/components/es7210/audio_adc.py +51 -0
  70. esphome/components/es7210/es7210.cpp +228 -0
  71. esphome/components/es7210/es7210.h +62 -0
  72. esphome/components/es7210/es7210_const.h +129 -0
  73. esphome/components/es7243e/__init__.py +0 -0
  74. esphome/components/es7243e/audio_adc.py +34 -0
  75. esphome/components/es7243e/es7243e.cpp +125 -0
  76. esphome/components/es7243e/es7243e.h +37 -0
  77. esphome/components/es7243e/es7243e_const.h +54 -0
  78. esphome/components/es8156/__init__.py +0 -0
  79. esphome/components/es8156/audio_dac.py +27 -0
  80. esphome/components/es8156/es8156.cpp +87 -0
  81. esphome/components/es8156/es8156.h +51 -0
  82. esphome/components/es8156/es8156_const.h +68 -0
  83. esphome/components/es8311/audio_dac.py +1 -2
  84. esphome/components/esp32/__init__.py +1 -0
  85. esphome/components/esp32/core.cpp +5 -1
  86. esphome/components/esp32/gpio.h +2 -0
  87. esphome/components/esp32_ble/__init__.py +39 -0
  88. esphome/components/esp32_ble/queue.h +4 -4
  89. esphome/components/esp32_ble_client/ble_client_base.cpp +46 -0
  90. esphome/components/esp32_ble_client/ble_client_base.h +2 -0
  91. esphome/components/esp32_ble_server/__init__.py +582 -12
  92. esphome/components/esp32_ble_server/ble_characteristic.cpp +48 -60
  93. esphome/components/esp32_ble_server/ble_characteristic.h +24 -17
  94. esphome/components/esp32_ble_server/ble_descriptor.cpp +21 -9
  95. esphome/components/esp32_ble_server/ble_descriptor.h +17 -6
  96. esphome/components/esp32_ble_server/ble_server.cpp +62 -67
  97. esphome/components/esp32_ble_server/ble_server.h +28 -32
  98. esphome/components/esp32_ble_server/ble_server_automations.cpp +77 -0
  99. esphome/components/esp32_ble_server/ble_server_automations.h +115 -0
  100. esphome/components/esp32_ble_server/ble_service.cpp +17 -15
  101. esphome/components/esp32_ble_server/ble_service.h +10 -14
  102. esphome/components/esp32_ble_tracker/__init__.py +6 -39
  103. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +33 -10
  104. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +8 -4
  105. esphome/components/esp32_improv/__init__.py +2 -8
  106. esphome/components/esp32_improv/esp32_improv_component.cpp +21 -20
  107. esphome/components/esp32_improv/esp32_improv_component.h +3 -4
  108. esphome/components/esp32_rmt/__init__.py +28 -3
  109. esphome/components/esp32_rmt_led_strip/led_strip.cpp +73 -6
  110. esphome/components/esp32_rmt_led_strip/led_strip.h +21 -3
  111. esphome/components/esp32_rmt_led_strip/light.py +72 -7
  112. esphome/components/esp32_touch/esp32_touch.cpp +5 -0
  113. esphome/components/esp8266/__init__.py +1 -0
  114. esphome/components/esp8266/gpio.h +1 -0
  115. esphome/components/ethernet/__init__.py +10 -10
  116. esphome/components/event/event.cpp +4 -2
  117. esphome/components/event/event.h +2 -0
  118. esphome/components/event_emitter/__init__.py +5 -0
  119. esphome/components/event_emitter/event_emitter.cpp +14 -0
  120. esphome/components/event_emitter/event_emitter.h +63 -0
  121. esphome/components/gcja5/gcja5.cpp +2 -1
  122. esphome/components/graph/graph.cpp +4 -9
  123. esphome/components/haier/haier_base.cpp +2 -1
  124. esphome/components/haier/hon_climate.cpp +2 -1
  125. esphome/components/heatpumpir/heatpumpir.cpp +2 -1
  126. esphome/components/host/__init__.py +1 -0
  127. esphome/components/host/gpio.h +1 -0
  128. esphome/components/http_request/http_request.h +2 -2
  129. esphome/components/http_request/http_request_arduino.cpp +1 -1
  130. esphome/components/http_request/http_request_idf.cpp +1 -1
  131. esphome/components/i2c/i2c_bus_esp_idf.cpp +4 -0
  132. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +7 -5
  133. esphome/components/i2s_audio/speaker/__init__.py +53 -6
  134. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +92 -46
  135. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -0
  136. esphome/components/ili9xxx/display.py +29 -11
  137. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -5
  138. esphome/components/ili9xxx/ili9xxx_display.h +2 -1
  139. esphome/components/image/__init__.py +443 -255
  140. esphome/components/image/image.cpp +115 -61
  141. esphome/components/image/image.h +15 -24
  142. esphome/components/json/json_util.cpp +8 -34
  143. esphome/components/libretiny/__init__.py +1 -0
  144. esphome/components/libretiny/gpio_arduino.h +1 -0
  145. esphome/components/light/light_color_values.h +1 -1
  146. esphome/components/logger/__init__.py +43 -7
  147. esphome/components/logger/logger.cpp +16 -11
  148. esphome/components/logger/logger.h +11 -7
  149. esphome/components/logger/select/__init__.py +29 -0
  150. esphome/components/logger/select/logger_level_select.cpp +27 -0
  151. esphome/components/logger/select/logger_level_select.h +15 -0
  152. esphome/components/lvgl/__init__.py +96 -73
  153. esphome/components/lvgl/automation.py +39 -7
  154. esphome/components/lvgl/defines.py +8 -2
  155. esphome/components/lvgl/lvgl_esphome.cpp +8 -15
  156. esphome/components/lvgl/lvgl_esphome.h +20 -5
  157. esphome/components/lvgl/schemas.py +25 -14
  158. esphome/components/lvgl/trigger.py +27 -3
  159. esphome/components/lvgl/widgets/dropdown.py +1 -1
  160. esphome/components/lvgl/widgets/keyboard.py +8 -1
  161. esphome/components/lvgl/widgets/meter.py +2 -1
  162. esphome/components/lvgl/widgets/msgbox.py +1 -1
  163. esphome/components/lvgl/widgets/obj.py +1 -12
  164. esphome/components/lvgl/widgets/page.py +37 -2
  165. esphome/components/lvgl/widgets/tabview.py +1 -1
  166. esphome/components/max6956/max6956.h +2 -0
  167. esphome/components/mcp23016/mcp23016.h +2 -0
  168. esphome/components/mcp23xxx_base/mcp23xxx_base.h +2 -0
  169. esphome/components/mdns/__init__.py +1 -1
  170. esphome/components/media_player/__init__.py +37 -8
  171. esphome/components/media_player/automation.h +11 -2
  172. esphome/components/media_player/media_player.cpp +8 -0
  173. esphome/components/media_player/media_player.h +8 -4
  174. esphome/components/micronova/switch/micronova_switch.cpp +4 -2
  175. esphome/components/midea/ac_automations.h +3 -1
  176. esphome/components/midea/air_conditioner.cpp +7 -5
  177. esphome/components/midea/air_conditioner.h +1 -1
  178. esphome/components/midea/climate.py +4 -2
  179. esphome/components/midea/ir_transmitter.h +36 -5
  180. esphome/components/mixer/__init__.py +0 -0
  181. esphome/components/mixer/speaker/__init__.py +172 -0
  182. esphome/components/mixer/speaker/automation.h +19 -0
  183. esphome/components/mixer/speaker/mixer_speaker.cpp +624 -0
  184. esphome/components/mixer/speaker/mixer_speaker.h +207 -0
  185. esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp +7 -13
  186. esphome/components/mpr121/mpr121.h +2 -0
  187. esphome/components/mqtt/__init__.py +1 -1
  188. esphome/components/mqtt/mqtt_client.cpp +7 -1
  189. esphome/components/mqtt/mqtt_client.h +1 -1
  190. esphome/components/mqtt/mqtt_climate.cpp +2 -2
  191. esphome/components/network/ip_address.h +2 -0
  192. esphome/components/nextion/automation.h +17 -0
  193. esphome/components/nextion/display.py +42 -17
  194. esphome/components/nextion/nextion.cpp +4 -10
  195. esphome/components/nextion/nextion.h +89 -82
  196. esphome/components/nextion/nextion_commands.cpp +10 -10
  197. esphome/components/ntc/sensor.py +2 -4
  198. esphome/components/online_image/__init__.py +98 -46
  199. esphome/components/online_image/bmp_image.cpp +101 -0
  200. esphome/components/online_image/bmp_image.h +40 -0
  201. esphome/components/online_image/image_decoder.cpp +28 -2
  202. esphome/components/online_image/image_decoder.h +24 -15
  203. esphome/components/online_image/jpeg_image.cpp +90 -0
  204. esphome/components/online_image/jpeg_image.h +34 -0
  205. esphome/components/online_image/online_image.cpp +112 -53
  206. esphome/components/online_image/online_image.h +24 -7
  207. esphome/components/online_image/png_image.cpp +7 -3
  208. esphome/components/online_image/png_image.h +2 -1
  209. esphome/components/opentherm/__init__.py +73 -7
  210. esphome/components/opentherm/automation.h +25 -0
  211. esphome/components/opentherm/const.py +1 -0
  212. esphome/components/opentherm/generate.py +39 -6
  213. esphome/components/opentherm/hub.cpp +117 -79
  214. esphome/components/opentherm/hub.h +31 -15
  215. esphome/components/opentherm/opentherm.cpp +47 -23
  216. esphome/components/opentherm/opentherm.h +27 -6
  217. esphome/components/opentherm/opentherm_macros.h +11 -0
  218. esphome/components/opentherm/schema.py +78 -1
  219. esphome/components/opentherm/validate.py +7 -2
  220. esphome/components/pca6416a/pca6416a.h +2 -0
  221. esphome/components/pca9554/pca9554.h +2 -0
  222. esphome/components/pcf8574/pcf8574.h +2 -0
  223. esphome/components/preferences/__init__.py +2 -4
  224. esphome/components/preferences/syncer.h +10 -3
  225. esphome/components/prometheus/prometheus_handler.cpp +313 -0
  226. esphome/components/prometheus/prometheus_handler.h +48 -7
  227. esphome/components/psram/psram.cpp +8 -1
  228. esphome/components/pulse_counter/pulse_counter_sensor.cpp +14 -9
  229. esphome/components/pulse_counter/pulse_counter_sensor.h +4 -4
  230. esphome/components/pulse_meter/pulse_meter_sensor.cpp +2 -0
  231. esphome/components/qspi_dbi/__init__.py +3 -0
  232. esphome/components/qspi_dbi/display.py +74 -47
  233. esphome/components/qspi_dbi/models.py +245 -2
  234. esphome/components/qspi_dbi/qspi_dbi.cpp +9 -16
  235. esphome/components/qspi_dbi/qspi_dbi.h +2 -2
  236. esphome/components/remote_base/__init__.py +77 -25
  237. esphome/components/remote_base/remote_base.cpp +1 -1
  238. esphome/components/remote_base/remote_base.h +20 -2
  239. esphome/components/remote_base/toto_protocol.cpp +100 -0
  240. esphome/components/remote_base/toto_protocol.h +45 -0
  241. esphome/components/remote_receiver/__init__.py +55 -10
  242. esphome/components/remote_receiver/remote_receiver.h +36 -3
  243. esphome/components/remote_receiver/remote_receiver_esp32.cpp +145 -6
  244. esphome/components/remote_transmitter/__init__.py +62 -4
  245. esphome/components/remote_transmitter/remote_transmitter.h +21 -2
  246. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +140 -4
  247. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +3 -3
  248. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +3 -3
  249. esphome/components/resampler/__init__.py +0 -0
  250. esphome/components/resampler/speaker/__init__.py +103 -0
  251. esphome/components/resampler/speaker/resampler_speaker.cpp +318 -0
  252. esphome/components/resampler/speaker/resampler_speaker.h +107 -0
  253. esphome/components/resistance/resistance_sensor.h +2 -3
  254. esphome/components/resistance/sensor.py +2 -9
  255. esphome/components/rotary_encoder/rotary_encoder.cpp +8 -4
  256. esphome/components/rp2040/__init__.py +1 -0
  257. esphome/components/rp2040/gpio.h +1 -0
  258. esphome/components/rtl87xx/__init__.py +2 -0
  259. esphome/components/sdl/binary_sensor.py +270 -0
  260. esphome/components/sdl/sdl_esphome.cpp +16 -0
  261. esphome/components/sdl/sdl_esphome.h +9 -0
  262. esphome/components/seeed_mr60bha2/binary_sensor.py +25 -0
  263. esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +26 -2
  264. esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +9 -20
  265. esphome/components/seeed_mr60bha2/sensor.py +9 -1
  266. esphome/components/sn74hc165/sn74hc165.h +3 -0
  267. esphome/components/sn74hc595/sn74hc595.h +3 -0
  268. esphome/components/speaker/__init__.py +5 -4
  269. esphome/components/speaker/media_player/__init__.py +458 -0
  270. esphome/components/speaker/media_player/audio_pipeline.cpp +568 -0
  271. esphome/components/speaker/media_player/audio_pipeline.h +159 -0
  272. esphome/components/speaker/media_player/automation.h +26 -0
  273. esphome/components/speaker/media_player/speaker_media_player.cpp +577 -0
  274. esphome/components/speaker/media_player/speaker_media_player.h +160 -0
  275. esphome/components/speaker/speaker.h +20 -0
  276. esphome/components/spi/__init__.py +1 -5
  277. esphome/components/spi/spi.cpp +7 -1
  278. esphome/components/spi/spi.h +21 -2
  279. esphome/components/spi_led_strip/light.py +3 -5
  280. esphome/components/spi_led_strip/spi_led_strip.cpp +67 -0
  281. esphome/components/spi_led_strip/spi_led_strip.h +8 -60
  282. esphome/components/sprinkler/sprinkler.cpp +3 -1
  283. esphome/components/sx1509/sx1509_gpio_pin.h +2 -0
  284. esphome/components/tca9555/tca9555.h +2 -0
  285. esphome/components/toshiba/toshiba.cpp +2 -1
  286. esphome/components/tuya/light/tuya_light.cpp +4 -2
  287. esphome/components/uart/uart_component_esp32_arduino.cpp +2 -2
  288. esphome/components/uart/uart_component_esp_idf.cpp +2 -2
  289. esphome/components/udp/__init__.py +8 -2
  290. esphome/components/udp/udp_component.cpp +25 -56
  291. esphome/components/udp/udp_component.h +3 -0
  292. esphome/components/uponor_smatrix/sensor/__init__.py +14 -4
  293. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +5 -0
  294. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.h +1 -0
  295. esphome/components/uptime/text_sensor/__init__.py +19 -0
  296. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +63 -0
  297. esphome/components/uptime/text_sensor/uptime_text_sensor.h +25 -0
  298. esphome/components/voice_assistant/voice_assistant.cpp +24 -14
  299. esphome/components/voice_assistant/voice_assistant.h +8 -0
  300. esphome/components/waveshare_epaper/display.py +22 -1
  301. esphome/components/waveshare_epaper/waveshare_213v3.cpp +9 -3
  302. esphome/components/waveshare_epaper/waveshare_epaper.cpp +1155 -44
  303. esphome/components/waveshare_epaper/waveshare_epaper.h +208 -7
  304. esphome/components/web_server/web_server.cpp +28 -6
  305. esphome/components/weikai/weikai.h +2 -0
  306. esphome/components/wifi/__init__.py +6 -6
  307. esphome/components/wifi/wifi_component.cpp +1 -1
  308. esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -1
  309. esphome/components/wireguard/__init__.py +2 -2
  310. esphome/components/xl9535/xl9535.h +2 -0
  311. esphome/components/xxtea/__init__.py +3 -0
  312. esphome/components/xxtea/xxtea.cpp +46 -0
  313. esphome/components/xxtea/xxtea.h +26 -0
  314. esphome/components/yashima/yashima.cpp +2 -1
  315. esphome/config.py +9 -5
  316. esphome/config_validation.py +55 -17
  317. esphome/const.py +7 -10
  318. esphome/core/__init__.py +6 -13
  319. esphome/core/base_automation.h +1 -0
  320. esphome/core/config.py +59 -72
  321. esphome/core/defines.h +9 -1
  322. esphome/core/gpio.h +7 -0
  323. esphome/core/helpers.cpp +19 -15
  324. esphome/core/helpers.h +57 -8
  325. esphome/core/log.h +9 -7
  326. esphome/cpp_generator.py +2 -2
  327. esphome/espota2.py +3 -2
  328. esphome/loader.py +12 -4
  329. esphome/log.py +5 -7
  330. esphome/yaml_util.py +2 -2
  331. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/METADATA +12 -7
  332. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/RECORD +341 -292
  333. esphome/components/custom/binary_sensor/custom_binary_sensor.cpp +0 -16
  334. esphome/components/custom/binary_sensor/custom_binary_sensor.h +0 -26
  335. esphome/components/custom/climate/custom_climate.h +0 -22
  336. esphome/components/custom/cover/custom_cover.h +0 -21
  337. esphome/components/custom/light/custom_light_output.h +0 -24
  338. esphome/components/custom/output/custom_output.h +0 -37
  339. esphome/components/custom/sensor/custom_sensor.cpp +0 -16
  340. esphome/components/custom/sensor/custom_sensor.h +0 -24
  341. esphome/components/custom/switch/custom_switch.cpp +0 -16
  342. esphome/components/custom/switch/custom_switch.h +0 -24
  343. esphome/components/custom/text_sensor/custom_text_sensor.cpp +0 -16
  344. esphome/components/custom/text_sensor/custom_text_sensor.h +0 -26
  345. esphome/components/custom_component/custom_component.h +0 -28
  346. esphome/components/esp32_ble_server/ble_2901.cpp +0 -18
  347. esphome/components/esp32_ble_server/ble_2901.h +0 -19
  348. esphome/components/resistance_sampler/__init__.py +0 -6
  349. esphome/components/resistance_sampler/resistance_sampler.h +0 -10
  350. esphome/components/uptime/{sensor.py → sensor/__init__.py} +3 -3
  351. /esphome/components/uptime/{uptime_seconds_sensor.cpp → sensor/uptime_seconds_sensor.cpp} +0 -0
  352. /esphome/components/uptime/{uptime_seconds_sensor.h → sensor/uptime_seconds_sensor.h} +0 -0
  353. /esphome/components/uptime/{uptime_timestamp_sensor.cpp → sensor/uptime_timestamp_sensor.cpp} +0 -0
  354. /esphome/components/uptime/{uptime_timestamp_sensor.h → sensor/uptime_timestamp_sensor.h} +0 -0
  355. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/LICENSE +0 -0
  356. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/WHEEL +0 -0
  357. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/entry_points.txt +0 -0
  358. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.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() { this->configure_rmt_(); }
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->pin_->is_inverted()) {
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_ > current_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_ >= target)
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_ >= target)
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_ > micros()) {
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_ >= target)
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_ >= target)
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