esphome 2025.4.1__py3-none-any.whl → 2025.5.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 (412) hide show
  1. esphome/components/ac_dimmer/ac_dimmer.cpp +3 -2
  2. esphome/components/adc/__init__.py +51 -34
  3. esphome/components/airthings_wave_base/__init__.py +1 -1
  4. esphome/components/alarm_control_panel/__init__.py +37 -2
  5. esphome/components/am43/cover/__init__.py +4 -5
  6. esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp +6 -4
  7. esphome/components/analog_threshold/analog_threshold_binary_sensor.h +4 -5
  8. esphome/components/analog_threshold/binary_sensor.py +10 -8
  9. esphome/components/anova/climate.py +4 -5
  10. esphome/components/api/__init__.py +25 -8
  11. esphome/components/api/api_connection.cpp +77 -10
  12. esphome/components/api/api_connection.h +6 -1
  13. esphome/components/api/api_frame_helper.cpp +98 -130
  14. esphome/components/api/api_frame_helper.h +12 -2
  15. esphome/components/api/api_noise_context.h +13 -4
  16. esphome/components/api/api_pb2.cpp +1422 -1
  17. esphome/components/api/api_pb2.h +255 -1
  18. esphome/components/api/api_pb2_service.cpp +162 -49
  19. esphome/components/api/api_pb2_service.h +90 -51
  20. esphome/components/api/api_pb2_size.h +361 -0
  21. esphome/components/api/api_server.cpp +110 -34
  22. esphome/components/api/api_server.h +8 -0
  23. esphome/components/api/proto.h +38 -9
  24. esphome/components/as3935_i2c/as3935_i2c.h +0 -3
  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/climate/__init__.py +3 -8
  45. esphome/components/bedjet/fan/__init__.py +2 -11
  46. esphome/components/binary/fan/__init__.py +13 -16
  47. esphome/components/binary_sensor/__init__.py +13 -10
  48. esphome/components/binary_sensor/binary_sensor.cpp +6 -10
  49. esphome/components/binary_sensor/binary_sensor.h +1 -1
  50. esphome/components/binary_sensor/filter.cpp +21 -21
  51. esphome/components/binary_sensor/filter.h +10 -10
  52. esphome/components/bl0906/constants.h +16 -16
  53. esphome/components/ble_client/text_sensor/__init__.py +3 -5
  54. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +4 -6
  55. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +135 -21
  56. esphome/components/bluetooth_proxy/bluetooth_proxy.h +7 -0
  57. esphome/components/button/__init__.py +11 -8
  58. esphome/components/canbus/canbus.cpp +3 -0
  59. esphome/components/canbus/canbus.h +16 -0
  60. esphome/components/climate/__init__.py +35 -2
  61. esphome/components/climate/climate_mode.h +1 -1
  62. esphome/components/climate/climate_traits.h +63 -57
  63. esphome/components/climate_ir/__init__.py +57 -17
  64. esphome/components/climate_ir_lg/climate.py +2 -5
  65. esphome/components/climate_ir_lg/climate_ir_lg.cpp +7 -7
  66. esphome/components/climate_ir_lg/climate_ir_lg.h +1 -1
  67. esphome/components/color/__init__.py +2 -0
  68. esphome/components/const/__init__.py +5 -0
  69. esphome/components/coolix/climate.py +2 -9
  70. esphome/components/copy/cover/__init__.py +10 -9
  71. esphome/components/copy/fan/__init__.py +11 -9
  72. esphome/components/copy/lock/__init__.py +11 -9
  73. esphome/components/copy/text/__init__.py +9 -6
  74. esphome/components/cover/__init__.py +37 -2
  75. esphome/components/cst226/binary_sensor/__init__.py +28 -0
  76. esphome/components/cst226/binary_sensor/cs226_button.h +22 -0
  77. esphome/components/cst226/binary_sensor/cstt6_button.cpp +19 -0
  78. esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +27 -5
  79. esphome/components/cst226/touchscreen/cst226_touchscreen.h +10 -10
  80. esphome/components/current_based/cover.py +37 -36
  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/debug/debug_component.cpp +5 -0
  89. esphome/components/debug/debug_component.h +6 -0
  90. esphome/components/debug/debug_esp32.cpp +109 -254
  91. esphome/components/debug/sensor.py +14 -0
  92. esphome/components/deep_sleep/deep_sleep_esp32.cpp +13 -1
  93. esphome/components/delonghi/climate.py +2 -9
  94. esphome/components/demo/__init__.py +18 -20
  95. esphome/components/dfrobot_sen0395/switch/__init__.py +21 -22
  96. esphome/components/display/rect.cpp +4 -9
  97. esphome/components/display/rect.h +1 -1
  98. esphome/components/emmeti/climate.py +2 -9
  99. esphome/components/endstop/cover.py +17 -16
  100. esphome/components/esp32/__init__.py +60 -3
  101. esphome/components/esp32/core.cpp +11 -5
  102. esphome/components/esp32/gpio.cpp +86 -24
  103. esphome/components/esp32/gpio.py +15 -16
  104. esphome/components/esp32/gpio_esp32.py +1 -2
  105. esphome/components/esp32/gpio_esp32_c2.py +1 -1
  106. esphome/components/esp32/gpio_esp32_c3.py +1 -1
  107. esphome/components/esp32/gpio_esp32_c6.py +1 -1
  108. esphome/components/esp32/gpio_esp32_h2.py +1 -1
  109. esphome/components/esp32_ble/ble.cpp +1 -8
  110. esphome/components/esp32_ble/ble.h +5 -3
  111. esphome/components/esp32_ble/ble_advertising.h +1 -0
  112. esphome/components/esp32_ble_server/__init__.py +3 -0
  113. esphome/components/esp32_ble_tracker/__init__.py +7 -1
  114. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +192 -118
  115. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +29 -3
  116. esphome/components/esp32_can/esp32_can.cpp +1 -1
  117. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  118. esphome/components/esp32_rmt_led_strip/led_strip.h +7 -5
  119. esphome/components/esp32_rmt_led_strip/light.py +9 -1
  120. esphome/components/esp8266/gpio.cpp +69 -8
  121. esphome/components/event/__init__.py +13 -10
  122. esphome/components/factory_reset/switch/__init__.py +7 -21
  123. esphome/components/fan/__init__.py +52 -5
  124. esphome/components/fastled_base/__init__.py +1 -4
  125. esphome/components/fastled_base/fastled_light.cpp +1 -1
  126. esphome/components/feedback/cover.py +38 -33
  127. esphome/components/fujitsu_general/climate.py +2 -9
  128. esphome/components/gpio/one_wire/gpio_one_wire.cpp +45 -43
  129. esphome/components/gpio/one_wire/gpio_one_wire.h +2 -1
  130. esphome/components/gpio_expander/cached_gpio.h +22 -7
  131. esphome/components/gps/__init__.py +11 -2
  132. esphome/components/gps/gps.cpp +11 -8
  133. esphome/components/gps/gps.h +9 -6
  134. esphome/components/graph/__init__.py +1 -2
  135. esphome/components/gree/climate.py +4 -6
  136. esphome/components/gree/gree.cpp +16 -2
  137. esphome/components/gree/gree.h +2 -2
  138. esphome/components/haier/climate.py +37 -34
  139. esphome/components/hbridge/fan/__init__.py +19 -17
  140. esphome/components/he60r/cover.py +4 -5
  141. esphome/components/heatpumpir/climate.py +3 -6
  142. esphome/components/hitachi_ac344/climate.py +2 -9
  143. esphome/components/hitachi_ac424/climate.py +2 -9
  144. esphome/components/hlw8012/hlw8012.cpp +1 -1
  145. esphome/components/hm3301/hm3301.h +1 -1
  146. esphome/components/http_request/__init__.py +39 -6
  147. esphome/components/http_request/http_request.cpp +20 -0
  148. esphome/components/http_request/http_request.h +57 -15
  149. esphome/components/http_request/http_request_arduino.cpp +22 -6
  150. esphome/components/http_request/http_request_arduino.h +4 -3
  151. esphome/components/http_request/http_request_host.cpp +141 -0
  152. esphome/components/http_request/http_request_host.h +37 -0
  153. esphome/components/http_request/http_request_idf.cpp +35 -3
  154. esphome/components/http_request/http_request_idf.h +10 -3
  155. esphome/components/http_request/httplib.h +9691 -0
  156. esphome/components/http_request/update/__init__.py +11 -8
  157. esphome/components/i2c/i2c.h +4 -0
  158. esphome/components/i2c/i2c_bus_esp_idf.cpp +1 -1
  159. esphome/components/i2s_audio/__init__.py +131 -22
  160. esphome/components/i2s_audio/i2s_audio.h +44 -4
  161. esphome/components/i2s_audio/media_player/__init__.py +19 -9
  162. esphome/components/i2s_audio/microphone/__init__.py +63 -5
  163. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +351 -61
  164. esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +40 -6
  165. esphome/components/i2s_audio/speaker/__init__.py +31 -5
  166. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +155 -19
  167. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +17 -4
  168. esphome/components/ili9xxx/ili9xxx_init.h +1 -1
  169. esphome/components/image/__init__.py +37 -17
  170. esphome/components/image/image.cpp +25 -8
  171. esphome/components/internal_temperature/internal_temperature.cpp +6 -4
  172. esphome/components/key_collector/__init__.py +35 -0
  173. esphome/components/key_collector/key_collector.cpp +8 -0
  174. esphome/components/key_collector/key_collector.h +10 -0
  175. esphome/components/ld2410/ld2410.h +1 -1
  176. esphome/components/ld2450/ld2450.h +1 -1
  177. esphome/components/light/__init__.py +57 -0
  178. esphome/components/lock/__init__.py +51 -4
  179. esphome/components/lock/automation.h +2 -13
  180. esphome/components/logger/__init__.py +21 -0
  181. esphome/components/logger/logger.cpp +125 -95
  182. esphome/components/logger/logger.h +160 -35
  183. esphome/components/logger/task_log_buffer.cpp +138 -0
  184. esphome/components/logger/task_log_buffer.h +69 -0
  185. esphome/components/lvgl/__init__.py +13 -5
  186. esphome/components/lvgl/automation.py +50 -1
  187. esphome/components/lvgl/defines.py +0 -1
  188. esphome/components/lvgl/lv_validation.py +10 -1
  189. esphome/components/lvgl/lvgl_esphome.cpp +5 -1
  190. esphome/components/lvgl/schemas.py +14 -14
  191. esphome/components/lvgl/text/__init__.py +1 -2
  192. esphome/components/lvgl/widgets/arc.py +7 -6
  193. esphome/components/lvgl/widgets/buttonmatrix.py +3 -3
  194. esphome/components/lvgl/widgets/checkbox.py +2 -2
  195. esphome/components/lvgl/widgets/dropdown.py +2 -1
  196. esphome/components/lvgl/widgets/img.py +15 -12
  197. esphome/components/mapping/__init__.py +134 -0
  198. esphome/components/max7219digit/max7219digit.cpp +27 -27
  199. esphome/components/mdns/__init__.py +11 -5
  200. esphome/components/mdns/mdns_component.cpp +11 -5
  201. esphome/components/mdns/mdns_component.h +3 -2
  202. esphome/components/mdns/mdns_esp32.cpp +4 -3
  203. esphome/components/mdns/mdns_esp8266.cpp +4 -2
  204. esphome/components/mdns/mdns_libretiny.cpp +4 -2
  205. esphome/components/mdns/mdns_rp2040.cpp +4 -2
  206. esphome/components/media_player/__init__.py +40 -6
  207. esphome/components/micro_wake_word/__init__.py +99 -31
  208. esphome/components/micro_wake_word/automation.h +54 -0
  209. esphome/components/micro_wake_word/micro_wake_word.cpp +331 -319
  210. esphome/components/micro_wake_word/micro_wake_word.h +58 -105
  211. esphome/components/micro_wake_word/preprocessor_settings.h +19 -2
  212. esphome/components/micro_wake_word/streaming_model.cpp +158 -41
  213. esphome/components/micro_wake_word/streaming_model.h +85 -13
  214. esphome/components/microphone/__init__.py +139 -9
  215. esphome/components/microphone/automation.h +14 -2
  216. esphome/components/microphone/microphone.cpp +21 -0
  217. esphome/components/microphone/microphone.h +14 -5
  218. esphome/components/microphone/microphone_source.cpp +95 -0
  219. esphome/components/microphone/microphone_source.h +80 -0
  220. esphome/components/mics_4514/sensor.py +25 -14
  221. esphome/components/midea/climate.py +3 -4
  222. esphome/components/midea_ir/climate.py +3 -5
  223. esphome/components/mipi_spi/__init__.py +15 -0
  224. esphome/components/mipi_spi/display.py +474 -0
  225. esphome/components/mipi_spi/mipi_spi.cpp +481 -0
  226. esphome/components/mipi_spi/mipi_spi.h +171 -0
  227. esphome/components/mipi_spi/models/__init__.py +65 -0
  228. esphome/components/mipi_spi/models/amoled.py +72 -0
  229. esphome/components/mipi_spi/models/commands.py +82 -0
  230. esphome/components/mipi_spi/models/cyd.py +10 -0
  231. esphome/components/mipi_spi/models/ili.py +749 -0
  232. esphome/components/mipi_spi/models/jc.py +260 -0
  233. esphome/components/mipi_spi/models/lanbon.py +15 -0
  234. esphome/components/mipi_spi/models/lilygo.py +60 -0
  235. esphome/components/mipi_spi/models/waveshare.py +139 -0
  236. esphome/components/mitsubishi/climate.py +2 -5
  237. esphome/components/mitsubishi/mitsubishi.cpp +9 -9
  238. esphome/components/mixer/speaker/mixer_speaker.cpp +12 -22
  239. esphome/components/mixer/speaker/mixer_speaker.h +1 -3
  240. esphome/components/mlx90393/sensor.py +5 -0
  241. esphome/components/mlx90393/sensor_mlx90393.cpp +195 -13
  242. esphome/components/mlx90393/sensor_mlx90393.h +21 -4
  243. esphome/components/mqtt/__init__.py +1 -1
  244. esphome/components/mqtt/mqtt_client.cpp +5 -1
  245. esphome/components/mqtt/mqtt_const.h +4 -0
  246. esphome/components/mqtt/mqtt_fan.cpp +39 -0
  247. esphome/components/mqtt/mqtt_fan.h +2 -0
  248. esphome/components/network/__init__.py +1 -1
  249. esphome/components/nextion/base_component.py +17 -16
  250. esphome/components/nextion/display.py +11 -2
  251. esphome/components/nextion/nextion.cpp +39 -1
  252. esphome/components/nextion/nextion.h +50 -0
  253. esphome/components/noblex/climate.py +2 -9
  254. esphome/components/number/__init__.py +12 -9
  255. esphome/components/one_wire/one_wire_bus.cpp +14 -10
  256. esphome/components/one_wire/one_wire_bus.h +14 -8
  257. esphome/components/online_image/bmp_image.cpp +48 -11
  258. esphome/components/online_image/bmp_image.h +2 -0
  259. esphome/components/opentherm/binary_sensor/__init__.py +2 -4
  260. esphome/components/opentherm/number/__init__.py +11 -20
  261. esphome/components/opentherm/sensor/__init__.py +3 -3
  262. esphome/components/opentherm/switch/__init__.py +3 -5
  263. esphome/components/output/lock/__init__.py +11 -9
  264. esphome/components/packages/__init__.py +33 -31
  265. esphome/components/packet_transport/__init__.py +201 -0
  266. esphome/components/packet_transport/binary_sensor.py +19 -0
  267. esphome/components/packet_transport/packet_transport.cpp +534 -0
  268. esphome/components/packet_transport/packet_transport.h +154 -0
  269. esphome/components/packet_transport/sensor.py +19 -0
  270. esphome/components/pca9685/pca9685_output.cpp +2 -1
  271. esphome/components/pid/climate.py +2 -4
  272. esphome/components/pm2005/__init__.py +1 -0
  273. esphome/components/pm2005/pm2005.cpp +123 -0
  274. esphome/components/pm2005/pm2005.h +46 -0
  275. esphome/components/pm2005/sensor.py +86 -0
  276. esphome/components/pmsa003i/pmsa003i.cpp +43 -16
  277. esphome/components/pmsa003i/pmsa003i.h +25 -25
  278. esphome/components/pmsx003/pmsx003.cpp +193 -229
  279. esphome/components/pmsx003/pmsx003.h +51 -33
  280. esphome/components/pmsx003/sensor.py +21 -11
  281. esphome/components/pn7150/pn7150.h +2 -2
  282. esphome/components/pn7160/pn7160.h +2 -2
  283. esphome/components/prometheus/prometheus_handler.cpp +174 -0
  284. esphome/components/prometheus/prometheus_handler.h +17 -0
  285. esphome/components/psram/__init__.py +7 -5
  286. esphome/components/pulse_meter/pulse_meter_sensor.cpp +32 -12
  287. esphome/components/pulse_meter/pulse_meter_sensor.h +5 -5
  288. esphome/components/qspi_dbi/__init__.py +0 -1
  289. esphome/components/qspi_dbi/display.py +2 -1
  290. esphome/components/qspi_dbi/models.py +1 -2
  291. esphome/components/remote_base/__init__.py +91 -0
  292. esphome/components/remote_base/beo4_protocol.cpp +153 -0
  293. esphome/components/remote_base/beo4_protocol.h +43 -0
  294. esphome/components/remote_base/gobox_protocol.cpp +131 -0
  295. esphome/components/remote_base/gobox_protocol.h +54 -0
  296. esphome/components/remote_receiver/remote_receiver_esp32.cpp +16 -9
  297. esphome/components/resampler/speaker/resampler_speaker.cpp +12 -10
  298. esphome/components/resampler/speaker/resampler_speaker.h +1 -1
  299. esphome/components/scd30/sensor.py +2 -3
  300. esphome/components/scd4x/sensor.py +4 -5
  301. esphome/components/sdp3x/sensor.py +2 -1
  302. esphome/components/select/__init__.py +19 -20
  303. esphome/components/sen5x/sensor.py +1 -1
  304. esphome/components/sensor/__init__.py +158 -14
  305. esphome/components/sensor/filter.cpp +23 -0
  306. esphome/components/sensor/filter.h +22 -0
  307. esphome/components/sgp4x/sensor.py +1 -1
  308. esphome/components/sht4x/sht4x.cpp +43 -22
  309. esphome/components/sht4x/sht4x.h +1 -1
  310. esphome/components/sml/text_sensor/__init__.py +4 -6
  311. esphome/components/sound_level/__init__.py +0 -0
  312. esphome/components/sound_level/sensor.py +97 -0
  313. esphome/components/sound_level/sound_level.cpp +194 -0
  314. esphome/components/sound_level/sound_level.h +73 -0
  315. esphome/components/speaker/media_player/__init__.py +4 -8
  316. esphome/components/speaker/media_player/speaker_media_player.cpp +0 -18
  317. esphome/components/speaker/media_player/speaker_media_player.h +0 -11
  318. esphome/components/speaker/speaker.h +4 -7
  319. esphome/components/speed/fan/__init__.py +17 -16
  320. esphome/components/spi/spi.h +11 -1
  321. esphome/components/sprinkler/__init__.py +18 -19
  322. esphome/components/switch/__init__.py +32 -42
  323. esphome/components/syslog/__init__.py +41 -0
  324. esphome/components/syslog/esphome_syslog.cpp +49 -0
  325. esphome/components/syslog/esphome_syslog.h +27 -0
  326. esphome/components/tca9555/tca9555.cpp +11 -6
  327. esphome/components/tcl112/climate.py +2 -9
  328. esphome/components/template/alarm_control_panel/__init__.py +7 -6
  329. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +21 -17
  330. esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +2 -1
  331. esphome/components/template/cover/__init__.py +27 -21
  332. esphome/components/template/fan/__init__.py +14 -12
  333. esphome/components/template/lock/__init__.py +20 -25
  334. esphome/components/template/lock/automation.h +18 -0
  335. esphome/components/template/text/__init__.py +4 -3
  336. esphome/components/template/valve/__init__.py +32 -21
  337. esphome/components/template/valve/automation.h +24 -0
  338. esphome/components/text/__init__.py +32 -1
  339. esphome/components/text_sensor/__init__.py +24 -29
  340. esphome/components/thermostat/climate.py +5 -5
  341. esphome/components/time_based/cover.py +17 -16
  342. esphome/components/tm1638/switch/__init__.py +10 -7
  343. esphome/components/tormatic/cover.py +4 -5
  344. esphome/components/toshiba/climate.py +3 -5
  345. esphome/components/touchscreen/touchscreen.cpp +3 -1
  346. esphome/components/tt21100/touchscreen/tt21100.cpp +1 -1
  347. esphome/components/tuya/climate/__init__.py +5 -6
  348. esphome/components/tuya/cover/__init__.py +6 -11
  349. esphome/components/tuya/select/__init__.py +15 -5
  350. esphome/components/tuya/select/tuya_select.cpp +6 -1
  351. esphome/components/tuya/select/tuya_select.h +5 -1
  352. esphome/components/uart/packet_transport/__init__.py +20 -0
  353. esphome/components/uart/packet_transport/uart_transport.cpp +88 -0
  354. esphome/components/uart/packet_transport/uart_transport.h +41 -0
  355. esphome/components/udp/__init__.py +126 -128
  356. esphome/components/udp/automation.h +40 -0
  357. esphome/components/udp/binary_sensor.py +3 -25
  358. esphome/components/udp/packet_transport/__init__.py +29 -0
  359. esphome/components/udp/packet_transport/udp_transport.cpp +36 -0
  360. esphome/components/udp/packet_transport/udp_transport.h +28 -0
  361. esphome/components/udp/sensor.py +3 -25
  362. esphome/components/udp/udp_component.cpp +26 -470
  363. esphome/components/udp/udp_component.h +21 -128
  364. esphome/components/update/__init__.py +31 -1
  365. esphome/components/uponor_smatrix/climate/__init__.py +4 -9
  366. esphome/components/uptime/text_sensor/__init__.py +47 -7
  367. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +12 -7
  368. esphome/components/uptime/text_sensor/uptime_text_sensor.h +19 -0
  369. esphome/components/valve/__init__.py +34 -3
  370. esphome/components/valve/automation.h +1 -19
  371. esphome/components/vl53l0x/sensor.py +11 -0
  372. esphome/components/vl53l0x/vl53l0x_sensor.cpp +5 -1
  373. esphome/components/vl53l0x/vl53l0x_sensor.h +2 -1
  374. esphome/components/voice_assistant/__init__.py +36 -10
  375. esphome/components/voice_assistant/voice_assistant.cpp +170 -144
  376. esphome/components/voice_assistant/voice_assistant.h +26 -25
  377. esphome/components/waveshare_epaper/display.py +6 -0
  378. esphome/components/waveshare_epaper/waveshare_epaper.cpp +439 -37
  379. esphome/components/waveshare_epaper/waveshare_epaper.h +60 -11
  380. esphome/components/whirlpool/climate.py +3 -5
  381. esphome/components/whynter/climate.py +3 -5
  382. esphome/components/xpt2046/touchscreen/xpt2046.cpp +1 -1
  383. esphome/components/yashima/climate.py +6 -6
  384. esphome/components/zhlt01/climate.py +2 -7
  385. esphome/config_validation.py +38 -58
  386. esphome/const.py +15 -1
  387. esphome/core/__init__.py +2 -0
  388. esphome/core/application.cpp +1 -0
  389. esphome/core/application.h +4 -0
  390. esphome/core/automation.h +4 -3
  391. esphome/core/component.cpp +19 -3
  392. esphome/core/component.h +5 -0
  393. esphome/core/defines.h +23 -17
  394. esphome/core/macros.h +4 -0
  395. esphome/core/scheduler.cpp +3 -0
  396. esphome/cpp_generator.py +6 -2
  397. esphome/dashboard/web_server.py +3 -3
  398. esphome/helpers.py +39 -0
  399. esphome/loader.py +4 -0
  400. esphome/mqtt.py +21 -8
  401. esphome/platformio_api.py +1 -1
  402. esphome/schema_extractors.py +0 -1
  403. esphome/vscode.py +15 -0
  404. esphome/wizard.py +2 -2
  405. esphome/zeroconf.py +7 -3
  406. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/METADATA +10 -11
  407. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/RECORD +411 -352
  408. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/WHEEL +1 -1
  409. esphome/components/esp32_ble/const_esp32c6.h +0 -74
  410. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/entry_points.txt +0 -0
  411. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/licenses/LICENSE +0 -0
  412. {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/top_level.txt +0 -0
@@ -156,13 +156,13 @@ STYLE_PROPS = {
156
156
  "opa_layered": lvalid.opacity,
157
157
  "outline_color": lvalid.lv_color,
158
158
  "outline_opa": lvalid.opacity,
159
- "outline_pad": lvalid.pixels,
159
+ "outline_pad": lvalid.padding,
160
160
  "outline_width": lvalid.pixels,
161
- "pad_all": lvalid.pixels,
162
- "pad_bottom": lvalid.pixels,
163
- "pad_left": lvalid.pixels,
164
- "pad_right": lvalid.pixels,
165
- "pad_top": lvalid.pixels,
161
+ "pad_all": lvalid.padding,
162
+ "pad_bottom": lvalid.padding,
163
+ "pad_left": lvalid.padding,
164
+ "pad_right": lvalid.padding,
165
+ "pad_top": lvalid.padding,
166
166
  "shadow_color": lvalid.lv_color,
167
167
  "shadow_ofs_x": lvalid.lv_int,
168
168
  "shadow_ofs_y": lvalid.lv_int,
@@ -226,8 +226,8 @@ FULL_STYLE_SCHEMA = STYLE_SCHEMA.extend(
226
226
  {
227
227
  cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments,
228
228
  cv.Optional(df.CONF_GRID_CELL_Y_ALIGN): grid_alignments,
229
- cv.Optional(df.CONF_PAD_ROW): lvalid.pixels,
230
- cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels,
229
+ cv.Optional(df.CONF_PAD_ROW): lvalid.padding,
230
+ cv.Optional(df.CONF_PAD_COLUMN): lvalid.padding,
231
231
  }
232
232
  )
233
233
 
@@ -370,8 +370,8 @@ LAYOUT_SCHEMA = {
370
370
  cv.Required(df.CONF_GRID_COLUMNS): [grid_spec],
371
371
  cv.Optional(df.CONF_GRID_COLUMN_ALIGN): grid_alignments,
372
372
  cv.Optional(df.CONF_GRID_ROW_ALIGN): grid_alignments,
373
- cv.Optional(df.CONF_PAD_ROW): lvalid.pixels,
374
- cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels,
373
+ cv.Optional(df.CONF_PAD_ROW): lvalid.padding,
374
+ cv.Optional(df.CONF_PAD_COLUMN): lvalid.padding,
375
375
  },
376
376
  df.TYPE_FLEX: {
377
377
  cv.Optional(
@@ -380,8 +380,8 @@ LAYOUT_SCHEMA = {
380
380
  cv.Optional(df.CONF_FLEX_ALIGN_MAIN, default="start"): flex_alignments,
381
381
  cv.Optional(df.CONF_FLEX_ALIGN_CROSS, default="start"): flex_alignments,
382
382
  cv.Optional(df.CONF_FLEX_ALIGN_TRACK, default="start"): flex_alignments,
383
- cv.Optional(df.CONF_PAD_ROW): lvalid.pixels,
384
- cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels,
383
+ cv.Optional(df.CONF_PAD_ROW): lvalid.padding,
384
+ cv.Optional(df.CONF_PAD_COLUMN): lvalid.padding,
385
385
  },
386
386
  },
387
387
  lower=True,
@@ -427,8 +427,8 @@ ALL_STYLES = {
427
427
  **STYLE_PROPS,
428
428
  **GRID_CELL_SCHEMA,
429
429
  **FLEX_OBJ_SCHEMA,
430
- cv.Optional(df.CONF_PAD_ROW): lvalid.pixels,
431
- cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels,
430
+ cv.Optional(df.CONF_PAD_ROW): lvalid.padding,
431
+ cv.Optional(df.CONF_PAD_COLUMN): lvalid.padding,
432
432
  }
433
433
 
434
434
 
@@ -19,9 +19,8 @@ from ..widgets import get_widgets, wait_for_widgets
19
19
 
20
20
  LVGLText = lvgl_ns.class_("LVGLText", text.Text)
21
21
 
22
- CONFIG_SCHEMA = text.TEXT_SCHEMA.extend(
22
+ CONFIG_SCHEMA = text.text_schema(LVGLText).extend(
23
23
  {
24
- cv.GenerateID(): cv.declare_id(LVGLText),
25
24
  cv.Required(CONF_WIDGET): cv.use_id(LvText),
26
25
  }
27
26
  )
@@ -67,12 +67,13 @@ class ArcType(NumberType):
67
67
  lv.arc_set_mode(w.obj, literal(config[CONF_MODE]))
68
68
  lv.arc_set_change_rate(w.obj, config[CONF_CHANGE_RATE])
69
69
 
70
- if config.get(CONF_ADJUSTABLE) is False:
71
- lv_obj.remove_style(w.obj, nullptr, literal("LV_PART_KNOB"))
72
- w.clear_flag("LV_OBJ_FLAG_CLICKABLE")
73
- elif CONF_GROUP not in config:
74
- # For some reason arc does not get automatically added to the default group
75
- lv.group_add_obj(lv_expr.group_get_default(), w.obj)
70
+ if CONF_ADJUSTABLE in config:
71
+ if not config[CONF_ADJUSTABLE]:
72
+ lv_obj.remove_style(w.obj, nullptr, literal("LV_PART_KNOB"))
73
+ w.clear_flag("LV_OBJ_FLAG_CLICKABLE")
74
+ elif CONF_GROUP not in config:
75
+ # For some reason arc does not get automatically added to the default group
76
+ lv.group_add_obj(lv_expr.group_get_default(), w.obj)
76
77
 
77
78
  value = await get_start_value(config)
78
79
  if value is not None:
@@ -19,7 +19,7 @@ from ..defines import (
19
19
  CONF_SELECTED,
20
20
  )
21
21
  from ..helpers import lvgl_components_required
22
- from ..lv_validation import key_code, lv_bool, pixels
22
+ from ..lv_validation import key_code, lv_bool, padding
23
23
  from ..lvcode import lv, lv_add, lv_expr
24
24
  from ..schemas import automation_schema
25
25
  from ..types import (
@@ -59,8 +59,8 @@ BUTTONMATRIX_BUTTON_SCHEMA = cv.Schema(
59
59
  BUTTONMATRIX_SCHEMA = cv.Schema(
60
60
  {
61
61
  cv.Optional(CONF_ONE_CHECKED, default=False): lv_bool,
62
- cv.Optional(CONF_PAD_ROW): pixels,
63
- cv.Optional(CONF_PAD_COLUMN): pixels,
62
+ cv.Optional(CONF_PAD_ROW): padding,
63
+ cv.Optional(CONF_PAD_COLUMN): padding,
64
64
  cv.GenerateID(CONF_BUTTON_TEXT_LIST_ID): cv.declare_id(char_ptr),
65
65
  cv.Required(CONF_ROWS): cv.ensure_list(
66
66
  cv.Schema(
@@ -2,7 +2,7 @@ from esphome.config_validation import Optional
2
2
  from esphome.const import CONF_TEXT
3
3
 
4
4
  from ..defines import CONF_INDICATOR, CONF_MAIN, CONF_PAD_COLUMN
5
- from ..lv_validation import lv_text, pixels
5
+ from ..lv_validation import lv_text, padding
6
6
  from ..lvcode import lv
7
7
  from ..schemas import TEXT_SCHEMA
8
8
  from ..types import LvBoolean
@@ -19,7 +19,7 @@ class CheckboxType(WidgetType):
19
19
  (CONF_MAIN, CONF_INDICATOR),
20
20
  TEXT_SCHEMA.extend(
21
21
  {
22
- Optional(CONF_PAD_COLUMN): pixels,
22
+ Optional(CONF_PAD_COLUMN): padding,
23
23
  }
24
24
  ),
25
25
  )
@@ -36,7 +36,6 @@ DROPDOWN_BASE_SCHEMA = cv.Schema(
36
36
  cv.Optional(CONF_SYMBOL): lv_text,
37
37
  cv.Exclusive(CONF_SELECTED_INDEX, CONF_SELECTED_TEXT): lv_int,
38
38
  cv.Exclusive(CONF_SELECTED_TEXT, CONF_SELECTED_TEXT): lv_text,
39
- cv.Optional(CONF_DIR, default="BOTTOM"): DIRECTIONS.one_of,
40
39
  cv.Optional(CONF_DROPDOWN_LIST): part_schema(dropdown_list_spec.parts),
41
40
  }
42
41
  )
@@ -44,12 +43,14 @@ DROPDOWN_BASE_SCHEMA = cv.Schema(
44
43
  DROPDOWN_SCHEMA = DROPDOWN_BASE_SCHEMA.extend(
45
44
  {
46
45
  cv.Required(CONF_OPTIONS): cv.ensure_list(option_string),
46
+ cv.Optional(CONF_DIR, default="BOTTOM"): DIRECTIONS.one_of,
47
47
  }
48
48
  )
49
49
 
50
50
  DROPDOWN_UPDATE_SCHEMA = DROPDOWN_BASE_SCHEMA.extend(
51
51
  {
52
52
  cv.Optional(CONF_OPTIONS): cv.ensure_list(option_string),
53
+ cv.Optional(CONF_DIR): DIRECTIONS.one_of,
53
54
  }
54
55
  )
55
56
 
@@ -10,7 +10,7 @@ from ..defines import (
10
10
  CONF_ZOOM,
11
11
  LvConstant,
12
12
  )
13
- from ..lv_validation import angle, lv_bool, lv_image, size, zoom
13
+ from ..lv_validation import lv_angle, lv_bool, lv_image, size, zoom
14
14
  from ..lvcode import lv
15
15
  from ..types import lv_img_t
16
16
  from . import Widget, WidgetType
@@ -20,9 +20,9 @@ CONF_IMAGE = "image"
20
20
 
21
21
  BASE_IMG_SCHEMA = cv.Schema(
22
22
  {
23
- cv.Optional(CONF_PIVOT_X, default="50%"): size,
24
- cv.Optional(CONF_PIVOT_Y, default="50%"): size,
25
- cv.Optional(CONF_ANGLE): angle,
23
+ cv.Optional(CONF_PIVOT_X): size,
24
+ cv.Optional(CONF_PIVOT_Y): size,
25
+ cv.Optional(CONF_ANGLE): lv_angle,
26
26
  cv.Optional(CONF_ZOOM): zoom,
27
27
  cv.Optional(CONF_OFFSET_X): size,
28
28
  cv.Optional(CONF_OFFSET_Y): size,
@@ -63,19 +63,22 @@ class ImgType(WidgetType):
63
63
  async def to_code(self, w: Widget, config):
64
64
  if src := config.get(CONF_SRC):
65
65
  lv.img_set_src(w.obj, await lv_image.process(src))
66
+ if (pivot_x := config.get(CONF_PIVOT_X)) and (
67
+ pivot_y := config.get(CONF_PIVOT_Y)
68
+ ):
69
+ lv.img_set_pivot(
70
+ w.obj, await size.process(pivot_x), await size.process(pivot_y)
71
+ )
66
72
  if (cf_angle := config.get(CONF_ANGLE)) is not None:
67
- pivot_x = config[CONF_PIVOT_X]
68
- pivot_y = config[CONF_PIVOT_Y]
69
- lv.img_set_pivot(w.obj, pivot_x, pivot_y)
70
- lv.img_set_angle(w.obj, cf_angle)
73
+ lv.img_set_angle(w.obj, await lv_angle.process(cf_angle))
71
74
  if (img_zoom := config.get(CONF_ZOOM)) is not None:
72
- lv.img_set_zoom(w.obj, img_zoom)
75
+ lv.img_set_zoom(w.obj, await zoom.process(img_zoom))
73
76
  if (offset := config.get(CONF_OFFSET_X)) is not None:
74
- lv.img_set_offset_x(w.obj, offset)
77
+ lv.img_set_offset_x(w.obj, await size.process(offset))
75
78
  if (offset := config.get(CONF_OFFSET_Y)) is not None:
76
- lv.img_set_offset_y(w.obj, offset)
79
+ lv.img_set_offset_y(w.obj, await size.process(offset))
77
80
  if CONF_ANTIALIAS in config:
78
- lv.img_set_antialias(w.obj, config[CONF_ANTIALIAS])
81
+ lv.img_set_antialias(w.obj, await lv_bool.process(config[CONF_ANTIALIAS]))
79
82
  if mode := config.get(CONF_MODE):
80
83
  await w.set_property("size_mode", mode)
81
84
 
@@ -0,0 +1,134 @@
1
+ import difflib
2
+
3
+ import esphome.codegen as cg
4
+ import esphome.config_validation as cv
5
+ from esphome.const import CONF_FROM, CONF_ID, CONF_TO
6
+ from esphome.core import CORE
7
+ from esphome.cpp_generator import MockObj, VariableDeclarationExpression, add_global
8
+ from esphome.loader import get_component
9
+
10
+ CODEOWNERS = ["@clydebarrow"]
11
+ MULTI_CONF = True
12
+
13
+ map_ = cg.std_ns.class_("map")
14
+
15
+ CONF_ENTRIES = "entries"
16
+ CONF_CLASS = "class"
17
+
18
+
19
+ class IndexType:
20
+ """
21
+ Represents a type of index in a map.
22
+ """
23
+
24
+ def __init__(self, validator, data_type, conversion):
25
+ self.validator = validator
26
+ self.data_type = data_type
27
+ self.conversion = conversion
28
+
29
+
30
+ INDEX_TYPES = {
31
+ "int": IndexType(cv.int_, cg.int_, int),
32
+ "string": IndexType(cv.string, cg.std_string, str),
33
+ }
34
+
35
+
36
+ def to_schema(value):
37
+ """
38
+ Generate a schema for the 'to' field of a map. This can be either one of the index types or a class name.
39
+ :param value:
40
+ :return:
41
+ """
42
+ return cv.Any(
43
+ cv.one_of(*INDEX_TYPES, lower=True),
44
+ cv.one_of(*CORE.id_classes.keys()),
45
+ )(value)
46
+
47
+
48
+ BASE_SCHEMA = cv.Schema(
49
+ {
50
+ cv.Required(CONF_ID): cv.declare_id(map_),
51
+ cv.Required(CONF_FROM): cv.one_of(*INDEX_TYPES, lower=True),
52
+ cv.Required(CONF_TO): cv.string,
53
+ },
54
+ extra=cv.ALLOW_EXTRA,
55
+ )
56
+
57
+
58
+ def get_object_type(to_):
59
+ """
60
+ Get the object type from a string. Possible formats:
61
+ xxx The name of a component which defines INSTANCE_TYPE
62
+ esphome::xxx::yyy A C++ class name defined in a component
63
+ xxx::yyy A C++ class name defined in a component
64
+ yyy A C++ class name defined in the core
65
+ """
66
+
67
+ if cls := CORE.id_classes.get(to_):
68
+ return cls
69
+ if cls := CORE.id_classes.get(to_.removeprefix("esphome::")):
70
+ return cls
71
+ # get_component will throw a wobbly if we don't check this first.
72
+ if "." in to_:
73
+ return None
74
+ if component := get_component(to_):
75
+ return component.instance_type
76
+ return None
77
+
78
+
79
+ def map_schema(config):
80
+ config = BASE_SCHEMA(config)
81
+ if CONF_ENTRIES not in config or not isinstance(config[CONF_ENTRIES], dict):
82
+ raise cv.Invalid("an entries list is required for a map")
83
+ entries = config[CONF_ENTRIES]
84
+ if len(entries) == 0:
85
+ raise cv.Invalid("Map must have at least one entry")
86
+ to_ = config[CONF_TO]
87
+ if to_ in INDEX_TYPES:
88
+ value_type = INDEX_TYPES[to_].validator
89
+ else:
90
+ value_type = get_object_type(to_)
91
+ if value_type is None:
92
+ matches = difflib.get_close_matches(to_, CORE.id_classes)
93
+ raise cv.Invalid(
94
+ f"No known mappable class name matches '{to_}'; did you mean one of {', '.join(matches)}?"
95
+ )
96
+ value_type = cv.use_id(value_type)
97
+ config[CONF_ENTRIES] = {k: value_type(v) for k, v in entries.items()}
98
+ return config
99
+
100
+
101
+ CONFIG_SCHEMA = map_schema
102
+
103
+
104
+ async def to_code(config):
105
+ entries = config[CONF_ENTRIES]
106
+ from_ = config[CONF_FROM]
107
+ to_ = config[CONF_TO]
108
+ index_conversion = INDEX_TYPES[from_].conversion
109
+ index_type = INDEX_TYPES[from_].data_type
110
+ if to_ in INDEX_TYPES:
111
+ value_conversion = INDEX_TYPES[to_].conversion
112
+ value_type = INDEX_TYPES[to_].data_type
113
+ entries = {
114
+ index_conversion(key): value_conversion(value)
115
+ for key, value in entries.items()
116
+ }
117
+ else:
118
+ entries = {
119
+ index_conversion(key): await cg.get_variable(value)
120
+ for key, value in entries.items()
121
+ }
122
+ value_type = get_object_type(to_)
123
+ if list(entries.values())[0].op != ".":
124
+ value_type = value_type.operator("ptr")
125
+ varid = config[CONF_ID]
126
+ varid.type = map_.template(index_type, value_type)
127
+ var = MockObj(varid, ".")
128
+ decl = VariableDeclarationExpression(varid.type, "", varid)
129
+ add_global(decl)
130
+ CORE.register_variable(varid, var)
131
+
132
+ for key, value in entries.items():
133
+ cg.add(var.insert((key, value)))
134
+ return var
@@ -4,6 +4,8 @@
4
4
  #include "esphome/core/hal.h"
5
5
  #include "max7219font.h"
6
6
 
7
+ #include <algorithm>
8
+
7
9
  namespace esphome {
8
10
  namespace max7219digit {
9
11
 
@@ -61,45 +63,42 @@ void MAX7219Component::dump_config() {
61
63
  }
62
64
 
63
65
  void MAX7219Component::loop() {
64
- uint32_t now = millis();
65
-
66
+ const uint32_t now = millis();
67
+ const uint32_t millis_since_last_scroll = now - this->last_scroll_;
68
+ const size_t first_line_size = this->max_displaybuffer_[0].size();
66
69
  // check if the buffer has shrunk past the current position since last update
67
- if ((this->max_displaybuffer_[0].size() >= this->old_buffer_size_ + 3) ||
68
- (this->max_displaybuffer_[0].size() <= this->old_buffer_size_ - 3)) {
70
+ if ((first_line_size >= this->old_buffer_size_ + 3) || (first_line_size <= this->old_buffer_size_ - 3)) {
71
+ ESP_LOGV(TAG, "Buffer size changed %d to %d", this->old_buffer_size_, first_line_size);
69
72
  this->stepsleft_ = 0;
70
73
  this->display();
71
- this->old_buffer_size_ = this->max_displaybuffer_[0].size();
74
+ this->old_buffer_size_ = first_line_size;
72
75
  }
73
76
 
74
- // Reset the counter back to 0 when full string has been displayed.
75
- if (this->stepsleft_ > this->max_displaybuffer_[0].size())
76
- this->stepsleft_ = 0;
77
-
78
- // Return if there is no need to scroll or scroll is off
79
- if (!this->scroll_ || (this->max_displaybuffer_[0].size() <= (size_t) get_width_internal())) {
77
+ if (!this->scroll_ || (first_line_size <= (size_t) get_width_internal())) {
78
+ ESP_LOGVV(TAG, "Return if there is no need to scroll or scroll is off.");
80
79
  this->display();
81
80
  return;
82
81
  }
83
82
 
84
- if ((this->stepsleft_ == 0) && (now - this->last_scroll_ < this->scroll_delay_)) {
83
+ if ((this->stepsleft_ == 0) && (millis_since_last_scroll < this->scroll_delay_)) {
84
+ ESP_LOGVV(TAG, "At first step. Waiting for scroll delay");
85
85
  this->display();
86
86
  return;
87
87
  }
88
88
 
89
- // Dwell time at end of string in case of stop at end
90
89
  if (this->scroll_mode_ == ScrollMode::STOP) {
91
- if (this->stepsleft_ >= this->max_displaybuffer_[0].size() - (size_t) get_width_internal() + 1) {
92
- if (now - this->last_scroll_ >= this->scroll_dwell_) {
93
- this->stepsleft_ = 0;
94
- this->last_scroll_ = now;
95
- this->display();
90
+ if (this->stepsleft_ + get_width_internal() == first_line_size + 1) {
91
+ if (millis_since_last_scroll < this->scroll_dwell_) {
92
+ ESP_LOGVV(TAG, "Dwell time at end of string in case of stop at end. Step %d, since last scroll %d, dwell %d.",
93
+ this->stepsleft_, millis_since_last_scroll, this->scroll_dwell_);
94
+ return;
96
95
  }
97
- return;
96
+ ESP_LOGV(TAG, "Dwell time passed. Continue scrolling.");
98
97
  }
99
98
  }
100
99
 
101
- // Actual call to scroll left action
102
- if (now - this->last_scroll_ >= this->scroll_speed_) {
100
+ if (millis_since_last_scroll >= this->scroll_speed_) {
101
+ ESP_LOGVV(TAG, "Call to scroll left action");
103
102
  this->last_scroll_ = now;
104
103
  this->scroll_left();
105
104
  this->display();
@@ -227,19 +226,20 @@ void MAX7219Component::scroll(bool on_off) { this->set_scroll(on_off); }
227
226
 
228
227
  void MAX7219Component::scroll_left() {
229
228
  for (int chip_line = 0; chip_line < this->num_chip_lines_; chip_line++) {
229
+ auto scroll = [&](std::vector<uint8_t> &line, uint16_t steps) {
230
+ std::rotate(line.begin(), std::next(line.begin(), steps), line.end());
231
+ };
230
232
  if (this->update_) {
231
233
  this->max_displaybuffer_[chip_line].push_back(this->bckgrnd_);
232
- for (uint16_t i = 0; i < this->stepsleft_; i++) {
233
- this->max_displaybuffer_[chip_line].push_back(this->max_displaybuffer_[chip_line].front());
234
- this->max_displaybuffer_[chip_line].erase(this->max_displaybuffer_[chip_line].begin());
235
- }
234
+ scroll(this->max_displaybuffer_[chip_line],
235
+ (this->stepsleft_ + 1) % (this->max_displaybuffer_[chip_line].size()));
236
236
  } else {
237
- this->max_displaybuffer_[chip_line].push_back(this->max_displaybuffer_[chip_line].front());
238
- this->max_displaybuffer_[chip_line].erase(this->max_displaybuffer_[chip_line].begin());
237
+ scroll(this->max_displaybuffer_[chip_line], 1);
239
238
  }
240
239
  }
241
240
  this->update_ = false;
242
241
  this->stepsleft_++;
242
+ this->stepsleft_ %= this->max_displaybuffer_[0].size();
243
243
  }
244
244
 
245
245
  void MAX7219Component::send_char(uint8_t chip, uint8_t data) {
@@ -35,8 +35,8 @@ SERVICE_SCHEMA = cv.Schema(
35
35
  {
36
36
  cv.Required(CONF_SERVICE): cv.string,
37
37
  cv.Required(CONF_PROTOCOL): cv.string,
38
- cv.Optional(CONF_PORT, default=0): cv.Any(0, cv.port),
39
- cv.Optional(CONF_TXT, default={}): {cv.string: cv.string},
38
+ cv.Optional(CONF_PORT, default=0): cv.templatable(cv.Any(0, cv.port)),
39
+ cv.Optional(CONF_TXT, default={}): {cv.string: cv.templatable(cv.string)},
40
40
  }
41
41
  )
42
42
 
@@ -102,12 +102,18 @@ async def to_code(config):
102
102
 
103
103
  for service in config[CONF_SERVICES]:
104
104
  txt = [
105
- mdns_txt_record(txt_key, txt_value)
105
+ cg.StructInitializer(
106
+ MDNSTXTRecord,
107
+ ("key", txt_key),
108
+ ("value", await cg.templatable(txt_value, [], cg.std_string)),
109
+ )
106
110
  for txt_key, txt_value in service[CONF_TXT].items()
107
111
  ]
108
-
109
112
  exp = mdns_service(
110
- service[CONF_SERVICE], service[CONF_PROTOCOL], service[CONF_PORT], txt
113
+ service[CONF_SERVICE],
114
+ service[CONF_PROTOCOL],
115
+ await cg.templatable(service[CONF_PORT], [], cg.uint16),
116
+ txt,
111
117
  )
112
118
 
113
119
  cg.add(var.add_extra_service(exp))
@@ -1,9 +1,9 @@
1
1
  #include "esphome/core/defines.h"
2
2
  #ifdef USE_MDNS
3
- #include "mdns_component.h"
4
- #include "esphome/core/version.h"
5
3
  #include "esphome/core/application.h"
6
4
  #include "esphome/core/log.h"
5
+ #include "esphome/core/version.h"
6
+ #include "mdns_component.h"
7
7
 
8
8
  #ifdef USE_API
9
9
  #include "esphome/components/api/api_server.h"
@@ -62,7 +62,11 @@ void MDNSComponent::compile_records_() {
62
62
  #endif
63
63
 
64
64
  #ifdef USE_API_NOISE
65
- service.txt_records.push_back({"api_encryption", "Noise_NNpsk0_25519_ChaChaPoly_SHA256"});
65
+ if (api::global_api_server->get_noise_ctx()->has_psk()) {
66
+ service.txt_records.push_back({"api_encryption", "Noise_NNpsk0_25519_ChaChaPoly_SHA256"});
67
+ } else {
68
+ service.txt_records.push_back({"api_encryption_supported", "Noise_NNpsk0_25519_ChaChaPoly_SHA256"});
69
+ }
66
70
  #endif
67
71
 
68
72
  #ifdef ESPHOME_PROJECT_NAME
@@ -117,9 +121,11 @@ void MDNSComponent::dump_config() {
117
121
  ESP_LOGCONFIG(TAG, " Hostname: %s", this->hostname_.c_str());
118
122
  ESP_LOGV(TAG, " Services:");
119
123
  for (const auto &service : this->services_) {
120
- ESP_LOGV(TAG, " - %s, %s, %d", service.service_type.c_str(), service.proto.c_str(), service.port);
124
+ ESP_LOGV(TAG, " - %s, %s, %d", service.service_type.c_str(), service.proto.c_str(),
125
+ const_cast<TemplatableValue<uint16_t> &>(service.port).value());
121
126
  for (const auto &record : service.txt_records) {
122
- ESP_LOGV(TAG, " TXT: %s = %s", record.key.c_str(), record.value.c_str());
127
+ ESP_LOGV(TAG, " TXT: %s = %s", record.key.c_str(),
128
+ const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
123
129
  }
124
130
  }
125
131
  }
@@ -3,6 +3,7 @@
3
3
  #ifdef USE_MDNS
4
4
  #include <string>
5
5
  #include <vector>
6
+ #include "esphome/core/automation.h"
6
7
  #include "esphome/core/component.h"
7
8
 
8
9
  namespace esphome {
@@ -10,7 +11,7 @@ namespace mdns {
10
11
 
11
12
  struct MDNSTXTRecord {
12
13
  std::string key;
13
- std::string value;
14
+ TemplatableValue<std::string> value;
14
15
  };
15
16
 
16
17
  struct MDNSService {
@@ -20,7 +21,7 @@ struct MDNSService {
20
21
  // second label indicating protocol _including_ underscore character prefix
21
22
  // as defined in RFC6763 Section 7, like "_tcp" or "_udp"
22
23
  std::string proto;
23
- uint16_t port;
24
+ TemplatableValue<uint16_t> port;
24
25
  std::vector<MDNSTXTRecord> txt_records;
25
26
  };
26
27
 
@@ -31,11 +31,12 @@ void MDNSComponent::setup() {
31
31
  mdns_txt_item_t it{};
32
32
  // dup strings to ensure the pointer is valid even after the record loop
33
33
  it.key = strdup(record.key.c_str());
34
- it.value = strdup(record.value.c_str());
34
+ it.value = strdup(const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
35
35
  txt_records.push_back(it);
36
36
  }
37
- err = mdns_service_add(nullptr, service.service_type.c_str(), service.proto.c_str(), service.port,
38
- txt_records.data(), txt_records.size());
37
+ uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
38
+ err = mdns_service_add(nullptr, service.service_type.c_str(), service.proto.c_str(), port, txt_records.data(),
39
+ txt_records.size());
39
40
 
40
41
  // free records
41
42
  for (const auto &it : txt_records) {
@@ -29,9 +29,11 @@ void MDNSComponent::setup() {
29
29
  while (*service_type == '_') {
30
30
  service_type++;
31
31
  }
32
- MDNS.addService(service_type, proto, service.port);
32
+ uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
33
+ MDNS.addService(service_type, proto, port);
33
34
  for (const auto &record : service.txt_records) {
34
- MDNS.addServiceTxt(service_type, proto, record.key.c_str(), record.value.c_str());
35
+ MDNS.addServiceTxt(service_type, proto, record.key.c_str(),
36
+ const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
35
37
  }
36
38
  }
37
39
  }
@@ -29,9 +29,11 @@ void MDNSComponent::setup() {
29
29
  while (*service_type == '_') {
30
30
  service_type++;
31
31
  }
32
- MDNS.addService(service_type, proto, service.port);
32
+ uint16_t port_ = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
33
+ MDNS.addService(service_type, proto, port_);
33
34
  for (const auto &record : service.txt_records) {
34
- MDNS.addServiceTxt(service_type, proto, record.key.c_str(), record.value.c_str());
35
+ MDNS.addServiceTxt(service_type, proto, record.key.c_str(),
36
+ const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
35
37
  }
36
38
  }
37
39
  }
@@ -29,9 +29,11 @@ void MDNSComponent::setup() {
29
29
  while (*service_type == '_') {
30
30
  service_type++;
31
31
  }
32
- MDNS.addService(service_type, proto, service.port);
32
+ uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
33
+ MDNS.addService(service_type, proto, port);
33
34
  for (const auto &record : service.txt_records) {
34
- MDNS.addServiceTxt(service_type, proto, record.key.c_str(), record.value.c_str());
35
+ MDNS.addServiceTxt(service_type, proto, record.key.c_str(),
36
+ const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
35
37
  }
36
38
  }
37
39
  }