esphome 2025.8.4__py3-none-any.whl → 2025.9.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. esphome/__main__.py +36 -42
  2. esphome/components/absolute_humidity/absolute_humidity.cpp +3 -5
  3. esphome/components/adc/adc_sensor_esp32.cpp +29 -6
  4. esphome/components/ags10/ags10.cpp +3 -18
  5. esphome/components/ags10/ags10.h +2 -12
  6. esphome/components/aht10/aht10.cpp +3 -3
  7. esphome/components/airthings_ble/__init__.py +2 -2
  8. esphome/components/alarm_control_panel/__init__.py +2 -2
  9. esphome/components/am2315c/am2315c.cpp +1 -17
  10. esphome/components/am2315c/am2315c.h +2 -3
  11. esphome/components/api/__init__.py +2 -2
  12. esphome/components/api/api_connection.cpp +34 -23
  13. esphome/components/api/api_connection.h +20 -39
  14. esphome/components/api/api_frame_helper.cpp +25 -25
  15. esphome/components/api/api_frame_helper.h +3 -3
  16. esphome/components/api/api_frame_helper_noise.cpp +75 -40
  17. esphome/components/api/api_frame_helper_noise.h +3 -7
  18. esphome/components/api/api_frame_helper_plaintext.cpp +17 -4
  19. esphome/components/api/api_frame_helper_plaintext.h +1 -4
  20. esphome/components/api/api_pb2.cpp +20 -2
  21. esphome/components/api/api_pb2.h +146 -141
  22. esphome/components/api/api_pb2_dump.cpp +12 -1
  23. esphome/components/api/proto.cpp +33 -37
  24. esphome/components/async_tcp/__init__.py +2 -2
  25. esphome/components/atm90e26/sensor.py +2 -0
  26. esphome/components/atm90e32/sensor.py +4 -2
  27. esphome/components/audio_adc/__init__.py +2 -2
  28. esphome/components/audio_dac/__init__.py +2 -2
  29. esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +1 -1
  30. esphome/components/bedjet/bedjet_hub.cpp +1 -1
  31. esphome/components/binary_sensor/__init__.py +2 -2
  32. esphome/components/binary_sensor/binary_sensor.cpp +13 -0
  33. esphome/components/binary_sensor/binary_sensor.h +4 -7
  34. esphome/components/bl0940/__init__.py +6 -1
  35. esphome/components/bl0940/bl0940.cpp +178 -41
  36. esphome/components/bl0940/bl0940.h +121 -76
  37. esphome/components/bl0940/button/__init__.py +27 -0
  38. esphome/components/bl0940/button/calibration_reset_button.cpp +20 -0
  39. esphome/components/bl0940/button/calibration_reset_button.h +19 -0
  40. esphome/components/bl0940/number/__init__.py +94 -0
  41. esphome/components/bl0940/number/calibration_number.cpp +29 -0
  42. esphome/components/bl0940/number/calibration_number.h +26 -0
  43. esphome/components/bl0940/sensor.py +151 -2
  44. esphome/components/bl0942/bl0942.cpp +1 -1
  45. esphome/components/ble_client/output/__init__.py +4 -4
  46. esphome/components/bluetooth_proxy/__init__.py +1 -1
  47. esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -1
  48. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +15 -7
  49. esphome/components/bluetooth_proxy/bluetooth_proxy.h +3 -2
  50. esphome/components/button/__init__.py +2 -2
  51. esphome/components/button/button.cpp +13 -0
  52. esphome/components/button/button.h +4 -7
  53. esphome/components/camera/buffer.h +18 -0
  54. esphome/components/camera/buffer_impl.cpp +20 -0
  55. esphome/components/camera/buffer_impl.h +26 -0
  56. esphome/components/camera/camera.h +43 -0
  57. esphome/components/camera/encoder.h +69 -0
  58. esphome/components/camera_encoder/__init__.py +62 -0
  59. esphome/components/camera_encoder/encoder_buffer_impl.cpp +23 -0
  60. esphome/components/camera_encoder/encoder_buffer_impl.h +25 -0
  61. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +82 -0
  62. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +39 -0
  63. esphome/components/captive_portal/__init__.py +2 -2
  64. esphome/components/captive_portal/captive_portal.cpp +35 -12
  65. esphome/components/captive_portal/captive_portal.h +3 -3
  66. esphome/components/ccs811/ccs811.cpp +3 -3
  67. esphome/components/climate/__init__.py +2 -2
  68. esphome/components/climate/climate.cpp +1 -1
  69. esphome/components/cover/__init__.py +5 -5
  70. esphome/components/cover/cover.cpp +1 -1
  71. esphome/components/cover/cover.h +2 -2
  72. esphome/components/dallas_temp/dallas_temp.cpp +2 -2
  73. esphome/components/datetime/__init__.py +2 -2
  74. esphome/components/datetime/date_entity.h +2 -2
  75. esphome/components/datetime/datetime_entity.h +2 -2
  76. esphome/components/datetime/time_entity.h +2 -2
  77. esphome/components/debug/debug_esp32.cpp +1 -1
  78. esphome/components/display/__init__.py +4 -4
  79. esphome/components/duty_time/duty_time_sensor.cpp +1 -1
  80. esphome/components/esp32/__init__.py +0 -5
  81. esphome/components/esp32/gpio.cpp +27 -23
  82. esphome/components/esp32/gpio.h +26 -11
  83. esphome/components/esp32/preferences.cpp +8 -4
  84. esphome/components/esp32_ble/__init__.py +7 -2
  85. esphome/components/esp32_ble_client/ble_client_base.cpp +7 -3
  86. esphome/components/esp32_ble_tracker/__init__.py +2 -2
  87. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +9 -44
  88. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -14
  89. esphome/components/esp8266/__init__.py +2 -2
  90. esphome/components/esp8266/core.cpp +2 -2
  91. esphome/components/esp8266/gpio.py +4 -4
  92. esphome/components/esp8266/preferences.cpp +30 -28
  93. esphome/components/esphome/ota/__init__.py +2 -2
  94. esphome/components/esphome/ota/ota_esphome.cpp +21 -19
  95. esphome/components/esphome/ota/ota_esphome.h +6 -5
  96. esphome/components/ethernet/__init__.py +7 -2
  97. esphome/components/ethernet/ethernet_component.cpp +1 -1
  98. esphome/components/event/__init__.py +2 -2
  99. esphome/components/event/event.h +4 -4
  100. esphome/components/fan/__init__.py +2 -2
  101. esphome/components/fan/fan.cpp +2 -1
  102. esphome/components/gdk101/gdk101.cpp +4 -4
  103. esphome/components/globals/__init__.py +2 -2
  104. esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +19 -18
  105. esphome/components/gpio_expander/cached_gpio.h +36 -16
  106. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +5 -5
  107. esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +1 -1
  108. esphome/components/haier/haier_base.cpp +1 -1
  109. esphome/components/haier/hon_climate.cpp +1 -1
  110. esphome/components/hlw8012/hlw8012.cpp +5 -5
  111. esphome/components/honeywellabp2_i2c/honeywellabp2.cpp +4 -4
  112. esphome/components/host/preferences.h +3 -2
  113. esphome/components/hte501/hte501.cpp +3 -21
  114. esphome/components/hte501/hte501.h +2 -3
  115. esphome/components/http_request/ota/__init__.py +2 -2
  116. esphome/components/i2c/__init__.py +2 -2
  117. esphome/components/i2c/i2c.cpp +13 -9
  118. esphome/components/i2c/i2c_bus.h +36 -6
  119. esphome/components/i2s_audio/__init__.py +8 -2
  120. esphome/components/i2s_audio/media_player/__init__.py +1 -1
  121. esphome/components/i2s_audio/microphone/__init__.py +1 -1
  122. esphome/components/i2s_audio/speaker/__init__.py +1 -1
  123. esphome/components/inkplate/__init__.py +1 -0
  124. esphome/components/inkplate/const.py +105 -0
  125. esphome/components/inkplate/display.py +238 -0
  126. esphome/components/{inkplate6 → inkplate}/inkplate.cpp +156 -74
  127. esphome/components/{inkplate6 → inkplate}/inkplate.h +28 -68
  128. esphome/components/inkplate6/__init__.py +0 -1
  129. esphome/components/inkplate6/display.py +2 -211
  130. esphome/components/integration/integration_sensor.cpp +1 -1
  131. esphome/components/json/__init__.py +2 -2
  132. esphome/components/lc709203f/lc709203f.cpp +4 -17
  133. esphome/components/lc709203f/lc709203f.h +2 -3
  134. esphome/components/ld2420/text_sensor/{text_sensor.cpp → ld2420_text_sensor.cpp} +1 -1
  135. esphome/components/ld2450/ld2450.cpp +1 -1
  136. esphome/components/libretiny/preferences.cpp +13 -5
  137. esphome/components/light/__init__.py +2 -2
  138. esphome/components/light/addressable_light_effect.h +7 -0
  139. esphome/components/light/base_light_effects.h +8 -0
  140. esphome/components/light/light_call.cpp +22 -20
  141. esphome/components/light/light_effect.cpp +36 -0
  142. esphome/components/light/light_effect.h +14 -0
  143. esphome/components/light/light_json_schema.cpp +9 -1
  144. esphome/components/light/light_state.cpp +2 -2
  145. esphome/components/light/light_state.h +38 -0
  146. esphome/components/lock/__init__.py +2 -2
  147. esphome/components/lock/lock.h +2 -2
  148. esphome/components/logger/__init__.py +2 -2
  149. esphome/components/logger/logger.cpp +25 -4
  150. esphome/components/logger/logger.h +1 -1
  151. esphome/components/logger/logger_esp32.cpp +16 -8
  152. esphome/components/logger/logger_esp8266.cpp +11 -3
  153. esphome/components/logger/logger_libretiny.cpp +13 -3
  154. esphome/components/logger/logger_rp2040.cpp +14 -3
  155. esphome/components/logger/logger_zephyr.cpp +15 -4
  156. esphome/components/lvgl/defines.py +1 -0
  157. esphome/components/lvgl/hello_world.py +96 -33
  158. esphome/components/lvgl/number/lvgl_number.h +1 -1
  159. esphome/components/lvgl/select/lvgl_select.h +1 -1
  160. esphome/components/lvgl/widgets/__init__.py +0 -1
  161. esphome/components/lvgl/widgets/spinbox.py +20 -11
  162. esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp +1 -1
  163. esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp +1 -1
  164. esphome/components/mapping/__init__.py +13 -5
  165. esphome/components/mapping/mapping.h +69 -0
  166. esphome/components/max17043/max17043.cpp +2 -2
  167. esphome/components/mcp23016/__init__.py +1 -0
  168. esphome/components/mcp23016/mcp23016.cpp +20 -5
  169. esphome/components/mcp23016/mcp23016.h +10 -4
  170. esphome/components/mcp23x08_base/mcp23x08_base.cpp +1 -1
  171. esphome/components/mcp23x17_base/mcp23x17_base.cpp +2 -2
  172. esphome/components/mdns/__init__.py +2 -2
  173. esphome/components/mdns/mdns_component.cpp +145 -54
  174. esphome/components/media_player/__init__.py +2 -2
  175. esphome/components/micro_wake_word/__init__.py +2 -2
  176. esphome/components/microphone/__init__.py +2 -2
  177. esphome/components/mipi/__init__.py +77 -33
  178. esphome/components/mipi_rgb/__init__.py +2 -0
  179. esphome/components/mipi_rgb/display.py +321 -0
  180. esphome/components/mipi_rgb/mipi_rgb.cpp +388 -0
  181. esphome/components/mipi_rgb/mipi_rgb.h +127 -0
  182. esphome/components/mipi_rgb/models/guition.py +24 -0
  183. esphome/components/mipi_rgb/models/lilygo.py +228 -0
  184. esphome/components/mipi_rgb/models/rpi.py +9 -0
  185. esphome/components/mipi_rgb/models/st7701s.py +214 -0
  186. esphome/components/mipi_rgb/models/waveshare.py +64 -0
  187. esphome/components/mipi_spi/models/jc.py +229 -0
  188. esphome/components/mlx90614/mlx90614.cpp +1 -16
  189. esphome/components/mlx90614/mlx90614.h +0 -1
  190. esphome/components/mqtt/__init__.py +2 -2
  191. esphome/components/mqtt/mqtt_sensor.cpp +7 -2
  192. esphome/components/ms5611/ms5611.cpp +7 -6
  193. esphome/components/network/__init__.py +2 -2
  194. esphome/components/nextion/nextion_upload.cpp +4 -1
  195. esphome/components/nrf52/__init__.py +49 -6
  196. esphome/components/nrf52/const.py +1 -0
  197. esphome/components/nrf52/dfu.cpp +51 -0
  198. esphome/components/nrf52/dfu.h +24 -0
  199. esphome/components/ntc/ntc.cpp +1 -1
  200. esphome/components/number/__init__.py +2 -2
  201. esphome/components/number/automation.cpp +1 -1
  202. esphome/components/number/number.cpp +21 -0
  203. esphome/components/number/number.h +4 -13
  204. esphome/components/opentherm/hub.h +6 -6
  205. esphome/components/opentherm/number/{number.cpp → opentherm_number.cpp} +2 -2
  206. esphome/components/opentherm/output/{output.cpp → opentherm_output.cpp} +1 -1
  207. esphome/components/opentherm/switch/{switch.cpp → opentherm_switch.cpp} +1 -1
  208. esphome/components/ota/__init__.py +2 -2
  209. esphome/components/pca6416a/__init__.py +1 -0
  210. esphome/components/pca6416a/pca6416a.cpp +20 -5
  211. esphome/components/pca6416a/pca6416a.h +12 -5
  212. esphome/components/pca9554/__init__.py +2 -1
  213. esphome/components/pca9554/pca9554.cpp +12 -18
  214. esphome/components/pca9554/pca9554.h +10 -9
  215. esphome/components/pcf8574/__init__.py +1 -0
  216. esphome/components/pcf8574/pcf8574.cpp +14 -5
  217. esphome/components/pcf8574/pcf8574.h +13 -6
  218. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +7 -7
  219. esphome/components/pipsolar/__init__.py +3 -3
  220. esphome/components/pipsolar/output/__init__.py +4 -4
  221. esphome/components/pulse_width/pulse_width.cpp +2 -2
  222. esphome/components/qmp6988/qmp6988.cpp +81 -126
  223. esphome/components/qmp6988/qmp6988.h +31 -37
  224. esphome/components/radon_eye_ble/__init__.py +2 -2
  225. esphome/components/remote_base/__init__.py +6 -8
  226. esphome/components/rotary_encoder/rotary_encoder.cpp +1 -1
  227. esphome/components/rp2040/__init__.py +2 -2
  228. esphome/components/runtime_stats/runtime_stats.cpp +10 -23
  229. esphome/components/runtime_stats/runtime_stats.h +4 -10
  230. esphome/components/safe_mode/__init__.py +2 -2
  231. esphome/components/safe_mode/safe_mode.cpp +33 -31
  232. esphome/components/script/script.cpp +6 -0
  233. esphome/components/script/script.h +19 -5
  234. esphome/components/sdm_meter/sensor.py +3 -1
  235. esphome/components/select/__init__.py +2 -2
  236. esphome/components/select/select.h +2 -2
  237. esphome/components/sen5x/sen5x.cpp +57 -55
  238. esphome/components/sen5x/sen5x.h +21 -15
  239. esphome/components/sen5x/sensor.py +67 -44
  240. esphome/components/sensirion_common/i2c_sensirion.cpp +18 -47
  241. esphome/components/sensirion_common/i2c_sensirion.h +39 -55
  242. esphome/components/sensor/__init__.py +2 -2
  243. esphome/components/sensor/automation.h +1 -1
  244. esphome/components/sensor/sensor.cpp +34 -6
  245. esphome/components/sensor/sensor.h +4 -21
  246. esphome/components/sgp30/sgp30.cpp +34 -35
  247. esphome/components/sgp30/sgp30.h +11 -10
  248. esphome/components/sgp4x/sgp4x.cpp +2 -2
  249. esphome/components/shelly_dimmer/light.py +7 -7
  250. esphome/components/sht4x/sht4x.cpp +1 -1
  251. esphome/components/sntp/sntp_component.cpp +36 -9
  252. esphome/components/sntp/sntp_component.h +7 -0
  253. esphome/components/sound_level/sound_level.cpp +1 -1
  254. esphome/components/speaker/__init__.py +2 -2
  255. esphome/components/speaker/media_player/__init__.py +2 -2
  256. esphome/components/speaker/media_player/speaker_media_player.cpp +1 -1
  257. esphome/components/spi/__init__.py +2 -2
  258. esphome/components/sprinkler/sprinkler.cpp +1 -1
  259. esphome/components/sps30/sps30.cpp +18 -23
  260. esphome/components/sps30/sps30.h +3 -3
  261. esphome/components/status_led/__init__.py +2 -2
  262. esphome/components/stepper/__init__.py +2 -2
  263. esphome/components/switch/__init__.py +2 -2
  264. esphome/components/switch/switch.cpp +5 -5
  265. esphome/components/sx1509/__init__.py +1 -1
  266. esphome/components/sx1509/sx1509.cpp +12 -7
  267. esphome/components/sx1509/sx1509.h +11 -4
  268. esphome/components/tca9555/tca9555.cpp +5 -5
  269. esphome/components/tee501/tee501.cpp +2 -21
  270. esphome/components/tee501/tee501.h +2 -4
  271. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +1 -1
  272. esphome/components/template/datetime/template_date.cpp +1 -1
  273. esphome/components/template/datetime/template_datetime.cpp +2 -2
  274. esphome/components/template/datetime/template_time.cpp +1 -1
  275. esphome/components/template/number/template_number.cpp +1 -1
  276. esphome/components/template/select/template_select.cpp +1 -1
  277. esphome/components/template/text/template_text.cpp +1 -1
  278. esphome/components/text/__init__.py +2 -2
  279. esphome/components/text/text.h +2 -2
  280. esphome/components/text_sensor/__init__.py +2 -2
  281. esphome/components/text_sensor/text_sensor.h +4 -4
  282. esphome/components/thermostat/climate.py +11 -7
  283. esphome/components/thermostat/thermostat_climate.cpp +237 -206
  284. esphome/components/thermostat/thermostat_climate.h +52 -41
  285. esphome/components/time/__init__.py +2 -2
  286. esphome/components/tmp1075/tmp1075.cpp +1 -1
  287. esphome/components/total_daily_energy/total_daily_energy.cpp +1 -1
  288. esphome/components/touchscreen/__init__.py +2 -2
  289. esphome/components/tuya/number/tuya_number.cpp +1 -1
  290. esphome/components/udp/udp_component.cpp +3 -3
  291. esphome/components/ufire_ec/ufire_ec.cpp +4 -4
  292. esphome/components/ufire_ise/ufire_ise.cpp +4 -4
  293. esphome/components/update/__init__.py +2 -2
  294. esphome/components/usb_uart/usb_uart.cpp +1 -1
  295. esphome/components/valve/__init__.py +5 -5
  296. esphome/components/valve/valve.cpp +1 -1
  297. esphome/components/valve/valve.h +2 -2
  298. esphome/components/wake_on_lan/wake_on_lan.cpp +2 -2
  299. esphome/components/waveshare_epaper/waveshare_213v3.cpp +1 -1
  300. esphome/components/web_server/__init__.py +2 -2
  301. esphome/components/web_server/ota/__init__.py +2 -2
  302. esphome/components/web_server/ota/ota_web_server.cpp +11 -0
  303. esphome/components/web_server/web_server.cpp +58 -12
  304. esphome/components/web_server_base/__init__.py +2 -2
  305. esphome/components/wifi/__init__.py +5 -5
  306. esphome/components/wifi/wifi_component.cpp +3 -3
  307. esphome/components/wifi/wifi_component_esp_idf.cpp +2 -0
  308. esphome/config_validation.py +2 -2
  309. esphome/const.py +2 -1
  310. esphome/core/__init__.py +1 -0
  311. esphome/core/application.cpp +89 -51
  312. esphome/core/application.h +1 -0
  313. esphome/core/component.cpp +41 -19
  314. esphome/core/component.h +17 -13
  315. esphome/core/config.py +7 -7
  316. esphome/core/defines.h +4 -0
  317. esphome/core/entity_base.cpp +22 -8
  318. esphome/core/entity_base.h +43 -0
  319. esphome/core/helpers.cpp +26 -13
  320. esphome/core/helpers.h +4 -3
  321. esphome/core/ring_buffer.cpp +6 -2
  322. esphome/core/ring_buffer.h +2 -1
  323. esphome/core/scheduler.cpp +175 -94
  324. esphome/core/scheduler.h +66 -35
  325. esphome/core/time.cpp +6 -20
  326. esphome/coroutine.py +80 -3
  327. esphome/cpp_generator.py +13 -0
  328. esphome/cpp_helpers.py +2 -2
  329. esphome/dashboard/web_server.py +67 -10
  330. esphome/espota2.py +13 -6
  331. esphome/helpers.py +68 -83
  332. esphome/resolver.py +67 -0
  333. esphome/util.py +9 -6
  334. esphome/wizard.py +39 -26
  335. {esphome-2025.8.4.dist-info → esphome-2025.9.0b1.dist-info}/METADATA +9 -9
  336. {esphome-2025.8.4.dist-info → esphome-2025.9.0b1.dist-info}/RECORD +344 -313
  337. /esphome/components/ld2420/text_sensor/{text_sensor.h → ld2420_text_sensor.h} +0 -0
  338. /esphome/components/opentherm/number/{number.h → opentherm_number.h} +0 -0
  339. /esphome/components/opentherm/output/{output.h → opentherm_output.h} +0 -0
  340. /esphome/components/opentherm/switch/{switch.h → opentherm_switch.h} +0 -0
  341. {esphome-2025.8.4.dist-info → esphome-2025.9.0b1.dist-info}/WHEEL +0 -0
  342. {esphome-2025.8.4.dist-info → esphome-2025.9.0b1.dist-info}/entry_points.txt +0 -0
  343. {esphome-2025.8.4.dist-info → esphome-2025.9.0b1.dist-info}/licenses/LICENSE +0 -0
  344. {esphome-2025.8.4.dist-info → esphome-2025.9.0b1.dist-info}/top_level.txt +0 -0
