esphome 2025.4.2__py3-none-any.whl → 2025.5.0b3__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 (440) hide show
  1. esphome/__main__.py +16 -14
  2. esphome/components/ac_dimmer/ac_dimmer.cpp +3 -2
  3. esphome/components/adc/__init__.py +51 -34
  4. esphome/components/airthings_wave_base/__init__.py +1 -1
  5. esphome/components/alarm_control_panel/__init__.py +37 -2
  6. esphome/components/am43/cover/__init__.py +4 -5
  7. esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp +6 -4
  8. esphome/components/analog_threshold/analog_threshold_binary_sensor.h +4 -5
  9. esphome/components/analog_threshold/binary_sensor.py +10 -8
  10. esphome/components/anova/climate.py +4 -5
  11. esphome/components/api/__init__.py +25 -8
  12. esphome/components/api/api_connection.cpp +81 -13
  13. esphome/components/api/api_connection.h +13 -1
  14. esphome/components/api/api_frame_helper.cpp +232 -177
  15. esphome/components/api/api_frame_helper.h +61 -8
  16. esphome/components/api/api_noise_context.h +13 -4
  17. esphome/components/api/api_pb2.cpp +1422 -1
  18. esphome/components/api/api_pb2.h +255 -1
  19. esphome/components/api/api_pb2_service.cpp +162 -49
  20. esphome/components/api/api_pb2_service.h +90 -51
  21. esphome/components/api/api_pb2_size.h +361 -0
  22. esphome/components/api/api_server.cpp +110 -34
  23. esphome/components/api/api_server.h +8 -0
  24. esphome/components/api/proto.h +86 -17
  25. esphome/components/as7341/as7341.h +1 -1
  26. esphome/components/atm90e32/__init__.py +1 -0
  27. esphome/components/atm90e32/atm90e32.cpp +576 -199
  28. esphome/components/atm90e32/atm90e32.h +128 -31
  29. esphome/components/atm90e32/atm90e32_reg.h +4 -2
  30. esphome/components/atm90e32/button/__init__.py +62 -10
  31. esphome/components/atm90e32/button/atm90e32_button.cpp +63 -4
  32. esphome/components/atm90e32/button/atm90e32_button.h +36 -4
  33. esphome/components/atm90e32/number/__init__.py +130 -0
  34. esphome/components/atm90e32/number/atm90e32_number.h +16 -0
  35. esphome/components/atm90e32/sensor.py +21 -4
  36. esphome/components/atm90e32/text_sensor/__init__.py +48 -0
  37. esphome/components/audio/__init__.py +96 -49
  38. esphome/components/audio/audio.h +48 -0
  39. esphome/components/audio/audio_decoder.cpp +1 -1
  40. esphome/components/audio/audio_resampler.cpp +2 -0
  41. esphome/components/audio/audio_resampler.h +1 -0
  42. esphome/components/ballu/climate.py +2 -9
  43. esphome/components/bang_bang/climate.py +5 -6
  44. esphome/components/bedjet/bedjet_hub.cpp +1 -0
  45. esphome/components/bedjet/climate/__init__.py +3 -8
  46. esphome/components/bedjet/fan/__init__.py +2 -11
  47. esphome/components/binary/fan/__init__.py +13 -16
  48. esphome/components/binary_sensor/__init__.py +13 -10
  49. esphome/components/bl0906/constants.h +16 -16
  50. esphome/components/ble_client/text_sensor/__init__.py +3 -5
  51. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +4 -6
  52. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +136 -21
  53. esphome/components/bluetooth_proxy/bluetooth_proxy.h +7 -0
  54. esphome/components/button/__init__.py +11 -8
  55. esphome/components/canbus/canbus.cpp +3 -0
  56. esphome/components/canbus/canbus.h +16 -0
  57. esphome/components/ccs811/sensor.py +9 -6
  58. esphome/components/climate/__init__.py +35 -2
  59. esphome/components/climate/climate_mode.h +1 -1
  60. esphome/components/climate/climate_traits.h +63 -57
  61. esphome/components/climate_ir/__init__.py +57 -17
  62. esphome/components/climate_ir_lg/climate.py +2 -5
  63. esphome/components/climate_ir_lg/climate_ir_lg.cpp +7 -7
  64. esphome/components/climate_ir_lg/climate_ir_lg.h +1 -1
  65. esphome/components/color/__init__.py +2 -0
  66. esphome/components/const/__init__.py +5 -0
  67. esphome/components/coolix/climate.py +2 -9
  68. esphome/components/copy/cover/__init__.py +10 -9
  69. esphome/components/copy/fan/__init__.py +11 -9
  70. esphome/components/copy/lock/__init__.py +11 -9
  71. esphome/components/copy/text/__init__.py +9 -6
  72. esphome/components/cover/__init__.py +37 -2
  73. esphome/components/cse7766/cse7766.cpp +2 -1
  74. esphome/components/cst226/binary_sensor/__init__.py +28 -0
  75. esphome/components/cst226/binary_sensor/cs226_button.h +22 -0
  76. esphome/components/cst226/binary_sensor/cstt6_button.cpp +19 -0
  77. esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +27 -5
  78. esphome/components/cst226/touchscreen/cst226_touchscreen.h +10 -10
  79. esphome/components/current_based/cover.py +37 -36
  80. esphome/components/current_based/current_based_cover.cpp +2 -1
  81. esphome/components/daikin/climate.py +2 -9
  82. esphome/components/daikin/daikin.cpp +15 -9
  83. esphome/components/daikin/daikin.h +5 -5
  84. esphome/components/daikin_arc/climate.py +2 -7
  85. esphome/components/daikin_brc/climate.py +3 -5
  86. esphome/components/dallas_temp/dallas_temp.cpp +17 -24
  87. esphome/components/dallas_temp/dallas_temp.h +0 -1
  88. esphome/components/daly_bms/daly_bms.cpp +2 -1
  89. esphome/components/debug/debug_component.cpp +6 -1
  90. esphome/components/debug/debug_component.h +6 -0
  91. esphome/components/debug/debug_esp32.cpp +109 -254
  92. esphome/components/debug/sensor.py +14 -0
  93. esphome/components/deep_sleep/deep_sleep_esp32.cpp +13 -1
  94. esphome/components/delonghi/climate.py +2 -9
  95. esphome/components/demo/__init__.py +18 -20
  96. esphome/components/dfrobot_sen0395/switch/__init__.py +21 -22
  97. esphome/components/dps310/sensor.py +6 -6
  98. esphome/components/ee895/sensor.py +9 -9
  99. esphome/components/emmeti/climate.py +2 -9
  100. esphome/components/endstop/cover.py +17 -16
  101. esphome/components/endstop/endstop_cover.cpp +2 -1
  102. esphome/components/ens160_base/__init__.py +12 -9
  103. esphome/components/esp32/__init__.py +60 -3
  104. esphome/components/esp32/core.cpp +11 -5
  105. esphome/components/esp32/gpio.cpp +86 -24
  106. esphome/components/esp32/gpio.py +15 -16
  107. esphome/components/esp32/gpio_esp32.py +1 -2
  108. esphome/components/esp32/gpio_esp32_c2.py +1 -1
  109. esphome/components/esp32/gpio_esp32_c3.py +1 -1
  110. esphome/components/esp32/gpio_esp32_c6.py +1 -1
  111. esphome/components/esp32/gpio_esp32_h2.py +1 -1
  112. esphome/components/esp32_ble/ble.cpp +1 -0
  113. esphome/components/esp32_ble/ble.h +5 -3
  114. esphome/components/esp32_ble/ble_advertising.cpp +2 -1
  115. esphome/components/esp32_ble/ble_advertising.h +1 -0
  116. esphome/components/esp32_ble_server/__init__.py +3 -0
  117. esphome/components/esp32_ble_tracker/__init__.py +7 -1
  118. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +192 -118
  119. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +29 -3
  120. esphome/components/esp32_camera/esp32_camera.cpp +2 -1
  121. esphome/components/esp32_camera/esp32_camera.h +1 -1
  122. esphome/components/esp32_can/esp32_can.cpp +1 -1
  123. esphome/components/esp32_improv/esp32_improv_component.cpp +1 -1
  124. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  125. esphome/components/esp32_rmt_led_strip/led_strip.h +7 -5
  126. esphome/components/esp32_rmt_led_strip/light.py +9 -1
  127. esphome/components/esp32_touch/esp32_touch.cpp +1 -1
  128. esphome/components/esp8266/gpio.cpp +69 -8
  129. esphome/components/ethernet/ethernet_component.cpp +1 -1
  130. esphome/components/event/__init__.py +13 -10
  131. esphome/components/factory_reset/switch/__init__.py +7 -21
  132. esphome/components/fan/__init__.py +52 -5
  133. esphome/components/fastled_base/__init__.py +1 -4
  134. esphome/components/fastled_base/fastled_light.cpp +1 -1
  135. esphome/components/feedback/cover.py +38 -33
  136. esphome/components/feedback/feedback_cover.cpp +2 -1
  137. esphome/components/fujitsu_general/climate.py +2 -9
  138. esphome/components/gcja5/gcja5.cpp +2 -1
  139. esphome/components/gpio/one_wire/gpio_one_wire.cpp +45 -43
  140. esphome/components/gpio/one_wire/gpio_one_wire.h +2 -1
  141. esphome/components/gpio_expander/cached_gpio.h +22 -7
  142. esphome/components/gps/__init__.py +47 -17
  143. esphome/components/gps/gps.cpp +42 -23
  144. esphome/components/gps/gps.h +17 -13
  145. esphome/components/graph/__init__.py +1 -2
  146. esphome/components/gree/climate.py +4 -6
  147. esphome/components/gree/gree.cpp +16 -2
  148. esphome/components/gree/gree.h +2 -2
  149. esphome/components/growatt_solar/growatt_solar.cpp +2 -1
  150. esphome/components/haier/climate.py +37 -34
  151. esphome/components/hbridge/fan/__init__.py +19 -17
  152. esphome/components/he60r/cover.py +4 -5
  153. esphome/components/heatpumpir/climate.py +3 -6
  154. esphome/components/hitachi_ac344/climate.py +2 -9
  155. esphome/components/hitachi_ac424/climate.py +2 -9
  156. esphome/components/hm3301/hm3301.h +1 -1
  157. esphome/components/hte501/sensor.py +6 -6
  158. esphome/components/http_request/__init__.py +39 -6
  159. esphome/components/http_request/http_request.cpp +20 -0
  160. esphome/components/http_request/http_request.h +57 -15
  161. esphome/components/http_request/http_request_arduino.cpp +22 -6
  162. esphome/components/http_request/http_request_arduino.h +4 -3
  163. esphome/components/http_request/http_request_host.cpp +141 -0
  164. esphome/components/http_request/http_request_host.h +37 -0
  165. esphome/components/http_request/http_request_idf.cpp +35 -3
  166. esphome/components/http_request/http_request_idf.h +10 -3
  167. esphome/components/http_request/httplib.h +9691 -0
  168. esphome/components/http_request/update/__init__.py +11 -8
  169. esphome/components/hyt271/sensor.py +6 -6
  170. esphome/components/i2c/i2c.h +4 -0
  171. esphome/components/i2c/i2c_bus_esp_idf.cpp +1 -1
  172. esphome/components/i2s_audio/__init__.py +131 -22
  173. esphome/components/i2s_audio/i2s_audio.h +44 -4
  174. esphome/components/i2s_audio/media_player/__init__.py +19 -9
  175. esphome/components/i2s_audio/microphone/__init__.py +63 -5
  176. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +351 -61
  177. esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +40 -6
  178. esphome/components/i2s_audio/speaker/__init__.py +31 -5
  179. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +155 -19
  180. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +17 -4
  181. esphome/components/ili9xxx/ili9xxx_init.h +1 -1
  182. esphome/components/image/__init__.py +37 -17
  183. esphome/components/image/image.cpp +25 -8
  184. esphome/components/internal_temperature/internal_temperature.cpp +6 -4
  185. esphome/components/key_collector/__init__.py +35 -0
  186. esphome/components/key_collector/key_collector.cpp +8 -0
  187. esphome/components/key_collector/key_collector.h +10 -0
  188. esphome/components/kuntze/kuntze.cpp +2 -1
  189. esphome/components/ld2410/ld2410.h +1 -1
  190. esphome/components/ld2450/ld2450.h +1 -1
  191. esphome/components/light/__init__.py +57 -0
  192. esphome/components/lock/__init__.py +51 -4
  193. esphome/components/lock/automation.h +2 -13
  194. esphome/components/logger/__init__.py +22 -0
  195. esphome/components/logger/logger.cpp +154 -103
  196. esphome/components/logger/logger.h +211 -36
  197. esphome/components/logger/task_log_buffer.cpp +138 -0
  198. esphome/components/logger/task_log_buffer.h +69 -0
  199. esphome/components/lvgl/__init__.py +13 -5
  200. esphome/components/lvgl/automation.py +50 -1
  201. esphome/components/lvgl/defines.py +0 -1
  202. esphome/components/lvgl/lvgl_esphome.cpp +5 -1
  203. esphome/components/lvgl/text/__init__.py +1 -2
  204. esphome/components/mapping/__init__.py +134 -0
  205. esphome/components/matrix_keypad/matrix_keypad.cpp +2 -1
  206. esphome/components/max7219digit/max7219digit.cpp +28 -27
  207. esphome/components/mdns/__init__.py +11 -5
  208. esphome/components/mdns/mdns_component.cpp +11 -5
  209. esphome/components/mdns/mdns_component.h +3 -2
  210. esphome/components/mdns/mdns_esp32.cpp +4 -3
  211. esphome/components/mdns/mdns_esp8266.cpp +4 -2
  212. esphome/components/mdns/mdns_libretiny.cpp +4 -2
  213. esphome/components/mdns/mdns_rp2040.cpp +4 -2
  214. esphome/components/media_player/__init__.py +33 -1
  215. esphome/components/mhz19/sensor.py +11 -7
  216. esphome/components/micro_wake_word/__init__.py +99 -31
  217. esphome/components/micro_wake_word/automation.h +54 -0
  218. esphome/components/micro_wake_word/micro_wake_word.cpp +331 -319
  219. esphome/components/micro_wake_word/micro_wake_word.h +58 -105
  220. esphome/components/micro_wake_word/preprocessor_settings.h +19 -2
  221. esphome/components/micro_wake_word/streaming_model.cpp +158 -41
  222. esphome/components/micro_wake_word/streaming_model.h +85 -13
  223. esphome/components/microphone/__init__.py +139 -9
  224. esphome/components/microphone/automation.h +14 -2
  225. esphome/components/microphone/microphone.cpp +21 -0
  226. esphome/components/microphone/microphone.h +14 -5
  227. esphome/components/microphone/microphone_source.cpp +95 -0
  228. esphome/components/microphone/microphone_source.h +80 -0
  229. esphome/components/mics_4514/sensor.py +25 -14
  230. esphome/components/midea/climate.py +3 -4
  231. esphome/components/midea_ir/climate.py +3 -5
  232. esphome/components/mipi_spi/__init__.py +15 -0
  233. esphome/components/mipi_spi/display.py +474 -0
  234. esphome/components/mipi_spi/mipi_spi.cpp +481 -0
  235. esphome/components/mipi_spi/mipi_spi.h +171 -0
  236. esphome/components/mipi_spi/models/__init__.py +65 -0
  237. esphome/components/mipi_spi/models/amoled.py +72 -0
  238. esphome/components/mipi_spi/models/commands.py +82 -0
  239. esphome/components/mipi_spi/models/cyd.py +10 -0
  240. esphome/components/mipi_spi/models/ili.py +749 -0
  241. esphome/components/mipi_spi/models/jc.py +260 -0
  242. esphome/components/mipi_spi/models/lanbon.py +15 -0
  243. esphome/components/mipi_spi/models/lilygo.py +60 -0
  244. esphome/components/mipi_spi/models/waveshare.py +139 -0
  245. esphome/components/mitsubishi/climate.py +2 -5
  246. esphome/components/mitsubishi/mitsubishi.cpp +9 -9
  247. esphome/components/mixer/speaker/mixer_speaker.cpp +12 -22
  248. esphome/components/mixer/speaker/mixer_speaker.h +1 -3
  249. esphome/components/mlx90393/sensor.py +5 -0
  250. esphome/components/mlx90393/sensor_mlx90393.cpp +195 -13
  251. esphome/components/mlx90393/sensor_mlx90393.h +21 -4
  252. esphome/components/modbus/modbus.cpp +2 -1
  253. esphome/components/mqtt/__init__.py +1 -1
  254. esphome/components/mqtt/mqtt_client.cpp +6 -2
  255. esphome/components/mqtt/mqtt_const.h +4 -0
  256. esphome/components/mqtt/mqtt_fan.cpp +39 -0
  257. esphome/components/mqtt/mqtt_fan.h +2 -0
  258. esphome/components/ms5611/sensor.py +6 -6
  259. esphome/components/ms8607/sensor.py +3 -3
  260. esphome/components/network/__init__.py +1 -1
  261. esphome/components/nextion/base_component.py +17 -16
  262. esphome/components/nextion/display.py +11 -2
  263. esphome/components/nextion/nextion.cpp +39 -1
  264. esphome/components/nextion/nextion.h +50 -0
  265. esphome/components/noblex/climate.py +2 -9
  266. esphome/components/number/__init__.py +12 -9
  267. esphome/components/one_wire/one_wire_bus.cpp +14 -10
  268. esphome/components/one_wire/one_wire_bus.h +14 -8
  269. esphome/components/online_image/bmp_image.cpp +48 -11
  270. esphome/components/online_image/bmp_image.h +2 -0
  271. esphome/components/opentherm/binary_sensor/__init__.py +2 -4
  272. esphome/components/opentherm/number/__init__.py +11 -20
  273. esphome/components/opentherm/sensor/__init__.py +3 -3
  274. esphome/components/opentherm/switch/__init__.py +3 -5
  275. esphome/components/output/lock/__init__.py +11 -9
  276. esphome/components/packages/__init__.py +33 -31
  277. esphome/components/packet_transport/__init__.py +201 -0
  278. esphome/components/packet_transport/binary_sensor.py +19 -0
  279. esphome/components/packet_transport/packet_transport.cpp +534 -0
  280. esphome/components/packet_transport/packet_transport.h +154 -0
  281. esphome/components/packet_transport/sensor.py +19 -0
  282. esphome/components/pca9685/pca9685_output.cpp +2 -1
  283. esphome/components/pid/climate.py +2 -4
  284. esphome/components/pm2005/__init__.py +1 -0
  285. esphome/components/pm2005/pm2005.cpp +123 -0
  286. esphome/components/pm2005/pm2005.h +46 -0
  287. esphome/components/pm2005/sensor.py +86 -0
  288. esphome/components/pmsa003i/pmsa003i.cpp +43 -16
  289. esphome/components/pmsa003i/pmsa003i.h +25 -25
  290. esphome/components/pmsx003/pmsx003.cpp +195 -230
  291. esphome/components/pmsx003/pmsx003.h +51 -33
  292. esphome/components/pmsx003/sensor.py +21 -11
  293. esphome/components/pn7150/pn7150.h +2 -2
  294. esphome/components/pn7160/pn7160.h +2 -2
  295. esphome/components/prometheus/prometheus_handler.cpp +174 -0
  296. esphome/components/prometheus/prometheus_handler.h +17 -0
  297. esphome/components/psram/__init__.py +7 -5
  298. esphome/components/pulse_meter/pulse_meter_sensor.cpp +32 -12
  299. esphome/components/pulse_meter/pulse_meter_sensor.h +5 -5
  300. esphome/components/pzem004t/pzem004t.cpp +2 -1
  301. esphome/components/qspi_dbi/__init__.py +0 -1
  302. esphome/components/qspi_dbi/display.py +2 -1
  303. esphome/components/qspi_dbi/models.py +1 -2
  304. esphome/components/remote_base/__init__.py +91 -0
  305. esphome/components/remote_base/beo4_protocol.cpp +153 -0
  306. esphome/components/remote_base/beo4_protocol.h +43 -0
  307. esphome/components/remote_base/gobox_protocol.cpp +131 -0
  308. esphome/components/remote_base/gobox_protocol.h +54 -0
  309. esphome/components/remote_receiver/remote_receiver_esp32.cpp +16 -9
  310. esphome/components/resampler/speaker/resampler_speaker.cpp +12 -10
  311. esphome/components/resampler/speaker/resampler_speaker.h +1 -1
  312. esphome/components/rf_bridge/rf_bridge.cpp +2 -1
  313. esphome/components/scd30/sensor.py +2 -3
  314. esphome/components/scd4x/sensor.py +4 -5
  315. esphome/components/sdp3x/sensor.py +2 -1
  316. esphome/components/sds011/sds011.cpp +2 -1
  317. esphome/components/select/__init__.py +19 -20
  318. esphome/components/sen5x/sen5x.cpp +55 -36
  319. esphome/components/sen5x/sensor.py +1 -1
  320. esphome/components/senseair/sensor.py +3 -3
  321. esphome/components/sensor/__init__.py +158 -14
  322. esphome/components/sensor/filter.cpp +23 -0
  323. esphome/components/sensor/filter.h +22 -0
  324. esphome/components/sgp30/sensor.py +14 -16
  325. esphome/components/sgp4x/sensor.py +1 -1
  326. esphome/components/sht4x/sht4x.cpp +43 -22
  327. esphome/components/sht4x/sht4x.h +1 -1
  328. esphome/components/shtcx/sensor.py +6 -6
  329. esphome/components/slow_pwm/slow_pwm_output.cpp +2 -1
  330. esphome/components/sml/text_sensor/__init__.py +4 -6
  331. esphome/components/sound_level/__init__.py +0 -0
  332. esphome/components/sound_level/sensor.py +97 -0
  333. esphome/components/sound_level/sound_level.cpp +194 -0
  334. esphome/components/sound_level/sound_level.h +73 -0
  335. esphome/components/speaker/media_player/__init__.py +4 -8
  336. esphome/components/speaker/media_player/speaker_media_player.cpp +0 -18
  337. esphome/components/speaker/media_player/speaker_media_player.h +0 -11
  338. esphome/components/speaker/speaker.h +4 -7
  339. esphome/components/speed/fan/__init__.py +17 -16
  340. esphome/components/spi/spi.h +11 -1
  341. esphome/components/sprinkler/__init__.py +18 -19
  342. esphome/components/sprinkler/sprinkler.cpp +6 -5
  343. esphome/components/switch/__init__.py +32 -42
  344. esphome/components/syslog/__init__.py +41 -0
  345. esphome/components/syslog/esphome_syslog.cpp +49 -0
  346. esphome/components/syslog/esphome_syslog.h +27 -0
  347. esphome/components/t6615/sensor.py +3 -3
  348. esphome/components/t6615/t6615.cpp +2 -1
  349. esphome/components/tca9555/tca9555.cpp +11 -6
  350. esphome/components/tcl112/climate.py +2 -9
  351. esphome/components/template/alarm_control_panel/__init__.py +7 -6
  352. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +21 -17
  353. esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +2 -1
  354. esphome/components/template/cover/__init__.py +27 -21
  355. esphome/components/template/fan/__init__.py +14 -12
  356. esphome/components/template/lock/__init__.py +20 -25
  357. esphome/components/template/lock/automation.h +18 -0
  358. esphome/components/template/text/__init__.py +4 -3
  359. esphome/components/template/valve/__init__.py +32 -21
  360. esphome/components/template/valve/automation.h +24 -0
  361. esphome/components/text/__init__.py +32 -1
  362. esphome/components/text_sensor/__init__.py +24 -29
  363. esphome/components/thermostat/climate.py +5 -5
  364. esphome/components/time_based/cover.py +17 -16
  365. esphome/components/time_based/time_based_cover.cpp +2 -1
  366. esphome/components/tm1638/switch/__init__.py +10 -7
  367. esphome/components/tormatic/cover.py +4 -5
  368. esphome/components/toshiba/climate.py +3 -5
  369. esphome/components/touchscreen/touchscreen.cpp +3 -1
  370. esphome/components/tuya/climate/__init__.py +5 -6
  371. esphome/components/tuya/cover/__init__.py +6 -11
  372. esphome/components/tuya/select/__init__.py +15 -5
  373. esphome/components/tuya/select/tuya_select.cpp +6 -1
  374. esphome/components/tuya/select/tuya_select.h +5 -1
  375. esphome/components/uart/packet_transport/__init__.py +20 -0
  376. esphome/components/uart/packet_transport/uart_transport.cpp +88 -0
  377. esphome/components/uart/packet_transport/uart_transport.h +41 -0
  378. esphome/components/uart/switch/uart_switch.cpp +2 -1
  379. esphome/components/udp/__init__.py +126 -128
  380. esphome/components/udp/automation.h +40 -0
  381. esphome/components/udp/binary_sensor.py +3 -25
  382. esphome/components/udp/packet_transport/__init__.py +29 -0
  383. esphome/components/udp/packet_transport/udp_transport.cpp +36 -0
  384. esphome/components/udp/packet_transport/udp_transport.h +28 -0
  385. esphome/components/udp/sensor.py +3 -25
  386. esphome/components/udp/udp_component.cpp +26 -470
  387. esphome/components/udp/udp_component.h +21 -128
  388. esphome/components/update/__init__.py +31 -1
  389. esphome/components/uponor_smatrix/climate/__init__.py +4 -9
  390. esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +2 -1
  391. esphome/components/uponor_smatrix/uponor_smatrix.cpp +2 -1
  392. esphome/components/uptime/text_sensor/__init__.py +47 -7
  393. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +12 -7
  394. esphome/components/uptime/text_sensor/uptime_text_sensor.h +19 -0
  395. esphome/components/valve/__init__.py +34 -3
  396. esphome/components/valve/automation.h +1 -19
  397. esphome/components/vl53l0x/sensor.py +11 -0
  398. esphome/components/vl53l0x/vl53l0x_sensor.cpp +5 -1
  399. esphome/components/vl53l0x/vl53l0x_sensor.h +2 -1
  400. esphome/components/voice_assistant/__init__.py +36 -10
  401. esphome/components/voice_assistant/voice_assistant.cpp +170 -144
  402. esphome/components/voice_assistant/voice_assistant.h +26 -25
  403. esphome/components/waveshare_epaper/display.py +6 -0
  404. esphome/components/waveshare_epaper/waveshare_epaper.cpp +439 -37
  405. esphome/components/waveshare_epaper/waveshare_epaper.h +60 -11
  406. esphome/components/whirlpool/climate.py +3 -5
  407. esphome/components/whynter/climate.py +3 -5
  408. esphome/components/xpt2046/touchscreen/xpt2046.cpp +1 -1
  409. esphome/components/yashima/climate.py +6 -6
  410. esphome/components/zhlt01/climate.py +2 -7
  411. esphome/config.py +13 -13
  412. esphome/config_validation.py +38 -58
  413. esphome/const.py +15 -1
  414. esphome/core/__init__.py +2 -0
  415. esphome/core/application.cpp +23 -10
  416. esphome/core/application.h +9 -1
  417. esphome/core/automation.h +4 -3
  418. esphome/core/component.cpp +28 -7
  419. esphome/core/component.h +10 -1
  420. esphome/core/defines.h +23 -17
  421. esphome/core/macros.h +4 -0
  422. esphome/core/scheduler.cpp +7 -1
  423. esphome/cpp_generator.py +6 -2
  424. esphome/dashboard/web_server.py +3 -3
  425. esphome/helpers.py +39 -0
  426. esphome/loader.py +4 -0
  427. esphome/log.py +15 -19
  428. esphome/mqtt.py +23 -10
  429. esphome/platformio_api.py +1 -1
  430. esphome/schema_extractors.py +0 -1
  431. esphome/voluptuous_schema.py +3 -1
  432. esphome/vscode.py +15 -0
  433. esphome/wizard.py +47 -37
  434. esphome/zeroconf.py +7 -3
  435. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/METADATA +10 -11
  436. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/RECORD +440 -380
  437. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/WHEEL +1 -1
  438. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/entry_points.txt +0 -0
  439. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/licenses/LICENSE +0 -0
  440. {esphome-2025.4.2.dist-info → esphome-2025.5.0b3.dist-info}/top_level.txt +0 -0
