esphome 2024.10.3__py3-none-any.whl → 2024.11.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 (234) hide show
  1. esphome/__main__.py +22 -4
  2. esphome/automation.py +29 -2
  3. esphome/components/animation/__init__.py +5 -8
  4. esphome/components/animation/animation.cpp +1 -1
  5. esphome/components/audio/__init__.py +9 -0
  6. esphome/components/audio/audio.h +21 -0
  7. esphome/components/axs15231/__init__.py +6 -0
  8. esphome/components/axs15231/touchscreen/__init__.py +36 -0
  9. esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +64 -0
  10. esphome/components/axs15231/touchscreen/axs15231_touchscreen.h +27 -0
  11. esphome/components/bme68x_bsec2/__init__.py +1 -1
  12. esphome/components/bme68x_bsec2/bme68x_bsec2.cpp +50 -47
  13. esphome/components/bme68x_bsec2/bme68x_bsec2.h +0 -2
  14. esphome/components/bytebuffer/__init__.py +5 -0
  15. esphome/components/bytebuffer/bytebuffer.h +421 -0
  16. esphome/components/climate/__init__.py +14 -13
  17. esphome/components/datetime/__init__.py +3 -3
  18. esphome/components/debug/debug_esp32.cpp +16 -8
  19. esphome/components/dfplayer/dfplayer.cpp +132 -6
  20. esphome/components/dfplayer/dfplayer.h +19 -53
  21. esphome/components/display/display.cpp +142 -0
  22. esphome/components/display/display.h +7 -0
  23. esphome/components/es8311/__init__.py +0 -0
  24. esphome/components/es8311/audio_dac.py +70 -0
  25. esphome/components/es8311/es8311.cpp +227 -0
  26. esphome/components/es8311/es8311.h +135 -0
  27. esphome/components/es8311/es8311_const.h +195 -0
  28. esphome/components/esp32/boards.py +199 -1
  29. esphome/components/esp32/gpio.py +3 -1
  30. esphome/components/esp32_ble/const_esp32c6.h +7 -0
  31. esphome/components/esp32_ble_client/ble_client_base.h +1 -1
  32. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +3 -0
  33. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -1
  34. esphome/components/esp32_rmt_led_strip/led_strip.cpp +2 -2
  35. esphome/components/esp32_rmt_led_strip/led_strip.h +2 -0
  36. esphome/components/esp32_rmt_led_strip/light.py +3 -1
  37. esphome/components/esp8266/gpio.py +7 -5
  38. esphome/components/ethernet/__init__.py +55 -1
  39. esphome/components/ethernet/ethernet_component.cpp +14 -1
  40. esphome/components/ethernet/ethernet_component.h +7 -1
  41. esphome/components/font/__init__.py +213 -108
  42. esphome/components/gp8403/output/__init__.py +1 -1
  43. esphome/components/host/gpio.py +6 -4
  44. esphome/components/http_request/__init__.py +12 -0
  45. esphome/components/http_request/http_request.h +65 -3
  46. esphome/components/http_request/http_request_arduino.cpp +4 -3
  47. esphome/components/http_request/http_request_idf.cpp +12 -14
  48. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  49. esphome/components/http_request/update/http_request_update.cpp +1 -1
  50. esphome/components/i2c_device/__init__.py +26 -0
  51. esphome/components/i2c_device/i2c_device.cpp +17 -0
  52. esphome/components/i2c_device/i2c_device.h +18 -0
  53. esphome/components/i2s_audio/__init__.py +1 -3
  54. esphome/components/i2s_audio/speaker/__init__.py +12 -4
  55. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +426 -200
  56. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +92 -33
  57. esphome/components/ili9xxx/display.py +5 -1
  58. esphome/components/image/__init__.py +5 -8
  59. esphome/components/image/image.cpp +14 -14
  60. esphome/components/image/image.h +20 -24
  61. esphome/components/internal_temperature/internal_temperature.cpp +51 -2
  62. esphome/components/internal_temperature/internal_temperature.h +1 -0
  63. esphome/components/ld2420/ld2420.cpp +1 -1
  64. esphome/components/libretiny/gpio.py +4 -2
  65. esphome/components/light/__init__.py +32 -1
  66. esphome/components/light/automation.py +39 -32
  67. esphome/components/light/effects.py +36 -36
  68. esphome/components/light/light_state.cpp +6 -16
  69. esphome/components/light/light_state.h +34 -0
  70. esphome/components/light/types.py +3 -1
  71. esphome/components/logger/logger_esp32.cpp +15 -0
  72. esphome/components/lvgl/__init__.py +202 -95
  73. esphome/components/lvgl/automation.py +42 -40
  74. esphome/components/lvgl/binary_sensor/__init__.py +8 -15
  75. esphome/components/lvgl/defines.py +14 -8
  76. esphome/components/lvgl/encoders.py +11 -8
  77. esphome/components/lvgl/keypads.py +77 -0
  78. esphome/components/lvgl/light/__init__.py +6 -8
  79. esphome/components/lvgl/lv_validation.py +2 -4
  80. esphome/components/lvgl/lvcode.py +3 -9
  81. esphome/components/lvgl/lvgl_esphome.cpp +210 -89
  82. esphome/components/lvgl/lvgl_esphome.h +113 -30
  83. esphome/components/lvgl/lvgl_proxy.h +17 -0
  84. esphome/components/lvgl/number/__init__.py +10 -15
  85. esphome/components/lvgl/schemas.py +4 -2
  86. esphome/components/lvgl/select/__init__.py +12 -37
  87. esphome/components/lvgl/select/lvgl_select.h +27 -33
  88. esphome/components/lvgl/sensor/__init__.py +8 -14
  89. esphome/components/lvgl/styles.py +3 -4
  90. esphome/components/lvgl/switch/__init__.py +8 -13
  91. esphome/components/lvgl/text/__init__.py +5 -6
  92. esphome/components/lvgl/text_sensor/__init__.py +15 -15
  93. esphome/components/lvgl/touchscreens.py +2 -3
  94. esphome/components/lvgl/trigger.py +7 -9
  95. esphome/components/lvgl/types.py +9 -3
  96. esphome/components/lvgl/widgets/__init__.py +32 -21
  97. esphome/components/lvgl/widgets/dropdown.py +22 -10
  98. esphome/components/lvgl/widgets/msgbox.py +6 -5
  99. esphome/components/lvgl/widgets/obj.py +4 -2
  100. esphome/components/lvgl/widgets/page.py +3 -2
  101. esphome/components/lvgl/widgets/qrcode.py +54 -0
  102. esphome/components/lvgl/widgets/roller.py +21 -14
  103. esphome/components/lvgl/widgets/tileview.py +2 -1
  104. esphome/components/max17043/__init__.py +1 -0
  105. esphome/components/max17043/automation.h +20 -0
  106. esphome/components/max17043/max17043.cpp +98 -0
  107. esphome/components/max17043/max17043.h +29 -0
  108. esphome/components/max17043/sensor.py +77 -0
  109. esphome/components/media_player/__init__.py +11 -0
  110. esphome/components/media_player/automation.h +10 -0
  111. esphome/components/media_player/media_player.cpp +4 -0
  112. esphome/components/midea/air_conditioner.cpp +17 -1
  113. esphome/components/mlx90393/sensor.py +1 -1
  114. esphome/components/modbus_controller/__init__.py +31 -1
  115. esphome/components/modbus_controller/automation.h +16 -0
  116. esphome/components/modbus_controller/const.py +2 -0
  117. esphome/components/modbus_controller/modbus_controller.cpp +14 -2
  118. esphome/components/modbus_controller/modbus_controller.h +9 -0
  119. esphome/components/mopeka_pro_check/mopeka_pro_check.cpp +40 -21
  120. esphome/components/mopeka_pro_check/mopeka_pro_check.h +9 -2
  121. esphome/components/mopeka_pro_check/sensor.py +41 -0
  122. esphome/components/mqtt/__init__.py +36 -0
  123. esphome/components/mqtt/mqtt_client.cpp +27 -3
  124. esphome/components/mqtt/mqtt_client.h +27 -2
  125. esphome/components/mqtt/mqtt_climate.cpp +4 -2
  126. esphome/components/mqtt/mqtt_component.cpp +6 -0
  127. esphome/components/mqtt/mqtt_component.h +4 -0
  128. esphome/components/mqtt/mqtt_const.h +6 -0
  129. esphome/components/online_image/online_image.cpp +2 -8
  130. esphome/components/online_image/online_image.h +2 -6
  131. esphome/components/opentherm/__init__.py +35 -9
  132. esphome/components/opentherm/binary_sensor/__init__.py +33 -0
  133. esphome/components/opentherm/const.py +11 -0
  134. esphome/components/opentherm/generate.py +142 -0
  135. esphome/components/opentherm/hub.cpp +130 -24
  136. esphome/components/opentherm/hub.h +62 -9
  137. esphome/components/opentherm/input.h +18 -0
  138. esphome/components/opentherm/input.py +51 -0
  139. esphome/components/opentherm/number/__init__.py +74 -0
  140. esphome/components/opentherm/number/number.cpp +40 -0
  141. esphome/components/opentherm/number/number.h +31 -0
  142. esphome/components/opentherm/opentherm.cpp +30 -0
  143. esphome/components/opentherm/opentherm.h +34 -2
  144. esphome/components/opentherm/opentherm_macros.h +151 -0
  145. esphome/components/opentherm/output/__init__.py +47 -0
  146. esphome/components/opentherm/output/output.cpp +18 -0
  147. esphome/components/opentherm/output/output.h +33 -0
  148. esphome/components/opentherm/schema.py +814 -0
  149. esphome/components/opentherm/sensor/__init__.py +51 -0
  150. esphome/components/opentherm/switch/__init__.py +43 -0
  151. esphome/components/opentherm/switch/switch.cpp +28 -0
  152. esphome/components/opentherm/switch/switch.h +20 -0
  153. esphome/components/opentherm/validate.py +31 -0
  154. esphome/components/pcd8544/display.py +8 -4
  155. esphome/components/prometheus/prometheus_handler.cpp +176 -14
  156. esphome/components/prometheus/prometheus_handler.h +25 -7
  157. esphome/components/qspi_amoled/display.py +1 -141
  158. esphome/components/qspi_dbi/display.py +185 -0
  159. esphome/components/qspi_dbi/models.py +64 -0
  160. esphome/components/{qspi_amoled/qspi_amoled.cpp → qspi_dbi/qspi_dbi.cpp} +95 -46
  161. esphome/components/{qspi_amoled/qspi_amoled.h → qspi_dbi/qspi_dbi.h} +26 -15
  162. esphome/components/rp2040/__init__.py +6 -3
  163. esphome/components/rp2040/gpio.py +5 -3
  164. esphome/components/rtttl/rtttl.cpp +4 -1
  165. esphome/components/rtttl/rtttl.h +1 -0
  166. esphome/components/sdl/sdl_esphome.cpp +22 -5
  167. esphome/components/sdl/sdl_esphome.h +1 -0
  168. esphome/components/sdm_meter/sdm_meter.cpp +1 -1
  169. esphome/components/sensor/__init__.py +18 -8
  170. esphome/components/sensor/filter.cpp +19 -18
  171. esphome/components/sensor/filter.h +9 -10
  172. esphome/components/sgp4x/sgp4x.cpp +40 -74
  173. esphome/components/sgp4x/sgp4x.h +5 -3
  174. esphome/components/speaker/__init__.py +51 -5
  175. esphome/components/speaker/automation.h +25 -0
  176. esphome/components/speaker/speaker.h +72 -1
  177. esphome/components/spi/__init__.py +15 -14
  178. esphome/components/spi_device/__init__.py +4 -15
  179. esphome/components/ssd1306_spi/display.py +6 -2
  180. esphome/components/ssd1322_spi/display.py +6 -2
  181. esphome/components/ssd1325_spi/display.py +6 -2
  182. esphome/components/ssd1327_spi/display.py +6 -2
  183. esphome/components/ssd1331_spi/display.py +6 -2
  184. esphome/components/ssd1351_spi/display.py +6 -2
  185. esphome/components/st7567_spi/display.py +6 -2
  186. esphome/components/st7701s/display.py +5 -1
  187. esphome/components/st7735/display.py +10 -5
  188. esphome/components/st7789v/display.py +12 -7
  189. esphome/components/statsd/statsd.cpp +2 -0
  190. esphome/components/statsd/statsd.h +2 -0
  191. esphome/components/sun/sun.h +3 -0
  192. esphome/components/tc74/__init__.py +1 -0
  193. esphome/components/tc74/sensor.py +32 -0
  194. esphome/components/tc74/tc74.cpp +68 -0
  195. esphome/components/tc74/tc74.h +28 -0
  196. esphome/components/touchscreen/__init__.py +41 -50
  197. esphome/components/touchscreen/touchscreen.h +4 -8
  198. esphome/components/tuya/fan/tuya_fan.cpp +1 -1
  199. esphome/components/udp/udp_component.cpp +6 -3
  200. esphome/components/udp/udp_component.h +4 -2
  201. esphome/components/waveshare_epaper/display.py +6 -2
  202. esphome/components/web_server/web_server.cpp +22 -0
  203. esphome/components/web_server/web_server.h +3 -0
  204. esphome/components/weikai/weikai.h +2 -2
  205. esphome/components/wifi/wifi_component.cpp +2 -2
  206. esphome/components/wifi/wifi_component_esp32_arduino.cpp +4 -4
  207. esphome/components/wifi/wifi_component_esp8266.cpp +4 -4
  208. esphome/components/wifi/wifi_component_esp_idf.cpp +2 -2
  209. esphome/components/xpt2046/touchscreen/__init__.py +7 -32
  210. esphome/config_validation.py +3 -1
  211. esphome/const.py +9 -2
  212. esphome/core/defines.h +8 -2
  213. esphome/core/helpers.cpp +32 -17
  214. esphome/core/helpers.h +32 -16
  215. esphome/core/ring_buffer.cpp +2 -2
  216. esphome/core/ring_buffer.h +2 -2
  217. esphome/dashboard/core.py +25 -0
  218. esphome/dashboard/status/mdns.py +3 -4
  219. esphome/dashboard/web_server.py +54 -19
  220. esphome/espota2.py +36 -35
  221. esphome/helpers.py +68 -16
  222. esphome/mqtt.py +9 -2
  223. esphome/storage_json.py +4 -0
  224. esphome/writer.py +7 -18
  225. esphome/zeroconf.py +8 -6
  226. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/METADATA +7 -5
  227. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/RECORD +232 -186
  228. esphome/core/bytebuffer.cpp +0 -167
  229. esphome/core/bytebuffer.h +0 -144
  230. /esphome/components/{qspi_amoled → qspi_dbi}/__init__.py +0 -0
  231. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/LICENSE +0 -0
  232. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/WHEEL +0 -0
  233. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/entry_points.txt +0 -0
  234. {esphome-2024.10.3.dist-info → esphome-2024.11.0.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,7 @@ from esphome.components import number
3
3
  import esphome.config_validation as cv
4
4
  from esphome.cpp_generator import MockObj
5
5
 
6
- from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_UPDATE_ON_RELEASE, CONF_WIDGET
6
+ from ..defines import CONF_ANIMATED, CONF_UPDATE_ON_RELEASE, CONF_WIDGET
7
7
  from ..lv_validation import animated
8
8
  from ..lvcode import (
9
9
  API_EVENT,
@@ -13,28 +13,23 @@ from ..lvcode import (
13
13
  LvContext,
14
14
  lv,
15
15
  lv_add,
16
+ lvgl_static,
16
17
  )
17
- from ..schemas import LVGL_SCHEMA
18
18
  from ..types import LV_EVENT, LvNumber, lvgl_ns
19
19
  from ..widgets import get_widgets, wait_for_widgets
20
20
 
21
21
  LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number)
22
22
 
23
- CONFIG_SCHEMA = (
24
- number.number_schema(LVGLNumber)
25
- .extend(LVGL_SCHEMA)
26
- .extend(
27
- {
28
- cv.Required(CONF_WIDGET): cv.use_id(LvNumber),
29
- cv.Optional(CONF_ANIMATED, default=True): animated,
30
- cv.Optional(CONF_UPDATE_ON_RELEASE, default=False): cv.boolean,
31
- }
32
- )
23
+ CONFIG_SCHEMA = number.number_schema(LVGLNumber).extend(
24
+ {
25
+ cv.Required(CONF_WIDGET): cv.use_id(LvNumber),
26
+ cv.Optional(CONF_ANIMATED, default=True): animated,
27
+ cv.Optional(CONF_UPDATE_ON_RELEASE, default=False): cv.boolean,
28
+ }
33
29
  )
34
30
 
35
31
 
36
32
  async def to_code(config):
37
- paren = await cg.get_variable(config[CONF_LVGL_ID])
38
33
  widget = await get_widgets(config, CONF_WIDGET)
39
34
  widget = widget[0]
40
35
  var = await number.new_number(
@@ -58,10 +53,10 @@ async def to_code(config):
58
53
  if not config[CONF_UPDATE_ON_RELEASE]
59
54
  else LV_EVENT.RELEASED
60
55
  )
61
- async with LvContext(paren):
56
+ async with LvContext():
62
57
  lv_add(var.set_control_lambda(await control.get_lambda()))
63
58
  lv_add(
64
- paren.add_event_cb(
59
+ lvgl_static.add_event_cb(
65
60
  widget.obj, await event.get_lambda(), UPDATE_EVENT, event_code
66
61
  )
67
62
  )
@@ -216,7 +216,7 @@ def automation_schema(typ: LvType):
216
216
  events = df.LV_EVENT_TRIGGERS + (CONF_ON_VALUE,)
217
217
  else:
218
218
  events = df.LV_EVENT_TRIGGERS
219
- args = [typ.get_arg_type()] if isinstance(typ, LvType) else []
219
+ args = typ.get_arg_type() if isinstance(typ, LvType) else []
220
220
  args.append(lv_event_t_ptr)
221
221
  return {
222
222
  cv.Optional(event): validate_automation(
@@ -391,7 +391,9 @@ def container_validator(schema, widget_type: WidgetType):
391
391
  add_lv_use(ltype)
392
392
  if value == SCHEMA_EXTRACT:
393
393
  return result
394
- result = result.extend(LAYOUT_SCHEMAS[ltype.lower()])
394
+ result = result.extend(
395
+ LAYOUT_SCHEMAS.get(ltype.lower(), LAYOUT_SCHEMAS[df.TYPE_NONE])
396
+ )
395
397
  return result(value)
396
398
 
397
399
  return validator
@@ -1,33 +1,19 @@
1
- import esphome.codegen as cg
2
1
  from esphome.components import select
3
2
  import esphome.config_validation as cv
4
3
  from esphome.const import CONF_OPTIONS
5
4
 
6
- from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_WIDGET
7
- from ..lvcode import (
8
- API_EVENT,
9
- EVENT_ARG,
10
- UPDATE_EVENT,
11
- LambdaContext,
12
- LvContext,
13
- lv,
14
- lv_add,
15
- )
16
- from ..schemas import LVGL_SCHEMA
17
- from ..types import LV_EVENT, LvSelect, lvgl_ns
5
+ from ..defines import CONF_ANIMATED, CONF_WIDGET, literal
6
+ from ..lvcode import LvContext
7
+ from ..types import LvSelect, lvgl_ns
18
8
  from ..widgets import get_widgets, wait_for_widgets
19
9
 
20
10
  LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select)
21
11
 
22
- CONFIG_SCHEMA = (
23
- select.select_schema(LVGLSelect)
24
- .extend(LVGL_SCHEMA)
25
- .extend(
26
- {
27
- cv.Required(CONF_WIDGET): cv.use_id(LvSelect),
28
- cv.Optional(CONF_ANIMATED, default=False): cv.boolean,
29
- }
30
- )
12
+ CONFIG_SCHEMA = select.select_schema(LVGLSelect).extend(
13
+ {
14
+ cv.Required(CONF_WIDGET): cv.use_id(LvSelect),
15
+ cv.Optional(CONF_ANIMATED, default=False): cv.boolean,
16
+ }
31
17
  )
32
18
 
33
19
 
@@ -36,22 +22,11 @@ async def to_code(config):
36
22
  widget = widget[0]
37
23
  options = widget.config.get(CONF_OPTIONS, [])
38
24
  selector = await select.new_select(config, options=options)
39
- paren = await cg.get_variable(config[CONF_LVGL_ID])
40
25
  await wait_for_widgets()
41
- async with LambdaContext(EVENT_ARG) as pub_ctx:
42
- pub_ctx.add(selector.publish_index(widget.get_value()))
43
- async with LambdaContext([(cg.uint16, "v")]) as control:
44
- await widget.set_property("selected", "v", animated=config[CONF_ANIMATED])
45
- lv.event_send(widget.obj, API_EVENT, cg.nullptr)
46
- control.add(selector.publish_index(widget.get_value()))
47
- async with LvContext(paren) as ctx:
48
- lv_add(selector.set_control_lambda(await control.get_lambda()))
26
+ async with LvContext() as ctx:
49
27
  ctx.add(
50
- paren.add_event_cb(
51
- widget.obj,
52
- await pub_ctx.get_lambda(),
53
- LV_EVENT.VALUE_CHANGED,
54
- UPDATE_EVENT,
28
+ selector.set_widget(
29
+ widget.var,
30
+ literal("LV_ANIM_ON" if config[CONF_ANIMATED] else "LV_ANIM_OFF"),
55
31
  )
56
32
  )
57
- lv_add(selector.publish_index(widget.get_value()))
@@ -6,58 +6,52 @@
6
6
  #include "esphome/core/automation.h"
7
7
  #include "esphome/core/component.h"
8
8
  #include "esphome/core/preferences.h"
9
+ #include "../lvgl.h"
9
10
 
10
11
  namespace esphome {
11
12
  namespace lvgl {
12
13
 
13
- static std::vector<std::string> split_string(const std::string &str) {
14
- std::vector<std::string> strings;
15
- auto delimiter = std::string("\n");
16
-
17
- std::string::size_type pos;
18
- std::string::size_type prev = 0;
19
- while ((pos = str.find(delimiter, prev)) != std::string::npos) {
20
- strings.push_back(str.substr(prev, pos - prev));
21
- prev = pos + delimiter.size();
22
- }
23
-
24
- // To get the last substring (or only, if delimiter is not found)
25
- strings.push_back(str.substr(prev));
26
-
27
- return strings;
28
- }
29
-
30
14
  class LVGLSelect : public select::Select {
31
15
  public:
32
- void set_control_lambda(std::function<void(size_t)> lambda) {
33
- this->control_lambda_ = std::move(lambda);
16
+ void set_widget(LvSelectable *widget, lv_anim_enable_t anim = LV_ANIM_OFF) {
17
+ this->widget_ = widget;
18
+ this->anim_ = anim;
19
+ this->set_options_();
20
+ lv_obj_add_event_cb(
21
+ this->widget_->obj,
22
+ [](lv_event_t *e) {
23
+ auto *it = static_cast<LVGLSelect *>(e->user_data);
24
+ it->set_options_();
25
+ },
26
+ LV_EVENT_REFRESH, this);
34
27
  if (this->initial_state_.has_value()) {
35
28
  this->control(this->initial_state_.value());
36
29
  this->initial_state_.reset();
37
30
  }
31
+ this->publish();
32
+ auto lamb = [](lv_event_t *e) {
33
+ auto *self = static_cast<LVGLSelect *>(e->user_data);
34
+ self->publish();
35
+ };
36
+ lv_obj_add_event_cb(this->widget_->obj, lamb, LV_EVENT_VALUE_CHANGED, this);
37
+ lv_obj_add_event_cb(this->widget_->obj, lamb, lv_update_event, this);
38
38
  }
39
39
 
40
- void publish_index(size_t index) {
41
- auto value = this->at(index);
42
- if (value)
43
- this->publish_state(value.value());
44
- }
45
-
46
- void set_options(const char *str) { this->traits.set_options(split_string(str)); }
40
+ void publish() { this->publish_state(this->widget_->get_selected_text()); }
47
41
 
48
42
  protected:
49
43
  void control(const std::string &value) override {
50
- if (this->control_lambda_ != nullptr) {
51
- auto index = index_of(value);
52
- if (index)
53
- this->control_lambda_(index.value());
44
+ if (this->widget_ != nullptr) {
45
+ this->widget_->set_selected_text(value, this->anim_);
54
46
  } else {
55
- this->initial_state_ = value.c_str();
47
+ this->initial_state_ = value;
56
48
  }
57
49
  }
50
+ void set_options_() { this->traits.set_options(this->widget_->get_options()); }
58
51
 
59
- std::function<void(size_t)> control_lambda_{};
60
- optional<const char *> initial_state_{};
52
+ LvSelectable *widget_{};
53
+ optional<std::string> initial_state_{};
54
+ lv_anim_enable_t anim_{LV_ANIM_OFF};
61
55
  };
62
56
 
63
57
  } // namespace lvgl
@@ -1,8 +1,7 @@
1
- import esphome.codegen as cg
2
1
  from esphome.components.sensor import Sensor, new_sensor, sensor_schema
3
2
  import esphome.config_validation as cv
4
3
 
5
- from ..defines import CONF_LVGL_ID, CONF_WIDGET
4
+ from ..defines import CONF_WIDGET
6
5
  from ..lvcode import (
7
6
  API_EVENT,
8
7
  EVENT_ARG,
@@ -11,34 +10,29 @@ from ..lvcode import (
11
10
  LambdaContext,
12
11
  LvContext,
13
12
  lv_add,
13
+ lvgl_static,
14
14
  )
15
- from ..schemas import LVGL_SCHEMA
16
15
  from ..types import LV_EVENT, LvNumber
17
16
  from ..widgets import Widget, get_widgets, wait_for_widgets
18
17
 
19
- CONFIG_SCHEMA = (
20
- sensor_schema(Sensor)
21
- .extend(LVGL_SCHEMA)
22
- .extend(
23
- {
24
- cv.Required(CONF_WIDGET): cv.use_id(LvNumber),
25
- }
26
- )
18
+ CONFIG_SCHEMA = sensor_schema(Sensor).extend(
19
+ {
20
+ cv.Required(CONF_WIDGET): cv.use_id(LvNumber),
21
+ }
27
22
  )
28
23
 
29
24
 
30
25
  async def to_code(config):
31
26
  sensor = await new_sensor(config)
32
- paren = await cg.get_variable(config[CONF_LVGL_ID])
33
27
  widget = await get_widgets(config, CONF_WIDGET)
34
28
  widget = widget[0]
35
29
  assert isinstance(widget, Widget)
36
30
  await wait_for_widgets()
37
31
  async with LambdaContext(EVENT_ARG) as lamb:
38
32
  lv_add(sensor.publish_state(widget.get_value()))
39
- async with LvContext(paren, LVGL_COMP_ARG):
33
+ async with LvContext(LVGL_COMP_ARG):
40
34
  lv_add(
41
- paren.add_event_cb(
35
+ lvgl_static.add_event_cb(
42
36
  widget.obj,
43
37
  await lamb.get_lambda(),
44
38
  LV_EVENT.VALUE_CHANGED,
@@ -17,8 +17,6 @@ from .types import lv_lambda_t, lv_obj_t, lv_obj_t_ptr
17
17
  from .widgets import Widget, add_widgets, set_obj_properties, theme_widget_map
18
18
  from .widgets.obj import obj_spec
19
19
 
20
- TOP_LAYER = literal("lv_disp_get_layer_top(lv_component->get_disp())")
21
-
22
20
 
23
21
  async def styles_to_code(config):
24
22
  """Convert styles to C__ code."""
@@ -51,9 +49,10 @@ async def theme_to_code(config):
51
49
  lv_assign(apply, await context.get_lambda())
52
50
 
53
51
 
54
- async def add_top_layer(config):
52
+ async def add_top_layer(lv_component, config):
53
+ top_layer = lv.disp_get_layer_top(lv_component.get_disp())
55
54
  if top_conf := config.get(CONF_TOP_LAYER):
56
- with LocalVariable("top_layer", lv_obj_t, TOP_LAYER) as top_layer_obj:
55
+ with LocalVariable("top_layer", lv_obj_t, top_layer) as top_layer_obj:
57
56
  top_w = Widget(top_layer_obj, obj_spec, top_conf)
58
57
  await set_obj_properties(top_w, top_conf)
59
58
  await add_widgets(top_w, top_conf)
@@ -3,7 +3,7 @@ from esphome.components.switch import Switch, new_switch, switch_schema
3
3
  import esphome.config_validation as cv
4
4
  from esphome.cpp_generator import MockObj
5
5
 
6
- from ..defines import CONF_LVGL_ID, CONF_WIDGET, literal
6
+ from ..defines import CONF_WIDGET, literal
7
7
  from ..lvcode import (
8
8
  API_EVENT,
9
9
  EVENT_ARG,
@@ -13,26 +13,21 @@ from ..lvcode import (
13
13
  LvContext,
14
14
  lv,
15
15
  lv_add,
16
+ lvgl_static,
16
17
  )
17
- from ..schemas import LVGL_SCHEMA
18
18
  from ..types import LV_EVENT, LV_STATE, lv_pseudo_button_t, lvgl_ns
19
19
  from ..widgets import get_widgets, wait_for_widgets
20
20
 
21
21
  LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch)
22
- CONFIG_SCHEMA = (
23
- switch_schema(LVGLSwitch)
24
- .extend(LVGL_SCHEMA)
25
- .extend(
26
- {
27
- cv.Required(CONF_WIDGET): cv.use_id(lv_pseudo_button_t),
28
- }
29
- )
22
+ CONFIG_SCHEMA = switch_schema(LVGLSwitch).extend(
23
+ {
24
+ cv.Required(CONF_WIDGET): cv.use_id(lv_pseudo_button_t),
25
+ }
30
26
  )
31
27
 
32
28
 
33
29
  async def to_code(config):
34
30
  switch = await new_switch(config)
35
- paren = await cg.get_variable(config[CONF_LVGL_ID])
36
31
  widget = await get_widgets(config, CONF_WIDGET)
37
32
  widget = widget[0]
38
33
  await wait_for_widgets()
@@ -45,10 +40,10 @@ async def to_code(config):
45
40
  widget.clear_state(LV_STATE.CHECKED)
46
41
  lv.event_send(widget.obj, API_EVENT, cg.nullptr)
47
42
  control.add(switch.publish_state(literal("v")))
48
- async with LvContext(paren) as ctx:
43
+ async with LvContext() as ctx:
49
44
  lv_add(switch.set_control_lambda(await control.get_lambda()))
50
45
  ctx.add(
51
- paren.add_event_cb(
46
+ lvgl_static.add_event_cb(
52
47
  widget.obj,
53
48
  await checked_ctx.get_lambda(),
54
49
  LV_EVENT.VALUE_CHANGED,
@@ -3,7 +3,7 @@ from esphome.components import text
3
3
  from esphome.components.text import new_text
4
4
  import esphome.config_validation as cv
5
5
 
6
- from ..defines import CONF_LVGL_ID, CONF_WIDGET
6
+ from ..defines import CONF_WIDGET
7
7
  from ..lvcode import (
8
8
  API_EVENT,
9
9
  EVENT_ARG,
@@ -12,14 +12,14 @@ from ..lvcode import (
12
12
  LvContext,
13
13
  lv,
14
14
  lv_add,
15
+ lvgl_static,
15
16
  )
16
- from ..schemas import LVGL_SCHEMA
17
17
  from ..types import LV_EVENT, LvText, lvgl_ns
18
18
  from ..widgets import get_widgets, wait_for_widgets
19
19
 
20
20
  LVGLText = lvgl_ns.class_("LVGLText", text.Text)
21
21
 
22
- CONFIG_SCHEMA = text.TEXT_SCHEMA.extend(LVGL_SCHEMA).extend(
22
+ CONFIG_SCHEMA = text.TEXT_SCHEMA.extend(
23
23
  {
24
24
  cv.GenerateID(): cv.declare_id(LVGLText),
25
25
  cv.Required(CONF_WIDGET): cv.use_id(LvText),
@@ -29,7 +29,6 @@ CONFIG_SCHEMA = text.TEXT_SCHEMA.extend(LVGL_SCHEMA).extend(
29
29
 
30
30
  async def to_code(config):
31
31
  textvar = await new_text(config)
32
- paren = await cg.get_variable(config[CONF_LVGL_ID])
33
32
  widget = await get_widgets(config, CONF_WIDGET)
34
33
  widget = widget[0]
35
34
  await wait_for_widgets()
@@ -39,10 +38,10 @@ async def to_code(config):
39
38
  control.add(textvar.publish_state(widget.get_value()))
40
39
  async with LambdaContext(EVENT_ARG) as lamb:
41
40
  lv_add(textvar.publish_state(widget.get_value()))
42
- async with LvContext(paren):
41
+ async with LvContext():
43
42
  lv_add(textvar.set_control_lambda(await control.get_lambda()))
44
43
  lv_add(
45
- paren.add_event_cb(
44
+ lvgl_static.add_event_cb(
46
45
  widget.obj,
47
46
  await lamb.get_lambda(),
48
47
  LV_EVENT.VALUE_CHANGED,
@@ -1,4 +1,3 @@
1
- import esphome.codegen as cg
2
1
  from esphome.components.text_sensor import (
3
2
  TextSensor,
4
3
  new_text_sensor,
@@ -6,34 +5,35 @@ from esphome.components.text_sensor import (
6
5
  )
7
6
  import esphome.config_validation as cv
8
7
 
9
- from ..defines import CONF_LVGL_ID, CONF_WIDGET
10
- from ..lvcode import API_EVENT, EVENT_ARG, UPDATE_EVENT, LambdaContext, LvContext
11
- from ..schemas import LVGL_SCHEMA
8
+ from ..defines import CONF_WIDGET
9
+ from ..lvcode import (
10
+ API_EVENT,
11
+ EVENT_ARG,
12
+ UPDATE_EVENT,
13
+ LambdaContext,
14
+ LvContext,
15
+ lvgl_static,
16
+ )
12
17
  from ..types import LV_EVENT, LvText
13
18
  from ..widgets import get_widgets, wait_for_widgets
14
19
 
15
- CONFIG_SCHEMA = (
16
- text_sensor_schema(TextSensor)
17
- .extend(LVGL_SCHEMA)
18
- .extend(
19
- {
20
- cv.Required(CONF_WIDGET): cv.use_id(LvText),
21
- }
22
- )
20
+ CONFIG_SCHEMA = text_sensor_schema(TextSensor).extend(
21
+ {
22
+ cv.Required(CONF_WIDGET): cv.use_id(LvText),
23
+ }
23
24
  )
24
25
 
25
26
 
26
27
  async def to_code(config):
27
28
  sensor = await new_text_sensor(config)
28
- paren = await cg.get_variable(config[CONF_LVGL_ID])
29
29
  widget = await get_widgets(config, CONF_WIDGET)
30
30
  widget = widget[0]
31
31
  await wait_for_widgets()
32
32
  async with LambdaContext(EVENT_ARG) as pressed_ctx:
33
33
  pressed_ctx.add(sensor.publish_state(widget.get_value()))
34
- async with LvContext(paren) as ctx:
34
+ async with LvContext() as ctx:
35
35
  ctx.add(
36
- paren.add_event_cb(
36
+ lvgl_static.add_event_cb(
37
37
  widget.obj,
38
38
  await pressed_ctx.get_lambda(),
39
39
  LV_EVENT.VALUE_CHANGED,
@@ -33,13 +33,12 @@ def touchscreen_schema(config):
33
33
  return [TOUCHSCREENS_CONFIG(config)]
34
34
 
35
35
 
36
- async def touchscreens_to_code(var, config):
36
+ async def touchscreens_to_code(lv_component, config):
37
37
  for tconf in config[CONF_TOUCHSCREENS]:
38
38
  lvgl_components_required.add(CONF_TOUCHSCREEN)
39
39
  touchscreen = await cg.get_variable(tconf[CONF_TOUCHSCREEN_ID])
40
40
  lpt = tconf[CONF_LONG_PRESS_TIME].total_milliseconds
41
41
  lprt = tconf[CONF_LONG_PRESS_REPEAT_TIME].total_milliseconds
42
- listener = cg.new_Pvariable(tconf[CONF_ID], lpt, lprt)
43
- await cg.register_parented(listener, var)
42
+ listener = cg.new_Pvariable(tconf[CONF_ID], lpt, lprt, lv_component)
44
43
  lv.indev_drv_register(listener.get_drv())
45
44
  cg.add(touchscreen.register_listener(listener))
@@ -20,17 +20,16 @@ from .lvcode import (
20
20
  lv,
21
21
  lv_add,
22
22
  lv_event_t_ptr,
23
+ lvgl_static,
23
24
  )
24
25
  from .types import LV_EVENT
25
26
  from .widgets import widget_map
26
27
 
27
28
 
28
- async def generate_triggers(lv_component):
29
+ async def generate_triggers():
29
30
  """
30
31
  Generate LVGL triggers for all defined widgets
31
32
  Must be done after all widgets completed
32
- :param lv_component: The parent component
33
- :return:
34
33
  """
35
34
 
36
35
  for w in widget_map.values():
@@ -43,11 +42,10 @@ async def generate_triggers(lv_component):
43
42
  conf = conf[0]
44
43
  w.add_flag("LV_OBJ_FLAG_CLICKABLE")
45
44
  event = literal("LV_EVENT_" + LV_EVENT_MAP[event[3:].upper()])
46
- await add_trigger(conf, lv_component, w, event)
45
+ await add_trigger(conf, w, event)
47
46
  for conf in w.config.get(CONF_ON_VALUE, ()):
48
47
  await add_trigger(
49
48
  conf,
50
- lv_component,
51
49
  w,
52
50
  LV_EVENT.VALUE_CHANGED,
53
51
  API_EVENT,
@@ -63,13 +61,13 @@ async def generate_triggers(lv_component):
63
61
  lv.obj_align_to(w.obj, target, align, x, y)
64
62
 
65
63
 
66
- async def add_trigger(conf, lv_component, w, *events):
64
+ async def add_trigger(conf, w, *events):
67
65
  tid = conf[CONF_TRIGGER_ID]
68
66
  trigger = cg.new_Pvariable(tid)
69
67
  args = w.get_args() + [(lv_event_t_ptr, "event")]
70
- value = w.get_value()
68
+ value = w.get_values()
71
69
  await automation.build_automation(trigger, args, conf)
72
70
  async with LambdaContext(EVENT_ARG, where=tid) as context:
73
71
  with LvConditional(w.is_selected()):
74
- lv_add(trigger.trigger(value, literal("event")))
75
- lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), *events))
72
+ lv_add(trigger.trigger(*value, literal("event")))
73
+ lv_add(lvgl_static.add_event_cb(w.obj, await context.get_lambda(), *events))
@@ -18,7 +18,9 @@ class LvType(cg.MockObjClass):
18
18
  self.value_property = None
19
19
 
20
20
  def get_arg_type(self):
21
- return self.args[0][0] if len(self.args) else None
21
+ if len(self.args) == 0:
22
+ return None
23
+ return [arg[0] for arg in self.args]
22
24
 
23
25
 
24
26
  class LvNumber(LvType):
@@ -38,8 +40,10 @@ void_ptr = cg.void.operator("ptr")
38
40
  lv_coord_t = cg.global_ns.namespace("lv_coord_t")
39
41
  lv_event_code_t = cg.global_ns.enum("lv_event_code_t")
40
42
  lv_indev_type_t = cg.global_ns.enum("lv_indev_type_t")
43
+ lv_key_t = cg.global_ns.enum("lv_key_t")
41
44
  FontEngine = lvgl_ns.class_("FontEngine")
42
45
  IdleTrigger = lvgl_ns.class_("IdleTrigger", automation.Trigger.template())
46
+ PauseTrigger = lvgl_ns.class_("PauseTrigger", automation.Trigger.template())
43
47
  ObjUpdateAction = lvgl_ns.class_("ObjUpdateAction", automation.Action)
44
48
  LvglCondition = lvgl_ns.class_("LvglCondition", automation.Condition)
45
49
  LvglAction = lvgl_ns.class_("LvglAction", automation.Action)
@@ -91,11 +95,13 @@ class LvBoolean(LvType):
91
95
 
92
96
  class LvSelect(LvType):
93
97
  def __init__(self, *args, **kwargs):
98
+ parens = kwargs.pop("parents", ()) + (LvCompound,)
94
99
  super().__init__(
95
100
  *args,
96
- largs=[(cg.int_, "x")],
97
- lvalue=lambda w: w.get_property("selected"),
101
+ largs=[(cg.int_, "x"), (cg.std_string, "text")],
102
+ lvalue=lambda w: [w.var.get_selected_index(), w.var.get_selected_text()],
98
103
  has_on_value=True,
104
+ parents=parens,
99
105
  **kwargs,
100
106
  )
101
107
 
@@ -55,29 +55,14 @@ theme_widget_map = {}
55
55
  styles_used = set()
56
56
 
57
57
 
58
- class LvScrActType(WidgetType):
59
- """
60
- A "widget" representing the active screen.
61
- """
62
-
63
- def __init__(self):
64
- super().__init__("lv_scr_act()", lv_obj_t, ())
65
-
66
- async def to_code(self, w, config: dict):
67
- return []
68
-
69
-
70
58
  class Widget:
71
59
  """
72
60
  Represents a Widget.
61
+ This class has a lot of methods. Adding any more runs foul of lint checks ("too many public methods").
73
62
  """
74
63
 
75
64
  widgets_completed = False
76
65
 
77
- @staticmethod
78
- def set_completed():
79
- Widget.widgets_completed = True
80
-
81
66
  def __init__(self, var, wtype: WidgetType, config: dict = None):
82
67
  self.var = var
83
68
  self.type = wtype
@@ -179,9 +164,20 @@ class Widget:
179
164
 
180
165
  def get_value(self):
181
166
  if isinstance(self.type.w_type, LvType):
182
- return self.type.w_type.value(self)
167
+ result = self.type.w_type.value(self)
168
+ if isinstance(result, list):
169
+ return result[0]
170
+ return result
183
171
  return self.obj
184
172
 
173
+ def get_values(self):
174
+ if isinstance(self.type.w_type, LvType):
175
+ result = self.type.w_type.value(self)
176
+ if isinstance(result, list):
177
+ return result
178
+ return [result]
179
+ return [self.obj]
180
+
185
181
  def get_number_value(self):
186
182
  value = self.type.mock_obj.get_value(self.obj)
187
183
  if self.scale == 1.0:
@@ -213,6 +209,25 @@ class Widget:
213
209
  widget_map: dict[Any, Widget] = {}
214
210
 
215
211
 
212
+ class LvScrActType(WidgetType):
213
+ """
214
+ A "widget" representing the active screen.
215
+ """
216
+
217
+ def __init__(self):
218
+ super().__init__("lv_scr_act()", lv_obj_t, ())
219
+
220
+ async def to_code(self, w, config: dict):
221
+ return []
222
+
223
+
224
+ lv_scr_act_spec = LvScrActType()
225
+
226
+
227
+ def get_scr_act(lv_comp: MockObj) -> Widget:
228
+ return Widget.create(None, lv_comp.get_scr_act(), lv_scr_act_spec, {})
229
+
230
+
216
231
  def get_widget_generator(wid):
217
232
  """
218
233
  Used to wait for a widget during code generation.
@@ -443,7 +458,3 @@ async def widget_to_code(w_cnfig, w_type: WidgetType, parent):
443
458
  await set_obj_properties(w, w_cnfig)
444
459
  await add_widgets(w, w_cnfig)
445
460
  await spec.to_code(w, w_cnfig)
446
-
447
-
448
- lv_scr_act_spec = LvScrActType()
449
- lv_scr_act = Widget.create(None, literal("lv_scr_act()"), lv_scr_act_spec, {})