esphome 2025.6.3__py3-none-any.whl → 2025.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (646) hide show
  1. esphome/__main__.py +1 -3
  2. esphome/codegen.py +2 -0
  3. esphome/components/ac_dimmer/ac_dimmer.cpp +6 -6
  4. esphome/components/adc/__init__.py +25 -1
  5. esphome/components/adc/adc_sensor.h +11 -11
  6. esphome/components/adc/adc_sensor_common.cpp +1 -1
  7. esphome/components/adc/adc_sensor_esp32.cpp +16 -8
  8. esphome/components/ade7880/ade7880.h +0 -2
  9. esphome/components/ads1115/ads1115.h +0 -1
  10. esphome/components/ads1118/ads1118.h +0 -1
  11. esphome/components/ags10/ags10.h +0 -2
  12. esphome/components/aic3204/aic3204.h +0 -1
  13. esphome/components/alarm_control_panel/__init__.py +5 -2
  14. esphome/components/alpha3/alpha3.h +0 -1
  15. esphome/components/am43/cover/am43_cover.h +0 -1
  16. esphome/components/am43/sensor/am43_sensor.h +0 -1
  17. esphome/components/analog_threshold/analog_threshold_binary_sensor.h +0 -2
  18. esphome/components/anova/anova.cpp +5 -1
  19. esphome/components/anova/anova.h +0 -1
  20. esphome/components/apds9960/apds9960.cpp +1 -1
  21. esphome/components/api/__init__.py +57 -21
  22. esphome/components/api/api_connection.cpp +344 -539
  23. esphome/components/api/api_connection.h +224 -141
  24. esphome/components/api/api_frame_helper.cpp +91 -127
  25. esphome/components/api/api_frame_helper.h +64 -54
  26. esphome/components/api/api_pb2.cpp +1837 -9044
  27. esphome/components/api/api_pb2.h +532 -685
  28. esphome/components/api/api_pb2_dump.cpp +4432 -0
  29. esphome/components/api/api_pb2_service.cpp +184 -425
  30. esphome/components/api/api_pb2_service.h +13 -6
  31. esphome/components/api/api_server.cpp +131 -167
  32. esphome/components/api/api_server.h +38 -10
  33. esphome/components/api/client.py +8 -2
  34. esphome/components/api/custom_api_device.h +8 -0
  35. esphome/components/api/list_entities.cpp +37 -104
  36. esphome/components/api/list_entities.h +33 -23
  37. esphome/components/api/proto.h +532 -26
  38. esphome/components/api/subscribe_state.cpp +23 -29
  39. esphome/components/api/subscribe_state.h +26 -19
  40. esphome/components/api/user_services.h +2 -0
  41. esphome/components/as3935_spi/as3935_spi.h +0 -2
  42. esphome/components/as5600/as5600.h +0 -1
  43. esphome/components/async_tcp/__init__.py +14 -5
  44. esphome/components/atc_mithermometer/atc_mithermometer.h +0 -1
  45. esphome/components/atm90e32/atm90e32.cpp +2 -1
  46. esphome/components/audio/audio_decoder.cpp +1 -1
  47. esphome/components/audio/audio_transfer_buffer.cpp +2 -2
  48. esphome/components/b_parasite/b_parasite.h +0 -1
  49. esphome/components/bedjet/bedjet_hub.cpp +5 -1
  50. esphome/components/bedjet/climate/bedjet_climate.cpp +5 -1
  51. esphome/components/beken_spi_led_strip/led_strip.cpp +4 -2
  52. esphome/components/bh1750/bh1750.cpp +5 -5
  53. esphome/components/binary_sensor/__init__.py +82 -5
  54. esphome/components/binary_sensor/automation.h +19 -1
  55. esphome/components/binary_sensor/binary_sensor.cpp +12 -30
  56. esphome/components/binary_sensor/binary_sensor.h +11 -25
  57. esphome/components/binary_sensor/filter.cpp +29 -24
  58. esphome/components/binary_sensor/filter.h +20 -10
  59. esphome/components/ble_client/output/ble_binary_output.h +0 -1
  60. esphome/components/ble_client/sensor/ble_rssi_sensor.cpp +5 -1
  61. esphome/components/ble_client/sensor/ble_rssi_sensor.h +0 -1
  62. esphome/components/ble_client/sensor/ble_sensor.cpp +5 -1
  63. esphome/components/ble_client/sensor/ble_sensor.h +0 -1
  64. esphome/components/ble_client/switch/ble_switch.h +0 -1
  65. esphome/components/ble_client/text_sensor/ble_text_sensor.cpp +5 -1
  66. esphome/components/ble_client/text_sensor/ble_text_sensor.h +0 -1
  67. esphome/components/ble_presence/ble_presence_device.h +0 -1
  68. esphome/components/ble_rssi/ble_rssi_sensor.h +0 -1
  69. esphome/components/ble_scanner/ble_scanner.h +0 -1
  70. esphome/components/bluetooth_proxy/bluetooth_connection.h +9 -2
  71. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +16 -6
  72. esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -2
  73. esphome/components/bme680/sensor.py +1 -1
  74. esphome/components/bmp581/bmp581.h +0 -2
  75. esphome/components/button/__init__.py +5 -2
  76. esphome/components/camera/__init__.py +1 -0
  77. esphome/components/camera/camera.cpp +22 -0
  78. esphome/components/camera/camera.h +80 -0
  79. esphome/components/canbus/__init__.py +1 -0
  80. esphome/components/cap1188/cap1188.h +0 -1
  81. esphome/components/captive_portal/__init__.py +12 -2
  82. esphome/components/captive_portal/captive_portal.cpp +12 -2
  83. esphome/components/captive_portal/captive_portal.h +5 -2
  84. esphome/components/ccs811/ccs811.h +0 -2
  85. esphome/components/climate/__init__.py +5 -2
  86. esphome/components/cm1106/sensor.py +2 -2
  87. esphome/components/const/__init__.py +2 -0
  88. esphome/components/copy/binary_sensor/copy_binary_sensor.h +0 -1
  89. esphome/components/copy/button/copy_button.h +0 -1
  90. esphome/components/copy/cover/copy_cover.h +0 -1
  91. esphome/components/copy/fan/copy_fan.h +0 -1
  92. esphome/components/copy/lock/copy_lock.h +0 -1
  93. esphome/components/copy/number/copy_number.h +0 -1
  94. esphome/components/copy/select/copy_select.h +0 -1
  95. esphome/components/copy/sensor/copy_sensor.h +0 -1
  96. esphome/components/copy/switch/copy_switch.h +0 -1
  97. esphome/components/copy/text/copy_text.h +0 -1
  98. esphome/components/copy/text_sensor/copy_text_sensor.h +0 -1
  99. esphome/components/cover/__init__.py +5 -2
  100. esphome/components/cs5460a/cs5460a.h +0 -1
  101. esphome/components/datetime/__init__.py +4 -2
  102. esphome/components/debug/__init__.py +20 -0
  103. esphome/components/debug/debug_esp32.cpp +2 -0
  104. esphome/components/deep_sleep/__init__.py +43 -9
  105. esphome/components/demo/__init__.py +2 -2
  106. esphome/components/display/display.cpp +4 -3
  107. esphome/components/display/display.h +0 -2
  108. esphome/components/display/display_buffer.cpp +1 -1
  109. esphome/components/ds2484/__init__.py +1 -0
  110. esphome/components/ds2484/ds2484.cpp +209 -0
  111. esphome/components/ds2484/ds2484.h +43 -0
  112. esphome/components/ds2484/one_wire.py +37 -0
  113. esphome/components/duty_time/duty_time_sensor.h +0 -1
  114. esphome/components/ens160_base/ens160_base.h +0 -1
  115. esphome/components/es7210/es7210.h +0 -1
  116. esphome/components/es7243e/es7243e.h +0 -1
  117. esphome/components/es8156/es8156.h +0 -1
  118. esphome/components/es8311/es8311.h +0 -1
  119. esphome/components/es8388/es8388.h +0 -1
  120. esphome/components/esp32/__init__.py +103 -135
  121. esphome/components/esp32/core.cpp +0 -4
  122. esphome/components/esp32/gpio.h +1 -1
  123. esphome/components/esp32/helpers.cpp +69 -0
  124. esphome/components/esp32_ble/ble.cpp +5 -6
  125. esphome/components/esp32_ble/ble.h +29 -14
  126. esphome/components/esp32_ble/ble_event.h +6 -6
  127. esphome/components/esp32_ble_client/ble_client_base.cpp +21 -6
  128. esphome/components/esp32_ble_client/ble_client_base.h +24 -9
  129. esphome/components/esp32_ble_tracker/__init__.py +2 -8
  130. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +5 -5
  131. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +11 -7
  132. esphome/components/esp32_camera/__init__.py +112 -98
  133. esphome/components/esp32_camera/esp32_camera.cpp +41 -31
  134. esphome/components/esp32_camera/esp32_camera.h +35 -30
  135. esphome/components/esp32_camera_web_server/__init__.py +2 -1
  136. esphome/components/esp32_camera_web_server/camera_web_server.cpp +8 -8
  137. esphome/components/esp32_camera_web_server/camera_web_server.h +3 -3
  138. esphome/components/esp32_hall/sensor.py +2 -21
  139. esphome/components/esp32_hosted/__init__.py +101 -0
  140. esphome/components/esp32_hosted/esp32_hosted.py.script +12 -0
  141. esphome/components/esp32_improv/esp32_improv_component.cpp +3 -0
  142. esphome/components/esp32_rmt/__init__.py +0 -58
  143. esphome/components/esp32_rmt_led_strip/led_strip.cpp +77 -63
  144. esphome/components/esp32_rmt_led_strip/led_strip.h +11 -17
  145. esphome/components/esp32_rmt_led_strip/light.py +14 -76
  146. esphome/components/esp32_touch/esp32_touch.h +174 -28
  147. esphome/components/esp32_touch/esp32_touch_common.cpp +162 -0
  148. esphome/components/esp32_touch/esp32_touch_v1.cpp +240 -0
  149. esphome/components/esp32_touch/esp32_touch_v2.cpp +397 -0
  150. esphome/components/esp8266/__init__.py +2 -0
  151. esphome/components/esp8266/gpio.cpp +10 -10
  152. esphome/components/esp8266/helpers.cpp +31 -0
  153. esphome/components/esp_ldo/__init__.py +10 -8
  154. esphome/components/esp_ldo/esp_ldo.h +3 -0
  155. esphome/components/esphome/ota/__init__.py +1 -0
  156. esphome/components/esphome/ota/ota_esphome.cpp +24 -19
  157. esphome/components/ethernet/__init__.py +42 -23
  158. esphome/components/ethernet/esp_eth_phy_jl1101.c +0 -16
  159. esphome/components/ethernet/ethernet_component.cpp +69 -29
  160. esphome/components/ethernet/ethernet_component.h +18 -10
  161. esphome/components/event/__init__.py +5 -2
  162. esphome/components/ezo/ezo.h +0 -1
  163. esphome/components/ezo_pmp/ezo_pmp.h +0 -1
  164. esphome/components/fan/__init__.py +5 -2
  165. esphome/components/fan/fan.cpp +4 -0
  166. esphome/components/feedback/feedback_cover.h +0 -1
  167. esphome/components/font/__init__.py +92 -82
  168. esphome/components/font/font.cpp +9 -2
  169. esphome/components/font/font.h +20 -5
  170. esphome/components/fs3000/fs3000.h +0 -1
  171. esphome/components/gcja5/gcja5.h +0 -1
  172. esphome/components/gl_r01_i2c/__init__.py +0 -0
  173. esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +68 -0
  174. esphome/components/gl_r01_i2c/gl_r01_i2c.h +22 -0
  175. esphome/components/gl_r01_i2c/sensor.py +36 -0
  176. esphome/components/gp8403/gp8403.h +0 -1
  177. esphome/components/gpio/binary_sensor/__init__.py +39 -1
  178. esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +77 -3
  179. esphome/components/gpio/binary_sensor/gpio_binary_sensor.h +40 -0
  180. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +0 -2
  181. esphome/components/he60r/he60r.h +0 -1
  182. esphome/components/heatpumpir/climate.py +2 -1
  183. esphome/components/heatpumpir/heatpumpir.cpp +1 -0
  184. esphome/components/heatpumpir/heatpumpir.h +1 -0
  185. esphome/components/honeywellabp2_i2c/honeywellabp2.h +0 -1
  186. esphome/components/host/__init__.py +3 -1
  187. esphome/components/host/helpers.cpp +57 -0
  188. esphome/components/http_request/__init__.py +19 -1
  189. esphome/components/http_request/http_request.h +1 -1
  190. esphome/components/http_request/http_request_arduino.h +1 -0
  191. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  192. esphome/components/http_request/update/http_request_update.cpp +35 -16
  193. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +3 -9
  194. esphome/components/hydreon_rgxx/sensor.py +1 -1
  195. esphome/components/i2c/__init__.py +23 -11
  196. esphome/components/i2c/i2c_bus.h +8 -1
  197. esphome/components/i2c/i2c_bus_arduino.cpp +4 -3
  198. esphome/components/i2c/i2c_bus_arduino.h +6 -3
  199. esphome/components/i2c/i2c_bus_esp_idf.h +5 -3
  200. esphome/components/i2c_device/i2c_device.h +0 -1
  201. esphome/components/i2s_audio/__init__.py +2 -10
  202. esphome/components/i2s_audio/i2s_audio.cpp +1 -5
  203. esphome/components/i2s_audio/media_player/__init__.py +2 -2
  204. esphome/components/i2s_audio/speaker/__init__.py +1 -1
  205. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +2 -2
  206. esphome/components/iaqcore/iaqcore.h +0 -2
  207. esphome/components/image/__init__.py +123 -24
  208. esphome/components/improv_serial/improv_serial_component.cpp +0 -4
  209. esphome/components/ina219/ina219.cpp +7 -0
  210. esphome/components/ina219/ina219.h +1 -0
  211. esphome/components/ina260/ina260.h +0 -2
  212. esphome/components/inkbird_ibsth1_mini/inkbird_ibsth1_mini.h +0 -1
  213. esphome/components/inkplate6/display.py +15 -0
  214. esphome/components/inkplate6/inkplate.cpp +2 -2
  215. esphome/components/integration/integration_sensor.h +0 -1
  216. esphome/components/internal_temperature/internal_temperature.cpp +8 -27
  217. esphome/components/internal_temperature/sensor.py +0 -26
  218. esphome/components/interval/interval.h +0 -2
  219. esphome/components/json/__init__.py +1 -1
  220. esphome/components/json/json_util.cpp +56 -63
  221. esphome/components/ld2410/button/__init__.py +3 -3
  222. esphome/components/ld2410/button/factory_reset_button.cpp +9 -0
  223. esphome/components/ld2410/button/{reset_button.h → factory_reset_button.h} +2 -2
  224. esphome/components/ld2410/ld2410.cpp +421 -268
  225. esphome/components/ld2410/ld2410.h +44 -146
  226. esphome/components/ld2410/number/__init__.py +2 -2
  227. esphome/components/ld2410/sensor.py +1 -1
  228. esphome/components/ld2410/switch/__init__.py +1 -1
  229. esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp +2 -2
  230. esphome/components/ld2420/button/reconfig_buttons.cpp +1 -1
  231. esphome/components/ld2420/ld2420.cpp +252 -147
  232. esphome/components/ld2420/ld2420.h +52 -126
  233. esphome/components/ld2420/number/__init__.py +2 -2
  234. esphome/components/ld2420/number/gate_config_number.cpp +1 -1
  235. esphome/components/ld2420/select/operating_mode_select.cpp +1 -1
  236. esphome/components/ld2420/sensor/__init__.py +6 -2
  237. esphome/components/ld2420/sensor/ld2420_sensor.cpp +2 -2
  238. esphome/components/ld2420/sensor/ld2420_sensor.h +1 -1
  239. esphome/components/ld2420/text_sensor/text_sensor.cpp +2 -2
  240. esphome/components/ld2450/button/__init__.py +3 -3
  241. esphome/components/ld2450/button/factory_reset_button.cpp +9 -0
  242. esphome/components/ld2450/button/{reset_button.h → factory_reset_button.h} +2 -2
  243. esphome/components/ld2450/ld2450.cpp +384 -232
  244. esphome/components/ld2450/ld2450.h +60 -69
  245. esphome/components/ld2450/switch/__init__.py +1 -1
  246. esphome/components/ledc/ledc_output.cpp +1 -63
  247. esphome/components/libretiny/__init__.py +5 -3
  248. esphome/components/libretiny/const.py +5 -0
  249. esphome/components/libretiny/generate_components.py +1 -0
  250. esphome/components/libretiny/helpers.cpp +35 -0
  251. esphome/components/libretiny/lt_component.cpp +5 -3
  252. esphome/components/light/__init__.py +4 -2
  253. esphome/components/light/addressable_light.h +3 -3
  254. esphome/components/light/light_call.cpp +180 -243
  255. esphome/components/light/light_call.h +72 -20
  256. esphome/components/light/light_color_values.h +14 -14
  257. esphome/components/light/light_json_schema.cpp +17 -16
  258. esphome/components/light/light_state.h +15 -13
  259. esphome/components/light/transformers.h +2 -2
  260. esphome/components/ln882x/__init__.py +52 -0
  261. esphome/components/ln882x/boards.py +285 -0
  262. esphome/components/lock/__init__.py +5 -2
  263. esphome/components/logger/__init__.py +40 -3
  264. esphome/components/logger/logger.cpp +47 -12
  265. esphome/components/logger/logger.h +80 -49
  266. esphome/components/logger/logger_esp32.cpp +3 -3
  267. esphome/components/lps22/__init__.py +0 -0
  268. esphome/components/lps22/lps22.cpp +75 -0
  269. esphome/components/lps22/lps22.h +27 -0
  270. esphome/components/lps22/sensor.py +58 -0
  271. esphome/components/ltr390/ltr390.h +0 -1
  272. esphome/components/ltr501/ltr501.h +0 -1
  273. esphome/components/ltr_als_ps/ltr_als_ps.h +0 -1
  274. esphome/components/lvgl/__init__.py +1 -1
  275. esphome/components/lvgl/schemas.py +66 -6
  276. esphome/components/lvgl/styles.py +24 -16
  277. esphome/components/lvgl/widgets/__init__.py +12 -2
  278. esphome/components/lvgl/widgets/lv_bar.py +40 -19
  279. esphome/components/lvgl/widgets/meter.py +20 -13
  280. esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +1 -1
  281. esphome/components/max9611/max9611.h +0 -1
  282. esphome/components/mcp23016/__init__.py +1 -1
  283. esphome/components/mcp23xxx_base/__init__.py +1 -1
  284. esphome/components/mcp4461/__init__.py +1 -1
  285. esphome/components/mcp4461/output/__init__.py +3 -2
  286. esphome/components/mcp9600/mcp9600.h +0 -2
  287. esphome/components/md5/md5.cpp +3 -3
  288. esphome/components/md5/md5.h +1 -6
  289. esphome/components/mdns/__init__.py +22 -11
  290. esphome/components/media_player/__init__.py +4 -3
  291. esphome/components/micro_wake_word/__init__.py +1 -5
  292. esphome/components/micro_wake_word/streaming_model.cpp +2 -2
  293. esphome/components/microphone/microphone.cpp +7 -9
  294. esphome/components/microphone/microphone.h +0 -2
  295. esphome/components/mipi_spi/display.py +1 -0
  296. esphome/components/mmc5603/mmc5603.cpp +1 -1
  297. esphome/components/modbus/modbus.cpp +33 -15
  298. esphome/components/modbus/modbus.h +9 -0
  299. esphome/components/modbus_controller/__init__.py +42 -10
  300. esphome/components/modbus_controller/modbus_controller.cpp +92 -11
  301. esphome/components/modbus_controller/modbus_controller.h +61 -7
  302. esphome/components/mopeka_pro_check/mopeka_pro_check.h +0 -1
  303. esphome/components/mopeka_std_check/mopeka_std_check.h +0 -1
  304. esphome/components/mpl3115a2/mpl3115a2.h +0 -2
  305. esphome/components/mqtt/__init__.py +16 -0
  306. esphome/components/mqtt/mqtt_alarm_control_panel.cpp +2 -1
  307. esphome/components/mqtt/mqtt_backend.h +2 -1
  308. esphome/components/mqtt/mqtt_backend_esp32.cpp +132 -47
  309. esphome/components/mqtt/mqtt_backend_esp32.h +106 -4
  310. esphome/components/mqtt/mqtt_binary_sensor.cpp +1 -0
  311. esphome/components/mqtt/mqtt_button.cpp +4 -1
  312. esphome/components/mqtt/mqtt_client.cpp +17 -9
  313. esphome/components/mqtt/mqtt_client.h +8 -3
  314. esphome/components/mqtt/mqtt_climate.cpp +6 -4
  315. esphome/components/mqtt/mqtt_component.cpp +3 -1
  316. esphome/components/mqtt/mqtt_cover.cpp +1 -0
  317. esphome/components/mqtt/mqtt_date.cpp +4 -3
  318. esphome/components/mqtt/mqtt_datetime.cpp +7 -6
  319. esphome/components/mqtt/mqtt_event.cpp +6 -3
  320. esphome/components/mqtt/mqtt_fan.cpp +1 -0
  321. esphome/components/mqtt/mqtt_light.cpp +8 -4
  322. esphome/components/mqtt/mqtt_lock.cpp +3 -1
  323. esphome/components/mqtt/mqtt_number.cpp +1 -0
  324. esphome/components/mqtt/mqtt_select.cpp +2 -1
  325. esphome/components/mqtt/mqtt_sensor.cpp +3 -1
  326. esphome/components/mqtt/mqtt_switch.cpp +3 -1
  327. esphome/components/mqtt/mqtt_text.cpp +1 -0
  328. esphome/components/mqtt/mqtt_text_sensor.cpp +3 -1
  329. esphome/components/mqtt/mqtt_time.cpp +4 -3
  330. esphome/components/mqtt/mqtt_update.cpp +1 -0
  331. esphome/components/mqtt/mqtt_valve.cpp +3 -1
  332. esphome/components/ms8607/ms8607.cpp +1 -1
  333. esphome/components/ms8607/ms8607.h +0 -1
  334. esphome/components/neopixelbus/light.py +4 -1
  335. esphome/components/neopixelbus/neopixelbus_light.h +1 -1
  336. esphome/components/network/__init__.py +4 -1
  337. esphome/components/network/ip_address.h +1 -0
  338. esphome/components/nextion/__init__.py +16 -0
  339. esphome/components/nextion/base_component.py +1 -0
  340. esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
  341. esphome/components/nextion/display.py +14 -4
  342. esphome/components/nextion/nextion.cpp +166 -101
  343. esphome/components/nextion/nextion.h +84 -53
  344. esphome/components/nextion/nextion_commands.cpp +11 -10
  345. esphome/components/nextion/nextion_component.cpp +28 -28
  346. esphome/components/nextion/nextion_component.h +53 -18
  347. esphome/components/nextion/nextion_component_base.h +3 -0
  348. esphome/components/nextion/nextion_upload.cpp +36 -0
  349. esphome/components/nextion/nextion_upload_arduino.cpp +10 -35
  350. esphome/components/nextion/nextion_upload_idf.cpp +9 -33
  351. esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
  352. esphome/components/nextion/switch/nextion_switch.cpp +1 -1
  353. esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
  354. esphome/components/nfc/nfc.cpp +3 -22
  355. esphome/components/nfc/nfc.h +3 -3
  356. esphome/components/number/__init__.py +5 -2
  357. esphome/components/online_image/__init__.py +9 -1
  358. esphome/components/online_image/online_image.cpp +17 -7
  359. esphome/components/online_image/online_image.h +10 -2
  360. esphome/components/opentherm/opentherm.cpp +7 -12
  361. esphome/components/opentherm/output/output.cpp +1 -1
  362. esphome/components/openthread/__init__.py +47 -40
  363. esphome/components/openthread/const.py +1 -0
  364. esphome/components/openthread/openthread_esp.cpp +27 -5
  365. esphome/components/opt3001/__init__.py +0 -0
  366. esphome/components/opt3001/opt3001.cpp +122 -0
  367. esphome/components/opt3001/opt3001.h +27 -0
  368. esphome/components/opt3001/sensor.py +35 -0
  369. esphome/components/ota/__init__.py +17 -0
  370. esphome/components/ota/ota_backend.h +27 -1
  371. esphome/components/ota/ota_backend_arduino_esp32.cpp +12 -2
  372. esphome/components/ota/ota_backend_arduino_esp32.h +3 -0
  373. esphome/components/ota/ota_backend_arduino_esp8266.cpp +18 -4
  374. esphome/components/ota/ota_backend_arduino_esp8266.h +3 -0
  375. esphome/components/ota/ota_backend_arduino_libretiny.cpp +12 -2
  376. esphome/components/ota/ota_backend_arduino_libretiny.h +3 -0
  377. esphome/components/ota/ota_backend_arduino_rp2040.cpp +9 -2
  378. esphome/components/ota/ota_backend_arduino_rp2040.h +3 -0
  379. esphome/components/ota/ota_backend_esp_idf.cpp +10 -16
  380. esphome/components/ota/ota_backend_esp_idf.h +1 -0
  381. esphome/components/packages/__init__.py +5 -2
  382. esphome/components/packet_transport/binary_sensor.py +61 -4
  383. esphome/components/packet_transport/packet_transport.cpp +34 -1
  384. esphome/components/packet_transport/packet_transport.h +11 -5
  385. esphome/components/pcf8574/__init__.py +1 -1
  386. esphome/components/pi4ioe5v6408/__init__.py +84 -0
  387. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +171 -0
  388. esphome/components/pi4ioe5v6408/pi4ioe5v6408.h +70 -0
  389. esphome/components/pmsa003i/pmsa003i.h +0 -1
  390. esphome/components/pmsx003/pmsx003.h +0 -1
  391. esphome/components/pn7150/pn7150.cpp +7 -7
  392. esphome/components/pn7150/pn7150.h +0 -1
  393. esphome/components/pn7160/pn7160.cpp +7 -7
  394. esphome/components/pn7160/pn7160.h +0 -1
  395. esphome/components/preferences/syncer.h +2 -0
  396. esphome/components/prometheus/prometheus_handler.h +1 -1
  397. esphome/components/psram/psram.cpp +0 -20
  398. esphome/components/pulse_counter/pulse_counter_sensor.h +0 -1
  399. esphome/components/pulse_meter/pulse_meter_sensor.cpp +8 -4
  400. esphome/components/pulse_width/pulse_width.h +0 -1
  401. esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +0 -4
  402. esphome/components/pvvx_mithermometer/display/pvvx_display.h +0 -2
  403. esphome/components/pvvx_mithermometer/pvvx_mithermometer.h +0 -1
  404. esphome/components/qr_code/__init__.py +13 -10
  405. esphome/components/qwiic_pir/qwiic_pir.h +0 -1
  406. esphome/components/radon_eye_ble/radon_eye_listener.cpp +1 -1
  407. esphome/components/rc522/rc522.h +0 -1
  408. esphome/components/rdm6300/rdm6300.h +0 -2
  409. esphome/components/remote_base/__init__.py +7 -5
  410. esphome/components/remote_base/remote_base.cpp +24 -21
  411. esphome/components/remote_base/remote_base.h +3 -26
  412. esphome/components/remote_receiver/__init__.py +40 -46
  413. esphome/components/remote_receiver/remote_receiver.h +4 -18
  414. esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -87
  415. esphome/components/remote_receiver/remote_receiver_esp8266.cpp +1 -1
  416. esphome/components/remote_transmitter/__init__.py +42 -43
  417. esphome/components/remote_transmitter/remote_transmitter.h +2 -14
  418. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -77
  419. esphome/components/resistance/resistance_sensor.h +0 -1
  420. esphome/components/rp2040/__init__.py +2 -0
  421. esphome/components/rp2040/helpers.cpp +55 -0
  422. esphome/components/rp2040_pio_led_strip/led_strip.cpp +2 -2
  423. esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -4
  424. esphome/components/rtttl/__init__.py +4 -4
  425. esphome/components/rtttl/rtttl.cpp +10 -1
  426. esphome/components/ruuvitag/ruuvitag.h +0 -1
  427. esphome/components/safe_mode/safe_mode.cpp +2 -0
  428. esphome/components/safe_mode/safe_mode.h +4 -1
  429. esphome/components/scd30/scd30.h +0 -1
  430. esphome/components/scd30/sensor.py +2 -2
  431. esphome/components/scd4x/scd4x.cpp +61 -54
  432. esphome/components/scd4x/scd4x.h +17 -15
  433. esphome/components/scd4x/sensor.py +4 -4
  434. esphome/components/script/script.h +0 -2
  435. esphome/components/sdp3x/sensor.py +1 -1
  436. esphome/components/select/__init__.py +5 -2
  437. esphome/components/sen5x/sen5x.h +0 -1
  438. esphome/components/senseair/senseair.h +0 -1
  439. esphome/components/sensor/__init__.py +4 -2
  440. esphome/components/sensor/filter.cpp +1 -1
  441. esphome/components/sensor/sensor.cpp +12 -6
  442. esphome/components/sensor/sensor.h +13 -5
  443. esphome/components/servo/servo.cpp +2 -2
  444. esphome/components/servo/servo.h +0 -1
  445. esphome/components/sfa30/sfa30.h +0 -1
  446. esphome/components/sgp30/sgp30.h +0 -1
  447. esphome/components/sgp4x/sgp4x.h +0 -1
  448. esphome/components/shelly_dimmer/stm32flash.cpp +1 -2
  449. esphome/components/sht4x/sht4x.h +0 -1
  450. esphome/components/sm300d2/sm300d2.h +0 -2
  451. esphome/components/smt100/sensor.py +8 -4
  452. esphome/components/smt100/smt100.cpp +5 -5
  453. esphome/components/smt100/smt100.h +3 -3
  454. esphome/components/sn74hc595/__init__.py +1 -1
  455. esphome/components/sn74hc595/sn74hc595.cpp +5 -4
  456. esphome/components/sntp/sntp_component.cpp +9 -3
  457. esphome/components/sntp/time.py +2 -0
  458. esphome/components/socket/__init__.py +17 -0
  459. esphome/components/spi/__init__.py +27 -6
  460. esphome/components/spi/spi.cpp +3 -2
  461. esphome/components/spi/spi.h +9 -3
  462. esphome/components/spi/spi_arduino.cpp +3 -5
  463. esphome/components/spi/spi_esp_idf.cpp +40 -21
  464. esphome/components/spi_led_strip/spi_led_strip.cpp +1 -1
  465. esphome/components/sps30/sps30.h +0 -1
  466. esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
  467. esphome/components/st7701s/st7701s.cpp +0 -4
  468. esphome/components/status/status_binary_sensor.h +0 -2
  469. esphome/components/substitutions/__init__.py +81 -21
  470. esphome/components/substitutions/jinja.py +99 -0
  471. esphome/components/sun/sun.cpp +3 -4
  472. esphome/components/switch/__init__.py +5 -2
  473. esphome/components/switch/binary_sensor/switch_binary_sensor.h +0 -1
  474. esphome/components/sx126x/__init__.py +317 -0
  475. esphome/components/sx126x/automation.h +62 -0
  476. esphome/components/sx126x/packet_transport/__init__.py +26 -0
  477. esphome/components/sx126x/packet_transport/sx126x_transport.cpp +26 -0
  478. esphome/components/sx126x/packet_transport/sx126x_transport.h +25 -0
  479. esphome/components/sx126x/sx126x.cpp +523 -0
  480. esphome/components/sx126x/sx126x.h +140 -0
  481. esphome/components/sx126x/sx126x_reg.h +163 -0
  482. esphome/components/sx127x/__init__.py +325 -0
  483. esphome/components/sx127x/automation.h +62 -0
  484. esphome/components/sx127x/packet_transport/__init__.py +26 -0
  485. esphome/components/sx127x/packet_transport/sx127x_transport.cpp +26 -0
  486. esphome/components/sx127x/packet_transport/sx127x_transport.h +25 -0
  487. esphome/components/sx127x/sx127x.cpp +498 -0
  488. esphome/components/sx127x/sx127x.h +128 -0
  489. esphome/components/sx127x/sx127x_reg.h +295 -0
  490. esphome/components/syslog/esphome_syslog.cpp +5 -3
  491. esphome/components/syslog/esphome_syslog.h +1 -1
  492. esphome/components/tca9555/__init__.py +1 -1
  493. esphome/components/template/binary_sensor/template_binary_sensor.cpp +1 -9
  494. esphome/components/text/__init__.py +5 -2
  495. esphome/components/text_sensor/__init__.py +5 -2
  496. esphome/components/thermostat/thermostat_climate.cpp +34 -31
  497. esphome/components/thermostat/thermostat_climate.h +43 -39
  498. esphome/components/time/__init__.py +16 -2
  499. esphome/components/time/real_time_clock.cpp +4 -0
  500. esphome/components/time/real_time_clock.h +5 -1
  501. esphome/components/tlc5971/tlc5971.cpp +4 -1
  502. esphome/components/tmp1075/tmp1075.h +0 -2
  503. esphome/components/tof10120/tof10120_sensor.h +0 -1
  504. esphome/components/tormatic/tormatic_cover.h +0 -1
  505. esphome/components/total_daily_energy/total_daily_energy.h +0 -1
  506. esphome/components/tsl2591/tsl2591.cpp +1 -1
  507. esphome/components/ttp229_bsf/ttp229_bsf.h +0 -1
  508. esphome/components/ttp229_lsf/ttp229_lsf.h +0 -1
  509. esphome/components/tx20/tx20.cpp +2 -2
  510. esphome/components/uart/__init__.py +18 -0
  511. esphome/components/uart/uart_component_esp_idf.cpp +0 -4
  512. esphome/components/update/__init__.py +5 -2
  513. esphome/components/update/update_entity.h +8 -0
  514. esphome/components/usb_host/__init__.py +5 -2
  515. esphome/components/usb_host/usb_host_client.cpp +10 -10
  516. esphome/components/usb_uart/cp210x.cpp +1 -1
  517. esphome/components/usb_uart/usb_uart.cpp +41 -44
  518. esphome/components/usb_uart/usb_uart.h +4 -3
  519. esphome/components/valve/__init__.py +5 -2
  520. esphome/components/vbus/vbus.h +0 -1
  521. esphome/components/veml3235/veml3235.h +0 -1
  522. esphome/components/veml7700/veml7700.h +0 -1
  523. esphome/components/vl53l0x/vl53l0x_sensor.h +0 -1
  524. esphome/components/voice_assistant/voice_assistant.cpp +4 -4
  525. esphome/components/watchdog/watchdog.cpp +0 -4
  526. esphome/components/waveshare_epaper/waveshare_epaper.cpp +6 -6
  527. esphome/components/web_server/__init__.py +34 -19
  528. esphome/components/web_server/ota/__init__.py +32 -0
  529. esphome/components/web_server/ota/ota_web_server.cpp +210 -0
  530. esphome/components/web_server/ota/ota_web_server.h +26 -0
  531. esphome/components/web_server/web_server.cpp +318 -436
  532. esphome/components/web_server/web_server.h +33 -23
  533. esphome/components/web_server/web_server_v1.cpp +4 -5
  534. esphome/components/web_server_base/__init__.py +5 -2
  535. esphome/components/web_server_base/web_server_base.cpp +2 -94
  536. esphome/components/web_server_base/web_server_base.h +5 -25
  537. esphome/components/web_server_idf/multipart.cpp +254 -0
  538. esphome/components/web_server_idf/multipart.h +86 -0
  539. esphome/components/web_server_idf/utils.cpp +32 -0
  540. esphome/components/web_server_idf/utils.h +10 -0
  541. esphome/components/web_server_idf/web_server_idf.cpp +164 -16
  542. esphome/components/web_server_idf/web_server_idf.h +11 -10
  543. esphome/components/wiegand/wiegand.cpp +2 -2
  544. esphome/components/wifi/__init__.py +18 -0
  545. esphome/components/wifi/wifi_component.cpp +17 -22
  546. esphome/components/wifi/wifi_component.h +27 -23
  547. esphome/components/wifi/wifi_component_esp32_arduino.cpp +52 -59
  548. esphome/components/wifi/wifi_component_esp8266.cpp +46 -46
  549. esphome/components/wifi/wifi_component_esp_idf.cpp +35 -36
  550. esphome/components/wifi/wifi_component_libretiny.cpp +26 -27
  551. esphome/components/wifi/wifi_component_pico_w.cpp +3 -3
  552. esphome/components/wifi_info/wifi_info_text_sensor.cpp +6 -6
  553. esphome/components/wireguard/__init__.py +2 -11
  554. esphome/components/xiaomi_ble/xiaomi_ble.cpp +13 -1
  555. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  556. esphome/components/xiaomi_cgd1/xiaomi_cgd1.h +0 -1
  557. esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h +0 -1
  558. esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +0 -1
  559. esphome/components/xiaomi_cgpr1/xiaomi_cgpr1.h +0 -1
  560. esphome/components/xiaomi_gcls002/xiaomi_gcls002.h +0 -1
  561. esphome/components/xiaomi_hhccjcy01/xiaomi_hhccjcy01.h +0 -1
  562. esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h +0 -1
  563. esphome/components/xiaomi_hhccpot002/xiaomi_hhccpot002.h +0 -1
  564. esphome/components/xiaomi_jqjcy01ym/xiaomi_jqjcy01ym.h +0 -1
  565. esphome/components/xiaomi_lywsd02/xiaomi_lywsd02.h +0 -1
  566. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +0 -1
  567. esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.h +0 -1
  568. esphome/components/xiaomi_lywsdcgq/xiaomi_lywsdcgq.h +0 -1
  569. esphome/components/xiaomi_mhoc303/xiaomi_mhoc303.h +0 -1
  570. esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.h +0 -1
  571. esphome/components/xiaomi_miscale/xiaomi_miscale.h +0 -1
  572. esphome/components/xiaomi_mjyd02yla/xiaomi_mjyd02yla.h +0 -1
  573. esphome/components/xiaomi_mue4094rt/xiaomi_mue4094rt.h +0 -1
  574. esphome/components/xiaomi_rtcgq02lm/xiaomi_rtcgq02lm.h +0 -1
  575. esphome/components/xiaomi_wx08zm/xiaomi_wx08zm.h +0 -1
  576. esphome/components/xiaomi_xmwsdj04mmc/__init__.py +0 -0
  577. esphome/components/xiaomi_xmwsdj04mmc/sensor.py +77 -0
  578. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.cpp +77 -0
  579. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.h +36 -0
  580. esphome/components/zio_ultrasonic/zio_ultrasonic.h +0 -2
  581. esphome/components/zyaura/zyaura.h +0 -1
  582. esphome/config.py +88 -22
  583. esphome/config_helpers.py +74 -1
  584. esphome/config_validation.py +12 -1
  585. esphome/const.py +65 -10
  586. esphome/core/__init__.py +18 -2
  587. esphome/core/application.cpp +169 -10
  588. esphome/core/application.h +145 -165
  589. esphome/core/area.h +19 -0
  590. esphome/core/automation.h +58 -9
  591. esphome/core/color.cpp +3 -5
  592. esphome/core/color.h +16 -16
  593. esphome/core/component.cpp +156 -22
  594. esphome/core/component.h +98 -4
  595. esphome/core/component_iterator.cpp +11 -9
  596. esphome/core/component_iterator.h +12 -10
  597. esphome/core/config.py +155 -6
  598. esphome/core/controller.cpp +4 -2
  599. esphome/core/controller.h +1 -1
  600. esphome/core/datatypes.h +2 -2
  601. esphome/core/defines.h +17 -2
  602. esphome/core/device.h +20 -0
  603. esphome/core/entity_base.cpp +20 -15
  604. esphome/core/entity_base.h +76 -0
  605. esphome/core/entity_helpers.py +168 -1
  606. esphome/core/event_pool.h +81 -0
  607. esphome/core/helpers.cpp +75 -230
  608. esphome/core/helpers.h +165 -105
  609. esphome/core/lock_free_queue.h +151 -0
  610. esphome/core/log.cpp +2 -2
  611. esphome/core/log.h +2 -0
  612. esphome/core/optional.h +5 -0
  613. esphome/core/ring_buffer.cpp +2 -2
  614. esphome/core/scheduler.cpp +275 -103
  615. esphome/core/scheduler.h +154 -17
  616. esphome/core/time.cpp +5 -5
  617. esphome/core/time.h +5 -5
  618. esphome/cpp_generator.py +17 -0
  619. esphome/cpp_helpers.py +0 -22
  620. esphome/cpp_types.py +3 -1
  621. esphome/dashboard/entries.py +1 -1
  622. esphome/dashboard/util/text.py +5 -21
  623. esphome/dashboard/web_server.py +9 -1
  624. esphome/helpers.py +47 -0
  625. esphome/loader.py +15 -1
  626. esphome/pins.py +14 -8
  627. esphome/platformio_api.py +2 -0
  628. esphome/wizard.py +17 -4
  629. esphome/writer.py +44 -3
  630. esphome/yaml_util.py +0 -2
  631. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/METADATA +10 -9
  632. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/RECORD +637 -578
  633. esphome/components/api/api_pb2_size.h +0 -361
  634. esphome/components/esp32_ble/ble_event_pool.h +0 -72
  635. esphome/components/esp32_ble/queue.h +0 -85
  636. esphome/components/esp32_hall/esp32_hall.cpp +0 -25
  637. esphome/components/esp32_hall/esp32_hall.h +0 -23
  638. esphome/components/esp32_touch/esp32_touch.cpp +0 -355
  639. esphome/components/ld2410/button/reset_button.cpp +0 -9
  640. esphome/components/ld2450/button/reset_button.cpp +0 -9
  641. esphome/components/openthread/tlv.py +0 -65
  642. /esphome/{dashboard/enum.py → enum.py} +0 -0
  643. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/WHEEL +0 -0
  644. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/entry_points.txt +0 -0
  645. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/licenses/LICENSE +0 -0
  646. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/top_level.txt +0 -0
