esphome 2024.12.3__py3-none-any.whl → 2025.2.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) 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/custom/__init__.py +0 -3
  46. esphome/components/custom/binary_sensor/__init__.py +2 -28
  47. esphome/components/custom/climate/__init__.py +2 -27
  48. esphome/components/custom/cover/__init__.py +2 -27
  49. esphome/components/custom/light/__init__.py +2 -27
  50. esphome/components/custom/output/__init__.py +2 -58
  51. esphome/components/custom/sensor/__init__.py +2 -24
  52. esphome/components/custom/switch/__init__.py +2 -24
  53. esphome/components/custom/text_sensor/__init__.py +2 -29
  54. esphome/components/custom_component/__init__.py +3 -27
  55. esphome/components/daly_bms/daly_bms.cpp +6 -0
  56. esphome/components/daly_bms/daly_bms.h +2 -0
  57. esphome/components/daly_bms/sensor.py +6 -0
  58. esphome/components/debug/debug_component.cpp +4 -0
  59. esphome/components/debug/debug_component.h +14 -0
  60. esphome/components/debug/debug_esp32.cpp +154 -74
  61. esphome/components/dfplayer/dfplayer.cpp +15 -2
  62. esphome/components/dfrobot_sen0395/dfrobot_sen0395.cpp +2 -1
  63. esphome/components/dht/dht.cpp +2 -1
  64. esphome/components/display/__init__.py +18 -5
  65. esphome/components/display/display.cpp +2 -1
  66. esphome/components/display/rect.cpp +2 -1
  67. esphome/components/es7210/__init__.py +0 -0
  68. esphome/components/es7210/audio_adc.py +51 -0
  69. esphome/components/es7210/es7210.cpp +228 -0
  70. esphome/components/es7210/es7210.h +62 -0
  71. esphome/components/es7210/es7210_const.h +129 -0
  72. esphome/components/es7243e/__init__.py +0 -0
  73. esphome/components/es7243e/audio_adc.py +34 -0
  74. esphome/components/es7243e/es7243e.cpp +125 -0
  75. esphome/components/es7243e/es7243e.h +37 -0
  76. esphome/components/es7243e/es7243e_const.h +54 -0
  77. esphome/components/es8156/__init__.py +0 -0
  78. esphome/components/es8156/audio_dac.py +27 -0
  79. esphome/components/es8156/es8156.cpp +87 -0
  80. esphome/components/es8156/es8156.h +51 -0
  81. esphome/components/es8156/es8156_const.h +68 -0
  82. esphome/components/es8311/audio_dac.py +1 -2
  83. esphome/components/esp32/__init__.py +1 -0
  84. esphome/components/esp32/core.cpp +5 -1
  85. esphome/components/esp32/gpio.h +2 -0
  86. esphome/components/esp32_ble/__init__.py +39 -0
  87. esphome/components/esp32_ble/queue.h +4 -4
  88. esphome/components/esp32_ble_client/ble_client_base.cpp +46 -0
  89. esphome/components/esp32_ble_client/ble_client_base.h +2 -0
  90. esphome/components/esp32_ble_server/__init__.py +582 -12
  91. esphome/components/esp32_ble_server/ble_characteristic.cpp +48 -60
  92. esphome/components/esp32_ble_server/ble_characteristic.h +24 -17
  93. esphome/components/esp32_ble_server/ble_descriptor.cpp +21 -9
  94. esphome/components/esp32_ble_server/ble_descriptor.h +17 -6
  95. esphome/components/esp32_ble_server/ble_server.cpp +62 -67
  96. esphome/components/esp32_ble_server/ble_server.h +28 -32
  97. esphome/components/esp32_ble_server/ble_server_automations.cpp +77 -0
  98. esphome/components/esp32_ble_server/ble_server_automations.h +115 -0
  99. esphome/components/esp32_ble_server/ble_service.cpp +17 -15
  100. esphome/components/esp32_ble_server/ble_service.h +10 -14
  101. esphome/components/esp32_ble_tracker/__init__.py +6 -39
  102. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +33 -10
  103. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +8 -4
  104. esphome/components/esp32_improv/__init__.py +2 -8
  105. esphome/components/esp32_improv/esp32_improv_component.cpp +21 -20
  106. esphome/components/esp32_improv/esp32_improv_component.h +3 -4
  107. esphome/components/esp32_rmt/__init__.py +28 -3
  108. esphome/components/esp32_rmt_led_strip/led_strip.cpp +73 -6
  109. esphome/components/esp32_rmt_led_strip/led_strip.h +21 -3
  110. esphome/components/esp32_rmt_led_strip/light.py +72 -7
  111. esphome/components/esp32_touch/esp32_touch.cpp +5 -0
  112. esphome/components/esp8266/__init__.py +1 -0
  113. esphome/components/esp8266/gpio.h +1 -0
  114. esphome/components/ethernet/__init__.py +10 -10
  115. esphome/components/event/event.cpp +4 -2
  116. esphome/components/event/event.h +2 -0
  117. esphome/components/event_emitter/__init__.py +5 -0
  118. esphome/components/event_emitter/event_emitter.cpp +14 -0
  119. esphome/components/event_emitter/event_emitter.h +63 -0
  120. esphome/components/gcja5/gcja5.cpp +2 -1
  121. esphome/components/haier/haier_base.cpp +2 -1
  122. esphome/components/haier/hon_climate.cpp +2 -1
  123. esphome/components/heatpumpir/heatpumpir.cpp +2 -1
  124. esphome/components/host/__init__.py +1 -0
  125. esphome/components/host/gpio.h +1 -0
  126. esphome/components/http_request/http_request.h +2 -2
  127. esphome/components/http_request/http_request_arduino.cpp +1 -1
  128. esphome/components/http_request/http_request_idf.cpp +1 -1
  129. esphome/components/i2c/i2c_bus_esp_idf.cpp +4 -0
  130. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +7 -5
  131. esphome/components/i2s_audio/speaker/__init__.py +53 -6
  132. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +92 -46
  133. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -0
  134. esphome/components/ili9xxx/display.py +29 -11
  135. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -5
  136. esphome/components/ili9xxx/ili9xxx_display.h +2 -1
  137. esphome/components/image/__init__.py +443 -255
  138. esphome/components/image/image.cpp +115 -61
  139. esphome/components/image/image.h +15 -24
  140. esphome/components/json/json_util.cpp +8 -34
  141. esphome/components/libretiny/__init__.py +1 -0
  142. esphome/components/libretiny/gpio_arduino.h +1 -0
  143. esphome/components/light/light_color_values.h +1 -1
  144. esphome/components/logger/__init__.py +43 -7
  145. esphome/components/logger/logger.cpp +16 -11
  146. esphome/components/logger/logger.h +11 -7
  147. esphome/components/logger/select/__init__.py +29 -0
  148. esphome/components/logger/select/logger_level_select.cpp +27 -0
  149. esphome/components/logger/select/logger_level_select.h +15 -0
  150. esphome/components/lvgl/__init__.py +96 -73
  151. esphome/components/lvgl/automation.py +39 -7
  152. esphome/components/lvgl/defines.py +8 -2
  153. esphome/components/lvgl/lvgl_esphome.cpp +8 -15
  154. esphome/components/lvgl/lvgl_esphome.h +20 -5
  155. esphome/components/lvgl/schemas.py +25 -14
  156. esphome/components/lvgl/trigger.py +27 -3
  157. esphome/components/lvgl/widgets/dropdown.py +1 -1
  158. esphome/components/lvgl/widgets/keyboard.py +8 -1
  159. esphome/components/lvgl/widgets/meter.py +2 -1
  160. esphome/components/lvgl/widgets/msgbox.py +1 -1
  161. esphome/components/lvgl/widgets/obj.py +1 -12
  162. esphome/components/lvgl/widgets/page.py +37 -2
  163. esphome/components/lvgl/widgets/tabview.py +1 -1
  164. esphome/components/max6956/max6956.h +2 -0
  165. esphome/components/mcp23016/mcp23016.h +2 -0
  166. esphome/components/mcp23xxx_base/mcp23xxx_base.h +2 -0
  167. esphome/components/mdns/__init__.py +1 -1
  168. esphome/components/media_player/__init__.py +37 -8
  169. esphome/components/media_player/automation.h +11 -2
  170. esphome/components/media_player/media_player.cpp +8 -0
  171. esphome/components/media_player/media_player.h +8 -4
  172. esphome/components/micronova/switch/micronova_switch.cpp +4 -2
  173. esphome/components/midea/ac_automations.h +3 -1
  174. esphome/components/midea/air_conditioner.cpp +7 -5
  175. esphome/components/midea/air_conditioner.h +1 -1
  176. esphome/components/midea/climate.py +4 -2
  177. esphome/components/midea/ir_transmitter.h +36 -5
  178. esphome/components/mixer/__init__.py +0 -0
  179. esphome/components/mixer/speaker/__init__.py +172 -0
  180. esphome/components/mixer/speaker/automation.h +19 -0
  181. esphome/components/mixer/speaker/mixer_speaker.cpp +624 -0
  182. esphome/components/mixer/speaker/mixer_speaker.h +207 -0
  183. esphome/components/mpr121/mpr121.h +2 -0
  184. esphome/components/mqtt/__init__.py +1 -1
  185. esphome/components/mqtt/mqtt_client.cpp +7 -1
  186. esphome/components/mqtt/mqtt_client.h +1 -1
  187. esphome/components/mqtt/mqtt_climate.cpp +2 -2
  188. esphome/components/network/ip_address.h +2 -0
  189. esphome/components/nextion/automation.h +17 -0
  190. esphome/components/nextion/display.py +42 -17
  191. esphome/components/nextion/nextion.cpp +4 -10
  192. esphome/components/nextion/nextion.h +89 -82
  193. esphome/components/nextion/nextion_commands.cpp +10 -10
  194. esphome/components/ntc/sensor.py +2 -4
  195. esphome/components/online_image/__init__.py +98 -46
  196. esphome/components/online_image/bmp_image.cpp +101 -0
  197. esphome/components/online_image/bmp_image.h +40 -0
  198. esphome/components/online_image/image_decoder.cpp +28 -2
  199. esphome/components/online_image/image_decoder.h +24 -15
  200. esphome/components/online_image/jpeg_image.cpp +90 -0
  201. esphome/components/online_image/jpeg_image.h +34 -0
  202. esphome/components/online_image/online_image.cpp +112 -53
  203. esphome/components/online_image/online_image.h +24 -7
  204. esphome/components/online_image/png_image.cpp +7 -3
  205. esphome/components/online_image/png_image.h +2 -1
  206. esphome/components/opentherm/__init__.py +73 -7
  207. esphome/components/opentherm/automation.h +25 -0
  208. esphome/components/opentherm/const.py +1 -0
  209. esphome/components/opentherm/generate.py +39 -6
  210. esphome/components/opentherm/hub.cpp +117 -79
  211. esphome/components/opentherm/hub.h +31 -15
  212. esphome/components/opentherm/opentherm.cpp +47 -23
  213. esphome/components/opentherm/opentherm.h +27 -6
  214. esphome/components/opentherm/opentherm_macros.h +11 -0
  215. esphome/components/opentherm/schema.py +78 -1
  216. esphome/components/opentherm/validate.py +7 -2
  217. esphome/components/pca6416a/pca6416a.h +2 -0
  218. esphome/components/pca9554/pca9554.h +2 -0
  219. esphome/components/pcf8574/pcf8574.h +2 -0
  220. esphome/components/preferences/__init__.py +2 -4
  221. esphome/components/preferences/syncer.h +10 -3
  222. esphome/components/prometheus/prometheus_handler.cpp +313 -0
  223. esphome/components/prometheus/prometheus_handler.h +48 -7
  224. esphome/components/psram/psram.cpp +8 -1
  225. esphome/components/pulse_counter/pulse_counter_sensor.cpp +14 -9
  226. esphome/components/pulse_counter/pulse_counter_sensor.h +4 -4
  227. esphome/components/pulse_meter/pulse_meter_sensor.cpp +2 -0
  228. esphome/components/qspi_dbi/__init__.py +3 -0
  229. esphome/components/qspi_dbi/display.py +74 -47
  230. esphome/components/qspi_dbi/models.py +245 -2
  231. esphome/components/qspi_dbi/qspi_dbi.cpp +9 -16
  232. esphome/components/qspi_dbi/qspi_dbi.h +2 -2
  233. esphome/components/remote_base/__init__.py +77 -25
  234. esphome/components/remote_base/remote_base.cpp +1 -1
  235. esphome/components/remote_base/remote_base.h +20 -2
  236. esphome/components/remote_base/toto_protocol.cpp +100 -0
  237. esphome/components/remote_base/toto_protocol.h +45 -0
  238. esphome/components/remote_receiver/__init__.py +55 -10
  239. esphome/components/remote_receiver/remote_receiver.h +36 -3
  240. esphome/components/remote_receiver/remote_receiver_esp32.cpp +145 -6
  241. esphome/components/remote_transmitter/__init__.py +62 -4
  242. esphome/components/remote_transmitter/remote_transmitter.h +21 -2
  243. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +140 -4
  244. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +3 -3
  245. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +3 -3
  246. esphome/components/resampler/__init__.py +0 -0
  247. esphome/components/resampler/speaker/__init__.py +103 -0
  248. esphome/components/resampler/speaker/resampler_speaker.cpp +318 -0
  249. esphome/components/resampler/speaker/resampler_speaker.h +107 -0
  250. esphome/components/resistance/resistance_sensor.h +2 -3
  251. esphome/components/resistance/sensor.py +2 -9
  252. esphome/components/rotary_encoder/rotary_encoder.cpp +8 -4
  253. esphome/components/rp2040/__init__.py +1 -0
  254. esphome/components/rp2040/gpio.h +1 -0
  255. esphome/components/rtl87xx/__init__.py +2 -0
  256. esphome/components/sdl/binary_sensor.py +270 -0
  257. esphome/components/sdl/sdl_esphome.cpp +16 -0
  258. esphome/components/sdl/sdl_esphome.h +9 -0
  259. esphome/components/seeed_mr60bha2/binary_sensor.py +25 -0
  260. esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +26 -2
  261. esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +9 -20
  262. esphome/components/seeed_mr60bha2/sensor.py +9 -1
  263. esphome/components/sn74hc165/sn74hc165.h +3 -0
  264. esphome/components/sn74hc595/sn74hc595.h +3 -0
  265. esphome/components/speaker/__init__.py +5 -4
  266. esphome/components/speaker/media_player/__init__.py +458 -0
  267. esphome/components/speaker/media_player/audio_pipeline.cpp +568 -0
  268. esphome/components/speaker/media_player/audio_pipeline.h +159 -0
  269. esphome/components/speaker/media_player/automation.h +26 -0
  270. esphome/components/speaker/media_player/speaker_media_player.cpp +577 -0
  271. esphome/components/speaker/media_player/speaker_media_player.h +160 -0
  272. esphome/components/speaker/speaker.h +20 -0
  273. esphome/components/spi/__init__.py +1 -5
  274. esphome/components/spi/spi.cpp +7 -1
  275. esphome/components/spi/spi.h +21 -2
  276. esphome/components/spi_led_strip/light.py +3 -5
  277. esphome/components/spi_led_strip/spi_led_strip.cpp +67 -0
  278. esphome/components/spi_led_strip/spi_led_strip.h +8 -60
  279. esphome/components/sprinkler/sprinkler.cpp +3 -1
  280. esphome/components/sx1509/sx1509_gpio_pin.h +2 -0
  281. esphome/components/tca9555/tca9555.h +2 -0
  282. esphome/components/toshiba/toshiba.cpp +2 -1
  283. esphome/components/tuya/light/tuya_light.cpp +4 -2
  284. esphome/components/uart/uart_component_esp32_arduino.cpp +2 -2
  285. esphome/components/uart/uart_component_esp_idf.cpp +2 -2
  286. esphome/components/udp/__init__.py +8 -2
  287. esphome/components/udp/udp_component.cpp +25 -56
  288. esphome/components/udp/udp_component.h +3 -0
  289. esphome/components/uponor_smatrix/sensor/__init__.py +14 -4
  290. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +5 -0
  291. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.h +1 -0
  292. esphome/components/uptime/text_sensor/__init__.py +19 -0
  293. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +63 -0
  294. esphome/components/uptime/text_sensor/uptime_text_sensor.h +25 -0
  295. esphome/components/voice_assistant/voice_assistant.cpp +24 -14
  296. esphome/components/voice_assistant/voice_assistant.h +8 -0
  297. esphome/components/waveshare_epaper/display.py +22 -1
  298. esphome/components/waveshare_epaper/waveshare_213v3.cpp +9 -3
  299. esphome/components/waveshare_epaper/waveshare_epaper.cpp +1155 -44
  300. esphome/components/waveshare_epaper/waveshare_epaper.h +208 -7
  301. esphome/components/web_server/web_server.cpp +28 -6
  302. esphome/components/weikai/weikai.h +2 -0
  303. esphome/components/wifi/__init__.py +6 -6
  304. esphome/components/wifi/wifi_component.cpp +1 -1
  305. esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -1
  306. esphome/components/wireguard/__init__.py +2 -2
  307. esphome/components/xl9535/xl9535.h +2 -0
  308. esphome/components/xxtea/__init__.py +3 -0
  309. esphome/components/xxtea/xxtea.cpp +46 -0
  310. esphome/components/xxtea/xxtea.h +26 -0
  311. esphome/components/yashima/yashima.cpp +2 -1
  312. esphome/config.py +9 -5
  313. esphome/config_validation.py +55 -17
  314. esphome/const.py +7 -10
  315. esphome/core/__init__.py +6 -13
  316. esphome/core/base_automation.h +1 -0
  317. esphome/core/config.py +57 -72
  318. esphome/core/defines.h +9 -1
  319. esphome/core/gpio.h +7 -0
  320. esphome/core/helpers.cpp +19 -15
  321. esphome/core/helpers.h +57 -8
  322. esphome/core/log.h +9 -7
  323. esphome/cpp_generator.py +2 -2
  324. esphome/espota2.py +3 -2
  325. esphome/loader.py +12 -4
  326. esphome/log.py +5 -7
  327. esphome/yaml_util.py +2 -2
  328. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/METADATA +12 -7
  329. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/RECORD +338 -289
  330. esphome/components/custom/binary_sensor/custom_binary_sensor.cpp +0 -16
  331. esphome/components/custom/binary_sensor/custom_binary_sensor.h +0 -26
  332. esphome/components/custom/climate/custom_climate.h +0 -22
  333. esphome/components/custom/cover/custom_cover.h +0 -21
  334. esphome/components/custom/light/custom_light_output.h +0 -24
  335. esphome/components/custom/output/custom_output.h +0 -37
  336. esphome/components/custom/sensor/custom_sensor.cpp +0 -16
  337. esphome/components/custom/sensor/custom_sensor.h +0 -24
  338. esphome/components/custom/switch/custom_switch.cpp +0 -16
  339. esphome/components/custom/switch/custom_switch.h +0 -24
  340. esphome/components/custom/text_sensor/custom_text_sensor.cpp +0 -16
  341. esphome/components/custom/text_sensor/custom_text_sensor.h +0 -26
  342. esphome/components/custom_component/custom_component.h +0 -28
  343. esphome/components/esp32_ble_server/ble_2901.cpp +0 -18
  344. esphome/components/esp32_ble_server/ble_2901.h +0 -19
  345. esphome/components/resistance_sampler/__init__.py +0 -6
  346. esphome/components/resistance_sampler/resistance_sampler.h +0 -10
  347. esphome/components/uptime/{sensor.py → sensor/__init__.py} +3 -3
  348. /esphome/components/uptime/{uptime_seconds_sensor.cpp → sensor/uptime_seconds_sensor.cpp} +0 -0
  349. /esphome/components/uptime/{uptime_seconds_sensor.h → sensor/uptime_seconds_sensor.h} +0 -0
  350. /esphome/components/uptime/{uptime_timestamp_sensor.cpp → sensor/uptime_timestamp_sensor.cpp} +0 -0
  351. /esphome/components/uptime/{uptime_timestamp_sensor.h → sensor/uptime_timestamp_sensor.h} +0 -0
  352. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/LICENSE +0 -0
  353. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/WHEEL +0 -0
  354. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/entry_points.txt +0 -0
  355. {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,458 @@
1
+ """Speaker Media Player Setup."""
2
+
3
+ import hashlib
4
+ import logging
5
+ from pathlib import Path
6
+
7
+ from esphome import automation, external_files
8
+ import esphome.codegen as cg
9
+ from esphome.components import audio, esp32, media_player, speaker
10
+ import esphome.config_validation as cv
11
+ from esphome.const import (
12
+ CONF_BUFFER_SIZE,
13
+ CONF_FILE,
14
+ CONF_FILES,
15
+ CONF_FORMAT,
16
+ CONF_ID,
17
+ CONF_NUM_CHANNELS,
18
+ CONF_PATH,
19
+ CONF_RAW_DATA_ID,
20
+ CONF_SAMPLE_RATE,
21
+ CONF_SPEAKER,
22
+ CONF_TASK_STACK_IN_PSRAM,
23
+ CONF_TYPE,
24
+ CONF_URL,
25
+ )
26
+ from esphome.core import CORE, HexInt
27
+ from esphome.core.entity_helpers import inherit_property_from
28
+ from esphome.external_files import download_content
29
+
30
+ _LOGGER = logging.getLogger(__name__)
31
+
32
+ AUTO_LOAD = ["audio", "psram"]
33
+
34
+ CODEOWNERS = ["@kahrendt", "@synesthesiam"]
35
+ DOMAIN = "media_player"
36
+
37
+ TYPE_LOCAL = "local"
38
+ TYPE_WEB = "web"
39
+
40
+ CONF_ANNOUNCEMENT = "announcement"
41
+ CONF_ANNOUNCEMENT_PIPELINE = "announcement_pipeline"
42
+ CONF_CODEC_SUPPORT_ENABLED = "codec_support_enabled"
43
+ CONF_ENQUEUE = "enqueue"
44
+ CONF_MEDIA_FILE = "media_file"
45
+ CONF_MEDIA_PIPELINE = "media_pipeline"
46
+ CONF_ON_MUTE = "on_mute"
47
+ CONF_ON_UNMUTE = "on_unmute"
48
+ CONF_ON_VOLUME = "on_volume"
49
+ CONF_STREAM = "stream"
50
+ CONF_VOLUME_INCREMENT = "volume_increment"
51
+ CONF_VOLUME_MIN = "volume_min"
52
+ CONF_VOLUME_MAX = "volume_max"
53
+
54
+
55
+ speaker_ns = cg.esphome_ns.namespace("speaker")
56
+ SpeakerMediaPlayer = speaker_ns.class_(
57
+ "SpeakerMediaPlayer",
58
+ media_player.MediaPlayer,
59
+ cg.Component,
60
+ )
61
+
62
+ AudioPipeline = speaker_ns.class_("AudioPipeline")
63
+ AudioPipelineType = speaker_ns.enum("AudioPipelineType", is_class=True)
64
+ AUDIO_PIPELINE_TYPE_ENUM = {
65
+ "MEDIA": AudioPipelineType.MEDIA,
66
+ "ANNOUNCEMENT": AudioPipelineType.ANNOUNCEMENT,
67
+ }
68
+
69
+ PlayOnDeviceMediaAction = speaker_ns.class_(
70
+ "PlayOnDeviceMediaAction",
71
+ automation.Action,
72
+ cg.Parented.template(SpeakerMediaPlayer),
73
+ )
74
+ StopStreamAction = speaker_ns.class_(
75
+ "StopStreamAction", automation.Action, cg.Parented.template(SpeakerMediaPlayer)
76
+ )
77
+
78
+
79
+ def _compute_local_file_path(value: dict) -> Path:
80
+ url = value[CONF_URL]
81
+ h = hashlib.new("sha256")
82
+ h.update(url.encode())
83
+ key = h.hexdigest()[:8]
84
+ base_dir = external_files.compute_local_file_dir(DOMAIN)
85
+ _LOGGER.debug("_compute_local_file_path: base_dir=%s", base_dir / key)
86
+ return base_dir / key
87
+
88
+
89
+ def _download_web_file(value):
90
+ url = value[CONF_URL]
91
+ path = _compute_local_file_path(value)
92
+
93
+ download_content(url, path)
94
+ _LOGGER.debug("download_web_file: path=%s", path)
95
+ return value
96
+
97
+
98
+ # Returns a media_player.MediaPlayerSupportedFormat struct with the configured
99
+ # format, sample rate, number of channels, purpose, and bytes per sample
100
+ def _get_supported_format_struct(pipeline, type):
101
+ args = [
102
+ media_player.MediaPlayerSupportedFormat,
103
+ ]
104
+
105
+ if pipeline[CONF_FORMAT] == "FLAC":
106
+ args.append(("format", "flac"))
107
+ elif pipeline[CONF_FORMAT] == "MP3":
108
+ args.append(("format", "mp3"))
109
+ elif pipeline[CONF_FORMAT] == "WAV":
110
+ args.append(("format", "wav"))
111
+
112
+ args.append(("sample_rate", pipeline[CONF_SAMPLE_RATE]))
113
+ args.append(("num_channels", pipeline[CONF_NUM_CHANNELS]))
114
+
115
+ if type == "MEDIA":
116
+ args.append(
117
+ (
118
+ "purpose",
119
+ media_player.MEDIA_PLAYER_FORMAT_PURPOSE_ENUM["default"],
120
+ )
121
+ )
122
+ elif type == "ANNOUNCEMENT":
123
+ args.append(
124
+ (
125
+ "purpose",
126
+ media_player.MEDIA_PLAYER_FORMAT_PURPOSE_ENUM["announcement"],
127
+ )
128
+ )
129
+ if pipeline[CONF_FORMAT] != "MP3":
130
+ args.append(("sample_bytes", 2))
131
+
132
+ return cg.StructInitializer(*args)
133
+
134
+
135
+ def _file_schema(value):
136
+ if isinstance(value, str):
137
+ return _validate_file_shorthand(value)
138
+ return TYPED_FILE_SCHEMA(value)
139
+
140
+
141
+ def _read_audio_file_and_type(file_config):
142
+ conf_file = file_config[CONF_FILE]
143
+ file_source = conf_file[CONF_TYPE]
144
+ if file_source == TYPE_LOCAL:
145
+ path = CORE.relative_config_path(conf_file[CONF_PATH])
146
+ elif file_source == TYPE_WEB:
147
+ path = _compute_local_file_path(conf_file)
148
+ else:
149
+ raise cv.Invalid("Unsupported file source.")
150
+
151
+ with open(path, "rb") as f:
152
+ data = f.read()
153
+
154
+ import puremagic
155
+
156
+ file_type: str = puremagic.from_string(data)
157
+ if file_type.startswith("."):
158
+ file_type = file_type[1:]
159
+
160
+ media_file_type = audio.AUDIO_FILE_TYPE_ENUM["NONE"]
161
+ if file_type in ("wav"):
162
+ media_file_type = audio.AUDIO_FILE_TYPE_ENUM["WAV"]
163
+ elif file_type in ("mp3", "mpeg", "mpga"):
164
+ media_file_type = audio.AUDIO_FILE_TYPE_ENUM["MP3"]
165
+ elif file_type in ("flac"):
166
+ media_file_type = audio.AUDIO_FILE_TYPE_ENUM["FLAC"]
167
+
168
+ return data, media_file_type
169
+
170
+
171
+ def _validate_file_shorthand(value):
172
+ value = cv.string_strict(value)
173
+ if value.startswith("http://") or value.startswith("https://"):
174
+ return _file_schema(
175
+ {
176
+ CONF_TYPE: TYPE_WEB,
177
+ CONF_URL: value,
178
+ }
179
+ )
180
+ return _file_schema(
181
+ {
182
+ CONF_TYPE: TYPE_LOCAL,
183
+ CONF_PATH: value,
184
+ }
185
+ )
186
+
187
+
188
+ def _validate_pipeline(config):
189
+ # Inherit transcoder settings from speaker if not manually set
190
+ inherit_property_from(CONF_NUM_CHANNELS, CONF_SPEAKER)(config)
191
+ inherit_property_from(CONF_SAMPLE_RATE, CONF_SPEAKER)(config)
192
+
193
+ # Validate the transcoder settings is compatible with the speaker
194
+ audio.final_validate_audio_schema(
195
+ "speaker media_player",
196
+ audio_device=CONF_SPEAKER,
197
+ bits_per_sample=16,
198
+ channels=config.get(CONF_NUM_CHANNELS),
199
+ sample_rate=config.get(CONF_SAMPLE_RATE),
200
+ )(config)
201
+
202
+ return config
203
+
204
+
205
+ def _validate_repeated_speaker(config):
206
+ if (announcement_config := config.get(CONF_ANNOUNCEMENT_PIPELINE)) and (
207
+ media_config := config.get(CONF_MEDIA_PIPELINE)
208
+ ):
209
+ if announcement_config[CONF_SPEAKER] == media_config[CONF_SPEAKER]:
210
+ raise cv.Invalid(
211
+ "The announcement and media pipelines cannot use the same speaker. Use the `mixer` speaker component to create two source speakers."
212
+ )
213
+
214
+ return config
215
+
216
+
217
+ def _validate_supported_local_file(config):
218
+ for file_config in config.get(CONF_FILES, []):
219
+ _, media_file_type = _read_audio_file_and_type(file_config)
220
+ if str(media_file_type) == str(audio.AUDIO_FILE_TYPE_ENUM["NONE"]):
221
+ raise cv.Invalid("Unsupported local media file.")
222
+ if not config[CONF_CODEC_SUPPORT_ENABLED] and str(media_file_type) != str(
223
+ audio.AUDIO_FILE_TYPE_ENUM["WAV"]
224
+ ):
225
+ # Only wav files are supported
226
+ raise cv.Invalid(
227
+ f"Unsupported local media file type, set {CONF_CODEC_SUPPORT_ENABLED} to true or convert the media file to wav"
228
+ )
229
+
230
+ return config
231
+
232
+
233
+ LOCAL_SCHEMA = cv.Schema(
234
+ {
235
+ cv.Required(CONF_PATH): cv.file_,
236
+ }
237
+ )
238
+
239
+ WEB_SCHEMA = cv.All(
240
+ {
241
+ cv.Required(CONF_URL): cv.url,
242
+ },
243
+ _download_web_file,
244
+ )
245
+
246
+
247
+ TYPED_FILE_SCHEMA = cv.typed_schema(
248
+ {
249
+ TYPE_LOCAL: LOCAL_SCHEMA,
250
+ TYPE_WEB: WEB_SCHEMA,
251
+ },
252
+ )
253
+
254
+
255
+ MEDIA_FILE_TYPE_SCHEMA = cv.Schema(
256
+ {
257
+ cv.Required(CONF_ID): cv.declare_id(audio.AudioFile),
258
+ cv.Required(CONF_FILE): _file_schema,
259
+ cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
260
+ }
261
+ )
262
+
263
+ PIPELINE_SCHEMA = cv.Schema(
264
+ {
265
+ cv.GenerateID(): cv.declare_id(AudioPipeline),
266
+ cv.Required(CONF_SPEAKER): cv.use_id(speaker.Speaker),
267
+ cv.Optional(CONF_FORMAT, default="FLAC"): cv.enum(audio.AUDIO_FILE_TYPE_ENUM),
268
+ cv.Optional(CONF_SAMPLE_RATE): cv.int_range(min=1),
269
+ cv.Optional(CONF_NUM_CHANNELS): cv.int_range(1, 2),
270
+ }
271
+ )
272
+
273
+ CONFIG_SCHEMA = cv.All(
274
+ media_player.MEDIA_PLAYER_SCHEMA.extend(
275
+ {
276
+ cv.GenerateID(): cv.declare_id(SpeakerMediaPlayer),
277
+ cv.Required(CONF_ANNOUNCEMENT_PIPELINE): PIPELINE_SCHEMA,
278
+ cv.Optional(CONF_MEDIA_PIPELINE): PIPELINE_SCHEMA,
279
+ cv.Optional(CONF_BUFFER_SIZE, default=1000000): cv.int_range(
280
+ min=4000, max=4000000
281
+ ),
282
+ cv.Optional(CONF_CODEC_SUPPORT_ENABLED, default=True): cv.boolean,
283
+ cv.Optional(CONF_FILES): cv.ensure_list(MEDIA_FILE_TYPE_SCHEMA),
284
+ cv.Optional(CONF_TASK_STACK_IN_PSRAM, default=False): cv.boolean,
285
+ cv.Optional(CONF_VOLUME_INCREMENT, default=0.05): cv.percentage,
286
+ cv.Optional(CONF_VOLUME_MAX, default=1.0): cv.percentage,
287
+ cv.Optional(CONF_VOLUME_MIN, default=0.0): cv.percentage,
288
+ cv.Optional(CONF_ON_MUTE): automation.validate_automation(single=True),
289
+ cv.Optional(CONF_ON_UNMUTE): automation.validate_automation(single=True),
290
+ cv.Optional(CONF_ON_VOLUME): automation.validate_automation(single=True),
291
+ }
292
+ ),
293
+ cv.only_with_esp_idf,
294
+ _validate_repeated_speaker,
295
+ )
296
+
297
+
298
+ FINAL_VALIDATE_SCHEMA = cv.All(
299
+ cv.Schema(
300
+ {
301
+ cv.Optional(CONF_ANNOUNCEMENT_PIPELINE): _validate_pipeline,
302
+ cv.Optional(CONF_MEDIA_PIPELINE): _validate_pipeline,
303
+ },
304
+ extra=cv.ALLOW_EXTRA,
305
+ ),
306
+ _validate_supported_local_file,
307
+ )
308
+
309
+
310
+ async def to_code(config):
311
+ if config[CONF_CODEC_SUPPORT_ENABLED]:
312
+ # Compile all supported audio codecs and optimize the wifi settings
313
+
314
+ cg.add_define("USE_AUDIO_FLAC_SUPPORT", True)
315
+ cg.add_define("USE_AUDIO_MP3_SUPPORT", True)
316
+
317
+ # Wifi settings based on https://github.com/espressif/esp-adf/issues/297#issuecomment-783811702
318
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM", 16)
319
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM", 512)
320
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_STATIC_TX_BUFFER", True)
321
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_TX_BUFFER_TYPE", 0)
322
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM", 8)
323
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM", 32)
324
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED", True)
325
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_TX_BA_WIN", 16)
326
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED", True)
327
+ esp32.add_idf_sdkconfig_option("CONFIG_ESP32_WIFI_RX_BA_WIN", 32)
328
+ esp32.add_idf_sdkconfig_option("CONFIG_LWIP_MAX_ACTIVE_TCP", 16)
329
+ esp32.add_idf_sdkconfig_option("CONFIG_LWIP_MAX_LISTENING_TCP", 16)
330
+ esp32.add_idf_sdkconfig_option("CONFIG_TCP_MAXRTX", 12)
331
+ esp32.add_idf_sdkconfig_option("CONFIG_TCP_SYNMAXRTX", 6)
332
+ esp32.add_idf_sdkconfig_option("CONFIG_TCP_MSS", 1436)
333
+ esp32.add_idf_sdkconfig_option("CONFIG_TCP_MSL", 60000)
334
+ esp32.add_idf_sdkconfig_option("CONFIG_TCP_SND_BUF_DEFAULT", 65535)
335
+ esp32.add_idf_sdkconfig_option(
336
+ "CONFIG_TCP_WND_DEFAULT", 65535
337
+ ) # Adjusted from referenced settings to avoid compilation error
338
+ esp32.add_idf_sdkconfig_option("CONFIG_TCP_RECVMBOX_SIZE", 512)
339
+ esp32.add_idf_sdkconfig_option("CONFIG_TCP_QUEUE_OOSEQ", True)
340
+ esp32.add_idf_sdkconfig_option("CONFIG_TCP_OVERSIZE_MSS", True)
341
+ esp32.add_idf_sdkconfig_option("CONFIG_LWIP_WND_SCALE", True)
342
+ esp32.add_idf_sdkconfig_option("CONFIG_TCP_RCV_SCALE", 3)
343
+ esp32.add_idf_sdkconfig_option("CONFIG_LWIP_TCPIP_RECVMBOX_SIZE", 512)
344
+
345
+ # Allocate wifi buffers in PSRAM
346
+ esp32.add_idf_sdkconfig_option("CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP", True)
347
+
348
+ var = cg.new_Pvariable(config[CONF_ID])
349
+ await cg.register_component(var, config)
350
+ await media_player.register_media_player(var, config)
351
+
352
+ cg.add_define("USE_OTA_STATE_CALLBACK")
353
+
354
+ cg.add(var.set_buffer_size(config[CONF_BUFFER_SIZE]))
355
+
356
+ cg.add(var.set_task_stack_in_psram(config[CONF_TASK_STACK_IN_PSRAM]))
357
+ if config[CONF_TASK_STACK_IN_PSRAM]:
358
+ esp32.add_idf_sdkconfig_option(
359
+ "CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY", True
360
+ )
361
+
362
+ cg.add(var.set_volume_increment(config[CONF_VOLUME_INCREMENT]))
363
+ cg.add(var.set_volume_max(config[CONF_VOLUME_MAX]))
364
+ cg.add(var.set_volume_min(config[CONF_VOLUME_MIN]))
365
+
366
+ announcement_pipeline_config = config[CONF_ANNOUNCEMENT_PIPELINE]
367
+ spkr = await cg.get_variable(announcement_pipeline_config[CONF_SPEAKER])
368
+ cg.add(var.set_announcement_speaker(spkr))
369
+ if announcement_pipeline_config[CONF_FORMAT] != "NONE":
370
+ cg.add(
371
+ var.set_announcement_format(
372
+ _get_supported_format_struct(
373
+ announcement_pipeline_config, "ANNOUNCEMENT"
374
+ )
375
+ )
376
+ )
377
+
378
+ if media_pipeline_config := config.get(CONF_MEDIA_PIPELINE):
379
+ spkr = await cg.get_variable(media_pipeline_config[CONF_SPEAKER])
380
+ cg.add(var.set_media_speaker(spkr))
381
+ if media_pipeline_config[CONF_FORMAT] != "NONE":
382
+ cg.add(
383
+ var.set_media_format(
384
+ _get_supported_format_struct(media_pipeline_config, "MEDIA")
385
+ )
386
+ )
387
+
388
+ if on_mute := config.get(CONF_ON_MUTE):
389
+ await automation.build_automation(
390
+ var.get_mute_trigger(),
391
+ [],
392
+ on_mute,
393
+ )
394
+ if on_unmute := config.get(CONF_ON_UNMUTE):
395
+ await automation.build_automation(
396
+ var.get_unmute_trigger(),
397
+ [],
398
+ on_unmute,
399
+ )
400
+ if on_volume := config.get(CONF_ON_VOLUME):
401
+ await automation.build_automation(
402
+ var.get_volume_trigger(),
403
+ [(cg.float_, "x")],
404
+ on_volume,
405
+ )
406
+
407
+ for file_config in config.get(CONF_FILES, []):
408
+ data, media_file_type = _read_audio_file_and_type(file_config)
409
+
410
+ rhs = [HexInt(x) for x in data]
411
+ prog_arr = cg.progmem_array(file_config[CONF_RAW_DATA_ID], rhs)
412
+
413
+ media_files_struct = cg.StructInitializer(
414
+ audio.AudioFile,
415
+ (
416
+ "data",
417
+ prog_arr,
418
+ ),
419
+ (
420
+ "length",
421
+ len(rhs),
422
+ ),
423
+ (
424
+ "file_type",
425
+ media_file_type,
426
+ ),
427
+ )
428
+
429
+ cg.new_Pvariable(
430
+ file_config[CONF_ID],
431
+ media_files_struct,
432
+ )
433
+
434
+
435
+ @automation.register_action(
436
+ "media_player.speaker.play_on_device_media_file",
437
+ PlayOnDeviceMediaAction,
438
+ cv.maybe_simple_value(
439
+ {
440
+ cv.GenerateID(): cv.use_id(SpeakerMediaPlayer),
441
+ cv.Required(CONF_MEDIA_FILE): cv.use_id(audio.AudioFile),
442
+ cv.Optional(CONF_ANNOUNCEMENT, default=False): cv.templatable(cv.boolean),
443
+ cv.Optional(CONF_ENQUEUE, default=False): cv.templatable(cv.boolean),
444
+ },
445
+ key=CONF_MEDIA_FILE,
446
+ ),
447
+ )
448
+ async def play_on_device_media_media_action(config, action_id, template_arg, args):
449
+ var = cg.new_Pvariable(action_id, template_arg)
450
+ await cg.register_parented(var, config[CONF_ID])
451
+ media_file = await cg.get_variable(config[CONF_MEDIA_FILE])
452
+ announcement = await cg.templatable(config[CONF_ANNOUNCEMENT], args, cg.bool_)
453
+ enqueue = await cg.templatable(config[CONF_ENQUEUE], args, cg.bool_)
454
+
455
+ cg.add(var.set_audio_file(media_file))
456
+ cg.add(var.set_announcement(announcement))
457
+ cg.add(var.set_enqueue(enqueue))
458
+ return var