@@ -16,14 +16,17 @@ HttpRequestUpdate = http_request_ns.class_(
16
16
 
17
17
  CONF_OTA_ID = "ota_id"
18
18
 
19
- CONFIG_SCHEMA = update.UPDATE_SCHEMA.extend(
20
- {
21
- cv.GenerateID(): cv.declare_id(HttpRequestUpdate),
22
- cv.GenerateID(CONF_OTA_ID): cv.use_id(OtaHttpRequestComponent),
23
- cv.GenerateID(CONF_HTTP_REQUEST_ID): cv.use_id(HttpRequestComponent),
24
- cv.Required(CONF_SOURCE): cv.url,
25
- }
26
- ).extend(cv.polling_component_schema("6h"))
19
+ CONFIG_SCHEMA = (
20
+ update.update_schema(HttpRequestUpdate)
21
+ .extend(
22
+ {
23
+ cv.GenerateID(CONF_OTA_ID): cv.use_id(OtaHttpRequestComponent),
24
+ cv.GenerateID(CONF_HTTP_REQUEST_ID): cv.use_id(HttpRequestComponent),
25
+ cv.Required(CONF_SOURCE): cv.url,
26
+ }
27
+ )
28
+ .extend(cv.polling_component_schema("6h"))
29
+ )
27
30
 
28
31
 
29
32
  async def to_code(config):
@@ -23,13 +23,13 @@ CONFIG_SCHEMA = (
23
23
  cv.Schema(
24
24
  {
25
25
  cv.GenerateID(): cv.declare_id(HYT271Component),
26
- cv.Required(CONF_TEMPERATURE): sensor.sensor_schema(
26
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
27
27
  unit_of_measurement=UNIT_CELSIUS,
28
28
  accuracy_decimals=1,
29
29
  device_class=DEVICE_CLASS_TEMPERATURE,
30
30
  state_class=STATE_CLASS_MEASUREMENT,
31
31
  ),
32
- cv.Required(CONF_HUMIDITY): sensor.sensor_schema(
32
+ cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
33
33
  unit_of_measurement=UNIT_PERCENT,
34
34
  accuracy_decimals=1,
35
35
  device_class=DEVICE_CLASS_HUMIDITY,
@@ -47,10 +47,10 @@ async def to_code(config):
47
47
  await cg.register_component(var, config)
48
48
  await i2c.register_i2c_device(var, config)
49
49
 
50
- if CONF_TEMPERATURE in config:
51
- sens = await sensor.new_sensor(config[CONF_TEMPERATURE])
50
+ if temperature := config.get(CONF_TEMPERATURE):
51
+ sens = await sensor.new_sensor(temperature)
52
52
  cg.add(var.set_temperature(sens))
53
53
 
54
- if CONF_HUMIDITY in config:
55
- sens = await sensor.new_sensor(config[CONF_HUMIDITY])
54
+ if humidity := config.get(CONF_HUMIDITY):
55
+ sens = await sensor.new_sensor(humidity)
56
56
  cg.add(var.set_humidity(sens))
@@ -139,6 +139,10 @@ class I2CDevice {
139
139
  /// @param address of the device
140
140
  void set_i2c_address(uint8_t address) { address_ = address; }
141
141
 
142
+ /// @brief Returns the I2C address of the object.
143
+ /// @return the I2C address
144
+ uint8_t get_i2c_address() const { return this->address_; }
145
+
142
146
  /// @brief we store the pointer to the I2CBus to use
143
147
  /// @param bus pointer to the I2CBus object
144
148
  void set_i2c_bus(I2CBus *bus) { bus_ = bus; }
@@ -67,7 +67,7 @@ void IDFI2CBus::setup() {
67
67
  ESP_LOGV(TAG, "i2c_timeout set to %" PRIu32 " ticks (%" PRIu32 " us)", timeout_ * 80, timeout_);
68
68
  }
69
69
  }
70
- err = i2c_driver_install(port_, I2C_MODE_MASTER, 0, 0, ESP_INTR_FLAG_IRAM);
70
+ err = i2c_driver_install(port_, I2C_MODE_MASTER, 0, 0, 0);
71
71
  if (err != ESP_OK) {
72
72
  ESP_LOGW(TAG, "i2c_driver_install failed: %s", esp_err_to_name(err));
73
73
  this->mark_failed();
@@ -8,7 +8,15 @@ from esphome.components.esp32.const import (
8
8
  VARIANT_ESP32S3,
9
9
  )
10
10
  import esphome.config_validation as cv
11
- from esphome.const import CONF_BITS_PER_SAMPLE, CONF_CHANNEL, CONF_ID, CONF_SAMPLE_RATE
11
+ from esphome.const import (
12
+ CONF_BITS_PER_SAMPLE,
13
+ CONF_CHANNEL,
14
+ CONF_ID,
15
+ CONF_SAMPLE_RATE,
16
+ KEY_CORE,
17
+ KEY_FRAMEWORK_VERSION,
18
+ )
19
+ from esphome.core import CORE
12
20
  from esphome.cpp_generator import MockObjClass
13
21
  import esphome.final_validate as fv
14
22
 
@@ -31,10 +39,14 @@ CONF_SECONDARY = "secondary"
31
39
 
32
40
  CONF_USE_APLL = "use_apll"
33
41
  CONF_BITS_PER_CHANNEL = "bits_per_channel"
42
+ CONF_MCLK_MULTIPLE = "mclk_multiple"
34
43
  CONF_MONO = "mono"
35
44
  CONF_LEFT = "left"
36
45
  CONF_RIGHT = "right"
37
46
  CONF_STEREO = "stereo"
47
+ CONF_BOTH = "both"
48
+
49
+ CONF_USE_LEGACY = "use_legacy"
38
50
 
39
51
  i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio")
40
52
  I2SAudioComponent = i2s_audio_ns.class_("I2SAudioComponent", cg.Component)
@@ -50,6 +62,12 @@ I2S_MODE_OPTIONS = {
50
62
  CONF_SECONDARY: i2s_mode_t.I2S_MODE_SLAVE, # NOLINT
51
63
  }
52
64
 
65
+ i2s_role_t = cg.global_ns.enum("i2s_role_t")
66
+ I2S_ROLE_OPTIONS = {
67
+ CONF_PRIMARY: i2s_role_t.I2S_ROLE_MASTER, # NOLINT
68
+ CONF_SECONDARY: i2s_role_t.I2S_ROLE_SLAVE, # NOLINT
69
+ }
70
+
53
71
  # https://github.com/espressif/esp-idf/blob/master/components/soc/{variant}/include/soc/soc_caps.h
54
72
  I2S_PORTS = {
55
73
  VARIANT_ESP32: 2,
@@ -60,10 +78,23 @@ I2S_PORTS = {
60
78
 
61
79
  i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t")
62
80
  I2S_CHANNELS = {
63
- CONF_MONO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ALL_LEFT,
64
- CONF_LEFT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_LEFT,
65
- CONF_RIGHT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_RIGHT,
66
- CONF_STEREO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_RIGHT_LEFT,
81
+ CONF_MONO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ALL_LEFT, # left data to both channels
82
+ CONF_LEFT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_LEFT, # mono data
83
+ CONF_RIGHT: i2s_channel_fmt_t.I2S_CHANNEL_FMT_ONLY_RIGHT, # mono data
84
+ CONF_STEREO: i2s_channel_fmt_t.I2S_CHANNEL_FMT_RIGHT_LEFT, # stereo data to both channels
85
+ }
86
+
87
+ i2s_slot_mode_t = cg.global_ns.enum("i2s_slot_mode_t")
88
+ I2S_SLOT_MODE = {
89
+ CONF_MONO: i2s_slot_mode_t.I2S_SLOT_MODE_MONO,
90
+ CONF_STEREO: i2s_slot_mode_t.I2S_SLOT_MODE_STEREO,
91
+ }
92
+
93
+ i2s_std_slot_mask_t = cg.global_ns.enum("i2s_std_slot_mask_t")
94
+ I2S_STD_SLOT_MASK = {
95
+ CONF_LEFT: i2s_std_slot_mask_t.I2S_STD_SLOT_LEFT,
96
+ CONF_RIGHT: i2s_std_slot_mask_t.I2S_STD_SLOT_RIGHT,
97
+ CONF_BOTH: i2s_std_slot_mask_t.I2S_STD_SLOT_BOTH,
67
98
  }
68
99
 
69
100
  i2s_bits_per_sample_t = cg.global_ns.enum("i2s_bits_per_sample_t")
@@ -83,9 +114,37 @@ I2S_BITS_PER_CHANNEL = {
83
114
  32: i2s_bits_per_chan_t.I2S_BITS_PER_CHAN_32BIT,
84
115
  }
85
116
 
117
+ i2s_slot_bit_width_t = cg.global_ns.enum("i2s_slot_bit_width_t")
118
+ I2S_SLOT_BIT_WIDTH = {
119
+ "default": i2s_slot_bit_width_t.I2S_SLOT_BIT_WIDTH_AUTO,
120
+ 8: i2s_slot_bit_width_t.I2S_SLOT_BIT_WIDTH_8BIT,
121
+ 16: i2s_slot_bit_width_t.I2S_SLOT_BIT_WIDTH_16BIT,
122
+ 24: i2s_slot_bit_width_t.I2S_SLOT_BIT_WIDTH_24BIT,
123
+ 32: i2s_slot_bit_width_t.I2S_SLOT_BIT_WIDTH_32BIT,
124
+ }
125
+
126
+ i2s_mclk_multiple_t = cg.global_ns.enum("i2s_mclk_multiple_t")
127
+ I2S_MCLK_MULTIPLE = {
128
+ 128: i2s_mclk_multiple_t.I2S_MCLK_MULTIPLE_128,
129
+ 256: i2s_mclk_multiple_t.I2S_MCLK_MULTIPLE_256,
130
+ 384: i2s_mclk_multiple_t.I2S_MCLK_MULTIPLE_384,
131
+ 512: i2s_mclk_multiple_t.I2S_MCLK_MULTIPLE_512,
132
+ }
133
+
86
134
  _validate_bits = cv.float_with_unit("bits", "bit")
87
135
 
88
136
 
137
+ def validate_mclk_divisible_by_3(config):
138
+ if config[CONF_BITS_PER_SAMPLE] == 24 and config[CONF_MCLK_MULTIPLE] % 3 != 0:
139
+ raise cv.Invalid(
140
+ f"{CONF_MCLK_MULTIPLE} must be divisible by 3 when bits per sample is 24"
141
+ )
142
+ return config
143
+
144
+
145
+ _use_legacy_driver = None
146
+
147
+
89
148
  def i2s_audio_component_schema(
90
149
  class_: MockObjClass,
91
150
  *,
@@ -97,43 +156,83 @@ def i2s_audio_component_schema(
97
156
  {
98
157
  cv.GenerateID(): cv.declare_id(class_),
99
158
  cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent),
100
- cv.Optional(CONF_CHANNEL, default=default_channel): cv.enum(I2S_CHANNELS),
159
+ cv.Optional(CONF_CHANNEL, default=default_channel): cv.one_of(
160
+ *I2S_CHANNELS
161
+ ),
101
162
  cv.Optional(CONF_SAMPLE_RATE, default=default_sample_rate): cv.int_range(
102
163
  min=1
103
164
  ),
104
165
  cv.Optional(CONF_BITS_PER_SAMPLE, default=default_bits_per_sample): cv.All(
105
- _validate_bits, cv.enum(I2S_BITS_PER_SAMPLE)
166
+ _validate_bits, cv.one_of(*I2S_BITS_PER_SAMPLE)
106
167
  ),
107
- cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.enum(
108
- I2S_MODE_OPTIONS, lower=True
168
+ cv.Optional(CONF_I2S_MODE, default=CONF_PRIMARY): cv.one_of(
169
+ *I2S_MODE_OPTIONS, lower=True
109
170
  ),
110
171
  cv.Optional(CONF_USE_APLL, default=False): cv.boolean,
111
172
  cv.Optional(CONF_BITS_PER_CHANNEL, default="default"): cv.All(
112
173
  cv.Any(cv.float_with_unit("bits", "bit"), "default"),
113
- cv.enum(I2S_BITS_PER_CHANNEL),
174
+ cv.one_of(*I2S_BITS_PER_CHANNEL),
114
175
  ),
176
+ cv.Optional(CONF_MCLK_MULTIPLE, default=256): cv.one_of(*I2S_MCLK_MULTIPLE),
115
177
  }
116
178
  )
117
179
 
118
180
 
119
181
  async def register_i2s_audio_component(var, config):
120
182
  await cg.register_parented(var, config[CONF_I2S_AUDIO_ID])
121
-
122
- cg.add(var.set_i2s_mode(config[CONF_I2S_MODE]))
123
- cg.add(var.set_channel(config[CONF_CHANNEL]))
183
+ if use_legacy():
184
+ cg.add(var.set_i2s_mode(I2S_MODE_OPTIONS[config[CONF_I2S_MODE]]))
185
+ cg.add(var.set_channel(I2S_CHANNELS[config[CONF_CHANNEL]]))
186
+ cg.add(
187
+ var.set_bits_per_sample(I2S_BITS_PER_SAMPLE[config[CONF_BITS_PER_SAMPLE]])
188
+ )
189
+ cg.add(
190
+ var.set_bits_per_channel(
191
+ I2S_BITS_PER_CHANNEL[config[CONF_BITS_PER_CHANNEL]]
192
+ )
193
+ )
194
+ else:
195
+ cg.add(var.set_i2s_role(I2S_ROLE_OPTIONS[config[CONF_I2S_MODE]]))
196
+ slot_mode = config[CONF_CHANNEL]
197
+ if slot_mode != CONF_STEREO:
198
+ slot_mode = CONF_MONO
199
+ slot_mask = config[CONF_CHANNEL]
200
+ if slot_mask not in [CONF_LEFT, CONF_RIGHT]:
201
+ slot_mask = CONF_BOTH
202
+ cg.add(var.set_slot_mode(I2S_SLOT_MODE[slot_mode]))
203
+ cg.add(var.set_std_slot_mask(I2S_STD_SLOT_MASK[slot_mask]))
204
+ cg.add(var.set_slot_bit_width(I2S_SLOT_BIT_WIDTH[config[CONF_BITS_PER_SAMPLE]]))
124
205
  cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))
125
- cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE]))
126
- cg.add(var.set_bits_per_channel(config[CONF_BITS_PER_CHANNEL]))
127
206
  cg.add(var.set_use_apll(config[CONF_USE_APLL]))
207
+ cg.add(var.set_mclk_multiple(I2S_MCLK_MULTIPLE[config[CONF_MCLK_MULTIPLE]]))
208
+
209
+
210
+ def validate_use_legacy(value):
211
+ global _use_legacy_driver # noqa: PLW0603
212
+ if CONF_USE_LEGACY in value:
213
+ if (_use_legacy_driver is not None) and (
214
+ _use_legacy_driver != value[CONF_USE_LEGACY]
215
+ ):
216
+ raise cv.Invalid(
217
+ f"All i2s_audio components must set {CONF_USE_LEGACY} to the same value."
218
+ )
219
+ if (not value[CONF_USE_LEGACY]) and (CORE.using_arduino):
220
+ raise cv.Invalid("Arduino supports only the legacy i2s driver.")
221
+ _use_legacy_driver = value[CONF_USE_LEGACY]
222
+ return value
128
223
 
129
224
 
130
- CONFIG_SCHEMA = cv.Schema(
131
- {
132
- cv.GenerateID(): cv.declare_id(I2SAudioComponent),
133
- cv.Required(CONF_I2S_LRCLK_PIN): pins.internal_gpio_output_pin_number,
134
- cv.Optional(CONF_I2S_BCLK_PIN): pins.internal_gpio_output_pin_number,
135
- cv.Optional(CONF_I2S_MCLK_PIN): pins.internal_gpio_output_pin_number,
136
- }
225
+ CONFIG_SCHEMA = cv.All(
226
+ cv.Schema(
227
+ {
228
+ cv.GenerateID(): cv.declare_id(I2SAudioComponent),
229
+ cv.Required(CONF_I2S_LRCLK_PIN): pins.internal_gpio_output_pin_number,
230
+ cv.Optional(CONF_I2S_BCLK_PIN): pins.internal_gpio_output_pin_number,
231
+ cv.Optional(CONF_I2S_MCLK_PIN): pins.internal_gpio_output_pin_number,
232
+ cv.Optional(CONF_USE_LEGACY): cv.boolean,
233
+ },
234
+ ),
235
+ validate_use_legacy,
137
236
  )
138
237
 
139
238
 
@@ -148,12 +247,22 @@ def _final_validate(_):
148
247
  )
149
248
 
150
249
 
250
+ def use_legacy():
251
+ framework_version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]
252
+ if CORE.using_esp_idf and framework_version >= cv.Version(5, 0, 0):
253
+ if not _use_legacy_driver:
254
+ return False
255
+ return True
256
+
257
+
151
258
  FINAL_VALIDATE_SCHEMA = _final_validate
152
259
 
153
260
 
154
261
  async def to_code(config):
155
262
  var = cg.new_Pvariable(config[CONF_ID])
156
263
  await cg.register_component(var, config)
264
+ if use_legacy():
265
+ cg.add_define("USE_I2S_LEGACY")
157
266
 
158
267
  cg.add(var.set_lrclk_pin(config[CONF_I2S_LRCLK_PIN]))
159
268
  if CONF_I2S_BCLK_PIN in config:
@@ -2,9 +2,14 @@
2
2
 
3
3
  #ifdef USE_ESP32
4
4
 
5
- #include <driver/i2s.h>
6
5
  #include "esphome/core/component.h"
7
6
  #include "esphome/core/helpers.h"
7
+ #include "esphome/core/defines.h"
8
+ #ifdef USE_I2S_LEGACY
9
+ #include <driver/i2s.h>
10
+ #else
11
+ #include <driver/i2s_std.h>
12
+ #endif
8
13
 
9
14
  namespace esphome {
10
15
  namespace i2s_audio {
@@ -13,20 +18,36 @@ class I2SAudioComponent;
13
18
 
14
19
  class I2SAudioBase : public Parented<I2SAudioComponent> {
15
20
  public:
21
+ #ifdef USE_I2S_LEGACY
16
22
  void set_i2s_mode(i2s_mode_t mode) { this->i2s_mode_ = mode; }
17
23
  void set_channel(i2s_channel_fmt_t channel) { this->channel_ = channel; }
18
- void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; }
19
24
  void set_bits_per_sample(i2s_bits_per_sample_t bits_per_sample) { this->bits_per_sample_ = bits_per_sample; }
20
25
  void set_bits_per_channel(i2s_bits_per_chan_t bits_per_channel) { this->bits_per_channel_ = bits_per_channel; }
26
+ #else
27
+ void set_i2s_role(i2s_role_t role) { this->i2s_role_ = role; }
28
+ void set_slot_mode(i2s_slot_mode_t slot_mode) { this->slot_mode_ = slot_mode; }
29
+ void set_std_slot_mask(i2s_std_slot_mask_t std_slot_mask) { this->std_slot_mask_ = std_slot_mask; }
30
+ void set_slot_bit_width(i2s_slot_bit_width_t slot_bit_width) { this->slot_bit_width_ = slot_bit_width; }
31
+ #endif
32
+ void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; }
21
33
  void set_use_apll(uint32_t use_apll) { this->use_apll_ = use_apll; }
34
+ void set_mclk_multiple(i2s_mclk_multiple_t mclk_multiple) { this->mclk_multiple_ = mclk_multiple; }
22
35
 
23
36
  protected:
37
+ #ifdef USE_I2S_LEGACY
24
38
  i2s_mode_t i2s_mode_{};
25
39
  i2s_channel_fmt_t channel_;
26
- uint32_t sample_rate_;
27
40
  i2s_bits_per_sample_t bits_per_sample_;
28
41
  i2s_bits_per_chan_t bits_per_channel_;
42
+ #else
43
+ i2s_role_t i2s_role_{};
44
+ i2s_slot_mode_t slot_mode_;
45
+ i2s_std_slot_mask_t std_slot_mask_;
46
+ i2s_slot_bit_width_t slot_bit_width_;
47
+ #endif
48
+ uint32_t sample_rate_;
29
49
  bool use_apll_;
50
+ i2s_mclk_multiple_t mclk_multiple_;
30
51
  };
31
52
 
32
53
  class I2SAudioIn : public I2SAudioBase {};
@@ -37,6 +58,7 @@ class I2SAudioComponent : public Component {
37
58
  public:
38
59
  void setup() override;
39
60
 
61
+ #ifdef USE_I2S_LEGACY
40
62
  i2s_pin_config_t get_pin_config() const {
41
63
  return {
42
64
  .mck_io_num = this->mclk_pin_,
@@ -46,6 +68,20 @@ class I2SAudioComponent : public Component {
46
68
  .data_in_num = I2S_PIN_NO_CHANGE,
47
69
  };
48
70
  }
71
+ #else
72
+ i2s_std_gpio_config_t get_pin_config() const {
73
+ return {.mclk = (gpio_num_t) this->mclk_pin_,
74
+ .bclk = (gpio_num_t) this->bclk_pin_,
75
+ .ws = (gpio_num_t) this->lrclk_pin_,
76
+ .dout = I2S_GPIO_UNUSED, // add local ports
77
+ .din = I2S_GPIO_UNUSED,
78
+ .invert_flags = {
79
+ .mclk_inv = false,
80
+ .bclk_inv = false,
81
+ .ws_inv = false,
82
+ }};
83
+ }
84
+ #endif
49
85
 
50
86
  void set_mclk_pin(int pin) { this->mclk_pin_ = pin; }
51
87
  void set_bclk_pin(int pin) { this->bclk_pin_ = pin; }
@@ -62,9 +98,13 @@ class I2SAudioComponent : public Component {
62
98
 
63
99
  I2SAudioIn *audio_in_{nullptr};
64
100
  I2SAudioOut *audio_out_{nullptr};
65
-
101
+ #ifdef USE_I2S_LEGACY
66
102
  int mclk_pin_{I2S_PIN_NO_CHANGE};
67
103
  int bclk_pin_{I2S_PIN_NO_CHANGE};
104
+ #else
105
+ int mclk_pin_{I2S_GPIO_UNUSED};
106
+ int bclk_pin_{I2S_GPIO_UNUSED};
107
+ #endif
68
108
  int lrclk_pin_;
69
109
  i2s_port_t port_{};
70
110
  };
@@ -2,7 +2,7 @@ from esphome import pins
2
2
  import esphome.codegen as cg
3
3
  from esphome.components import esp32, media_player
4
4
  import esphome.config_validation as cv
5
- from esphome.const import CONF_ID, CONF_MODE
5
+ from esphome.const import CONF_MODE
6
6
 
7
7
  from .. import (
8
8
  CONF_I2S_AUDIO_ID,
@@ -14,6 +14,7 @@ from .. import (
14
14
  I2SAudioComponent,
15
15
  I2SAudioOut,
16
16
  i2s_audio_ns,
17
+ use_legacy,
17
18
  )
18
19
 
19
20
  CODEOWNERS = ["@jesserockz"]
@@ -56,16 +57,17 @@ def validate_esp32_variant(config):
56
57
  CONFIG_SCHEMA = cv.All(
57
58
  cv.typed_schema(
58
59
  {
59
- "internal": media_player.MEDIA_PLAYER_SCHEMA.extend(
60
+ "internal": media_player.media_player_schema(I2SAudioMediaPlayer)
61
+ .extend(
60
62
  {
61
- cv.GenerateID(): cv.declare_id(I2SAudioMediaPlayer),
62
63
  cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent),
63
64
  cv.Required(CONF_MODE): cv.enum(INTERNAL_DAC_OPTIONS, lower=True),
64
65
  }
65
- ).extend(cv.COMPONENT_SCHEMA),
66
- "external": media_player.MEDIA_PLAYER_SCHEMA.extend(
66
+ )
67
+ .extend(cv.COMPONENT_SCHEMA),
68
+ "external": media_player.media_player_schema(I2SAudioMediaPlayer)
69
+ .extend(
67
70
  {
68
- cv.GenerateID(): cv.declare_id(I2SAudioMediaPlayer),
69
71
  cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent),
70
72
  cv.Required(
71
73
  CONF_I2S_DOUT_PIN
@@ -78,7 +80,8 @@ CONFIG_SCHEMA = cv.All(
78
80
  *I2C_COMM_FMT_OPTIONS, lower=True
79
81
  ),
80
82
  }
81
- ).extend(cv.COMPONENT_SCHEMA),
83
+ )
84
+ .extend(cv.COMPONENT_SCHEMA),
82
85
  },
83
86
  key=CONF_DAC_TYPE,
84
87
  ),
@@ -87,10 +90,17 @@ CONFIG_SCHEMA = cv.All(
87
90
  )
88
91
 
89
92
 
93
+ def _final_validate(_):
94
+ if not use_legacy():
95
+ raise cv.Invalid("I2S media player is only compatible with legacy i2s driver.")
96
+
97
+
98
+ FINAL_VALIDATE_SCHEMA = _final_validate
99
+
100
+
90
101
  async def to_code(config):
91
- var = cg.new_Pvariable(config[CONF_ID])
102
+ var = await media_player.new_media_player(config)
92
103
  await cg.register_component(var, config)
93
- await media_player.register_media_player(var, config)
94
104
 
95
105
  await cg.register_parented(var, config[CONF_I2S_AUDIO_ID])
96
106
 
@@ -1,17 +1,28 @@
1
1
  from esphome import pins
2
2
  import esphome.codegen as cg
3
- from esphome.components import esp32, microphone
3
+ from esphome.components import audio, esp32, microphone
4
4
  from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin
5
5
  import esphome.config_validation as cv
6
- from esphome.const import CONF_ID, CONF_NUMBER
6
+ from esphome.const import (
7
+ CONF_BITS_PER_SAMPLE,
8
+ CONF_CHANNEL,
9
+ CONF_ID,
10
+ CONF_NUM_CHANNELS,
11
+ CONF_NUMBER,
12
+ CONF_SAMPLE_RATE,
13
+ )
7
14
 
8
15
  from .. import (
9
16
  CONF_I2S_DIN_PIN,
17
+ CONF_LEFT,
18
+ CONF_MONO,
10
19
  CONF_RIGHT,
11
20
  I2SAudioIn,
12
21
  i2s_audio_component_schema,
13
22
  i2s_audio_ns,
14
23
  register_i2s_audio_component,
24
+ use_legacy,
25
+ validate_mclk_divisible_by_3,
15
26
  )
16
27
 
17
28
  CODEOWNERS = ["@jesserockz"]
@@ -19,6 +30,7 @@ DEPENDENCIES = ["i2s_audio"]
19
30
 
20
31
  CONF_ADC_PIN = "adc_pin"
21
32
  CONF_ADC_TYPE = "adc_type"
33
+ CONF_CORRECT_DC_OFFSET = "correct_dc_offset"
22
34
  CONF_PDM = "pdm"
23
35
 
24
36
  I2SAudioMicrophone = i2s_audio_ns.class_(
@@ -29,7 +41,7 @@ INTERNAL_ADC_VARIANTS = [esp32.const.VARIANT_ESP32]
29
41
  PDM_VARIANTS = [esp32.const.VARIANT_ESP32, esp32.const.VARIANT_ESP32S3]
30
42
 
31
43
 
32
- def validate_esp32_variant(config):
44
+ def _validate_esp32_variant(config):
33
45
  variant = esp32.get_esp32_variant()
34
46
  if config[CONF_ADC_TYPE] == "external":
35
47
  if config[CONF_PDM]:
@@ -43,16 +55,47 @@ def validate_esp32_variant(config):
43
55
  raise NotImplementedError
44
56
 
45
57
 
58
+ def _validate_channel(config):
59
+ if config[CONF_CHANNEL] == CONF_MONO:
60
+ raise cv.Invalid(f"I2S microphone does not support {CONF_MONO}.")
61
+ return config
62
+
63
+
64
+ def _set_num_channels_from_config(config):
65
+ if config[CONF_CHANNEL] in (CONF_LEFT, CONF_RIGHT):
66
+ config[CONF_NUM_CHANNELS] = 1
67
+ else:
68
+ config[CONF_NUM_CHANNELS] = 2
69
+
70
+ return config
71
+
72
+
73
+ def _set_stream_limits(config):
74
+ audio.set_stream_limits(
75
+ min_bits_per_sample=config.get(CONF_BITS_PER_SAMPLE),
76
+ max_bits_per_sample=config.get(CONF_BITS_PER_SAMPLE),
77
+ min_channels=config.get(CONF_NUM_CHANNELS),
78
+ max_channels=config.get(CONF_NUM_CHANNELS),
79
+ min_sample_rate=config.get(CONF_SAMPLE_RATE),
80
+ max_sample_rate=config.get(CONF_SAMPLE_RATE),
81
+ )(config)
82
+
83
+ return config
84
+
85
+
46
86
  BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend(
47
87
  i2s_audio_component_schema(
48
88
  I2SAudioMicrophone,
49
89
  default_sample_rate=16000,
50
90
  default_channel=CONF_RIGHT,
51
91
  default_bits_per_sample="32bit",
92
+ ).extend(
93
+ {
94
+ cv.Optional(CONF_CORRECT_DC_OFFSET, default=False): cv.boolean,
95
+ }
52
96
  )
53
97
  ).extend(cv.COMPONENT_SCHEMA)
54
98
 
55
-
56
99
  CONFIG_SCHEMA = cv.All(
57
100
  cv.typed_schema(
58
101
  {
@@ -70,10 +113,23 @@ CONFIG_SCHEMA = cv.All(
70
113
  },
71
114
  key=CONF_ADC_TYPE,
72
115
  ),
73
- validate_esp32_variant,
116
+ _validate_esp32_variant,
117
+ _validate_channel,
118
+ _set_num_channels_from_config,
119
+ _set_stream_limits,
120
+ validate_mclk_divisible_by_3,
74
121
  )
75
122
 
76
123
 
124
+ def _final_validate(config):
125
+ if not use_legacy():
126
+ if config[CONF_ADC_TYPE] == "internal":
127
+ raise cv.Invalid("Internal ADC is only compatible with legacy i2s driver.")
128
+
129
+
130
+ FINAL_VALIDATE_SCHEMA = _final_validate
131
+
132
+
77
133
  async def to_code(config):
78
134
  var = cg.new_Pvariable(config[CONF_ID])
79
135
  await cg.register_component(var, config)
@@ -88,3 +144,5 @@ async def to_code(config):
88
144
  else:
89
145
  cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN]))
90
146
  cg.add(var.set_pdm(config[CONF_PDM]))
147
+
148
+ cg.add(var.set_correct_dc_offset(config[CONF_CORRECT_DC_OFFSET]))