@@ -61,7 +61,7 @@ static const char *const LOG_LEVEL_LETTERS[] = {
61
61
  *
62
62
  * Advanced configuration (pin selection, etc) is not supported.
63
63
  */
64
- enum UARTSelection {
64
+ enum UARTSelection : uint8_t {
65
65
  #ifdef USE_LIBRETINY
66
66
  UART_SELECTION_DEFAULT = 0,
67
67
  UART_SELECTION_UART0,
@@ -129,10 +129,10 @@ class Logger : public Component {
129
129
  #endif
130
130
 
131
131
  /// Set the default log level for this logger.
132
- void set_log_level(int level);
132
+ void set_log_level(uint8_t level);
133
133
  /// Set the log level of the specified tag.
134
- void set_log_level(const std::string &tag, int log_level);
135
- int get_log_level() { return this->current_level_; }
134
+ void set_log_level(const std::string &tag, uint8_t log_level);
135
+ uint8_t get_log_level() { return this->current_level_; }
136
136
 
137
137
  // ========== INTERNAL METHODS ==========
138
138
  // (In most use cases you won't need these)
@@ -140,19 +140,20 @@ class Logger : public Component {
140
140
  void pre_setup();
141
141
  void dump_config() override;
142
142
 
143
- inline int level_for(const char *tag);
143
+ inline uint8_t level_for(const char *tag);
144
144
 
145
145
  /// Register a callback that will be called for every log message sent
146
- void add_on_log_callback(std::function<void(int, const char *, const char *)> &&callback);
146
+ void add_on_log_callback(std::function<void(uint8_t, const char *, const char *, size_t)> &&callback);
147
147
 
148
148
  // add a listener for log level changes
149
- void add_listener(std::function<void(int)> &&callback) { this->level_callback_.add(std::move(callback)); }
149
+ void add_listener(std::function<void(uint8_t)> &&callback) { this->level_callback_.add(std::move(callback)); }
150
150
 
151
151
  float get_setup_priority() const override;
152
152
 
153
- void log_vprintf_(int level, const char *tag, int line, const char *format, va_list args); // NOLINT
153
+ void log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args); // NOLINT
154
154
  #ifdef USE_STORE_LOG_STR_IN_FLASH
155
- void log_vprintf_(int level, const char *tag, int line, const __FlashStringHelper *format, va_list args); // NOLINT
155
+ void log_vprintf_(uint8_t level, const char *tag, int line, const __FlashStringHelper *format,
156
+ va_list args); // NOLINT
156
157
  #endif
157
158
 
158
159
  protected:
@@ -160,8 +161,9 @@ class Logger : public Component {
160
161
 
161
162
  // Format a log message with printf-style arguments and write it to a buffer with header, footer, and null terminator
162
163
  // It's the caller's responsibility to initialize buffer_at (typically to 0)
163
- inline void HOT format_log_to_buffer_with_terminator_(int level, const char *tag, int line, const char *format,
164
- va_list args, char *buffer, int *buffer_at, int buffer_size) {
164
+ inline void HOT format_log_to_buffer_with_terminator_(uint8_t level, const char *tag, int line, const char *format,
165
+ va_list args, char *buffer, uint16_t *buffer_at,
166
+ uint16_t buffer_size) {
165
167
  #if defined(USE_ESP32) || defined(USE_LIBRETINY)
166
168
  this->write_header_to_buffer_(level, tag, line, this->get_thread_name_(), buffer, buffer_at, buffer_size);
167
169
  #else
@@ -180,7 +182,7 @@ class Logger : public Component {
180
182
  }
181
183
 
182
184
  // Helper to format and send a log message to both console and callbacks
183
- inline void HOT log_message_to_buffer_and_send_(int level, const char *tag, int line, const char *format,
185
+ inline void HOT log_message_to_buffer_and_send_(uint8_t level, const char *tag, int line, const char *format,
184
186
  va_list args) {
185
187
  // Format to tx_buffer and prepare for output
186
188
  this->tx_buffer_at_ = 0; // Initialize buffer position
@@ -190,15 +192,16 @@ class Logger : public Component {
190
192
  if (this->baud_rate_ > 0) {
191
193
  this->write_msg_(this->tx_buffer_); // If logging is enabled, write to console
192
194
  }
193
- this->log_callback_.call(level, tag, this->tx_buffer_);
195
+ this->log_callback_.call(level, tag, this->tx_buffer_, this->tx_buffer_at_);
194
196
  }
195
197
 
196
198
  // Write the body of the log message to the buffer
197
- inline void write_body_to_buffer_(const char *value, size_t length, char *buffer, int *buffer_at, int buffer_size) {
199
+ inline void write_body_to_buffer_(const char *value, size_t length, char *buffer, uint16_t *buffer_at,
200
+ uint16_t buffer_size) {
198
201
  // Calculate available space
199
- const int available = buffer_size - *buffer_at;
200
- if (available <= 0)
202
+ if (*buffer_at >= buffer_size)
201
203
  return;
204
+ const uint16_t available = buffer_size - *buffer_at;
202
205
 
203
206
  // Determine copy length (minimum of remaining capacity and string length)
204
207
  const size_t copy_len = (length < static_cast<size_t>(available)) ? length : available;
@@ -211,7 +214,7 @@ class Logger : public Component {
211
214
  }
212
215
 
213
216
  // Format string to explicit buffer with varargs
214
- inline void printf_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format, ...) {
217
+ inline void printf_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size, const char *format, ...) {
215
218
  va_list arg;
216
219
  va_start(arg, format);
217
220
  this->format_body_to_buffer_(buffer, buffer_at, buffer_size, format, arg);
@@ -222,41 +225,50 @@ class Logger : public Component {
222
225
  const char *get_uart_selection_();
223
226
  #endif
224
227
 
228
+ // Group 4-byte aligned members first
225
229
  uint32_t baud_rate_;
226
230
  char *tx_buffer_{nullptr};
227
- int tx_buffer_at_{0};
228
- int tx_buffer_size_{0};
229
- #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040)
230
- UARTSelection uart_{UART_SELECTION_UART0};
231
- #endif
232
- #ifdef USE_LIBRETINY
233
- UARTSelection uart_{UART_SELECTION_DEFAULT};
234
- #endif
235
231
  #ifdef USE_ARDUINO
236
232
  Stream *hw_serial_{nullptr};
237
233
  #endif
234
+ #if defined(USE_ESP32) || defined(USE_LIBRETINY)
235
+ void *main_task_ = nullptr; // Only used for thread name identification
236
+ #endif
237
+ #ifdef USE_ESP32
238
+ // Task-specific recursion guards:
239
+ // - Main task uses a dedicated member variable for efficiency
240
+ // - Other tasks use pthread TLS with a dynamically created key via pthread_key_create
241
+ pthread_key_t log_recursion_key_; // 4 bytes
242
+ #endif
238
243
  #ifdef USE_ESP_IDF
239
- uart_port_t uart_num_;
244
+ uart_port_t uart_num_; // 4 bytes (enum defaults to int size)
240
245
  #endif
241
- std::map<std::string, int> log_levels_{};
242
- CallbackManager<void(int, const char *, const char *)> log_callback_{};
243
- int current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE};
246
+
247
+ // Large objects (internally aligned)
248
+ std::map<std::string, uint8_t> log_levels_{};
249
+ CallbackManager<void(uint8_t, const char *, const char *, size_t)> log_callback_{};
250
+ CallbackManager<void(uint8_t)> level_callback_{};
244
251
  #ifdef USE_ESPHOME_TASK_LOG_BUFFER
245
252
  std::unique_ptr<logger::TaskLogBuffer> log_buffer_; // Will be initialized with init_log_buffer
246
253
  #endif
254
+
255
+ // Group smaller types together at the end
256
+ uint16_t tx_buffer_at_{0};
257
+ uint16_t tx_buffer_size_{0};
258
+ uint8_t current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE};
259
+ #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040)
260
+ UARTSelection uart_{UART_SELECTION_UART0};
261
+ #endif
262
+ #ifdef USE_LIBRETINY
263
+ UARTSelection uart_{UART_SELECTION_DEFAULT};
264
+ #endif
247
265
  #ifdef USE_ESP32
248
- // Task-specific recursion guards:
249
- // - Main task uses a dedicated member variable for efficiency
250
- // - Other tasks use pthread TLS with a dynamically created key via pthread_key_create
251
266
  bool main_task_recursion_guard_{false};
252
- pthread_key_t log_recursion_key_;
253
267
  #else
254
268
  bool global_recursion_guard_{false}; // Simple global recursion guard for single-task platforms
255
269
  #endif
256
- CallbackManager<void(int)> level_callback_{};
257
270
 
258
271
  #if defined(USE_ESP32) || defined(USE_LIBRETINY)
259
- void *main_task_ = nullptr; // Only used for thread name identification
260
272
  const char *HOT get_thread_name_() {
261
273
  TaskHandle_t current_task = xTaskGetCurrentTaskHandle();
262
274
  if (current_task == main_task_) {
@@ -297,11 +309,10 @@ class Logger : public Component {
297
309
  }
298
310
  #endif
299
311
 
300
- inline void HOT write_header_to_buffer_(int level, const char *tag, int line, const char *thread_name, char *buffer,
301
- int *buffer_at, int buffer_size) {
312
+ inline void HOT write_header_to_buffer_(uint8_t level, const char *tag, int line, const char *thread_name,
313
+ char *buffer, uint16_t *buffer_at, uint16_t buffer_size) {
302
314
  // Format header
303
- if (level < 0)
304
- level = 0;
315
+ // uint8_t level is already bounded 0-255, just ensure it's <= 7
305
316
  if (level > 7)
306
317
  level = 7;
307
318
 
@@ -320,12 +331,12 @@ class Logger : public Component {
320
331
  this->printf_to_buffer_(buffer, buffer_at, buffer_size, "%s[%s][%s:%03u]: ", color, letter, tag, line);
321
332
  }
322
333
 
323
- inline void HOT format_body_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format,
334
+ inline void HOT format_body_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size, const char *format,
324
335
  va_list args) {
325
336
  // Get remaining capacity in the buffer
326
- const int remaining = buffer_size - *buffer_at;
327
- if (remaining <= 0)
337
+ if (*buffer_at >= buffer_size)
328
338
  return;
339
+ const uint16_t remaining = buffer_size - *buffer_at;
329
340
 
330
341
  const int ret = vsnprintf(buffer + *buffer_at, remaining, format, args);
331
342
 
@@ -334,7 +345,7 @@ class Logger : public Component {
334
345
  }
335
346
 
336
347
  // Update buffer_at with the formatted length (handle truncation)
337
- int formatted_len = (ret >= remaining) ? remaining : ret;
348
+ uint16_t formatted_len = (ret >= remaining) ? remaining : ret;
338
349
  *buffer_at += formatted_len;
339
350
 
340
351
  // Remove all trailing newlines right after formatting
@@ -343,18 +354,38 @@ class Logger : public Component {
343
354
  }
344
355
  }
345
356
 
346
- inline void HOT write_footer_to_buffer_(char *buffer, int *buffer_at, int buffer_size) {
347
- static const int RESET_COLOR_LEN = strlen(ESPHOME_LOG_RESET_COLOR);
357
+ inline void HOT write_footer_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size) {
358
+ static constexpr uint16_t RESET_COLOR_LEN = sizeof(ESPHOME_LOG_RESET_COLOR) - 1;
348
359
  this->write_body_to_buffer_(ESPHOME_LOG_RESET_COLOR, RESET_COLOR_LEN, buffer, buffer_at, buffer_size);
349
360
  }
361
+
362
+ #ifdef USE_ESP32
363
+ // Disable loop when task buffer is empty (with USB CDC check)
364
+ inline void disable_loop_when_buffer_empty_() {
365
+ // Thread safety note: This is safe even if another task calls enable_loop_soon_any_context()
366
+ // concurrently. If that happens between our check and disable_loop(), the enable request
367
+ // will be processed on the next main loop iteration since:
368
+ // - disable_loop() takes effect immediately
369
+ // - enable_loop_soon_any_context() sets a pending flag that's checked at loop start
370
+ #if defined(USE_LOGGER_USB_CDC) && defined(USE_ARDUINO)
371
+ // Only disable if not using USB CDC (which needs loop for connection detection)
372
+ if (this->uart_ != UART_SELECTION_USB_CDC) {
373
+ this->disable_loop();
374
+ }
375
+ #else
376
+ // No USB CDC support, always safe to disable
377
+ this->disable_loop();
378
+ #endif
379
+ }
380
+ #endif
350
381
  };
351
382
  extern Logger *global_logger; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
352
383
 
353
- class LoggerMessageTrigger : public Trigger<int, const char *, const char *> {
384
+ class LoggerMessageTrigger : public Trigger<uint8_t, const char *, const char *> {
354
385
  public:
355
- explicit LoggerMessageTrigger(Logger *parent, int level) {
386
+ explicit LoggerMessageTrigger(Logger *parent, uint8_t level) {
356
387
  this->level_ = level;
357
- parent->add_on_log_callback([this](int level, const char *tag, const char *message) {
388
+ parent->add_on_log_callback([this](uint8_t level, const char *tag, const char *message, size_t message_len) {
358
389
  if (level <= this->level_) {
359
390
  this->trigger(level, tag, message);
360
391
  }
@@ -362,7 +393,7 @@ class LoggerMessageTrigger : public Trigger<int, const char *, const char *> {
362
393
  }
363
394
 
364
395
  protected:
365
- int level_;
396
+ uint8_t level_;
366
397
  };
367
398
 
368
399
  } // namespace logger
@@ -83,9 +83,7 @@ void init_uart(uart_port_t uart_num, uint32_t baud_rate, int tx_buffer_size) {
83
83
  uart_config.parity = UART_PARITY_DISABLE;
84
84
  uart_config.stop_bits = UART_STOP_BITS_1;
85
85
  uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
86
- #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
87
86
  uart_config.source_clk = UART_SCLK_DEFAULT;
88
- #endif
89
87
  uart_param_config(uart_num, &uart_config);
90
88
  const int uart_buffer_size = tx_buffer_size;
91
89
  // Install UART driver using an event queue here
@@ -186,7 +184,9 @@ void HOT Logger::write_msg_(const char *msg) {
186
184
  ) {
187
185
  puts(msg);
188
186
  } else {
189
- uart_write_bytes(this->uart_num_, msg, strlen(msg));
187
+ // Use tx_buffer_at_ if msg points to tx_buffer_, otherwise fall back to strlen
188
+ size_t len = (msg == this->tx_buffer_) ? this->tx_buffer_at_ : strlen(msg);
189
+ uart_write_bytes(this->uart_num_, msg, len);
190
190
  uart_write_bytes(this->uart_num_, "\n", 1);
191
191
  }
192
192
  }
File without changes
@@ -0,0 +1,75 @@
1
+ #include "lps22.h"
2
+
3
+ namespace esphome {
4
+ namespace lps22 {
5
+
6
+ static constexpr const char *const TAG = "lps22";
7
+
8
+ static constexpr uint8_t WHO_AM_I = 0x0F;
9
+ static constexpr uint8_t LPS22HB_ID = 0xB1;
10
+ static constexpr uint8_t LPS22HH_ID = 0xB3;
11
+ static constexpr uint8_t CTRL_REG2 = 0x11;
12
+ static constexpr uint8_t CTRL_REG2_ONE_SHOT_MASK = 0b1;
13
+ static constexpr uint8_t STATUS = 0x27;
14
+ static constexpr uint8_t STATUS_T_DA_MASK = 0b10;
15
+ static constexpr uint8_t STATUS_P_DA_MASK = 0b01;
16
+ static constexpr uint8_t TEMP_L = 0x2b;
17
+ static constexpr uint8_t PRES_OUT_XL = 0x28;
18
+ static constexpr uint8_t REF_P_XL = 0x28;
19
+ static constexpr uint8_t READ_ATTEMPTS = 10;
20
+ static constexpr uint8_t READ_INTERVAL = 5;
21
+ static constexpr float PRESSURE_SCALE = 1.0f / 4096.0f;
22
+ static constexpr float TEMPERATURE_SCALE = 0.01f;
23
+
24
+ void LPS22Component::setup() {
25
+ uint8_t value = 0x00;
26
+ this->read_register(WHO_AM_I, &value, 1);
27
+ if (value != LPS22HB_ID && value != LPS22HH_ID) {
28
+ ESP_LOGW(TAG, "device IDs as %02x, which isn't a known LPS22HB or LPS22HH ID", value);
29
+ this->mark_failed();
30
+ }
31
+ }
32
+
33
+ void LPS22Component::dump_config() {
34
+ ESP_LOGCONFIG(TAG, "LPS22:");
35
+ LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
36
+ LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
37
+ LOG_I2C_DEVICE(this);
38
+ LOG_UPDATE_INTERVAL(this);
39
+ }
40
+
41
+ void LPS22Component::update() {
42
+ uint8_t value = 0x00;
43
+ this->read_register(CTRL_REG2, &value, 1);
44
+ value |= CTRL_REG2_ONE_SHOT_MASK;
45
+ this->write_register(CTRL_REG2, &value, 1);
46
+ this->set_retry(READ_INTERVAL, READ_ATTEMPTS, [this](uint8_t _) { return this->try_read_(); });
47
+ }
48
+
49
+ RetryResult LPS22Component::try_read_() {
50
+ uint8_t value = 0x00;
51
+ this->read_register(STATUS, &value, 1);
52
+ const uint8_t expected_status_mask = STATUS_T_DA_MASK | STATUS_P_DA_MASK;
53
+ if ((value & expected_status_mask) != expected_status_mask) {
54
+ ESP_LOGD(TAG, "STATUS not ready: %x", value);
55
+ return RetryResult::RETRY;
56
+ }
57
+
58
+ if (this->temperature_sensor_ != nullptr) {
59
+ uint8_t t_buf[2]{0};
60
+ this->read_register(TEMP_L, t_buf, 2);
61
+ int16_t encoded = static_cast<int16_t>(encode_uint16(t_buf[1], t_buf[0]));
62
+ float temp = TEMPERATURE_SCALE * static_cast<float>(encoded);
63
+ this->temperature_sensor_->publish_state(temp);
64
+ }
65
+ if (this->pressure_sensor_ != nullptr) {
66
+ uint8_t p_buf[3]{0};
67
+ this->read_register(PRES_OUT_XL, p_buf, 3);
68
+ uint32_t p_lsb = encode_uint24(p_buf[2], p_buf[1], p_buf[0]);
69
+ this->pressure_sensor_->publish_state(PRESSURE_SCALE * static_cast<float>(p_lsb));
70
+ }
71
+ return RetryResult::DONE;
72
+ }
73
+
74
+ } // namespace lps22
75
+ } // namespace esphome
@@ -0,0 +1,27 @@
1
+ #pragma once
2
+
3
+ #include "esphome/core/component.h"
4
+ #include "esphome/components/sensor/sensor.h"
5
+ #include "esphome/components/i2c/i2c.h"
6
+
7
+ namespace esphome {
8
+ namespace lps22 {
9
+
10
+ class LPS22Component : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
11
+ public:
12
+ void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }
13
+ void set_pressure_sensor(sensor::Sensor *pressure_sensor) { this->pressure_sensor_ = pressure_sensor; }
14
+
15
+ void setup() override;
16
+ void update() override;
17
+ void dump_config() override;
18
+
19
+ protected:
20
+ sensor::Sensor *temperature_sensor_{nullptr};
21
+ sensor::Sensor *pressure_sensor_{nullptr};
22
+
23
+ RetryResult try_read_();
24
+ };
25
+
26
+ } // namespace lps22
27
+ } // namespace esphome
@@ -0,0 +1,58 @@
1
+ import esphome.codegen as cg
2
+ import esphome.config_validation as cv
3
+ from esphome.components import i2c, sensor
4
+ from esphome.const import (
5
+ CONF_ID,
6
+ CONF_TEMPERATURE,
7
+ CONF_PRESSURE,
8
+ STATE_CLASS_MEASUREMENT,
9
+ UNIT_CELSIUS,
10
+ UNIT_HECTOPASCAL,
11
+ ICON_THERMOMETER,
12
+ DEVICE_CLASS_TEMPERATURE,
13
+ DEVICE_CLASS_PRESSURE,
14
+ )
15
+
16
+ CODEOWNERS = ["@nagisa"]
17
+ DEPENDENCIES = ["i2c"]
18
+
19
+ lps22 = cg.esphome_ns.namespace("lps22")
20
+
21
+ LPS22Component = lps22.class_("LPS22Component", cg.PollingComponent, i2c.I2CDevice)
22
+
23
+ CONFIG_SCHEMA = (
24
+ cv.Schema(
25
+ {
26
+ cv.GenerateID(): cv.declare_id(LPS22Component),
27
+ cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
28
+ unit_of_measurement=UNIT_CELSIUS,
29
+ icon=ICON_THERMOMETER,
30
+ accuracy_decimals=2,
31
+ device_class=DEVICE_CLASS_TEMPERATURE,
32
+ state_class=STATE_CLASS_MEASUREMENT,
33
+ ),
34
+ cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
35
+ unit_of_measurement=UNIT_HECTOPASCAL,
36
+ accuracy_decimals=2,
37
+ device_class=DEVICE_CLASS_PRESSURE,
38
+ state_class=STATE_CLASS_MEASUREMENT,
39
+ ),
40
+ }
41
+ )
42
+ .extend(cv.polling_component_schema("60s"))
43
+ .extend(i2c.i2c_device_schema(0x5D)) # can also be 0x5C
44
+ )
45
+
46
+
47
+ async def to_code(config):
48
+ var = cg.new_Pvariable(config[CONF_ID])
49
+ await cg.register_component(var, config)
50
+ await i2c.register_i2c_device(var, config)
51
+
52
+ if temperature_config := config.get(CONF_TEMPERATURE):
53
+ sens = await sensor.new_sensor(temperature_config)
54
+ cg.add(var.set_temperature_sensor(sens))
55
+
56
+ if pressure_config := config.get(CONF_PRESSURE):
57
+ sens = await sensor.new_sensor(pressure_config)
58
+ cg.add(var.set_pressure_sensor(sens))
@@ -44,7 +44,6 @@ enum LTR390RESOLUTION {
44
44
 
45
45
  class LTR390Component : public PollingComponent, public i2c::I2CDevice {
46
46
  public:
47
- float get_setup_priority() const override { return setup_priority::DATA; }
48
47
  void setup() override;
49
48
  void dump_config() override;
50
49
  void update() override;
@@ -25,7 +25,6 @@ class LTRAlsPs501Component : public PollingComponent, public i2c::I2CDevice {
25
25
  //
26
26
  // EspHome framework functions
27
27
  //
28
- float get_setup_priority() const override { return setup_priority::DATA; }
29
28
  void setup() override;
30
29
  void dump_config() override;
31
30
  void update() override;
@@ -25,7 +25,6 @@ class LTRAlsPsComponent : public PollingComponent, public i2c::I2CDevice {
25
25
  //
26
26
  // EspHome framework functions
27
27
  //
28
- float get_setup_priority() const override { return setup_priority::DATA; }
29
28
  void setup() override;
30
29
  void dump_config() override;
31
30
  void update() override;
@@ -466,7 +466,7 @@ LVGL_SCHEMA = cv.All(
466
466
  ): lvalid.lv_color,
467
467
  cv.Optional(df.CONF_THEME): cv.Schema(
468
468
  {
469
- cv.Optional(name): obj_schema(w)
469
+ cv.Optional(name): obj_schema(w).extend(FULL_STYLE_SCHEMA)
470
470
  for name, w in WIDGET_TYPES.items()
471
471
  }
472
472
  ),
@@ -21,7 +21,7 @@ from esphome.core.config import StartupTrigger
21
21
  from esphome.schema_extractors import SCHEMA_EXTRACT
22
22
 
23
23
  from . import defines as df, lv_validation as lvalid
24
- from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR
24
+ from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR, TYPE_GRID
25
25
  from .helpers import add_lv_use, requires_component, validate_printf
26
26
  from .lv_validation import lv_color, lv_font, lv_gradient, lv_image, opacity
27
27
  from .lvcode import LvglComponent, lv_event_t_ptr
@@ -349,7 +349,60 @@ def obj_schema(widget_type: WidgetType):
349
349
  )
350
350
 
351
351
 
352
+ def _validate_grid_layout(config):
353
+ layout = config[df.CONF_LAYOUT]
354
+ rows = len(layout[df.CONF_GRID_ROWS])
355
+ columns = len(layout[df.CONF_GRID_COLUMNS])
356
+ used_cells = [[None] * columns for _ in range(rows)]
357
+ for index, widget in enumerate(config[df.CONF_WIDGETS]):
358
+ _, w = next(iter(widget.items()))
359
+ if (df.CONF_GRID_CELL_COLUMN_POS in w) != (df.CONF_GRID_CELL_ROW_POS in w):
360
+ # pylint: disable=raise-missing-from
361
+ raise cv.Invalid(
362
+ "Both row and column positions must be specified, or both omitted",
363
+ [df.CONF_WIDGETS, index],
364
+ )
365
+ if df.CONF_GRID_CELL_ROW_POS in w:
366
+ row = w[df.CONF_GRID_CELL_ROW_POS]
367
+ column = w[df.CONF_GRID_CELL_COLUMN_POS]
368
+ else:
369
+ try:
370
+ row, column = next(
371
+ (r_idx, c_idx)
372
+ for r_idx, row in enumerate(used_cells)
373
+ for c_idx, value in enumerate(row)
374
+ if value is None
375
+ )
376
+ except StopIteration:
377
+ # pylint: disable=raise-missing-from
378
+ raise cv.Invalid(
379
+ "No free cells available in grid layout", [df.CONF_WIDGETS, index]
380
+ )
381
+ w[df.CONF_GRID_CELL_ROW_POS] = row
382
+ w[df.CONF_GRID_CELL_COLUMN_POS] = column
383
+
384
+ for i in range(w[df.CONF_GRID_CELL_ROW_SPAN]):
385
+ for j in range(w[df.CONF_GRID_CELL_COLUMN_SPAN]):
386
+ if row + i >= rows or column + j >= columns:
387
+ # pylint: disable=raise-missing-from
388
+ raise cv.Invalid(
389
+ f"Cell at {row}/{column} span {w[df.CONF_GRID_CELL_ROW_SPAN]}x{w[df.CONF_GRID_CELL_COLUMN_SPAN]} "
390
+ f"exceeds grid size {rows}x{columns}",
391
+ [df.CONF_WIDGETS, index],
392
+ )
393
+ if used_cells[row + i][column + j] is not None:
394
+ # pylint: disable=raise-missing-from
395
+ raise cv.Invalid(
396
+ f"Cell span {row + i}/{column + j} already occupied by widget at index {used_cells[row + i][column + j]}",
397
+ [df.CONF_WIDGETS, index],
398
+ )
399
+ used_cells[row + i][column + j] = index
400
+
401
+ return config
402
+
403
+
352
404
  LAYOUT_SCHEMAS = {}
405
+ LAYOUT_VALIDATORS = {TYPE_GRID: _validate_grid_layout}
353
406
 
354
407
  ALIGN_TO_SCHEMA = {
355
408
  cv.Optional(df.CONF_ALIGN_TO): cv.Schema(
@@ -402,8 +455,8 @@ LAYOUT_SCHEMA = {
402
455
  }
403
456
 
404
457
  GRID_CELL_SCHEMA = {
405
- cv.Required(df.CONF_GRID_CELL_ROW_POS): cv.positive_int,
406
- cv.Required(df.CONF_GRID_CELL_COLUMN_POS): cv.positive_int,
458
+ cv.Optional(df.CONF_GRID_CELL_ROW_POS): cv.positive_int,
459
+ cv.Optional(df.CONF_GRID_CELL_COLUMN_POS): cv.positive_int,
407
460
  cv.Optional(df.CONF_GRID_CELL_ROW_SPAN, default=1): cv.positive_int,
408
461
  cv.Optional(df.CONF_GRID_CELL_COLUMN_SPAN, default=1): cv.positive_int,
409
462
  cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments,
@@ -454,9 +507,13 @@ def container_validator(schema, widget_type: WidgetType):
454
507
  """
455
508
 
456
509
  def validator(value):
457
- result = schema
458
510
  if w_sch := widget_type.schema:
459
- result = result.extend(w_sch)
511
+ if isinstance(w_sch, dict):
512
+ w_sch = cv.Schema(w_sch)
513
+ # order is important here to preserve extras
514
+ result = w_sch.extend(schema)
515
+ else:
516
+ result = schema
460
517
  ltype = df.TYPE_NONE
461
518
  if value and (layout := value.get(df.CONF_LAYOUT)):
462
519
  if not isinstance(layout, dict):
@@ -470,7 +527,10 @@ def container_validator(schema, widget_type: WidgetType):
470
527
  result = result.extend(
471
528
  LAYOUT_SCHEMAS.get(ltype.lower(), LAYOUT_SCHEMAS[df.TYPE_NONE])
472
529
  )
473
- return result(value)
530
+ value = result(value)
531
+ if layout_validator := LAYOUT_VALIDATORS.get(ltype):
532
+ value = layout_validator(value)
533
+ return value
474
534
 
475
535
  return validator
476
536
 
@@ -3,7 +3,6 @@ import esphome.codegen as cg
3
3
  import esphome.config_validation as cv
4
4
  from esphome.const import CONF_ID
5
5
  from esphome.core import ID
6
- from esphome.cpp_generator import MockObj
7
6
 
8
7
  from .defines import (
9
8
  CONF_STYLE_DEFINITIONS,
@@ -13,12 +12,13 @@ from .defines import (
13
12
  literal,
14
13
  )
15
14
  from .helpers import add_lv_use
16
- from .lvcode import LambdaContext, LocalVariable, lv, lv_assign, lv_variable
15
+ from .lvcode import LambdaContext, LocalVariable, lv
17
16
  from .schemas import ALL_STYLES, FULL_STYLE_SCHEMA, STYLE_REMAP
18
- from .types import ObjUpdateAction, lv_lambda_t, lv_obj_t, lv_obj_t_ptr, lv_style_t
17
+ from .types import ObjUpdateAction, lv_obj_t, lv_style_t
19
18
  from .widgets import (
20
19
  Widget,
21
20
  add_widgets,
21
+ collect_parts,
22
22
  set_obj_properties,
23
23
  theme_widget_map,
24
24
  wait_for_widgets,
@@ -37,12 +37,18 @@ async def style_set(svar, style):
37
37
  lv.call(f"style_set_{remapped_prop}", svar, literal(value))
38
38
 
39
39
 
40
+ async def create_style(style, id_name):
41
+ style_id = ID(id_name, True, lv_style_t)
42
+ svar = cg.new_Pvariable(style_id)
43
+ lv.style_init(svar)
44
+ await style_set(svar, style)
45
+ return svar
46
+
47
+
40
48
  async def styles_to_code(config):
41
49
  """Convert styles to C__ code."""
42
50
  for style in config.get(CONF_STYLE_DEFINITIONS, ()):
43
- svar = cg.new_Pvariable(style[CONF_ID])
44
- lv.style_init(svar)
45
- await style_set(svar, style)
51
+ await create_style(style, style[CONF_ID].id)
46
52
 
47
53
 
48
54
  @automation.register_action(
@@ -68,16 +74,18 @@ async def theme_to_code(config):
68
74
  if theme := config.get(CONF_THEME):
69
75
  add_lv_use(CONF_THEME)
70
76
  for w_name, style in theme.items():
71
- if not isinstance(style, dict):
72
- continue
73
-
74
- lname = "lv_theme_apply_" + w_name
75
- apply = lv_variable(lv_lambda_t, lname)
76
- theme_widget_map[w_name] = apply
77
- ow = Widget.create("obj", MockObj(ID("obj")), obj_spec)
78
- async with LambdaContext([(lv_obj_t_ptr, "obj")], where=w_name) as context:
79
- await set_obj_properties(ow, style)
80
- lv_assign(apply, await context.get_lambda())
77
+ # Work around Python 3.10 bug with nested async comprehensions
78
+ # With Python 3.11 this could be simplified
79
+ styles = {}
80
+ for part, states in collect_parts(style).items():
81
+ styles[part] = {
82
+ state: await create_style(
83
+ props,
84
+ "_lv_theme_style_" + w_name + "_" + part + "_" + state,
85
+ )
86
+ for state, props in states.items()
87
+ }
88
+ theme_widget_map[w_name] = styles
81
89
 
82
90
 
83
91
  async def add_top_layer(lv_component, config):