@@ -4,49 +4,112 @@ from esphome.yaml_util import parse_yaml
4
4
 
5
5
  CONFIG = """
6
6
  - obj:
7
- radius: 0
7
+ id: hello_world_card_
8
8
  pad_all: 12
9
- bg_color: 0xFFFFFF
9
+ bg_color: white
10
10
  height: 100%
11
11
  width: 100%
12
+ scrollable: false
12
13
  widgets:
13
- - spinner:
14
- id: hello_world_spinner_
15
- align: center
16
- indicator:
17
- arc_color: tomato
18
- height: 100
19
- width: 100
20
- spin_time: 2s
21
- arc_length: 60deg
22
- - label:
23
- id: hello_world_label_
24
- text: "Hello World!"
14
+ - obj:
15
+ align: top_mid
16
+ outline_width: 0
17
+ border_width: 0
18
+ pad_all: 4
19
+ scrollable: false
20
+ height: size_content
21
+ width: 100%
22
+ layout:
23
+ type: flex
24
+ flex_flow: row
25
+ flex_align_cross: center
26
+ flex_align_track: start
27
+ flex_align_main: space_between
28
+ widgets:
29
+ - button:
30
+ checkable: true
31
+ radius: 4
32
+ text_font: montserrat_20
33
+ on_click:
34
+ lvgl.label.update:
35
+ id: hello_world_label_
36
+ text: "Clicked!"
37
+ widgets:
38
+ - label:
39
+ text: "Button"
40
+ - label:
41
+ id: hello_world_title_
42
+ text: ESPHome
43
+ text_font: montserrat_20
44
+ width: 100%
45
+ text_align: center
46
+ on_boot:
47
+ lvgl.widget.refresh: hello_world_title_
48
+ hidden: !lambda |-
49
+ return lv_obj_get_width(lv_scr_act()) < 400;
50
+ - checkbox:
51
+ text: Checkbox
52
+ id: hello_world_checkbox_
53
+ on_boot:
54
+ lvgl.widget.refresh: hello_world_checkbox_
55
+ hidden: !lambda |-
56
+ return lv_obj_get_width(lv_scr_act()) < 240;
57
+ on_click:
58
+ lvgl.label.update:
59
+ id: hello_world_label_
60
+ text: "Checked!"
61
+ - obj:
62
+ id: hello_world_container_
25
63
  align: center
64
+ y: 14
65
+ pad_all: 0
66
+ outline_width: 0
67
+ border_width: 0
68
+ width: 100%
69
+ height: size_content
70
+ scrollable: false
26
71
  on_click:
27
72
  lvgl.spinner.update:
28
73
  id: hello_world_spinner_
29
74
  arc_color: springgreen
30
- - checkbox:
31
- pad_all: 8
32
- text: Checkbox
33
- align: top_right
34
- on_click:
35
- lvgl.label.update:
36
- id: hello_world_label_
37
- text: "Checked!"
38
- - button:
39
- pad_all: 8
40
- checkable: true
41
- align: top_left
42
- text_font: montserrat_20
43
- on_click:
44
- lvgl.label.update:
45
- id: hello_world_label_
46
- text: "Clicked!"
75
+ layout:
76
+ type: flex
77
+ flex_flow: row_wrap
78
+ flex_align_cross: center
79
+ flex_align_track: center
80
+ flex_align_main: space_evenly
47
81
  widgets:
48
- - label:
49
- text: "Button"
82
+ - spinner:
83
+ id: hello_world_spinner_
84
+ indicator:
85
+ arc_color: tomato
86
+ height: 100
87
+ width: 100
88
+ spin_time: 2s
89
+ arc_length: 60deg
90
+ widgets:
91
+ - label:
92
+ id: hello_world_label_
93
+ text: "Hello World!"
94
+ align: center
95
+ - obj:
96
+ id: hello_world_qrcode_
97
+ outline_width: 0
98
+ border_width: 0
99
+ hidden: !lambda |-
100
+ return lv_obj_get_width(lv_scr_act()) < 300 && lv_obj_get_height(lv_scr_act()) < 400;
101
+ widgets:
102
+ - label:
103
+ text_font: montserrat_14
104
+ text: esphome.io
105
+ align: top_mid
106
+ - qrcode:
107
+ text: "https://esphome.io"
108
+ size: 80
109
+ align: bottom_mid
110
+ on_boot:
111
+ lvgl.widget.refresh: hello_world_qrcode_
112
+
50
113
  - slider:
51
114
  width: 80%
52
115
  align: bottom_mid
@@ -21,7 +21,7 @@ class LVGLNumber : public number::Number, public Component {
21
21
  void setup() override {
22
22
  float value = this->value_lambda_();
23
23
  if (this->restore_) {
24
- this->pref_ = global_preferences->make_preference<float>(this->get_object_id_hash());
24
+ this->pref_ = global_preferences->make_preference<float>(this->get_preference_hash());
25
25
  if (this->pref_.load(&value)) {
26
26
  this->control_lambda_(value);
27
27
  }
@@ -20,7 +20,7 @@ class LVGLSelect : public select::Select, public Component {
20
20
  this->set_options_();
21
21
  if (this->restore_) {
22
22
  size_t index;
23
- this->pref_ = global_preferences->make_preference<size_t>(this->get_object_id_hash());
23
+ this->pref_ = global_preferences->make_preference<size_t>(this->get_preference_hash());
24
24
  if (this->pref_.load(&index))
25
25
  this->widget_->set_selected_index(index, LV_ANIM_OFF);
26
26
  }
@@ -67,7 +67,6 @@ class Widget:
67
67
  self.type = wtype
68
68
  self.config = config
69
69
  self.scale = 1.0
70
- self.step = 1.0
71
70
  self.range_from = -sys.maxsize
72
71
  self.range_to = sys.maxsize
73
72
  if wtype.is_compound():
@@ -11,6 +11,7 @@ from ..defines import (
11
11
  CONF_ROLLOVER,
12
12
  CONF_SCROLLBAR,
13
13
  CONF_SELECTED,
14
+ CONF_SELECTED_DIGIT,
14
15
  CONF_TEXTAREA_PLACEHOLDER,
15
16
  )
16
17
  from ..lv_validation import lv_bool, lv_float
@@ -38,18 +39,24 @@ def validate_spinbox(config):
38
39
  min_val = -1 - max_val
39
40
  range_from = int(config[CONF_RANGE_FROM])
40
41
  range_to = int(config[CONF_RANGE_TO])
41
- step = int(config[CONF_STEP])
42
+ step = config[CONF_SELECTED_DIGIT]
43
+ digits = config[CONF_DIGITS]
42
44
  if (
43
45
  range_from > max_val
44
46
  or range_from < min_val
45
47
  or range_to > max_val
46
48
  or range_to < min_val
47
49
  ):
48
- raise cv.Invalid("Range outside allowed limits")
49
- if step <= 0 or step >= (range_to - range_from) / 2:
50
- raise cv.Invalid("Invalid step value")
51
- if config[CONF_DIGITS] <= config[CONF_DECIMAL_PLACES]:
52
- raise cv.Invalid("Number of digits must exceed number of decimal places")
50
+ raise cv.Invalid("Range outside allowed limits", path=[CONF_RANGE_FROM])
51
+ if digits <= config[CONF_DECIMAL_PLACES]:
52
+ raise cv.Invalid(
53
+ "Number of digits must exceed number of decimal places", path=[CONF_DIGITS]
54
+ )
55
+ if step >= digits:
56
+ raise cv.Invalid(
57
+ "Initial selected digit must be less than number of digits",
58
+ path=[CONF_SELECTED_DIGIT],
59
+ )
53
60
  return config
54
61
 
55
62
 
@@ -59,7 +66,10 @@ SPINBOX_SCHEMA = cv.Schema(
59
66
  cv.Optional(CONF_RANGE_FROM, default=0): cv.float_,
60
67
  cv.Optional(CONF_RANGE_TO, default=100): cv.float_,
61
68
  cv.Optional(CONF_DIGITS, default=4): cv.int_range(1, 10),
62
- cv.Optional(CONF_STEP, default=1.0): cv.positive_float,
69
+ cv.Optional(CONF_STEP): cv.invalid(
70
+ f"{CONF_STEP} has been replaced by {CONF_SELECTED_DIGIT}"
71
+ ),
72
+ cv.Optional(CONF_SELECTED_DIGIT, default=0): cv.positive_int,
63
73
  cv.Optional(CONF_DECIMAL_PLACES, default=0): cv.int_range(0, 6),
64
74
  cv.Optional(CONF_ROLLOVER, default=False): lv_bool,
65
75
  }
@@ -93,13 +103,12 @@ class SpinboxType(WidgetType):
93
103
  scale = 10 ** config[CONF_DECIMAL_PLACES]
94
104
  range_from = int(config[CONF_RANGE_FROM]) * scale
95
105
  range_to = int(config[CONF_RANGE_TO]) * scale
96
- step = int(config[CONF_STEP]) * scale
106
+ step = config[CONF_SELECTED_DIGIT]
97
107
  w.scale = scale
98
- w.step = step
99
108
  w.range_to = range_to
100
109
  w.range_from = range_from
101
110
  lv.spinbox_set_range(w.obj, range_from, range_to)
102
- await w.set_property(CONF_STEP, step)
111
+ await w.set_property("step", 10**step)
103
112
  await w.set_property(CONF_ROLLOVER, config)
104
113
  lv.spinbox_set_digit_format(
105
114
  w.obj, digits, digits - config[CONF_DECIMAL_PLACES]
@@ -120,7 +129,7 @@ class SpinboxType(WidgetType):
120
129
  return config[CONF_RANGE_FROM]
121
130
 
122
131
  def get_step(self, config: dict):
123
- return config[CONF_STEP]
132
+ return 10 ** config[CONF_SELECTED_DIGIT]
124
133
 
125
134
 
126
135
  spinbox_spec = SpinboxType()
@@ -6,7 +6,7 @@ namespace m5stack_8angle {
6
6
  void M5Stack8AngleSwitchBinarySensor::update() {
7
7
  int8_t out = this->parent_->read_switch();
8
8
  if (out == -1) {
9
- this->status_set_warning("Could not read binary sensor state from M5Stack 8Angle.");
9
+ this->status_set_warning(LOG_STR("Could not read binary sensor state from M5Stack 8Angle."));
10
10
  return;
11
11
  }
12
12
  this->publish_state(out != 0);
@@ -7,7 +7,7 @@ void M5Stack8AngleKnobSensor::update() {
7
7
  if (this->parent_ != nullptr) {
8
8
  int32_t raw_pos = this->parent_->read_knob_pos_raw(this->channel_, this->bits_);
9
9
  if (raw_pos == -1) {
10
- this->status_set_warning("Could not read knob position from M5Stack 8Angle.");
10
+ this->status_set_warning(LOG_STR("Could not read knob position from M5Stack 8Angle."));
11
11
  return;
12
12
  }
13
13
  if (this->raw_) {
@@ -10,7 +10,8 @@ from esphome.loader import get_component
10
10
  CODEOWNERS = ["@clydebarrow"]
11
11
  MULTI_CONF = True
12
12
 
13
- map_ = cg.std_ns.class_("map")
13
+ mapping_ns = cg.esphome_ns.namespace("mapping")
14
+ mapping_class = mapping_ns.class_("Mapping")
14
15
 
15
16
  CONF_ENTRIES = "entries"
16
17
  CONF_CLASS = "class"
@@ -29,7 +30,11 @@ class IndexType:
29
30
 
30
31
  INDEX_TYPES = {
31
32
  "int": IndexType(cv.int_, cg.int_, int),
32
- "string": IndexType(cv.string, cg.std_string, str),
33
+ "string": IndexType(
34
+ cv.string,
35
+ cg.std_string,
36
+ str,
37
+ ),
33
38
  }
34
39
 
35
40
 
@@ -47,7 +52,7 @@ def to_schema(value):
47
52
 
48
53
  BASE_SCHEMA = cv.Schema(
49
54
  {
50
- cv.Required(CONF_ID): cv.declare_id(map_),
55
+ cv.Required(CONF_ID): cv.declare_id(mapping_class),
51
56
  cv.Required(CONF_FROM): cv.one_of(*INDEX_TYPES, lower=True),
52
57
  cv.Required(CONF_TO): cv.string,
53
58
  },
@@ -123,12 +128,15 @@ async def to_code(config):
123
128
  if list(entries.values())[0].op != ".":
124
129
  value_type = value_type.operator("ptr")
125
130
  varid = config[CONF_ID]
126
- varid.type = map_.template(index_type, value_type)
131
+ varid.type = mapping_class.template(
132
+ index_type,
133
+ value_type,
134
+ )
127
135
  var = MockObj(varid, ".")
128
136
  decl = VariableDeclarationExpression(varid.type, "", varid)
129
137
  add_global(decl)
130
138
  CORE.register_variable(varid, var)
131
139
 
132
140
  for key, value in entries.items():
133
- cg.add(var.insert((key, value)))
141
+ cg.add(var.set(key, value))
134
142
  return var
@@ -0,0 +1,69 @@
1
+ #pragma once
2
+
3
+ #include "esphome/core/helpers.h"
4
+ #include "esphome/core/log.h"
5
+ #include <map>
6
+ #include <string>
7
+
8
+ namespace esphome::mapping {
9
+
10
+ using alloc_string_t = std::basic_string<char, std::char_traits<char>, RAMAllocator<char>>;
11
+
12
+ /**
13
+ *
14
+ * Mapping class with custom allocator.
15
+ * Additionally, when std::string is used as key or value, it will be replaced with a custom string type
16
+ * that uses RAMAllocator.
17
+ * @tparam K The type of the key in the mapping.
18
+ * @tparam V The type of the value in the mapping. Should be a basic type or pointer.
19
+ */
20
+
21
+ static const char *const TAG = "mapping";
22
+
23
+ template<typename K, typename V> class Mapping {
24
+ public:
25
+ // Constructor
26
+ Mapping() = default;
27
+
28
+ using key_t = const std::conditional_t<std::is_same_v<K, std::string>,
29
+ alloc_string_t, // if K is std::string, custom string type
30
+ K>;
31
+ using value_t = std::conditional_t<std::is_same_v<V, std::string>,
32
+ alloc_string_t, // if V is std::string, custom string type
33
+ V>;
34
+
35
+ void set(const K &key, const V &value) { this->map_[key_t{key}] = value; }
36
+
37
+ V get(const K &key) const {
38
+ auto it = this->map_.find(key_t{key});
39
+ if (it != this->map_.end()) {
40
+ return V{it->second};
41
+ }
42
+ if constexpr (std::is_pointer_v<K>) {
43
+ esph_log_e(TAG, "Key '%p' not found in mapping", key);
44
+ } else if constexpr (std::is_same_v<K, std::string>) {
45
+ esph_log_e(TAG, "Key '%s' not found in mapping", key.c_str());
46
+ } else {
47
+ esph_log_e(TAG, "Key '%s' not found in mapping", to_string(key).c_str());
48
+ }
49
+ return {};
50
+ }
51
+
52
+ // index map overload
53
+ V operator[](K key) { return this->get(key); }
54
+
55
+ // convenience function for strings to get a C-style string
56
+ template<typename T = V, std::enable_if_t<std::is_same_v<T, std::string>, int> = 0>
57
+ const char *operator[](K key) const {
58
+ auto it = this->map_.find(key_t{key});
59
+ if (it != this->map_.end()) {
60
+ return it->second.c_str(); // safe since value remains in map
61
+ }
62
+ return "";
63
+ }
64
+
65
+ protected:
66
+ std::map<key_t, value_t, std::less<key_t>, RAMAllocator<std::pair<key_t, value_t>>> map_;
67
+ };
68
+
69
+ } // namespace esphome::mapping
@@ -22,7 +22,7 @@ void MAX17043Component::update() {
22
22
 
23
23
  if (this->voltage_sensor_ != nullptr) {
24
24
  if (!this->read_byte_16(MAX17043_VCELL, &raw_voltage)) {
25
- this->status_set_warning("Unable to read MAX17043_VCELL");
25
+ this->status_set_warning(LOG_STR("Unable to read MAX17043_VCELL"));
26
26
  } else {
27
27
  float voltage = (1.25 * (float) (raw_voltage >> 4)) / 1000.0;
28
28
  this->voltage_sensor_->publish_state(voltage);
@@ -31,7 +31,7 @@ void MAX17043Component::update() {
31
31
  }
32
32
  if (this->battery_remaining_sensor_ != nullptr) {
33
33
  if (!this->read_byte_16(MAX17043_SOC, &raw_percent)) {
34
- this->status_set_warning("Unable to read MAX17043_SOC");
34
+ this->status_set_warning(LOG_STR("Unable to read MAX17043_SOC"));
35
35
  } else {
36
36
  float percent = (float) ((raw_percent >> 8) + 0.003906f * (raw_percent & 0x00ff));
37
37
  this->battery_remaining_sensor_->publish_state(percent);
@@ -11,6 +11,7 @@ from esphome.const import (
11
11
  CONF_OUTPUT,
12
12
  )
13
13
 
14
+ AUTO_LOAD = ["gpio_expander"]
14
15
  DEPENDENCIES = ["i2c"]
15
16
  MULTI_CONF = True
16
17
 
@@ -22,14 +22,29 @@ void MCP23016::setup() {
22
22
  this->write_reg_(MCP23016_IODIR0, 0xFF);
23
23
  this->write_reg_(MCP23016_IODIR1, 0xFF);
24
24
  }
25
- bool MCP23016::digital_read(uint8_t pin) {
26
- uint8_t bit = pin % 8;
25
+
26
+ void MCP23016::loop() {
27
+ // Invalidate cache at the start of each loop
28
+ this->reset_pin_cache_();
29
+ }
30
+ bool MCP23016::digital_read_hw(uint8_t pin) {
27
31
  uint8_t reg_addr = pin < 8 ? MCP23016_GP0 : MCP23016_GP1;
28
32
  uint8_t value = 0;
29
- this->read_reg_(reg_addr, &value);
30
- return value & (1 << bit);
33
+ if (!this->read_reg_(reg_addr, &value)) {
34
+ return false;
35
+ }
36
+
37
+ // Update the appropriate part of input_mask_
38
+ if (pin < 8) {
39
+ this->input_mask_ = (this->input_mask_ & 0xFF00) | value;
40
+ } else {
41
+ this->input_mask_ = (this->input_mask_ & 0x00FF) | (uint16_t(value) << 8);
42
+ }
43
+ return true;
31
44
  }
32
- void MCP23016::digital_write(uint8_t pin, bool value) {
45
+
46
+ bool MCP23016::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); }
47
+ void MCP23016::digital_write_hw(uint8_t pin, bool value) {
33
48
  uint8_t reg_addr = pin < 8 ? MCP23016_OLAT0 : MCP23016_OLAT1;
34
49
  this->update_reg_(pin, value, reg_addr);
35
50
  }
@@ -3,6 +3,7 @@
3
3
  #include "esphome/core/component.h"
4
4
  #include "esphome/core/hal.h"
5
5
  #include "esphome/components/i2c/i2c.h"
6
+ #include "esphome/components/gpio_expander/cached_gpio.h"
6
7
 
7
8
  namespace esphome {
8
9
  namespace mcp23016 {
@@ -24,19 +25,22 @@ enum MCP23016GPIORegisters {
24
25
  MCP23016_IOCON1 = 0x0B,
25
26
  };
26
27
 
27
- class MCP23016 : public Component, public i2c::I2CDevice {
28
+ class MCP23016 : public Component, public i2c::I2CDevice, public gpio_expander::CachedGpioExpander<uint8_t, 16> {
28
29
  public:
29
30
  MCP23016() = default;
30
31
 
31
32
  void setup() override;
32
-
33
- bool digital_read(uint8_t pin);
34
- void digital_write(uint8_t pin, bool value);
33
+ void loop() override;
35
34
  void pin_mode(uint8_t pin, gpio::Flags flags);
36
35
 
37
36
  float get_setup_priority() const override;
38
37
 
39
38
  protected:
39
+ // Virtual methods from CachedGpioExpander
40
+ bool digital_read_hw(uint8_t pin) override;
41
+ bool digital_read_cache(uint8_t pin) override;
42
+ void digital_write_hw(uint8_t pin, bool value) override;
43
+
40
44
  // read a given register
41
45
  bool read_reg_(uint8_t reg, uint8_t *value);
42
46
  // write a value to a given register
@@ -46,6 +50,8 @@ class MCP23016 : public Component, public i2c::I2CDevice {
46
50
 
47
51
  uint8_t olat_0_{0x00};
48
52
  uint8_t olat_1_{0x00};
53
+ // Cache for input values (16-bit combined for both banks)
54
+ uint16_t input_mask_{0x00};
49
55
  };
50
56
 
51
57
  class MCP23016GPIOPin : public GPIOPin {
@@ -8,7 +8,7 @@ static const char *const TAG = "mcp23x08_base";
8
8
 
9
9
  bool MCP23X08Base::digital_read_hw(uint8_t pin) {
10
10
  if (!this->read_reg(mcp23x08_base::MCP23X08_GPIO, &this->input_mask_)) {
11
- this->status_set_warning(ESP_LOG_MSG_COMM_FAIL);
11
+ this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
12
12
  return false;
13
13
  }
14
14
  return true;
@@ -11,13 +11,13 @@ bool MCP23X17Base::digital_read_hw(uint8_t pin) {
11
11
  uint8_t data;
12
12
  if (pin < 8) {
13
13
  if (!this->read_reg(mcp23x17_base::MCP23X17_GPIOA, &data)) {
14
- this->status_set_warning(ESP_LOG_MSG_COMM_FAIL);
14
+ this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
15
15
  return false;
16
16
  }
17
17
  this->input_mask_ = encode_uint16(this->input_mask_ >> 8, data);
18
18
  } else {
19
19
  if (!this->read_reg(mcp23x17_base::MCP23X17_GPIOB, &data)) {
20
- this->status_set_warning(ESP_LOG_MSG_COMM_FAIL);
20
+ this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
21
21
  return false;
22
22
  }
23
23
  this->input_mask_ = encode_uint16(data, this->input_mask_ & 0xFF);
@@ -11,7 +11,7 @@ from esphome.const import (
11
11
  CONF_SERVICES,
12
12
  PlatformFramework,
13
13
  )
14
- from esphome.core import CORE, coroutine_with_priority
14
+ from esphome.core import CORE, CoroPriority, coroutine_with_priority
15
15
 
16
16
  CODEOWNERS = ["@esphome/core"]
17
17
  DEPENDENCIES = ["network"]
@@ -72,7 +72,7 @@ def mdns_service(
72
72
  )
73
73
 
74
74
 
75
- @coroutine_with_priority(55.0)
75
+ @coroutine_with_priority(CoroPriority.COMMUNICATION)
76
76
  async def to_code(config):
77
77
  if config[CONF_DISABLED] is True:
78
78
  return