From ee21a0bc18de1d87970deb55e1f29e2a8753b079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 12:18:08 +0100 Subject: [PATCH 001/350] initial LVGL doc for ESPHome --- components/images/logo_lvgl.png | Bin 0 -> 6743 bytes components/lvgl.rst | 234 ++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 components/images/logo_lvgl.png create mode 100644 components/lvgl.rst diff --git a/components/images/logo_lvgl.png b/components/images/logo_lvgl.png new file mode 100644 index 0000000000000000000000000000000000000000..26e5a48a0b1de3643f265ea8575c63c143d0a896 GIT binary patch literal 6743 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 (Light and Versatile Graphics Library) a most popular free and open-source +embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports +`LVGL version 8.3.9 `__. + +.. figure:: ../images/logo_lvgl.png + :align: center + + + +Component +--------- + +.. code-block:: yaml + + # Example configuration entry + lvgl: + log_level: WARN + color_depth: 16 + bg_color: 0x000000 + text_font: unscii_8 + touchscreens: my_toucher + style_definitions: + - id: style_line + line_color: color_blue + line_width: 8 + line_rounded: true + - id: date_style + text_font: unscii_8 + align: center + text_color: 0xFFFFFF + bg_opa: cover + radius: 4 + pad_all: 2 + layout: grid + width: 100% + widgets: + - btn: + id: lv_button0 + x: 5 + y: 30 + widgets: + - img: + src: my_image0 + width: 96 + height: 96 + + +Configuration variables: + +- **log_level** (*Optional*): Set the logger level specifically for the messages of the lvgl component. +- **color_depth** (**Required**, int8): The color deph at which the contents are generated. Valid values are 1 (monochrome), 8, 16 or 32. +- **bg_color** (*Optional*, :ref:`color `): A basic background color, to draw contents on. +- **text_font** (**Required**, :ref:`font `): The ID of the font used to render textual contents by default on all _lvgl_ widget. +- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the _lvgl_ widget on the screen. +- **style_definitions** (*Optional*, list): A list of style definitions to use with _lvgl_ widget: + - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. + - **line_color** (*Optional*, :ref:`color `): The ID of a color you want to use for lines. If not specified, defaults to ??? + - **line_width** (*Optional*, int16): The desired width of the line, in pixels. Defaults to ??? + - **line_rounded** (*Optional*, boolean): Draw the end of the lines rounded. Defaults to ??? + - **text_font** (*Optional*, :ref:`font `): The ID of the font used to override the render of textual contents on _lvgl_ widget using this style. + - **align** (*Optional*): The alignment of the text within the object. Possible values: ``left``, ``center``, ``right``. Defaults to ``center``. + - **text_color** (*Optional*, :ref:`color `): The ID of a color for text rendering. + - **bg_opa**(*Optional*): The opacity of the background of the widget. ??? + - **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height) + - **pad_all** (*Optional*, int16): Paddigng of all the edges of the widget. Default based on widget type. +- **layout** (*Optional*): ??? +- **width** (*Optional*, percentage): Percentage of the screen width used by _lvgl_. +- **height** (*Optional*, percentage): Percentage of the screen height used by _lvgl_. +- **widgets** (*Optional*, list): A list of _lvgl_ widgets to be drawn on the screen. + - :ref:`Widgets ` (**Required**): ``btn``, ``img``, ??? + - **widgets** (*Optional*, list): A list of _lvgl_ widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. + - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. + - **x** (**Required**, int16): Horizontal position of the widget (anchored in the top left corner). Can be a negative value, and it's relative to the screen. + - **y** (**Required**, int16): Vertical position of the widget (anchored in the top left corner). Can be a negative value, and it's relative to the screen. + - **w** (**Required**, int16): Width of the widget (anchored in the top left corner). + - **h** (**Required**, int16): Height of the widget (anchored in the top left corner). + - **enabled** (*Optional*, boolean): Widget is touchable, if ``false``, a _disabled_ style is applied. Defaults to ``true``. + - **hidden** (*Optional*, boolean): Widget is hidden. Defaults to ``false``. + - **opacity** (*Optional*, uint8): How much the the widget is opaque (0-255). + - **click** (*Optional*, boolean): Widget is touch/clickable (also see ``enabled``). Defaults to ``true``. + - **ext_click_h** (*Optional*, uint8): Extended horizontal clickable area on the left and right. Defaults to ``0``. + - **ext_click_v** (*Optional*, uint8): Extended vertical clickable area on the top and bottom. Defaults to ``0``. + + +.. note:: + + By default, LVGL draws new widgets on top of old widgets, including their children. + + + +.. _lvgl-widgets: + +LVGL Widgets +------------ + +**Base Object**: ``obj`` + +The Base Object can be directly used as a simple, empty widget. It is nothing more then a (rounded) rectangle. You can use it as a background shape for other objects by putting its jsonl line before the object. It catches touches! + +**Text Label**: ``label`` + + - **text** (*Optional*, string): The text of the label. Use``\n`` for line break. Defaults to "Text". + - **mode** (*Optional*, string): The wrapping mode of long text labels: ``expand`` expands the object size to the text size; ``break`` keeps the object width, breaks the too long lines and expands the object height; ``dots`` keeps the size and writes dots at the end if the text is too long; ``scroll`` keeps the size and rolls the text back and forth; ``loop`` keeps the size and rolls the text circularly; ``crop`` keeps the size and crops the text out of it. Defaults to ``crop``. + - **align** (*Optional*, string): Text alignment: ``left``, ``center``, ``right``. Defaults to ``left``. + + +**Button**: ``btn`` + + - **toggle** (*Optional*, boolean): When enabled, creates a toggle-on/toggle-off button. If false, creates a normal button. Defaults to ``false``. + - **text** (*Optional*, string): The text of the label. Defaults to "" (empty string). + - **mode** (*Optional*, string): The wrapping mode of long text button texts: ``expand`` expands the object size to the text size; ``break`` keeps the object width, breaks the too long lines and expands the object height; ``dots`` keeps the size and writes dots at the end if the text is too long; ``scroll`` keeps the size and rolls the text back and forth; ``loop`` keeps the size and rolls the text circularly; ``crop`` keeps the size and crops the text out of it. Defaults to ``expand``. + - **align** (*Optional*, string): Text alignment: ``left``, ``center``, ``right``. Defaults to ``left``. + +**Switch**: ``switch`` + + - **bg_color10** (*Optional*, :ref:`color `): The ID of a color for indicator + - **bg_color20** (*Optional*, :ref:`color `): The ID of a color for knob + - **radius20** (*Optional*, int16): Knob corner radius + + +**Checkbox**: ``checkbox`` + + - **text** (*Optional*, string): The label of the checkbox. Defaults to "Checkbox" + + +**Progress Bar**: ``bar`` + + - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0`` + - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100`` + - **start_value** (*Optional*, int16): Minimal allowed value of the indicator. Defaults to ``0`` + +**Slider**: ``slider`` + + - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0`` + - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100`` + - **start_value** (*Optional*, int16): Minimal allowed value of the indicator. Defaults to ``0`` + +**Arc**: ``arc`` + + - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0`` + - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100`` + - **rotation** (*Optional*, int16): Offset to the 0 degree position. Defaults to ``0`` + - **type** (*Optional*, 0-2): ``0`` = normal, ``1`` = symmetrical, ``2`` = reverse. Defaults to ``0`` + - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false`` + - **start_angle** (*Optional*, 0-360): start angle of the arc background (see note) + - **end_angle** (*Optional*, 0-360): end angle of the arc background (see note) + - **start_angle10** (*Optional*, 0-360): start angle of the arc indicator (see note) + - **end_angle10** (*Optional*, 0-360): end angle of the arc indicator (see note) + + .. note:: + + Zero degree is at the middle right (3 o'clock) of the object and the degrees are increasing in a clockwise direction. The angles should be in the [0-360] range. + + +**Dropdown List**: ``dropdown`` + + - **options** (*Optional*, string): List of items separated by ``\n``. Defaults to "" (empty). + - **text** (*Optional*, string): *Read-only* The text of the selected item. Defaults to "" (empty). + - **direction** (*Optional*, 0-3): Direction where the dropdown expands: ``0`` = down, ``1`` = up, ``2`` = left, ``3`` = right. _Note:_ up and down are superseeded by the screen size. + - **show_selected** (*Optional*, boolean): Show the selected option or a static text. Defaults to ``true`` + - **max_height** (*Optional*, int16): The maximum height of the open drop-down list. Defaults to 3/4 of screen height + + +**Roller**: ``roller`` + + - **options** (*Optional*, string): List of items separated by ``\n``. Defaults to "" (empty). + - **text** (*Optional*, string): *Read-only* The text of the selected item. Defaults to "" (empty). + - **rows** (*Optional*, int8): The number of rows that are visible. Use this property instead of ``h`` to set object height! Defaults to ``3``. + - **mode** (*Optional*, 0-1): Roller mode: ``0`` = normal (finite), ``1`` = infinite. Defaults to ``0``. + - **align** (*Optional*, string): Text alignment: ``left``, ``center``, ``right``. Defaults to ``center`` + + +**Line Meter**: ``linemeter`` + + - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. + - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. + - **angle** (*Optional*, 0-360): Angle between start and end of the scale. Defaults to ``240``. + - **line_count** (*Optional*, uint16): Rick count of the scale. Defaults to ``31``. + - **rotation** (*Optional*, 0-360): Offset for the scale angles to rotate it. Defaults to ``0``. + - **type** (*Optional*, 0-1): ``0`` = indicator lines are activated clock-wise, ``1`` = indicator lines are activated counter-clock-wise. Defaults to ``0``. + +**Gauge**: ``gauge`` + + - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. + - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. + - **critical_value** (*Optional*, int16): Scale color will be changed to scale_end_color after this value. Defaults to ``80``. + - **scale_end_color**: (*Optional*, :ref:`color `): The ID of a color for values above critical. + - **label_count** (*Optional*, uint8): Number of labels (and major ticks) of the scale. Defaults to ``0``. + - **line_count** (*Optional*, uint16): Number of minor ticks of the entire scale. Defaults to ``31``. + - **angle** (*Optional*, 0-360): Angle between start and end of the scale. Defaults to ``240``. + - **rotation** (*Optional*, 0-360): Offset for the gauge's angles to rotate it. Defaults to ``0``. + - **scale** ??? + - **format** (*Optional*, uint16): Divider for major tick values. Defaults to ``0``. + + .. note:: + + To strip trailing zero's of major tick labels the `format` divider can be used to scale the values before printing: + - `0` : print the major tick value as is + - `1` : strip 1 zero, i.e. divide tick value by 10 before printing the major tick label + - `2` : strip 2 zeros, i.e. divide tick value by 100 before printing the major tick label + - `3` : strip 3 zeros, i.e. divide tick value by 1000 before printing the major tick label + - `4` : strip 4 zeros, i.e. divide tick value by 10000 before printing the major tick label + + Only these values are allowed, arbitrary numbers are not supported. + + + + +Data types +---------- + +LVLG supports numeric properties only as integer values with variable minimums and maximums. Certain object properties also support negative values. + +- _int8_ (signed) supports values ranging from -128 to 127. +- _uint8_ (unsigned) supports values ranging from 0 to 255. +- _int16_ (signed) supports values ranging from -32768 to 32767. +- _uint16_ (unsigned) supports values ranging from 0 to 65535. + + +See Also +-------- + +- :doc:`/components/key_collector` +- `LVGL 8.3 docs `__ +- :ghedit:`Edit` From 08e7b581fc3c87fac24c26433360ee8be438cef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 12:26:12 +0100 Subject: [PATCH 002/350] Update lvgl.rst --- components/lvgl.rst | 84 ++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 61ff599a8..3f370b98d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -11,7 +11,7 @@ LVGL embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.9 `__. -.. figure:: ../images/logo_lvgl.png +.. figure:: /images/logo_lvgl.png :align: center @@ -59,36 +59,36 @@ Configuration variables: - **log_level** (*Optional*): Set the logger level specifically for the messages of the lvgl component. - **color_depth** (**Required**, int8): The color deph at which the contents are generated. Valid values are 1 (monochrome), 8, 16 or 32. - **bg_color** (*Optional*, :ref:`color `): A basic background color, to draw contents on. -- **text_font** (**Required**, :ref:`font `): The ID of the font used to render textual contents by default on all _lvgl_ widget. -- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the _lvgl_ widget on the screen. -- **style_definitions** (*Optional*, list): A list of style definitions to use with _lvgl_ widget: - - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. - - **line_color** (*Optional*, :ref:`color `): The ID of a color you want to use for lines. If not specified, defaults to ??? - - **line_width** (*Optional*, int16): The desired width of the line, in pixels. Defaults to ??? - - **line_rounded** (*Optional*, boolean): Draw the end of the lines rounded. Defaults to ??? - - **text_font** (*Optional*, :ref:`font `): The ID of the font used to override the render of textual contents on _lvgl_ widget using this style. - - **align** (*Optional*): The alignment of the text within the object. Possible values: ``left``, ``center``, ``right``. Defaults to ``center``. - - **text_color** (*Optional*, :ref:`color `): The ID of a color for text rendering. - - **bg_opa**(*Optional*): The opacity of the background of the widget. ??? - - **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height) - - **pad_all** (*Optional*, int16): Paddigng of all the edges of the widget. Default based on widget type. +- **text_font** (**Required**, :ref:`font `): The ID of the font used to render textual contents by default on all *lvgl* widget. +- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the *lvgl* widget on the screen. +- **style_definitions** (*Optional*, list): A list of style definitions to use with *lvgl* widget: + - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. + - **line_color** (*Optional*, :ref:`color `): The ID of a color you want to use for lines. If not specified, defaults to ??? + - **line_width** (*Optional*, int16): The desired width of the line, in pixels. Defaults to ??? + - **line_rounded** (*Optional*, boolean): Draw the end of the lines rounded. Defaults to ??? + - **text_font** (*Optional*, :ref:`font `): The ID of the font used to override the render of textual contents on *lvgl* widget using this style. + - **align** (*Optional*): The alignment of the text within the object. Possible values: ``left``, ``center``, ``right``. Defaults to ``center``. + - **text_color** (*Optional*, :ref:`color `): The ID of a color for text rendering. + - **bg_opa**(*Optional*): The opacity of the background of the widget. ??? + - **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height) + - **pad_all** (*Optional*, int16): Paddigng of all the edges of the widget. Default based on widget type. - **layout** (*Optional*): ??? -- **width** (*Optional*, percentage): Percentage of the screen width used by _lvgl_. -- **height** (*Optional*, percentage): Percentage of the screen height used by _lvgl_. -- **widgets** (*Optional*, list): A list of _lvgl_ widgets to be drawn on the screen. - - :ref:`Widgets ` (**Required**): ``btn``, ``img``, ??? - - **widgets** (*Optional*, list): A list of _lvgl_ widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. - - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. - - **x** (**Required**, int16): Horizontal position of the widget (anchored in the top left corner). Can be a negative value, and it's relative to the screen. - - **y** (**Required**, int16): Vertical position of the widget (anchored in the top left corner). Can be a negative value, and it's relative to the screen. - - **w** (**Required**, int16): Width of the widget (anchored in the top left corner). - - **h** (**Required**, int16): Height of the widget (anchored in the top left corner). - - **enabled** (*Optional*, boolean): Widget is touchable, if ``false``, a _disabled_ style is applied. Defaults to ``true``. - - **hidden** (*Optional*, boolean): Widget is hidden. Defaults to ``false``. - - **opacity** (*Optional*, uint8): How much the the widget is opaque (0-255). - - **click** (*Optional*, boolean): Widget is touch/clickable (also see ``enabled``). Defaults to ``true``. - - **ext_click_h** (*Optional*, uint8): Extended horizontal clickable area on the left and right. Defaults to ``0``. - - **ext_click_v** (*Optional*, uint8): Extended vertical clickable area on the top and bottom. Defaults to ``0``. +- **width** (*Optional*, percentage): Percentage of the screen width used by *lvgl*. +- **height** (*Optional*, percentage): Percentage of the screen height used by *lvgl*. +- **widgets** (*Optional*, list): A list of *lvgl* widgets to be drawn on the screen. + - :ref:`Widgets ` (**Required**): ``btn``, ``img``, ??? + - **widgets** (*Optional*, list): A list of *lvgl* widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. + - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. + - **x** (**Required**, int16): Horizontal position of the widget (anchored in the top left corner). Can be a negative value, and it's relative to the screen. + - **y** (**Required**, int16): Vertical position of the widget (anchored in the top left corner). Can be a negative value, and it's relative to the screen. + - **w** (**Required**, int16): Width of the widget (anchored in the top left corner). + - **h** (**Required**, int16): Height of the widget (anchored in the top left corner). + - **enabled** (*Optional*, boolean): Widget is touchable, if ``false``, a _disabled_ style is applied. Defaults to ``true``. + - **hidden** (*Optional*, boolean): Widget is hidden. Defaults to ``false``. + - **opacity** (*Optional*, uint8): How much the the widget is opaque (0-255). + - **click** (*Optional*, boolean): Widget is touch/clickable (also see ``enabled``). Defaults to ``true``. + - **ext_click_h** (*Optional*, uint8): Extended horizontal clickable area on the left and right. Defaults to ``0``. + - **ext_click_v** (*Optional*, uint8): Extended vertical clickable area on the top and bottom. Defaults to ``0``. .. note:: @@ -165,7 +165,7 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo - **options** (*Optional*, string): List of items separated by ``\n``. Defaults to "" (empty). - **text** (*Optional*, string): *Read-only* The text of the selected item. Defaults to "" (empty). - - **direction** (*Optional*, 0-3): Direction where the dropdown expands: ``0`` = down, ``1`` = up, ``2`` = left, ``3`` = right. _Note:_ up and down are superseeded by the screen size. + - **direction** (*Optional*, 0-3): Direction where the dropdown expands: ``0`` = down, ``1`` = up, ``2`` = left, ``3`` = right. *Note:* up and down are superseeded by the screen size. - **show_selected** (*Optional*, boolean): Show the selected option or a static text. Defaults to ``true`` - **max_height** (*Optional*, int16): The maximum height of the open drop-down list. Defaults to 3/4 of screen height @@ -203,12 +203,13 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo .. note:: - To strip trailing zero's of major tick labels the `format` divider can be used to scale the values before printing: - - `0` : print the major tick value as is - - `1` : strip 1 zero, i.e. divide tick value by 10 before printing the major tick label - - `2` : strip 2 zeros, i.e. divide tick value by 100 before printing the major tick label - - `3` : strip 3 zeros, i.e. divide tick value by 1000 before printing the major tick label - - `4` : strip 4 zeros, i.e. divide tick value by 10000 before printing the major tick label + To strip trailing zero's of major tick labels the ``format`` divider can be used to scale the values before printing: + + - ``0`` : print the major tick value as is + - ``1`` : strip 1 zero, i.e. divide tick value by 10 before printing the major tick label + - ``2`` : strip 2 zeros, i.e. divide tick value by 100 before printing the major tick label + - ``3`` : strip 3 zeros, i.e. divide tick value by 1000 before printing the major tick label + - ``4`` : strip 4 zeros, i.e. divide tick value by 10000 before printing the major tick label Only these values are allowed, arbitrary numbers are not supported. @@ -220,15 +221,14 @@ Data types LVLG supports numeric properties only as integer values with variable minimums and maximums. Certain object properties also support negative values. -- _int8_ (signed) supports values ranging from -128 to 127. -- _uint8_ (unsigned) supports values ranging from 0 to 255. -- _int16_ (signed) supports values ranging from -32768 to 32767. -- _uint16_ (unsigned) supports values ranging from 0 to 65535. +- ``int8`` (signed) supports values ranging from -128 to 127. +- ``uint8`` (unsigned) supports values ranging from 0 to 255. +- ``int16`` (signed) supports values ranging from -32768 to 32767. +- ``uint16`` (unsigned) supports values ranging from 0 to 65535. See Also -------- -- :doc:`/components/key_collector` - `LVGL 8.3 docs `__ - :ghedit:`Edit` From dc3f97d197466d181ec7527da487b7e353cf363e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 12:28:48 +0100 Subject: [PATCH 003/350] Update index.rst --- index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/index.rst b/index.rst index 0bcdd3e79..d78bdd10e 100644 --- a/index.rst +++ b/index.rst @@ -656,6 +656,7 @@ Display Components ILI9488, components/display/ili9xxx, ili9488.svg Inkplate, components/display/inkplate6, inkplate6.jpg LCD Display, components/display/lcd_display, lcd.jpg + LVGL, components/lvgl, logo_lvgl.png MAX7219, components/display/max7219, max7219.jpg MAX7219 Dot Matrix, components/display/max7219digit, max7219digit.jpg Nextion, components/display/nextion, nextion.jpg From f04405b8ab1111f5025593140d95f0cde33b7d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 12:32:34 +0100 Subject: [PATCH 004/350] move image file --- {components/images => images}/logo_lvgl.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename {components/images => images}/logo_lvgl.png (100%) diff --git a/components/images/logo_lvgl.png b/images/logo_lvgl.png similarity index 100% rename from components/images/logo_lvgl.png rename to images/logo_lvgl.png From 75aeb23ed849f965fd49b9d6319c5f66719d9f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 12:35:19 +0100 Subject: [PATCH 005/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 3f370b98d..ececf6922 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -7,7 +7,7 @@ LVGL :description: LVGL - ESPHome Displays showing contents created with Light and Versatile Graphics Library -`LVGL `__ (Light and Versatile Graphics Library) a most popular free and open-source +`LVGL `__ (Light and Versatile Graphics Library) is a most free and open-source embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.9 `__. From 80b2480d7b39f45226bfb99041e7335994d54fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 12:37:16 +0100 Subject: [PATCH 006/350] Update lvgl.rst --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ececf6922..999e83a01 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -7,7 +7,7 @@ LVGL :description: LVGL - ESPHome Displays showing contents created with Light and Versatile Graphics Library -`LVGL `__ (Light and Versatile Graphics Library) is a most free and open-source +`LVGL `__ (Light and Versatile Graphics Library) is a free and open-source embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.9 `__. @@ -69,7 +69,7 @@ Configuration variables: - **text_font** (*Optional*, :ref:`font `): The ID of the font used to override the render of textual contents on *lvgl* widget using this style. - **align** (*Optional*): The alignment of the text within the object. Possible values: ``left``, ``center``, ``right``. Defaults to ``center``. - **text_color** (*Optional*, :ref:`color `): The ID of a color for text rendering. - - **bg_opa**(*Optional*): The opacity of the background of the widget. ??? + - **bg_opa** (*Optional*): The opacity of the background of the widget. ??? - **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height) - **pad_all** (*Optional*, int16): Paddigng of all the edges of the widget. Default based on widget type. - **layout** (*Optional*): ??? From 447d94964a73d7cb008e55894b2d4c5c1b593428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 12:46:24 +0100 Subject: [PATCH 007/350] Update lvgl.rst --- components/lvgl.rst | 64 +++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 999e83a01..15e1e3b6d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -83,7 +83,7 @@ Configuration variables: - **y** (**Required**, int16): Vertical position of the widget (anchored in the top left corner). Can be a negative value, and it's relative to the screen. - **w** (**Required**, int16): Width of the widget (anchored in the top left corner). - **h** (**Required**, int16): Height of the widget (anchored in the top left corner). - - **enabled** (*Optional*, boolean): Widget is touchable, if ``false``, a _disabled_ style is applied. Defaults to ``true``. + - **enabled** (*Optional*, boolean): Widget is touchable, if ``false``, a *disabled* style is applied. Defaults to ``true``. - **hidden** (*Optional*, boolean): Widget is hidden. Defaults to ``false``. - **opacity** (*Optional*, uint8): How much the the widget is opaque (0-255). - **click** (*Optional*, boolean): Widget is touch/clickable (also see ``enabled``). Defaults to ``true``. @@ -93,7 +93,9 @@ Configuration variables: .. note:: - By default, LVGL draws new widgets on top of old widgets, including their children. + By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. + + When a parent object is deleted, all children will be deleted too. @@ -122,39 +124,39 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo **Switch**: ``switch`` - - **bg_color10** (*Optional*, :ref:`color `): The ID of a color for indicator - - **bg_color20** (*Optional*, :ref:`color `): The ID of a color for knob - - **radius20** (*Optional*, int16): Knob corner radius + - **bg_color10** (*Optional*, :ref:`color `): The ID of a color for indicator. + - **bg_color20** (*Optional*, :ref:`color `): The ID of a color for knob. + - **radius20** (*Optional*, int16): Knob corner radius. **Checkbox**: ``checkbox`` - - **text** (*Optional*, string): The label of the checkbox. Defaults to "Checkbox" + - **text** (*Optional*, string): The label of the checkbox. Defaults to "Checkbox". **Progress Bar**: ``bar`` - - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0`` - - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100`` - - **start_value** (*Optional*, int16): Minimal allowed value of the indicator. Defaults to ``0`` + - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. + - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. + - **start_value** (*Optional*, int16): Minimal allowed value of the indicator. Defaults to ``0``. **Slider**: ``slider`` - - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0`` - - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100`` - - **start_value** (*Optional*, int16): Minimal allowed value of the indicator. Defaults to ``0`` + - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. + - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. + - **start_value** (*Optional*, int16): Minimal allowed value of the indicator. Defaults to ``0``. **Arc**: ``arc`` - - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0`` - - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100`` - - **rotation** (*Optional*, int16): Offset to the 0 degree position. Defaults to ``0`` - - **type** (*Optional*, 0-2): ``0`` = normal, ``1`` = symmetrical, ``2`` = reverse. Defaults to ``0`` - - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false`` - - **start_angle** (*Optional*, 0-360): start angle of the arc background (see note) - - **end_angle** (*Optional*, 0-360): end angle of the arc background (see note) - - **start_angle10** (*Optional*, 0-360): start angle of the arc indicator (see note) - - **end_angle10** (*Optional*, 0-360): end angle of the arc indicator (see note) + - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. + - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. + - **rotation** (*Optional*, int16): Offset to the 0 degree position. Defaults to ``0``. + - **type** (*Optional*, 0-2): ``0`` = normal, ``1`` = symmetrical, ``2`` = reverse. Defaults to ``0``. + - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. + - **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). + - **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). + - **start_angle10** (*Optional*, 0-360): start angle of the arc indicator (see note). + - **end_angle10** (*Optional*, 0-360): end angle of the arc indicator (see note). .. note:: @@ -166,8 +168,8 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo - **options** (*Optional*, string): List of items separated by ``\n``. Defaults to "" (empty). - **text** (*Optional*, string): *Read-only* The text of the selected item. Defaults to "" (empty). - **direction** (*Optional*, 0-3): Direction where the dropdown expands: ``0`` = down, ``1`` = up, ``2`` = left, ``3`` = right. *Note:* up and down are superseeded by the screen size. - - **show_selected** (*Optional*, boolean): Show the selected option or a static text. Defaults to ``true`` - - **max_height** (*Optional*, int16): The maximum height of the open drop-down list. Defaults to 3/4 of screen height + - **show_selected** (*Optional*, boolean): Show the selected option or a static text. Defaults to ``true``. + - **max_height** (*Optional*, int16): The maximum height of the open drop-down list. Defaults to 3/4 of screen height. **Roller**: ``roller`` @@ -176,7 +178,7 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo - **text** (*Optional*, string): *Read-only* The text of the selected item. Defaults to "" (empty). - **rows** (*Optional*, int8): The number of rows that are visible. Use this property instead of ``h`` to set object height! Defaults to ``3``. - **mode** (*Optional*, 0-1): Roller mode: ``0`` = normal (finite), ``1`` = infinite. Defaults to ``0``. - - **align** (*Optional*, string): Text alignment: ``left``, ``center``, ``right``. Defaults to ``center`` + - **align** (*Optional*, string): Text alignment: ``left``, ``center``, ``right``. Defaults to ``center``. **Line Meter**: ``linemeter`` @@ -184,7 +186,7 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. - **angle** (*Optional*, 0-360): Angle between start and end of the scale. Defaults to ``240``. - - **line_count** (*Optional*, uint16): Rick count of the scale. Defaults to ``31``. + - **line_count** (*Optional*, uint16): Tick count of the scale. Defaults to ``31``. - **rotation** (*Optional*, 0-360): Offset for the scale angles to rotate it. Defaults to ``0``. - **type** (*Optional*, 0-1): ``0`` = indicator lines are activated clock-wise, ``1`` = indicator lines are activated counter-clock-wise. Defaults to ``0``. @@ -192,7 +194,7 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. - - **critical_value** (*Optional*, int16): Scale color will be changed to scale_end_color after this value. Defaults to ``80``. + - **critical_value** (*Optional*, int16): Scale color will be changed to ``scale_end_color`` after this value. Defaults to ``80``. - **scale_end_color**: (*Optional*, :ref:`color `): The ID of a color for values above critical. - **label_count** (*Optional*, uint8): Number of labels (and major ticks) of the scale. Defaults to ``0``. - **line_count** (*Optional*, uint16): Number of minor ticks of the entire scale. Defaults to ``31``. @@ -205,11 +207,11 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo To strip trailing zero's of major tick labels the ``format`` divider can be used to scale the values before printing: - - ``0`` : print the major tick value as is - - ``1`` : strip 1 zero, i.e. divide tick value by 10 before printing the major tick label - - ``2`` : strip 2 zeros, i.e. divide tick value by 100 before printing the major tick label - - ``3`` : strip 3 zeros, i.e. divide tick value by 1000 before printing the major tick label - - ``4`` : strip 4 zeros, i.e. divide tick value by 10000 before printing the major tick label + - ``0``: print the major tick value as is. + - ``1``: strip 1 zero, i.e. divide tick value by 10 before printing the major tick label. + - ``2``: strip 2 zeros, i.e. divide tick value by 100 before printing the major tick label. + - ``3``: strip 3 zeros, i.e. divide tick value by 1000 before printing the major tick label. + - ``4``: strip 4 zeros, i.e. divide tick value by 10000 before printing the major tick label. Only these values are allowed, arbitrary numbers are not supported. From dbb19d574c1c5305c4d3b5208d0aae4a48ead4a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 15:51:22 +0100 Subject: [PATCH 008/350] Update lvgl.rst --- components/lvgl.rst | 167 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 138 insertions(+), 29 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 15e1e3b6d..7a21aa00b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -56,40 +56,24 @@ Component Configuration variables: -- **log_level** (*Optional*): Set the logger level specifically for the messages of the lvgl component. +- **display_id** (*Optional*, :ref:`config-id`): The ID of a display configuration where to render this entire *lvgl* configuration. If there's only one display configured, this item can be omitted. +- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the *lvgl* widgets on the display. +- **rotary_encoders** (*Optional*, list): IDs of rotary encoders interacting with the *lvgl* widgets on the display. - **color_depth** (**Required**, int8): The color deph at which the contents are generated. Valid values are 1 (monochrome), 8, 16 or 32. -- **bg_color** (*Optional*, :ref:`color `): A basic background color, to draw contents on. -- **text_font** (**Required**, :ref:`font `): The ID of the font used to render textual contents by default on all *lvgl* widget. -- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the *lvgl* widget on the screen. -- **style_definitions** (*Optional*, list): A list of style definitions to use with *lvgl* widget: +- **log_level** (*Optional*): Set the logger level specifically for the messages of the *lvgl* component. +- **byte_order**: The byte order of the data processed by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. +- ... (select the default styles from :ref:``) +- **style_definitions** (*Optional*, list): A list of style definitions to use with *lvgl* widgets: - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. - - **line_color** (*Optional*, :ref:`color `): The ID of a color you want to use for lines. If not specified, defaults to ??? - - **line_width** (*Optional*, int16): The desired width of the line, in pixels. Defaults to ??? - - **line_rounded** (*Optional*, boolean): Draw the end of the lines rounded. Defaults to ??? - - **text_font** (*Optional*, :ref:`font `): The ID of the font used to override the render of textual contents on *lvgl* widget using this style. - - **align** (*Optional*): The alignment of the text within the object. Possible values: ``left``, ``center``, ``right``. Defaults to ``center``. - - **text_color** (*Optional*, :ref:`color `): The ID of a color for text rendering. - - **bg_opa** (*Optional*): The opacity of the background of the widget. ??? - - **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height) - - **pad_all** (*Optional*, int16): Paddigng of all the edges of the widget. Default based on widget type. -- **layout** (*Optional*): ??? -- **width** (*Optional*, percentage): Percentage of the screen width used by *lvgl*. -- **height** (*Optional*, percentage): Percentage of the screen height used by *lvgl*. + - ... (select your styles from :ref:``) +- **theme** ??? - **widgets** (*Optional*, list): A list of *lvgl* widgets to be drawn on the screen. - :ref:`Widgets ` (**Required**): ``btn``, ``img``, ??? - - **widgets** (*Optional*, list): A list of *lvgl* widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. + - ... (select your styles from :ref:``) + - **widgets** (*Optional*, list): A list of child *lvgl* widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. - - **x** (**Required**, int16): Horizontal position of the widget (anchored in the top left corner). Can be a negative value, and it's relative to the screen. - - **y** (**Required**, int16): Vertical position of the widget (anchored in the top left corner). Can be a negative value, and it's relative to the screen. - - **w** (**Required**, int16): Width of the widget (anchored in the top left corner). - - **h** (**Required**, int16): Height of the widget (anchored in the top left corner). - - **enabled** (*Optional*, boolean): Widget is touchable, if ``false``, a *disabled* style is applied. Defaults to ``true``. - - **hidden** (*Optional*, boolean): Widget is hidden. Defaults to ``false``. - - **opacity** (*Optional*, uint8): How much the the widget is opaque (0-255). - - **click** (*Optional*, boolean): Widget is touch/clickable (also see ``enabled``). Defaults to ``true``. - - **ext_click_h** (*Optional*, uint8): Extended horizontal clickable area on the left and right. Defaults to ``0``. - - **ext_click_v** (*Optional*, uint8): Extended vertical clickable area on the top and bottom. Defaults to ``0``. - + - ... (select your styles from :ref:``) +- **on_idle**: (*Optional*, :ref:`Action `): An automation to perform when the display enters *idle* state. .. note:: @@ -98,6 +82,130 @@ Configuration variables: When a parent object is deleted, all children will be deleted too. +.. _lvgl-fonts: + +Fonts +----- + +LVGL internally uses fonts in a C array. The library offers by default the following ones preconverted: + +- ``montserrat_12_subpx`` +- ``montserrat_28_compressed`` +- ``dejavu_16_persian_hebrew`` +- ``simsun_16_cjk16`` +- ``unscii_8`` +- ``unscii_16`` + +These may not contain all the glyphs corresponding to certain diacritic characters. You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. + +In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. + +.. _lvgl-styling: + +Styling +------- + +You can adjust the appearance of objects by changing the foreground, background and/or border color of each object. Some objects allow for more complex styling, effectively changing the appearance of their sub-components. + +- **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to the parent or screen). +- **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to the parent or screen). +- **width** (*Optional*): Width of the widget - one of ``size_content``, a number (pixels) or a percentage. +- **height** (*Optional*): Height of the widget - one of ``size_content``, a number (pixels) or a percentage. +- **opa** (*Optional*, string or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **opa_layered** (*Optional*, string or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **align** (*Optional*, string): Alignment of the contents of the widget. One of the values below: + - ``TOP_LEFT`` + - ``TOP_MID`` + - ``TOP_RIGHT`` + - ``LEFT_MID`` + - ``CENTER`` + - ``RIGHT_MID`` + - ``BOTTOM_LEFT`` + - ``BOTTOM_MID`` + - ``BOTTOM_RIGHT`` + - ``OUT_LEFT_TOP`` + - ``OUT_TOP_LEFT`` + - ``OUT_TOP_MID`` + - ``OUT_TOP_RIGHT`` + - ``OUT_RIGHT_TOP`` + - ``OUT_LEFT_MID`` + - ``OUT_CENTER`` + - ``OUT_RIGHT_MID`` + - ``OUT_LEFT_BOTTOM`` + - ``OUT_BOTTOM_LEFT`` + - ``OUT_BOTTOM_MID`` + - ``OUT_BOTTOM_RIGHT`` + - ``OUT_RIGHT_BOTTOM`` +- **bg_color** (*Optional*, :ref:`color `): The ID of a color for the background of the widget. +- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a color to make the background gradually fade to. +- **bg_dither_mode** (*Optional*, string): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. +- **bg_grad_dir** (*Optional*, string): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. +- **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. +- **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. +- **bg_img_opa** (*Optional*, string or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a color to mix with every pixel of the image. +- **bg_img_recolor_opa** (*Optional*, string or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **bg_opa** (*Optional*, string or percentage): Opacity of the background. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **border_color** (*Optional*, :ref:`color `): The ID of a color to draw borders of the widget. +- **border_opa** (*Optional*, string or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. +- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be chosen): + - ``NONE`` + - ``TOP`` + - ``BOTTOM`` + - ``LEFT`` + - ``RIGHT`` + - ``INTERNAL`` +- **border_width** (*Optional*, int16): Set the width of the border in pixels. +- **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height). +- **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. +- **text_align** (*Optional*, string): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` +- **text_color** (*Optional*, :ref:`color `): The ID of a color to render the text in. +- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) +- **text_font``: (*Optional*, :ref:`font `): The ID or the C array file of the font used to render the text. +- **text_letter_space** (*Optional*, int16): Characher spacing of the text. +- **text_line_space** (*Optional*, int16): Line spacing of the text. +- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **line_width** (*Optional*, int16): Set the width of the line in pixels. +- **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). +- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). +- **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **line_color** (*Optional*, :ref:`color `): The ID of a color for the line. +- **outline_color** (*Optional*, :ref:`color `): The ID of a color to draw an outline around the widget. +- **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. +- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. +- **pad_all** (*Optional*, int16): Set the padding in all directions, in pixels. +- **pad_top** (*Optional*, int16): Set the padding on the top, in pixels. +- **pad_bottom** (*Optional*, int16): Set the padding on the bottom, in pixels. +- **pad_left** (*Optional*, int16): Set the padding on the left, in pixels. +- **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. +- **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. +- **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. +- **shadow_color** (*Optional*, :ref:`color `): The ID of a color to create a drop shadow under the widget. +- **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels +- **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels +- **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **shadow_spread** (*Optional*, int16): Spread of the shadow, in pixels. +- **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. +- **transform_angle** (*Optional*, 0-360): Trannsformation angle of the widget (eg. rotation) +- **transform_height** (*Optional*, int16 or percentage): Trannsformation height of the widget (eg. stretching) +- **transform_pivot_x** (*Optional*, int16 or percentage): Horizontal anchor point of the transformation. Relative to the widget's top left corner. +- **transform_pivot_y** (*Optional*, int16 or percentage): Vertical anchor point of the transformation. Relative to the widget's top left corner. +- **transform_zoom** (*Optional*, 0.1-10): Trannsformation zoom of the widget (eg. resizing) +- **translate_x** (*Optional*, int16 or percentage): Move of the object with this value in horizontal direction. +- **translate_y** (*Optional*, int16 or percentage): Move of the object with this value in vertical direction. +- **max_height** (*Optional*, int16 or percentage): Sets a maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. +- **min_height** (*Optional*, int16 or percentage): Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area. Defaults to ``0``. +- **max_width** (*Optional*, int16 or percentage): Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. +- **min_width** (*Optional*, int16 or percentage): Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. +- **arc_opa** (*Optional*, string or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **arc_color** (*Optional*, :ref:`color `): The ID of a color to use to draw the arcs. +- **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. + + + .. _lvgl-widgets: @@ -233,4 +341,5 @@ See Also -------- - `LVGL 8.3 docs `__ +- `LVGL Online Font Converter `__ - :ghedit:`Edit` From cffa8c23bfcf04731447faadb505aecf90955341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 16:11:00 +0100 Subject: [PATCH 009/350] Update lvgl.rst --- components/lvgl.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7a21aa00b..e8a96b121 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -59,20 +59,20 @@ Configuration variables: - **display_id** (*Optional*, :ref:`config-id`): The ID of a display configuration where to render this entire *lvgl* configuration. If there's only one display configured, this item can be omitted. - **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the *lvgl* widgets on the display. - **rotary_encoders** (*Optional*, list): IDs of rotary encoders interacting with the *lvgl* widgets on the display. -- **color_depth** (**Required**, int8): The color deph at which the contents are generated. Valid values are 1 (monochrome), 8, 16 or 32. -- **log_level** (*Optional*): Set the logger level specifically for the messages of the *lvgl* component. +- **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``8``. +- **log_level** (*Optional*): Set the :doc:`/components/logger` level specifically for the messages of the *lvgl* component. Defaults to ``WARN``. - **byte_order**: The byte order of the data processed by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. -- ... (select the default styles from :ref:``) +- ... (select the default styles from :ref:`Styling `) - **style_definitions** (*Optional*, list): A list of style definitions to use with *lvgl* widgets: - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. - - ... (select your styles from :ref:``) + - ... (select your styles from :ref:`Styling `) - **theme** ??? - **widgets** (*Optional*, list): A list of *lvgl* widgets to be drawn on the screen. - :ref:`Widgets ` (**Required**): ``btn``, ``img``, ??? - - ... (select your styles from :ref:``) + - ... (select your styles from :ref:`Styling `) - **widgets** (*Optional*, list): A list of child *lvgl* widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. - - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. - - ... (select your styles from :ref:``) + - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. + - ... (select your styles from :ref:`Styling `) - **on_idle**: (*Optional*, :ref:`Action `): An automation to perform when the display enters *idle* state. .. note:: From 6fe18e840cebc9dcd42e7a96dd1d694a074c038a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 16:15:19 +0100 Subject: [PATCH 010/350] Update lvgl.rst --- components/lvgl.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index e8a96b121..e8b7b8fca 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -14,6 +14,21 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t .. figure:: /images/logo_lvgl.png :align: center +In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although +PSRAM is not a strict requirement, it is recommended. + +For interactivity, a capacitive touchscreen is highly prefered because it is more responsive over resistive touchscreens. + +Basics +------ + +In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called objects or widgets. See :ref:`lvgl-widgets` to see the full +list of available widgets in ESPHome. + +Every object has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. +The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within +their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A Screen is the "root" parent. +You can have any number of screens. Component From 047f789f6bc2cdf38ce818a5dfe64ef0769741b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 16:17:26 +0100 Subject: [PATCH 011/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index e8b7b8fca..5fe5f8d44 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -120,7 +120,7 @@ In ESPHome you can also use a :ref:`font configured in the normal way Date: Tue, 2 Jan 2024 16:21:31 +0100 Subject: [PATCH 012/350] Update lvgl.rst --- components/lvgl.rst | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 5fe5f8d44..3473ccc91 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -71,21 +71,21 @@ Component Configuration variables: -- **display_id** (*Optional*, :ref:`config-id`): The ID of a display configuration where to render this entire *lvgl* configuration. If there's only one display configured, this item can be omitted. -- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the *lvgl* widgets on the display. -- **rotary_encoders** (*Optional*, list): IDs of rotary encoders interacting with the *lvgl* widgets on the display. +- **display_id** (*Optional*, :ref:`config-id`): The ID of a display configuration where to render this entire LVGL configuration. If there's only one display configured, this item can be omitted. +- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the LVGL widgets on the display. +- **rotary_encoders** (*Optional*, list): IDs of rotary encoders interacting with the LVGL widgets on the display. - **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``8``. -- **log_level** (*Optional*): Set the :doc:`/components/logger` level specifically for the messages of the *lvgl* component. Defaults to ``WARN``. -- **byte_order**: The byte order of the data processed by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. +- **log_level** (*Optional*): Set the :ref:`logger ` level specifically for the messages of the LVGL component. Defaults to ``WARN``. +- **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. - ... (select the default styles from :ref:`Styling `) -- **style_definitions** (*Optional*, list): A list of style definitions to use with *lvgl* widgets: +- **style_definitions** (*Optional*, list): A list of style definitions to use with LVGL widgets: - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. - ... (select your styles from :ref:`Styling `) - **theme** ??? -- **widgets** (*Optional*, list): A list of *lvgl* widgets to be drawn on the screen. +- **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. - :ref:`Widgets ` (**Required**): ``btn``, ``img``, ??? - ... (select your styles from :ref:`Styling `) - - **widgets** (*Optional*, list): A list of child *lvgl* widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. + - **widgets** (*Optional*, list): A list of child LVGL widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. - ... (select your styles from :ref:`Styling `) - **on_idle**: (*Optional*, :ref:`Action `): An automation to perform when the display enters *idle* state. @@ -94,8 +94,6 @@ Configuration variables: By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. - When a parent object is deleted, all children will be deleted too. - .. _lvgl-fonts: From 156e23440dc22732b10f626d66211de353d7d154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 16:55:30 +0100 Subject: [PATCH 013/350] Update lvgl.rst --- components/lvgl.rst | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 3473ccc91..18473973e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -30,6 +30,20 @@ The child object moves with the parent and if the parent is deleted the children their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A Screen is the "root" parent. You can have any number of screens. +Widgets integrate in ESPHome as components: + ++-------------+------------------------+ +| LVGL Widget | ESPHome component type | ++=============+========================+ +| Checkbox | Binary Sensor | ++-------------+------------------------+ +| Button | Binary Sensor | ++-------------+------------------------+ +| Slider | Number | ++-------------+------------------------+ +| Arc | Number | ++-------------+------------------------+ + Component --------- @@ -72,8 +86,8 @@ Component Configuration variables: - **display_id** (*Optional*, :ref:`config-id`): The ID of a display configuration where to render this entire LVGL configuration. If there's only one display configured, this item can be omitted. -- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the LVGL widgets on the display. -- **rotary_encoders** (*Optional*, list): IDs of rotary encoders interacting with the LVGL widgets on the display. +- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the LVGL widgets on the display. If there's only one touchscreen configured, this item can be omitted. +- **rotary_encoders** (*Optional*, list): IDs of rotary encoders interacting with the LVGL widgets on the display. If there's only one rotary encoder configured, this item can be omitted. - **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``8``. - **log_level** (*Optional*): Set the :ref:`logger ` level specifically for the messages of the LVGL component. Defaults to ``WARN``. - **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. From 39f45f57c48ca5c6a32a6e41b81fbca1c91eef50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Jan 2024 16:58:08 +0100 Subject: [PATCH 014/350] Update lvgl.rst --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 18473973e..ff7ef8e73 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -45,8 +45,8 @@ Widgets integrate in ESPHome as components: +-------------+------------------------+ -Component ---------- +Main Component +-------------- .. code-block:: yaml From 04a51264a1ceca02a317952956233a6ad9334ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 3 Jan 2024 08:42:01 +0100 Subject: [PATCH 015/350] Update lvgl.rst --- components/lvgl.rst | 76 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ff7ef8e73..2e652ced6 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -23,11 +23,11 @@ Basics ------ In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called objects or widgets. See :ref:`lvgl-widgets` to see the full -list of available widgets in ESPHome. +list of available LVGL widgets in ESPHome. Every object has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within -their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A Screen is the "root" parent. +their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A screen is the *root* parent. You can have any number of screens. Widgets integrate in ESPHome as components: @@ -39,9 +39,9 @@ Widgets integrate in ESPHome as components: +-------------+------------------------+ | Button | Binary Sensor | +-------------+------------------------+ -| Slider | Number | +| Slider | Number, Sensor | +-------------+------------------------+ -| Arc | Number | +| Arc | Number, Sensor | +-------------+------------------------+ @@ -89,25 +89,44 @@ Configuration variables: - **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the LVGL widgets on the display. If there's only one touchscreen configured, this item can be omitted. - **rotary_encoders** (*Optional*, list): IDs of rotary encoders interacting with the LVGL widgets on the display. If there's only one rotary encoder configured, this item can be omitted. - **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``8``. -- **log_level** (*Optional*): Set the :ref:`logger ` level specifically for the messages of the LVGL component. Defaults to ``WARN``. +- **log_level** (*Optional*): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. - **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. -- ... (select the default styles from :ref:`Styling `) +- ...select the *root* (default) styles from :ref:`Styling ` - **style_definitions** (*Optional*, list): A list of style definitions to use with LVGL widgets: - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. - - ... (select your styles from :ref:`Styling `) + - ...select your styles from :ref:`Styling ` - **theme** ??? - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. - :ref:`Widgets ` (**Required**): ``btn``, ``img``, ??? - - ... (select your styles from :ref:`Styling `) + - ...select your styles from :ref:`Styling ` - **widgets** (*Optional*, list): A list of child LVGL widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. - - ... (select your styles from :ref:`Styling `) + - ...select your styles from :ref:`Styling ` - **on_idle**: (*Optional*, :ref:`Action `): An automation to perform when the display enters *idle* state. .. note:: By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. +Widget states: + +Widgets always have a state: + +- ``default`` +- ``checked`` +- ``focused`` +- ``focus_key`` +- ``edited`` +- ``hovered`` +- ``pressed`` +- ``scrolled`` +- ``disabled`` +- ``user_1`` +- ``user_2`` +- ``user_3`` +- ``user_4`` + +TODO: get and set the state with a lambda! .. _lvgl-fonts: @@ -132,7 +151,7 @@ In ESPHome you can also use a :ref:`font configured in the normal way`): The ID of a color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) -- **text_font``: (*Optional*, :ref:`font `): The ID or the C array file of the font used to render the text. +- **text_font**: (*Optional*, :ref:`font `): The ID or the C array file of the font used to render the text. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. - **text_line_space** (*Optional*, int16): Line spacing of the text. - **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. @@ -220,8 +239,8 @@ You can adjust the appearance of objects by changing the foreground, background - **transform_pivot_x** (*Optional*, int16 or percentage): Horizontal anchor point of the transformation. Relative to the widget's top left corner. - **transform_pivot_y** (*Optional*, int16 or percentage): Vertical anchor point of the transformation. Relative to the widget's top left corner. - **transform_zoom** (*Optional*, 0.1-10): Trannsformation zoom of the widget (eg. resizing) -- **translate_x** (*Optional*, int16 or percentage): Move of the object with this value in horizontal direction. -- **translate_y** (*Optional*, int16 or percentage): Move of the object with this value in vertical direction. +- **translate_x** (*Optional*, int16 or percentage): Move of the widget with this value in horizontal direction. +- **translate_y** (*Optional*, int16 or percentage): Move of the widget with this value in vertical direction. - **max_height** (*Optional*, int16 or percentage): Sets a maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. - **min_height** (*Optional*, int16 or percentage): Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area. Defaults to ``0``. - **max_width** (*Optional*, int16 or percentage): Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. @@ -231,8 +250,37 @@ You can adjust the appearance of objects by changing the foreground, background - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. +In addition to visual stilyng, each widget supports some flags to influence the behavior: - +- **hidden** (*Optional*, boolean): +- **clickable** (*Optional*, boolean): +- **click_focusable** (*Optional*, boolean): +- **checkable** (*Optional*, boolean): +- **scrollable** (*Optional*, boolean): +- **scroll_elastic** (*Optional*, boolean): +- **scroll_momentum** (*Optional*, boolean): +- **scroll_one** (*Optional*, boolean): +- **scroll_chain_hor** (*Optional*, boolean): +- **scroll_chain_ver** (*Optional*, boolean): +- **scroll_chain** (*Optional*, boolean): +- **scroll_on_focus** (*Optional*, boolean): +- **scroll_with_arrow** (*Optional*, boolean): +- **snappable** (*Optional*, boolean): +- **press_lock** (*Optional*, boolean): +- **event_bubble** (*Optional*, boolean): +- **gesture_bubble** (*Optional*, boolean): +- **adv_hittest** (*Optional*, boolean): +- **ignore_layout** (*Optional*, boolean): +- **floating** (*Optional*, boolean): +- **overflow_visible** (*Optional*, boolean): +- **layout_1** (*Optional*, boolean): +- **layout_2** (*Optional*, boolean): +- **widget_1** (*Optional*, boolean): +- **widget_2** (*Optional*, boolean): +- **user_1** (*Optional*, boolean): +- **user_2** (*Optional*, boolean): +- **user_3** (*Optional*, boolean): +- **user_4** (*Optional*, boolean): .. _lvgl-widgets: From c9dd71fada05f5f7016512a4280b5166a9c2e404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 3 Jan 2024 09:40:48 +0100 Subject: [PATCH 016/350] Update lvgl.rst --- components/lvgl.rst | 118 ++++++-------------------------------------- 1 file changed, 15 insertions(+), 103 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2e652ced6..064cdd5e8 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -287,116 +287,28 @@ In addition to visual stilyng, each widget supports some flags to influence the LVGL Widgets ------------ -**Base Object**: ``obj`` +**Arc**: ``arc:`` -The Base Object can be directly used as a simple, empty widget. It is nothing more then a (rounded) rectangle. You can use it as a background shape for other objects by putting its jsonl line before the object. It catches touches! +The Arc consists of a background and a foreground arc. The foreground (indicator) can be touch-adjusted. -**Text Label**: ``label`` +Specific configuration options: - - **text** (*Optional*, string): The text of the label. Use``\n`` for line break. Defaults to "Text". - - **mode** (*Optional*, string): The wrapping mode of long text labels: ``expand`` expands the object size to the text size; ``break`` keeps the object width, breaks the too long lines and expands the object height; ``dots`` keeps the size and writes dots at the end if the text is too long; ``scroll`` keeps the size and rolls the text back and forth; ``loop`` keeps the size and rolls the text circularly; ``crop`` keeps the size and crops the text out of it. Defaults to ``crop``. - - **align** (*Optional*, string): Text alignment: ``left``, ``center``, ``right``. Defaults to ``left``. - - -**Button**: ``btn`` - - - **toggle** (*Optional*, boolean): When enabled, creates a toggle-on/toggle-off button. If false, creates a normal button. Defaults to ``false``. - - **text** (*Optional*, string): The text of the label. Defaults to "" (empty string). - - **mode** (*Optional*, string): The wrapping mode of long text button texts: ``expand`` expands the object size to the text size; ``break`` keeps the object width, breaks the too long lines and expands the object height; ``dots`` keeps the size and writes dots at the end if the text is too long; ``scroll`` keeps the size and rolls the text back and forth; ``loop`` keeps the size and rolls the text circularly; ``crop`` keeps the size and crops the text out of it. Defaults to ``expand``. - - **align** (*Optional*, string): Text alignment: ``left``, ``center``, ``right``. Defaults to ``left``. - -**Switch**: ``switch`` - - - **bg_color10** (*Optional*, :ref:`color `): The ID of a color for indicator. - - **bg_color20** (*Optional*, :ref:`color `): The ID of a color for knob. - - **radius20** (*Optional*, int16): Knob corner radius. - - -**Checkbox**: ``checkbox`` - - - **text** (*Optional*, string): The label of the checkbox. Defaults to "Checkbox". - - -**Progress Bar**: ``bar`` - - - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. - - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. - - **start_value** (*Optional*, int16): Minimal allowed value of the indicator. Defaults to ``0``. - -**Slider**: ``slider`` - - - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. - - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. - - **start_value** (*Optional*, int16): Minimal allowed value of the indicator. Defaults to ``0``. - -**Arc**: ``arc`` - - - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. - - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. - - **rotation** (*Optional*, int16): Offset to the 0 degree position. Defaults to ``0``. - - **type** (*Optional*, 0-2): ``0`` = normal, ``1`` = symmetrical, ``2`` = reverse. Defaults to ``0``. + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. + - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. + - **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). Defaults to ``135``. + - **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. + - **rotation** (*Optional*, int8): Offset to the 0 degree position. Defaults to ``0.0``. - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. - - **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). - - **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). - - **start_angle10** (*Optional*, 0-360): start angle of the arc indicator (see note). - - **end_angle10** (*Optional*, 0-360): end angle of the arc indicator (see note). + - **mode** (*Optional*, string): One of ``NORMAL``, ``REVERSE``, ``SYMMETRICAL``. Defaults to ``NORMAL``. + - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. + - **knob** (*Optional*, string): Add a knob to control the value: + - **indicator** + - any :ref:`Styling ` option to override styles inherited from parent .. note:: - Zero degree is at the middle right (3 o'clock) of the object and the degrees are increasing in a clockwise direction. The angles should be in the [0-360] range. - - -**Dropdown List**: ``dropdown`` - - - **options** (*Optional*, string): List of items separated by ``\n``. Defaults to "" (empty). - - **text** (*Optional*, string): *Read-only* The text of the selected item. Defaults to "" (empty). - - **direction** (*Optional*, 0-3): Direction where the dropdown expands: ``0`` = down, ``1`` = up, ``2`` = left, ``3`` = right. *Note:* up and down are superseeded by the screen size. - - **show_selected** (*Optional*, boolean): Show the selected option or a static text. Defaults to ``true``. - - **max_height** (*Optional*, int16): The maximum height of the open drop-down list. Defaults to 3/4 of screen height. - - -**Roller**: ``roller`` - - - **options** (*Optional*, string): List of items separated by ``\n``. Defaults to "" (empty). - - **text** (*Optional*, string): *Read-only* The text of the selected item. Defaults to "" (empty). - - **rows** (*Optional*, int8): The number of rows that are visible. Use this property instead of ``h`` to set object height! Defaults to ``3``. - - **mode** (*Optional*, 0-1): Roller mode: ``0`` = normal (finite), ``1`` = infinite. Defaults to ``0``. - - **align** (*Optional*, string): Text alignment: ``left``, ``center``, ``right``. Defaults to ``center``. - - -**Line Meter**: ``linemeter`` - - - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. - - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. - - **angle** (*Optional*, 0-360): Angle between start and end of the scale. Defaults to ``240``. - - **line_count** (*Optional*, uint16): Tick count of the scale. Defaults to ``31``. - - **rotation** (*Optional*, 0-360): Offset for the scale angles to rotate it. Defaults to ``0``. - - **type** (*Optional*, 0-1): ``0`` = indicator lines are activated clock-wise, ``1`` = indicator lines are activated counter-clock-wise. Defaults to ``0``. - -**Gauge**: ``gauge`` - - - **min** (*Optional*, int16): Minimum value of the indicator. Defaults to ``0``. - - **max** (*Optional*, int16): Maximum value of the indicator. Defaults to ``100``. - - **critical_value** (*Optional*, int16): Scale color will be changed to ``scale_end_color`` after this value. Defaults to ``80``. - - **scale_end_color**: (*Optional*, :ref:`color `): The ID of a color for values above critical. - - **label_count** (*Optional*, uint8): Number of labels (and major ticks) of the scale. Defaults to ``0``. - - **line_count** (*Optional*, uint16): Number of minor ticks of the entire scale. Defaults to ``31``. - - **angle** (*Optional*, 0-360): Angle between start and end of the scale. Defaults to ``240``. - - **rotation** (*Optional*, 0-360): Offset for the gauge's angles to rotate it. Defaults to ``0``. - - **scale** ??? - - **format** (*Optional*, uint16): Divider for major tick values. Defaults to ``0``. - - .. note:: - - To strip trailing zero's of major tick labels the ``format`` divider can be used to scale the values before printing: - - - ``0``: print the major tick value as is. - - ``1``: strip 1 zero, i.e. divide tick value by 10 before printing the major tick label. - - ``2``: strip 2 zeros, i.e. divide tick value by 100 before printing the major tick label. - - ``3``: strip 3 zeros, i.e. divide tick value by 1000 before printing the major tick label. - - ``4``: strip 4 zeros, i.e. divide tick value by 10000 before printing the major tick label. - - Only these values are allowed, arbitrary numbers are not supported. + Zero degree is at the middle right (3 o'clock) of the object and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. From 43b049e04ed22b48b473cdf63f294355ade7afe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 3 Jan 2024 11:00:31 +0100 Subject: [PATCH 017/350] Update lvgl.rst --- components/lvgl.rst | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 064cdd5e8..ad99852fd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -22,13 +22,13 @@ For interactivity, a capacitive touchscreen is highly prefered because it is mor Basics ------ -In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called objects or widgets. See :ref:`lvgl-widgets` to see the full +In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` to see the full list of available LVGL widgets in ESPHome. -Every object has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. -The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within -their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A screen is the *root* parent. -You can have any number of screens. +Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome this is simplified to a hierarchy. + +The widget is at the top level, and it allows main styling. It also has sub-parts, which can be styled separately. +Usually styles are inherited. The widget and the parts have states, and the different styling can be set for different states. Widgets integrate in ESPHome as components: @@ -43,6 +43,12 @@ Widgets integrate in ESPHome as components: +-------------+------------------------+ | Arc | Number, Sensor | +-------------+------------------------+ +| ??? | TODO | ++-------------+------------------------+ + +Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. +The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within +their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A screen is the *root* parent. Main Component @@ -72,15 +78,7 @@ Main Component layout: grid width: 100% widgets: - - btn: - id: lv_button0 - x: 5 - y: 30 - widgets: - - img: - src: my_image0 - width: 96 - height: 96 + - ... Configuration variables: @@ -95,9 +93,10 @@ Configuration variables: - **style_definitions** (*Optional*, list): A list of style definitions to use with LVGL widgets: - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. - ...select your styles from :ref:`Styling ` -- **theme** ??? +- **theme** TODO +- **layout** TODO - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. - - :ref:`Widgets ` (**Required**): ``btn``, ``img``, ??? + - :ref:`Widgets ` (**Required**): ``btn``, ``img``, TODO - ...select your styles from :ref:`Styling ` - **widgets** (*Optional*, list): A list of child LVGL widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. From 166e37d7933adecb4edf4aa3e188c4dfeb725514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 3 Jan 2024 11:33:28 +0100 Subject: [PATCH 018/350] Update lvgl.rst --- components/lvgl.rst | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ad99852fd..cd76aa301 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -68,17 +68,14 @@ Main Component line_color: color_blue line_width: 8 line_rounded: true - - id: date_style - text_font: unscii_8 - align: center - text_color: 0xFFFFFF - bg_opa: cover - radius: 4 - pad_all: 2 layout: grid width: 100% widgets: - - ... + - btn: + id: lv_button0 + x: 5 + y: 30 + Configuration variables: From a3c77dcafca11fbcef223b5a3e1086e908c05798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 3 Jan 2024 13:18:04 +0100 Subject: [PATCH 019/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index cd76aa301..b6e220ae5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -106,7 +106,7 @@ Configuration variables: Widget states: -Widgets always have a state: +Widgets or their parts can have have states: - ``default`` - ``checked`` From 9785e5bfab3cf70abb95d31006e9eacb5cb72e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 3 Jan 2024 17:13:51 +0100 Subject: [PATCH 020/350] Update lvgl.rst --- components/lvgl.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b6e220ae5..e47bfc944 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -17,7 +17,7 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. -For interactivity, a capacitive touchscreen is highly prefered because it is more responsive over resistive touchscreens. +For interactivity, a touchscreen (capacitive highly prefered) or a rotary encoder can be used. Basics ------ @@ -278,6 +278,8 @@ In addition to visual stilyng, each widget supports some flags to influence the - **user_3** (*Optional*, boolean): - **user_4** (*Optional*, boolean): +- **group** (*Optional*, int??): + .. _lvgl-widgets: LVGL Widgets From dccbf0e000380efc02a0fe283a42981512303ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 10:24:50 +0100 Subject: [PATCH 021/350] Update index.rst --- components/display/index.rst | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 12fdee505..5ee443f19 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -11,11 +11,20 @@ engine. Fundamentally, there are these types of displays: - Text based displays like :doc:`7-Segment displays ` or :doc:`some LCD displays `. - Displays like the :doc:`nextion` that have their own processors for rendering. -- Binary displays which can toggle ON/OFF any pixel, like :doc:`E-Paper displays ` or - :doc:`OLED displays `. +- Binary graphical displays which can toggle ON/OFF any pixel, like :doc:`E-Paper `, + :doc:`OLED ` or :doc:`TFT ` displays. -For the last type, ESPHome has a powerful rendering engine that can do -many things like draw some basic shapes, print text with any font you want, or even show images. +For graphical displays, there are two options: +- ESPHome's :ref:`own powerful rendering engine ` +- :ref:`LVGL ` - Light and Versatile Graphics Library + +.. _display-engine: + +Display Rendering Engine +------------------------ + +ESPHome's own powerful rendering engine can do many things like draw some basic shapes, print text with any font +you want, or even show images. To achieve all this flexibility displays tie in directly into ESPHome's :ref:`lambda system `. So when you want to write some text or sensor values to the screen you will be writing in C++ code @@ -24,20 +33,15 @@ using an API that is designed to - be simple and to be used without programming experience - but also be flexible enough to work with more complex tasks like displaying an analog clock. +In this section we will be discussing how to use ESPHome's display rendering engine from ESPHome +and some basic commands. Please note that this only applies to displays that can control each pixel +individually. + .. note:: Display hardware is complex and sometimes doesn't behave as expected. If you're having trouble with your display, please see :ref:`troubleshooting` below. -.. _display-engine: - -Display Rendering Engine ------------------------- - -In this section we will be discussing how to use ESPHome's display rendering engine from ESPHome -and some basic commands. Please note that this only applies to displays that can control each pixel -individually. - So, first a few basics: When setting up a display platform in ESPHome there will be a configuration option called ``lambda:`` which will be called every time ESPHome wants to re-render the display. In each cycle, the display is automatically cleared before the lambda is executed. You can disable From ee8293612437c705b4df65eebd87ce66f2ab34b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 10:28:50 +0100 Subject: [PATCH 022/350] Update index.rst --- components/display/index.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 5ee443f19..fc028c318 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -9,12 +9,13 @@ The ``display`` component houses ESPHome's powerful rendering and display engine. Fundamentally, there are these types of displays: - Text based displays like :doc:`7-Segment displays ` or - :doc:`some LCD displays `. -- Displays like the :doc:`nextion` that have their own processors for rendering. -- Binary graphical displays which can toggle ON/OFF any pixel, like :doc:`E-Paper `, + :doc:`LCD displays `. +- Graphical serial displays like :doc:`nextion` that have their own processors for rendering. +- Graphical binary displays which can toggle ON/OFF any pixel, like :doc:`E-Paper `, :doc:`OLED ` or :doc:`TFT ` displays. -For graphical displays, there are two options: +For graphical binary displays, there are two options: + - ESPHome's :ref:`own powerful rendering engine ` - :ref:`LVGL ` - Light and Versatile Graphics Library @@ -1027,6 +1028,7 @@ See Also -------- - :apiref:`display/display_buffer.h` +- :ref:`LVGL ` - :ghedit:`Edit` .. toctree:: From 146b351f772bad0a681250d270d8a52e2dea89d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 10:45:48 +0100 Subject: [PATCH 023/350] add binary sensor --- components/binary_sensor/lvgl.rst | 37 +++++++++++++++++++++++++++++++ components/lvgl.rst | 1 + index.rst | 3 ++- 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 components/binary_sensor/lvgl.rst diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst new file mode 100644 index 000000000..a7d9d035a --- /dev/null +++ b/components/binary_sensor/lvgl.rst @@ -0,0 +1,37 @@ +LVGL Binary Sensor +================== + +.. seo:: + :description: Instructions for setting up a LVGL widget binary sensor. + :image: ../images/logo_lvgl.png + +The ``lvgl`` binary sensor platform creates a binary sensor from LVGL widget +and requires :ref:`LVGL ` to be configured. + + +Configuration variables: +------------------------ + +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. +- **name** (**Required**, string): The name of the sensor. +- **checkbox** (*Optional*): The ID of a checkbox widget configured in LVGL. +- **btn** (*Optional*): The ID of a button widget configured in LVGL. + + .. note:: + + Choose only one of ``checkbox`` or ``btn`` for a single binary sensor. + + +Example + +.. code-block:: yaml + + binary_sensor: + - platform: lvgl + name: LVGL checkbox + checkbox: lv_checkbox + +See Also +-------- +- :ref:`LVGL ` +- :ghedit:`Edit` diff --git a/components/lvgl.rst b/components/lvgl.rst index e47bfc944..13443432e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -5,6 +5,7 @@ LVGL .. seo:: :description: LVGL - ESPHome Displays showing contents created with Light and Versatile Graphics Library + :image: /images/logo_lvgl.png `LVGL `__ (Light and Versatile Graphics Library) is a free and open-source diff --git a/index.rst b/index.rst index d78bdd10e..e00053067 100644 --- a/index.rst +++ b/index.rst @@ -493,7 +493,8 @@ Touchscreen *********** .. imgtable:: - Nextion Binary Sensor, components/binary_sensor/nextion, nextion.jpg + LVGL widget, components/binary_sensor/lvgl, logo_lvgl.png + Nextion, components/binary_sensor/nextion, nextion.jpg Touchscreen, components/touchscreen/index, touch.svg, dark-invert TT21100, components/touchscreen/tt21100, esp32-s3-korvo-2-lcd.png FT5X06, components/touchscreen/ft5x06, indicator.jpg From fc814bff6ffd49af763b734675eec115fef24d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 10:54:06 +0100 Subject: [PATCH 024/350] Update lvgl.rst --- components/binary_sensor/lvgl.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index a7d9d035a..1247cef6c 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -5,22 +5,19 @@ LVGL Binary Sensor :description: Instructions for setting up a LVGL widget binary sensor. :image: ../images/logo_lvgl.png -The ``lvgl`` binary sensor platform creates a binary sensor from LVGL widget +The ``lvgl`` binary sensor platform creates a binary sensor from a LVGL widget and requires :ref:`LVGL ` to be configured. +Supported widgets are ``btn`` and ``checkbox``. A single binary sensor supports +a single widget, thus you need to choose among which one's state you want to use. Configuration variables: ------------------------ - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. -- **checkbox** (*Optional*): The ID of a checkbox widget configured in LVGL. - **btn** (*Optional*): The ID of a button widget configured in LVGL. - - .. note:: - - Choose only one of ``checkbox`` or ``btn`` for a single binary sensor. - +- **checkbox** (*Optional*): The ID of a checkbox widget configured in LVGL. Example From eee9ecdfa523d49d813ee2d2277dff1b72146cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 10:58:01 +0100 Subject: [PATCH 025/350] Update lvgl.rst --- components/binary_sensor/lvgl.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 1247cef6c..e23323c7a 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -11,6 +11,7 @@ and requires :ref:`LVGL ` to be configured. Supported widgets are ``btn`` and ``checkbox``. A single binary sensor supports a single widget, thus you need to choose among which one's state you want to use. + Configuration variables: ------------------------ @@ -18,8 +19,10 @@ Configuration variables: - **name** (**Required**, string): The name of the sensor. - **btn** (*Optional*): The ID of a button widget configured in LVGL. - **checkbox** (*Optional*): The ID of a checkbox widget configured in LVGL. +- All other options from :ref:`Binary Sensor `. -Example + +Example: .. code-block:: yaml From 95c7e9da2ccea16233790ab1d29fb93d5ca91cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 11:28:25 +0100 Subject: [PATCH 026/350] add components --- components/binary_sensor/lvgl.rst | 4 ++- components/lvgl.rst | 3 +++ components/number/lvgl.rst | 43 +++++++++++++++++++++++++++++++ components/sensor/lvgl.rst | 42 ++++++++++++++++++++++++++++++ index.rst | 1 + 5 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 components/number/lvgl.rst create mode 100644 components/sensor/lvgl.rst diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index e23323c7a..881f77ee9 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -16,7 +16,7 @@ Configuration variables: ------------------------ - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **name** (**Required**, string): The name of the sensor. +- **name** (**Required**, string): The name of the binary sensor. - **btn** (*Optional*): The ID of a button widget configured in LVGL. - **checkbox** (*Optional*): The ID of a checkbox widget configured in LVGL. - All other options from :ref:`Binary Sensor `. @@ -34,4 +34,6 @@ Example: See Also -------- - :ref:`LVGL ` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` - :ghedit:`Edit` diff --git a/components/lvgl.rst b/components/lvgl.rst index 13443432e..97ee09a2e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -326,6 +326,9 @@ LVLG supports numeric properties only as integer values with variable minimums a See Also -------- +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` - `LVGL 8.3 docs `__ - `LVGL Online Font Converter `__ - :ghedit:`Edit` diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst new file mode 100644 index 000000000..4c9272945 --- /dev/null +++ b/components/number/lvgl.rst @@ -0,0 +1,43 @@ +LVGL Number +=========== + +.. seo:: + :description: Instructions for setting up a LVGL widget number component. + :image: ../images/logo_lvgl.png + +The ``lvgl`` number platform creates a number component from a LVGL widget +and requires :ref:`LVGL ` to be configured. + +Supported widgets are ``arc`` and ``slider``. A single number supports +a single widget, thus you need to choose among which one's state you want to use. + + +Configuration variables: +------------------------ + +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. +- **name** (**Required**, string): The name of the number. +- **animated** (*Optional*, boolean): Wether to set the value of the widget with an animation. Defaults to ``true``. +- **arc_id** (*Optional*): The ID of an arc widget configured in LVGL. +- **slider_id** (*Optional*): The ID of a slider widget configured in LVGL. +- All other options from :ref:`Number `. + + +Example: + +.. code-block:: yaml + + number: + - platform: lvgl + slider_id: lv_slider + id: lvgl_slider_sensor + name: LVGL Slider + + + +See Also +-------- +- :ref:`LVGL ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :ghedit:`Edit` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst new file mode 100644 index 000000000..f2a8f81fb --- /dev/null +++ b/components/sensor/lvgl.rst @@ -0,0 +1,42 @@ +LVGL Sensor +=========== + +.. seo:: + :description: Instructions for setting up a LVGL widget sensor. + :image: ../images/logo_lvgl.png + +The ``lvgl`` sensor platform creates a sensor from a LVGL widget +and requires :ref:`LVGL ` to be configured. + +Supported widgets are ``arc`` and ``slider``. A single sensor supports +a single widget, thus you need to choose among which one's state you want to use. + + +Configuration variables: +------------------------ + +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. +- **name** (**Required**, string): The name of the sensor. +- **arc_id** (*Optional*): The ID of an arc widget configured in LVGL. +- **slider_id** (*Optional*): The ID of a slider widget configured in LVGL. +- All other options from :ref:`Sensor `. + + +Example: + +.. code-block:: yaml + + sensor: + - platform: lvgl + arc_id: arc_value + id: lvgl_arc_sensor + name: LVGL Arc + + + +See Also +-------- +- :ref:`LVGL ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/number/lvgl` +- :ghedit:`Edit` diff --git a/index.rst b/index.rst index e00053067..cc1f7b9a7 100644 --- a/index.rst +++ b/index.rst @@ -752,6 +752,7 @@ Number Components .. imgtable:: Number Core, components/number/index, folder-open.svg, dark-invert + LVGL widget Number, components/number/lvgl, logo_lvgl.png Modbus Number, components/number/modbus_controller, modbus.png Template Number, components/number/template, description.svg, dark-invert Tuya Number, components/number/tuya, tuya.png From 459622ea521140c7858379330769a4b52b950416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 11:32:16 +0100 Subject: [PATCH 027/350] fix seealso --- components/binary_sensor/lvgl.rst | 2 +- components/number/lvgl.rst | 2 +- components/sensor/lvgl.rst | 2 +- index.rst | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 881f77ee9..1521a6846 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -33,7 +33,7 @@ Example: See Also -------- -- :ref:`LVGL ` +- :ref:`LVGL Main component ` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` - :ghedit:`Edit` diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 4c9272945..548af2658 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -37,7 +37,7 @@ Example: See Also -------- -- :ref:`LVGL ` +- :ref:`LVGL Main component ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :ghedit:`Edit` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index f2a8f81fb..865f1149d 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -36,7 +36,7 @@ Example: See Also -------- -- :ref:`LVGL ` +- :ref:`LVGL Main component ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/number/lvgl` - :ghedit:`Edit` diff --git a/index.rst b/index.rst index cc1f7b9a7..d1fdadb15 100644 --- a/index.rst +++ b/index.rst @@ -390,6 +390,7 @@ Miscellaneous Integration, components/sensor/integration, sigma.svg, dark-invert Growatt Solar, components/sensor/growatt_solar, growatt.jpg, Solar rooftop Kalman Combinator, components/sensor/kalman_combinator, function.svg, dark-invert + LVGL widget, components/sensor/lvgl, logo_lvgl.png Modbus Sensor, components/sensor/modbus_controller, modbus.png Nextion, components/sensor/nextion, nextion.jpg, Sensors from display Rotary Encoder, components/sensor/rotary_encoder, rotary_encoder.jpg From a64eba9f1d9d0144a8b71845cf5fd7a9d3d86970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 11:39:11 +0100 Subject: [PATCH 028/350] Update lvgl.rst --- components/lvgl.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 97ee09a2e..cca26a4cd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -36,17 +36,20 @@ Widgets integrate in ESPHome as components: +-------------+------------------------+ | LVGL Widget | ESPHome component type | +=============+========================+ -| Checkbox | Binary Sensor | +| Checkbox | :doc:`/components/binary_sensor/lvgl` | +-------------+------------------------+ -| Button | Binary Sensor | +| Button | :doc:`/components/binary_sensor/lvgl` | +-------------+------------------------+ -| Slider | Number, Sensor | +| Slider | :doc:`/components/number/lvgl`, :doc:`/components/sensor/lvgl` | +-------------+------------------------+ -| Arc | Number, Sensor | +| Arc | :doc:`/components/number/lvgl`, :doc:`/components/sensor/lvgl` | +-------------+------------------------+ | ??? | TODO | +-------------+------------------------+ + + + Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A screen is the *root* parent. From 70ebc7a22a510516a8e98a82da3a4e512d1db468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 12:04:01 +0100 Subject: [PATCH 029/350] updates --- components/binary_sensor/lvgl.rst | 2 ++ components/lvgl.rst | 34 +++++++++++++++++++------------ components/number/lvgl.rst | 2 ++ components/sensor/lvgl.rst | 2 ++ components/touchscreen/index.rst | 2 ++ 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 1521a6846..5f852a614 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -1,3 +1,5 @@ +.. _lvgl-bse: + LVGL Binary Sensor ================== diff --git a/components/lvgl.rst b/components/lvgl.rst index cca26a4cd..5a91b409c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -18,7 +18,7 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. -For interactivity, a touchscreen (capacitive highly prefered) or a rotary encoder can be used. +For interactivity, a :ref:`Touchscreen `(capacitive highly prefered) or a :doc:`/components/sensor/rotary_encoder` can be used. Basics ------ @@ -31,29 +31,32 @@ Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome thi The widget is at the top level, and it allows main styling. It also has sub-parts, which can be styled separately. Usually styles are inherited. The widget and the parts have states, and the different styling can be set for different states. -Widgets integrate in ESPHome as components: +Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. +The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within +their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A screen is the *root* parent. +TODO - SCREEN/PAGE + +Widgets integrate in ESPHome also as components: +-------------+------------------------+ | LVGL Widget | ESPHome component type | +=============+========================+ -| Checkbox | :doc:`/components/binary_sensor/lvgl` | +| Checkbox | Binary Sensor | +-------------+------------------------+ -| Button | :doc:`/components/binary_sensor/lvgl` | +| Button | Binary Sensor | +-------------+------------------------+ -| Slider | :doc:`/components/number/lvgl`, :doc:`/components/sensor/lvgl` | +| Slider | Sensor, Number | +-------------+------------------------+ -| Arc | :doc:`/components/number/lvgl`, :doc:`/components/sensor/lvgl` | +| Arc | Sensor, Number | +-------------+------------------------+ | ??? | TODO | +-------------+------------------------+ +These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the *See Also* +section at the bottom of this document. -Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. -The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within -their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A screen is the *root* parent. - Main Component -------------- @@ -88,6 +91,7 @@ Configuration variables: - **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the LVGL widgets on the display. If there's only one touchscreen configured, this item can be omitted. - **rotary_encoders** (*Optional*, list): IDs of rotary encoders interacting with the LVGL widgets on the display. If there's only one rotary encoder configured, this item can be omitted. - **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``8``. +- **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. - **log_level** (*Optional*): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. - **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. - ...select the *root* (default) styles from :ref:`Styling ` @@ -148,8 +152,11 @@ In ESPHome you can also use a :ref:`font configured in the normal way`__ - `LVGL Online Font Converter `__ - :ghedit:`Edit` diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 548af2658..d7688fe0c 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -1,3 +1,5 @@ +.. _lvgl-num: + LVGL Number =========== diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 865f1149d..600b7b674 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -1,3 +1,5 @@ +.. _lvgl-sen: + LVGL Sensor =========== diff --git a/components/touchscreen/index.rst b/components/touchscreen/index.rst index 26ea94196..6119f826c 100644 --- a/components/touchscreen/index.rst +++ b/components/touchscreen/index.rst @@ -1,3 +1,5 @@ +.. _touchscreen-main: + Touchscreen Components ====================== From 041964dc1d71ee94e9ecd3a8b169740faddc0008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 13:57:21 +0100 Subject: [PATCH 030/350] Update lvgl.rst --- components/lvgl.rst | 95 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 5a91b409c..708d79a2e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -89,7 +89,10 @@ Configuration variables: - **display_id** (*Optional*, :ref:`config-id`): The ID of a display configuration where to render this entire LVGL configuration. If there's only one display configured, this item can be omitted. - **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the LVGL widgets on the display. If there's only one touchscreen configured, this item can be omitted. -- **rotary_encoders** (*Optional*, list): IDs of rotary encoders interacting with the LVGL widgets on the display. If there's only one rotary encoder configured, this item can be omitted. +- **rotary_encoders** (*Optional*, list): + - **sensor:** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. + - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. + - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See :ref:`below ` for more information on groups. - **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``8``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. - **log_level** (*Optional*): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. @@ -155,7 +158,7 @@ In ESPHome you can also use a :ref:`font configured in the normal way` value after which LVGL should enter idle state. + +.. code-block:: yaml + + lvgl: + on_idle: + timeout: 30s + then: + - logger.log: "LVGL is idle" + - lvgl.pause: + - light.turn_off: + id: display_backlight + + +.. _lvgl-paused-cond: + +``lvgl.is_paused`` Condition +**************************** + +This :ref:`Condition ` checks if LVGL is in paused state or not. + +.. code-block:: yaml + + # In some trigger: + on_...: + then: + - if: + condition: lvgl.is_paused + then: + - lvgl.resume: + - light.turn_on: + id: display_backlight + + +.. _lvgl-idle-cond: + +``lvgl.is_idle`` Condition +************************** + +This :ref:`Condition ` checks if LVGL is in idle state or not. + +.. code-block:: yaml + + # In some trigger: + on_...: + then: + - if: + condition: lvgl.is_idle + then: + - light.turn_off: + id: display_backlight + + +.. _lvgl-pause-act: + +``lvgl.pause`` Action +********************* + +This action pauses the activity of LVGL, including rendering. + +.. code-block:: yaml + + on_...: + then: + - lvgl.pause + + +.. _lvgl-resume-act: + +``lvgl.resume`` Action +********************** + +This action resumes the activity of LVGL, including rendering. + +.. code-block:: yaml + + on_...: + then: + - lvgl.resume + Data types From a420f11a80a708d9ca915314a377f4a49b8c13bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 14:02:26 +0100 Subject: [PATCH 031/350] Update lvgl.rst --- components/lvgl.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 708d79a2e..9194fad51 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -18,7 +18,7 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. -For interactivity, a :ref:`Touchscreen `(capacitive highly prefered) or a :doc:`/components/sensor/rotary_encoder` can be used. +For interactivity, a :ref:`Touchscreen ` (capacitive highly prefered) or a :doc:`/components/sensor/rotary_encoder` can be used. Basics ------ @@ -322,9 +322,11 @@ Specific configuration options: Zero degree is at the middle right (3 o'clock) of the object and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. -.. _lvgl-onidle-act: + +.. _lvgl-onidle-act: + ``switch.on_idle`` Trigger ************************** From d405b3c5ee116c329b6e033004fd04768a485aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 14:06:55 +0100 Subject: [PATCH 032/350] Update lvgl.rst --- components/lvgl.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9194fad51..ed9aaf63d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -327,10 +327,10 @@ Specific configuration options: .. _lvgl-onidle-act: -``switch.on_idle`` Trigger +``lvgl.on_idle`` Trigger ************************** -This trigger is activated when lvgl enters in idle state after the specified ``timeout``. +This :ref:`trigger ` is activated when lvgl enters in idle state after the specified ``timeout``. - **timeout** (**Required**): :ref:`` value after which LVGL should enter idle state. @@ -351,7 +351,7 @@ This trigger is activated when lvgl enters in idle state after the specified ``t ``lvgl.is_paused`` Condition **************************** -This :ref:`Condition ` checks if LVGL is in paused state or not. +This :ref:`condition ` checks if LVGL is in paused state or not. .. code-block:: yaml @@ -371,7 +371,7 @@ This :ref:`Condition ` checks if LVGL is in paused state or no ``lvgl.is_idle`` Condition ************************** -This :ref:`Condition ` checks if LVGL is in idle state or not. +This :ref:`condition ` checks if LVGL is in idle state or not. .. code-block:: yaml @@ -390,7 +390,7 @@ This :ref:`Condition ` checks if LVGL is in idle state or not. ``lvgl.pause`` Action ********************* -This action pauses the activity of LVGL, including rendering. +This :ref:`action ` pauses the activity of LVGL, including rendering. .. code-block:: yaml @@ -404,7 +404,7 @@ This action pauses the activity of LVGL, including rendering. ``lvgl.resume`` Action ********************** -This action resumes the activity of LVGL, including rendering. +This :ref:`action ` resumes the activity of LVGL, including rendering. .. code-block:: yaml From f805cc80f6dd3ef64555eae2b97abb80eff8fc4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 14:08:23 +0100 Subject: [PATCH 033/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ed9aaf63d..06853f330 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -332,7 +332,7 @@ Specific configuration options: This :ref:`trigger ` is activated when lvgl enters in idle state after the specified ``timeout``. -- **timeout** (**Required**): :ref:`` value after which LVGL should enter idle state. +- **timeout** (**Required**): :ref:`Time ` value after which LVGL should enter idle state. .. code-block:: yaml From c306d590ae07049c530630c924f425deac634ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 14:26:25 +0100 Subject: [PATCH 034/350] Update lvgl.rst --- components/lvgl.rst | 51 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 06853f330..2c26ce3c1 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -101,8 +101,8 @@ Configuration variables: - **style_definitions** (*Optional*, list): A list of style definitions to use with LVGL widgets: - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. - ...select your styles from :ref:`Styling ` -- **theme** TODO -- **layout** TODO +- **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. +- **layout** (*Optional*, string): LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. - :ref:`Widgets ` (**Required**): ``btn``, ``img``, TODO - ...select your styles from :ref:`Styling ` @@ -135,6 +135,39 @@ Widgets or their parts can have have states: TODO: get and set the state with a lambda! + +.. _lvgl-theme: + +Theme +----- + +You can configure a global theme for all the widgets at the top level. In the example below, all the ``arc``, ``slider`` +and ``btn`` widgets will use the styles and properties predefined here. + +.. code-block:: yaml + + lvgl: + theme: + arc: + scroll_on_focus: true + group: general + slider: + scroll_on_focus: true + group: general + btn: + scroll_on_focus: true + group: general + border_width: 2 + outline_pad: 6 + pressed: + border_color: 0xFF0000 + checked: + border_color: 0xFFFF00 + focused: + border_color: 0x00FF00 + +Naturally, you can override these at the indivdual configuration level of each widget. + .. _lvgl-fonts: Fonts @@ -315,7 +348,8 @@ Specific configuration options: - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. - **knob** (*Optional*, string): Add a knob to control the value: - **indicator** - - any :ref:`Styling ` option to override styles inherited from parent + - any :ref:`Styling ` option to override styles inherited from parent. + .. note:: @@ -324,11 +358,10 @@ Specific configuration options: - .. _lvgl-onidle-act: ``lvgl.on_idle`` Trigger -************************** +------------------------ This :ref:`trigger ` is activated when lvgl enters in idle state after the specified ``timeout``. @@ -349,7 +382,7 @@ This :ref:`trigger ` is activated when lvgl enters in idle state aft .. _lvgl-paused-cond: ``lvgl.is_paused`` Condition -**************************** +---------------------------- This :ref:`condition ` checks if LVGL is in paused state or not. @@ -369,7 +402,7 @@ This :ref:`condition ` checks if LVGL is in paused state or no .. _lvgl-idle-cond: ``lvgl.is_idle`` Condition -************************** +-------------------------- This :ref:`condition ` checks if LVGL is in idle state or not. @@ -388,7 +421,7 @@ This :ref:`condition ` checks if LVGL is in idle state or not. .. _lvgl-pause-act: ``lvgl.pause`` Action -********************* +--------------------- This :ref:`action ` pauses the activity of LVGL, including rendering. @@ -402,7 +435,7 @@ This :ref:`action ` pauses the activity of LVGL, including render .. _lvgl-resume-act: ``lvgl.resume`` Action -********************** +---------------------- This :ref:`action ` resumes the activity of LVGL, including rendering. From 27ec3a86b1c746e73f6ab56f0fa56c406805c6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 14:30:53 +0100 Subject: [PATCH 035/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2c26ce3c1..9580c5f11 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -464,7 +464,7 @@ See Also - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` -- :doc:`/components/touchscreen` +- :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` - `LVGL 8.3 docs `__ - `LVGL Online Font Converter `__ From 1704a0c5aebc7e41cb43c9c2e40b56b08deb741d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 14:51:32 +0100 Subject: [PATCH 036/350] Update lvgl.rst --- components/lvgl.rst | 78 ++++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9580c5f11..3a935cc0d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -98,9 +98,7 @@ Configuration variables: - **log_level** (*Optional*): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. - **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. - ...select the *root* (default) styles from :ref:`Styling ` -- **style_definitions** (*Optional*, list): A list of style definitions to use with LVGL widgets: - - **id** (*Optional*, :ref:`config-id`): Set the ID of this style definition. - - ...select your styles from :ref:`Styling ` +- **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. @@ -138,10 +136,12 @@ TODO: get and set the state with a lambda! .. _lvgl-theme: -Theme ------ +Theming and Styling +------------------- -You can configure a global theme for all the widgets at the top level. In the example below, all the ``arc``, ``slider`` +The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. + +You can configure a global theme for all the widgets at the top level with the ``theme`` configuration option. In the example below, all the ``arc``, ``slider`` and ``btn`` widgets will use the styles and properties predefined here. .. code-block:: yaml @@ -166,30 +166,43 @@ and ``btn`` widgets will use the styles and properties predefined here. focused: border_color: 0x00FF00 -Naturally, you can override these at the indivdual configuration level of each widget. +Naturally, you can override these at the indivdual configuration level of each widget. This can be done in batches, using ``style_definitions`` configuration option. +In the example below, you defined ``date_style``: -.. _lvgl-fonts: +.. code-block:: yaml -Fonts ------ + lvgl: + style_definitions: + - id: date_style # choose an ID for your definition + text_font: unscii_8 + align: center + text_color: 0x000000 + bg_opa: cover + radius: 4 + pad_all: 2 -LVGL internally uses fonts in a C array. The library offers by default the following ones preconverted: -- ``montserrat_12_subpx`` -- ``montserrat_28_compressed`` -- ``dejavu_16_persian_hebrew`` -- ``simsun_16_cjk16`` -- ``unscii_8`` -- ``unscii_16`` +And then you apply these selected styles to two labels, and only change very specific stlye ``y`` locally: -These may not contain all the glyphs corresponding to certain diacritic characters. You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. +.. code-block:: yaml + + widgets: + - label: + id: day_label + styles: date_style # apply the definiton here by the ID chosen above + y: -20 + - label: + id: date_label + styles: date_style + y: +20 + +So the inheritance happens like this: locally specified styles override the style definitions, which override the theme, which overrides the top level styles. -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. .. _lvgl-styling: -Properties and Styling ----------------------- +Properties and Styles +--------------------- - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. @@ -326,10 +339,29 @@ In addition to visual stilyng, each widget supports some flags to influence the - **user_4** (*Optional*, boolean): +.. _lvgl-fonts: + +Fonts +----- + +LVGL internally uses fonts in a C array. The library offers by default the following ones preconverted: + +- ``montserrat_12_subpx`` +- ``montserrat_28_compressed`` +- ``dejavu_16_persian_hebrew`` +- ``simsun_16_cjk16`` +- ``unscii_8`` +- ``unscii_16`` + +These may not contain all the glyphs corresponding to certain diacritic characters. You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. + +In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. + + .. _lvgl-widgets: -LVGL Widgets ------------- +Widgets +------- **Arc**: ``arc:`` From 1eff10651574bafedca786b77e2857709523d728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 14:53:17 +0100 Subject: [PATCH 037/350] Update lvgl.rst --- components/lvgl.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 3a935cc0d..d80b7ef45 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -186,15 +186,15 @@ And then you apply these selected styles to two labels, and only change very spe .. code-block:: yaml - widgets: - - label: - id: day_label - styles: date_style # apply the definiton here by the ID chosen above - y: -20 - - label: - id: date_label - styles: date_style - y: +20 + widgets: + - label: + id: day_label + styles: date_style # apply the definiton here by the ID chosen above + y: -20 + - label: + id: date_label + styles: date_style + y: +20 So the inheritance happens like this: locally specified styles override the style definitions, which override the theme, which overrides the top level styles. From ff9b04f38389b2459a2d453a801c60a61e4cecd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 15:15:05 +0100 Subject: [PATCH 038/350] Update lvgl.rst --- components/lvgl.rst | 88 +++++++++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 23 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d80b7ef45..bea11b2ef 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -115,23 +115,6 @@ Configuration variables: Widget states: -Widgets or their parts can have have states: - -- ``default`` -- ``checked`` -- ``focused`` -- ``focus_key`` -- ``edited`` -- ``hovered`` -- ``pressed`` -- ``scrolled`` -- ``disabled`` -- ``user_1`` -- ``user_2`` -- ``user_3`` -- ``user_4`` - -TODO: get and set the state with a lambda! .. _lvgl-theme: @@ -196,7 +179,40 @@ And then you apply these selected styles to two labels, and only change very spe styles: date_style y: +20 -So the inheritance happens like this: locally specified styles override the style definitions, which override the theme, which overrides the top level styles. +Additionally, you can change the styles based on the state of the widgets or their parts. Widgets or their parts can have have states: + + - ``default`` + - ``disabled`` + - ``hovered`` + - ``pressed`` + - ``checked`` + - ``scrolled`` + - ``focused`` + - ``focus_key`` + - ``edited`` + - ``user_1`` + - ``user_2`` + - ``user_3`` + - ``user_4`` + +In the example below, you have an ``arc`` with some styles set here. Note how you change the ``arc_color`` of the ``indicator`` part, based on state changes: + +.. code-block:: yaml + + - arc: + id: my_arc + value: 75 + min_value: 1 + max_value: 100 + indicator: + arc_color: 0xF000FF + pressed: + arc_color: 0xFFFF00 + focused: + arc_color: 0x808080 + + +So the inheritance happens like this: state based styles override the locally specified styles, which override the style definitions, which override the theme, which overrides the top level styles. .. _lvgl-styling: @@ -363,7 +379,16 @@ In ESPHome you can also use a :ref:`font configured in the normal way` option to override styles inherited from parent. - + - **knob** (*Optional*, list): Adds a knob *part* to control the value. Supports a list of styles and state-based styles to customize. + - **indicator** (*Optional*, list): Adds an indicator *part* to show the value. Supports a list of styles and state-based styles to customize. + - any :ref:`Styling ` and state-based option to override styles inherited from parent. .. note:: Zero degree is at the middle right (3 o'clock) of the object and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. +Example: +.. code-block:: yaml + + # Example widget: + - arc: + group: general + scroll_on_focus: true + id: arc_value + value: 75 + min_value: 1 + max_value: 100 + arc_color: 0xFF0000 + indicator: + arc_color: 0xF000FF + pressed: + arc_color: 0xFFFF00 + focused: + arc_color: 0x808080 .. _lvgl-onidle-act: From 87eda742a81832c4b726edae3b68d10362a69205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 15:21:57 +0100 Subject: [PATCH 039/350] Update lvgl.rst --- components/lvgl.rst | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index bea11b2ef..339bd0a5b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -102,20 +102,12 @@ Configuration variables: - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. - - :ref:`Widgets ` (**Required**): ``btn``, ``img``, TODO - - ...select your styles from :ref:`Styling ` - - **widgets** (*Optional*, list): A list of child LVGL widgets to be drawn as children of this widget. Configuration options are is the same as the parent widgets, and values aren inherited. - - **id** (*Optional*, :ref:`config-id`): Set the ID of this widget. - - ...select your styles from :ref:`Styling ` -- **on_idle**: (*Optional*, :ref:`Action `): An automation to perform when the display enters *idle* state. +- All other options from :ref:`lvgl-styling`. .. note:: By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. -Widget states: - - .. _lvgl-theme: @@ -317,10 +309,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **min_height** (*Optional*, int16 or percentage): Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area. Defaults to ``0``. - **max_width** (*Optional*, int16 or percentage): Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. - **min_width** (*Optional*, int16 or percentage): Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. -- **arc_opa** (*Optional*, string or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a color to use to draw the arcs. -- **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. + In addition to visual stilyng, each widget supports some flags to influence the behavior: @@ -380,7 +369,6 @@ Widgets ------- Common properties -***************** The properties below are common to all widgets. TODO @@ -403,6 +391,10 @@ Specific configuration options: - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. - **mode** (*Optional*, string): One of ``NORMAL``, ``REVERSE``, ``SYMMETRICAL``. Defaults to ``NORMAL``. - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. + - **arc_opa** (*Optional*, string or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. + - **arc_color** (*Optional*, :ref:`color `): The ID of a color to use to draw the arcs. + - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. + - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - **knob** (*Optional*, list): Adds a knob *part* to control the value. Supports a list of styles and state-based styles to customize. - **indicator** (*Optional*, list): Adds an indicator *part* to show the value. Supports a list of styles and state-based styles to customize. - any :ref:`Styling ` and state-based option to override styles inherited from parent. From 8e939d29a796d847fc79fed8f696444818d40b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 15:29:30 +0100 Subject: [PATCH 040/350] Update lvgl.rst --- components/lvgl.rst | 224 ++++++++++++++++++++++---------------------- 1 file changed, 113 insertions(+), 111 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 339bd0a5b..06b07dc7c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -97,7 +97,6 @@ Configuration variables: - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. - **log_level** (*Optional*): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. - **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. -- ...select the *root* (default) styles from :ref:`Styling ` - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. @@ -109,104 +108,6 @@ Configuration variables: By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. -.. _lvgl-theme: - -Theming and Styling -------------------- - -The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. - -You can configure a global theme for all the widgets at the top level with the ``theme`` configuration option. In the example below, all the ``arc``, ``slider`` -and ``btn`` widgets will use the styles and properties predefined here. - -.. code-block:: yaml - - lvgl: - theme: - arc: - scroll_on_focus: true - group: general - slider: - scroll_on_focus: true - group: general - btn: - scroll_on_focus: true - group: general - border_width: 2 - outline_pad: 6 - pressed: - border_color: 0xFF0000 - checked: - border_color: 0xFFFF00 - focused: - border_color: 0x00FF00 - -Naturally, you can override these at the indivdual configuration level of each widget. This can be done in batches, using ``style_definitions`` configuration option. -In the example below, you defined ``date_style``: - -.. code-block:: yaml - - lvgl: - style_definitions: - - id: date_style # choose an ID for your definition - text_font: unscii_8 - align: center - text_color: 0x000000 - bg_opa: cover - radius: 4 - pad_all: 2 - - -And then you apply these selected styles to two labels, and only change very specific stlye ``y`` locally: - -.. code-block:: yaml - - widgets: - - label: - id: day_label - styles: date_style # apply the definiton here by the ID chosen above - y: -20 - - label: - id: date_label - styles: date_style - y: +20 - -Additionally, you can change the styles based on the state of the widgets or their parts. Widgets or their parts can have have states: - - - ``default`` - - ``disabled`` - - ``hovered`` - - ``pressed`` - - ``checked`` - - ``scrolled`` - - ``focused`` - - ``focus_key`` - - ``edited`` - - ``user_1`` - - ``user_2`` - - ``user_3`` - - ``user_4`` - -In the example below, you have an ``arc`` with some styles set here. Note how you change the ``arc_color`` of the ``indicator`` part, based on state changes: - -.. code-block:: yaml - - - arc: - id: my_arc - value: 75 - min_value: 1 - max_value: 100 - indicator: - arc_color: 0xF000FF - pressed: - arc_color: 0xFFFF00 - focused: - arc_color: 0x808080 - - -So the inheritance happens like this: state based styles override the locally specified styles, which override the style definitions, which override the theme, which overrides the top level styles. - - .. _lvgl-styling: Properties and Styles @@ -344,23 +245,102 @@ In addition to visual stilyng, each widget supports some flags to influence the - **user_4** (*Optional*, boolean): -.. _lvgl-fonts: +.. _lvgl-theme: -Fonts ------ +Theming and Styling +------------------- -LVGL internally uses fonts in a C array. The library offers by default the following ones preconverted: +The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. -- ``montserrat_12_subpx`` -- ``montserrat_28_compressed`` -- ``dejavu_16_persian_hebrew`` -- ``simsun_16_cjk16`` -- ``unscii_8`` -- ``unscii_16`` +You can configure a global theme for all the widgets at the top level with the ``theme`` configuration option. In the example below, all the ``arc``, ``slider`` +and ``btn`` widgets will use the styles and properties predefined here. -These may not contain all the glyphs corresponding to certain diacritic characters. You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. +.. code-block:: yaml -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. + lvgl: + theme: + arc: + scroll_on_focus: true + group: general + slider: + scroll_on_focus: true + group: general + btn: + scroll_on_focus: true + group: general + border_width: 2 + outline_pad: 6 + pressed: + border_color: 0xFF0000 + checked: + border_color: 0xFFFF00 + focused: + border_color: 0x00FF00 + +Naturally, you can override these at the indivdual configuration level of each widget. This can be done in batches, using ``style_definitions`` configuration option. +In the example below, you defined ``date_style``: + +.. code-block:: yaml + + lvgl: + style_definitions: + - id: date_style # choose an ID for your definition + text_font: unscii_8 + align: center + text_color: 0x000000 + bg_opa: cover + radius: 4 + pad_all: 2 + + +And then you apply these selected styles to two labels, and only change very specific stlye ``y`` locally: + +.. code-block:: yaml + + widgets: + - label: + id: day_label + styles: date_style # apply the definiton here by the ID chosen above + y: -20 + - label: + id: date_label + styles: date_style + y: +20 + +Additionally, you can change the styles based on the state of the widgets or their parts. Widgets or their parts can have have states: + + - ``default`` + - ``disabled`` + - ``hovered`` + - ``pressed`` + - ``checked`` + - ``scrolled`` + - ``focused`` + - ``focus_key`` + - ``edited`` + - ``user_1`` + - ``user_2`` + - ``user_3`` + - ``user_4`` + +In the example below, you have an ``arc`` with some styles set here. Note how you change the ``arc_color`` of the ``indicator`` part, based on state changes: + +.. code-block:: yaml + + - arc: + id: my_arc + value: 75 + min_value: 1 + max_value: 100 + indicator: + arc_color: 0xF000FF + pressed: + arc_color: 0xFFFF00 + focused: + arc_color: 0x808080 + + +So the inheritance happens like this: state based styles override the locally specified styles, which override the style definitions, which override the theme, which overrides the top level styles. .. _lvgl-widgets: @@ -424,6 +404,28 @@ Example: arc_color: 0x808080 + +.. _lvgl-fonts: + +Fonts +----- + +LVGL internally uses fonts in a C array. The library offers by default the following ones preconverted: + +- ``montserrat_12_subpx`` +- ``montserrat_28_compressed`` +- ``dejavu_16_persian_hebrew`` +- ``simsun_16_cjk16`` +- ``unscii_8`` +- ``unscii_16`` + +These may not contain all the glyphs corresponding to certain diacritic characters. You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. + +In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. + + + + .. _lvgl-onidle-act: ``lvgl.on_idle`` Trigger From 1a8043fbad60a6bc4501e3b0e037f06a60f36e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 16:17:10 +0100 Subject: [PATCH 041/350] Update lvgl.rst --- components/lvgl.rst | 293 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 290 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 06b07dc7c..3083df47b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -355,10 +355,10 @@ TODO -``arc:`` -******** +``arc`` +******* -The Arc consists of a background and a foreground arc. The foreground (indicator) can be touch-adjusted. +The Arc consists of a background and a foreground arc. The foreground (indicator) can be touch-adjusted with a knob. Specific configuration options: @@ -402,6 +402,293 @@ Example: arc_color: 0xFFFF00 focused: arc_color: 0x808080 + knob: + focused: + bg_color: 0x808080 + + +``bar`` +******* + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + +``btn`` +******* + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``btnmatrix`` +************* + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``canvas`` +********** + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``checkbox`` +************ + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``dropdown`` +************ + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``img`` +******* + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``label`` +********* + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``line`` +******** + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``meter`` +********* + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``roller`` +********** + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``slider`` +********** + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``switch`` +********** + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``table`` +********* + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + +``textarea`` +************ + +Descr + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + From 6e53087855025e9b641faead78a3461aa860ab20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 17:05:20 +0100 Subject: [PATCH 042/350] xxx --- components/images/lvgl_align.png | Bin 0 -> 11061 bytes components/lvgl.rst | 170 ++++++++++++++++++++----------- 2 files changed, 108 insertions(+), 62 deletions(-) create mode 100644 components/images/lvgl_align.png diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png new file mode 100644 index 0000000000000000000000000000000000000000..ebf0c4ef3dfbd5e198124daa661015e1946889f8 GIT binary patch literal 11061 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 triggered by actions performed at the screen. Check out the *See Also* section at the bottom of this document. - - - Main Component -------------- +Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome this is simplified to a hierarchy. + +At the highest level of the LVGL object hierarchy is the display which represents the driver for a display device (physical display). A display can have one or more screens associated with it. Each screen contains a hierarchy of objects for graphical widgets representing a layout that covers the entire display. + +The widget is at the top level, and it allows main styling. It also has sub-parts, which can be styled separately. +Usually styles are inherited. The widget and the parts have states, and the different styling can be set for different states. + +Configuration variables: + +- **display_id** (*Optional*, :ref:`config-id`): The ID of a display configuration where to render this entire LVGL configuration. If there's only one display configured, this item can be omitted. +- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the LVGL widgets on the display. If there's only one touchscreen configured, this item can be omitted. +- **rotary_encoders** (*Optional*, list): + - **sensor:** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. + - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. + - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See :ref:`below ` for more information on groups. +- **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``8``. +- **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. +- **log_level** (*Optional*): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. +- **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. +- **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. +- **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. +- **layout** (*Optional*, string): LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. +- **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. +- All other options from :ref:`lvgl-styling`. + +Example: + .. code-block:: yaml # Example configuration entry @@ -84,25 +103,6 @@ Main Component y: 30 - -Configuration variables: - -- **display_id** (*Optional*, :ref:`config-id`): The ID of a display configuration where to render this entire LVGL configuration. If there's only one display configured, this item can be omitted. -- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the LVGL widgets on the display. If there's only one touchscreen configured, this item can be omitted. -- **rotary_encoders** (*Optional*, list): - - **sensor:** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. - - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. - - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See :ref:`below ` for more information on groups. -- **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``8``. -- **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. -- **log_level** (*Optional*): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. -- **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. -- **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. -- **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. -- **layout** (*Optional*, string): LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. -- **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. -- All other options from :ref:`lvgl-styling`. - .. note:: By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. @@ -110,8 +110,8 @@ Configuration variables: .. _lvgl-styling: -Properties and Styles ---------------------- +Style properties +---------------- - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. @@ -124,7 +124,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **height** (*Optional*): Height of the widget - one of ``size_content``, a number (pixels) or a percentage. - **opa** (*Optional*, string or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. - **opa_layered** (*Optional*, string or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **align** (*Optional*, string): Alignment of the contents of the widget. One of the values below: +- **align** (*Optional*, string): Alignment of the contents of the widget. Check `LVGL `__ documentation to see how they act. One of the values below: - ``TOP_LEFT`` - ``TOP_MID`` - ``TOP_RIGHT`` @@ -309,19 +309,19 @@ And then you apply these selected styles to two labels, and only change very spe Additionally, you can change the styles based on the state of the widgets or their parts. Widgets or their parts can have have states: - - ``default`` - - ``disabled`` - - ``hovered`` - - ``pressed`` - - ``checked`` - - ``scrolled`` - - ``focused`` - - ``focus_key`` - - ``edited`` - - ``user_1`` - - ``user_2`` - - ``user_3`` - - ``user_4`` + - ``default``: Normal, released state + - ``disabled``: Disabled state + - ``hovered``: Hovered by mouse (not supported now) + - ``pressed``: Being pressed + - ``checked``: Toggled or checked state + - ``scrolled``: Being scrolled + - ``focused``: Focused via keypad or encoder or clicked via touchpad/mouse + - ``focus_key``: Focused via keypad or encoder but not via touchpad/mouse + - ``edited``: Edit by an encoder + - ``user_1``: Custom state + - ``user_2``: Custom state + - ``user_3``: Custom state + - ``user_4``: Custom state In the example below, you have an ``arc`` with some styles set here. Note how you change the ``arc_color`` of the ``indicator`` part, based on state changes: @@ -375,8 +375,8 @@ Specific configuration options: - **arc_color** (*Optional*, :ref:`color `): The ID of a color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - - **knob** (*Optional*, list): Adds a knob *part* to control the value. Supports a list of styles and state-based styles to customize. - - **indicator** (*Optional*, list): Adds an indicator *part* to show the value. Supports a list of styles and state-based styles to customize. + - **knob** (*Optional*, list): Adds a knob **part** to control the value. Supports a list of styles and state-based styles to customize. + - **indicator** (*Optional*, list): Adds an indicator **part** to show the value. Supports a list of styles and state-based styles to customize. - any :ref:`Styling ` and state-based option to override styles inherited from parent. .. note:: @@ -410,11 +410,16 @@ Example: ``bar`` ******* -Descr +The bar object has a background and an indicator on it. The width of the indicator is set according to the current value of the bar. + +Vertical bars can be created if the width of the object is smaller than its height. + +Not only the end, but also the start value of the bar can be set, which changes the start position of the indicator. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + - **indicator** (*Optional*, list): Adds an indicator **part** Example: @@ -428,7 +433,7 @@ Example: ``btn`` ******* -Descr +Simple push or toggle button. Specific configuration options: @@ -447,11 +452,12 @@ Example: ``btnmatrix`` ************* -Descr +The Button Matrix object is a lightweight way to display multiple buttons in rows and columns. Lightweight because the buttons are not actually created but just virtually drawn on the fly. This way, one button use only eight extra bytes of memory instead of the ~100-150 bytes a normal Button object plus the 100 or so bytes for the Label object. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + - **items** (*Optional*, list): Adds a items **part** Example: @@ -466,7 +472,7 @@ Example: ``canvas`` ********** -Descr +A Canvas inherits from Image where the user can draw anything. Rectangles, texts, images, lines, arcs can be drawn here using lvgl's drawing engine. Additionally "effects" can be applied, such as rotation, zoom and blur. Specific configuration options: @@ -485,11 +491,12 @@ Example: ``checkbox`` ************ -Descr +The Checkbox object is made from a "tick box" and a label. When the Checkbox is clicked the tick box is toggled. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + - **indicator** (*Optional*, list): Adds an indicator **part** Example: @@ -504,11 +511,14 @@ Example: ``dropdown`` ************ -Descr +The drop-down list allows the user to select one value from a list. + +The drop-down list is closed by default and displays a single value or a predefined text. When activated (by click on the drop-down list), a list is drawn from which the user may select one option. When the user selects a new value, the list is deleted from the screen. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + - **indicator** (*Optional*, list): Adds an indicator **part** Example: @@ -523,7 +533,7 @@ Example: ``img`` ******* -Descr +Images are the basic widgets to display images. Specific configuration options: @@ -542,11 +552,13 @@ Example: ``label`` ********* -Descr +A label is the basic object type that is used to display text. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + - **scrollbar** (*Optional*, list): Adds a scrollbar **part** + - **selected** (*Optional*, list): Adds a selected **part** Example: @@ -561,7 +573,7 @@ Example: ``line`` ******** -Descr +The Line object is capable of drawing straight lines between a set of points. Specific configuration options: @@ -580,7 +592,27 @@ Example: ``meter`` ********* -Descr +The Meter widget can visualize data in very flexible ways. In can show arcs, needles, ticks lines and labels. + +Specific configuration options: + + - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + +``obj`` +******* + +The Base Object can be directly used as a simple, empty widget. It is nothing more than a (rounded) rectangle. + +You can use it as a parent background shape for other objects. It catches touches! Specific configuration options: @@ -596,14 +628,16 @@ Example: + ``roller`` ********** -Descr +Roller allows you to simply select one option from a list by scrolling. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + - **selected** (*Optional*, list): Adds a selected **part** Example: @@ -618,11 +652,13 @@ Example: ``slider`` ********** -Descr +The Slider object looks like a Bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider can be vertical or horizontal. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + - **indicator** (*Optional*, list): Adds an indicator **part** + - **knob** (*Optional*, list): Adds a knob **part** Example: @@ -637,11 +673,13 @@ Example: ``switch`` ********** -Descr +The Switch looks like a little slider and can be used to turn something on and off. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. + - **indicator** (*Optional*, list): Adds an indicator **part** + - **knob** (*Optional*, list): Adds a knob **part** Example: @@ -656,12 +694,15 @@ Example: ``table`` ********* -Descr +Tables, as usual, are built from rows, columns, and cells containing texts. + +The Table object is very lightweight because only the texts are stored. No real objects are created for cells but they are just drawn on the fly. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - + - **items** (*Optional*, list): Adds a items **part** + Example: @@ -675,12 +716,17 @@ Example: ``textarea`` ************ -Descr +The Text Area is a Base object with a Label and a cursor on it. Texts or characters can be added to it. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. + +One line mode and password modes are supported. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - + - **scrollbar** (*Optional*, list): Adds a scrollbar **part** + - **selected** (*Optional*, list): Adds a selected **part** + - **cursor** (*Optional*, list): Adds a cursor **part** + - **textarea_placeholder** (*Optional*, list): Adds a textarea_placeholder **part** Example: From a0b327434411f77b6605535541e98c79e489cd1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 4 Jan 2024 17:07:47 +0100 Subject: [PATCH 043/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 133a21a69..d3ded2afb 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -124,7 +124,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **height** (*Optional*): Height of the widget - one of ``size_content``, a number (pixels) or a percentage. - **opa** (*Optional*, string or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. - **opa_layered** (*Optional*, string or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **align** (*Optional*, string): Alignment of the contents of the widget. Check `LVGL `__ documentation to see how they act. One of the values below: +- **align** (*Optional*, string): Alignment of the contents of the widget. Check `this image `__ to understand. One of the values below: - ``TOP_LEFT`` - ``TOP_MID`` - ``TOP_RIGHT`` From 932145938eee6f96f82299ef31f43335c7daf28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 5 Jan 2024 10:03:23 +0100 Subject: [PATCH 044/350] update --- components/images/lvgl_align.png | Bin 11061 -> 0 bytes components/lvgl.rst | 61 ++++++++++++++----------------- 2 files changed, 27 insertions(+), 34 deletions(-) delete mode 100644 components/images/lvgl_align.png diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png deleted file mode 100644 index ebf0c4ef3dfbd5e198124daa661015e1946889f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11061 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 for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. -- **layout** (*Optional*, string): LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. +- **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. - All other options from :ref:`lvgl-styling`. @@ -124,7 +124,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **height** (*Optional*): Height of the widget - one of ``size_content``, a number (pixels) or a percentage. - **opa** (*Optional*, string or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. - **opa_layered** (*Optional*, string or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **align** (*Optional*, string): Alignment of the contents of the widget. Check `this image `__ to understand. One of the values below: +- **align** (*Optional*, string): Alignment of the contents of the widget. One of: - ``TOP_LEFT`` - ``TOP_MID`` - ``TOP_RIGHT`` @@ -134,19 +134,6 @@ You can adjust the appearance of widgets by changing the foreground, background - ``BOTTOM_LEFT`` - ``BOTTOM_MID`` - ``BOTTOM_RIGHT`` - - ``OUT_LEFT_TOP`` - - ``OUT_TOP_LEFT`` - - ``OUT_TOP_MID`` - - ``OUT_TOP_RIGHT`` - - ``OUT_RIGHT_TOP`` - - ``OUT_LEFT_MID`` - - ``OUT_CENTER`` - - ``OUT_RIGHT_MID`` - - ``OUT_LEFT_BOTTOM`` - - ``OUT_BOTTOM_LEFT`` - - ``OUT_BOTTOM_MID`` - - ``OUT_BOTTOM_RIGHT`` - - ``OUT_RIGHT_BOTTOM`` - **bg_color** (*Optional*, :ref:`color `): The ID of a color for the background of the widget. - **bg_grad_color** (*Optional*, :ref:`color `): The ID of a color to make the background gradually fade to. - **bg_dither_mode** (*Optional*, string): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. @@ -369,14 +356,14 @@ Specific configuration options: - **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. - **rotation** (*Optional*, int8): Offset to the 0 degree position. Defaults to ``0.0``. - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. - - **mode** (*Optional*, string): One of ``NORMAL``, ``REVERSE``, ``SYMMETRICAL``. Defaults to ``NORMAL``. + - **mode** (*Optional*, string): One of ``NORMAL``, ``REVERSE``, ``SYMMETRICAL``. ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. - **arc_opa** (*Optional*, string or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. - **arc_color** (*Optional*, :ref:`color `): The ID of a color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - - **knob** (*Optional*, list): Adds a knob **part** to control the value. Supports a list of styles and state-based styles to customize. - - **indicator** (*Optional*, list): Adds an indicator **part** to show the value. Supports a list of styles and state-based styles to customize. + - **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of styles and state-based styles to customize. + - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. - any :ref:`Styling ` and state-based option to override styles inherited from parent. .. note:: @@ -407,6 +394,9 @@ Example: bg_color: 0x808080 +The ``arc`` can be also integrated as :doc:`/components/sensor/lvgl` and :doc:`/components/number/lvgl`. + + ``bar`` ******* @@ -419,7 +409,7 @@ Not only the end, but also the start value of the bar can be set, which changes Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Adds an indicator **part** + - **indicator** (*Optional*, list): Settings for the indicator **part** Example: @@ -447,6 +437,7 @@ Example: # Example widget: - +The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl`. ``btnmatrix`` @@ -457,7 +448,7 @@ The Button Matrix object is a lightweight way to display multiple buttons in row Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **items** (*Optional*, list): Adds a items **part** + - **items** (*Optional*, list): Settings for the items **part** Example: @@ -496,7 +487,7 @@ The Checkbox object is made from a "tick box" and a label. When the Checkbox is Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Adds an indicator **part** + - **indicator** (*Optional*, list): Settings for the indicator **part** Example: @@ -506,6 +497,7 @@ Example: # Example widget: - +The ``checkbox`` can be also integrated as :doc:`/components/binary_sensor/lvgl`. ``dropdown`` @@ -518,7 +510,7 @@ The drop-down list is closed by default and displays a single value or a predefi Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Adds an indicator **part** + - **indicator** (*Optional*, list): Settings for the indicator **part** Example: @@ -557,8 +549,8 @@ A label is the basic object type that is used to display text. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **scrollbar** (*Optional*, list): Adds a scrollbar **part** - - **selected** (*Optional*, list): Adds a selected **part** + - **scrollbar** (*Optional*, list): Settings for the scrollbar **part** + - **selected** (*Optional*, list): Settings for the selected **part** Example: @@ -637,7 +629,7 @@ Roller allows you to simply select one option from a list by scrolling. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **selected** (*Optional*, list): Adds a selected **part** + - **selected** (*Optional*, list): Settings for the selected **part** Example: @@ -657,8 +649,8 @@ The Slider object looks like a Bar supplemented with a knob. The knob can be dra Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Adds an indicator **part** - - **knob** (*Optional*, list): Adds a knob **part** + - **indicator** (*Optional*, list): Settings for the indicator **part** + - **knob** (*Optional*, list): Settings for the knob **part** Example: @@ -668,6 +660,7 @@ Example: # Example widget: - +The ``slider`` can be also integrated as :doc:`/components/sensor/lvgl` and :doc:`/components/number/lvgl`. ``switch`` @@ -678,8 +671,8 @@ The Switch looks like a little slider and can be used to turn something on and o Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Adds an indicator **part** - - **knob** (*Optional*, list): Adds a knob **part** + - **indicator** (*Optional*, list): Settings for the indicator **part** + - **knob** (*Optional*, list): Settings for the knob **part** Example: @@ -701,7 +694,7 @@ The Table object is very lightweight because only the texts are stored. No real Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **items** (*Optional*, list): Adds a items **part** + - **items** (*Optional*, list): Settings for the items **part** Example: @@ -723,10 +716,10 @@ One line mode and password modes are supported. Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **scrollbar** (*Optional*, list): Adds a scrollbar **part** - - **selected** (*Optional*, list): Adds a selected **part** - - **cursor** (*Optional*, list): Adds a cursor **part** - - **textarea_placeholder** (*Optional*, list): Adds a textarea_placeholder **part** + - **scrollbar** (*Optional*, list): Settings for the scrollbar **part** + - **selected** (*Optional*, list): Settings for the selected **part** + - **cursor** (*Optional*, list): Settings for the cursor **part** + - **textarea_placeholder** (*Optional*, list): Settings for the textarea_placeholder **part** Example: From d721e02bf52a9b78f1d0888afd762bb4212fc829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 5 Jan 2024 14:00:22 +0100 Subject: [PATCH 045/350] Update lvgl.rst --- components/lvgl.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 6db6b03bc..06f2e5934 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -356,7 +356,7 @@ Specific configuration options: - **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. - **rotation** (*Optional*, int8): Offset to the 0 degree position. Defaults to ``0.0``. - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. - - **mode** (*Optional*, string): One of ``NORMAL``, ``REVERSE``, ``SYMMETRICAL``. ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. + - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. - **arc_opa** (*Optional*, string or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. - **arc_color** (*Optional*, :ref:`color `): The ID of a color to use to draw the arcs. @@ -757,7 +757,9 @@ In ESPHome you can also use a :ref:`font configured in the normal way` is activated when lvgl enters in idle state after the specified ``timeout``. +LVGL has a notion of screen inactivity, i.e. how long did the user not interact with the screen. This can be use to dim the display backlight or turn it off after a moment of inactivity (like a screen saver). Every use of an input device (touchscreen, rotary encoder) counts as an activity and resets the inactivity counter. + +The ``on_idle`` :ref:`trigger ` is activated when inactivity time becomes longer than the specified ``timeout``. - **timeout** (**Required**): :ref:`Time ` value after which LVGL should enter idle state. From 38e20bdd8b2f7a38d6143a932d493c0ab087a08e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 10:27:15 +0100 Subject: [PATCH 046/350] Update lvgl.rst --- components/lvgl.rst | 279 ++++++++++++++++++++++++++++---------------- 1 file changed, 180 insertions(+), 99 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 06f2e5934..a1b2dfbfe 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -38,7 +38,7 @@ Widgets integrate in ESPHome also as components: +=============+========================+ | Checkbox | Binary Sensor | +-------------+------------------------+ -| Button | Binary Sensor | +| Button | Binary Sensor, Button | +-------------+------------------------+ | Slider | Sensor, Number | +-------------+------------------------+ @@ -68,13 +68,22 @@ Configuration variables: - **sensor:** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See :ref:`below ` for more information on groups. -- **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``8``. +- **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. - **log_level** (*Optional*): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. - **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. +- **flex_flow** (*Optional*, string): In case of ``FLEX`` layout, choose one of the following options: + - ``ROW`` to place the children in a row without wrapping + - ``COLUMN`` to place the children in a column without wrapping + - ``ROW_WRAP`` to place the children in a row with wrapping + - ``COLUMN_WRAP`` to place the children in a column with wrapping + - ``ROW_REVERSE`` to place the children in a row without wrapping but in reversed order + - ``COLUMN_REVERSE`` to place the children in a column without wrapping but in reversed order + - ``ROW_WRAP_REVERSE`` to place the children in a row with wrapping but in reversed order + - ``COLUMN_WRAP_REVERSE`` to place the children in a column with wrapping but in reversed order - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. - All other options from :ref:`lvgl-styling`. @@ -113,9 +122,6 @@ Example: Style properties ---------------- -- **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. - - You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each object. Some widgets allow for more complex styling, effectively changing the appearance of their parts. - **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to the parent or screen). @@ -199,37 +205,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **min_width** (*Optional*, int16 or percentage): Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. -In addition to visual stilyng, each widget supports some flags to influence the behavior: -- **hidden** (*Optional*, boolean): -- **clickable** (*Optional*, boolean): -- **click_focusable** (*Optional*, boolean): -- **checkable** (*Optional*, boolean): -- **scrollable** (*Optional*, boolean): -- **scroll_elastic** (*Optional*, boolean): -- **scroll_momentum** (*Optional*, boolean): -- **scroll_one** (*Optional*, boolean): -- **scroll_chain_hor** (*Optional*, boolean): -- **scroll_chain_ver** (*Optional*, boolean): -- **scroll_chain** (*Optional*, boolean): -- **scroll_on_focus** (*Optional*, boolean): -- **scroll_with_arrow** (*Optional*, boolean): -- **snappable** (*Optional*, boolean): -- **press_lock** (*Optional*, boolean): -- **event_bubble** (*Optional*, boolean): -- **gesture_bubble** (*Optional*, boolean): -- **adv_hittest** (*Optional*, boolean): -- **ignore_layout** (*Optional*, boolean): -- **floating** (*Optional*, boolean): -- **overflow_visible** (*Optional*, boolean): -- **layout_1** (*Optional*, boolean): -- **layout_2** (*Optional*, boolean): -- **widget_1** (*Optional*, boolean): -- **widget_2** (*Optional*, boolean): -- **user_1** (*Optional*, boolean): -- **user_2** (*Optional*, boolean): -- **user_3** (*Optional*, boolean): -- **user_4** (*Optional*, boolean): .. _lvgl-theme: @@ -294,21 +270,7 @@ And then you apply these selected styles to two labels, and only change very spe styles: date_style y: +20 -Additionally, you can change the styles based on the state of the widgets or their parts. Widgets or their parts can have have states: - - - ``default``: Normal, released state - - ``disabled``: Disabled state - - ``hovered``: Hovered by mouse (not supported now) - - ``pressed``: Being pressed - - ``checked``: Toggled or checked state - - ``scrolled``: Being scrolled - - ``focused``: Focused via keypad or encoder or clicked via touchpad/mouse - - ``focus_key``: Focused via keypad or encoder but not via touchpad/mouse - - ``edited``: Edit by an encoder - - ``user_1``: Custom state - - ``user_2``: Custom state - - ``user_3``: Custom state - - ``user_4``: Custom state +Additionally, you can change the styles based on the state of the widgets or their parts. In the example below, you have an ``arc`` with some styles set here. Note how you change the ``arc_color`` of the ``indicator`` part, based on state changes: @@ -336,10 +298,26 @@ Widgets ------- Common properties +***************** The properties below are common to all widgets. -TODO +- **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. +- **state** (*Optional*, string): Widgets or their (sub)parts can have have states, which support separate styling. These state styless inherit from theme, but can be locally overriden withing style definitions or locally set. The state itself can be can be changed by interacting with the widget itself, or :ref:`programatically ` with ``lvgl.obj.update`` action. + - ``default``: Normal, released state + - ``disabled``: Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.obj.enable`` and ``lvgl.obj.disable``) + - ``pressed``: Being pressed + - ``checked``: Toggled or checked state + - ``scrolled``: Being scrolled + - ``focused``: Focused via keypad or encoder or clicked via touchpad/mouse + - ``focus_key``: Focused via keypad or encoder but not via touchpad/mouse + - ``edited``: Edit by an encoder + - ``user_1``: Custom state + - ``user_2``: Custom state + - ``user_3``: Custom state + - ``user_4``: Custom state + +In addition to visual stilyng, each widget supports :ref:`dynamically settable flags ` to influence the behavior at runtime. ``arc`` @@ -752,66 +730,107 @@ In ESPHome you can also use a :ref:`font configured in the normal way` is activated when inactivity time becomes longer than the specified ``timeout``. - -- **timeout** (**Required**): :ref:`Time ` value after which LVGL should enter idle state. - -.. code-block:: yaml - - lvgl: - on_idle: - timeout: 30s - then: - - logger.log: "LVGL is idle" - - lvgl.pause: - - light.turn_off: - id: display_backlight -.. _lvgl-paused-cond: - -``lvgl.is_paused`` Condition ----------------------------- - -This :ref:`condition ` checks if LVGL is in paused state or not. - -.. code-block:: yaml - - # In some trigger: - on_...: - then: - - if: - condition: lvgl.is_paused - then: - - lvgl.resume: - - light.turn_on: - id: display_backlight -.. _lvgl-idle-cond: -``lvgl.is_idle`` Condition + + +.. _lvgl-objupd-act: + +``lvgl.obj.update`` Action -------------------------- -This :ref:`condition ` checks if LVGL is in idle state or not. +This powerful :ref:`action ` allows changing on the fly any property or flag of any widget. .. code-block:: yaml - # In some trigger: on_...: then: - - if: - condition: lvgl.is_idle - then: - - light.turn_off: - id: display_backlight + - lvgl.obj.update: + id: btn_relay_1 + state: + disabled: true + + + +.. _lvgl-objupdflag-act: + +In addition to visual stilyng, each widget supports some flags to influence the behavior: + + +.. code-block:: yaml + + on_...: + then: + - lvgl.obj.update: + id: btn_relay_1 + hidden: true + + + - **hidden** (*Optional*, boolean): make the object hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.obj.show`` and ``lvgl.obj.hide`` + - **clickable** (*Optional*, boolean): make the object clickable by input devices + - **click_focusable** (*Optional*, boolean): add focused state to the object when clicked + - **checkable** (*Optional*, boolean): toggle checked state when the object is clicked + - **scrollable** (*Optional*, boolean): make the object scrollable + - **scroll_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed + - **scroll_momentum** (*Optional*, boolean): make the object scroll further when "thrown" + - **scroll_one** (*Optional*, boolean): allow scrolling only one snappable children + - **scroll_chain_hor** (*Optional*, boolean): allow propagating the horizontal scroll to a parent + - **scroll_chain_ver** (*Optional*, boolean): allow propagating the vertical scroll to a parent + - **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor** or ``scroll_chain_ver``) + - **scroll_on_focus** (*Optional*, boolean): automatically scroll object to make it visible when focused + - **scroll_with_arrow** (*Optional*, boolean): allow scrolling the focused object with arrow keys + - **snappable** (*Optional*, boolean): if scroll snap is enabled on the parent it can snap to this object + - **press_lock** (*Optional*, boolean): keep the object pressed even if the press slid from the object + - **event_bubble** (*Optional*, boolean): propagate the events to the parent too + - **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent + - **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. E.g. Accounting for rounded corners + - **ignore_layout** (*Optional*, boolean): make the object positionable by the layouts + - **floating** (*Optional*, boolean): do not scroll the object when the parent scrolls and ignore layout + - **overflow_visible** (*Optional*, boolean): do not clip the children's content to the parent's boundary + - **layout_1** (*Optional*, boolean): custom flag, free to use by layouts + - **layout_2** (*Optional*, boolean): custom flag, free to use by layouts + - **widget_1** (*Optional*, boolean): custom flag, free to use by widget + - **widget_2** (*Optional*, boolean): custom flag, free to use by widget + - **user_1** (*Optional*, boolean): custom flag, free to use by user + - **user_2** (*Optional*, boolean): custom flag, free to use by user + - **user_3** (*Optional*, boolean): custom flag, free to use by user + - **user_4** (*Optional*, boolean): custom flag, free to use by user + + + +.. _lvgl-objupd-shorthands: + +``lvgl.obj.hide`` and ``lvgl.obj.show`` Actions +----------------------------------------------- + +These :ref:`actions ` are shorthands for toggling the ``hidden`` flag of any widget: + +.. code-block:: yaml + + on_...: + then: + - lvgl.obj.hide: my_label_id + - delay: 0.5s + - lvgl.obj.show: my_label_id + + +``lvgl.obj.disable`` and ``lvgl.obj.enable`` Actions +---------------------------------------------------- + +These :ref:`actions ` are shorthands for toggling the ``disabled`` state of any widget (which controls the appearance of the corresponding *disabled* style set of the theme): + +.. code-block:: yaml + + - on_...: + then: + - lvgl.obj.disable: my_button_id + - on_...: + then: + - lvgl.obj.enable: my_button_id + .. _lvgl-pause-act: @@ -842,6 +861,68 @@ This :ref:`action ` resumes the activity of LVGL, including rende - lvgl.resume +.. _lvgl-idle-cond: + +``lvgl.is_idle`` Condition +-------------------------- + +This :ref:`condition ` checks if LVGL is in idle state or not. + +.. code-block:: yaml + + # In some trigger: + on_...: + then: + - if: + condition: lvgl.is_idle + then: + - light.turn_off: + id: display_backlight + + +.. _lvgl-paused-cond: + +``lvgl.is_paused`` Condition +---------------------------- + +This :ref:`condition ` checks if LVGL is in paused state or not. + +.. code-block:: yaml + + # In some trigger: + on_...: + then: + - if: + condition: lvgl.is_paused + then: + - lvgl.resume: + - light.turn_on: + id: display_backlight + + +.. _lvgl-onidle-act: + +``lvgl.on_idle`` Trigger +------------------------ + +LVGL has a notion of screen inactivity, i.e. how long did the user not interact with the screen. This can be use to dim the display backlight or turn it off after a moment of inactivity (like a screen saver). Every use of an input device (touchscreen, rotary encoder) counts as an activity and resets the inactivity counter. + +The ``on_idle`` :ref:`trigger ` is activated when inactivity time becomes longer than the specified ``timeout``. + +- **timeout** (**Required**): :ref:`Time ` value after which LVGL should enter idle state. + +.. code-block:: yaml + + lvgl: + on_idle: + timeout: 30s + then: + - logger.log: "LVGL is idle" + - lvgl.pause: + - light.turn_off: + id: display_backlight + + Data types ---------- From 5a7a180a00062940958ba0b27faa7bdc0217432e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 10:58:54 +0100 Subject: [PATCH 047/350] Update lvgl.rst --- components/lvgl.rst | 271 ++++++++++++++++++++++---------------------- 1 file changed, 138 insertions(+), 133 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a1b2dfbfe..11049c318 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -117,96 +117,6 @@ Example: By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. -.. _lvgl-styling: - -Style properties ----------------- - -You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each object. Some widgets allow for more complex styling, effectively changing the appearance of their parts. - -- **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to the parent or screen). -- **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to the parent or screen). -- **width** (*Optional*): Width of the widget - one of ``size_content``, a number (pixels) or a percentage. -- **height** (*Optional*): Height of the widget - one of ``size_content``, a number (pixels) or a percentage. -- **opa** (*Optional*, string or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **opa_layered** (*Optional*, string or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **align** (*Optional*, string): Alignment of the contents of the widget. One of: - - ``TOP_LEFT`` - - ``TOP_MID`` - - ``TOP_RIGHT`` - - ``LEFT_MID`` - - ``CENTER`` - - ``RIGHT_MID`` - - ``BOTTOM_LEFT`` - - ``BOTTOM_MID`` - - ``BOTTOM_RIGHT`` -- **bg_color** (*Optional*, :ref:`color `): The ID of a color for the background of the widget. -- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a color to make the background gradually fade to. -- **bg_dither_mode** (*Optional*, string): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. -- **bg_grad_dir** (*Optional*, string): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. -- **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. -- **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. -- **bg_img_opa** (*Optional*, string or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a color to mix with every pixel of the image. -- **bg_img_recolor_opa** (*Optional*, string or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **bg_opa** (*Optional*, string or percentage): Opacity of the background. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **border_color** (*Optional*, :ref:`color `): The ID of a color to draw borders of the widget. -- **border_opa** (*Optional*, string or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. -- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be chosen): - - ``NONE`` - - ``TOP`` - - ``BOTTOM`` - - ``LEFT`` - - ``RIGHT`` - - ``INTERNAL`` -- **border_width** (*Optional*, int16): Set the width of the border in pixels. -- **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height). -- **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. -- **text_align** (*Optional*, string): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` -- **text_color** (*Optional*, :ref:`color `): The ID of a color to render the text in. -- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) -- **text_font**: (*Optional*, :ref:`font `): The ID or the C array file of the font used to render the text. -- **text_letter_space** (*Optional*, int16): Characher spacing of the text. -- **text_line_space** (*Optional*, int16): Line spacing of the text. -- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **line_width** (*Optional*, int16): Set the width of the line in pixels. -- **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). -- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). -- **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **line_color** (*Optional*, :ref:`color `): The ID of a color for the line. -- **outline_color** (*Optional*, :ref:`color `): The ID of a color to draw an outline around the widget. -- **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. -- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. -- **pad_all** (*Optional*, int16): Set the padding in all directions, in pixels. -- **pad_top** (*Optional*, int16): Set the padding on the top, in pixels. -- **pad_bottom** (*Optional*, int16): Set the padding on the bottom, in pixels. -- **pad_left** (*Optional*, int16): Set the padding on the left, in pixels. -- **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. -- **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. -- **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. -- **shadow_color** (*Optional*, :ref:`color `): The ID of a color to create a drop shadow under the widget. -- **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels -- **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels -- **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **shadow_spread** (*Optional*, int16): Spread of the shadow, in pixels. -- **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. -- **transform_angle** (*Optional*, 0-360): Trannsformation angle of the widget (eg. rotation) -- **transform_height** (*Optional*, int16 or percentage): Trannsformation height of the widget (eg. stretching) -- **transform_pivot_x** (*Optional*, int16 or percentage): Horizontal anchor point of the transformation. Relative to the widget's top left corner. -- **transform_pivot_y** (*Optional*, int16 or percentage): Vertical anchor point of the transformation. Relative to the widget's top left corner. -- **transform_zoom** (*Optional*, 0.1-10): Trannsformation zoom of the widget (eg. resizing) -- **translate_x** (*Optional*, int16 or percentage): Move of the widget with this value in horizontal direction. -- **translate_y** (*Optional*, int16 or percentage): Move of the widget with this value in vertical direction. -- **max_height** (*Optional*, int16 or percentage): Sets a maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. -- **min_height** (*Optional*, int16 or percentage): Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area. Defaults to ``0``. -- **max_width** (*Optional*, int16 or percentage): Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. -- **min_width** (*Optional*, int16 or percentage): Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. - - - - .. _lvgl-theme: @@ -292,6 +202,103 @@ In the example below, you have an ``arc`` with some styles set here. Note how yo So the inheritance happens like this: state based styles override the locally specified styles, which override the style definitions, which override the theme, which overrides the top level styles. +.. _lvgl-styling: + +Style properties +---------------- + +You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each object. Some widgets allow for more complex styling, effectively changing the appearance of their parts. + +- **align** (*Optional*, string): Alignment of the of the widget `relative to the parent `__. One of: + - ``TOP_LEFT`` + - ``TOP_MID`` + - ``TOP_RIGHT`` + - ``LEFT_MID`` + - ``CENTER`` + - ``RIGHT_MID`` + - ``BOTTOM_LEFT`` + - ``BOTTOM_MID`` + - ``BOTTOM_RIGHT`` + - ``OUT_LEFT_TOP`` + - ``OUT_TOP_LEFT`` + - ``OUT_TOP_MID`` + - ``OUT_TOP_RIGHT`` + - ``OUT_RIGHT_TOP`` + - ``OUT_LEFT_MID`` + - ``OUT_CENTER`` + - ``OUT_RIGHT_MID`` + - ``OUT_LEFT_BOTTOM`` + - ``OUT_BOTTOM_LEFT`` + - ``OUT_BOTTOM_MID`` + - ``OUT_BOTTOM_RIGHT`` + - ``OUT_RIGHT_BOTTOM`` +- **bg_color** (*Optional*, :ref:`color `): The ID of a color for the background of the widget. +- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a color to make the background gradually fade to. +- **bg_dither_mode** (*Optional*, string): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. +- **bg_grad_dir** (*Optional*, string): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. +- **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. +- **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. +- **bg_img_opa** (*Optional*, string or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a color to mix with every pixel of the image. +- **bg_img_recolor_opa** (*Optional*, string or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **bg_opa** (*Optional*, string or percentage): Opacity of the background. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **opa** (*Optional*, string or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **opa_layered** (*Optional*, string or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **border_color** (*Optional*, :ref:`color `): The ID of a color to draw borders of the widget. +- **border_opa** (*Optional*, string or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. +- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be chosen): + - ``NONE`` + - ``TOP`` + - ``BOTTOM`` + - ``LEFT`` + - ``RIGHT`` + - ``INTERNAL`` +- **border_width** (*Optional*, int16): Set the width of the border in pixels. +- **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height). +- **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. +- **text_align** (*Optional*, string): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` +- **text_color** (*Optional*, :ref:`color `): The ID of a color to render the text in. +- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) +- **text_font**: (*Optional*, :ref:`font `): The ID or the C array file of the font used to render the text. +- **text_letter_space** (*Optional*, int16): Characher spacing of the text. +- **text_line_space** (*Optional*, int16): Line spacing of the text. +- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **line_width** (*Optional*, int16): Set the width of the line in pixels. +- **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). +- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). +- **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **line_color** (*Optional*, :ref:`color `): The ID of a color for the line. +- **outline_color** (*Optional*, :ref:`color `): The ID of a color to draw an outline around the widget. +- **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. +- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. +- **pad_all** (*Optional*, int16): Set the padding in all directions, in pixels. +- **pad_top** (*Optional*, int16): Set the padding on the top, in pixels. +- **pad_bottom** (*Optional*, int16): Set the padding on the bottom, in pixels. +- **pad_left** (*Optional*, int16): Set the padding on the left, in pixels. +- **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. +- **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. +- **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. +- **shadow_color** (*Optional*, :ref:`color `): The ID of a color to create a drop shadow under the widget. +- **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels +- **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels +- **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **shadow_spread** (*Optional*, int16): Spread of the shadow, in pixels. +- **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. +- **transform_angle** (*Optional*, 0-360): Trannsformation angle of the widget (eg. rotation) +- **transform_height** (*Optional*, int16 or percentage): Trannsformation height of the widget (eg. stretching) +- **transform_pivot_x** (*Optional*, int16 or percentage): Horizontal anchor point of the transformation. Relative to the widget's top left corner. +- **transform_pivot_y** (*Optional*, int16 or percentage): Vertical anchor point of the transformation. Relative to the widget's top left corner. +- **transform_zoom** (*Optional*, 0.1-10): Trannsformation zoom of the widget (eg. resizing) +- **translate_x** (*Optional*, int16 or percentage): Move of the widget with this value in horizontal direction. +- **translate_y** (*Optional*, int16 or percentage): Move of the widget with this value in vertical direction. +- **max_height** (*Optional*, int16 or percentage): Sets a maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. +- **min_height** (*Optional*, int16 or percentage): Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area. Defaults to ``0``. +- **max_width** (*Optional*, int16 or percentage): Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. +- **min_width** (*Optional*, int16 or percentage): Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. + + .. _lvgl-widgets: Widgets @@ -301,7 +308,10 @@ Common properties ***************** The properties below are common to all widgets. - +- **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to top left of parent or screen). If layouts are used, or if specfiyng ``align``, can be omitted for automatic placement. +- **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to to top left of the parent or screen). If layouts are used, or if specfiyng ``align``, can be omitted for automatic placement. +- **width** (*Optional*): Width of the widget in pixels or a percentage, or ``size_content`` (see below). +- **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents (children objects, or eg. image size in case of ``img``. - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. - **state** (*Optional*, string): Widgets or their (sub)parts can have have states, which support separate styling. These state styless inherit from theme, but can be locally overriden withing style definitions or locally set. The state itself can be can be changed by interacting with the widget itself, or :ref:`programatically ` with ``lvgl.obj.update`` action. - ``default``: Normal, released state @@ -731,73 +741,66 @@ In ESPHome you can also use a :ref:`font configured in the normal way` allows changing on the fly any property or flag of any widget. +This powerful :ref:`action ` allows changing on the fly any :ref:`style property ` or :ref:`flag ` of any widget. .. code-block:: yaml on_...: then: - lvgl.obj.update: - id: btn_relay_1 + id: my_button_id + bg_color: 0xFF0000 state: disabled: true - - + .. _lvgl-objupdflag-act: -In addition to visual stilyng, each widget supports some flags to influence the behavior: - +In addition to visual stilyng, each widget supports some boolean flags to influence the behavior: .. code-block:: yaml on_...: then: - lvgl.obj.update: - id: btn_relay_1 + id: my_label_id hidden: true - - **hidden** (*Optional*, boolean): make the object hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.obj.show`` and ``lvgl.obj.hide`` - - **clickable** (*Optional*, boolean): make the object clickable by input devices - - **click_focusable** (*Optional*, boolean): add focused state to the object when clicked - - **checkable** (*Optional*, boolean): toggle checked state when the object is clicked - - **scrollable** (*Optional*, boolean): make the object scrollable - - **scroll_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed - - **scroll_momentum** (*Optional*, boolean): make the object scroll further when "thrown" - - **scroll_one** (*Optional*, boolean): allow scrolling only one snappable children - - **scroll_chain_hor** (*Optional*, boolean): allow propagating the horizontal scroll to a parent - - **scroll_chain_ver** (*Optional*, boolean): allow propagating the vertical scroll to a parent - - **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor** or ``scroll_chain_ver``) - - **scroll_on_focus** (*Optional*, boolean): automatically scroll object to make it visible when focused - - **scroll_with_arrow** (*Optional*, boolean): allow scrolling the focused object with arrow keys - - **snappable** (*Optional*, boolean): if scroll snap is enabled on the parent it can snap to this object - - **press_lock** (*Optional*, boolean): keep the object pressed even if the press slid from the object - - **event_bubble** (*Optional*, boolean): propagate the events to the parent too - - **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent - - **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. E.g. Accounting for rounded corners - - **ignore_layout** (*Optional*, boolean): make the object positionable by the layouts - - **floating** (*Optional*, boolean): do not scroll the object when the parent scrolls and ignore layout - - **overflow_visible** (*Optional*, boolean): do not clip the children's content to the parent's boundary - - **layout_1** (*Optional*, boolean): custom flag, free to use by layouts - - **layout_2** (*Optional*, boolean): custom flag, free to use by layouts - - **widget_1** (*Optional*, boolean): custom flag, free to use by widget - - **widget_2** (*Optional*, boolean): custom flag, free to use by widget - - **user_1** (*Optional*, boolean): custom flag, free to use by user - - **user_2** (*Optional*, boolean): custom flag, free to use by user - - **user_3** (*Optional*, boolean): custom flag, free to use by user - - **user_4** (*Optional*, boolean): custom flag, free to use by user +- **hidden** (*Optional*, boolean): make the object hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.obj.show`` and ``lvgl.obj.hide`` +- **clickable** (*Optional*, boolean): make the object clickable by input devices +- **click_focusable** (*Optional*, boolean): add focused state to the object when clicked +- **checkable** (*Optional*, boolean): toggle checked state when the object is clicked +- **scrollable** (*Optional*, boolean): make the object scrollable +- **scroll_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed +- **scroll_momentum** (*Optional*, boolean): make the object scroll further when "thrown" +- **scroll_one** (*Optional*, boolean): allow scrolling only one snappable children +- **scroll_chain_hor** (*Optional*, boolean): allow propagating the horizontal scroll to a parent +- **scroll_chain_ver** (*Optional*, boolean): allow propagating the vertical scroll to a parent +- **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor** or ``scroll_chain_ver``) +- **scroll_on_focus** (*Optional*, boolean): automatically scroll object to make it visible when focused +- **scroll_with_arrow** (*Optional*, boolean): allow scrolling the focused object with arrow keys +- **snappable** (*Optional*, boolean): if scroll snap is enabled on the parent it can snap to this object +- **press_lock** (*Optional*, boolean): keep the object pressed even if the press slid from the object +- **event_bubble** (*Optional*, boolean): propagate the events to the parent too +- **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent +- **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. E.g. Accounting for rounded corners +- **ignore_layout** (*Optional*, boolean): make the object positionable by the layouts +- **floating** (*Optional*, boolean): do not scroll the object when the parent scrolls and ignore layout +- **overflow_visible** (*Optional*, boolean): do not clip the children's content to the parent's boundary +- **layout_1** (*Optional*, boolean): custom flag, free to use by layouts +- **layout_2** (*Optional*, boolean): custom flag, free to use by layouts +- **widget_1** (*Optional*, boolean): custom flag, free to use by widget +- **widget_2** (*Optional*, boolean): custom flag, free to use by widget +- **user_1** (*Optional*, boolean): custom flag, free to use by user +- **user_2** (*Optional*, boolean): custom flag, free to use by user +- **user_3** (*Optional*, boolean): custom flag, free to use by user +- **user_4** (*Optional*, boolean): custom flag, free to use by user @@ -878,6 +881,7 @@ This :ref:`condition ` checks if LVGL is in idle state or not. then: - light.turn_off: id: display_backlight + transition_length: 3s .. _lvgl-paused-cond: @@ -898,6 +902,7 @@ This :ref:`condition ` checks if LVGL is in paused state or no - lvgl.resume: - light.turn_on: id: display_backlight + transition_length: 150ms .. _lvgl-onidle-act: From 13e1858ff86f6b58eb5be00ec31bef1a6ff71ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 11:07:07 +0100 Subject: [PATCH 048/350] Update lvgl.rst --- components/lvgl.rst | 105 +++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 51 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 11049c318..52d1bf042 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -308,12 +308,13 @@ Common properties ***************** The properties below are common to all widgets. + - **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to top left of parent or screen). If layouts are used, or if specfiyng ``align``, can be omitted for automatic placement. - **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to to top left of the parent or screen). If layouts are used, or if specfiyng ``align``, can be omitted for automatic placement. - **width** (*Optional*): Width of the widget in pixels or a percentage, or ``size_content`` (see below). - **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents (children objects, or eg. image size in case of ``img``. - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. -- **state** (*Optional*, string): Widgets or their (sub)parts can have have states, which support separate styling. These state styless inherit from theme, but can be locally overriden withing style definitions or locally set. The state itself can be can be changed by interacting with the widget itself, or :ref:`programatically ` with ``lvgl.obj.update`` action. +- **state** (*Optional*, string): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden withing style definitions or locally set. The state itself can be can be changed by interacting with the widget itself, or :ref:`programatically ` with ``lvgl.obj.update`` action. Can be one of: - ``default``: Normal, released state - ``disabled``: Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.obj.enable`` and ``lvgl.obj.disable``) - ``pressed``: Being pressed @@ -337,26 +338,26 @@ The Arc consists of a background and a foreground arc. The foreground (indicator Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - - **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). Defaults to ``135``. - - **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. - - **rotation** (*Optional*, int8): Offset to the 0 degree position. Defaults to ``0.0``. - - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. - - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. - - **arc_opa** (*Optional*, string or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. - - **arc_color** (*Optional*, :ref:`color `): The ID of a color to use to draw the arcs. - - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - - **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of styles and state-based styles to customize. - - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. - - any :ref:`Styling ` and state-based option to override styles inherited from parent. +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. +- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. +- **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). Defaults to ``135``. +- **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. +- **rotation** (*Optional*, int8): Offset to the 0 degree position. Defaults to ``0.0``. +- **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. +- **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. +- **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. +- **arc_opa** (*Optional*, string or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **arc_color** (*Optional*, :ref:`color `): The ID of a color to use to draw the arcs. +- **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. +- **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of styles and state-based styles to customize. +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. +- any :ref:`Styling ` and state-based option to override styles inherited from parent. - .. note:: +.. note:: - Zero degree is at the middle right (3 o'clock) of the object and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. + Zero degree is at the middle right (3 o'clock) of the object and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. Example: @@ -396,8 +397,8 @@ Not only the end, but also the start value of the bar can be set, which changes Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Settings for the indicator **part** +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **indicator** (*Optional*, list): Settings for the indicator **part** Example: @@ -415,7 +416,7 @@ Simple push or toggle button. Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. Example: @@ -435,8 +436,8 @@ The Button Matrix object is a lightweight way to display multiple buttons in row Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **items** (*Optional*, list): Settings for the items **part** +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **items** (*Optional*, list): Settings for the items **part** Example: @@ -455,7 +456,7 @@ A Canvas inherits from Image where the user can draw anything. Rectangles, texts Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. Example: @@ -474,8 +475,8 @@ The Checkbox object is made from a "tick box" and a label. When the Checkbox is Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Settings for the indicator **part** +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **indicator** (*Optional*, list): Settings for the indicator **part** Example: @@ -497,8 +498,8 @@ The drop-down list is closed by default and displays a single value or a predefi Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Settings for the indicator **part** +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **indicator** (*Optional*, list): Settings for the indicator **part** Example: @@ -517,7 +518,7 @@ Images are the basic widgets to display images. Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. Example: @@ -536,9 +537,9 @@ A label is the basic object type that is used to display text. Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **scrollbar** (*Optional*, list): Settings for the scrollbar **part** - - **selected** (*Optional*, list): Settings for the selected **part** +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **scrollbar** (*Optional*, list): Settings for the scrollbar **part** +- **selected** (*Optional*, list): Settings for the selected **part** Example: @@ -576,7 +577,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. Example: @@ -596,7 +597,7 @@ You can use it as a parent background shape for other objects. It catches touche Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. Example: @@ -616,8 +617,8 @@ Roller allows you to simply select one option from a list by scrolling. Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **selected** (*Optional*, list): Settings for the selected **part** +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **selected** (*Optional*, list): Settings for the selected **part** Example: @@ -636,9 +637,9 @@ The Slider object looks like a Bar supplemented with a knob. The knob can be dra Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Settings for the indicator **part** - - **knob** (*Optional*, list): Settings for the knob **part** +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **indicator** (*Optional*, list): Settings for the indicator **part** +- **knob** (*Optional*, list): Settings for the knob **part** Example: @@ -658,9 +659,9 @@ The Switch looks like a little slider and can be used to turn something on and o Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **indicator** (*Optional*, list): Settings for the indicator **part** - - **knob** (*Optional*, list): Settings for the knob **part** +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **indicator** (*Optional*, list): Settings for the indicator **part** +- **knob** (*Optional*, list): Settings for the knob **part** Example: @@ -681,9 +682,9 @@ The Table object is very lightweight because only the texts are stored. No real Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **items** (*Optional*, list): Settings for the items **part** - +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **items** (*Optional*, list): Settings for the items **part** + Example: @@ -703,11 +704,11 @@ One line mode and password modes are supported. Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - - **scrollbar** (*Optional*, list): Settings for the scrollbar **part** - - **selected** (*Optional*, list): Settings for the selected **part** - - **cursor** (*Optional*, list): Settings for the cursor **part** - - **textarea_placeholder** (*Optional*, list): Settings for the textarea_placeholder **part** +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **scrollbar** (*Optional*, list): Settings for the scrollbar **part** +- **selected** (*Optional*, list): Settings for the selected **part** +- **cursor** (*Optional*, list): Settings for the cursor **part** +- **textarea_placeholder** (*Optional*, list): Settings for the textarea_placeholder **part** Example: @@ -724,6 +725,8 @@ Example: Fonts ----- +TODO + LVGL internally uses fonts in a C array. The library offers by default the following ones preconverted: - ``montserrat_12_subpx`` From 7533b35039f05723ab6e384c326547bdc9ceb346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 12:25:31 +0100 Subject: [PATCH 049/350] updates --- components/binary_sensor/lvgl.rst | 6 +- components/lvgl.rst | 155 ++++++++++++++++++++++-------- components/number/lvgl.rst | 7 +- components/sensor/lvgl.rst | 7 +- components/switch/lvgl.rst | 41 ++++++++ 5 files changed, 165 insertions(+), 51 deletions(-) create mode 100644 components/switch/lvgl.rst diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 5f852a614..65d68ee6c 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -19,8 +19,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the binary sensor. -- **btn** (*Optional*): The ID of a button widget configured in LVGL. -- **checkbox** (*Optional*): The ID of a checkbox widget configured in LVGL. +- **obj** (*Optional*): The ID of a button widget configured in LVGL. - All other options from :ref:`Binary Sensor `. @@ -30,12 +29,13 @@ Example: binary_sensor: - platform: lvgl + obj: checkbox_id name: LVGL checkbox - checkbox: lv_checkbox See Also -------- - :ref:`LVGL Main component ` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` - :ghedit:`Edit` diff --git a/components/lvgl.rst b/components/lvgl.rst index 52d1bf042..b42d0a5bb 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -62,20 +62,22 @@ Usually styles are inherited. The widget and the parts have states, and the diff Configuration variables: -- **display_id** (*Optional*, :ref:`config-id`): The ID of a display configuration where to render this entire LVGL configuration. If there's only one display configured, this item can be omitted. -- **touchscreens** (*Optional*, list): IDs of touchscreens interacting with the LVGL widgets on the display. If there's only one touchscreen configured, this item can be omitted. -- **rotary_encoders** (*Optional*, list): - - **sensor:** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. +- **display_id** (**Required**, list): A list of displays where to render this entire LVGL configuration: + - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. +- **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. Can be omitted if there's at least a rotary encoder configured. + - **touchscreen_id** (*Required*, :ref:`config-id`): ID of a touchscreen configuration- +- **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. Can be omitted if there's at least a touchscreen configured. + - **sensor:** (*Required*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See :ref:`below ` for more information on groups. -- **color_depth** (*Optional*, int8): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. +- **color_depth** (*Optional*, enum): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. -- **log_level** (*Optional*): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. -- **byte_order**: The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. +- **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. +- **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. -- **flex_flow** (*Optional*, string): In case of ``FLEX`` layout, choose one of the following options: +- **flex_flow** (*Optional*, string): In case of ``FLEX`` layout, choose one of the following options. Defaults to ``ROW_WRAP``: - ``ROW`` to place the children in a row without wrapping - ``COLUMN`` to place the children in a column without wrapping - ``ROW_WRAP`` to place the children in a row with wrapping @@ -125,8 +127,7 @@ Theming and Styling The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. -You can configure a global theme for all the widgets at the top level with the ``theme`` configuration option. In the example below, all the ``arc``, ``slider`` -and ``btn`` widgets will use the styles and properties predefined here. +You can configure a global theme for all the widgets at the top level with the ``theme`` configuration option. In the example below, all the ``arc``, ``slider`` and ``btn`` widgets will use the styles and properties predefined by default here. A combination of styles and states can be chosen for every widget. .. code-block:: yaml @@ -150,7 +151,7 @@ and ``btn`` widgets will use the styles and properties predefined here. focused: border_color: 0x00FF00 -Naturally, you can override these at the indivdual configuration level of each widget. This can be done in batches, using ``style_definitions`` configuration option. +Naturally, you can override these at the indivdual configuration level of each widget. This can be done in batches, using ``style_definitions`` configuration option of the main component. In the example below, you defined ``date_style``: .. code-block:: yaml @@ -209,7 +210,7 @@ Style properties You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each object. Some widgets allow for more complex styling, effectively changing the appearance of their parts. -- **align** (*Optional*, string): Alignment of the of the widget `relative to the parent `__. One of: +- **align** (*Optional*, enum): Alignment of the of the widget `relative to the parent `__. One of: - ``TOP_LEFT`` - ``TOP_MID`` - ``TOP_RIGHT`` @@ -232,20 +233,20 @@ You can adjust the appearance of widgets by changing the foreground, background - ``OUT_BOTTOM_MID`` - ``OUT_BOTTOM_RIGHT`` - ``OUT_RIGHT_BOTTOM`` -- **bg_color** (*Optional*, :ref:`color `): The ID of a color for the background of the widget. -- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a color to make the background gradually fade to. -- **bg_dither_mode** (*Optional*, string): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. -- **bg_grad_dir** (*Optional*, string): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. +- **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background of the widget. +- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to make the background gradually fade to. +- **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. +- **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. - **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. - **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. -- **bg_img_opa** (*Optional*, string or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a color to mix with every pixel of the image. -- **bg_img_recolor_opa** (*Optional*, string or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **bg_opa** (*Optional*, string or percentage): Opacity of the background. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **opa** (*Optional*, string or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **opa_layered** (*Optional*, string or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **border_color** (*Optional*, :ref:`color `): The ID of a color to draw borders of the widget. -- **border_opa** (*Optional*, string or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **bg_img_opa** (*Optional*, enum or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to mix with every pixel of the image. +- **bg_img_recolor_opa** (*Optional*, enum or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **bg_opa** (*Optional*, enum or percentage): Opacity of the background. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **opa** (*Optional*, enum or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **opa_layered** (*Optional*, enum or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **border_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw borders of the widget. +- **border_opa** (*Optional*, enum or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. - **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. - **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be chosen): - ``NONE`` @@ -257,19 +258,12 @@ You can adjust the appearance of widgets by changing the foreground, background - **border_width** (*Optional*, int16): Set the width of the border in pixels. - **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height). - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. -- **text_align** (*Optional*, string): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` -- **text_color** (*Optional*, :ref:`color `): The ID of a color to render the text in. -- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) -- **text_font**: (*Optional*, :ref:`font `): The ID or the C array file of the font used to render the text. -- **text_letter_space** (*Optional*, int16): Characher spacing of the text. -- **text_line_space** (*Optional*, int16): Line spacing of the text. -- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. - **line_width** (*Optional*, int16): Set the width of the line in pixels. - **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). - **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). - **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **line_color** (*Optional*, :ref:`color `): The ID of a color for the line. -- **outline_color** (*Optional*, :ref:`color `): The ID of a color to draw an outline around the widget. +- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. +- **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw an outline around the widget. - **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. - **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. - **outline_width** (*Optional*, int16): Set the width of the outline in pixels. @@ -280,7 +274,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. - **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. - **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. -- **shadow_color** (*Optional*, :ref:`color `): The ID of a color to create a drop shadow under the widget. +- **shadow_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to create a drop shadow under the widget. - **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels - **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels - **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. @@ -297,6 +291,13 @@ You can adjust the appearance of widgets by changing the foreground, background - **min_height** (*Optional*, int16 or percentage): Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area. Defaults to ``0``. - **max_width** (*Optional*, int16 or percentage): Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. - **min_width** (*Optional*, int16 or percentage): Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0``. +- **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` +- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. +- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) +- **text_font**: (*Optional*, :ref:`font `): The ID or the C array file of the font used to render the text. +- **text_letter_space** (*Optional*, int16): Characher spacing of the text. +- **text_line_space** (*Optional*, int16): Line spacing of the text. +- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. .. _lvgl-widgets: @@ -314,6 +315,11 @@ The properties below are common to all widgets. - **width** (*Optional*): Width of the widget in pixels or a percentage, or ``size_content`` (see below). - **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents (children objects, or eg. image size in case of ``img``. - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. +- **styles** (*Optional*, :ref:`config-id`): The ID of a *style definition* from the main component configuration to override the theme styles. +- **theme** (*Optional*, list): A list of styles to apply to the widget and children. Same configuration option as at the main component. +- **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Same configuration option as at the main component. +- **flex_flow** (*Optional*, string): Option for ``FLEX`` layout, similar configuration as at the main component. +- **widgets** (*Optional*, list): A list of LVGL widgets to be drawn as children of this widget. Same configuration option as at the main component. - **state** (*Optional*, string): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden withing style definitions or locally set. The state itself can be can be changed by interacting with the widget itself, or :ref:`programatically ` with ``lvgl.obj.update`` action. Can be one of: - ``default``: Normal, released state - ``disabled``: Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.obj.enable`` and ``lvgl.obj.disable``) @@ -347,8 +353,8 @@ Specific configuration options: - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. -- **arc_opa** (*Optional*, string or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a color to use to draw the arcs. +- **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0`` and ``100`` for percentage. +- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of styles and state-based styles to customize. @@ -399,6 +405,12 @@ Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **indicator** (*Optional*, list): Settings for the indicator **part** +- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. +- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. +- **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. +- **animated** (*Optional*, boolean): ``true`` , ``false`` . TODO +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and additionally: + - **r_mod** (*Optional*): TODO in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the object based on its contents. Example: @@ -498,9 +510,72 @@ The drop-down list is closed by default and displays a single value or a predefi Specific configuration options: -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **indicator** (*Optional*, list): Settings for the indicator **part** - +- **selected** (*Optional*): +- **scrollbar** +- **selected_index** +- **dir** +- **dropdown_list** +- **symbol** (*Optional*, enum): A symbol (typically an arrow) can be added to the dropdown list. If the direction of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. One of: + - ``AUDIO`` + - ``VIDEO`` + - ``LIST`` + - ``OK`` + - ``CLOSE`` + - ``POWER`` + - ``SETTINGS`` + - ``HOME`` + - ``DOWNLOAD`` + - ``DRIVE`` + - ``REFRESH`` + - ``MUTE`` + - ``VOLUME_MID`` + - ``VOLUME_MAX`` + - ``IMAGE`` + - ``TINT`` + - ``PREV`` + - ``PLAY`` + - ``PAUSE`` + - ``STOP`` + - ``NEXT`` + - ``EJECT`` + - ``LEFT`` + - ``RIGHT`` + - ``PLUS`` + - ``MINUS`` + - ``EYE_OPEN`` + - ``EYE_CLOSE`` + - ``WARNING`` + - ``SHUFFLE`` + - ``UP`` + - ``DOWN`` + - ``LOOP`` + - ``DIRECTORY`` + - ``UPLOAD`` + - ``CALL`` + - ``CUT`` + - ``COPY`` + - ``SAVE`` + - ``BARS`` + - ``ENVELOPE`` + - ``CHARGE`` + - ``PASTE`` + - ``BELL`` + - ``KEYBOARD`` + - ``GPS`` + - ``FILE`` + - ``WIFI`` + - ``BATTERY_FULL`` + - ``BATTERY_3`` + - ``BATTERY_2`` + - ``BATTERY_1`` + - ``BATTERY_EMPTY`` + - ``USB`` + - ``BLUETOOTH`` + - ``TRASH`` + - ``EDIT`` + - ``BACKSPACE`` + - ``SD_CARD`` + - ``NEW_LINE`` Example: @@ -917,7 +992,7 @@ LVGL has a notion of screen inactivity, i.e. how long did the user not interact The ``on_idle`` :ref:`trigger ` is activated when inactivity time becomes longer than the specified ``timeout``. -- **timeout** (**Required**): :ref:`Time ` value after which LVGL should enter idle state. +- **timeout** (**Required**, :ref:`templatable `, int): :ref:`Time ` value after which LVGL should enter idle state. .. code-block:: yaml diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index d7688fe0c..115180569 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -20,8 +20,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the number. - **animated** (*Optional*, boolean): Wether to set the value of the widget with an animation. Defaults to ``true``. -- **arc_id** (*Optional*): The ID of an arc widget configured in LVGL. -- **slider_id** (*Optional*): The ID of a slider widget configured in LVGL. +- **obj** (*Optional*): The ID of a widget configured in LVGL, which will reflect the state of the switch. - All other options from :ref:`Number `. @@ -31,8 +30,7 @@ Example: number: - platform: lvgl - slider_id: lv_slider - id: lvgl_slider_sensor + obj: slider_id name: LVGL Slider @@ -42,4 +40,5 @@ See Also - :ref:`LVGL Main component ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` +- :doc:`/components/switch/lvgl` - :ghedit:`Edit` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 600b7b674..ccaef1a4a 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -19,8 +19,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. -- **arc_id** (*Optional*): The ID of an arc widget configured in LVGL. -- **slider_id** (*Optional*): The ID of a slider widget configured in LVGL. +- **obj** (*Optional*): The ID of a widget configured in LVGL, which will reflect the state of the switch. - All other options from :ref:`Sensor `. @@ -30,8 +29,7 @@ Example: sensor: - platform: lvgl - arc_id: arc_value - id: lvgl_arc_sensor + obj: arc_id name: LVGL Arc @@ -41,4 +39,5 @@ See Also - :ref:`LVGL Main component ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` - :ghedit:`Edit` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst new file mode 100644 index 000000000..a509e63ef --- /dev/null +++ b/components/switch/lvgl.rst @@ -0,0 +1,41 @@ +.. _lvgl-swi: + +LVGL Switch +=========== + +.. seo:: + :description: Instructions for setting up a LVGL widget switch. + :image: ../images/logo_lvgl.png + +The ``lvgl`` switch platform creates a switch from a LVGL widget +and requires :ref:`LVGL ` to be configured. + +Supported widgets are ``btn`` and ``checkbox``. A single switch supports +a single widget, thus you need to choose among which one's state you want to use. + + +Configuration variables: +------------------------ + +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. +- **name** (**Required**, string): The name of the switch. +- **obj** (*Optional*): The ID of a widget configured in LVGL, which will reflect the state of the switch. +- All other options from :ref:`Switch `. + + +Example: + +.. code-block:: yaml + + switch: + - platform: lvgl + obj: checkbox_id + name: LVGL switch + +See Also +-------- +- :ref:`LVGL Main component ` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/number/lvgl` +- :ghedit:`Edit` From 204a62b9d241a935f716d7ac8e3b1129aa664112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 13:19:26 +0100 Subject: [PATCH 050/350] Update lvgl.rst --- components/lvgl.rst | 66 +++------------------------------------------ 1 file changed, 4 insertions(+), 62 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b42d0a5bb..c30f331ef 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -438,7 +438,7 @@ Example: # Example widget: - -The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl`. +The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. ``btnmatrix`` @@ -515,67 +515,7 @@ Specific configuration options: - **selected_index** - **dir** - **dropdown_list** -- **symbol** (*Optional*, enum): A symbol (typically an arrow) can be added to the dropdown list. If the direction of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. One of: - - ``AUDIO`` - - ``VIDEO`` - - ``LIST`` - - ``OK`` - - ``CLOSE`` - - ``POWER`` - - ``SETTINGS`` - - ``HOME`` - - ``DOWNLOAD`` - - ``DRIVE`` - - ``REFRESH`` - - ``MUTE`` - - ``VOLUME_MID`` - - ``VOLUME_MAX`` - - ``IMAGE`` - - ``TINT`` - - ``PREV`` - - ``PLAY`` - - ``PAUSE`` - - ``STOP`` - - ``NEXT`` - - ``EJECT`` - - ``LEFT`` - - ``RIGHT`` - - ``PLUS`` - - ``MINUS`` - - ``EYE_OPEN`` - - ``EYE_CLOSE`` - - ``WARNING`` - - ``SHUFFLE`` - - ``UP`` - - ``DOWN`` - - ``LOOP`` - - ``DIRECTORY`` - - ``UPLOAD`` - - ``CALL`` - - ``CUT`` - - ``COPY`` - - ``SAVE`` - - ``BARS`` - - ``ENVELOPE`` - - ``CHARGE`` - - ``PASTE`` - - ``BELL`` - - ``KEYBOARD`` - - ``GPS`` - - ``FILE`` - - ``WIFI`` - - ``BATTERY_FULL`` - - ``BATTERY_3`` - - ``BATTERY_2`` - - ``BATTERY_1`` - - ``BATTERY_EMPTY`` - - ``USB`` - - ``BLUETOOTH`` - - ``TRASH`` - - ``EDIT`` - - ``BACKSPACE`` - - ``SD_CARD`` - - ``NEW_LINE`` +- **symbol** (*Optional*, enum): A symbol (typically an arrow) can be added to the dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. One of: ``AUDIO``, ``VIDEO``, ``LIST``, ``OK``, ``CLOSE``, ``POWER``, ``SETTINGS``, ``HOME``, ``DOWNLOAD``, ``DRIVE``, ``REFRESH``, ``MUTE``, ``VOLUME_MID``, ``VOLUME_MAX``, ``IMAGE``, ``TINT``, ``PREV``, ``PLAY``, ``PAUSE``, ``STOP``, ``NEXT``, ``EJECT``, ``LEFT``, ``RIGHT``, ``PLUS``, ``MINUS``, ``EYE_OPEN``, ``EYE_CLOSE``, ``WARNING``, ``SHUFFLE``, ``UP``, ``DOWN``, ``LOOP``, ``DIRECTORY``, ``UPLOAD``, ``CALL``, ``CUT``, ``COPY``, ``SAVE``, ``BARS``, ``ENVELOPE``, ``CHARGE``, ``PASTE``, ``BELL``, ``KEYBOARD``, ``GPS``, ``FILE``, ``WIFI``, ``BATTERY_FULL``, ``BATTERY_3``, ``BATTERY_2``, ``BATTERY_1``, ``BATTERY_EMPTY``, ``USB``, ``BLUETOOTH``, ``TRASH``, ``EDIT``, ``BACKSPACE``, ``SD_CARD``, ``NEW_LINE`` Example: @@ -738,6 +678,7 @@ Specific configuration options: - **indicator** (*Optional*, list): Settings for the indicator **part** - **knob** (*Optional*, list): Settings for the knob **part** +The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. Example: @@ -1023,6 +964,7 @@ See Also - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` +- :doc:`/components/switch/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` From 7195232cf4bbca0fcd2f81fa0e093dc06b25e4e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 14:58:57 +0100 Subject: [PATCH 051/350] Update lvgl.rst --- components/lvgl.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index c30f331ef..4031fd8d8 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -855,6 +855,26 @@ These :ref:`actions ` are shorthands for toggling the ``disabled` +.. _lvgl-rfrsh-act: + +``lvgl.obj.invalidate`` Action +------------------------------ + +This :ref:`action ` redraws the entire screen, or optionally only a widget on it. + +- **obj_id** (*Optional*): The ID of a widget configured in LVGL, which you want to redraw. + +obj_id + +.. code-block:: yaml + + on_...: + then: + - lvgl.obj.invalidate: + + + + .. _lvgl-pause-act: ``lvgl.pause`` Action @@ -883,6 +903,10 @@ This :ref:`action ` resumes the activity of LVGL, including rende - lvgl.resume + + + + .. _lvgl-idle-cond: ``lvgl.is_idle`` Condition From 97661846a7e2b88366974f0bc63f2a249215ac70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 15:12:19 +0100 Subject: [PATCH 052/350] screenshot --- components/images/lvgl_main_screenshot.png | Bin 0 -> 10549 bytes components/lvgl.rst | 9 ++++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 components/images/lvgl_main_screenshot.png diff --git a/components/images/lvgl_main_screenshot.png b/components/images/lvgl_main_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..c8428921f209cdee3ff8d32c98dff0d612e89fce GIT binary patch literal 10549 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 }!$OA}(QH_W0(yEZ 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 literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index 4031fd8d8..e28ed46f8 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -12,7 +12,7 @@ LVGL embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.9 `__. -.. figure:: /images/logo_lvgl.png +.. figure:: /components/images/lvgl_main_screenshot.png :align: center In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although @@ -87,8 +87,10 @@ Configuration variables: - ``ROW_WRAP_REVERSE`` to place the children in a row with wrapping but in reversed order - ``COLUMN_WRAP_REVERSE`` to place the children in a column with wrapping but in reversed order - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. +- **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to 1s. - All other options from :ref:`lvgl-styling`. + Example: .. code-block:: yaml @@ -564,6 +566,11 @@ Example: # Example widget: - +TODO + - lvgl.label.update: + id: day_label + text: !lambda |- + ``line`` From 7e54b49eae43f154b2d476f9b2bd7b808e5aba6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 15:51:55 +0100 Subject: [PATCH 053/350] Update lvgl.rst --- components/lvgl.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index e28ed46f8..de3a33427 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -566,10 +566,6 @@ Example: # Example widget: - -TODO - - lvgl.label.update: - id: day_label - text: !lambda |- From 1b13af69bdc95076e09d79594ff9e85eaf0a4426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 17:04:08 +0100 Subject: [PATCH 054/350] update pack --- components/binary_sensor/lvgl.rst | 1 + components/lvgl.rst | 48 +++++++++++++++++-------------- components/number/lvgl.rst | 1 + components/select/lvgl.rst | 42 +++++++++++++++++++++++++++ components/sensor/lvgl.rst | 1 + components/switch/lvgl.rst | 1 + index.rst | 1 + 7 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 components/select/lvgl.rst diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 65d68ee6c..e6b73691e 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -38,4 +38,5 @@ See Also - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/switch/lvgl` +- :doc:`/components/select/lvgl` - :ghedit:`Edit` diff --git a/components/lvgl.rst b/components/lvgl.rst index de3a33427..976d828f2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -29,26 +29,28 @@ list of available LVGL widgets in ESPHome. Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A screen is the *root* parent. + TODO - SCREEN/PAGE Widgets integrate in ESPHome also as components: -+-------------+------------------------+ -| LVGL Widget | ESPHome component type | -+=============+========================+ -| Checkbox | Binary Sensor | -+-------------+------------------------+ -| Button | Binary Sensor, Button | -+-------------+------------------------+ -| Slider | Sensor, Number | -+-------------+------------------------+ -| Arc | Sensor, Number | -+-------------+------------------------+ -| ??? | TODO | -+-------------+------------------------+ ++-------------+-------------------------------+ +| LVGL Widget | ESPHome component type | ++=============+===============================+ +| Checkbox | Binary Sensor, Switch | ++-------------+-------------------------------+ +| Button | Binary Sensor, Button, Switch | ++-------------+-------------------------------+ +| Slider | Sensor, Number | ++-------------+-------------------------------+ +| Arc | Sensor, Number | ++-------------+-------------------------------+ +| Dropdown | Select | ++-------------+-------------------------------+ +| Roller | Select | ++-------------+-------------------------------+ -These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the *See Also* -section at the bottom of this document. +These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the *See Also* section at the bottom of this document. Main Component -------------- @@ -411,9 +413,7 @@ Specific configuration options: - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **animated** (*Optional*, boolean): ``true`` , ``false`` . TODO -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and additionally: - - **r_mod** (*Optional*): TODO in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the object based on its contents. - +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Example: @@ -500,7 +500,7 @@ Example: # Example widget: - -The ``checkbox`` can be also integrated as :doc:`/components/binary_sensor/lvgl`. +The ``checkbox`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. ``dropdown`` @@ -510,15 +510,17 @@ The drop-down list allows the user to select one value from a list. The drop-down list is closed by default and displays a single value or a predefined text. When activated (by click on the drop-down list), a list is drawn from which the user may select one option. When the user selects a new value, the list is deleted from the screen. + Specific configuration options: - **selected** (*Optional*): - **scrollbar** - **selected_index** -- **dir** +- **dir** ``LEFT``, ``RIGHT``, ``BOTTOM``, ``TOP``, defaults to ``BOTTOM``. - **dropdown_list** - **symbol** (*Optional*, enum): A symbol (typically an arrow) can be added to the dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. One of: ``AUDIO``, ``VIDEO``, ``LIST``, ``OK``, ``CLOSE``, ``POWER``, ``SETTINGS``, ``HOME``, ``DOWNLOAD``, ``DRIVE``, ``REFRESH``, ``MUTE``, ``VOLUME_MID``, ``VOLUME_MAX``, ``IMAGE``, ``TINT``, ``PREV``, ``PLAY``, ``PAUSE``, ``STOP``, ``NEXT``, ``EJECT``, ``LEFT``, ``RIGHT``, ``PLUS``, ``MINUS``, ``EYE_OPEN``, ``EYE_CLOSE``, ``WARNING``, ``SHUFFLE``, ``UP``, ``DOWN``, ``LOOP``, ``DIRECTORY``, ``UPLOAD``, ``CALL``, ``CUT``, ``COPY``, ``SAVE``, ``BARS``, ``ENVELOPE``, ``CHARGE``, ``PASTE``, ``BELL``, ``KEYBOARD``, ``GPS``, ``FILE``, ``WIFI``, ``BATTERY_FULL``, ``BATTERY_3``, ``BATTERY_2``, ``BATTERY_1``, ``BATTERY_EMPTY``, ``USB``, ``BLUETOOTH``, ``TRASH``, ``EDIT``, ``BACKSPACE``, ``SD_CARD``, ``NEW_LINE`` + Example: .. code-block:: yaml @@ -526,6 +528,7 @@ Example: # Example widget: - +The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. ``img`` @@ -596,7 +599,8 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and additionally: + - **r_mod** (*Optional*): TODO in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the object based on its contents. Example: @@ -646,6 +650,7 @@ Example: # Example widget: - +The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. ``slider`` @@ -993,6 +998,7 @@ See Also - :doc:`/components/sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/number/lvgl` +- :doc:`/components/select/lvgl` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` - `LVGL 8.3 docs `__ diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 115180569..dc4fc0f62 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -41,4 +41,5 @@ See Also - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/switch/lvgl` +- :doc:`/components/select/lvgl` - :ghedit:`Edit` diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst new file mode 100644 index 000000000..9952817cb --- /dev/null +++ b/components/select/lvgl.rst @@ -0,0 +1,42 @@ +.. _lvgl-sel: + +LVGL Select +=========== + +.. seo:: + :description: Instructions for setting up a LVGL widget select. + :image: ../images/logo_lvgl.png + +The ``lvgl`` switch platform creates a select from a LVGL widget +and requires :ref:`LVGL ` to be configured. + +Supported widgets are ``dropdown`` and ``roller``. A single select supports +a single widget, thus you need to choose among which one's state you want to use. + + +Configuration variables: +------------------------ + +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. +- **name** (**Required**, string): The name of the select. +- **obj** (*Optional*): The ID of a widget configured in LVGL, which will reflect the state of the select. +- All other options from :ref:`Switch `. + + +Example: + +.. code-block:: yaml + + select: + - platform: lvgl + obj: dropdown_id + name: LVGL Dropdown + +See Also +-------- +- :ref:`LVGL Main component ` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/number/lvgl` +- :ghedit:`Edit` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index ccaef1a4a..7dc8112b8 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -40,4 +40,5 @@ See Also - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/switch/lvgl` +- :doc:`/components/select/lvgl` - :ghedit:`Edit` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index a509e63ef..6fa18f84e 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -38,4 +38,5 @@ See Also - :doc:`/components/sensor/lvgl` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/number/lvgl` +- :doc:`/components/select/lvgl` - :ghedit:`Edit` diff --git a/index.rst b/index.rst index d1fdadb15..ae06fd31a 100644 --- a/index.rst +++ b/index.rst @@ -615,6 +615,7 @@ Switch Components Modbus Switch, components/switch/modbus_controller, modbus.png BLE Client Switch, components/switch/ble_client, bluetooth.svg, dark-invert Nextion Switch, components/switch/nextion, nextion.jpg + LVGL widget, components/switch/lvgl, logo_lvgl.png Button Components ----------------- From dd899b8fd54cdad11911b69fcb956a24a51b3f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 17:15:11 +0100 Subject: [PATCH 055/350] add pictures --- components/images/lvgl_button.png | Bin 0 -> 439 bytes components/images/lvgl_dropdown.png | Bin 0 -> 2959 bytes components/images/lvgl_label.png | Bin 0 -> 1654 bytes components/images/lvgl_switch.png | Bin 0 -> 737 bytes components/lvgl.rst | 11 +++++++++++ 5 files changed, 11 insertions(+) create mode 100644 components/images/lvgl_button.png create mode 100644 components/images/lvgl_dropdown.png create mode 100644 components/images/lvgl_label.png create mode 100644 components/images/lvgl_switch.png diff --git a/components/images/lvgl_button.png b/components/images/lvgl_button.png new file mode 100644 index 0000000000000000000000000000000000000000..266c9deaab2a304d2da44a170f73e643fc844bb6 GIT binary patch literal 439 zcmV;o0Z9IdP)HXNx{uqaPtx-<5-$G>?=)ZLbXo44TREx36LZr*~M zx8UY2xOoe1-l)4L9GTRfmqgv8uJ5a;*1RO@9`~(;=lbeO!j1c$BNXaRVm%#f8bX(F z)4?W*HC?E>Rjh`}HG%$%9xA6|Mc1n5RRGMF$=Sa?@o=1 zkeny_#IxTXH%j{Mrz`mOUPOP}v=5DaZUFY%=AXIAjdPCKErifYt60fndMvnWue;&V h=dvvYH*alq{{R}cg&U6;4gUZD002ovPDHLkV1h}r)F}V} literal 0 HcmV?d00001 diff --git a/components/images/lvgl_dropdown.png b/components/images/lvgl_dropdown.png new file mode 100644 index 0000000000000000000000000000000000000000..191f0bdb53abff60b1af56628cf2dc5105f417a4 GIT binary patch literal 2959 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 Ac>n+a literal 0 HcmV?d00001 diff --git a/components/images/lvgl_switch.png b/components/images/lvgl_switch.png new file mode 100644 index 0000000000000000000000000000000000000000..9864b2b79bb7768789c766ac5f2c10deb94eace9 GIT binary patch literal 737 zcmV<70v`Q|P)4}07>3^*7Bi4QgcMG3#TF?HECf4?EwmEhiePDJy88)Q>QA^XmX?y@KvJ1v3%ejJ z#3IEOSFA-~0}3;RkSiwKox>a%~N#F znK;_>1NM7QW7)e^|J(RAf~kIu)xBNnd%XK$I*eQzi$l~sR7*HJfmeJni&J_3h}ja; z7|HtO%8svkLGjNQ3A?<%|4b*poJsQnx&hkdU0nn)TF5~NxdDLYSM}qYS$(Uw+fG*m zt{N!vJ<^&~%F7$vCBXKsoA<$KEFDU>eT*-7Mri;=&c_$L?E}CtV$)dCD~#UBO7?CQ zO>LK#?e1Zg?i7H^dGUN?$N{!U5AKK@A!!X z_EbwWu|wA(V$^$)lE9v`6Pnne>ku*O?dmNL`1=@tBf1U|quzOedh>#_`!Y`H!@>?- zhlo+{vf*98lKV%R*rDqXG3xCdlfa(Yk|uWOIz)_mS4+V-8pBjS}r%ZyrE%sE^i<= z5KMK>>FPCjizD8z(d(?aOVA5#THXt#9(npT!+3A-22l5S$9L0m0HX-4Yngq)q*Au7 z Date: Tue, 9 Jan 2024 17:18:31 +0100 Subject: [PATCH 056/350] Update lvgl.rst --- components/lvgl.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 3e49ce9f1..cadc01560 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -429,7 +429,7 @@ Example: Simple push or toggle button. .. figure:: /components/images/lvgl_button.png - :align: left + :align: center Specific configuration options: @@ -514,7 +514,7 @@ The drop-down list allows the user to select one value from a list. The drop-down list is closed by default and displays a single value or a predefined text. When activated (by click on the drop-down list), a list is drawn from which the user may select one option. When the user selects a new value, the list is deleted from the screen. .. figure:: /components/images/lvgl_dropdown.png - :align: left + :align: center Specific configuration options: @@ -561,7 +561,7 @@ Example: A label is the basic object type that is used to display text. .. figure:: /components/images/lvgl_label.png - :align: left + :align: center Specific configuration options: @@ -689,7 +689,7 @@ The ``slider`` can be also integrated as :doc:`/components/sensor/lvgl` and :doc The Switch looks like a little slider and can be used to turn something on and off. .. figure:: /components/images/lvgl_switch.png - :align: left + :align: center Specific configuration options: From d6f2b233c75b377c0bcfa3bdcfef1948fbf107bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 17:21:43 +0100 Subject: [PATCH 057/350] Update lvgl.rst --- components/lvgl.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index cadc01560..4c9f6dcf7 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -50,7 +50,8 @@ Widgets integrate in ESPHome also as components: | Roller | Select | +-------------+-------------------------------+ -These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the *See Also* section at the bottom of this document. +These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`` section at the bottom of this document. + Main Component -------------- @@ -1002,6 +1003,8 @@ LVLG supports numeric properties only as integer values with variable minimums a - ``uint16`` (unsigned) supports values ranging from 0 to 65535. +.. _lvgl-seealso: + See Also -------- From 646ab50e0587f235ee42b07e35ab92494050ecf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 9 Jan 2024 17:23:57 +0100 Subject: [PATCH 058/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4c9f6dcf7..dd20ab88d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -50,7 +50,7 @@ Widgets integrate in ESPHome also as components: | Roller | Select | +-------------+-------------------------------+ -These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`` section at the bottom of this document. +These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`lvgl-seealso` section at the bottom of this document. Main Component From 6852774a1dff7f9f37ee031584db7105eea14270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 10 Jan 2024 16:37:02 +0100 Subject: [PATCH 059/350] big addition pack --- components/binary_sensor/lvgl.rst | 3 +- components/display/index.rst | 6 + components/images/lvgl_symbols.png | Bin 0 -> 38208 bytes components/light/lvgl.rst | 44 +++++ components/lvgl.rst | 292 ++++++++++++++++++++--------- components/number/lvgl.rst | 3 +- components/select/lvgl.rst | 3 +- components/sensor/lvgl.rst | 3 +- components/switch/lvgl.rst | 3 +- index.rst | 1 + 10 files changed, 268 insertions(+), 90 deletions(-) create mode 100644 components/images/lvgl_symbols.png create mode 100644 components/light/lvgl.rst diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index e6b73691e..80543b22a 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -19,7 +19,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the binary sensor. -- **obj** (*Optional*): The ID of a button widget configured in LVGL. +- **obj** (**Required**): The ID of a button widget configured in LVGL. - All other options from :ref:`Binary Sensor `. @@ -39,4 +39,5 @@ See Also - :doc:`/components/number/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` - :ghedit:`Edit` diff --git a/components/display/index.rst b/components/display/index.rst index 8378efdda..8e5c3b018 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -628,6 +628,9 @@ And then later in code: - Axis labels are currently not possible without manually placing them. - The grid and border color is set with it.graph(), while the traces are defined separately. + +.. _display-qrcode: + QR Code Component ***************** @@ -664,6 +667,9 @@ To draw the QR-code, call the ``it.qr_code`` function from your render lambda: // Draw the QR-code at position [x=50,y=0] with white color and a 2x scale it.qr_code(50, 0, id(homepage_qr), Color(255,255,255), 2); + +.. _display-image: + Images ****** diff --git a/components/images/lvgl_symbols.png b/components/images/lvgl_symbols.png new file mode 100644 index 0000000000000000000000000000000000000000..6b9d14d8642dd0a30d4ec51bdb03b43f553d0847 GIT binary patch literal 38208 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�rqIG)qoz_`$^SBHI&#hi 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 literal 0 HcmV?d00001 diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst new file mode 100644 index 000000000..497cdd95f --- /dev/null +++ b/components/light/lvgl.rst @@ -0,0 +1,44 @@ +.. _lvgl-lgh: + +LVGL Light +========== + +.. seo:: + :description: Instructions for setting up a LVGL widget light. + :image: ../images/logo_lvgl.png + +The ``lvgl`` light platform creates a light from a LVGL widget +and requires :ref:`LVGL ` to be configured. + +Supported widgets are ``led``. A single light supports +a single widget, thus you need to choose among which one's state you want to use. + + +Configuration variables: +------------------------ + +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. +- **name** (**Required**, string): The name of the light. +- **led** (**Required**): The ID of a ``led`` widget configured in LVGL, which will reflect the state of the light. +- **output_id** (**Required**): TODO +- All other options from :ref:`light `. + + +Example: + +.. code-block:: yaml + + light: + - platform: lvgl + led: led_id + name: LVGL light + +See Also +-------- +- :ref:`LVGL Main component ` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/select/lvgl` +- :ghedit:`Edit` diff --git a/components/lvgl.rst b/components/lvgl.rst index dd20ab88d..49eb0068f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -30,7 +30,7 @@ Every widget has a parent object where it is created. For example, if a label is The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A screen is the *root* parent. -TODO - SCREEN/PAGE +TODO - PAGE Widgets integrate in ESPHome also as components: @@ -49,6 +49,8 @@ Widgets integrate in ESPHome also as components: +-------------+-------------------------------+ | Roller | Select | +-------------+-------------------------------+ +| LED | Light | ++-------------+-------------------------------+ These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`lvgl-seealso` section at the bottom of this document. @@ -238,6 +240,7 @@ You can adjust the appearance of widgets by changing the foreground, background - ``OUT_BOTTOM_MID`` - ``OUT_BOTTOM_RIGHT`` - ``OUT_RIGHT_BOTTOM`` +- **anim_time** TODO !! - **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background of the widget. - **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to make the background gradually fade to. - **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. @@ -362,9 +365,13 @@ Specific configuration options: - **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. -- **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of styles and state-based styles to customize. -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. -- any :ref:`Styling ` and state-based option to override styles inherited from parent. +- **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws a handle on the end of the indicator using all background properties and padding values. With zero padding the knob size is the same as the indicator's width. Larger padding makes it larger, smaller padding makes it smaller. +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws another arc using the arc style properties. Its padding values are interpreted relative to the background arc. +- any :ref:`Styling ` and state-based option to override styles inherited from parent. The arc's size and position will respect the padding style properties. + + +If the ``adv_hittest`` flag is enabled the arc can be clicked through in the middle. Clicks are recognized only on the ring of the background arc. + .. note:: @@ -376,25 +383,15 @@ Example: # Example widget: - arc: - group: general - scroll_on_focus: true - id: arc_value + x: 10 + y: 10 + id: arc_id value: 75 min_value: 1 max_value: 100 - arc_color: 0xFF0000 - indicator: - arc_color: 0xF000FF - pressed: - arc_color: 0xFFFF00 - focused: - arc_color: 0x808080 - knob: - focused: - bg_color: 0x808080 + adjustable: true - -The ``arc`` can be also integrated as :doc:`/components/sensor/lvgl` and :doc:`/components/number/lvgl`. +The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. ``bar`` @@ -409,40 +406,75 @@ Not only the end, but also the start value of the bar can be set, which changes Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **indicator** (*Optional*, list): Settings for the indicator **part** - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. -- **animated** (*Optional*, boolean): ``true`` , ``false`` . TODO -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, all the typical background properties. +- **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. +- Style options from :ref:`lvgl-styling`. The background of the bar and it uses the typical background style properties. Adding padding makes the indicator smaller or larger. Example: .. code-block:: yaml # Example widget: - - + - bar: + x: 10 + y: 100 + id: bar_id + value: 75 + min_value: 1 + max_value: 100 + + +The ``bar`` can be also integrated as :doc:`/components/number/lvgl`. ``btn`` ******* -Simple push or toggle button. +Simple push or toggle button. .. figure:: /components/images/lvgl_button.png :align: center Specific configuration options: -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - +- **checkable** (*Optional*, boolean): A significant flag to make a toggle button (which remains pressed in ``checked`` state). Defaults to ``false``. +- Style options from :ref:`lvgl-styling` for the background of the button. Uses the typical background style properties. Example: .. code-block:: yaml # Example widget: - - + - btn: + x: 10 + y: 10 + width: 50 + height: 30 + id: btn_id + + +To have a button with a text label on it, add a ``label`` widget as child to it: + +.. code-block:: yaml + + # Example toggle button with text: + - btn: + x: 10 + y: 10 + width: 70 + height: 30 + id: btn_id + checkable: true + widgets: + - label: + align: center + text: "Light" + + +A notable state is ``checked`` (boolean) which can have different styles applied. The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. @@ -454,8 +486,8 @@ The Button Matrix object is a lightweight way to display multiple buttons in row Specific configuration options: -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **items** (*Optional*, list): Settings for the items **part** +- **items** (*Optional*, list): Settings for the items **part**, the buttons all use the text and typical background style properties except translations and transformations. +- Style options from :ref:`lvgl-styling` for the background of the button matrix, uses the typical background style properties. ``pad_row`` and ``pad_column`` set the space between the buttons. Example: @@ -464,7 +496,16 @@ Example: # Example widget: - - + - btnmatrix: + x: 10 + y: 100 + items: + rows: + - buttons: + text: "a" + text: "b" + width: 50 + - control: "\n" ``canvas`` @@ -475,6 +516,7 @@ A Canvas inherits from Image where the user can draw anything. Rectangles, texts Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- Style options from :ref:`lvgl-styling`. Example: @@ -489,12 +531,12 @@ Example: ``checkbox`` ************ -The Checkbox object is made from a "tick box" and a label. When the Checkbox is clicked the tick box is toggled. +The Checkbox object is made internally from a "tick box" and a label. When the Checkbox is clicked the tick box is ``checked`` state toggled. Specific configuration options: -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **indicator** (*Optional*, list): Settings for the indicator **part** +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The "tick box" is a square that uses all the typical background style properties. By default, its size is equal to the height of the main part's font. Padding properties make the tick box larger in the respective directions. +- Style options from :ref:`lvgl-styling` for the background of the widget and it uses the text and all the typical background style properties. ``pad_column`` adjusts the spacing between the tickbox and the label. Example: @@ -502,9 +544,14 @@ Example: .. code-block:: yaml # Example widget: - - + - checkbox: + x: 10 + y: 10 + id: checkbox_id + text: Checkbox + +The ``checkbox`` can be also integrated as a :doc:`/components/switch/lvgl`. -The ``checkbox`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. ``dropdown`` @@ -517,14 +564,17 @@ The drop-down list is closed by default and displays a single value or a predefi .. figure:: /components/images/lvgl_dropdown.png :align: center +The Dropdown widget is built internall from a *button* and a *list* (both not related to the actual widgets with the same name). + Specific configuration options: -- **selected** (*Optional*): -- **scrollbar** -- **selected_index** -- **dir** ``LEFT``, ``RIGHT``, ``BOTTOM``, ``TOP``, defaults to ``BOTTOM``. -- **dropdown_list** -- **symbol** (*Optional*, enum): A symbol (typically an arrow) can be added to the dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. One of: ``AUDIO``, ``VIDEO``, ``LIST``, ``OK``, ``CLOSE``, ``POWER``, ``SETTINGS``, ``HOME``, ``DOWNLOAD``, ``DRIVE``, ``REFRESH``, ``MUTE``, ``VOLUME_MID``, ``VOLUME_MAX``, ``IMAGE``, ``TINT``, ``PREV``, ``PLAY``, ``PAUSE``, ``STOP``, ``NEXT``, ``EJECT``, ``LEFT``, ``RIGHT``, ``PLUS``, ``MINUS``, ``EYE_OPEN``, ``EYE_CLOSE``, ``WARNING``, ``SHUFFLE``, ``UP``, ``DOWN``, ``LOOP``, ``DIRECTORY``, ``UPLOAD``, ``CALL``, ``CUT``, ``COPY``, ``SAVE``, ``BARS``, ``ENVELOPE``, ``CHARGE``, ``PASTE``, ``BELL``, ``KEYBOARD``, ``GPS``, ``FILE``, ``WIFI``, ``BATTERY_FULL``, ``BATTERY_3``, ``BATTERY_2``, ``BATTERY_1``, ``BATTERY_EMPTY``, ``USB``, ``BLUETOOTH``, ``TRASH``, ``EDIT``, ``BACKSPACE``, ``SD_CARD``, ``NEW_LINE`` +- **options** (*Required*, list): The list of available options in the drop-down. +- **dir** (*Optional*, enum): Where the list part of the dropdown gets created relative to the button part. ``LEFT``, ``RIGHT``, ``BOTTOM``, ``TOP``, defaults to ``BOTTOM``. +- **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Refers to the currently pressed, checked or pressed+checked option. Uses the typical background properties. +- **scrollbar** (*Optional*, list): Settings for the scrollbar **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar background, border, shadow properties and width (for its own width) and right padding for the spacing on the right. +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and is the parent of ``symbol``. +- **symbol** (*Optional*, enum): A symbol (typically an chevron) is shown in dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. Choose a different :ref:`symbol ` from the built-in ones. +- Style options from :ref:`lvgl-styling` for the background of the button and the list. Uses the typical background properties and text properties for the text on it. ``max_height`` can be used to limit the height of the list. Example: @@ -533,6 +583,15 @@ Example: # Example widget: - + - dropdown: + x: 10 + y: 60 + width: 90 + id: dropdown_id + options: + - Violin + - Piano + - Bassoon The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. @@ -540,11 +599,13 @@ The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. ``img`` ******* -Images are the basic widgets to display images. +Images are the basic widgets to display images. Specific configuration options: -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **src** (**Required**, :ref:`image `): The ID of an existing image configuration. +- Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. + Example: @@ -552,8 +613,11 @@ Example: .. code-block:: yaml # Example widget: - - - + - img: + x: 10 + y: 10 + src: cat_image + id: img_id ``label`` @@ -566,18 +630,27 @@ A label is the basic object type that is used to display text. Specific configuration options: -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **scrollbar** (*Optional*, list): Settings for the scrollbar **part** -- **selected** (*Optional*, list): Settings for the selected **part** +- **text** (*Required*, string): The text to display. To display an empty string, specify ``''``- +- **scrollbar** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar that is shown when the text is larger than the widget's size. +- **selected** (*Optional*, list): Tells the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. +- Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. +Newline characters are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``line1\nline2\n\nline4``. + +It's possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #ff0000 red# word``. + +By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Example: .. code-block:: yaml # Example widget: - - - + - label: + x: 15 + y: 235 + id: lbl_id + text: 'Wi-Fi signal:' @@ -588,7 +661,29 @@ The Line object is capable of drawing straight lines between a set of points. Specific configuration options: - - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **points** (*Required*, list): TODO +- Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. + +By default, the Line's width and height are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts on the line may not be visible. + +Example: + +.. code-block:: yaml + + # Example widget: + - + + +``led`` +******** + +The LEDs are rectangle-like (or circle) object whose brightness can be adjusted. With lower brightness the colors of the LED become darker. + +Specific configuration options: + +- **color** (*Required*, list): TODO +- **brightness** (*Required*, list): TODO +- Style options from :ref:`lvgl-styling`, using all the typical background style properties. Example: @@ -599,6 +694,8 @@ Example: - +The ``led`` can be also integrated as :doc:`/components/light/lvgl`. + ``meter`` ********* @@ -607,29 +704,13 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee Specific configuration options: -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +TODO !!! + +- **scales** (*Required*, list): TODO +- **ticks** (*Required*, list): TODO - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and additionally: - **r_mod** (*Optional*): TODO in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the object based on its contents. - -Example: - -.. code-block:: yaml - - # Example widget: - - - - -``obj`` -******* - -The Base Object can be directly used as a simple, empty widget. It is nothing more than a (rounded) rectangle. - -You can use it as a parent background shape for other objects. It catches touches! - -Specific configuration options: - -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - +- Style options from :ref:`lvgl-styling`. Example: @@ -648,8 +729,11 @@ Roller allows you to simply select one option from a list by scrolling. Specific configuration options: -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **selected** (*Optional*, list): Settings for the selected **part** +- **options** (*Required*, list): The list of available options in the roller. +- **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. +- **visible_rows** TODO +- **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the text style properties to change the appearance of the text in the selected area. +- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and text style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. Example: @@ -670,9 +754,13 @@ The Slider object looks like a Bar supplemented with a knob. The knob can be dra Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **indicator** (*Optional*, list): Settings for the indicator **part** -- **knob** (*Optional*, list): Settings for the knob **part** +- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. +- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. +- **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. A rectangle (or circle) drawn at the current value. Also uses all the typical background properties to describe the knob. By default, the knob is square (with an optional corner radius) with side length equal to the smaller side of the slider. The knob can be made larger with the padding values. Padding values can be asymmetric too. +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The indicator that shows the current state of the slider. Also uses all the typical background style properties. +- any :ref:`Styling ` and state-based option for the background of the slider. Uses all the typical background style properties. Padding makes the indicator smaller in the respective direction. +Normally, the slider can be adjusted either by dragging the knob, or by clicking on the slider bar. In the latter case the knob moves to the point clicked and slider value changes accordingly. In some cases it is desirable to set the slider to react on dragging the knob only. This feature is enabled by enabling the ``adv_hittest`` flag. Example: @@ -681,7 +769,7 @@ Example: # Example widget: - -The ``slider`` can be also integrated as :doc:`/components/sensor/lvgl` and :doc:`/components/number/lvgl`. +The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. ``switch`` @@ -694,19 +782,24 @@ The Switch looks like a little slider and can be used to turn something on and o Specific configuration options: -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **indicator** (*Optional*, list): Settings for the indicator **part** -- **knob** (*Optional*, list): Settings for the knob **part** - -The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. +- **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. +- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. +- Style options from :ref:`lvgl-styling`. Example: .. code-block:: yaml # Example widget: - - + - switch: + x: 10 + y: 10 + id: switch_id + indicator: + knob + +The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. ``table`` @@ -720,6 +813,7 @@ Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **items** (*Optional*, list): Settings for the items **part** +- Style options from :ref:`lvgl-styling`. Example: @@ -745,6 +839,7 @@ Specific configuration options: - **selected** (*Optional*, list): Settings for the selected **part** - **cursor** (*Optional*, list): Settings for the cursor **part** - **textarea_placeholder** (*Optional*, list): Settings for the textarea_placeholder **part** +- Style options from :ref:`lvgl-styling`. Example: @@ -754,6 +849,31 @@ Example: - +``obj`` +******* + +The Base Object can be directly used as a simple, empty widget. It is nothing more than a (rounded) rectangle. + +You can use it as a parent background shape for other objects. It catches touches! + +Specific configuration options: + +- Style options from :ref:`lvgl-styling`. + + +Example: + +.. code-block:: yaml + + # Example widget: + - obj: + x: 10 + y: 10 + width: 220 + height: 300 + widgets: + - ... + .. _lvgl-fonts: @@ -776,8 +896,10 @@ These may not contain all the glyphs corresponding to certain diacritic characte In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. +In addition to the built-in fonts, the following symbols are also available from the `FontAwesome `__ font. You can use them on supported widgets using the ``symbol`` configuration option: - +.. figure:: /components/images/lvgl_symbols.png + :align: center .. _lvgl-objupd-act: @@ -1009,10 +1131,10 @@ See Also -------- - :doc:`/components/binary_sensor/lvgl` -- :doc:`/components/sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` - `LVGL 8.3 docs `__ diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index dc4fc0f62..aa25cf54e 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -20,7 +20,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the number. - **animated** (*Optional*, boolean): Wether to set the value of the widget with an animation. Defaults to ``true``. -- **obj** (*Optional*): The ID of a widget configured in LVGL, which will reflect the state of the switch. +- **obj** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. - All other options from :ref:`Number `. @@ -42,4 +42,5 @@ See Also - :doc:`/components/sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` - :ghedit:`Edit` diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 9952817cb..c5015babf 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -19,7 +19,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the select. -- **obj** (*Optional*): The ID of a widget configured in LVGL, which will reflect the state of the select. +- **obj** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the select. - All other options from :ref:`Switch `. @@ -39,4 +39,5 @@ See Also - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/number/lvgl` +- :doc:`/components/light/lvgl` - :ghedit:`Edit` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 7dc8112b8..099a171cd 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -19,7 +19,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. -- **obj** (*Optional*): The ID of a widget configured in LVGL, which will reflect the state of the switch. +- **obj** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. - All other options from :ref:`Sensor `. @@ -41,4 +41,5 @@ See Also - :doc:`/components/number/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` - :ghedit:`Edit` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 6fa18f84e..766e2577b 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -19,7 +19,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the switch. -- **obj** (*Optional*): The ID of a widget configured in LVGL, which will reflect the state of the switch. +- **obj** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. - All other options from :ref:`Switch `. @@ -39,4 +39,5 @@ See Also - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` - :ghedit:`Edit` diff --git a/index.rst b/index.rst index ae06fd31a..807a5e241 100644 --- a/index.rst +++ b/index.rst @@ -592,6 +592,7 @@ Light Components H-bridge Light, components/light/hbridge, brightness-medium.svg, dark-invert Sonoff D1 Dimmer, components/light/sonoff_d1, sonoff_d1.jpg + LVGL widget, components/light/lvgl, logo_lvgl.png Looking for WS2811 and similar individually addressable lights? Have a look at the :doc:`FastLED Light `. From a8f6fb989c442116f015eb16bda694303b81603c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 10 Jan 2024 16:43:09 +0100 Subject: [PATCH 060/350] align image --- components/images/lvgl_align.png | Bin 0 -> 10700 bytes components/lvgl.rst | 26 ++++---------------------- 2 files changed, 4 insertions(+), 22 deletions(-) create mode 100644 components/images/lvgl_align.png diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png new file mode 100644 index 0000000000000000000000000000000000000000..f5269fed16115e7b103a332ac8626aa622f7020a GIT binary patch literal 10700 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 literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index 49eb0068f..622bfe542 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -218,28 +218,10 @@ Style properties You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each object. Some widgets allow for more complex styling, effectively changing the appearance of their parts. - **align** (*Optional*, enum): Alignment of the of the widget `relative to the parent `__. One of: - - ``TOP_LEFT`` - - ``TOP_MID`` - - ``TOP_RIGHT`` - - ``LEFT_MID`` - - ``CENTER`` - - ``RIGHT_MID`` - - ``BOTTOM_LEFT`` - - ``BOTTOM_MID`` - - ``BOTTOM_RIGHT`` - - ``OUT_LEFT_TOP`` - - ``OUT_TOP_LEFT`` - - ``OUT_TOP_MID`` - - ``OUT_TOP_RIGHT`` - - ``OUT_RIGHT_TOP`` - - ``OUT_LEFT_MID`` - - ``OUT_CENTER`` - - ``OUT_RIGHT_MID`` - - ``OUT_LEFT_BOTTOM`` - - ``OUT_BOTTOM_LEFT`` - - ``OUT_BOTTOM_MID`` - - ``OUT_BOTTOM_RIGHT`` - - ``OUT_RIGHT_BOTTOM`` + +.. figure:: /components/images/lvgl_align.png + :align: center + - **anim_time** TODO !! - **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background of the widget. - **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to make the background gradually fade to. From 8cd14bb84713281d977988ab2f93aca16d4a1818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 10 Jan 2024 19:22:51 +0100 Subject: [PATCH 061/350] add some images --- components/images/lvgl_arc.png | Bin 0 -> 2738 bytes components/images/lvgl_bar.png | Bin 0 -> 374 bytes components/images/lvgl_button.png | Bin 439 -> 1049 bytes components/images/lvgl_checkbox.png | Bin 0 -> 1420 bytes components/lvgl.rst | 9 +++++++++ 5 files changed, 9 insertions(+) create mode 100644 components/images/lvgl_arc.png create mode 100644 components/images/lvgl_bar.png create mode 100644 components/images/lvgl_checkbox.png diff --git a/components/images/lvgl_arc.png b/components/images/lvgl_arc.png new file mode 100644 index 0000000000000000000000000000000000000000..d2114ce262c51fe7573427c2a12a4a0bc03d9dc1 GIT binary patch literal 2738 zcmV;j3QhHiP)!C*laBD03Em_Td@#F`0Aw9LVi-NQP|9^#{YTi+%*C3ExM z;-hj{#+gf;9EK=?$vT069hku$5J-Uy$lya86ljACRbYenpp2p^_n%j-maLZQJH9Aw zyT7jYURAZaFPxs9LK74IAO|#kjJ6dgw5>RyZN&*g4)i^hIzKo<^*}f$sD6Mr0f3!4 zlRpOl$fX4UW*|F?l!5FR8%tm^ZOWgE2^admC#=+Y^#I!kqIT$MMU`AyWRjQ}W7)Ad z$?IQR8)d$IAa-ojj-oN-MJ6F~7G}oS&8dFZ)_1lx%6xNAyt2Vhx-01{rXl7mG$_!C9|uZPxhOFMXQ#DCE*&>2sFPoKJ4-oh`e; z@4ptM{kVE+r!X$=Tw~TqubuVC)<&7%-4^}O??r`ah)s^3~MfA3I_W8;y(cxvAON+wAZb>>zQ(NhM zr)&I~gjk(px$$oO&Jo+%+2{Xw-cg|{jEki!=e9sssq?kB9ZfS#LwtXuTf(BW)k&Lf z8e$=fZ!Vpir*zYXU-p1kOAoZXobkuOt4W2?C9 z{QKuHS7I(LzP-||yb%dI`~17NVLB$$5dXRy@w#FJwl>Oq<&7K+#5Bax6qaV9{A0Su z+P1S+4s$uKUPXi{u~S>&+KOCS+`HCysn4HEo!@<}JjkMLIy$lyPE~Ivl3gOils`gY z;ceLse(R~)ysDRrG~FY_a#|)K*5@ObJBGjebNPjus!T#Wo{zmM0Qrphc%EevLjDJD zYDaAOg~I2(2x;s78%HUF=h9+*K4yi=hsm_LKF^xBmJ->iv-@uxIjTsQOt@L&i_hht z4~22D_H|qfl|M^AI!Y6=;th0?U6gIv4gSRs3R!#B66^DWsjA7Xrw)Bl*fhj{{~o@8 zDQCi!mkO#1;{&b=!1{cuFiuU0{DiH%q<;7;YPL4YoPHhU(gT|SCDy)9(QDY2%{Izh zj?z%bgi1Lus-872sLp3BhOCAB1PT*KnbfnSV2fT+O+!2$pbn5orOyBQlzKI{Fb&+E z#>!>VxuV)q>H|CMeBz7JS!!o8iDwJJXN+36)_$Sp<;5v6oT>oiGv?wH^+dH(ImGOL zf{Pi+R&kd)7tW<)yapHvcdjaQ9PQXg_{*aJVMJSU#1+#J_pXto4mR1*kSC#Xh}EC{ zgaz9w?mEPK@Rp`rZt5F09L}HoPY%*~xC@7S3ZvMPBd+AqA}(8tU8S@Kej*3y@Dr5w zcTN`Cg99Z98A$@G%+1!&Os`wlsz}BO8q=H!(7m@6?4FJ`;98tyR2!6IIbxvso zO+zf{f%O~qksMLQ=Lmkb9{x%iSPNO*T=WP(Tcw&Dapjv!dSLYkPg@&hPFeCQj0-)m z+OZOHL=~SSc-q?BBc(xIu_Ur-IiiZs5j<_ZvgOEGa%nxVWbzYoL=~SSxZ9$p!HaT4 zQ<#9+!Gq~c1BD4W*uve`_5mpk7A^)G9X3*?d3#z8(z!kDw>jxlU_B?7EGVk&J~M^^*OV@S0nDIpYXQC4!Z$>7gunxstgRu;Fi z;0+ue1`P$@y)iixR_cCLuEp$x9MJ?ryTW}M4cS)nQ9J%vOc$*%n17_5H1FXh+o}>; z3~NM=XsEbU9vPp~CEIem#kQCplOq};jM1{82ePf|2Pxn}ig1BwLgUlK%eI;?n((Lj zkU32VNMp-efox0D&&akYldUnu6)?>wC`BaNv88t)Lql!iJqTkwkY4iq^#3x-0_}EeZqTACfm~VGqNq_Ew%+^S4HEB&u+*k zycNi{vZGSK1O)5QFcRiX}7Rx&O#bn-pIBnyCHT%j%cV5(vr`vifoIr zzHSRhZAc1?w#IbTg3JCtvxxS35J#heb(t^TcAz3s)xa!(Mb4g;eWz=V8PW^ zhH&@xChaT9nsz8HhELIgtF0MAqftB3rArNd%tDu_Cr%D0#EQid!2=8a zwr+n$I>e)@zOTj|e$0DkYcg$8R(Sad)78rrV#Nxa6u0oR1z>^pq{z}f+u7H{>vwQY ztyswfVI3Vnpskxzro~7<@;g1eeoyej7Jh@$Uo;7@1z?f(M6jJYTifpRy@&&Y<2aN# z767L5klJP5W0^6=s(?CxvoZ#lpmexT++rGW*qE$Vx3 zB6&}2tfA*X7-|CxL|XusKBry<#WLHh4QW2)TpwXi7QM^LNpgGlxQh`hA&qw z!rQV&%+)!Cj$@b!-LgxBw*??KZhn7*1=d-5&WscjnDe!)Za4Sq+bZQI0>Wx&&djl+!5R22DR@c5IHInilUa54He|rSB06hDfd&iMU zi1qn^t1s>(N0aWt3?#=Q=q%c~aC&+w$HG$FbxQ9)c7VCGC|twX0ssI2fP6HM0003!NklZC#3+I%5K^YS~X8W40yibF*ReF zHlCq3oob$h-5&2-9#eAwy1wW2HzVlfiWl+fW6Mi|c6(lk5w!jVPRIJ2mjoSnU`Eg) zc~Q{fiV^hvB`@MtQ}L1@^VOme^xXw7;#FJolAsuPAx6+=i}LoINAV|y)bE7=3fT8T zBWM6m*J|3iHq)$07*qoM6N<$g3UFf+W-In literal 0 HcmV?d00001 diff --git a/components/images/lvgl_button.png b/components/images/lvgl_button.png index 266c9deaab2a304d2da44a170f73e643fc844bb6..38ecdd4229fc39accb0b39cc2b1f29298fda896f 100644 GIT binary patch literal 1049 zcmV+!1m^pRP)h+G7A8@#iud2JYVnu$n=>jd4&v?*G{*RAlI9%o z+>

(Y*?&!PkR?#qd0b>?y%Idzeu_w3BZSmthd;AY5m7mew7u9|-T#B)af2M5|>n ze7e;tjO}yKMLM+5$@f0RYPeQQ4HT<&@1JY%5kS;r>n8VZ+zUWE&Gld{s zHf216<=cD_fZ4z=udl048P8zhI$!id)ALwKGsfrnN=T3{JEoX}*>H{CO`~uY8e_}r zG`)nUm+@o?vo&}Acm`ub&=_0LY4RhCIsnXG!?}J2K)(+F$!8vW|4xxEeKBbtjrBPgZ4FC@+D5NQS5)Udc1s!5Ym)(=-Lw=AI zDpb}1U~vtGMKifwC#5D){>{H}&A{9kOZ1UZhf#-R0}%OhjqH88C*2PKj!1`{V~2&G z?%2_m)ZB_#q|2aD_w7|EU3SmPIsoKTZe`~`TZpT^S7yg*R2N1zqG}5HTYI2q1f4eYvhEf#*jRn)Q)@Hcc;)Fs#R+%mNH#S z5Q1KjD7N#R8cMNad_U;n5?eaAKiZAp;;h8n2Q5mZL(ennhj#Mq?Gga}A#1}jEz`E` zfL$tzqN$o1SNBHGCq2xlAKJ`!QHXNx{uqaPtx-<5-$G>?=)ZLbXo44TREx36LZr*~M zx8UY2xOoe1-l)4L9GTRfmqgv8uJ5a;*1RO@9`~(;=lbeO!j1c$BNXaRVm%#f8bX(F z)4?W*HC?E>Rjh`}HG%$%9xA6|Mc1n5RRGMF$=Sa?@o=1 zkeny_#IxTXH%j{Mrz`mOUPOP}v=5DaZUFY%=AXIAjdPCKErifYt60fndMvnWue;&V h=dvvYH*alq{{R}cg&U6;4gUZD002ovPDHLkV1h}r)F}V} diff --git a/components/images/lvgl_checkbox.png b/components/images/lvgl_checkbox.png new file mode 100644 index 0000000000000000000000000000000000000000..31b63cc7f5eeecdcfb2f5b39df9a530a6e7496b1 GIT binary patch literal 1420 zcmV;71#|j|P)byW|fOd1}$n`~N-W0kQSD##-#3YSbUUc{2 z2zTG#@A(D3d7j@rciFYMxd|F=;T2NQ_|MS1ZXcT0?L+greRPmQHH1uYb_t3br2ZnP z4j8q7yO$yZ|8I8H-G>O7qL?AYMsW3Nc9&7Vhs-XKN`o{#aHmq=>&9CLLDK_wD)qf? z9I69YM2bzokMJ(1i&S5N8U<^FT29NnraB<;5r{U*-AjgEgcue%8;1}=2=OC)GL42!Y(n0?TWbG&}9x!bHv`P}22YIG^Y**Ib~h+)ynSP?>2 z#v1)0stzg0vdq~y&c>-lb;0bttU6S+U^10N2;odIESkH`vMiT|Rbv}o8#*C51a?!I zNEpri2u})S36;pQEGfw+ameL#NpZ>J z_r&I7Odm5gI)?3bpLYuZfj_}VW+Ut%JNeZl@k_|EJnR?-fW$%qi_(Im6pYM9^snpf zAK0;pl?BDH2mk~91NI^N_^0Clkb9gH0z&B95KYs#W_32}VHDSuV9%r4WotxDPhQyH3XvCMyQRdv2=af$@)?gd+ zT6(y3GRaV5mS$#jS$hT}Zud)(UIG zj^X78%dXQdVgmN}^{W+jkWDS7pjtu4kOKhltPgz`id~BVfZ!K!P7NA*MpqCr08n)G zQUEZ?P_Dy8nrg;q%V7%uq*G}$vW*?0Tqt$Jgp|;C>Q%w|q!-hME`znt>I?YTLAL&S zuf|$ot?crjHAR$Vxsig~nAZRxWI)UmmGkC|1^}9-SsUvM_=r0maZ{>F&*2^bkm3^k z8~{*0m5_QTqpol0G9;u#C>YXr>Xnv_NiC+-w>2p)DXXfopcI$j`8tzjdHl?{d%|t8 zSjN8?$2m24_0pwFq*hKaQ}+Cq{tI-lapVmhG+^}EUL7d`0D#qMP5qn_0>bLk)n|V` zyZ7t8nVA`%$G7k8edhhlgWe-QbNH%P`6uGC={aCqGvxpd+^XfgwWiLIrJ8?e`u#D%JQB?ye#T=>yGpu z0f4z1bGe7P`Jd+Xd-eB!zwh(;vf1qPH`9i_hRTBCWzjw1RtBE>?3BS^nD$Q(yg%Uk z+6MrNUW0A)5R8xkd85c506t#J=o-*8omfbSVKI6&seDt0@KGRGt@q0*LUhKp1)Wu6wL?B zvH2L@5mgrCM|c1b!{XA?((PNf0f44ykKf}yi28V{sU_f4SB8666*I5jaH#~-99w0+lS_L a`}h~hYBww` and state-based styles to customize. The "tick box" is a square that uses all the typical background style properties. By default, its size is equal to the height of the main part's font. Padding properties make the tick box larger in the respective directions. From 57e1103ad98aa7b73eabb2bf30ac429c654b7f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 10 Jan 2024 19:54:14 +0100 Subject: [PATCH 062/350] add more imgs --- components/images/lvgl_image.png | Bin 0 -> 7270 bytes components/images/lvgl_led.png | Bin 0 -> 1123 bytes components/images/lvgl_roller.png | Bin 0 -> 2677 bytes components/lvgl.rst | 12 +++++++++++- 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 components/images/lvgl_image.png create mode 100644 components/images/lvgl_led.png create mode 100644 components/images/lvgl_roller.png diff --git a/components/images/lvgl_image.png b/components/images/lvgl_image.png new file mode 100644 index 0000000000000000000000000000000000000000..9fcf3f080155db4b4ea5e801a455b6ca0aa60819 GIT binary patch literal 7270 zcmV-s9GT;ZP)ME@$k_9Y$ncBN0zyCy~I540xe2Sw!ANOOb`6WEYHa z2C|9CB6#WSOco|BgN(GW83im_2Ah5Y2|a;CZWBFHm&}7YFc+UMp2IkcQ}_Lw?w{yiYvK5-MvvON6y!*Bf2 zHy)op-ke7Jg8qwj?f#5J0( z&$p5I6b6sDeKpt!kWFYrwDZ8q`z<_$*>IF=qwfVsyo5S^^*6ry-fzBl`@#{=B=P>| z?w@`C?AFOoC-JC&S1bgmSG=?jw`l?bLbn!n>s!;^l(U!YRrk4R1UK2d&Equ^0ax2E zN@BzI&Fv3Pe{lOO@GPG={rq&r;B$#foz$#~nyMO8ao{M!758m9K zyml{jqWZczD6A7#Sb4mGa7~*)L9wkWwB@bC`;ETvOVc}_pYCr(U0iS9<|()(n_GC! zrBB2DeE-JD8@JEGKlrWR`mO87@BQ|B4<9~kpPOcckFUx2iu1PMYFGbd{b&E=)%*YW zl~+>ix;y^MgR8?!A^fc3&jvmYu2oWasn!ZXd|de$UV@L&O9~-W>YaZWq)`8g`f&{} zh5A<}aQ_$5JOA|6U-(DeE9sSbsQItLkN(d^txxlUpTx%mLcNsgOCkI$^(FWiKBj(L z`Izuhs2{)B-Hy2Ue;1Ydg@68q>nCsc#AR82?iYUUGLk$+=vTHQDg=Y5e(+lQ{K-fF zX}|Yww>;k4wz|}UX$%l3hf9|T!Uq%-1(mev?b7_6tA!uDK0Nr$G;Dfx1H>m!c60Xc zf9vt}K=-LIN8JHqBPn$NdyR*hEc(i{JGJ_6dw#O#ua-}pjQO)0f{8&B7rFP zsn1@Pnr~0(I&QHOu2M_jNb423ml5W9g1L!@Uw<}AQ9-m>1cazW=mV9{dchFTiMGeNxFtlUcAhuLyHNL`qXK7b=!AI>f5pr3Io-6P8;Q* z<^0T*VI#0@F4Mh=B*L2gDkNsGj(|34L<;Hd&Ur82opO{*o1o0QTx4t?r}>Fzk)O|C#pDaDs59~rP0 z=s9Gm?>7_2IoXD?E~6sJc1me_eXEdii)=y7QDz(DyjMz5J+NHtb6)10^I>sCojz3` z|8{6>zKD(AX6q^R9U*SblTz1%cjr4D63$~HIobG-eJCgnNd%|{r%tgGP^xpz`LF<&W+Fvk zIb`L$AVLw5Kr};;Y^gV|`KAprX zS9p2K^ZC47%mn&0jvY}GwfK(4AOcHXTFLB+ z_j^JDL0nvbaTo>togO8iRHu|UwzFKXqQQ&dng@L@gD;3@llW8tR#s`ZNqa%Pj+WcT z+eS)~b2g?fc3USj#gRix)dnOP_jx zHII=bq->`UV_;uVNNrh0QItbln{)Nvc?b;7soIrcGfwxWB|BeGY~-r|+UR%@UfP)F zuKp6wcZl4+%_nYpUBoxU-9mJLN>qZ3p%#pTRatD;#W_o$xY(-LrNswV_i4=g#SnvZ zC-q${1~H`GF2&g&d2ylA3oPf^hY=Vz>Ez`8?tI>dox&e-VQpyinI7Z255U z0Rntr1?lB=mNBHXnda}EdhEwEE_vxUL-UC#rDcEGZ-#ytid9R^L&x=!Sltk|G>rerPd!>)j<>Cb5^%rdM=wyf!5ugn`0q&ObH?NgVH?j4C)dGD@~~zeb}i} zKMbjhsZXiGN0Nylsnc?iT}_ZG&e<2U?(}pibtK6Lp*W_vxQuz2FFYS|UhKoNWWf?E z1W_q1l3ZW>W#qi%;JH*9R97l*;S(n=adf3u^ns*t)AuQzY_})B^o4Ph51BQXEKANl zEIrIa)h zz~t?+WbfyBezM!0?@OKK*mtqiR(H1LTyeU7dK!0Es5qd?JEXTmx_;%^ns^P@m61w5 zWZSA4+a=@0rqs1~ka{%>%9&br3y+_8Z_j(Dl*S(|4^G|~5`?~lgiVdvJo?kq#jz!D zN*br_^yWmK=O6EuyyV4_=n}Ma@;D^St}bcqlZBv7TN z&#O&sw;jrgKmoy6^(FeDvR|v#6*ov6+lFM*>Z4f7rPxj1F{OUm3{e6@Syy$mky7D9 z8`2%cE)gX0_UE?qe#tdYcgN*oc4axRRUbR0G-l?U`jfXF5HY2HWjJ|rE3rG@3ltJU zojEL2VD*Neb%qiFg@~lkaw!1{^qVm%s!KVg)b0B=XSXiga;asjNCEfS;Lltk3`1#|mZbVH2t8O*~is`GyF47X0V(MjTR;c(uu1=kjBH%+V7kj$l zozG9ZAMK5|Z{Md%T}rQ{v>DZD&?Lp-=eN_nDJB&=?{~{?ml7fZ1F3Dl(0)*x7=R!| z1?ZAO-%5Z>@hgDTZ(5%Y0unnZh5i2A!zSihmV>FbNl8?|7(tH)7@HbaT*+XZA%^Fs zI1iAB>*L$FORcP!wi(ioA?YK)ZY}=mb$JyZybh~v8A2?FeLoD_FTUHqGAX4wTb1$d zBmu-Oa(5W-4s^#dyy62GAFKeP?~)-&N~07(3Nfmz3MiqTAYC$e^mhs(piSRQJKsq| z*XPZgr=eu$pX`>Lvx|*V?||)cvGgWYR9Az~)rJWTN;U=d>qA!DATd>F*~v|&8w{#K ziA~ST;v?fmRw-U`@se$$r2ds&T|$7QetUQ5r~AWeTe`t`N^94^6>I`NWV#gX#S0bN zf`X16VyjD%QrE{c5EB6cTpDk<%^;xbJc@oJ3rS9WKMpLD^HMgWFXp_=Hd0&yK3}q1 zPU(VMwwr=Rv~BfgyX_6yZXP`eZh?Qb>HwfiBMN|oIV==`6oh&!M_FN(Jamd(pE||n z-MbzorBRYyT=!H6EP1ivLzlz4+0wr{IQ2O%985J!UR^CsqoWj2BE)rKf#&-ND|fz} z_7#E0^|h90*GtidQo2OSzDP>ZIrWFJ7#m$I^LbH?;H8oSQ%Dm^A*uoe#~unt13lsf ziF3`YQ;{H6j)%=P2<-i$^O@9>1Q8{rX+RR`PEP!*1@v5&YO%(@j_(EqFCfdHl{dzq8b=Kn&0bt~l6L zu1?{(nz%o5r}opN4T6F}5nAXZL;>|Uvk;>qF9YyVOXrK*bniqyf`C6<6k=g@F|Mf7 zcyAId2egfARuFB6+F6x8rR9*9oYkec=@rxhU4edI^z~D|cB;G($Q$wc$jMf3O^hQ+ zBv2H_*k$#bsaFTc;7eTzZNW)_v-3yue%E}$F@{)cEoat*@dj>?$Vyhjnqf3=NPrrJ zTtx*#2S9}i5)rK}Ww*wYqXFFL1(R`48|D8`xGpU=y8ALl=Os5FjmZqwUa4I?S(m0lZ>)c>n@PRw`y z^Y8i?*^e(Gs+rx5vKhEV;`#8lDh z$5miY&aebjm5>8V^_b`K?S*fjCPYY1(FumM`^*?$pSJ({o%jFXA=L`x3YefP`d0N? zaf8IUE`8_|5=yKLwjl-D9wx$SToZ%V8-!-><|Ft0@wFz1)umc5N0-9N9n_VwrL`d2 z;w7LQ_K=!}x)tLU9peK~?D)f7{@N*dISZbv_hA7i7?rlQADZ*w(ijzK?*Nrtolqa* zt`-4-h#TFmSr=Is?3F|5mZ_V5>3I9s7*FRt!q|u3$PA8m=M<-#&A9_ zfBYyv+0DUcEzqAT|;g~ex=k>pkEWBm}ngi+(~x_OC=CPl#=dp-Lf+G`-%JAVP{Y zQYl1g90R!)!Hjd@vbyb8Z=2gwN^pi!uZU4)0tIC_qqSx=)EgRkgT%+x6HGx(j$X?h z5-7-$hTftaGF@uXq^+OOvOEJy$>5ex1ngt#<92A)t7^F<0aKO({V=4~j0w=hX0HGNUS2EBm|^7`rZJaTwLk1Sx2${alwP!3ChrTR8x$iBRoI31o0! zHKX9%LNkoudOd+zaf8GsIAf!ekfw@TQUY^Jt=nA=wu@?_wOcCO(HcqHnnP0u#ZHo1 z=gQU2OF88H!R%T}#fRn)Z5N=wJEYB+x)ftYd?#7@*+}BcS979?{T%3&sbHJcg2~f*>`ufVXqs*FyDD^UN}1RVFlqey({A zrH85Zr81&cX=KVScp>lWGBKVg{dYfcbClIFsPzp2niW?ZSYVB-6+^)@>|wx>%O2f| z8%OExus`1$mdaV>B;;-IgalKFePGT@ezF@rGnHl&NNXJ_I>qD7VwV&ml+__tTArv* z(s(~fchdeRyR+|~E=ED)>nGcj2Qdv=bF5;UgQ>kLRQEs3afb78T*rE{DV`@=NV@T!999| zsP$~2YB8CRQs}ppMA-)3_x|_leq^75#wr4PyueaD!Whzo znh66j&{rm8TELN^z&l@j_xK#RMdJ30@7(|D^o2tUCZ2H)p7E}FUwsM#+z;u5q#y45 zPlZ}qKdL2(xgPf?MCwH935wN) zvcq#_7d+b!0zGR|Ijt^C230QmS5zfpUsrlZ7&O7|ecPbWsBcN4w?V+8wwc;2dYuJs zw!F?cZNK;q*KmWx*!TDT?U&B})9+3}6Dkl%3*HA7JVUO2pZpk4A#IVKsC*O7Gp`SQ ziiXuB@5n$Wbv;n3V}%f1p%z+_5CBAMl}WRG)3Qsb=wN+s=If8fw87hJt^t6kyn$3UXnT? z^6VOZd-=J%_|z?YTo zRo<|s_HG~SS(dO8rzRe7C{!C#U_=5{40GTt_+ibDs`mjZ1AIk8UwK&fI{*Y@&^qtK@2@{`8!4LqGh;MY#>&)+@mkwU9QHL&j82o&PjOa=f~mcU$#19Uw}-t-!h#*w>; zyJLJMsq0Oli&RQ2aIFJW3kS1Ue{wqh@#E!uzoR@M7qG}^SM#Il98l#!NNRJhk3?Wumea32eE;j;IQxr7 zyZs(;1!%-wic|=$_JafwB@o)4;Z%$GNlAer1^onz24eR zzxvMhi|_pH|D?-L@q&2DAJX_K{-*dTiGL6H|2<=+(tCN30ssI207*qoM6N<$f@CEO5QWcMQj9tYQpm8y22vzl{{L@S*w-aRAc0-5ihxx-&?y4hVkB9Xof}{0F61OF#o^}je@DW%#r#x#F9q8|qwY6(EjZIwuE9^gCAp^Tysi)R7= zF+c$l0ifV#VeJL#QAjYAMq`pl`7zb1v#@rBY^EU*Cv8w0X$52iB4S-8tBrk3Uptgi z<3yYgBbhKo#0VzD$OcG6U@gSZMmQ^CKvt%-gXt7dZ%mAg6Q+nT=5_^51OOu}ArtFh zE&Tu{Az>}7!;bKs0sCx#I*B1XK=Z}AGS7S@U%U>#iqDNOXt6vd~{Oxgz8rg?oq z2$&{5zaWI{N~d?=E#fWmp8)UW_68)G1R$`7X#;3Zoi)uk^63$8v43YR60fiP73J<8 zg=WDdl2TeTZ2$o^bt2-9w@8Mqc9?jm?l0QqEV52dMpz#FH{hLANroaZ|#S64J1>Z z;Zx-E%dWgRp|{BA7fdAwnr&yXRd+yH+Ev%$7&W!~J_i&+Ha@RmW%XKW1w?{Lm%eOI z7&qTMTO`AnP09;>T93Q}LUAa&nh?JitX8`H&4c$e=z&UHk%(Aay)aN2Q_F-E)(kW! z7m2b%k!*K{@9G`%unkI^*Q=0e?WgK$or_5ApFb|97&d@Zen@zf#xM#E3EqbWHCRYE6l@|-2=-r)LsfxEVHdz0<)gVd0TboJ1dLqPsloP{6Y2RJ8p z_nZIFE{Vw9J)A3}72~(m&uL>!UJ$Jlk^_Z_x=23oNYN;QhkFbIych2=c(JY?9e3B% z>Zi3r>Io*-=U1|~$X8ukxhph(+~gdnlYdJaK*pGq5=7M1N~6w*$f;vcl}J7YIXBY` zLr!fGtg30%1`w8kL(3!vn(x04n+HWK4~m+F;(brE6)e>@5H^{N=66@brKbVfO@sYFsvc{8CIEABw|wqIQJn{*TAVdodsK=7 p;7kj-vNS77XZ4f{slH09W%Z?{pkPz002ovPDHLkV1ihd@-+Ye literal 0 HcmV?d00001 diff --git a/components/images/lvgl_roller.png b/components/images/lvgl_roller.png new file mode 100644 index 0000000000000000000000000000000000000000..3eab1039c096540a7710312f2ba2b9f9dfc3b3a7 GIT binary patch literal 2677 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 literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index 03a5ca643..d99b88634 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -592,6 +592,9 @@ The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. Images are the basic widgets to display images. +.. figure:: /components/images/lvgl_image.png + :align: center + Specific configuration options: - **src** (**Required**, :ref:`image `): The ID of an existing image configuration. @@ -609,7 +612,8 @@ Example: y: 10 src: cat_image id: img_id - + radius: 11 + clip_corner: true ``label`` ********* @@ -670,6 +674,9 @@ Example: The LEDs are rectangle-like (or circle) object whose brightness can be adjusted. With lower brightness the colors of the LED become darker. +.. figure:: /components/images/lvgl_led.png + :align: center + Specific configuration options: - **color** (*Required*, list): TODO @@ -718,6 +725,9 @@ Example: Roller allows you to simply select one option from a list by scrolling. +.. figure:: /components/images/lvgl_roller.png + :align: center + Specific configuration options: - **options** (*Required*, list): The list of available options in the roller. From e1cfb7a83381dd8346f6e27dd9b672605db8db7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 10 Jan 2024 20:08:13 +0100 Subject: [PATCH 063/350] add slider img --- components/images/lvgl_slider.png | Bin 0 -> 521 bytes components/light/lvgl.rst | 5 +++++ components/lvgl.rst | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 components/images/lvgl_slider.png diff --git a/components/images/lvgl_slider.png b/components/images/lvgl_slider.png new file mode 100644 index 0000000000000000000000000000000000000000..d2de4030d2fc6ddbf12efd85046016cfbc97f645 GIT binary patch literal 521 zcmV+k0`~ohP) zu}cC`90%~P;o!jyItU33Iy5LX6g1QrG?b&8fkXWZ{uz#~H3Ygf))F+@5Y&*^(4a$L z;BXDXa}aD1@qWC-mgjqS-_LemIJn`<@q72)C8pCUh}^Lu10uVzvg8<6mK>9m0Yy}x z)I%RneS8ct7|p_*k75?bd7R~u@x0Itwn}jM6$gzMb@K)_k@=jL#Kj)!2M)BBm5sh~ zOLc!_s8veizG{1GS=op?x>fTrU==wZ?V8oCw*IK@K1D|H;w5o)igZfm#-xB!R^M7V7_hGdKuz%a zEkl#WKzFF0PePUL1?(%$Jb%f=urUxQO>0AyZFUx~DAsy`Ow7}+9YdAndW+_Qu}sX< zK7yQOi7dy;l4C-Zz1&^AqFBqU?+e$Q_7OsrJzvw;W3o^oBNOv-zDyu0TgZ5o?ZtrN z>u^gZhNYn21Cz6C^XMEfFfh{ld_8}KQ+tBMjX$} zl4II6uauVIUrK4)`wG5gV}k#Fk$d=uEzx>#mL` diff --git a/components/lvgl.rst b/components/lvgl.rst index d99b88634..ec226ee34 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -752,6 +752,9 @@ The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. The Slider object looks like a Bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider can be vertical or horizontal. +.. figure:: /components/images/lvgl_slider.png + :align: center + Specific configuration options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. From 0040489a9efec33cf937550901b49dd4bb782e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 10 Jan 2024 20:18:35 +0100 Subject: [PATCH 064/350] Update lvgl.rst --- components/lvgl.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ec226ee34..cb258776a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -742,7 +742,16 @@ Example: .. code-block:: yaml # Example widget: - - + - roller: + x: 10 + y: 10 + id: roller_id + options: + - Violin + - Piano + - Bassoon + - Chello + - Drums The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. @@ -771,7 +780,14 @@ Example: .. code-block:: yaml # Example widget: - - + - slider: + x: 10 + y: 10 + width: 220 + id: slider_id + value: 75 + min_value: 1 + max_value: 100 The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. From 8aad420d5eb5f70b44b500a983c152e5b94cc220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 10 Jan 2024 20:26:31 +0100 Subject: [PATCH 065/350] Update lvgl_button.png --- components/images/lvgl_button.png | Bin 1049 -> 1062 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_button.png b/components/images/lvgl_button.png index 38ecdd4229fc39accb0b39cc2b1f29298fda896f..c80d07f2d16b54fcc0b841b1e9d703cec2db3ecf 100644 GIT binary patch literal 1062 zcmV+>1ljwEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!Tn5(2X;z~XmcwWQv(jI%y4)B}v20|L)e?=}Y)^wG^h_0BZa(hq@q z1wd@8H!R0%1D*~8gJ+s!EZ6kW&3=0CTK-%VjQUD_roNlzs2hsdPw&)BMN|64=k5wd zzn~9y%q@kk>!X`mdZ%V8iV<8EjQUPvFoo;-=%$w5DO2TT(CIoR$IuG;=q5{(l&Oj> zkj0oBLo4W`n=DQEITfQFHWi~CHkD<}4g=GdRizFZ{hSHdR83~0ANYJ%RWgWVMzvuu zcBAiKxTz|JU{hJf#JrqwKB&+T&rMOSXR}&9x{H z`qWn4lsqWN`d5KsByeR;VDOolZ7nvH#n3E6Mj0;%%r4Vjo1DpHN%bsf8)@_vkT1$v z>04|fnw65-YW+7*D#x$sWChhtz^1a8zK*yglkB9rp0My!y-*}aa>5`kn+2Qd2;jG= z7fpgqWiiW}aakRZX9egs!KOMSD1)oMs-c*N0_*7^uaW^$8!D+z2o)dI!|GNXXN`oY zTy%UzH*BgyfHF7A;Hs~k>3_oHdtmCL!1(z%>l^8gv%p57c#MoXGwfmNk~CPxcm6M_ zLwey8^Cu^pfvM*&w&+7=#oylYDvtzAWpMRStvAn9mO~FL=^-Y?QMCL~`Qn<)^on*E zDhoE1koTq)c_aOTdG>zeegijlmSI>!X`mdZ$bkwg-6FyY8fL)Mx5D zjlmQy>!X{!^iG+|Z}-vX$BkVQE*T*8oyK4aSM|}&etM^}KO*`Sp}1B=Nv5&+jQ~rV zKGw@Qb=NK^NTfA=jVSa62h)+x5%LwWa@&%`jAg z3;O7$9=$V7MTkEFrL7X8QiO83Y^AAkxf}vNs7%4$2{X^8YGJ!Rx~WI+nxh+G7A8@#iud2JYVnu$n=>jd4&v?*G{*RAlI9%o z+>

(Y*?&!PkR?#qd0b>?y%Idzeu_w3BZSmthd;AY5m7mew7u9|-T#B)af2M5|>n ze7e;tjO}yKMLM+5$@f0RYPeQQ4HT<&@1JY%5kS;r>n8VZ+zUWE&Gld{s zHf216<=cD_fZ4z=udl048P8zhI$!id)ALwKGsfrnN=T3{JEoX}*>H{CO`~uY8e_}r zG`)nUm+@o?vo&}Acm`ub&=_0LY4RhCIsnXG!?}J2K)(+F$!8vW|4xxEeKBbtjrBPgZ4FC@+D5NQS5)Udc1s!5Ym)(=-Lw=AI zDpb}1U~vtGMKifwC#5D){>{H}&A{9kOZ1UZhf#-R0}%OhjqH88C*2PKj!1`{V~2&G z?%2_m)ZB_#q|2aD_w7|EU3SmPIsoKTZe`~`TZpT^S7yg*R2N1zqG}5HTYI2q1f4eYvhEf#*jRn)Q)@Hcc;)Fs#R+%mNH#S z5Q1KjD7N#R8cMNad_U;n5?eaAKiZAp;;h8n2Q5mZL(ennhj#Mq?Gga}A#1}jEz`E` zfL$tzqN$o1SNBHGCq2xlAKJ`!Q Date: Wed, 10 Jan 2024 20:37:44 +0100 Subject: [PATCH 066/350] obj img --- components/images/lvgl_baseobj.png | Bin 0 -> 730 bytes components/lvgl.rst | 3 +++ 2 files changed, 3 insertions(+) create mode 100644 components/images/lvgl_baseobj.png diff --git a/components/images/lvgl_baseobj.png b/components/images/lvgl_baseobj.png new file mode 100644 index 0000000000000000000000000000000000000000..5fe7294ce66f7e61a72fe4a3f18a876e81800fc5 GIT binary patch literal 730 zcmeAS@N?(olHy`uVBq!ia0vp^`+&Hfg9%99TlD@m0|V1SPZ!6KinzBo4rV5}4? za@!BS)%knB-}_zF6u;_PRJLqf``07k`uu$-*KWOhJJa@5UeEDDiFa%z=5s6O{r`*7aVCdjI$H;`z&7zSa%D{qoMP$_)_&3@@WIpU+5 zKM5ZGUZ4JMN$}FcSA`CLE)nyyymO~J(OR~`%c^CGv&TpzGOXubyH(Y(cbE8KtGQ9x znoGa$lS3>D`cm2SI*miZiD-Fp1j06Yc6Xp?K!@2%BAyv z?|Jvl%~-1&eQwf`Q*Ks=4X!xrE}e7F@7uh)v!4I_Ql_=^inDCn*J;6Cl{;hfUT+NY z()?_5-_Pc2K=$3Z^ZJ*gUhl21`*PW&cJI?yc~(oOT)TBi_P2@LarWOw7ng{=-TU=k y?Yj5wYqwte^*3hECmY!tTMB*J=1<^TSnv2`%R|Sb!Iyw(mci52&t;ucLK6UZ)mUHv literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index cb258776a..74eacc097 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -874,6 +874,9 @@ Example: The Base Object can be directly used as a simple, empty widget. It is nothing more than a (rounded) rectangle. +.. figure:: /components/images/lvgl_baseobj.png + :align: center + You can use it as a parent background shape for other objects. It catches touches! Specific configuration options: From 58b33ae9dc836bfc46ef03107b293d763b6caf32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 11 Jan 2024 18:20:30 +0100 Subject: [PATCH 067/350] add pages --- components/lvgl.rst | 140 ++++++++++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 44 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 74eacc097..2941cc4cc 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -26,9 +26,11 @@ Basics In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` to see the full list of available LVGL widgets in ESPHome. +Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent object. There is always one active screen on a display. + Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. -The child object moves with the parent and if the parent is deleted the children will be deleted too. Children can be visible only within -their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A screen is the *root* parent. +The child object moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within +their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A page is the *root* parent. TODO - PAGE @@ -60,10 +62,9 @@ Main Component Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome this is simplified to a hierarchy. -At the highest level of the LVGL object hierarchy is the display which represents the driver for a display device (physical display). A display can have one or more screens associated with it. Each screen contains a hierarchy of objects for graphical widgets representing a layout that covers the entire display. +At the highest level of the LVGL object hierarchy is the display which represents the driver for a display device (physical display). A display can have one or more pages associated with it. Each page contains a hierarchy of objects for graphical widgets representing a layout that covers the entire display. -The widget is at the top level, and it allows main styling. It also has sub-parts, which can be styled separately. -Usually styles are inherited. The widget and the parts have states, and the different styling can be set for different states. +The widget is at the top level, and it allows main styling. It also has sub-parts, which can be styled separately. Usually styles are inherited. The widget and the parts have states, and the different styling can be set for different states. Configuration variables: @@ -77,6 +78,7 @@ Configuration variables: - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See :ref:`below ` for more information on groups. - **color_depth** (*Optional*, enum): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. +- **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to 1s. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. @@ -91,9 +93,14 @@ Configuration variables: - ``COLUMN_REVERSE`` to place the children in a column without wrapping but in reversed order - ``ROW_WRAP_REVERSE`` to place the children in a row with wrapping but in reversed order - ``COLUMN_WRAP_REVERSE`` to place the children in a column with wrapping but in reversed order -- **widgets** (*Optional*, list): A list of LVGL widgets to be drawn on the screen. -- **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to 1s. -- All other options from :ref:`lvgl-styling`. +- All other options from :ref:`lvgl-styling` to be commonly apply to the widgets directly. +- **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. Not possible if you configure ``pages``. +- **pages** (*Optional*, list): A list of page IDs, where each page acts as a parent for widgets placed on it. Only of no ``widgets`` are configured at this level. Options for each page: + - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with ``previous`` and ``next``. + - **layout** (*Optional*, string): Layout to be applied to this page. Same option as above. + - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. + - All other options from :ref:`lvgl-styling` to be applied to this page. + - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. Example: @@ -103,23 +110,17 @@ Example: # Example configuration entry lvgl: log_level: WARN - color_depth: 16 - bg_color: 0x000000 - text_font: unscii_8 - touchscreens: my_toucher - style_definitions: - - id: style_line - line_color: color_blue - line_width: 8 - line_rounded: true - layout: grid - width: 100% - widgets: - - btn: - id: lv_button0 - x: 5 - y: 30 - + displays: + - display_id: tft_display + touchscreens: + - touchscreen_id: tft_touch + pages: + - id: main_page + widgets: + - label: + x: 10 + y: 10 + text: 'Hello World!' .. note:: @@ -496,24 +497,6 @@ Example: - control: "\n" -``canvas`` -********** - -A Canvas inherits from Image where the user can draw anything. Rectangles, texts, images, lines, arcs can be drawn here using lvgl's drawing engine. Additionally "effects" can be applied, such as rotation, zoom and blur. - -Specific configuration options: - -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- Style options from :ref:`lvgl-styling`. - - -Example: - -.. code-block:: yaml - - # Example widget: - - - ``checkbox`` @@ -869,6 +852,27 @@ Example: - +``canvas`` +********** + +A Canvas inherits from Image where the user can draw anything. Rectangles, texts, images, lines, arcs can be drawn here using lvgl's drawing engine. Additionally "effects" can be applied, such as rotation, zoom and blur. + +Specific configuration options: + +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- Style options from :ref:`lvgl-styling`. + + +Example: + +.. code-block:: yaml + + # Example widget: + - + + + + ``obj`` ******* @@ -1027,7 +1031,7 @@ These :ref:`actions ` are shorthands for toggling the ``disabled` This :ref:`action ` redraws the entire screen, or optionally only a widget on it. -- **obj_id** (*Optional*): The ID of a widget configured in LVGL, which you want to redraw. +- **obj_id** (*Optional*): The ID of a widget configured in LVGL, which you want to redraw. Entire screen if omitted. obj_id @@ -1069,6 +1073,54 @@ This :ref:`action ` resumes the activity of LVGL, including rende +.. _lvgl-pgnx-act: + +``lvgl.page.next`` and ``lvgl.page.previous`` Actions +----------------------------------------------------- + +This :ref:`action ` changes page to the next following in the configuration (except the ones with ``skip`` option enabled), wraps around at the end. + +- **animation** (*Optional*): The page change with one of these animations: ``NONE``, ``OVER_LEFT``, ``OVER_RIGHT``, ``OVER_TOP``, ``OVER_BOTTOM``, ``MOVE_LEFT``, ``MOVE_RIGHT``, ``MOVE_TOP``, ``MOVE_BOTTOM``, ``FADE_IN``, ``FADE_OUT``, ``OUT_LEFT``, ``OUT_RIGHT``, ``OUT_TOP``, ``OUT_BOTTOM``. Defaults to ``NONE`` if not specified. +- **time** (*Optional*, :ref:`Time `): Duration of the page change animation. Defaults to ``50ms``. + + +.. code-block:: yaml + + on_...: + then: + - lvgl.page.next: + animation: OUT_LEFT + time: 300ms + + on_...: + then: + - lvgl.page.previous: + animation: OUT_RIGHT + time: 300ms + + +.. _lvgl-pgsh-act: + +``lvgl.page.show`` Action +----------------------------- + +This :ref:`action ` shows a specific page (even the ones with ``skip`` option enabled). + +- **id** (*Optional*): The ID of the page to be shown. +- **animation** (*Optional*): The page change with one of these animations: ``NONE``, ``OVER_LEFT``, ``OVER_RIGHT``, ``OVER_TOP``, ``OVER_BOTTOM``, ``MOVE_LEFT``, ``MOVE_RIGHT``, ``MOVE_TOP``, ``MOVE_BOTTOM``, ``FADE_IN``, ``FADE_OUT``, ``OUT_LEFT``, ``OUT_RIGHT``, ``OUT_TOP``, ``OUT_BOTTOM``. Defaults to ``NONE`` if not specified. +- **time** (*Optional*, :ref:`Time `): Duration of the page change animation. Defaults to ``50ms``. + + +.. code-block:: yaml + + on_...: + then: + - lvgl.page.show: + id: secret_page + + on_...: + then: + - lvgl.page.show: secret_page # shorthand version From 47a0fea684fcd323fc1f1e366c45017e50e628aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 11 Jan 2024 19:43:15 +0100 Subject: [PATCH 068/350] updates --- components/lvgl.rst | 2 +- components/switch/lvgl.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2941cc4cc..695f32d1a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1106,7 +1106,7 @@ This :ref:`action ` changes page to the next following in the con This :ref:`action ` shows a specific page (even the ones with ``skip`` option enabled). -- **id** (*Optional*): The ID of the page to be shown. +- **id** (**Required**): The ID of the page to be shown. - **animation** (*Optional*): The page change with one of these animations: ``NONE``, ``OVER_LEFT``, ``OVER_RIGHT``, ``OVER_TOP``, ``OVER_BOTTOM``, ``MOVE_LEFT``, ``MOVE_RIGHT``, ``MOVE_TOP``, ``MOVE_BOTTOM``, ``FADE_IN``, ``FADE_OUT``, ``OUT_LEFT``, ``OUT_RIGHT``, ``OUT_TOP``, ``OUT_BOTTOM``. Defaults to ``NONE`` if not specified. - **time** (*Optional*, :ref:`Time `): Duration of the page change animation. Defaults to ``50ms``. diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 766e2577b..518c169f3 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -10,7 +10,7 @@ LVGL Switch The ``lvgl`` switch platform creates a switch from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are ``btn`` and ``checkbox``. A single switch supports +Supported widgets are ``btn`` (with ``checkable`` option enabled) and ``checkbox``. A single switch supports a single widget, thus you need to choose among which one's state you want to use. From 7be670fdf1e7060ee6b2461ecb08100dfffe3a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 11 Jan 2024 19:47:16 +0100 Subject: [PATCH 069/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 695f32d1a..d59ea75c2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -96,7 +96,7 @@ Configuration variables: - All other options from :ref:`lvgl-styling` to be commonly apply to the widgets directly. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. Not possible if you configure ``pages``. - **pages** (*Optional*, list): A list of page IDs, where each page acts as a parent for widgets placed on it. Only of no ``widgets`` are configured at this level. Options for each page: - - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with ``previous`` and ``next``. + - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. - **layout** (*Optional*, string): Layout to be applied to this page. Same option as above. - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. - All other options from :ref:`lvgl-styling` to be applied to this page. From bee5d29a91c388c42d353e4e54b79d520ed475c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 12 Jan 2024 14:49:03 +0100 Subject: [PATCH 070/350] update --- components/binary_sensor/lvgl.rst | 4 +- components/images/lvgl_btnmatrix.png | Bin 0 -> 2739 bytes components/lvgl.rst | 106 +++++++++++++++++++++++---- components/sensor/lvgl.rst | 4 +- components/switch/lvgl.rst | 2 +- 5 files changed, 96 insertions(+), 20 deletions(-) create mode 100644 components/images/lvgl_btnmatrix.png diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 80543b22a..6fb0b59f5 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -19,7 +19,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the binary sensor. -- **obj** (**Required**): The ID of a button widget configured in LVGL. +- **widget** (**Required**): The ID of a button widget configured in LVGL. - All other options from :ref:`Binary Sensor `. @@ -29,7 +29,7 @@ Example: binary_sensor: - platform: lvgl - obj: checkbox_id + widget: checkbox_id name: LVGL checkbox See Also diff --git a/components/images/lvgl_btnmatrix.png b/components/images/lvgl_btnmatrix.png new file mode 100644 index 0000000000000000000000000000000000000000..4842d58f3a7b8a7635dc840f4cd3429fe18ef40c GIT binary patch literal 2739 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 Q4Wj@X%hRYTq|fz#16OP$v;Y7A literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index d59ea75c2..ff5bedd0b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -72,10 +72,14 @@ Configuration variables: - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. - **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. Can be omitted if there's at least a rotary encoder configured. - **touchscreen_id** (*Required*, :ref:`config-id`): ID of a touchscreen configuration- + - **long_press_time** (*Optional*, ms): Delay after which the ``on_long_pressed`` trigger will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, ms): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` trigger will be called. Defaults to ``100ms``. - **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. Can be omitted if there's at least a touchscreen configured. - **sensor:** (*Required*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. - - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See :ref:`below ` for more information on groups. + - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See the :ref:`common properties ` of the widgets for more information on groups. + - **long_press_time** (*Optional*, ms): Delay after which the ``on_long_pressed`` trigger will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, ms): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` trigger will be called. Defaults to ``100ms``. - **color_depth** (*Optional*, enum): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to 1s. @@ -473,8 +477,26 @@ The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or a The Button Matrix object is a lightweight way to display multiple buttons in rows and columns. Lightweight because the buttons are not actually created but just virtually drawn on the fly. This way, one button use only eight extra bytes of memory instead of the ~100-150 bytes a normal Button object plus the 100 or so bytes for the Label object. +.. figure:: /components/images/lvgl_btnmatrix.png + :align: center + Specific configuration options: +- **rows** (**Required**, list): A list for the button rows. + - **buttons** (**Required**, list): A list of buttons in a row + - **id** (*Optional*): An ID for a button + - **text** or **symbol** (*Optional*): Text or symbol to display on the button. + - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1``. E.g. in a line with two buttons: btnA, width = 1 and btnB, width = 2, btnA will have 33 % width and btnB will have 66 % width. + - **control** (*Optional*): Binary flags to control behavior of the buttons: + - ``HIDDEN``: Makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). + - ``NO_REPEAT``: Disable repeating when the button is long pressed. + - ``DISABLED``: Applies *disabled* styles and properties to the button. + - ``CHECKABLE``: Enable toggling of a button, ``checked`` state will be added/removed as the button is clicked. + - ``CHECKED``: Make the button checked. It will use the styles of the ``checked`` state. + - ``CLICK_TRIG``: Controls when to happen the ``on_value`` trigger: if ``true`` on *click*, if ``false`` on *press*. + - ``POPOVER``: Show the button label in a popover when pressing this key. + - ``RECOLOR``: Enable recoloring of button texts with #. E.g. ``It's #ff0000 red#`` + - ``CUSTOM_1`` and ``CUSTOM_2``: Custom free to use flags - **items** (*Optional*, list): Settings for the items **part**, the buttons all use the text and typical background style properties except translations and transformations. - Style options from :ref:`lvgl-styling` for the background of the button matrix, uses the typical background style properties. ``pad_row`` and ``pad_column`` set the space between the buttons. @@ -484,17 +506,39 @@ Example: .. code-block:: yaml # Example widget: - - - btnmatrix: x: 10 - y: 100 + y: 40 + width: 220 items: - rows: - - buttons: - text: "a" - text: "b" - width: 50 - - control: "\n" + pressed: + bg_color: 0xFFFF00 + id: b_matrix + rows: + - buttons: + - id: button_1 + symbol: PLAY + control: + checkable: true + - id: button_2 + symbol: PAUSE + control: + checkable: true + - buttons: + - id: button_3 + text: "A" + control: + popover: true + - id: button_4 + text: "B" + control: + disabled: true + - buttons: + - id: button_5 + text: "It's #ff0000 red#" + width: 2 + control: + recolor: true @@ -608,7 +652,7 @@ A label is the basic object type that is used to display text. Specific configuration options: -- **text** (*Required*, string): The text to display. To display an empty string, specify ``''``- +- **text** or **symbol** (*Required*, string): The text to display. To display an empty string, specify ``''``- - **scrollbar** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar that is shown when the text is larger than the widget's size. - **selected** (*Optional*, list): Tells the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. @@ -1026,20 +1070,18 @@ These :ref:`actions ` are shorthands for toggling the ``disabled` .. _lvgl-rfrsh-act: -``lvgl.obj.invalidate`` Action +``lvgl.widget.redraw`` Action ------------------------------ This :ref:`action ` redraws the entire screen, or optionally only a widget on it. -- **obj_id** (*Optional*): The ID of a widget configured in LVGL, which you want to redraw. Entire screen if omitted. - -obj_id +- **id** (*Optional*): The ID of a widget configured in LVGL, which you want to redraw. Entire screen if omitted. .. code-block:: yaml on_...: then: - - lvgl.obj.invalidate: + - lvgl.widget.redraw: @@ -1189,6 +1231,40 @@ The ``on_idle`` :ref:`trigger ` is activated when inactivity time be +.. _lvgl-event-act: + +Widget Event Triggers +--------------------- + +ESPHome implements as triggers the following LVGL events: + +- ``on_pressed``: A widget has been pressed. +- ``on_short_clicked``: A widget was pressed for a short period of time, then released. Not called if scrolled. +- ``on_long_pressed``: A widget has been pressed for at least the ``long_press_time`` specified in the input device configuration. Not called if scrolled. +- ``on_long_pressed_repeat``: Called after ``long_press_time`` in every ``long_press_repeat_time`` ms. Not called if scrolled. +- ``on_clicked``: Called on release if a widget did not scroll (regardless of long press). +- ``on_released``: Called in every case when a widget has been released. +- ``on_scroll_begin``: Scrolling of the widget begins. +- ``on_scroll_end``: Scrolling of the widget ends. +- ``on_scroll``: A widget was scrolled. +- ``on_focused``: A widget is focused. +- ``on_defocused``: A widget is unfocused. + +These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself support generating such events. + +.. code-block:: yaml + + lvgl: + widgets: + btn: + ... + on_released: + then: + - light.turn_off: + id: display_backlight + + + Data types ---------- diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 099a171cd..db67db79b 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -19,7 +19,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the sensor. -- **obj** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. +- **widget** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. - All other options from :ref:`Sensor `. @@ -29,7 +29,7 @@ Example: sensor: - platform: lvgl - obj: arc_id + widget: arc_id name: LVGL Arc diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 518c169f3..be966744c 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -19,7 +19,7 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the switch. -- **obj** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. +- **widget** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. - All other options from :ref:`Switch `. From ebedbfda8898fcfa3b2c27371e7d531f25443822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 12 Jan 2024 15:05:28 +0100 Subject: [PATCH 071/350] Update lvgl.rst --- components/lvgl.rst | 54 ++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ff5bedd0b..4f7f604b7 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -72,14 +72,14 @@ Configuration variables: - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. - **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. Can be omitted if there's at least a rotary encoder configured. - **touchscreen_id** (*Required*, :ref:`config-id`): ID of a touchscreen configuration- - - **long_press_time** (*Optional*, ms): Delay after which the ``on_long_pressed`` trigger will be called. Defaults to ``400ms``. - - **long_press_repeat_time** (*Optional*, ms): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` trigger will be called. Defaults to ``100ms``. + - **long_press_time** (*Optional*, ms): Delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, ms): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. - **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. Can be omitted if there's at least a touchscreen configured. - **sensor:** (*Required*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See the :ref:`common properties ` of the widgets for more information on groups. - - **long_press_time** (*Optional*, ms): Delay after which the ``on_long_pressed`` trigger will be called. Defaults to ``400ms``. - - **long_press_repeat_time** (*Optional*, ms): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` trigger will be called. Defaults to ``100ms``. + - **long_press_time** (*Optional*, ms): Delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, ms): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. - **color_depth** (*Optional*, enum): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to 1s. @@ -482,8 +482,8 @@ The Button Matrix object is a lightweight way to display multiple buttons in row Specific configuration options: -- **rows** (**Required**, list): A list for the button rows. - - **buttons** (**Required**, list): A list of buttons in a row +- **rows** (**Required**, list): A list for the button rows: + - **buttons** (**Required**, list): A list of buttons in a row: - **id** (*Optional*): An ID for a button - **text** or **symbol** (*Optional*): Text or symbol to display on the button. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1``. E.g. in a line with two buttons: btnA, width = 1 and btnB, width = 2, btnA will have 33 % width and btnB will have 66 % width. @@ -1025,20 +1025,14 @@ In addition to visual stilyng, each widget supports some boolean flags to influe - **ignore_layout** (*Optional*, boolean): make the object positionable by the layouts - **floating** (*Optional*, boolean): do not scroll the object when the parent scrolls and ignore layout - **overflow_visible** (*Optional*, boolean): do not clip the children's content to the parent's boundary -- **layout_1** (*Optional*, boolean): custom flag, free to use by layouts -- **layout_2** (*Optional*, boolean): custom flag, free to use by layouts -- **widget_1** (*Optional*, boolean): custom flag, free to use by widget -- **widget_2** (*Optional*, boolean): custom flag, free to use by widget -- **user_1** (*Optional*, boolean): custom flag, free to use by user -- **user_2** (*Optional*, boolean): custom flag, free to use by user -- **user_3** (*Optional*, boolean): custom flag, free to use by user -- **user_4** (*Optional*, boolean): custom flag, free to use by user - +- **layout_1**, **layout_2** (*Optional*, boolean): custom flags, free to use by layouts +- **widget_1**, **widget_2** (*Optional*, boolean): custom flags, free to use by widget +- **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): custom flags, free to use by user .. _lvgl-objupd-shorthands: -``lvgl.obj.hide`` and ``lvgl.obj.show`` Actions +``lvgl.widget.hide`` and ``lvgl.widget.show`` Actions ----------------------------------------------- These :ref:`actions ` are shorthands for toggling the ``hidden`` flag of any widget: @@ -1047,12 +1041,12 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` on_...: then: - - lvgl.obj.hide: my_label_id + - lvgl.widget.hide: my_label_id - delay: 0.5s - - lvgl.obj.show: my_label_id + - lvgl.widget.show: my_label_id -``lvgl.obj.disable`` and ``lvgl.obj.enable`` Actions +``lvgl.widget.disable`` and ``lvgl.widget.enable`` Actions ---------------------------------------------------- These :ref:`actions ` are shorthands for toggling the ``disabled`` state of any widget (which controls the appearance of the corresponding *disabled* style set of the theme): @@ -1061,10 +1055,10 @@ These :ref:`actions ` are shorthands for toggling the ``disabled` - on_...: then: - - lvgl.obj.disable: my_button_id + - lvgl.widget.disable: my_button_id - on_...: then: - - lvgl.obj.enable: my_button_id + - lvgl.widget.enable: my_button_id @@ -1207,7 +1201,7 @@ This :ref:`condition ` checks if LVGL is in paused state or no transition_length: 150ms -.. _lvgl-onidle-act: +.. _lvgl-onidle-trg: ``lvgl.on_idle`` Trigger ------------------------ @@ -1231,26 +1225,26 @@ The ``on_idle`` :ref:`trigger ` is activated when inactivity time be -.. _lvgl-event-act: +.. _lvgl-event-trg: Widget Event Triggers --------------------- ESPHome implements as triggers the following LVGL events: -- ``on_pressed``: A widget has been pressed. -- ``on_short_clicked``: A widget was pressed for a short period of time, then released. Not called if scrolled. -- ``on_long_pressed``: A widget has been pressed for at least the ``long_press_time`` specified in the input device configuration. Not called if scrolled. +- ``on_pressed``: The widget has been pressed. +- ``on_short_clicked``: The widget was pressed for a short period of time, then released. Not called if scrolled. +- ``on_long_pressed``: The widget has been pressed for at least the ``long_press_time`` specified in the input device configuration. Not called if scrolled. - ``on_long_pressed_repeat``: Called after ``long_press_time`` in every ``long_press_repeat_time`` ms. Not called if scrolled. - ``on_clicked``: Called on release if a widget did not scroll (regardless of long press). - ``on_released``: Called in every case when a widget has been released. - ``on_scroll_begin``: Scrolling of the widget begins. - ``on_scroll_end``: Scrolling of the widget ends. -- ``on_scroll``: A widget was scrolled. -- ``on_focused``: A widget is focused. -- ``on_defocused``: A widget is unfocused. +- ``on_scroll``: The widget was scrolled. +- ``on_focused``: The widget is focused. +- ``on_defocused``: The widget is unfocused. -These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself support generating such events. +These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself supports generating such events. .. code-block:: yaml From f117ecd45d8206c03f47488ca415601bfd869cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 12 Jan 2024 15:06:33 +0100 Subject: [PATCH 072/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4f7f604b7..ee3ec2f09 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -68,7 +68,7 @@ The widget is at the top level, and it allows main styling. It also has sub-part Configuration variables: -- **display_id** (**Required**, list): A list of displays where to render this entire LVGL configuration: +- **displays** (**Required**, list): A list of displays where to render this entire LVGL configuration: - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. - **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. Can be omitted if there's at least a rotary encoder configured. - **touchscreen_id** (*Required*, :ref:`config-id`): ID of a touchscreen configuration- From 8793e2a2aafcf358b0de3156a80882cf3d064ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 12 Jan 2024 15:08:43 +0100 Subject: [PATCH 073/350] Update lvgl.rst --- components/lvgl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ee3ec2f09..9f8556434 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1033,7 +1033,7 @@ In addition to visual stilyng, each widget supports some boolean flags to influe .. _lvgl-objupd-shorthands: ``lvgl.widget.hide`` and ``lvgl.widget.show`` Actions ------------------------------------------------ +----------------------------------------------------- These :ref:`actions ` are shorthands for toggling the ``hidden`` flag of any widget: @@ -1047,7 +1047,7 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` ``lvgl.widget.disable`` and ``lvgl.widget.enable`` Actions ----------------------------------------------------- +---------------------------------------------------------- These :ref:`actions ` are shorthands for toggling the ``disabled`` state of any widget (which controls the appearance of the corresponding *disabled* style set of the theme): @@ -1138,7 +1138,7 @@ This :ref:`action ` changes page to the next following in the con .. _lvgl-pgsh-act: ``lvgl.page.show`` Action ------------------------------ +------------------------- This :ref:`action ` shows a specific page (even the ones with ``skip`` option enabled). From 84e22eaf3f339d0304e7c1ea7a54f4504204860e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 12 Jan 2024 15:18:39 +0100 Subject: [PATCH 074/350] Update lvgl.rst --- components/lvgl.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9f8556434..516d9ef60 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -487,13 +487,13 @@ Specific configuration options: - **id** (*Optional*): An ID for a button - **text** or **symbol** (*Optional*): Text or symbol to display on the button. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1``. E.g. in a line with two buttons: btnA, width = 1 and btnB, width = 2, btnA will have 33 % width and btnB will have 66 % width. - - **control** (*Optional*): Binary flags to control behavior of the buttons: + - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): - ``HIDDEN``: Makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). - ``NO_REPEAT``: Disable repeating when the button is long pressed. - ``DISABLED``: Applies *disabled* styles and properties to the button. - ``CHECKABLE``: Enable toggling of a button, ``checked`` state will be added/removed as the button is clicked. - ``CHECKED``: Make the button checked. It will use the styles of the ``checked`` state. - - ``CLICK_TRIG``: Controls when to happen the ``on_value`` trigger: if ``true`` on *click*, if ``false`` on *press*. + - ``CLICK_TRIG``: Controls how to :ref:`trigger ` ``on_value`` : if ``true`` on *click*, if ``false`` on *press*. - ``POPOVER``: Show the button label in a popover when pressing this key. - ``RECOLOR``: Enable recoloring of button texts with #. E.g. ``It's #ff0000 red#`` - ``CUSTOM_1`` and ``CUSTOM_2``: Custom free to use flags @@ -1243,6 +1243,7 @@ ESPHome implements as triggers the following LVGL events: - ``on_scroll``: The widget was scrolled. - ``on_focused``: The widget is focused. - ``on_defocused``: The widget is unfocused. +- ``on_value``: TODO!! These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself supports generating such events. From b2559f67a86791204661b20aa35db4ba918e3817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 12 Jan 2024 18:52:43 +0100 Subject: [PATCH 075/350] Update lvgl.rst --- components/lvgl.rst | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 516d9ef60..ffeab34ac 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -317,17 +317,14 @@ The properties below are common to all widgets. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn as children of this widget. Same configuration option as at the main component. - **state** (*Optional*, string): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden withing style definitions or locally set. The state itself can be can be changed by interacting with the widget itself, or :ref:`programatically ` with ``lvgl.obj.update`` action. Can be one of: - ``default``: Normal, released state - - ``disabled``: Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.obj.enable`` and ``lvgl.obj.disable``) + - ``disabled``: Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``) - ``pressed``: Being pressed - ``checked``: Toggled or checked state - ``scrolled``: Being scrolled - ``focused``: Focused via keypad or encoder or clicked via touchpad/mouse - ``focus_key``: Focused via keypad or encoder but not via touchpad/mouse - ``edited``: Edit by an encoder - - ``user_1``: Custom state - - ``user_2``: Custom state - - ``user_3``: Custom state - - ``user_4``: Custom state + - ``user_1``, ``user_2``, ``user_3``, ``user_4``: Custom states In addition to visual stilyng, each widget supports :ref:`dynamically settable flags ` to influence the behavior at runtime. @@ -570,8 +567,6 @@ Example: The ``checkbox`` can be also integrated as a :doc:`/components/switch/lvgl`. - - ``dropdown`` ************ @@ -652,7 +647,7 @@ A label is the basic object type that is used to display text. Specific configuration options: -- **text** or **symbol** (*Required*, string): The text to display. To display an empty string, specify ``''``- +- **text** or **symbol** (*Required*, string): The text to display. To display an empty text string, specify ``''`` - **scrollbar** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar that is shown when the text is larger than the widget's size. - **selected** (*Optional*, list): Tells the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. @@ -674,8 +669,6 @@ Example: id: lbl_id text: 'Wi-Fi signal:' - - ``line`` ******** @@ -763,7 +756,6 @@ Specific configuration options: - **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the text style properties to change the appearance of the text in the selected area. - Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and text style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. - Example: .. code-block:: yaml @@ -1004,7 +996,7 @@ In addition to visual stilyng, each widget supports some boolean flags to influe hidden: true -- **hidden** (*Optional*, boolean): make the object hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.obj.show`` and ``lvgl.obj.hide`` +- **hidden** (*Optional*, boolean): make the object hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.widget.show`` and ``lvgl.widget.hide`` - **clickable** (*Optional*, boolean): make the object clickable by input devices - **click_focusable** (*Optional*, boolean): add focused state to the object when clicked - **checkable** (*Optional*, boolean): toggle checked state when the object is clicked From 436cfcc2c99095cd6683b3cc096c8216abb12e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 14 Jan 2024 17:10:35 +0100 Subject: [PATCH 076/350] Update lvgl.rst --- components/lvgl.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ffeab34ac..379032ce9 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -623,6 +623,8 @@ Specific configuration options: - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. +TODO !! supported image encodings + Example: @@ -967,7 +969,7 @@ In addition to the built-in fonts, the following symbols are also available from .. _lvgl-objupd-act: -``lvgl.obj.update`` Action +``lvgl.widget.update`` Action -------------------------- This powerful :ref:`action ` allows changing on the fly any :ref:`style property ` or :ref:`flag ` of any widget. @@ -976,7 +978,7 @@ This powerful :ref:`action ` allows changing on the fly any :ref: on_...: then: - - lvgl.obj.update: + - lvgl.widget.update: id: my_button_id bg_color: 0xFF0000 state: @@ -991,7 +993,7 @@ In addition to visual stilyng, each widget supports some boolean flags to influe on_...: then: - - lvgl.obj.update: + - lvgl.widget.update: id: my_label_id hidden: true @@ -1006,7 +1008,7 @@ In addition to visual stilyng, each widget supports some boolean flags to influe - **scroll_one** (*Optional*, boolean): allow scrolling only one snappable children - **scroll_chain_hor** (*Optional*, boolean): allow propagating the horizontal scroll to a parent - **scroll_chain_ver** (*Optional*, boolean): allow propagating the vertical scroll to a parent -- **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor** or ``scroll_chain_ver``) +- **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor | scroll_chain_ver``) - **scroll_on_focus** (*Optional*, boolean): automatically scroll object to make it visible when focused - **scroll_with_arrow** (*Optional*, boolean): allow scrolling the focused object with arrow keys - **snappable** (*Optional*, boolean): if scroll snap is enabled on the parent it can snap to this object From c92ea0e103bfe15f7577f5f0ceb2d355d413d315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 10:07:14 +0100 Subject: [PATCH 077/350] additions --- components/light/lvgl.rst | 2 +- components/lvgl.rst | 43 +++++++++++++++++++++----------------- components/switch/lvgl.rst | 2 +- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 7b5edec3d..5437735ea 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -35,7 +35,7 @@ Example: .. note:: - To have linear brightness control, set `gamma_correct` to `0`. + To have linear brightness control, ``gamma_correct`` of the light is set by default to ``0``. See Also diff --git a/components/lvgl.rst b/components/lvgl.rst index 379032ce9..81723965a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -305,8 +305,8 @@ Common properties The properties below are common to all widgets. -- **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to top left of parent or screen). If layouts are used, or if specfiyng ``align``, can be omitted for automatic placement. -- **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to to top left of the parent or screen). If layouts are used, or if specfiyng ``align``, can be omitted for automatic placement. +- **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to top left of parent or screen). If layouts are used, or if specfiyng ``align``, it is used as an offset to the calculated position (can also be negative). +- **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to to top left of the parent or screen). If layouts are used, or if specfiyng ``align``, it is used as an offset to the calculated position (can also be negative). - **width** (*Optional*): Width of the widget in pixels or a percentage, or ``size_content`` (see below). - **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents (children objects, or eg. image size in case of ``img``. - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. @@ -485,16 +485,17 @@ Specific configuration options: - **text** or **symbol** (*Optional*): Text or symbol to display on the button. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1``. E.g. in a line with two buttons: btnA, width = 1 and btnB, width = 2, btnA will have 33 % width and btnB will have 66 % width. - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): - - ``HIDDEN``: Makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). - - ``NO_REPEAT``: Disable repeating when the button is long pressed. - - ``DISABLED``: Applies *disabled* styles and properties to the button. - - ``CHECKABLE``: Enable toggling of a button, ``checked`` state will be added/removed as the button is clicked. - - ``CHECKED``: Make the button checked. It will use the styles of the ``checked`` state. - - ``CLICK_TRIG``: Controls how to :ref:`trigger ` ``on_value`` : if ``true`` on *click*, if ``false`` on *press*. - - ``POPOVER``: Show the button label in a popover when pressing this key. - - ``RECOLOR``: Enable recoloring of button texts with #. E.g. ``It's #ff0000 red#`` - - ``CUSTOM_1`` and ``CUSTOM_2``: Custom free to use flags + - **hidden** (*Optional*, boolean): makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). + - **no_repeat** (*Optional*, boolean): Disable repeating when the button is long pressed. + - **disabled** (*Optional*, boolean): applies *disabled* styles and properties to the button. + - **checkable** (*Optional*, boolean): Enable toggling of a button, ``checked`` state will be added/removed as the button is clicked. + - **checked** (*Optional*, boolean): make the button checked. It will use the styles of the ``checked`` state. + - **click_trig** (*Optional*, boolean): Controls how to :ref:`trigger ` ``on_value`` : if ``true`` on *click*, if ``false`` on *press*. TODO !!! + - **popover** (*Optional*, boolean): show the button label in a popover when pressing this key. + - **recolor** (*Optional*, boolean): Enable recoloring of button texts with #. E.g. ``It's #ff0000 red#`` + - **custom_1** and **custom_2** (*Optional*, boolean): custom free to use flags - **items** (*Optional*, list): Settings for the items **part**, the buttons all use the text and typical background style properties except translations and transformations. +- **one_checked** (*Optional*, boolean): Allow only one button to be checked at a time (aka. radio buttons). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button matrix, uses the typical background style properties. ``pad_row`` and ``pad_column`` set the space between the buttons. @@ -650,15 +651,19 @@ A label is the basic object type that is used to display text. Specific configuration options: - **text** or **symbol** (*Required*, string): The text to display. To display an empty text string, specify ``''`` +- **recolor** (*Optional*, boolean): Enable recoloring of button texts with #. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #ff0000 red# word``. +- **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. + - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) + - ``DOT``: Replaces the last 3 characters from bottom right corner of the label with dots. + - ``SCROLL``: If the text is wider than the label scroll it horizontally back and forth. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. + - ``SCROLL_CIRCULAR``: If the text is wider than the label scroll it horizontally continuously. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. + - ``CLIP``: Simply clip the parts of the text outside the label. - **scrollbar** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar that is shown when the text is larger than the widget's size. -- **selected** (*Optional*, list): Tells the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. +- **selected** (*Optional*, list): Settings for the the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. Newline characters are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``line1\nline2\n\nline4``. -It's possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #ff0000 red# word``. - -By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Example: @@ -666,10 +671,10 @@ Example: # Example widget: - label: - x: 15 - y: 235 + align: center id: lbl_id - text: 'Wi-Fi signal:' + recolor: true + text: 'Write a #ff0000 red# word' ``line`` ******** @@ -970,7 +975,7 @@ In addition to the built-in fonts, the following symbols are also available from .. _lvgl-objupd-act: ``lvgl.widget.update`` Action --------------------------- +----------------------------- This powerful :ref:`action ` allows changing on the fly any :ref:`style property ` or :ref:`flag ` of any widget. diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index be966744c..34786fa46 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -29,7 +29,7 @@ Example: switch: - platform: lvgl - obj: checkbox_id + widget: checkbox_id name: LVGL switch See Also From f94dd3f70d1112274e7cad2c674bf51331e12ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 10:41:02 +0100 Subject: [PATCH 078/350] updates --- components/images/lvgl_label.png | Bin 1654 -> 1123 bytes components/light/lvgl.rst | 3 ++- components/lvgl.rst | 11 +++++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/components/images/lvgl_label.png b/components/images/lvgl_label.png index a3d14c07c75f5346c07647b5f9bbde8c4c10c006..9a31c4ef3ec47f986f1a330506709c9b9c0ce6f7 100644 GIT binary patch literal 1123 zcmeAS@N?(olHy`uVBq!ia0vp^3xHUQg9%9PZaaR2fq_NK)5S5QBJS;M!~ENB5^eF~ zvUv{@a(NaoeD!efHoAH*V}rgrg5S7LQu()S@sUM92&QAFRpjw zm9)|FZb(^VQ}W_l*$!dPz%9NfOS|OWF|vQ!{od~G%Z2C4o4AEi+dgm+q`+MxAD&5d)j-l%>G=ji8#1d&d&0} zcl~*fKQ7)H=3M!Ysb9{#Il6E@m%KSM|Ec`_=E~FB+in|ukT~_KP)ax5u`=C!^GQk*J#9e=x|dOQ?ZV4h&6d@{$a;b)Axi!fKaYhiM0U(Wqxsm<@h z`n|4}d^J7$IZMQOKErQ4^@(-NUI)8bk2C((du}PtJ-6QKlKydl^83v5t1j-# zOMd$VJu5ynp`mPzQRsT38&M0bZ*%K$G0l1YBun9O1GE43KIXL(o?KY2e68-z(u7G1 zW2yr~R{r8~ikup|@d1;|p(S#ez3x35X2oj$IA`Lx@XEB4tM)ksRed?N?5x%7CeKp= z*}*w}A#GpSe%*VUJ@;UR?!vf4?QP;dMK4~5RtXipc&(^C@oCnYOKo*GJ>Bz!=BTl} z=y;VCJxNGyY5(oVtlR>Y#n)Kw&wRF7YJ-=U$WvCQ()()`Pbn9ivxG%s&Z|}aCi8_e zUhV0BFxM&KX@u)|F5N)na5_&oJS{x8Giif*4li1^}F34esTT&efEK0 z%;Q~>S&JuLb1ps*zT?*MyUwpB1wVgP`rGCHUiOC9**eps>nqp3DebszJ7)WMy~6Z>u=d3?{2{~K}lCR|HCrVb?@ds%9M0` zZsIy~k5mBvYV(B6=UDYl{l0B!#nSL)Q|hAAs{3r5O%6U>Zeh8)d>8xK`6cdt?kuam zhW$-E_G{aUeG2(*S7yyo^AX;=r=OXLM>Sn?`NvyX@yW&0zv$;}dNup4QDjisnWST1 z?|$u2b`&%|H`Bf63e&w^E~`x~J!dYdT6Ay*L+Xi~V-;QxU;Le7zrdz&WCae1@bD#E^Jt?=D~b2~Nf{he_|;7rt}1ruVV zgQh1>a*`B1cT4lc+t&+tN?qo5i+E+t+#k76xq8e0n+Yb?e|fk4sV6=w0(0z~dIoJ( WlPM2Y`?diK4+c+HKbLh*2~7ZgofS|3 literal 1654 zcmV-+28sEJP)bC9LIlM_TWGc8Q28}Dr9cXV4&vI4C_I0L0^cMz(Qw;2ZtU^q0Y=5;_B-R6=J!luGCfh*Ali0Z}TUGayPO zbOtx3RB2p_Mxu7>Wn634wVeM0U;6oX5W_H7mM!cT>;u=QwNf*i8J1-Y!>}3!zaWiE zR*PQIS(eo+Ismv`ZstB?9W_~8USu6)HZySHEGO4;CfqD~MUO_Jyq9NLR`3hzt_lG7 zmStI+Fxp{L0`KJmqk${x_*=UH002-B#TVlF-MqO1t)x|ttJUMGVHh+`V`Juz4Aaf9 zJuCpEpQg>}PAC_ZT1#0i{SW%#vRO8+1u;Fzxd zwrZcy9?C^+Ww-Ek?PE=OuE-N|;bj4<=pveJ5W}Jv7R}qlQbG)iTpzdf`<7|+KlG>4 zDSR!4#mHpD9I}#FN^pIg-P&w6+t1qG+4ev5dpsVlkBdx3PEJmm4(C)l#r1I>j|YvQ zy~3V#ZDLrQ{&jl#*Jqd<2#p}S z^^C}5#3mJMTs$7nUSZEVWO_E6&6AT8kH>SBuex>h2LLpT4qhFYx7l144I>mp`9Jg6 zqF40laTNuT>2p(PB`x+OCWR$+M@=jz0Km-RCecVVxsr@dMwJZ(1(7@gOrTJOBWrX4sx~m(eTw;k(1>U#9H? zt%ydV$}uCTO`eDdE=Ad=;hqDGi-Bm-ukXF(f^#%$eriYOy zWZVE)OaIMME|viRZ*F{EUnm%|Ip`HV|017UOX8uS!J+P+?%0!<)rWFXxD^Hf*29Lz zLV88Vt2ONaK)Yz?x9RixbX~U@?=1R1Ish1TLmHQG@B!E-MTOG))f;4pA;Dznceu{BFKwLe)x|*)qpw zPt}9hXA&34IsSwIVsXMCq7n_MG z&lGF!Xh++e3IO6GF}@H7fc$QLZe|V}aRVR>3hhe2&+AinRD8|eKYe?weKY{j?u*_b znxhUa4;y+EiZ8@#^%}=<<#HJ}LtS*2)vYD?bS#_8Mk7(Jq?vib z3ONT~pTg6QzwAsRkc8I(%OTvIaWcn4;sX0|EY0A2?|7st12q=hJcASK-hE7!~ z;jYp49qLT5mfO6UxTQVE^GzX$1(^j8cTKmY&$07*qoM6N<$g1fK; Ac>n+a diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 5437735ea..25d8fff4e 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -10,7 +10,7 @@ LVGL Light The ``lvgl`` light platform creates a light from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are ``led``. A single light supports +Supported widgets are :ref:``. A single light supports a single widget, thus you need to choose among which one's state you want to use. @@ -41,6 +41,7 @@ Example: See Also -------- - :ref:`LVGL Main component ` +- :ref:`LVGL LED widget ` - :doc:`/components/sensor/lvgl` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` diff --git a/components/lvgl.rst b/components/lvgl.rst index 81723965a..6bc5d40b5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -308,7 +308,7 @@ The properties below are common to all widgets. - **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to top left of parent or screen). If layouts are used, or if specfiyng ``align``, it is used as an offset to the calculated position (can also be negative). - **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to to top left of the parent or screen). If layouts are used, or if specfiyng ``align``, it is used as an offset to the calculated position (can also be negative). - **width** (*Optional*): Width of the widget in pixels or a percentage, or ``size_content`` (see below). -- **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents (children objects, or eg. image size in case of ``img``. +- **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents (children objects, text size, image size etc.) - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. - **styles** (*Optional*, :ref:`config-id`): The ID of a *style definition* from the main component configuration to override the theme styles. - **theme** (*Optional*, list): A list of styles to apply to the widget and children. Same configuration option as at the main component. @@ -651,7 +651,7 @@ A label is the basic object type that is used to display text. Specific configuration options: - **text** or **symbol** (*Required*, string): The text to display. To display an empty text string, specify ``''`` -- **recolor** (*Optional*, boolean): Enable recoloring of button texts with #. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #ff0000 red# word``. +- **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB `` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) - ``DOT``: Replaces the last 3 characters from bottom right corner of the label with dots. @@ -662,7 +662,7 @@ Specific configuration options: - **selected** (*Optional*, list): Settings for the the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. -Newline characters are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``line1\nline2\n\nline4``. +Newline characters are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``line1\nline2\n\nline4``. TODO Example: @@ -674,7 +674,8 @@ Example: align: center id: lbl_id recolor: true - text: 'Write a #ff0000 red# word' + text: '#FF0000 write# #00FF00 colored# #0000FF text#' + ``line`` ******** @@ -696,6 +697,8 @@ Example: - +.. _lvgl-wgt-led: + ``led`` ******** From cc23499f1a01109739823b93eb5bd6b4fcf92034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 11:58:22 +0100 Subject: [PATCH 079/350] updates --- components/light/lvgl.rst | 2 +- components/lvgl.rst | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 25d8fff4e..8e28f3e8d 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -10,7 +10,7 @@ LVGL Light The ``lvgl`` light platform creates a light from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are :ref:``. A single light supports +Supported widgets are :ref:`lvgl-wgt-led`. A single light supports a single widget, thus you need to choose among which one's state you want to use. diff --git a/components/lvgl.rst b/components/lvgl.rst index 6bc5d40b5..daa2189ba 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -671,7 +671,7 @@ Example: # Example widget: - label: - align: center + align: CENTER id: lbl_id recolor: true text: '#FF0000 write# #00FF00 colored# #0000FF text#' @@ -713,17 +713,24 @@ Specific configuration options: - **brightness** (*Required*, list): TODO - Style options from :ref:`lvgl-styling`, using all the typical background style properties. - Example: .. code-block:: yaml # Example widget: - - + - led: + id: led_id + align: CENTER + color: 0xFF0000 + brightness: 70% The ``led`` can be also integrated as :doc:`/components/light/lvgl`. +.. note:: + + ``color`` and ``brightness`` are overridden by the light component at startup. + ``meter`` ********* From 543d8f4ee5529d392bd79ba439f150c5deb664c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 12:23:30 +0100 Subject: [PATCH 080/350] adding widget crosslinks to components --- components/binary_sensor/lvgl.rst | 9 ++++----- components/light/lvgl.rst | 2 +- components/lvgl.rst | 21 ++++++++++++++------- components/number/lvgl.rst | 6 ++++-- components/select/lvgl.rst | 6 +++--- components/sensor/lvgl.rst | 2 ++ components/switch/lvgl.rst | 7 +++++-- 7 files changed, 33 insertions(+), 20 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 6fb0b59f5..211ecb00e 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -10,10 +10,9 @@ LVGL Binary Sensor The ``lvgl`` binary sensor platform creates a binary sensor from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are ``btn`` and ``checkbox``. A single binary sensor supports +Supported widget is :ref:`lvgl-wgt-btn`. A single binary sensor supports a single widget, thus you need to choose among which one's state you want to use. - Configuration variables: ------------------------ @@ -22,19 +21,19 @@ Configuration variables: - **widget** (**Required**): The ID of a button widget configured in LVGL. - All other options from :ref:`Binary Sensor `. - Example: .. code-block:: yaml binary_sensor: - platform: lvgl - widget: checkbox_id - name: LVGL checkbox + widget: btn_id + name: LVGL push button See Also -------- - :ref:`LVGL Main component ` +- :ref:`Button widget ` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/switch/lvgl` diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 8e28f3e8d..4a54b3fc2 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -41,7 +41,7 @@ Example: See Also -------- - :ref:`LVGL Main component ` -- :ref:`LVGL LED widget ` +- :ref:`LED widget ` - :doc:`/components/sensor/lvgl` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` diff --git a/components/lvgl.rst b/components/lvgl.rst index daa2189ba..d64ee8019 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -328,6 +328,7 @@ The properties below are common to all widgets. In addition to visual stilyng, each widget supports :ref:`dynamically settable flags ` to influence the behavior at runtime. +.. _lvgl-wgt-arc: ``arc`` ******* @@ -380,6 +381,7 @@ Example: The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. +.. _lvgl-wgt-bar: ``bar`` ******* @@ -419,6 +421,7 @@ Example: The ``bar`` can be also integrated as :doc:`/components/number/lvgl`. +.. _lvgl-wgt-btn: ``btn`` ******* @@ -539,7 +542,7 @@ Example: recolor: true - +.. _lvgl-wgt-chk: ``checkbox`` ************ @@ -568,12 +571,14 @@ Example: The ``checkbox`` can be also integrated as a :doc:`/components/switch/lvgl`. +.. _lvgl-wgt-drp: + ``dropdown`` ************ -The drop-down list allows the user to select one value from a list. +The Dropdown widget allows the user to select one value from a list. -The drop-down list is closed by default and displays a single value or a predefined text. When activated (by click on the drop-down list), a list is drawn from which the user may select one option. When the user selects a new value, the list is deleted from the screen. +The dropdown list is closed by default and displays a single value or a predefined text. When activated (by click on the drop-down list), a list is drawn from which the user may select one option. When the user selects a new value, the list is deleted from the screen. .. figure:: /components/images/lvgl_dropdown.png :align: center @@ -709,8 +714,8 @@ The LEDs are rectangle-like (or circle) object whose brightness can be adjusted. Specific configuration options: -- **color** (*Required*, list): TODO -- **brightness** (*Required*, list): TODO +- **color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background, border, and shadow of the widget. +- **brightness** (*Optional*, percentage): The brightness of the LED color, where ``0`` corresponds to black, and ``100`` corresponds to the full brightness of the color specified above. - Style options from :ref:`lvgl-styling`, using all the typical background style properties. Example: @@ -729,7 +734,7 @@ The ``led`` can be also integrated as :doc:`/components/light/lvgl`. .. note:: - ``color`` and ``brightness`` are overridden by the light component at startup. + If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup. ``meter`` @@ -755,7 +760,7 @@ Example: - - +.. _lvgl-wgt-rol: ``roller`` ********** @@ -791,6 +796,7 @@ Example: The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. +.. _lvgl-wgt-sli: ``slider`` ********** @@ -827,6 +833,7 @@ Example: The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. +.. _lvgl-wgt-swi: ``switch`` ********** diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index aa25cf54e..9a7b799da 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -10,7 +10,7 @@ LVGL Number The ``lvgl`` number platform creates a number component from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are ``arc`` and ``slider``. A single number supports +Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar` and :ref:`lvgl-wgt-sli`. A single number supports a single widget, thus you need to choose among which one's state you want to use. @@ -34,10 +34,12 @@ Example: name: LVGL Slider - See Also -------- - :ref:`LVGL Main component ` +- :ref:`Arc widget ` +- :ref:`Bar widget ` +- :ref:`Slider widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/switch/lvgl` diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index c5015babf..5fd6e9d70 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -10,10 +10,9 @@ LVGL Select The ``lvgl`` switch platform creates a select from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are ``dropdown`` and ``roller``. A single select supports +Supported widgets are :ref:`lvgl-wgt-drp` and :ref:`lvgl-wgt-rol`. A single select supports a single widget, thus you need to choose among which one's state you want to use. - Configuration variables: ------------------------ @@ -22,7 +21,6 @@ Configuration variables: - **obj** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the select. - All other options from :ref:`Switch `. - Example: .. code-block:: yaml @@ -35,6 +33,8 @@ Example: See Also -------- - :ref:`LVGL Main component ` +- :ref:`Roller widget ` +- :ref:`Dropdown widget ` - :doc:`/components/sensor/lvgl` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index db67db79b..2df218257 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -3,6 +3,8 @@ LVGL Sensor =========== +???? + .. seo:: :description: Instructions for setting up a LVGL widget sensor. :image: ../images/logo_lvgl.png diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 34786fa46..99c4066b2 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -10,8 +10,8 @@ LVGL Switch The ``lvgl`` switch platform creates a switch from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are ``btn`` (with ``checkable`` option enabled) and ``checkbox``. A single switch supports -a single widget, thus you need to choose among which one's state you want to use. +Supported widgets are :ref:`lvgl-wgt-btn` (with ``checkable`` option enabled), :ref:`lvgl-wgt-swi` and :ref:`lvgl-wgt-chk` +. A single switch supports a single widget, thus you need to choose among which one's state you want to use. Configuration variables: @@ -35,6 +35,9 @@ Example: See Also -------- - :ref:`LVGL Main component ` +- :ref:`Button widget ` +- :ref:`Switch widget ` +- :ref:`Checkbox widget ` - :doc:`/components/sensor/lvgl` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/number/lvgl` From b6cfe0660662dd29f7031b91819eb17591180ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 12:35:42 +0100 Subject: [PATCH 081/350] removing sensor component --- components/lvgl.rst | 2 +- components/sensor/lvgl.rst | 47 -------------------------------------- index.rst | 1 - 3 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 components/sensor/lvgl.rst diff --git a/components/lvgl.rst b/components/lvgl.rst index d64ee8019..2beb7cdf3 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -656,7 +656,7 @@ A label is the basic object type that is used to display text. Specific configuration options: - **text** or **symbol** (*Required*, string): The text to display. To display an empty text string, specify ``''`` -- **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB `` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. +- **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) - ``DOT``: Replaces the last 3 characters from bottom right corner of the label with dots. diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst deleted file mode 100644 index 2df218257..000000000 --- a/components/sensor/lvgl.rst +++ /dev/null @@ -1,47 +0,0 @@ -.. _lvgl-sen: - -LVGL Sensor -=========== - -???? - -.. seo:: - :description: Instructions for setting up a LVGL widget sensor. - :image: ../images/logo_lvgl.png - -The ``lvgl`` sensor platform creates a sensor from a LVGL widget -and requires :ref:`LVGL ` to be configured. - -Supported widgets are ``arc`` and ``slider``. A single sensor supports -a single widget, thus you need to choose among which one's state you want to use. - - -Configuration variables: ------------------------- - -- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **name** (**Required**, string): The name of the sensor. -- **widget** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. -- All other options from :ref:`Sensor `. - - -Example: - -.. code-block:: yaml - - sensor: - - platform: lvgl - widget: arc_id - name: LVGL Arc - - - -See Also --------- -- :ref:`LVGL Main component ` -- :doc:`/components/binary_sensor/lvgl` -- :doc:`/components/number/lvgl` -- :doc:`/components/switch/lvgl` -- :doc:`/components/select/lvgl` -- :doc:`/components/light/lvgl` -- :ghedit:`Edit` diff --git a/index.rst b/index.rst index 53eeb3201..704bfd117 100644 --- a/index.rst +++ b/index.rst @@ -390,7 +390,6 @@ Miscellaneous Integration, components/sensor/integration, sigma.svg, dark-invert Growatt Solar, components/sensor/growatt_solar, growatt.jpg, Solar rooftop Kalman Combinator, components/sensor/kalman_combinator, function.svg, dark-invert - LVGL widget, components/sensor/lvgl, logo_lvgl.png Modbus Sensor, components/sensor/modbus_controller, modbus.png Nextion, components/sensor/nextion, nextion.jpg, Sensors from display Rotary Encoder, components/sensor/rotary_encoder, rotary_encoder.jpg From 1de972a73974d218da593cc089638351201d665e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 12:44:43 +0100 Subject: [PATCH 082/350] remove *ed from triggers --- components/lvgl.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2beb7cdf3..fc3e28795 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1248,17 +1248,17 @@ Widget Event Triggers ESPHome implements as triggers the following LVGL events: -- ``on_pressed``: The widget has been pressed. -- ``on_short_clicked``: The widget was pressed for a short period of time, then released. Not called if scrolled. -- ``on_long_pressed``: The widget has been pressed for at least the ``long_press_time`` specified in the input device configuration. Not called if scrolled. -- ``on_long_pressed_repeat``: Called after ``long_press_time`` in every ``long_press_repeat_time`` ms. Not called if scrolled. -- ``on_clicked``: Called on release if a widget did not scroll (regardless of long press). -- ``on_released``: Called in every case when a widget has been released. +- ``on_press``: The widget has been pressed. +- ``on_short_click``: The widget was pressed for a short period of time, then released. Not called if scrolled. +- ``on_long_press``: The widget has been pressed for at least the ``long_press_time`` specified in the input device configuration. Not called if scrolled. +- ``on_long_press_repeat``: Called after ``long_press_time`` in every ``long_press_repeat_time`` ms. Not called if scrolled. +- ``on_click``: Called on release if a widget did not scroll (regardless of long press). +- ``on_release``: Called in every case when a widget has been released. - ``on_scroll_begin``: Scrolling of the widget begins. - ``on_scroll_end``: Scrolling of the widget ends. - ``on_scroll``: The widget was scrolled. -- ``on_focused``: The widget is focused. -- ``on_defocused``: The widget is unfocused. +- ``on_focus``: The widget is focused. +- ``on_defocus``: The widget is unfocused. - ``on_value``: TODO!! These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself supports generating such events. From 9f16c77be62063ae3e74905423181e888f21e3e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 12:47:51 +0100 Subject: [PATCH 083/350] fix links --- components/binary_sensor/lvgl.rst | 1 - components/light/lvgl.rst | 1 - components/number/lvgl.rst | 1 - components/select/lvgl.rst | 1 - components/switch/lvgl.rst | 1 - 5 files changed, 5 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 211ecb00e..f2a7763e3 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -34,7 +34,6 @@ See Also -------- - :ref:`LVGL Main component ` - :ref:`Button widget ` -- :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/select/lvgl` diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 4a54b3fc2..98172eb74 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -42,7 +42,6 @@ See Also -------- - :ref:`LVGL Main component ` - :ref:`LED widget ` -- :doc:`/components/sensor/lvgl` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/number/lvgl` diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 9a7b799da..f1def3713 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -41,7 +41,6 @@ See Also - :ref:`Bar widget ` - :ref:`Slider widget ` - :doc:`/components/binary_sensor/lvgl` -- :doc:`/components/sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 5fd6e9d70..cd56df20a 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -35,7 +35,6 @@ See Also - :ref:`LVGL Main component ` - :ref:`Roller widget ` - :ref:`Dropdown widget ` -- :doc:`/components/sensor/lvgl` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/number/lvgl` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 99c4066b2..5623ea0cf 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -38,7 +38,6 @@ See Also - :ref:`Button widget ` - :ref:`Switch widget ` - :ref:`Checkbox widget ` -- :doc:`/components/sensor/lvgl` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/select/lvgl` From 56cb93a8c675318ea7902636089e94d9bc1c81a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 13:52:34 +0100 Subject: [PATCH 084/350] Update lvgl.rst --- components/lvgl.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index fc3e28795..acc219cb2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -358,7 +358,7 @@ Specific configuration options: - any :ref:`Styling ` and state-based option to override styles inherited from parent. The arc's size and position will respect the padding style properties. -If the ``adv_hittest`` flag is enabled the arc can be clicked through in the middle. Clicks are recognized only on the ring of the background arc. +If the ``adv_hittest`` :ref:`flag ` is enabled the arc can be clicked through in the middle. Clicks are recognized only on the ring of the background arc. .. note:: @@ -433,7 +433,7 @@ Simple push or toggle button. Specific configuration options: -- **checkable** (*Optional*, boolean): A significant flag to make a toggle button (which remains pressed in ``checked`` state). Defaults to ``false``. +- **checkable** (*Optional*, boolean): A significant :ref:`flag ` to make a toggle button (which remains pressed in ``checked`` state). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button. Uses the typical background style properties. Example: @@ -713,6 +713,7 @@ The LEDs are rectangle-like (or circle) object whose brightness can be adjusted. :align: center Specific configuration options: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - **color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background, border, and shadow of the widget. - **brightness** (*Optional*, percentage): The brightness of the LED color, where ``0`` corresponds to black, and ``100`` corresponds to the full brightness of the color specified above. @@ -729,6 +730,10 @@ Example: color: 0xFF0000 brightness: 70% +Specific actions: +^^^^^^^^^^^^^^^^^ + +- **lvgl.led.update** The ``led`` can be also integrated as :doc:`/components/light/lvgl`. @@ -1051,7 +1056,7 @@ In addition to visual stilyng, each widget supports some boolean flags to influe ``lvgl.widget.hide`` and ``lvgl.widget.show`` Actions ----------------------------------------------------- -These :ref:`actions ` are shorthands for toggling the ``hidden`` flag of any widget: +These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget: .. code-block:: yaml From 698baa384bc4af0a6ce3beb4d8adbc10e859b25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 14:08:53 +0100 Subject: [PATCH 085/350] Update lvgl.rst --- components/lvgl.rst | 49 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index acc219cb2..c8a388c2e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -315,7 +315,7 @@ The properties below are common to all widgets. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Same configuration option as at the main component. - **flex_flow** (*Optional*, string): Option for ``FLEX`` layout, similar configuration as at the main component. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn as children of this widget. Same configuration option as at the main component. -- **state** (*Optional*, string): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden withing style definitions or locally set. The state itself can be can be changed by interacting with the widget itself, or :ref:`programatically ` with ``lvgl.obj.update`` action. Can be one of: +- **state** (*Optional*, string): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden withing style definitions or locally set. The state itself can be can be changed by interacting with the widget itself, or :ref:`programatically ` with ``lvgl.widget.update`` action. Can be one of: - ``default``: Normal, released state - ``disabled``: Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``) - ``pressed``: Being pressed @@ -338,7 +338,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator .. figure:: /components/images/lvgl_arc.png :align: center -Specific configuration options: +Specific options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. @@ -395,7 +395,7 @@ Vertical bars can be created if the width of the object is smaller than its heig Not only the end, but also the start value of the bar can be set, which changes the start position of the indicator. -Specific configuration options: +Specific options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. @@ -431,7 +431,7 @@ Simple push or toggle button. .. figure:: /components/images/lvgl_button.png :align: center -Specific configuration options: +Specific options: - **checkable** (*Optional*, boolean): A significant :ref:`flag ` to make a toggle button (which remains pressed in ``checked`` state). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button. Uses the typical background style properties. @@ -480,7 +480,7 @@ The Button Matrix object is a lightweight way to display multiple buttons in row .. figure:: /components/images/lvgl_btnmatrix.png :align: center -Specific configuration options: +Specific options: - **rows** (**Required**, list): A list for the button rows: - **buttons** (**Required**, list): A list of buttons in a row: @@ -552,7 +552,7 @@ The Checkbox object is made internally from a "tick box" and a label. When the C .. figure:: /components/images/lvgl_checkbox.png :align: center -Specific configuration options: +Specific options: - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The "tick box" is a square that uses all the typical background style properties. By default, its size is equal to the height of the main part's font. Padding properties make the tick box larger in the respective directions. - Style options from :ref:`lvgl-styling` for the background of the widget and it uses the text and all the typical background style properties. ``pad_column`` adjusts the spacing between the tickbox and the label. @@ -585,7 +585,7 @@ The dropdown list is closed by default and displays a single value or a predefin The Dropdown widget is built internall from a *button* and a *list* (both not related to the actual widgets with the same name). -Specific configuration options: +Specific options: - **options** (*Required*, list): The list of available options in the drop-down. - **dir** (*Optional*, enum): Where the list part of the dropdown gets created relative to the button part. ``LEFT``, ``RIGHT``, ``BOTTOM``, ``TOP``, defaults to ``BOTTOM``. @@ -623,7 +623,7 @@ Images are the basic widgets to display images. .. figure:: /components/images/lvgl_image.png :align: center -Specific configuration options: +Specific options: - **src** (**Required**, :ref:`image `): The ID of an existing image configuration. - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. @@ -653,7 +653,7 @@ A label is the basic object type that is used to display text. .. figure:: /components/images/lvgl_label.png :align: center -Specific configuration options: +Specific options: - **text** or **symbol** (*Required*, string): The text to display. To display an empty text string, specify ``''`` - **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. @@ -687,7 +687,7 @@ Example: The Line object is capable of drawing straight lines between a set of points. -Specific configuration options: +Specific options: - **points** (*Required*, list): TODO - Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. @@ -712,13 +712,16 @@ The LEDs are rectangle-like (or circle) object whose brightness can be adjusted. .. figure:: /components/images/lvgl_led.png :align: center -Specific configuration options: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Specific options: - **color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background, border, and shadow of the widget. - **brightness** (*Optional*, percentage): The brightness of the LED color, where ``0`` corresponds to black, and ``100`` corresponds to the full brightness of the color specified above. - Style options from :ref:`lvgl-styling`, using all the typical background style properties. +Specific actions: + +``lvgl.led.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + Example: .. code-block:: yaml @@ -730,10 +733,6 @@ Example: color: 0xFF0000 brightness: 70% -Specific actions: -^^^^^^^^^^^^^^^^^ - -- **lvgl.led.update** The ``led`` can be also integrated as :doc:`/components/light/lvgl`. @@ -747,7 +746,7 @@ The ``led`` can be also integrated as :doc:`/components/light/lvgl`. The Meter widget can visualize data in very flexible ways. In can show arcs, needles, ticks lines and labels. -Specific configuration options: +Specific options: TODO !!! @@ -775,7 +774,7 @@ Roller allows you to simply select one option from a list by scrolling. .. figure:: /components/images/lvgl_roller.png :align: center -Specific configuration options: +Specific options: - **options** (*Required*, list): The list of available options in the roller. - **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. @@ -811,7 +810,7 @@ The Slider object looks like a Bar supplemented with a knob. The knob can be dra .. figure:: /components/images/lvgl_slider.png :align: center -Specific configuration options: +Specific options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. @@ -848,7 +847,7 @@ The Switch looks like a little slider and can be used to turn something on and o .. figure:: /components/images/lvgl_switch.png :align: center -Specific configuration options: +Specific options: - **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. @@ -877,7 +876,7 @@ Tables, as usual, are built from rows, columns, and cells containing texts. The Table object is very lightweight because only the texts are stored. No real objects are created for cells but they are just drawn on the fly. -Specific configuration options: +Specific options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **items** (*Optional*, list): Settings for the items **part** @@ -900,7 +899,7 @@ The Text Area is a Base object with a Label and a cursor on it. Texts or charact One line mode and password modes are supported. -Specific configuration options: +Specific options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **scrollbar** (*Optional*, list): Settings for the scrollbar **part** @@ -922,7 +921,7 @@ Example: A Canvas inherits from Image where the user can draw anything. Rectangles, texts, images, lines, arcs can be drawn here using lvgl's drawing engine. Additionally "effects" can be applied, such as rotation, zoom and blur. -Specific configuration options: +Specific options: - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - Style options from :ref:`lvgl-styling`. @@ -948,7 +947,7 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo You can use it as a parent background shape for other objects. It catches touches! -Specific configuration options: +Specific options: - Style options from :ref:`lvgl-styling`. @@ -999,7 +998,7 @@ In addition to the built-in fonts, the following symbols are also available from ``lvgl.widget.update`` Action ----------------------------- -This powerful :ref:`action ` allows changing on the fly any :ref:`style property ` or :ref:`flag ` of any widget. +This powerful :ref:`action ` allows changing on the fly any common :ref:`style property ` or :ref:`flag ` of any widget. .. code-block:: yaml From 9a594a812b86d5baefa37f90940a5eb03f6e3eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 15:30:35 +0100 Subject: [PATCH 086/350] Update lvgl.rst --- components/lvgl.rst | 81 ++++++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c8a388c2e..2d2f14f27 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -338,7 +338,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator .. figure:: /components/images/lvgl_arc.png :align: center -Specific options: +**Specific options:** - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. @@ -365,6 +365,10 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can Zero degree is at the middle right (3 o'clock) of the object and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. +**Specific actions:** + +``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + Example: .. code-block:: yaml @@ -395,7 +399,7 @@ Vertical bars can be created if the width of the object is smaller than its heig Not only the end, but also the start value of the bar can be set, which changes the start position of the indicator. -Specific options: +**Specific options:** - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. @@ -431,11 +435,15 @@ Simple push or toggle button. .. figure:: /components/images/lvgl_button.png :align: center -Specific options: +**Specific options:** - **checkable** (*Optional*, boolean): A significant :ref:`flag ` to make a toggle button (which remains pressed in ``checked`` state). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button. Uses the typical background style properties. +**Specific actions:** + +``lvgl.button.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + Example: .. code-block:: yaml @@ -480,12 +488,12 @@ The Button Matrix object is a lightweight way to display multiple buttons in row .. figure:: /components/images/lvgl_btnmatrix.png :align: center -Specific options: +**Specific options:** - **rows** (**Required**, list): A list for the button rows: - **buttons** (**Required**, list): A list of buttons in a row: - **id** (*Optional*): An ID for a button - - **text** or **symbol** (*Optional*): Text or symbol to display on the button. + - **text** or **symbol** (*Optional*): Text or built-in symbol to display on the button. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1``. E.g. in a line with two buttons: btnA, width = 1 and btnB, width = 2, btnA will have 33 % width and btnB will have 66 % width. - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): - **hidden** (*Optional*, boolean): makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). @@ -501,6 +509,9 @@ Specific options: - **one_checked** (*Optional*, boolean): Allow only one button to be checked at a time (aka. radio buttons). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button matrix, uses the typical background style properties. ``pad_row`` and ``pad_column`` set the space between the buttons. +**Specific actions:** + +``lvgl.button.update`` :ref:`action ` updates the button styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Example: @@ -552,11 +563,14 @@ The Checkbox object is made internally from a "tick box" and a label. When the C .. figure:: /components/images/lvgl_checkbox.png :align: center -Specific options: +**Specific options:** - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The "tick box" is a square that uses all the typical background style properties. By default, its size is equal to the height of the main part's font. Padding properties make the tick box larger in the respective directions. - Style options from :ref:`lvgl-styling` for the background of the widget and it uses the text and all the typical background style properties. ``pad_column`` adjusts the spacing between the tickbox and the label. +**Specific actions:** + +``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Example: @@ -585,7 +599,7 @@ The dropdown list is closed by default and displays a single value or a predefin The Dropdown widget is built internall from a *button* and a *list* (both not related to the actual widgets with the same name). -Specific options: +**Specific options:** - **options** (*Required*, list): The list of available options in the drop-down. - **dir** (*Optional*, enum): Where the list part of the dropdown gets created relative to the button part. ``LEFT``, ``RIGHT``, ``BOTTOM``, ``TOP``, defaults to ``BOTTOM``. @@ -595,6 +609,9 @@ Specific options: - **symbol** (*Optional*, enum): A symbol (typically an chevron) is shown in dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. Choose a different :ref:`symbol ` from the built-in ones. - Style options from :ref:`lvgl-styling` for the background of the button and the list. Uses the typical background properties and text properties for the text on it. ``max_height`` can be used to limit the height of the list. +**Specific actions:** + +``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Example: @@ -623,7 +640,11 @@ Images are the basic widgets to display images. .. figure:: /components/images/lvgl_image.png :align: center -Specific options: +**Specific actions:** + +``lvgl.img.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +**Specific options:** - **src** (**Required**, :ref:`image `): The ID of an existing image configuration. - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. @@ -653,9 +674,9 @@ A label is the basic object type that is used to display text. .. figure:: /components/images/lvgl_label.png :align: center -Specific options: +**Specific options:** -- **text** or **symbol** (*Required*, string): The text to display. To display an empty text string, specify ``''`` +- **text** or **symbol** (*Required*, string): The text or built-in symbol to display. To display an empty label, specify ``" "`` (space). - **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) @@ -669,6 +690,9 @@ Specific options: Newline characters are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``line1\nline2\n\nline4``. TODO +**Specific actions:** + +``lvgl.label.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Example: @@ -687,13 +711,17 @@ Example: The Line object is capable of drawing straight lines between a set of points. -Specific options: +**Specific options:** - **points** (*Required*, list): TODO - Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. By default, the Line's width and height are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts on the line may not be visible. +**Specific actions:** + +``lvgl.indicator.line.update`` :ref:`action ` updates the line indicator styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + Example: .. code-block:: yaml @@ -712,13 +740,13 @@ The LEDs are rectangle-like (or circle) object whose brightness can be adjusted. .. figure:: /components/images/lvgl_led.png :align: center -Specific options: +**Specific options:** - **color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background, border, and shadow of the widget. - **brightness** (*Optional*, percentage): The brightness of the LED color, where ``0`` corresponds to black, and ``100`` corresponds to the full brightness of the color specified above. - Style options from :ref:`lvgl-styling`, using all the typical background style properties. -Specific actions: +**Specific actions:** ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. @@ -746,7 +774,7 @@ The ``led`` can be also integrated as :doc:`/components/light/lvgl`. The Meter widget can visualize data in very flexible ways. In can show arcs, needles, ticks lines and labels. -Specific options: +**Specific options:** TODO !!! @@ -774,7 +802,7 @@ Roller allows you to simply select one option from a list by scrolling. .. figure:: /components/images/lvgl_roller.png :align: center -Specific options: +**Specific options:** - **options** (*Required*, list): The list of available options in the roller. - **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. @@ -782,6 +810,10 @@ Specific options: - **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the text style properties to change the appearance of the text in the selected area. - Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and text style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. +**Specific actions:** + +``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + Example: .. code-block:: yaml @@ -810,7 +842,7 @@ The Slider object looks like a Bar supplemented with a knob. The knob can be dra .. figure:: /components/images/lvgl_slider.png :align: center -Specific options: +**Specific options:** - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. @@ -821,6 +853,10 @@ Specific options: Normally, the slider can be adjusted either by dragging the knob, or by clicking on the slider bar. In the latter case the knob moves to the point clicked and slider value changes accordingly. In some cases it is desirable to set the slider to react on dragging the knob only. This feature is enabled by enabling the ``adv_hittest`` flag. +**Specific actions:** + +``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + Example: .. code-block:: yaml @@ -847,7 +883,7 @@ The Switch looks like a little slider and can be used to turn something on and o .. figure:: /components/images/lvgl_switch.png :align: center -Specific options: +**Specific options:** - **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. @@ -876,7 +912,7 @@ Tables, as usual, are built from rows, columns, and cells containing texts. The Table object is very lightweight because only the texts are stored. No real objects are created for cells but they are just drawn on the fly. -Specific options: +**Specific options:** - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **items** (*Optional*, list): Settings for the items **part** @@ -891,7 +927,6 @@ Example: - - ``textarea`` ************ @@ -899,7 +934,7 @@ The Text Area is a Base object with a Label and a cursor on it. Texts or charact One line mode and password modes are supported. -Specific options: +**Specific options:** - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **scrollbar** (*Optional*, list): Settings for the scrollbar **part** @@ -921,7 +956,7 @@ Example: A Canvas inherits from Image where the user can draw anything. Rectangles, texts, images, lines, arcs can be drawn here using lvgl's drawing engine. Additionally "effects" can be applied, such as rotation, zoom and blur. -Specific options: +**Specific options:** - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - Style options from :ref:`lvgl-styling`. @@ -947,7 +982,7 @@ The Base Object can be directly used as a simple, empty widget. It is nothing mo You can use it as a parent background shape for other objects. It catches touches! -Specific options: +**Specific options:** - Style options from :ref:`lvgl-styling`. @@ -987,7 +1022,7 @@ These may not contain all the glyphs corresponding to certain diacritic characte In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. -In addition to the built-in fonts, the following symbols are also available from the `FontAwesome `__ font. You can use them on supported widgets using the ``symbol`` configuration option: +In addition to the built-in fonts, the following built-in symbols are also available from the `FontAwesome `__ font. You can use them on supported widgets using the ``symbol`` configuration option: .. figure:: /components/images/lvgl_symbols.png :align: center From 604a7ab8f13b82c927909a62d588769a9cb8d525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 15:42:27 +0100 Subject: [PATCH 087/350] Update lvgl.rst --- components/lvgl.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2d2f14f27..d0aa2613f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -507,11 +507,12 @@ The Button Matrix object is a lightweight way to display multiple buttons in row - **custom_1** and **custom_2** (*Optional*, boolean): custom free to use flags - **items** (*Optional*, list): Settings for the items **part**, the buttons all use the text and typical background style properties except translations and transformations. - **one_checked** (*Optional*, boolean): Allow only one button to be checked at a time (aka. radio buttons). Defaults to ``false``. +- **selected** (*Optional*, boolean): To return the index of the most recently released or focused button. Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button matrix, uses the typical background style properties. ``pad_row`` and ``pad_column`` set the space between the buttons. **Specific actions:** -``lvgl.button.update`` :ref:`action ` updates the button styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.button.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Example: @@ -552,6 +553,15 @@ Example: control: recolor: true + # Example action: + on_...: + then: + - lvgl.button.update: + id: button_1 + width: 1 + selected: true + control: + checkable: false .. _lvgl-wgt-chk: From a613059e39c4388902cfb980704f93b297ac7ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 15 Jan 2024 15:49:52 +0100 Subject: [PATCH 088/350] Update lvgl.rst --- components/lvgl.rst | 60 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d0aa2613f..210f60567 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -383,6 +383,11 @@ Example: max_value: 100 adjustable: true + # Example action: + on_...: + then: + - lvgl.arc.update + The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. .. _lvgl-wgt-bar: @@ -440,10 +445,6 @@ Simple push or toggle button. - **checkable** (*Optional*, boolean): A significant :ref:`flag ` to make a toggle button (which remains pressed in ``checked`` state). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button. Uses the typical background style properties. -**Specific actions:** - -``lvgl.button.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - Example: .. code-block:: yaml @@ -456,7 +457,6 @@ Example: height: 30 id: btn_id - To have a button with a text label on it, add a ``label`` widget as child to it: .. code-block:: yaml @@ -495,6 +495,7 @@ The Button Matrix object is a lightweight way to display multiple buttons in row - **id** (*Optional*): An ID for a button - **text** or **symbol** (*Optional*): Text or built-in symbol to display on the button. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1``. E.g. in a line with two buttons: btnA, width = 1 and btnB, width = 2, btnA will have 33 % width and btnB will have 66 % width. + - **selected** (*Optional*, boolean): Set the button as the most recently released or focused. Defaults to ``false``. - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): - **hidden** (*Optional*, boolean): makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). - **no_repeat** (*Optional*, boolean): Disable repeating when the button is long pressed. @@ -507,7 +508,6 @@ The Button Matrix object is a lightweight way to display multiple buttons in row - **custom_1** and **custom_2** (*Optional*, boolean): custom free to use flags - **items** (*Optional*, list): Settings for the items **part**, the buttons all use the text and typical background style properties except translations and transformations. - **one_checked** (*Optional*, boolean): Allow only one button to be checked at a time (aka. radio buttons). Defaults to ``false``. -- **selected** (*Optional*, boolean): To return the index of the most recently released or focused button. Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button matrix, uses the typical background style properties. ``pad_row`` and ``pad_column`` set the space between the buttons. **Specific actions:** @@ -593,6 +593,12 @@ Example: id: checkbox_id text: Checkbox + # Example action: + on_...: + then: + - lvgl. + + The ``checkbox`` can be also integrated as a :doc:`/components/switch/lvgl`. .. _lvgl-wgt-drp: @@ -639,6 +645,12 @@ Example: - Piano - Bassoon + # Example action: + on_...: + then: + - lvgl. + + The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. @@ -676,6 +688,12 @@ Example: radius: 11 clip_corner: true + # Example action: + on_...: + then: + - lvgl. + + ``label`` ********* @@ -715,6 +733,12 @@ Example: recolor: true text: '#FF0000 write# #00FF00 colored# #0000FF text#' + # Example action: + on_...: + then: + - lvgl. + + ``line`` ******** @@ -740,6 +764,12 @@ Example: - + # Example action: + on_...: + then: + - lvgl. + + .. _lvgl-wgt-led: ``led`` @@ -771,6 +801,12 @@ Example: color: 0xFF0000 brightness: 70% + # Example action: + on_...: + then: + - lvgl. + + The ``led`` can be also integrated as :doc:`/components/light/lvgl`. @@ -840,6 +876,12 @@ Example: - Chello - Drums + # Example action: + on_...: + then: + - lvgl. + + The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. .. _lvgl-wgt-sli: @@ -881,6 +923,12 @@ Example: min_value: 1 max_value: 100 + # Example action: + on_...: + then: + - lvgl. + + The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. .. _lvgl-wgt-swi: From 4fe6de1c7e9e923364289eaf72f9695ea92bf732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 16 Jan 2024 12:40:11 +0100 Subject: [PATCH 089/350] light upd --- components/light/lvgl.rst | 1 - components/lvgl.rst | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 98172eb74..e4cd80826 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -20,7 +20,6 @@ Configuration variables: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the light. - **led** (**Required**): The ID of a ``led`` widget configured in LVGL, which will reflect the state of the light. -- **output_id** (**Required**): TODO - All other options from :ref:`light `. diff --git a/components/lvgl.rst b/components/lvgl.rst index 210f60567..ce9fafb1e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -812,7 +812,7 @@ The ``led`` can be also integrated as :doc:`/components/light/lvgl`. .. note:: - If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup. + If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. ``meter`` From f624c95097bf12957a73736745698eda02771225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 16 Jan 2024 14:26:15 +0100 Subject: [PATCH 090/350] Update lvgl.rst --- components/lvgl.rst | 69 +++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ce9fafb1e..269c7e8c0 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -387,6 +387,11 @@ Example: on_...: then: - lvgl.arc.update + id: arc_id + knob: + bg_color: 0x00FF00 + value: 55 + The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. @@ -596,8 +601,11 @@ Example: # Example action: on_...: then: - - lvgl. - + - lvgl.checkbox.update: + id: checkbox_id + state: + checked: true + text: Checked The ``checkbox`` can be also integrated as a :doc:`/components/switch/lvgl`. @@ -619,6 +627,7 @@ The Dropdown widget is built internall from a *button* and a *list* (both not re - **options** (*Required*, list): The list of available options in the drop-down. - **dir** (*Optional*, enum): Where the list part of the dropdown gets created relative to the button part. ``LEFT``, ``RIGHT``, ``BOTTOM``, ``TOP``, defaults to ``BOTTOM``. +- **selected_index** (*Optional*, int8): The index of the item you wish to be selected. - **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Refers to the currently pressed, checked or pressed+checked option. Uses the typical background properties. - **scrollbar** (*Optional*, list): Settings for the scrollbar **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar background, border, shadow properties and width (for its own width) and right padding for the spacing on the right. - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and is the parent of ``symbol``. @@ -648,8 +657,9 @@ Example: # Example action: on_...: then: - - lvgl. - + - lvgl.dropdown.update: + id: dropdown_id + selected_index: 3 The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. @@ -662,18 +672,16 @@ Images are the basic widgets to display images. .. figure:: /components/images/lvgl_image.png :align: center -**Specific actions:** - -``lvgl.img.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **Specific options:** - **src** (**Required**, :ref:`image `): The ID of an existing image configuration. - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. - TODO !! supported image encodings +**Specific actions:** + +``lvgl.img.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Example: @@ -691,7 +699,9 @@ Example: # Example action: on_...: then: - - lvgl. + - lvgl.img.update: + id: img_id + src: dog_image ``label`` @@ -733,12 +743,15 @@ Example: recolor: true text: '#FF0000 write# #00FF00 colored# #0000FF text#' - # Example action: + # Example action (update label with a value from a sensor): on_...: then: - - lvgl. - - + - lvgl.label.update: + id: lbl_id + text: !lambda |- + static char buf[10]; + snprintf(buf, 10, "%.0fdBm", id(wifi_signal_db).get_state()); + return buf; ``line`` ******** @@ -752,7 +765,7 @@ The Line object is capable of drawing straight lines between a set of points. By default, the Line's width and height are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts on the line may not be visible. -**Specific actions:** +**Specific actions:** ??? ``lvgl.indicator.line.update`` :ref:`action ` updates the line indicator styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. @@ -830,6 +843,11 @@ TODO !!! - **r_mod** (*Optional*): TODO in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the object based on its contents. - Style options from :ref:`lvgl-styling`. +**Specific actions:** + +``lvgl.indicator.line.update`` :ref:`action ` updates the line indicator styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + + Example: .. code-block:: yaml @@ -837,6 +855,14 @@ Example: # Example widget: - + # Example action: + on_...: + then: + - lvgl.indicator.line.update: + id: minute_hand + value: !lambda |- + return id(time_comp).now().minute; + .. _lvgl-wgt-rol: @@ -854,6 +880,7 @@ Roller allows you to simply select one option from a list by scrolling. - **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. - **visible_rows** TODO - **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the text style properties to change the appearance of the text in the selected area. +- **selected_index** (*Optional*, int8): The index of the item you wish to be selected. - Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and text style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. **Specific actions:** @@ -879,8 +906,9 @@ Example: # Example action: on_...: then: - - lvgl. - + - lvgl.roller.update: + id: roller_id + selected_index: 5 The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. @@ -901,6 +929,7 @@ The Slider object looks like a Bar supplemented with a knob. The knob can be dra - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. A rectangle (or circle) drawn at the current value. Also uses all the typical background properties to describe the knob. By default, the knob is square (with an optional corner radius) with side length equal to the smaller side of the slider. The knob can be made larger with the padding values. Padding values can be asymmetric too. - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The indicator that shows the current state of the slider. Also uses all the typical background style properties. +- **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. - any :ref:`Styling ` and state-based option for the background of the slider. Uses all the typical background style properties. Padding makes the indicator smaller in the respective direction. Normally, the slider can be adjusted either by dragging the knob, or by clicking on the slider bar. In the latter case the knob moves to the point clicked and slider value changes accordingly. In some cases it is desirable to set the slider to react on dragging the knob only. This feature is enabled by enabling the ``adv_hittest`` flag. @@ -926,7 +955,11 @@ Example: # Example action: on_...: then: - - lvgl. + - lvgl.slider.update: + id: slider_id + knob: + bg_color: 0x00FF00 + value: 55 The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. From 703e6df1136523e4a1bd17450b77a2673fa22dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 16 Jan 2024 14:40:39 +0100 Subject: [PATCH 091/350] Update lvgl.rst --- components/lvgl.rst | 71 +++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 269c7e8c0..491d1a925 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -107,7 +107,7 @@ Configuration variables: - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. -Example: +**Example:** .. code-block:: yaml @@ -369,7 +369,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -419,7 +419,7 @@ Not only the end, but also the start value of the bar can be set, which changes - **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. - Style options from :ref:`lvgl-styling`. The background of the bar and it uses the typical background style properties. Adding padding makes the indicator smaller or larger. -Example: +**Example:** .. code-block:: yaml @@ -450,7 +450,7 @@ Simple push or toggle button. - **checkable** (*Optional*, boolean): A significant :ref:`flag ` to make a toggle button (which remains pressed in ``checked`` state). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button. Uses the typical background style properties. -Example: +**Example:** .. code-block:: yaml @@ -519,7 +519,7 @@ The Button Matrix object is a lightweight way to display multiple buttons in row ``lvgl.button.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -587,7 +587,7 @@ The Checkbox object is made internally from a "tick box" and a label. When the C ``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -638,7 +638,7 @@ The Dropdown widget is built internall from a *button* and a *list* (both not re ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -683,7 +683,7 @@ TODO !! supported image encodings ``lvgl.img.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -732,7 +732,7 @@ Newline characters are handled automatically by the label widget. You can use `` ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -769,7 +769,7 @@ By default, the Line's width and height are set to ``size_content``. This means ``lvgl.indicator.line.update`` :ref:`action ` updates the line indicator styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -803,7 +803,7 @@ The LEDs are rectangle-like (or circle) object whose brightness can be adjusted. ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -843,12 +843,45 @@ TODO !!! - **r_mod** (*Optional*): TODO in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the object based on its contents. - Style options from :ref:`lvgl-styling`. + + + + + - meter: # Gradient color arc + height: 160 + width: 160 + align: center + bg_color: 0 + scales: + angle_range: 360 + rotation: 255 + range_from: 0 + range_to: 12 + ticks: + width: 35 + count: 13 + length: 8 + indicators: + - ticks: + local: true + start_value: 0 + end_value: 12 + color_start: 0xFF0000 + color_end: 0x0000FF + - meter: + + + + + + + **Specific actions:** ``lvgl.indicator.line.update`` :ref:`action ` updates the line indicator styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -887,7 +920,7 @@ Roller allows you to simply select one option from a list by scrolling. ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -938,7 +971,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -Example: +**Example:** .. code-block:: yaml @@ -980,7 +1013,7 @@ The Switch looks like a little slider and can be used to turn something on and o - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. - Style options from :ref:`lvgl-styling`. -Example: +**Example:** .. code-block:: yaml @@ -1010,7 +1043,7 @@ The Table object is very lightweight because only the texts are stored. No real - Style options from :ref:`lvgl-styling`. -Example: +**Example:** .. code-block:: yaml @@ -1034,7 +1067,7 @@ One line mode and password modes are supported. - **textarea_placeholder** (*Optional*, list): Settings for the textarea_placeholder **part** - Style options from :ref:`lvgl-styling`. -Example: +**Example:** .. code-block:: yaml @@ -1053,7 +1086,7 @@ A Canvas inherits from Image where the user can draw anything. Rectangles, texts - Style options from :ref:`lvgl-styling`. -Example: +**Example:** .. code-block:: yaml @@ -1078,7 +1111,7 @@ You can use it as a parent background shape for other objects. It catches touche - Style options from :ref:`lvgl-styling`. -Example: +**Example:** .. code-block:: yaml From e60d50d24e51ce003004513e901354ab5a79243c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 16 Jan 2024 14:43:08 +0100 Subject: [PATCH 092/350] Update lvgl.rst --- components/lvgl.rst | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 491d1a925..01f4b141e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -844,38 +844,6 @@ TODO !!! - Style options from :ref:`lvgl-styling`. - - - - - meter: # Gradient color arc - height: 160 - width: 160 - align: center - bg_color: 0 - scales: - angle_range: 360 - rotation: 255 - range_from: 0 - range_to: 12 - ticks: - width: 35 - count: 13 - length: 8 - indicators: - - ticks: - local: true - start_value: 0 - end_value: 12 - color_start: 0xFF0000 - color_end: 0x0000FF - - meter: - - - - - - - **Specific actions:** ``lvgl.indicator.line.update`` :ref:`action ` updates the line indicator styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. From 24b440f3047175cfdec3dfa84b1ddd5ef0694de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 16 Jan 2024 15:36:32 +0100 Subject: [PATCH 093/350] Update lvgl.rst --- components/lvgl.rst | 124 +++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 01f4b141e..a602918ad 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -251,7 +251,7 @@ You can adjust the appearance of widgets by changing the foreground, background - ``RIGHT`` - ``INTERNAL`` - **border_width** (*Optional*, int16): Set the width of the border in pixels. -- **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if object has same width and height). +- **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if it has same width and height). - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. - **line_width** (*Optional*, int16): Set the width of the line in pixels. - **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). @@ -309,7 +309,7 @@ The properties below are common to all widgets. - **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to to top left of the parent or screen). If layouts are used, or if specfiyng ``align``, it is used as an offset to the calculated position (can also be negative). - **width** (*Optional*): Width of the widget in pixels or a percentage, or ``size_content`` (see below). - **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents (children objects, text size, image size etc.) -- **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused object which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. +- **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused widget which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. - **styles** (*Optional*, :ref:`config-id`): The ID of a *style definition* from the main component configuration to override the theme styles. - **theme** (*Optional*, list): A list of styles to apply to the widget and children. Same configuration option as at the main component. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Same configuration option as at the main component. @@ -363,7 +363,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can .. note:: - Zero degree is at the middle right (3 o'clock) of the object and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. + Zero degree is at the middle right (3 o'clock) of the widget and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. **Specific actions:** @@ -400,12 +400,12 @@ The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. ``bar`` ******* -The bar object has a background and an indicator on it. The width of the indicator is set according to the current value of the bar. +The bar widget has a background and an indicator on it. The width of the indicator is set according to the current value of the bar. .. figure:: /components/images/lvgl_bar.png :align: center -Vertical bars can be created if the width of the object is smaller than its height. +Vertical bars can be created if the width is smaller than the height. Not only the end, but also the start value of the bar can be set, which changes the start position of the indicator. @@ -488,7 +488,7 @@ The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or a ``btnmatrix`` ************* -The Button Matrix object is a lightweight way to display multiple buttons in rows and columns. Lightweight because the buttons are not actually created but just virtually drawn on the fly. This way, one button use only eight extra bytes of memory instead of the ~100-150 bytes a normal Button object plus the 100 or so bytes for the Label object. +The Button Matrix widget is a lightweight way to display multiple buttons in rows and columns. Lightweight because the buttons are not actually created but just virtually drawn on the fly. This way, one button use only eight extra bytes of memory instead of the ~100-150 bytes a normal Button widget plus the 100 or so bytes for the Label widget. .. figure:: /components/images/lvgl_btnmatrix.png :align: center @@ -573,7 +573,7 @@ The Button Matrix object is a lightweight way to display multiple buttons in row ``checkbox`` ************ -The Checkbox object is made internally from a "tick box" and a label. When the Checkbox is clicked the tick box is ``checked`` state toggled. +The Checkbox widget is made internally from a "tick box" and a label. When the Checkbox is clicked the tick box is ``checked`` state toggled. .. figure:: /components/images/lvgl_checkbox.png :align: center @@ -707,7 +707,7 @@ TODO !! supported image encodings ``label`` ********* -A label is the basic object type that is used to display text. +A label is the basic widget type that is used to display text. .. figure:: /components/images/lvgl_label.png :align: center @@ -756,7 +756,7 @@ Newline characters are handled automatically by the label widget. You can use `` ``line`` ******** -The Line object is capable of drawing straight lines between a set of points. +The Line widget is capable of drawing straight lines between a set of points. **Specific options:** @@ -788,7 +788,7 @@ By default, the Line's width and height are set to ``size_content``. This means ``led`` ******** -The LEDs are rectangle-like (or circle) object whose brightness can be adjusted. With lower brightness the colors of the LED become darker. +The LEDs are rectangle-like (or circle) widget whose brightness can be adjusted. With lower brightness the colors of the LED become darker. .. figure:: /components/images/lvgl_led.png :align: center @@ -840,7 +840,7 @@ TODO !!! - **scales** (*Required*, list): TODO - **ticks** (*Required*, list): TODO - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and additionally: - - **r_mod** (*Optional*): TODO in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the object based on its contents. + - **r_mod** (*Optional*): TODO in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents. - Style options from :ref:`lvgl-styling`. @@ -918,7 +918,7 @@ The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. ``slider`` ********** -The Slider object looks like a Bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider can be vertical or horizontal. +The Slider widget looks like a bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider can be vertical or horizontal. .. figure:: /components/images/lvgl_slider.png :align: center @@ -1002,7 +1002,7 @@ The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` o Tables, as usual, are built from rows, columns, and cells containing texts. -The Table object is very lightweight because only the texts are stored. No real objects are created for cells but they are just drawn on the fly. +The Table widget is very lightweight because only the texts are stored. No real objects are created for cells but they are just drawn on the fly. **Specific options:** @@ -1022,7 +1022,7 @@ The Table object is very lightweight because only the texts are stored. No real ``textarea`` ************ -The Text Area is a Base object with a Label and a cursor on it. Texts or characters can be added to it. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. +The Text Area is a base widget with a label and a cursor on it. Texts or characters can be added to it. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. One line mode and password modes are supported. @@ -1151,26 +1151,26 @@ In addition to visual stilyng, each widget supports some boolean flags to influe hidden: true -- **hidden** (*Optional*, boolean): make the object hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.widget.show`` and ``lvgl.widget.hide`` -- **clickable** (*Optional*, boolean): make the object clickable by input devices -- **click_focusable** (*Optional*, boolean): add focused state to the object when clicked -- **checkable** (*Optional*, boolean): toggle checked state when the object is clicked -- **scrollable** (*Optional*, boolean): make the object scrollable +- **hidden** (*Optional*, boolean): make the widget hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.widget.show`` and ``lvgl.widget.hide`` +- **clickable** (*Optional*, boolean): make the widget clickable by input devices +- **click_focusable** (*Optional*, boolean): add focused state to the widget when clicked +- **checkable** (*Optional*, boolean): toggle checked state when the widget is clicked +- **scrollable** (*Optional*, boolean): make the widget scrollable - **scroll_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed -- **scroll_momentum** (*Optional*, boolean): make the object scroll further when "thrown" +- **scroll_momentum** (*Optional*, boolean): make the widget scroll further when "thrown" - **scroll_one** (*Optional*, boolean): allow scrolling only one snappable children - **scroll_chain_hor** (*Optional*, boolean): allow propagating the horizontal scroll to a parent - **scroll_chain_ver** (*Optional*, boolean): allow propagating the vertical scroll to a parent - **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor | scroll_chain_ver``) -- **scroll_on_focus** (*Optional*, boolean): automatically scroll object to make it visible when focused -- **scroll_with_arrow** (*Optional*, boolean): allow scrolling the focused object with arrow keys -- **snappable** (*Optional*, boolean): if scroll snap is enabled on the parent it can snap to this object -- **press_lock** (*Optional*, boolean): keep the object pressed even if the press slid from the object +- **scroll_on_focus** (*Optional*, boolean): automatically scroll widget to make it visible when focused +- **scroll_with_arrow** (*Optional*, boolean): allow scrolling the focused widget with arrow keys +- **snappable** (*Optional*, boolean): if scroll snap is enabled on the parent it can snap to this widget +- **press_lock** (*Optional*, boolean): keep the widget pressed even if the press slid from the widget - **event_bubble** (*Optional*, boolean): propagate the events to the parent too - **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent - **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. E.g. Accounting for rounded corners -- **ignore_layout** (*Optional*, boolean): make the object positionable by the layouts -- **floating** (*Optional*, boolean): do not scroll the object when the parent scrolls and ignore layout +- **ignore_layout** (*Optional*, boolean): make the widget positionable by the layouts +- **floating** (*Optional*, boolean): do not scroll the widget when the parent scrolls and ignore layout - **overflow_visible** (*Optional*, boolean): do not clip the children's content to the parent's boundary - **layout_1**, **layout_2** (*Optional*, boolean): custom flags, free to use by layouts - **widget_1**, **widget_2** (*Optional*, boolean): custom flags, free to use by widget @@ -1347,6 +1347,39 @@ This :ref:`condition ` checks if LVGL is in paused state or no id: display_backlight transition_length: 150ms +.. _lvgl-event-trg: + +Widget Event Triggers +--------------------- + +ESPHome implements as triggers the following LVGL events: + +- ``on_press``: The widget has been pressed. +- ``on_long_press``: The widget has been pressed for at least the ``long_press_time`` specified in the input device configuration. Not called if scrolled. +- ``on_long_press_repeat``: Called after ``long_press_time`` in every ``long_press_repeat_time`` ms. Not called if scrolled. +- ``on_short_click``: The widget was pressed for a short period of time, then released. Not called if scrolled or long pressed. +- ``on_click``: Called on release if a widget did not scroll (regardless of long press). +- ``on_release``: Called in every case when a widget has been released. +- ``on_scroll_begin``: Scrolling of the widget begins. +- ``on_scroll_end``: Scrolling of the widget ends. +- ``on_scroll``: The widget was scrolled. +- ``on_focus``: The widget is focused. +- ``on_defocus``: The widget is unfocused. +- ``on_value``: TODO!! + +These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself supports generating such events. + +.. code-block:: yaml + + # Example triggers: + - btn: + ... + on_short_click: + then: + lvgl.page.show: main_page + on_long_press: + then: + light.toggle: display_backlight .. _lvgl-onidle-trg: @@ -1370,47 +1403,10 @@ The ``on_idle`` :ref:`trigger ` is activated when inactivity time be - light.turn_off: id: display_backlight - - -.. _lvgl-event-trg: - -Widget Event Triggers ---------------------- - -ESPHome implements as triggers the following LVGL events: - -- ``on_press``: The widget has been pressed. -- ``on_short_click``: The widget was pressed for a short period of time, then released. Not called if scrolled. -- ``on_long_press``: The widget has been pressed for at least the ``long_press_time`` specified in the input device configuration. Not called if scrolled. -- ``on_long_press_repeat``: Called after ``long_press_time`` in every ``long_press_repeat_time`` ms. Not called if scrolled. -- ``on_click``: Called on release if a widget did not scroll (regardless of long press). -- ``on_release``: Called in every case when a widget has been released. -- ``on_scroll_begin``: Scrolling of the widget begins. -- ``on_scroll_end``: Scrolling of the widget ends. -- ``on_scroll``: The widget was scrolled. -- ``on_focus``: The widget is focused. -- ``on_defocus``: The widget is unfocused. -- ``on_value``: TODO!! - -These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself supports generating such events. - -.. code-block:: yaml - - lvgl: - widgets: - btn: - ... - on_released: - then: - - light.turn_off: - id: display_backlight - - - Data types ---------- -LVLG supports numeric properties only as integer values with variable minimums and maximums. Certain object properties also support negative values. +LVLG supports numeric properties only as integer values with variable minimums and maximums. Certain widget properties also support negative values. - ``int8`` (signed) supports values ranging from -128 to 127. - ``uint8`` (unsigned) supports values ranging from 0 to 255. From ae5d2defb2c588880d72dc6acccbcf80fa62d43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 16 Jan 2024 16:51:07 +0100 Subject: [PATCH 094/350] meter --- components/images/lvgl_meter.png | Bin 0 -> 7065 bytes components/lvgl.rst | 67 +++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 components/images/lvgl_meter.png diff --git a/components/images/lvgl_meter.png b/components/images/lvgl_meter.png new file mode 100644 index 0000000000000000000000000000000000000000..1283126cccb54041511b0ec5e9084869e81a5eef GIT binary patch literal 7065 zcmW+*1zc257k!8VF06Dn(k)$rbV$QWBM3-?Al+RO(%mIXucWkeH_|OgNT)3Dz5n;y z*|)oIXLs(*+$Xg^7zgsGfUqU1gN*&UxTX@U=t?Qpv z&9^PJur2kUaT|Wd7TPvHd}W9Jqv3N=WXp0+GK28oZ=&I1BZGW$K3Wdm0*;J)0k7~y z?(2TG82Q4tN(Ai;xL$LCdY^biJ;y0-uZV{<=-nO-dP&t zSB^DE8Bk_Abb>3pPfBEaA`LraV^g1`2?ntxVY_<}0%Y0NcC@7Qn{=P_+M-)a%s@2 zS9~T}$*huD?Q`PV6x@%Xj1kPR67FwfU; z1WL=7HsbopV4Yf|>zw*alLe@M0aP2qjNL!GOoZQi%O-f0wWdX&!D5j)lwNU&B;;6T zc2NF(x;iCdNf54A*)GN3a#{HXYTUybhi$>WL5+Q4+quyC?+iJbp-E+UaPp)Ed4#?BmzvJ+tn7)wWkqL zWhGJvXY&EB+S4Lt(WRVfD4pv|!P3WAD4o@hzkiXKiQ4A2i$MXmInKcZw^sH+pmS}* zGY35&@-04oDkFE_axg_-+ODStL47b=h$+cjSCD<73_L^1L->F=&t~rWk0GB6Z4dXz zUaIQ3*tpa3@-js?H)raXj&4zkSaY7|0Q<0wiXdR}>}5z#(H|Ef6dFIaqt)HmwJ6>Q zQ<9SF%hhyjOCUhIXUNoz8#EmU2td|Hr2rdPz1V!m*| z0DMNryk3H-Nr{pJ==@{ zjQ7}g8NRilBxSK%_*;|B->#Od5wz}kCu$D2G%j^UEr-3WIa5$L|S(C_T zR{=3m;n!vGeIGmH7ME=~dgqq~+1&987(riEOVPv72C#R{&b#wB*3TtjFr&+=-s0Zd z`Bv`^1K4a}eqb!I=m7Pei@vBLX^|$2CgYwXs|a>JUFg(ah1mNPF13G4b)R(9VY4)m z85}b9-fPX`2MAtfbBG2*yh78y5ghK;Ixl(g`Ot|T@40iOHfyp1{nVPi(Qw90s$M+1 zV_Mi5Av{)W&xI~NVmSgQK7-n^UF0(i=V?C`y5}`l&YmU={IJC}nx~-%1@$DNmgbY+f1{+#t*bjfAvpglAgKaC`B65xl*>2agp*q+mS|IHdN zrl>>3R)FcohZ}tBPpXbGGv9ieI$LsV_@17OmQbOIO~yfnNWwrHcDXqqtJysyeWQtU z1PP+i)}$QPW`3#G{7aP{@3p13HVi6GP4NQCbi_y}NEbPd2Zy7@q7kJM@%BTZ-+=uu zls|GEXw0_EzHclj@ZmM%Dwa+M(SVClrX9r>)mO-(>mRpg7r^qHxo#CNg#kNoK2e+X zH{6}WuffVeSCeHH&4yBwjhEnpUi>X+5}rHn@zDHD+Cv-)9Kc|?M6Y#eQgWlv`$ za(Ny~NYcmH0}usCqz>Fl9~BuKpE^ObVfLbvZcf_;aJY_Tm4L)*#s9qwHhZh~-?qqg znC-wJdE%>C-!)(`ST=NgEX?vAbQ#q;YXd`0ou$ZzT8U`TUq3e+8dbafei(@ARU-m_ zs6VXaFyFS8tyDaxBL+Ql{Y4q>u(<+d9&M`UTV$ zJL?}KVWgb0YWo)$$_(-^91geX$E3`VT9t2IT!X_^jniG44bO8YM93mrB74;kDtTa+ z4AoM_LWRY*Fc?!Q(`9NN(=<);k#2I{*EwO1OId|t%_4tZ>P)6Ks3guni?z@ca>Vk7 zHgIW}>(l~=i-h92*{)T`W+hCqNc#mE}i7PnKJ`(9f}sT#F)q@jYyz ztA-sDK(KGk;*rtohw`Lz3NTx9lbb0+3LazpfIq&KzkVGacr~-7EAI>!;d7 zeZ2EuT63$Yyq4%sy%Ji#qHLlPpi)wK%)HNcmwqU{58g!=egCJ`@BH6s!&+jz2^LVaMy^?50n9BqZbwx^D5f_> z4O$81%a{kjyF$Ujzf4R0YvjlN-#hM#kLJuOmshj2aHWpJ^yBKK@`v~IxlpmXBMJuA zHcD4>6D)3P-;4F-;f;t}^){g;b>sIE4n^N5C0MXT(RFkG5^q8SIMfa^w4#NAVv!+B_`Nd{gBTbui z)}yBOKv_p58$`)fX=A)~mdKzka!C+pjVeyj32;1@?^Y6Z7!{kWz;HHa_7H{)1h9Kf zfwbeLmH%<=p@34CEmX;MV`{Ag-yOfqQPX$#UmZkyO2u~M|EOWanL4>Hwp#JzTXAb; z$i_qs8@5VhP->xx5Z~eIaSn96WO}c6oM=y!K1tQ6D@&_2>UR+qP!TK;(dj?-#a*Tb zWp|TaPsH!+X5QNjdW5#+l+69=#ozu7D_}L3=V+1s1Lmu$oWzclUM?A6eP6hA+FEP? zYY30?8_u9R2a7Ly_2xFQqI2Q57fzRkmrT!1u_Ril37)kpOTOxF6TsQc+;(!l%=#>t zEcSGdO;Lm3V0kZSRefz&X>3VOPs>&kKnX$NO#u?;06fs(&ldr|`LP&t=hj zKvY0nZsfVIVDN>t`k@tVHZcR#h)eI&8 zny5`w2`>{Dm%4-BRVTUD{p7q5(z(nj?wPWJkCSic$tL^!s>Tfe4nZ?U{dv?LrblF5 zD=4~nx{Fw?1Qq=o7Zc?QaJx^5bor2;t`QiDZ7yamoQvS@cL#>8{_+wg7QA_ar$C(El_GTMZ;}IAaa5D4;bhxFY7ILv;fzuCAC!0}0cvJb%Qab#cp)8M0uyM72`Rc7+z4ARRI z{iQ`SJUh|+oMh{d{NyxOcKc)aH5elo?W+d1o#e)JL%A$Dz9>3eA-{T+MX=%nNGn{0b6)Bah1r7p@Ocf> zC%y?k7v74h7m5itqOAqYpyb$U7vt9Z+>aKv)9S+}crm6927up5oCKJc2vS(luoQa@ z<=Cp@CD7MD^`h`~zfXB6VLG8zPlbi11uDu$rgFrUP}MsYtoH~+JO(-_`zwZT6y#&0FEyzRd{ z?%x%M>{mFbokQ@xF^H{WUtyhp!hdK>LtGg$7CR=2q`dcx5`RK^$2Ita;BfzssC=l1 zN{I)y=e^o3syu4fZg5xti{u(Pmv>blzu9qIbJVLVKkJ1&GzCO5EtT{+hCS0FQth@a zycJY)_imWV!yP_szaHiMxk<2)JnNnV(mR}_1MUld-9#USxfpx3itN#WfVonGbdiro zJ6T6>^h+Lfmjfm!v?5L}Pu4rvPi{?HR;oyqhvZLQ?_;6`gX|sGCRnm&%<9sn#rqX1 z>@JJ~Ts;B47GDE-do_yXx>ts%wjccY1^jL&D9j*_!v3rt@W;k`^Pb_YQ>+|nJKrC( zo49pS0B{|geiZJ?s-`hiEgd>QU0wdEs;h)XQS+{P@m?PJZ=^^iA1RXbUgtw@A7HXS zM9|1|?x&a_!}!u>l-=|4W~tRrAN%oHuEYeQS=lfHC$Zore_#($`{VuokzbkjjeEEH zI_}wUk@Jwwx4UEq#S{YBcm}wxoxuB@jBa`lW&AXrPIoHo7(VmGgZ~{NrtN-{9tv(Wha^U zgC;>@fp=~u<8ioZezlDH(I6KP{pjTLFK#-ccZtraIbp!335yI~v zjO*We+nBN#SD$FX(SQ;#5vqQ}WqK{%=$*Ud-=n6L6AD@D(aMuij@o7n>dN!ZZ5iTi zK5|0JBiV=h9D7S2Z8NrnGUnZAozDp%X;PTrqiT28FF@oOANzOf_x2%Qml&H*-JSO@f zjPnB%9FmK&8?vol9{3aV{zpT}uiDt+6)v(5UgAfqROf5-)s-!pd7)l3vSI{1vOI#y zW=__WCNbJxV35u6A`t6JOB53<_ozrXCRljhAZsp?%{OjR1?}Ni>x5!L+yhP&{Z1V6 z`U>jt5AU*7EkQ(hWI%4^BGY_$BO#jW9~Ixp4fh|Km}g?y)_HmaTB6d&$FuX08bpLX zQpEa_+4?e0Pg&Ip@z^UN4YAtDGeCWChCO75qoq>-vSqM7$Pr;~uJH9Gk zkI~1Xj?0C2|12Op@{4oCxT9UVW$g9^EasPNI&EKkHbU%1a+iw#o0m$@Z)a$D7>gr+ zvQj(?HYJyvx|fqp?UV8E&iXc#uJg-#pI+or?>vrOKa}VwN73^uN;H^i~bVyv~UK~ zwW4e3)uVz&FneCPTLEE{orrCqzko@GTj$#hAs5KaH@Ro{FKe3W6iWEx>kGg%xy(j6 z6HW>$`hiNk*B1|U8}C9}q@=FX3&3zvE#-McBvBFG2Vdm3u0y3j)p~iKv!|9h1o{wvaoEadv%~a?PsmRiJrk&QmbY9E zozhz3);PHPkoMx=^E!g-zq^_9#-0)ceZ1r`^H)HfrL~aNAPD8D?Qv*47ptydW*>IG zr1<^zf-=A~EesW!Ko9DDVHRG2zQIX;Xt~fcu zQ5U%ubnoC+W{#^baOZ!Fl*UAhLOKsk+Q-j;fN8y-zk(FI5~LbB!EEfdz|hE-+^deR z{sb4}9R%f#b$Pj?bj%e4uoWv7#azU}&|(w=k9e2H$974if#EXyO?`1+fFV%lmG84B zWTA(me|wlp-ANm2X|$pR;E<<$5ELN&LurMbPN5PlCEfrL3sf8O3QKwpH>o2f=B|O| znPvb6?LVs5$x?Zwqx{3k`Hi(txhxAlC2`;czRO2Qgf>A@Qtw`=>W2ngRN{0tRI+_h z&d=X8(ne)qeyV@h@a|Kc2e}qK%Q=Un7rJC2UufD;hxEfes?JsA-4wx-&0n(?$RB^v z%9uR}Es>2s@Q{M98Q7kh*W!|QHYoH?Y@=ijLO7C=3UL5XJ|+aKArtMD<1I+%0J}FC zVQ0)*w4=9Z&x)!W+R*Tes_79wJj19=Fa0AYh(&?p2)0!l&vSTAEPznx@$PfJ4= z|24b7?rx1NAt^b$Qk&|VIxS%0_OTM4vbaHnn2c{*Ul(r z83j{7k5;N(aZmxKbY3dUlg9DUqcKE^%tP3~*b8AJnO`5NgaRHN1^d7PboI5f zC9_!(^#oI$!@7FBEHVMnCP08)L=i5NlvS0fk}?VUAM{3>+W-In literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index a602918ad..0c8a105ea 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -833,20 +833,42 @@ The ``led`` can be also integrated as :doc:`/components/light/lvgl`. The Meter widget can visualize data in very flexible ways. In can show arcs, needles, ticks lines and labels. +.. figure:: /components/images/lvgl_meter.png + :align: center + **Specific options:** -TODO !!! - -- **scales** (*Required*, list): TODO -- **ticks** (*Required*, list): TODO -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and additionally: - - **r_mod** (*Optional*): TODO in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents. +- **scales** (**Required**, list): A list with (any number of) scales to be added to meter. + - **range_from** (**Required**): The minimum value of the tick scale. + - **range_to** (**Required**): The maximum value of the tick scale. + - **angle_range** (**Required**): The angle between start and end of the tick scale. + - **rotation** (**Required**): The rotation angle offset of the tick scale. + - **ticks** (**Required**, list): A scale has minor and major ticks and labels on the major ticks. To add the minor ticks: + - **count** (**Required**): How many ticks to be on the scale + - **width** (**Required**): Tick line width in pixels + - **length** (**Required**): Tick line length in pixels + - **color** (**Required**): ID or hex code for the ticks :ref:`color ` + - **major** (*Optional*, list): If you want major ticks, value labels displayed too: + - **stride**: How many minor ticks to skip+1 when adding major ticks + - **width**: Tick line width in pixels + - **length**: Tick line length in pixels + - **color**: ID or hex code for the ticks :ref:`color ` + - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. + - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their ``value`` is interpreted in the range of the scale (see the *action* below): + - **line** (*Optional*): Add a needle line to a Scale. By default, the length of the line is the same as the scale's radius. + - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. + - **width**: Needle line width in pixels. + - **color**: ID or hex code for the ticks :ref:`color `. + - **r_mod**: Adjust the length of the needle with this amount (can be negative). - Style options from :ref:`lvgl-styling`. +.. note:: + + Zero degree is at the middle right (3 o'clock) of the widget and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. **Specific actions:** -``lvgl.indicator.line.update`` :ref:`action ` updates the line indicator styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.indicator.line.update`` :ref:`action ` updates the indicator needle ``value``, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -854,16 +876,37 @@ TODO !!! .. code-block:: yaml # Example widget: - - + - meter: + align: center + scales: + - ticks: + width: 1 + count: 81 + length: 5 + color: 0x000000 + major: + stride: 10 + width: 2 + length: 8 + color: 0xC0C0C0 + label_gap: 8 + range_from: -30 + range_to: 50 + angle_range: 240 + rotation: 150 + indicators: + - line: + id: temperature_needle + width: 2 + color: 0xFF0000 + r_mod: -4 # Example action: on_...: then: - lvgl.indicator.line.update: - id: minute_hand - value: !lambda |- - return id(time_comp).now().minute; - + id: temperature_needle + value: 3 .. _lvgl-wgt-rol: From bdc02a43d733d348b1610bb6bf02fc521342ec27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 16 Jan 2024 17:05:55 +0100 Subject: [PATCH 095/350] Update lvgl.rst --- components/lvgl.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 0c8a105ea..0e3438841 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -854,13 +854,15 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **length**: Tick line length in pixels - **color**: ID or hex code for the ticks :ref:`color ` - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. + - Style options from :ref:`lvgl-styling` for the tick lines a labels using the *line* and *text* style properties. - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their ``value`` is interpreted in the range of the scale (see the *action* below): - **line** (*Optional*): Add a needle line to a Scale. By default, the length of the line is the same as the scale's radius. - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **width**: Needle line width in pixels. - **color**: ID or hex code for the ticks :ref:`color `. - **r_mod**: Adjust the length of the needle with this amount (can be negative). -- Style options from :ref:`lvgl-styling`. + - Style options from :ref:`lvgl-styling` for the needle line using the *line* style properties, as well as the background properties to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. +- Style options from :ref:`lvgl-styling` for the background of the meter, using the typical background properties. .. note:: @@ -871,6 +873,8 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee ``lvgl.indicator.line.update`` :ref:`action ` updates the indicator needle ``value``, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +The needle line using the line style properties, as well as the background properties to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. + **Example:** .. code-block:: yaml From e55508ca64e76410c3504c3c2380c81609fbd497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Jan 2024 12:00:50 +0100 Subject: [PATCH 096/350] updates --- components/binary_sensor/lvgl.rst | 10 +++++-- components/light/lvgl.rst | 4 +-- components/lvgl.rst | 48 +++++++++++++++++++------------ components/number/lvgl.rst | 12 ++++---- components/select/lvgl.rst | 13 +++++---- components/switch/lvgl.rst | 7 ++--- 6 files changed, 56 insertions(+), 38 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index f2a7763e3..844cc55cd 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -13,14 +13,18 @@ and requires :ref:`LVGL ` to be configured. Supported widget is :ref:`lvgl-wgt-btn`. A single binary sensor supports a single widget, thus you need to choose among which one's state you want to use. -Configuration variables: ------------------------- +Configuration options: +---------------------- - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the binary sensor. -- **widget** (**Required**): The ID of a button widget configured in LVGL. +- **widget** (**Required**): The ID of a ``btn`` widget configured in LVGL. - All other options from :ref:`Binary Sensor `. +.. note:: + + ``publish_initial_state`` ?? + Example: .. code-block:: yaml diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index e4cd80826..7c2636337 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -14,8 +14,8 @@ Supported widgets are :ref:`lvgl-wgt-led`. A single light supports a single widget, thus you need to choose among which one's state you want to use. -Configuration variables: ------------------------- +Configuration options: +---------------------- - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the light. diff --git a/components/lvgl.rst b/components/lvgl.rst index 0e3438841..cae7e1419 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -82,7 +82,7 @@ Configuration variables: - **long_press_repeat_time** (*Optional*, ms): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. - **color_depth** (*Optional*, enum): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. -- **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to 1s. +- **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. @@ -105,7 +105,7 @@ Configuration variables: - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. - All other options from :ref:`lvgl-styling` to be applied to this page. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. - +- **page_wrap** (*Optional*, boolean): Wrap pages around when navigating between them with :ref:`lvgl-pgnx-act`. ``true`` if not specified. **Example:** @@ -113,17 +113,15 @@ Configuration variables: # Example configuration entry lvgl: - log_level: WARN displays: - - display_id: tft_display + - display_id: my_display touchscreens: - - touchscreen_id: tft_touch + - touchscreen_id: my_touch pages: - id: main_page widgets: - label: - x: 10 - y: 10 + align: CENTER text: 'Hello World!' .. note:: @@ -315,16 +313,30 @@ The properties below are common to all widgets. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Same configuration option as at the main component. - **flex_flow** (*Optional*, string): Option for ``FLEX`` layout, similar configuration as at the main component. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn as children of this widget. Same configuration option as at the main component. -- **state** (*Optional*, string): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden withing style definitions or locally set. The state itself can be can be changed by interacting with the widget itself, or :ref:`programatically ` with ``lvgl.widget.update`` action. Can be one of: - - ``default``: Normal, released state - - ``disabled``: Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``) - - ``pressed``: Being pressed - - ``checked``: Toggled or checked state - - ``scrolled``: Being scrolled - - ``focused``: Focused via keypad or encoder or clicked via touchpad/mouse - - ``focus_key``: Focused via keypad or encoder but not via touchpad/mouse - - ``edited``: Edit by an encoder - - ``user_1``, ``user_2``, ``user_3``, ``user_4``: Custom states +- **state** (*Optional*, enum): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden withing style definitions or locally set. Can be one of: + - **default** (*Optional*, boolean): Normal, released state + - **disabled** (*Optional*, boolean): Disabled state (also usable with :ref:`shorthand ` actions **lvgl.widget.enable** and **lvgl.widget.disable**) + - **pressed** (*Optional*, boolean): Being pressed + - **checked** (*Optional*, boolean): Toggled or checked state + - **scrolled** (*Optional*, boolean): Being scrolled + - **focused** (*Optional*, boolean): Focused via keypad or encoder or clicked via touchpad/mouse + - **focus_key** (*Optional*, boolean): Focused via keypad or encoder but not via touchpad/mouse + - **edited** (*Optional*, boolean): Edit by an encoder + - **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): Custom states + +By default, states are all ``false``. To apply styles to the states, you need to specify them one level above, for example: + +.. code-block:: yaml + + - btn: + checkable: true + state: + checked: true # here you activate the state to be used at boot + checked: + bg_color: 0x00FF00 # here you apply styles to be used when in the respective state + + +The state itself can be can be changed by interacting with the widget, or :ref:`programatically ` with ``lvgl.widget.update`` action. In addition to visual stilyng, each widget supports :ref:`dynamically settable flags ` to influence the behavior at runtime. @@ -849,7 +861,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **length** (**Required**): Tick line length in pixels - **color** (**Required**): ID or hex code for the ticks :ref:`color ` - **major** (*Optional*, list): If you want major ticks, value labels displayed too: - - **stride**: How many minor ticks to skip+1 when adding major ticks + - **stride**: How many minor ticks to skip when adding major ticks - **width**: Tick line width in pixels - **length**: Tick line length in pixels - **color**: ID or hex code for the ticks :ref:`color ` diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index f1def3713..45d81acf7 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -11,16 +11,18 @@ The ``lvgl`` number platform creates a number component from a LVGL widget and requires :ref:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar` and :ref:`lvgl-wgt-sli`. A single number supports -a single widget, thus you need to choose among which one's state you want to use. +a single widget, thus you need to choose among which one's state you want to use, options are mutually exclusive. -Configuration variables: ------------------------- +Configuration options: +---------------------- - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the number. - **animated** (*Optional*, boolean): Wether to set the value of the widget with an animation. Defaults to ``true``. -- **obj** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. +- **arc** (**Required**): The ID of an ``arc`` widget configured in LVGL, which will reflect the state of the number; or +- **bar** (**Required**): The ID of a ``bar`` widget configured in LVGL, which will reflect the state of the number; or +- **slider** (**Required**): The ID of a ``slider`` widget configured in LVGL, which will reflect the state of the number. - All other options from :ref:`Number `. @@ -30,7 +32,7 @@ Example: number: - platform: lvgl - obj: slider_id + slider: slider_id name: LVGL Slider diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index cd56df20a..44c41b458 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -11,15 +11,16 @@ The ``lvgl`` switch platform creates a select from a LVGL widget and requires :ref:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-wgt-drp` and :ref:`lvgl-wgt-rol`. A single select supports -a single widget, thus you need to choose among which one's state you want to use. +a single widget, thus you need to choose among which one's state you want to use, options are mutually exclusive. -Configuration variables: ------------------------- +Configuration options: +---------------------- - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the select. -- **obj** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the select. -- All other options from :ref:`Switch `. +- **dropdown** (**Required**): The ID of a ``dropdown`` widget configured in LVGL, which will reflect the state of the select; or +- **roller** (**Required**): The ID of a ``roller`` widget configured in LVGL, which will reflect the state of the select. +- All other options from :ref:`Select `. Example: @@ -27,7 +28,7 @@ Example: select: - platform: lvgl - obj: dropdown_id + dropdown: dropdown_id name: LVGL Dropdown See Also diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 5623ea0cf..b12724ca0 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -10,12 +10,11 @@ LVGL Switch The ``lvgl`` switch platform creates a switch from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are :ref:`lvgl-wgt-btn` (with ``checkable`` option enabled), :ref:`lvgl-wgt-swi` and :ref:`lvgl-wgt-chk` -. A single switch supports a single widget, thus you need to choose among which one's state you want to use. +Supported widgets are :ref:`lvgl-wgt-btn` (with ``checkable`` option enabled), :ref:`lvgl-wgt-swi` and :ref:`lvgl-wgt-chk`. A single switch supports a single widget, thus you need to choose among which one's state you want to use, options are mutually exclusive. -Configuration variables: ------------------------- +Configuration options: +---------------------- - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the switch. From d42e0817336b315646de7e0ca945cfe1f756b97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Jan 2024 14:30:51 +0100 Subject: [PATCH 097/350] msgbox --- components/images/lvgl_msgbox.png | Bin 0 -> 5162 bytes components/lvgl.rst | 58 +++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 components/images/lvgl_msgbox.png diff --git a/components/images/lvgl_msgbox.png b/components/images/lvgl_msgbox.png new file mode 100644 index 0000000000000000000000000000000000000000..dfbbc51a52326e4e7788d8f4d696f5a6ec7348b2 GIT binary patch literal 5162 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 literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index cae7e1419..8ccb1ee2f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -726,7 +726,7 @@ A label is the basic widget type that is used to display text. **Specific options:** -- **text** or **symbol** (*Required*, string): The text or built-in symbol to display. To display an empty label, specify ``" "`` (space). +- **text** or **symbol** (**Required**, string): The text or built-in symbol to display. To display an empty label, specify ``" "`` (space). - **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) @@ -924,6 +924,62 @@ The needle line using the line style properties, as well as the background prope id: temperature_needle value: 3 + +.. _lvgl-wgt-msg: + +``msgboxes`` +************ + +The Message boxes act as pop-ups. They are built from a background container, a title, an optional close button, a text and optional buttons. + +.. figure:: /components/images/lvgl_msgbox.png + :align: center + +The text will be broken into multiple lines automatically and the height will be set automatically to include the text and the buttons. The message box is modal (blocks clicks on the rest of the screen until closed). + +**Specific options:** + +- **msgboxes** (*Optional*, enum): A list of message boxes to use. This option has to be added to the top level of the LVGL component configuration. + - **close_button** (*Required*, boolean): Add a close button to the top right of the message box. + - **title** (**Required**, string): A string to display at the top of the meessage box. + - **body** (*Required*, enum): The content of body of the message box: + - **text** (**Required**, string): The string to be displayed in the body of the message box. Can be shorthanded if no further options are specified. + - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. + - **buttons** (*Required*, enum): A list of buttons to show at the bottom of the message box: + - **text** or **symbol** (**Required**, string): The text or built-in symbol to display on the button. + +**Specific actions:** + +The configured message boxes are hidden by default. One can show them with ``lvgl.widget.show`` and ``lvgl.widget.hide`` :ref:`actions `. + +**Example:** + +.. code-block:: yaml + + # Example widget: + lvgl: + ... + msgboxes: + - id: message_box + close_button: true + title: Messagebox + body: + text: "This is a sample messagebox." + bg_color: 0x808080 + buttons: + - id: msgbox_apply + text: "Apply" + - id: msgbox_close + symbol: close + on_click: + then: + - lvgl.widget.hide: message_box + +.. note:: + + You can create your own more complex modal dialogs with a full-screen sized, half-opaque ``obj`` with any child widgets on it, and the ``hidden`` flag set to ``true`` by default. + + .. _lvgl-wgt-rol: ``roller`` From 457e0f72fff7f2896776cf69845b6d7e57a4f679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Jan 2024 14:40:54 +0100 Subject: [PATCH 098/350] Update lvgl.rst --- components/lvgl.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 8ccb1ee2f..b570c74d1 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -977,7 +977,7 @@ The configured message boxes are hidden by default. One can show them with ``lvg .. note:: - You can create your own more complex modal dialogs with a full-screen sized, half-opaque ``obj`` with any child widgets on it, and the ``hidden`` flag set to ``true`` by default. + You can create your own more complex dialogs with a full-screen sized, half-opaque ``obj`` with any child widgets on it, and the ``hidden`` flag set to ``true`` by default. For non-modal dialogs, simply set the ``clickable`` flag to ``false`` on it. .. _lvgl-wgt-rol: @@ -1266,10 +1266,10 @@ In addition to visual stilyng, each widget supports some boolean flags to influe hidden: true -- **hidden** (*Optional*, boolean): make the widget hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.widget.show`` and ``lvgl.widget.hide`` -- **clickable** (*Optional*, boolean): make the widget clickable by input devices -- **click_focusable** (*Optional*, boolean): add focused state to the widget when clicked +- **hidden** (*Optional*, boolean): make the widget hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.widget.show`` and ``lvgl.widget.hide``. Defaults to ``false``. - **checkable** (*Optional*, boolean): toggle checked state when the widget is clicked +- **clickable** (*Optional*, boolean): make the widget clickable by input devices. Defaults to ``true``. If ``false``, it will pass the click to the widgets behind it (clicking through). +- **click_focusable** (*Optional*, boolean): add focused state to the widget when clicked - **scrollable** (*Optional*, boolean): make the widget scrollable - **scroll_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed - **scroll_momentum** (*Optional*, boolean): make the widget scroll further when "thrown" From 16fe38a8ab87533f912e9e43c22051d04db72c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Jan 2024 15:25:53 +0100 Subject: [PATCH 099/350] Update lvgl.rst --- components/lvgl.rst | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b570c74d1..2b60a325f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -83,7 +83,7 @@ Configuration variables: - **color_depth** (*Optional*, enum): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to ``1s``. -- **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE"``. Defaults to ``WARN``. +- **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. @@ -106,6 +106,12 @@ Configuration variables: - All other options from :ref:`lvgl-styling` to be applied to this page. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. - **page_wrap** (*Optional*, boolean): Wrap pages around when navigating between them with :ref:`lvgl-pgnx-act`. ``true`` if not specified. +- **top_layer** (*Optional*, list): A special kind of *Always on Top* page, which acts as a parent for widgets placed on it. It's shown above all the pages - useful for widgets which need to be always visible, regardless of the pages. Only of no ``widgets`` are configured at this level. Options: + - **layout** (*Optional*, string): Layout to be applied to this page. Same option as above. + - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. + - All other options from :ref:`lvgl-styling` to be applied to this page. + - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. + **Example:** @@ -315,7 +321,7 @@ The properties below are common to all widgets. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn as children of this widget. Same configuration option as at the main component. - **state** (*Optional*, enum): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden withing style definitions or locally set. Can be one of: - **default** (*Optional*, boolean): Normal, released state - - **disabled** (*Optional*, boolean): Disabled state (also usable with :ref:`shorthand ` actions **lvgl.widget.enable** and **lvgl.widget.disable**) + - **disabled** (*Optional*, boolean): Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``) - **pressed** (*Optional*, boolean): Being pressed - **checked** (*Optional*, boolean): Toggled or checked state - **scrolled** (*Optional*, boolean): Being scrolled @@ -866,14 +872,14 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **length**: Tick line length in pixels - **color**: ID or hex code for the ticks :ref:`color ` - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. - - Style options from :ref:`lvgl-styling` for the tick lines a labels using the *line* and *text* style properties. + - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the *line* and *text* style properties. - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their ``value`` is interpreted in the range of the scale (see the *action* below): - **line** (*Optional*): Add a needle line to a Scale. By default, the length of the line is the same as the scale's radius. - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **width**: Needle line width in pixels. - **color**: ID or hex code for the ticks :ref:`color `. - **r_mod**: Adjust the length of the needle with this amount (can be negative). - - Style options from :ref:`lvgl-styling` for the needle line using the *line* style properties, as well as the background properties to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. + - Style options from :ref:`lvgl-styling` for the *needle line* using the *line* style properties, as well as the background properties to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - Style options from :ref:`lvgl-styling` for the background of the meter, using the typical background properties. .. note:: @@ -940,12 +946,12 @@ The text will be broken into multiple lines automatically and the height will be **Specific options:** - **msgboxes** (*Optional*, enum): A list of message boxes to use. This option has to be added to the top level of the LVGL component configuration. - - **close_button** (*Required*, boolean): Add a close button to the top right of the message box. + - **close_button** (**Required**, boolean): Controls the appearance of the close button to the top right of the message box. - **title** (**Required**, string): A string to display at the top of the meessage box. - - **body** (*Required*, enum): The content of body of the message box: + - **body** (**Required**, enum): The content of body of the message box: - **text** (**Required**, string): The string to be displayed in the body of the message box. Can be shorthanded if no further options are specified. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. - - **buttons** (*Required*, enum): A list of buttons to show at the bottom of the message box: + - **buttons** (**Required**, enum): A list of buttons to show at the bottom of the message box: - **text** or **symbol** (**Required**, string): The text or built-in symbol to display on the button. **Specific actions:** From f5125471e83bff59e810cf50b5b46f3b4b615eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 09:57:46 +0100 Subject: [PATCH 100/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2b60a325f..5909050f1 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -956,7 +956,7 @@ The text will be broken into multiple lines automatically and the height will be **Specific actions:** -The configured message boxes are hidden by default. One can show them with ``lvgl.widget.show`` and ``lvgl.widget.hide`` :ref:`actions `. +The configured message boxes are hidden by default. One can show them with ``lvgl.widget.show`` and ``lvgl.widget.hide`` :ref:`actions `. **Example:** From 65cd8c7abebf1005709bb0af2d2a8efa4494baa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 13:42:16 +0100 Subject: [PATCH 101/350] add lvgl cookbook --- components/lvgl.rst | 1 + cookbook/lvgl.rst | 113 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 cookbook/lvgl.rst diff --git a/components/lvgl.rst b/components/lvgl.rst index 5909050f1..abde9df5f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1547,6 +1547,7 @@ See Also - :doc:`/components/light/lvgl` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` +- :doc:`/cookbook/lvgl` - `LVGL 8.3 docs `__ - `LVGL Online Font Converter `__ - :ghedit:`Edit` diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst new file mode 100644 index 000000000..2f009bab9 --- /dev/null +++ b/cookbook/lvgl.rst @@ -0,0 +1,113 @@ +LVGL: Tips and Tricks +===================== + +.. seo:: + :description: Recipes for common use cases of LVGL Displays with ESPHome + :image: /images/logo_lvgl.png + +Here are a couple recipes for various interesting things you can do with :ref:`lvgl-main` in ESPHome. + +.. note:: + + The examples below assume you've set up LVGL correctly with your display and input device, and you have the knowledge to set up various components in ESPHome. + +.. _lvgl-cook-relay: + +Toggle local light +------------------ + +If you have a display with GPIO outputs usable with local relays, you can simply create a wall switch for your light. + +.. code-block:: yaml + + light: + - platform: ... + id: room_light + name: 'Room light' + on_state: + if: + condition: + light.is_on: room_light + then: + - lvgl.widget.update: + id: light_btn + state: + checked: true + else: + - lvgl.widget.update: + id: light_btn + state: + checked: false + + lvgl: + ... + pages: + - id: main_page + widgets: + - btn: + id: light_btn + align: center + width: 100 + height: 70 + checkable: true + widgets: + - label: + align: center + text: 'Room light' + on_click: + light.toggle: room_light + +.. _lvgl-cook-binent: + +Toggle remote light +------------------- + +If you'd like to control a remote light, which appears as an entity in Home Assistant, first you need to import the light state into ESPHome, and then control it using a service call: + +.. code-block:: yaml + + binary_sensor: + - platform: homeassistant + id: remote_light + entity_id: light.remote_light + on_state: + then: + if: + condition: + lambda: return x; + then: + - lvgl.widget.update: + id: light_switch + state: + checked: true + else: + - lvgl.widget.update: + id: light_switch + state: + checked: false + + lvgl: + ... + pages: + - id: main_page + widgets: + - switch: + align: center + id: light_switch + on_click: + - homeassistant.service: + service: light.toggle + data: + entity_id: light.remote_light + + + + +See Also +-------- + +- :ref:`lvgl-main` +- :ref:`config-lambda` +- :ref:`automation` + +- :ghedit:`Edit` From 9fcd7dd568890430d4def19c6c3cdd2a0dbdb4a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 14:23:07 +0100 Subject: [PATCH 102/350] lvgl cover cook --- cookbook/images/lvgl_cook_covers.png | Bin 0 -> 4712 bytes cookbook/lvgl.rst | 126 +++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 cookbook/images/lvgl_cook_covers.png diff --git a/cookbook/images/lvgl_cook_covers.png b/cookbook/images/lvgl_cook_covers.png new file mode 100644 index 0000000000000000000000000000000000000000..42910a1caa0132d425745c29978be9f89b98eb90 GIT binary patch literal 4712 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 adGgju7!jJj~3DD8h*C@ROkN6+zLbD$L literal 0 HcmV?d00001 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 2f009bab9..ce76440a0 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -100,6 +100,132 @@ If you'd like to control a remote light, which appears as an entity in Home Assi data: entity_id: light.remote_light +.. _lvgl-cook-cover: + +Cover status and control +------------------------ + +To make a nice user interface for controlling covers you could use 3 buttons, which also display the state. + +.. figure:: images/lvgl_cook_covers.jpg + :align: center + +Just as above, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and wuth a text sensor we retrive the current movement state of it. We are particularly intersted in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show **STOP**. Otherwise, this button label will show the percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. + +.. code-block:: yaml + + sensor: + - platform: homeassistant + id: cover_myroom_pos + entity_id: cover.myroom + attribute: current_position + on_value: + - if: + condition: + lambda: |- + return x == 100; + then: + - lvgl.widget.update: + id: cov_up_myroom + text_opa: 50% + else: + - lvgl.widget.update: + id: cov_up_myroom + text_opa: 100% + - if: + condition: + lambda: |- + return x == 0; + then: + - lvgl.widget.update: + id: cov_down_myroom + text_opa: 50% + else: + - lvgl.widget.update: + id: cov_down_myroom + text_opa: 100% + + text_sensor: + - platform: homeassistant + id: cover_myroom_state + entity_id: cover.myroom + on_value: + - if: + condition: + lambda: |- + return ((0 == x.compare(std::string{"opening"})) or (0 == x.compare(std::string{"closing"}))); + then: + - lvgl.label.update: + id: cov_stop_myroom + text: "STOP" + else: + - lvgl.label.update: + id: cov_stop_myroom + text: !lambda |- + static char buf[10]; + snprintf(buf, 10, "%.0f%%", id(cover_myroom_pos).get_state()); + return buf; + + lvgl: + ... + pages: + - id: main_page + widgets: + - label: + x: 10 + y: 6 + width: 70 + text: "My room" + text_align: center + - btn: + x: 10 + y: 30 + width: 70 + height: 68 + widgets: + - label: + id: cov_up_myroom + align: center + symbol: UP + on_press: + then: + - homeassistant.service: + service: cover.open + data: + entity_id: cover.myroom + - btn: + x: 10 + y: 103 + width: 70 + height: 68 + widgets: + - label: + id: cov_stop_myroom + align: center + text: STOP + on_press: + then: + - homeassistant.service: + service: cover.stop + data: + entity_id: cover.myroom + - btn: + x: 10 + y: 178 + width: 70 + height: 68 + widgets: + - label: + id: cov_down_myroom + align: center + symbol: DOWN + on_press: + then: + - homeassistant.service: + service: cover.close + data: + entity_id: cover.myroom + From 44a529eac2a2bccad614965b1a0a9f3fc40269d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 14:31:31 +0100 Subject: [PATCH 103/350] cookbook2index --- cookbook/images/lvgl_cook_covers.png | Bin 4712 -> 4539 bytes cookbook/lvgl.rst | 2 +- index.rst | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cookbook/images/lvgl_cook_covers.png b/cookbook/images/lvgl_cook_covers.png index 42910a1caa0132d425745c29978be9f89b98eb90..5c9fe2987167fe988d4d2efe28cfcf0c58a5a55b 100644 GIT binary patch literal 4539 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 adGgju7!jJj~3DD8h*C@ROkN6+zLbD$L diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index ce76440a0..a109c60d3 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -110,7 +110,7 @@ To make a nice user interface for controlling covers you could use 3 buttons, wh .. figure:: images/lvgl_cook_covers.jpg :align: center -Just as above, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and wuth a text sensor we retrive the current movement state of it. We are particularly intersted in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show **STOP**. Otherwise, this button label will show the percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. +Just as above, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and wuth a text sensor we retrive the current movement state of it. We are particularly intersted in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. .. code-block:: yaml diff --git a/index.rst b/index.rst index 46f446d17..172bee9cb 100644 --- a/index.rst +++ b/index.rst @@ -942,6 +942,7 @@ Cookbook Arduino Port Extender, cookbook/arduino_port_extender, arduino_logo.svg EHMTX a matrix status/text display, cookbook/ehmtx, ehmtx.jpg Share data directly between ESPHome nodes, cookbook/http_request_sensor, connection.svg, dark-invert + LVGL: Tips and Tricks, cookbook/lvgl, logo_lvgl.png Do you have other awesome automations or cool setups? Please feel free to add them to the documentation for others to copy. See :doc:`Contributing `. From f5e9945a46f61855daf3ed4dd793595ecb230896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 15:19:52 +0100 Subject: [PATCH 104/350] more cookies --- ...gl_cook_covers.png => lvgl_cook_cover.png} | Bin cookbook/images/lvgl_cook_gradient_styles.png | Bin 0 -> 10498 bytes cookbook/images/lvgl_cook_pagenav.png | Bin 0 -> 1125 bytes cookbook/images/lvgl_cook_statico.png | Bin 0 -> 700 bytes cookbook/images/lvgl_cook_titlebar.png | Bin 0 -> 2366 bytes cookbook/lvgl.rst | 185 +++++++++++++++++- 6 files changed, 184 insertions(+), 1 deletion(-) rename cookbook/images/{lvgl_cook_covers.png => lvgl_cook_cover.png} (100%) create mode 100644 cookbook/images/lvgl_cook_gradient_styles.png create mode 100644 cookbook/images/lvgl_cook_pagenav.png create mode 100644 cookbook/images/lvgl_cook_statico.png create mode 100644 cookbook/images/lvgl_cook_titlebar.png diff --git a/cookbook/images/lvgl_cook_covers.png b/cookbook/images/lvgl_cook_cover.png similarity index 100% rename from cookbook/images/lvgl_cook_covers.png rename to cookbook/images/lvgl_cook_cover.png diff --git a/cookbook/images/lvgl_cook_gradient_styles.png b/cookbook/images/lvgl_cook_gradient_styles.png new file mode 100644 index 0000000000000000000000000000000000000000..9130b348a23e8dc01bf666550b49cc45e5ff3dfa GIT binary patch literal 10498 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 literal 0 HcmV?d00001 diff --git a/cookbook/images/lvgl_cook_statico.png b/cookbook/images/lvgl_cook_statico.png new file mode 100644 index 0000000000000000000000000000000000000000..b09edd29c033aaeefb90b2c1cffd29f4b3924b49 GIT binary patch literal 700 zcmeAS@N?(olHy`uVBq!ia0vp^?}1pCg9%8UG+G_Vz`)e(>EaktG3V_a!wlg-3HA@~ zzqE+^Jdl;xAuYovv*%I55l1aP-V)A|3w=$lP0d&ME?HSvtc^NJE-_fPyYY?lIh=>?tggx`0-Q0qftNn7<5+j zrd?5G_|oZhrDGRc!@mH|y^=dDL`oSMY8M9?gM}RO+3c<`6dM;T6iU3*5Mit`^LUF7 zhf>it=HvWL%tqbDyd9d};+MsHPWF8Ke(Bh<@4r^ZN0jfj3;%NaJzJ3Uf&E5HX3RI( zeC@qVwKcE3f~JSJs#W>9y&C${U%d@?-QQ~B-1Efm{j9uCY?@w? zq;h>2|K!~8JE!}#9$tF*QBV_Jl3=J?GNYgKAUt_ zzvhRdR`0A?GyOti*6$J(n5dM$uWMOW!(R@^&B@RHn*05jWt|(dY0DeWSZ~!mbK4%X ze={#nJj=Pe^jpiaN+nassg4#uox`C;Z!PC{x JWt~$(69A@pIDh~E literal 0 HcmV?d00001 diff --git a/cookbook/images/lvgl_cook_titlebar.png b/cookbook/images/lvgl_cook_titlebar.png new file mode 100644 index 0000000000000000000000000000000000000000..dd7f2e3038c1d9b6c6b973a2934f00260e76ad2a GIT binary patch literal 2366 zcmV-E3BmS>P)sQ4@tU()|r8=(}kV558HYd zw(Cq`HkpBLyoKp_3e&awkahe};tm9qLOM<%MGj1{0u6Hu4l6+l5+qdj!4LbORFQw$ zrfupJ?fo81ban2z=Nz4Tbg$(2fH3tdP$-U|#i;DJ2^7j6(E?!Xw+$4^-p~THHdCC! zZ}!^&3T4k|feP7g8z_{$f!1bE8<)A!9RmU%J0< znp&I3Por2Ds%ebnO6g^lVIY1Q^&fR}tuDM_NbCBnfM7~jUbNc zIm-15td+7>FO~tJor`yS0v+7QEt{T(UhLy-r+Vn*0#2Rv@dvl(rwPNrfR~T_D4D`@ z7rnlAF13U+4;29LcXFv=Uu>q7URGbGwjO(U5yuRla0(2V_Dr*k%$J}BPS6$2rccwsX4Y z=(eY36_4d)LbhX~5wJXs&BzVo9Oz`PbR%CoXYXFP$Eja_IV;f6u(=N%ewzCJ2~iK7)UN) z05AX|el#a5qqmF9L1wy75HEUJhKc_qs~cqaV?O(Z&vR8&bOQjsAM*G**s+|9RlVQq z&VJz=_*X$(({|}&>LHGu_QYmNR!iiBd+I(W6~ipj(HRLptI~#_*_6CQ?Q4ggTEHVG z`Dlh6*7SLvXuNXMORzB~ez9o9!1keao<7B9*n#+eKxIjCUdN%Ru03QC1Cm zcK|pa6lPbHiMuj$kV$l-=^^3FO=ol=@rCp3%hiDY5~Vi zdxrhIsl4Yn&$YTzOBetGA8`P%An&%)zbWFX9y-F-Gi%*kNKiW>lsEt0(u0D#Prk{krf&4?f24b7YhO`zFN=(J5Ed_%MjbpoaV znI$}1#Qk0r>fomP1n3jSa>eSLCIG-N5cr6j9Q5K1OI8s@AN3zc0L0tD0YH9b z=f;;>k`uii!42l!Q(RT82&fx604&Ig)q-_`Sg`c`{3pMqhii3NRyCrwoe;<_R0DvnPCoMx zH&9ZkYk4(wGNB{9^i;3XRspgFp17do03h337o54*sI@GN8B@rY0KNDvqX%;eEF zjqpFWgMxKJc0JXLPc;DOInG;UzTe9Oz%I9sHG2BJytPEJY}-AuN~E%OJ}3}Eq_Sq& zV3zGfuTXrdys2TYCEA71A#UVmgB1}Wka>vBDJ11CWRVx54u zogM$3F!u}Aw}{oNxZZeKX`Zd|!fM3NNOGZ+J|BqZq+(h3A7J;(U)F%-{9w&-oUeEt-Q1W{@cKYd0z z+8A_*ljdboApnGHbrmj!;<+LK4EvFL1t|;dAbhd7r`^hzN{In1`g`!;^ z0FcT`jj69t+fYW^H1exz_`2B8&irE~aF|c@dbw5?-q7MX$r>xYjOBIBycSYf@m-yh z)!I@*2!yYT(?i}wpATgBH?gj(Z~lbwT{yse{(UpYqkQ1}=VD0TGDdH` z>uc2iP7ROUS(<&+)OX+?%DS223?_&C`63?nBb|^Yr!vrQ9Z?$dR$0L?(9!0a`!XzH zC3G#{{M0(YoSSa;m=wzUfqq+`;vDEN5Kx>0T{lyl1N|>oigTd9KtOR0v^G<{9 literal 0 HcmV?d00001 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index a109c60d3..22d95caae 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -107,7 +107,7 @@ Cover status and control To make a nice user interface for controlling covers you could use 3 buttons, which also display the state. -.. figure:: images/lvgl_cook_covers.jpg +.. figure:: images/lvgl_cook_cover.jpg :align: center Just as above, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and wuth a text sensor we retrive the current movement state of it. We are particularly intersted in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. @@ -226,7 +226,190 @@ Just as above, we need to get the states of the cover first. With a numeric sens data: entity_id: cover.myroom +.. _lvgl-cook-gradient: +Gradient styles for widgets +--------------------------- + +Since LVGL uses inheritance to apply styles across the widgets, it's possible to apply them at the top level, and only make modifications on demand, if necessarry. + +.. figure:: images/lvgl_cook_gradient_styles.jpg + :align: center + +In this example we prepare a set of gradient styles in the *theme*, and make some modifications in a *style_definition* which can be applied in a batch to the desired widgets. Theme is applied automatically, the style definition is applied manually. + +.. code-block:: yaml + + lvgl: + ... + theme: + btn: + bg_color: 0x2F8CD8 + bg_grad_color: 0x005782 #0x006699 + bg_grad_dir: VER + bg_opa: cover + border_color: 0x0077b3 + border_width: 1 + text_color: 0xFFFFFF + pressed: + bg_color: 0x006699 + bg_grad_color: 0x00334d + checked: + bg_color: 0x1d5f96 + bg_grad_color: 0x03324A + text_color: 0x005580 + style_definitions: + - id: header_footer + bg_color: 0x2F8CD8 + bg_grad_color: 0x005782 #0x004466 + bg_grad_dir: VER + bg_opa: cover + border_width: 0 + radius: 0 + pad_all: 0 + pad_row: 0 + pad_column: 0 + border_color: 0x0077b3 + text_color: 0xFFFFFF + +.. _lvgl-cook-navigator: + +Page navigation footer +---------------------- + +If using multiple pages, a navigation bar can be useful at the bottom of the screen: + +.. figure:: images/lvgl_cook_pagenav.jpg + :align: center + +To save from repeating the same widgets on each page, there's the *top_layer* which is the *Always on Top* transparent page above all the pages. Everything you put on this page will be on top of all the others. + +For the navigation bar we use a button matrix. Note how the *header_footer* style definition is being applied to the widget and its children objects, and how a few more styles are configured to the main widget: + +.. code-block:: yaml + + lvgl: + ... + top_layer: + widgets: + - btnmatrix: + width: 100% + height: 30px + align: bottom_mid + styles: header_footer + pad_all: 0 + outline_width: 0 + id: top_layer + items: + styles: header_footer + rows: + - buttons: + - id: top_prev + symbol: left + on_press: + then: + lvgl.page.previous: + - id: top_home + symbol: home + on_press: + then: + lvgl.page.show: main_page + - id: top_next + symbol: right + on_press: + then: + lvgl.page.next: + + +.. _lvgl-cook-statico: + +HA connection status icon +------------------------- + +The top layer is useful to show status icons visible on all pages: + +.. figure:: images/lvgl_cook_statico.jpg + :align: center + +In the example below we only show the icon when connection with Home Assistant is established: + +.. code-block:: yaml + + api: + on_client_connected: + - if: + condition: + lambda: 'return (0 == client_address.compare(std::string{"your.ha.static.ip"}));' + then: + - lvgl.widget.show: lbl_hastatus + on_client_disconnected: + - if: + condition: + lambda: 'return (0 == client_address.compare(std::string{"your.ha.static.ip"}));' + then: + - lvgl.widget.hide: lbl_hastatus + + lvgl: + ... + top_layer: + widgets: + - label: + symbol: WIFI + id: lbl_hastatus + hidden: true + align: top_right + x: -2 + y: 7 + text_align: right + text_color: 0xFFFFFF + +Two notable things here, the widget starts *hidden* at boot, and it's only shown when triggered by connection with the API, and alignment of the widget: since the *align* option is given, the *x* and *y* options are used to position the widget relative to the calculated position. + +.. _lvgl-cook-titlebar: + +Title bar for each page +----------------------- + +Each page can have its own title bar + +.. figure:: images/lvgl_cook_titlebar.jpg + :align: center + +To put a titlebar under the status icon, we need to add it to each page, also containing the label with a unique title: + +.. code-block:: yaml + + lvgl: + ... + pages: + - id: main_page + widgets: + - obj: + align: TOP_MID + width: 240 + height: 30 + styles: header_footer + widgets: + - label: + text: "ESPHome LVGL Display" + align: center + text_align: center + text_color: 0xFFFFFF + ... + - id: second_page + widgets: + - obj: + align: TOP_MID + width: 240 + height: 30 + styles: header_footer + widgets: + - label: + text: "A second page" + align: center + text_align: center + text_color: 0xFFFFFF + ... See Also From c93937f7ab2c4e348995c950ed141d72e562801b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 15:21:11 +0100 Subject: [PATCH 105/350] Update lvgl_main_screenshot.png --- components/images/lvgl_main_screenshot.png | Bin 10549 -> 10498 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_main_screenshot.png b/components/images/lvgl_main_screenshot.png index c8428921f209cdee3ff8d32c98dff0d612e89fce..9130b348a23e8dc01bf666550b49cc45e5ff3dfa 100644 GIT binary patch literal 10498 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 }!$OA}(QH_W0(yEZ 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 From 72e3bed455398d0e03044b473bfcfe4d56a3fd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 15:27:13 +0100 Subject: [PATCH 106/350] Update lvgl.rst --- cookbook/lvgl.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 22d95caae..c6aef7ff7 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -107,7 +107,7 @@ Cover status and control To make a nice user interface for controlling covers you could use 3 buttons, which also display the state. -.. figure:: images/lvgl_cook_cover.jpg +.. figure:: /cookbook/images/lvgl_cook_cover.jpg :align: center Just as above, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and wuth a text sensor we retrive the current movement state of it. We are particularly intersted in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. @@ -233,7 +233,7 @@ Gradient styles for widgets Since LVGL uses inheritance to apply styles across the widgets, it's possible to apply them at the top level, and only make modifications on demand, if necessarry. -.. figure:: images/lvgl_cook_gradient_styles.jpg +.. figure:: /cookbook/images/lvgl_cook_gradient_styles.jpg :align: center In this example we prepare a set of gradient styles in the *theme*, and make some modifications in a *style_definition* which can be applied in a batch to the desired widgets. Theme is applied automatically, the style definition is applied manually. @@ -279,7 +279,7 @@ Page navigation footer If using multiple pages, a navigation bar can be useful at the bottom of the screen: -.. figure:: images/lvgl_cook_pagenav.jpg +.. figure:: /cookbook/images/lvgl_cook_pagenav.jpg :align: center To save from repeating the same widgets on each page, there's the *top_layer* which is the *Always on Top* transparent page above all the pages. Everything you put on this page will be on top of all the others. @@ -328,7 +328,7 @@ HA connection status icon The top layer is useful to show status icons visible on all pages: -.. figure:: images/lvgl_cook_statico.jpg +.. figure:: /cookbook/images/lvgl_cook_statico.jpg :align: center In the example below we only show the icon when connection with Home Assistant is established: @@ -372,7 +372,7 @@ Title bar for each page Each page can have its own title bar -.. figure:: images/lvgl_cook_titlebar.jpg +.. figure:: /cookbook/images/lvgl_cook_titlebar.jpg :align: center To put a titlebar under the status icon, we need to add it to each page, also containing the label with a unique title: From b199e31ac6610885c9d0fafe67ae6f5677660473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 15:35:25 +0100 Subject: [PATCH 107/350] fix img --- cookbook/images/lvgl_cook_pagenav.png | Bin 1125 -> 1312 bytes cookbook/lvgl.rst | 12 +++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cookbook/images/lvgl_cook_pagenav.png b/cookbook/images/lvgl_cook_pagenav.png index c1445024960921ad33b66217865238776a486154..db7b3b55f008b75bf4ce25b1dc35119aa73e433c 100644 GIT binary patch literal 1312 zcmeAS@N?(olHy`uVBq!ia0vp^AAne!gAGW!tzoSLQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XB4uLSEsD@VqP|a3P7srr_xVN+YGh{+#j@Rqj`Y0UITVlX1 zy6MrvU=g3Zo39os+upd~EWIa0BrRgHCKxH(0%m+8b*3f4`?pTg-Mfe4tsdx0zd6scgP}1qqx>yH%l?o9@n$#V#Wpe&NCY>sdvD|Z zweW9(Crqz1E8Bs@64r0FcNi}V99`CQ0BQi+jtu?Ax{gPEc}stB*Yro-o$;t*alDL5 z)}7lsrm0{0>)HNyCd2y)+7sAg-~J7p6&bPUrTm#yOGOr$S~IZz+Fh{0XL9ngO}^*! zF8SA&tgI_)Ic3d$?RTZ}#ruD%8AWaT53SzrdgqB8JJ9iR8>Xiu9*VyByw~2^WZe=k zrKsquYgOvA-dsHMnz7ZfGwOSIX~InJ?NKHloAR0O2nZ!a{<{(T`f$Mf&AUImYI-5C z*YGw(bf<1WoVd)A%* z+WXB;?not@m+rQ_Wh52n`V8U^jeE>QmHhh zjn`ng%75js%%?}S+LnfveY~^cdwHr1=U%&NtM*ynveK*dufN!`>PY&x{J&}Z?7LU& zi{ELno;m-;-`)PtJzji`{CE7JVEop$Te9<-zWj@;bN|GlyXMSaE740YHm7ALK3Y9% z()9O>?}e4Ted5uypILwEi(?o6hpBp{uU49uqw@3inV-!Ef1NFOw%ygr`1+OSlM?Ec z#5czM-LfsNbM+{)^_?`{OV3 zx+7`x%>J>4Cq-(n{FvalUFeT&?M|QYzMPN;+S@B0%&h%_4;NyYRXrYFqB_vt1U=@K66w({rB+VIS6aZrijczt-Bb znOirsG4=1c#jq) z!ZMye`wS%xpVoXfg+EJK{%uJv1T+R0pR&Bq-q%qb7+*JSOYlmLQbs|G9K=osL;Br1jM=pp`_-Gl zOh~*=QuKbUjPQam4ExK*QMix#KS_w!{#7{>Vr7K9T&OlWm3tm_ZCbyxV`jOS1yH`* zT6+*w&st_W87&hjpz^yqX&FK|i%r5K_8BPa)={Pb_sn#% zdM-D=J~)O$LgN&Lgg{}$03avx&SFDhvek5JDJF%G}pLW}Ku@_!!Quy1ZhW>7<-2I^QTuwt|@uDq12EG``AJa-H8PHDY&2f0{gt9> z8&)P+pK$-Q4V0&fo3Xb26V5gG>W3jwS0ej`aLX z%dT-OS(~!Y6|)MZ4vBWRXU|ChX4eKAs$Qqxuh`^WqTw zrUcwA|AX)A*H7mrUN!%{!qWLd<(_NLt*%Zw!xlr}_nEwx?;Dq!9op&w`xhaEo%6S= zPBdPg_)f}A>SPB(03h)D_AA+?kN&SwWoK#xTb<1BK|UX|rr*i|sQ%uXUT#yC4uqh- z2#I*}rgXP_0JSN{dC8y`Ktt-laLL>DD=Thg#XY!!p=vxeWE5t4z~JUN>CrrTW9^S? zPGKZln{v)9NV!QlIUqpfcfZ8igU(mKwgHr1H_deaNbWreNo0`u1rB8T+x6D;a+9X$ z-w{ywsMF{T>27rZ{B)tHN&|DaWKyDXx&W1#?xXU-)Y0o}cP z*$JYGt!@x?Yk#*FJPrtN$53qH?oL=)u8X7M%N3QG#$d=Og05N}WQ3^<0QRdZVJcI) zzrZhj#emNqzoN@%2!Bu^9>mP=UaU{# rmC7K8{c24D0B*jcS_Z=$9;MP#)`qNfUO#W200000NkvXXu0mjfDP<_0 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index c6aef7ff7..b9b067063 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1,3 +1,5 @@ +.. _lvgl-cook: + LVGL: Tips and Tricks ===================== @@ -107,7 +109,7 @@ Cover status and control To make a nice user interface for controlling covers you could use 3 buttons, which also display the state. -.. figure:: /cookbook/images/lvgl_cook_cover.jpg +.. figure:: images/lvgl_cook_cover.png :align: center Just as above, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and wuth a text sensor we retrive the current movement state of it. We are particularly intersted in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. @@ -233,7 +235,7 @@ Gradient styles for widgets Since LVGL uses inheritance to apply styles across the widgets, it's possible to apply them at the top level, and only make modifications on demand, if necessarry. -.. figure:: /cookbook/images/lvgl_cook_gradient_styles.jpg +.. figure:: images/lvgl_cook_gradient_styles.png :align: center In this example we prepare a set of gradient styles in the *theme*, and make some modifications in a *style_definition* which can be applied in a batch to the desired widgets. Theme is applied automatically, the style definition is applied manually. @@ -279,7 +281,7 @@ Page navigation footer If using multiple pages, a navigation bar can be useful at the bottom of the screen: -.. figure:: /cookbook/images/lvgl_cook_pagenav.jpg +.. figure:: images/lvgl_cook_pagenav.png :align: center To save from repeating the same widgets on each page, there's the *top_layer* which is the *Always on Top* transparent page above all the pages. Everything you put on this page will be on top of all the others. @@ -328,7 +330,7 @@ HA connection status icon The top layer is useful to show status icons visible on all pages: -.. figure:: /cookbook/images/lvgl_cook_statico.jpg +.. figure:: images/lvgl_cook_statico.png :align: center In the example below we only show the icon when connection with Home Assistant is established: @@ -372,7 +374,7 @@ Title bar for each page Each page can have its own title bar -.. figure:: /cookbook/images/lvgl_cook_titlebar.jpg +.. figure:: images/lvgl_cook_titlebar.png :align: center To put a titlebar under the status icon, we need to add it to each page, also containing the label with a unique title: From 70b535cf95e3919da7ef64518a631ac3bd9129e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 15:42:49 +0100 Subject: [PATCH 108/350] Update lvgl.rst --- cookbook/lvgl.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index b9b067063..c732ef560 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -18,7 +18,7 @@ Here are a couple recipes for various interesting things you can do with :ref:`l Toggle local light ------------------ -If you have a display with GPIO outputs usable with local relays, you can simply create a wall switch for your light. +If you have a display some local lights configured, you can simply create a wall switch for it. .. code-block:: yaml @@ -40,7 +40,6 @@ If you have a display with GPIO outputs usable with local relays, you can simply id: light_btn state: checked: false - lvgl: ... pages: @@ -112,7 +111,7 @@ To make a nice user interface for controlling covers you could use 3 buttons, wh .. figure:: images/lvgl_cook_cover.png :align: center -Just as above, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and wuth a text sensor we retrive the current movement state of it. We are particularly intersted in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. +Just as in the previous example, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and wuth a text sensor we retrive the current movement state of it. We are particularly intersted in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. .. code-block:: yaml @@ -238,7 +237,7 @@ Since LVGL uses inheritance to apply styles across the widgets, it's possible to .. figure:: images/lvgl_cook_gradient_styles.png :align: center -In this example we prepare a set of gradient styles in the *theme*, and make some modifications in a *style_definition* which can be applied in a batch to the desired widgets. Theme is applied automatically, the style definition is applied manually. +In this example we prepare a set of gradient styles in the *theme*, and make some modifications in a *style_definition* which can be applied in a batch to the desired widgets. Theme is applied automatically, the style definition is applied manually (read further to see how). .. code-block:: yaml @@ -286,7 +285,7 @@ If using multiple pages, a navigation bar can be useful at the bottom of the scr To save from repeating the same widgets on each page, there's the *top_layer* which is the *Always on Top* transparent page above all the pages. Everything you put on this page will be on top of all the others. -For the navigation bar we use a button matrix. Note how the *header_footer* style definition is being applied to the widget and its children objects, and how a few more styles are configured to the main widget: +For the navigation bar we use a button matrix. Note how the *header_footer* style definition is being applied to the widget and its children objects, and how a few more styles are configured manually at the main widget: .. code-block:: yaml From 8d37a37da4d41d415b6fc65bf08e7eda20032c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 16:04:14 +0100 Subject: [PATCH 109/350] clock --- cookbook/images/lvgl_cook_clock.png | Bin 0 -> 11469 bytes cookbook/lvgl.rst | 140 ++++++++++++++++++++++++++-- 2 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 cookbook/images/lvgl_cook_clock.png diff --git a/cookbook/images/lvgl_cook_clock.png b/cookbook/images/lvgl_cook_clock.png new file mode 100644 index 0000000000000000000000000000000000000000..72ef41ed0678ba2a1fe5647ec6df5ed54d302f0a GIT binary patch literal 11469 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 literal 0 HcmV?d00001 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index c732ef560..7535bfafc 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -18,7 +18,7 @@ Here are a couple recipes for various interesting things you can do with :ref:`l Toggle local light ------------------ -If you have a display some local lights configured, you can simply create a wall switch for it. +If you have a display device with a local light configured, you can simply create a wall switch for it. .. code-block:: yaml @@ -111,7 +111,7 @@ To make a nice user interface for controlling covers you could use 3 buttons, wh .. figure:: images/lvgl_cook_cover.png :align: center -Just as in the previous example, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and wuth a text sensor we retrive the current movement state of it. We are particularly intersted in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. +Just as in the previous example, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. .. code-block:: yaml @@ -227,9 +227,11 @@ Just as in the previous example, we need to get the states of the cover first. W data: entity_id: cover.myroom -.. _lvgl-cook-gradient: +Notable here is the way the label is updated with a sensor numeric value using ``snprintf``. -Gradient styles for widgets +.. _lvgl-cook-theme: + +Theme and style definitions --------------------------- Since LVGL uses inheritance to apply styles across the widgets, it's possible to apply them at the top level, and only make modifications on demand, if necessarry. @@ -285,7 +287,7 @@ If using multiple pages, a navigation bar can be useful at the bottom of the scr To save from repeating the same widgets on each page, there's the *top_layer* which is the *Always on Top* transparent page above all the pages. Everything you put on this page will be on top of all the others. -For the navigation bar we use a button matrix. Note how the *header_footer* style definition is being applied to the widget and its children objects, and how a few more styles are configured manually at the main widget: +For the navigation bar we can use a button matrix. Note how the *header_footer* style definition is being applied to the widget and its children objects, and how a few more styles are configured manually at the main widget: .. code-block:: yaml @@ -371,12 +373,12 @@ Two notable things here, the widget starts *hidden* at boot, and it's only shown Title bar for each page ----------------------- -Each page can have its own title bar +Each page can have its own title bar: .. figure:: images/lvgl_cook_titlebar.png :align: center -To put a titlebar under the status icon, we need to add it to each page, also containing the label with a unique title: +To put a titlebar behind the status icon, we need to add it to each page, also containing the label with a unique title: .. code-block:: yaml @@ -413,6 +415,130 @@ To put a titlebar under the status icon, we need to add it to each page, also co ... +.. _lvgl-cook-clock: + +Analog clock with meter +----------------------- + +Using the meter widget, one can create an analog clock on the screen. + +.. figure:: images/lvgl_cook_clock.png + :align: center + +To put a titlebar behind the status icon, we need to add it to each page, also containing the label with a unique title: + +.. code-block:: yaml + + lvgl: + ... + pages: + - id: main_page + widgets: + - obj: # Clock container + height: size_content + width: 240 + align: CENTER + pad_all: 0 + border_width: 0 + bg_color: 0xFFFFFF + widgets: + - meter: # Clock face + height: 220 + width: 220 + align: center + bg_opa: TRANSP + text_color: 0x000000 + scales: + - ticks: # minutes scale + width: 1 + count: 61 + length: 10 + color: 0x000000 + range_from: 0 + range_to: 60 + angle_range: 360 + rotation: 270 + indicators: + - line: + id: minute_hand + width: 3 + color: 0xa6a6a6 + r_mod: -4 + value: 0 + - ticks: # hours scale + width: 1 + count: 12 + length: 1 + major: + stride: 1 + width: 4 + length: 8 + color: 0xC0C0C0 + label_gap: 12 + angle_range: 330 + rotation: 300 + range_from: 1 + range_to: 12 + - indicators: + - line: + id: hour_hand + width: 5 + color: 0xa6a6a6 + r_mod: -30 + value: 0 + angle_range: 360 + rotation: 270 + range_from: 0 + range_to: 720 + - label: + styles: date_style + id: day_label + y: -30 + - label: + id: date_label + styles: date_style + y: +30 + + time: + - platform: homeassistant + id: time_comp + + interval: + - interval: 1min + then: + if: + condition: + time.has_time: + then: + - script.execute: time_update + + script: + - id: time_update + then: + - lvgl.indicator.line.update: + id: minute_hand + value: !lambda |- + return id(time_comp).now().minute; + - lvgl.indicator.line.update: + id: hour_hand + value: !lambda |- + auto now = id(time_comp).now(); + return std::fmod(now.hour, 12) * 60 + now.minute; + - lvgl.label.update: + id: date_label + text: !lambda |- + static const char * const mon_names[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; + static char date_buf[8]; + auto now = id(time_comp).now(); + snprintf(date_buf, sizeof(date_buf), "%s %2d", mon_names[now.month-1], now.day_of_month); + return date_buf; + - lvgl.label.update: + id: day_label + text: !lambda |- + static const char * const day_names[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}; + return day_names[id(time_comp).now().day_of_week-1]; + + See Also -------- From 34a5fc5721220f314f6ba9c304256c93cd76aa20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 16:12:00 +0100 Subject: [PATCH 110/350] Update lvgl.rst --- cookbook/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 7535bfafc..d956ff6e0 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -11,7 +11,7 @@ Here are a couple recipes for various interesting things you can do with :ref:`l .. note:: - The examples below assume you've set up LVGL correctly with your display and input device, and you have the knowledge to set up various components in ESPHome. + The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of 240px, you have to adjust them to your screen in order to obtain expected results. .. _lvgl-cook-relay: @@ -425,7 +425,7 @@ Using the meter widget, one can create an analog clock on the screen. .. figure:: images/lvgl_cook_clock.png :align: center -To put a titlebar behind the status icon, we need to add it to each page, also containing the label with a unique title: +The script runs every minute to update the hand line positions and the label texts. .. code-block:: yaml From 44563339322ace2a4140e5c0387ea72a28fc179c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 18:44:58 +0100 Subject: [PATCH 111/350] cookbook update --- components/lvgl.rst | 2 +- cookbook/lvgl.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index abde9df5f..73764097a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1545,9 +1545,9 @@ See Also - :doc:`/components/number/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` +- :doc:`/cookbook/lvgl` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` -- :doc:`/cookbook/lvgl` - `LVGL 8.3 docs `__ - `LVGL Online Font Converter `__ - :ghedit:`Edit` diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index d956ff6e0..bea6e4574 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -323,6 +323,7 @@ For the navigation bar we can use a button matrix. Note how the *header_footer* then: lvgl.page.next: +For this example to work, use the theme and style options from :ref:`above `. .. _lvgl-cook-statico: @@ -414,6 +415,7 @@ To put a titlebar behind the status icon, we need to add it to each page, also c text_color: 0xFFFFFF ... +For this example to work, use the theme and style options from :ref:`above `. .. _lvgl-cook-clock: From 0bc76390d9f04bedb749c7ea4caa039b1fef722f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 20:20:35 +0100 Subject: [PATCH 112/350] Update lvgl.rst --- cookbook/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index bea6e4574..0e4dfe52c 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -343,13 +343,13 @@ In the example below we only show the icon when connection with Home Assistant i on_client_connected: - if: condition: - lambda: 'return (0 == client_address.compare(std::string{"your.ha.static.ip"}));' + lambda: 'return (0 == client_info.find("Home Assistant "));' then: - lvgl.widget.show: lbl_hastatus on_client_disconnected: - if: condition: - lambda: 'return (0 == client_address.compare(std::string{"your.ha.static.ip"}));' + lambda: 'return (0 == client_info.find("Home Assistant "));' then: - lvgl.widget.hide: lbl_hastatus From 0d37aba61d39ff29232ac4bc7664e91dd1254f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 20:44:21 +0100 Subject: [PATCH 113/350] Update lvgl.rst --- cookbook/lvgl.rst | 66 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 0e4dfe52c..351ef0415 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -540,6 +540,72 @@ The script runs every minute to update the hand line positions and the label tex static const char * const day_names[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}; return day_names[id(time_comp).now().day_of_week-1]; +.. _lvgl-cook-idlescreen: + +Turn off screen when idle +------------------------- + +LVGL has a notion of screen inactivity, i.e. how long did the user not interact with the screen. This can be use to dim the display backlight or turn it off after a moment of inactivity (like a screen saver). Touching the screen counts as an activity and resets the inactivity counter. + +You need a full screen ``obj`` on the *top_layer*, above everything else, to catch the first touch before waking up the screen, to make sure you don't click onto something you don't see. With a template number you can make the timeout settable by the users. + +.. code-block:: yaml + + lvgl: + ... + on_idle: + timeout: !lambda "return (id(display_timeout).state * 1000);" + then: + - logger.log: "LVGL is idle" + - light.turn_off: display_backlight + - lvgl.widget.show: blank_screen + - lvgl.pause: + top_layer: + widgets: + - ... # put here all the visible widgets + - obj: # put as the last a fullscreen click-catcher object, hidden by default + id: blank_screen + hidden: true + x: 0 + y: 0 + width: 240 + height: 320 + bg_color: 0x000000 + bg_opa: cover + radius: 0 + pad_all: 0 + border_width: 0 + on_press: + - lvgl.widget.hide: blank_screen + + touchscreen: + - platform: ... + on_touch: + - if: + condition: lvgl.is_paused + then: + - logger.log: "LVGL resuming" + - lvgl.resume: + - lvgl.widget.redraw: + - light.turn_on: display_backlight + + light: + - platform: ... + id: display_backlight + + number: + - platform: template + name: LVGL Screen timeout + optimistic: true + id: display_timeout + unit_of_measurement: "s" + initial_value: 45 + restore_value: true + min_value: 10 + max_value: 180 + step: 5 + mode: box + See Also -------- From cf731c81bbe54b1167d8660473ed8a38ab735826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 20:45:53 +0100 Subject: [PATCH 114/350] Update lvgl.rst --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 351ef0415..98cbba376 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -563,7 +563,7 @@ You need a full screen ``obj`` on the *top_layer*, above everything else, to cat top_layer: widgets: - ... # put here all the visible widgets - - obj: # put as the last a fullscreen click-catcher object, hidden by default + - obj: # put as last a fullscreen click-catcher object, hidden by default id: blank_screen hidden: true x: 0 From 61a008a9df64fafc01bfbc744e28ebd8907a1706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Jan 2024 21:14:34 +0100 Subject: [PATCH 115/350] Update lvgl.rst --- cookbook/lvgl.rst | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 98cbba376..e9cf8579e 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -11,7 +11,7 @@ Here are a couple recipes for various interesting things you can do with :ref:`l .. note:: - The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of 240px, you have to adjust them to your screen in order to obtain expected results. + The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of *240x320px*, you have to adjust them to your screen in order to obtain expected results. .. _lvgl-cook-relay: @@ -419,10 +419,10 @@ For this example to work, use the theme and style options from :ref:`above

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 literal 6573 zcmV;e8B*qnP)GaxWt zXyKI^FULFM#eg?PT3DmjuE!v|dZD39xSPHWT{s`qgG^i(M=+I4e7J&=7ZG{yeLq#z zgAE=J6I_aSZ~n#kKj%9q>ubOH&2RA6XkGh%y@CJB>u>1!tG&#N4~Gyw{Lc?Q{KZF` zUwsr#HwQ-qLuD;rx&M8)@?UZz2j_G5)u3zJ^;@^@{*!z6-v7XR|Ki(x?FIheU;W#k z|Ixqy51KaA$Sjpz8zAfa#?LL5Ll=lKFC*{L3A}WICI8v){r(^Pi+}lo+dP+^JMaI& z=GUJv56EJ^uzBhETjZWpK37~XC2zU@@_OUV_0K>4XL_fBfUa z?|=BO|L8yc^xxrsiO*z!{7eAx%;1?Z&&=OFa^HLZ@At>AIOlGi{GIM^cMm=v=D*1K z84V1snR@2ekzsHx<66eEuTBo~H5{IA06l}jB{zHxkN?LuKf|5({^5l?oRd!o;UE0H zH^O|V^o9KdKC>jh~lDtVaA;|-S_^{2|yOVmw_zJ zQL`jPDGHL5Dbx@4pRcy|#8lT>R+{zU&whI0-1GGO$w&2?i>#7wc=vX1ji80`88l28 z_ulJozuA#+4III;8Uj#;vSLv6FEBSHu0!PJwCyo6SX+aE_kwEF6+i7>o>Mxudps zZP-Q{!a!zG7(+SY<+nT#O`0L)Z<8tZMBM-UPeC8_8+WdwkRAN=8=vGv5eLHWnw@%T3hPT(=)0O=kq;RT# z?>>jTTQm?w7Yt~sWKQ1frfsr~w~ezTNq2)Zv}D(I%B;J60X@jo|5PP0AmNC)Rrh%I|Y)M}XO}RsdmG^MFPE-~FBbqTddfL{lg{Z_)u;^8BEuRc2pP(-CEyeTFqRZ)iFEs|ZrCc#k>;xB)G)9_ z-dz12$XyJ$`%ZiNq@AWjda|mbs(}HpBs=c`T^YYF);~2?mV5wp$F5-sO14@p6D*2W z5y%OKwsFenkI=XH{9%c?Ea_~O!-Z$=8AljG5zzYB-TPJ_C%MLhWaE$}fkq%y0!apt z9M9e4YI+JM4&p<#{{GdjGAOGA8E+Q;K@fxlR<55Mb38*O!|c4!d6Lf84%Q$@o#Xev zbBBg(;a4q;MFz4>NYawvg92$ROEr0^9KGP*$Xue{axm|0js`L$;Ey`K(z4K;>d7S@ zMaBMAyT0khc}ag3nV+YmRD@!Q`VxuneP`_mWN_tD29)Zl1`;$23yYT+SybNjp4@zO_96bQxMm+D98ndJ?LrU#xHY(z1%HZo69% zjl~q9R2*wEvVx2Rk%g(Uv~YxR)^L5~#+xh|T*{cH*dK9>(yStRNsc6W>n;DSclym| zqn-#WXpYEkR9K=5krC%8iA%&2RIT8}{@{v(CFTe;fT0wt515emzPH8{*^SIu9foPXY$E=>Udlj4>hu zIgy?Xl$BJnzN@!c2yAGP`o5DSC3=e-6d_tflV5p2 zX$Bz0phz`hLpH6Y^(zkv5)F|hP%!}KkcO-2+2^3UXl2kj*R32$Z3hVRz*R5R?-jlE_F|QHt9DS^(oD zE=g1WsvRB$T5lVdB;=$FHcXNv*ZDC9Jpqr{woXEf(41 zbMc4g2&@Sb8`hKr0s@*^nWlM!QSqNiigOsw#^Eu>EyAo20xiNE;;fo3)7kmNkaDM;|nItNm<=9`7ZjA1~BVH~xn^yRGgyuV(gvT(>tTHg*~*u~kWr%@@f6ekSl7G#+m17=}OP)dk!!Y_)O_axN3{MiaPEUfnVUd&bOj6v&*4UyEDa)^j zC`*vg9EZ&qXYBy6%k|HNdI5r%OY%u%5SmVhxOJ}a%EAmXl){dN$Ouu&VB<;W8XxB{ zd>OrC+d4~v7Flr$)8k0*B=oO#NdX4KF!X&tjsw7?(0MA$(S|5Ci6$WjWvdAwy^)l{ zENgAZaS1BoB{^Np-_A!|kyyXxkQL(qBp}5Yff8OAW+^8rASdVOSEQll;4DbeSlbXy zC&}G_YtZ-3IcFP>EC|lA?>paE3FG6aBq1q>7^5o4oRkr#ah%2wBMkvc=dh<2$p;2* z4BVB*nArAeY@+Ado&(^^WHWc z@<>C$BST6s76z^XUvV^6P}g?KNKy%LVHRn-S1>+`JPTcG$Ef&3Va9MeZMLe~wgYEg zET3JOUGQj{glua%1Ew5m$0}=lBq-i~n-Ltha#_gn!(YVj{nOj-MvDwfN5hZ>SO73e zv(Q))-D^FKrfD1=DP>rL)+0gQxyrbP@o`jAh*k;1B&lYG%uuZwuJ8$$>mMSE1PM<% zLJANPBt>MhDGq>f)~$ElC^v?#JL!kb#_2%^oIZ^GTfT(iio6+O4nY9mO`8m8Hb4E@ zW;m;85rDSko!icmDWmi_+$(N)G{KOTl`q7C>{W}pye`rMpa5bP6(xm~io}ewZC}dL z2sr-GmvKvGr$G>eS`J(NEB~lN z52RO4B^CCL%F+`!SCD;;D6N;e+$HnB5Pw*yGAJklie_hk&aV2B?2xWzA%%G|&?vY2T~K zrThmC&^Tm#{$R5{0t}*{9IV3-InFqF9hxOUPk`#%EiIK~4O&-l5;}wOd3ilo@q=6t zXF8HbrM+R1G$+ynP8pr!#`M$K=7VoBL`@MVujAgkil>z6alIn37AaB2Tl z(|B@>FzfS&)9~=L6wk`&UjA9FYx$Hxdyf@k68PHR+Agu>JOGJl{PcShz7fhd87 zbPlvo2veyMEE}%ha+^p>~HqnaW|fY2cMP(8L$Ton6&f+t|I0lJ$pfwW%gOmE*{4?N~t@3qrYis+RYan zv`PY`)0p5_hLUaxvrGWL2+bbhlzLI(%skb@fS!Lci+M7H6J`+f8t;W!8L4O z@x!A~x)X5*4Hq2m$}L|-PwBk@D6=`6EjtHt2NifAxRsM^m`2~a{$|&|zNWngI_o^Z zG)s?3`kLA*!hnr119J@VW6W6h?VtWCe6pGDyo+0F0%}*>JS2R-zUfsA}q430lePCJ#ZUx?GhmpKt?|!o*-FP;|7&J#@NI^oJV*%FFvb$n$FV{EQ z&{h#~U#m7ApbP=oruGF(gNZl1rN?1tD?OPVQeN7u2G(FIML#9QH{QC}ue;&X`_nWD zShuZjY|7mH*@JNkEFK@!6G%vca|CI#2*ixIL(E^CkEW#^3nLhY*{16b^tQ}L7yv#Y zS!YRtjv$bBz%U?WSfi9v60ET(O0T6gYCs|>gvX!IcU|8Dicyj_XEDr*<5)W9h4%?0 zp=}NEsdo7nO0I%LF6E;J0IXrk!W{I(MWHK|z?_g1vP}Ro3Ch5h?baqFYx1h1vBFaU zPKYUE*M?z^F%F!EB1TDJ8siKYxXvjoT1|LD1~eGA(bp7Vi9F|h zF-4zdf`Hi@M#_Rzq+{#oRROw?1U!jL6$!u+fLKo`S@s-3mn10Eo)UnJ_&C;R)38Ky z8hPi2DaIM&Tv7a;n!P0c6l4euts$GGZG@x@TOljhd@yuU@SV!4#V^kxo^4nA^efU62F^19mhz4|z(Qz1 z)7D>>Xqz%%(7tt&wn5_46>4O!4kpp1aNP(B7|2m=XmI}sekuC+T4w(m9>0#=F(kjcHd0|5M+C*xLe z7)7ps_m(|AX5&jVOgUQ8Hh^&{BW`1oNYXgxt1?%(LP;PHE99FMB?ykYR__bxA(3jT z4%ax}IJfd_80OICuCU)8NC}zHo(4g9x#710F;DXGXg+T*!47(5mh=U0tDlhaTY1l)57?a zB_!vZ;uK@5@Uj2{Hf=Tfj5wDGsEEbC6**s-n4Y6&nqsJrCjj3#l58+e(b08nDYCGG z^C}so<6FW=UitztgyLLi*${}O86$!jVGgC3U&aXNoR4!zl5HG}Ex{TxJ-j_8#tGI&x#`4 z()HZreGqTjgdnMB|YY2$IUO87V7C3G&9P4kIpJqo@rnvJ?fP;76tNGn|c^FDD6> z4wwMMSu}9Fd7l^ee*hpaVT&y4>z$)v+{O`f&cZlnkPcz)1q~}KW2SN$nOZtY`_X}f zoFEi0LQ)xYZW*FQwGE(%`|vVVEXB-nHX4Y`!cQ1^0~EmFU>R z3@S~3?7Ex>lcSYu`>TrcB`Vw(W=TpXqFy#!Lb3@_}@6>aERr(E(})Wpef+(z5bIZITi;6U2CRFEX)GJzb+C`2)j zbLx>xz9VF4jwrR~i~?IK#4@Q+W;&*=HV>!%$hB_CGb)O3QRB|hV*&4+z;T)iUr9LU zkoCrKd$R7?uq0IV4|6!ORi2cVy)MSOtCy6Zq@2oxea&uEk{xLl4HJ;E*wEi_=Vso3 zC~Y22-O9BMwbO@}_kYN7nyTxlwKvws{mDt+IfrUsqFJob?33%ddnA-sX1EM}9`@2o zlW+fg7NozR(%v~`A(PI##t&1(ffG~4a5{But6b}v%j+CH?al7NXM>jZdO6-YuGd}X z9J&0u(^^9dV5vp`9!Mr3@7x9#IMePqXO@4>5{NTk$P8t4t-E!yj!MJX>7oCO8JMQ7 zZ8c5GXphMEej$sS;^CSm6=3}7s1X)Kri zI*HxzV;xkiyogKj%eLkExN~$DOkNow#%4NmN zIr83jK6nv5_ul`YbaP(Pgf$kl=k&A|^s1@dqK$zw62eD6G)GJf#Se|Y(I z)GOWxymRu#gU>eYig(`Z`>w6_(^Mb=uobqy4m>RdoUIN3ON$ahUc6YYa7=-bZPB?4 z)1L;|F(O-3Uz{Y2+xXL8+<)-J>4mIn{pR}fPd~pXwJY)X`wu?v`_4loXatBxBt1PW z@f65WN|+ZlgJ2ewD4u#pNsfmQb`iXVQknE$YTKomX91*wwJWJaC#g&kAJWqvwO0~@ z=e@r@4CC$FcRKF?q&UWDP>jmJQ{g&bo%5dF@`h#O>o~S_5NC>qprym5WTFsYO?`#z zA~8rMf)yt#VF_q^$&8Q2E4Piy?`!VXKmP9bQ&!x5YQJs_LGv{LU%PhQe4~!{85na7 z=DIQ8u>8gi*z0(99mvW8GBV1`n%BYWUpM(#zJ6_|3q?2<*RGdy(lg{|`TDb*aot?I zZg_*V#$0b`?Qe1WKezLrNBu>{Z}CSz`q5AR<4>MP3|{>HHh}ab3=i*5n~&2xU>1zC zjpvQSiN%^4*39~;mS9?{qYFv>&Rf`vPda>PK_GG}-Gne}iaL4c?*Hlg=>I>izi$8k f!QasHS9|?$9B`l(n?nq-00000NkvXXu0mjfLlK-# From 3f2da4714cea5b9bb72d925193ff52faec20d866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Jan 2024 10:12:39 +0100 Subject: [PATCH 122/350] dimensioning doc --- components/images/lvgl_boxmodel.png | Bin 0 -> 18948 bytes components/lvgl.rst | 38 +++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 components/images/lvgl_boxmodel.png diff --git a/components/images/lvgl_boxmodel.png b/components/images/lvgl_boxmodel.png new file mode 100644 index 0000000000000000000000000000000000000000..0368fa99a620bf1bab8bab9cd9aace6db25e0d36 GIT binary patch literal 18948 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. An object's "box" is built from the following parts: + +.. figure:: /components/images/lvgl_boxmodel.png + :align: center + +- **bounding box**: the width/height of the elements. +- **border width**: the width of the border. +- **padding**: space between the sides of the object and its children. +- **content**: the content area which is the size of the bounding box reduced by the border width and padding. + +The border is drawn inside the bounding box. Inside the border LVGL keeps a "padding margin" when placing an object's children. + +The outline is drawn outside the bounding box. + You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each object. Some widgets allow for more complex styling, effectively changing the appearance of their parts. - **align** (*Optional*, enum): Alignment of the of the widget `relative to the parent `__. One of: @@ -289,10 +303,6 @@ You can adjust the appearance of widgets by changing the foreground, background - **transform_zoom** (*Optional*, 0.1-10): Trannsformation zoom of the widget (eg. resizing) - **translate_x** (*Optional*, int16 or percentage): Move of the widget with this value in horizontal direction. - **translate_y** (*Optional*, int16 or percentage): Move of the widget with this value in vertical direction. -- **max_height** (*Optional*, int16 or percentage): Sets a maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. -- **min_height** (*Optional*, int16 or percentage): Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area. Defaults to ``0%``. -- **max_width** (*Optional*, int16 or percentage): Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. -- **min_width** (*Optional*, int16 or percentage): Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` - **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) @@ -314,8 +324,24 @@ The properties below are common to all widgets. - **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to top left of parent or screen). If layouts are used, or if specfiyng ``align``, it is used as an offset to the calculated position (can also be negative). - **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to to top left of the parent or screen). If layouts are used, or if specfiyng ``align``, it is used as an offset to the calculated position (can also be negative). -- **width** (*Optional*): Width of the widget in pixels or a percentage, or ``size_content`` (see below). -- **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content``. Use ``size_content`` to automatically size the widget based on its contents (children objects, text size, image size etc.) + +.. note:: + + By default, the ``x`` and ``y`` coordinates are measured from the *top left corner* of the parent's content area. Important: content area starts *after the padding* thus if the parent has a non-zero padding value, position will be shifted with that. Percentage values are calculated from the parent's content area size. + +- **width** (*Optional*): Width of the widget in pixels or a percentage, or ``size_content`` (see note below). +- **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content`` (see note below). + +.. note:: + + The size settings support a special value: ``size_content``. It means the object's size in the respective direction will be set to the size of its children. Note that only children on the right and bottom sides will be considered and children on the top and left remain cropped. This limitation makes the behavior more predictable. Objects with ``hidden`` or ``floating`` flags will be ignored by the ``size_content`` calculation. + + Similarly to CSS, LVGL also supports ``min_width``, ``max_width``, ``min_height`` and ``max_height``. These are limits preventing an object's size from becoming smaller/larger than these values. They are especially useful if the size is set by percentage or ``size_content``. + +- **min_width** (*Optional*, int16 or percentage): Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. +- **max_width** (*Optional*, int16 or percentage): Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. +- **min_height** (*Optional*, int16 or percentage): Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area. Defaults to ``0%``. +- **max_height** (*Optional*, int16 or percentage): Sets a maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused widget which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. - **styles** (*Optional*, :ref:`config-id`): The ID of a *style definition* from the main component configuration to override the theme styles. - **theme** (*Optional*, list): A list of styles to apply to the widget and children. Same configuration option as at the main component. From 5cf504702dc1679de9119dd618c6ba3ac0919870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Jan 2024 11:16:20 +0100 Subject: [PATCH 123/350] cookies --- cookbook/images/lvgl_cook_clock.png | Bin 11469 -> 11500 bytes cookbook/lvgl.rst | 106 ++++++++++++++-------------- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/cookbook/images/lvgl_cook_clock.png b/cookbook/images/lvgl_cook_clock.png index 72ef41ed0678ba2a1fe5647ec6df5ed54d302f0a..631d41fe84037d761d8706b0c94e7f1a828ba596 100644 GIT binary patch literal 11500 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 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index e9cf8579e..3fef258fd 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -15,7 +15,7 @@ Here are a couple recipes for various interesting things you can do with :ref:`l .. _lvgl-cook-relay: -Toggle local light +Local light switch ------------------ If you have a display device with a local light configured, you can simply create a wall switch for it. @@ -30,6 +30,48 @@ If you have a display device with a local light configured, you can simply creat if: condition: light.is_on: room_light + then: + - lvgl.widget.update: + id: light_switch + state: + checked: true + else: + - lvgl.widget.update: + id: light_switch + state: + checked: false + lvgl: + ... + pages: + - id: main_page + widgets: + - switch: + align: center + id: light_switch + on_click: + - homeassistant.service: + service: light.toggle + data: + entity_id: light.remote_light + +.. _lvgl-cook-binent: + +Remote light switch +------------------- + +If you'd like to control a remote light, which appears as an entity in Home Assistant, first you need to import the light state into ESPHome, and then control it using a service call: + +.. code-block:: yaml + + binary_sensor: + - platform: homeassistant + id: remote_light + entity_id: light.remote_light + on_state: + then: + if: + condition: + lambda: return x; then: - lvgl.widget.update: id: light_btn @@ -40,6 +82,7 @@ If you have a display device with a local light configured, you can simply creat id: light_btn state: checked: false + lvgl: ... pages: @@ -58,60 +101,17 @@ If you have a display device with a local light configured, you can simply creat on_click: light.toggle: room_light -.. _lvgl-cook-binent: - -Toggle remote light -------------------- - -If you'd like to control a remote light, which appears as an entity in Home Assistant, first you need to import the light state into ESPHome, and then control it using a service call: - -.. code-block:: yaml - - binary_sensor: - - platform: homeassistant - id: remote_light - entity_id: light.remote_light - on_state: - then: - if: - condition: - lambda: return x; - then: - - lvgl.widget.update: - id: light_switch - state: - checked: true - else: - - lvgl.widget.update: - id: light_switch - state: - checked: false - - lvgl: - ... - pages: - - id: main_page - widgets: - - switch: - align: center - id: light_switch - on_click: - - homeassistant.service: - service: light.toggle - data: - entity_id: light.remote_light - .. _lvgl-cook-cover: Cover status and control ------------------------ -To make a nice user interface for controlling covers you could use 3 buttons, which also display the state. +To make a nice user interface for controlling Home Assistant covers you could use 3 buttons, which also display the state. .. figure:: images/lvgl_cook_cover.png :align: center -Just as in the previous example, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *opening*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. +Just as in the previous example, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. .. code-block:: yaml @@ -248,7 +248,7 @@ In this example we prepare a set of gradient styles in the *theme*, and make som theme: btn: bg_color: 0x2F8CD8 - bg_grad_color: 0x005782 #0x006699 + bg_grad_color: 0x005782 bg_grad_dir: VER bg_opa: cover border_color: 0x0077b3 @@ -264,7 +264,7 @@ In this example we prepare a set of gradient styles in the *theme*, and make som style_definitions: - id: header_footer bg_color: 0x2F8CD8 - bg_grad_color: 0x005782 #0x004466 + bg_grad_color: 0x005782 bg_grad_dir: VER bg_opa: cover border_width: 0 @@ -274,6 +274,10 @@ In this example we prepare a set of gradient styles in the *theme*, and make som pad_column: 0 border_color: 0x0077b3 text_color: 0xFFFFFF + width: 100% + height: 30 + +Note that style definitions can contain common properties too, like positioning and sizing. .. _lvgl-cook-navigator: @@ -296,8 +300,6 @@ For the navigation bar we can use a button matrix. Note how the *header_footer* top_layer: widgets: - btnmatrix: - width: 100% - height: 30px align: bottom_mid styles: header_footer pad_all: 0 @@ -390,8 +392,6 @@ To put a titlebar behind the status icon, we need to add it to each page, also c widgets: - obj: align: TOP_MID - width: 240 - height: 30 styles: header_footer widgets: - label: @@ -404,8 +404,6 @@ To put a titlebar behind the status icon, we need to add it to each page, also c widgets: - obj: align: TOP_MID - width: 240 - height: 30 styles: header_footer widgets: - label: From 680b2bf32dc347c80277e958fd21f29ae74da8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Jan 2024 12:20:16 +0100 Subject: [PATCH 124/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7d6a491ed..cfac98157 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -493,7 +493,7 @@ Not only the end, but also the start value of the bar can be set, which changes - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, all the typical background properties. - **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. -- Style options from :ref:`lvgl-styling`. The background of the bar and it uses the typical background style properties. Adding padding makes the indicator smaller or larger. +- Style options from :ref:`lvgl-styling`. The background of the bar and it uses the typical background style properties. Adding padding will make the indicator smaller or larger. **Example:** From fd380751046b0ce60cc2ebb5f9651d51faf20f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Jan 2024 17:14:31 +0100 Subject: [PATCH 125/350] thremocookie --- cookbook/images/lvgl_cook_thermometer.png | Bin 0 -> 11532 bytes cookbook/lvgl.rst | 78 +++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 cookbook/images/lvgl_cook_thermometer.png diff --git a/cookbook/images/lvgl_cook_thermometer.png b/cookbook/images/lvgl_cook_thermometer.png new file mode 100644 index 0000000000000000000000000000000000000000..ee38819578cb9e3f9d0f7f34c11d9df3e0998c09 GIT binary patch literal 11532 zcmW++Wmpwm7ah8hlI}*j8|m(ny3$?J-JQavySuwnr8}iNE+CD7f_(S=e$1KY%*=D< z`3_gxO zaG0KEXnAphiZYRcG?BbAk-WtpC⪻Zu*3B`h@RP3He3XW>QkLh}P<8*%EbOmtXmb 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 literal 0 HcmV?d00001 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 3fef258fd..0a328dbfa 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -101,6 +101,82 @@ If you'd like to control a remote light, which appears as an entity in Home Assi on_click: light.toggle: room_light +.. _lvgl-cook-thermometer: + +Thermometer +----------- + +A thermometer with a gauge acomplished with ``meter`` widget and numeric display using ``label``: + +.. figure:: images/lvgl_cook_thermometer.png + :align: center + +With a numeric sensor we retrieve the desired temperature sensor value from Home Assistant, and with it we update the needle indicator, and the text label respectively. + +.. code-block:: yaml + + sensor: + - platform: homeassistant + id: outdoor_temperature + entity_id: sensor.outdoor_temperature + on_value: + - lvgl.indicator.line.update: + id: temperature_needle + value: !lambda return id(outdoor_temperature).state; + - lvgl.label.update: + id: temperature_text + text: !lambda |- + static char buf[10]; + snprintf(buf, 10, "%.2f%°C", id(outdoor_temperature).state); + return buf; + + lvgl: + ... + pages: + - id: main_page + widgets: + - meter: + align: CENTER + height: 180 + width: 180 + scales: + - ticks: + width: 2 + count: 51 + length: 10 + color: 0x000000 + major: + stride: 5 + width: 4 + length: 10 + color: 0x404040 + label_gap: 13 + range_from: -10 + range_to: 40 + angle_range: 240 + rotation: 150 + indicators: + - line: + id: temperature_needle + width: 2 + color: 0xFF0000 + r_mod: -4 + - ticks: + start_value: -10 + end_value: 40 + color_start: 0x0000bd + color_end: 0xbd0000 + widgets: + - label: + text: "°C" + id: temperature_text + align: CENTER + y: 45 + - label: + text: "Outdoor" + align: CENTER + y: 65 + .. _lvgl-cook-cover: Cover status and control @@ -111,7 +187,7 @@ To make a nice user interface for controlling Home Assistant covers you could us .. figure:: images/lvgl_cook_cover.png :align: center -Just as in the previous example, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. +Just as in the previous examples, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. .. code-block:: yaml From e54574fa56ea5e2c4d8e954b0f7a6f2b0469aa02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Jan 2024 20:14:51 +0100 Subject: [PATCH 126/350] test --- cookbook/lvgl.rst | 9 ++++----- images/logo_lvgl_white.png | Bin 0 -> 6798 bytes index.rst | 12 ++++++------ 3 files changed, 10 insertions(+), 11 deletions(-) create mode 100644 images/logo_lvgl_white.png diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 0a328dbfa..aff4d5fd1 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -111,14 +111,13 @@ A thermometer with a gauge acomplished with ``meter`` widget and numeric display .. figure:: images/lvgl_cook_thermometer.png :align: center -With a numeric sensor we retrieve the desired temperature sensor value from Home Assistant, and with it we update the needle indicator, and the text label respectively. +Whenever a new value comes from the sensor, we update the needle indicator, and the text label respectively. .. code-block:: yaml sensor: - - platform: homeassistant + - platform: ... id: outdoor_temperature - entity_id: sensor.outdoor_temperature on_value: - lvgl.indicator.line.update: id: temperature_needle @@ -177,6 +176,8 @@ With a numeric sensor we retrieve the desired temperature sensor value from Home align: CENTER y: 65 +Notable here is the way the label is updated with a sensor numeric value using `snprintf `__. + .. _lvgl-cook-cover: Cover status and control @@ -303,8 +304,6 @@ Just as in the previous examples, we need to get the states of the cover first. data: entity_id: cover.myroom -Notable here is the way the label is updated with a sensor numeric value using ``snprintf``. - .. _lvgl-cook-theme: Theme and style definitions diff --git a/images/logo_lvgl_white.png b/images/logo_lvgl_white.png new file mode 100644 index 0000000000000000000000000000000000000000..8104acd2b94a162962a6524e2b70f9eed5ffe66c GIT binary patch literal 6798 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 literal 0 HcmV?d00001 diff --git a/index.rst b/index.rst index 172bee9cb..ee3dc262e 100644 --- a/index.rst +++ b/index.rst @@ -496,7 +496,7 @@ Touchscreen *********** .. imgtable:: - LVGL widget, components/binary_sensor/lvgl, logo_lvgl.png + LVGL widget, components/binary_sensor/lvgl, logo_lvgl.png, logo_lvgl_white.png Nextion, components/binary_sensor/nextion, nextion.jpg Touchscreen, components/touchscreen/index, touch.svg, dark-invert TT21100, components/touchscreen/tt21100, esp32-s3-korvo-2-lcd.png @@ -594,7 +594,7 @@ Light Components H-bridge Light, components/light/hbridge, brightness-medium.svg, dark-invert Sonoff D1 Dimmer, components/light/sonoff_d1, sonoff_d1.jpg - LVGL widget, components/light/lvgl, logo_lvgl.png + LVGL widget, components/light/lvgl, logo_lvgl.png, logo_lvgl_white.png Looking for WS2811 and similar individually addressable lights? Have a look at the :doc:`FastLED Light `. @@ -618,7 +618,7 @@ Switch Components Modbus Switch, components/switch/modbus_controller, modbus.png BLE Client Switch, components/switch/ble_client, bluetooth.svg, dark-invert Nextion Switch, components/switch/nextion, nextion.jpg - LVGL widget, components/switch/lvgl, logo_lvgl.png + LVGL widget, components/switch/lvgl, logo_lvgl.png, logo_lvgl_white.png Button Components ----------------- @@ -664,7 +664,7 @@ Display Components Inkplate, components/display/inkplate6, inkplate6.jpg LCD Display, components/display/lcd_display, lcd.jpg - LVGL, components/lvgl, logo_lvgl.png + LVGL, components/lvgl, logo_lvgl.png, logo_lvgl_white.png MAX7219, components/display/max7219, max7219.jpg MAX7219 Dot Matrix, components/display/max7219digit, max7219digit.jpg Nextion, components/display/nextion, nextion.jpg @@ -759,7 +759,7 @@ Number Components .. imgtable:: Number Core, components/number/index, folder-open.svg, dark-invert - LVGL widget Number, components/number/lvgl, logo_lvgl.png + LVGL widget Number, components/number/lvgl, logo_lvgl.png, logo_lvgl_white.png Modbus Number, components/number/modbus_controller, modbus.png Template Number, components/number/template, description.svg, dark-invert Tuya Number, components/number/tuya, tuya.png @@ -942,7 +942,7 @@ Cookbook Arduino Port Extender, cookbook/arduino_port_extender, arduino_logo.svg EHMTX a matrix status/text display, cookbook/ehmtx, ehmtx.jpg Share data directly between ESPHome nodes, cookbook/http_request_sensor, connection.svg, dark-invert - LVGL: Tips and Tricks, cookbook/lvgl, logo_lvgl.png + LVGL: Tips and Tricks, cookbook/lvgl, logo_lvgl.png, logo_lvgl_white.png Do you have other awesome automations or cool setups? Please feel free to add them to the documentation for others to copy. See :doc:`Contributing `. From 63eb89fc33ec471c785eb81d537ac57bbf557465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Jan 2024 20:28:21 +0100 Subject: [PATCH 127/350] lvgl logo --- images/logo_lvgl.png | Bin 6743 -> 8178 bytes images/logo_lvgl_white.png | Bin 6798 -> 0 bytes index.rst | 12 ++++++------ 3 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 images/logo_lvgl_white.png diff --git a/images/logo_lvgl.png b/images/logo_lvgl.png index 26e5a48a0b1de3643f265ea8575c63c143d0a896..8f6af263319b063c678054b256fc4762e697498a 100644 GIT binary patch delta 5705 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 diff --git a/images/logo_lvgl_white.png b/images/logo_lvgl_white.png deleted file mode 100644 index 8104acd2b94a162962a6524e2b70f9eed5ffe66c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6798 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 diff --git a/index.rst b/index.rst index ee3dc262e..327052a60 100644 --- a/index.rst +++ b/index.rst @@ -496,7 +496,7 @@ Touchscreen *********** .. imgtable:: - LVGL widget, components/binary_sensor/lvgl, logo_lvgl.png, logo_lvgl_white.png + LVGL widget, components/binary_sensor/lvgl, logo_lvgl.png Nextion, components/binary_sensor/nextion, nextion.jpg Touchscreen, components/touchscreen/index, touch.svg, dark-invert TT21100, components/touchscreen/tt21100, esp32-s3-korvo-2-lcd.png @@ -594,7 +594,7 @@ Light Components H-bridge Light, components/light/hbridge, brightness-medium.svg, dark-invert Sonoff D1 Dimmer, components/light/sonoff_d1, sonoff_d1.jpg - LVGL widget, components/light/lvgl, logo_lvgl.png, logo_lvgl_white.png + LVGL widget, components/light/lvgl, logo_lvgl.png Looking for WS2811 and similar individually addressable lights? Have a look at the :doc:`FastLED Light `. @@ -618,7 +618,7 @@ Switch Components Modbus Switch, components/switch/modbus_controller, modbus.png BLE Client Switch, components/switch/ble_client, bluetooth.svg, dark-invert Nextion Switch, components/switch/nextion, nextion.jpg - LVGL widget, components/switch/lvgl, logo_lvgl.png, logo_lvgl_white.png + LVGL widget, components/switch/lvgl, logo_lvgl.png Button Components ----------------- @@ -664,7 +664,7 @@ Display Components Inkplate, components/display/inkplate6, inkplate6.jpg LCD Display, components/display/lcd_display, lcd.jpg - LVGL, components/lvgl, logo_lvgl.png, logo_lvgl_white.png + LVGL, components/lvgl, logo_lvgl.png MAX7219, components/display/max7219, max7219.jpg MAX7219 Dot Matrix, components/display/max7219digit, max7219digit.jpg Nextion, components/display/nextion, nextion.jpg @@ -759,7 +759,7 @@ Number Components .. imgtable:: Number Core, components/number/index, folder-open.svg, dark-invert - LVGL widget Number, components/number/lvgl, logo_lvgl.png, logo_lvgl_white.png + LVGL widget Number, components/number/lvgl, logo_lvgl.png Modbus Number, components/number/modbus_controller, modbus.png Template Number, components/number/template, description.svg, dark-invert Tuya Number, components/number/tuya, tuya.png @@ -942,7 +942,7 @@ Cookbook Arduino Port Extender, cookbook/arduino_port_extender, arduino_logo.svg EHMTX a matrix status/text display, cookbook/ehmtx, ehmtx.jpg Share data directly between ESPHome nodes, cookbook/http_request_sensor, connection.svg, dark-invert - LVGL: Tips and Tricks, cookbook/lvgl, logo_lvgl.png, logo_lvgl_white.png + LVGL Display: Tips and Tricks, cookbook/lvgl, logo_lvgl.png Do you have other awesome automations or cool setups? Please feel free to add them to the documentation for others to copy. See :doc:`Contributing `. From 8d8f83b3424db3870594f02f42c9c38427572b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Jan 2024 20:34:08 +0100 Subject: [PATCH 128/350] Update logo_lvgl.png --- images/logo_lvgl.png | Bin 8178 -> 5445 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/logo_lvgl.png b/images/logo_lvgl.png index 8f6af263319b063c678054b256fc4762e697498a..5cdda0ad07fa0af944151c2848fcf7fa638ebf8b 100644 GIT binary patch literal 5445 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 literal 8178 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 Date: Mon, 22 Jan 2024 20:38:21 +0100 Subject: [PATCH 129/350] Update index.rst --- index.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.rst b/index.rst index 327052a60..14eab0e0e 100644 --- a/index.rst +++ b/index.rst @@ -496,7 +496,7 @@ Touchscreen *********** .. imgtable:: - LVGL widget, components/binary_sensor/lvgl, logo_lvgl.png + LVGL Widget, components/binary_sensor/lvgl, logo_lvgl.png Nextion, components/binary_sensor/nextion, nextion.jpg Touchscreen, components/touchscreen/index, touch.svg, dark-invert TT21100, components/touchscreen/tt21100, esp32-s3-korvo-2-lcd.png @@ -594,7 +594,7 @@ Light Components H-bridge Light, components/light/hbridge, brightness-medium.svg, dark-invert Sonoff D1 Dimmer, components/light/sonoff_d1, sonoff_d1.jpg - LVGL widget, components/light/lvgl, logo_lvgl.png + LVGL Widget, components/light/lvgl, logo_lvgl.png Looking for WS2811 and similar individually addressable lights? Have a look at the :doc:`FastLED Light `. @@ -618,7 +618,7 @@ Switch Components Modbus Switch, components/switch/modbus_controller, modbus.png BLE Client Switch, components/switch/ble_client, bluetooth.svg, dark-invert Nextion Switch, components/switch/nextion, nextion.jpg - LVGL widget, components/switch/lvgl, logo_lvgl.png + LVGL Widget, components/switch/lvgl, logo_lvgl.png Button Components ----------------- @@ -664,7 +664,7 @@ Display Components Inkplate, components/display/inkplate6, inkplate6.jpg LCD Display, components/display/lcd_display, lcd.jpg - LVGL, components/lvgl, logo_lvgl.png + LVGL Graphics, components/lvgl, logo_lvgl.png MAX7219, components/display/max7219, max7219.jpg MAX7219 Dot Matrix, components/display/max7219digit, max7219digit.jpg Nextion, components/display/nextion, nextion.jpg @@ -759,7 +759,7 @@ Number Components .. imgtable:: Number Core, components/number/index, folder-open.svg, dark-invert - LVGL widget Number, components/number/lvgl, logo_lvgl.png + LVGL Widget Number, components/number/lvgl, logo_lvgl.png Modbus Number, components/number/modbus_controller, modbus.png Template Number, components/number/template, description.svg, dark-invert Tuya Number, components/number/tuya, tuya.png @@ -942,7 +942,7 @@ Cookbook Arduino Port Extender, cookbook/arduino_port_extender, arduino_logo.svg EHMTX a matrix status/text display, cookbook/ehmtx, ehmtx.jpg Share data directly between ESPHome nodes, cookbook/http_request_sensor, connection.svg, dark-invert - LVGL Display: Tips and Tricks, cookbook/lvgl, logo_lvgl.png + LVGL Graphics: Tips and Tricks, cookbook/lvgl, logo_lvgl.png Do you have other awesome automations or cool setups? Please feel free to add them to the documentation for others to copy. See :doc:`Contributing `. From 66a1044c8e37c2092cd239c9d6766624e3ff5afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Jan 2024 20:42:43 +0100 Subject: [PATCH 130/350] Update lvgl.rst --- components/lvgl.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index cfac98157..7006ab1e5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -15,11 +15,12 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t .. figure:: /components/images/lvgl_main_screenshot.png :align: center -In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although -PSRAM is not a strict requirement, it is recommended. +In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. For interactivity, a :ref:`Touchscreen ` (capacitive highly prefered) or a :doc:`/components/sensor/rotary_encoder` can be used. +Check out a few detailed examples :ref:`in the Cookbook ` to see a couple ways to integrate LVGL through ESPHome with your environment. + Basics ------ From fd48678f5ccda51b628db4e7909f8d5d01380862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 23 Jan 2024 13:56:57 +0100 Subject: [PATCH 131/350] newpic --- components/images/lvgl_main_screenshot.png | Bin 10498 -> 38134 bytes components/lvgl.rst | 1 - 2 files changed, 1 deletion(-) diff --git a/components/images/lvgl_main_screenshot.png b/components/images/lvgl_main_screenshot.png index 9130b348a23e8dc01bf666550b49cc45e5ff3dfa..5d1d012df24b288c2b1d1601e173b5a4021923ee 100644 GIT binary patch literal 38134 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%0D1FikzWIVS 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 literal 10498 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 Date: Tue, 23 Jan 2024 14:14:26 +0100 Subject: [PATCH 132/350] Update lvgl_main_screenshot.png --- components/images/lvgl_main_screenshot.png | Bin 38134 -> 40589 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_main_screenshot.png b/components/images/lvgl_main_screenshot.png index 5d1d012df24b288c2b1d1601e173b5a4021923ee..0729ccd37c89464c77166b7253eb521570c4f366 100644 GIT binary patch literal 40589 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 HdmHv&hqQfH literal 38134 zcma%iWl&sA6Yjy?-6dFX2ol^O1PL45o#5`S!QCAe3GVI?EV#P`cP9|^?)$ypcdPEd zyS24-YR=A_nVz2Rr@NmMuB0e~hD?kM005foC&{k>0Id!HP@;&?kQQ>I2^#>Q1Y{+} zRNS*pJAJH4)Kj*+JjvZ0ET%990#H@BcM(*7df1nqX@bH@=vK)kojbxx7zmX?Fe%n- z)W3-ORXpQ9P2@?G2E`O|=`jy3Njm#4CAb+!!fRm(naen14$*ekN)Vqll-!?!kiyt$ zD?+NEnf*h!vGm5UZ#F2TlyNl+A6UM&i6BC&Qrzb-;$4(Fo%0>M20OhlVIsmp2h^}k zOMx?4paVoHF%dI^(JAYeIsd)Ecj&(q2>FNTQq}Xk8OlHRVf%{ngBUifiT>#+xK>xeX|1`3|NkC}_F$h5eS4jAHQL~3_E*xN#ZVn>1V<>+D z@oaTimjY7^M{-jVHxh|2@6NsIo~n}EeaU}7`hGUPrXlESar?ZMG>a5$)H^-wkY@3L zqqKdWJk&cjNyVpO0{=7}8|d*!g6lbU9VNGHD~~5Ad_6(oDxxqqBSMC^4GYNHtj1cny!QYHhBb7Ous*ig*2tRezVu@dL);EVW#{N=eS z96Oami(vh)f?~hA3oC5;HB{`Oa;UN{GewtR36Z0l>eOr%-a>MuaZz!h=T)rMY^>L8 zNX^aWYiWI#__e3HO8|fKK55wFKhtV41cei$wRWYKAGv(X95^Z86WVs09(S{rYz|s0 zVwqf{Q5DkOa?Lo|WOJrzgD8<_t1~r_qrF)osK$unZE~k4Kn|(|B9Y=fXFTX!i`vIg zSKlyzhFL>i2Uc&N#dA%EXO(xxVMi`_!Fl8T&VC#}$OUgwN*$UV1Svhw^mR_1H3q-ld(V-ySOBB$l(qALX1nX% zAW5!wHVz&tP=>}&mh@PSvLG}k`r!xpnxF2cq^9b0)oxwL*1Y2#m_v~beLS=0;(%FP z%%Y8<v9x!7D6^`;nm)-eiU{a@~Lxo_kgw@o2K=4q^?)|?TU z?*pRV*hgL1bKcBwL@2yciwd>X=@1pHBsE^8FWuxMiz!x7irhw|B#o}Yg$Bgbuw$|C z#-=?NE6lyW(fv^7;-|(`0b>E5e8dawVSzE`ZGuMfoTPg1NG!m>QpujSaNVqLaN788 zJ#;yM1f|b-;F*+rMK2b!<(m``1~_Lf6Nw$SVoSnvxkl}5a)J=iyjh07*bhOOJw^{c zVz|qO13g7MchN2?7cOE+cdX9Ju5CWw;l zX?(vxPO4`WY!UmpmC;`}=9E}>u^5^hbU-(h@1ldtQ9=}+Yi$f7H$|N+lFoN6t0X(A zrFt2A?{ZL4g24uSllR=U?|6-?HJjiECx|M&EOr!q4lN{A*t;28&7`6XcL&8q;|_I) z1t>Bp$4pSL5lw%#C{sMP(7qn5?M%hr_(t_|a39#(Sz8%ANQDqcbp4f&S7RvFUIokB81-XP1L(ntTRX$- z9<%+xB#cx_oFvLX8fCmG{C#G!!@|goXs10&;BGMcad3SQvPlKa_|mo!&tDN!7AD5y z-Uo!tV*>WvafiN!?{~8?iujmfl@Ve6mk>vX-c;C2Frw%wJ%hmO{aPnc#zP-J4&Lcu zR4s-O0+`Tpl@1N-G{Q(%atUUcz?6;I85%RdGfxE7!`r=|M}mR)v+|A-ng9!$^m{l48zL^^T)fggC-Meb&xhtKpn80aG4 z^Kb2+h3aV=I<)34wWY%Q4lUce<3`YiG00l~MESu}hQ=5=|4_$g9bDFP)sE6p66P4j zaoD=9axa#$Zh9)BMe!h}=r~_kT1*BP7T6FmK%ZarleC-At5#KCr4xfDy8ilOi0CI# zjcIZm2SPzNsYzWdKzgO8Kiam_^br36qo`ilDg2Ap*G#Ir>cjevF~RSm z`5T(7Ui9WCP(mE8KRllf>*wr9$hLku%5kkctI|e!z1OPnib}w?ShG3p+*Zf9VG9NF zEHHLj*(|xR6_yjylZ-38(pybUb*(@>h9wl&%On~nPJ_QwHQl@l_I?tH4O$53zL8L+ z2^*7jHnKaYqZ(S5eo)MZ(nTLre^}Ao{P08wID>|fw zmJZk_kT}-{7lgwBz8oG+MliAFZz}eWQFq4{kr(;>=i)CiCqoykpOE*>cm1l1oceN) z^FO(Sdbqq4VOS4^qEbp$JhUj>n_V)7VG7A!|vw}B`55m964U35u{}nG7GmiB*^G{o->n0Lg7;FY zcN1t@?HKhh%Fuwu{Y<#}H@|>Ag2bR?W*2F|ejWR(U0~r>>rnprPv(%@9k;}n5?FCi z9PXME?S8HS!<<`EwpY}ADBmlsf_SKMnT0U`tFeCWMbqfrhe5WpMi!m_BR=57sY)9f z_+*GE6wUB^$#5Bh0SYC29GShM!bu2rzF@3~9y#^}^cb)y?g1E`-F}Zj; z(>XkmLg^vM4fhe?pnVM8E4tE#!%l?1Um*1$}FxB z2`_|U!ul#5TTa=RANB76-D%IRB_7dNKXrJ6674jg@@|}jLHjtVFPkre$9~lVLhUt_ z?*Rjk7>nge)XgMpHg?_m4Bf?f%2nTDQxO4sAJ*UJ1FWqln5#Z%WZg`x)!S{v{pXw$ z>)7_VFa|q{oo^K`Tb`Hz|CsfTt?{I(-wc`Z`t-Wlf{Waixn;vTED&#QZ6Bsj_q5@B zJS;(po0{HSams4U>yNG0aU_AvW!;-IdZLH%S1SC?=lXA5pxmBJhO5ahO)g_a#$7j|uZ?aZOkQ)qNH97E<;Z2FmM0MxKaj#+dY#<$%s4vF;J>|>aOSAAqu~>|2xwE;55qg zzqq>#^S}7||F=Pj&a=(S^U3q(BM6lA_~`jcuJ0U=C<*b8u;Rk*RUXGDCwNk_YwrD? zg+JQq9U@z(7Zw*InWzCuZH1+nr3{;&5kf??jp&f_}kx&%<-6EqaT%nVU=1`;# zd34LgXizggaEl8zhbdn?ie&vpiy1C0PS_4z$3%%vR_R7s$g52aonN7ZYs#VhVE4BL z|91USb1Y@+rvcdVcKvoac6EMIXk92wyo~kq=-kkf=+6JsM114|{y~S9~W_HTl6u&5Z;F@)5D|gT@ zsA0J6UcGQ%H59VOOO@QLuv1o{G%0|HVdq;aUIU|z>eCk-+-QH&jOgu@$%k~_O3j>k zM=3;RCawW6i{+a|U|jq{eox(+qZDOCTuo&dpH%ntvR*Axq&N*}E%)l-y7L7|XPGkB zG+9Q(MqW3Uuk6d%x#8-m&344_LLKC1b5}-$Sd}~FE)EYg?6Xlx{=O<~R(ZD6i|hwk znP4Bd=WMSZ52S;=y0S`Ftx%>lm>FBQdu z^;aue#yjnLXX4cH)Fs$X1A<3B0x0V$edEv>V7S|9S}#UvUz;%z@nEGur{oK~CosSy zckF<5KEsITa2fC6JZQshHgy6M7P$G%t)5u+q2Ck>2=;&iu<;~}-j#X@tO`JhYT&BS zS6)b0SVb<+xU|XXV9#TcZz|-zqzTD>pIcBNOUWky%&qL4{K#iVa0uwzzPJs2@fd$y zx#@P-dm-u;WMvJ%!k2$ia0r@Qu%0EkoqXH=3sDfEML}6H={*w|7WY3XVQPCeCD5vv zfL8M41~#uS?$+rz+)59nC}xPwLl7_xzkfO&^7Ty_F*pKz<4*6FhyXyQa95NzZEV$a zwRz3qW^RS9hOXA|EjtR{_8t@m$dZ{dr$!69Ny6~X^+-8q)B|chEhl8*FxdPTDV5PcOdRB3&pTtC3)E$?E3XxmPUji0ohT3Fd>FU~1Y+@S))?5i>$ zm7%K`j>V)+(H8=B(5-jxWAM=CzGR=zA&>1S^MUprV6y;H_dDH_KKZO>< zd4%mMVm6_bDXT;~g~vXWDLZ>wwmsdQ3$B=0XOblC>gAb(kFN8I18gNuxUcaKpXl2Ky+pOV0}B`utV-+Szfpct*XVdW;}YSf?Pp4@HxHL;U@YpdnUELWE_bRrHKE`&?{>3^9L zZ9fJ@s)=rAKYVQ&ERERYiF)>((tl6&dJMCPph+$BsYBo#J=(^)N#Tpa!7jRj$r$%O z|AAw+Tj_g*17YD*LOTB2cB;0Nm;-iHRCJn08XEzkYrg2fWV|OdfO881b%#B(m}yml%|{{gS1Sp$)A93JAdfaBP=# zNE2oz_~ADR(M|1%(Q5c;wkQK!tEv*yd-Y9{A&t!&2bu4a$?|`*^FJYMdqvymGe4xx zx(a(_p&71u>5g1Di}M&nQ6UrBGnbTMVk-`vkezDy^g9FmqW+=?h*+JUC~-fRHstLP z+VP@9PyPbfZ}M!ni$gGM*>A#Y^^&;3;WIYXAL}x4PX$J9DfCdtk))`>fikw?uSILB zpwsTq56)zL8Y(lSaRW!N3J`dx$o{}J4Mnr;1OOx@tWk-TgK4Z$bk6uQH3Tw4(uobvDJfh1tLH>jcBNX6X|v<=#x}>f-UAR`)c_ zqNV}#4+1`AwO7X7DuMoM8}AdEl}I@)x?1{X@s8W%=i?C=hpmsIizJe;S(3}&<6!*Dx}6E|a3ckzbT zb{*{W&%l4Qc$&Yb+f#i9EMdS!3mEQ;tuIG5xyt}s9|!Nrw5^_JRyP8e6mqmvbgIE~ zh}SF8+1gnB_sqrXNw*cA;+vr2C%Bc8#Yx$GnhzWn>PDGOFLOO|%vN)u)L6c<;Vr!gBQNHezw!-~(>#^aAUB)}Xw ztQz)S$tKcNmOE2EV@Bq7+{QFJR4+ZHE9m5(g@zn$dan9f={u!JCkly_=C)@BeZV;O zoLG*B!pPnI=F2<%Ag$kV)kJ4#(8tXDK_{E*Mcd9%fR=Vt4}2mij!0?-54ekgcw-vt zqZ?J;TtGSlO)rB-%F#ABPG#c6R^L|T$1W8(7(&J>93EASJH%q7ch2s9@=CpiVrmCj zXJLgVwvXC-?)x^ASS0K39pS06mEjkDmqs-PdiZrLjBpT>CE|s^DV@~7*o4&=D9(0q z8wGJ6^)Y!;EF!=@XO}mNQ=aA)SJ8W_)E8gf{EZ%GtSaudzl3MwZ~VC1A}rt?hoc^y zc=5=|)5J&Uc3gz9nEs=n9?VbCuQX+5L@W~FAp@rg4IF@)Ol6haT)gnTV{w5?Hd(@- zqE6NkwGO<{z`ZUK083OpM3eCM7WF0NkWPhiWu)5EJL(rP7QMStI6n>MOicj(*gU3E zY-}Olbb}ia(DhVJu&o^>uy_|(|8V-06X}N@feO?#);&PxcHY^}b9dNj73k*Up(E90 zvib!QtDaqJQ5WCwS?0CssZl3lm?*Qr0nM8_?Z`WdE*{7g=hs47OzLMo3_{Ar?vMGW z-r>3r(Z8NP;qMOLO8nJKgPYigOwP;$q>2_}M5+k#ov&bzLl1z$%yTId0+A6bCF>Cf zDCtC4qdXF50yW%-I7dIWiQj%lVYBY{NhIYzN+0)oh>4{Tecrr+{_vNw7#!n`kNP{B zjq!>wD*wtm&qlI1(%SSEH}TjYxV4@4MQkL#TMT$1kVwC^PFn7UQA;kVl&qoLK< z;X4LcQ$&Y@&=!*X877VpL_&ToxBXuHW>JvTlD*0zj{8J04NQ43gyjZ4!n`pB<_e#{ zv5V4#PELQLdIg2?Zn(@*Y|gvP=s!T?ZMSw7}U zhBWpJRWPQi1eGPrDVHyfeF_F&K+PV5Z?WVBebXw1M?V|g8gC0+JUlS!TU&3@dLxl} z&w9|+i{=K0*%u&VO-4rS>+`4o;>^1SaUgY%Uiuzw;^joM016?MaF*Png$V!#8U-TZ zWQGQ*3ZT*n=WNVE?U(`o!mTU+k5gK)sE<7uR10BQZ1qBmux|;}@7?(sqRDrnJRQz! zjeKGpJ6c>f`7x%*5QrvyWKj(l!j^PBe^0b|=A?g_oU+qAm-+k2)%O^nYN(ujwRh<|188P)04*kf#D9Sa)abM52E6cI32}`x;K?~FPh0Sk$ zeewLl7M))U4oLG5ZSEjYc6lMNp1~<==leK?g(?JhkERS#$%|NV*Y{#p2JZ)>TlGah%WHTvT{OL6TCC4DNY*ZAS>CaItM!_(VCo+5bI9da#?|Z;{4cYL1oD zgxSJhPAf=o?nQdsil62C6WX6c(pzMBU&zxXb!F=T21_&~ltF{X7QPXtD`P21QB^)3W!jNHf*Ot)DDg%zk9IWy`MGljYIUz$h8cD)w3MdJ; zR#G4l%3_i48xJ-vYDFRcqmueeGYg%(?0?T|qoI&lhW*W;6y&UAG2amWx*B)p8mU!< zSTBcdV}Qx%Y(ESWCE=)Hx$<)?YmHLS*J&@9h0zilPerD|zU#?E=W85W56h_Z{5t=Q zKdTNLc3J8fPs;(?43(q}L3_fa0YFS-u9#th@w%oX}+5eVSag6EM5g?%xru#Bo=)kC-n~fSY+W)C^0JzsgyzQ1s@Y|lhNi9IOm`~4|q|zw1X+HYHJzJ*t|JF*Rn%(Th@E8 zF8wKOWX8;ln#G3JQ?EJ;dV$B#GPPia+JV2${tUsW$=Bnge7u2;jMps_t*)m_wZ=o} zi+rj3;a$}}y?^uet2l#D8H6>%IMi^9KG&b7s=rI-F?mO(rKj-fs-Bmn^a3t6p6yT< zqOe50hgI;b8nbCa#EU+zP!_RELBTc7s@nX;l=w$YpqaP%&<40v^k8Arl1C#hcQiY! zlB{rwlZIj<#8jCmm;R%&5|^!*^EnZxDYzs9*UzVyi-o57W-nBjHp){tDxJ<}CV+XwNNvw8k;Q{g71}Oj6F&bcrB<;5` zoogz`E!Vbol2`TLNRV`cw|=-wy?-VF+)n!S!^OkUnsJ5~QAWJUdkhu^VSE8sD>jbx z%|$zp>6vN0bGVXujoNu?dX?l7Viif}v7-BjiGop>+{{3^B#T(i z8<1m}@4@t5D@Do1joAqBG8FXecQ^0m42WjVuK0ORxGLE?X-OEu0;Eh|UU}FrTYtIb z{yrAxsaGM#)8Jw4v^^5+LD$Je5mu9LFHP5{_xdP+QR5T~x@ZJUMPFq2UTv&io`eDO zr?E}Hr1~@C72%t5+Iqf>4DX-(_C6E$QI@-j)_ehLj0-B>~c?U}m1 z9a%E<3CtW^1+7e%lv6%!0462h1$vK7+eV|g~9_rwQ z1*(|nTng^hCfK%;Q5EthV5|=gI^6W20bdYyE<>VSg>oR-Y&d2VrEw=)TSLNCnmdi+tk zgRRjDjRv;NZDXM&d%u2z1upKtdZ*rdS**W5Mh={O#Z|)vN~$?5n=V?}Agno6S!ZLFnA;tF&5L&?^v;Uan2wkb1|o@=)~ND?;8tbJ%D-H{FZmz>S)o2 zZf{8$~I1$(x=uGX*hHX^|II8JR?LZrK7m_`yxIIk)BQ z6r=F>3z&J!iYA>iUxeVS$dCY0q6EcopFu+3{afdb9<7{$(Ae~~AI#Ad^5qfrM!le@ zuhQ4ggt-SOG*PD&^y@FQbV)c-HH?%O|Zq;!NOaQov?wT8`y2c z%C7lfMR%iw3Af5aru1`E@~1*AT$jdSBvslnI+A^qlsV#lV5!?2*1u}Oz*}A2%Kqhj z=@0s*^fh7hpZ#cm`VmsPn_R-M9UEAa#)+A^UultmHuTEqzVO@|z&Ndi{*Mm&bHn62 zVI&udDsu$RK_tdF#$@EVF-xT*>x)}?4=%TKJ$5(>^Kabj^1|fPsEL7n9ZH)@)vYMT zW1BlRGNZ))(U{^Yr+xu=S-;`cV2dWo7*n21W{Xx5Aev35U3280_Hb|-)L5&X!f=1r zcI6f%4U?k{CcbAVfb6MKpJuc}FRkSkZWC`fu;ta`%oQGE41VHg8VM`n7~N{67*SOa zNPWu5hdaq}!3Vk-hVDnomxS84giX1RU&J^}jG}*@;X}qb@%oamyZnJF40+YMfwu-S z7L991k1MakPJQ3CWnq={{1CANN-1R@yE}{X#>SP$%`>+g zm*VrfG?vb{sd5i|?V*TKqvJna^*%n|o**7!+D)yXeQ#*=)b>oB^bMwa|2@#N`C9?4 z*!dp8c6;M+}W(rESvF4iHY3H_Ll#Pz@UQ8;?{Y} z9QKOi_$@fIMQ{3#0yd=lneL{I-CT1aPxrd)M@w1B=);x?sf#*+=dP#aXRe4Yec9R| z#hXbD2&F`3BE&nE21N#=In!7UTk&shk+ury@g;K6eV}XhIsbKT>_-&ZiUC-G#NKJm%6|ByvUOkSTJ|}DPQD|aa)SD82i;K>{2vaafCR5 zz%jTV^y|j&nap?hXFMdqwIF!%<8A26!7Ep)t@zcqw}VMrNFvNhuRg58v_?gb?1t>( z=9aF~Hx-H~G@*+#`8~Z#Yspbb*kPK;mj@a+k8ect(R`0)_H?4^amW=kT_g>1hNoVX ztkvI-Eu(&(?Wczt?UnRw*RkS%XS{YNZXpQU3cD-Xy$Ih~jCpl?nzazqF1OkJiKW0| zE^M8m)_CwX)2i_yPm>cKxc!vN`Vi9n)5)vVnQ_W%eRXLntqgikRZ|CdJap#!>h5Re zaPiU%ccMO?AE=GSJp26@3KNNahnXC_#ZS`fTi>Ep53B}F(?J3b@or5S+qUxe*;`vG zQb`%i{6)$Eec-L^>#`Khm##;eMnhq9X~Zix_i_I(Cy@&{KNN@SvdXNlm0Uawgv}MX zF;#i&Lw)yMyMAyK{F=O;sq3G-UMN^_W;sBfp~@3|xmV4iu9!=|Fe#H#EMWvS4wt~y zLi58G#Xexe?u6en7oF4kVM2F+UPW6ui-Pg?`oGl!d!GormJVFd25oSFRH@>T*R%`su)!*Qo#QSEl0 z#BP0RE1yWFkqWb9ltxh-Kl!h9gHPwAHSZC%7_ziuWB9&txGDe6pOKMTl^+uv=|D1< z<-ic|E~(hUbuvR;Nh>~Bit32)iQ}nnTm0BH8MJ5)S0)Oi{oRpo;}cnwshX?#N;(kG ze$uyad~ZQ-up6pnrSL-f7K)9SEKR39r4=fe2Gc6O13!xJQ}cv}Fs!n17)RP)VlTeL zQ7oykiLyv_rd1TrD$&K;LhzMdWVGIEsW67rj&CiujT^;;06YI?(eL7`50k=ET6#Sh zz<#Z2;O(lYH-H#mLm}{|Et=6aCV+YL_2MO!j+NF1V*){9WCh2HGyO1wdNEa_9f352LhQR z`M3ydEh-}>z!1SnrXlAzWJvlfoW@1F;8WNBs^il(ljq@dryu~JDh`mY1TDJXXXoum z;S6zZmuyDmFIVtm?tqW`3gkRm~wo?Ozx*JqjDUxv?@ zUnV(Eorupx9QEx_Uq}fYxqJBw|BWQVW!B!99y>7)A{@^@xAIY94{dDt7pEYXXcwyd z5mnF}gD?{TknK2T9TkhbR0>n)yFz$g6OQ4mcrO?{b!KNvAha{S&;#v%V5?MVE$qCu zvS=Aj;)g5#t@`paA;BW4bCzr2g46Gd%W!>5t3=h=L9_{kW&Wm~Cnbl7IMGj(vmKOD zpmnneNy8;OINje;!)0eOp@!Y_lD};~H2-E01*tTLbASNuRTsL(?;M~h8>4G-j>QyN z#ss`D%$avD!>w53x+%qJM?nQkjy(xwFrTy4e_BMK zLTO?0S{_ZNUVex5TenV);;%CM68pbnzuQ#uRBRO&(~TQ@ZX7zi4yLn0ai}khW8tsP zX9*FO8Bc)!bvB7;4V0#NX~brygpdk9+hGN!ny3~awNWP_C@wnPGZz%VUr)e~VK0xC zc*rm+daB3$(}dmGFg}Fgdkyr*2Gi_c{D2883>?3+8QU=zQGK_%Y=vs*`#(CA;)gQ_ zsd`WIRvG6CUhQO5CKViz+7;0xJEsq9SH*22t7XPTWHaol%m=V zH7IK4Jq!Hyq-Ie5rG}24STXBNIL;Y8WN{C8pJQf}proZ`!;G{-A&1q_jPl+K4`D|m z{S;eu)#zji;;#6hP&?4gLd8XwBzCCD=Jj57TOZvB;2y zr>XoD^D}Gbvc6J#vVR&%l(`P(2va#T*0kQWdTdM!`eva+o#VPo9g_`5YnwQq?2PPH z!1rFttyJA$5{5R4WRv2+yddKv2+1JoOBTPw(TyDKV{AYEKAJJCV~M;rl7JsN{G8+9E-e7!iXl+t5OtsrHJOvQp}#nU$t3Tk2*F`mUboxR#Q6FHgXQ zm3|wI8^j16LP{TFLrD~>aEyj)9!tBK1oIRQE{Ql}2w5;>^a3+@oT^A`7$!^YRF;(> zrNws@Ie5oAL3apP>@lISDItQ%RrTp!JQ{4b`UF58&gJg=(GRNw-5?mE zsgCDoee|#rAWm8ZjkB^sk}@ggp{#WvA`EE)!OL%5;ASWtm4Du6+D6D)K{soXmkqjS zYmQkVA7YGU{qR{=_Y-FKtkWnDyAJX9;l|7OTe02XDT7CF-q%CQA|p(7lhgg^6jrb< zH91;03`@jmzgSU#F~Ov3@;bcWuc=HUUlge=;X$+Ul`;@68g)@v7zcOScVWU~!TEHm z?s12e{8r)0%78}h8d3#|SIx6sXFj5oG6dkl<>It*8C)W&l!%Cih@BG}5mG4@$EgA1 zZ>M*hbqOQt13EsyhoQEtQt5vT47M52l0;>6l#IHQD#!k+n8km!N72P>R1cfn^Wy*X z;eL$bTf`EbI3jowf4_3;Q~K-s-g~8e0&Zlur+wPd&<{of6<4y7<9J3W*dq$t;=59I zYrbO}&JCrD)7rNw&3t{}sW;oVTZ-aH@{bXylhme+?Zr|129?yq$)+RNAg4fcF>y^z zxj43EK}hL4D4&QsFh~j4MDyIE;NX}*T@LpW&x;V8T!o0FjlGRUn}k8i(&wCaVU@d= zM|)#`O6vTF-?MYEbAZLC&W6YyJ<5kOrM0H)37qK_Gin#V;Zk~A((gO{S$=G)ZR2wi zPMMwxOBg;)QY^Q=Ig}pvJ5y_qMp}ul!6Rv26?Hly^J7IzH)~3SdV5p^7p9!LA&=?B#=TE=II0~w!p$Hc{rQY?)&P8exhTRDp(w zWFS4C$-2z@us#PtJm|X6tH3J+w@+xpl~ojBU^~SreTHy-81SsV8}y2CG^N@^qeVkx z^UZFYA0fN{uVy;zK@eoOK5jVT(wYz)VJ;;1kyhYmYq2|}iD^vK~(C70rL{Oz6D$F)_w+cDh7Vgcb$mQyf=*%W4`Re4hbtrF?>+8(x^m2$S z)X{-kj0kk8RRsQ8iQNmf1hr;khYu=JMc9ujOG>a~9cccztGR2`@7#ZmPE;AGB4r

zTvtC!`E^Q}-@j{zVs?SZvJf6@nU5)rI#V%W*itR;7rcOcG@s z>vKR0^Tfo&cQuKR5eiR^DCzH)PbmX13rIP@o@7g9me?}?lAH9HscV0<|7fnBY8=HO z`PJ16cGfjR=7Q~1)&mgXgLVjpf^PU8*O2faC}!hC?;?q}fjIEn+nNs5K4pGklAyFo zbx^viLA2+6(C}f9^`xaoqm&Nzi?83G>gOsaR)}8Myt?KD79)VdiXuw~Bj*i{SX(LQ z;u+Z_*zMUco8Q<6pIL+nQF*wz<2BOCU}S3Fazq{s*1b?o^PumcA@C(DBO)`%9||=j z9B%-K@5^9-DqZR1+zVzT;6^K&4|Kpo1e%26itusq;T&X5%*`Av>*8DlA_vmSr$S~w zuN&+s8PpOUg(o%8HV|JcdMpc7RL)C-VawrYE9CWZ`U&OuWkmzIpDWf%SSJxA(C}Hj zX+4PzHGd%J$QJO-%rba%R7vvXA4@67APIrP8QF2eoi~R6NG|fJYkO(mADxFs;)Jhi z>)AMDYcmzoR)yW&-5n=+{iF7&L$sP@)&G2ADR#OJg^h&1>g)UUd-gkxC$`QW_+5GX z`1nBn=oGt;?MBP@0b!GZ)Z0% zQT4pn`wO_oK4xyFV@Y7^kJI{(_8Yk(8Gc+ZV>afp9xb_m{64cJw4_EJ&BFhf*g0q1 zUVIZ&_GRRAk2FO@D7mizEXtH2^_B`cST9g-W4s@%Sx)#bu6_3EJL|5F9gGPE=~xvX zE*^(iqXzVOAdAV$$#CsB+xo~#hzQ|Jg!WM>?9??^r*{7uiaqstH>O&Gtnm*8YeT`S+RJP6P&H)o*mBX01yS5`@mV2f{U`d1>nD%0D1FikzWIVS zQDrtw4cvdSFCAw!dMJGgPV%rd@eRu@7KTQ(PKN-09c1^Pd@ z4&XU>T6*3VfbN`6sF=WU5b}m9N(2+NU*Z=bPF;P^px2oP+PnH|6(VwCazfI>j~n?p zPtWTIKD<7f{Eo`)W<*VI>#v39X0IO$e0kF4ZT|2$NSRnI&&i>~2LXAm<7azyt#$*n zlW*XDWI&=toa z+|b~>>iKPN+GY!Sam6TaJi^@UM0E~vgVmv!PTKZ9z$&|wu$`_9RN_% z?f|UGpU(^yGTUk^ zJIB3yvYZPmms7-0GBB#q>TYfMJx~-znH)F7SM+LWEqeP0RYT}mBQu(cE0_2AFFaof zCRa0T*7PP8teNUr2<74!5)KkLmHzPwY+PS)O&8MVN&lAHtw0&rTk`m(+39(obu?R0 z%+8x6=LSm`KhGpiEuHN7!Yt9D>g}w%1;!94kdB6xN1S|r8@>?oBR_)n-?FUn>k_%7 z$s?Dg8u`W7e(y{$n;Z?;i@nFem2$~U>xm$Y;>;AWoUI5Cw8cq$6slzAGmQL?G+HH{&3$m|H|T4ohQ_Zvxp{OD>@OG&2hu>y$~BzrYJ{G8*= z2vrHrs+pIZFZ?*oQGn6&Lb;C%am>&?{R2ott1%WA&d=XYZ#evVs=o)WDtmWhBC6zu`w1D?BU8~X-UnpTc4 zKnz{-kBDC;pKV&5OT^0z1uUJTj>C&w&FJL zUG<%_S1Ip)5F#7W!U8&H{MuQS9LPqFgK&U>6qcTip$H*ZZ)~|&@zX&4DN)j+;g>O? zpG2)rXa^Oy@b@X*Kih>}!$*zYmS4wYECW#yLpcWF28K%}HGUxRD{P^EdPb&|v0#wE zbi|$Ix2}{z{{RC(V*S4sn_PU&4JD{0H9tY9y>lObU5)NoE}3lOW}M+^Z;9o-t^0P0`9a__t`ypfZCF)N=VHe{1umRe zLs`@RvDl>kp%QyRsJ7`pB_qQacOkmecv3q#RCmFDlrSDTUdG0S9mCGGcf3+j;YUZy}3VMo;xUeQ~w=aSM&+s0{Ka36Ar>A^ld?r!z zz(as34|u(J3d%QNhJ^?HddjKCx_cI0;@1P z>|coY%g}5=FIvvC94801P(t2D?av6^Fp{?Z9L;}7a{G&3FMH1uFo1@;(3?{;42fhQ^lwZqjYoI2H9c=PF|!z zxM9$odEkyAh6rrrPOTS zyu~LSqee|CsmQ@C0u5UrB&s==y7Ci~)MMTgzvkSx?~_}b238Dh@U3=m+YlPBeh(o( zdX*ELu_pfFr1)={z{}?DLYePN&5y`Q9+`Ot1C57{NLHpyr|oAFXc85MLEpGPQuHJL zd8_a4@$UUt+uz%l1$HPa;`I7ANcsHQv~{C?twSbW9VC)FRz1lQR>RQ3)&}DSQ${ko zV0|K>ZMwr5W5jKZ2a>9~q=uOK^lJxgOl(eCYdS?=Y)2omQ_pz0k)$5NNL`^35sM^8 z>CmyYgH)yIn=2Op5P01|2Oh3Ajr42#Mdl~N3vFX_35{>Y#O@Qkc7KNj=1Q3}IaBaj z7aJ|`s9Tv>jqn~PpL@Ks{&Kw-=uuHuzRe!5>e`Gu;23K51&kkDQNO?UKKAf1WDb@D z#%SHx*$Z@_q}*TtAD#BeyL}KUGat@}sjF8eNSr~902wOeppvrs#$#BH=oFC&n z+ZMwmJu5axw#Ck>o2spQs|%qu;i`+XE*&TB$h}aCziPM05hcO)M+!EDFe#iXd?SCq zPE2d;K^Q#IC5(`lJdnXXAK^9^g%^jadhVgz|0uo{-H$#impRF_{zS366}5zNCc{mV z0jY9;WkYJ>(fRHL$h=6Ua-nfk2YU0xF1XnM`==HN9Q0r-&~=wjfpFB_t)N7|P$5$l zE*{-j(R)!(BMxfxB8!?Fns@FPsO`J_-3zv%w50y$;ndx-y(-@NPdWrTyM4VP<(lc5&K+srw_GB3hFUmRTwd zghj5h@b!U_Fm$(Ot|2s?ueG=1VSfZkTV;+W48H;w7xfwWa+ET7;dqh*ek;nL62^*U zw>?cB>Ah53AS7grvaM{zGsrW?-Ve&etWKiv=niPq z!Gaz|Hq8TRM&T*gbAf|Royd|6hpS-u3`fH=M&91R^Nspc&}e>du>h0ie_R0P^f&a&i-9naNa$y;-sp;<`csRi?p52@ zJ+s@*0-%Se_08bx{*%kSsqMIKD{xyb(I;O{OrzgPO&eZS4l)}6-l z>enE}Q1X{Oj-tgk@IsuYXb8m8%c&@Yv9$bc&_Mt#Kd=J^@6-6yj4T`t<>=T_-^Ci; zXfQ#xV;QfnO5-|{c#WffHmo#`9{;~2r_eGmB!r+YqoYwaO622Au0)0fKmqTRi<0Qn zuXSa>3ConReS8{gf)RC8-v@B+6-irNXsV!}TDn5^Ll{*90IL%@lgX`SYG|PusxWcd zXNY;vqj=`=;2Zm#=wua^fewb_O-woAV-uqd$=~y|DEyWBnSt)BP6<5D{p9AfU5@NJ zZLS-V-;qrkw_-uLo=*Oy!$rLSxCm96rPbB3CZ`D!a{|$+b0-q8$-#rW&bt5RIbHG*|0d<55p56?5&ld68?cuTW zZa~X0Pm(fNW3i-mJ|#mYfC8zHEvGu=j)5+P4xSvnAH^^;s(6|}dYs$z^T-&vAqY_z z)peIRq!1=d{LhITbG7v0+F~x#`%j@M>JqXf|9$@dq3JE4+IqgO;h;rA2@VB{y9IY` zaM$AQQrxw;dm*?LC|aE2R;)-VP~0sz6nDP--v9Hh#e%R{HyP%hIkV5+`^>HXM?4pd z9UzWRk5ja82dVo@AZ*Wrp+QUwG|Wiy;3-f64-v5&p0D51gtKz!Dp{xPh78V{R_4k_ zK)w;xl!;H+?WjW}Uxp=jBa{qlx-%qbFp=HQZ=wXBE4+f zO1>fmyNJonG{N6x&Hgt`eq>j@nrDD6Pvi?dgCn{+@1g`IE`e?qq!`Q))?ACMEGwzj zpb<_C-g!ZhKnuK&;y{ovBt*hSbiai?ls`mBe_kHT!iJJ!^X)ler4vKcb77U%?@_vm z&|Z`S|IL>$LKWEI@dM|$o{ZjGI11Wwl7j`;-TC-<_A;LmJr1@75is@I%fW6VTx4XufAjV*M9)Gr z7EJi6sJh?&9eSjWFJVu0{Io%Zi=v$*IGkK1ePqQt5*`$8Ul_wrC6+Ve#Z}#6^Ad-{B4FBHp&V z4H>eohsf2nReowMA{c_K*y8W&FU3KtkB$p%W8V3`j;E;YV4WCQ;GP@?TrdSL!XZpY9ygL80W~GeM zEY+7gnuFXTSM~abvW}%JMylhpW&2)k6_Xq0SYEvN?)a}S(q%7ycK&1aKXjfQE-@9L zx!v95urbbEY+(l9fKmY@Qr(t*FdL>iQQ1^FW_+C8zxszVdJV_w6K&s9 zhX3dyYyCLj{jn62m$on8^Ig)?Pt80ZJKxnr0=>E}sh-tgppbhds7wVRQG_hUx&EvL zn-^FgY5q0W`Tb<03T#oC>#lOp`~S#ZX&sJBR+LGi-g~Kvh(#~Uo(5BDR+JA>3X~IN z8d;u@ONoh+vI)s0> zJiq-<4G*#HQ{MCP_pIgpJ`|m?7J|t>hNSs)OoL8UcVZEhXt0=l2nCiHx7h8ehZlog z*4S!#JmK%W_kJ8+T~c&|MH+Z;IpE1+@_F(XQ+VFzl<$Z%nlE1y#9wYxRj;VSU5Gz+ zXeQRhfZ*HJI2qEdh>}RS+=Fw&f4H;nkD5$9Gr(2*e)lo$hG+p^f*^%F>TLMJ?t0qE zv=sEEtZ)sIwtj^#%u|>o^-IraWVgO?m3KU{Oy&s>y z-r`eUqtqgTVCoEeoV955Fg{$@ zv&%v?ofVzU0>@*_L^&}zKWN|tnMk`**Y0b@z%#rW>`h&{rf${NU~Zu=6M7hHJqeu17(I&^y5%P6&VKz@8CfCnrQj{K zJ@rpQT1PSQmphAgqsfos@UN{(b4WB-Azp#s;yVjLE1I3yn$Oz7ubs{-{2Z0RW&f{< z>oPhcV_G^*=F-W~otWKj_NaxRxey6GJap8*TNbMW^pW7~cB?HdrzPKiljpr{JPgfR zpiHD6pNKA3B&LIkK;Tt&ArdYEeY2J6#!y2e!IA^f&CmCh1;%fe+Q;T9^}l%EU^N#$ zpH;ejUYY#e8A^8e$==d|(N&wIAg{zhP3S|i#5XdyWT(Xw%6R`ih8W2xEcb*E#`4!l zd^~7eEXdc;P=WNd|I}=oz_K!Kl>Y?2Chm@NJ7fRiz9GnFlBBGTf-6(V8^A(LsCjv(0%Af120{lY`$w;WrE z0B;DF(ko)L-%H|NJ6Z#JLeS~H&K8mRs=XwqbuNGRQpXfZmY~GPe&j5^gg0G=*h=F>lS{>mPJz#Z&0?n0?oMmAS4>@E*RS4-(SR+^e+UsJs6s^T8(%;DTRL zjZ_cloi*j+)pBj2D8m0Q)!ug?xHP$$LoUmnK4_;F9hxE|QZbAm$&Zj;ph`2Mkque`s2vIG<@<8K z5x$Z6KQsYfP8ZU*j(^gqMIn9nlz`;(EH+h6%(LC?w>24d)%GcPl?qx|@DSOFs|_jb z0RZ4lxS`l#a0CVa4!^))cxm|rg89i8u5NGkoVAiQLEl2*Ew&k9gt5gJj&VvDxEPTl zV&Ni^A>a+eG&=AQ%?BEHY#8D#5|1+fsRK`zGQ5Ryx3F|Jq79v(KQs7FBf~1Vm*Pom zzk5T>^$_wTzwgh|O7KQI$yP;`@^dospV07t(W6C4v_GCr+jSQ3XnSG4n6cYG^o*VZ^?u6Dd{P{>`Ku1FsYO&p#ap5E z)aR>#dmxx+;>5YB+p&>v`Qp8dD?U*{$Z>%#|o2RIe=Czv#Z6BTH>;1f+{23NPK3IOVeR1uEN8!0AO z7?-c&{?4SN!@jG5ub4`)-2G@jh6=;7-r)CgruSAE1Ql8x_gZfC7oSj;9d5N)l0?%A z*U`2{GnKnA5!f>Rm7^<@pqsOmTC!yu{pO@Dag|Eys{F=Pi9}iHohS3VR->A8-4PJz zGf6K5hRAbHHai~$8{q9QOzjwJ-5t}oM52oBXl%5JYP>9Puf25plCB!dlrV@SHyF>E zSx3T%ZoX?{)9E!=>mwsh7D2nm&2f#@<9WX_<$vjoQBFG*QWxI#Cl`k4%#vyl6HkYK zRbR;*eyxHxF`^5IQ%bPIKXJqt{-ai=V`{8@xqdfE^?Ez-6HY1QQ$Pv0iBTQn4CB5P zBWH+zlLdWKh>6hNN&7W82pW3t**V?6vE+X9g&TAn_BBM(k4SIKkZ8UV*iRPpq?YvM-&w_|2hKgl+QpZ8E5myL5tS_xX5 z-jGR1M#-=gzUE_f^L6{oCB6ype?h-0H!ehT3nQzNsmH^zvX|aFM|m`U#~2`joG8bM zP(fUAHSGQ~e|YKApew`L2DV*er0R)_!>#KKP~hhSe0c2uqvv*c?hZInLeW&o#hFX1 zPcrvyBEFQ;PZ9-ISCapocJk@cu^ke7eh*QU+n0Mu z!0_woU8+}RJ$;JC`{(5n@4)BUus3htKHJ+?xIzDp+04f1GyFLh{vgka5V~dVr^rcJ zu|P1}!bT)NSLKZi;aqBs-RQV)d@YxdIk0wOrbXGmI6$!VqvK1Kwjr_RII_X{V0_Ki!SsR{r_D5*mw4~()TO?UJmk2*H? zvKX4FmLQyHN+2#IlrnmxP=i52C&XNbRZloB)gptHj+e|UqH`UV$Z(t)l#zI4YLF>Y)yqOzV!Fd?0%(%Dz8k)Os&fhO9)2Uf<`4g| z5fu^j666x$^zHKvqK$Yr<*NP|?vFE@Oee1OfFRhf9?vC+|K`8^d|449 z;6|I>^=twTA<5a6V^|Arc5WNL5lMC~tR>ZHg4M*>-OF4Qs-K__!#N7Z|C&9=v*<+q z2U6{TI~}jw$Ql+o3IN)VEk=-XnX9B3PK$y|G)hQHR&tA-&20buTpM<~ulYnwUuK0Q zFCSlIirbbbOo-a(z`&)0$`zepPN($DH9r9EyqYV0=MdFq{doMPe$pv_p7u#zkVj{P z_q#23IL8Yt&W*~DUQb^)dp{O@Rln|UwzGvP93jnRZB}#qE&B>H51%nngO-)X-9v_tM-2mvu_C`oySWTAyVw$W81>5~t`>$Z9&e5vUej)t z{uU6KEF7rHyjDGqN1ok2e?R3e;SY`DsFw4nJ$|nu9KgNOePN>b`n_J6_m{Vre*wXo zpY$*IY~24;%v2To`=@OJ>HO6L3mByPtv+zmZxfz|{`xm~i#2y%Qq`pBIzHqqAK!={ z?&Y9O2v+O7CCABjzo$P8p7qRGjm@b>7p`AZs*zJR0kiqMiN!^;t>7*)eU~0m)Qdqc zcLZYT1;;=~Xlb2pf4tB#)PE&8(>%RD*yA$IgQ0_?75);D-wHYTG63GKNZx7d|5c-2Tak~sNLgbI;+tJ;4^Vl4lWd7 zY)?0SpBe1xyYU5q$?7)cbjC(?zI$5q>K4{X|9E$L(q`QO#v$);*)8f3zm4j?&hl=T zN#+!X|J`ft$Wt`80H)~X4U>5ZwA`>kGI&{M^Y=PC@auM9qT^IVkFpP^TcK}#RnH}j zGwwc>}WW;cNS=uUAu+cQik1FZ@kfA4iq3EF_d5{L9>* z96Jhm1yiYEQFJwQAQxL7hB3FuoB2=szx+a{`NL*%dX+e2Xv0iFx`??BIC;yWBn@?r zpcJ}7D2XK)ty)n4KLodf12MI8rLZt4scatWnBi~?Jy5(HnY;4sa zqqgkQ^6r<*y7<-gt71=UMZc%b*^Iw1#p%l9)mmxKAKb8FjbGf(xg>Xs5=Sj_`4rb4 zA_BMnNS^9IDi{8N{$2D4y$-l1IYuX$$8EvtX@`VA^&JcwGzKq_&XOY10(_^}&!4-e z!`_&X2;Kdff+w#W=Za2&9f8SzYulp3eyGOeKKsJh&7T|sPupO7mmh0;ar=vQZvYE9 z!)qd_GGUwOILtP5)bg?9VZzxJRTC&1d~Hjqyf(0QK2N^p?%|~)<|>$?yIH65r^9%r zIqAQ{ezO~JTohnu?wjL@k^7QQ8Rdz-~!sC9}RrMVZ%NnmFlkot{R8qz>GVtN*( z*)u%`fHNAX=?$(p)2=YAx)JO0-q`)D$)MUSIyL8~S{3xu$t!{m^*1(rGGF(T5?h>| z#jn#eOEYb|$b5VYuSODOy$w5putH$IfPnRR(p>*-LlA21w%2oEm0_B_i02jq1N>@w z*M{9ww$5R6B4O!2_*L?azh$>SXe+3UeHb($FjonS(D@G-eP42qUl+eJhV792( zZ5+}x`t6C;#jWLc*!zO?*HP?`zqu?dkygbT%}hSY)3HS?y)2qlgwYRPEz?3U~9$xkO!dqLjcWn0L79`U(rxq3tL2PbAY zIFg(UOIEB7*0v!49oyd>0~B=nwM}IjOK1sYoga|Ys?!_7IV<{q}BBAtFI$ z8x}7`W?Cd5p@j~cOcQUdLd?J{b4ZvdMVHIQ25Xo@R`+D3O@axM^x(gpTIJ^}u_4-M zs=Jr>7lIKT-K`Gi0s75>rwQ&x;!q2ee}}^#5o|eUj_=pr13rqkwHKBPQB-*z%uCto zml5_`rAjC>2VHl(TI_A!M#%>AW0-nH7S-)fz`S2>#l3_7eP4Zj{=Mof*5h8PdBYvT z@zUIp{VMwK_^1C`|DXg@=63t{%P$ho(wp{;E6nUf8{9T!@4W0NZ97B&`#@Jty!PL7d9hs!iBjx@+Bo8h?)1344@qz|K!2buGeW*ZW^d&bEMD4_fJ6Hi z7IcSi5~Y2DxEcR$S|XuvAC5_F9Sy44yo=?D)+;07`y zYDrn9q3Gm-J>r_Jtl$}u68I22W#WY7oYo3YWMQy3cv;5}Yqj<{Uu;+BFgB(QG8Gb6 zrwl#-^v~@6Rz+g^Rr2jh{ZPXFMinPuyi-_;`-1iQ%lSJbZBPb`vE1rhFw+V@fE?`Z zLNf)E0OS0ZHc#^nA6u6*xi*B@@W#pd;{CYGF;wW>?Muz}AgCcAHa_>_BgBg8ws=Ce z#G)t_I@YWr#piRn&hLwAv?I+ZZi4ep4Ve6)jIkrscrmcH@$uYbCn;&xK1-=SdP!6X z7Xw287cfStVY+k}Y<qY*uxp{8=?b2|v({JxQWx!qR@4YRoo`QTk+WmfI-&yvJF$wgjX1eupV_p25 z;c1D&tb(=1MNL64z-pm~vk?hpm@IO0`Z*^43l$V-y@E<0#)OX%ar0*Ba`_@ofHT9G z9-5+_umrj%NlL?9KJ1=DWP;dsbiW!CL4nYOf@9@#AM#Png#D$jbl}A^<5ofeH)9;8*8+VASF{aCDI6SeQN%3gwxHP_6 zp!WZJ0ZK50+Nw|1S|U#Cv?x;|K5!pSQUv~!{>!K0z3M8PeW*XTLpOh%>(jDohYK&? zsF{jP^(iIw(eyaozdE1_&S@s1VZ2QAE?Xk)tj7cJ7%v%`q`(ODk;@^9Giu8l}CYLssG3IsX)aqr*qD!hJYj6O#{(| zpRKTMQfkrdcgD83pmBcJ^gc2_5}??wyPj2NJQX2XcbvEC7ET$HniY1{hz6gTcSgl) zmlxZt2Y$8pb>PkLk@;J8%m1<)dS#`xzPulsjG($8>|PApM42C~{hIf~N$KzSALSfi zXbP(I^%eDR&WLTq4FStJQH$hn$Uq(RUI=mo1RE_kUV=V^(vrEw?2<3*Wg=Q>xe3w_ z{8ERgmk#D`bUBfb3Ba6HN~D2O(Fv$by9KBT{Q;R;FXKeSfMeSPV!ZzfJe3UOC3zUP zyU6RBi^^|MLz%O5(}frQ$qmDU8o(Mz$7JD&BXt}QP%eII(w16#v3IJc#9Qu#d}Kh0 zV7f7IzR)ob&`fp-w_$&EEQHYExUbtT@E=kHTPn^!Ut%~{cjo=TQerE&PTX&TWqHK$ zRCx#wNg$3Pn=;e7n)0Qb(x-vP1TH>gv_>m|T=At(^P;y#w7ix=l<5Ft0;Y7MAswR` z_4s^kiRYLpbxde9RN-vn9!@EqG017se!jS2_oQ4;}c|XK5nz(Dd2CjSmV>yDjQ?&(Bk1zg85n=&a4z9HzQ=bql6nAhI zQifvC>x7toh50#ttUDU{f7S;hYz3GT639UX_+Y$z-7rO1xMr;)nvp1{7{MrtilA-gTe( z8iVctbYyLO_2!b+v{}{R@yN{PR&HpZMO1DE_3<)083n>IL8#6m!#LDD=G0XB$u)R= z=23{^$Phxb7jG32y%z915f&U&xBWRW-$L|y>BLPSRCcXvPnVr!s?@Lwjl_lZcBEsT zncb>}T(~|_sb+*s)2rOu!i;*So4!z2fkG|>a@#!pY*Gx>qZ`N3qDEd+hM>BVp=*{4 zv%2=t_P5V)^!SIM7@MABk4($Bs{( zqbMcF)U1BqaVY~mOwOll7dK^|)zEBD-;i2UmpT;cK~_hHjEMo zAe8#}i+dOcJ+!Wb!;|Y1A&ya8vZP&HhmU+P5z}tB=%dUUh40z?nU%w5hg|q{ii#il zZjCaqziwUNdN;#|TPpQquJY4Jp<+bVW(Th=!@Koadw41&ZSR!iZ{!?cYHfZ*-f^>K%k-|Yd}f)G+svPLPG^$b~U0h zoNq!lm8yTuVl})KOe~~koZ}_siVql-G$b?lmf;<^sYu_`Eul$oUMN$nJUL^E3lOucq zKr$-4KN(CNl#P>xBaoI+a$!mIc_PQtqSG=YSG&95f}Z|KtZ_Y~Tcd>dQb|Eq6vh*( zI%Ag^XNZ{~a6}$lavpOW@bg+wp_L= zg<=UBh(vTp90*4+`+SOT2?ctQXAuUO+sn}+82`2hmP=PQ!WbM6YJ#F4W8i8t6+9D&KwLn2v8 zohQNeuhibgz#^NjMsA%D!2n5iwl}!pC|tOVX?pyRF(x|*4N-fDz63}mEue% z^OHUGtyFgOC^Su_45JRg#8Je53E;In z3%QojW=&w**c7oh9y|55&&umDNs#E>XuTC~CUMdPeR(X0p|7O9-A zYYd2lk~{6bzd7)cliGUkuntx&jzaxW3jtvuSsbJgCxI9QE{x1|<~zK0_)~NQ-Zrg`RK ziS0Vdws1L3^l3h79iFyIqm;0__&jc&vuMon=pR0qSg3krKeu(?&7*i<0U zEw|dNA2gO9`M+|0!B1PAv#dsQ|3(QQhAainFrAH~do+9llVd|Hp}3$MZCnw*2s3aN zmpO9Uf-ePbmPE?i*iaHVUDwp1VdN21hJl{zF!UR;>9#+i8&M)$@4Q3+)H&LSD8zLr z_2%6uRB~K^x4qThJSeF5I6Wg`oqiNimgb7~iIk8vd}AjnsmQm#Chn~wdHAcgE`DS5 za9`?ot?!=w?X{wU(B#p$ZKbVwbDqX(e7UvVC}~!_wdL{tRMN&}KCNT2E2!2uMsX}1 zKP^Q)EW5o34V9=FWS8UEWiH#_WY`c*5RL5KYsz82V^*-YRXqh*| z(*!o5di9i~knMtpO&@4aCN0^p6I*~*v}I8sDaQO}@KBo}qO}eswHYP}XI46`UpPmK zc5YV%uYXYE@U&S}=iSf2Wd!O<3qYfYav6Kuna#R@|3QCgYw*1nxhQJR_@qh~!~uoHD2*l1mw z4(~a+%XcFI6_Ky-$Aui?5|KZlu`V%!lY1 z69PkTh`fO zy5cb+_QoxE;ApK#w5l3h6Y)l zTe5FY<=BH=BZ#l-|OSEl_@Meo1Mdt&9Bh46m zTIu#OHHrm3gGa5Az|^{Y>h;?lDvh+}R*1BY^Z5C-B~j)x07ufnQep1Z)KOCsSrHOk z!FzxAHvg_7??~C9p;h`RnPKc`zHIW_4hS_Atu$UBL(Mc1N@XFB>beNT?n;D8Lr5bk zDwX#hG9t)N#d4Q33_QkgCwd<(jIe9ppd(M+&PBfn2>wnm7xT9Q_7;ohfuu0aj4*h3 z$2EB`Sn%O-JEi{rD7R+ZX055F5v5hh>}+A@ML@kIAcyea6KmPqtWQnK4eG|dp8%+m zuA}9%RJkVcQ$WnA}izcNRNPz3<5?Hy7Vp95-A&jlOZP=mNz%u#S(zKVDS`Rr>Jkf`A0 zEv(kVUW6Fj-@h8a332b?2=94^R2Nv~|FGDl`0p+Gu;4RC`K@TzcXq4nnGB@HclYty z#TlPy$L-p}`@oE`6FV%3mN|q}h4&}JfCX2S7q8LXdLo8gxB zl^^a4gIB+&2>cp{Yw06u@6SYyEyRtmVIS!Uh4|hF9Sypx;E}Jdni=etn)V^52ggEujLSsC2P7vH^;6kySSI zgXmg_R`dXToMo;!yc zYo&=~0dT?G@yO!~FAC1}(>ELV)+ly&i(ToIww@t=`_M+GU|Qj%*+K@bZ=cnXv_{2W zFy)G79nqzqRxw9J7@7?=DJC9Y!sF?)Yg7wEparg^S{dmpA@-(!Dr8XniA#%X?Sibm zq9Yl^K65A$r+a`1Y>7Dkz+{2U=^-z}1X^0)r){OM1R)(y-cRh}lMyPf5CZ9;th zT@3Q#dR;PDnNjPHT}NB=Q274`{9m5To3S#8-{w`m#n-cg3^8kVguO!xkuH<8#37+4 z`6;K{$HT}L{?UpqZQSaUUOhE+;tu4q#8d~sU9pi=3lw&`h^mzNM(d=JQ@#mdq-zJ%ji{H zq*Mc`@spgvEu&LHirKQ|O6O8&}5{!rX_GPfIy*1}ImpRwmJKjbMbEYf=v^XV2S`7Gd?<1g3 znQ|S0Z~~#Gx|9R*6ijoo3>e^zl{8g)nzx~h*7v^nN)6Av%N;!l+0j;LgXpqkjgw*o ziDQMPoxQD=xZEU^)8t)QBYV&+Nx~wifgJLT1Y+_pKMQ{5-7GGUr^BYv4`YFqKw{Lj z_kR92jn#K6q_7p`(?30;@CUXSe(%G-gpVPl_RVE!=a*cIVE78O*f#67+8rnMagvBk z1=>41I6vMr(Id5WxHCMeyuTl#ISHN)I(ap&nip=^(*70A)M!>YWUoB)zncRWiQz6X zIW+SKQ!Y!UF!`?jOzY3t5c(85kQ{)%F+3JZvllM7C6LOsF&cv4@9^HFzLcU)>hzD! z+2+aYPD6v40D8E5?a7Z8ml0et8nZb(+7;zQ82UUxKRqH84;4ZG9Xdv;U^>}>4i}4i zFIUDJD#+o?Si5g{RKD;}&Vm=%3_;xTkQmuE^f|Q0`_}k%NGaG>557?nbQOMyk4}6E zN~b#_O-%WNb3&LobL}`k`P$|FG<3I_Kj7&*?1o-FPg_P%V$t}#c6st}W5wqzHq#Ch z^Nvuil(9aPs#p|`O#Vt&1Inmlqsn${V2q`aZCm=wJtiW>h!{pd6o*M-LO2+sWRH7c zP3xAwxRT09%Vmy24b8~W>1DA-4Ko}LtJ5pR4y6k*FZtl{U#BTZhgko#)W>u!+F%C#f;9#B<&qmm(l{gAo-72&&Q+H>Ef)4HD> zPx6dm!L6~a^Qz_9NLyG5fz;c};w>wm`j3s{v+2H>Nx#*Z%-*@=gsa$@(LK8|F`%S7 zVKxrBDygONac@Hqm_yAFlNrm#zadK$hv+s~X-t+*7;7lyQUQL2BlLzV0H#w^SJf+^ z(nA30dO}%q8C+M&XE~`MX_kbnS3R<>vnZM%+=eV-#B2SgkB-a-YSX7#qS&>DbyYZ7 z3M4gYAfZI}%3H0$^2qN>M^TIQT^2+B@=TcXm~o$Egc#r(hErUkG4bi+Ut*k_l>*^< ze+2D7%u<)G1Bh-3;J4HnaSggGJs z7{-OjFsvDAUDJP7yIbl?axG9MW|i(hOVhdFY`=Q7?C3JO5^6XIV)|vjDHB44Fyc0X z3#g|iL5h^SWC9dc=j<1sGx)CGyNt11*M*eN)UFNZU9|?qg20Cf+5@d~E z@}t1S(!`(!MEqibSb8Kul8`J5^sw+cGqqxm{7MId7Q4l=Ix~r(>NGDoG-`z&<2cXJ z-$BHuKYBkdBCrL6V}ELUc^PgrQcQNfw@RlBgJ?d_qm8v)oPN155q_U_5YBm-#XspG zY7!;4p&t_cR>X5-yo%dht;_oNvdHceikaGvZm26BFSLblf%csiA}=@lqJ!o~o~#PY z;tXtpK|c?Q6oeUEKlW6LhPS@$wY0e4a6Nm%So0I)!YDZ~oGZikxE3Wrqo;}WTvtzv zK}Te+@uHMa7#&wbPhksZK|bo2WXk|En$yNZ`+jy{BDel`tNnS$xr^ti50m^xW@gP65gxZLqU>`7s%LbouU2I`oXv>M0g_$g zG7vbDqYHs>4m%p`2!#rMo@NQHe$7jjz)vf}q8_7~tW$Xd_$^X+T~DZ+AaRkg{UN^)&dAQ+acjapu$icFDOx9H#i`^R zp_$3Q$vuSb&~*>ePrN^rjm1uW@x~7==92n$Dw~ zZ_>=bo0xGU3U5*;7-Ofb;xDVy1s*%<5{)<3$kv|NMon|5#deEnR_4D6bEw^ zWyopI;pyXWcZ7ZerGluGr`=O~dT+d^j55L3*#w%fPQoZ){Ob8L7V*0yO@zOX&+ zqLT$-$*yThWu)hI#Gfzl6E2Mk_%ZW6_ysDK=RbxC+cH zMi5EG{ZUIYc%`6=@}v1cBo+Y$hapFW+PAVo zMOg*CL!9=EX|uA%E0pr~S2%-u)H|y%o6B2pV@cJjCs9vPhLq~4X#4q!&$p$n2prgg zMDXSSQM1-eWBf9ANwiNX>QBj)6kt3y#9U1pff8z&iWOG$!{tLP{V%6aOz}}%>_Mvp zfIZ(8ALE1*Ke`AnSXTTXe>D}-s&DRHbnTE=AW(lkSsGj@%se9Brc~7O&fO2eu-oPS zsz+K;xw-khmqf3QGSGrn-j*5~t-6V&W z)}+DAE({WJ*f8mj?Mu}Q6@1Qe-N7%^y^Y({mHM5MWM+>|nVJ$0=%qyMmuFu=>$2XA zHphM!La;YZd;I*xghO_UZmrF?LU^%_gq>6F>ZMYrd!N7iJ^_oAk9FjY(46}*++Ep> zmX>%;*0EjX&AJuA0{C;4{qV)9;56wmCB8D^!*GyzM$h*P%}rR*a?^%abnUi|`;wc1 zyG22~w!az7BJabi4liRnnGzfFp&^u)?ehWoL-vCmzVQ6#3WAD7WzxC`Q#DZJ!6CUM z8p5D~er~`dO`M0t?<;XsTZQ0eu><2mEA~pM?D0`_0kbcB+47I22hu2mWZWd_fEe?J zku^qWGevTc(5T@LoOb2@dfP*b-@6%D^Bh+T-4$Y=O2@fO0Ra32d5ENz|6`dTko3`~ z`rNM1&I|7U`<8Q!HP#f6wWZbn#q7M_G~swEB}r!Kw5l_EKj|^Qb;FUBDtrUIggvOdPfvs?Uz+3V(rJq2s$j9T{A-E;U&ou6VUFehVM-u)`ZqPl zHoq4Y&%)1Pg6vc*#=Jnk2R`0kf4}-V{&GsQDior#MY{epRG)8AYVzzF3|}ko`u(8% z!T1o9p&x$J(m8~$^N+iZj=Y@~>i%=aHmfO%@IxM&$O z+T1}1rM|vCGpaQCFjcYrKMg9#tN1m?)(Ig7i^{SgJ`o}}`nWB`z6Mi>?R3FY)YV#H zhfK09_XtB$E1=2akkk^9QRNZo+c>6Dp@KY5xCdx@wp6@kio-fV!xb#bR2O;_Jr|(j zwxt@M`F%hhCA{cJfGo0l?^G3s#FJ(H8WQ-aMHC@~x};(ER((Ve8@xm)rSpbc0zy5E;bzb^X(NejrT`#R0|s z??5*1`~F=9FELj*FEK4Nw>Up3G@$~w^4d3WQvAw9*W;?T%F;AZNuUwG`3Iff(&jdO z+VgpACAyS18pi4`H0REQyFn~0EdFX}9O*t8CsY_tq3WXLPMQ;4e9Zp;N#u$`Z`Du7 zepKWSDs~73N495i(M^U3a*ss-IeevFWID#2dmCCc%8;1}C1T2x1&%RSBiezMsL1Dxg`#Sa_`xxsmwn&x`#!_hb z+;@E+kMHL%_?(~ay|34OZTH^i>zs4XayY30{8bHqo zy@RAzIF=|C)tf4-nA>TN=HN9OasQaP3ULIw+u}f1yFq@y2)Z9j86QVsw<)NbJV#x zu^hGJh~5$YWJg_oxdegmqY(KiiD5nd0M4dgNdX z-ik+(a+AwKF^&^F>s~=ALWxPikQ!{Xu3Bg zqHUZv52wnamdlEilITq~Gh==+A)A zh+q033bW=wBBlU=rJi0Wb}g)4FFgG}Uoz>6+>s(509W*Ix^=kpK+V-8)R4=*?lsJz z{vNMNkBE}j1ba}1RU2D7ZBdH{JtGD|*{sd(!iYB6)YQnbeyMe~TVKb>vCN*K2 zfN7H{$;dasTz^hGomF~*e$FcZc$j!;bhh61x9P{C@;!thfbGD(0^l65*(oZafOj^R z+mfziD8BiJO!^Z`ny{q(#7O0!wYa$bZ-A0JC-PwP)a_Szw(=Q@+c37tOMz_PDt=hK zTu(#%lYI&xuut2mYqtoH*l_6j@&~giH6WkV8L`^N?^*4{)OJ1@Oc}4226K-vaH+Jnb+q+~DEuZrgN*<#ed6sm z7gX`v^^E|ldc`o-u*RR1XNcnx&tJ?8?5OFAwmYdv$Pni`UVINgBGPrWqlPBTVUr4f zq+Oi!+;7mZW^C^pSL^U-_(AKq7IPrrpLUMvqYm=ZQeAjpjVt>*_%-|sz4Jr8nR3zl z-7F4+O(uXLLv%<-P1dF4&icEbb~gpzfPcRVBECYZx1YbClFk76mQ$9`a*{9a^x%Fc z$!C1uhahu7Kl$P{X+H4xUM5vE79GfiXDe!tR*9umQ1{n0Wf#e{+l z52xZ9{sli_8JgSv^6AkbQJ7nHo-kD40`5;{sI=J`yUKa%FE3c);C>Nxn9K`ubrHMY z;2JjwDC8qwGqhxbI9Lt*c&XU!1&*Ho%4gKiKn#qDCdR?g=jY?DS&@x^P5;WGn8q;+i1Xypoom)HL;wAYI7h$XtpY!W!W)!)%G_%g* znoh^vsR+j0eF`U8k62!260ViS+?PMe!VA7P6m&^7cTuwHRsi^>qa$L5_R|1ED4{orPe*-+B!CbBOzv)Xa4f(D?f@?*YF2 zlkgc8h)E^DQUDvQFSaTv+&(unhvd`CgfW@uoLjv_%!wF`T#L}2eCT)Rnj8~Gd$=3U z%;vmxv++Xwx1Hr*%x3!OlH8*p`1(>V+zH~%O|}U*If0=5eeZ}PMJa2rO+!7kfj0v+ zDV>v0$ME=Rh&%ehS;-A7Mn8ctdCrbSTk~OoFO(2Cd!)?+s?Z5oB|jPd;XG1jmDAKo zW6j*67UDYF#!L&EJL>W%ea7!L&NKFjefIWo2EqhE6}uO&EhiBGl}kaS`rVOr3+!R8 zXMo>Zd&;!i+_q(RROU+uVK=+^^!+e$Hx}FKnET$O1P|zA&NbxY54Mgo5t2gYb;;gi zEpKXVf>F_I4RW;h0#1?21zVbCguQKQ@t(5_{3K!A_%0`T3VEz{g02K zV$LE~UG~mX4Y~cR%Oh|Pdte%Zm6fJQWB{$y1zQ8a zMg?>S%>%mm>e6H+mXOC^xl}@L18a?%DlO~%ji8dADXoJGvCoc+h~DaaZ0Eb1HQRCW zyv=A6%Rc~$ze=a)W;IFV=yCd`VnTQZSl!%)_gH@*)m7Ev@s4wt<`D=lq@C0&Tj<}J<7+19U#dsJxC$Gk_@TxRyK%W3?#w@^3T6TkHjoos-6 z7MW!a=e_&+eKClj@63gfd^`t?52{mBob9t1Uj%AyU{h1Rm!0M<9d13H8xb`w_FKd{ zy-Zrk62#n98reZve5*gClFj84yPZvgKk<3Kn9W(~SpD+HUa(7g7ecSv`O1OvTgvJH ze4SpChx~Wd>xBvNj^xdEfebgABRkmT!UfhtyEs}*Vw?;)K$Wjp|9V%t(l5%o2~9pL zF_&|=truo=n0_1xFmz%E8$^J&Z!zF{g^>zA-A0ndf6=!p1=Oy7oNqiUCV!`E0AxFk zkiZycoYxTatohpjApyN=a5ly;E`{VTgh&b9D`rE93H-g5d zX<1-o3~>H7@Wa%!e|=9_i9yO#rvCs;V}oi788DDYZCHL^u7O$bOfv=kkpA={Q9E!) zJY2m}#D=LWPIrTe-VjhY|BCBkRY2(O|;Q>mmmv!gdsgK!n((Yh6!TloS`= zTn|2|ASPw703MDvlH4C?1U*Co9+}-}o*uy8_XQjMkEmzrs z3tKJ!v1(1q{)RV)d#xk`tV?ovZ`m-8(NGk6rAP?8&OB5>BW+bM#~&jaWQqQ;{sx9w zSHN@b_P(Kn>$1eUvw44OJbw8*)iHPA+)6*DU@{hI<%6<-?TUPigQTkZtxQOVr5bhj ztpNLAQlv5}t!!`cI@{RD2N;v6ed~s2f#(E z#{H*+ht_SMKWN?nIbCSz+ls!r`sG7LMYwUI)zgAB))Y4o>@$#;IAg$y(+kezR zIgrMuc-FVFH#^*K1gtqgR=);4CL`|sM_;fo1aw^LFHKTpU37&3G}{If$wUD3_#~yo z@o%*)J=D{G?TP=NR2tx3>}|)?)BWv}4gG9nwAQ80tJlgh(a4@M8EMIOAfQwsmHuqE z&x1O-te%Z+BW1It-|BMpo=5?X)fnxi{sqhbw+3+equhfa{eRO)py)<>X?zL$Uu9Y1 z|8K4jeVN^ct*C(}oE3U;=tQhD=t1nYzsF5|3d?$~hG#xDjf#lVcP7s_*I?sWqFMoM z%be_|P8(SxU)O9--DgI@u+<6MoRC2!{K`3bi4dTdUs<7N@=|{+x8{*6JM=`wsPqeq5q*A|t30dt9fu;O zOr#Z?USVWS<8eXIw&C75-+nhsqjNqbHvx-&>)zhyzderJ9Hvs&UCI^@8z^8OgsM*v^JT8Q&F>YfI|!xrd_0gHDlIQy_6QZ%J&)bS77BMyZ0d?b-ZAjdjpWSM$;&4yoMo z);@gHBP=({JfZ$r^{1bhlF{|~cT6|^E8{XGF)Q$HWXiFyk;u2kS&y#&JkzdtT%xo*wbQF zZRW+_JX>r{MvJ|RYcroUmzzLKX?*SGA0L}&^iXryeVrOFT)`H6ZSBVLMaAFuUa5Y( zL+?ig?S*{!5_;#6dU-yO;H|6Cg~dAg#+q6=LlXtUVpcX^9P#%|vW-^#|JMd}9CU}? nS-bQ1o^d9rVe(T@jK>c-U(218SA*paAb@o48fuoSJ3jp%W1Sfk From cc101ea8a325740ed64ea557d8a9ab8b1a363c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 23 Jan 2024 16:09:30 +0100 Subject: [PATCH 133/350] more cookies --- components/lvgl.rst | 10 +-- cookbook/images/lvgl_cook_volume.png | Bin 0 -> 1228 bytes cookbook/lvgl.rst | 106 +++++++++++++++++++++++++-- 3 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 cookbook/images/lvgl_cook_volume.png diff --git a/components/lvgl.rst b/components/lvgl.rst index 2163e64ff..b8a1b3366 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -31,14 +31,12 @@ Pages in ESPHome are implemented as LVGL screens, which are special objects whic Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. The child object moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within -their parent's bounding area. In other words, the parts of the children outside the parent are clipped. A page is the *root* parent. - -TODO - PAGE +their parent's bounding area. In other words, the parts of the children outside the parent are clipped. Widgets integrate in ESPHome also as components: +-------------+-------------------------------+ -| LVGL Widget | ESPHome component type | +| LVGL Widget | ESPHome component | +=============+===============================+ | Checkbox | Binary Sensor, Switch | +-------------+-------------------------------+ @@ -561,7 +559,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. -See :ref:`lvgl-cook-relay` for an example how to use a checkable button to act on a local component. +See :ref:`lvgl-cook-binent` for an example how to use a checkable button to act on a Home Assistant service. .. _lvgl-wgt-bmx: @@ -1184,7 +1182,7 @@ The Switch looks like a little slider and can be used to turn something on and o The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. -See :ref:`lvgl-cook-binent` for an example how to use a switch to act on a Home Assistant service. +See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local component. ``table`` ********* diff --git a/cookbook/images/lvgl_cook_volume.png b/cookbook/images/lvgl_cook_volume.png new file mode 100644 index 0000000000000000000000000000000000000000..7aa8924c122ab184126ede9637f7748fc31007fb GIT binary patch literal 1228 zcmeAS@N?(olHy`uVBq!ia0vp^HbDG}g9%6${@f_ez`!!u)5S5QV$R#Uh8fb~GRHs0 zcX6d(P-tY&G;nEl)MHtbXISy_#m0MYbXU8rmoz@M_*%}pX?>ErS>~)YV##u56Swhb zb};97t{`RQQ5qY)>-Ycrwtr);?|+}+_rBJ`uYCFBGu36awY|r$mGkp*cxHq-ZLXT~ z!fQ?AC7#Ecn=}pnUjN|9`jsoob4?|~gUFwszZ5hThV6;8bzB@(w5oFHh0L~tN4`%= zGd&c?Z@;Wvc)P@bgr~3jrivNWJyL{8d_RJ{s&_3qT>d(UW zqFAff?k-{5W$&~;{?$QWTgUCq=k8ydy10Jlf#3T3ET?VV-`Q;T!2S0*x#Q^=u-SW@GWxYI;(Y4o)FJIVLYiM=$ z!>?qE6E|M>_Z?q;^u^@v8UFvLo6dOfZab%jd7P-px>3^l;xZ*6*cR zcW<)3h<`kHs;=bn)6VnzCEP#1Wt+^pJ@xx(=iPqJ8#npPYXA3F@xnCE&lfab>%N$4 zQtr>cDDX|BTJ4nif~{#&+y8C!O#Y#E*7^FPzf;akOucl+_HKvU#`Kvc{C__|^hLkU zaQme?cVpVsFDLgrc=PddnoO_Z;}X^vhs~}<r z1p*SSrC;Rzj(fBt(JHF3I-S|w&u~w9rTgt0{pHW@-RBWheqcSl*=*Z2W&4ot-%|GN z+mY$E-9GL9{hrURfh+y>wx<01+q|*4Y)<{*ANOnT{5r3O6#qh)Nn&7yY(u}qX+KMw zX7fVzb;=uC^SxCs)Bc%Gka>}E^2OP#k5vwqw{@h=)Y*6KtNF5hcjdb@(fsN95>t%d zY?65~CsljWsi5yZb2eKuhaE0hW5kqTp&4;3)nKOnOr|r_9ZuR8z2cPmw{%%ehE9~i zQlERSfoVJaD+RAV;F3GlyH0h*@rcPw=e4YVD^ygN88UH7vASdXC*Q{KBVndB_1A^B zoRUp`IQ?VW!&yc9)3#o*oA=bN`p)_fHWu1%-fY{z@gg#_?W4#|ksW(igt7v&zSo?u nQ}Vjn(!PbfU;Y!E-Rc<=9Sm5?uSetnODP6VS3j3^P6KkC! literal 0 HcmV?d00001 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index aff4d5fd1..bb3bc9a3e 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -49,10 +49,8 @@ If you have a display device with a local light configured, you can simply creat align: center id: light_switch on_click: - - homeassistant.service: - service: light.toggle - data: - entity_id: light.remote_light + light.toggle: room_light + .. _lvgl-cook-binent: @@ -97,9 +95,58 @@ If you'd like to control a remote light, which appears as an entity in Home Assi widgets: - label: align: center - text: 'Room light' + text: 'Remote light' on_click: - light.toggle: room_light + - homeassistant.service: + service: light.toggle + data: + entity_id: light.remote_light + +.. _lvgl-cook-volume: + +Media player volume slider +-------------------------- + +You can use a :ref:`slider ` or an :ref:`arc ` to control the volume level of a media player, or the brightness of a dimmable light. + +.. figure:: images/lvgl_cook_volume.png + :align: center + +We can use a sensor to retrieve the current volume level of the media player, which is stored in Home Assistant as an attribute of the entity, and is a float value between ``0`` (min) and ``1`` (max). Since LVGL only handles integers, it's conveninent to set the slider's possible values to be between ``0`` and ``100``. Thus a conversion is needed back and forth, meaning that when we read the value from Home Assistant we have to multiply it by ``100``, and when we set the volume through the service call, we have to divide the value by ``100``: + +.. code-block:: yaml + + sensor: + - platform: homeassistant + id: media_player_volume + entity_id: media_player.your_room + attribute: volume_level + on_value: + - lvgl.slider.update: + id: slider_media_player + value: !lambda return (x * 100); + + lvgl: + ... + pages: + - id: main_page + widgets: + - slider: + id: slider_media_player + x: 20 + y: 50 + width: 30 + height: 220 + pad_all: 8 + min_value: 0 + max_value: 100 + adv_hittest: true + on_value: + - homeassistant.service: + service: media_player.volume_set + data: + entity_id: media_player.hang_ebedlo + volume_level: !lambda return (x / 100); .. _lvgl-cook-thermometer: @@ -121,12 +168,12 @@ Whenever a new value comes from the sensor, we update the needle indicator, and on_value: - lvgl.indicator.line.update: id: temperature_needle - value: !lambda return id(outdoor_temperature).state; + value: !lambda return x; - lvgl.label.update: id: temperature_text text: !lambda |- static char buf[10]; - snprintf(buf, 10, "%.2f%°C", id(outdoor_temperature).state); + snprintf(buf, 10, "%.2f%°C", x); return buf; lvgl: @@ -490,6 +537,49 @@ To put a titlebar behind the status icon, we need to add it to each page, also c For this example to work, use the theme and style options from :ref:`above `. +.. _lvgl-cook-btlg: + +ESPHome Boot Logo +----------------- + +To display a boot screen which disappears automatically after a few moments or on touch of the screen you can use the *top layer*. The trick is to put the full screen widget as the last item of the widgets list, so it draws on top of all the others. To make it automatically disappear afer boot, you use ESPHome's ``on_boot`` trigger: + +.. code-block:: yaml + + esphome: + ... + on_boot: + - delay: 5s + - lvgl.widget.hide: boot_screen + + image: + - file: https://esphome.io/_static/apple-touch-icon.png + id: boot_logo + type: RGB565 + + lvgl: + ... + top_layer: + widgets: + ... # make sure it's the last one in this list: + - obj: + id: boot_screen + x: 0 + y: 0 + width: 100% + height: 100% + bg_color: 0xFFFFFF + bg_opa: cover + radius: 0 + pad_all: 0 + border_width: 0 + widgets: + - img: + align: center + src: boot_logo + on_press: + - lvgl.widget.hide: boot_screen + .. _lvgl-cook-clock: An analog clock From 7d2eb638f572e949561018fd515203f3d10a7703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 23 Jan 2024 16:29:06 +0100 Subject: [PATCH 134/350] Update lvgl.rst --- cookbook/lvgl.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index bb3bc9a3e..3bc644841 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -112,7 +112,7 @@ You can use a :ref:`slider ` or an :ref:`arc ` to co .. figure:: images/lvgl_cook_volume.png :align: center -We can use a sensor to retrieve the current volume level of the media player, which is stored in Home Assistant as an attribute of the entity, and is a float value between ``0`` (min) and ``1`` (max). Since LVGL only handles integers, it's conveninent to set the slider's possible values to be between ``0`` and ``100``. Thus a conversion is needed back and forth, meaning that when we read the value from Home Assistant we have to multiply it by ``100``, and when we set the volume through the service call, we have to divide the value by ``100``: +We can use a sensor to retrieve the current volume level of the media player, which is stored in Home Assistant as an attribute of the entity, and is a float value between ``0`` (min) and ``1`` (max). Since LVGL only handles integers, it's conveninent to set the slider's possible values to be between ``0`` and ``100``. Thus a conversion is needed back and forth, meaning that when we read the value from Home Assistant we have to multiply it by ``100``, and when we set the volume through the service call, we have to divide it by ``100``: .. code-block:: yaml @@ -148,6 +148,8 @@ We can use a sensor to retrieve the current volume level of the media player, wh entity_id: media_player.hang_ebedlo volume_level: !lambda return (x / 100); +In case of a dimmable light you use the ``brightness`` attribute of the light entity, which is an integer between ``0`` and ``255``. This doesn't need conversion, you can set the slider's ``min_value`` and ``max_value`` directly to these, and just use ``return x;`` in the lambdas. + .. _lvgl-cook-thermometer: Thermometer @@ -546,12 +548,6 @@ To display a boot screen which disappears automatically after a few moments or o .. code-block:: yaml - esphome: - ... - on_boot: - - delay: 5s - - lvgl.widget.hide: boot_screen - image: - file: https://esphome.io/_static/apple-touch-icon.png id: boot_logo @@ -580,6 +576,12 @@ To display a boot screen which disappears automatically after a few moments or o on_press: - lvgl.widget.hide: boot_screen + esphome: + ... + on_boot: + - delay: 5s + - lvgl.widget.hide: boot_screen + .. _lvgl-cook-clock: An analog clock From bccc9ae6216c18fe3b446d714c38af3eeeaeecd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 23 Jan 2024 16:33:48 +0100 Subject: [PATCH 135/350] Update lvgl.rst --- cookbook/lvgl.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 3bc644841..00520660b 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -453,8 +453,8 @@ For this example to work, use the theme and style options from :ref:`above Date: Tue, 23 Jan 2024 16:42:10 +0100 Subject: [PATCH 136/350] add lint url exception fpr lvgl cookbook --- cookbook/lvgl.rst | 2 +- lint.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 00520660b..7fcf3b35b 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -541,7 +541,7 @@ For this example to work, use the theme and style options from :ref:`above Date: Tue, 23 Jan 2024 17:09:50 +0100 Subject: [PATCH 137/350] Update lvgl.rst --- cookbook/lvgl.rst | 57 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 7fcf3b35b..a3a0f4f1a 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -102,17 +102,64 @@ If you'd like to control a remote light, which appears as an entity in Home Assi data: entity_id: light.remote_light +.. _lvgl-cook-bright: + +Light brightness slider +----------------------- + +You can use a :ref:`slider ` or an :ref:`arc ` to control the the brightness of a dimmable light. + +.. figure:: images/lvgl_cook_volume.png + :align: center + +We can use a sensor to retrieve the current brightness of a light, which is stored in Home Assistant as an attribute of the entity, as an integer value between ``0`` (min) and ``255`` (max). It's conveninent to set the slider's ``min_value`` and ``max_value`` accordingly. + +.. code-block:: yaml + + sensor: + - platform: homeassistant + id: light_brightness + entity_id: light.your_room_dimmer + attribute: brightness + on_value: + - lvgl.slider.update: + id: slider_dimmer + value: !lambda return x; + + lvgl: + ... + pages: + - id: main_page + widgets: + - slider: + id: slider_dimmer + x: 20 + y: 50 + width: 30 + height: 220 + pad_all: 8 + min_value: 0 + max_value: 255 + on_value: + - homeassistant.service: + service: light.turn_on + data: + entity_id: light.your_room_dimmer + brightness: !lambda return int(x); + +Note that Home Assistant expects an integer at the ``brightness`` parameter of the ``light.turn_on`` service call, and since ESPHome uses floats, ``x`` needs to be converted accordingly. + .. _lvgl-cook-volume: Media player volume slider -------------------------- -You can use a :ref:`slider ` or an :ref:`arc ` to control the volume level of a media player, or the brightness of a dimmable light. +Similarly, you can use a :ref:`slider ` or an :ref:`arc ` to control the volume level of a media player. .. figure:: images/lvgl_cook_volume.png :align: center -We can use a sensor to retrieve the current volume level of the media player, which is stored in Home Assistant as an attribute of the entity, and is a float value between ``0`` (min) and ``1`` (max). Since LVGL only handles integers, it's conveninent to set the slider's possible values to be between ``0`` and ``100``. Thus a conversion is needed back and forth, meaning that when we read the value from Home Assistant we have to multiply it by ``100``, and when we set the volume through the service call, we have to divide it by ``100``: +With a sensor we retrieve the current volume level of the media player, which is stored in Home Assistant as an attribute of the entity, and is a float value between ``0`` (min) and ``1`` (max). Since LVGL only handles integers, it's conveninent to set the slider's possible values to be between ``0`` and ``100``. Thus a conversion is needed back and forth, meaning that when we read the value from Home Assistant we have to multiply it by ``100``, and when we set the volume through the service call, we have to divide it by ``100``: .. code-block:: yaml @@ -133,7 +180,7 @@ We can use a sensor to retrieve the current volume level of the media player, wh widgets: - slider: id: slider_media_player - x: 20 + x: 60 y: 50 width: 30 height: 220 @@ -145,11 +192,9 @@ We can use a sensor to retrieve the current volume level of the media player, wh - homeassistant.service: service: media_player.volume_set data: - entity_id: media_player.hang_ebedlo + entity_id: media_player.your_room volume_level: !lambda return (x / 100); -In case of a dimmable light you use the ``brightness`` attribute of the light entity, which is an integer between ``0`` and ``255``. This doesn't need conversion, you can set the slider's ``min_value`` and ``max_value`` directly to these, and just use ``return x;`` in the lambdas. - .. _lvgl-cook-thermometer: Thermometer From e93bf2984866dde327444a7792f29fe5540878c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 23 Jan 2024 17:12:18 +0100 Subject: [PATCH 138/350] Update lvgl.rst --- components/lvgl.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index b8a1b3366..66c35dc8c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -470,6 +470,8 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. +See :ref:`lvgl-cook-bright` or :ref:`lvgl-cook-volume` for an example how to use a slider to control entities in Home Assistant. + .. _lvgl-wgt-bar: ``bar`` @@ -1151,6 +1153,8 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. +See :ref:`lvgl-cook-bright` or :ref:`lvgl-cook-volume` for an example how to use a slider to control entities in Home Assistant. + .. _lvgl-wgt-swi: ``switch`` From 7b48dd33c52b1918c848edbbe0e2883d1c6e91bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 23 Jan 2024 17:19:01 +0100 Subject: [PATCH 139/350] Update lvgl.rst --- cookbook/lvgl.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index a3a0f4f1a..dda4841a6 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -147,7 +147,7 @@ We can use a sensor to retrieve the current brightness of a light, which is stor entity_id: light.your_room_dimmer brightness: !lambda return int(x); -Note that Home Assistant expects an integer at the ``brightness`` parameter of the ``light.turn_on`` service call, and since ESPHome uses floats, ``x`` needs to be converted accordingly. +Note that Home Assistant expects an integer at the ``brightness`` parameter of the ``light.turn_on`` service call, and since ESPHome uses floats, ``x`` needs to be converted. .. _lvgl-cook-volume: @@ -195,6 +195,8 @@ With a sensor we retrieve the current volume level of the media player, which is entity_id: media_player.your_room volume_level: !lambda return (x / 100); +Nothe the ``adv_hittest`` option, which ensures that accidental touches to the screen won't cause sudden volume changes (more details in the :ref:`slider doc `). + .. _lvgl-cook-thermometer: Thermometer From df894e0d8c7a0bd3068b29f21a8bbc614164c645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 24 Jan 2024 09:37:05 +0100 Subject: [PATCH 140/350] align_to --- components/images/lvgl_align.png | Bin 10700 -> 12879 bytes components/lvgl.rst | 7 ++++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png index f5269fed16115e7b103a332ac8626aa622f7020a..99110614b808f43d2f4ad75681f5b87be7b2336c 100644 GIT binary patch literal 12879 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 PWDunXD)L|DjQsu=RC4bl literal 10700 zcmdUVc{r49-~VVM5$+^eZz?Kd$&#HyR1Age5?Qh@k=<05ND@N!Qg%kR8N2K>#?pkC z8M2IRGInF1_nhwgd5-t_z0ZH|dmQikyZ*pou4~TaI?vDdvz$?PbhVfnxfmf32=lF* z8u}2(;o}ep9UsFX@E_f(-T?^YPslBe>xO>!7YSEfa7G7TR+7`rWrz8Ez6elnc|Cg- z&t!4+0%JebR*|b$JE)PVmv!_rz362+`kTk@g&x*;+S9JijN(dfmPv1qwzTu2%iDZ% zlqV2+#~iCF_kQ|9@=R~?-isGXlAkp0zUDF5q)2goi;WHXwADj7x2=&8xH1_Idh(Q2 zEplxP{PE?irrQw+@2eCX>tERAVsP{tvpQeGiQ#t4hJgoua;Z%h8OXYYoW-fu7~FccCJGSu+jSuYTd z*UeLATS1y!%bA**!r^eMK1zK2oSa*$Xz{^cZs335`2iooDZ>hFG#XuCSZE#O?fsoM zZjbxIFvhjI503U*KriNKWJ>#eakw3Bu7JV06ONvJm4wn8=x-Wd#A!i zRD^l_Tj5|Kf>dUrb3+H~4THZhD|W?+h=_dr`0>Pv6NP&1Y?b&#W*KKrKFrIiV(FmW z;|BWo@<_G0j;o71JGFI#+cM_<-bcMYMqW<5O@?n6f?qjIt(=^k3|lYWjzrj*szv%K zjTPI{T8nA7@fy<*{NR{s&3Q0&6Cx9c_N$Q5=&ZueGl%1^|J8yvR=ULSGN!lpD~g_; zK9*lK1Qppz_@-ZAC>STfG}Xxu4??kz_Inv${a$SCCoKZTySyl@(+zI8$o{?kgW=`D zUutj7D-yMgAJpGvcXf3=E}$fQKQuIS#Si~@w;*)1#1JcuLpI#?PJH4UpjBz^=%J1E z2?q1!>ucO7ns_@it%lCq66I=+iGEU5C!&~5xE+d%HE)eCuU(E|%sX6jmwk}5;ip87 zVPuQ#ByH5njtaQm3-Iu`b2;(Yv13Xr4{{xI$Gx)rWTL04tE#YyIVHEvkcO!5?+*gD-a}9 z)rTiC&Ddr3gwG(T`qb?hSKN}nYMot<8Ut2(@WJb6&z{+o&AmO*tc>VtKw>84+`ua~ zu9UVMHa0Q>?df3O9=_93;ffny6Zn)wTWXz_k_p}5UHRt8BFFcE(euPIcSrZF67+5>I@6iK@0GMny(N?KXE0NDH+g`#T#WBO}et%>fN=srJiVoo}9toNoMh z4T3KJF5@u4l{CjPX?t{OeGVn<=;7gEXO}~~ac=OCEAGCjssH-iKugPW6zeEky~xM$ z5X0`HWr4D8ELoXvRU_C>iWKX7}M*mSTVt}h6g6PxYJqV6xj;S()K zmyT%g4aa1YFln-VS*p}U)OZ*xfAIPM|H1MLJ(cZGd3i5Ru|XnpL1R38d}t`wT0~K)%}HkF`C4+w8MSIsB+{zAo-y@)ScTh+5=>iy!h%OU+fD*NkL z&{yg>b$=Y4EUvmU_i=3OK3lfIqkPjd*gF+&?XZ#v1SvJQ8wDC_)|+9f;R48p-;{7Z zuuk`I1G^5NrA>oL{RrzLs*3lNZA}>lmM<-d$^<$Us`8a1?Ay)U-WOhpyZI>9p0mT) zD)_=u?s0(wFbnaVbk~w=JtkWC!JJsZ_cy>A;D_(6)I6Rwd&0;pL$cv=`cdNd_3iB( zwGZ#bPUh$rNStw0Ludl@MJe~B!a0Svc@IiTLIxmKP7_f#DXl#=w}e?qPVQpj?Zbx;t3?`@-ajsYr{vK=EN}DmSTzI;8s#k? z(9q6c|48XK4;gz0hruPw+PW4R*7-Ubx8A;y;OgreDLi?8sX%5=BaC!vJue37DqGh) z!a=DPq#UBPK|IDNpo5i$88q^7a$e+!R*P(HRTpRz&I($6auRY46;Hp`+S;0wp{5m} z?2C%;w!NJAwGPWofyMGE>#KUqpAB&4j0gy}WfnOtpwM>86O4r?qp`eva*V#ptmJ+v zT1hrVhfF3H-jd95edmWn)37c?T2%H=hL_v9V;G&Px!f`lp9#~&A0iSX=2`XHZp~<_McR}-;_LuhXiv_m%B;#vlq1^9 z>c3*%qpAofT7UR>xbv%bs(w7rW$$dIzQ=8^3Hx`Rg7mYIL;XGS`s42F`2bY9kcN5v z>eVOxOL}MfoLt=9;ZK{Dn{i@?6x&#Sg*`qee-bT?iHbT-BRV|*8UseJ3&xq4m`K1X z%t|_9cPc|cM@oza&9@_u>V4KP$ajv)I9>k?@>J?VwZYuY(!4gCGPMs6I6Elg@THV# zQ?Ta%p#9YQpdjLhJ4c+(+W&D$U0pphvPs7KtLN~>uMsJMw%IH=IRgTjQ)}8=jb@#k zY>ys0zBExCnEghuoGZg8!0RJ63@||5gsH9=k08zgz!(2JtTCXTE}b!1%yKm%Y-@Wq zE1XqPQIY87@8HmhTy(jrC@=57I4WcMz{TZPcY^S$k6>IE(aV>Nzgtlk6BA=sF;Y-) zN$(CutOSABq)=pEv9Pezor||n*BGLIWIXRZN+WJyw-+Hlab*UUrRG}JJ#qE&DsO5U zR~Fapr+*}hxgBuw4te3*{QCNOWpOW@#~|)$VyEdfH*W=37Z(NrD4L6p@4lra;6Rd% zNMusqEOisr1k=+)qfl;y)RdGO|FvAGguMJEE7jng_2y9eBs)SA+)9^G9V51}u^|&J zYp$+gTG24n{6t1oRaHiY=*Ggrr{wXQv)P$yYion$9vvNBnB3mI11Y(nbL$>qdfFDs zk>C#Bnt1W^p>9QD=h^F^Ki!|&%Awn4`wzz(0*8Z{7M5sN-|SkAg>F(5jiNO+s=%EiEmuNn)%xMloW zyiM6VSKQdeWkfHssGy(#gTZ8E@NRF8H3Vjwqv&#TbAhs16MU|KGsANwy&Vj9S9_}A z<{iPq!;_!jf&z{2?+5F7z~NNzM2$u7DHbEKWbuZ?zFG4QPeyN~WxGuo_*$Onspk<-`299Bt+`sr2i314Z>e zqQaOmQ#f@uO97I)_s=10!D4gZ&_trizMlvFy&y&TDIHQc_Y2k*q3FWl(gmT5g2c zPN>|5!VknJ3$bL3J(2S6Q2wS+Q{E=QcU)9VEZ~HIjlvHz!|s}z8nE)m>;17=X9EiZ zSEr-kCV%_{3kf;xRWmp^=vAY1^{P-7)N6W4sqgnygj((9&-{tUTbR%8&*}5J7=LYj z!O{S@(%3XnaGUA8yMRWIXJwKJ^s2J5Xj3}Clmf8~U2!q7Z@R3%@X=?)>#w9&I`m~8 z7f_+@Jzfe+SZ+UKa3^mL2j(Gp^^RR|lcC=V#o#c8;)--!DPROV6?KEH06 zH{}0>#{54ec>gCm6RF`=Sy!j1q7ni)skef%ib`WuRgMrdGjmCCarM`iMaHFWuC6)U zo@Wd?Iy;;8H_hSwQcGmATSc|7pg+gOnAq69-rj)cNp?AwXk(En1PM@EtB~y+DE89B zhYta-sZ#Zuw*&x=naqrwHhnLB_3Gx&=EHjZ<;B_vVo@R}F@TxMXZ4{a=M=zg;34?I zT9&wFEx0px^I_}E`6=I}F(2{kGE92@m;CNtUIpuCD~&(<&j+&p0H%@a$xVB9j~`c9 zU-8ut9l==YM~%`gRM#opd+_K{7vX|`fI7u#Z=)1`uV`XP`d(WBt{vQB=kI~cb9f>}-QF0$_BZ{=-d z33SBph6yxRFxRm*w@H1_4!8OB>({xtxt5leL=oe9qJoo`*Xj%=ZNb&b%Bo_kqa%W~ zrM!4zVq$Rc9z}B-)7Pg5gVmt7STtW2qRWeOa&o|D?d|Q(!w7%0K+Dk3(CYTy_`xP> ze%^8W2`F`WSt0QT`UP*% z+1`A?AHtwAbENWY(;Uxxm21g)0ZG6p!AiU04i<_^mF&Jd&D8=45LDOL$hUU|S;aN5 z#C$kC=r_5=2-3LirB(@`g%3T6*Rg}5|4?h2T6r3eX|uVK$a1t3SE!Ax)Gzq7N(8#I zGnT)}ylnzOqcMLRZSSeQg~!QDOQj_x z4YWs!nwpwQOU1MLirh|HPLK(80N^e=&o3=CJ)V7?y5O#>uaMC@yT;AUJ;7~WaihS` z$|@_@aXV;ie15Vmd;|v8NCqIhsj2bq%B}?|Pp?j$$vFI-es0yUFaG9vX_ypKYZf;c z4B*nF+Mu-CIgNX(Xy0h*{vjugCRrwr7RvYO8%lbOfb4R{cA`)yLbKZk($3~4vX;-} za-!js^Q~bY98z!3Y;r&c26J_DD~#>~1=K*RHtBawBX5N}^YHtlTZ83=X()^)c64;q zpBmGHasai?eWOhp4=Wc9SGC}QX`H;n--yOaW2hYWH3plTueUnO-@f)ZewLj1OpERi#|6_Qa5pGpzK60ujkr1eNa9oS z``pwdZdJ$qB}Y3sQ^|kTZRC!i*VCOZmYH^@xsLXdXZ7kQoO*hD3thb_q4VB5kNnNo z16v`&L3$;op?3m%v(`qDyg{*2=l`bmt-y@2v$Jz{MoYu|wd9p>$bA^H0{>AKZ>*8l z-kO%0YG!6OipN8f(bi&7bt6c^GKX;XrMR2GN5z#FX3u%}ra$l-oJ0l`zN2jKzquPqKO$Y{i!I8y6zP7x4);GaFgLKl!LkT2Z4}i z>hur0g{*5i3@il|0HbnpCZ)qLEEC`7p*MD>Wb}t9)W`0O-ndCfSLKiUv~%zJQI6sYN1pDNE>5 zS@h$bDo`eJF38-kvXiRwUz$V+!KY2`xX{Txer^S z_iawIdD^lVFl=%Kw*uiO;T(8 z^N^n!8k>*}w0IMPfY|-|xr}AL*Hzq%;(|p3rg@iT6=bs0ff+yQ!&Afdy6<>w`!NV4 zlKuaP8~;B^PX5<}hmW1yUmULh#xmV~YU64ernjeOePg2=1vc1!(W3%w05iWsn?nw^ z9R`Br)gsHv%DfeVXM1@m7D;xNzz*~AsRA04HyP9guEX=6*Vw2Sm83xp`e61%V1H8UtbjH0N?Pt#4NO^tKF+F`dmqR)Glg z;U3WN1&9KCL!hs{{S079tFG|hmr7P2(Q8%bE}z`a&d&6&cva5NJf@o1%0LPk=*aFv zpsWG;v+83GzCEs7X^0EPp+h=zfg7N{^sGzA9Dd~epPt>FXsSLO!m^`lSSh5E4&*=C!4pUvwREmr7JE< zqlH_!sJ4vmE!r+c`?vtW{#yP#>0)0;$4klR?qPBXhnmOBqfsQyyp;O0;)HsCsSI5} z+q%UcRlm5#C;+G`;23)jmUJ!Rv%MLLzykS0Er0569iDr#_gQMY=Me&qHesxjq|&A# z>5`^_Gw*wI-CQ6}&?i^ZVCVlh2)))CK){<5I<1emdlKf}8d!Dutxk7i^Yrra^1@ju zOXI-NpuK`HM-TypgoN1J=MtvWx`;rux?B}0a_cUKQvC0a%m~aZrlc|?!b1~V2M_jTH_%sz{BbZZkCU`+0)b0 zRgrHYhN`VK6HD&w=$H=G1m7?is@Za)DgAfhfc5-C8$T2Lt&QJ3zFnEaZ65uHJ!p5D zm^~<@hmo(St)&CiV19lc*eR_ns(wQL3$Q#asHDFFjwn(l+fTSN2``RRIH*PTsZ#NZ z6YSfxTEj-Y&iv+)s004eBglX9+ak|rK9ywjS5@UkEOy$lv$8v~Gj&Z#qF zW0|xvt2w+OVvOjz1>C<{MC_|q`7OZh1@RpSf-Yw(1@C<4{=+6HXzy#HNG&4pIY>>( zU8}2JmlK^h`FVMLv_9GU)Hw9nO19eox4R34xe8WEk?Hg9+i9X&3|CZCGIfN&XtZfy z2rN1xkx1RnqI!1HLGm=O4fn@o8g96)_ys+9aLq?LQ+KF=tJ}8x&c&|5WlHT^y=In?TT@#075VvzArFs@%3Bf$ixsWp&O z)yjdmKq=XT%gI?rV_I8b|oA-R1b}io_K2%7Rx?frS(z0uJ-SUk5Y3f&9ptvO?$Udc#6(Z-r^ z9@3S5{1sC-Eh7D5zw!oO;qLCv9TBG^WbS5vQy}>xX$Oe$p`j$l)YaDo-*LEIU`l}a z3{`J)91>X#{yHH5vNrQ4%)IlrU|7S$&XOrQIr{#-0aJVn|4dNjNqW z(o+7TM+Ps3v(myHknsRFn#gMext3fGC4nSvZ+i`V;E6_jIHx@SZ<#;;U(BDKsEf?` zJRB3o+HNx-@rppOOgTQ}R0Z6AC~r#u!DmG$k{=P?U>qp4$V~#)waZ*LRecJ zJkZMTc?gm)cXvIZ#OAcK_q&KpCr=`Zi~Uwd9?$j$Z;m)1U8y^yQd%d&Pn^LUfP`lP zaQLQ!og&sr5Em-?lG7gz%6NYgPP`Sxnyp`8TQLHL`gTc#lsWigY;2Q7I{+THXlw3t zPB#8yx(+t|-Mi1OiV58yh0S+3e*TZB@bIHpX%N8f5gaau8UIDzMfe~5JZ^M35n0}3 zk2mI>TJbA0d5im_K4l`@s#kVAXo~sx01g)j(!ykME0w^_UwZHzEO0^=MCl-rpU;Tj z-<#s6vZ`5Bdwf8ljE{xZMZ8}BbQ{V6^6LoeF7duPf1`6LI$}`hmO(y+ZAJI$j~eih z-@{IK;0>KxS*p?9e&gdalqTz*sR|dPUjZ4a7JRFfUuAnbAv2TDe-$*7`mZS}aTp6e zJ>@fyUm^Id?uM<50?F3vTo`4Qh=%WztjL`YAt34mua(Bb&aw~0bj8$u0S(-5_#OL# zU@QJSB(faDjua3t0M)a($=68~41)Y-&aXd@Ptb#NHYff%XyY36f}j7#KOeT{%quZ9+%0nr1m1$TcjXAypjHjtSMlMg<;-vlOl^_)x52eZ zwQVRg9`=D@r*R;6`RQ=_mgVL*9Q6&j6AM92=}Zl2)E>sM?u@Y%y2uZhKqqIy!Us?%vAL2ZT!E6>TFC^esOU zXGiXQ5p&KbrG|~7qcqg8(ybDEv|@3Yoe}U*fZA(H9ZzBE>sQ7uz69qx!dNrccU9N-e*$N?7 zS~pZwR4f>)5X>`l^KiGfSWWQ;(b@J|%o|nXU3Uv-~WNc zO$Y=C+O4uc=EcKPJWR@UJjRmmqWSt1yBY{{mlhYhvBf_NTLCi%Ct?y46D1t{)EK}? zm>ic0uEjZ)OwVTigA`X){Vr3(y7+N}z`qZ`+@UZWDD}A{yh(}qC-}0#cSr@kfq^(x z=YAv@SHI zyEkrka64s#ytwGzhLH-i?NqVhW$WHEdZ?c))E*@Ng&t_3rDJN6j!>HNxjgeD@J#6_ z6R6QecBa;4YD9hB*zfSTe=vqlbS2O!Z~V8bL7k0Fb+eeo7IIT=$RZw}neT{2aSxvr mj{JQ_u-U}r|F1;nfM2CU-71Q@UI+ROxphNV1EKcd`F{X#{QU<2 diff --git a/components/lvgl.rst b/components/lvgl.rst index 66c35dc8c..6d5df25be 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -242,7 +242,12 @@ The outline is drawn outside the bounding box. You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each object. Some widgets allow for more complex styling, effectively changing the appearance of their parts. -- **align** (*Optional*, enum): Alignment of the of the widget `relative to the parent `__. One of: +- **align** (*Optional*, enum): Alignment of the of the widget relative to the parent. A child widget is clipped to its parent boundaries. One of the values *not* starting with ``OUT_`` (see picture below). +- **align_to** (*Optional*, enum): Alignment of the of the widget relative to another widget on the same level: + - **id** (**Required**): The ID of a widget *to* which you want to align. + - **align** (*Required*, enum): Desired alignment (one of the values starting with ``OUT_``). + - **x** (*Optional*, int16 or percentage): Horizontal offset position. + - **y** (*Optional*, int16 or percentage): Vertical offset position. .. figure:: /components/images/lvgl_align.png :align: center From 52585f83cb070f7e31c4ae68c50061409f283252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 24 Jan 2024 10:05:50 +0100 Subject: [PATCH 141/350] state templatablle in cook --- components/lvgl.rst | 29 +++++++++++++---------------- cookbook/lvgl.rst | 19 +++++-------------- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 6d5df25be..862934adf 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -226,7 +226,7 @@ See :ref:`lvgl-cook-theme` in the Cookbook for an example how to easily implemen Style properties ---------------- -LVGL follows CSS's `border-box model `__. An object's "box" is built from the following parts: +LVGL follows CSS's `border-box model `__. An object's *box* is built from the following parts: .. figure:: /components/images/lvgl_boxmodel.png :align: center @@ -236,22 +236,12 @@ LVGL follows CSS's `border-box model `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background of the widget. - **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to make the background gradually fade to. @@ -342,10 +332,17 @@ The properties below are common to all widgets. Similarly to CSS, LVGL also supports ``min_width``, ``max_width``, ``min_height`` and ``max_height``. These are limits preventing an object's size from becoming smaller/larger than these values. They are especially useful if the size is set by percentage or ``size_content``. -- **min_width** (*Optional*, int16 or percentage): Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. -- **max_width** (*Optional*, int16 or percentage): Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. -- **min_height** (*Optional*, int16 or percentage): Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area. Defaults to ``0%``. -- **max_height** (*Optional*, int16 or percentage): Sets a maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. +- **min_width**, **max_width**, **min_height**, **max_height** (*Optional*, int16 or percentage): Sets a minimal/maximal width or a minimal/maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. +- **align** (*Optional*, enum): Alignment of the of the widget relative to the parent. A child widget is clipped to its parent boundaries. One of the values *not* starting with ``OUT_`` (see picture below). +- **align_to** (*Optional*, list): Alignment of the of the widget relative to another widget on the same level: + - **id** (**Required**): The ID of a widget *to* which you want to align. + - **align** (**Required**, enum): Desired alignment (one of the values starting with ``OUT_``). + - **x** (*Optional*, int16 or percentage): Horizontal offset position. Default ``0``. + - **y** (*Optional*, int16 or percentage): Vertical offset position. Default ``0``. + +.. figure:: /components/images/lvgl_align.png + :align: center + - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused widget which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. - **styles** (*Optional*, :ref:`config-id`): The ID of a *style definition* from the main component configuration to override the theme styles. - **theme** (*Optional*, list): A list of styles to apply to the widget and children. Same configuration option as at the main component. diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index dda4841a6..2ba4ebed6 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -54,7 +54,7 @@ If you have a display device with a local light configured, you can simply creat .. _lvgl-cook-binent: -Remote light switch +Remote light button ------------------- If you'd like to control a remote light, which appears as an entity in Home Assistant, first you need to import the light state into ESPHome, and then control it using a service call: @@ -67,19 +67,10 @@ If you'd like to control a remote light, which appears as an entity in Home Assi entity_id: light.remote_light on_state: then: - if: - condition: - lambda: return x; - then: - - lvgl.widget.update: - id: light_btn - state: - checked: true - else: - - lvgl.widget.update: - id: light_btn - state: - checked: false + lvgl.widget.update: + id: light_btn + state: + checked: !lambda return x; lvgl: ... From d3d80943d0f049f881ea6bfc4af4b7b38f382c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 24 Jan 2024 11:52:52 +0100 Subject: [PATCH 142/350] updates --- components/images/lvgl_align.png | Bin 12879 -> 10052 bytes components/lvgl.rst | 3 ++- cookbook/lvgl.rst | 12 +++++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png index 99110614b808f43d2f4ad75681f5b87be7b2336c..fccf53c377f219d1b121128f5456547f134cd9ad 100644 GIT binary patch literal 10052 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 literal 12879 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 PWDunXD)L|DjQsu=RC4bl diff --git a/components/lvgl.rst b/components/lvgl.rst index 862934adf..ab35aaa57 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -360,7 +360,8 @@ The properties below are common to all widgets. - **edited** (*Optional*, boolean): Edit by an encoder - **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): Custom states -By default, states are all ``false``. To apply styles to the states, you need to specify them one level above, for example: +By default, states are all ``false``, and they are templatable. +To apply styles to the states, you need to specify them one level above, for example: .. code-block:: yaml diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 2ba4ebed6..f623f7845 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -110,11 +110,11 @@ We can use a sensor to retrieve the current brightness of a light, which is stor sensor: - platform: homeassistant id: light_brightness - entity_id: light.your_room_dimmer + entity_id: light.your_dimmer attribute: brightness on_value: - lvgl.slider.update: - id: slider_dimmer + id: dimmer_slider value: !lambda return x; lvgl: @@ -123,7 +123,7 @@ We can use a sensor to retrieve the current brightness of a light, which is stor - id: main_page widgets: - slider: - id: slider_dimmer + id: dimmer_slider x: 20 y: 50 width: 30 @@ -135,17 +135,19 @@ We can use a sensor to retrieve the current brightness of a light, which is stor - homeassistant.service: service: light.turn_on data: - entity_id: light.your_room_dimmer + entity_id: light.your_dimmer brightness: !lambda return int(x); Note that Home Assistant expects an integer at the ``brightness`` parameter of the ``light.turn_on`` service call, and since ESPHome uses floats, ``x`` needs to be converted. +This is applicable to service calls like ``fan.set_percentage``, ``valve.set_valve_position`` too, only difference is that ``max_value`` has to be ``100``. + .. _lvgl-cook-volume: Media player volume slider -------------------------- -Similarly, you can use a :ref:`slider ` or an :ref:`arc ` to control the volume level of a media player. +Similarly, you can use a :ref:`slider ` or an :ref:`arc ` to control the volume level of a media player, which uses float values. .. figure:: images/lvgl_cook_volume.png :align: center From 2f750fdc92a71dc5357c51cbcac249786f02a524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 24 Jan 2024 12:05:06 +0100 Subject: [PATCH 143/350] Update lvgl_align.png --- components/images/lvgl_align.png | Bin 10052 -> 11381 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png index fccf53c377f219d1b121128f5456547f134cd9ad..090cbc25873e4003ce033442f41a86387ff64ed9 100644 GIT binary patch literal 11381 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 From 2e5c898edd2c118855890b8e610e591dbfb205eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 24 Jan 2024 14:01:43 +0100 Subject: [PATCH 144/350] Update lvgl.rst --- components/lvgl.rst | 50 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ab35aaa57..4a7105caf 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -300,7 +300,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` - **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) -- **text_font**: (*Optional*, :ref:`font `): The ID or the C array file of the font used to render the text. +- **text_font**: (*Optional*, :ref:`font `): The ID or the C array name of the font used to render the text. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. - **text_line_space** (*Optional*, int16): Line spacing of the text. - **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. @@ -1295,24 +1295,52 @@ Fonts TODO -LVGL internally uses fonts in a C array. The library offers by default the following ones preconverted: +LVGL internally stores fonts rendered in a C array. The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: +- ``montserrat_8`` +- ``montserrat_10`` +- ``montserrat_12`` - ``montserrat_12_subpx`` +- ``montserrat_14`` +- ``montserrat_16`` +- ``montserrat_18`` +- ``montserrat_20`` +- ``montserrat_22`` +- ``montserrat_24`` +- ``montserrat_26`` +- ``montserrat_28`` - ``montserrat_28_compressed`` -- ``dejavu_16_persian_hebrew`` -- ``simsun_16_cjk16`` -- ``unscii_8`` -- ``unscii_16`` +- ``montserrat_30`` +- ``montserrat_32`` +- ``montserrat_34`` +- ``montserrat_36`` +- ``montserrat_38`` +- ``montserrat_40`` +- ``montserrat_42`` +- ``montserrat_44`` +- ``montserrat_46`` +- ``montserrat_48`` -These may not contain all the glyphs corresponding to certain diacritic characters. You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. - -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. - -In addition to the built-in fonts, the following built-in symbols are also available from the `FontAwesome `__ font. You can use them on supported widgets using the ``symbol`` configuration option: +You can display the embedded symbols easily on supported widgets using the ``symbol`` configuration option: .. figure:: /components/images/lvgl_symbols.png :align: center +.. note:: + + The ``text_font`` parameter influences the size of the symbol, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes + +In addition to the above, the following special fonts are available from LVGL as built-in: + +- ``unscii_8``: 8 px pixel perfect font with only ASCII characters +- ``unscii_16``: 16 px pixel perfect font with only ASCII characters +- ``simsun_16_cjk``: 16 px font with normal range + 1000 most common CJK radicals +- ``dejavu_16_persian_hebrew``: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms + +TODO !! You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. + +In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. + .. _lvgl-objupd-act: From 2cc8c98ca947f41515dacbee0a33f0102bbaf9b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 24 Jan 2024 14:12:11 +0100 Subject: [PATCH 145/350] Update lvgl.rst --- components/lvgl.rst | 50 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4a7105caf..f52831391 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1297,29 +1297,29 @@ TODO LVGL internally stores fonts rendered in a C array. The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: -- ``montserrat_8`` -- ``montserrat_10`` -- ``montserrat_12`` -- ``montserrat_12_subpx`` -- ``montserrat_14`` -- ``montserrat_16`` -- ``montserrat_18`` -- ``montserrat_20`` -- ``montserrat_22`` -- ``montserrat_24`` -- ``montserrat_26`` -- ``montserrat_28`` -- ``montserrat_28_compressed`` -- ``montserrat_30`` -- ``montserrat_32`` -- ``montserrat_34`` -- ``montserrat_36`` -- ``montserrat_38`` -- ``montserrat_40`` -- ``montserrat_42`` -- ``montserrat_44`` -- ``montserrat_46`` -- ``montserrat_48`` +- ``montserrat_8``: 8px font +- ``montserrat_10``: 10px font +- ``montserrat_12``: 12px font +- ``montserrat_12_subpx``: 12px font +- ``montserrat_14``: 14px font +- ``montserrat_16``: 16px font +- ``montserrat_18``: 18px font +- ``montserrat_20``: 20px font +- ``montserrat_22``: 22px font +- ``montserrat_24``: 24px font +- ``montserrat_26``: 26px font +- ``montserrat_28``: 28px font +- ``montserrat_28_compressed``: 28px font +- ``montserrat_30``: 30px font +- ``montserrat_32``: 32px font +- ``montserrat_34``: 34px font +- ``montserrat_36``: 36px font +- ``montserrat_38``: 38px font +- ``montserrat_40``: 40px font +- ``montserrat_42``: 42px font +- ``montserrat_44``: 44px font +- ``montserrat_46``: 46px font +- ``montserrat_48``: 48px font You can display the embedded symbols easily on supported widgets using the ``symbol`` configuration option: @@ -1328,13 +1328,13 @@ You can display the embedded symbols easily on supported widgets using the ``sym .. note:: - The ``text_font`` parameter influences the size of the symbol, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes + The ``text_font`` parameter influences the size of ``symbol``, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. In addition to the above, the following special fonts are available from LVGL as built-in: - ``unscii_8``: 8 px pixel perfect font with only ASCII characters - ``unscii_16``: 16 px pixel perfect font with only ASCII characters -- ``simsun_16_cjk``: 16 px font with normal range + 1000 most common CJK radicals +- ``simsun_16_cjk``: 16 px font with normal range + 1000 most common `CJK Radicals `__ - ``dejavu_16_persian_hebrew``: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms TODO !! You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. From ca6636313157ac1a4fb257d3b87764b060a6151a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 24 Jan 2024 15:10:20 +0100 Subject: [PATCH 146/350] Update lvgl.rst --- components/lvgl.rst | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f52831391..4eb1c7358 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -300,7 +300,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` - **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) -- **text_font**: (*Optional*, :ref:`font `): The ID or the C array name of the font used to render the text. +- **text_font**: (*Optional*, :ref:`font `): The ID or the C array name of the font used to render the text or symbol. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. - **text_line_space** (*Optional*, int16): Line spacing of the text. - **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. @@ -447,6 +447,10 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply. + **Example:** .. code-block:: yaml @@ -457,7 +461,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can y: 10 id: arc_id value: 75 - min_value: 1 + min_value: 0 max_value: 100 adjustable: true @@ -470,6 +474,13 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can bg_color: 0x00FF00 value: 55 + # Example trigger: + - arc: + ... + on_value: + - logger.log: + format: "Arc value is: %.0f" + args: [ 'x' ] The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. @@ -581,7 +592,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **rows** (**Required**, list): A list for the button rows: - **buttons** (**Required**, list): A list of buttons in a row: - **id** (*Optional*): An ID for a button - - **text** or **symbol** (*Optional*): Text or built-in symbol to display on the button. + - **text** or **symbol** (*Optional*): Text or built-in :ref:`symbol ` to display on the button. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1``. E.g. in a line with two buttons: btnA, width = 1 and btnB, width = 2, btnA will have 33 % width and btnB will have 66 % width. - **selected** (*Optional*, boolean): Set the button as the most recently released or focused. Defaults to ``false``. - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): @@ -801,7 +812,7 @@ A label is the basic widget type that is used to display text. **Specific options:** -- **text** or **symbol** (**Required**, string): The text or built-in symbol to display. To display an empty label, specify ``" "`` (space). +- **text** or **symbol** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``" "`` (space). - **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) @@ -1022,7 +1033,7 @@ The text will be broken into multiple lines automatically and the height will be - **text** (**Required**, string): The string to be displayed in the body of the message box. Can be shorthanded if no further options are specified. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. - **buttons** (**Required**, enum): A list of buttons to show at the bottom of the message box: - - **text** or **symbol** (**Required**, string): The text or built-in symbol to display on the button. + - **text** or **symbol** (**Required**, string): The text or built-in :ref:`symbol ` to display on the button. **Specific actions:** @@ -1130,6 +1141,10 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply. + **Example:** .. code-block:: yaml @@ -1141,7 +1156,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking width: 220 id: slider_id value: 75 - min_value: 1 + min_value: 0 max_value: 100 # Example action: @@ -1153,6 +1168,13 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking bg_color: 0x00FF00 value: 55 + # Example trigger: + - slider: + ... + on_value: + - logger.log: + format: "Slider value is: %.0f" + args: [ 'x' ] The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. @@ -1563,7 +1585,7 @@ See :ref:`lvgl-cook-idlescreen` example how to implement screen saving with idle Widget Event Triggers --------------------- -ESPHome implements as triggers the following LVGL events: +ESPHome implements as universal triggers the following LVGL events: - ``on_press``: The widget has been pressed. - ``on_long_press``: The widget has been pressed for at least the ``long_press_time`` specified in the input device configuration. Not called if scrolled. @@ -1576,7 +1598,6 @@ ESPHome implements as triggers the following LVGL events: - ``on_scroll``: The widget was scrolled. - ``on_focus``: The widget is focused. - ``on_defocus``: The widget is unfocused. -- ``on_value``: TODO!! These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself supports generating such events. From 7ef45887a4c812e70df9dc57a285ab27e8d54737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 24 Jan 2024 15:11:31 +0100 Subject: [PATCH 147/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4eb1c7358..de993aabc 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1323,7 +1323,7 @@ LVGL internally stores fonts rendered in a C array. The library offers by defaul - ``montserrat_10``: 10px font - ``montserrat_12``: 12px font - ``montserrat_12_subpx``: 12px font -- ``montserrat_14``: 14px font +- ``montserrat_14``: 14px font (**default**) - ``montserrat_16``: 16px font - ``montserrat_18``: 18px font - ``montserrat_20``: 20px font From ee199b4c49f46cdc58112b225718e37317ad268e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 24 Jan 2024 16:33:13 +0100 Subject: [PATCH 148/350] Update lvgl_align.png --- components/images/lvgl_align.png | Bin 11381 -> 13085 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png index 090cbc25873e4003ce033442f41a86387ff64ed9..8472a39bee8c832fcac5d7f69f75f3525a39c201 100644 GIT binary patch literal 13085 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 DP5`() literal 11381 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 Date: Wed, 24 Jan 2024 18:31:41 +0100 Subject: [PATCH 149/350] Update lvgl_align.png --- components/images/lvgl_align.png | Bin 13085 -> 13120 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png index 8472a39bee8c832fcac5d7f69f75f3525a39c201..bfe20a56b00b5b96228792ad6b260d1ff7d81725 100644 GIT binary patch literal 13120 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 DP5`() From a85432fcfa9cefa7f0c0155c60522536773603d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 25 Jan 2024 10:02:15 +0100 Subject: [PATCH 150/350] Update lvgl.rst --- components/lvgl.rst | 98 +++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 52 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index de993aabc..24d38c2fd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1322,7 +1322,6 @@ LVGL internally stores fonts rendered in a C array. The library offers by defaul - ``montserrat_8``: 8px font - ``montserrat_10``: 10px font - ``montserrat_12``: 12px font -- ``montserrat_12_subpx``: 12px font - ``montserrat_14``: 14px font (**default**) - ``montserrat_16``: 16px font - ``montserrat_18``: 18px font @@ -1331,7 +1330,6 @@ LVGL internally stores fonts rendered in a C array. The library offers by defaul - ``montserrat_24``: 24px font - ``montserrat_26``: 26px font - ``montserrat_28``: 28px font -- ``montserrat_28_compressed``: 28px font - ``montserrat_30``: 30px font - ``montserrat_32``: 32px font - ``montserrat_34``: 34px font @@ -1363,11 +1361,13 @@ TODO !! You can generate your own set of glyphs in a C array using LVGL's `Onlin In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. +Actions +------- .. _lvgl-objupd-act: -``lvgl.widget.update`` Action ------------------------------ +``lvgl.widget.update`` +********************** This powerful :ref:`action ` allows changing on the fly any common :ref:`style property ` or :ref:`flag ` of any widget. @@ -1391,8 +1391,8 @@ This powerful :ref:`action ` allows changing on the fly any commo .. _lvgl-objupd-shorthands: -``lvgl.widget.hide`` and ``lvgl.widget.show`` Actions ------------------------------------------------------ +``lvgl.widget.hide``, ``lvgl.widget.show`` +****************************************** These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget: @@ -1405,8 +1405,8 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` - lvgl.widget.show: my_label_id -``lvgl.widget.disable`` and ``lvgl.widget.enable`` Actions ----------------------------------------------------------- +``lvgl.widget.disable``, ``lvgl.widget.enable`` +*********************************************** These :ref:`actions ` are shorthands for toggling the ``disabled`` state of any widget (which controls the appearance of the corresponding *disabled* style set of the theme): @@ -1423,8 +1423,8 @@ These :ref:`actions ` are shorthands for toggling the ``disabled` .. _lvgl-rfrsh-act: -``lvgl.widget.redraw`` Action ------------------------------- +``lvgl.widget.redraw`` +********************** This :ref:`action ` redraws the entire screen, or optionally only a widget on it. @@ -1441,8 +1441,8 @@ This :ref:`action ` redraws the entire screen, or optionally only .. _lvgl-pause-act: -``lvgl.pause`` Action ---------------------- +``lvgl.pause`` +************** This :ref:`action ` pauses the activity of LVGL, including rendering. @@ -1455,8 +1455,8 @@ This :ref:`action ` pauses the activity of LVGL, including render .. _lvgl-resume-act: -``lvgl.resume`` Action ----------------------- +``lvgl.resume`` +*************** This :ref:`action ` resumes the activity of LVGL, including rendering. @@ -1469,8 +1469,8 @@ This :ref:`action ` resumes the activity of LVGL, including rende .. _lvgl-pgnx-act: -``lvgl.page.next`` and ``lvgl.page.previous`` Actions ------------------------------------------------------ +``lvgl.page.next``, ``lvgl.page.previous`` +****************************************** This :ref:`action ` changes page to the next following in the configuration (except the ones with ``skip`` option enabled), wraps around at the end. @@ -1495,8 +1495,8 @@ This :ref:`action ` changes page to the next following in the con .. _lvgl-pgsh-act: -``lvgl.page.show`` Action -------------------------- +``lvgl.page.show`` +****************** This :ref:`action ` shows a specific page (even the ones with ``skip`` option enabled). @@ -1517,11 +1517,13 @@ This :ref:`action ` shows a specific page (even the ones with ``s - lvgl.page.show: secret_page # shorthand version +Conditions +---------- .. _lvgl-idle-cond: -``lvgl.is_idle`` Condition --------------------------- +``lvgl.is_idle`` +**************** This :ref:`condition ` checks if LVGL is in idle state or not. @@ -1540,8 +1542,8 @@ This :ref:`condition ` checks if LVGL is in idle state or not. .. _lvgl-paused-cond: -``lvgl.is_paused`` Condition ----------------------------- +``lvgl.is_paused`` +****************** This :ref:`condition ` checks if LVGL is in paused state or not. @@ -1558,32 +1560,13 @@ This :ref:`condition ` checks if LVGL is in paused state or no id: display_backlight transition_length: 150ms -``lvgl.on_idle`` Trigger ------------------------- - -LVGL has a notion of screen inactivity, i.e. how long did the user not interact with the screen. This can be use to dim the display backlight or turn it off after a moment of inactivity (like a screen saver). Every use of an input device (touchscreen, rotary encoder) counts as an activity and resets the inactivity counter. - -The ``on_idle`` :ref:`trigger ` is activated when inactivity time becomes longer than the specified ``timeout``. - -- **timeout** (**Required**, :ref:`templatable `, int): :ref:`Time ` value after which LVGL should enter idle state. - -.. code-block:: yaml - - lvgl: - on_idle: - timeout: 30s - then: - - logger.log: "LVGL is idle" - - lvgl.pause: - - light.turn_off: - id: display_backlight - -See :ref:`lvgl-cook-idlescreen` example how to implement screen saving with idle settings. +Triggers +-------- .. _lvgl-event-trg: -Widget Event Triggers ---------------------- +Widget Events +************* ESPHome implements as universal triggers the following LVGL events: @@ -1615,16 +1598,27 @@ These triggers can be applied directly to any widget in the lvgl configuration, .. _lvgl-onidle-trg: -Data types ----------- +``lvgl.on_idle`` +**************** -LVLG supports numeric properties only as integer values with variable minimums and maximums. Certain widget properties also support negative values. +LVGL has a notion of screen inactivity, i.e. how long did the user not interact with the screen. This can be use to dim the display backlight or turn it off after a moment of inactivity (like a screen saver). Every use of an input device (touchscreen, rotary encoder) counts as an activity and resets the inactivity counter. -- ``int8`` (signed) supports values ranging from -128 to 127. -- ``uint8`` (unsigned) supports values ranging from 0 to 255. -- ``int16`` (signed) supports values ranging from -32768 to 32767. -- ``uint16`` (unsigned) supports values ranging from 0 to 65535. +The ``on_idle`` :ref:`trigger ` is activated when inactivity time becomes longer than the specified ``timeout``. +- **timeout** (**Required**, :ref:`templatable `, int): :ref:`Time ` value after which LVGL should enter idle state. + +.. code-block:: yaml + + lvgl: + on_idle: + timeout: 30s + then: + - logger.log: "LVGL is idle" + - lvgl.pause: + - light.turn_off: + id: display_backlight + +See :ref:`lvgl-cook-idlescreen` example how to implement screen saving with idle settings. .. _lvgl-seealso: From 3d4a029b2e88eff48a435f7f50860dd6a916539d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 25 Jan 2024 10:11:14 +0100 Subject: [PATCH 151/350] Update lvgl.rst --- components/lvgl.rst | 116 ++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 24d38c2fd..45781f6c8 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -224,7 +224,7 @@ See :ref:`lvgl-cook-theme` in the Cookbook for an example how to easily implemen .. _lvgl-styling: Style properties ----------------- +**************** LVGL follows CSS's `border-box model `__. An object's *box* is built from the following parts: @@ -306,6 +306,55 @@ You can adjust the appearance of widgets by changing the foreground, background - **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +.. _lvgl-fonts: + +Fonts +----- + +LVGL internally stores fonts rendered in a C array. The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: + +- ``montserrat_8``: 8px font +- ``montserrat_10``: 10px font +- ``montserrat_12``: 12px font +- ``montserrat_14``: 14px font (**default**) +- ``montserrat_16``: 16px font +- ``montserrat_18``: 18px font +- ``montserrat_20``: 20px font +- ``montserrat_22``: 22px font +- ``montserrat_24``: 24px font +- ``montserrat_26``: 26px font +- ``montserrat_28``: 28px font +- ``montserrat_30``: 30px font +- ``montserrat_32``: 32px font +- ``montserrat_34``: 34px font +- ``montserrat_36``: 36px font +- ``montserrat_38``: 38px font +- ``montserrat_40``: 40px font +- ``montserrat_42``: 42px font +- ``montserrat_44``: 44px font +- ``montserrat_46``: 46px font +- ``montserrat_48``: 48px font + +You can display the embedded symbols easily on supported widgets using the ``symbol`` configuration option: + +.. figure:: /components/images/lvgl_symbols.png + :align: center + +.. note:: + + The ``text_font`` parameter influences the size of ``symbol``, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. + +In addition to the above, the following special fonts are available from LVGL as built-in: + +- ``unscii_8``: 8 px pixel perfect font with only ASCII characters +- ``unscii_16``: 16 px pixel perfect font with only ASCII characters +- ``simsun_16_cjk``: 16 px font with normal range + 1000 most common `CJK Radicals `__ +- ``dejavu_16_persian_hebrew``: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms + +TODO !! You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. + +In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. + .. _lvgl-widgets: Widgets @@ -1308,62 +1357,11 @@ You can use it as a parent background shape for other objects. It catches touche widgets: - ... - - -.. _lvgl-fonts: - -Fonts ------ - -TODO - -LVGL internally stores fonts rendered in a C array. The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: - -- ``montserrat_8``: 8px font -- ``montserrat_10``: 10px font -- ``montserrat_12``: 12px font -- ``montserrat_14``: 14px font (**default**) -- ``montserrat_16``: 16px font -- ``montserrat_18``: 18px font -- ``montserrat_20``: 20px font -- ``montserrat_22``: 22px font -- ``montserrat_24``: 24px font -- ``montserrat_26``: 26px font -- ``montserrat_28``: 28px font -- ``montserrat_30``: 30px font -- ``montserrat_32``: 32px font -- ``montserrat_34``: 34px font -- ``montserrat_36``: 36px font -- ``montserrat_38``: 38px font -- ``montserrat_40``: 40px font -- ``montserrat_42``: 42px font -- ``montserrat_44``: 44px font -- ``montserrat_46``: 46px font -- ``montserrat_48``: 48px font - -You can display the embedded symbols easily on supported widgets using the ``symbol`` configuration option: - -.. figure:: /components/images/lvgl_symbols.png - :align: center - -.. note:: - - The ``text_font`` parameter influences the size of ``symbol``, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. - -In addition to the above, the following special fonts are available from LVGL as built-in: - -- ``unscii_8``: 8 px pixel perfect font with only ASCII characters -- ``unscii_16``: 16 px pixel perfect font with only ASCII characters -- ``simsun_16_cjk``: 16 px font with normal range + 1000 most common `CJK Radicals `__ -- ``dejavu_16_persian_hebrew``: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms - -TODO !! You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. - -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. - Actions ------- +Specific actions are available for cetrain widgets, they are described above in their respective section. Some universal actions are available for all the widgets or for LVGL itself: + .. _lvgl-objupd-act: ``lvgl.widget.update`` @@ -1391,7 +1389,7 @@ This powerful :ref:`action ` allows changing on the fly any commo .. _lvgl-objupd-shorthands: -``lvgl.widget.hide``, ``lvgl.widget.show`` +``lvgl.widget.hide`` ``lvgl.widget.show`` ****************************************** These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget: @@ -1405,7 +1403,7 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` - lvgl.widget.show: my_label_id -``lvgl.widget.disable``, ``lvgl.widget.enable`` +``lvgl.widget.disable`` ``lvgl.widget.enable`` *********************************************** These :ref:`actions ` are shorthands for toggling the ``disabled`` state of any widget (which controls the appearance of the corresponding *disabled* style set of the theme): @@ -1469,8 +1467,8 @@ This :ref:`action ` resumes the activity of LVGL, including rende .. _lvgl-pgnx-act: -``lvgl.page.next``, ``lvgl.page.previous`` -****************************************** +``lvgl.page.next`` ``lvgl.page.previous`` +***************************************** This :ref:`action ` changes page to the next following in the configuration (except the ones with ``skip`` option enabled), wraps around at the end. @@ -1563,6 +1561,8 @@ This :ref:`condition ` checks if LVGL is in paused state or no Triggers -------- +Specific triggers like ``on_value`` are available for cetrain widgets, they are described above in their respective section. Some universal triggers are available for all the widgets or for LVGL itself: + .. _lvgl-event-trg: Widget Events From 25a8db9c23cb984bf7c91bdb778a3a176c3bde50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 25 Jan 2024 10:23:01 +0100 Subject: [PATCH 152/350] Update lvgl.rst --- components/lvgl.rst | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 45781f6c8..98def38ff 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -309,7 +309,7 @@ You can adjust the appearance of widgets by changing the foreground, background .. _lvgl-fonts: Fonts ------ +***** LVGL internally stores fonts rendered in a C array. The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: @@ -1367,7 +1367,7 @@ Specific actions are available for cetrain widgets, they are described above in ``lvgl.widget.update`` ********************** -This powerful :ref:`action ` allows changing on the fly any common :ref:`style property ` or :ref:`flag ` of any widget. +This powerful :ref:`action ` allows changing on the fly any common :ref:`style property `, state (templatable) or :ref:`flag ` of any widget. .. code-block:: yaml @@ -1387,9 +1387,11 @@ This powerful :ref:`action ` allows changing on the fly any commo id: my_label_id hidden: true +Check out in the Cookbook :ref:`lvgl-cook-binent` for an example how to use a template to update the state. + .. _lvgl-objupd-shorthands: -``lvgl.widget.hide`` ``lvgl.widget.show`` +``lvgl.widget.hide``, ``lvgl.widget.show`` ****************************************** These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget: @@ -1402,8 +1404,7 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` - delay: 0.5s - lvgl.widget.show: my_label_id - -``lvgl.widget.disable`` ``lvgl.widget.enable`` +``lvgl.widget.disable``, ``lvgl.widget.enable`` *********************************************** These :ref:`actions ` are shorthands for toggling the ``disabled`` state of any widget (which controls the appearance of the corresponding *disabled* style set of the theme): @@ -1417,8 +1418,6 @@ These :ref:`actions ` are shorthands for toggling the ``disabled` then: - lvgl.widget.enable: my_button_id - - .. _lvgl-rfrsh-act: ``lvgl.widget.redraw`` @@ -1435,8 +1434,6 @@ This :ref:`action ` redraws the entire screen, or optionally only - lvgl.widget.redraw: - - .. _lvgl-pause-act: ``lvgl.pause`` @@ -1467,7 +1464,7 @@ This :ref:`action ` resumes the activity of LVGL, including rende .. _lvgl-pgnx-act: -``lvgl.page.next`` ``lvgl.page.previous`` +``lvgl.page.next``, ``lvgl.page.previous`` ***************************************** This :ref:`action ` changes page to the next following in the configuration (except the ones with ``skip`` option enabled), wraps around at the end. From 6fc762ae2fdc7d0457581b03156208b66d85aee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 25 Jan 2024 10:30:36 +0100 Subject: [PATCH 153/350] Update lvgl.rst --- components/lvgl.rst | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 98def38ff..9b1f22ef3 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -9,14 +9,15 @@ LVGL `LVGL `__ (Light and Versatile Graphics Library) is a free and open-source -embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports -`LVGL version 8.3.9 `__. +embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.9 `__. .. figure:: /components/images/lvgl_main_screenshot.png :align: center In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. +TODO !! Display requirement/recommendation/spec, monochrome supported? + For interactivity, a :ref:`Touchscreen ` (capacitive highly prefered) or a :doc:`/components/sensor/rotary_encoder` can be used. Check out a few detailed examples :ref:`in the Cookbook ` to see a couple ways to integrate LVGL through ESPHome with your environment. @@ -24,14 +25,12 @@ Check out a few detailed examples :ref:`in the Cookbook ` to see a co Basics ------ -In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` to see the full -list of available LVGL widgets in ESPHome. +In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` to see the full list of available LVGL widgets in ESPHome. -Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent object. There is always one active screen on a display. +Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent object. There is always one active page on a display. Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. -The child object moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within -their parent's bounding area. In other words, the parts of the children outside the parent are clipped. +The child object moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within their parent's bounding area. In other words, the parts of the children outside the parent are clipped. Widgets integrate in ESPHome also as components: @@ -55,7 +54,6 @@ Widgets integrate in ESPHome also as components: These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`lvgl-seealso` section at the bottom of this document. - Main Component -------------- @@ -1465,7 +1463,7 @@ This :ref:`action ` resumes the activity of LVGL, including rende .. _lvgl-pgnx-act: ``lvgl.page.next``, ``lvgl.page.previous`` -***************************************** +****************************************** This :ref:`action ` changes page to the next following in the configuration (except the ones with ``skip`` option enabled), wraps around at the end. From 776419ad726d98ece6004535da4c2080f3337361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 25 Jan 2024 15:30:24 +0100 Subject: [PATCH 154/350] Update lvgl.rst --- cookbook/lvgl.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index f623f7845..d734592ff 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -277,7 +277,7 @@ To make a nice user interface for controlling Home Assistant covers you could us .. figure:: images/lvgl_cook_cover.png :align: center -Just as in the previous examples, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. +Just as in the previous examples, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label on the middle to show the *STOP* symbol. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. .. code-block:: yaml @@ -294,7 +294,7 @@ Just as in the previous examples, we need to get the states of the cover first. then: - lvgl.widget.update: id: cov_up_myroom - text_opa: 50% + text_opa: 60% else: - lvgl.widget.update: id: cov_up_myroom @@ -306,7 +306,7 @@ Just as in the previous examples, we need to get the states of the cover first. then: - lvgl.widget.update: id: cov_down_myroom - text_opa: 50% + text_opa: 60% else: - lvgl.widget.update: id: cov_down_myroom @@ -324,7 +324,7 @@ Just as in the previous examples, we need to get the states of the cover first. then: - lvgl.label.update: id: cov_stop_myroom - text: "STOP" + symbol: "STOP" else: - lvgl.label.update: id: cov_stop_myroom From 38dbd2138dc8003148943abe27d02cc387ad4e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 25 Jan 2024 16:51:38 +0100 Subject: [PATCH 155/350] Update lvgl.rst --- components/lvgl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9b1f22ef3..cce1e5c19 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1560,10 +1560,10 @@ Specific triggers like ``on_value`` are available for cetrain widgets, they are .. _lvgl-event-trg: -Widget Events -************* +Interaction Events +****************** -ESPHome implements as universal triggers the following LVGL events: +ESPHome implements as universal triggers the following interaction events generated by LVGL: - ``on_press``: The widget has been pressed. - ``on_long_press``: The widget has been pressed for at least the ``long_press_time`` specified in the input device configuration. Not called if scrolled. From 48947576defccd1fa071e631b1236cf1852b2571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 25 Jan 2024 20:59:32 +0100 Subject: [PATCH 156/350] on_state warn --- components/lvgl.rst | 10 +++++++++- cookbook/lvgl.rst | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index cce1e5c19..3dcb9d36e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -529,9 +529,13 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can format: "Arc value is: %.0f" args: [ 'x' ] +.. note:: + + The ``on_value`` is sent while the arc is being dragged or changed with keys. The event is sent *continuously* while the arc is being dragged, this can affect performance and have negative effects on the actions to be performed. + The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. -See :ref:`lvgl-cook-bright` or :ref:`lvgl-cook-volume` for an example how to use a slider to control entities in Home Assistant. +See :ref:`lvgl-cook-bright` or :ref:`lvgl-cook-volume` for an example how to use a slider or an arc to control entities in Home Assistant. .. _lvgl-wgt-bar: @@ -1223,6 +1227,10 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking format: "Slider value is: %.0f" args: [ 'x' ] +.. note:: + + The ``on_value`` is sent while the slider is being dragged or changed with keys. The event is sent *continuously* while the slider is being dragged, this can affect performance and have negative effects on the actions to be performed. + The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. See :ref:`lvgl-cook-bright` or :ref:`lvgl-cook-volume` for an example how to use a slider to control entities in Home Assistant. diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index d734592ff..0444ecc65 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -142,6 +142,10 @@ Note that Home Assistant expects an integer at the ``brightness`` parameter of t This is applicable to service calls like ``fan.set_percentage``, ``valve.set_valve_position`` too, only difference is that ``max_value`` has to be ``100``. +.. note:: + + Keep in mind that the ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heatpump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. + .. _lvgl-cook-volume: Media player volume slider From d0d61ec852c8660b831dd6399c23f51a3d9f3d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Jan 2024 11:38:29 +0100 Subject: [PATCH 157/350] warn --- components/lvgl.rst | 4 ++-- cookbook/lvgl.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 3dcb9d36e..359f7b4ef 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -531,7 +531,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can .. note:: - The ``on_value`` is sent while the arc is being dragged or changed with keys. The event is sent *continuously* while the arc is being dragged, this can affect performance and have negative effects on the actions to be performed. + The ``on_value`` trigger is sent while the arc is being dragged or changed with keys. The event is sent *continuously* while the arc is being dragged, this can affect performance and have negative effects on the actions to be performed. The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. @@ -1229,7 +1229,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking .. note:: - The ``on_value`` is sent while the slider is being dragged or changed with keys. The event is sent *continuously* while the slider is being dragged, this can affect performance and have negative effects on the actions to be performed. + The ``on_value`` trigger is sent while the slider is being dragged or changed with keys. The event is sent *continuously* while the slider is being dragged, this can affect performance and have negative effects on the actions to be performed. The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 0444ecc65..2097e75cc 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -144,7 +144,7 @@ This is applicable to service calls like ``fan.set_percentage``, ``valve.set_val .. note:: - Keep in mind that the ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heatpump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. + Keep in mind that ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heatpump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. .. _lvgl-cook-volume: From 95565668e0e589eea39e3236c770b1f159340131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Jan 2024 21:14:47 +0100 Subject: [PATCH 158/350] line --- components/images/lvgl_line.png | Bin 0 -> 1775 bytes components/lvgl.rst | 69 +++++++++++++++++--------------- 2 files changed, 37 insertions(+), 32 deletions(-) create mode 100644 components/images/lvgl_line.png diff --git a/components/images/lvgl_line.png b/components/images/lvgl_line.png new file mode 100644 index 0000000000000000000000000000000000000000..6d85c445b4d1abcd49c9ac4f5737c40c9a234036 GIT binary patch literal 1775 zcmZ8iX;_k36sD%d-AbE46Du}T)AZ981JhgpMay=le6&%-78lGECG07;C=ex58d1kW zZF0<9A|o|RLj}VLOVdnD#z_WqW!#9GZ~o4Y_nzn6d(ZZs^W4ik6pS}DvND1|Af`lu z?_p5tK%6jG39dnMVH79~69}OfArQ0n|FGh=gPAo1vZjpa>wT0a_)@$-W;5PWqJ(Y4 z9P(PT5zXIn)oL$#9l?TdZ^WK&xyIc!v24Vj$$i;qaN}@0l{~bE`ywJG*@94Mmltt~ zxc*VmuZY_QtDGM81vMTyvv~OZ=2^eAx%r-nraP(oMUN()y^GQJ4y7wqjb;#6)`dMA z(^h1^v5#)b-}HaPshq>hf^$4<#Fxvn{()wPdtA2NzqH2Y8~sm>;ou^-MK4)+VA8f} z2!3Trsu5efF&3w0v@8#5xF&6gA-Ga4SZrVieNeOQe&e5xt=zpW3rJ7RqE`^ZEvi;s z8wq%LD~Z;LQ^v*HPk-IpywpeYADnvgG|S6aYSI)PyP`RUsC!Qlm;^5n(3aFmyJ zexFu#aO;me*raZ8*tVgz3)d=ienkoYqn^^CZ!;Dzy2L7D>9~OvFzcc%qq*#$Pj~8~ z&wrr8n2*vnW_XWhRor|_<7*!e46F`nWMf{AuD0|WACt7rN~<)YrqT2SL)95Yf5h{g zNgiRLuww!{PcPe4U2+$y^c5e;t>gi4Gy`>GW&Io~$yWavH*DOT^h&E654OGdak03i zVP>Z~&=oqOHxJN!`IO$Qo3sc*n~flxg`p>l1!Vlhgoo3KxfFKVhca;LiA{fwfo)ilK==?$h?C(=5g+N8>dUyQ zswlNnIzAIk_URSeeba6cSkiJol?PblGSbeU;*sah>})MZJ()bOxm)iZ2_7P*bq!HD z$=QGuEenX7zn-8GX*1a{^O37?}r!85(CB&2y4Q@?X9wa zXp;MtTAURJD~x|2$j?hIh&?B1SM}3`PK^37RwlCkLOp3-0=#qIB{($1i z5jo-dZrO5?%S^*LEH|&^b)x?PR%oAw#jK1~t$(WhQV0eJ5^)_hbV<8KE6vw|(F$I% z3>9U;EDl0d>&vt+Kw_lz7xsZZBP0lW^=%%oAt`!b7lnk~%En_An(Y*1jI3@)51+Qu zngbQ~AD0`1aLFG^U1lQX%Qk2F(k|6>Oi3Qc)t*kTc*!WmA z@E=cg6Ys0;a=}*oF1eSj1(}7JY_7??=kt!m#QdxZA*MM{q@&$+gJ6wRYYtbjpd0$4 z){=5TU(xS{U{w~)GwTB5$4EBw^p4YR;0%{ovT{hE+24RT+u1tharr)# zu5&l5T;AsWlxPzfclF!y#jnmig7Pch%xbNCRxqs(`rZPcTH2o)CsU(e1STRl!m(@k z9Sdr9Hg)V>Y2gV2pI+Q~g;HgzvQtmZWK%7H;ZEcK;pTUU{{DopBA~1f{J|hZzhK{o I2O_Th3;G^#zyJUM literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index 359f7b4ef..1b37d4191 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -266,11 +266,6 @@ You can adjust the appearance of widgets by changing the foreground, background - **border_width** (*Optional*, int16): Set the width of the border in pixels. - **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if it has same width and height). - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. -- **line_width** (*Optional*, int16): Set the width of the line in pixels. -- **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). -- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). -- **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. - **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw an outline around the widget. - **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. @@ -295,14 +290,6 @@ You can adjust the appearance of widgets by changing the foreground, background - **transform_zoom** (*Optional*, 0.1-10): Trannsformation zoom of the widget (eg. resizing) - **translate_x** (*Optional*, int16 or percentage): Move of the widget with this value in horizontal direction. - **translate_y** (*Optional*, int16 or percentage): Move of the widget with this value in vertical direction. -- **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` -- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. -- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) -- **text_font**: (*Optional*, :ref:`font `): The ID or the C array name of the font used to render the text or symbol. -- **text_letter_space** (*Optional*, int16): Characher spacing of the text. -- **text_line_space** (*Optional*, int16): Line spacing of the text. -- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - .. _lvgl-fonts: @@ -782,7 +769,7 @@ The Dropdown widget is built internall from a *button* and a *list* (both not re - **scrollbar** (*Optional*, list): Settings for the scrollbar **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar background, border, shadow properties and width (for its own width) and right padding for the spacing on the right. - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and is the parent of ``symbol``. - **symbol** (*Optional*, enum): A symbol (typically an chevron) is shown in dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. Choose a different :ref:`symbol ` from the built-in ones. -- Style options from :ref:`lvgl-styling` for the background of the button and the list. Uses the typical background properties and text properties for the text on it. ``max_height`` can be used to limit the height of the list. +- Style options from :ref:`lvgl-styling` for the background of the button and the list. Uses the typical background properties and :ref:`lvgl-wgt-lbl` text properties for the text on it. ``max_height`` can be used to limit the height of the list. **Specific actions:** @@ -852,6 +839,7 @@ TODO !! supported image encodings id: img_id src: dog_image +.. _lvgl-wgt-lbl: ``label`` ********* @@ -864,6 +852,13 @@ A label is the basic widget type that is used to display text. **Specific options:** - **text** or **symbol** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``" "`` (space). +- **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` +- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. +- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) +- **text_font**: (*Optional*, :ref:`font `): The ID or the C array name of the font used to render the text or symbol. +- **text_letter_space** (*Optional*, int16): Characher spacing of the text. +- **text_line_space** (*Optional*, int16): Line spacing of the text. +- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) @@ -875,7 +870,7 @@ A label is the basic widget type that is used to display text. - **selected** (*Optional*, list): Settings for the the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. -Newline characters are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``line1\nline2\n\nline4``. TODO +TODO Newline characters are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``line1\nline2\n\nline4``. **Specific actions:** @@ -902,35 +897,45 @@ Newline characters are handled automatically by the label widget. You can use `` snprintf(buf, 10, "%.0fdBm", id(wifi_signal_db).get_state()); return buf; +.. _lvgl-wgt-lin: + ``line`` ******** The Line widget is capable of drawing straight lines between a set of points. +.. figure:: /components/images/lvgl_line.png + :align: center + **Specific options:** -- **points** (*Required*, list): TODO +- **points** (*Required*, list): A list of ``x, y`` integer pairs for point coordinates (origin from top left of parent) +- **line_width** (*Optional*, int16): Set the width of the line in pixels. +- **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). +- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). +- **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. - Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. -By default, the Line's width and height are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts on the line may not be visible. +TODO invert_y ??? -**Specific actions:** ??? - -``lvgl.indicator.line.update`` :ref:`action ` updates the line indicator styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +By default, the Line's width and height are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts of the line may not be visible. **Example:** .. code-block:: yaml # Example widget: - - - - - # Example action: - on_...: - then: - - lvgl. - + - line: + points: + - 5, 5 + - 70, 70 + - 120, 10 + - 180, 60 + - 230, 15 + line_width: 8 + line_color: 0x0000FF + line_rounded: true .. _lvgl-wgt-led: @@ -1003,14 +1008,14 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **length**: Tick line length in pixels - **color**: ID or hex code for the ticks :ref:`color ` - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. - - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the *line* and *text* style properties. + - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-wgt-lin` and :ref:`lvgl-wgt-lbl` text style properties. - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their ``value`` is interpreted in the range of the scale (see the *action* below): - **line** (*Optional*): Add a needle line to a Scale. By default, the length of the line is the same as the scale's radius. - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **width**: Needle line width in pixels. - **color**: ID or hex code for the ticks :ref:`color `. - **r_mod**: Adjust the length of the needle with this amount (can be negative). - - Style options from :ref:`lvgl-styling` for the *needle line* using the *line* style properties, as well as the background properties to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. + - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - Style options from :ref:`lvgl-styling` for the background of the meter, using the typical background properties. .. note:: @@ -1133,9 +1138,9 @@ Roller allows you to simply select one option from a list by scrolling. - **options** (*Required*, list): The list of available options in the roller. - **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. - **visible_rows** TODO -- **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the text style properties to change the appearance of the text in the selected area. +- **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-wgt-lbl` text style properties to change the appearance of the text in the selected area. - **selected_index** (*Optional*, int8): The index of the item you wish to be selected. -- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and text style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. +- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-wgt-lbl` style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. **Specific actions:** From 0998f36c6707a34e18f0c486234d992cf3f2aa61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Jan 2024 21:34:05 +0100 Subject: [PATCH 159/350] Update lvgl.rst --- components/lvgl.rst | 83 ++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1b37d4191..9be088a38 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -897,46 +897,6 @@ TODO Newline characters are handled automatically by the label widget. You can u snprintf(buf, 10, "%.0fdBm", id(wifi_signal_db).get_state()); return buf; -.. _lvgl-wgt-lin: - -``line`` -******** - -The Line widget is capable of drawing straight lines between a set of points. - -.. figure:: /components/images/lvgl_line.png - :align: center - -**Specific options:** - -- **points** (*Required*, list): A list of ``x, y`` integer pairs for point coordinates (origin from top left of parent) -- **line_width** (*Optional*, int16): Set the width of the line in pixels. -- **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). -- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). -- **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. -- Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. - -TODO invert_y ??? - -By default, the Line's width and height are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts of the line may not be visible. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - line: - points: - - 5, 5 - - 70, 70 - - 120, 10 - - 180, 60 - - 230, 15 - line_width: 8 - line_color: 0x0000FF - line_rounded: true - .. _lvgl-wgt-led: ``led`` @@ -982,6 +942,46 @@ The ``led`` can be also integrated as :doc:`/components/light/lvgl`. If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. +.. _lvgl-wgt-lin: + +``line`` +******** + +The Line widget is capable of drawing straight lines between a set of points. + +.. figure:: /components/images/lvgl_line.png + :align: center + +**Specific options:** + +- **points** (*Required*, list): A list of ``x, y`` integer pairs for point coordinates (origin from top left of parent) +- **line_width** (*Optional*, int16): Set the width of the line in pixels. +- **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). +- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). +- **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. +- Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. + +TODO invert_y ??? + +By default, the Line widget width and height dimensions are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts of the line may not be visible. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - line: + points: + - 5, 5 + - 70, 70 + - 120, 10 + - 180, 60 + - 230, 15 + line_width: 8 + line_color: 0x0000FF + line_rounded: true + ``meter`` ********* @@ -1026,9 +1026,6 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee ``lvgl.indicator.line.update`` :ref:`action ` updates the indicator needle ``value``, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - -The needle line using the line style properties, as well as the background properties to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - **Example:** .. code-block:: yaml From a391842c800238f59c732d49bc7c274fed8f60fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Jan 2024 21:41:21 +0100 Subject: [PATCH 160/350] Update lvgl.rst --- components/lvgl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9be088a38..a10a47354 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -522,7 +522,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. -See :ref:`lvgl-cook-bright` or :ref:`lvgl-cook-volume` for an example how to use a slider or an arc to control entities in Home Assistant. +See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider (or an arc) to control entities in Home Assistant. .. _lvgl-wgt-bar: @@ -1063,7 +1063,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee id: temperature_needle value: 3 -See :ref:`lvgl-cook-clock` in the Cookbook for an example how to implement an analog clock which also shows the date. +See :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clock` in the Cookbook for examples how to effectively use this widget. .. _lvgl-wgt-msg: @@ -1235,7 +1235,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. -See :ref:`lvgl-cook-bright` or :ref:`lvgl-cook-volume` for an example how to use a slider to control entities in Home Assistant. +See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider to control entities in Home Assistant. .. _lvgl-wgt-swi: From 5eac21d3d4bab3c43c4690e64b9bc60ce1014105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Jan 2024 21:55:12 +0100 Subject: [PATCH 161/350] cookie fix --- cookbook/images/lvgl_cook_remligbut.png | Bin 0 -> 1696 bytes cookbook/lvgl.rst | 6 ++++++ 2 files changed, 6 insertions(+) create mode 100644 cookbook/images/lvgl_cook_remligbut.png diff --git a/cookbook/images/lvgl_cook_remligbut.png b/cookbook/images/lvgl_cook_remligbut.png new file mode 100644 index 0000000000000000000000000000000000000000..ee0e77b8d58818f3ee3df9d7aa2bfd3c19471202 GIT binary patch literal 1696 zcmV;R24DG!P)m^Sscf|UAiz2B4l8N4D7*yEi^?B78V-Wg|(Q2 zN)IY5M7x5`>LvS!wrOG2dZ?|1lD6!2bFtJt)IYGGLQA)YQa!Yo!h#+YJ!D}#EWCh) z2}Jk}>_Yc2vq?;5OkyVgYCh!Py!Yn4pI_de-}}9JC*Hq*k2-ntQKb#2G3t61MqRJM zsOwc2C-W>vT)~?)yk0?c2bxw=o63YB;FKF*p2rt$Op^0_=|s-;k)qppcn_N!MH^Vf zw6x;;tL)U7oCR~}MKfVMd2F9u)y+44b}4Xp5lg)&q2kUsB9Ri;9yS%W$~0deX(oJ3#R3qC&`cqEQFQwl%~_^Ac}&r5(;Tz@_3&P4t*Hqt zM99>OxblI!4tcVq1_!e5h7WJq5!~906o2|L8Rz59)(jSr$UHv0O;sq4I;gK zj{CRaX~S@UNiuN-4?=0x0=|A+=rghw=J0F@0H$Y+9rEfr0BS#L6t-&A4(!k?oyZyh zG|5mDj83BY3?AI3T?JotvAbcq9!OfxdIl)6g2{1mFkBwP%p4p}JPK2c!`sE~hUx2W z>~R42;VSDHpy?3(rJ(sNyE0A=0SogOyGFi#oNL2a5c~g+okJTf9=r9DBmme|&?qr) zcj|vu!USMAWjZC))Ub6p*_Cm+f6M4Ne@5tB8#>ytFpoxw^$gI>AXZn5EKOx2L0Xu{ z9!Ek0VDx1mXQRbqpI(B1mR4L25?7!oXg?1Ck7twl`lg?f&u`Pb8+~lPjT}g6lmMXF z4ZsjfXL$)DK_rKKI(p$l8ZDY)^elc(#N+PRny_BuIjYt#!C03HsWlYSyWrKNdz^ufnM7RTy=>3Zq!EJIl z;TyouzZ%hJ)8JR>siSnMG=pu*Xe;UuB`9{zP_c zYc=Z#D?Lo6OViX;VzUmT2K_Gwt6<|5)k_aorO)meGkx_@(fLacSLx>$`g}hU1c3c` zUaw~azsmAeZKc;oJzVAU>&IVoJ)kdNEGAVoyrctonPP=2?uCiEFrNq2l!f7{SCL0M8|6X!Q zYG-fUZPFW$197)o?d+9YCW|9X^%5II$t7{0{}@UZce}aIFS#Vq;wufy`!L(lZEar@ zUo5#^{!vN`tB9DlOYQ6x9Kspvi)z;QhyEdDSJC!0{H;jK^Um^ynaWIDmU&M Date: Fri, 26 Jan 2024 21:56:10 +0100 Subject: [PATCH 162/350] Update lvgl.rst --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index f7e69b0e4..750b91fbe 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -11,7 +11,7 @@ Here are a couple recipes for various interesting things you can do with :ref:`l .. note:: - The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of *240x320px*, you have to adjust them to your screen in order to obtain expected results. + The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of ``240x320px``, you have to adjust them to your screen in order to obtain expected results. .. _lvgl-cook-relay: From aad276ab1fa0345dd6938f690d34b0bb05287e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Jan 2024 21:58:31 +0100 Subject: [PATCH 163/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a10a47354..308f66ff5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -591,7 +591,7 @@ Simple push or toggle button. height: 30 id: btn_id -To have a button with a text label on it, add a ``label`` widget as child to it: +To have a button with a text label on it, add a :ref:`lvgl-wgt-lbl` widget as child to it: .. code-block:: yaml From 2bbffc3445862d3062c10158f5182e8bffcad7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 27 Jan 2024 23:30:38 +0100 Subject: [PATCH 164/350] keypad cookie --- components/lvgl.rst | 2 +- cookbook/images/lvgl_cook_keypad.png | Bin 0 -> 5839 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 cookbook/images/lvgl_cook_keypad.png diff --git a/components/lvgl.rst b/components/lvgl.rst index 308f66ff5..bd96d7747 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -702,7 +702,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row .. note:: - The Button Matrix widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. + The Button Matrix widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. Check out :ref:`lvgl-cook-keypad` for an example. .. _lvgl-wgt-chk: diff --git a/cookbook/images/lvgl_cook_keypad.png b/cookbook/images/lvgl_cook_keypad.png new file mode 100644 index 0000000000000000000000000000000000000000..726d0a5020a6aded62d1fd98291cfb0675710591 GIT binary patch literal 5839 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 IEN$ZRUnZ_bJ^%m! literal 0 HcmV?d00001 From 06dec634cf182bce016b6e9a5d79bb3af83944f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 27 Jan 2024 23:30:52 +0100 Subject: [PATCH 165/350] Update lvgl.rst --- cookbook/lvgl.rst | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 750b91fbe..7f74e364c 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -756,6 +756,145 @@ The script runs every minute to update the hand line positions and the label tex static const char * const day_names[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}; return day_names[id(time_comp).now().day_of_week-1]; + +.. _lvgl-cook-keypad: + +A numeric input keypad +---------------------- + +The btnmatrix widget can work together with the :ref:`key_collector` to collect the button presses as key press sequences. It sends the ``text`` of the buttons to the key collector. + +.. figure:: images/lvgl_cook_keypad.png + :align: center + +If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change color accordingly: + +.. code-block:: yaml + + lvgl: + ... + pages: + - id: main_page + widgets: + - led: + id: lvgl_led + x: 30 + y: 47 + color: 0xFF0000 + brightness: 70% + - obj: + width: 140 + height: 25 + align_to: + id: lvgl_led + align: OUT_RIGHT_MID + x: 17 + border_width: 1 + border_color: 0 + border_opa: 50% + pad_all: 0 + bg_opa: 80% + bg_color: 0xFFFFFF + shadow_color: 0 + shadow_opa: 50% + shadow_width: 10 + shadow_spread: 3 + radius: 5 + widgets: + - label: + id: keypad_label + align: CENTER + text: "* delete, # enter" + text_align: center + - btnmatrix: + x: 20 + y: 85 + width: 200 + height: 190 + items: + pressed: + bg_color: 0xFFFF00 + id: lvgl_keypad + rows: + - buttons: + - text: 1 + control: + no_repeat: true + - text: 2 + control: + no_repeat: true + - text: 3 + control: + no_repeat: true + - buttons: + - text: 4 + control: + no_repeat: true + - text: 5 + control: + no_repeat: true + - text: 6 + control: + no_repeat: true + - buttons: + - text: 7 + control: + no_repeat: true + - text: 8 + control: + no_repeat: true + - text: 9 + control: + no_repeat: true + - buttons: + - text: '*' + control: + no_repeat: true + - text: 0 + control: + no_repeat: true + - text: '#' + control: + no_repeat: true + +key_collector: + - id: pincode_reader + source_id: lvgl_keypad + min_length: 4 + max_length: 4 + end_keys: "#" + end_key_required: true + back_keys: "*" + allowed_keys: "0123456789*#" + timeout: 5s + on_progress: + - if: + condition: + lambda: return (0 != x.compare(std::string{""})); + then: + - lvgl.label.update: + id: keypad_label + text: !lambda 'return x.c_str();' + else: + - lvgl.label.update: + id: keypad_label + text: "Please enter code" + on_result: + - if: + condition: + lambda: return (0 == x.compare(std::string{"1234"})); + then: + - lvgl.led.update: + id: lvgl_led + color: 0x00FF00 + else: + - lvgl.led.update: + id: lvgl_led + color: 0xFF0000 + +See :ref:`key_collector` documentation for more details on how to use it in automations. + + .. _lvgl-cook-idlescreen: Turn off screen when idle @@ -809,5 +948,6 @@ See Also - :ref:`lvgl-main` - :ref:`config-lambda` - :ref:`automation` +- :ref:`key_collector` - :ghedit:`Edit` From 842c9601c8d6b7ff8879509b140c8d11fd96d79e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 27 Jan 2024 23:32:49 +0100 Subject: [PATCH 166/350] Update lvgl.rst --- cookbook/lvgl.rst | 69 +++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 7f74e364c..6f41ce76b 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -857,44 +857,43 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c control: no_repeat: true -key_collector: - - id: pincode_reader - source_id: lvgl_keypad - min_length: 4 - max_length: 4 - end_keys: "#" - end_key_required: true - back_keys: "*" - allowed_keys: "0123456789*#" - timeout: 5s - on_progress: - - if: - condition: - lambda: return (0 != x.compare(std::string{""})); - then: - - lvgl.label.update: - id: keypad_label - text: !lambda 'return x.c_str();' - else: - - lvgl.label.update: - id: keypad_label - text: "Please enter code" - on_result: - - if: - condition: - lambda: return (0 == x.compare(std::string{"1234"})); - then: - - lvgl.led.update: - id: lvgl_led - color: 0x00FF00 - else: - - lvgl.led.update: - id: lvgl_led - color: 0xFF0000 + key_collector: + - id: pincode_reader + source_id: lvgl_keypad + min_length: 4 + max_length: 4 + end_keys: "#" + end_key_required: true + back_keys: "*" + allowed_keys: "0123456789*#" + timeout: 5s + on_progress: + - if: + condition: + lambda: return (0 != x.compare(std::string{""})); + then: + - lvgl.label.update: + id: keypad_label + text: !lambda 'return x.c_str();' + else: + - lvgl.label.update: + id: keypad_label + text: "Please enter code" + on_result: + - if: + condition: + lambda: return (0 == x.compare(std::string{"1234"})); + then: + - lvgl.led.update: + id: lvgl_led + color: 0x00FF00 + else: + - lvgl.led.update: + id: lvgl_led + color: 0xFF0000 See :ref:`key_collector` documentation for more details on how to use it in automations. - .. _lvgl-cook-idlescreen: Turn off screen when idle From 7ac664154459397fa267970cb5764d7ceacb1fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 27 Jan 2024 23:38:57 +0100 Subject: [PATCH 167/350] Update lvgl.rst --- components/lvgl.rst | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index bd96d7747..af6a0d32f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -479,7 +479,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can **Specific actions:** -``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Specific triggers:** @@ -649,7 +649,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row **Specific actions:** -``lvgl.button.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.button.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -722,7 +722,7 @@ The Checkbox widget is made internally from a "tick box" and a label. When the C **Specific actions:** -``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -773,7 +773,7 @@ The Dropdown widget is built internall from a *button* and a *list* (both not re **Specific actions:** -``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -817,7 +817,7 @@ TODO !! supported image encodings **Specific actions:** -``lvgl.img.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -874,7 +874,7 @@ TODO Newline characters are handled automatically by the label widget. You can u **Specific actions:** -``lvgl.label.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -902,7 +902,7 @@ TODO Newline characters are handled automatically by the label widget. You can u ``led`` ******** -The LEDs are rectangle-like (or circle) widget whose brightness can be adjusted. With lower brightness the colors of the LED become darker. +The Led widgets are rectangle-like (or circle) widget whose brightness can be adjusted. With lower brightness the colors become darker. .. figure:: /components/images/lvgl_led.png :align: center @@ -915,7 +915,7 @@ The LEDs are rectangle-like (or circle) widget whose brightness can be adjusted. **Specific actions:** -``lvgl.led.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -931,9 +931,9 @@ The LEDs are rectangle-like (or circle) widget whose brightness can be adjusted. # Example action: on_...: then: - - lvgl. - - + - lvgl.led.update: + id: lvgl_led + color: 0x00FF00 The ``led`` can be also integrated as :doc:`/components/light/lvgl`. @@ -941,6 +941,7 @@ The ``led`` can be also integrated as :doc:`/components/light/lvgl`. If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. +Check out :ref:`lvgl-cook-keypad` for an example how to change the led styling properties from an automation. .. _lvgl-wgt-lin: @@ -1024,7 +1025,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee **Specific actions:** -``lvgl.indicator.line.update`` :ref:`action ` updates the indicator needle ``value``, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.indicator.line.update`` :ref:`action ` updates the indicator needle ``value``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1141,7 +1142,7 @@ Roller allows you to simply select one option from a list by scrolling. **Specific actions:** -``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1192,7 +1193,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking **Specific actions:** -``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties specified in the specific options above, similarly to way :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Specific triggers:** From 7a0bd140596c329d0f4f37b44a1c38384f753425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 27 Jan 2024 23:55:30 +0100 Subject: [PATCH 168/350] Update lvgl.rst --- cookbook/lvgl.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 6f41ce76b..4080732df 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -858,8 +858,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c no_repeat: true key_collector: - - id: pincode_reader - source_id: lvgl_keypad + - source_id: lvgl_keypad min_length: 4 max_length: 4 end_keys: "#" @@ -892,7 +891,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c id: lvgl_led color: 0xFF0000 -See :ref:`key_collector` documentation for more details on how to use it in automations. +A few notable things in this example: usage of ``align_to`` to align the text display to the led vertically; usage of a base object ``obj`` as a parent for the label, in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions; changing the background color of the buttons in ``pressed`` state. .. _lvgl-cook-idlescreen: From f090f5fb0d1f7c0ee511ba8c1e69f02b548d8796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 28 Jan 2024 00:00:18 +0100 Subject: [PATCH 169/350] Update lvgl.rst --- cookbook/lvgl.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 4080732df..4aaf04297 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -81,7 +81,7 @@ If you'd like to control a remote light, which appears as an entity in Home Assi lvgl: ... pages: - - id: main_page + - id: room_page widgets: - btn: id: light_btn @@ -126,7 +126,7 @@ We can use a sensor to retrieve the current brightness of a light, which is stor lvgl: ... pages: - - id: main_page + - id: room_page widgets: - slider: id: dimmer_slider @@ -179,7 +179,7 @@ With a sensor we retrieve the current volume level of the media player, which is lvgl: ... pages: - - id: main_page + - id: mediaplayer_page widgets: - slider: id: slider_media_player @@ -231,7 +231,7 @@ Whenever a new value comes from the sensor, we update the needle indicator, and lvgl: ... pages: - - id: main_page + - id: meter_page widgets: - meter: align: CENTER @@ -346,7 +346,7 @@ Just as in the previous examples, we need to get the states of the cover first. lvgl: ... pages: - - id: main_page + - id: room_page widgets: - label: x: 10 @@ -650,7 +650,7 @@ The script runs every minute to update the hand line positions and the label tex lvgl: ... pages: - - id: main_page + - id: clock_page widgets: - obj: # Clock container height: size_content @@ -774,7 +774,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c lvgl: ... pages: - - id: main_page + - id: keypad_page widgets: - led: id: lvgl_led @@ -802,11 +802,12 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c radius: 5 widgets: - label: - id: keypad_label + id: lvgl_label align: CENTER text: "* delete, # enter" text_align: center - btnmatrix: + id: lvgl_keypad x: 20 y: 85 width: 200 @@ -814,7 +815,6 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c items: pressed: bg_color: 0xFFFF00 - id: lvgl_keypad rows: - buttons: - text: 1 @@ -872,11 +872,11 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c lambda: return (0 != x.compare(std::string{""})); then: - lvgl.label.update: - id: keypad_label + id: lvgl_label text: !lambda 'return x.c_str();' else: - lvgl.label.update: - id: keypad_label + id: lvgl_label text: "Please enter code" on_result: - if: From f086db225cdb043524133cdcb6c0598388de2b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 28 Jan 2024 12:25:38 +0100 Subject: [PATCH 170/350] links back from cook to doc --- components/lvgl.rst | 27 +++++++-------------------- cookbook/lvgl.rst | 18 +++++++++--------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index af6a0d32f..2caae1099 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -799,6 +799,7 @@ The Dropdown widget is built internall from a *button* and a *list* (both not re The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. +.. _lvgl-wgt-img: ``img`` ******* @@ -983,6 +984,8 @@ By default, the Line widget width and height dimensions are set to ``size_conten line_color: 0x0000FF line_rounded: true +.. _lvgl-wgt-mtr: + ``meter`` ********* @@ -1271,6 +1274,8 @@ The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` o See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local component. +.. _lvgl-wgt-tbl: + ``table`` ********* @@ -1292,6 +1297,7 @@ The Table widget is very lightweight because only the texts are stored. No real # Example widget: - +.. _lvgl-wgt-txt: ``textarea`` ************ @@ -1317,26 +1323,7 @@ One line mode and password modes are supported. - -``canvas`` -********** - -A Canvas inherits from Image where the user can draw anything. Rectangles, texts, images, lines, arcs can be drawn here using lvgl's drawing engine. Additionally "effects" can be applied, such as rotation, zoom and blur. - -**Specific options:** - -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- Style options from :ref:`lvgl-styling`. - - -**Example:** - -.. code-block:: yaml - - # Example widget: - - - - - +.. _lvgl-wgt-obj: ``obj`` ******* diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 4aaf04297..c9ebb11fc 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -18,7 +18,7 @@ Here are a couple recipes for various interesting things you can do with :ref:`l Local light switch ------------------ -If you have a display device with a local light configured, you can simply create a wall switch for it. +If you have a display device with a local light configured, you can simply create a :ref:`lvgl-wgt-swi` for it. .. figure:: /components/images/lvgl_switch.png :align: center @@ -63,7 +63,7 @@ Remote light button .. figure:: images/lvgl_cook_remligbut.png :align: center -If you'd like to control a remote light, which appears as an entity in Home Assistant, first you need to import the light state into ESPHome, and then control it using a service call: +If you'd like to control a remote light which appears as an entity in Home Assistant from a toggle (checkable) :ref:`lvgl-wgt-btn`, first you need to import the light state into ESPHome, and then control it using a service call: .. code-block:: yaml @@ -205,7 +205,7 @@ Nothe the ``adv_hittest`` option, which ensures that accidental touches to the s Thermometer ----------- -A thermometer with a gauge acomplished with ``meter`` widget and numeric display using ``label``: +A thermometer with a gauge acomplished with :ref:`lvgl-wgt-mtr` widget and numeric display using :ref:`lvgl-wgt-lbl`: .. figure:: images/lvgl_cook_thermometer.png :align: center @@ -594,7 +594,7 @@ For this example to work, use the theme and style options from :ref:`above Date: Mon, 29 Jan 2024 08:52:45 +0100 Subject: [PATCH 171/350] Update lvgl_cook_volume.png --- cookbook/images/lvgl_cook_volume.png | Bin 1228 -> 1264 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cookbook/images/lvgl_cook_volume.png b/cookbook/images/lvgl_cook_volume.png index 7aa8924c122ab184126ede9637f7748fc31007fb..3d42748c97934c4cf05925a6fcfc36f17a9d9aa1 100644 GIT binary patch literal 1264 zcmeAS@N?(olHy`uVBq!ia0vp^9zcAag9%99v|=b=U|`wq>EaktG3V{vjo#9QBFFbn zlYXbb$}eJ*(bgavv`Ix^LXMb>h}D)n+1D>t)Vtj&*)sd?t&1D;964sVz6wxmZWY#v zadE6p~`@dH&ul-~<+i?H)caL}fe){ga@t&Cv3p$pc*nHfsVNZZzX2ni7 z|DKm$6WLz$?|s4C*d8gLDDY%@mD=)?%KOX;>p$IAlE3&l=F5+xLdm<#%bdMf|GhHo z_KjSj^JeK|k=JT!k{8hWY}c%g=-(X^lNfun=eEfF_=xb0HC)F8zMZt& zwqk}!h>w((8n5W&wk}WSqe~VhT>`onC|q>s$Lntwb{@Iu|AqZWS?TXzt1ExVohn|T zx4>j}c-i&4(~db@OV!zgGM_ z6Mwe;<*NVP5zmFH->zI$BEPWztko*+{q=wJkJ!z9^m(TDjOc5pE8-dF9F<5rIyc!& zn_>R>4aH{!j+chrv2=Ug^w8p%B&$uuW04~(lg@5S+%9!-m&4|_TOK-zXUERiyUqI* z=bNn;cP-d02n@Y#{UiEmg@z{?JF)<2vLoNQ>GWm?|dP@suf2ho|Y8k>S%XCevTu4_b6T$h7NV+FY9| zquHebVyLT^fDz9sDnuW|Jmag@_HQ~pX|6@qEFRb{t`)i@@p<7C)ieFyN zcX{%83U^Nu!>&$Gwl5DCwg;U^W{oqv6TiLF;93^TW{HL)Gv4*yoeErS>~)YV##u56Swhb zb};97t{`RQQ5qY)>-Ycrwtr);?|+}+_rBJ`uYCFBGu36awY|r$mGkp*cxHq-ZLXT~ z!fQ?AC7#Ecn=}pnUjN|9`jsoob4?|~gUFwszZ5hThV6;8bzB@(w5oFHh0L~tN4`%= zGd&c?Z@;Wvc)P@bgr~3jrivNWJyL{8d_RJ{s&_3qT>d(UW zqFAff?k-{5W$&~;{?$QWTgUCq=k8ydy10Jlf#3T3ET?VV-`Q;T!2S0*x#Q^=u-SW@GWxYI;(Y4o)FJIVLYiM=$ z!>?qE6E|M>_Z?q;^u^@v8UFvLo6dOfZab%jd7P-px>3^l;xZ*6*cR zcW<)3h<`kHs;=bn)6VnzCEP#1Wt+^pJ@xx(=iPqJ8#npPYXA3F@xnCE&lfab>%N$4 zQtr>cDDX|BTJ4nif~{#&+y8C!O#Y#E*7^FPzf;akOucl+_HKvU#`Kvc{C__|^hLkU zaQme?cVpVsFDLgrc=PddnoO_Z;}X^vhs~}<r z1p*SSrC;Rzj(fBt(JHF3I-S|w&u~w9rTgt0{pHW@-RBWheqcSl*=*Z2W&4ot-%|GN z+mY$E-9GL9{hrURfh+y>wx<01+q|*4Y)<{*ANOnT{5r3O6#qh)Nn&7yY(u}qX+KMw zX7fVzb;=uC^SxCs)Bc%Gka>}E^2OP#k5vwqw{@h=)Y*6KtNF5hcjdb@(fsN95>t%d zY?65~CsljWsi5yZb2eKuhaE0hW5kqTp&4;3)nKOnOr|r_9ZuR8z2cPmw{%%ehE9~i zQlERSfoVJaD+RAV;F3GlyH0h*@rcPw=e4YVD^ygN88UH7vASdXC*Q{KBVndB_1A^B zoRUp`IQ?VW!&yc9)3#o*oA=bN`p)_fHWu1%-fY{z@gg#_?W4#|ksW(igt7v&zSo?u nQ}Vjn(!PbfU;Y!E-Rc<=9Sm5?uSetnODP6VS3j3^P6KkC! From ef849c8f58a828517dc482ecb3bd26e8f2a34e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jan 2024 09:16:58 +0100 Subject: [PATCH 172/350] key_code --- components/lvgl.rst | 2 ++ cookbook/images/lvgl_cook_keypad.png | Bin 5839 -> 5951 bytes cookbook/lvgl.rst | 8 +++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2caae1099..cca32f694 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -643,6 +643,8 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **popover** (*Optional*, boolean): show the button label in a popover when pressing this key. - **recolor** (*Optional*, boolean): Enable recoloring of button texts with #. E.g. ``It's #ff0000 red#`` - **custom_1** and **custom_2** (*Optional*, boolean): custom free to use flags + - **key_code** (*Optional*, string): one character be sent as the key code to a :ref:`key_collector` instead of ``text`` when the button is pressed. +collector instead of the button text, if present. - **items** (*Optional*, list): Settings for the items **part**, the buttons all use the text and typical background style properties except translations and transformations. - **one_checked** (*Optional*, boolean): Allow only one button to be checked at a time (aka. radio buttons). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button matrix, uses the typical background style properties. ``pad_row`` and ``pad_column`` set the space between the buttons. diff --git a/cookbook/images/lvgl_cook_keypad.png b/cookbook/images/lvgl_cook_keypad.png index 726d0a5020a6aded62d1fd98291cfb0675710591..8fdff1916650c4ac54aabb4f45f24f8d03a26b99 100644 GIT binary patch literal 5951 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 TzWxJsFb+^r(3G!~wG8<$^H^HV literal 5839 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 IEN$ZRUnZ_bJ^%m! diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index c9ebb11fc..3cf2adebc 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -847,13 +847,15 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c control: no_repeat: true - buttons: - - text: '*' + - symbol: BACKSPACE + key_code: "*" control: no_repeat: true - text: 0 control: no_repeat: true - - text: '#' + - symbol: OK + key_code: "#" control: no_repeat: true @@ -891,7 +893,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c id: lvgl_led color: 0xFF0000 -A few notable things in this example: usage of ``align_to`` to align the text display to the led vertically; usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); changing the background color of the buttons in ``pressed`` state. +A few notable things in this example: usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); usage of ``align_to`` to align it to the led vertically; changing the background color of the buttons in ``pressed`` state; using the ``key_code`` configuration option to send a different character to ``key_collector`` instead of the displayed symbol. .. _lvgl-cook-idlescreen: From beecfe80d1b682c4a27a70e0080c538af4235a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jan 2024 09:22:36 +0100 Subject: [PATCH 173/350] Update lvgl.rst --- components/lvgl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index cca32f694..311075c00 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -631,8 +631,9 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **buttons** (**Required**, list): A list of buttons in a row: - **id** (*Optional*): An ID for a button - **text** or **symbol** (*Optional*): Text or built-in :ref:`symbol ` to display on the button. - - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1``. E.g. in a line with two buttons: btnA, width = 1 and btnB, width = 2, btnA will have 33 % width and btnB will have 66 % width. + - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1`` (eg. in a line with two buttons: one ``width: 1`` and another one ``width: 2``, the first will be ``33%`` wide while the second will be ``66%`` wide). - **selected** (*Optional*, boolean): Set the button as the most recently released or focused. Defaults to ``false``. + - **key_code** (*Optional*, string): One character be sent as the key code to a :ref:`key_collector` instead of ``text`` when the button is pressed. - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): - **hidden** (*Optional*, boolean): makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). - **no_repeat** (*Optional*, boolean): Disable repeating when the button is long pressed. @@ -643,8 +644,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **popover** (*Optional*, boolean): show the button label in a popover when pressing this key. - **recolor** (*Optional*, boolean): Enable recoloring of button texts with #. E.g. ``It's #ff0000 red#`` - **custom_1** and **custom_2** (*Optional*, boolean): custom free to use flags - - **key_code** (*Optional*, string): one character be sent as the key code to a :ref:`key_collector` instead of ``text`` when the button is pressed. -collector instead of the button text, if present. + - **items** (*Optional*, list): Settings for the items **part**, the buttons all use the text and typical background style properties except translations and transformations. - **one_checked** (*Optional*, boolean): Allow only one button to be checked at a time (aka. radio buttons). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button matrix, uses the typical background style properties. ``pad_row`` and ``pad_column`` set the space between the buttons. From 29bbd71aa94a52f5310625ef072e82b01f25a28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jan 2024 11:04:49 +0100 Subject: [PATCH 174/350] symbols list update --- components/images/lvgl_symbols.png | Bin 38208 -> 55365 bytes components/lvgl.rst | 8 ++++---- cookbook/lvgl.rst | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/images/lvgl_symbols.png b/components/images/lvgl_symbols.png index 6b9d14d8642dd0a30d4ec51bdb03b43f553d0847..8ac564a53129f1daef35c74b8829837c03e7b516 100644 GIT binary patch literal 55365 zcmZsjby!thxAr$7T>{dfG*Z$HN{6&`OLun)0@4zKv~&qbcXxM4cXvvEQ=d5RIp4c3 z|M22c_TF>PHRkx;_dQmyysS7X5&;qf0zs9O5K)9cpa&rkC`<%s@RQ&opHc|qIYd(A z%{$lR{YGumIn&ukpZkYjEzsy{pPwKr=IP;Jjtf~C>t`m!IlYB`8f zLA&5@hsz;DlP&B0!w&sHIJphmMK8xrkMxe{d#U}aPA^klDZNldi6~Tt`2bkM8DA83 z3HT59#Pj$Y5fuHW(mF-x*&XiHB}ZO+bxXy2k9S*wk5IUOUGXr>kG#9^wswCm?#deP zz|cQe|C^N?e8#^n_<%i=8b_>(;E0>2T3T9Ygw@OSGb1@^A2<|@nX%G7mD3ZZeR8=< z(2}JI$q-=_rLuWTa^YW7Q$vJ#EtE>QN)}Ic7}}EkwCEZ?+a!Da9cJN6{xlpN1c>iq zDxaK+LhSqWyn@{~O9)mOt5PT5j_ltqBlAIy=^8R<#P8`LL8eA2sVrAd?R(;!2F)eG zOY)JvU6krm#*a7`wdHcRH5%a{p@t78e1EAQr@Nxrc++$I>0OkFLYA4v(${3Exaod4 z|4!;v?=->kuTZ`dS}$*D3Xd{8CpJRk4RpK7;>mBizz?gFV>l?hq>Y)|ab5Gt6a-#k zBY9n1sFseZWx~^`_PrGpR=|cx5MsL9(7$MPcoSy?^*V0DKKuKW@-gI=nefg_Ua-qv z)h-)>7Xoo49YnR;$5(MDfAR5nQkF9z2>(vpn%m@O;pnzF4L=jZeM1%@HsRIuR&#XO zD1)`b)60P-ZSB(2#S0(W>-&de(l*HR#xL@nu9Z=vQK>90(iIxJ2@tGDr3Qs1wV=3X z)1q$D9LYj%v_5G|_8#l~pDa{}MHN`kS+h!Cod~L5nQXJOLSW(jrmeNcEsQ-f=|Wg| z1^aPbD~nm6sIZYJALH0!?ZUA5C7uO;Pk?&uPN%%2sx0#a{gv0ia_t+>Czxdu_1X1S zMA!J?$tYAUdU8{kcEYhQF|qUr8l5b^c}}!lA^);*QyOB}!kotJo$D2wZbg%^q~{Re zK!e;V3AoYK*3~7ZN^6poSkkS?wRxoRV>DqSGh4j3##ra)RJq8=@E9Fvs$17;+1`h*qBaWVi~)j)duWx# zI>gQ9KizG;qlSvUlRrqqqA%~lLB2wSZ=IV{sxl=@D09+&dW9{%;shIpyfNxW{RpCa zzUr=&TV`^q9I{2*n4I(`Id3)nMmF3q>TY*vi6~e~V-NJiNt9WUgrI~w`$hW_qYcZv zgaGyzZglyyi2^paxdkxgpc@wh>>AN@@4;f*Cd4gtd8&~O#A zv0Ngbz|&!R(j_L(c> zId?hVd7B}xuW5HGvyzof6Rj(db;TE>D~VB$GHy-FeZ2Zw7|`we&r{6KLdC0TACYx$ zt4rSzetxNF|I+Ldn^-4{PG!+6x;nanL0n*|{^|WwRMLY7hVMwRkz@DKIX;4ys-+3W~8Rv>K*=cdBSauE;Utq1sRsvqRd0~c<>;7>5kizO_5RLfi zXHeG=kEp`0XAeUMyl@9yVg{otd5ba4N3nH6ZsGR^I6+?W?_`XI54Gd?+x_6zt$rHE zU-Q(MIlaxHC&J)-v{x!RA|%>S{Uy7|6B{YDAiWWPW~H0uK(`iIMxTjG@0ZA1dW znHJ5?LAke+SQlWFTFpFlfnroSsRzaC8Ra`@`I2e1VXA+#mmpCb%hEA^*q--%$wJ zyDMeRWuNdH1=xbyw%F3L!=y{xe6x3^t0_=xKv!5$*HkqG`&F#H zluaf`5YZwra53GylHmHZx-iAu!Qhe`zd78B(uT6MaC8L{l0maqGM$^7lK?T$&n%A9 zefK6dp2ekH)A9(aTqD{mdBbOAa#p8&aoLUHG0xGu@|Q^Rj>*7Ux^ZSV_3G#-jqY*) zyS}lxv9bB)!@O7M&wJv%^z-kqBrU>eGSXhdec!NVuUMsqrKGeK_Ff(?ll3xeL7qDs zr9CebJdCKg_VV7Zi2hccm%l~Fhb5H$S>Iq=2;t~Gbyyk36fBhd`b@5+C zlv$JPUKAvdcQUBw@RrWpbqhN}x@!i9lWHa3yVEn_4rAtHi*g z#55%)-&GbwJH?%AMC(Y;n-E#ItXzF=9%i~L0Y!I%{=>MqF|&a)%Q5n|sKS-3i9)9@ z-{)&Xwahs-wm)c8>@SKde<`#-PPU6y&pc?9T(|EyPDM*a-(Aa^7ag*v>BuprD&^#n z89xc;vM!{^jqcTyOj7>np|;a{b68MUSB2C;^prY#F*Uy^y$Ohi=51l|LP@P({5)=Lz0dqv z7Ea8CeIOk>Io7>ToWGa9)u;U4vYn^Vp#RV-$_0TBr@yGEI?cJfN_=$~hxPS`yaae* z|IOZ89u6_i0X$*?fvc?ESh_LF;OyQ~2xtZXkY>ZcuzMtGbBzh=j%>c7Ra5ExRwYJ4Hjz}GuQ^xQZTei{!$?h z@fDnS<@xuIk1ceGA900FoyQbQ5;_NZjwRL=VVP{8AfBF%T;@N`jxO9R<|5!`z)2QT zBBHOX2OXxNI_lAJ&g!c3b&wIpb$xMu&%u0|(SD{KlvNaq#eFaFppU~rN>_^GF1fV2 z$mNZ7?~Ote-s^}o7q`kpElH9AU zm*&x=8wZgkbLrwbm%oH>VhzrDw0^h3AVQc$kz7vXcBagk9%xH^-hhD;sze{oX#J^_ zu5{a$jfE)P%du8#h;P6am%$x7dG7-(FaB;s-(|ULCsGsk{nLfK34c0&=h8D)0w;|Q zF@x+cm?Rkn&;$3)OVn2aI-W#?<=e9aq=acryk1+E#EChfbe-$(SgMni_FisezBef4 ztv>n;U+BbcXQdj-C5v0z()-pf`>Xl@{e45M?$DaR-TBpy7{6sjq*!8Rr6fxGM?u7R zI-{L%SQ0(>OENA{LFEf4TM~S{gsu-SUD}XWHj9$3whrZV(ujg1^nQL_BC`TrFX$o4 zafg%B#-7n}k~zM3R~(D_#{0M!tW}tdzU4X{8^ZD!Z_fsmh&TEPH zP==P@*S zuL^f?;`4Bp_NaC!k4;ImSja>}DhjtW5y_q2>{=?1;)5xWJnCpBTwtvl*-td%ufLO< z4Ql;54pj^Ny+N-x>f9TLuPReJPaH_OgKX5Nzf;U(P^%hIwQ#AsxFZlHl4#*qh_^cx zvB_*bCTuaVcoS-_G!m^5WGIpl8ngr_-6^bSf zwoqGvZG|ixQSlci_ttswp%u+3b~;IO#!l^Z9Pd{{al9|lWYCLIX4|djDLe({-F%zZ zdY4`sjeY2zvO8;N{+MAm|6H% zA5)eZ7Epb2)@pC}})}xo+_!o4E$_FPaxjntZ^>>wC90N=N9<{Xo~jBLm$k-sfL56J+AoV~-sGN3 z_a0pZJ^q+ZSqu5lAt~9-_Ht;(>X~TNKFL}j*X0$xnPWvTfV}K2%1e~c!bIJ)N2yey zDM2`%*pD@geVSd9Ut;4!Jn^}UelN@VV*=;-``L+^z`mt13>i94V(QE2mzc61VppSF zO*KE?l4p|Rs2)Q=V-62zrxp=oouAn`H2lr;-Tt0htrp-$(I(UFdlGyS?*7zpFJe{^ zvj*oijZ>AeSMIqqNX>0)>!X|X^q$T2Xqt<$4*j(ql_ICk(P3J$B>t_E?#Bia&uBSt z2uTUyArG`^4PUghwXG%sRjR%mQ;Xyuzy8(MB(!>U3*gS^e*yYzFM_1G4?D=Gq=ImNAW%u;%OLPP>vXrP$J%igE%KuV^-$R>ijViU{ zi}mbA2E-Bv%I!~&n5{5bF;KZ0D1e3GeSCf#xBG1%czKeM+_#afH^)R~94y&5SlRuR61E9h(OF|7%_jz5>reqJd%}Uc}?+$N7}4#@6SD7fTcr0 z{W!o*9ARLCKxl$5S`1+1_CH~y>SwkkoqH&}s^?gewoS@m=HTIFzTs(C)(a~~@=Hq| zB>ye=nCj@&z&yf*oy8?nNmp$J=tZ)|FY8v^r?n?;vZZ)sg2ve)Y?#Efr=tFaABdkM zmrZ(RcuCr5B-e%#Jvt5#1Es(vN>f*tIt9I{rTeksXi8C3N|rJSZPAGl@ozxcJL#88 z!0XYPhm%vtZ9j?4$>puUJv{haZD?h}IjvEogM9vk;0Zcq(zthX^LfR)!pR?Lc9;xK zZ+~b`7fekqUoQ`8auO1M_KKy%g53*?3@1!1uicnmcS2^+VEG3^idkW5^4-CCBrJnV z7%m!=8RsDN8$psH*J(+ym6are;{V|fT!_2?Qloeu{1aV~;y(9Xrg=<7?ChNdIkuDF z8e!`8*X!j75Vn_HmmW^Z$Y9ef{||`-IMDATzh}-eR*H>O+}o9KgoS5n)1!ugltm_C z>!7HQrC@Ju<0`OF+gfwu-jfj!ho8#1PzG^CX?@AeRJh0M6VE=(KJCBGc>&KGFT#aQ zwG^?rsZ&AZ z5kBraH+ zewSI=MIUy9YRNpq1*8Z8EDFT;^vzSX@4`4=NrRS5&wkO_hp_M4GwbWSb22n_h(0KbD;t6cgzqQ#X((2Gu+iEu-fmE znW(EfAIB_Sr7n>p=vpz}GU@+v`deRkKuOH8!-91&UPUQRp|{TR#7@xb{2bi$#JOef zgrEu=*~6eZHgY$s-p0#{SdRGgra?m+NKJbddr?e2_21x+!zgeuMHQxWOXTEaSfN7o zx$H{>Ovfb984yYgC_%UR7yGPL=4ztMOt#dziD!^o3eE+_jJ{-(frt0Y{-S8f7N`D<&0-vcuj zh9j3K+*)3n&9n{x35aQ8&VlLnLK8mT`W*`7bF~pbr^wk`#@r#rAmNy6d{g9={Mt2x zwZI#m>g2-v`oKmE*5JM1nJ;(|`OlRpgb#n^APj$$H(lx=btp6AW0i2F`hnFIqN7%> z_S|65TYqH+g1^_hg12Fs7s`r;)am!lwK^q+XHIrV z7N01?K1)c1KoHHrE+w$obgc0XdWfz_MY+s8Mn`(gBKS6}aMB`I2PLa;v??Y&-Z7}t z&C`+yIgIJpJj`3w3e`^rf%o#A8L=x(U;Sq&l_lkF2ozj6RY zwn@Eo*1AlBPaiVV$Mu7(H#s-Vc$Wr1h%v@t1#MK6bkvL*JsSoz#M9kz=Dj*G#MNtY zwkmV9vem(Vl}gGOWEO9Vb&IvGC6 z5qs1bT5=A8OfSb(jf|bBOZKQHmmN~j;6(xXNFqsN7wYjq1RO7ZwQU&<*u^`?=C?W+ zFdl*T7uO}G$lPuvGx3hpo%rY}>+xrZwwum zM@clZ0B?$GBR-mQmLEQ>1Op5vf?q1@LkZL_C#GlbBygdi9`D*KCxzYojesS zTChygf=ob>;`$+XbL*JNJ0?J27J);>jDqz*p;a84&57yiOFR=gWLQpj>XvnvL*E$X zoOyE2EW8zX%s4+cO8&HlJf8g8XR{(?u55j41M|S?^WS% zB!^4PN%6#`rd*J;i--`*4#B=BGoSgYJH$!AHVVX}0QOdlQe52W|XdTE^SDBtuL^hkjkDp}bTGd3`mSj-1{I*N%q3bY)zoq!Yqs&7@f%?9SLM z`3F|4D_n1uKXYX5I$vPt!sw|3&~4k*p%qP{dC;|EiQOt)&5MQbKM%y}i;`IV724|U zEVP=`aUPpVtFFEE`M~Lp!O3!`wv?(aGOqA+rCECf2MLYK96n7RgQbdLhLwKDnTRt& z3ULJHJy$wWFhxW&9_A9oz{!MD;^hlsq9DtXHJf|`>EUa9e;EHZ={LltUL5l9%Mh5u ztPO+CC>kg&W+DSLT})~r6!A&z(b)Ei>EIs|rP*6uGQj@$eW9V&yMFuI9brsa22P2# zZ&>xgA2!J_;1nd+?NQ|{gkW%CeG2b7kAyp3^ml(9Z-6dq`2of~b?R3j_`f`+Sm`bj z`E-z$RHH$=OD!#l{Y{h44mu(VC_#i>E6gSAT(JMb2VW%mU+@w4)5{%0k$ThUup2{_ zdx4BSJ|sd6o$qw5)d6rvuoMPo$A0^FBiHTa*ROa8_*Lj;(0}GokA4dZR1(ZQZ@{jd zuwD4kIxO)AG0cQnh{UW_v5lO)VcvCr#gY!kzJ%wxN>YBz1+AwP@ks{SMC!UJbT(sms!@mF{M3 zD*hDr$Zt=82nYT&%_1e9_a_Uvgx@``Qy-R!pdqZM9A*MM=u?rKk8p; z&++zwZD;4ccqe$aa<(#|RiH&n7@>cYAm*Lh_=PnTzo|v~8KU^!4IrU`l$^`%8H<6} zLD3k~qGx?_ebS;$VKgC%#j#(ko&;^Zhgajb-$qn~o)sB)$?3Hmh>dJ3l|e22rFf;d zS=M|$K6bufR@MRy;p`}FHtA&v2eW!&m6j#F`*^p z18IL2Yejj7IQseYH)c40SvrD;sK<4xk}Zgro2XY7XCRI365yl_GJ3w@r;E%n+rDoa z@U|4(+ng>HDJld?4WOA@pJto!vFtw%4CLFyms2rrV5UvM`e*6|*SwH=7L53+b|d*= zR_&Mm3wzpVru7R>)L9Ww%pTI*&Ytn84lTCd0k>pZHqg6Osf1{u7vekfMeQN&TBA{{ zDai3~zG>V%m*11Zfg#obi`QSOx)965b&`rIYq@*j4%M z2{7N#E+d@2`LK<2^$^X9D2kG0qV3&`S06VYSNcp7JkgCY!iS(d)u4x|id~9z(tQS@ z5u|L4i!Dcz8Rw`U&_&Hv`#x!|rszm&)B zS;R+RVGQ{&^9mN;;_u^gaNr~*B#z#PB`qz6g?A39?uFPpH?L_*F2<3kX-b?s(owU= zW9lHZe)#q->iDsgj``!~^u70|U51(1VH|H4zlvyn+HVe%>o_T7WW#8C77%0bN|tS^ zmI4Cd^T_Qf3lom)KQbCaHNwlOQKVPxn_=gsm2!P`1p$6mIlx1s6O=Ucpy41OT-$Z~ z9}7L__lA5kORVoXk-NG>X=-u6t-ZK#8oORb_Pmory?vvJ)Uh*?GqVy?Z76Kan>3@F zTW?B=;k+l~x8=WL%SD8?_VxHi9LCi~difn&3T)`RU8D`G#mEfLzl@T8GguPP;3a8q z?&TGPEWUssoF5qbbdeNiuWe++=njGQUx~UAJ8GB=GExznAw$uCK~*BRT1Trpvsc{0 z#61rc$F!aulC_0Oy`#nbE0exI&#w))4O?^tRyrklkc|pts4#h z?X;wVP!tnYlO#eRv@^?Tz}S&?x2_mxp}p*d#BTv1HN z^G4RDrg@Xk=>FI(vS=`n_NdtSG4sStiyDiob~J3{+rZ18<=+Le5gru^r{{yGE|-hn z376Thnj%9%4lGU$j7f|$+7&$Wd-wQMYLx%U0>q$il6>x~6?74Fqr)c-A9_2Ob(l>r zGhS;CEWK}^N;;NnpIcwWrpEc<`g!OcSJ1&%>t1vYMD<5mQ+lcSG@?P~jfNURZ^?r^ z#FL2(B+0{_L@{~#;6;y0O`yXXD5Y&EtI{T&+0N1OXLYRH6k}hHv!Nk|u;TPiHpYF` zP|XgZP|n)Vq?dIZlR$LchP`qCg1m+*AjM6T7$DROQ*-!JSuKy`Ozkr@|8Dmca~r`< zl3j~%;m5ZIk_EuaCpv0a#yQ5|&*AWbP3znYR7tnR%$PjU!5frLDBlK#OeA2nFCHhs z9}|(`dh8dX{}0e~EgFVod{$!o*9W@)K4ZFnvbqMa0XWUFA_r>R1qH<=MXXRcE3Ykw z>AGKWtQd0bzc$M#EmooW%`5@L@`3s@P&mpM1Xt0B4^;e_8GFS0SUQE5IOtT02TPENua@K@+C+6&cj#jaJ`|11Jx%1a%i4oxb zzJ1R91sJ5x*g@@5L^Iiwy9AyU)#8&AuYFpKaj!qFFKK8ywcz2?&H48YJnEMM3=FSExM4b~2R z0`K>*bPe_V>{TYGb5d$3^%deUtaIBhO+*W5EIlF;e=}i&`U;xh#>j$~svFC-jp^&l zNB*r#@L$kFrq{A*r0(KfNA9oTyW7x_cOH|vkYO&u!M5rpj7jK3VM`KX7T^%@av^{K zu`$wYH681a#YE6l=sJ(Omik6~cF8^HL->_mTaIu>e5msrkva)`MX*FE8Y(JiRoCa& zs9eEDYv(wtJr`%&$R6>?8s2-8gy8Ip_==-`|FFLN@hG)lcpCaLs=gn@jAjG`ssw+#B952}B_)@xhB=Rqemj&9AUW9mszd2 z`SrnfE(avjQ~oef+n0ktew+UI_QuxZ<0m7M_Ai6sWt=&^@ny864M~i@LJXF6CN<)} zvL-nPDQQ&He_D|9^O76*HRI~uq<=@*FR(jSj(HvB=+ueI>`aM693d7+UJ=O{-w%H0 ze9Y!?ZKFVmKuTZg|Bp3{mmKx4Zo)`p#$)TqYA6YKl@`<`Mm-+Zo1U#B;6qxz>IMZr4v01 zY}1(k+C?QVp@H7X)PMo%P-Ci{JxW(^e?HxBo-y2B`m!h$8w8D>$Np>>eX{X0RuL?p z0y(-H(}B|rdU%lRX}?=pLH8dds?NbQNS>R(Y|sj5NVMM2p_$e0&filmtTtw?ET$?x z7?;_()(OBAARQ7IGWHn&B`weC%c;WXXx_%Iuh__Md{M#pzxYyRSdI+QgZ~&WqD8& z;1YVN_iOm^x8taWfX_TOEPcJf7t#9VLBPs2ft$N)2X`l$0z=4^o6apnWqgFgk2n)$ z`6JyMA9B->(z%wvZPRxJ65wD63g|Y7`nmha5-t|!fcC^$fEUoGo3IS zfn0ohK>%0^Kp*0JMY7Dw@lA~;P!MsB-cdk43pKw^`(TRg7At&F;I}(cK2^vU@vPWh z3k86PYy~DbrGTBEE-yhU$!$&4BqLYx1|7Tp0mc8ymSX55sv{|b>PDu!<~IgxB2#YL zo_q=?Cd%)Kr6mT`*}k=XcFeXEz+I36R1x8JGtgeW6U?#w!QStz4IK@oPqR$sQ{nm1t5H=Z2Yrc?Ni<7JXwcCq9?eB`>fj-7b0Pky{qzUD>eIf*r@*%ibvp=MG1u3 zmA!*kBFb+xKjoP9hu?Jn6$tY&gnoM`XLnX_Zs;mfAOS~8$^C`CBpy{g7Nk#_ha=-p z|4)W$2Ol5hYQgKP2d%^Fxnc>~e{2%HFc~)?Wf!Nrf)~=|=VJDl;;qNGN&>s5o&AB& zMhyq`N@8-RCJLWJfE^nwNDbm=;oizbWGF=Mw8BZu3|%`Oc?BZ^3Jhpfx7GAk>r5kT z<=pan;-9Wf^1XJ;Z~gG5p{*R%X#@HC@%re|&h^LA7AM8))~_<;-h zmCs{S=eE8(p6@E#@BMr?7sy!=p9_^ zSN2YOPFX3*JMhpD0?}O_^oE;~`ag-TSsDR0XBI$BagF5esYdtt?YNi9KfRktA%^NW zy1_L~Dtj*ro);Ad2(v6pstqvnhinR4n=x>Voni3XM$m1Ua1-U~S zMzu3^rh7cP8)XVpXwiQ>VzTM0-OyUqXrl`J-Y9GN-7L@VBRdqQL0P2B64Fl)Sz;Jd zI$TlBj0q_mC1<$%fl-Uynm>FJWr`JrA1KL#i}!Cdth2E~KxF8Z%=m~0MH6Q2FgFoj zy|NQXl@OBzr{BdI@yq2TGpfQu;GT$sca~FVOP;NNtgGZm7kRl-J?_lXMs#sLwv_1eL+sTKph!( zgQz=Q@0|U*!y2(%+U|NmLkU(PbQ^MOnMh2tAX-y&svM9w&0|A5bg1K|D!%)n?Cf0Y z{+eyRnyek7D;A5yCJY^XJGgC=|2Hcw6*_!?g1BDFMj8FYI8EM%KEJ)s&dt^+3hbN; ztOKVR=qO~$<-j2vXLQ!@R+UysU%oE)vYSBcy79pxNyfN&At%el^vxD0 z&vPOv8drfH?}1%nyx1UM$QBgrYSPouB$*dA7W7&-BF>5cO5YY?;llsz6p|@n2k5RG z%{Lj$ko+-b5DRmW7t?w?kt$j?tc~-wJbDWm#^)8F}{l^V>jJ z5!%ioBz~8OeyFF{^w5wxzfmecdNI?~b{nZoGnLd5wwRe{2Gh=r+;<9bKonm=)(^?( zaeY&~D*?Vm5VpJ>nYp$MenTC{R^Ye4gj1xV6&Lw&?xaRPrRUWRVW9`Z%5((I1YP zyN?3K;OGjC%Jlk0FT4YK^47<<3(_)6DVxBBO90I_OLE?na@jZ&7Y18o16UJabkVHR zF@y3aHQu}R-T@oN`Q<%5Fx8N-M(FvM3u zO1bGs84VLn0uJxJ;UGP8ECtW|#1HaMS|+||4zbS~y_(t$ojmtUJTN&anb6O-ap#q` zs<3$jy@e*jX{Id%k`2d@RO3;FCzEyHL!!)gf2$_|JtyB||6*^8lHNxXXkLB3*J@Z_ zTXgj0_g(_4^u~;~{A)rJFFziEB@arDAiH|VaeT`|yvp=)W+Q(=4%`h4N4+hRyj8vN z&y8(+TRbFcmniAML)o=9W##?8rkuBz-3zq1-f5)Of)XQ|B2^-P(8rEADp~4xfeDOK zN{FhU;jRdHC!<{WQvEc0I{I8=RbWkP5+5TKG5zz!1h)fa({Xzfw~MjG?7KG{74PhR z3XXwvPo#EmLN49xXhzGWz$$Z%Lzl9wp+iiLSy8bQS2>sGi{!fLbwUuLo2RjIecGl5 z60#KmASj_Fdm!zVG(7(;%VpXxoQQy$U752q8beHZa@8H+dx5G$^qrM?5vq2u*P06=4eJG;LoL59J6lyD77W*lX1AZV0yG&Wx7 zDC%%J^Pk8WwkR`{Sb@ZYfS~%$9_uLt;ymwaybwg6Y$<55Eg-Wfi>6I9Ry|Q=5p022 z5e!s9&JH6|qu#)XniqY_Zlrb_s4WG?JVi|yOa*Z?UG zH=dMWL1w(Ca{SCQ>ZS^FHiKe{1KU@k2i_YSx>DHF`k4UL<1rRj2Vqn{)X93CR<*k% z(IdG*pkzZ)k`=TNovIl>UcQ17D=OUPe}99o6*+eVPPmVc&%S!Y^-KR$SuY5KFFfAI zh<(2DX#C9uCkp58;hM2Zus$-VFP4G5ULM25nrawv1 z(^X=3msp@Rs~`r|XQo%)&Ehx}$}s z%W4z{=#4>_1|o!ZHH5dAXpq1C$n|hZ;TF5DD}Tk`iXdPk@fcot%;pt07VH?V2QcA;xIgpkkswrbs(1g@pDBmYn@>^P_u(sy zQSAw=-N$GcRVRL5&D<1vzb%GYbQxi15*l%`^vezhmOB)E1jgICxd@O)Zd(OEHw9rqAV(A z)dZ2@yRLz6($m5fk})te3`D%5!neMN0YbgalqU;H4zxshu^q=PU;pIGX1abyJm`pl zBd#L;pVm(v*I(98PNe<~zLyc}UwGvdtGhfiHUX+^ML^HA9C;GQjn_FI`=uiD_6I~T zoYFb?298-fs$&uBLGkqVenoJgJ|)_McIq5Ql4aoSJ!s0 zXgrXe6~ni~P$DIs^)CM+I1GjP)Y%mAvjcHkOE4rOmd?mXv-K1h-bD5a?sVxPC*~kS zCZ3((`QlOV@m>%O{qpwC{r>Iyhk&2nm-WrwCJzCFaOM}caepz=x%rRL889>S=;ED> zD%`DDfp-_eW+~D`<{2kkx!mGakn>&=C6$ovmeNpJNsD&X_VmwuPj{6{=>;o^F+}g? zkPWiT=>m-T%wfj+2E(ECh>NF$q2ZC?Am>j-QB0W_2*sY#ThunQRIJ=|EK|ka+70vg;^lH0m)u zN%q#<@ilQHFe-^V@`6BJcBOp<1*Z$!DBdRh;?xb+L@UFqzB%>J&<%h5Rg@`}8{N;b zli0MfFl<@lXa9mx;H&sJIP-T5+iEJf93_Eb1e*U^R4zEPB8E8XFr%Z}%gfInH1p{| zb?MK`S$@kf7WgrMGoKa51`{aPmy766Tykd~?>`AE!SnuH^Q9x0oRh*@z`Aq?j0VVeyy7(3^pWXK~ zmW$~h-|2zi;rI4p322+BMXA#&qU(8~kGYzdfUn}T)$Ns2Q_`$>sh@C_KM!`W;`{33 z>ktoaxI|(EMVsF#`XbOJuq@R%-1lg*T({}{Z2$qoC# zFMs}I5tjKcFYmIW7tP5gx9ZZ5VRw|mxI!zoYMuKX2sN90z2G;2 z7sq%=(2IMjD9U0;QA)x6MGIsK%iCkP-XW_|>E2m|wij%=PQ8?wsuW`sA6q)wi>=y! z+S!j<(@#|4H>f^O>XM5y_P?fIR8lom)uH=oU;Q5(`QbNWRk-rep2l zGz+=^Mn|`mJif68cBf_S+!-4(zxzyF*U;42sYyk56=?M3ld`zN#I@YdRNjFCCozcoaZvUe zd1$G+H=da?bBKk)t}**)07EW7F~2(pY@)|W6g5mLW`Sa z8pz-Iwz67DtNK8XQmuiRxd~r~{AIDQ2VjU~8;6&7eK%9UQ$UMk3D!&O^Enkr)#1lcv1UY)KnZQiZi%_=>oQgbB2*QH^9vDfz{^rWB z6Oz&46CAkcH1B$Gbq%7HhUx+Z`>kJ(18jFwD__6~``;{WUf|v`3QbJ@%T$OJCf}%r z=a(n-M$~Md*8p6@&%Ao{76kKbskXBScc15t80~3SdpOG!`wz?WcXwxBVz5f=7baqr zhRqKRKTioG)71iDX*uMJF`d(**W-?kTs&X|6~yjhf~=B##Y{GS5B5y6hjTowbul%i zX--zf&JI|bhDkIgT7H!#>m#BBDu%ebo7g|j5y66zJ6(Pv!OhpaEa&+e)A|Z?r69!* z_u+U|X;w7R5tJ)`vTswkI!ItkE*QxZuCYna9u&9tX#gOqrz08=9m7(ZS3>V zF5bUx6WI`xn*x*bpZth9`7CArHvSjD)RDsr)FIEA>Gli5V2z05? zKi9ZQ^AmCuNA1R%C!a~Gy`4Q(T(9OTihe%#{WLB)QD&vLXuo^^JY@lK4bMOA>3v238pRz+!wG+a zVZF*a94^9d4L~uSyi)Fy)|cCmV8bGgIHlt=Q}JlJxhWJgQvbhXHuJjZ{h9g5VBH@A z>;Xw!s{#0$>-eN?hLA^E5-zMfYZU-tWkhQZc{uxqdAu*@hIf^Nrnf-!GD(GfU3B@^ zo%$jj{S<-KIobwzglLHjggyX>bGcOfR>f68)F)pg23s;vxT9lJ+ z1{{TPP32t5(@pw8b;lsc_s93t$AW@ww^8T^V<|;N#XhQ7gp>ylO zWD#8=oGutk+M(4rV{HRrn|b$RnRpV26rb!0Q*?+Qmy|I6uEHIC;$58$i`0DSXY~@o*njVngCtF>xMWe#l z+Q7pMj(&n9?Ky)fmMEjB?I)7<1Lw3AotFYnT}~-@Hlz}EOpZPEK%Ou+0}YH6=Qotm zgOR$*Vn6tqNEeuWY}F7h57Y&52jS!u^1m=K-GB?fMl;XJiGt^p;tDpXz7+98e4;dn z=QImEeyLzt{4^cOUbX`gLg2_j816*1OPBwoyV8n8k7+L*6bJ{g(`FOFA;l-&c@s+5 zLOXjA8J=;vXG98=2(8s&#CH3~sFkPrWcV+k6iFz;s|dH}xBnr<(()N76?AyZ{2(QA zU(XkE#^V*;M`zUFnF!)YoUx{T;-&ZdEi8<7B>IE>5~z z$-9r`8(M;LR+V=D!&jg{;Uz-FO$~$SA2N!lW_MXn^@-xYfkr3x3>gvQD0W}3`IFKU zklLFZG~d+EQApVo@dmV5g)uj*_%AO8hP=CrMwN8+glI+1x@;> zG=Jk9k@k@ft~-XaL!lIQrgWLXx|1*?)sUeQxyJ;Ue;P9@?1m@}1uj zQALU5zGgldWo|SFa}&K44?lb3&HD>LXkdgDOql2(Z^NJc&N34A=gMvc=9mEs=gAFp z9PW-xC@}QxlFMLyC_G*>#~Cfj`IUw<)m~D>)$a4|l=!Ryc>6_i>h}Mr@a_As| zJvT5Bc4#txcWG=%KSe`weLiu%ej#};etdfe@~4BnlSF+?|I2(cROH_&qOj?Y8YY*O z#xx5S>#U?1=*fIVV|3odnTXJdFg9xN_u5bOR4!`8}s(BKOan z(yltxC{=V}SuKu(-vdS9fs{5gg;ABr^|!o4DGsgw$JSp*Rkg)?AN$KtokZz>AL!`T;r5ow^O+Dw_d!O;XdoUdP55{(|_F8j(KRE$^?ke)L zZeY|B!kz4H()s30U757FKH%(akw+1z>ZrCK%nT&Osf=qH3fH!(z3(n%&a?kDE$-cnHl3+v5b7?D(~P#!E0M^O;@f-;o}}>o zixva!xiN@YNrTFmTP@kb^Jrd_A36kv^S<2Y4)mm5HADRuF;ZE~p+`mZ<^$ZWMI>Wm^F7nBDr%x|-bDN(QY%d1r_ey7DkTO% z`rScnu@Jxn5yMrGD zVvu!016yObzDqg3;*EeiQ5D4ndHeq@l0a@gux--Qf&+ZzkJfmFouKT-Q69(`kkiM< z`2W%Sz0_BQ+y~b~bCz11F`vAij;|JZGKdhfT3Ayu6_YX(nv{v>hBW-5MrU^r^sY5H@OK(zf2O<&%V4A~ISx*s@!KP)Jd z^3zGu-_=48@Riz9Rnyhi0Y=UT6U4K4-N=YbAY%eYXnWT=thc+>N6Q?;SM-@3oe$$V zexJN#9>_n&bR&E?l_y$D>3Do+^y~L>Ko^<720Y5{!M@c3$`a6)!q!}IcbOk=XTdo%hofLi6oOdtyZG- zH!**TC)lJ=JONw*0M$8MBLnc!u45)2H6J&!r6wj!O;4FlpR_myVQDFMq>N)i5n3BVg4 zoS`Cy+JsO!fN<85L1FIvpUPM|RQjPwqp9lZi>J~ih_K;4^QCg<0j>%yn2kS><$(jh_gM5o%>_Je|eAE z{``WDiVMfueof0EFQhwd)jCM*mG~wlB;^0bwbI}~8a1_{ZuABeef-!n`CrKPr4u>F zi(`VQ4B7~f>RtwnfpYc~ClLNh+`;}#?Xu^{OLHnPA7iZTvB-tcac2U|nKO5F7;Hf= zM;BuDg=fWWatkYMDZ=SfC}K(EUgrohu>k2aU#r^UHVr7>qg+5kCo(QfTAeD%7KlTZ zL+`@<_jgEBAi0RYPS=e+_UlgxT^^M!WWmGl@p}M`{8uwiJShn&6lC}JPb=W~&K5^* zZyu)Ym-UD|>)J-V0bJfGha(cEL0j7G$SQui6WH;t<0`j`Z_8iWN>3l|RS}ErM}vI8 zw*#$eSq$!;xrAgdm@8=>3-SGQ^)PcB_8`M+a8t0o*gRbu3xDIN4LjyK=G&rwZ?hZb12gK>DglD9=bZV;W1$jLPGrUzb0ldplNk~66~JL2BKWsG8XMO_QiD3UIA;a%kC;*@XaiKChb>8}P1E zBZKA#?w+*>kOoOMPNVsMTk3YL_fPursCN`g!OH#K$knj(yc0VG?9UuNMcTfAtT)lv9}X?>vGD;m zM5pMst=J0upS#AOpGO(X86!dtl<^@#Kq}Mxk*~YrgeM^*hXy=X8`@-8FSMS+S94%O z{*gelLqTfjLCD99^+U2t&p&onIEugBdDeO{nzwnIS9je$@Gu=R+=YTSVn5m18YsQ9 zR;qt-U>W`|j9oSSYiZ4)*~75T}5C~zJ7r-i4mc=71dcrz-0YaDPL_dj%srQtM{6l zf-6OW9(hBULm^!Nk3MWx6TvC>S(7pTuWWl($ulDYx1Fy;K?t#(*%Z>N1U59Cc(Q1s z(_LZq4)ObrYDKEmroGksQjc^=N~4Y0K(so-o$7F_mD=*E z51Om#P*PBR@B8&!Lm+qX9wBjrktmL#uJn>ZVRh&V-M;w@+41+zDAcJQL_MKZOE&=$ zNHj&!b#aKKY!Urev8g5kq-UqA09e6&(2I2DPK|3S2qh$AJQzYfG1>32lxJswWgf;x zgnVvBm>K4h!!j;@&M=gp#U(FttJQRQocjCp8a3BsqketxIBr2si+&W{6j;t?uU}e@ zPMFbXs0OxB*8V1Fi~fmGj@~!?j2X7-EBj0)$>;DdapMf^I_#{q^6lelywF(ch_bqC z&w1kWTj+81u^*Bi;H;|eOW?hHCEHI~1euf&YX+GPJ6!Q5<<}O9$!eFiZ?*Wm>B~Rh zgr!MTkvZxyeT&cjRi6T_B#+(QWi+PisLN!Z797_YcryLog;&lw)&|oS zTZ`B=M#{%lyZvXRn6~EUhgnCZ75AeO!!2`z5w}B}QpBhP1+=_!i#%wENm>Xt`Uiv! z9OIv^8}-3`f3cD`#$=g9sm4|9X39Xz_uDGu)~h37pN&?mFSyg@i62o)bJl#<4_$ zaWW?w(9e~7B9Nu~{S4-pp{KS3924B9P6LPB!q$b{8!64ZU!C_b?t$Vy#0+h?cg^M9 zt9hM0%g?NgojCaTIpx|d;`9|HrE+I*818(uZp~`uRHYH={dB@_XFlj7mt2RRm>W7V zL|;rg?K#l>=8O2addc8c99ezWb80x4%a%_lm@XX5l)o{_hS z2o(Jk$F6M8CP+;2;m1NlD`19$LtTbkTcG754ah6+M%IgNAREDM{! zL`oJkS~GqaaE!KPjB~;;D3LUo(WF`5rO;aGIyVltQ3rKHL_Sh%7)_7v45R!C2#0pO8k&q_ z3!k+Ibi{(WJtP{2lT%XBX960JFQqDZnP(ZU>&cC*2FJHT@(LJ={f3S=*GqDqa!5V$ z0`*@^1s^&4xxCG6+#T64)(=1K z4*W_+^A=-uexklGT>9}!cD9m%@Sdlzn9fbEc-rb(@wj3P4v)hwdJj%#qjCOi zqD!CFgu9A6R%${ctGs{ZUx@C+MPDkquIMQ5(`87&KqS;!V1Akm(!q})1mZ_~5GJ|=TM_6wb zPHoj%HvKCG%qYT${KmXw0Xx)7+S+LD%|h{)w%^hF)2*91ms?~u++0F(=w#K#z3ISe zxP&I275GLP>S%-9l~+2r;@U5NSV3bz!v|df6GiVuEOD&X_b**vkjHT%;e0RHPx_Hz-ma=~x0aYN?EB}fx%A^v*<)TcZjX>S|`O`R*DX_9H za0U+pYp3qEGZ0~$08XQz5E@TD85SZjn0pjAHJ*Cf!;O+6b(##JkWwowu%Z z^JBHqOjfPP)V~JUYSD6XXsnrM-`U|t@GTYK23Uu>=$2@rZ6rkp*y=*7P`naF!zwr-=r4p0H9u-z7w8pkQ;qb zLunFh(VTRne})4WTpmyXC6O)s5gHyG)nwUJy1yk775)DuzbBc7f@l#EEt*fT*!gJ`R z%jhPZDvEhB!DsnPuef>d6jFZOi7!DC8kTFMfxt=AQxSF2pBmg z6(@P_fe%bGjMkI!;OYiUE2qpG_Yg%F>Dzve?X87ko|Tw7URQ_8Iz7xs+V?O--Zq=M zTE(&r<e&6Nv`9rHlmM` z4m5H9rZ8;^7(>A!C9sObd8!L>gXI_6GFN%USo)gX3v(vm=dD%EdyiPuIB{|D@%`}w zM;8|>oL1z%VS|HDb`tcTaHt;`BKq0ws2l}zkmuF*LS6WtLvnJ*#jTaujkt}wn!X?t z50q^xN2!DfGn*wBMqvYLS2>-W_%wx=vqGL*#G?8pu{F;(D8B^5oz zl0u57i>s#x4zL=C4Dcj9$?1xrA?tnK=?vT*RZw*WfhD@Ldsmzoasd^AwdInV?yv9m zwL@v^W98&2!9r={J3emF?C?lznFh)zD*{>VF{t#6@8(zgI}^z#1R0gA z!NNs$)QfYW5HZTqMIH;uK|~H4;qS zMDkwrLVwywL(zp~Zin~(yez`F_PY3a{(02|ZkYf3mI&9j;GD(|=LU*|{6|hIjNn2f`VcmciG2|q4Ier!h!{_N7fk3aDDc@h|GwL ziUPa?)#*ATz<213Q>`#^FtM_37PEcRqq@JTyPVCBQIJkMP8b&mBjPADUlfkmFPiil zidRK@?S0NpTNh#N@{udp+2VXMvGm~6lj4e%*X?pzwCaQ`xl76a^8%P2t-Uj&&DB9M zSxR43)OV<7TzZlS3fKu8WZo!tDp z!x2FY5z`PmeTuYBs;uRJ)mB(-d3Vrm#Pc2yKI=CbQuS?otO+zp-}@@=#(zVhuY^oz z(B(4$s`U{%Y6w>`OLTzA{AmT4bkpEGmNI+vG5QW@`A%8wf=E}}AAebI5J<{TsWRZ~ zvbZ%fmz`J}o^DH|QEiQdn%p)!ar5=`%iReKd-FV@k2>6*4M?fF{!l1TxHo-Au5vBa zxpDgJshc7##U<(OqU{a7Nm|b%JC$1ASi)G>6VudQ?VL|vIP(?S7g-6ZT;p70Nc0nB zRzsSmj?Sc+t;(M4o`WnmhFqNtSp5{}Q6S-ITGx*vj6|hBzl#4%@FyiLOu=vQTrD$X zq?Cybtq8Rc0(F0Mpr@r%1Pzr*gM)OuH7H?xIfQg|P+c)KL0mioX=F$%KA5Xl%rn2a z;XHzJch}tVENCoLN)qPd>(4OBVaex?rOk$L(}HSCXqKGYD$MQ+m%ECR)pA-YPZ;Bz zE{3`xE1{DYCob|()6W{2z`8$p^R<$R;jso7w8XBhG}AJZ0dPB2WF#Jg^96HQ5&aS* zSo_uS_g)Q&9}3>LNS`vgptbQ(jZ;^&bb#8bBPT4^Z{O=o?7wdIwlpL?X^6qJa9B~; zb|rg&dc5S<_R~6pQ_gU2s>}hQ@hP3lL&) zW(#k2TKKsz`bAA=L%)xF7Gx$K;z?I=pXzwn1&xI_T4^yqQVpPt?`eUdwK-j3N#U6% z)S(g>`FOeb@*|+faeiml$RGR7Z#ZkI$j24N>nH7oz(QC^B$v>(5ZOo=4yE_>az);h z>78GCMBsuuI(OSObes=Ac<9mcmCy!L6XjEs=i$mNl_+mhk5(clHmgTu9;`5+bRF0) z$em_hSHSkut$H1@HZ9jwP4Zb?Ds;AesrVPK=~3_zWMrh~nSBHk!H&gLvSbtatA!SNCiIWwcK98d7{tH9(d zQZZIt#l2`Z^p!|9=3u4pFe>Sn8-us2IrdMV!BL+Y{kGs;ZY<6`cGcwH@7+{uflu&c--UrV;NU2&Ry&B{ofPAIAJXBfIkxW8z% z)P>`47bL)s{F-?%dhDn-a(r%Ws-npV&-@J3vN76eC*f=Cd(xiqYrVy`jS3JR6(^N$ zjy*MyQ0pjlCAkbW(XzXG}%AzH_D;jo&#OE3L}asdTd_H~1&{Vlt`t<{uv_ovNIDsM2 zwq&3f#!m5z`RBL3x~piRCUM3P7Wl)F1t0$ zRs!U#2^~gdqwJ#~4SM(*LA^)DI}7O=ntf%Y$G%s=|5bdG5fOFIY0iWs0z_<9KHpV5 zE8vVCZVzSSJYKsSBLV($S@Lfx-#)Air?lPY?u!rW!t95xnJ>N+7!^Q$KJ4+- zH!6BR)NpD0HS;T3H@XuywVk4X`*mU2r`DPJZ!ENh(o-50Zh&26NQ3~$GRPv19QxS zhl{7p(#4Af1YU}7@q^6VoJ7MNFMfYp`SDBLF-({d*s6edq$}Tir1$I75{yQcTs>ty zi1vo3S#sCA?|egp6c!gB6>T!ow$UA-7G6RDxnvFskn6Bpc*5=msdSqzalj8;E( z%)$%f{9@R;iVaGeC`u92HH7^*yzFl$OS1Aw3X~Oa~#6P#ZFy zbamko;PWE(!Z6e|<2?gG^KZQj+A+8EZ2D|4Fo{7QKmGQ;ketG!wvb4>^@ZsIY}_|4 z?>=NP$Db6?@j12|03=k4gZb}XGRHrMkq8yCYaYx&)wgKL>Y|I|&4V^DUrwgw_}{=aVNC4I{O~I9abOsFvyzs1w}P=Lc;|7C{&Bwu-Z{^W{3js z$x#t!;s~T>;DQW!n5orYE4EAR3mOpZSWdsF7C*Q+K)=h9fkazJ(B1>iV_nZ^=eu{h zifuhkJ2v%VPeaH-hy}Lge;7=gUYWn<-nCZsAYbDsx(kL6{~w6x)fc>Wi|Y9sc!-WS z8ofuh9CvZl#&sk1t!r8Z%TRR@4UtaPN5hn-DQK!0!N?CNZ2*9fSf2adGrIxAg&&!` z=X78uuZfG{W7#wyiyQgfr)R&Wf6E166PHZe|34s%_LV(?F3K~Hhyh}6UpNR-=xGCg zZjqp$0+5WU+%@G+i9hAay=z{VqhFtplqoCuiKy4tOH-`8T+GJwTv!gQ7dXapd^%iL z27e5si*td_ui9h#oy)+UvnKckvJ(x9*TSQzQ-Sb=)c}RE;@d(mr#9#_UojOwX^uwL z4T3#CANRWcV5s?|>ISVIpQ-;vQ4kRq-jXTo4Ge5>+<|*6n=Yj_9Acapw&kgP*jmXN zpc@YPm2H>dEpJZwa*VjU^Sg56vJYqh`U8o?cb7!g7^HhfN^Lk`yMFX*-CvSr`pr{& zeNOf~{W&yLQ|3>sFadvA-OfDLc+iSc@TD}3vbZeIl&Bw87$uS3^t2YvpK?Ozo7UN z!=#s&$eUL6bi2y->~1oa)6El6EWLumvVQii*{*;cVlv&nNs>>8=6P1!pMDRZbmncE zM`Nn}%&`Vw!F^mRh+M}+u73QSe{^gtdVY;M>}Vgxaj$mWX%dquke2lIn)AZXw6`)+ z24mbbEm&AtrVTSOuNI#zC=MOJCvuWnkN@`a7IRCgPVNuVKm;A&Tj;di8{QPSgqD zH?e;B-sxsd8&152NTy#&0{d~lg(~osufLB z>0&<1`bc~rmKvobd&bwhXG3=`_ zZ{>bq*jM;PGGZCl%x3p%A;CHy0UJEcH(M>5=&bCc+xni78QI|O22?LCPT0b+x&=+o zQ|2s6UbHPn8v)b3_Uh>Q2h?q_qUy4tE``X&);w`d9LP8sV9+i5&p)-sgE%Ad`#Gc@ zg>g;jIk2;yHpNmT(3|F!i;$j>a>l}LsXJ=s1Ra{QDwO{1(f^siYL0ch!TRylzj$dQ z%sI(at26|{f`MPfbwZ)k0cvAyFD478LJa?26s7Lu$B>fIf;_56IL~;NN|T8n%^J_ z^gBorLm+*<0Z&**&RX2YfKV+`?J6A`e3Geq_bEPEHeSwD7q(|^IJy6@^8+JCkA=Yv z)Z@N=o1K|~?RNt9GRyOWHQK*E*&;f_Up6B{$hXh&gLwUwkFfe{%M<>nYut2`(u>Mw zw3zMK1(t1S9P}WxH@AZa+4LC%1JTUP3?OY{_G7@G18fUc%-}{VqLWcW*oR;3>&?RD zWtJ*SP}b<{??Zj7xU?=)6O7FrW+buM@(1wB#aM4&S;c(ZTJ29=`rw7u;`tJrIMF)x zuN3!7{{NBUmKqlLwOnc6>!DQ0)P>%=7hebyV8`nP?}XP&GljiQqzF z(7CZi>&*ytpmV1a!5eCwI~E~z}dzFsd*jPa_3)xWv1~wy@qkiXK*{|d|}3Lp}}ssF`*%C zOsyf>6dyBjBWoc)*uapBm>7*i#IW|u6tGgM6%rnnjbI4%rQvN)F=m0t zj3m{OJPU~#80-cssPc-jNRC9#Sgn!A)geWPGZUi|r#cSC^-xvh*0zFB5^4iF$~qO< z8_EkbgPiln=NCH>pgh7`etG!L$p5EVNhgC&Jm5*UdNeNp2F9xK} zqbeV}z$76F*L8bk)%onKsfRY-P4#=lkW&vd1P_(mF60arA2rd1!dVd(VktM_J;)O| zRJQp&fo(ymE{oIsB7@SE)?#IP&gbo{;mL%-x*hbsrDYT=cIZQ>>;=w^&!+WLIp_Wr zkuKW5I$pgN0nup$&7tg?Fp;Y-lk}#)3R6OnJfNZIbGU{Y#U`e0+L%`=~&bes#gco1xa95d6%U>ra_p`#W^%xJd5tgz2hl`yM2 z&;aJOhPYkaSW3KxitIfv8q)JHLWx|_N?L2MxjmsPQmZEmNqRCG;S0EF_Gu;5oc|TRuT}#0aGUg z?Z)`EP9ycV_|NyO7>y)@PZRJW+~vEQd;fh$oIy}I?Xn?+L-emC-UQ&iO$!lwUB9Wqqj1-LIkjKe}*tE@RNN!s%O_1|VJMf-E@VLe6 zLheD{`zC`yjk0gJ!!qftYQkNB{8GQ_hjJg@Wp4xivZk1v*sNGrF$9tqf$?bR_=7t8 zUX}#%evhI#Jwh)EhdWGG_w&1`_uGxvWjyXa|S& zWSYKLyMZz>6=5}3MPL#P@wJ=i6r<7pgFOphhZ)3;z#E}T2S&f>Y(~9(Ue!Fc9Qcm5$W7~r5npoH9&`J@)kSV0}WKYISvX-nbJ?m`CA-SmDF$Y zUh#1PXLVo7WG-UUuX4Xuu{D6!`R#mOm?#Vbv5=!r27vkSE>=o+a;vxH^YMuUMm7h4 zmd~%4$}e?}t`8uzKvI1s1d6s{*Rqa>HAn-5CKq!iske;tYO^}Cwm;k~Nt?Xhw_>rQ zN*X1$4rd*z_RearR1VRLGD~Cwl2oE;_iR^qT4zz*y`vs~vZ#!Ze4^YI@YSz)Ka{DU zk`Fn$(1txYLy{ZVW6~9I)DeSALu=s5g_7*#?A%s(*zEGl=sytk-?<*nMiQ>Fye<(X zHCWnlh|{-A{+g)w>3<=iO`=Tra<~Hw5wY0pn|ZR7JR~oOj*}Rgg}poGFn<>%M!36yQ ziQ%BA_7@)~3$xnFE{-`=5n5j_5nkc3gO;(bD~~3%J@CH}CPe_AEZIFa)r03_NRnmt zD}(5>g|OO9&sfq`g`C=jBxl1~h?hw2d)a-;zFwr;=el-D+8RR%j+U)hkCT2XZ?fW} zuys!HcdP)77?f2m&X3*uAZvoV$B>Z7BLNJW$DLhbaCs z9Z6*YH{dd@AAIjayf##!#WZRX)~o*`C8`tzn@x5`Q-zUhB}OcVuLZwiO#l{{RgJHv z8=)(aKqy2kfd%-jH00{ZUH{`&cl^1X$`}ue-eTGAF9j!#d<~||Vt31;e%kcG33qIL zpYz|j?R))Bfa)9Wsu8q9MbWc*Wgk)}J|QoTRu=D{^vNXHB$2I7T`6sl;O$>Ml;f3< zNg7c|7cU%1RKbayC?SyxU7lyD<_$jh)M9*+dUJqbs-D89_iEn>)dNhD5w-<)ZB|0( zq!Cv<(RB#xx*`SS$d^uxUw>;<56$1pdLK1Q&cVIOpvcGIv7DH@E|9)g7Xa$gII5Y} zrQ0vJ3&|Q)IxXRZVQQKG6u_k1(!-hc`gNR`&kHLh1^v^b-k!G~$#}n05jA%6=g^`9oHv{q@(9R* z6TqMd1NA%r&wgg&{z9U|GK^Q6bfR3G--Qkxx! zgxAG1r3mRsDtj;H$(A7I3%M98A@Za!USFoLkd$(UA>?SgsofhL`Eh<@AFHqHdrziW zGTdiBiGBVVqMQxC|LH`m634w6i~|eP4wbX;7F%$xL5A`Y1vO?k;JQXOQ=@%gH)oa@X2($LD|<2SoM_ROUhSMU>^pP&S-#_N$8* z94$37&v#WsUWEf~;phbWFpMzW*PMGMSkE#%qEH4X`K+<~fAlnt_4wV9F>Jdh4E#-s9N3?IxmNdxxb&M5yof6{=lz{vPX3TxtfH@zh+u+S{u z*-P3{CMC)#yQfZ{v&n^y;0r zF32oJ2L9Q zDLqo>$NpvZN7E@E#L3O4PPBXRX#(~$5&h?)0K2jxl#!u~8j1_j*JERM)khLd%+^xh zXEY@y@2O+jJ*qj3Y`D=}c-tLO!m=#94VK|dQz`Ra+&ceojOX;!}JRHk_NB&>?Pg@#~d z?$>_WdGDluG(a2u*pq=!>e%JhIPe=j|A*fdZHUlL?r%I@^{%)t9%biF*y@Nlc{l3% zrH_D2$w%C>jFf)%O+%tR#0nRGKXUD_O6U}`xzyeGLs@bOODaf8p#2;V6XnfP${d+a zV?z27U&Q3FkTb}Z60RzBtmhY&NTWc&j1^9lNKy2Tmfjim*7vCpP*3%--A24N!X?A% z^lj)R{AxeKfMf6;HgkhVo>2;(mp^;p;(W67HII?XQPVe|={gpbmh=H^blxD?z$Kfw z1$T}LkZN8znA_3dDIQ~4I6q0L`u9b7QOCWAaiL5li4Y#em6I?wdi@tz3vqro&}Bo8 zv97)xCM<&z?(lgSp6!c=0i>gm1OrZ(c8O6Li*6!6hvo4#1<+vuiO`M-NQ5MdinLEa zlhbK&H?ztI-Ha#+DZBW&rgpSP;`OIy`EB!3p-rMi{UFY!R~nN1`ShGwi2Il4H=g{I zRY0TR_~>ywCYlMO+0ef-3s6yob+$ZNf0;QU-`~ScHZwlO=IFIav7=`#YX za;u}v!x$hR}s*p6Ls-g-+`9m?6$PS`oI3qFy7EPPq#SXmc2Lr9T0PGKY0&Se0D#ziy+9H_v^S@g6amsV+EQ1eU|XN)ofx?iy6@iIJDj75&dZ#n z^?m1=c{a;(JU@s1F-ervUoOC2^j|Ju-1g9N*ZheY5$Lv}v*26)yof2QFj%qa%t=Gz z(&NP=uORrbEryZ&fkEMCbYpPDgsLmQlO8yEuWFnXGVm0uxTH{8R%SWbp-CF&om$u6 ztuyyl%vKcUU+f)N5eNhtcH)f|qJ6uDUwfJ0go~Pq2e{c*9MGG~66Rwm#0$n&pr?X^ zTLFf$zSbWfKZp$;xbvSe=X`QeP$!jasN25bqna0WAmwyiJ_;8SAdE5~*C z&kJBD>9LZyJI4~$%H$Jf$(MAtU+vQK>6B$Xh(?pU}H^C9>-^>=3mxBA|j&>67h0nmr95rzNkPrLoJ$8MS zE$=&UMQknI!h3%&cI9J$-Q_0Am9MJnf_2^c?OQBMIjel*1Kz|Ld~m7>@c)ip`|oF} z5m^}4M(chDA}3iE2hQ)zjMQ3uKLH2xPv?%i)VF@jve(~OAb9%U=XR2rrX9>^*&Ui& zIpQ64>r@zZy{YMoKV@M5D}dgfo=Ex`Wa(=xhHD!hkYpU48~{!cQw8BZN|viVy@0Uj z*j|*qaS<*I55f9ZD?Ou>1`L4RQwgFgUrtL6UKZAhYEGg|Z!pmKE0}1#5tQllXe2jD zgJ%u^w^)sLb}x2emy^oT%%SeGN=h5dtobdT_GC#xUQ{<8u!lcFw}TTs`VY0P4WT@; z4RYsGL!0?mE3bf>o8g1`mn%3aIv|>?+O8@HfEXx;#2A)3BmIw|mud)ZR# zkD4fNHDIfNIFN z$66X8s~bU|{$dy4l5akv)eLD`-^U`e==PDx=g_XQtBm((0W$yzC{I!KM)ktz`hv;d zU-Mf!q+AuO^aubOKcf}}mku;j16B$Q_VodgA)fD-zn!sHLX7`F>*e=)kuC&4fK(s# zSC{ZRd^zN3najb>+3m)=!43KtoEXPPJJ_NY>hm*Do%@*`eiBV`V2VS0s9Hoa7|pZ0yFahvt!{F`?KlYXaaChr?>Am z^T}SOES<^WmiDzG+z1(VS3@$4e@=lIKA3sfgt}=QbP;tusuI%`&tL@VEVL5A6nL;g zm{ksJ%7Zs1hP4J*0pm(eT1UgHJdszYU&UC6q8!+lIy&>m?_XJJBBJR;Sxr`+ zQmNI+FB+nB_YtvK99=z7#6VbVawmQLU3d%-YXF$4)IPcJ=m~Xws!42;B0d~GAS2$zAv9W5cn2M_FnIAk~CqYdW;#l zgJwemW_3h2@fu?EL{o6>EQY`i-Lo7Zk>#4jHQll02n7-D04Uy*Yb{S?!_jx7NLL_m zI^jTGIXTBR`#%L0OWlkX2GaCX?sndLDzG+tCvr)r?&H((!{f@`*2n6S(Owq$Q+UNL-gDse{R`+fkh_{X+<4Ra zYhGVT|9TTdYbF~)6Ixx@_8e~Gt@a+Ci;cho$y(MY3NPOUKgop?c1TAPUJWsr!Iags z8(QsO)?}`3YQ*7QBMw6ceoFcTY>y8NhYlY1LQiWgFVv<{Px0G7ftAjI)g(*_A;uQk z!$6fM{0#dq3gi@AI7U9Gy-W2#y)~}o>T(Z%L;um+x1RkAF2RdDA9?G$2Cx&VCV<1! z*<+fpWq?pKpLYPI^-@Y521tBND#Mazi6U8sp=(Gq;yPo2V@1?OJ*_=s2@f(`3wDg& z^lwb93~8FEKI$A2Lp}~3o3!T6f1BuM9RkJ%KxhNkB-5j<1F$|W$=U(aRS_M2L1WrD z+o9|b*H0!Mv_~LP0CJ;*Vt&g8L=vu+(}#`uf&?j_IkD-LH!d;RLI*ymAo1nXBsy;h z6&^VsjAX8)pynFdz(H2s+1CQ28NcDiP8`|-%Mq}0 z&IR%3JonDh_hf_y#>Mp(1i&T}d>Wdl(ctI&jz;jJHl2HL>q8$3i~_0FVp+n_)`2pY z12fcdcUd^1{Jl`SOF~Lf_D=Ou*<$mxq{%Jb4oqIY0X&N{hllp9pNNQd%-AK^x;8F> zF9b~GYaw3Wf|lf$;$0S9zhOq?>&fjofMW+JJUPSVQXr7_*D-7G4`Xw@`Q&q|Voq%F zf`O!~4xe9S4rLmr?P^-)ew|S}hGpI`!cr@;Q``M|2=)YeVRCSIxUet!jd4%I+ah`( z7u<9I+MQq$X79?{j$5I|{D|rAC#tgC3tN7T8s;&+JsX%`ZI@VBr_S-72=|^xvpl|c z7HA&Flhk|JEJ&DbIDP4Kcwf8z;x`%tB&@^TfeO@5Z&MpK8U8b_{)K?RHr2)*0r!8Q z;SymZNw!C=(`#hc%wVCH*kX0?7f{<(9A_ zr&>WjoZzb!I`pccf|({2I7Ns|c@X}(^JL?w^?G*JQ?8*}3i4SO31o zI7gQLQ+~x~dG=Zm%HQ#=#hn6MD+-EKaAF!*z=^&c8(`|3Q)$9d1G#4h7zu>A_<~A8 ztMo`;wQ2{C{ndp(9XR69Cr|BhzH|IEri#flGky9y3#H)mjJKp=EsNVnjQul95FP2d zLS$EAS61UA_Xf^Z&p3p+MM6nbP zp5VM$w2`6SM|w&2nw?87E^lsJ;9hPYdgL_K@&?Rcd%DKni|s9FKaq82gdZt9sat)2wNx2FJ5?XMd<4EoCJRXP%HUVAuezVj zraC=n|C~XXR~(Sy%i0O(TS1B|5L-0v?}k4QVC7;8dv5n?1=JLc9t!};WN##+fxSwi z&XK+`QG-j33qXN4;5;Reld3_>@;Pm+v-Y<5mJ1HpnjC-B%9tqJypov=Eycp!pWwqE zw$r$-t-LAm|3GWQ|aRhkS|3E6jvOH=Rac_ivfP#e4fKW|YNPGa?o_-kMmEBN}5 z=4V*=ODzd=S1sTm1OKCu`lTW?C4EY;u{pBZPX$>5lVJIkv|l41lJ5lC)48qch-*08 zpdhy|U2l95qf8SiWa!%Hz!B&^e&E6vq1Bc@hY@v9>3KI59{l#7V59c6HXd^hqeB0m zv}8PejWBKbt4ZDSukFZ5BfJ!Na=xs21%Gy61@Zk`k+;~|U#n`~ z##&deY+tzw)M_h~hSX{!tL&u1HtKM^N4zoWgwiF()Jg)(evjJ=*hq-BV_rRm3Mz11&K+p(1J~4anD2x z<+*J{)M3~rACew{{E`9|ci7Zn?SO)rbyBN!tSy=PYuoB`aq5zOit{E4yL{edpq%os z`T4N@V{WbfC$UKGEKf?_hJ!89879pi+cdkwQTb3ht}o<8u^k6i#s#LK9~a@jX^kZ0 zal;4d}m^$dUjjNK$Vj}`X( zr+k~{dl8-eXAq!AhNq3A2-hT>zF!~t|JZs9sH(cQU3k+V-Q6wSNQZzl(%l^r0s>Of z5>nD#A}QUC2-4l%UD6`_6QAdOzw`a)jKNUcjIm{}HP@W?Rrd`$N11#;R1d%zpwz!F zz3jjrE$+=xBpk;C=^P!>v9G$VmMnHQzs05*?txZ21Mu5STYl=gixye@?u zKV7KQHdwae^i1%sTq>W>%49d=qsHY|7j-21mffT>i> z%BVcU&U7nTGO2Q!YQ{p4HWQRa={K0ZrD~pYVLEQxulso{4SYX^(pyNcgB=XRR4o8GUO@Q70UZm0;TTZ?Jm>L(RCr4 ztY5)4Va{!Zd~bIA*;&{4=HuhF?-L4%TKVUqL|Fl^>Y&2j?=XyIKz7H1 zuS443zHX6<@^h`!5d=Z}`!2&c6zsug1^oI^|G)NF)Im#dujLZPfn93o`4Py%(y4%j zG*t%e-&FX_E}(@82C}o1wTS9Xf?@cqOLT=VR|L`Ls*Qf0+9j!2^~Tl%1X3?1YFJ;9 z$n^YOA(m!eL zgRY0-Z#*B@`Hd}oG_82#W_S(k56GvmG6ckh8v>Tz+3SvPU4=kn+6{$Oni zGqVz~Tw1408`^A>e(xXY@Gj7e6n|@;=CMc?aSgJu|AB9|`~-Y?q-s;e-!j}6rg{Ef zkWAT4{T&_zs8hEVTujvnuHhMPY~-hEK)`ww;WyVe={rcEq_RkQl3hyq%H(@sECMc< zL%!<9ghfE4)_OTu+QOUhvb_2~)zY$^n&}`P0UGPG+CKEtdpNR^AKzN_ksldRAO)Ae zNDK~j)_VD}k}bK$8pAFFNGr`XFv$R~pS}nmmvEp)EeKM)Mc`f`tKMECPq@6Yh&+?5+EMquiP3dB%j(^EEV8w@= z!nAnzTRc6Xri&|xNp>4!D?Ly<7$cE zQ`EiWnkAWn#?Ex)uv3a1985U!S9Vn-1G4Lt8E2EtPh#bTMg4jnqSp&$M+o7W!uE|O z;Bkh0{nPwqiD7`V7%ob5Jl74Mu06G-!>Gbh`lx~8>RVCu>R-48Tw)H3V`qn{%_^(V5{LujHMb&N?Vj~^+NYvf2 zr%uUk)gbqGNrT&jB@k5U)M(%uFqGOE5eTveZxXwi5PLcpSl}Eoa9eP`-|7m$5x3!iR{p>&2TEpNe|kZhKW3@FTz1>Q zMdRgJ+YNw+fCkAWuV#Jmb`%Ntx--q@-j?3zGM6QJke@iex4k4P!q|mL)rIj=J9h9S zaG!5`-G;~thSfKvPi-f-H3PRM;NO7`0yfJbyOc*-FfI|;_Lp?w?Lxn7jqHU&Nd{dP~ zcg?7wfx9XR*xaPyo`llPljjBKi8%1#4;+~@nFNXLxRJOm01n|bc zt!NSmesA^53vCGFO`Zub0H@PlB5?U~BxLu4F|(>V2yAc;wm|ViO)mcWLs<)mih7JSNB8NUtZ^V6WH?5+=p>>b{y4o}I&Axy6{ghfoK?_zh#!8D zAexYvH0{>i@^0BRiNzE7?b1uUI|HAN%eO!(oKGlk9Ul}7(^z)S+#%%qweYQdNMVFv z=vjHRs2UqnefosWAP41}@TsN!BBa&b7fp25q@Na*nS{$;v%ICNJxKR)68X#@!!FqstdVYyfIiHTDDC<4D)9Z}rG`oP=BzM+Hb4voyVQ z^RyE|P!$N!tS`|CQBbZDk;m*W%~RzYl7Q(*ixkDVkX$#s~=R> zX1ajG{wa0HeWzgMEer8<(UK!}W3^AYmP+!^@==DT66U+l!JTb_;GQ!Ai;BwVhDqu(B| zO|*q8+1%yxF$3aQH#P8By!itJg!Pliuj`yx!=;G_PpgGjEjr5qT^VtpD0@RHA}lFCSmMnaX^$JJ89_N_Ss)id4^{Z9ykMG{nlY7y$(E zC1|aKtK6lYh7>!k@+V<)f>uSb;zn#&_1k>x=c>Y(aNpm3mzejVQg0X9Peh-QMbqDq zi$k2+pxrCBtW@Z`UBCTBLQUI>Pa(q^8y!RHy+YJrkjabZGe0)TYk=%yXr@k+Mf1eC z_BFelZoph#1SFwvCU$c2#?jy!;m-Lcws$bO1*?bYY6X7CZeWZf?Lt5OFYY3G-ui^c zKl~4xI*tZu#Kb%k2n6hNo8DLuP<;Ro_Kh%5py=CE!GjFi(gvU4r*7$U;5zT>BKDdU zolz~k)EgfAVrtzvq5;6w<@aCz0ax>|pTI!k|F)3HKK|6Bn9u}<4!x;<`}U<9oP2Ff zgRu;^rq;LN`H|7qw}11C^$BxD4LUeXR6AS1shyEgiI;db4T=s8%_90S(gjoJME!U| zd|)AI*VlK>+ub`!&j0igPy#ZX6&$%G&PV+`8?ktf+RgIwiNK@?I>M|Qb~X4<-@)Yc ze9E5`PH^LE(Qs47<$I}n+8PWC1aUgj7PlsCwF*cJE%|}Yai(A z`!BHZjndtQ?e;!zYGL|fqYZGHy{P=b`oAf}e}Nhd!M{Mwgy2ifYg^5Rlq0Js)?b7{ zS4!Z#NY@9s?tD_lhm|vZk!w&6aR^uU%=FZdn7VQoAJHiK@_=2~HbSu`f%(l}@HH=j zp{W6!SRfDSz~=r~^{+!Vw?QZWy0)Q68xvdYV2ba^@RfbQ3V9yr0=$|hEiJ6Qo# z8wjEg);KDBa@*UZftv28hBN`2pdrl$n0Qg4;OI~qu>iLqftu%O`nB!PQ5;Pt*(v#% zQ-A}q8z+PU)Dq<(HPk$58ucFC^9Ge^9ET;KAQ&%_89;|MRZ~S_uc<4mpaba13yX!8 zp$)UZfbl*Q2HnY&*3G3N9Q2km|KBK#u0)h>vuUtFH#(#5sVU737>pkBPwo&4Lh!bZ z9R*k=6Pj{MlodODBSDL#_alg)SOwYktx+KTcu)de+U}BwMH1Nj7N(oK(0SdBss@0a zgRDFk3IcN1Mn9ET(x!bZb7%5E_l14giH{z+)dWoSQZZ3rYmF4Eq(J#F;GChb zkn6@7vm3PwB(y{U$50@^q$kOXjw#p9e*cos(4+dg{HJ6VcQJD9=WH6;e2IXhK$LE4 zNin4_`ARq$MT*UTBe}`$YG4ct=p3M+NQdXOB;V;H=&z_SaZLJ^@WN}9XCbU1`YdEcNnq60 zXJU3pyGS+l);%Qgnrmx!zqqMv5({FC?gF@fX&DiL+)4qzfMwJ5s}G&<5$}}7T9v&R z?@s>F?H)S8<&Z%q*HLI#4Lrm55Ul52{^Q{wkNr_)^Ietu>?7}D zXOJ8_N|V~C`F34#+5BtPpCv+tEy+n(RC-8uW`|MktTB+rR@#tGQC z{uudxAg=z+w=Vpy8YV+aNy7Z>FHp<$YT=$zfgjv;mAqMiT;}(omuLla73l(r#99%5 z;WT`a3|MF=10AP*bBKS0uuAZYi;o}o>M@-Ek8U!1KQxPdRbNanBf~j2>bsp)Hri=*&zHw z1jAEO*PTD64qlfyxz_eVW2#ARX9ohvv=jgOGe;>MJtLT*$n1eFXo#=>wbA*+3RMe^ zxsH2_mid|=K07oF1du?Wp+r})e^wSq1YLM>b4(>GAQ_B}tf(=+^ajEo=zYR{Gq9~A zz<#HojeC>kB~Mw3JfD!#M5etfXMNoHL9f1L@7Lfjv+1w|VB(wFGTFz3*g2 zSuPgLE}%QlGwi^+0{2DiNx2&%Mu2ArA%_}IqUHh63vjl*_UyQh|FZ*>{6~gxDh=Al z9&BC111BZ;@o8c_ph{*-ala$hzH{Fl_q-GC5`~kEW2On?Sx+d=z101W-!&awT)y-^ z@^Gbk7Mmq$py6`|G;mFwD2{jwZh%J+CJmee;MlFBR$XM4)3C9&-bFrNw`G�mC--jru?QR%Z-ks^7g4MdQAtNoYtSXsU9g zwQa5i=6BSc$!B)|L?{=P936x|SVSnzCME&_{0?QSRw=~cMR@!e9`M%|J!e@IiA;c0 zFfm3R^JO|vifd&>9EeiLtQB@+=B=`zm&s8ZVyI&&^8O8>@V`o z;KYO&=OiL(n0cv9zTHj#@$3K^0z7>~%b-_OBcS4s1o5YXLDq7(Y5LG*I=KP?axdby zFB@Kr-Fmscg4eCp4T$+%?$?W;^VCrp_>Z2tcMY=6;(7TOy*yoM_-fdEy*ZnB!R2FY zsizduL;R&V-vNo(Y~65u)Hg>_Hi1{p*5K0cl#^BZb;7=8f|8cbt5Nd={|IsVjm@WP zJ%b>bcY1NAcF@gi$_beN@9I?5pI`4k+puJR7oVZG5!VNUZgyi``B$mKbN*jSot?R9 zXDr84n9&Tm0qPTKg%C*i$2_CdgT3?r<>D&TqFK`EjHYsp0lLD}$1#=SfeHt?1p1Q+ zaJm82u0h!3hKGqa{ChxvE*A)_JWnlc zs)-_;Uo?5rvM>+WuDk#yjG%Gl33q6sOc7t(CQFCEU1O2b+%{0&+f<8}dF*!iLF;DvLfH4eE>4214M+*4;GQKZn)vk;u0UC3r+g=u zs`!57LSiCUGJPl)YZ3OqUdn%3)9~BWyvAStH*uN6@)zl?ovt=if?TE~my)t~NO!0y zNGg>7jPTPFdKvpX)G)t7H|Bs7GN?54+>O?i_5w6}f)P7)86AT{KtLdM_-+L>6r*9{ ziEVxoQk}%$B#E2owc{YR*ng!r0T&)!oXqXq4pZ#$I#|e}=djM1MHZ_aG>IIc^(67m zpT{E~BWvQBx@+IlKzQ|0e`F#j3YZrZ=t$pl$tUGVKS_-QTBL_k55wt|uSwU$^xX)# zx~$G}=Da*Z=-uzuqCz10EI~Zr#M*=|V}0)wp}+5H-(Z5{M1Vvz3r{TVgu6QaeChFO7}fWaUX7Ar=@8DvhVH~Rx7!a*gJ~~s~C$H z^|A4|3-kH;(IjMK#}O^>^`FI_V7xg(@%E>uj<+@Fne|F@buk^kZW}4Jz`Dl%?O_xl z558@Hrq`6}i@Vrqzt_p4Wvq?sci0@cxE*g z;~7GMn8W-k^hecXP$=Rfqy8c@C)5``lktMG@%ye8T`g+tSf3Vjw@E}cC@EzOiI~J8 z%7mz;$xU7tOG6uPYcmNbB6LiNoJy5@(G7M%w23I)O0C4L-je7>=%?wd%2AP#6@FH0 zf0lhj1R0X&`Ius)OGi)FQ_O%Ekonvl#%?BRJi6fW zWcoeVDod8FyG;o&33Tg@8xS5s)o5gIWo$?4S(d#*AIo|?dRwhovkB>Fos}qe_4wt? zmTZ-4F~I7U^ucm0Gd=aCCKdY3rR3Rg<4(WhdWhk>lNAem?XqKtSfWKA2MW1KUGBsf zaIOYnTnqQIRtO3T8ob~un4TKc{UL_w?O#1ob+on^>c%)kx+~{8d(q8m_Qnz1kjzgd|kQ~lLRUJJ=G=) zop;c@%9&p2;qxJZRWgYI_fQNhLu3_(AhO&ukz+id=B;J<-rKla;#Eb;&`}lj4iOy} zl&QLKq^$J4g*%oy4wh6k87M-E3hk=zzLhZ48#{xVo;kHQlRy>PeCMf1+vwLnxICAl z;~kbn#{61~p)ap==X+D!?E?oa zuS}FNN~pF9U5H<_=Fg(qUwNuUTebgO&#Kh4QD*WPPlI~rQGAPCRXVNFCAlhDI>I(* zKq%yh_#S$aeY_mZRw@}ReI%w-FH#?b4{9Tba>+Mu|M}zOhrDPaO06UF3;$uNI%D(v zwpX26tZ=_dYwYI=jyW+%sk5`rJevanoR9Q3| zeH`lHv`Ya$a*a91+eS?_KV2QSgva zEDd4CCssCAyLt16>f2pcbXJ4sk@OMlSW;Y}fyTWg9DG=u=v|%3d*#d+f)* zwG!^>@t%D(RmrIjRijArD`ogatf|K2!Cm>l>TRdJx!9ePhh1oT1;y{vvJ5jRHVbM# znSjphQ{7QE+C&mDD@;8TW&b3B)t_^)6Fe*i?nMzO>igk-qmB>##{#PXP9u9Q9}8kX zVCX)+@!{lT9FV31M5VP540z0e(e2{k$B*$q+G;nflrZzmc}*#2^nPV9GQ9mhsZQ>m z*HMQm=b8oF9tP0_AKOJ)NyMLSDW^48gFoB*Y$c}_$}Vt;P$~9aNhDhMB2w{VO=6Rt zn7PCRRf!o>r_ommn@@9AHYPI<>?Ls98&x7R*Z(|QxIY|ZmO!-j$4E6w7Cnd#*m~wz z0@i$KI4jdevPrL`6?Hf2`~VgH{U#p! z3brgug-p{gT35@4RR2d;gH0o?#0KSn#9EYB_eQNr|K0+IM2H{~`j|>&LCl$+0xIFq z0^N@9RDy95gPT?`gC13D>URCDUcDpIdkNR)x_6cN3Ei3pwtE&f9v<4iZ#*t5EvV7d zepzq5zS7a0#ZJUeQZvfGAeIM<6oIVn`tuLNI2!Ou)ksy&7)EoS?cJ`zpF>vc3$Ek) zSNK20405QjG51t#i@HuJr4eJ7x795(Ex}8mh3xx}Y+7wW2P_EFXu_nYX6np1wSITc z3T{}w+z+K@UGNZTDZBc-vpBtHf1GQXvnij}@K`{J4zYYR_4my2oz%La;EryvFc`W0z~tNQ7Duyo ziKZaRP(M5H-2DPqK!DWXVZp_@y5ZrdNmVN@LRJz^&y#_HMAADfIIw z`OICb_Qhh~aFKkW6TtOpyAtxEm%C-`uCscN?L`(g)I+6)S>AEhe1E=v4!-gdWKx@Z zHAI{HVIv6NiShOMqgOhP_C91tecEDL;|IIB>}{G=EO6@fF47#+kC*I?Ya+F|k!cHF zxOO0@>~_aIP>X43?5RBSnY<6bg$XRtj&p_MZ=w&}2_5z5t9Xq%s{fNlc35E~xtk1? zeXwu%O390-Y)Zj-+n-oLnr@F$w>11!Lf18pM1O6CF^;9LIDRDk6n&u7wOLE{wrIx z?~DX*T142nE;~fcs$Vo-81GFV>7~>vY};&)^-~W_4>#3rwOLr5>fQIfioochE1kqk zZjJJSX?=GdHLvnVQZZ0jV=7~b)O-s^T|=W-cJT7o^Q&K*2lQ(TCa}%;?foW}EY%N3 zUgsv9x9ml5gCRd8&?@=C!rdj0&V84gNPK=wKlvf_NZ7)dO*XEwk>DO-PAbvB_|kM7 z?QGr@nscZjO-2AAXtiTyTa3h`bwUKZgRZ#eEXh=+L*40+Eb=gnU8o^iLxBODZiJtw z?F8A$#`4U_0qkl6cQVn~9z%otwrHB)`DOg3scI2Z;&vF>9U;;(;<{w|LSJW%fKx}* ztOQxorQ-~jUCL(n=4oHWLp{mO1R0BgZQL6Uj0`#gpI}zJa8*UB73!mMBZlJ_bA-2k zTM5)~Plw`o3H?|G8ZJ>FUjP_J?HhmT>7(F3CQVo;K=w@pEh_W^t<0Np#KEPAP1obC zWM0l;b?I^p&J}DCUDT&fM8`C;E_~FYZ-@DGbSh7%0<a@{Ycjs*xwhBdLfkn1NHx1WaHCM9EIWB1aAiCbLudv1Y9 zLrjHMEtk|w)PbZI-`-tdILxwJkyqrI(XW@1FoKeZV4M}Dl(dO&HL=5ygEYISGk$?6 zD&$ly#xK@{uNk3x88=xGwY)>>0q4WSVSMaQdL!W%YThC6ET)qwFf2WZr&!r~pafng zc6PVCDkS#{D01CaUZ}B`jMwfUg#q*rXZn(xYiGmGh2XqLaBnx*4p@p837tA{Df3CK z;J`@|j~x#dRoIdgqVvkzdtUOCFakrT%Vouz%TteJFtfecIV`**l>axg{4L|ar3f$n z#yij1mfD~kpF5%>&W|Poi7b9_N~&iILcjfM^Rs&opx&3$hI~Uu{s!wCT6q6iSL;mV zO9;a()q-bZ9$Co+M%nF-kfCzCGGb?umXDef5nMoiQ^2W5!-W~+6*)%{-BOc}ou!xM z%@6iH+O@ued!wCO2QqR~s~7f;w!;_dz%2{*oDoUiq|k{OqKrWl`=5r0Vi5{2yRc2h zoIg!Arf4$-{0%71Ne(i(zv}1l8(gO1Q70BFyiUy(!lVrAgLk&G%|= zrwdo_%YH}(selWYMT!6~P{HRxo$Ql2qmJ7LW zKhGWu;0xS)T(CJOM%?5y%1X%u4Fp()wOyVzXP1sK4lF~Y!ejDWFv&aAj5=tyq~=Ci z9cJINZ?%!CHSWsOhh>9383MER2*0~zi%8k8Y{M9=>ylkCOLR(gy$&|akH0?->V6S^ za9u87<&0_UqzJODO>O!{71Ss0vbl{Yj^RGT5)GaGuD8|K;D*k)3#DQJdCm<7xn~uj z)6i@9yKtqu`hl~TF^j|3w9gr&>q|=33%kPDDpuyBxjv{)N}pYvPnFCYWjId9KH~qmqg5aqVjO`R*C1TC!tN#FgCFBol9Tlz&JX{``qN#)iD^gu%aWr5* zl&{fRG`mPf`fA1rjUE>;ViHv z%qZzPFbt`<@l+3NcaYRs@$X!1Vcu+rok4|!dlT@L%}mNYcV>I-Yw&3$Ds6&NK}q3m z`8p+D0aOlGXKlQ;DYYnCtKW+eKSn>?Cy5?RxEE-uHb$l2`cpOcY4+oGkM?exihM(7 zrffz)H3C1|PUjjfBGs=eB}b@y{wyFnqXP1ghlT+;DnwdZdN57$9_{4JBby<$f!=m1 zoCn-2L}Cyh{U1b+MR{gbS!bk1{G3Q^l7h$Ehv0m&xLCJHGd~q}&Wcf#hs4@f<1fBH zvNr!}lj{>iqczNT(2F1)_yAKzk1o;yc1|C)?GI94kP7bA595<95xQY*=E5%Vc|-^v z+#3k9F$pNY!zMRhpUiLNpEx}auA(3%8X&?Zqq;A2a;`?ajOi1{x{47<7f%{>4S2}4 z@Rc@CCF+tNmAu&T`>ik7c|sBCF0n%q>E$XOW}m4Vt>J^J(6Kp5vpht^&$R#hetD`5O`L3wriC8 z2J6MH1q(M`_@mY0srq|?wbDP%lJq*UNBOu9cz$?xp*%69E;0Gv#+}NilnjjA1seOa zOf(s)nBT&EVsg4i8xb*%M~@GwC9H}j#u^x?Lb1_VqaLLaAPwGhUc4r0?l?X?Y#15d zgVdITtuCY$?=Lr?tH>6Fu|}Ke?N+>vh|{;%Vi6QmK_8|8=4OK1?Cy6e&HiAMZeSe9 z7s$?kNEKnv8PzZ2atgEb=>qa>S*TY0=+`ZVL>vv$H`vt@T`gx^zWu1xS1OCxwWT$- zl0A-Lm4d+q_u)@`!JD*+kgAiP1^JSS@qOwvx9mT0`J+Tt z8l{V6@1XI(W~}Bbw-LA10bPTXaNuI`EzVH!S98lW)K`Xs^R4WyA$aIt%|gu`yqh5f z8S`uER6&U79Ns?K%|;$9Vzv0zg{o!NMsECptg-rXsq!DHk?n8tDz+Led?=B&UV#E8 zY9;Exp_eyk3{`;Kv$>F{7q!gaW21qx4X>6avNa`Oxg%z>iq_J~@{H2ZtKy|WPWC>u z)++alsgbJxuqP}WUr7h6@Y;!Ih-)1Vf~v22Q8Ub?>f$wnRQ?h^wqd#7#z(VH<&58O z7U#|v9SkVZ(+g5_6UEs|=b=#293tgMGrRNv>;oPhP|SGoI56}e&-GHGx43is;+FJ4 zGL~NVg(f#`O$2nnc`*32pJ1h%;+Q#GQ>UNf!^Fws;jYg2ecZ0vV$*65n!JwIB0tbc z(^ojQKN^udt<9_7m$#Isrkql6S<6rZT+XGa(? zK{wJt{KCMPN-ji!`u+Pkm$3UTJv%-?oaTqxKQd zO!U#O;_@xXX4W(}hvP`-#e&&T9)-|RnI3QHFZp~Q7AzeTB~%_ z@p1;Ti}GSyi=*0K^;wADq@`qXd`1FL_^GksOjJ|>f;@ZyNk+Id9aT!9K^RNHJr1_< z#eknp$#=(JiHrv$c^2OOw+zSx&` z54pqE{lah)N$8BtHY8s6Q9z5k6EO6u5e__t(kNsB)J?6oexe1&+vMzDl3GDuX@jaL zn9g@Y>4Syev%}$ItE5J(RMv^J#5QDQ->Y90xy|7S>P#FAD!F#0+-<}uxsMkY7puo7 zL(F3IhZ1YmW|A_Lj?(!)Sb#+Vx_H|fBv_;nLm1DZ^wMPz zeXLtQj>Bhq{|Q>yteLIZG{x#~-9LGKP%Pr@eiuq+Ak{(SCcux6z7_ zG0B=Gc!Rvz2-c7TgNTY4GDi;FM3eq_4IjN9L=T2fQ3#t@{Fkg|`9S7y*&o)Q6&rk%W50 zzt^cin;!|Eq9y3J&o)5ss1y!H^(}gILf@T?XE!dn_oL)$RhL=pOysN~;?_CuJHDXZ zvoLWAIQXOqD-ykmGly2Nsm93&-{y5usd^zqM%Mz{pws|e=wR7EsC_hie&F&%5-@hV zzxJXvVAKMesNdaLVdCRAt|jn%zLxwPoK;Yw_OT@S6ocg%Rk{!SNKn6F&s9m)r53!- z!rZd#w=aMNSkQ7*CeX{)qjr46k&Wv_4~UY6Y454kEyJd~bD-eGk5G_mfbKmxABY$L zU(uRmbB*HyGFq+ydg&QT<@r;vflbo8E)zwhf?zR@?OD4%Pi@G8@Cmi|=xP24Ux|=8 zc`2_)yOOP38Xo;{hFC7?f#2RU@m4x7Ze@$nFM{#R(`Wk~-8~oYLW?|l;+v(m1f2l@ zRLIJNs_e^zyI#y4@u)x`_}^t;imTV79MkwQBk?oUgn46tgv3S|dA1iv#qVxsF1y1i4kriAoMk372h z^0V7N)NKu+!MaD(eZiufT=Z&v_;ldt42QfTBvu;k{&IXk_f#5#e0@<`>7?CJ?ROT^ zQB=#68j&&X8S32)xreM5pT-<3&a1e{Auu83FF}!UgyI_!Dp_q=^SSoT9&FMdj;>e& zcpJFuP?!8!Poda^rU%rHpTm8ROz47m339ZpUgzQPOmdbi-3~5uJ39On#x_>4j<6|^ z_&;<9zwVMDd5oB|`yMTK{M=;Y2YLS?4QLDyqe1|Q=M{l_$1WgX+YnFl6YRF&>7(m# zoym58^WqnGw}`P!uhL!KUz|SLUd24ZHrOi~724Z<@TiZzf|iC}K@l_xvE`0jsM}_N zIv0*R#qc1vn@1%#c8%=NSJQCY+4|Ib;5?jK5RAd=?9GeKU7a}gzIn2#pS22Ji^wCD z86S(^t&6p4mD|SfUX8|=FVi!1tlgU*omt?IlF;May~bVfR)9?0X2fE|ZpPQ8H)X$u zh(3hMgcz_yEhYDFCjg$J;p+$2AA~~Kvr^M@jfB6WljYHc?R_$+oA}PR3n`>Wt_nxq zK4axX(cIqMwf3cUY_|Jda^>MN;&oK7$INXp&XTcOEPA|~-$_vhE3V=zR~p_Xp0zwV z3g0VhU}P!q!cCw2(?R>X6~6Wnlehmw$=)P>(W!@rizz2JUe!e1|3xGqVoCoGk+2>Q zmi(XIQxAS2GD~QM`!^)HRHu}~A_JQz0H)@OC7nqun1JH)5+?0D1#SE6bdJfYPK_~Ijl0kxj8xMK~ z>TTc{xeu&zd?TDw#wOqSD))zoRe_(5n;TiY(Nnb~+BaWcW7_j~%QB#L5_f`+zS*6> z#$81_$OrQQNE$>RZVfV5wriL7$8Oba`8s~`?MM#`1X=}mTf&PK%O>g(=_W_Gg_3_wQiL&r%83!?AJ zPbyV^4y2q`ed?vpfGYttOGGe2J{f2%V0jq<*FIp!h$S%dw3BBlL8@!ejL0?JaUT#e ziE=x*7|4IBDw@9Gd=PIhXo6S##LAViNc5^ANYv;(8aZHVX%54OdcGGkY}!liulkov z2ao~8_e3c!dHGVKdo~Tq`c5|4^0%TErh!D9d+g9Z)Wk<1*ep2mbyFgaE&93&?2CK| zwHUzoXxfIh4E30uwX!WQn#s`n{SR#WK$;PhEZaxo@?p-`IJox|+C`c`G9nUl%}y}| zM?-B6RnYet`o>5g%#cua`=MwptAFP+4X=)(ZD#G-Jj$4vw{VY`QC@^z0I0 zNbK&i%K}+)kRRHD6g&Ra!>c-!#~+91zW5ks^(^=qOgX+$^X-o*=nyAhx%6LhYxS8Z zi>?3OHxw&ZYx=4b)+pl|M_(K4C)Fd>bBN$y-!DWtH{C<;)D57K4J-}* zA#pmn`Q1EJU`^qVvogIoHF%bSdb?wyk=?z2igVtG$AB51R%3sWl$$z!rh$1Q^flFW zF23Q^asUXOnCe=R9SVd8Q>j!Wi9SF6Seuvn{$w?!syDeB;X!G1ph)Nd#T}X@j|$tE z)zW=ap7JF=q5H?rkTd0tVT75bjR0!{D-fE17jU_uIi^h{V>U3P9)Q9RTHK^yobn>o z3_<4zx^4o68cvXDZP1C2(f#tA3-W{IzwaFIm%}a26=8qJ!kT*y0G&-E{Zkr(|-Lhx4X_kT%@#cW5bi!m8;Kwij@?*xMZe!aI6v)GH4 zf=B;Q9()Lezv#L$E2>*J(kr4bV$m+W*(mN_3kk!2uIvbHh;ZJ+Clsce6*SRmi+MbG zymRDxch}N((|SWYj^6s+Q*G;Axu;k3G8^k|++bCF28SS*U0=01(mJCFfAnWvS)fQe zy?(5RN;FbbQV7?0jRE`1d2UcQgvrTN<0T>o)b{b8W?fabBaFwQtFkycjbdEeFle%{ z_qmOSG;cFL1OeF^yjBaWsV|M}=#DV`@SLY^`Zg!?-`cGcW14w?5yDPF)D73aL$C2Y zpsI}n3Yq$g4|5#JL{-e9hCYM1{I%t(zP9G(L4O31WfPejbK3h@s}fv#Vk#*A@hW6> zf4~|x(iyL{g2nC+XuRN9qf{z>OR0XB6*sbj{E$TEMV_IxenZvDa=#R$z0i*gR7(DyXYay@^*Vp zEsV3uAtn+RNS^*Y0KdgkjyHQU3Y4=h(^60l!KYt)70} z7nx94NkmLC33;ZEPZotciSe$-XV#Dpu}~iLhXJMffMW+WAA<*V-=cAL=8?I1+{zkI zEvU3!BEkiVZ>_MLa|g!8-cc2>+$Ktr5}^k>hW-j}aVHk(xRc1ZZz<&PRCnY>Del2Tke<`cxC(vJYZ9hLlRdZB!{I zWR-wpDx%vv$S?J)SGp~#lNWVgmW9#p_q}z~(KM&)xbYT|0{yGMGK4RaC0OW`l>~)$ zglfynF&%%5=}AAu{D+ZQ@ZMkl#>R5)D)oiRIQNIh$2~i372p2Gm^i5Is?}}tDa4#7 zHUZ`8iA@ORau)r7UTJ9YecN;!`Weeaf%v$GWH|0XBop8g{t&~gQG>}j-WqhWswKO9 zC#OM4{2EO&UwB+%xEJc$3B?jVge-zs=J|rRO$iO@tB%B*Lgzh|b>0_U@}-ZzCes*1 zI)DkF@TPWfc8QXNVNBYkl?(%gG6-IYES5$#t4aG_=kurhQ*vdu4brNC>xYj}FXQr= zv(77p&{*@71d@j#^Z4dufTbAfCXf~uL1Sx%4EH;r$zpcf%|WgGh%ODxYj=Qb5Ibguu& zBCO4M+KkGjSw0X{Si7U}Af-wCyoDtFei{<@NlAezhq*6Y=q{&HqLj8HlE->&1tnK) zY*(F|7hm2l0bWxq_IlTqyD{0koGU1a!9}XuTU?PMNkfOm^eHqO_`2>cywen*754)`W>wBPh zcyK&9_`OOAodQ+0eB)ot^Sms~t#F|T0(V{;7ifryCBSN<0+qnzlyf$^yZf~XW!H}vYOT4aZtO(W@ z!Ro{hWzeBkXHc0LDHhO?FT`d|zLJ*-nc~m(shfK`zqpi=do<$3rhBjoJDis zECmAFB%aP0Jn#QdA9r7XC81dtEFU1G*_3Qn=;8k58tNtru7|0DP^1;Gd;7RnIrJ-Q zP}0TY%ufT2^Ts+Hoy#-@KaLTL<)FJYDTp?~AVN3zcKav5P~s3FSNd6r%Y3eryM64} zn^ubWe>f$)=v#dyFeSjk8wlU@;R|S3RR*@;p9hu1l4-=#4);$i1Yi_9Z^#lL4 z?yJPDe<_tBUgZhbgy%}T$;2w3i64d?H*-w)Q(_EdwfYl)Z4PmLtou#5?Em6tbVUBk z&&(tYMJfq+J}alM`M=4YZmQhkVpj$mON3tt@LH8Lgabw3lUqYFT;_}pFAHijVjs0c zJg5m;Fo6h>k*=)gRpEMYRW_(g_lq02b7I%@7`_*<5l3P4`^KY2hf=PGfU%g3cwg)U zm#V8!I+z_MiFFy^C0;pveV}Z=!lYZ~+uiV6y%cJwz}spB1aLt)@P4dq_QiwY;=sQ( zMKdmcE+|z0)8;G(K8A)cEuvGdgSF}qy2Q_iTjA?+A8<*X@)jXH5FV`Pkk$k;^_WPo zAx$r0wGUGSoljLOR(}=WQZwMUk)f;;8ah6 zU=tzl)wf-$9N1bj*8m5HC5zcD)*k!hQ+?n?|7;l>2Bnhd24jcU1z5ZS(bnF1_OIX= zBCzDUEf{Bt0Q$uvoA4e_lyjWwdjnEvJq~e4NTW+W!9Cql4`9>YkX>fqe}=&|+B94Q zGWx@}U)>)}y0zTjqSh{9O6Y%>ATeJR0EWn>E$+RFc%_O|6>op#o{5%FZxN%t-&jG! z0ZJQ2nM4jP(Y2RSe;p{3njUk4FOgZfprnac(9k>MX@HxB5y&U71iv)Rw{1dvIzD~M z2ohwFkpu8vT9gyhv*m8qMdrYsKrBkS+i8fIc=J8Y8s$ZG#FNqDb5=k@n!E2^L-%?E zKEBtG{B04H7L9D&0}RU)4U0hJ%J$Hg5X!iBuCCkw;Pu7}Qg9RXiwx|q@K93uxL&A# zkAyK9rY(}}g`GI=bmSni{=_2uQZ2C1(E27x=*d4}#Pfb+t_PN2HWb7~Q?A|8=-HLu zN}_kkLkR!+BrpxB42TqraRm60FZ?e=X=DS?!1cIj9l{5;MFa%K*Gw!yN@<0^vWAQb zz6qQxSWR=PDtft$^y4|p;96n8ir+F;KEH$a@lxCPjNvvIwP_l65xYwDj$dR0C5{GM z_m?Lx2ezsPWIF!;%#Mv8eNjn0QKSs2+)$FEfJH$f1M@_txv}gTsa=v{x1`K^=C6;%bP~a(uHlSD1Yd{2 z$RM6I3$+jRiVEXy+B=bq&sYcI0m{1nb%dI`|Jp%!7t@E8HAc~bX^oa>;1KYR-h6i> z-MZGkPcH;awsyaHX6L5Kg1(ylVS^SO{T3VDZqkv1g;56lJ3LwCv=njFoR~<;L9%Q* zMe3Z&Tor=*+x1-=CUhO&PkwA<{n(=%-qDpG0(@7^7(lA1$D zQmTdPYN1+{;Id*h%2i-N7yRSkG&mi0V>=wXuaR0>N*X#eSe9)T!Tz&c5 zx2&>I(rBy8GNrQPz?<3c=xplF$x~+U2i9KcRd@K(l&03{M8?_kH!&I<`}KIuxfiy( zflIpoxXGC`&#k+#&fP9=?@r#|R|Oop?(lAv%!<9b+eX7awc_Ws*8(Rlv(7yD;5M++ zSTJ{=)AIdZz}2_g&aZlJ_T=Ry`P*g(Y(wWb3b<6*@JP;4I4o`H!Di2K=(NB1PTAuB0>t{vZj=m-Od}p7J>ycF%3j$KKfXiuim(04+SuAeN39O(W+P7)vYXJxDW-ia3 zAhp-7%dfrcm1F$Uqvnf_KL*aTIC<36Diuyot^IlTYOB6j*DQf=Jdfr@Sg(rJ>yO&b zV7aQ^Ue&M4f5Uy_-Fl`~4pZ-Qn$M6vX3NkrAyw#A@lor@mho^rprWGO!ZxW2=< z?fpFS4~l6_Vv{~pGo)OvxW4y=EUNaZ{GfN9IBNlHgPXBTDEn=+0_V9mpyI&_= TWwwh?U;qM7S3j3^P6EpQe* zd+*;q?>Xo5{)G;Xv+ny|>$<*mO^~vp3>G>GIs^j2dMPXU8UjJogFq03&=A2ZjekY! zAP_3ZOGz;`XZ`I45mVABf^)A%1J4e8?R|R^+29QgY+cj9ch4tVryX#KDYWRrV92E$ zI$CnUTH8jJA42rrEIv=dH)rl>!;^TN&mO%XM(>AL<4pCOHxyk&V}yTgNEyqd(C&KhX^qlQ}$o`c){xX5&J{!oy}|=(K`CLdfkH+{^N1m-b_D5{R-s zGxP21`*#XXPS5?Q|DIlen~A4#X(VE=_sP>#`?jpQxO%cMfid{0{7hA{`hkDfk>G`C zlJVBS*LOq^oRq-Q#=R+G+xo!5NvjIdIxPN_lTaw>rVdvVjDZrPLww26x93cJX2O(s z#Np3&qCL7?ffKPcp2Z%k&&a$))7kS^uP@CKe=BXg$vgaEsI()osn2xAYoa6+R)%O9 z90x@~_z~Z~sX5RujS3NNHz=$`^EFGVa8;O6D@gq?fTZQsNRb>mrK(g`(LhJ|0owkM z=fUst&>}IOE!~fbdvHTZWJvF-xbB*Y@lC%V*#HW$9ufweT!s zK03vU+w;SZEapr~eM0&CBh;NvZqCHL0 zEnh^RPfcP#;xV?F?ZaslcNq9*6|RLBX~vPQ3%MVlBCn6XZ?*?cDh-;t`}M!^ImqMv z^HFx!rl@2Fhc?r4{8xoSOL6LkG{aMqnD2cuNO}|bCm##-?J5Ex3k9zj`ZQkDC1mF- zx@5#o^t7k&PZw1Qz+k&3GZI`qX(1GgEKE{Do|o>oAPnYIu!zYB-Lw=I5Q>bSn(TaE8!)J=+sv@xpei%08vN>L|%*k?=b!(UHhk{Lq z@3Tv0Ot-m*4Yl{+d2Y{!V~4AsO1F;(jBkVxeP(a=9QBk|LBjyQar?ng{&VU`Q0%4K z(P`ND_%QbHYDH<;Oo-`Kl5VUK9(!RSI5LHW9rT8_Dvl|0#4qjjipR_$&3@IR4QiYE z!5B6W<@||PBjxdq5@;AHw~qTBWn;(?cA82Z8B%m@uSy8jp~FfwFJm!2wEg*WR<5(~ zTKXc{<=5c7a|u*m9^{+EP4uYcH98YIj&bM)=37pDe;rTGPGjhVJO+DCIAde_6LHKb z*PdUPNn9%(FT*Q2Tv`ZQ=4Rrru5JGWqb)VGD@n?&m^>|f=5g|^+3AP{#9L!fkQ2ch z!=_H4u3S=+c}!&|+?^ZcX9)L_>OuBu_F353r@6+5!Z)Iq4`)QbdCBJPW-}Et6=^q? zzF8C}yS9i+jjP6)P)ZA@SgqiAMBtY!zH0+L<7Jq|hcs`#0sCoMz797f)RAAtQRR<{ z-_J;xLUe2szgNpf#rIA{+H0zmbK!R<1wNIzc7mFW1SEA>CxsD32u-aLrit=_2i?t& zV3ozhX^JN@Jo;Ak7iXlo2pErk*@68|B98c|g>TNv=Bi@Dbo9vjTwC(#5u=gPW}B92 zZ|X|Wp*RAh;PzyFOL`*V;_B7SgrK87v5Cpsx`YIU0uh6WY3+?SW;gwRt@G=yzgQ}- z8LvZ{$B(4I3UX&VbC)FxBe?rCMjW&;&9=FH1C=dkjP0@XCJ@s9d{k0U>agkv-Hqz8 z@-Q88+ZnC;F;=#uYLmL2g*VixIA3RerCq3BhV}Vz72Z&gX@-{d&g$eoRPg)PnlD;H z%ykJ0w+a1Fb?8J!Kvk@KEg*HXRy^Y@X*HKV#Ng=A^LF~ol0X?0J%H_DCD>+PRS zwb^0iKr!?_k@~hT-;&BnrTC6?2|?W2uX{X$o_E!eh0|E)6RG+N*Ho%K$p=*%y@vD_ zzTy5~k03;Pw8G?sQefLx!vn7jWEVd+$eq6G>+4^QKdLQ?p%cZofbedUFVP%GyL{FS ziM@Gq3BCEV`6*wllS~Z#ljSE|b?7Wk{|($zu^@G9&YUpV?~w9?u6;V;@(`yd;qC4y zmrsyFXElz@S4{I6E)F|+aIIfFPb}=QY6s+$Y7ES*PdmQKI?7WcSmt6K_y<;~vXR$xL6CrE)U51$$y|8JE55N@ldQ^-G_i z4d=)_efJExaSBAZ)#uv|}I(GDcM0V1x8uaw;5TB&kp&#@W{sqFR?2s)PcSoecf3Dn)nT(W=wXNpF}ELB8A^s6?(H$B={fQLkge zG&9epSYlU#wpP8r~$j*^wMOgAUbq-DTDz%YrHBO}u5yoFzZU zi90SbU#gg_h%ClC>beBWN>KhcYl|Ay!<77qPSeCg6gt2BRAwXq2h%KRx-q9-dD?9! zZ{wMpN+%V}tlo469|swq`*I*>#CFjHU(8v5#R zV(k&mWVgN*i$nXCDDer0-2B*cHL|cb?o3uQp{n^4plS%xml#zUa&$r1F8ZFn3{{kz zaobr*$x0eM<;pi%q+s;rgxXLSm5f+d_Ww<}IHX+l#DHZoE+OX$wPBeo9)CXG?YDAd z*ST!Kzu>oZcAmVLWEUnbc^L1eXY6~%6+nMNDS zt+}uVs}MK$_+^>;O%_>7;P3#koc39|PNC*Wc;mrvqX!bTZQbE-^qd8aSZ}47Cmmxj z&|P_X?NWnFTs4}WDImua`6VL?vErwNSDj72uMZ4RPC3P{qc75tmT!tL4VeO$$1Ap3 zCmB46o~H6!7iIrAN~i+6ZD&vPo6So!46*^flj={&D0wCgSu?Q5x~OpqpQJI+296j% zPdBdFFRu!P^dGq|#)~h;Bkqzqanl*0x&LjRst;^2%T)!}q|dyJumhLmJYriGx`=Uu znQwE$tnvXoiqm{z&z94uj?sZwV`j)*a%}yO691S*swh~g;|2DMV>{){zj_F(Y!5}G zi+yIA7g31&35cG!U$HJamtv!=UT!d*%Sc4-|(2s*ms4~Kdjg5^& za7uUXQOwT>J5^IEk|0b4Slf5mh!B+=m*WnT+hl_~4t}=0)n)FtSG+^yM4`B!{|(Of z`Eu`G!6cc`o7dI}@gUXlYV3D>8w#I-!OdGaD(Z4`BNSpg~z-P*q@!0 zLzl0lnGvx^8u2Mzm8b>Whu3Q2CX7XTPZ6Ij@9<@(y{6shzrk&J=0-6bzUT1YWMR_5 zSq^Tjt*xKgP%yNN$s5kMYe`b!vD2-j6k6m%qp8n4BK%qRL4|fPIE(x2T~K37MWn&& z+smVq$@jey2@PedeyZ-8u~Y zSyAHwU+0Dz3h6T%CZNS}`4vAD)Iq%nRO-k!i7xb7d0s*>{0IUX@~TLW#=v9R%(zI>5$?39((-3bZTd zm&17;G`FylNmlp7+|%@NoZQv7-F4fPbf@Fd27F?4+2v?Bnse(p=Abk#>ZK_OZB(G@ z(*g0zfN~d8@CX3pwLt5tt~{UVu#?2^fJ>JD`8X03mLlDxrNW8y(&9r|s~@lHpX}p; zFN@Y2IGS0gL(vBt=dIU%07?R6p^`_mNw7on&}|EWaLLihaRc3H$Bzw)zpj;*AZ;K< zM2j2p)xCw#P)9;$C1jOvZr-QDJ|&_7d+hZ_BM;P5ihhxSysVx5#;Dpt5^G;6ge z2AxEnmJAZTWO(*jTBUI~U8UX2WqH-#xoy5^Qgr!;1ruPXh56!IU4lJ>v~J0qt=^ZT zcdKz>Gn~#yQ~5@ShR9*a^}_I22OGVAs>w%e`4izooNb(D?S1z|KPfKBc7p^&Y;-F)5dE@fxNz^4th9* z+TDIPY_W%sGZ;cu+%0z6!rq8Rky~r|1|fchxCm_C5Guapf-&<>AKa8clzCwsUBj5N zZm{u+wpO~Ev4mSJ_t8Ytw$hqje7fFiXQU~4cqL3iDz3$dk8#)Jzj>yE&bQOx*oIHGmQjWw(}ZwhX#CO2xnSQ^Sf)(hTaAD9*j+d8fCH(Y z&uft&wO!VI=+#dLtUKnR(JF7(jeb>L;NVg3%SL$%$j`W0s?|}P%N698=Td%ia&jyS znTj*eVAIo&L4cUx$`D12v~N&`*VDW;dN5Q5c={?A9}rTWAwATw;LuLOSeSVG=-#>;; z)~EY1oEMoYHZ?A=iIhdO6i~t5Hq7TGm569jjw76!UOII8rKYIH6R^pul1WJmDxv%> zezHAO3dH+f8PNE*_FYWH3lb^U@h>(|XJ(0~)%5Rm#of1;E)Jz6k3(i-TZl;1>h2U5 zO$Jqy8-**}dH*1Sz~-&YyV(+u8&W-2XG?on7W z0(ajoKU1WEOEF|d71M&kP?ay$x%y>C<^vm))>->=HH+x05#25ph(M1ApRzvVrofm> zaFTRrAfQT3-}ND)zPr@5Mae=jieeLV!_|@|Q-2ew;A8C7#COK(q7n67W9|ZaNYa~4NrZW!mpq^*hlWS zj)=PzUpF44awbtfZ1??nyL|G?0axr-jZU9dSaSjYC zOg8#2tu5M~MY<^So$FMPSrUXzx8glv8MnyCr~2v^9MbYRAGD<>0B#4JD$Bf=h$IZ1 zjGJ-pxzu_lcZ8zkk;r<9$f(k7W}RN{NHti}L0D*8a4#TWq@W9W*qaJINw`$ZQR-~(8A>WC$Iff2Wbz}7$ zke69t9gH-0Yy5aM4f;vzi0@%Btw~qWrRK!Rq4pb>YiQ`TW7e)N(aPgw(Sl`~!*FOyV3o!4r%Vd&l7Mp=Qh-hREU4-%yj2acGPG)U^g zI<07*hgW-@4g^`++d9_k$dSaqK6~BRk}ahI7{N<#n{Oo}Xha8Va!0j?{AUrmmtsjQ z*FQdu0VTvi*pWZw5k!(Es%s(&aH_A>DGM%*#|5JnTyYB7$4Z1ERYTn|AJv@Hs9AuT z7e^>_a;v${3V+ekST#frnr4GW~DuUqCo@)Vp__JwyJ4l37Z2gAj*ZBHq!ju z#93!bL+$j2AN8bo`gb(kKDshFGD|a6o@6{pu}+kff{)GT6TRLUUNRzV8f_$nw(sn2 z=TLqNqHyY8VY?I~?EpLp0`APfTM~B6DTl$(w6GAi;DxEzpb6zqz#mBcE{8+xW;Mwa zCwu1;<3nr<^(E@QH>wtLq@N&50vR#0`@T*lncvg&s8_=onoY+0yr5Ux#@`(yYhoMf{O@90&r1E`bl zAN?#D!D(%+_;}s@iQez$Tl+8omHq^wLPj{j^Ev!M^TiMRA}?e+Ftf|AdQCrOZizG{ z^vB+)>{CR@b!SM?R%58$J4oF*U(`J&>B)JWKQUU%^u@0?D^w;e#HX4>3c@JFtQTqa zt>S%C3OqC;NU7r`=Fp3!Kd%#Jgy5Ux4dt#(uk!+K6og~}{v15zI`E&IGe0Ap3S|-; zXez3A413;l?Ky(ot_OUb zj`o+lHJy$22211j336 zsjsip+v3rBugfUxI8^hyGtqW;FyI%0=zl?kvXD9OY^5_UWY*{*A8TdwTb-0!mnu#Kt1`rS>x`_k2y09Pg< z=ER&06>sB>#n+DP$+ui-jqwzuq~_OCK*tVOlteo9C0_UAgaXlGAE&|YJ$T zpySZmiT~UsFOPtxi@MofMYmP}J6sV%*AU+dz5J~qWqcT66PmDN)Ee2@pUL*#wOo2` zV!T$w;3=Ref&Ouos(SXCVS?>)!TiV_1II9?M7#uu7hOeN|L)$Q0|-f-FH(20WjD^i z(&{Q2{H_!&uP7Fe$7NLTI|9Eu*;oE;x^Wk(OX%P^6%>KdqF<(S`)cr3x@J#0ZUiJMM)pPS_ zs4a4{e_rGD`8Of{$E_j?#Y@n8&juyTHlcgQwCdHDyq35m%1#uz z`1VSLIP~`eKC%wK>f_IxM;^S>lQ5VlrOe`etA4-uYeXs>=Tl%nKmbLJ;DEp<^j}t? zus16?2_LRpxT{hWVFqZw&OTNq0U_ZA0+DF_ltVP$j;$SkYf5Zm2 zAC%XEF}>MqY?XwN^bxPnqYwFQ_eRd7bB&KfV?~2{{sf!+9vm+HNTld*{V-_OU2&as zmpNZnENpN3>yOSP88V6VT+H3%p*`F@ELt}n%N|YAXVvleaTa647FaS*0ywsNoBfsBG9n7-R)_wrotY}A?Gx8|pAhc)t9$zM5e}fI?SC+L%l|7g zwfP2)SwO~QLh)hHOMTsl0RY5kObF2wj35JOLEN}8sV|+20kpfm22SANkEIg zX@EM?f`R_&kB2ZE4iQa?<{Sb4`MxUqR0m68EJFHG$+B7$(ek#(vd~N7m;P+Q5M>v2 zn~D%?{%ArH6c+{PU)!Zm8WRp#<`B^jWi&!D3+3^=_f+;cUVb@R2D*eR9NIs8&xZYS zAFLXnU-rjMydQ@5Y2bB?>ts96ZrR#C+6p1c6x)Mi5VLCXegV+q;_Ap&MPokCRwcDb zq^Y7o%2qS2C^MagNO>RV1)ZIpvNTzgfQ-*~H2uDHT@o3P-nH4SJ9o18bNh^aoLu#( zyz;AOWTh0<@F`af<1czcZJm6LA3%*!XkW<;O(Dg6G&m;^tRp`cLsj)JLu!fm&6L_; z8*ZDlQ5CzFm%d8|W)(beCs5&{@qi-v*<1Ayxx}aa^NH)?uzJVG5a#q?GUD<|g1>(8 z?Tsgt$G_-}3?;YSw+DlIn1S^KU{jw^9qCwz^gTF`3Xh2}AN4t!#fgy$7TIE9G~&qv!ufuGP)EH7xMGdm`NM5G5vcfy>GsCR)zL7zr=GsN$Uh=fwp$|`coOW_ zX|){c>QxT*qbFb54LiAY`8qm!tP7DTeCmF!F3?EoEatCf&sgzS{a(9j)F#(5&*J}F z_Wk}zJ^zm32o3-q*5>drB{F#_Kdol$v_iWnrQVcV53 zujHI(a{WB$mc30-yiG`z?*oVc#|oWv6)T!KO#UFx8T6#NAtdRP5rNCr>j#HF##yhl zvj!TI>+g$liTl4iezT8O5-dmb4ys4B^Vq$|G&jjwFf8=-fniLonaCK** zkgT?l13Yvh?>n!gl(vw0VEX3?R9Eh?AWNMd-H$~;rn_y6 z_u%}z)If+rSLHT1Cg5sT@m`e#Sl`m6ckFzYe#fI&J}^S>X}Z7Eh%-SJ5%O}3%7z*w z{UqZ9%A8;~6|VxV?ko8VnqV5jr6e~6wWaTYSurXnDI`EmXeJJatzY!Ey>cn+HC7eE zp*1vf`00uC=9k}c-=$iPfLQEdI+JbeekwV6Qnyab``^qIRp0A>3?{z?jC;U}Pzc=F zl`Et9PK&yo1?Ray&rE4dz`I77$&#hhzizS0j)7}5b9r{?@E%AcmQ5VAROM!0j?ACU z3LI5+&F|9^F4dy`QKf^_qUu50qasRzv;fWLWm{5}DRT_k_@XV6RAn>P|8MUGIT2oG zWlarjf+@`^PQDP#;L@}9Wn7KYjJn>ZKm<}@IK}CsZnqDrL5h+#+kp!$4^ImD;V;<8 z5@m>M7^45%4#NF_0zuu_zfK7Q~hKjKK!54j(vPuPh&OY zH3n#~Ns(Uuk#D#-OCHF=S=4$qvW^9!4Mcj&N!Y6Z$((+JI2%Zveq&_CuPCB7#!E0g zVVT{Q2HqF6J>~Z#OR1`kB@rUjs$be!VFLm?>QoxD!4P+DI(~+>Hh>LMw|A zMDLXr8#lIY5JuSB-8LpHV{Rg|Olw23+(2bWKDjq*tleR_;3nQ#HRSQqGLkCoQ)+IV z4u0okB_=Su$sXhb|L>G=3b~82sWo|!tFQ`esY0!O{$SpYI=tGu1u3ilhxBvTPA>Y( z99fYF!R&eYsgCXO)A5?U{9uJn^bR0PQ3)-yTlmiXUj7@^9`{9NeCpvQYCmV6U1Dt8 z9s)!=h9oVN=hpMHfvMg8=T*K`jNMlOHu~vE42MHwtHJkCjOe@*Ah8}RT`_rV&m>r@ zrW4K$W#BhVO^%h|-FSPKDbaqm^bNpW3QH>pkh#;Z|(ricrOp*=FJrsX3v z-HUx8Hdr<(T1DeO#Q5!U%qS=*P@Y}5pnW7{GmrehZ zLxS=N1L*b-0A#D{`u~-3uIk>g5vAcxvx-2T8sjN?UEA|7%NZSUB74A4z?L|D741i< zM93#zPYu@Xx^gJESN{yMPpywHWkOK%%y`N(^FP1VJS7GNX8?9lXS#2_b% zTgVM^_Kl}KZ)1Z{@#AK*I?dsSa}^7n{P012wUg(0Y&Yb6Ib_j|5dYF z8Sc@lj~QAE5`w?%TxAGbTY;$|e?xRWBem*h=(dC)Iy1pfDG;=WcfHw~>`8LO5`69& z{2h-om>a?FhuRkmo4#AloxESX9@x0RK4RNUCBjwN=ZN4azmnWTEZ=^U^T8f#okv#( z7Um#bNA#`I@*|-Qzq5H|5&&@@r7aEI4oC2^%yG!&u8Ix^>+O5g+oy04Y%E!mW8Y!T z&?DLFrOEdrc<0Zsn!FgQUULnse2(!aEGmJ5J1zX&9QbJ)l#04EGm)8(Yi2q7Kuf5( zA&f^)b5VoUE{e}y9yz#jrs(x*3+0!Lq$8yxBMXpE`T<|lR!Lu5U)=1CM=iRC_U{~% z-x(awC%JK-7sr|5>Uq>|GG%6&5SnG7L0n}Fx>zh?c|fef6+Qed1}Zs@r9n&x$F((( zvR5)+&DLEJc#mYr4RNLG#-{us@2pwSo2f0z+FI^0mU1Of+sG=9_CaJ){-8?Dl+d^V zU;Mao>662GYT27b8Vuq?hLY{dbI7Z4zIus=lxZ_DjhxWz-R!RO$u$Wwq-|#+sS!?4 z%i6C52aXISN9&*z%g`snS60f2Ae{kNmI@(zFl2Dfe5U6L0QJ>OSb_rQ?MQ*f5Aam* z%7EQocR5a*o*JgmUS6qDs8&%)kQ~@8m57NP6sW;G_A$Hmz&5L4BF88zJ#e@f7hc6* zlUy6};>kIHQl=#G19JA|RPHH__7JAzC(!mGp~m5|$An9==NR*d+|H>6E~SWSrb?Y1 ziv>U=zK4~Rg$h|t$H3y|FnSs$pGgawGo_WHi->Qq|7rEzEUA-00yAxsoZFFP19bz$ z0rE{ermEdcE16lDAcGcMcUnqp31Q}fi|`q*jFV%^?H{`KU(o1uaZ{42%Bnz>Z+4%7 z|E?RDm5avqL$+dftoV4W?3HBHD0UuP65mK3p?Rxk3odDYIR4T**Dj-E##$OPTt{4!is6b=AcIzWZAuB?9}>W{C(Jn{>kwpH<%i3C+^%I<=^G8gu#d6&xDx&DExV1 zg+6H`_P=Fn?1JjiMimamivLu26lxR?#aMzE2$7x|wdhZJ~)E>dvo7fr~!`7$$qz zgsSlRUhhc6vw+WXgo zUYK0z6$32lr}9yB#H^-n^QT782qiq6@Vy7O69xA#eLORJHq}e7%&Z(iR~Ly7#5h(! zxQlr`-HM62VaI|5G)UUzGNg!br5&M1mf{?CVd^+<1k8E$uz@p$^`4>0IF#wrp zrveovQ<5qvomurJ*7pW<0>;PYoFo>+$=Jnp0|inpR^QQ(zyL9G%vZ?auqKo~mpgBDS&Qmg}^zFwoBbsejXs*bImYY%NfNPwR+ri#8>m{8D4 z#YH_s$$xuy8^t1h@!yCGm^{hEZB`>V+G_Y6D;Ci(>Y8#;99^@pe9gm-AC3KP<{}(g z04gtta8`aknz znGfq@gg$3oB;^cyFJNk|%awB|t}>sBxdyA&mpU%E3!6xf->OLZ{S?K>cxSu;D=>NQ&3epv;wkZ^c`78PtgW z4`*04&l+{H9{^Q#U7W0;%8SY{h8^18Z7ySi3R;d)uFb`X_keShzD7G&2Y^qdSPXRu zCqm&yNIbt2a$eFGIOwq!$GyOA;J%^WlP9{8c33?Z+rW_i;v7)+OFil_3@wOq} z*Qg7c3Ca!tc*){s!u?X;)xx6S#001neEhgiq*U;ws9ErXA3zfR8ow491TGjXI=iXw zbU)Pp1r{v6G&dEYAq!98w;!)9W>e`K1ju?d&Ixs)RDgHmvn9csh{=AIM?IjEj^*aB z=m$-G+0p}L`^L)l7nFD-jC;D#|8@l@CML%Wq|g*Y1FKsz8r9=8gAcl$kM?*32eR`0 z;?k6MmY#eHgjn-95JF6a+b=Ubv)lOw03z3HowcBT`yV0dZ! z*FaU8YNnTunuql9arO`?cDafAAM(Szw&Hi?o2I2V96cXi^0gsd!P`T6iRg^+sAcXNT;fK z6!6+qoo?JjTtH(g?90jf6~6j18q#MPpwBmiG(I5W9%PA%SP|Qa-|edzZ8A#&;@EW~ z>iYcUDo4@7qLH7P$9elzA?tw(k^x)7&cFHaRPF*RFh8I>{Dat5&bNVU2J$S++AaS! z+y37mZee+^^C91;*VjlAOq49jO1t1|G-uB!o9>btWMAO}zxzB&cWXp$2pRPp4hYc* z*}A0O!705I-ZIk&=&?+@;Lfv&C;z3zf!JHt3LW)#J+=8CfE}9Y(xkHPW7S5J^k=gy z&)WP@gSKPsEdJR*=sy)5Dcz)2T=s5Bo70<6KA@V`PJ*m<*F&ln66dNqtAip`6> z`^}*IMjPIBC1{Vh)`ByLXM&6%c43q-sZT#^wAXgu3=f==Jp9jKdt=y}d*YbBRZrzR zs`SWGh<*Y;a}UPj3n9u(JyLIT&G2~4@8*L z)-KsEt_4>X3temk4ROh;<2b3TYqhOVXJCXrZ6WRQH+P$=KhE$~=%q(*!j~lm#UHr) zAZH*zODLz3mp0@lTyw397?YktDN5O7w??sgC zitkc(8sW{d)JY)|;Rgs?EsARlHM}-FOS*b)2gGA7=!+i zqbk2#AUGszyay%1f`(ow#(xWE$WI0(-(-pmnO4!vhUPWYI*w4zrO<*R>AENrBa8P* zDnTG*u!gfwLlxRnPSbUp1PrBZ4GR#WabW||Dwx7>)%cz4HjW8~IRNJm837o-Hi>zg|H zz}rSr`$TLADJze~KrLf1__=?*S)6bG6_rtTOzs5il0DKr5Gb!<%<7Qh3;hp<^snJ< zP5x{A7&7f6CZa3>$~f>JFqD*BO(wpGt@{p(d{Ytc zU5?bJNar028^ivf3PRg|1oU02ks)KXA-LIj78)Ri>y!o{r*0r~an07F86~D`{b7O2 z@lyiN-FS?+ucXs#fvYX1pEz)ua=$^ZMi z^2W6cuYnEiMWO2QSMn|yjI6Q4Wy8Sh0H<6VSBws%sE-6GQvy@vSESOdf{Q)ZG-f6~ zo{$I~R307$4{-sawZio#G!UsT5r{3P`d5d)l8+K)EO*JnE`@F`RxBRxj2omh!7^Ii zGalrX%rtw$IEhMe=VchO+R=Xq{J+zzGNC$2&+fy`#3O zKdSTuZ{qRhJ@8cQJR5TbvZ~D1ahcu4YW*&;05#RI!s4-Y>-qa{Uaydv-|gYV!?=57 zj(j0hcgi7ekz=8V0mDY4>6P|wuCAfuPlo-F1tUTmngk6xMdwt)yMWv0-d^64htXAJ zAe;=)$FIzP#o@^n%H@_{Z%Huo+i(VhPOdf1( zV47+a=Q)6-CCVgH*ZwSuB=KLC3s>quax^c(o;%8~E|3rg6Da@yma06+5?a=NeJ)J| z`El~GiR)%z(&{5pN7+9@;fb25I;2ammoqvH1VXF*UMSdsbOq2!G+#lV1E=vJ;gZFt z1!u@2r&$q9D)MK=pf>4$qV2$H2Pevi~&_8-V9|Tfs ze$~t_gXsgHs)PIYj%d9iK~A1v*D#wyhInskC?m0+>*e^3O_eoJrRK1H)|I(A*1>(O zRjKAFued=@b%wiT$&|}^Vw|(juh;i}m}bW%{xM}8FA!Yz;QUWUHA&)ON=V`BzM3P0 zzEA%pU<%s%5lS;;Z3=Kb4uU|0^p7>#=Qg7k(Tg^2o*(kKp+Jyv7&O7mg%EuDaU5YV z722E;$pl6ns$T7{wW}DExP9h;9pxNO=(F3`##RI0_tXsPculbknCk<)i+H(mnE~TC z)Spu8qDDoo!pr}p{%M1k73c=GDpr+ACL6quvz*mO3kDiVGZBRF$-2?CY#3!%q<|W3 zOOzZ4vI-;uVdtYmqvnSE8BX@I7&wFN(en!pP2um5cq~zHyLz);8CCf>jwYYm*VjyZ zbMk}N>VwEGwLNz9y}&3e@IJ}dt~e2<@H$%&?IuP#sQ*_#*xs|z(rELTI>z%{;;rdi z?h3MhJ1pQ87s3cBNZcwuf}nL)_v+yIQSsoA8?O!VWoV3 zZQ8&CJLuNB_#h=R*s$l|vQNxPZ^eM#;X76ardAHj;-?fX4cZVIaR?BnrS4YLlaJo; zV>`AD{=Qtr0^;C}yr(l$H1xS+0VW?{`lZD$Y*(yGyBLJmVZ8?^*l0}2=z96*>d5wG zAoumMFdxhV!1zFZ+*$j#<^@PU{5z)=&b`-d&XJSGaJr)D5IX4Pj1x0+3RBHzGNU)VQn1suN6Kf&EpZ3i~ePx)~z_bOtX zwv$HHaYvr9X>Udg`)tYM^vPlsM{F||h z{F4kW0+JASaxirw{dV_mP?89<_1_-!Q0F@Aeuk200{#DDRNEYP3-xDvy+VDMbSGzq z`keh)@#-T*MS(~*h9mO{cbu25P^|B>FW^})w@=#>rL2PARHm8OHE;QtB^8S3D4q$$ zNBZp0?2LLpT&D{ll6tQ^GHJo}a)IZ|SA^WZgQbg1;{Uscz2>SsmV<^fqwraF`N@L^ zeU8G;ymjzt0{avGIYuW3V+TvqO2P=u5{MqFBYB8|_Q)>}lxHb! zTUT3*@o_bywgP|!-Wuvk{NVFf%DXAe7Qbo$W-l>q`Jd2O0DRje!A_Go7@cow5e%W` zp>ujAB74>8R~;Prh>>t4%39NWLP(acj@eSBpS%5FTB!9F22&ZDtqL*G8@=- z2QF^zv!E3f8pq&UECHcDT=o0brLOHG2v8hz?Raxx!*{A@?(_ekTy6uSb92jxuUPJH zL9A>|f8>-!Py6q6){+^@Jq zcgR0o2~MT@P0eBz=!Bo_O>kcGAHr2CK|-6WpkDbnT%VD^ITa*bm0VxER+HGzn#jd*q^Ozh zVV6UPgbb&SLNc}FsyyuK{075-43q$_;J~?|6Qpb1Z5piqj@g~Y#q<~hXlI{R1+F3r zcZ13f;fdIPMby`CDD@}`QY);z-kG_)tY18AM-fBAke;yiPdldLCI-HR`N{O`_Uz;& zkv~%XV|mFmA2Gr>m?vk-J%}~L%k3lrnf6OD{sRwjXph18me3uD?E%v}#`$?p$JwiN zZW$xU#H@PU?x$H+mY?`$IM|b$_uq0#Pk^Dcje3f_q8YNY2S%i{MvuFwB z8}v%uLvYI#fXr)fG-rf~qdgD2T1d@who?yz;r7waol!C(KNWi=&iE|9mCOVxQ9kH@ z3X)Mo!ZD)wK4WF|Y0RODxs9qj#Iymrv12LJw+i9wz;80D%4j4%C)G$T03Wko9(g6x zzxn1OO=-!N4ROhm>-h*!i@>%xF0kiu(5!w|AjpT#hz!}(8QXjVkl(=3P!POEQXhFU z=X{gl!#@!{zWTT{P34*2=A}fqP3cjMyzZSL;2@zqX6LoK;lY8WS(Mb8ze|!nC8^R~naOQ;q};7zx;3sjt23 zbolCLLjW{Cen*gk_sKP}|8c@Jb;Hdg5O2_*CjaWeWex-f3{pj(+&SbZ-feT#Pz%dg zrOYA#Pu-cqb&x@Ih&fhi{RKS~G&s)|{l?CoOeKK@SX(c>EJ1_Zb_E=X{c`8%gu_e`X>3r_`{Y zKU6CiIgeG!4Ok35(;%N&8Uo2`7UqPUAhB;YZEyd9wVP9#mY0QE)aMW|L+2{PS~$(4 z^q#_)q+8mahX2R(z%OX3z;N|(;{gC|A5W6BHNgpBVzMBjaQjTD4Cz(I}3|#7DrqNI3Z(Bz#-dD*`@#fX$++Jj@a5fI=ZE% z98MNVmV}V)>C(xw)v>JXGp}f>hxW=UfZ}~0475`V@Gm;wt^+b}xohk5We{@!D|KX- zFMg=5ukL;(oRE{ZW4=}*!ErALqrGc6YsH|sme39j1lbHv9H8EEzXahO)7!3=h~KBI zlfdP=E;UJm;#`fdi#hEw{41AO!H#@4Zd;Y1n$e&zVzJA0!1;)b8L?DK*4!MB`p}}G z;wxW)4v~oPb6<=4S>EE?l5*`*Fc*?7H^K>I2k;tC|3OhZzp0#8)Ai?LFP2g zu1FezAEK>k6Y{yT_>B;T(^uSYHbEFR>!nxzv-k$(YLD0UdVvv5L9T}i&Lq$284+Cd~`Rb5KJ@x$BY$2S-h z0LhH#sm(6 z&p-JwH^if#YJpDl(xM-$Kaeq)SJhCyii@DOCTimSaglcrBkNo~HZAsP+)kc}D42G} z2Kk6C>XIJg2N2kG#)?HL_+p17zXeCm_!w|gE)c*>=d-;n?h;2EXBN_v zE%!;xva{m?^P*o0DQ|%AaU>6WR)nWk?#$nGG5oj-TeoaXGT;HXh&AxdX~pqgK6Tnwl+H+5sUadQ~*XH3l6JXLi9wf*kt+dJJ(wrNKS)= z-F!e-Ep+*e!5|*OsIf#>%w=hCwD0Zy@b-a0ovG0v0T{3djk+6_zvYUUc}-&=gP8i} zZs-DK`3Kuikl6%(GWv4xud&9?3g7=D*!g#Wl|wq{{#zuXWS{aApFER^#%qbc=kkG;UvMHlksjJJ`TBSb$sv%bj)MP1*IP$bx%KVBG)qEK0YPBVN+aFfjeydfN_UG3 zq`M^q1e6pIq(Qn{>F(~XGts@D=Y7xlzA^S64#r@w8@T73*YB#ShO^`pJH)Ync&G*R zAjX>`x~x^;J+=F;P@z{;m!GCR6G)>?3Ne3q&M=Y*2JzB9@&v4t!!czLb; z0#iCGMNE`n(4p+l1(ge|+8<~4R?R_5CZF#Y*c}#}q$uqKPzHlu-I~Nevt~*gtp5p1 zFQ>hO=C&Kj)OnxQbe@EU`aif{00xg2>01{K@MDtZFaCP1DvKY06ZyK<$^E%Z<+rIQp6e< za@h1l|I7qy=h;bx#Rg-8{7xBupNST^uBO_UAud2Ae#={$LGk+!mfes7#@%%YnOk3U zJ9QY6f2++!m51$K#oNl*wF{uLJ1wq6kE;M~eJxB^4CH{08drC|W<--?p}cSRw6nZ# zu>jZ)9K^td*sNf<(xrmW2?vN1jR7EfyQhQL(E#-!g)�rqIG)qoz_`$^SBHI&#hi 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 diff --git a/components/lvgl.rst b/components/lvgl.rst index 311075c00..2776a5d72 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -320,14 +320,14 @@ LVGL internally stores fonts rendered in a C array. The library offers by defaul - ``montserrat_46``: 46px font - ``montserrat_48``: 48px font -You can display the embedded symbols easily on supported widgets using the ``symbol`` configuration option: +You can display the embedded symbols among the text by their codepoint address (the hexadecimal value in grey below, preceeded by ``\u``, eg. ``\uF00C``) or more easily on supported widgets using the ``symbol`` configuration option: .. figure:: /components/images/lvgl_symbols.png :align: center .. note:: - The ``text_font`` parameter influences the size of ``symbol``, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. + The ``text_font`` parameter influences the size of ``symbol`` configuration option, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. In addition to the above, the following special fonts are available from LVGL as built-in: @@ -631,9 +631,9 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **buttons** (**Required**, list): A list of buttons in a row: - **id** (*Optional*): An ID for a button - **text** or **symbol** (*Optional*): Text or built-in :ref:`symbol ` to display on the button. + - **key_code** (*Optional*, string): One character be sent as the key code to a :ref:`key_collector` instead of ``text`` when the button is pressed. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1`` (eg. in a line with two buttons: one ``width: 1`` and another one ``width: 2``, the first will be ``33%`` wide while the second will be ``66%`` wide). - **selected** (*Optional*, boolean): Set the button as the most recently released or focused. Defaults to ``false``. - - **key_code** (*Optional*, string): One character be sent as the key code to a :ref:`key_collector` instead of ``text`` when the button is pressed. - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): - **hidden** (*Optional*, boolean): makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). - **no_repeat** (*Optional*, boolean): Disable repeating when the button is long pressed. @@ -944,7 +944,7 @@ The ``led`` can be also integrated as :doc:`/components/light/lvgl`. If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. -Check out :ref:`lvgl-cook-keypad` for an example how to change the led styling properties from an automation. +Check out :ref:`lvgl-cook-keypad` in the Cookbook for an example how to change the led styling properties from an automation. .. _lvgl-wgt-lin: diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 3cf2adebc..bd8313b4a 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -762,7 +762,7 @@ The script runs every minute to update the hand line positions and the texts. A numeric input keypad ---------------------- -The :ref:`lvgl-wgt-bmx` widget can work together with the :ref:`key_collector` to collect the button presses as key press sequences. It sends the ``text`` of the buttons to the key collector. +The :ref:`lvgl-wgt-bmx` widget can work together with the :ref:`key_collector` to collect the button presses as key press sequences. It sends the ``text`` of the buttons (or ``key_code`` where configured) to the key collector. .. figure:: images/lvgl_cook_keypad.png :align: center @@ -804,7 +804,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c - label: id: lvgl_label align: CENTER - text: "* delete, # enter" + text: "Enter code and \uF00C" text_align: center - btnmatrix: id: lvgl_keypad @@ -879,7 +879,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c else: - lvgl.label.update: id: lvgl_label - text: "Please enter code" + text: "Enter code and \uF00C" on_result: - if: condition: @@ -893,7 +893,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c id: lvgl_led color: 0xFF0000 -A few notable things in this example: usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); usage of ``align_to`` to align it to the led vertically; changing the background color of the buttons in ``pressed`` state; using the ``key_code`` configuration option to send a different character to ``key_collector`` instead of the displayed symbol. +A few notable things in this example: usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); usage of ``align_to`` to align it to the led vertically; changing the background color of the buttons in ``pressed`` state; using the ``key_code`` configuration option to send a different character to ``key_collector`` instead of the displayed symbol; display a symbol within the text by its unicode codepoint address in the :ref:` font `. .. _lvgl-cook-idlescreen: From e9b8c11f9adb57e75d7cf0f0848783d583bcae19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jan 2024 11:17:54 +0100 Subject: [PATCH 175/350] Update lvgl.rst --- components/lvgl.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2776a5d72..091c8fd02 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -854,7 +854,7 @@ A label is the basic widget type that is used to display text. **Specific options:** -- **text** or **symbol** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``" "`` (space). +- **text** or **symbol** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` - **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) @@ -888,7 +888,12 @@ TODO Newline characters are handled automatically by the label widget. You can u align: CENTER id: lbl_id recolor: true - text: '#FF0000 write# #00FF00 colored# #0000FF text#' + text: "#FF0000 write# #00FF00 colored# #0000FF text#" + + - label: + align: TOP_MID + id: lbl_symbol + symbol: SETTINGS #same result as text: "\uF013" # Example action (update label with a value from a sensor): on_...: From 93d11a93805dd0c4ce11131b7ebac3a043e04862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jan 2024 11:34:33 +0100 Subject: [PATCH 176/350] label/symbols --- components/images/lvgl_symbols.png | Bin 55365 -> 55848 bytes components/lvgl.rst | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/images/lvgl_symbols.png b/components/images/lvgl_symbols.png index 8ac564a53129f1daef35c74b8829837c03e7b516..a18daf371fd8d7411c2ed201bbf3e090b0dbdafa 100644 GIT binary patch literal 55848 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 E09la3x&QzG literal 55365 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�mC--jru?QR%Z-ks^7g4MdQAtNoYtSXsU9g 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 TWwwh?U;qM7S3j3^P6 Date: Mon, 29 Jan 2024 11:57:03 +0100 Subject: [PATCH 177/350] Update lvgl.rst --- components/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 05605d95a..a75bc7aae 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -893,6 +893,7 @@ TODO Newline characters are handled automatically by the label widget. You can u - label: align: TOP_MID id: lbl_symbol + text_font: montserrat_28 symbol: SETTINGS #same result as text: "\uF013" # Example action (update label with a value from a sensor): From 3282fda9aace70df592abfd57f82c395ad0f159d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jan 2024 11:58:18 +0100 Subject: [PATCH 178/350] Update lvgl.rst --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index bd8313b4a..072f4215c 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -893,7 +893,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c id: lvgl_led color: 0xFF0000 -A few notable things in this example: usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); usage of ``align_to`` to align it to the led vertically; changing the background color of the buttons in ``pressed`` state; using the ``key_code`` configuration option to send a different character to ``key_collector`` instead of the displayed symbol; display a symbol within the text by its unicode codepoint address in the :ref:` font `. +A few notable things in this example: usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); usage of ``align_to`` to align it to the led vertically; changing the background color of the buttons in ``pressed`` state; using the ``key_code`` configuration option to send a different character to ``key_collector`` instead of the displayed symbol; display a symbol within the text by its unicode codepoint address in the :ref:`font `. .. _lvgl-cook-idlescreen: From a91f025ed12f47e9efc16921d7ab3a396f9ada8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jan 2024 12:00:14 +0100 Subject: [PATCH 179/350] Update lvgl.rst --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 072f4215c..17c93339e 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -893,7 +893,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c id: lvgl_led color: 0xFF0000 -A few notable things in this example: usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); usage of ``align_to`` to align it to the led vertically; changing the background color of the buttons in ``pressed`` state; using the ``key_code`` configuration option to send a different character to ``key_collector`` instead of the displayed symbol; display a symbol within the text by its unicode codepoint address in the :ref:`font `. +A few notable things in this example: usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); usage of ``align_to`` to align it to the led vertically; changing the background color of the buttons in ``pressed`` state; using the ``key_code`` configuration option to send a different character to ``key_collector`` instead of the displayed symbol; display a symbol within the text by its codepoint unicode address in the :ref:`font `. .. _lvgl-cook-idlescreen: From 0f1f9d07dd6d5d5720c9d565b7caf7237256f100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jan 2024 14:19:00 +0100 Subject: [PATCH 180/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a75bc7aae..033ec8cde 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -296,7 +296,7 @@ You can adjust the appearance of widgets by changing the foreground, background Fonts ***** -LVGL internally stores fonts rendered in a C array. The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: +LVGL internally stores fonts rendered in a C array. The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: - ``montserrat_8``: 8px font - ``montserrat_10``: 10px font From b378e03befb7c3c1b0c23163fc7bba7416edcbd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 30 Jan 2024 19:50:09 +0100 Subject: [PATCH 181/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 033ec8cde..7233a4361 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -640,7 +640,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **disabled** (*Optional*, boolean): applies *disabled* styles and properties to the button. - **checkable** (*Optional*, boolean): Enable toggling of a button, ``checked`` state will be added/removed as the button is clicked. - **checked** (*Optional*, boolean): make the button checked. It will use the styles of the ``checked`` state. - - **click_trig** (*Optional*, boolean): Controls how to :ref:`trigger ` ``on_value`` : if ``true`` on *click*, if ``false`` on *press*. TODO !!! + - **click_trig** (*Optional*, boolean): Controls how to :ref:`trigger ` ``on_value`` : if ``true`` on *click*, if ``false`` on *press*. - **popover** (*Optional*, boolean): show the button label in a popover when pressing this key. - **recolor** (*Optional*, boolean): Enable recoloring of button texts with #. E.g. ``It's #ff0000 red#`` - **custom_1** and **custom_2** (*Optional*, boolean): custom free to use flags From bf22cc791ad3e12eb1833a37a83b75774589931e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 31 Jan 2024 12:17:55 +0100 Subject: [PATCH 182/350] Update lvgl.rst --- components/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7233a4361..9e7152650 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -82,6 +82,7 @@ Configuration variables: - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. +- **default_font** (*Optional*, enum): The C array name of the internal :ref:`font ` used by default to render the text or symbol. Defaults to ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. From 2216dabb88cf883ced713ed895a9430d90ac0250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 31 Jan 2024 16:52:04 +0100 Subject: [PATCH 183/350] Update lvgl.rst --- cookbook/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 17c93339e..c6404a9ca 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -71,6 +71,7 @@ If you'd like to control a remote light which appears as an entity in Home Assis - platform: homeassistant id: remote_light entity_id: light.remote_light + publish_initial_state: true on_state: then: lvgl.widget.update: From f2c213e471eea0b625437d66a7195c200525cf53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 1 Feb 2024 17:00:08 +0100 Subject: [PATCH 184/350] font support --- components/display/index.rst | 91 ++++++++++++++++++++++++++++-------- components/lvgl.rst | 24 ++++++---- cookbook/lvgl.rst | 8 ++-- 3 files changed, 91 insertions(+), 32 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 75bc58246..5f07a0024 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -169,19 +169,24 @@ at **any** size, as well as fixed-size `PCF , , , [color=COLOR_ON], [align=TextAlign::TOP_LEFT], ); it.print(0, 0, id(my_font), COLOR_ON, "Left aligned"); +And you can also specify a background color for the text, using an optional parameter after the text: + +.. code-block:: yaml + + display: + - platform: ... + # ... + lambda: |- + // Syntax is always: it.print(, , , [color=COLOR_ON], [align=TextAlign::TOP_LEFT], , [color=COLOR_OFF]); + it.print(0, 0, id(my_font), COLOR_ON, "Left aligned"); + it.print(it.get_width()/2, it.get_height()/4 + 25, id(my_font_with_icons_20), display::COLOR_ON, TextAlign::CENTER, "I \uF004 You \uF001", COLOR_OFF); .. _display-printf: diff --git a/components/lvgl.rst b/components/lvgl.rst index 9e7152650..7337eeb5e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -297,7 +297,11 @@ You can adjust the appearance of widgets by changing the foreground, background Fonts ***** -LVGL internally stores fonts rendered in a C array. The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: +In ESPHome LVGL offers two font choices: the internal fonts offered by the library or :ref:`fonts configured in the normal way`. + +**Built-in fonts** + +The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: - ``montserrat_8``: 8px font - ``montserrat_10``: 10px font @@ -328,18 +332,21 @@ You can display the embedded symbols among the text by their codepoint address ( .. note:: - The ``text_font`` parameter affects the size of ``symbol``, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. + The ``text_font`` parameter affects the size of ``symbol``, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. If you set `text_font`` on a widget to a custom ESPHome font, these symbols will likely not display correctly. In addition to the above, the following special fonts are available from LVGL as built-in: -- ``unscii_8``: 8 px pixel perfect font with only ASCII characters -- ``unscii_16``: 16 px pixel perfect font with only ASCII characters -- ``simsun_16_cjk``: 16 px font with normal range + 1000 most common `CJK Radicals `__ -- ``dejavu_16_persian_hebrew``: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms +- ``unscii_8``: 8 px pixel perfect font with only ASCII characters. +- ``unscii_16``: 16 px pixel perfect font with only ASCII characters. +- ``simsun_16_cjk``: 16 px font with normal range + 1000 most common `CJK Radicals `__. +- ``dejavu_16_persian_hebrew``: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms. + +**ESPHome fonts** + +In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters for any language from any TrueType font. + -TODO !! You can generate your own set of glyphs in a C array using LVGL's `Online Font Converter `__ or use the tool `Offline `__. -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. .. _lvgl-widgets: @@ -1633,6 +1640,7 @@ See Also - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` - :doc:`/cookbook/lvgl` +- :doc:`/components/display/index` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` - `LVGL 8.3 docs `__ diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index c6404a9ca..adc2684e6 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -21,7 +21,7 @@ Local light switch If you have a display device with a local light configured, you can simply create a :ref:`lvgl-wgt-swi` for it. .. figure:: /components/images/lvgl_switch.png - :align: center + :align: left .. code-block:: yaml @@ -61,7 +61,7 @@ Remote light button ------------------- .. figure:: images/lvgl_cook_remligbut.png - :align: center + :align: right If you'd like to control a remote light which appears as an entity in Home Assistant from a toggle (checkable) :ref:`lvgl-wgt-btn`, first you need to import the light state into ESPHome, and then control it using a service call: @@ -108,7 +108,7 @@ Light brightness slider You can use a :ref:`slider ` or an :ref:`arc ` to control the the brightness of a dimmable light. .. figure:: images/lvgl_cook_volume.png - :align: center + :align: left We can use a sensor to retrieve the current brightness of a light, which is stored in Home Assistant as an attribute of the entity, as an integer value between ``0`` (min) and ``255`` (max). It's conveninent to set the slider's ``min_value`` and ``max_value`` accordingly. @@ -161,7 +161,7 @@ Media player volume slider Similarly, you can use a :ref:`slider ` or an :ref:`arc ` to control the volume level of a media player, which uses float values. .. figure:: images/lvgl_cook_volume.png - :align: center + :align: right With a sensor we retrieve the current volume level of the media player, which is stored in Home Assistant as an attribute of the entity, and is a float value between ``0`` (min) and ``1`` (max). Since LVGL only handles integers, it's conveninent to set the slider's possible values to be between ``0`` and ``100``. Thus a conversion is needed back and forth, meaning that when we read the value from Home Assistant we have to multiply it by ``100``, and when we set the volume through the service call, we have to divide it by ``100``: From ef56bc51b348339b3954202b18502ac86fbe389f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 1 Feb 2024 17:03:16 +0100 Subject: [PATCH 185/350] Update index.rst --- components/display/index.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 5f07a0024..52520d7ad 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -252,15 +252,15 @@ Configuration variables: - **family** (**Required**, string): The name of the Google Font family. - **italic** (*Optional*, boolean): Whether the font should be italic. - **weight** (*Optional*, enum): The weight of the font. Can be either the text name or the integer value: - - **thin**: 100 - - **extra-light**: 200 - - **light**: 300 - - **regular**: 400 (**default**) - - **medium**: 500 - - **semi-bold**: 600 - - **bold**: 700 - - **extra-bold**: 800 - - **black**: 900 + - **thin**: 100 + - **extra-light**: 200 + - **light**: 300 + - **regular**: 400 (**default**) + - **medium**: 500 + - **semi-bold**: 600 + - **bold**: 700 + - **extra-bold**: 800 + - **black**: 900 - **id** (**Required**, :ref:`config-id`): The ID with which you will be able to reference the font later in your display code. From 6f2aa59b82870c927fcdd0a42a3b7b38fc2e32ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 1 Feb 2024 17:12:30 +0100 Subject: [PATCH 186/350] lints --- components/display/index.rst | 18 +++++++----------- components/lvgl.rst | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 52520d7ad..aa1b82bd6 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -203,7 +203,7 @@ Next, create a ``font:`` section in your configuration: size: 50 glyphs: ["\U0000e425"] # mdi-timer - - file: 'custom/RobotoCondensed-Regular.ttf' + - file: 'fonts/RobotoCondensed-Regular.ttf' id: roboto_special_28 size: 28 bpp: 4 @@ -213,12 +213,7 @@ Next, create a ``font:`` section in your configuration: "\u0020", #space "\u0021", #! "\u0022", #" - "\u0025", #% "\u0027", #' - "\u002C", #, - "\u003A", #: - "\u003D", #= - "\u003F", #? ] - file: "fonts/RobotoCondensed-Regular.ttf" @@ -230,6 +225,8 @@ Next, create a ``font:`` section in your configuration: glyphs: - "\uF001" # music - "\uF004" # heart + - "\uF0EB" # lightbulb + - "\uF5C5" # pool display: # ... @@ -276,8 +273,8 @@ Configuration variables: ``!"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz``. - **extras** (*Optional*, enum):A list of font glyph configurations you'd like to include within this font, from other TrueType files (eg. icons from other font, but at the same size as the main font): - - **file** (**Required**): The path of the font file with the extra glyphs. - - **glyphs** (**Required**, list): A list of glyphs you want to include. + - **file** (**Required**): The path of the font file with the extra glyphs. + - **glyphs** (**Required**, list): A list of glyphs you want to include. .. note:: @@ -289,8 +286,8 @@ Configuration variables: TrueType font files offer icons at codepoints far from what's reachable on a standard keyboard, for these it's needed to specify the unicode codepoint of the glyph as a hex address escaped with ``\u`` or ``\U``. - Code points up to `0xFFFF` are encoded like ``\uE6E8``. Lowercase ``\u`` and exactly 4 hexadecimal digits. - Code points above `0xFFFF` are encoded like ``\U0001F5E9``. Capital ``\U`` and exactly 8 hexadecimal digits. + Code points up to ``0xFFFF`` are encoded like ``\uE6E8``. Lowercase ``\u`` and exactly 4 hexadecimal digits. + Code points above ``0xFFFF`` are encoded like ``\U0001F5E9``. Capital ``\U`` and exactly 8 hexadecimal digits. The ``extras`` section only supports TrueType files, ``size`` and ``bpp`` will be the same as one level above. This will allow printing icons alongside the characters in the same string, like ``I \uF004 You \uF001``. @@ -350,7 +347,6 @@ And you can also specify a background color for the text, using an optional para # ... lambda: |- // Syntax is always: it.print(, , , [color=COLOR_ON], [align=TextAlign::TOP_LEFT], , [color=COLOR_OFF]); - it.print(0, 0, id(my_font), COLOR_ON, "Left aligned"); it.print(it.get_width()/2, it.get_height()/4 + 25, id(my_font_with_icons_20), display::COLOR_ON, TextAlign::CENTER, "I \uF004 You \uF001", COLOR_OFF); .. _display-printf: diff --git a/components/lvgl.rst b/components/lvgl.rst index 7337eeb5e..3cd522fcd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -332,7 +332,7 @@ You can display the embedded symbols among the text by their codepoint address ( .. note:: - The ``text_font`` parameter affects the size of ``symbol``, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. If you set `text_font`` on a widget to a custom ESPHome font, these symbols will likely not display correctly. + The ``text_font`` parameter affects the size of ``symbol``, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. If you set ``text_font`` on a widget to a custom ESPHome font, these symbols will likely not display correctly. In addition to the above, the following special fonts are available from LVGL as built-in: From 96ab5d5e3bc3448ce99912724d28589ba3dc18ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 1 Feb 2024 17:16:31 +0100 Subject: [PATCH 187/350] Update index.rst --- components/display/index.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index aa1b82bd6..51b44aa37 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -168,6 +168,8 @@ specific sizes, with ESPHome you have the option to use **any** TrueType (``.ttf at **any** size, as well as fixed-size `PCF `_ and `BDF `_ bitmap fonts! Granted the reason for it is actually not having to worry about the licensing of font files :) +These fonts can be also used in :ref:`LVGL `. + To use fonts you first have to define a font object in your ESPHome configuration file. Just grab a ``.ttf``, ``.otf``, ``.woff``, ``.pcf``, or ``.bdf`` file from somewhere on the internet and place it, for example, inside a ``fonts`` folder next to your configuration file. @@ -273,8 +275,8 @@ Configuration variables: ``!"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz``. - **extras** (*Optional*, enum):A list of font glyph configurations you'd like to include within this font, from other TrueType files (eg. icons from other font, but at the same size as the main font): - - **file** (**Required**): The path of the font file with the extra glyphs. - - **glyphs** (**Required**, list): A list of glyphs you want to include. + - **file** (**Required**): The path of the font file with the extra glyphs. + - **glyphs** (**Required**, list): A list of glyphs you want to include. .. note:: From 52a2573be95f46627b36a44d6a16e5474800886d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 1 Feb 2024 17:18:30 +0100 Subject: [PATCH 188/350] Update lvgl.rst --- cookbook/lvgl.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index adc2684e6..b395dd8f8 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -18,11 +18,11 @@ Here are a couple recipes for various interesting things you can do with :ref:`l Local light switch ------------------ -If you have a display device with a local light configured, you can simply create a :ref:`lvgl-wgt-swi` for it. - .. figure:: /components/images/lvgl_switch.png :align: left +If you have a display device with a local light configured, you can simply create a :ref:`lvgl-wgt-swi` for it. + .. code-block:: yaml light: @@ -105,11 +105,11 @@ If you'd like to control a remote light which appears as an entity in Home Assis Light brightness slider ----------------------- -You can use a :ref:`slider ` or an :ref:`arc ` to control the the brightness of a dimmable light. - .. figure:: images/lvgl_cook_volume.png :align: left +You can use a :ref:`slider ` or an :ref:`arc ` to control the the brightness of a dimmable light. + We can use a sensor to retrieve the current brightness of a light, which is stored in Home Assistant as an attribute of the entity, as an integer value between ``0`` (min) and ``255`` (max). It's conveninent to set the slider's ``min_value`` and ``max_value`` accordingly. .. code-block:: yaml @@ -158,11 +158,11 @@ This is applicable to service calls like ``fan.set_percentage``, ``valve.set_val Media player volume slider -------------------------- -Similarly, you can use a :ref:`slider ` or an :ref:`arc ` to control the volume level of a media player, which uses float values. - .. figure:: images/lvgl_cook_volume.png :align: right +Similarly, you can use a :ref:`slider ` or an :ref:`arc ` to control the volume level of a media player, which uses float values. + With a sensor we retrieve the current volume level of the media player, which is stored in Home Assistant as an attribute of the entity, and is a float value between ``0`` (min) and ``1`` (max). Since LVGL only handles integers, it's conveninent to set the slider's possible values to be between ``0`` and ``100``. Thus a conversion is needed back and forth, meaning that when we read the value from Home Assistant we have to multiply it by ``100``, and when we set the volume through the service call, we have to divide it by ``100``: .. code-block:: yaml From 75ad6d3f5a28e08f98b0623b0799e222ad2ca4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 1 Feb 2024 17:19:57 +0100 Subject: [PATCH 189/350] Update index.rst --- components/display/index.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 51b44aa37..491810bbf 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -273,10 +273,9 @@ Configuration variables: reduce the size of the binary if you don't plan to use some glyphs. The items in the list can also be more than one character long if you for example want to use font ligatures. You can also specify glyphs by their codepoint (see below). Defaults to ``!"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz``. -- **extras** (*Optional*, enum):A list of font glyph configurations you'd like to include within this - font, from other TrueType files (eg. icons from other font, but at the same size as the main font): - - **file** (**Required**): The path of the font file with the extra glyphs. - - **glyphs** (**Required**, list): A list of glyphs you want to include. +- **extras** (*Optional*, enum):A list of font glyph configurations you'd like to include within this font, from other TrueType files (eg. icons from other font, but at the same size as the main font): + - **file** (**Required**): The path of the font file with the extra glyphs. + - **glyphs** (**Required**, list): A list of glyphs you want to include. .. note:: From 9f11582e3c10a0df003b466bdd99a91deab802be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 1 Feb 2024 17:26:47 +0100 Subject: [PATCH 190/350] lints --- components/display/index.rst | 7 +++++-- components/lvgl.rst | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 491810bbf..278ad946d 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -237,6 +237,7 @@ Configuration variables: - **file** (**Required**): The path (relative to where the .yaml file is) of the font file. You can also use the ``gfonts://`` short form to use Google Fonts, or use the below structure: + - **type** (**Required**, string): Can be ``local`` or ``gfonts``. **Local Fonts**: @@ -266,14 +267,14 @@ Configuration variables: - **size** (*Optional*, int): The size of the font in pt (not pixel!). If you want to use the same font in different sizes, create two font objects. Note: *size* is ignored by bitmap fonts. Defaults to ``20``. -- **bpp** (*Optional*, int): The bit depth of the rendered font from TTF, for anti-aliasing. Can be ``1``,``2``, - ``4``,``8``. Defaults to ``1``. +- **bpp** (*Optional*, int): The bit depth of the rendered font from TrueType, for anti-aliasing. Can be ``1``,``2``,``4``,``8``. Defaults to ``1``. - **glyphs** (*Optional*, list): A list of characters you plan to use. Only the characters you specify here will be compiled into the binary. Adjust this if you need some special characters or want to reduce the size of the binary if you don't plan to use some glyphs. The items in the list can also be more than one character long if you for example want to use font ligatures. You can also specify glyphs by their codepoint (see below). Defaults to ``!"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz``. - **extras** (*Optional*, enum):A list of font glyph configurations you'd like to include within this font, from other TrueType files (eg. icons from other font, but at the same size as the main font): + - **file** (**Required**): The path of the font file with the extra glyphs. - **glyphs** (**Required**, list): A list of glyphs you want to include. @@ -292,6 +293,8 @@ Configuration variables: The ``extras`` section only supports TrueType files, ``size`` and ``bpp`` will be the same as one level above. This will allow printing icons alongside the characters in the same string, like ``I \uF004 You \uF001``. + + Many font sizes with multiple glyphs at high bit depths will increase the binary size considerably. Make your choices carefully. .. _display-static_text: diff --git a/components/lvgl.rst b/components/lvgl.rst index 3cd522fcd..e795b6147 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -299,7 +299,7 @@ Fonts In ESPHome LVGL offers two font choices: the internal fonts offered by the library or :ref:`fonts configured in the normal way`. -**Built-in fonts** +**Internal fonts** The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: From c009072de18bff9dc3c29ad7ff371f2bd9b25ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 1 Feb 2024 17:35:01 +0100 Subject: [PATCH 191/350] Update index.rst --- components/display/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 278ad946d..f06bf8cb6 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -276,7 +276,7 @@ Configuration variables: - **extras** (*Optional*, enum):A list of font glyph configurations you'd like to include within this font, from other TrueType files (eg. icons from other font, but at the same size as the main font): - **file** (**Required**): The path of the font file with the extra glyphs. - - **glyphs** (**Required**, list): A list of glyphs you want to include. + - **glyphs** (**Required**, list): A list of glyphs you want to include. Can't repeat the same glyph if it was declared in the level above. .. note:: @@ -291,8 +291,8 @@ Configuration variables: Code points up to ``0xFFFF`` are encoded like ``\uE6E8``. Lowercase ``\u`` and exactly 4 hexadecimal digits. Code points above ``0xFFFF`` are encoded like ``\U0001F5E9``. Capital ``\U`` and exactly 8 hexadecimal digits. - The ``extras`` section only supports TrueType files, ``size`` and ``bpp`` will be the same as one level above. This - will allow printing icons alongside the characters in the same string, like ``I \uF004 You \uF001``. + The ``extras`` section only supports TrueType files, ``size`` and ``bpp`` will be the same as the above level. This will allow + printing icons alongside the characters in the same string, like ``I \uF004 You \uF001``. Many font sizes with multiple glyphs at high bit depths will increase the binary size considerably. Make your choices carefully. From 61d264a5a3c34ee340de3776b5a19933be5d51d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 2 Feb 2024 11:08:30 +0100 Subject: [PATCH 192/350] Update index.rst --- components/display/index.rst | 64 ++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index f06bf8cb6..29cd3961d 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -162,11 +162,7 @@ You can view the full API documentation for the rendering engine in the "API Ref Fonts ***** -The rendering engine also has a powerful font drawer which integrates seamlessly into ESPHome. -Whereas in most Arduino display projects you have to use one of a few pre-defined fonts in very -specific sizes, with ESPHome you have the option to use **any** TrueType (``.ttf``) font file -at **any** size, as well as fixed-size `PCF `_ and `BDF `_ bitmap fonts! Granted the reason for it is -actually not having to worry about the licensing of font files :) +The rendering engine also has a powerful font drawer which integrates seamlessly into ESPHome. You have the option to use **any** OpenType/TrueType (``.ttf``, ``.otf``, ``.woff``) font file at **any** size, as well as fixed-size `PCF `_ and `BDF `_ bitmap fonts! These fonts can be also used in :ref:`LVGL `. @@ -190,22 +186,22 @@ Next, create a ``font:`` section in your configuration: # gfonts://family[@weight] - file: "gfonts://Roboto" - id: roboto + id: roboto_20 size: 20 - file: type: gfonts family: Roboto weight: 900 - id: font2 + id: roboto_16 size: 16 - file: "gfonts://Material+Symbols+Outlined" - id: icon_font_50 + id: icons_50 size: 50 glyphs: ["\U0000e425"] # mdi-timer - - file: 'fonts/RobotoCondensed-Regular.ttf' + - file: "fonts/RobotoCondensed-Regular.ttf" id: roboto_special_28 size: 28 bpp: 4 @@ -219,30 +215,29 @@ Next, create a ``font:`` section in your configuration: ] - file: "fonts/RobotoCondensed-Regular.ttf" - id: my_font_with_icons_20 + id: my_font_with_icons size: 20 bpp: 4 extras: - - file: "fonts/FontAwesome5-Solid+Brands+Regular.woff.ttf" - glyphs: - - "\uF001" # music - - "\uF004" # heart - - "\uF0EB" # lightbulb - - "\uF5C5" # pool + - file: "fonts/materialdesignicons-webfont.ttf" + glyphs: [ + "\U000F02D1", # mdi-heart + "\U000F05D4", # mdi-airplane-landing + ] display: # ... Configuration variables: -- **file** (**Required**): The path (relative to where the .yaml file is) of the font +- **file** (**Required**, string): The path (relative to where the .yaml file is) of the font file. You can also use the ``gfonts://`` short form to use Google Fonts, or use the below structure: - **type** (**Required**, string): Can be ``local`` or ``gfonts``. **Local Fonts**: - - **path** (**Required**, string): The path (relative to where the .yaml file is) of the TrueType or bitmap font file. + - **path** (**Required**, string): The path (relative to where the .yaml file is) of the OpenType/TrueType or bitmap font file. **Google Fonts**: @@ -267,35 +262,32 @@ Configuration variables: - **size** (*Optional*, int): The size of the font in pt (not pixel!). If you want to use the same font in different sizes, create two font objects. Note: *size* is ignored by bitmap fonts. Defaults to ``20``. -- **bpp** (*Optional*, int): The bit depth of the rendered font from TrueType, for anti-aliasing. Can be ``1``,``2``,``4``,``8``. Defaults to ``1``. +- **bpp** (*Optional*, int): The bit depth of the rendered font from OpenType/TrueType, for anti-aliasing. Can be ``1``, ``2``, ``4``, ``8``. Defaults to ``1``. - **glyphs** (*Optional*, list): A list of characters you plan to use. Only the characters you specify here will be compiled into the binary. Adjust this if you need some special characters or want to - reduce the size of the binary if you don't plan to use some glyphs. The items in the list can also - be more than one character long if you for example want to use font ligatures. You can also specify glyphs by their codepoint (see below). Defaults to - ``!"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz``. -- **extras** (*Optional*, enum):A list of font glyph configurations you'd like to include within this font, from other TrueType files (eg. icons from other font, but at the same size as the main font): + reduce the size of the binary if you don't plan to use some glyphs. You can also specify glyphs by their codepoint (see below). Defaults to ``!"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz``. +- **extras** (*Optional*, enum): A list of font glyph configurations you'd like to include within this font, from other OpenType/TrueType files (eg. icons from other font, but at the same size as the main font): - - **file** (**Required**): The path of the font file with the extra glyphs. - - **glyphs** (**Required**, list): A list of glyphs you want to include. Can't repeat the same glyph if it was declared in the level above. + - **file** (**Required**, string): The path of the font file with the extra glyphs. + - **glyphs** (**Required**, list): A list of glyphs you want to include. Can't repeat the same glyph codepoint if it was declared in the level above. .. note:: - To use fonts you will need to have the python ``pillow`` package installed, as ESPHome uses that package - to translate the TrueType and bitmap font files into an internal format. If you're running this as a Home Assistant - add-on or with the official ESPHome docker image, it should already be installed. Otherwise you need - to install it using ``pip install "pillow==10.1.0"``. - - TrueType font files offer icons at codepoints far from what's reachable on a standard keyboard, for these it's needed + OpenType/TrueType font files offer icons at codepoints far from what's reachable on a standard keyboard, for these it's needed to specify the unicode codepoint of the glyph as a hex address escaped with ``\u`` or ``\U``. Code points up to ``0xFFFF`` are encoded like ``\uE6E8``. Lowercase ``\u`` and exactly 4 hexadecimal digits. Code points above ``0xFFFF`` are encoded like ``\U0001F5E9``. Capital ``\U`` and exactly 8 hexadecimal digits. - The ``extras`` section only supports TrueType files, ``size`` and ``bpp`` will be the same as the above level. This will allow - printing icons alongside the characters in the same string, like ``I \uF004 You \uF001``. + The ``extras`` section only supports OpenType/TrueType files, ``size`` and ``bpp`` will be the same as the above level. This will allow printing icons alongside the characters in the same string, like ``I \uF004 You \uF001``. Many font sizes with multiple glyphs at high bit depths will increase the binary size considerably. Make your choices carefully. + To use fonts you will need to have the python ``pillow`` package installed, as ESPHome uses that package + to translate the OpenType/TrueType and bitmap font files into an internal format. If you're running this as a Home Assistant + add-on or with the official ESPHome docker image, it should already be installed. Otherwise you need + to install it using ``pip install "pillow==10.1.0"``. + .. _display-static_text: Drawing Static Text @@ -342,7 +334,7 @@ As with basic shapes, you can also specify a color for the text: // Syntax is always: it.print(, , , [color=COLOR_ON], [align=TextAlign::TOP_LEFT], ); it.print(0, 0, id(my_font), COLOR_ON, "Left aligned"); -And you can also specify a background color for the text, using an optional parameter after the text: +In case of fonts rendered at higher bit depths, the background color has to be specified after the text in order for antialiasing to work: .. code-block:: yaml @@ -350,8 +342,8 @@ And you can also specify a background color for the text, using an optional para - platform: ... # ... lambda: |- - // Syntax is always: it.print(, , , [color=COLOR_ON], [align=TextAlign::TOP_LEFT], , [color=COLOR_OFF]); - it.print(it.get_width()/2, it.get_height()/4 + 25, id(my_font_with_icons_20), display::COLOR_ON, TextAlign::CENTER, "I \uF004 You \uF001", COLOR_OFF); + // Syntax is always: it.print(, , , [color=COLOR_ON], [align], , [color=COLOR_OFF]); + it.print(0, 0, id(my_font_with_icons), COLOR_ON, TextAlign::CENTER, "Just\U000f05d4here. Already\U000F02D1this.", COLOR_OFF); .. _display-printf: From a3321bf5fd5acf8ee992566e9d6519ba7382ce2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 2 Feb 2024 13:28:40 +0100 Subject: [PATCH 193/350] double quotes --- components/display/index.rst | 2 +- components/lvgl.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 29cd3961d..598c66ff0 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -293,7 +293,7 @@ Configuration variables: Drawing Static Text ******************* -In your display code, you can render static text by referencing the font and just entering your string: +In your display code, you can render static text by referencing the font and just entering your string enclosed in double quotes: .. code-block:: yaml diff --git a/components/lvgl.rst b/components/lvgl.rst index e795b6147..4eb1216fd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -881,7 +881,7 @@ A label is the basic widget type that is used to display text. - **selected** (*Optional*, list): Settings for the the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. -TODO Newline characters are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``line1\nline2\n\nline4``. +Newline escape sequences are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``"line1\nline2\n\nline4"``. **Note**: For escape sequences like newline to be translated, enclose the string in double quotes. **Specific actions:** From d5522d2c17a0ff627b2675569b21268b961e87fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 2 Feb 2024 14:12:51 +0100 Subject: [PATCH 194/350] Update lvgl.rst --- cookbook/lvgl.rst | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index b395dd8f8..3e848b84a 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -13,6 +13,54 @@ Here are a couple recipes for various interesting things you can do with :ref:`l The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of ``240x320px``, you have to adjust them to your screen in order to obtain expected results. + +.. _lvgl-cook-icons: + +MDI icons in text +----------------- + +ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. + +One example is when you'd like some MDI icons to be used in line with the text (similarly how LVGL's internal fonts and symbols coexist). You can use a font of your choice, choose the symbols you want and mix them in a single sized set with icons from MDI. + +In the example below we use the default set of glyphs from RobotoCondensed-Regular, and append some extra symbols to it from MDI. Then we display these inline with the text by escaping their codepoints: + +.. code-block:: yaml + + font: + - file: "fonts/RobotoCondensed-Regular.ttf" + id: roboto_icons_42 + size: 42 + bpp: 4 + extras: + - file: "fonts/materialdesignicons-webfont.ttf" + glyphs: [ + "\U000F02D1", # mdi-heart + "\U000F05D4", # mdi-airplane-landing + ] + + lvgl: + ... + pages: + - id: main_page + widgets: + - label: + text: "Just\U000f05d4here. Already\U000F02D1this." + align: CENTER + text_align: center + text_font: roboto_icons_42 + + +.. note:: + + Follow these steps to choose your MDI icons: + + - To lookup your icons, use the `Pictogrammers `_ site. Click on the desired icon, and note down / copy the codepoint of it (it's the hexadecimal number near the download options). + - To get the TrueType font with all the icons in it, head on to the `Pictogrammers GitHub repository `_ and from a recent version folder, download the ``materialdesignicons-webfont.ttf`` file and place it in your ESPHome config directory under a folder named ``fonts`` (to match the example above). + - To use the desired icon, prepend the copied codepoint with ``\U000``. The unicode character escape sequence has to start with capital ``\U`` and have exactly 8 hexadecimal digits. + - To translate the escape sequence into the real glyph, make sure you enclose your strings in double quotes. + + .. _lvgl-cook-relay: Local light switch From dc0ec65d6363fe8584fb047290a83702647a62ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 2 Feb 2024 19:36:45 +0100 Subject: [PATCH 195/350] icons --- components/lvgl.rst | 2 +- cookbook/images/lvgl_cook_font_batt.png | Bin 0 -> 250 bytes cookbook/images/lvgl_cook_font_roboto_mdi.png | Bin 0 -> 2355 bytes cookbook/lvgl.rst | 243 ++++++++++++++---- 4 files changed, 194 insertions(+), 51 deletions(-) create mode 100644 cookbook/images/lvgl_cook_font_batt.png create mode 100644 cookbook/images/lvgl_cook_font_roboto_mdi.png diff --git a/components/lvgl.rst b/components/lvgl.rst index 4eb1216fd..3e0db8097 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -345,7 +345,7 @@ In addition to the above, the following special fonts are available from LVGL as In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters for any language from any TrueType font. - +Check out :ref:`lvgl-cook-icontext` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples how to play with texts and icons using various TrueType/OpenType fonts. .. _lvgl-widgets: diff --git a/cookbook/images/lvgl_cook_font_batt.png b/cookbook/images/lvgl_cook_font_batt.png new file mode 100644 index 0000000000000000000000000000000000000000..58d8843bc4fc6ca1a15ed5bc77fa9beb84786e46 GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^ia;#G!2~1|k{rE(6lZ})WHAE+-w_aIoT|+y4HR7C z>EamT(V6_`|9^YtUPj@yx)NKPRSr1qxl}y;{Mos7;^%zN`IucYU9?H|yZoK|+iIof zyngc1Wr=LhktKIu?0Avf-k&&i)26LayD~II-voq&q$DIvm@>gdxc=WGOJ?T7e}8}f zn5}NMMnzSnU)KG5*VLt=N2LBF>{xR5;1qkinx7lWK1caDCViPSVO;@Z)61+KM~<(M xb-uu-9j$G&LTcu7z^Vb(G9)t*`HY@csVqdcR(e$NT5!>+vGGx!6mB6hQz0NIE*$UOe>8 zLm@@FP-d20Zwu>Bg+jBcVY)nBsJqz61TNaRFl|ZR7i^{pFp~ zuC}<86ba!Bzg?z>sijJ>hV6i`pOr9rQ}%xeV>Sa{2?zw}^18^3Vzjw%1ne&-M@&zT zhv_WtZzCenP_$yn*8K{^nva%V4?3yI$#GhaZE- zo_$v=5`eK3Ej(EK6&%DZ5`~jcFWe1&p=bAXsspik=bRi96ZWS%Vs5oF!;EOSVIhF_ zB-n!818sD+;9~Me{}wMf$j@NG2ci24SsSghnIS$jkA9QM;Ebw=g?-p2)zbV?wZQ)9 zl!>z|kg>ZAmU9`x>&&?kqs)pU?)pC|z4u7)?Uv9Ceb(C<+o#H`#>xzNsKG*p;2=eexizIq!lNR16U z^H^qZ(poBN3h`%S1}eTf$mvIS@AAoq;(6u%P<{elZ7nq(xEXegEGm^_y&5{$Q&eX1ql&56% z$=qRnoV{U-b9^^$$Q20a+l-c|M$X!^>-~*5FM)C0$aD5V9mKf994;?9>sAuFCiQBw z8A<-jiP~Dq)q>f-&{HQb4qx5op7MRyaFHgubDM`LYVYG@%W)Zqh!*5=U^{85QTXPr zyHa|P^u3)4FGh=Pv>QZ8Vu&@s|BA>pZ}fP7(+sSK&V-~47c``=4g$~wGXnp)}WYa-D7jFEvrnQDlfZ1Q})siiruM2uw z>eBj{TSM~{_mTT?QTS#b4Q&>jXydydB(|eal#LN`s*MjzqS0Ufh!X=^_KF`Exu~6k zF~5UzR3!2;GOgZkE;;Iv?^l?vO95AcGx-nNTAG%pZ=>sH8>u5kSI5LjAZ$VBwkCiC z7dbhe;EFX|dHRA10Aaxz-5Nsw@~evmM;aBCN#0|Ci%UPWpGJ6C+9u!X&n;q=-on8~ zzYsmLb_U6EmGg^tZo`S7sXk>{HZ;{|!D8|qJ_4{_4PtTdgIEk`&b3DNZJj+HV` z*XIflk>fU@oh7|*2KXEJxXZy+6KhywRGCd6^~FnhTTMt0J7jZZNs{4P8}{+W=-{n} z>yUO$*62QVAJ~jviU4+7whaa2XIJEt33J)Q-cHA>4B`i9sI(90G&W?eVP(_gWlK~} z8F9p0woLM6}x{sW9sMr@2^Q0JvU1gTVcwi*;Mv` z3;4KfIr~%_j8W1v?($;VA!efG={5=ER#kHjYllkLuLc$huJ9r(!$iM)O8-@8sX^@8*co74D`Mt!ledl%EX=D~MFbdi@jT!@SUs4TwE^@M zr!;Djk8&B@XOCW8wvL2y>kV+@|#(G;|pyxB55-xWW2 zteL*0VkV}T3)g*H-TIqWVa^4+Xz9kNoa>SOn!hY$7J{3RJNyY;w~x>vNX+OquX52&~S>s9JMk`5`G=z3A?` z+954L+~PZS&2uNtHy$Tqb!@%r!(_4&nsXm|pP$*rnBj5O-{d;X+s!lYo}4aO?q!!K zP@b%tbC3}U+Xv}sq=-<;;`AH>tSmW|o7~zo&X2(jxZ?A6H~5)mXpV*8pc`&yasIsE z+m|YQ^%nRmzRTmr$obXXK9k68^a3F@XICSqkcjD-uApv>RDp6)sp1YxZ(JGH8`6tu4dDI`nfl)TbuMn(Ea}Q9=M?5 yqspHJ8FqttFL5JzSQRxJnG}(?|IbSJag-GNLD75;k#M+z0LNclZ0Xki8UF$5`GE}p literal 0 HcmV?d00001 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 3e848b84a..d43f65a16 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -14,53 +14,6 @@ Here are a couple recipes for various interesting things you can do with :ref:`l The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of ``240x320px``, you have to adjust them to your screen in order to obtain expected results. -.. _lvgl-cook-icons: - -MDI icons in text ------------------ - -ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. - -One example is when you'd like some MDI icons to be used in line with the text (similarly how LVGL's internal fonts and symbols coexist). You can use a font of your choice, choose the symbols you want and mix them in a single sized set with icons from MDI. - -In the example below we use the default set of glyphs from RobotoCondensed-Regular, and append some extra symbols to it from MDI. Then we display these inline with the text by escaping their codepoints: - -.. code-block:: yaml - - font: - - file: "fonts/RobotoCondensed-Regular.ttf" - id: roboto_icons_42 - size: 42 - bpp: 4 - extras: - - file: "fonts/materialdesignicons-webfont.ttf" - glyphs: [ - "\U000F02D1", # mdi-heart - "\U000F05D4", # mdi-airplane-landing - ] - - lvgl: - ... - pages: - - id: main_page - widgets: - - label: - text: "Just\U000f05d4here. Already\U000F02D1this." - align: CENTER - text_align: center - text_font: roboto_icons_42 - - -.. note:: - - Follow these steps to choose your MDI icons: - - - To lookup your icons, use the `Pictogrammers `_ site. Click on the desired icon, and note down / copy the codepoint of it (it's the hexadecimal number near the download options). - - To get the TrueType font with all the icons in it, head on to the `Pictogrammers GitHub repository `_ and from a recent version folder, download the ``materialdesignicons-webfont.ttf`` file and place it in your ESPHome config directory under a folder named ``fonts`` (to match the example above). - - To use the desired icon, prepend the copied codepoint with ``\U000``. The unicode character escape sequence has to start with capital ``\U`` and have exactly 8 hexadecimal digits. - - To translate the escape sequence into the real glyph, make sure you enclose your strings in double quotes. - - .. _lvgl-cook-relay: Local light switch @@ -469,6 +422,8 @@ In this example we prepare a set of gradient styles in the *theme*, and make som lvgl: ... theme: + label: + text_font: my_font # set all your labels to use your custom defined font btn: bg_color: 0x2F8CD8 bg_grad_color: 0x005782 @@ -477,13 +432,68 @@ In this example we prepare a set of gradient styles in the *theme*, and make som border_color: 0x0077b3 border_width: 1 text_color: 0xFFFFFF - pressed: + pressed: # set some btn colors to be different in pressed state bg_color: 0x006699 bg_grad_color: 0x00334d + checked: # set some btn colors to be different in checked state + bg_color: 0x1d5f96 + bg_grad_color: 0x03324A + text_color: 0xfff300 + btnmatrix: + bg_opa: transp + border_color: 0x0077b3 + border_width: 0 + text_color: 0xFFFFFF + pad_all: 0 + items: # set all your btnmatrix buttins to use your custom defined styles and font + bg_color: 0x2F8CD8 + bg_grad_color: 0x005782 + bg_grad_dir: VER + bg_opa: cover + border_color: 0x0077b3 + border_width: 1 + text_color: 0xFFFFFF + text_font: my_font + pressed: + bg_color: 0x006699 + bg_grad_color: 0x00334d + checked: + bg_color: 0x1d5f96 + bg_grad_color: 0x03324A + text_color: 0x005580 + switch: + bg_color: 0xC0C0C0 + bg_grad_color: 0xb0b0b0 + bg_grad_dir: VER + bg_opa: cover checked: bg_color: 0x1d5f96 bg_grad_color: 0x03324A - text_color: 0x005580 + bg_grad_dir: VER + bg_opa: cover + knob: + bg_color: 0xFFFFFF + bg_grad_color: 0xC0C0C0 + bg_grad_dir: VER + bg_opa: cover + slider: + border_width: 1 + border_opa: 15% + bg_color: 0xcccaca + bg_opa: 15% + indicator: + bg_color: 0x1d5f96 + bg_grad_color: 0x03324A + bg_grad_dir: VER + bg_opa: cover + knob: + bg_color: 0x2F8CD8 + bg_grad_color: 0x005782 + bg_grad_dir: VER + bg_opa: cover + border_color: 0x0077b3 + border_width: 1 + text_color: 0xFFFFFF style_definitions: - id: header_footer bg_color: 0x2F8CD8 @@ -533,7 +543,7 @@ For the navigation bar we can use a button matrix. Note how the *header_footer* rows: - buttons: - id: top_prev - symbol: left + symbol: left # symbol only works when text_font is one of the internal fonts on_press: then: lvgl.page.previous: @@ -682,6 +692,139 @@ To display a boot image which disappears automatically after a few moments or on on_press: - lvgl.widget.hide: boot_screen +.. _lvgl-cook-icontext: + +MDI icons in text +----------------- + +ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. + +One example is when you'd like some MDI icons to be used in line with the text (similarly how LVGL's internal fonts and symbols coexist). You can use a font of your choice, choose the symbols you want and mix them in a single sized set with icons from MDI. + +.. figure:: images/lvgl_cook_font_roboto_mdi.png + :align: center + +In the example below we use the default set of glyphs from RobotoCondensed-Regular, and append some extra symbols to it from MDI. Then we display these inline with the text by escaping their codepoints: + +.. code-block:: yaml + + font: + - file: "fonts/RobotoCondensed-Regular.ttf" + id: roboto_icons_42 + size: 42 + bpp: 4 + extras: + - file: "fonts/materialdesignicons-webfont.ttf" + glyphs: [ + "\U000F02D1", # mdi-heart + "\U000F05D4", # mdi-airplane-landing + ] + + lvgl: + ... + pages: + - id: main_page + widgets: + - label: + text: "Just\U000f05d4here. Already\U000F02D1this." + align: CENTER + text_align: center + text_font: roboto_icons_42 + + +.. note:: + + Follow these steps to choose your MDI icons: + + - To lookup your icons, use the `Pictogrammers `_ site. Click on the desired icon, and note down / copy the codepoint of it (it's the hexadecimal number near the download options). + - To get the TrueType font with all the icons in it, head on to the `Pictogrammers GitHub repository `_ and from a recent version folder, download the ``materialdesignicons-webfont.ttf`` file and place it in your ESPHome config directory under a folder named ``fonts`` (to match the example above). + - To use the desired icon, prepend the copied codepoint with ``\U000``. The unicode character escape sequence has to start with capital ``\U`` and have exactly 8 hexadecimal digits. + - To translate the escape sequence into the real glyph, make sure you enclose your strings in double quotes. + + +.. _lvgl-cook-iconbatt: + +Battery status icon +------------------- + +.. figure:: images/lvgl_cook_font_batt.png + :align: left + +Another example for using MDI icons is to display battery percentage in 10 steps. We need to have a font containing the glyphs corresponding to the different battery percentage levels, and we need a sensor to import the battery status from Home Assistant into a numeric value. We use a :ref:`lambda ` to return the codepoint of the corresponding glyph based on the sensor value: + +.. code-block:: yaml + + font: + - file: "fonts/materialdesignicons-webfont.ttf" + id: battery_icons_20 + size: 20 + bpp: 4 + glyphs: [ + "\U000F007A", # mdi-battery-10 + "\U000F007B", # mdi-battery-20 + "\U000F007C", # mdi-battery-30 + "\U000F007D", # mdi-battery-40 + "\U000F007E", # mdi-battery-50 + "\U000F007F", # mdi-battery-60 + "\U000F0080", # mdi-battery-70 + "\U000F0081", # mdi-battery-80 + "\U000F0082", # mdi-battery-90 + "\U000F0079", # mdi-battery (full) + "\U000F008E", # mdi-battery-outline + "\U000F0091", # mdi-battery-unknown + ] + + sensor: + - platform: homeassistant + id: sns_battery_percentage + entity_id: sensor.device_battery + on_value: + - lvgl.label.update: + id: lbl_battery_status + text: !lambda |- + static char buf[10]; + std::string icon; + if (x == 100.0) { + icon = "\U000F0079"; // mdi-battery (full) + } else if (x > 90) { + icon = "\U000F0082"; // mdi-battery-90 + } else if (x > 80) { + icon = "\U000F0081"; // mdi-battery-80 + } else if (x > 70) { + icon = "\U000F0080"; // mdi-battery-70 + } else if (x > 60) { + icon = "\U000F007F"; // mdi-battery-60 + } else if (x > 50) { + icon = "\U000F007E"; // mdi-battery-50 + } else if (x > 40) { + icon = "\U000F007D"; // mdi-battery-40 + } else if (x > 30) { + icon = "\U000F007C"; // mdi-battery-30 + } else if (x > 20) { + icon = "\U000F007B"; // mdi-battery-20 + } else if (x > 10) { + icon = "\U000F007A"; // mdi-battery-10 + } else if (x > 0) { + icon = "\U000F008E"; // mdi-battery-outline + } else { + icon = "\U000F0091"; // mdi-battery-unknown + } + snprintf(buf, sizeof(buf), "%s", icon.c_str()); + return buf; + + lvgl: + ... + pages: + - id: battery_page + widgets: + - label: + id: lbl_battery_status + align: TOP_RIGHT + y: 40 + x: -10 + text_font: roboto_icons_20 + text: "\U000F0091" # mdi-battery-unknown + .. _lvgl-cook-clock: An analog clock From b41a421c5f945b3d75e1455f4823da41a06af865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 2 Feb 2024 19:48:05 +0100 Subject: [PATCH 196/350] Update lvgl.rst --- cookbook/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index d43f65a16..a6702d404 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -822,8 +822,8 @@ Another example for using MDI icons is to display battery percentage in 10 steps align: TOP_RIGHT y: 40 x: -10 - text_font: roboto_icons_20 - text: "\U000F0091" # mdi-battery-unknown + text_font: battery_icons_20 + text: "\U000F0091" # start with mdi-battery-unknown .. _lvgl-cook-clock: From 66fd7b43c0e69d7ab337bef9eaa617d43b403137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 2 Feb 2024 19:50:44 +0100 Subject: [PATCH 197/350] Update lvgl_cook_font_roboto_mdi.png --- cookbook/images/lvgl_cook_font_roboto_mdi.png | Bin 2355 -> 2278 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cookbook/images/lvgl_cook_font_roboto_mdi.png b/cookbook/images/lvgl_cook_font_roboto_mdi.png index 387bda98d9ccfbf5d35f57aeb679559a2cff0d87..2ca6aa1c9009567beea7ce927ed445106b06fd0e 100644 GIT binary patch delta 2200 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 XL7x=Ozar!Q{0!i9+SQI~b2;_D8}e#P From 76f3db1779ceb69c792adcf11c78ab49280dbd8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 2 Feb 2024 22:24:21 +0100 Subject: [PATCH 198/350] button icon --- cookbook/images/lvgl_cook_font_binstat.png | Bin 0 -> 2715 bytes cookbook/lvgl.rst | 74 ++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 cookbook/images/lvgl_cook_font_binstat.png diff --git a/cookbook/images/lvgl_cook_font_binstat.png b/cookbook/images/lvgl_cook_font_binstat.png new file mode 100644 index 0000000000000000000000000000000000000000..4315ba8cceafce83febc3b99d15b3ed9ef839e9f GIT binary patch literal 2715 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 Date: Fri, 2 Feb 2024 22:25:14 +0100 Subject: [PATCH 199/350] Update lvgl.rst --- components/lvgl.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 3e0db8097..476cb8bca 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -345,8 +345,7 @@ In addition to the above, the following special fonts are available from LVGL as In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters for any language from any TrueType font. -Check out :ref:`lvgl-cook-icontext` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples how to play with texts and icons using various TrueType/OpenType fonts. - +Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples how to play with texts and icons using various TrueType/OpenType fonts. .. _lvgl-widgets: From c93ae4d2103f87e32c11bcd0efaa6c0608dd5fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 11:53:55 +0100 Subject: [PATCH 200/350] Update lvgl_symbols.png --- components/images/lvgl_symbols.png | Bin 55848 -> 30832 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_symbols.png b/components/images/lvgl_symbols.png index a18daf371fd8d7411c2ed201bbf3e090b0dbdafa..65320bd91def4102df25a482e862636bd2c77856 100644 GIT binary patch literal 30832 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 literal 55848 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 E09la3x&QzG From 4581a73505ef152eedec80889826a0332969aae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 11:54:08 +0100 Subject: [PATCH 201/350] Update lvgl.rst --- components/lvgl.rst | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 476cb8bca..45ba0d710 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -82,7 +82,7 @@ Configuration variables: - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. -- **default_font** (*Optional*, enum): The C array name of the internal :ref:`font ` used by default to render the text or symbol. Defaults to ``montserrat_14`` if not specified. +- **default_font** (*Optional*, enum): The C array name of the :ref:`font ` used by default to render the text or symbols. Defaults to ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. @@ -301,7 +301,7 @@ In ESPHome LVGL offers two font choices: the internal fonts offered by the libra **Internal fonts** -The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: +The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and 60 symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: - ``montserrat_8``: 8px font - ``montserrat_10``: 10px font @@ -325,14 +325,16 @@ The library offers by default the ASCII characters (``0x20-0x7F``) the degree s - ``montserrat_46``: 46px font - ``montserrat_48``: 48px font -You can display the embedded symbols among the text by their codepoint address (the hexadecimal value in grey below, preceeded by ``\u``, eg. ``\uF00C``) or more easily on supported widgets using the ``symbol`` configuration option with the following constants (see :ref:`lvgl-wgt-lbl` example): +You can display the embedded symbols among the text by their codepoint address preceeded by ``\u``, eg. ``\uF00C``: .. figure:: /components/images/lvgl_symbols.png :align: center .. note:: - The ``text_font`` parameter affects the size of ``symbol``, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. If you set ``text_font`` on a widget to a custom ESPHome font, these symbols will likely not display correctly. + The ``text_font`` parameter affects the size of symbols, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. If you set ``text_font`` on a widget to a custom ESPHome font, these symbols will likely not display, unles you include them manually from a FontAwesome OpenType file. + + For escape sequences to work, you have to put them in strings enclosed in double quotes. In addition to the above, the following special fonts are available from LVGL as built-in: @@ -343,7 +345,7 @@ In addition to the above, the following special fonts are available from LVGL as **ESPHome fonts** -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters for any language from any TrueType font. +In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters of your choice, for any language, from any TrueType/OpenType font. Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples how to play with texts and icons using various TrueType/OpenType fonts. @@ -637,7 +639,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **rows** (**Required**, list): A list for the button rows: - **buttons** (**Required**, list): A list of buttons in a row: - **id** (*Optional*): An ID for a button - - **text** or **symbol** (*Optional*): Text or built-in :ref:`symbol ` to display on the button. + - **text** (*Optional*): Text or built-in :ref:`symbol ` to display on the button. - **key_code** (*Optional*, string): One character be sent as the key code to a :ref:`key_collector` instead of ``text`` when the button is pressed. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1`` (eg. in a line with two buttons: one ``width: 1`` and another one ``width: 2``, the first will be ``33%`` wide while the second will be ``66%`` wide). - **selected** (*Optional*, boolean): Set the button as the most recently released or focused. Defaults to ``false``. @@ -676,11 +678,11 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row rows: - buttons: - id: button_1 - symbol: PLAY + text: "\uF04B" control: checkable: true - id: button_2 - symbol: PAUSE + text: "\uF04C" control: checkable: true - buttons: @@ -777,7 +779,7 @@ The Dropdown widget is built internall from a *button* and a *list* (both not re - **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Refers to the currently pressed, checked or pressed+checked option. Uses the typical background properties. - **scrollbar** (*Optional*, list): Settings for the scrollbar **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar background, border, shadow properties and width (for its own width) and right padding for the spacing on the right. - **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and is the parent of ``symbol``. -- **symbol** (*Optional*, enum): A symbol (typically an chevron) is shown in dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. Choose a different :ref:`symbol ` from the built-in ones. +- **symbol** (*Optional*, enum): A symbol (typically an chevron) is shown in dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. Choose a different :ref:`symbol ` from the built-in ones or from your own customized font. - Style options from :ref:`lvgl-styling` for the background of the button and the list. Uses the typical background properties and :ref:`lvgl-wgt-lbl` text properties for the text on it. ``max_height`` can be used to limit the height of the list. **Specific actions:** @@ -861,7 +863,7 @@ A label is the basic widget type that is used to display text. **Specific options:** -- **text** or **symbol** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. +- **text** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` - **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) @@ -901,7 +903,7 @@ Newline escape sequences are handled automatically by the label widget. You can align: TOP_MID id: lbl_symbol text_font: montserrat_28 - symbol: SETTINGS #same result as text: "\uF013" + text: "\uF013" # Example action (update label with a value from a sensor): on_...: @@ -1105,7 +1107,7 @@ The text will be broken into multiple lines automatically and the height will be - **text** (**Required**, string): The string to be displayed in the body of the message box. Can be shorthanded if no further options are specified. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. - **buttons** (**Required**, enum): A list of buttons to show at the bottom of the message box: - - **text** or **symbol** (**Required**, string): The text or built-in :ref:`symbol ` to display on the button. + - **text** (**Required**, string): The text or built-in :ref:`symbol ` to display on the button. **Specific actions:** @@ -1129,7 +1131,7 @@ The configured message boxes are hidden by default. One can show them with ``lvg - id: msgbox_apply text: "Apply" - id: msgbox_close - symbol: close + text: "\uF00D" on_click: then: - lvgl.widget.hide: message_box From adb185b9f3f884a1959167f5d45d5c052e09a8fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 12:38:06 +0100 Subject: [PATCH 202/350] Update logo_lvgl.png --- images/logo_lvgl.png | Bin 5445 -> 3401 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/logo_lvgl.png b/images/logo_lvgl.png index 5cdda0ad07fa0af944151c2848fcf7fa638ebf8b..a48dd7c4f8f569bb154d6365c0bd6d792e578b6d 100644 GIT binary patch literal 3401 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 From d8e33ce7789dc88371134225915c8f78c4937db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 14:03:52 +0100 Subject: [PATCH 203/350] LVGL logos --- images/{logo_lvgl.png => lvgl.png} | Bin images/lvgl_c_bns.png | Bin 0 -> 1688 bytes images/lvgl_c_lig.png | Bin 0 -> 1658 bytes images/lvgl_c_num.png | Bin 0 -> 998 bytes images/lvgl_c_sel.png | Bin 0 -> 1858 bytes images/lvgl_c_swi.png | Bin 0 -> 1437 bytes index.rst | 14 +++++++------- 7 files changed, 7 insertions(+), 7 deletions(-) rename images/{logo_lvgl.png => lvgl.png} (100%) create mode 100644 images/lvgl_c_bns.png create mode 100644 images/lvgl_c_lig.png create mode 100644 images/lvgl_c_num.png create mode 100644 images/lvgl_c_sel.png create mode 100644 images/lvgl_c_swi.png diff --git a/images/logo_lvgl.png b/images/lvgl.png similarity index 100% rename from images/logo_lvgl.png rename to images/lvgl.png diff --git a/images/lvgl_c_bns.png b/images/lvgl_c_bns.png new file mode 100644 index 0000000000000000000000000000000000000000..bcfb3e2065b50dcf4c80065ac8aab49f6fa15c9a GIT binary patch literal 1688 zcma)7dpy$%8~@dNvK>v1lgr$5={@Q=b7@xYCd$IdggHnYw7f3M?8AtaTsm&aHHyM! z%O!~{6Dm#bh%vL~o+V>W&aCOEa8`exKh7V|^L@V0=kq*&JfH9LJlDL@CzTYn6afHG zLb_cYvKOyJ?9$;fZoV`X=4_V+QG_;|~S>na)<2 z%}|Lv@C=Q8dKrwRduKY8l5#l5U(p3YD`UCN%7XAG%grQd*ApJbQ<;UK>nTo=>DJ(A zB%XAwu|02xWc0Rdp8e{C(@B)Sv}PHy zJ_B8Q5n!g%X#YslwaRQKc~M|bY~yvicbt%pc*}0I2s1R>ETjjsx~#KUDT|j#KjtAS z^3)OZ)?4qI02;}}H2hp~OImboz`%>2Dg*1*BgYa`O&2{qnv1+rk3YA8alKCCi(w1G zdyI;-N`lH7>nLn*)i@4|qcKvW4pQ;-37hl#Z0>hoyO19qR>6wc#*V2O=SL~W=jDnq zU3?_}v~2#TSN+YdXyZ zx@`av|7I)tP-)O4^5`TXeG1{_c`wVAs?=kpS*H|3P%NRdqE-}{K=DuS?rf%lQP_P zGIxroT+843FQEE~aChyBqX_!?dv82$X!O02Z_uQDAIkv|vWx7W9)+o_N5INrKi&6_ z_T8=;u1O*x#YLqW?Mb7I(?DwJ#B*4n(B(VATLlWNBi6G$HD!a zUp#6CIoL)R`kh&&wkzIAW4*mC#T8>i;5;5oG>s_^Uw%AF%}A&lMTr^Q@pg$8;F0*X z2a%BM_)rY}|7pBa;aeIB0K%;U0^@W!?DrB%B}=woe$~h11Fl9S*@*DO8RBtP8$VMO z=t-bV2cjr~%E3mjWlL>*^v=8x{WMFHWO$Khypm3a@`~2l~G% z`wxfzy3WXf9%H#?%;@o4%vV7LcsztSQv&{`y$p3`?5Xdbr_DplAKYrn1IoS%aHNlPxFK($-8(^GomSWF{1YTX&`&CIBQY7^f=#M6P$&{p=j_k;G+ zdZD#K$=zEaODkvHzyr2pzu1jPH|&9soF&ji+5PD*!}hHnqkN9VGvv=YJ&RL{z-rU0 z_#o?)la(^jSm@Lv%aYDD0a*X-7tmv&@Qn&Hx0>Hz>52Ex3QOs^=%?Mkhs=w>2CJ*= zLC*8HT4z~EYj;hyr70J#*>cltTn~@q1V%T`gO?iL#l8sHwXF8 zw3d;ixP7-K^w1T99nQz$Y1_gDAHFP)B)Nj>w0v?bwg`1kcYP2(RY9x4r=3 zgCWKU;}Bznai|~Py6d`m+gO_ZVubfag|JBVmn0d!`RQQf`?apGT0)KH+)R6U!n>n> zs;QxGDSkFDGVJwAcU^bYlFqc~A^?CnH#*Z-E!}lp|K^@C^R_{a$yxHl&kB)}oF%An z-ZuR^d&XD-Nf+S&b8d!%TA3>e;}BznafmU(IK&uX9AbjSYGb-h*Nam7x_@O|7*vRWMj7;Il0POzZhTYus_{+j>joO~)Iry0 zOacii)S!(rT4}4S25rDZ>rHgV3|(3KbwyR>s|K3K_ObM3MHK-ZjAIbcqIJq$rk5p@ zR#}TSgDg&O;xdMH;ZUi3RZ>|}xuR7`<g9m4;13 zgPVwq={8;C8;+Ke%7TiA_MxES^`AgM1r-GqIp#O%O^!Jsao9jKBjQ+$VO=;{3My9Z zYS}J-l`DUwprWMmI=!ByvmA3$+s}zXnkbCvbt!#WP;uYfkBXL`LO>7gL+Q&~eM|Ua zUhvX{Z_I%%i|>oIUmxqk`2*({^WAekfY7B0e3gKQx;50?868&_X6@ID?~8(p%2zei z1k^t}4wAq#hG#}=zvj;9=(;d#zrJtoQDdT#1QM-u0>Q>i$i{S=jy&-!deyG}eeCiZ zcrn=VQoW+plufT_#p{~n!<;mQX$$}m5HB&7 zR8HA$No4~~I?N)wJ|p^W_^E)9?EXFJ=NX26mMI z!wufCUBKxG(-_$8wv4m&lM<#eTr#4Seya=6N+TebI|W97#&8|lwr~XA;GQ9DYgS-T zQW*>Z8Uwp3MoyaPTko3=a+ge)#&8v*25r$!-?~N16>;GO3>J@sK#)|#D(=U zoK4yE3};qZt#puG5`=0DaK{A3qIKwU%%^EI$K0W_XbptfB|*T(aLi;XbLei;n+fh8 z0^X!I4qc|QPy+@6HU|2bQ8vf?I=w!1bJyv0j=5DK2MmO549ARB)}iB)`qQP`Hl40L8znC9g znoMQ$i}|oW3OHaO;0m{%z59nSznCB8G!TZPE63a^$CK)?b%7X+fqiKZ5jFnfi9-N@ zfc=R>R@q2&fk=#jfi$QvQHfC|$9(LmWW;~ZRU?R~4;xPtx(rh=c;C4j($CDF> zAmH}oMBJU6$d7kJAG-{R$QWR0HrowyyjaL{@7JHs%4!yF7?@{! zx;TbZ%z1lvWA>dinf8zIUCdREY?&MpOB*F79aNKz`fx#-JMzuO$Smi!(-o`#x8}v= zuW5I%S-N<$$egpXOlL1V;FHsv5Ws5Wk#JDELs4?lt$oECzLu8OrT(gMTUcG$-hO%Y z<}bfy)&59uNRDrv$FNSKt1<1_mxcSjH?KPL>hye`U8?;#66&+h&9$k>O_Ke*M58KH zRyELScHFx!7c7rD22TH)Cv(@oKUre8*4Mr7LraaOPvAbIGuL2pyaL=ZxYd>6!d9unx>(Arq-(JVB^=Es2Lp%5H%=o>x&t*)E z6gz!7Yv+uw_y6Yqe${?q*7D!mYHm+j(Yi2eb6{%aQ}KL`iy7gnMV#m4Z_UrYEwjPw zcC~uUo0cRu)}1AXfA z7uLz|%d9+bq9wj=Yw4L|wu?B=oW1eAIG0airte4dc;nkUo|o07`3j%;G`H-ZOG4Vj zn>A~mCJF!l{bc_2$};2ZbSsPC$?C~|(LOpSf{lK@{`0#2@Pl_&J#Ry=*KGXhDb{{6 zmFXzU=HCZ&)qMTqd~&`!{)p*GI&>?pv{|({-LB|STF!(;qJ&f1CHnnRz0v>sKvS@k(F5ppL+-Cd**%t>n)0KJOp*y?>m~=lOo0=bZC=&-s4N$#rqIm6kjq2>^gJ z%I=bzfN28r5*HGnS^L0O0g1-BIlBw^065q;o81yz@KKj6J?@lqE1YgA+RCM0w-?e^ zWx$O5v*lkxkQ(baX^;aRfwd2s%_~IKXox{2+pJ()nrg*`Bz&Qgq-SI_D$J1SZT#B% zqTC=8H|h{nmnU1-Oh4m`%uMJ3w-#h3dEeDMc>ViyAs_Y4Jh>pmv)-^eDlKGh^^nII z1Y~!sbOr=zIJ9bIlpd$1go)`tIAukWnv0?xmC6t=vYh_O33JWw&a*v_1m7|BoVOaM z69)Q~l{3H*NPVpSMxfUcMQQ@~;U44&;}K0GCK~{#$j3C&y?_Ve0Z>mYO2OozyhR^B zNsn#)hxUlZV|ZLAiITT)Xu1hvT41^~E$c&rt1BUB5E)gpxL5%!OV|$D3nGEp=@mFY z{D@+&fzw#{N`}N6`9MN~fA?y(FH|k-ho!|G>hJy2%5mso6U~t=dz=^4Y0NP&HorHS za6X5slAj3?IMz3R6`R{BZ6WNWYP+Gsy-M(xeH88`-w$zBcwOR zdhHQr&-Y=$O`o+#0NudRRsUDK7=h-!qBAtvZd;Y|pK^T_T!S-R)CB$d&9Wzlyl<}? z&)_!Fg-y^ez`Z{|9=^9`P0!gFlRY7 z()NSQ%U@yHeZ5SMnzgG{3UTRvP(U-2UKA1xzmE>M%cRh5Jvn}$uB`Zg^JBp22V6mc zU=Uxx;p7!ZLFbjfboIHN-`7B=B|5m0z0)`oF(M!VT>NE-vz*!0Gsn@X*U9~yi%^9q zOI_}M(k_YX>Y>igJ`d&g`bTa4V0sMZu~h0*O$o>L zW73Un))M=Pe_4QHYv&Teu9#NWT^5>fY;kqVz6QP@Y7(y8vU zWLQnxTw7Spg&Nxoo9Z~7Ru+pm<+7Z3nr9{qZ0RlL|8{qL^RP*bPwKH>}cm{Ij4jV=7g9 ze11QEkw(m)JJ~AfUQND1ru0^}ZLy62@1|HD)z0V!+QPwH`yk}nnBcFb8198f&fiaSQTxQNye?s$_sjcBW96E#m$ zP<$Z0BMs1}Dw?yivokU>)*bh>qR-6PZ`*8Zg(0jju)L|Hubul}Y=nVOln5a8O9!|z z)x}}0wBejDcEhSe=zmK7yQB)%GIO%@+@iN_zKKt zE!+j&`*WBqYCm&T2pEVhHz=B({a0jvigh(s(Mw#&%`VG>42JQ_T>19eM^GDVzGtMqvs1DNRfpYj zKCzsFC?YB}!RAqnSBIzI2B#+a+;5lgL4G;G1U}lVEGJQ=An4YcI`FpNmB#~_4 zwCl-Np535zaf<=APa5wC;rG1kDAns3% z-UZ%2h|cx2N|vjQtWBA?3Yj=xEin>kuHRByR;Zou^1GQ&_hGkvh%xx*A<)yh+;un! ziuk?~AEcYvPAsLB@|$y?Ncha;$Ttmai_2;w4Y9jZj4%x~iC|eJKyt%6)%BdHa76)) z&Hx=rV_TVh*EpLptbcH?c|oz=SqGfVb5S6f*5q;@^5Y-aUB;NR*LHr3IhDkYmj_gh zPi@zP5*L07A_;He*#t!kDAQ)&3z-I$Yl~ZnpBakO1aL)}^- z5#rdm>r82#QP1)msk+6n5wuF1&FjAXzWZV3_vX#ax0xTo&gP1g_(^d90HlysaC-rp z1>qznB*^daCEWsu;_Yo51mpw!uNSAd03c$Igqz=p$X%a?_{rW@?%@{bNar7x>6NnB ze5I%-*Kb!gk%})nWz}xZ8T~lYfC;Vjo@xry*B-G!9aa~MKgw))m3UOz#K(&JD7?W; zXb2=4oy2jIrEN}7bVL zN)5az3HiY*;fR}B4?D3Y`_>#*+Vfb_-fOY0k#4 zh#Me{v}1j1eoFy9U|QC!8Blt_o7_NUaH+|1dBw={9oq*^2evDHt{BJAVc3KoDm7T$ zSAh%CnMBr~L{>}JCts$?a%H8cfU-kSkSoqGCG5~F&F!~HmRx(>SCu$n| zwv-KnnEKw+4WY`{znZmjNc=C{lw=IVoL$j&-W6H6+>>?9XD%yU+m^F=dw5Afst>)o z4>uYyNhH_L@yE&aMGj&Wlue$SdBQEhQeZvd&Ha{Sc6Rdtk-Rf!35*9NOyeHkg6zax z?otR%%P*uY=l(mPhr;Z~|#fo<5&cf3&6)PP>BZU(Faj*>9R8K`T@ z)wb>@?nS`yM|GA~5bCfpXI*gVUZP)NKrO!Hsmcv4lDu~k9JC;Kn18CvyHIz+Jh#zL z?%fsP2WqwG?olM9GfnRFlwdI;aT!sE+)_b8#V5>}@h%YJYUBK1T##H%0#T$EeN`V0 zT32DES%leDd!qVxT#A)gh@^kJMB{ZZk@{K@P5ot}ydO15Qjf+&wwk=HH~}me7eDlf zE&d!`(?yVILu*Q0CI4ijPxFi?XVVxskzoxtmk)TPP!IYb)kEWW+K!Jx5y3QPm~_4w zpxXn@P62!Jpu(EMUabBxb~nHJ82eOC2OZWChl9i-{>)1LMsqu)+M33L@|I}?4+`x< zb#!8nb= zr?KSxx=PLKrexdz49}_)nu>@WY$nqfjogEX#KY;qt548v43Lk()3?_~{ZBnhY58c^ z?ZjZbBn`UDI7@2JQ?Sx`HDHk$>g?HCQt#(?1cycNi_}cnjGO&OT=EPMB~1E#QjaBs zoMP;r*V%ideBMcLqZ0S+Q$tQO#f<(tyqUt{UImlekyMty4Cgd8|a#(kI75YE69 sBK=)ffd@v`dG@Kt`4$_Q-;J`T6zHnxHRB*FC-5wQw6uX&T6o6)4HW3U#{d8T literal 0 HcmV?d00001 diff --git a/index.rst b/index.rst index 14eab0e0e..8c2d88721 100644 --- a/index.rst +++ b/index.rst @@ -496,7 +496,7 @@ Touchscreen *********** .. imgtable:: - LVGL Widget, components/binary_sensor/lvgl, logo_lvgl.png + LVGL widget, components/binary_sensor/lvgl, lvgl_c_bns.png Nextion, components/binary_sensor/nextion, nextion.jpg Touchscreen, components/touchscreen/index, touch.svg, dark-invert TT21100, components/touchscreen/tt21100, esp32-s3-korvo-2-lcd.png @@ -594,7 +594,7 @@ Light Components H-bridge Light, components/light/hbridge, brightness-medium.svg, dark-invert Sonoff D1 Dimmer, components/light/sonoff_d1, sonoff_d1.jpg - LVGL Widget, components/light/lvgl, logo_lvgl.png + LVGL widget, components/light/lvgl, lvgl_c_lig.png Looking for WS2811 and similar individually addressable lights? Have a look at the :doc:`FastLED Light `. @@ -618,7 +618,7 @@ Switch Components Modbus Switch, components/switch/modbus_controller, modbus.png BLE Client Switch, components/switch/ble_client, bluetooth.svg, dark-invert Nextion Switch, components/switch/nextion, nextion.jpg - LVGL Widget, components/switch/lvgl, logo_lvgl.png + LVGL Widget, components/switch/lvgl, lvgl_c_swi.png Button Components ----------------- @@ -653,6 +653,7 @@ Display Components .. imgtable:: Display Core, components/display/index, folder-open.svg, dark-invert + LVGL Graphics, components/lvgl, lvgl.png Addressable Light, components/display/addressable_light, addressable_light.jpg ILI9xxx, components/display/ili9xxx, ili9341.jpg ILI9341, components/display/ili9xxx, ili9341.svg @@ -661,10 +662,8 @@ Display Components ILI9486, components/display/ili9xxx, ili9341.jpg ILI9488, components/display/ili9xxx, ili9488.svg WSPICOLCD, components/display/ili9xxx, ili9488.svg - Inkplate, components/display/inkplate6, inkplate6.jpg LCD Display, components/display/lcd_display, lcd.jpg - LVGL Graphics, components/lvgl, logo_lvgl.png MAX7219, components/display/max7219, max7219.jpg MAX7219 Dot Matrix, components/display/max7219digit, max7219digit.jpg Nextion, components/display/nextion, nextion.jpg @@ -759,7 +758,7 @@ Number Components .. imgtable:: Number Core, components/number/index, folder-open.svg, dark-invert - LVGL Widget Number, components/number/lvgl, logo_lvgl.png + LVGL widget Number, components/number/lvgl, lvgl_c_num.png Modbus Number, components/number/modbus_controller, modbus.png Template Number, components/number/template, description.svg, dark-invert Tuya Number, components/number/tuya, tuya.png @@ -771,6 +770,7 @@ Select Components Select Core, components/select/index, folder-open.svg, dark-invert Template Select, components/select/template, description.svg, dark-invert + LVGL widget Select, components/select/lvgl, lvgl_c_sel.png Modbus Select, components/select/modbus_controller, modbus.png Tuya Select, components/select/tuya, tuya.png @@ -942,7 +942,7 @@ Cookbook Arduino Port Extender, cookbook/arduino_port_extender, arduino_logo.svg EHMTX a matrix status/text display, cookbook/ehmtx, ehmtx.jpg Share data directly between ESPHome nodes, cookbook/http_request_sensor, connection.svg, dark-invert - LVGL Graphics: Tips and Tricks, cookbook/lvgl, logo_lvgl.png + LVGL Graphics: Tips and Tricks, cookbook/lvgl, lvgl.png Do you have other awesome automations or cool setups? Please feel free to add them to the documentation for others to copy. See :doc:`Contributing `. From 6423429eaccc2da12a95a5122e34de90f079b9a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 14:10:23 +0100 Subject: [PATCH 204/350] seo --- components/lvgl.rst | 2 +- cookbook/lvgl.rst | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 45ba0d710..6aa4a3dbc 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -5,7 +5,7 @@ LVGL .. seo:: :description: LVGL - ESPHome Displays showing contents created with Light and Versatile Graphics Library - :image: /images/logo_lvgl.png + :image: /images/lvgl.png `LVGL `__ (Light and Versatile Graphics Library) is a free and open-source diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index d9c90b67d..94a0f7ca2 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -5,7 +5,6 @@ LVGL: Tips and Tricks .. seo:: :description: Recipes for common use cases of LVGL Displays with ESPHome - :image: /images/logo_lvgl.png Here are a couple recipes for various interesting things you can do with :ref:`lvgl-main` in ESPHome. From 22c4311aad09d1a6b84460a1f1ce66a56ac7d1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 14:13:12 +0100 Subject: [PATCH 205/350] seo --- components/binary_sensor/lvgl.rst | 2 +- components/light/lvgl.rst | 2 +- components/number/lvgl.rst | 2 +- components/select/lvgl.rst | 2 +- components/switch/lvgl.rst | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 844cc55cd..97e844617 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -5,7 +5,7 @@ LVGL Binary Sensor .. seo:: :description: Instructions for setting up a LVGL widget binary sensor. - :image: ../images/logo_lvgl.png + :image: ../images/lvgl_c_bns.png The ``lvgl`` binary sensor platform creates a binary sensor from a LVGL widget and requires :ref:`LVGL ` to be configured. diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 7c2636337..42a9287fe 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -5,7 +5,7 @@ LVGL Light .. seo:: :description: Instructions for setting up a LVGL widget light. - :image: ../images/logo_lvgl.png + :image: ../images/lvgl_c_lig.png The ``lvgl`` light platform creates a light from a LVGL widget and requires :ref:`LVGL ` to be configured. diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 45d81acf7..a7f9c0531 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -5,7 +5,7 @@ LVGL Number .. seo:: :description: Instructions for setting up a LVGL widget number component. - :image: ../images/logo_lvgl.png + :image: ../images/lvgl_c_num.png The ``lvgl`` number platform creates a number component from a LVGL widget and requires :ref:`LVGL ` to be configured. diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 44c41b458..e677557e4 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -5,7 +5,7 @@ LVGL Select .. seo:: :description: Instructions for setting up a LVGL widget select. - :image: ../images/logo_lvgl.png + :image: ../images/lvgl_c_sel.png The ``lvgl`` switch platform creates a select from a LVGL widget and requires :ref:`LVGL ` to be configured. diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index b12724ca0..2041d368a 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -5,7 +5,7 @@ LVGL Switch .. seo:: :description: Instructions for setting up a LVGL widget switch. - :image: ../images/logo_lvgl.png + :image: ../images/lvgl_c_swi.png The ``lvgl`` switch platform creates a switch from a LVGL widget and requires :ref:`LVGL ` to be configured. From 951dd6f1ba871f87c69768cf934df10462de02ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 14:13:59 +0100 Subject: [PATCH 206/350] Update lvgl.rst --- cookbook/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 94a0f7ca2..05cba64d8 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -5,6 +5,7 @@ LVGL: Tips and Tricks .. seo:: :description: Recipes for common use cases of LVGL Displays with ESPHome + :image: /images/lvgl.png Here are a couple recipes for various interesting things you can do with :ref:`lvgl-main` in ESPHome. From 3d724e8dd38ea5140fff781602644b2e61f9e021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 14:45:53 +0100 Subject: [PATCH 207/350] fonts a separate componnent --- components/display/fonts.rst | 145 +++++++++++++++++++++++++++++++++++ cookbook/lvgl.rst | 2 +- images/format-font.svg | 1 + index.rst | 1 + 4 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 components/display/fonts.rst create mode 100644 images/format-font.svg diff --git a/components/display/fonts.rst b/components/display/fonts.rst new file mode 100644 index 000000000..53c292573 --- /dev/null +++ b/components/display/fonts.rst @@ -0,0 +1,145 @@ +.. _display-fonts: + +Font Renderer Component +======================= + +.. seo:: + :description: Instructions for setting up fonts in ESPHome. + :image: format-font.svg + +ESPHome's graphical rendering engine also has a powerful font drawer which integrates seamlessly into the system. You have the option to use **any** OpenType/TrueType (``.ttf``, ``.otf``, ``.woff``) font file at **any** size, as well as fixed-size `PCF `_ and `BDF `_ bitmap fonts. + +These fonts can be used in ESPHome's :ref:`own rendering engine ` or in :ref:`LVGL `. + +To use fonts you first have to define a font object in your ESPHome configuration file. Just grab a ``.ttf``, ``.otf``, ``.woff``, ``.pcf``, or ``.bdf`` file from somewhere on the internet and place it, for example, inside a ``fonts`` folder next to your configuration file. + +Next, create a ``font:`` section in your configuration: + +.. code-block:: yaml + + # Various ways to configure fonts + font: + - file: "fonts/Comic Sans MS.ttf" + id: my_font + size: 20 + bpp: 2 + + - file: "fonts/tom-thumb.bdf" + id: tomthumb + + # gfonts://family[@weight] + - file: "gfonts://Roboto" + id: roboto_20 + size: 20 + + - file: + type: gfonts + family: Roboto + weight: 900 + id: roboto_16 + size: 16 + + - file: "gfonts://Material+Symbols+Outlined" + id: icons_50 + size: 50 + glyphs: ["\U0000e425"] # mdi-timer + + - file: "fonts/RobotoCondensed-Regular.ttf" + id: roboto_special_28 + size: 28 + bpp: 4 + glyphs: [ + a,A,á,Á,e,E,é,É, + (,),+,-,_,.,°,•,µ, + "\u0020", #space + "\u0021", #! + "\u0022", #" + "\u0027", #' + ] + + - file: "fonts/RobotoCondensed-Regular.ttf" + id: my_font_with_icons + size: 20 + bpp: 4 + extras: + - file: "fonts/materialdesignicons-webfont.ttf" + glyphs: [ + "\U000F02D1", # mdi-heart + "\U000F05D4", # mdi-airplane-landing + ] + + display: + # ... + +Configuration variables: + +- **file** (**Required**, string): The path (relative to where the .yaml file is) of the font + file. You can also use the ``gfonts://`` short form to use Google Fonts, or use the below structure: + + - **type** (**Required**, string): Can be ``local`` or ``gfonts``. + + **Local Fonts**: + + - **path** (**Required**, string): The path (relative to where the .yaml file is) of the OpenType/TrueType or bitmap font file. + + **Google Fonts**: + + Each Google Font will be downloaded once and cached for future use. This can also be used to download Material + Symbols or Icons as in the example above. + + - **family** (**Required**, string): The name of the Google Font family. + - **italic** (*Optional*, boolean): Whether the font should be italic. + - **weight** (*Optional*, enum): The weight of the font. Can be either the text name or the integer value: + - **thin**: 100 + - **extra-light**: 200 + - **light**: 300 + - **regular**: 400 (**default**) + - **medium**: 500 + - **semi-bold**: 600 + - **bold**: 700 + - **extra-bold**: 800 + - **black**: 900 + +- **id** (**Required**, :ref:`config-id`): The ID with which you will be able to reference the font later + in your display code. +- **size** (*Optional*, int): The size of the font in pt (not pixel!). + If you want to use the same font in different sizes, create two font objects. Note: *size* is ignored + by bitmap fonts. Defaults to ``20``. +- **bpp** (*Optional*, int): The bit depth of the rendered font from OpenType/TrueType, for anti-aliasing. Can be ``1``, ``2``, ``4``, ``8``. Defaults to ``1``. +- **glyphs** (*Optional*, list): A list of characters you plan to use. Only the characters you specify + here will be compiled into the binary. Adjust this if you need some special characters or want to + reduce the size of the binary if you don't plan to use some glyphs. You can also specify glyphs by their codepoint (see below). Defaults to ``!"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz``. +- **extras** (*Optional*, enum): A list of font glyph configurations you'd like to include within this font, from other OpenType/TrueType files (eg. icons from other font, but at the same size as the main font): + + - **file** (**Required**, string): The path of the font file with the extra glyphs. + - **glyphs** (**Required**, list): A list of glyphs you want to include. Can't repeat the same glyph codepoint if it was declared in the level above. + +.. note:: + + OpenType/TrueType font files offer icons at codepoints far from what's reachable on a standard keyboard, for these it's needed + to specify the unicode codepoint of the glyph as a hex address escaped with ``\u`` or ``\U``. + + Code points up to ``0xFFFF`` are encoded like ``\uE6E8``. Lowercase ``\u`` and exactly 4 hexadecimal digits. + Code points above ``0xFFFF`` are encoded like ``\U0001F5E9``. Capital ``\U`` and exactly 8 hexadecimal digits. + + The ``extras`` section only supports OpenType/TrueType files, ``size`` and ``bpp`` will be the same as the above level. This will allow printing icons alongside the characters in the same string, like ``I \uF004 You \uF001``. + + Many font sizes with multiple glyphs at high bit depths will increase the binary size considerably. Make your choices carefully. + + To use fonts you will need to have the python ``pillow`` package installed, as ESPHome uses that package + to translate the OpenType/TrueType and bitmap font files into an internal format. If you're running this as a Home Assistant + add-on or with the official ESPHome docker image, it should already be installed. Otherwise you need + to install it using ``pip install "pillow==10.1.0"``. + +See Also +-------- + +- :apiref:`display/display_buffer.h` +- :ref:`LVGL ` +- :ghedit:`Edit` + +.. toctree:: + :maxdepth: 1 + :glob: + + * diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 05cba64d8..f2b0505cb 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -697,7 +697,7 @@ To display a boot image which disappears automatically after a few moments or on MDI icons in text ----------------- -ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. +ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. One example is when you'd like some MDI icons to be used in line with the text (similarly how LVGL's internal fonts and symbols coexist). You can use a font of your choice, choose the symbols you want and mix them in a single sized set with icons from MDI. diff --git a/images/format-font.svg b/images/format-font.svg new file mode 100644 index 000000000..8ae4d41d2 --- /dev/null +++ b/images/format-font.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/index.rst b/index.rst index 8c2d88721..e1b9c34cd 100644 --- a/index.rst +++ b/index.rst @@ -653,6 +653,7 @@ Display Components .. imgtable:: Display Core, components/display/index, folder-open.svg, dark-invert + Font Renderer, components/display/fonts, format-font.svg, dark-invert LVGL Graphics, components/lvgl, lvgl.png Addressable Light, components/display/addressable_light, addressable_light.jpg ILI9xxx, components/display/ili9xxx, ili9341.jpg From 90c34a64eaa4ca3784883b6bf5ecae534075d066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 14:46:59 +0100 Subject: [PATCH 208/350] Update index.rst --- components/display/index.rst | 128 +---------------------------------- 1 file changed, 1 insertion(+), 127 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 598c66ff0..8b0ca091b 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -157,136 +157,10 @@ Additionally, you have access to two helper methods which will fetch the width a You can view the full API documentation for the rendering engine in the "API Reference" in the See Also section. -.. _display-fonts: - Fonts ***** -The rendering engine also has a powerful font drawer which integrates seamlessly into ESPHome. You have the option to use **any** OpenType/TrueType (``.ttf``, ``.otf``, ``.woff``) font file at **any** size, as well as fixed-size `PCF `_ and `BDF `_ bitmap fonts! - -These fonts can be also used in :ref:`LVGL `. - -To use fonts you first have to define a font object in your ESPHome configuration file. Just grab -a ``.ttf``, ``.otf``, ``.woff``, ``.pcf``, or ``.bdf`` file from somewhere on the internet and place it, for example, -inside a ``fonts`` folder next to your configuration file. - -Next, create a ``font:`` section in your configuration: - -.. code-block:: yaml - - # Various ways to configure fonts - font: - - file: "fonts/Comic Sans MS.ttf" - id: my_font - size: 20 - bpp: 2 - - - file: "fonts/tom-thumb.bdf" - id: tomthumb - - # gfonts://family[@weight] - - file: "gfonts://Roboto" - id: roboto_20 - size: 20 - - - file: - type: gfonts - family: Roboto - weight: 900 - id: roboto_16 - size: 16 - - - file: "gfonts://Material+Symbols+Outlined" - id: icons_50 - size: 50 - glyphs: ["\U0000e425"] # mdi-timer - - - file: "fonts/RobotoCondensed-Regular.ttf" - id: roboto_special_28 - size: 28 - bpp: 4 - glyphs: [ - a,A,á,Á,e,E,é,É, - (,),+,-,_,.,°,•,µ, - "\u0020", #space - "\u0021", #! - "\u0022", #" - "\u0027", #' - ] - - - file: "fonts/RobotoCondensed-Regular.ttf" - id: my_font_with_icons - size: 20 - bpp: 4 - extras: - - file: "fonts/materialdesignicons-webfont.ttf" - glyphs: [ - "\U000F02D1", # mdi-heart - "\U000F05D4", # mdi-airplane-landing - ] - - display: - # ... - -Configuration variables: - -- **file** (**Required**, string): The path (relative to where the .yaml file is) of the font - file. You can also use the ``gfonts://`` short form to use Google Fonts, or use the below structure: - - - **type** (**Required**, string): Can be ``local`` or ``gfonts``. - - **Local Fonts**: - - - **path** (**Required**, string): The path (relative to where the .yaml file is) of the OpenType/TrueType or bitmap font file. - - **Google Fonts**: - - Each Google Font will be downloaded once and cached for future use. This can also be used to download Material - Symbols or Icons as in the example above. - - - **family** (**Required**, string): The name of the Google Font family. - - **italic** (*Optional*, boolean): Whether the font should be italic. - - **weight** (*Optional*, enum): The weight of the font. Can be either the text name or the integer value: - - **thin**: 100 - - **extra-light**: 200 - - **light**: 300 - - **regular**: 400 (**default**) - - **medium**: 500 - - **semi-bold**: 600 - - **bold**: 700 - - **extra-bold**: 800 - - **black**: 900 - -- **id** (**Required**, :ref:`config-id`): The ID with which you will be able to reference the font later - in your display code. -- **size** (*Optional*, int): The size of the font in pt (not pixel!). - If you want to use the same font in different sizes, create two font objects. Note: *size* is ignored - by bitmap fonts. Defaults to ``20``. -- **bpp** (*Optional*, int): The bit depth of the rendered font from OpenType/TrueType, for anti-aliasing. Can be ``1``, ``2``, ``4``, ``8``. Defaults to ``1``. -- **glyphs** (*Optional*, list): A list of characters you plan to use. Only the characters you specify - here will be compiled into the binary. Adjust this if you need some special characters or want to - reduce the size of the binary if you don't plan to use some glyphs. You can also specify glyphs by their codepoint (see below). Defaults to ``!"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz``. -- **extras** (*Optional*, enum): A list of font glyph configurations you'd like to include within this font, from other OpenType/TrueType files (eg. icons from other font, but at the same size as the main font): - - - **file** (**Required**, string): The path of the font file with the extra glyphs. - - **glyphs** (**Required**, list): A list of glyphs you want to include. Can't repeat the same glyph codepoint if it was declared in the level above. - -.. note:: - - OpenType/TrueType font files offer icons at codepoints far from what's reachable on a standard keyboard, for these it's needed - to specify the unicode codepoint of the glyph as a hex address escaped with ``\u`` or ``\U``. - - Code points up to ``0xFFFF`` are encoded like ``\uE6E8``. Lowercase ``\u`` and exactly 4 hexadecimal digits. - Code points above ``0xFFFF`` are encoded like ``\U0001F5E9``. Capital ``\U`` and exactly 8 hexadecimal digits. - - The ``extras`` section only supports OpenType/TrueType files, ``size`` and ``bpp`` will be the same as the above level. This will allow printing icons alongside the characters in the same string, like ``I \uF004 You \uF001``. - - Many font sizes with multiple glyphs at high bit depths will increase the binary size considerably. Make your choices carefully. - - To use fonts you will need to have the python ``pillow`` package installed, as ESPHome uses that package - to translate the OpenType/TrueType and bitmap font files into an internal format. If you're running this as a Home Assistant - add-on or with the official ESPHome docker image, it should already be installed. Otherwise you need - to install it using ``pip install "pillow==10.1.0"``. +To be able to display text, you need to prepare some fonts. ESPHome's :ref:`font renderer ` allows you to use OpenType/TrueType/Bitmap fonts for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. .. _display-static_text: From ea5dd69984c04d707ead235ec131b3e94523514c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 14:49:51 +0100 Subject: [PATCH 209/350] Update fonts.rst --- components/display/fonts.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/components/display/fonts.rst b/components/display/fonts.rst index 53c292573..b4a0f04d4 100644 --- a/components/display/fonts.rst +++ b/components/display/fonts.rst @@ -135,11 +135,7 @@ See Also -------- - :apiref:`display/display_buffer.h` -- :ref:`LVGL ` +- :ref:`display-engine` +- :ref:`lvgl-main` - :ghedit:`Edit` -.. toctree:: - :maxdepth: 1 - :glob: - - * From a8cbea6869714c1f973fe1039b62081df7861612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 14:55:58 +0100 Subject: [PATCH 210/350] Update index.rst --- components/display/index.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 8b0ca091b..24d645212 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -157,16 +157,15 @@ Additionally, you have access to two helper methods which will fetch the width a You can view the full API documentation for the rendering engine in the "API Reference" in the See Also section. -Fonts -***** - -To be able to display text, you need to prepare some fonts. ESPHome's :ref:`font renderer ` allows you to use OpenType/TrueType/Bitmap fonts for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. - .. _display-static_text: Drawing Static Text ******************* +**Fonts** + +To be able to display text, you need to prepare some fonts. ESPHome's :ref:`font renderer ` allows you to use OpenType/TrueType/Bitmap fonts for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. + In your display code, you can render static text by referencing the font and just entering your string enclosed in double quotes: .. code-block:: yaml @@ -385,8 +384,6 @@ With ``get_clipping();`` you get a ``Rect`` object back with the latest set clip With ``is_clipping();`` tells you if clipping is activated. - - .. _config-color: Color From dd0a860c5384b6e52c4153ff1dbc67033d14d1c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 15:08:21 +0100 Subject: [PATCH 211/350] symbols out --- components/display/index.rst | 2 -- cookbook/lvgl.rst | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 24d645212..4ea101926 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -162,8 +162,6 @@ You can view the full API documentation for the rendering engine in the "API Ref Drawing Static Text ******************* -**Fonts** - To be able to display text, you need to prepare some fonts. ESPHome's :ref:`font renderer ` allows you to use OpenType/TrueType/Bitmap fonts for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. In your display code, you can render static text by referencing the font and just entering your string enclosed in double quotes: diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index f2b0505cb..283c8d90b 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -289,7 +289,7 @@ To make a nice user interface for controlling Home Assistant covers you could us .. figure:: images/lvgl_cook_cover.png :align: center -Just as in the previous examples, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label on the middle to show the *STOP* symbol. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. +Just as in the previous examples, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. .. code-block:: yaml @@ -336,7 +336,7 @@ Just as in the previous examples, we need to get the states of the cover first. then: - lvgl.label.update: id: cov_stop_myroom - symbol: "STOP" + text: "STOP" else: - lvgl.label.update: id: cov_stop_myroom @@ -365,7 +365,7 @@ Just as in the previous examples, we need to get the states of the cover first. - label: id: cov_up_myroom align: center - symbol: UP + text: "\uF077" on_press: then: - homeassistant.service: @@ -397,7 +397,7 @@ Just as in the previous examples, we need to get the states of the cover first. - label: id: cov_down_myroom align: center - symbol: DOWN + text: "\uF078" on_press: then: - homeassistant.service: @@ -543,22 +543,22 @@ For the navigation bar we can use a button matrix. Note how the *header_footer* rows: - buttons: - id: top_prev - symbol: left # symbol only works when text_font is one of the internal fonts + text: "\uF053" on_press: then: lvgl.page.previous: - id: top_home - symbol: home + text: "\uF015" on_press: then: lvgl.page.show: main_page - id: top_next - symbol: right + text: "\uF054" on_press: then: lvgl.page.next: -For this example to work, use the theme and style options from :ref:`above `. +For this example to look correctly, use the theme and style options from :ref:`above ` amd LVGL's built-in fonts. .. _lvgl-cook-statico: @@ -593,7 +593,7 @@ In the example below we only show the icon when connection with Home Assistant i top_layer: widgets: - label: - symbol: WIFI + text: "\uF1EB" id: lbl_hastatus hidden: true align: top_right @@ -1111,14 +1111,14 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c control: no_repeat: true - buttons: - - symbol: BACKSPACE + - text: "\uF55A" key_code: "*" control: no_repeat: true - text: 0 control: no_repeat: true - - symbol: OK + - text: "\uF00C" key_code: "#" control: no_repeat: true @@ -1157,7 +1157,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c id: lvgl_led color: 0xFF0000 -A few notable things in this example: usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); usage of ``align_to`` to align it to the led vertically; changing the background color of the buttons in ``pressed`` state; using the ``key_code`` configuration option to send a different character to ``key_collector`` instead of the displayed symbol; display a symbol within the text by its codepoint unicode address in the :ref:`font `. +A few notable things in this example: usage of a base object ``obj`` as a parent for the label (in order to center the label in the middle of it and emphasize it with shadows independently of the label's dimensions); usage of ``align_to`` to align it to the led vertically; changing the background color of the buttons in ``pressed`` state; using the ``key_code`` configuration option to send a different character to ``key_collector`` instead of the displayed symbol. .. _lvgl-cook-idlescreen: From d834bfdc52d769b24ff7a9104be00997f662653d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 15:18:17 +0100 Subject: [PATCH 212/350] Update lvgl.rst --- cookbook/lvgl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 283c8d90b..bb9f95511 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -542,17 +542,17 @@ For the navigation bar we can use a button matrix. Note how the *header_footer* styles: header_footer rows: - buttons: - - id: top_prev + - id: page_prev text: "\uF053" on_press: then: lvgl.page.previous: - - id: top_home + - id: page_home text: "\uF015" on_press: then: lvgl.page.show: main_page - - id: top_next + - id: page_next text: "\uF054" on_press: then: From 4ae3c86fc3cc1ae935d29fd981ca5907080b9293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 16:27:23 +0100 Subject: [PATCH 213/350] switch --- components/lvgl.rst | 3 --- components/switch/lvgl.rst | 5 ++++- cookbook/lvgl.rst | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 6aa4a3dbc..26b27f60a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1283,9 +1283,6 @@ The Switch looks like a little slider and can be used to turn something on and o x: 10 y: 10 id: switch_id - indicator: - knob - The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 2041d368a..43c412d1a 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -19,9 +19,9 @@ Configuration options: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the switch. - **widget** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. +- **output_id** (*Optional*, :ref:`config-id`): The ID of a binary output to drive in sync with the state of the switch widget. - All other options from :ref:`Switch `. - Example: .. code-block:: yaml @@ -31,6 +31,8 @@ Example: widget: checkbox_id name: LVGL switch +Check out :ref:`lvgl-cook-outbin` in the Cookbook for an example how to set up a LVGL Switch component to interact directly with a GPIO. + See Also -------- - :ref:`LVGL Main component ` @@ -41,4 +43,5 @@ See Also - :doc:`/components/number/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` +- :doc:`/components/output/index` - :ghedit:`Edit` diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index bb9f95511..81bac27d5 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -13,6 +13,37 @@ Here are a couple recipes for various interesting things you can do with :ref:`l The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of ``240x320px``, you have to adjust them to your screen in order to obtain expected results. +.. _lvgl-cook-outbin: + +Local GPIO switch +----------------- + +.. figure:: /components/images/lvgl_switch.png + :align: right + +The easiest way to integrate a LVGL :ref:`lvgl-wgt-swi` widget and a GPIO output on your display board is with the :ref:`lvgl-swi` component. This will create a Switch, which will toggle your GPIO directly: + +.. code-block:: yaml + + output: + - id: output_display_light + platform: gpio + pin: GPIO14 # choose yours + + switch: + - platform: lvgl + name: Display lights + widget: light_switch + output_id: output_display_light + + lvgl: + ... + pages: + - id: main_page + widgets: + - switch: + align: center + id: light_switch .. _lvgl-cook-relay: @@ -22,7 +53,7 @@ Local light switch .. figure:: /components/images/lvgl_switch.png :align: left -If you have a display device with a local light configured, you can simply create a :ref:`lvgl-wgt-swi` for it. +In case your local light implements as a different platform than GPIO, you can use :ref:`automations ` to link together triggers and states with the :ref:`lvgl-wgt-swi` widget: .. code-block:: yaml From 428994703d689838ce7dbd0b61b31167825c9598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 16:33:42 +0100 Subject: [PATCH 214/350] Update fonts.rst --- components/display/fonts.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/display/fonts.rst b/components/display/fonts.rst index b4a0f04d4..41c815ccb 100644 --- a/components/display/fonts.rst +++ b/components/display/fonts.rst @@ -119,16 +119,18 @@ Configuration variables: OpenType/TrueType font files offer icons at codepoints far from what's reachable on a standard keyboard, for these it's needed to specify the unicode codepoint of the glyph as a hex address escaped with ``\u`` or ``\U``. - Code points up to ``0xFFFF`` are encoded like ``\uE6E8``. Lowercase ``\u`` and exactly 4 hexadecimal digits. - Code points above ``0xFFFF`` are encoded like ``\U0001F5E9``. Capital ``\U`` and exactly 8 hexadecimal digits. + - Code points up to ``0xFFFF`` are encoded like ``\uE6E8``. Lowercase ``\u`` and exactly 4 hexadecimal digits. + - Code points above ``0xFFFF`` are encoded like ``\U0001F5E9``. Capital ``\U`` and exactly 8 hexadecimal digits. The ``extras`` section only supports OpenType/TrueType files, ``size`` and ``bpp`` will be the same as the above level. This will allow printing icons alongside the characters in the same string, like ``I \uF004 You \uF001``. Many font sizes with multiple glyphs at high bit depths will increase the binary size considerably. Make your choices carefully. + +.. note:: + To use fonts you will need to have the python ``pillow`` package installed, as ESPHome uses that package - to translate the OpenType/TrueType and bitmap font files into an internal format. If you're running this as a Home Assistant - add-on or with the official ESPHome docker image, it should already be installed. Otherwise you need + to translate the OpenType/TrueType and bitmap font files into an internal format. If you're running this as a Home Assistant add-on or with the official ESPHome docker image, it should already be installed. Otherwise you need to install it using ``pip install "pillow==10.1.0"``. See Also From b7740e2a6e803753c9f8dc66877de0fa0cf5d575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 16:39:44 +0100 Subject: [PATCH 215/350] images --- components/display/fonts.rst | 2 +- components/lvgl.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/display/fonts.rst b/components/display/fonts.rst index 41c815ccb..7ca667d4e 100644 --- a/components/display/fonts.rst +++ b/components/display/fonts.rst @@ -9,7 +9,7 @@ Font Renderer Component ESPHome's graphical rendering engine also has a powerful font drawer which integrates seamlessly into the system. You have the option to use **any** OpenType/TrueType (``.ttf``, ``.otf``, ``.woff``) font file at **any** size, as well as fixed-size `PCF `_ and `BDF `_ bitmap fonts. -These fonts can be used in ESPHome's :ref:`own rendering engine ` or in :ref:`LVGL `. +These fonts can be used in ESPHome's :ref:`own rendering engine ` or in the :ref:`LVGL ` component. To use fonts you first have to define a font object in your ESPHome configuration file. Just grab a ``.ttf``, ``.otf``, ``.woff``, ``.pcf``, or ``.bdf`` file from somewhere on the internet and place it, for example, inside a ``fonts`` folder next to your configuration file. diff --git a/components/lvgl.rst b/components/lvgl.rst index 26b27f60a..f3d18952d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1,7 +1,7 @@ .. _lvgl-main: -LVGL -==== +LVGL Graphics +============= .. seo:: :description: LVGL - ESPHome Displays showing contents created with Light and Versatile Graphics Library @@ -825,7 +825,7 @@ Images are the basic widgets to display images. - **src** (**Required**, :ref:`image `): The ID of an existing image configuration. - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. -TODO !! supported image encodings +Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. **Specific actions:** From 4ed45bee26549155b482fdaf520d19dd239df946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Feb 2024 19:30:17 +0100 Subject: [PATCH 216/350] font --- components/display/fonts.rst | 7 +++++-- components/switch/lvgl.rst | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/components/display/fonts.rst b/components/display/fonts.rst index 7ca667d4e..087195bc4 100644 --- a/components/display/fonts.rst +++ b/components/display/fonts.rst @@ -9,7 +9,7 @@ Font Renderer Component ESPHome's graphical rendering engine also has a powerful font drawer which integrates seamlessly into the system. You have the option to use **any** OpenType/TrueType (``.ttf``, ``.otf``, ``.woff``) font file at **any** size, as well as fixed-size `PCF `_ and `BDF `_ bitmap fonts. -These fonts can be used in ESPHome's :ref:`own rendering engine ` or in the :ref:`LVGL ` component. +These fonts can be used in ESPHome's :ref:`own rendering engine ` or in the :ref:`LVGL Graphics ` component. To use fonts you first have to define a font object in your ESPHome configuration file. Just grab a ``.ttf``, ``.otf``, ``.woff``, ``.pcf``, or ``.bdf`` file from somewhere on the internet and place it, for example, inside a ``fonts`` folder next to your configuration file. @@ -71,7 +71,8 @@ Next, create a ``font:`` section in your configuration: display: # ... -Configuration variables: +Configuration options: +---------------------- - **file** (**Required**, string): The path (relative to where the .yaml file is) of the font file. You can also use the ``gfonts://`` short form to use Google Fonts, or use the below structure: @@ -139,5 +140,7 @@ See Also - :apiref:`display/display_buffer.h` - :ref:`display-engine` - :ref:`lvgl-main` +- `MDI cheatsheet `_ +- `MDI font repository `_ - :ghedit:`Edit` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 43c412d1a..912ad92b3 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -19,7 +19,7 @@ Configuration options: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the switch. - **widget** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. -- **output_id** (*Optional*, :ref:`config-id`): The ID of a binary output to drive in sync with the state of the switch widget. +- **output_id** (*Optional*, :ref:`config-id`): The ID of a **binary** output to drive in sync with the state of the switch widget. - All other options from :ref:`Switch `. Example: From 2448ac177c5974defa32655ab655c3a12fb466fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 7 Feb 2024 13:16:29 +0100 Subject: [PATCH 217/350] spinner --- components/images/lvgl_spinner.png | Bin 0 -> 2756 bytes components/lvgl.rst | 92 ++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 20 deletions(-) create mode 100644 components/images/lvgl_spinner.png diff --git a/components/images/lvgl_spinner.png b/components/images/lvgl_spinner.png new file mode 100644 index 0000000000000000000000000000000000000000..ea4e37d474e2183e98317e62b89694e7c66155cd GIT binary patch literal 2756 zcmV;#3On_QP)iz}H000V$Nkl zO=uiP7RR5L9(V;~=mrgFz=9RTunGx8LvpZTAvPF-NG|c7tm7V~qTGCxZrR&z zE&=-xm@F(Pfq?Cka&Q>sV35Fv5saZ5W}qI-fcDVMtahe9UR76r&D8H?MkUYa{pY=U z^}6cSt?TP+u+*DBRQ&-g*;tVpfEB3$SdkilQ}qW>MouLFzzhI@h{6|XLa~FfjnO|4 z0ir)wv_!$5(J;5_pWQ{O5YUX0#83s>hz1=2>K&^}k))JC z5QKSJt#QD0T_Gxysv40RBhO8$ld5cy>KxoSR1yG770Dm_Ri$laK^MK-UTJSvl1OqY zgR8n^Zl-WI-Ev&243T`_Z*F``2ixd*g}YR-A{FRBPE?MY7v+|})N(3smiUOMpj4%3 zmnu*sDP{1^oI(yDMg_M#7Ky4&Gcv20yHQ}`SCmM`LL5f5wIaT%Q3;9&jC|61048?I>5yO3(<}$*PgKmsccBg&c4< zN~)=tLQZAyPRFJ4>y%3*J%t+NK+EX4R8F08?Yq+`X}cS4a}@#r&-2_3SM|4Y*8cT9 zN%=d~zz~;&M(E2EKQui_O1ZWQ0f1-;cf(cMSxOUm69aftFgHcH0i ziWHWFnS<9&p%5jVC{PG`T#@)w5w@|;Rqa9%Ld=h?Wx_WpOC*J*s{@U$`sBy+xJd+m zdCL-seO|IxaU5*%|8#jk4hw;5ZJl*nVQIFUFLlFjQBVdi+T z#*Yz+W;WIp0xROh89z=WMo|?VE0QuCqs1D3Q6%mb7ORm4Jfkg3pqV(>2}uKOqb-TV zc@EpWX5zJhW4a{?bUevs4ch3LZc(J7n{Zn)S(dYOX1EIPm9E7%oN@B z;w#pZO6Aw9>@ho?#aEU@(t31gVKN+NkJ`q)8l^Btj2d1q^N}OJ1kJ)b1a@GJzp2Vsv$WWuk}gB^o?YByPk@I52Gq8H{A+qgY6d zb&$SJV)j0?GgAuBerFly%e!eprY>fgIiC9E3v0q)B)>anjePP!+E3F&;`h|EGgB-l zuSm|a4cP0%uVLq8l!dq=k^VJXtIFA1)@%d-Pd>^RmLU?iMTAO&_ch@gUQ*Y^w3Hzv zyTHnCovd+v)2edv(&wy=0N~)0>|xm=3Bh$Hn?ZyOM)Kq}Yh)K`|HJI14(m|`zcIV^ z9rdfkS3k4z1>m_6Fhx?hac1p<-qA1IK-cTA+z9v&{gkc+TH8$T^g{mQHP=uFA9F`? zMG`H+Z(JO_3)XOQ8jR%Of4J+#y={89%{@P>@c7)jt#GN!y6H3=%flbJQ;~4!=u?I5 z+-iFq+)eh?F0=JYA`bseoP8!CUq3)k<^B~lkrXap0Du|zqqRsP4u0S!3jlDxo4tBn zKzX;2(oI%GG#m|8-=bOUKlhpC9{>;z9e<{LZbfHHmqO4309s{#I{3lo>@b;g{75a( zg=ls}QMzD}h=#-Aiscc*v3&f!f)4?}!7lJKx|`^Bj#Rl&6(GtZRz|16NbWx;{yYQ# zy$=2Do~h1}Y&_3XI~F*D;3`;wb?)hf{L6ENTn+%X+w|?{X8VG((YTi*o4P z^NIx8IssrCn{qYn$xHv_wVDHkJbeVJtDj9Wx?99-ROX5#8F|4LBIdlUJmaWZ&fI&tOC$Fenn_h%=59stFt?!&F2fLtM^~t0_k-)?hm537^&WTD>aW|t4M)GO` z0C0Xq{tSM-g5elAJxP=h4jn&2y~-(*Vnqru7W$I8*>tu{?sw_JkL&{B#}b=v2XnR#r{tfD73dtN1qn%KyylMIqlu{Bubi)spyy9bhZe39Xj|J zA8wagaxA+qxM&IC35hZYg8Y5+@~k>l=^`C`g8Lsvw0O7+(uL;)BvnV4dB1Wr7!c7xEuWd0000< KMNUMnLSTYU@FKYY literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index f3d18952d..1e206d6ea 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -474,8 +474,8 @@ The Arc consists of a background and a foreground arc. The foreground (indicator - **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. -- **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws a handle on the end of the indicator using all background properties and padding values. With zero padding the knob size is the same as the indicator's width. Larger padding makes it larger, smaller padding makes it smaller. -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws another arc using the arc style properties. Its padding values are interpreted relative to the background arc. +- **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws a handle on the end of the indicator using all background properties and padding values. With zero padding the knob size is the same as the indicator's width. Larger padding makes it larger, smaller padding makes it smaller. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws *another arc using the arc style* properties. Its padding values are interpreted relative to the background arc. - any :ref:`Styling ` and state-based option to override styles inherited from parent. The arc's size and position will respect the padding style properties. @@ -553,7 +553,7 @@ Not only the end, but also the start value of the bar can be set, which changes - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, all the typical background properties. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, all the typical background properties. - **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. - Style options from :ref:`lvgl-styling`. The background of the bar and it uses the typical background style properties. Adding padding will make the indicator smaller or larger. @@ -654,13 +654,15 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **recolor** (*Optional*, boolean): Enable recoloring of button texts with #. E.g. ``It's #ff0000 red#`` - **custom_1** and **custom_2** (*Optional*, boolean): custom free to use flags -- **items** (*Optional*, list): Settings for the items **part**, the buttons all use the text and typical background style properties except translations and transformations. +- **items** (*Optional*, list): Settings for the items *part*, the buttons all use the text and typical background style properties except translations and transformations. - **one_checked** (*Optional*, boolean): Allow only one button to be checked at a time (aka. radio buttons). Defaults to ``false``. - Style options from :ref:`lvgl-styling` for the background of the button matrix, uses the typical background style properties. ``pad_row`` and ``pad_column`` set the space between the buttons. **Specific actions:** -``lvgl.button.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.button.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. + +``lvgl.btnmatrix.update`` :ref:`action ` updates the items styles and properties specified in the specific ``state``, ``items`` options. **Example:** @@ -710,6 +712,12 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row selected: true control: checkable: false + - lvgl.btnmatrix.update: + id: b_matrix + state: + disabled: true + items: + bg_color: 0xf0f0f0 .. note:: @@ -728,7 +736,7 @@ The Checkbox widget is made internally from a "tick box" and a label. When the C **Specific options:** -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The "tick box" is a square that uses all the typical background style properties. By default, its size is equal to the height of the main part's font. Padding properties make the tick box larger in the respective directions. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The "tick box" is a square that uses all the typical background style properties. By default, its size is equal to the height of the main part's font. Padding properties make the tick box larger in the respective directions. - Style options from :ref:`lvgl-styling` for the background of the widget and it uses the text and all the typical background style properties. ``pad_column`` adjusts the spacing between the tickbox and the label. **Specific actions:** @@ -776,9 +784,9 @@ The Dropdown widget is built internall from a *button* and a *list* (both not re - **options** (*Required*, list): The list of available options in the drop-down. - **dir** (*Optional*, enum): Where the list part of the dropdown gets created relative to the button part. ``LEFT``, ``RIGHT``, ``BOTTOM``, ``TOP``, defaults to ``BOTTOM``. - **selected_index** (*Optional*, int8): The index of the item you wish to be selected. -- **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Refers to the currently pressed, checked or pressed+checked option. Uses the typical background properties. -- **scrollbar** (*Optional*, list): Settings for the scrollbar **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar background, border, shadow properties and width (for its own width) and right padding for the spacing on the right. -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and is the parent of ``symbol``. +- **selected** (*Optional*, list): Settings for the selected *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Refers to the currently pressed, checked or pressed+checked option. Uses the typical background properties. +- **scrollbar** (*Optional*, list): Settings for the scrollbar *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar background, border, shadow properties and width (for its own width) and right padding for the spacing on the right. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and is the parent of ``symbol``. - **symbol** (*Optional*, enum): A symbol (typically an chevron) is shown in dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. Choose a different :ref:`symbol ` from the built-in ones or from your own customized font. - Style options from :ref:`lvgl-styling` for the background of the button and the list. Uses the typical background properties and :ref:`lvgl-wgt-lbl` text properties for the text on it. ``max_height`` can be used to limit the height of the list. @@ -878,7 +886,7 @@ A label is the basic widget type that is used to display text. - ``SCROLL``: If the text is wider than the label scroll it horizontally back and forth. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. - ``SCROLL_CIRCULAR``: If the text is wider than the label scroll it horizontally continuously. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. - ``CLIP``: Simply clip the parts of the text outside the label. -- **scrollbar** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar that is shown when the text is larger than the widget's size. +- **scrollbar** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar that is shown when the text is larger than the widget's size. - **selected** (*Optional*, list): Settings for the the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. @@ -1156,7 +1164,7 @@ Roller allows you to simply select one option from a list by scrolling. - **options** (*Required*, list): The list of available options in the roller. - **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. - **visible_rows** TODO -- **selected** (*Optional*, list): Settings for the selected **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-wgt-lbl` text style properties to change the appearance of the text in the selected area. +- **selected** (*Optional*, list): Settings for the selected *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-wgt-lbl` text style properties to change the appearance of the text in the selected area. - **selected_index** (*Optional*, int8): The index of the item you wish to be selected. - Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-wgt-lbl` style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. @@ -1204,8 +1212,8 @@ The Slider widget looks like a bar supplemented with a knob. The knob can be dra - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. -- **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. A rectangle (or circle) drawn at the current value. Also uses all the typical background properties to describe the knob. By default, the knob is square (with an optional corner radius) with side length equal to the smaller side of the slider. The knob can be made larger with the padding values. Padding values can be asymmetric too. -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The indicator that shows the current state of the slider. Also uses all the typical background style properties. +- **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. A rectangle (or circle) drawn at the current value. Also uses all the typical background properties to describe the knob. By default, the knob is square (with an optional corner radius) with side length equal to the smaller side of the slider. The knob can be made larger with the padding values. Padding values can be asymmetric too. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The indicator that shows the current state of the slider. Also uses all the typical background style properties. - **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. - any :ref:`Styling ` and state-based option for the background of the slider. Uses all the typical background style properties. Padding makes the indicator smaller in the respective direction. @@ -1258,6 +1266,50 @@ The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider to control entities in Home Assistant. +.. _lvgl-wgt-spi: + +``spinner`` +********** + +The Spinner widget looks like a bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider can be vertical or horizontal. + +.. figure:: /components/images/lvgl_spinner.png + :align: center + +**Specific options:** + +- **spin_time** (*Required*, :ref:`Time `): Duration of one cycle of the spin. +- **arc_length** (*Required*, 0-360): Length of the spinning arc in degrees. +- **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. +- **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws *another arc using the arc style* properties. Its padding values are interpreted relative to the background arc. + +**Specific actions:** + +``lvgl.spinner.update`` :ref:`action ` updates the widget styles and properties for the *indicator* part (anything other than the properties that apply commonly to all objects), just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - spinner: + align: center + spin_time: 2s + arc_length: 60deg + id: spinner_id + indicator: + arc_color: 0xd4d4d4 + + # Example action: + on_...: + then: + - lvgl.spinner.update: + id: spinner_id + arc_color: 0x31de70 + .. _lvgl-wgt-swi: ``switch`` @@ -1270,8 +1322,8 @@ The Switch looks like a little slider and can be used to turn something on and o **Specific options:** -- **knob** (*Optional*, list): Settings for the knob **part** to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. -- **indicator** (*Optional*, list): Settings for the indicator **part** to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. +- **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. - Style options from :ref:`lvgl-styling`. **Example:** @@ -1300,7 +1352,7 @@ The Table widget is very lightweight because only the texts are stored. No real **Specific options:** - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **items** (*Optional*, list): Settings for the items **part** +- **items** (*Optional*, list): Settings for the items *part* - Style options from :ref:`lvgl-styling`. @@ -1323,10 +1375,10 @@ One line mode and password modes are supported. **Specific options:** - **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **scrollbar** (*Optional*, list): Settings for the scrollbar **part** -- **selected** (*Optional*, list): Settings for the selected **part** -- **cursor** (*Optional*, list): Settings for the cursor **part** -- **textarea_placeholder** (*Optional*, list): Settings for the textarea_placeholder **part** +- **scrollbar** (*Optional*, list): Settings for the scrollbar *part* +- **selected** (*Optional*, list): Settings for the selected *part* +- **cursor** (*Optional*, list): Settings for the cursor *part* +- **textarea_placeholder** (*Optional*, list): Settings for the textarea_placeholder *part* - Style options from :ref:`lvgl-styling`. **Example:** From c798a6586ed2e79b50ab94f435230b20ff3fb36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 7 Feb 2024 13:18:41 +0100 Subject: [PATCH 218/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1e206d6ea..8e20a6e6c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1269,7 +1269,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use .. _lvgl-wgt-spi: ``spinner`` -********** +*********** The Spinner widget looks like a bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider can be vertical or horizontal. From 7ecad205ab2ab8abcbbe32a8a1e99b378a14533d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 7 Feb 2024 13:23:31 +0100 Subject: [PATCH 219/350] updates --- components/binary_sensor/lvgl.rst | 2 +- components/lvgl.rst | 2 +- components/number/lvgl.rst | 4 +--- components/select/lvgl.rst | 3 +-- components/switch/lvgl.rst | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 97e844617..7c0ace787 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -18,7 +18,7 @@ Configuration options: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the binary sensor. -- **widget** (**Required**): The ID of a ``btn`` widget configured in LVGL. +- **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the binary sensor. - All other options from :ref:`Binary Sensor `. .. note:: diff --git a/components/lvgl.rst b/components/lvgl.rst index 8e20a6e6c..a91499c36 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1271,7 +1271,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use ``spinner`` *********** -The Spinner widget looks like a bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider can be vertical or horizontal. +The Spinner widget is a spinning arc over a ring. .. figure:: /components/images/lvgl_spinner.png :align: center diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index a7f9c0531..e1c3f9492 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -20,9 +20,7 @@ Configuration options: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the number. - **animated** (*Optional*, boolean): Wether to set the value of the widget with an animation. Defaults to ``true``. -- **arc** (**Required**): The ID of an ``arc`` widget configured in LVGL, which will reflect the state of the number; or -- **bar** (**Required**): The ID of a ``bar`` widget configured in LVGL, which will reflect the state of the number; or -- **slider** (**Required**): The ID of a ``slider`` widget configured in LVGL, which will reflect the state of the number. +- **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the number. - All other options from :ref:`Number `. diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index e677557e4..5571c7736 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -18,8 +18,7 @@ Configuration options: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the select. -- **dropdown** (**Required**): The ID of a ``dropdown`` widget configured in LVGL, which will reflect the state of the select; or -- **roller** (**Required**): The ID of a ``roller`` widget configured in LVGL, which will reflect the state of the select. +- **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the select. - All other options from :ref:`Select `. Example: diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 912ad92b3..dacd8d0fc 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -18,7 +18,7 @@ Configuration options: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the switch. -- **widget** (**Required**): The ID of a widget configured in LVGL, which will reflect the state of the switch. +- **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the switch. - **output_id** (*Optional*, :ref:`config-id`): The ID of a **binary** output to drive in sync with the state of the switch widget. - All other options from :ref:`Switch `. From 9b78cf503a67549813ed7341a669ff0d5768d012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 7 Feb 2024 14:10:52 +0100 Subject: [PATCH 220/350] antibrun --- components/lvgl.rst | 7 +++++-- cookbook/lvgl.rst | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a91499c36..951f11d45 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1503,11 +1503,14 @@ This :ref:`action ` redraws the entire screen, or optionally only This :ref:`action ` pauses the activity of LVGL, including rendering. +- **show_snow** (*Optional*, boolean): During paused, display random coloured pixels across the entire screen in order to minimize screen burn-in, to relief the tension put on each individual pixel. See :ref:`lvgl-cook-antiburn` for an example how to use this. + .. code-block:: yaml on_...: then: - - lvgl.pause + - lvgl.pause: + show_snow: true .. _lvgl-resume-act: @@ -1521,7 +1524,7 @@ This :ref:`action ` resumes the activity of LVGL, including rende on_...: then: - - lvgl.resume + - lvgl.resume: .. _lvgl-pgnx-act: diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 81bac27d5..d4ba73d4f 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1237,6 +1237,48 @@ LVGL has a notion of screen inactivity, i.e. how long did the user not interact mode: box +.. _lvgl-cook-antiburn: + +Prevent burn-in of LCD +---------------------- + +You can use this to protect and prolonge the lifetime of the LCD screens, thus being more green and generating less hazardous waste. + +Wall mounted LCD screens' main problem is that they display the same picture 99.999% of the time. Even if somebody turns off backlight during the night or dark periods, the LCD screen keeps showing the same picture, seen by nobody. There are high chances that this will lead to screen picture burn-in after a few years of operation. + +One way to mitigate this is to *train* the pixels periodically with completely different other content. ``show_snow`` option during LVGL paused state was developed in this scope, to display random coloured pixels across the entire screen in order to minimize screen burn-in, to relief the tension put on each individual pixel. + +In the example below pixel traning is done every night between 1:30 and 2:30, and can be stopped by touching the screen. + +.. code-block:: yaml + + time: + - platform: ... + on_time: + - hours: 1 + minutes: 30 + seconds: 0 + then: + - lvgl.pause: + show_snow: true + on_time: + - hours: 2 + minutes: 30 + seconds: 0 + then: + - lvgl.resume: + + touchscreen: + - platform: ... + on_release: + then: + - if: + condition: lvgl.is_paused + then: + - lvgl.resume: + +For best results, combine it with the previous example by turning off the backlight, so the users don't actually notice this. + See Also -------- @@ -1244,5 +1286,7 @@ See Also - :ref:`config-lambda` - :ref:`automation` - :ref:`key_collector` +- `What is Image Sticking, Image Burn-in, an After Image, or a Ghost Image on an LCD? `__ +- `Image persistence `__ - :ghedit:`Edit` From 9d770b6c10b9d949d4f04a9fcf7563082f5758ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 7 Feb 2024 15:05:23 +0100 Subject: [PATCH 221/350] dropdown fixes --- components/lvgl.rst | 24 ++++++++++++++++-------- images/lvgl_c_sel.png | Bin 1858 -> 2622 bytes 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 951f11d45..b9e9242d9 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -777,18 +777,19 @@ The dropdown list is closed by default and displays a single value or a predefin .. figure:: /components/images/lvgl_dropdown.png :align: center -The Dropdown widget is built internall from a *button* and a *list* (both not related to the actual widgets with the same name). +The Dropdown widget is built internally from a *button* part and a *list* part (both not related to the actual widgets with the same name). **Specific options:** - **options** (*Required*, list): The list of available options in the drop-down. - **dir** (*Optional*, enum): Where the list part of the dropdown gets created relative to the button part. ``LEFT``, ``RIGHT``, ``BOTTOM``, ``TOP``, defaults to ``BOTTOM``. - **selected_index** (*Optional*, int8): The index of the item you wish to be selected. -- **selected** (*Optional*, list): Settings for the selected *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Refers to the currently pressed, checked or pressed+checked option. Uses the typical background properties. -- **scrollbar** (*Optional*, list): Settings for the scrollbar *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar background, border, shadow properties and width (for its own width) and right padding for the spacing on the right. -- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, and is the parent of ``symbol``. - **symbol** (*Optional*, enum): A symbol (typically an chevron) is shown in dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. Choose a different :ref:`symbol ` from the built-in ones or from your own customized font. -- Style options from :ref:`lvgl-styling` for the background of the button and the list. Uses the typical background properties and :ref:`lvgl-wgt-lbl` text properties for the text on it. ``max_height`` can be used to limit the height of the list. +- **indicator** (*Optional*, list): Settings for the the parent of ``symbol``. Supports a list of :ref:`styles ` to customize. +- **dropdown_list** (*Optional*, list): Settings for the dropdown_list *part*, the list with items. Supports a list of :ref:`styles ` to customize. Notable are ``text_line_space`` and ``pad_all`` for spacing of list items, and ``text_font`` to separately change the font in the list. +- **selected** (*Optional*, list): Settings for the selected item in the list. Supports a list of :ref:`styles ` to customize. +- **scrollbar** (*Optional*, list): Settings for the scrollbar *part*. Supports a list of :ref:`styles ` to customize. The scrollbar background, border, shadow properties and width (for its own width) and right padding for the spacing on the right. +- Style options from :ref:`lvgl-styling` for the background of the button and the list. Uses the typical background properties and :ref:`lvgl-wgt-lbl` text properties for the text on it. ``max_height`` can be used to limit the height of the list. ``text_font`` to set the font of the button part, including the symbol. **Specific actions:** @@ -800,14 +801,21 @@ The Dropdown widget is built internall from a *button* and a *list* (both not re # Example widget: - dropdown: - x: 10 - y: 60 - width: 90 id: dropdown_id + width: 90 + align: center options: - Violin - Piano - Bassoon + selected_index: 2 + dir: top + symbol: ${arrow_down} + indicator: + text_font: helv20 + dropdown_list: + bg_color: color_blue + text_color: 0x800000 # Example action: on_...: diff --git a/images/lvgl_c_sel.png b/images/lvgl_c_sel.png index 2b76696c4e0de564e1bba4872369941e0859ec66..b0f0dab2442a559ce0d7cc69987d78b18c391d93 100644 GIT binary patch literal 2622 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 Date: Wed, 7 Feb 2024 15:07:57 +0100 Subject: [PATCH 222/350] Update lvgl.rst --- components/lvgl.rst | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b9e9242d9..1e9b779e9 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -803,26 +803,21 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( - dropdown: id: dropdown_id width: 90 - align: center + align: CENTER options: - Violin - Piano - Bassoon + - Chello + - Drums selected_index: 2 - dir: top - symbol: ${arrow_down} - indicator: - text_font: helv20 - dropdown_list: - bg_color: color_blue - text_color: 0x800000 # Example action: on_...: then: - lvgl.dropdown.update: id: dropdown_id - selected_index: 3 + selected_index: 5 The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. @@ -1186,8 +1181,7 @@ Roller allows you to simply select one option from a list by scrolling. # Example widget: - roller: - x: 10 - y: 10 + align: CENTER id: roller_id options: - Violin From ace575f487e1dcce2fbfdc95967f3843cd07e487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 7 Feb 2024 15:13:49 +0100 Subject: [PATCH 223/350] Update lvgl.rst --- components/lvgl.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1e9b779e9..ee90b6118 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -848,8 +848,7 @@ Currently ``RGB565`` type images are supported, with transparency using the opti # Example widget: - img: - x: 10 - y: 10 + align: CENTER src: cat_image id: img_id radius: 11 From 0077535bac31966c8450e65830ac6d1bc0990cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 8 Feb 2024 11:00:02 +0100 Subject: [PATCH 224/350] float thermometer --- cookbook/lvgl.rst | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index d4ba73d4f..99e8016a7 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -238,12 +238,12 @@ Nothe the ``adv_hittest`` option, which ensures that accidental touches to the s Thermometer ----------- -A thermometer with a gauge acomplished with :ref:`lvgl-wgt-mtr` widget and numeric display using :ref:`lvgl-wgt-lbl`: +A thermometer with a gauge acomplished with :ref:`lvgl-wgt-mtr` widget and a numeric display with :ref:`lvgl-wgt-lbl`: .. figure:: images/lvgl_cook_thermometer.png :align: center -Whenever a new value comes from the sensor, we update the needle indicator, and the text label respectively. +Whenever a new value comes from the sensor, we update the needle indicator, and the text label respectively. Since LVGL only handles integer values on the :ref:`lvgl-wgt-mtr` scale, but we want a float precision scale we use the same approach as in the examples above to multiply the needle values by ``10``. We use two scales on top of each other: one to set the needle in the multiplied interval, and one to show the labels in the original interval. .. code-block:: yaml @@ -253,14 +253,13 @@ Whenever a new value comes from the sensor, we update the needle indicator, and on_value: - lvgl.indicator.line.update: id: temperature_needle - value: !lambda return x; + value: !lambda return x * 10; - lvgl.label.update: id: temperature_text text: !lambda |- static char buf[10]; - snprintf(buf, 10, "%.2f%°C", x); + snprintf(buf, 10, "%.1f°C", x); return buf; - lvgl: ... pages: @@ -271,19 +270,8 @@ Whenever a new value comes from the sensor, we update the needle indicator, and height: 180 width: 180 scales: - - ticks: - width: 2 - count: 51 - length: 10 - color: 0x000000 - major: - stride: 5 - width: 4 - length: 10 - color: 0x404040 - label_gap: 13 - range_from: -10 - range_to: 40 + - range_from: -100 # scale for the needle value + range_to: 400 angle_range: 240 rotation: 150 indicators: @@ -297,16 +285,33 @@ Whenever a new value comes from the sensor, we update the needle indicator, and end_value: 40 color_start: 0x0000bd color_end: 0xbd0000 + - range_from: -10 # scale for the value labels + range_to: 40 + angle_range: 240 + rotation: 150 + ticks: + width: 2 + count: 51 + length: 10 + color: 0x000000 + major: + stride: 5 + width: 4 + length: 10 + color: 0x404040 + label_gap: 13 widgets: - label: - text: "°C" id: temperature_text + text: "-.-°C" align: CENTER y: 45 + text_align: center - label: text: "Outdoor" align: CENTER y: 65 + text_align: center Notable here is the way the label is updated with a sensor numeric value using `snprintf `__. From 825e0b543b65aa54b8f43e2c88372459e7672944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 8 Feb 2024 12:14:08 +0100 Subject: [PATCH 225/350] scrollbar_mode --- components/lvgl.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index ee90b6118..bdc77e159 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -376,6 +376,12 @@ The properties below are common to all widgets. Similarly to CSS, LVGL also supports ``min_width``, ``max_width``, ``min_height`` and ``max_height``. These are limits preventing an object's size from becoming smaller/larger than these values. They are especially useful if the size is set by percentage or ``size_content``. - **min_width**, **max_width**, **min_height**, **max_height** (*Optional*, int16 or percentage): Sets a minimal/maximal width or a minimal/maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. +- **scrollbar_mode** (*Optional*, string): If an object is outside its parent content area (the size without padding), the parent becomes scrollable. The object can either be scrolled horizontally or vertically in one stroke. Scrollbars can appear depending on the setting: + - ``"OFF"``: Never show the scrollbars (use the double quotes!). + - ``"ON"``: Always show the scrollbars (use the double quotes!). + - ``"ACTIVE"``: Show scroll bars while an object is being scrolled. + - ``"AUTO"``: Show scroll bars when the content is large enough to be scrolled (default). + - **align** (*Optional*, enum): Alignment of the of the widget relative to the parent. A child widget is clipped to its parent boundaries. One of the values *not* starting with ``OUT_`` (see picture below). - **align_to** (*Optional*, list): Alignment of the of the widget relative to another widget on the same level: - **id** (**Required**): The ID of a widget *to* which you want to align. From becef5969f821c1dbb379c61a41c0cf2651bbacd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 8 Feb 2024 12:34:31 +0100 Subject: [PATCH 226/350] value in triggers --- components/lvgl.rst | 10 +++++----- cookbook/lvgl.rst | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index bdc77e159..1e3ee6a6e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -498,7 +498,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can **Specific triggers:** -``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply. +``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the value in ``x``. **Example:** @@ -533,7 +533,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can .. note:: - The ``on_value`` trigger is sent while the arc is being dragged or changed with keys. The event is sent *continuously* while the arc is being dragged, this can affect performance and have negative effects on the actions to be performed. + The ``on_value`` trigger is sent while the arc knob is being dragged or changed with keys. The event is sent *continuously* while the knob is being dragged, this can affect performance and have negative effects on the actions to be performed. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. @@ -1232,7 +1232,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking **Specific triggers:** -``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply. +``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the value in ``x``. **Example:** @@ -1267,7 +1267,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking .. note:: - The ``on_value`` trigger is sent while the slider is being dragged or changed with keys. The event is sent *continuously* while the slider is being dragged, this can affect performance and have negative effects on the actions to be performed. + The ``on_value`` trigger is sent while the slider is being dragged or changed with keys. The event is sent *continuously* while the slider is being dragged, this can affect performance and have negative effects on the actions to be performed. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. @@ -1651,7 +1651,7 @@ ESPHome implements as universal triggers the following interaction events genera - ``on_focus``: The widget is focused. - ``on_defocus``: The widget is unfocused. -These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself supports generating such events. +These triggers can be applied directly to any widget in the lvgl configuration, given that the widget itself supports generating such events. For the widgets having a value, the triggers return the current value in variable ``x``. .. code-block:: yaml diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 99e8016a7..34a950dec 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -183,7 +183,7 @@ This is applicable to service calls like ``fan.set_percentage``, ``valve.set_val .. note:: - Keep in mind that ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heatpump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. + Keep in mind that ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heatpump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. .. _lvgl-cook-volume: From e741df6bbdc2b724b32e7bc56413249435a70c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 8 Feb 2024 13:45:43 +0100 Subject: [PATCH 227/350] Update lvgl_align.png --- components/images/lvgl_align.png | Bin 13120 -> 15911 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png index bfe20a56b00b5b96228792ad6b260d1ff7d81725..e7a1381ca6e132dea3ac5302df356af8131d754e 100644 GIT binary patch literal 15911 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 literal 13120 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 Date: Thu, 8 Feb 2024 17:22:15 +0100 Subject: [PATCH 228/350] Update lvgl.rst --- cookbook/lvgl.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 34a950dec..3a961e1a8 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -786,7 +786,7 @@ Toggle state icon button .. figure:: images/lvgl_cook_font_binstat.png :align: left -A good example for using icons is for showing a different icon on a checkable (toggle) button based on the state of the switch or light it is linked to. To put an icon on a button you use a :ref:`lvgl-wgt-lbl` widget as the child of the :ref:`lvgl-wgt-btn`. The coloring can alredy be different thanks to the :ref:`lvgl-cook-theme` where you can set a different color for the ``checked`` state. +A good example for using icons is for showing a different icon on a checkable (toggle) button based on the state of the switch or light it is linked to. To put an icon on a button you use a :ref:`lvgl-wgt-lbl` widget as the child of the :ref:`lvgl-wgt-btn`. The coloring can alredy be different thanks to the :ref:`lvgl-cook-theme` where you can set a different color for the ``checked`` state. Additionally, by using a ``text_sensor`` to import the state from Home Assistant, we can not only track the ``on`` state, but also the ``unavailable`` or ``unknown`` to apply *disabled styles* for these cases. If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like this: @@ -802,29 +802,29 @@ If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like t "\U000F0336", # mdi-lightbulb-outline ] - binary_sensor: + text_sensor: - platform: homeassistant - id: remote_light + id: ts_remote_light entity_id: light.remote_light - publish_initial_state: true - on_press: + on_value: then: - lvgl.widget.update: id: btn_lightbulb state: - checked: true + checked: !lambda return (0 == x.compare(std::string{"on"})); + disabled: !lambda return ((0 == x.compare(std::string{"unavailable"})) or (0 == x.compare(std::string{"unknown"}))); - lvgl.label.update: id: lbl_lightbulb - text: "\U000F0335" # mdi-lightbulb - on_release: - then: - - lvgl.widget.update: - id: btn_lightbulb - state: - checked: false - - lvgl.label.update: - id: lbl_lightbulb - text: "\U000F0336" # mdi-lightbulb-outline + text: !lambda |- + static char buf[5]; + std::string icon; + if (0 == x.compare(std::string{"on"})) { + icon = "\U000F0335"; + } else { + icon = "\U000F0336"; + } + snprintf(buf, sizeof(buf), "%s", icon.c_str()); + return buf; lvgl: ... From 8b331e93efb33dc3e5900e2f8dee9683f7de7448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 8 Feb 2024 21:21:28 +0100 Subject: [PATCH 229/350] Update lvgl.rst --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 3a961e1a8..2a6cff201 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -816,7 +816,7 @@ If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like t - lvgl.label.update: id: lbl_lightbulb text: !lambda |- - static char buf[5]; + static char buf[10]; std::string icon; if (0 == x.compare(std::string{"on"})) { icon = "\U000F0335"; From cb49472f4b7bb923f570e9a2a02d9acc17f9e427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 9 Feb 2024 20:53:20 +0100 Subject: [PATCH 230/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1e3ee6a6e..e361d645b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1694,12 +1694,12 @@ See :ref:`lvgl-cook-idlescreen` example how to implement screen saving with idle See Also -------- +- :doc:`LVGL examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` -- :doc:`/cookbook/lvgl` - :doc:`/components/display/index` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` From a7c94c52977bd364503283fdce6f54de8f69925c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 9 Feb 2024 22:09:01 +0100 Subject: [PATCH 231/350] Update lvgl.rst --- components/lvgl.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index e361d645b..ed3b1c520 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1592,7 +1592,9 @@ Conditions ``lvgl.is_idle`` **************** -This :ref:`condition ` checks if LVGL is in idle state or not. +This :ref:`condition ` checks if since the last touch event, the amount of time specified here has passed or not. + +- **timeout** (**Required**, :ref:`templatable `, int): :ref:`Time ` to check against the time that has elapsed since the last touch event. .. code-block:: yaml @@ -1601,6 +1603,7 @@ This :ref:`condition ` checks if LVGL is in idle state or not. then: - if: condition: lvgl.is_idle + timeout: 5s then: - light.turn_off: id: display_backlight @@ -1674,7 +1677,7 @@ LVGL has a notion of screen inactivity, i.e. how long did the user not interact The ``on_idle`` :ref:`trigger ` is activated when inactivity time becomes longer than the specified ``timeout``. -- **timeout** (**Required**, :ref:`templatable `, int): :ref:`Time ` value after which LVGL should enter idle state. +- **timeout** (**Required**, :ref:`templatable `, int): :ref:`Time ` that has elapsed since the last touch event, after which you want your actions to be performed. .. code-block:: yaml From 96bcfe4e10e441ccac50a6b63d369abcf6820cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 10 Feb 2024 15:13:36 +0100 Subject: [PATCH 232/350] multiple timeouts supported --- components/lvgl.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ed3b1c520..4f23b99e6 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1675,20 +1675,23 @@ These triggers can be applied directly to any widget in the lvgl configuration, LVGL has a notion of screen inactivity, i.e. how long did the user not interact with the screen. This can be use to dim the display backlight or turn it off after a moment of inactivity (like a screen saver). Every use of an input device (touchscreen, rotary encoder) counts as an activity and resets the inactivity counter. -The ``on_idle`` :ref:`trigger ` is activated when inactivity time becomes longer than the specified ``timeout``. +The ``on_idle`` :ref:`triggers ` are activated when inactivity time becomes longer than the specified ``timeout``. You can configure any desired number of timeouts with different actions. - **timeout** (**Required**, :ref:`templatable `, int): :ref:`Time ` that has elapsed since the last touch event, after which you want your actions to be performed. .. code-block:: yaml lvgl: - on_idle: - timeout: 30s + ... + on_idle: + - timeout: 30s then: - - logger.log: "LVGL is idle" + - lvgl.page.show: main_page + - timeout: 60s + then: + - light.turn_off: display_backlight - lvgl.pause: - - light.turn_off: - id: display_backlight + See :ref:`lvgl-cook-idlescreen` example how to implement screen saving with idle settings. From acbcfc577eccd9346438e4cbbfa2ddbc2b368e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 10 Feb 2024 15:19:42 +0100 Subject: [PATCH 233/350] update antiburn example --- cookbook/lvgl.rst | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 2a6cff201..375c649ac 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1253,25 +1253,50 @@ Wall mounted LCD screens' main problem is that they display the same picture 99. One way to mitigate this is to *train* the pixels periodically with completely different other content. ``show_snow`` option during LVGL paused state was developed in this scope, to display random coloured pixels across the entire screen in order to minimize screen burn-in, to relief the tension put on each individual pixel. -In the example below pixel traning is done every night between 1:30 and 2:30, and can be stopped by touching the screen. +In the example below pixel traning is done foru times for a half an hour every night, can also be stopped by touching the screen. .. code-block:: yaml time: - platform: ... on_time: - - hours: 1 - minutes: 30 + - hours: 2,3,4,5 + minutes: 5 seconds: 0 then: - - lvgl.pause: - show_snow: true - on_time: - - hours: 2 - minutes: 30 + - switch.turn_on: switch_antiburn + - hours: 2,3,4,5 + minutes: 35 seconds: 0 then: - - lvgl.resume: + - switch.turn_off: switch_antiburn + + switch: + - platform: template + name: Antiburn + id: switch_antiburn + icon: mdi:television-shimmer + optimistic: true + entity_category: "config" + turn_on_action: + - logger.log: "Starting Antiburn" + - if: + condition: lvgl.is_paused + then: + - lvgl.resume: + - lvgl.widget.redraw: + - delay: 1s + - lvgl.pause: + show_snow: true + turn_off_action: + - logger.log: "Stoping Antiburn" + - if: + condition: lvgl.is_paused + then: + - lvgl.resume: + - lvgl.widget.redraw: + - delay: 1s + - lvgl.pause: touchscreen: - platform: ... @@ -1282,7 +1307,7 @@ In the example below pixel traning is done every night between 1:30 and 2:30, an then: - lvgl.resume: -For best results, combine it with the previous example by turning off the backlight, so the users don't actually notice this. +You can combine it with the previous example to turn off the backlight, so the users don't actually notice this. See Also -------- From 26704ec1888b2e3572e8d9416fe1c70107a8c9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 10 Feb 2024 15:20:31 +0100 Subject: [PATCH 234/350] Update lvgl.rst --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 375c649ac..9623f5582 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1253,7 +1253,7 @@ Wall mounted LCD screens' main problem is that they display the same picture 99. One way to mitigate this is to *train* the pixels periodically with completely different other content. ``show_snow`` option during LVGL paused state was developed in this scope, to display random coloured pixels across the entire screen in order to minimize screen burn-in, to relief the tension put on each individual pixel. -In the example below pixel traning is done foru times for a half an hour every night, can also be stopped by touching the screen. +In the example below pixel traning is done four times for a half an hour every night, can also be stopped by touching the screen. .. code-block:: yaml From cd85d3f3b4f4e484839c816ff6fb8fd8ecb933b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 10 Feb 2024 15:29:45 +0100 Subject: [PATCH 235/350] add slider on_release with x --- components/lvgl.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4f23b99e6..0b81aa7b4 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1668,6 +1668,15 @@ These triggers can be applied directly to any widget in the lvgl configuration, then: light.toggle: display_backlight + - slider: + ... + on_release: + then: + - light.turn_on: + id: display_backlight + transition_length: 0ms + brightness: !lambda return int(x); + .. _lvgl-onidle-trg: ``lvgl.on_idle`` From d147c292409dcd84ebddf0c88acd99c77fe5510f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 10 Feb 2024 15:30:37 +0100 Subject: [PATCH 236/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 0b81aa7b4..b01a4ae1a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1675,7 +1675,7 @@ These triggers can be applied directly to any widget in the lvgl configuration, - light.turn_on: id: display_backlight transition_length: 0ms - brightness: !lambda return int(x); + brightness: !lambda return x / 100; .. _lvgl-onidle-trg: From ee4923d5697789293dc12dd29986dee576d1d323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 10 Feb 2024 15:33:42 +0100 Subject: [PATCH 237/350] Update lvgl.rst --- cookbook/lvgl.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 9623f5582..e3b753dc1 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -170,7 +170,7 @@ We can use a sensor to retrieve the current brightness of a light, which is stor pad_all: 8 min_value: 0 max_value: 255 - on_value: + on_release: - homeassistant.service: service: light.turn_on data: @@ -181,10 +181,6 @@ Note that Home Assistant expects an integer at the ``brightness`` parameter of t This is applicable to service calls like ``fan.set_percentage``, ``valve.set_valve_position`` too, only difference is that ``max_value`` has to be ``100``. -.. note:: - - Keep in mind that ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heatpump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. - .. _lvgl-cook-volume: Media player volume slider @@ -231,7 +227,11 @@ With a sensor we retrieve the current volume level of the media player, which is entity_id: media_player.your_room volume_level: !lambda return (x / 100); -Nothe the ``adv_hittest`` option, which ensures that accidental touches to the screen won't cause sudden volume changes (more details in the :ref:`slider doc `). +The ``adv_hittest`` option ensures that accidental touches to the screen won't cause sudden volume changes (more details in the :ref:`slider doc `). + +.. note:: + + Keep in mind that ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heatpump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. .. _lvgl-cook-thermometer: From a794b9c7e287abc9efa0ced19ed699b2cd6a225b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 10 Feb 2024 15:40:43 +0100 Subject: [PATCH 238/350] Update lvgl.rst --- cookbook/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index e3b753dc1..e01b73c75 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1306,6 +1306,7 @@ In the example below pixel traning is done four times for a half an hour every n condition: lvgl.is_paused then: - lvgl.resume: + - lvgl.widget.redraw: You can combine it with the previous example to turn off the backlight, so the users don't actually notice this. From 51315cd53d5d6210f2ec793f2f527d4213013651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 10 Feb 2024 15:41:51 +0100 Subject: [PATCH 239/350] Update lvgl.rst --- components/lvgl.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b01a4ae1a..55ab4710e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1626,9 +1626,6 @@ This :ref:`condition ` checks if LVGL is in paused state or no condition: lvgl.is_paused then: - lvgl.resume: - - light.turn_on: - id: display_backlight - transition_length: 150ms Triggers -------- From af98f0588701792e1220cc3f8a736a3a184e0dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 12 Mar 2024 10:32:27 +0100 Subject: [PATCH 240/350] 8311 --- components/lvgl.rst | 21 +++++++++++++++------ cookbook/lvgl.rst | 16 ++++++---------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 55ab4710e..788223984 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -9,7 +9,7 @@ LVGL Graphics `LVGL `__ (Light and Versatile Graphics Library) is a free and open-source -embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.9 `__. +embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.11 `__. .. figure:: /components/images/lvgl_main_screenshot.png :align: center @@ -749,6 +749,11 @@ The Checkbox widget is made internally from a "tick box" and a label. When the C ``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +- **text** (*Required**, :ref:`templatable `, string): The ``text`` option in this action can contain static text, a :ref:`lambda ` outputting a string or can be formatted using ``printf``-style formatting (see :ref:`display-printf`). + - **format** (*Optional*, string): The format for the message in :ref:`printf-style `. + - **args** (*Optional*, list of :ref:`lambda `): The optional arguments for the + format message. + **Example:** .. code-block:: yaml @@ -902,7 +907,12 @@ Newline escape sequences are handled automatically by the label widget. You can **Specific actions:** -``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +- **text** (*Required**, :ref:`templatable `, string): The ``text`` option in this action can contain static text, a :ref:`lambda ` outputting a string or can be formatted using ``printf``-style formatting (see :ref:`display-printf`). + - **format** (*Optional*, string): The format for the message in :ref:`printf-style `. + - **args** (*Optional*, list of :ref:`lambda `): The optional arguments for the + format message. **Example:** @@ -926,10 +936,9 @@ Newline escape sequences are handled automatically by the label widget. You can then: - lvgl.label.update: id: lbl_id - text: !lambda |- - static char buf[10]; - snprintf(buf, 10, "%.0fdBm", id(wifi_signal_db).get_state()); - return buf; + text: + format: "%.0fdBm" + args: [ 'id(wifi_signal_db).get_state()' ] .. _lvgl-wgt-led: diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index e01b73c75..3853c264d 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -256,10 +256,9 @@ Whenever a new value comes from the sensor, we update the needle indicator, and value: !lambda return x * 10; - lvgl.label.update: id: temperature_text - text: !lambda |- - static char buf[10]; - snprintf(buf, 10, "%.1f°C", x); - return buf; + text: + format: "%.1f°C" + args: [ 'x' ] lvgl: ... pages: @@ -313,8 +312,6 @@ Whenever a new value comes from the sensor, we update the needle indicator, and y: 65 text_align: center -Notable here is the way the label is updated with a sensor numeric value using `snprintf `__. - .. _lvgl-cook-cover: Cover status and control @@ -376,10 +373,9 @@ Just as in the previous examples, we need to get the states of the cover first. else: - lvgl.label.update: id: cov_stop_myroom - text: !lambda |- - static char buf[10]; - snprintf(buf, 10, "%.0f%%", id(cover_myroom_pos).get_state()); - return buf; + text: + format: "%.0f%%" + args: [ 'id(cover_myroom_pos).get_state()' ] lvgl: ... From 08fa8ac7acc0c2d02d7ccb28bb0fd89b5b440a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 12 Mar 2024 11:46:07 +0100 Subject: [PATCH 241/350] reorder widgets --- components/lvgl.rst | 1005 ++++++++++++++++++++----------------------- 1 file changed, 475 insertions(+), 530 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 788223984..c397d0c1d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -110,7 +110,6 @@ Configuration variables: - All other options from :ref:`lvgl-styling` to be applied to this page. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. - **Example:** .. code-block:: yaml @@ -134,8 +133,6 @@ See :ref:`lvgl-cook-navigator` in the Cookbook for an example how to easily impl By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. - - .. _lvgl-theme: Theming and Styling @@ -455,129 +452,73 @@ In addition to visual stilyng, each widget supports some boolean flags to influe - **widget_1**, **widget_2** (*Optional*, boolean): custom flags, free to use by widget - **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): custom flags, free to use by user -.. _lvgl-wgt-arc: +.. _lvgl-wgt-lbl: -``arc`` -******* +``label`` +********* -The Arc consists of a background and a foreground arc. The foreground (indicator) can be touch-adjusted with a knob. +A label is the basic widget type that is used to display text. -.. figure:: /components/images/lvgl_arc.png +.. figure:: /components/images/lvgl_label.png :align: center **Specific options:** -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. -- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. -- **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). Defaults to ``135``. -- **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. -- **rotation** (*Optional*, int8): Offset to the 0 degree position. Defaults to ``0.0``. -- **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. -- **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. -- **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. -- **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. -- **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. -- **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws a handle on the end of the indicator using all background properties and padding values. With zero padding the knob size is the same as the indicator's width. Larger padding makes it larger, smaller padding makes it smaller. -- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws *another arc using the arc style* properties. Its padding values are interpreted relative to the background arc. -- any :ref:`Styling ` and state-based option to override styles inherited from parent. The arc's size and position will respect the padding style properties. +- **text** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. +- **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` +- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. +- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) +- **text_font**: (*Optional*, :ref:`font `): The ID or the C array name of the font used to render the text or symbol. +- **text_letter_space** (*Optional*, int16): Characher spacing of the text. +- **text_line_space** (*Optional*, int16): Line spacing of the text. +- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. +- **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. + - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) + - ``DOT``: Replaces the last 3 characters from bottom right corner of the label with dots. + - ``SCROLL``: If the text is wider than the label scroll it horizontally back and forth. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. + - ``SCROLL_CIRCULAR``: If the text is wider than the label scroll it horizontally continuously. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. + - ``CLIP``: Simply clip the parts of the text outside the label. +- **scrollbar** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar that is shown when the text is larger than the widget's size. +- **selected** (*Optional*, list): Settings for the the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. +- Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. - -If the ``adv_hittest`` :ref:`flag ` is enabled the arc can be clicked through in the middle. Clicks are recognized only on the ring of the background arc. - - -.. note:: - - Zero degree is at the middle right (3 o'clock) of the widget and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. +Newline escape sequences are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``"line1\nline2\n\nline4"``. **Note**: For escape sequences like newline to be translated, enclose the string in double quotes. **Specific actions:** -``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -**Specific triggers:** - -``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the value in ``x``. +- **text** (**Required**, :ref:`templatable `, string): The ``text`` option in this action can contain static text, a :ref:`lambda ` outputting a string or can be formatted using ``printf``-style formatting (see :ref:`display-printf`). + - **format** (*Optional*, string): The format for the message in :ref:`printf-style `. + - **args** (*Optional*, list of :ref:`lambda `): The optional arguments for the + format message. **Example:** .. code-block:: yaml # Example widget: - - arc: - x: 10 - y: 10 - id: arc_id - value: 75 - min_value: 0 - max_value: 100 - adjustable: true + - label: + align: CENTER + id: lbl_id + recolor: true + text: "#FF0000 write# #00FF00 colored# #0000FF text#" - # Example action: + - label: + align: TOP_MID + id: lbl_symbol + text_font: montserrat_28 + text: "\uF013" + + # Example action (update label with a value from a sensor): on_...: then: - - lvgl.arc.update - id: arc_id - knob: - bg_color: 0x00FF00 - value: 55 - - # Example trigger: - - arc: - ... - on_value: - - logger.log: - format: "Arc value is: %.0f" - args: [ 'x' ] - -.. note:: - - The ``on_value`` trigger is sent while the arc knob is being dragged or changed with keys. The event is sent *continuously* while the knob is being dragged, this can affect performance and have negative effects on the actions to be performed. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. - -The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. - -See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider (or an arc) to control entities in Home Assistant. - -.. _lvgl-wgt-bar: - -``bar`` -******* - -The bar widget has a background and an indicator on it. The width of the indicator is set according to the current value of the bar. - -.. figure:: /components/images/lvgl_bar.png - :align: center - -Vertical bars can be created if the width is smaller than the height. - -Not only the end, but also the start value of the bar can be set, which changes the start position of the indicator. - -**Specific options:** - -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. -- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. -- **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. -- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, all the typical background properties. -- **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. -- Style options from :ref:`lvgl-styling`. The background of the bar and it uses the typical background style properties. Adding padding will make the indicator smaller or larger. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - bar: - x: 10 - y: 100 - id: bar_id - value: 75 - min_value: 1 - max_value: 100 - - -The ``bar`` can be also integrated as :doc:`/components/number/lvgl`. + - lvgl.label.update: + id: lbl_id + text: + format: "%.0fdBm" + args: [ 'id(wifi_signal_db).get_state()' ] .. _lvgl-wgt-btn: @@ -729,6 +670,35 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row The Button Matrix widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. Check out :ref:`lvgl-cook-keypad` for an example. +.. _lvgl-wgt-swi: + +``switch`` +********** + +The Switch looks like a little slider and can be used to turn something on and off. + +.. figure:: /components/images/lvgl_switch.png + :align: center + +**Specific options:** + +- **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. +- Style options from :ref:`lvgl-styling`. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - switch: + x: 10 + y: 10 + id: switch_id + +The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. + +See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local component. .. _lvgl-wgt-chk: @@ -749,7 +719,7 @@ The Checkbox widget is made internally from a "tick box" and a label. When the C ``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -- **text** (*Required**, :ref:`templatable `, string): The ``text`` option in this action can contain static text, a :ref:`lambda ` outputting a string or can be formatted using ``printf``-style formatting (see :ref:`display-printf`). +- **text** (**Required**, :ref:`templatable `, string): The ``text`` option in this action can contain static text, a :ref:`lambda ` outputting a string or can be formatted using ``printf``-style formatting (see :ref:`display-printf`). - **format** (*Optional*, string): The format for the message in :ref:`printf-style `. - **args** (*Optional*, list of :ref:`lambda `): The optional arguments for the format message. @@ -832,199 +802,244 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. -.. _lvgl-wgt-img: +.. _lvgl-wgt-rol: -``img`` +``roller`` +********** + +Roller allows you to simply select one option from a list by scrolling. + +.. figure:: /components/images/lvgl_roller.png + :align: center + +**Specific options:** + +- **options** (*Required*, list): The list of available options in the roller. +- **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. +- **visible_rows** TODO +- **selected** (*Optional*, list): Settings for the selected *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-wgt-lbl` text style properties to change the appearance of the text in the selected area. +- **selected_index** (*Optional*, int8): The index of the item you wish to be selected. +- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-wgt-lbl` style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. + +**Specific actions:** + +``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - roller: + align: CENTER + id: roller_id + options: + - Violin + - Piano + - Bassoon + - Chello + - Drums + + # Example action: + on_...: + then: + - lvgl.roller.update: + id: roller_id + selected_index: 5 + +The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. + + +.. _lvgl-wgt-bar: + +``bar`` ******* -Images are the basic widgets to display images. +The bar widget has a background and an indicator on it. The width of the indicator is set according to the current value of the bar. -.. figure:: /components/images/lvgl_image.png +.. figure:: /components/images/lvgl_bar.png :align: center +Vertical bars can be created if the width is smaller than the height. + +Not only the end, but also the start value of the bar can be set, which changes the start position of the indicator. + **Specific options:** -- **src** (**Required**, :ref:`image `): The ID of an existing image configuration. -- Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. - -Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. - -**Specific actions:** - -``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. +- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. +- **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, all the typical background properties. +- **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. +- Style options from :ref:`lvgl-styling`. The background of the bar and it uses the typical background style properties. Adding padding will make the indicator smaller or larger. **Example:** .. code-block:: yaml # Example widget: - - img: - align: CENTER - src: cat_image - id: img_id - radius: 11 - clip_corner: true + - bar: + x: 10 + y: 100 + id: bar_id + value: 75 + min_value: 1 + max_value: 100 + + +The ``bar`` can be also integrated as :doc:`/components/number/lvgl`. + +.. _lvgl-wgt-sli: + +``slider`` +********** + +The Slider widget looks like a bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider can be vertical or horizontal. + +.. figure:: /components/images/lvgl_slider.png + :align: center + +**Specific options:** + +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. +- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. +- **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. A rectangle (or circle) drawn at the current value. Also uses all the typical background properties to describe the knob. By default, the knob is square (with an optional corner radius) with side length equal to the smaller side of the slider. The knob can be made larger with the padding values. Padding values can be asymmetric too. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The indicator that shows the current state of the slider. Also uses all the typical background style properties. +- **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. +- any :ref:`Styling ` and state-based option for the background of the slider. Uses all the typical background style properties. Padding makes the indicator smaller in the respective direction. + +Normally, the slider can be adjusted either by dragging the knob, or by clicking on the slider bar. In the latter case the knob moves to the point clicked and slider value changes accordingly. In some cases it is desirable to set the slider to react on dragging the knob only. This feature is enabled by enabling the ``adv_hittest`` flag. + +**Specific actions:** + +``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the value in ``x``. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - slider: + x: 10 + y: 10 + width: 220 + id: slider_id + value: 75 + min_value: 0 + max_value: 100 # Example action: on_...: then: - - lvgl.img.update: - id: img_id - src: dog_image + - lvgl.slider.update: + id: slider_id + knob: + bg_color: 0x00FF00 + value: 55 -.. _lvgl-wgt-lbl: - -``label`` -********* - -A label is the basic widget type that is used to display text. - -.. figure:: /components/images/lvgl_label.png - :align: center - -**Specific options:** - -- **text** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. -- **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` -- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. -- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) -- **text_font**: (*Optional*, :ref:`font `): The ID or the C array name of the font used to render the text or symbol. -- **text_letter_space** (*Optional*, int16): Characher spacing of the text. -- **text_line_space** (*Optional*, int16): Line spacing of the text. -- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. -- **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) - - ``DOT``: Replaces the last 3 characters from bottom right corner of the label with dots. - - ``SCROLL``: If the text is wider than the label scroll it horizontally back and forth. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. - - ``SCROLL_CIRCULAR``: If the text is wider than the label scroll it horizontally continuously. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. - - ``CLIP``: Simply clip the parts of the text outside the label. -- **scrollbar** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar that is shown when the text is larger than the widget's size. -- **selected** (*Optional*, list): Settings for the the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. -- Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. - -Newline escape sequences are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``"line1\nline2\n\nline4"``. **Note**: For escape sequences like newline to be translated, enclose the string in double quotes. - -**Specific actions:** - -``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - -- **text** (*Required**, :ref:`templatable `, string): The ``text`` option in this action can contain static text, a :ref:`lambda ` outputting a string or can be formatted using ``printf``-style formatting (see :ref:`display-printf`). - - **format** (*Optional*, string): The format for the message in :ref:`printf-style `. - - **args** (*Optional*, list of :ref:`lambda `): The optional arguments for the - format message. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - label: - align: CENTER - id: lbl_id - recolor: true - text: "#FF0000 write# #00FF00 colored# #0000FF text#" - - - label: - align: TOP_MID - id: lbl_symbol - text_font: montserrat_28 - text: "\uF013" - - # Example action (update label with a value from a sensor): - on_...: - then: - - lvgl.label.update: - id: lbl_id - text: - format: "%.0fdBm" - args: [ 'id(wifi_signal_db).get_state()' ] - -.. _lvgl-wgt-led: - -``led`` -******** - -The Led widgets are rectangle-like (or circle) widget whose brightness can be adjusted. With lower brightness the colors become darker. - -.. figure:: /components/images/lvgl_led.png - :align: center - -**Specific options:** - -- **color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background, border, and shadow of the widget. -- **brightness** (*Optional*, percentage): The brightness of the LED color, where ``0%`` corresponds to black, and ``100%`` corresponds to the full brightness of the color specified above. -- Style options from :ref:`lvgl-styling`, using all the typical background style properties. - -**Specific actions:** - -``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - led: - id: led_id - align: CENTER - color: 0xFF0000 - brightness: 70% - - # Example action: - on_...: - then: - - lvgl.led.update: - id: lvgl_led - color: 0x00FF00 - -The ``led`` can be also integrated as :doc:`/components/light/lvgl`. + # Example trigger: + - slider: + ... + on_value: + - logger.log: + format: "Slider value is: %.0f" + args: [ 'x' ] .. note:: - If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. + The ``on_value`` trigger is sent while the slider is being dragged or changed with keys. The event is sent *continuously* while the slider is being dragged, this can affect performance and have negative effects on the actions to be performed. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. -Check out :ref:`lvgl-cook-keypad` in the Cookbook for an example how to change the led styling properties from an automation. +The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. -.. _lvgl-wgt-lin: +See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider to control entities in Home Assistant. -``line`` -******** +.. _lvgl-wgt-arc: -The Line widget is capable of drawing straight lines between a set of points. +``arc`` +******* -.. figure:: /components/images/lvgl_line.png +The Arc consists of a background and a foreground arc. The foreground (indicator) can be touch-adjusted with a knob. + +.. figure:: /components/images/lvgl_arc.png :align: center **Specific options:** -- **points** (*Required*, list): A list of ``x, y`` integer pairs for point coordinates (origin from top left of parent) -- **line_width** (*Optional*, int16): Set the width of the line in pixels. -- **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). -- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). -- **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. -- Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. +- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. +- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. +- **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). Defaults to ``135``. +- **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. +- **rotation** (*Optional*, int8): Offset to the 0 degree position. Defaults to ``0.0``. +- **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. +- **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. +- **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. +- **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. +- **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. +- **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws a handle on the end of the indicator using all background properties and padding values. With zero padding the knob size is the same as the indicator's width. Larger padding makes it larger, smaller padding makes it smaller. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws *another arc using the arc style* properties. Its padding values are interpreted relative to the background arc. +- any :ref:`Styling ` and state-based option to override styles inherited from parent. The arc's size and position will respect the padding style properties. -TODO invert_y ??? +If the ``adv_hittest`` :ref:`flag ` is enabled the arc can be clicked through in the middle. Clicks are recognized only on the ring of the background arc. -By default, the Line widget width and height dimensions are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts of the line may not be visible. +.. note:: + + Zero degree is at the middle right (3 o'clock) of the widget and the degrees are increasing in a clockwise direction. The angles should be in the ``0``-``360`` range. + +**Specific actions:** + +``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the value in ``x``. **Example:** .. code-block:: yaml # Example widget: - - line: - points: - - 5, 5 - - 70, 70 - - 120, 10 - - 180, 60 - - 230, 15 - line_width: 8 - line_color: 0x0000FF - line_rounded: true + - arc: + x: 10 + y: 10 + id: arc_id + value: 75 + min_value: 0 + max_value: 100 + adjustable: true + + # Example action: + on_...: + then: + - lvgl.arc.update + id: arc_id + knob: + bg_color: 0x00FF00 + value: 55 + + # Example trigger: + - arc: + ... + on_value: + - logger.log: + format: "Arc value is: %.0f" + args: [ 'x' ] + +.. note:: + + The ``on_value`` trigger is sent while the arc knob is being dragged or changed with keys. The event is sent *continuously* while the knob is being dragged, this can affect performance and have negative effects on the actions to be performed. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. + +The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. + +See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider (or an arc) to control entities in Home Assistant. .. _lvgl-wgt-mtr: @@ -1111,6 +1126,206 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee See :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clock` in the Cookbook for examples how to effectively use this widget. +.. _lvgl-wgt-img: + +``img`` +******* + +Images are the basic widgets to display images. + +.. figure:: /components/images/lvgl_image.png + :align: center + +**Specific options:** + +- **src** (**Required**, :ref:`image `): The ID of an existing image configuration. +- Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. + +Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. + +**Specific actions:** + +``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - img: + align: CENTER + src: cat_image + id: img_id + radius: 11 + clip_corner: true + + # Example action: + on_...: + then: + - lvgl.img.update: + id: img_id + src: dog_image + +.. _lvgl-wgt-lin: + +``line`` +******** + +The Line widget is capable of drawing straight lines between a set of points. + +.. figure:: /components/images/lvgl_line.png + :align: center + +**Specific options:** + +- **points** (*Required*, list): A list of ``x, y`` integer pairs for point coordinates (origin from top left of parent) +- **line_width** (*Optional*, int16): Set the width of the line in pixels. +- **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). +- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). +- **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. +- Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. + +TODO invert_y ??? + +By default, the Line widget width and height dimensions are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts of the line may not be visible. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - line: + points: + - 5, 5 + - 70, 70 + - 120, 10 + - 180, 60 + - 230, 15 + line_width: 8 + line_color: 0x0000FF + line_rounded: true + + +.. _lvgl-wgt-led: + +``led`` +******** + +The Led widgets are rectangle-like (or circle) widget whose brightness can be adjusted. With lower brightness the colors become darker. + +.. figure:: /components/images/lvgl_led.png + :align: center + +**Specific options:** + +- **color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background, border, and shadow of the widget. +- **brightness** (*Optional*, percentage): The brightness of the LED color, where ``0%`` corresponds to black, and ``100%`` corresponds to the full brightness of the color specified above. +- Style options from :ref:`lvgl-styling`, using all the typical background style properties. + +**Specific actions:** + +``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - led: + id: led_id + align: CENTER + color: 0xFF0000 + brightness: 70% + + # Example action: + on_...: + then: + - lvgl.led.update: + id: lvgl_led + color: 0x00FF00 + +The ``led`` can be also integrated as :doc:`/components/light/lvgl`. + +.. note:: + + If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. + +Check out :ref:`lvgl-cook-keypad` in the Cookbook for an example how to change the led styling properties from an automation. + +.. _lvgl-wgt-spi: + +``spinner`` +*********** + +The Spinner widget is a spinning arc over a ring. + +.. figure:: /components/images/lvgl_spinner.png + :align: center + +**Specific options:** + +- **spin_time** (*Required*, :ref:`Time `): Duration of one cycle of the spin. +- **arc_length** (*Required*, 0-360): Length of the spinning arc in degrees. +- **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. +- **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. +- **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. +- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws *another arc using the arc style* properties. Its padding values are interpreted relative to the background arc. + +**Specific actions:** + +``lvgl.spinner.update`` :ref:`action ` updates the widget styles and properties for the *indicator* part (anything other than the properties that apply commonly to all objects), just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - spinner: + align: center + spin_time: 2s + arc_length: 60deg + id: spinner_id + indicator: + arc_color: 0xd4d4d4 + + # Example action: + on_...: + then: + - lvgl.spinner.update: + id: spinner_id + arc_color: 0x31de70 + +.. _lvgl-wgt-obj: + +``obj`` +******* + +The Base Object can be directly used as a simple, empty widget. It is nothing more than a (rounded) rectangle. + +.. figure:: /components/images/lvgl_baseobj.png + :align: center + +You can use it as a parent background shape for other objects. It catches touches! + +**Specific options:** + +- Style options from :ref:`lvgl-styling`. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - obj: + x: 10 + y: 10 + width: 220 + height: 300 + widgets: + - ... + .. _lvgl-wgt-msg: ``msgboxes`` @@ -1165,276 +1380,6 @@ The configured message boxes are hidden by default. One can show them with ``lvg You can create your own more complex dialogs with a full-screen sized, half-opaque ``obj`` with any child widgets on it, and the ``hidden`` flag set to ``true`` by default. For non-modal dialogs, simply set the ``clickable`` flag to ``false`` on it. - -.. _lvgl-wgt-rol: - -``roller`` -********** - -Roller allows you to simply select one option from a list by scrolling. - -.. figure:: /components/images/lvgl_roller.png - :align: center - -**Specific options:** - -- **options** (*Required*, list): The list of available options in the roller. -- **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. -- **visible_rows** TODO -- **selected** (*Optional*, list): Settings for the selected *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-wgt-lbl` text style properties to change the appearance of the text in the selected area. -- **selected_index** (*Optional*, int8): The index of the item you wish to be selected. -- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-wgt-lbl` style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. - -**Specific actions:** - -``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - roller: - align: CENTER - id: roller_id - options: - - Violin - - Piano - - Bassoon - - Chello - - Drums - - # Example action: - on_...: - then: - - lvgl.roller.update: - id: roller_id - selected_index: 5 - -The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. - -.. _lvgl-wgt-sli: - -``slider`` -********** - -The Slider widget looks like a bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider can be vertical or horizontal. - -.. figure:: /components/images/lvgl_slider.png - :align: center - -**Specific options:** - -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. -- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. -- **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. A rectangle (or circle) drawn at the current value. Also uses all the typical background properties to describe the knob. By default, the knob is square (with an optional corner radius) with side length equal to the smaller side of the slider. The knob can be made larger with the padding values. Padding values can be asymmetric too. -- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The indicator that shows the current state of the slider. Also uses all the typical background style properties. -- **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. -- any :ref:`Styling ` and state-based option for the background of the slider. Uses all the typical background style properties. Padding makes the indicator smaller in the respective direction. - -Normally, the slider can be adjusted either by dragging the knob, or by clicking on the slider bar. In the latter case the knob moves to the point clicked and slider value changes accordingly. In some cases it is desirable to set the slider to react on dragging the knob only. This feature is enabled by enabling the ``adv_hittest`` flag. - -**Specific actions:** - -``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - -**Specific triggers:** - -``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the value in ``x``. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - slider: - x: 10 - y: 10 - width: 220 - id: slider_id - value: 75 - min_value: 0 - max_value: 100 - - # Example action: - on_...: - then: - - lvgl.slider.update: - id: slider_id - knob: - bg_color: 0x00FF00 - value: 55 - - # Example trigger: - - slider: - ... - on_value: - - logger.log: - format: "Slider value is: %.0f" - args: [ 'x' ] - -.. note:: - - The ``on_value`` trigger is sent while the slider is being dragged or changed with keys. The event is sent *continuously* while the slider is being dragged, this can affect performance and have negative effects on the actions to be performed. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. - -The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. - -See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider to control entities in Home Assistant. - -.. _lvgl-wgt-spi: - -``spinner`` -*********** - -The Spinner widget is a spinning arc over a ring. - -.. figure:: /components/images/lvgl_spinner.png - :align: center - -**Specific options:** - -- **spin_time** (*Required*, :ref:`Time `): Duration of one cycle of the spin. -- **arc_length** (*Required*, 0-360): Length of the spinning arc in degrees. -- **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. -- **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. -- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws *another arc using the arc style* properties. Its padding values are interpreted relative to the background arc. - -**Specific actions:** - -``lvgl.spinner.update`` :ref:`action ` updates the widget styles and properties for the *indicator* part (anything other than the properties that apply commonly to all objects), just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - spinner: - align: center - spin_time: 2s - arc_length: 60deg - id: spinner_id - indicator: - arc_color: 0xd4d4d4 - - # Example action: - on_...: - then: - - lvgl.spinner.update: - id: spinner_id - arc_color: 0x31de70 - -.. _lvgl-wgt-swi: - -``switch`` -********** - -The Switch looks like a little slider and can be used to turn something on and off. - -.. figure:: /components/images/lvgl_switch.png - :align: center - -**Specific options:** - -- **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. -- **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. -- Style options from :ref:`lvgl-styling`. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - switch: - x: 10 - y: 10 - id: switch_id - -The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. - -See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local component. - -.. _lvgl-wgt-tbl: - -``table`` -********* - -Tables, as usual, are built from rows, columns, and cells containing texts. - -The Table widget is very lightweight because only the texts are stored. No real objects are created for cells but they are just drawn on the fly. - -**Specific options:** - -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **items** (*Optional*, list): Settings for the items *part* -- Style options from :ref:`lvgl-styling`. - - -**Example:** - -.. code-block:: yaml - - # Example widget: - - - -.. _lvgl-wgt-txt: - -``textarea`` -************ - -The Text Area is a base widget with a label and a cursor on it. Texts or characters can be added to it. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. - -One line mode and password modes are supported. - -**Specific options:** - -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. -- **scrollbar** (*Optional*, list): Settings for the scrollbar *part* -- **selected** (*Optional*, list): Settings for the selected *part* -- **cursor** (*Optional*, list): Settings for the cursor *part* -- **textarea_placeholder** (*Optional*, list): Settings for the textarea_placeholder *part* -- Style options from :ref:`lvgl-styling`. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - - - -.. _lvgl-wgt-obj: - -``obj`` -******* - -The Base Object can be directly used as a simple, empty widget. It is nothing more than a (rounded) rectangle. - -.. figure:: /components/images/lvgl_baseobj.png - :align: center - -You can use it as a parent background shape for other objects. It catches touches! - -**Specific options:** - -- Style options from :ref:`lvgl-styling`. - - -**Example:** - -.. code-block:: yaml - - # Example widget: - - obj: - x: 10 - y: 10 - width: 220 - height: 300 - widgets: - - ... - Actions ------- From 55b3ab247df242ca5b111619c17e6df639032ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 12 Mar 2024 13:35:27 +0100 Subject: [PATCH 242/350] animimg --- components/lvgl.rst | 54 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c397d0c1d..7e9853714 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1145,7 +1145,7 @@ Currently ``RGB565`` type images are supported, with transparency using the opti **Specific actions:** -``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. **Example:** @@ -1166,6 +1166,58 @@ Currently ``RGB565`` type images are supported, with transparency using the opti id: img_id src: dog_image + +.. _lvgl-wgt-aim: + +``animimg`` +*********** + +The animation image is similar to the normal ``img`` object. The main difference is that instead of one source image, you set an array of multiple source images. You can also specify a duration and a repeat count. + +**Specific options:** + +- **src** (**Required**, list of :ref:`image `): A list of IDs of existing image configurations to be loaded as frames of the animation. +- **auto_start** (*Optional*, boolean): Start the animation playback automatically. Defaults to ``true``. +- **repeat_count** (*Optional*, int16 or *forever*): How many times to repeat the playback. Defaults to ``forever``. +- **duration** (*Required*, :ref:`Time `): Duration of one image frame. +- Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. + +Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. + +**Specific actions:** + +``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. + +``lvgl.animimg.update`` :ref:`action ` updates ``repeat_count`` and ``duration``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +.. note:: + + ``repeat_count`` and ``duration`` updates take place only at the next start of the animation. For example to stop an animation lasting ``forever``, just call the ``lvgl.animimg.update`` action with ``duration: 0ms``, and then call ``lvgl.animimg.start`` to activate the new animation parameter. + + ``src`` and ``auto_start`` cannot be updated at runtime. + + If the widget is configured with ``auto_start: true``, its initial dimensions and position will not be valid to be used with relative alignment (don't use ``align_to`` to align other widgets relative to this widget). + + +**Example:** + +.. code-block:: yaml + + # Example widget: + - animimg: + align: CENTER + id: anim_id + src: [ cat_image, dog_image ] + duration: 300ms + + # Example actions: + on_...: + then: + - lvgl.animimg.update: + id: anim_id + duration: 0ms + - lvgl.animimg.start: anim_id + .. _lvgl-wgt-lin: ``line`` From 8d9173b0ba3359730f9a7a9f807eb7d872626867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 12 Mar 2024 14:09:26 +0100 Subject: [PATCH 243/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7e9853714..020adf5db 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1172,7 +1172,7 @@ Currently ``RGB565`` type images are supported, with transparency using the opti ``animimg`` *********** -The animation image is similar to the normal ``img`` object. The main difference is that instead of one source image, you set an array of multiple source images. You can also specify a duration and a repeat count. +The animation image is similar to the normal ``img`` object. The main difference is that instead of one source image, you set a list of multiple source images. You can also specify a duration and a repeat count. **Specific options:** From 2974d5f8cdc9ad5124c3021d219f02e62f002dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 12 Mar 2024 14:19:07 +0100 Subject: [PATCH 244/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 020adf5db..9e3fc9941 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1176,7 +1176,7 @@ The animation image is similar to the normal ``img`` object. The main difference **Specific options:** -- **src** (**Required**, list of :ref:`image `): A list of IDs of existing image configurations to be loaded as frames of the animation. +- **src** (**Required**, list of :ref:`images `): A list of IDs of existing image configurations to be loaded as frames of the animation. - **auto_start** (*Optional*, boolean): Start the animation playback automatically. Defaults to ``true``. - **repeat_count** (*Optional*, int16 or *forever*): How many times to repeat the playback. Defaults to ``forever``. - **duration** (*Required*, :ref:`Time `): Duration of one image frame. From 4af4fa98acd82fcc13caaa420bf55f605a818b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 12 Mar 2024 14:49:31 +0100 Subject: [PATCH 245/350] Update lvgl.rst --- components/lvgl.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9e3fc9941..2cb69baf8 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -68,15 +68,15 @@ Configuration variables: - **displays** (**Required**, list): A list of displays where to render this entire LVGL configuration: - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. - **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. Can be omitted if there's at least a rotary encoder configured. - - **touchscreen_id** (*Required*, :ref:`config-id`): ID of a touchscreen configuration- - - **long_press_time** (*Optional*, ms): Delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. - - **long_press_repeat_time** (*Optional*, ms): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. + - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration- + - **long_press_time** (*Optional*, :ref:`Time `): Delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. - **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. Can be omitted if there's at least a touchscreen configured. - - **sensor:** (*Required*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. + - **sensor:** (**Required**, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See the :ref:`common properties ` of the widgets for more information on groups. - - **long_press_time** (*Optional*, ms): Delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. - - **long_press_repeat_time** (*Optional*, ms): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. + - **long_press_time** (*Optional*, :ref:`Time `): Delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. - **color_depth** (*Optional*, enum): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to ``1s``. @@ -762,7 +762,7 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( **Specific options:** -- **options** (*Required*, list): The list of available options in the drop-down. +- **options** (**Required**, list): The list of available options in the drop-down. - **dir** (*Optional*, enum): Where the list part of the dropdown gets created relative to the button part. ``LEFT``, ``RIGHT``, ``BOTTOM``, ``TOP``, defaults to ``BOTTOM``. - **selected_index** (*Optional*, int8): The index of the item you wish to be selected. - **symbol** (*Optional*, enum): A symbol (typically an chevron) is shown in dropdown list. If ``dir`` of the drop-down list is ``LEFT`` the symbol will be shown on the left, otherwise on the right. Choose a different :ref:`symbol ` from the built-in ones or from your own customized font. @@ -814,7 +814,7 @@ Roller allows you to simply select one option from a list by scrolling. **Specific options:** -- **options** (*Required*, list): The list of available options in the roller. +- **options** (**Required**, list): The list of available options in the roller. - **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. - **visible_rows** TODO - **selected** (*Optional*, list): Settings for the selected *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-wgt-lbl` text style properties to change the appearance of the text in the selected area. @@ -866,7 +866,7 @@ Not only the end, but also the start value of the bar can be set, which changes **Specific options:** -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (**Required**, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. @@ -902,7 +902,7 @@ The Slider widget looks like a bar supplemented with a knob. The knob can be dra **Specific options:** -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (**Required**, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. A rectangle (or circle) drawn at the current value. Also uses all the typical background properties to describe the knob. By default, the knob is square (with an optional corner radius) with side length equal to the smaller side of the slider. The knob can be made larger with the padding values. Padding values can be asymmetric too. @@ -971,7 +971,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator **Specific options:** -- **value** (*Required*, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (**Required**, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). Defaults to ``135``. @@ -1179,7 +1179,7 @@ The animation image is similar to the normal ``img`` object. The main difference - **src** (**Required**, list of :ref:`images `): A list of IDs of existing image configurations to be loaded as frames of the animation. - **auto_start** (*Optional*, boolean): Start the animation playback automatically. Defaults to ``true``. - **repeat_count** (*Optional*, int16 or *forever*): How many times to repeat the playback. Defaults to ``forever``. -- **duration** (*Required*, :ref:`Time `): Duration of one image frame. +- **duration** (**Required**, :ref:`Time `): Duration of one image frame. - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. @@ -1230,7 +1230,7 @@ The Line widget is capable of drawing straight lines between a set of points. **Specific options:** -- **points** (*Required*, list): A list of ``x, y`` integer pairs for point coordinates (origin from top left of parent) +- **points** (**Required**, list): A list of ``x, y`` integer pairs for point coordinates (origin from top left of parent) - **line_width** (*Optional*, int16): Set the width of the line in pixels. - **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). - **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). @@ -1317,8 +1317,8 @@ The Spinner widget is a spinning arc over a ring. **Specific options:** -- **spin_time** (*Required*, :ref:`Time `): Duration of one cycle of the spin. -- **arc_length** (*Required*, 0-360): Length of the spinning arc in degrees. +- **spin_time** (**Required**, :ref:`Time `): Duration of one cycle of the spin. +- **arc_length** (**Required**, 0-360): Length of the spinning arc in degrees. - **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. From 3fa979076e907e230431340003facaf528161797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 13 Mar 2024 16:38:59 +0100 Subject: [PATCH 246/350] Update lvgl.rst --- components/lvgl.rst | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2cb69baf8..b3f5711e6 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -16,7 +16,7 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. -TODO !! Display requirement/recommendation/spec, monochrome supported? +The display itself should have ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should be configured with an :ref:`config-id` which will be referenced in the main LGVL component configuration. For interactivity, a :ref:`Touchscreen ` (capacitive highly prefered) or a :doc:`/components/sensor/rotary_encoder` can be used. @@ -27,12 +27,12 @@ Basics In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` to see the full list of available LVGL widgets in ESPHome. -Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent object. There is always one active page on a display. - Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. The child object moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within their parent's bounding area. In other words, the parts of the children outside the parent are clipped. -Widgets integrate in ESPHome also as components: +Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent object. There is always one active page on a display. + +Some widgets integrate in ESPHome also as components: +-------------+-------------------------------+ | LVGL Widget | ESPHome component | @@ -52,7 +52,7 @@ Widgets integrate in ESPHome also as components: | LED | Light | +-------------+-------------------------------+ -These are useful to perform :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`lvgl-seealso` section at the bottom of this document. +These are useful to make :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`lvgl-seealso` section at the bottom of this document. Main Component -------------- @@ -61,7 +61,9 @@ Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome thi At the highest level of the LVGL object hierarchy is the display which represents the driver for a display device (physical display). A display can have one or more pages associated with it. Each page contains a hierarchy of objects for graphical widgets representing a layout that covers the entire display. -The widget is at the top level, and it allows main styling. It also has sub-parts, which can be styled separately. Usually styles are inherited. The widget and the parts have states, and the different styling can be set for different states. +The widget is at the next level, and it allows main styling. It can have sub-parts, which may be styled separately. Usually styles are inherited, but this depends on widget specifics or functionality. The widget and the parts have states, and the different styling can be set for different states. + +By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. Configuration variables: @@ -129,10 +131,6 @@ Configuration variables: See :ref:`lvgl-cook-navigator` in the Cookbook for an example how to easily implement a page navigation bar at the bottom of the screen. -.. note:: - - By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. - .. _lvgl-theme: Theming and Styling @@ -212,7 +210,6 @@ In the example below, you have an ``arc`` with some styles set here. Note how yo focused: arc_color: 0x808080 - So the inheritance happens like this: state based styles override the locally specified styles, which override the style definitions, which override the theme, which overrides the top level styles. See :ref:`lvgl-cook-theme` in the Cookbook for an example how to easily implement a gradient style for your widgets. @@ -1238,8 +1235,6 @@ The Line widget is capable of drawing straight lines between a set of points. - **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. - Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. -TODO invert_y ??? - By default, the Line widget width and height dimensions are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts of the line may not be visible. **Example:** From 1a6ae2e2fccaf75bfda047061367fd4363c0dfcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 13 Mar 2024 17:00:02 +0100 Subject: [PATCH 247/350] Update lvgl.rst --- components/lvgl.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b3f5711e6..158578472 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -70,21 +70,21 @@ Configuration variables: - **displays** (**Required**, list): A list of displays where to render this entire LVGL configuration: - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. - **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. Can be omitted if there's at least a rotary encoder configured. - - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration- - - **long_press_time** (*Optional*, :ref:`Time `): Delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. + - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a dsisplay. + - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen above, delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the touchscreen above, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. - **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. Can be omitted if there's at least a touchscreen configured. - **sensor:** (**Required**, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See the :ref:`common properties ` of the widgets for more information on groups. - - **long_press_time** (*Optional*, :ref:`Time `): Delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): Repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. + - **long_press_time** (*Optional*, :ref:`Time `): For the encoder above, delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the encoder above, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. - **color_depth** (*Optional*, enum): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. - **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. -- **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen. Defaults to ``1s``. +- **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessarry. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. -- **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, will default to ``big_endian``. -- **default_font** (*Optional*, enum): The C array name of the :ref:`font ` used by default to render the text or symbols. Defaults to ``montserrat_14`` if not specified. +- **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, defaults to ``big_endian``. +- **default_font** (*Optional*, enum): The C array name of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. From 92d42d3c33c844cb41d0b06609df30f7ea8ca7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 13 Mar 2024 17:02:58 +0100 Subject: [PATCH 248/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 158578472..2de5bf9a3 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -99,7 +99,7 @@ Configuration variables: - ``COLUMN_WRAP_REVERSE`` to place the children in a column with wrapping but in reversed order - All other options from :ref:`lvgl-styling` to be commonly apply to the widgets directly. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. Not possible if you configure ``pages``. -- **pages** (*Optional*, list): A list of page IDs, where each page acts as a parent for widgets placed on it. Only of no ``widgets`` are configured at this level. Options for each page: +- **pages** (*Optional*, list): A list of page IDs, where each page acts as a parent for widgets placed on it. Only if no ``widgets`` are configured at this level! Options for each page: - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. - **layout** (*Optional*, string): Layout to be applied to this page. Same option as above. - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. From a1e231189e87f22c8a03be3c309186645716e800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 15 Mar 2024 17:18:50 +0100 Subject: [PATCH 249/350] Update lvgl.rst --- components/lvgl.rst | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2de5bf9a3..ae5ffff55 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -34,23 +34,27 @@ Pages in ESPHome are implemented as LVGL screens, which are special objects whic Some widgets integrate in ESPHome also as components: -+-------------+-------------------------------+ -| LVGL Widget | ESPHome component | -+=============+===============================+ -| Checkbox | Binary Sensor, Switch | -+-------------+-------------------------------+ -| Button | Binary Sensor, Button, Switch | -+-------------+-------------------------------+ -| Slider | Sensor, Number | -+-------------+-------------------------------+ -| Arc | Sensor, Number | -+-------------+-------------------------------+ -| Dropdown | Select | -+-------------+-------------------------------+ -| Roller | Select | -+-------------+-------------------------------+ -| LED | Light | -+-------------+-------------------------------+ +.. list-table Widgets as Components + :widths: 60 250 + :header-rows: 1 + + * - LVGL Widget + - ESPHome component + * - Checkbox + - Binary Sensor, Switch + * - Button + - Binary Sensor, Button, Switch + * - Slider + - Sensor, Number + * - Arc + - Sensor, Number + * - Dropdown + - Select + * - Roller + - Select + * - LED + - Light + These are useful to make :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`lvgl-seealso` section at the bottom of this document. From 8b8f703e2576b6b5c2f778bb7b9ab9a6f813150c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 15 Mar 2024 17:25:35 +0100 Subject: [PATCH 250/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ae5ffff55..4a052c7b2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -34,7 +34,7 @@ Pages in ESPHome are implemented as LVGL screens, which are special objects whic Some widgets integrate in ESPHome also as components: -.. list-table Widgets as Components +.. list-table :widths: 60 250 :header-rows: 1 From 4629a7f10c43e72a330d02995d64a025638d5ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 15 Mar 2024 18:21:23 +0100 Subject: [PATCH 251/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4a052c7b2..f10490ddd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -35,8 +35,8 @@ Pages in ESPHome are implemented as LVGL screens, which are special objects whic Some widgets integrate in ESPHome also as components: .. list-table - :widths: 60 250 :header-rows: 1 + :widths: 1 2 * - LVGL Widget - ESPHome component From 83578beb79857f5293d95ffee81c15c6395dd777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 15 Mar 2024 18:36:54 +0100 Subject: [PATCH 252/350] Update lvgl.rst --- components/lvgl.rst | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f10490ddd..0be12cd43 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -34,26 +34,33 @@ Pages in ESPHome are implemented as LVGL screens, which are special objects whic Some widgets integrate in ESPHome also as components: -.. list-table - :header-rows: 1 - :widths: 1 2 +.. list-table:: + :header-rows: 1 + :widths: 1 3 - * - LVGL Widget - - ESPHome component - * - Checkbox - - Binary Sensor, Switch - * - Button - - Binary Sensor, Button, Switch - * - Slider - - Sensor, Number - * - Arc - - Sensor, Number - * - Dropdown - - Select - * - Roller - - Select - * - LED - - Light + * - LVGL Widget + - ESPHome component + + * - Checkbox + - Binary Sensor, Switch + + * - Button + - Binary Sensor, Button, Switch + + * - Slider + - Sensor, Number + + * - Arc + - Sensor, Number + + * - Dropdown + - Select + + * - Roller + - Select + + * - LED + - Light These are useful to make :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`lvgl-seealso` section at the bottom of this document. From 7010067a21269f86d7b8f235edaf42e0120a11c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 15 Mar 2024 18:43:24 +0100 Subject: [PATCH 253/350] Update lvgl.rst --- components/lvgl.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 0be12cd43..2024602f8 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -42,25 +42,25 @@ Some widgets integrate in ESPHome also as components: - ESPHome component * - Checkbox - - Binary Sensor, Switch + - :doc:`/components/binary_sensor/lvgl`, :doc:`/components/switch/lvgl` * - Button - - Binary Sensor, Button, Switch + - :doc:`/components/binary_sensor/lvgl`, Button, :doc:`/components/switch/lvgl` * - Slider - - Sensor, Number + - :doc:`/components/number/lvgl` * - Arc - - Sensor, Number + - :doc:`/components/number/lvgl` * - Dropdown - - Select + - :doc:`/components/select/lvgl` * - Roller - - Select + - :doc:`/components/select/lvgl` * - LED - - Light + - :doc:`/components/light/lvgl` These are useful to make :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`lvgl-seealso` section at the bottom of this document. From fe68ec68b00f6c5ca8819fee513b1e28fb3dc069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 15 Mar 2024 18:52:16 +0100 Subject: [PATCH 254/350] Update lvgl.rst --- components/lvgl.rst | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2024602f8..d374817ca 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -36,16 +36,19 @@ Some widgets integrate in ESPHome also as components: .. list-table:: :header-rows: 1 - :widths: 1 3 + :widths: 2 3 * - LVGL Widget - ESPHome component - * - Checkbox + * - Button - :doc:`/components/binary_sensor/lvgl`, :doc:`/components/switch/lvgl` - * - Button - - :doc:`/components/binary_sensor/lvgl`, Button, :doc:`/components/switch/lvgl` + * - Switch + - :doc:`/components/switch/lvgl` + + * - Checkbox + - :doc:`/components/switch/lvgl` * - Slider - :doc:`/components/number/lvgl` @@ -53,6 +56,9 @@ Some widgets integrate in ESPHome also as components: * - Arc - :doc:`/components/number/lvgl` + * - Spinbox + - :doc:`/components/number/lvgl` + * - Dropdown - :doc:`/components/select/lvgl` @@ -63,7 +69,7 @@ Some widgets integrate in ESPHome also as components: - :doc:`/components/light/lvgl` -These are useful to make :ref:`automations ` triggered by actions performed at the screen. Check out the :ref:`lvgl-seealso` section at the bottom of this document. +These are useful to make :ref:`automations ` triggered by actions performed at the screen. Main Component -------------- From 577c77264785ca386d0e449c21154a830005bbb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 15 Mar 2024 18:55:38 +0100 Subject: [PATCH 255/350] Update lvgl.rst --- components/lvgl.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d374817ca..982ca3cab 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -41,31 +41,31 @@ Some widgets integrate in ESPHome also as components: * - LVGL Widget - ESPHome component - * - Button + * - ``btn`` - :doc:`/components/binary_sensor/lvgl`, :doc:`/components/switch/lvgl` - * - Switch + * - ``switch`` - :doc:`/components/switch/lvgl` - * - Checkbox + * - ``checkbox`` - :doc:`/components/switch/lvgl` - * - Slider + * - ``slider`` - :doc:`/components/number/lvgl` - * - Arc + * - ``arc`` - :doc:`/components/number/lvgl` - * - Spinbox + * - ``spinbox`` - :doc:`/components/number/lvgl` - * - Dropdown + * - ``dropdown`` - :doc:`/components/select/lvgl` - * - Roller + * - ``roller`` - :doc:`/components/select/lvgl` - * - LED + * - ``led`` - :doc:`/components/light/lvgl` From 40397ea104f9595546eb983b152f2dbf335763bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 15 Mar 2024 19:01:44 +0100 Subject: [PATCH 256/350] Update lvgl.rst --- components/lvgl.rst | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 982ca3cab..4a45d958b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -42,27 +42,15 @@ Some widgets integrate in ESPHome also as components: - ESPHome component * - ``btn`` - - :doc:`/components/binary_sensor/lvgl`, :doc:`/components/switch/lvgl` + - :doc:`Binary Sensor `, :doc:`/components/switch/lvgl` - * - ``switch`` + * - ``switch``, ``checkbox`` - :doc:`/components/switch/lvgl` - * - ``checkbox`` - - :doc:`/components/switch/lvgl` - - * - ``slider`` + * - ``slider``, ``arc``, ``spinbox`` - :doc:`/components/number/lvgl` - * - ``arc`` - - :doc:`/components/number/lvgl` - - * - ``spinbox`` - - :doc:`/components/number/lvgl` - - * - ``dropdown`` - - :doc:`/components/select/lvgl` - - * - ``roller`` + * - ``dropdown``, ``roller`` - :doc:`/components/select/lvgl` * - ``led`` From b27f1dec8a96c49394f8ff752b8c183668536359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 15 Mar 2024 19:06:08 +0100 Subject: [PATCH 257/350] Update lvgl.rst --- components/lvgl.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4a45d958b..83cf79808 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -36,25 +36,25 @@ Some widgets integrate in ESPHome also as components: .. list-table:: :header-rows: 1 - :widths: 2 3 + :widths: 1 1 * - LVGL Widget - ESPHome component * - ``btn`` - - :doc:`Binary Sensor `, :doc:`/components/switch/lvgl` + - :doc:`Binary Sensor `, :doc:`Switch ` * - ``switch``, ``checkbox`` - - :doc:`/components/switch/lvgl` + - :doc:`Switch ` * - ``slider``, ``arc``, ``spinbox`` - - :doc:`/components/number/lvgl` + - :doc:`Number ` * - ``dropdown``, ``roller`` - - :doc:`/components/select/lvgl` + - :doc:`Select ` * - ``led`` - - :doc:`/components/light/lvgl` + - :doc:`Light ` These are useful to make :ref:`automations ` triggered by actions performed at the screen. From 33aad90aace77671f5ec4f3ab6b1a622d00d978d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 18 Mar 2024 14:26:18 +0100 Subject: [PATCH 258/350] spinbox and others --- components/binary_sensor/lvgl.rst | 4 --- components/lvgl.rst | 53 +++++++++++++++++++++++++++---- components/number/lvgl.rst | 10 +++--- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 7c0ace787..77eee53cc 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -21,10 +21,6 @@ Configuration options: - **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the binary sensor. - All other options from :ref:`Binary Sensor `. -.. note:: - - ``publish_initial_state`` ?? - Example: .. code-block:: yaml diff --git a/components/lvgl.rst b/components/lvgl.rst index 83cf79808..5983b51fb 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -240,7 +240,6 @@ The outline is drawn outside the bounding box. You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each object. Some widgets allow for more complex styling, effectively changing the appearance of their parts. -- **anim_time** TODO !! - **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background of the widget. - **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to make the background gradually fade to. - **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. @@ -818,10 +817,11 @@ Roller allows you to simply select one option from a list by scrolling. - **options** (**Required**, list): The list of available options in the roller. - **mode** (*Optional*, enum): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. -- **visible_rows** TODO +- **visible_row_count** (*Optional*, int8): The number of visible rows. - **selected** (*Optional*, list): Settings for the selected *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-wgt-lbl` text style properties to change the appearance of the text in the selected area. - **selected_index** (*Optional*, int8): The index of the item you wish to be selected. -- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-wgt-lbl` style properties. ``text_line_space`` adjusts the space between the options. When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. +- **anim_time** (*Optional*, :ref:`Time `): When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. +- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-wgt-lbl` style properties. ``text_line_space`` adjusts the space between the options. **Specific actions:** @@ -868,12 +868,13 @@ Not only the end, but also the start value of the bar can be set, which changes **Specific options:** -- **value** (**Required**, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (**Required**, int8): Actual value of the indicator at start, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize, all the typical background properties. - **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. +- **anim_time** (*Optional*, :ref:`Time `): Sets the animation time if the value is set with ``animated: true``. - Style options from :ref:`lvgl-styling`. The background of the bar and it uses the typical background style properties. Adding padding will make the indicator smaller or larger. **Example:** @@ -904,12 +905,13 @@ The Slider widget looks like a bar supplemented with a knob. The knob can be dra **Specific options:** -- **value** (**Required**, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (**Required**, int8): Actual value of the indicator at start, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. A rectangle (or circle) drawn at the current value. Also uses all the typical background properties to describe the knob. By default, the knob is square (with an optional corner radius) with side length equal to the smaller side of the slider. The knob can be made larger with the padding values. Padding values can be asymmetric too. - **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The indicator that shows the current state of the slider. Also uses all the typical background style properties. - **animated** (*Optional*, boolean): To animate indicator when bar changes value. Defaults to ``true``. +- **anim_time** (*Optional*, :ref:`Time `): Sets the animation time if the value is set with ``animated: true``. - any :ref:`Styling ` and state-based option for the background of the slider. Uses all the typical background style properties. Padding makes the indicator smaller in the respective direction. Normally, the slider can be adjusted either by dragging the knob, or by clicking on the slider bar. In the latter case the knob moves to the point clicked and slider value changes accordingly. In some cases it is desirable to set the slider to react on dragging the knob only. This feature is enabled by enabling the ``adv_hittest`` flag. @@ -973,7 +975,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator **Specific options:** -- **value** (**Required**, int8): Actual value of the indicator, in ``0``-``100`` range. Defaults to ``0``. +- **value** (**Required**, int8): Actual value of the indicator at start, in ``0``-``100`` range. Defaults to ``0``. - **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. - **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. - **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). Defaults to ``135``. @@ -1043,6 +1045,45 @@ The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider (or an arc) to control entities in Home Assistant. + +.. _lvgl-wgt-spb: + +``spinbox`` +*********** + +The Spinbox contains a number (as text) which can be increased or decreased with two buttons or physical keys. + +**Specific options:** + +- **value** (*Optional*, float): Actual value to be shown by the spinbox at start. +- **range_from** (**Required**, float): The maximum value allowded to set the spinbox to. +- **range_to** (**Required**, float): The minimum value allowded to set the spinbox to. +- **step** (*Optional*, int8): ???? sets which digits to change on increment/decrement. Only multiples of ten can be set, and not for example 3. +- **digits** (*Optional*, int8): The number of digits excluding the decimal separator and the sign. +- **decimal_places** (*Optional*, int8): The number of digits after the decimal point. If ``0``, no decimal point is displayed. +- **rollover** (*Optional*, boolean): While increasing or decreasing the value, if either the minimum or maximum value is reached with this option enabled, the value will change to the other limit. If disabled, the value will remain at the minimum or maximum value. Defaults to ``false``. +- **anim_time** (*Optional*, :ref:`Time `): Sets the cursor's blink time. + +**Specific actions:** + +``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the value in ``x``. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - spinbox: + x: 10 + y: 10 + + +The ``spinbox`` can be also integrated as :doc:`/components/number/lvgl`. + .. _lvgl-wgt-mtr: ``meter`` diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index e1c3f9492..014a1f5e1 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -10,27 +10,24 @@ LVGL Number The ``lvgl`` number platform creates a number component from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar` and :ref:`lvgl-wgt-sli`. A single number supports -a single widget, thus you need to choose among which one's state you want to use, options are mutually exclusive. - +Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar`, :ref:`lvgl-wgt-sli` and :ref:`lvgl-wgt-spb` A single number supports a single widget, thus you need to choose among which one's state you want to use, options are mutually exclusive. Configuration options: ---------------------- - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the number. -- **animated** (*Optional*, boolean): Wether to set the value of the widget with an animation. Defaults to ``true``. - **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the number. +- **animated** (*Optional*, boolean): Wether to set the value of the widget with an animation (if supported by the widget). Defaults to ``true``. - All other options from :ref:`Number `. - Example: .. code-block:: yaml number: - platform: lvgl - slider: slider_id + widget: slider_id name: LVGL Slider @@ -40,6 +37,7 @@ See Also - :ref:`Arc widget ` - :ref:`Bar widget ` - :ref:`Slider widget ` +- :ref:`Spinbox widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/select/lvgl` From ec374cc924f95fe0b961c9e37fe27395e0f657b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 18 Mar 2024 14:32:13 +0100 Subject: [PATCH 259/350] animimg updates --- components/lvgl.rst | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 5983b51fb..a29684752 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1220,7 +1220,7 @@ The animation image is similar to the normal ``img`` object. The main difference **Specific options:** - **src** (**Required**, list of :ref:`images `): A list of IDs of existing image configurations to be loaded as frames of the animation. -- **auto_start** (*Optional*, boolean): Start the animation playback automatically. Defaults to ``true``. +- **auto_start** (*Optional*, boolean): Start the animation playback automatically at boot and when updating the widget. Defaults to ``true``. - **repeat_count** (*Optional*, int16 or *forever*): How many times to repeat the playback. Defaults to ``forever``. - **duration** (**Required**, :ref:`Time `): Duration of one image frame. - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. @@ -1231,16 +1231,9 @@ Currently ``RGB565`` type images are supported, with transparency using the opti ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. -``lvgl.animimg.update`` :ref:`action ` updates ``repeat_count`` and ``duration``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - -.. note:: - - ``repeat_count`` and ``duration`` updates take place only at the next start of the animation. For example to stop an animation lasting ``forever``, just call the ``lvgl.animimg.update`` action with ``duration: 0ms``, and then call ``lvgl.animimg.start`` to activate the new animation parameter. - - ``src`` and ``auto_start`` cannot be updated at runtime. - - If the widget is configured with ``auto_start: true``, its initial dimensions and position will not be valid to be used with relative alignment (don't use ``align_to`` to align other widgets relative to this widget). +``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. +``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. **Example:** @@ -1258,8 +1251,8 @@ Currently ``RGB565`` type images are supported, with transparency using the opti then: - lvgl.animimg.update: id: anim_id - duration: 0ms - - lvgl.animimg.start: anim_id + repeat_count: 100 + duration: 200ms .. _lvgl-wgt-lin: From 15c684769855a505e743aef1d9cf12c5a8ff3219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 18 Mar 2024 14:44:22 +0100 Subject: [PATCH 260/350] animimg --- components/images/lvgl_animimg.gif | Bin 0 -> 483 bytes components/lvgl.rst | 9 ++++++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 components/images/lvgl_animimg.gif diff --git a/components/images/lvgl_animimg.gif b/components/images/lvgl_animimg.gif new file mode 100644 index 0000000000000000000000000000000000000000..a9ca99b7f8885985104abd11e6bed7ceab3a5ce0 GIT binary patch literal 483 zcmZ?wbhEHbv|+Ge_`m=KivPL&TtkAL9RpmA^bD98fx?PESs14=Ff! zdZsnyk8QB;ij%L3_HEF5+Y|lC?}$v%kvEL}S5v>;oV(0#YUs~va&7h(B=;SzZ{4nT z!|g|!guA)=)urE`ORT6+pV_{HedmrA%acD+SN^Qr{L<4hBC4Wl#;hO0M~t&>X^Ak* z@U)IT{qxr5-M7-8R!L_`&+*net^J1EE1X9=agG4*-x`CpRab(hubq4JtkBokUfp{; zi~HuS+js8Xx;U^WdC@!>gyP9Pzxmr9c}#oOx$M=cZSS~`fAYEht@rt_bKn2*a&Wb~ zFs$hik(+!%b@GcEt@t2~tyX_Cx8GU!otv-w_>)aPd;C^kfAeiIR%@d1TEpXTeVgq4 zU%c<_F8qGk`): A list of IDs of existing image configurations to be loaded as frames of the animation. @@ -1243,8 +1246,8 @@ Currently ``RGB565`` type images are supported, with transparency using the opti - animimg: align: CENTER id: anim_id - src: [ cat_image, dog_image ] - duration: 300ms + src: [ batt_lo, batt_mi, batt_hi ] + duration: 150ms # Example actions: on_...: @@ -1252,7 +1255,7 @@ Currently ``RGB565`` type images are supported, with transparency using the opti - lvgl.animimg.update: id: anim_id repeat_count: 100 - duration: 200ms + duration: 75ms .. _lvgl-wgt-lin: From 44042f12bcc15e73e99009c83104c9875f7ffc8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 18 Mar 2024 17:31:34 +0100 Subject: [PATCH 261/350] components --- components/number/lvgl.rst | 2 +- components/select/lvgl.rst | 4 ++-- components/switch/lvgl.rst | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 014a1f5e1..72f882dac 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -10,7 +10,7 @@ LVGL Number The ``lvgl`` number platform creates a number component from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar`, :ref:`lvgl-wgt-sli` and :ref:`lvgl-wgt-spb` A single number supports a single widget, thus you need to choose among which one's state you want to use, options are mutually exclusive. +Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar`, :ref:`lvgl-wgt-sli` and :ref:`lvgl-wgt-spb`. A single number supports a single widget, thus you need to choose among which one's state you want to use. Configuration options: ---------------------- diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 5571c7736..baff5427c 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -11,7 +11,7 @@ The ``lvgl`` switch platform creates a select from a LVGL widget and requires :ref:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-wgt-drp` and :ref:`lvgl-wgt-rol`. A single select supports -a single widget, thus you need to choose among which one's state you want to use, options are mutually exclusive. +a single widget, thus you need to choose among which one's state you want to use. Configuration options: ---------------------- @@ -27,7 +27,7 @@ Example: select: - platform: lvgl - dropdown: dropdown_id + widget: dropdown_id name: LVGL Dropdown See Also diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index dacd8d0fc..17bf232d1 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -10,7 +10,7 @@ LVGL Switch The ``lvgl`` switch platform creates a switch from a LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are :ref:`lvgl-wgt-btn` (with ``checkable`` option enabled), :ref:`lvgl-wgt-swi` and :ref:`lvgl-wgt-chk`. A single switch supports a single widget, thus you need to choose among which one's state you want to use, options are mutually exclusive. +Supported widgets are :ref:`lvgl-wgt-btn` (with ``checkable`` option enabled), :ref:`lvgl-wgt-swi` and :ref:`lvgl-wgt-chk`. A single switch supports a single widget, thus you need to choose among which one's state you want to use. Configuration options: @@ -19,7 +19,7 @@ Configuration options: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the switch. - **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the switch. -- **output_id** (*Optional*, :ref:`config-id`): The ID of a **binary** output to drive in sync with the state of the switch widget. +- **output_id** (*Optional*, :ref:`config-id`): The ID of a **binary** output to drive in sync with the ``checked`` state of the configured widget. - All other options from :ref:`Switch `. Example: From 2b12e2f61933739543894b48424beabc1a44604c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 21 Mar 2024 16:58:04 +0100 Subject: [PATCH 262/350] scrollable flag --- components/lvgl.rst | 64 ++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 75742856b..eaeeded7b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -374,7 +374,7 @@ The properties below are common to all widgets. Similarly to CSS, LVGL also supports ``min_width``, ``max_width``, ``min_height`` and ``max_height``. These are limits preventing an object's size from becoming smaller/larger than these values. They are especially useful if the size is set by percentage or ``size_content``. - **min_width**, **max_width**, **min_height**, **max_height** (*Optional*, int16 or percentage): Sets a minimal/maximal width or a minimal/maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. -- **scrollbar_mode** (*Optional*, string): If an object is outside its parent content area (the size without padding), the parent becomes scrollable. The object can either be scrolled horizontally or vertically in one stroke. Scrollbars can appear depending on the setting: +- **scrollbar_mode** (*Optional*, string): If an object is outside its parent content area (the size without padding), the parent can become scrollable (see the ``scrollable`` :ref:`flag `). The object can either be scrolled horizontally or vertically in one stroke. Scrollbars can appear depending on the setting: - ``"OFF"``: Never show the scrollbars (use the double quotes!). - ``"ON"``: Always show the scrollbars (use the double quotes!). - ``"ACTIVE"``: Show scroll bars while an object is being scrolled. @@ -397,15 +397,15 @@ The properties below are common to all widgets. - **flex_flow** (*Optional*, string): Option for ``FLEX`` layout, similar configuration as at the main component. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn as children of this widget. Same configuration option as at the main component. - **state** (*Optional*, enum): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden within style definitions or locally set. Can be one of: - - **default** (*Optional*, boolean): Normal, released state - - **disabled** (*Optional*, boolean): Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``) - - **pressed** (*Optional*, boolean): Being pressed - - **checked** (*Optional*, boolean): Toggled or checked state - - **scrolled** (*Optional*, boolean): Being scrolled - - **focused** (*Optional*, boolean): Focused via keypad or encoder or clicked via touchpad/mouse - - **focus_key** (*Optional*, boolean): Focused via keypad or encoder but not via touchpad/mouse - - **edited** (*Optional*, boolean): Edit by an encoder - - **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): Custom states + - **default** (*Optional*, boolean): Normal, released state. + - **disabled** (*Optional*, boolean): Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``). + - **pressed** (*Optional*, boolean): Being pressed. + - **checked** (*Optional*, boolean): Toggled or checked state. + - **scrolled** (*Optional*, boolean): Being scrolled. + - **focused** (*Optional*, boolean): Focused via keypad or encoder or clicked via touchpad/mouse. + - **focus_key** (*Optional*, boolean): Focused via keypad or encoder but not via touchpad/mouse. + - **edited** (*Optional*, boolean): Edit by an encoder. + - **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): Custom states. By default, states are all ``false``, and they are templatable. To apply styles to the states, you need to specify them one level above, for example: @@ -429,29 +429,29 @@ See :ref:`lvgl-cook-cover` for a cookbook example how to play with styling and p In addition to visual stilyng, each widget supports some boolean flags to influence the behavior: - **hidden** (*Optional*, boolean): make the widget hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.widget.show`` and ``lvgl.widget.hide``. Defaults to ``false``. -- **checkable** (*Optional*, boolean): toggle checked state when the widget is clicked +- **checkable** (*Optional*, boolean): toggle checked state when the widget is clicked. - **clickable** (*Optional*, boolean): make the widget clickable by input devices. Defaults to ``true``. If ``false``, it will pass the click to the widgets behind it (clicking through). -- **click_focusable** (*Optional*, boolean): add focused state to the widget when clicked -- **scrollable** (*Optional*, boolean): make the widget scrollable -- **scroll_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed -- **scroll_momentum** (*Optional*, boolean): make the widget scroll further when "thrown" -- **scroll_one** (*Optional*, boolean): allow scrolling only one snappable children -- **scroll_chain_hor** (*Optional*, boolean): allow propagating the horizontal scroll to a parent -- **scroll_chain_ver** (*Optional*, boolean): allow propagating the vertical scroll to a parent -- **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor | scroll_chain_ver``) -- **scroll_on_focus** (*Optional*, boolean): automatically scroll widget to make it visible when focused -- **scroll_with_arrow** (*Optional*, boolean): allow scrolling the focused widget with arrow keys -- **snappable** (*Optional*, boolean): if scroll snap is enabled on the parent it can snap to this widget -- **press_lock** (*Optional*, boolean): keep the widget pressed even if the press slid from the widget -- **event_bubble** (*Optional*, boolean): propagate the events to the parent too -- **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent -- **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. E.g. Accounting for rounded corners -- **ignore_layout** (*Optional*, boolean): make the widget positionable by the layouts -- **floating** (*Optional*, boolean): do not scroll the widget when the parent scrolls and ignore layout -- **overflow_visible** (*Optional*, boolean): do not clip the children's content to the parent's boundary -- **layout_1**, **layout_2** (*Optional*, boolean): custom flags, free to use by layouts -- **widget_1**, **widget_2** (*Optional*, boolean): custom flags, free to use by widget -- **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): custom flags, free to use by user +- **scrollable** (*Optional*, boolean): the widget can become scrollable. Defaults to ``true``. +- **scroll_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed. +- **scroll_momentum** (*Optional*, boolean): make the widget scroll further when "thrown". +- **scroll_one** (*Optional*, boolean): allow scrolling only one snappable children. +- **scroll_chain_hor** (*Optional*, boolean): allow propagating the horizontal scroll to a parent. +- **scroll_chain_ver** (*Optional*, boolean): allow propagating the vertical scroll to a parent. +- **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor | scroll_chain_ver``). +- **scroll_on_focus** (*Optional*, boolean): automatically scroll widget to make it visible when focused. +- **scroll_with_arrow** (*Optional*, boolean): allow scrolling the focused widget with arrow keys. +- **click_focusable** (*Optional*, boolean): add focused state to the widget when clicked. +- **snappable** (*Optional*, boolean): if scroll snap is enabled on the parent it can snap to this widget. +- **press_lock** (*Optional*, boolean): keep the widget pressed even if the press slid from the widget. +- **event_bubble** (*Optional*, boolean): propagate the events to the parent too. +- **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent. +- **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. E.g. Accounting for rounded corners. +- **ignore_layout** (*Optional*, boolean): make the widget positionable by the layouts. +- **floating** (*Optional*, boolean): do not scroll the widget when the parent scrolls and ignore layout. +- **overflow_visible** (*Optional*, boolean): do not clip the children's content to the parent's boundary. +- **layout_1**, **layout_2** (*Optional*, boolean): custom flags, free to use by layouts. +- **widget_1**, **widget_2** (*Optional*, boolean): custom flags, free to use by widget. +- **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): custom flags, free to use by user. .. _lvgl-wgt-lbl: From 51dbc4d8396cc53f7c3cff6db8982d50cfb26711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 21 Mar 2024 17:02:09 +0100 Subject: [PATCH 263/350] Update lvgl.rst --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index eaeeded7b..0354767cc 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -426,12 +426,12 @@ See :ref:`lvgl-cook-cover` for a cookbook example how to play with styling and p .. _lvgl-objupdflag-act: -In addition to visual stilyng, each widget supports some boolean flags to influence the behavior: +In addition to visual stilyng, each widget supports some boolean **flags** to influence the behavior: - **hidden** (*Optional*, boolean): make the widget hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.widget.show`` and ``lvgl.widget.hide``. Defaults to ``false``. - **checkable** (*Optional*, boolean): toggle checked state when the widget is clicked. - **clickable** (*Optional*, boolean): make the widget clickable by input devices. Defaults to ``true``. If ``false``, it will pass the click to the widgets behind it (clicking through). -- **scrollable** (*Optional*, boolean): the widget can become scrollable. Defaults to ``true``. +- **scrollable** (*Optional*, boolean): the widget can become scrollable. Defaults to ``true`` (also see the ``scrollbar_mode`` property). - **scroll_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed. - **scroll_momentum** (*Optional*, boolean): make the widget scroll further when "thrown". - **scroll_one** (*Optional*, boolean): allow scrolling only one snappable children. From 552953d2a95ec59739d85c82b36fde1f64f9a9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 21 Mar 2024 17:22:59 +0100 Subject: [PATCH 264/350] less objects more widgets --- components/lvgl.rst | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 0354767cc..bde88f42a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -28,9 +28,9 @@ Basics In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` to see the full list of available LVGL widgets in ESPHome. Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. -The child object moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within their parent's bounding area. In other words, the parts of the children outside the parent are clipped. +The child widget moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within their parent's bounding area. In other words, the parts of the children outside the parent are clipped. -Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent object. There is always one active page on a display. +Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent. There is always one active page on a display. Some widgets integrate in ESPHome also as components: @@ -197,7 +197,7 @@ And then you apply these selected styles to two labels, and only change very spe styles: date_style y: +20 -Additionally, you can change the styles based on the state of the widgets or their parts. +Additionally, you can change the styles based on the state of the widgets or their parts. If you want to set a property for all states (e.g. red background color) just set it for the default state, at the root of the widget. If the widget can't find a property for its current state it will fall back to the default state's property. In the example below, you have an ``arc`` with some styles set here. Note how you change the ``arc_color`` of the ``indicator`` part, based on state changes: @@ -217,6 +217,10 @@ In the example below, you have an ``arc`` with some styles set here. Note how yo So the inheritance happens like this: state based styles override the locally specified styles, which override the style definitions, which override the theme, which overrides the top level styles. +The precedence (value) of states is quite intuitive, and it's something the user would expect naturally. E.g. if a widget is focused the user will still want to see if it's pressed, therefore the pressed state has a higher precedence. If the focused state had a higher precedence it would overwrite the pressed color. + +Some properties (e.g. text color) can be inherited from a parent(s) if it's not specified in the widget. + See :ref:`lvgl-cook-theme` in the Cookbook for an example how to easily implement a gradient style for your widgets. .. _lvgl-styling: @@ -224,21 +228,21 @@ See :ref:`lvgl-cook-theme` in the Cookbook for an example how to easily implemen Style properties **************** -LVGL follows CSS's `border-box model `__. An object's *box* is built from the following parts: +LVGL follows CSS's `border-box model `__. A widget's *box* is built from the following parts: .. figure:: /components/images/lvgl_boxmodel.png :align: center - **bounding box**: the width/height of the elements. - **border width**: the width of the border. -- **padding**: space between the sides of the object and its children. +- **padding**: space between the sides of the widget and its children. - **content**: the content area which is the size of the bounding box reduced by the border width and padding. The border is drawn inside the bounding box. Padding sets the space on the inner sides of the border. It means *I don't want my children too close to my sides, so keep this space*. The outline is drawn outside the bounding box. -You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each object. Some widgets allow for more complex styling, effectively changing the appearance of their parts. +You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each of them. Some widgets allow for more complex styling, effectively changing the appearance of their parts. - **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background of the widget. - **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to make the background gradually fade to. @@ -263,7 +267,7 @@ You can adjust the appearance of widgets by changing the foreground, background - ``RIGHT`` - ``INTERNAL`` - **border_width** (*Optional*, int16): Set the width of the border in pixels. -- **radius** (*Optional*, uint16): The radius of the rounded corners of the object. 0 = no radius i.e. square corners; 65535 = pill shaped object (true circle if it has same width and height). +- **radius** (*Optional*, uint16): The radius of the rounded corners of the widget. 0 = no radius i.e. square corners; 65535 = pill shaped widget (true circle if it has same width and height). - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. - **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw an outline around the widget. - **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. @@ -369,15 +373,15 @@ The properties below are common to all widgets. .. note:: - The size settings support a special value: ``size_content``. It means the object's size in the respective direction will be set to the size of its children. Note that only children on the right and bottom sides will be considered and children on the top and left remain cropped. This limitation makes the behavior more predictable. Objects with ``hidden`` or ``floating`` flags will be ignored by the ``size_content`` calculation. + The size settings support a special value: ``size_content``. It means the widget's size in the respective direction will be set to the size of its children. Note that only children on the right and bottom sides will be considered and children on the top and left remain cropped. This limitation makes the behavior more predictable. Widgets with ``hidden`` or ``floating`` flags will be ignored by the ``size_content`` calculation. - Similarly to CSS, LVGL also supports ``min_width``, ``max_width``, ``min_height`` and ``max_height``. These are limits preventing an object's size from becoming smaller/larger than these values. They are especially useful if the size is set by percentage or ``size_content``. + Similarly to CSS, LVGL also supports ``min_width``, ``max_width``, ``min_height`` and ``max_height``. These are limits preventing a widget's size from becoming smaller/larger than these values. They are especially useful if the size is set by percentage or ``size_content``. - **min_width**, **max_width**, **min_height**, **max_height** (*Optional*, int16 or percentage): Sets a minimal/maximal width or a minimal/maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. -- **scrollbar_mode** (*Optional*, string): If an object is outside its parent content area (the size without padding), the parent can become scrollable (see the ``scrollable`` :ref:`flag `). The object can either be scrolled horizontally or vertically in one stroke. Scrollbars can appear depending on the setting: +- **scrollbar_mode** (*Optional*, string): If a child widget is outside its parent content area (the size without padding), the parent can become scrollable (see the ``scrollable`` :ref:`flag `). The widget can either be scrolled horizontally or vertically in one stroke. Scrollbars can appear depending on the setting: - ``"OFF"``: Never show the scrollbars (use the double quotes!). - ``"ON"``: Always show the scrollbars (use the double quotes!). - - ``"ACTIVE"``: Show scroll bars while an object is being scrolled. + - ``"ACTIVE"``: Show scroll bars while a widget is being scrolled. - ``"AUTO"``: Show scroll bars when the content is large enough to be scrolled (default). - **align** (*Optional*, enum): Alignment of the of the widget relative to the parent. A child widget is clipped to its parent boundaries. One of the values *not* starting with ``OUT_`` (see picture below). @@ -1215,7 +1219,7 @@ Currently ``RGB565`` type images are supported, with transparency using the opti ``animimg`` *********** -The animation image is similar to the normal ``img`` object. The main difference is that instead of one source image, you set a list of multiple source images. You can also specify a duration and a repeat count. +The animation image is similar to the normal ``img`` widget. The main difference is that instead of one source image, you set a list of multiple source images. You can also specify a duration and a repeat count. .. figure:: /components/images/lvgl_animimg.gif :align: center @@ -1364,7 +1368,7 @@ The Spinner widget is a spinning arc over a ring. **Specific actions:** -``lvgl.spinner.update`` :ref:`action ` updates the widget styles and properties for the *indicator* part (anything other than the properties that apply commonly to all objects), just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.spinner.update`` :ref:`action ` updates the widget styles and properties for the *indicator* part (anything other than the properties that apply commonly to all widgets), just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1391,12 +1395,12 @@ The Spinner widget is a spinning arc over a ring. ``obj`` ******* -The Base Object can be directly used as a simple, empty widget. It is nothing more than a (rounded) rectangle. +The Base Object is just a simple, empty widget. By default, it's nothing more than a rounded rectangle: .. figure:: /components/images/lvgl_baseobj.png :align: center -You can use it as a parent background shape for other objects. It catches touches! +You can use it as a parent for other widgets, like background shape. By default, it catches touches. **Specific options:** From 910cc0eff328c5ac1e0f7c7519714bc4bc57e127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 21 Mar 2024 19:30:57 +0100 Subject: [PATCH 265/350] Update lvgl.rst --- components/lvgl.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index bde88f42a..f4a50f397 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1753,7 +1753,7 @@ See :ref:`lvgl-cook-idlescreen` example how to implement screen saving with idle See Also -------- -- :doc:`LVGL examples in the Cookbook ` +- :doc:`Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/number/lvgl` @@ -1763,5 +1763,4 @@ See Also - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` - `LVGL 8.3 docs `__ -- `LVGL Online Font Converter `__ - :ghedit:`Edit` From f7e9903faeb4f235e8452c786a7a7302028e52a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 22 Mar 2024 10:05:43 +0100 Subject: [PATCH 266/350] Update lvgl_main_screenshot.png --- components/images/lvgl_main_screenshot.png | Bin 40589 -> 134021 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_main_screenshot.png b/components/images/lvgl_main_screenshot.png index 0729ccd37c89464c77166b7253eb521570c4f366..a8c971a901e5a2623316069fdd7d6615ebd4520d 100644 GIT binary patch literal 134021 zcmV*GKxw~;P)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{03ZNKL_t(|+U%WooTX)X_rLf3 zJf}^cot^DvfMr=0q)A6m5EKh25YX5~O`;NCqed)2^Tw7)F~-DTtcWHmsDLO%X#xwo zu)X&)y|*)`JmoI$AE%!)idvnRA}&zOVATe%J4Txiz=u*4&y~b8BwR zt+_R~=GNSrTXSn}&8@jLx8~N|np<;gZq2Q^HMi#0pU@JO|Firf_nsgl4gV>GJb+aP z(7|C$*oQR(SO&n3CvUkjoV#o<%+>X`_e!jdfHilyBiz!VRQ;>XMjxd=GXgkm-T;V zE&K4j$2;+s2ZeOTQ2q$U@5QM77_$q(9uR%Wn=a4IU8xt=TKqRZmBNYK9c^FvS}b6- zk5-fDU>N0%V1hnOcmQK|0=p5Scg~J4%(du)KaEH?wjtWK^c1uL69yPFj8z9PY9Bg0 zgbBMbY7p!Imf_?rSIo>^xfkYI^5LJqI?~j6m#_wOkin>Ktlo;X8^P?vs6LFD0h0ll zP2PO@8~`!5O3SVKKWz=#ShT84!32?*AQF=Z+JH6?CxLhi7K=3s75FI6M|;_>k3Beu zQ9HqI1hE-7gtaNG)`e;i6Ifx5EfHlRU)uMgX z^@&GDux1a|Y{uHHSbY$y#xOb!WDp{kyyyb%9H8*nmKybWtD z)`aN5LwPxrH`8_f{XJN{4a+kKu?^_OY7c8QLYU-@mzlY%`X`EDEqvdd$46T`w>ybu zr~GXJqVPZ#o*}BADGEO)3qjplFg70)jL}$~LWQGfe+=ynp@SsW>;}67!~v8yp8V%) z=8~@e-|G3gJJ&?omh5m6EoJ+O8cUb#C<`7$TT}?zv*^Ibgo7Bf3u`xl*@02r7&VDC zDX=Mw@seMwlXiRWol;2W&e(#LS0J78nJd|^#*W2*Lze%+Xp1QXZRPvtYN~)V&&(mszbjkb;R-kUWNiM5Gm%b(?-cc3SBSDbZQ&bMfVBpr0#x9k zb2*ehg$@sc-h$;>gxCoTVswyqvO*_snhV^&i?#T=pS&V6Z`pk^8qWv6qTj5If5nF_ z#y?Yxe?CTyql00zH;nds(P}@|>;!fp7)ajqy1BOFpF)Dw_TC>J7isR?;l`U>fj|gB z{y&%>6P&*&#$ZOXWl9lRQ4Ymx6X>(kv>Rz0sI3MEO1{ z=c9uWjM{@W8-ZsLVjsp#VND2D6%fifTm2TR{k?ZcDV-n1=PkcVNQo4c<`6_AB%~m1 zz#t3Xl+PWstLz9^tI%P9%H^wV9Sjwa=Jg;p0f(_VjWr5{%2(TSNb_&I=Dqhvu5_Z0 z$LB3OTL@9kp$dL5XCdauf@Lb~Sn{70wi7&8;La5S_Xx@x#rS;~RoO=FOWt((9E$n> zxjNtXH7!i&6%p8U0>WB$&NL}4@IQef;9@GrqSUT${R;}gXr)8R&NKk zA>`rYjhCh8to560`CV7Ik;h`~%g;qrqmheZl22T;h?Vma>>En+m8T{c_Duy)Ia|?M z*+t;_1#Y82hauMF+sG!|pC4EXdNFzcYkGj8CTV;=V(%CJAJ^G%$(u1^gbT~Yf~*|Ag*X^RRh%Cl%ci_uAJ0ll<( zSH8=jXTYX_bn@oc&m~|l&{f01QWh0jl#dXwwk^g?s2B(goox|ZM_{dGL2H!xQAJ-` zqh)oF7KM#cM8BjkWdyZ0rxP{RxUfJ)+?FNL{jHMf^v-ye~^(VpoQocob*6JuA&;^SaM{wVd~_6}cY)oAwc9Z2FeWV00cNn|lDAy(r(GCn z&*p7eJ~viK8Y7Z-y<{b4t)7pumJ_xObKTv&@9PDUUtT$=7|XhSqdd8P45FUw^Wn&EtMyvzW>pyyn0cldketiVme>LzS!XLQt;= z?8SeZy(*`gY?!ae=Mjy~gVtlq+%H}1ebe>n4U<@%#Ha)4Ac^w&u&Nhh4uS1S-g4#S zACfVB?OUTg+%UogOPjgzttVqG{KFkP=^sp^wBgB}gWPcUL2|yqHI~rYYQ&0S;Laz@ zri$BB{+V*%Hub1UZM8jH5(dS<4e`dNe1#@n1mZ0qEXHVbpio|j@^W1t`(+8y5ito8`K_n4D*rgzr zg1Dr>{W2I8qWpj`7j%96p)riwg*8tj#0KDCUgAZEK!}j)4;^I=wGUQnp>lXmgjb)o zh%=90#96E7^NAmBXJk6dlJ+L<-Ox*uw4Brt<+0%`?NtR#bzrXamllbs@pqz>h{;kA zmqJ&Z$=dc*MKWF8HkJqxCmN3vOSFPm2zE8rzADfAvS3XPqsLMHDB2tAy8ga?wAu$| z8ug+13~^VG)t`yFT@FU!LwjQXaj;^4e&fnW)BL?|yg9bI(dA#?aRzHwcH%k`r8Vmg z40B9p3ya$ta2*HN5p3Ky%o+c&kv41d4qJc}4#neM?EsF%BM>z_Em6fop>Xyqs{knq z;X#Nh(4@GbL=_KZmWiw*^}mfOpenva2Pv#Mm>-`un+xKrqZl=XwUb~{$y@&H1v5S! zf6L7)B269poOny@bw{=FAMd?@XvASA8!$cNkWiq`e*{LEyrZyRv)!EnY1#FS94c3NeJ%jeAP~KF2LMPmZ zHJgA<2$@8X!Dx~SNP#hysjSZfI|g~} zDa%MiU97S6jitHnTN`^1-}FT(9QT*8_GK4MA-V6(Cv)kUtMUb` zu}q{ro<20jxyN?W5|3f5Q48F}fFPl3)gtxBS^3%mi!V%{QGNX-rhrkh%mn}-r;z+hngmilb zM?j+^@QfuayRB+;WwtSDQPb|qKMKf77@%?i%Ja}cA69Q7-~ZkMb^xP1tO*e!{Cy%T z(Kmi^d9-Q%ekaiqTN;ym{>l?LbInp3V=hW-dd4%fH^yj*M@U2?#G)>H`zAR4U)Is4 zscI=5>1%xgG>cuY50NEH5(=CQ)8L+V91vgJAb! zO?UE^t6mVCA$iT`gb?!E@p&uWE~G#PW_NzVPEs+_7)Gv~kKP2D3QPnhKiQ zc10y3Rd6WJvnp4>U!F9Nx4 `-gHYpC9M8$NJbjIk>De*TFYhU9LE=axSr5) zIAQ5Lp5E2R?RzFr$~<>~twbei>{$-jvZ_5%3)Fo1mki2+)l+zdFr&fP4 zpT+2H=%5D^j$`x~n6cz7SN(o(Q*-ra zBvRfNYhCgRAzdi!;Z{emAmQ@COOE5uFFcWdzH1|6o@QBl6C3sp^3*_vF<;jyY}B`X zE6z&wsVsL7N@$g=_x4q2hN!n`{SZqDmF|p6S{zBYZ;s6Ws*~**6KPrSYbTO$t;kbaj!NY1dg{U^zJ1-x z+0i@6b>CUf{Dvq?IuZ?@zkT4f!CU~RL@xBv1~{_>k! z**vYeXi)?I^rqwazz_Fv{Us}Dj=LCb2m{0C?(0T4E|Z>NZzfL#@PULp5*jU^Uq_)d zg=_cN~jbB6!Njt$;g)tRV7Lv)r|xFcB57-fEg;{RN@oF#1yG)5h| zM{{iLo1ru2pcV9t`y3n(*f1W@6NI=z&?xioO&+NaUfy^vt~(DmG7r&Q*03?Eq^jQa z_s>jV&0$P<5asuxynbxhjWPSMHktg=e>bpOo39i-K%lkY*+Gv}=QZ+$H=apHYa@?t zKFEQQDL#G0X`HaUgPZT#%vdIeTTEs}(Q)f)M6uu(ECmihzOt!s`1MJcEG0|D1X@OM_*c(9RBHT5e{S&8C{?O6@s@E75YLYM`5a?j2neW z6rcmac_7a#ypcRYseFaX>8?*alESL}So<{aG_VI9PGOY?cp&`$5%~!X2y4(`K{pa2 zKx;(u(bt~NWoI47bk^gUUA+XcD61DY^Uh1w@{9eC(c=Y_!l0;b6;c-fs{^g6vg7kZ zn<-32)uGJ=2W^Gm+=X$z_{LT2>`U>Q_88|SQ{3>#5FJs;JI?In*tP_}+&jhH2Xhz! zOQM$kpzIGUl;{Q3)pn%~3;aDvJBV`%k0Q#f(0)jmQ(d2UB!vn0VeLAEcnZs2Y?#7m zAMg<}{2$eAGlf5Om`CCOg}?}hzq{;YE|J;AP zXbC^uKFOA`07|c$pPUOV#AGf1OU{CHBN4=KV=*FeXlU;QR$55b27zw=bm`8cp-kRjq7XKf;;?QN~jq2S%nb zDE{rSZbni8OIl-$WU{>TB}=(*Z6{aVx{WP4xb4D4^rb@L5y{e~7(Ej{2giIiO$77> zia}#p;fjiaYZf%RB-$sUIC3G8*g_I*^{r!Tg04?*=*OsinBWk~>q7^<7`-3N!Q?Gh zjs6KFSiaH9vnZ!f;etf+=&k|od1MP~j#+}|hpcId5_26a5Q_jRta9E~i>gGax&>Ep z;H!|3s+6oAu@d=sje_lMFH=MJaFFd#(S2`^3h;dF=8}Gloi(UQGylTuNIhMuK@WbsX-g-hi zKiZRGz*Ed~CGAm3(#s!~jI~6BATDJ+pP_giq?>;T<{`v9kT0%K;?7s(%BSmwC#ErG zUw(YrY()o2j6Z?VV^}*zZek|+@9(aM(3LVMZE;Oiusmjdg0t5w#gT&4bcV+dkFxpD zAgh+LUf(f&mcTUXiK4_q2z zf)*L%_gUe2*S~rtKixdc9lK_@^0*dWfBFINtm7P`sjTB`Qk79mnBRfC(a{l2z*Kt=*sz%tkU?VLH=dd0qD4nYsL^>b)s^dza1@~|3 z<$~iDGWtX}=bX^Nquct)1`4GOlj(pTA50M!f~XK=vmS|v!&^>lVf)j=v?ZXqG0yk5 zjBsXGGjF+g1;bMwR=}-~^zzyh=JSaM1~{!Vffs0=7z-(?trkC3)z`h%J$3io$0#a$y{FV%WeeoEG9gF^2e}h9Bao2)2ZZF-e&%=6D%EAt9+Dl zs;ZdooaCC@pI~7$f^RHKo1!dil%%F+=pPu}6prVyg z2ne(Ftsm|W`0H;z$zQ)}Ew4F!G2eJ_FTd(ZgRtCm)v+Axn_}I*ac)15LLx}z@=_D~ zhI6Ei<(d98(_>j)c3cP7-M)k2(D0FSmvD4vf|&Jq!}*I?(INT30|T7a5$8jfcX9Hq zJGpF8fw~T%LqntTE zPHSU~v>!6RErC%QDRf;jTl@!o1jMdx>ZJ;$EPmA$C}l-eT(}mR`ii^qHFCa1YeS>R z-?OinB!z*ZJt|n$Xn6l6E4Y7sFXNu#^Or5>|Ni&@$!y3?SFPfGKRLv3Mswl(7+0Lu z$$h&gIdgFnyN7aY91D0d8?w|9IEByb)QNUhj!6T8IBqnK8|x&|25<`2T$bkz={!_! z%`irFqx}A^>mL}*-x^Bq#M)hCdIytV`#^Qj)*c{Cs62|dS1DeH>+asf*Ph%*S8IZ2 z2d8-7%a3P%Lj(tyCk*{s&2r{ykl_l110m|{S&J@LIetuGpVr&amQ=7bH?L*y;0)Hn@Px-#em%_JU9yxgFl_Bl^Z9MlvNeeh*>j>FgNc+4f_Z^z%&V$oju&SMJJ#>hN`g625M0of4OKEchPF~qc zOVr_^UkwteKqSW{eB=BjeEpem4(1H5G#nL^guslpWGdobIRUHeC=_(Sq75J#69{`e zh~x8<w(7+avMgCW5OVhM2p~s$or~6u!4MxNt>EV!eD?w zoj*hqL5_EP@9_fnNR&`sYIUwerP8~oA2WSU)$n3FsxV@XtP2Wd=sUk@-+S^x(%SGB zw{PT{6Bh99S02x!-*}pw7jWO!J_4mlG&^8Dv=z*FIjpouo5NT6*P8JK3QN?6q$7S}6FFaz_Ck(b*2ujWGvAz^5-;!`1_1c-nH~mCN~?AM9t;H{AG|}aUFqx*WR;6DhD1c+sa&abl=cIfVuIxfh)MXw69f56B_&5Mh_id|1dh? z&~o~!HomsLj|+}#QBGOb!rqY_-`+D*ffQ8IM~*<|uhfeY zM1kc9u^d{<+^@V|6f`e3T{o=j1G^ogx1xi?sNBfF{`K<%tqKT35e3Y@^!CvSwvXk{ zzzx6J!k5?YC6Wyo3T)N;tU?`X5Ue`hTTP3?ic0B}ngA=FhaF4f;FhfC(-a4-b0{nM z&aPqRJCbMwqAG{cS^82EM_4Xc9OLnALtK8|N`A0qjH4FB7@5p4JegxA*{;jm7_tz7HXwx?vZ zvv(X2Gytm+jjKz@U9sBMK3$($m&2L^Si3QAL%$pCk7Lx3)oQqV-v*N>>6;29F#iS~ zN)90k2;nz>y@MzA_7KeY>>T&7J{^qoOMhK_iyUwq@(9C z8YWpF1vBX^>-G-u$)6?pi?bK;7w32Ij}P^8LwnE|0N_m?=VA5HP*GnO))3)$X3g9R4=z8#&+ z&_9;u@MwmelO6*(12_@iWg4T1natKrdgDzs}D$_g05^G%~F|L zA&82Q4_|&7{oj0or;?*w9jxN0jwrc6(>*-Jf9x7V3Q1F;H=fPr6Gq4QVDgg|SwAnv z*&qXqRZQh_G{q$|VHQ8sJh*d+Ph7f!FWhqg*RfpOBxp=HeCw$}Hm5bWNXhwKagw81 zmd|hCh9B?d>Qm?Qj~6fIJwHzpD@}oj`lL}*N?VAkTak$)O=Fcw!4cs&?dTxSUX(Kb zp!VK$a7YDw^kAUeR)(l3=Ki3XmJe~ zKmUHMAno}y#RW?FL|jRO_Bg32!ZSMu>Glj6lh138X>t*nkg<$UBqDftFwLG{WVy+) z5NJO2a6ii$B3yUrvHWb~AQ!D|<>*B*KKaZ38UasPjj#zyXjk>XX=UrN=CitSaN`n5 zL1A0Grif6UWiq&*L8@XzJFjnJL2Jf5RgETzBMcN!OYcojix1G`LA8WT=UWu9Mxnw zfAu_ecaM=)9)UKT(h;FuDU!Y>Yc0kYezIklo1PkA;|E^MnuO(T7cAqkog?&5c>LYv z$MC`L?P1r9E@*$%+_tMq!>zz|64f(%`JXSeF=S=Y;6S7Sq9hPSb?qX;j6nxVggM>P z*5jt8M)N$sNTiUom2VkV4AO_DavYk<)wO4J%`K3Gs62DBG^JTqe6K8uDs7|df_Djh ztVQ-_EnM@z!xxf^*DU0iCGC9c%@N|Rc>#`;40}G$>>KApuRo5cR!pURUVKz5E8Iiu&T5WY)IeKPgf=Gx z6&BERSx7jl{f;P+`DdSmJTm{w7Eys1ZZt+D3Jq-?z)@gcnI~^U$Lg2*{m=f)wUHP^ zBM@#(CRDaoq*Dkp+n6 zVj*+|wr~d#V?wO$$LRfCpZs+al^aC+Jy^X9YxX8@xoYC~nqXag!HW?>6#3?8oeyrA zY>rea!}!z;V-qRHC)13la!gHojLifLq(hQfO@C0Rt{gY-RAhY{tW=p(GbJ<2$Z)mb zTJ6MztkJy^d|^W`EpeBRUU@2sc!XRw$F}Yff-vN)<2nh9Vld^ic{oiKWz4#SI+4z(ELuG(Hh2a8-_%HM@L&U6LN( zvNGY~2xyI1KKD=$*PXYRc~+BAwvHHFB6o|T@M_IOPU$dJ-h!c4m0NIZ9KQO#mohOi zN$=1EhX*D(G?Hc@72+xIq)XOy$>ICWmpDG*z_ zTY)UAZWo+)xzaX;gprEdWQh7H&4P_xA;d>scM2!1JOveMydWT(^_iSbGcqf`yrq+dVL zT4O^~quEso)Iyd~=92V8jciNRw44wK9HeyIcoRQ-|EpNi;xm)UlA6gsCR16)Co>F9 zr0E&Uuy4|5Pey^3;JW$1?K%}jQTYPfLVLEzA2fBz5jAodwK6D`B<0#E>1tlMm7*pA z6TG4$!J-9C{Oiv*F%@XeJbFHFKYtZpeY%@;&Zn&*iY~P8g@B9N6CAU&jaBUfZ0;H3 zZRafGN4tke=dv8Pw1w|paSZd?67-Es)1S>Sl?&({Pjl{y2Kx3+(%BZFZ#+Xw#9~5K zN`kBRTltP5R@P1w1MyKc>o}hPlnxTm-(^*9(uuL1tgcgh$K~PCD zE{*i+GR!^Oh`6XFO;=z1D1v`@WG`KhA0X~H3~NYf%N@Vm!lkEm@xfQDrKu^wO+VSd zw{{GX&gJ!?BHBY08vdC;6R3cMRQTFwDw`$|5jZ-)4?^a-@Po(pbM3{)6^P#A}N{`>LkD?o{Z2RkU2F9nLGOtLv&P zz8bNJ;_#w1T}0iZ3Xa&Kl_6A$APC5L0okm_OvYm}m1cBohW?Rh4h>DSdo;_A83jfb zkjk3MyUI~i@Nr7PyL{+H4OzZC&_IRbs1+?WwNmg{0U8HC2)OW+rO3F$;8d1%2gjMt zrdiV7&i3&Xsf@=?!8+ruT_*+P@e4^#+IImuP2*;e0nE4JBeApzA@=pj~SQHu?6Lhr0ie(E+m)%;6(uN=i@%(^n&Lf@nn91aroK7=3K11I~ zii5)`c8umYoHh9kRAtL*M`UaGJta+p zMDNffPwwew>!D%(`8^l#3W{X`GVKF;#m| z*6BCZ^8$+rw5e6v7WHUDxusV=lZki(o%0iP&Tp##rbLzR3`0fE^O>H>Ffo~8bUek# zc#5&9EK@Tclj(rbtfoJw+3VSS6(XE`;4azHR3u?F!TSjEDCM>w73Z+xGwEuLD+A1H zY@&Z?lDjr_lk^mKZ|~#DPb}xs#Zgk(9BY=faqhw>W7&|tbij+2c96*hbS`OTQEMYh z=eMxZwPdnBogY5Bm#AZT<%#q7_Ms8lgd`JatgtMXK7GC= z?dOO^4JUU-85z&8b=+gegwIvyEazP-^fO26X-t5onFQ8mj_uUF-Q>pC6s)5L4zYmI1*`K%kT_e`1WJ;X2KGeY%*gQ z8cX5Y5R}h!CQH=#nOk z%FA$kX+sZ>>>uIpUcHt_)^zgD?`&i!v^8z8${U%>Dgtp;i@R3qr7>Rg{_SWVaX_~?wFosZRaygIGOooZ6G~<&gCZ;n?Ol6sz&M`dg z(K8*eCmk{#6daaYKv0BJjrP>G{p;=(D$7Z8h2#Ih-T}V1qaP5o#9V?xLifJ^c#KcH z<^j5a8hkA0pWFq6(Q zJ~_kS@Fa%^#@RnG#lEo|V>wGG9sEdyz;V$+mhR_U)nTYXrHgN5SXCB8k_U$Z9vGY~ z=!FV!1np9=D>*`#)5NUchTERxrK>wpVF=1FHkoGrqE@W($r*uCA&ssglL=`_xSZ1N zFqHBc@-$bjo`)BNyz<+|sLA>Q_~W&Hcswjd?AN)b?d_m^4FXd%&c;^XD(AS$Mwqfu~; zAhgt-ZGp4ocTaMkCBX`UfOICEKls>^qYzTyNC($(iMTF~>*6|YRe}Jv5a1<5ToUmZ zG&iyUIHqe!U4Zw40M84^WOJl5#p*o6*hHHC(G&-VXA0H1uCC5!<%HGq53rE6f^1@R9xOI=zb%TO6Jl^J@C1NjglMv>muCROdKBN zyH6*H2*Fo3^suvUl6RbU3^Um*AN%$e#&bEQreU~P0B;Y(+-j8CK(8kwYbc!GhEX-21g z(pkk+U>R3}VFlx+5YXzlea~S>nSV|y3=7;L!Grwu`=9LxN3uHZ5OXA*i711PliZ zFST^nL)%GCdE`P%b~?>xUVjp?c$DtJ3354~oreZ^5Rvcjs^~mWrR4`c z>6sZ?T3T^k7b#`oc5t@PvQQ|c2*Q9cmqi;@YO6R>BBfLQ>XiR3r9?_u_}Tn#bsR}U zB2Ggh&b;=Psy8KzyZ~FQ&V6Rmk#mR5V8cvw4 z)J3XtmJ+K3ULgs)d2a@k&jwGE7~~t*A`G>}-U01c7pYCq%tsA|`|& z`v2H_?=ZWn^X&V#c02u?=|!X73kV4zA$kYVMQEnk*w}s@zlm|;d?9uc=d+V5`Q8xQ zu}z$~V8@9K#vNmWjY0GdDj*3E>Y6@t%ACIY_s8Dn%sFR9LK2ct@@8GvT%#GCnb~Kr zwbyg6`?;U{(Nr`|r700(=Jc-d+_K}X3CHy|e#7v9SSpiaa5&B0{v@Y(xcpzH`7%d15C z#*d$8I8y}6U@)1(vMn&nY{?ot@$x%-;pP=wy<>##mJqgCrfij~0{<$I4+LsRMQ{j zvOzXqWOy_~?_i3Zy-D5~7-Mh7plEv9zLKm^5E4cOgf%kGRjpm)JdU#_j}7USWDq4= z@Ts4?#LS0YqdTb58dMoh>-_64USYIku{B%fmyf-{O{=H!sUN(=S8rX-f84Q}DJ?PX z`~5~_yM*D&^{LL9N1h@i}xvqkDRzN1Qi@Evn4lT|Ji#JCm%Kt{$c5(5>4O zB}u6UZ-_K_lX(Wmw&P%!CZ&>2p;#uDFOtm{8OxPOWeN->^XwhT^Y&<-*TzgR{Q$12 zpvn`T$y!Fbjzw_<+lqb|EEMaQ-EVH~y2jZn48b;H9Pemc|H&@K# zja@0`w%2HA9EWT+i{m;30s$<`q*yLu+m@d?l#pZzS(1_EN(}VkpCozTuRZK|2O^K8 zh(^ND*4zNLy#Q(34!UlVD-_9Oa*U?4jHYs=#)_n~B}T`}^k)rrWDVXaI==2e_OyM{ zL=fhRIv0*A3p8eo-`nqO?W;-|F8Q~0V0n|S1r!!XH4*`ZfMYRSw0Y#|H#vEJH-@28 zlx=dQGHpQz*VZW%^R$H9d0`|?u2|%A%bWT6<`LweOnR_HDp#T-rg7&(oB7JkCu3L+ zU8>8VZq{U~8ufLJY_y+MkZRdzZ!YIV6~HDIR*8jGPFZKFIoP{y`P z^N-4&Tl+Qfl`8nE^h&EO34iy^#|KWX&$N_v(wQ8?BN=*!QuGdH7)%%Zytqro5{z1cK^t^W z2-Bbmo1{lnV=JAiTe4JTpT}L8C3+-@mY_<;ap~2a16JHomkzDhJ=FzwYANt>l6+ZA z=6fF-Av9c5cwAi8m2=eziynfp1j&)V-= zFZMPs|9=)hIKZEVlv{|*#pzIOmV_(x*dpSGNsefNtY<~{^bwvH+?@64SdB@`a8u#= zF$!>^dLyB{0zL*Hx_+D_%_$c9>Ce!)r3G5~GX`&)wKhu6p|!&GYbz})OsegopGzSI z20p2VP*w6ibhKg+)6vHBU}LPAX%(x?w-VOQkK{P7bd*h(=E!BL+xGHD8x5nUhIJW|BnU*M< zVE&ntzEeU+p<{CYo70hxZ~;U6bBK)l(SVM2dqv1kdbfXBWQ&s}HvC7SB0_ppoT+9& z-a&iEXk&5AR1Un6tUDap4FKO!lb!+nh)~ij+S5jn%UsJblS>=d9IR^Uu_9Gw5aL>- znp}X$Z*Gm>)nrLT+Kk8EAo)0M3)G=ZtML|$RzHotVmH|I^^2E8+%$0c7lWXK3ZMq5 zS-x)>@^ht{7^c&N78w1)sX8T-uETxAy8Nz$6~~q`xb)I9ASk?nXivOUO)@_cy^lvU zG0h)uys4iVppu}yL1oqQ$EGKo9?!npp@;xt(H)i0C=UoSGoU^Y56(Y=%GJyiopi-_ z*cyLeU8>3)(Gz&VDPN;_n~*D40%rJA-Ii?nWL6ck=4pDdANt-)U-0?B`Z>OXyw5Je zp2h77Mzw!@eGoD9i>WWSzH50O-OLe;LDj7b=XRsjtj$jf)4eo0uLJ#YH1T~qWA6Oi zVO>-H{XFAU6-7LURbX%&23d8I@EwMgK2nqwFWVWtt)(S)v#7tR1{rCLos9`|td$w7Fo<$E_?h%fi?{f4a~%3I~YF$S@seQY2C%1>#L@x*2$X!rlzGrJKm)? zj^(Z=6>~e=Lyo16B1NUu=qU{%B8bndI&8B;1+L|x|3+U&Qi7_iJ8AS}2X225uvAys zi2QWIs6YL-%)_`tLJfN=mD9#}N{$u}53OQ2bM?V#&=jM)ID$R8=Lo~z`o(C4B11dE zxUKtJUH7DMz>+fGcWO6nNtIf35aJ~M=h;-0I5j8jLbx&Yh1cJ>Pw&5^((aJ$N_w2N zqckt7nv_(>dTvmeMNk!R8=%b8q9Os}r2Kh8(Az8EYWzmz!*yO;TOr#_`I6}2G_ zdlE~?)%HN=HLvnoW1TCohc*5Z`8*X&m0PLdx%@*CI@{MDG$hzrmZcz#q3WaOrNx0{ z*&voOyrq(Xr699cM4@~}ELG=5H+H3wQFsyGEa;zD2ZR6T8dzbz%;EF!2W1PM)h0qn zt5BiZ;L)m$ExgV0U=?xyCI58sNaQ?nYK5v(zmcq>&DBQAEUH3dTAGjZNT=NBHzD7( z`%M~{QC_h&M!c~sLu~X|qkq^nUqWZkPKZsk>@wXXqM}oDoC_4yup$!! zl@{Xp?iVUmzc#p$OH9emo2{S5#DK{4o}3Sx)@uk1B35Ls%@` zYVCgK36kwpgR3ADRO@FrP5nyYS=tcpY@xU7Gb2Lb%2hE6Uh8Aa)ABVIyPYjIfxQJG?DkG z5p|tMknxOZjd5+W`JCMgYAID*nvw$RPPSMw%SpMK`2C(v7JH(lyeb@@gTltvlWV`KvZnf?= z=CodR#5Xt6#-4Q$Q9RR{8JFB>n{=lJRmP}?NIT1jmJj}h?8zS&Tp2Z1)vsEq4rPTG z?`#H!y@v>*2frjLnrM%Wix*#wir@3-{|2(;31`LWc1C-<;$2a({RUC#oaadT_?7q5 zFVRAm)mCFXzQtX)(2|esR-{vSwbewbFMjMe+5|+O#s*dY)GX1MAHkK`yV2$I(07l{ z`LF*Nd$8%u1U;`y8t>~EZuFzzHx5w8GAh0;{;Wf5pvU+fE8~L=cr_s+WE2yZyPlwz z6Ipye|D|UM-DZ)%bhL-a$MHAILw{Y(_G1P1%StELduNvv34elD-=Am`aER_!Z)-m- z?=aV^vj+w@Tm4;lt!bsv3N=GE6TIBT3VE*SXG>4TT2Vm^vgu`|aL6sWuKj~`0B2=d zJ-}8ASIaJKFW7%AlLE$1Z8Dl4t zQ1I|nJl38x(~+z$j;ZD*D(p{Eu}Eq?+XUPd*2M`Tmy(AUH`=VwYoO_1(F>^ zMf%izuN&}vV)(!jFI3)2hOt#URs#@v+9pZ0ykv_LNr4$B89qcgp1!L3NHAoFb-Iia zYNAY+DqU2Mj9jw3&OJK$0rVN6XifY+gTALYyc~%9rQDG(br5uLeL_s*uD_65%2+5X zZ3zfTTh0TOoDxL{H3o7wcMi-JMIpdKVadSczdxbQ!>g#07cfxmB=GU$vDkYB^w)!G z=&;79=8W!8{w%NX_wsjGJQR;%Ij1Em(n%p|QbnrBZ`_NlfpYpnC)x^+%j-Exkzi-V zQh$C^>?ZvSW5U*XT*Kkp%$Dsl#_-v>4qFM`A(l-p=8uOZsNBDtS-#yk6m4HOq)y^la6SUjD=BSr3jbA;H!|wx{CSZ zeg;o!akcpG?Awa*iw7e{xx0Mnq2is26oRRgDU%7~ds1dH(Izs;Wno4a zCdN986$tG5mhf%?Lu)c}&>gAfM`SaKl{zsIz+q&|70%1oskoE3weKu*t3=d#!1Ps| z--77mBnXDfTm}=rx2@+gzY?kXyL4k?AqIy_7(stQ7;RH}^o#rWaQHaBVEIjmlVG22 zRjoC4PTGcD8L-c{iu4l$BXMW0?yQS_%&1eqMx#}Gkkv(YtRfIXTxkaDtEy@_l5*n7 ztEeiDE-T*Ea`q~=wA@1KDHL0uK0r$!Or|#T(+Ej_U=QQSI+}zfBlN+ZacDa?huVO2 z;$H;|kO0Ctp1`nOp0o4Q!^JgQQ6(&rr)veNqMuYd2ojQ#(o`5?6zI^bnX)s<<~v%S z4>li1%6WU&w7Cc4bLvS_RIvzSst&)>Oz>5eBZ7mR8#rstKcXGb4y+<%=gQbqLlWg_ zl1lt|CaOBI>>i5UjsEoK{xqpyvM2o43X*1vDG@#iNG_eRR*f-Yq+O)^Qu9p-dv$d+ zox@DtWtW(UsJOa1jb6EUdVO6rM^ZD@K_{)V)A!+GeaxbyQs^SEh4vs75??h$k@Xt| zNkPfqn4+jd6@|mpeYVLq+b1CdzGv?YV?N1E`_S_adalQqYwurhGB?gXs!bl*Fj?Lx zR-;{~Z|i>u&Wp$_5Nw}%qTUXIWa4apP1Sb9@+R6vdZPWx*`>rjURM=QEyo@swz>B* zEgCNQ(*Gaw*9wfx-Q8rc=9sODySM963Ff4^kR`#?Hk~XuduSX+O)UeT?^f2 zd8ovVp_NH#nW&R;^g%IRz1jRGiO2xyT!9MLaP&StiJX^bO#$#bh@v%cApIf{r~~Vq zrrTv$Q~RTp-ER`w>0)p^uyjdyNd<1~%f}0MRsyxijO)8^xgyq8y_VYby<{^+x0u_R zcsJuvY>y>gt$Xz1qMC}T(cvUliXDjusSAkA( zV_~`&x{YBJjL=X?R(+NM>2UGR$bH=nvVgT4A4M!6=hpr(_Jr`U6z6>TCbDjVQZibC zeK@_24M5nS%B_C=$IILtw}$VCEtk5n`TSDwIibngx72`&h;6B4AB7n90=H@)YsxA^aWe=+{wS&pr^Be$Em?lRt zWiVOR#7-M?CJxzN6sF}|{e_Y*>ivQS2BaKCK1dO2_*6UBM@~bNn+|J`vDWdK-H7*c zzQc}cs0j=>R95oq0h!8f1Nn_2sA?cnN21g4i77k3N4&M>%ReP0Vbn4>*FmorhtYHD z*YB5~w50FL#2Tq1P^fRoigexLxVpoq)m=TI_kQ=xuND1 zYiB;LL{nS!iU1E?J0lNvBbdP(YIY;)&{-JQIILy%pL^$lI!0~$li4keOlC9=IFD~f zXOu6x;BklT>$o-wV^Ys3uKk#a7@0p2av>E)Dboa9z?KNYZ&VtMF1_EqeCqxh|C$Li z*czQMx)08$bUj;rXj8yLn!5lTp*#B32X6^k+nd`iu`<}R|Q ze&^ZDs^lGIrNQ45Ua}MP#Lp}W1wTjYF3?eR9WvD==*AF5n7&bAWmu1I?p_brHn&}FsLoxdiwW%)wH3o z2vOQRWwL@Sr5F?gPP;z8{D6sXoo%P|8ACSsbSgsl~YS7&B$FyKkRMq6<<2`w`NhuZ8)VF5#-V}_Z zh*j3Uc?ahqj#p235M}B&ZonCVQj_kYbZl(h!EDs=`MKF#@e=R-e9GO$>2Jf! ztrir!_Sy_ZRw=tph`35ENdbcGS(&98`|U5e9tXUUMHo6c!~os)@NZ;Soh8DS9Ys_Y z|0Mn_7W_pgQuFjL8gh(|j%5R88UT~b03{q?YCK7JHkN74q_HO}K%79aOHzG0(lHTh zGV?XZ9QcC{i*NLHxjUDRJ;FU%OkngbcQVu?IC4`P@(!PTpwa@9yYMF!jPhqwE@zDik!}%*&ni7zaDyM+)*r- znzyZs|6%Uw)K^UaTPgJ?CGL+ zdG?TUzb2foF3850m4ZvTFvcrHI^~Js`&Y*Gg_+(&7>;r;klEv|dR7{8qzTJL5j)IF z7{}R>%(cWN9(V>(Kvgp+Vq6K4MrlO3Csqtb)4(P(CDa*0)^EiYi_$7t7WNnz(e_;+ z$o1XP?0lPgyc%G6!>+8X)OMbM5xAYN|1+m)tXcTGBc-+8tm71B4+%W(pJ-OK+!=a$ zc|G6v#o4bnT4~m~Un`lh$6`S_vaZ%x#{OfcPl?h<4cX-r5@cFnYLC>51bAhI?WxC< zmIW5Nmjn)WE6%(xPtM#cCsGBR@?ar}f5{xYB-I*f=dE|p*61?84AnJVowpdSi?+yE z@G@TG>d{A=10sY3W_vy0XFJbIdtZ8eiYQEBE!t^Jxh(07`3Se?SwxXzbCQf z)&amfBtpE;1+v|d{m$GIcdVfu><6&Dz$P_tTS)HlVTnH|#3}`&fnQ5==k2Ao>&Sp^ zNTNaAR`9^t`T6e0E9n;Mhdxu)DI}`gT({Z?}K)037~5 zkM0eDUX`0#MTJ%Mze6x_C#pVdhVB`2b#T|}IZ>ROmGfXq68Q9H6OGCV}dOpe;|#_`uAU((ZTk-3eH3w_R@SLvxq zT`OS4n`F+6mI@@1#K1_$xjOHVQ}*pf@N0Qp#0d#anU{u*Op%cfD}gW;0#F*CyY*qH zAr~c;30)OaV$DuO72u&p86vuZ>z2kQR}$OIhoK<(*-bVhl^lX}s7!}NmnO5|bEAm= z=FImUq+&Rld|^a%3&cQ((Pj>_$lOEn2<#!NHLrLPA{qjn^xhPCFQ9)TE9>rPb2UZ~ z{~3?%m-GB`q^L-Phdk~6Q2wOD`>~y`2uQ*o^UAD|&8_ubnF}h4IwN7KF=^;;YCnGt z0(DMhQK|BCxO)oG_7vrz3)~b@HX&T72T@yE=~$_0I4NVg{qrUK>w00>_agUpzWD*= zwtkPVmQxp4{c$UNy*H!GR*Z+pNW!1$6s-wRZ^>x&ptV>X;=-1g@ss+sKj}TZ45AOm%QImC9%X%gi(y z8xoWHI!tE;`EDH|Lb?4wvw)POb9#|y!RMqs_``NG>xfu7Ux0ItE>&_S+D zqU=l!&*^x5I;Rzi4-}Mak})hS?9tH~*#++R`KtZs zU+NI?%9$9-AdQo14TdnH7m6uD&~}@I(VUFlmB?%?)5eX*4_L< z(sVszrruV}TAe4vD|kG3xi{>Ix9!sv>6{f&qj%u+h7^iGkw07kW6R5UdGBK^tZo+o zW`Rp0d4X+c->W{-1aRb4|HHeg!M99tR9<%JF1bEOgRgpkf+gLG`{zlk((kQ6+TQf__x7gMQiw1Lath) zSNVgfEJ-h*Xgh@|ZtohM%GZtx@EsyEF6;cqJY3gem?4G;eGTw07sErRQZ&i}Z&_go z;uPAB*CBgI;;U;~<-dX*TLr*p0Tlh8yojxqbVv3N2u4kE99yHyO1+PovX+)TpZiaiUbpBXJ>Q=qNVR>CrQk3>k2gveM?d>NJWB|E_}}BKxk-^YkS0wf~i{} zf`WpIE*`Q+AFkVrID`zQwTj>WAp@*F%mpK4=U4wF3ONZSpMxGaNYv1;gHs-t%Oz_9pW*VNn_!?vqY0bieDKT?Ft6V<1;w=FNCwRrj9MxY`XW-3q zaoR+M<_CSN@#HA+tPAQpLW-iSG>$Ec>elFk<4xb5@?tdz%-Lbbc+&~%_JXP3-Z%Xc zgkN@rO_nAF|2a)HADx}(ug;USwecNitoHT7-10o{?ZeH_(M5{t*^#2Y9ntphvgvNN zr`%5QCbN6(RYVn`GYYhwu|J`c2klGp(bp=RGgf$|ZK@5e4hZ2Sm*0&%?iw0lg zd0*D{`WPYnrq@z6HYEI^ge7k9d}ETH8c|4x7aCAVH?GG@Dy{?u;yt)W;qEG8e(=>b z5kpMf1Vlu}tI@~V?!5>CuWv}>IUHf;RI&h^@2Mu8j~$n{5enXKK1g45`6<83&4s_N zca+Fx^d{5alW1}Ov$x?SCJ)}~Yu>zw(uljLA&g^DWlga#g9V<_meofh%O z)45V~{<;>FF|<{AsgV|s)R~Nh4;h+gjt<^eQ<8(9=>Ys1cz2f4CJw?SD3_aj#N?mC z;1-E0R3iUn*(t9!;B%+&K9MfUMXPhiM^h`VX2z@MMiQWKvue;3+bB)q;*A}O1TwO8 zCTrFoP+UC>`~-;!<Uyl8@N$G5xSZei zS%(--Cir$xZ;-M@CnMx_AVYQHpAKXO;Vnf_4aQ_imHY&ccp-PP z=OU>lLhfr5vRSKrw^LnWZVKH0p&TK%%}!64?*uk@Xa9~9nrvLE+AqS@>tRI(OOBH= zEFIAWX?VoaH$7{1Cf9}HE^L6bv6)R_DFKq-zkd^Jrt%(EaKvhiD`UZ|)y9qLazQGN zTwU)B@Y_lP@80V? z;r6_x&E?*;wGD%{re@ybKSkcBT8}qrd4HoEH4noc*Qd6&;E9PVz3+aLinLsdQ0UZD##CafVPIxgme6eo=7(ESl-T?B&7bsd%4EBBvhK> zr;e9XeBj{V?o_Xy>(h6?L=mk25!edQtV=J+^~D)-h+S*2ll0<0&2>*KqRs8jD9IZ< zn9z!+7TN3+@_k(9gMEEvl}plQj;lItXlyLBAOP<+egYzeXc?1ROFoG&ZfkX|mmj1~ zV@%wR`zdL+%SH;*+2+0MOolUbubz({Ami_}Bryg@u(cXkL-*Fy@;nCUVDz78?t0gm z=DmGX|}TX7pNB zCuDGEO-E;xa+obl{I&54DD8d7tMjI&&26z3<*Q}uR{hCaY*Bd1*H)m+oI;->lN?EX z6C$u;ojR@&>P$0X&L;=b?sYh0z?%bZLbMfL-(;|flPJhBl(FX)tF$jkM?Rj>)$P1% zl}Ri7sH;Xw>HwNh;@zIRScbfW!SwehtjuAH8(h3SzxAv#mU~i<)xAHKZSmwHA6yUR z>Fe7MkNr&7EmOq7@RUBxw5lpp1dxp(DwjN5f#D!~{qN&dKc)hQ*(4EgGicUDhvaSH zJDv&DIxvIHhydLF5m-9!5UbAZU+~L4-mYn-fz(H5NBRfj$6@VprFEX;RIsm6oGBi; z(d=cnBX|4U#TJSHoYT9qZ?_2<`;Wu=3so)eMOy-2V+V@mw4Tn)K12Q9g!PQ~N0n(r zx;7$APv$|+F0S+0b=F-CtJg9woXk9*+G>@2A%?ZV0BL9E24#k{=Y!_XJ_~RiWb@W5 zVTXLaZO6G=uPg64@@8Vl1&fL>w_SM`%VmucW;NHCT?$!`Q4mC2hkQQn3fzx7wcm^~ z!jsP}Ee!=e-#*W(cMcv3fASj69KB*d5aW{gAa#DIm6w>5nxMVMse!7#BZ!E%m(#{- z-R2`bKGnE5=u~6RGFG>TmJQ2hJucav|33@Bb>G5dZ*FC`yQpQmQ=s=5DvpGUfebtH zXK1<3g%J!PObUX}SRtYbq#KWv@>(5{hkEW2;3|s0{P!vdPVJJmT*Fc%uzoh9Fy%YU zgdE=H*lo&aE@}RKVE9qQjw<*Dzwel#%BVn|B3tWq31%I|Dh%kzu+p(K=%T%KOvajn ztTDgqB>4E&Ja!^VG6bDqr@Ednmb9I)d-Q88bt^1>eP1XY0C#kank#s<0A7>_4ID2Z z!hRo;_Je)mTk#ToUR$KT0%~M+5PD%}4AM6sR*p(Jr{-8unKwCJwo3B4d9Sr5PSMX5 z8R>&M@LD^z5``EB7}g&7Bu5%M@{XEJkzp!X#1!X0w<)9Ad(i(_`E-K`AF+(FtqA>U zWjw?n`u;19mW6c*s_sX~qmqb*dyWKPtc-+eC?HK6h9R@q@nOZx@sx@5ssckcNlak! zoU}D&Q|QLa_w$KQ=%Y4He+?zG7(Hsh+|t(6-59S!yXp&o9NMqOl?lA6qP5-JUC+ee zY7q!Vi;i|T9(tKyfdB_CkE2| zBg_|wUlFv?h$X&VH?~+~Hbs&+LUrsMs?973QW*p?Z7z*SEV*oWo-(Ob{^B)IR>6uB zbtP&JSi$&!I@|7ecu?cA{@34nm@UqO)msN}J>U2az}cV6`!MQ!p71(8v!=yBaCmoF zvR^$>o_TM-3qt*9V>pTG$Jnbg0;}>W3tr2ULbqVub?d)93I;Ylem)C3E0dvz9Dr8S zoezRoYu%VzQ)8m*fQUfd)riN{wlZf$qQ2j+A(ft;launZAS{qEVjt^Dg9Bxnjwf3p!09+s21Qzr24dZDIcI*v)TJ;J zd}}-=B3&?WB`@m-g3pBM4vD&NIObr5CP&Ndr0`%}MOkcFV-bwbQih-xPLW}RS*}m) zxJIhQTrs=Js0xYRBQ&Fejxac|QmhJw_~@-;Mck{nO}UZ_ZD9Xu7i*?JVM-oR09DS&wVYYZ%+ZSs(8; zw7D(*=Q$?`C@po=<}1}>d7C=%c4j90yQnn;iKRVWJPJpyG`$MiP4zy~@e5>3YHBLq z?(yo}(VzB{9W zj!p=^9Q%Sh@{TdDZ<{sXo4-Asww|nuSYj|*oH%{T9YTFo*{-ajlM}~Ub64N+5nY6P z_SrICV!ZqP!dLIBpynEf-P3=5pK;IKa8;5^U$uusl&}C}x$#wAFDqu6U&U|{FpyM(Wjnax#iVufs+J*yNaOmpuAhAk|vj_Ub6d}d6m zNv2}kwjPI`z_uF>j6~BUd0*RoLXtx->9~Ehv8jB!>V)HY{(~u9qP*3coJ%k8v{kLy zU{AhQzA{v38p^FAINvyaed^BS2acYXW3V2o1OjNHv~GtjzC{;PeW>7Q+1Q3~y{U#Z zod)2E6_!ip99AGmVU8q2)eEk63XFJo3-%s=F~$2YonkLw25I;xYGVdAgd-ZgLyqv>2WmiL@8z4*^D_&{9@wSe5MUoYStti5MkXgw z3Tuzh*CC8mzsHEt$;=vf{n1<@+Lt950@6aXIG_qSNI_URJ16_K9_qE6R{aJ4(xva^ z-+$K${ONoyCy;&@G2EN_QDiQl#sL&DB{Yl+>)79L5W~VbX^$)~^XX@t z`$gXN!GG2DC!XJDV4U|8S7uh0y-r$gF8zOh?`_EMpCozS;keV}-uRr_95?H5$KwZo zXcgFnR8+<81KN8>;Ve0n9dC}hUk{``9}$z%B!u6tGM?4~2<7JJPEA-OV1q6r0uoK0 zYmkztq<11{^L8Q`S7CS6pr#Y<@S+U9?sou*I`8`F% zvGK5WpYb|rwAe#dojN{fnq7g>Jy5iEI7MAof(oNpo7t=L8{M9vnJUl%8?Z9W3l2fBR4yZL0Mdxogm%gilZlSSfh_Y5Uy1|M5xJ~;{s$CMS zczq8jEeoIr0IzXiqO8=Hg4itl68{DmJ7W=J!K*{Hm-)XasYV5BT#3pOE=(A`h00Fp z7@_oR8IvutUa|$eCu~M3`FaQsiC1d{DufL`p+;l7(5Hd69rrX~8@H~UiHXVC)%EJ= zcN|Bi?Ci|UaD9kvb~Vn3@?uN5=-Uz9I|OSNcC^4**Wh*72k#gtpK*eOS`V+}*9zl;zg zYDB3@(WV)kDBEeU7UX4zHip^~R^iNVdXB+lJZ^RK?8tn`g~-#>bGh!G$+lyk2KEK+ zi15e^%(@ZGA(^|JzoNdMEdBFbV}gbvk#Xurfv=06U5s2^K_Q13??ckIn3VuH z_+zFc#cY#>rTQd<;J|qB?%1VT zv(p-XERCsr)EHc>-<#LRucleS~s&aR#P->o_Azb6|<)o z9IGsp>cX@Oly=!iaM-7>aYdg1G*|*S)2v_a@ZzRr(ix56)|Kp3+&i~fbKi4|V=F38 z%ChT3mzHX8@`VCxf+n;~)LCQbcO4VG1!z^LHz_QBIbBa@d8%E0bhk>%L``3w25KQS zE)qB%__HTUuFbU5ui{-AnrCLFH+CE5)YM1wH-%0I6cH)$OXR9>=qjQ zMnGENL@+?dz)@N$ly)*l@&d?uX%}!7&tR!Wgkl9|p27G?&nGfpY9Vn||5T`yw)4dH zOw)0dc9}pRZ#fRN%{x|YJzva{GGhmT2j8v5q|=*ul%RARsPSJH1s8o|@UfflYnA8q z#bja-Sai?LwrK9ka7*^JNwy1>x;^A{M1{Q+6xO|o;<9z&3|wpj1@zEN1|nK21%D}f z-!2pv`VPC+(z$#HaP=I~!M-@SXW&YwYWm)=FA6>buQk$tw)QJ42u_IO>U29zb$z2q z=w_9hr&Q@C8)5%th1BEWq}W!XZ|X+0aftvsQ#ez$sX{ESD~Il>8U*)uYAjKfhbNcs z?^PjEtxZ-8A$Oh6nrl_d4I+u>5qU5mUD!-W@8gh#qsR;KSS3?KAas|fy=j{>SNoAl zxmb4lq)~k-a!;LW7c?q!m9` zot=R)(hWnepU#rB$O6ZYQ8TYso^HOuv5wT^a&4>Osk-^tD3&$|e+}U1 z=f~b>radY1-#fz%cO#^tpAo3OSEk5)6gV-{XC)0;Sy>yHLDWIIH5XN|Pm#%8$WS#1q_8OSp2imXpPRyyN@os=Z`B?rmtmmL4Ed)Bu z%SHqK_60p-dvG>`3>|4iRY#8}AMFaVo+>5_|L>)8rehs?+yIZwJqQdEV0~)9MaQs~ z&I(L19apTboxs{hthNJ$dbDPM%=?RAH50 zkf7f%jU|LLiYnx2yH%%&!3HD(LD=xnbXZ87F=ri-+vD(t3rK z4y2L}7A5x-71VBi;Oo47_rf1Drb`)1l9amEqkK@U6J}HcLL z8JUeHsIAi3jQAekk06B}5>V?83X#AQK+kqZ+BIp0r!~alC-rX!b}DIbAbaESG%^&> zh80Hs+6}?TpzpPMAhs}<4!YSBNCv!RxNN`-MvZ*<w8#bEl>zoW?9F`va3o+=!QoSTyrhToGOkuk&eC zVRlth&wNl`z65B~-#Vk3I@uGJ4!%P})(S)DKxME0(&zg4g%Hv5Ct!Y5xHEyaxTwWj z(`r4B4G>1!mAZ4Wq!So`SN2D#fhn;m#NxEnHbFCS061at3%Xd0n(sFT6MBT01_eek zyak4cs_2|CP&}Uj!!jm)QyHZ#iKXB-S}B8DNycu_;|3$fwx2Jm=0-TN% zqv&}cUR!Cgpu9btG&45thcf7ac=q0ylR=nD_}kjrYRUXI8^v;6Y3GNu)-+74 zvM|~SWNa}uj1r_bPEwH#Tn ztZ1r5D%9I6Nm9ZMtDDZh2%4o$-XVwQbwa2&zqm6~*2DYHpHwi?N(gW&#bK(&L!8Cj z7P1y7(+Sh&u`uBwjH+HYEgIT4Eq9>d{U8c_=6j+U*9GbBdTp2!-H2L19n9fXO9wqT^X%IZ5I%(I3mf~{o&1P zQoZ8fPmhbW_0YH4uRz&Ms;nx183h$qYVx@Z@TKk`pg49fWQIRO8HA=(zSJz6967&a z0i1b$QOeV35}T7|C=uaqV@y72uo?{xRl7C)M7cWpNk*VKe13295(v+Q`OVm?&W$M+IR|y||s-aJFv{q;2ot;Zjn}e*oF0yVlBw%MB_%XeloI zw0N}rIsHBaTrXA!Hb48;_ndfbJI-l{hPJmi-%=+p5YG{y>uV(anYtB$KJP75j&c26>rVBSlHn|iMRCpjkaui2A+8z-~iZ*RlrjZK8 z2{A^eDfKJelQCm(HInf?r3oXH#qL&H) z=q(&pl>tub{fp+4P6wCKA~7?c zFAoGyzDRoyTwiGO#MVM^F@%q)=8KD^H9VCLy>+?9jzV?MsUK}$-#OLw`l47mhf^oC zj*d>Y0&khgFd}O1{uF^d@=wm#UHdVcW;DbQjdpi7;rC~SatgO0hjc+VE}wTWClO2& ztyQFb^1X?meIC#Af&I?ia{2KJ!7`vK4QJ}4$#T$w!psb2Xn#14+pNZo+5g?Q{?(}U zhM~=I#_+p+?%D?T$E#!EXJ^&8ds|A32>n&AR2xoK;!n&p8lyFIaC~jn0Iz^CvKQ=9 z4Hj83gWW07PIH|E?3Wifjrs$_%q)zvf2~Pgm+x*Ea&p@CJ*`wp^i$2UYTzB>?CN&Y zi^NiEKl5gJS{EctrfPy`K<3;4p{9dzyv~*Nv$lWwinWij&wA|v#mLA5sM^CS8!91* zPe5b{$T4s?PG<4FuKs}2CfVgC~(|2QMJ$OOf zJsQ2837c5B6AER%t|OKTDD>E8D5PbUIK7a_rJAOTJVELfRKNe2p~}+ri@_dKFL;KH zhBNd~QQfbopUk{^A6wKOq{h_=v{@@HTMFGf$g(p%U93!R8re_t0JX>Yo$dbfy6kuZ zymH8Eds2XX0J%o;tDB^>+j2NRaRHK&t}fEGricNf-Tl_;fVLNek-63(c?LS&{Ummo;S#Q*JPfSR;?@Fo^Gw{#e1;15rVv}Lt>g>}fTF9EB-$_&leuymyj)h~>Vh~~?l(UFCJ9y5z-?AJ zIXPn_7~kd#wkDfRX$3db2=_pDfIN_Z8Vdz|`b%lqFPGJ-g>FvRia~};bKq#1YWWFj zYyn!{^SGJ7DI_`hGsv49+NxT2tkdTe3>OV<4Mx9cXtV9Vgc_j1!8 zcu;C{t6E!OuN~%1KBd9@oeZtNQHO{~v4C8;DAUw)^;s~1}1LeX`8j@ z``3@_Pw$8v{zsKD16)9QU&vwJQ1=!@t9NdtovqR4hR|l15j{t-+}fr1a#J7wW&3v; z4zN^bIyjy|wNv|vF_<)DIBu=p`uax1azTIfZv*1p6|^JIb=&r zFIVUSL=9Fz%^2BU=yP^7xz$s7SjDH+^arQ+Bw~t=&$EMnh`yN~{vMs~#GgFFs>+&* z=f9Eh$7;!KI(4{5OhI%|(tfTm!@9kg+pFH52->x8!*IBqL=rh%G5T(}lf45#Et)Ee z0Ha;#AZSr?MNTSlAu{+Y|1NZM_V4M@-DF+uanRP@#^$Drj4UoQ z|K+bwCPjuuhKG!S7z!UE8vNY=%+I!^(xrGr>4+%sz>Z=DV8rED&O1W6s%p-bh0B7f zx~fr+j-M}X9fi{}8A|MzID{4U6XrNF$s^wM24Ks$Q4Z)fYt+$ETdd^l%{ZcwS zWx{l&$%en9!$<5lItBVAB@qgE$bt`P_bM+Vh@?A2r{LJfkjIA$cc>LV7 zTAG`>lV(2_Brhn&%yedL2>)3Wp`)0<=-C>$3?m{AbCwT;4^7G~miREgkYh!9h9BFxOVE_tMaFmw0 z)4$FApD^!&TK}i;>Yre9sonGy`!j1oX}Db48lB-~22i%Bo>~!0iJ_(L0%I9`cVoOL zC|;{H7q%igWWORJ-_=E>azaJlG$&RO+Ul?MY%YMo8qc<^{7g$slMD_+v)Z`mE7~-+ z@YSUpx$r#lo~oksih|oP>VvV#bzR;n0Zn%j)K=Zy{!i(z(hg8EnhZ5ROzr9PQyGnF zfU0{i8Yu?43Q7+(MB2EY6>M#m*%Zo%d`Y%5)zX>0nQ<0Hhe2zZOLYWy0Gs}!w9czP z-Sl7PHePu(_ftzcFX^-Fs6W`KrhI8XfgIP4&6d|4FoX zdAXUo9X$abh~;Ot-KY|W?-CjWLW%XFgNqKF(3PUv35wJ&g;+$MyYeG|4Ykcb?flet zsKoQPJqj^AIXE~Vk8`r?#(t_}NHyB!u^oYTXGvRhAhK=USN~_<7ZaVsmnBvhx1qCE z_Hof*p?t%o^xMM1q5uR+czN;Mamdp|4iSa^a?s7o5e->yEysk;!6cv8NxD_BDfQab zch$POxH2c*jf@6_!Z!BqhDT%la#!$AMEw6*fQS2?P#uZ_DPIHg_z{yALButG?vJm? zILY6$7RopEC)TVWH0qq$z&aMQprD}lqt{ZskCs;ijQ^nrk>3v6c)E~{V*m3zrb4~< z^9WexBVBTN9+>hQ;J4Z^*k}*ZxSjlUaiDy^(c*<`ZYQf229&%F<@MStJaKBP9O z)vWKI?w%&v5!w7^F%1m*(sy%xQ7xF*7zmuNSR0Akada#cX3mVRDR|rb0R&0o|8-YJR1LmysGaOy5dFW-8 zVB(dOj;hIyeza2OsgurxBGi}+a1uCED>>T=fELq#eZnQ6i2e_sL14ZR2n1$y0Ni|4v{p08SN=mw!+m{=@EU0ogZ@p@u;fDsObF->#8Z%{2YY%T|8BLx?RY52Z= zwo}v{_ugX5x^?Th;f5Re$S1$TQKy}S9*U65WyxjIWKu~|iC$8DJtTU%N%VA)=a6(P#-;|Aop?O4=-}zTJ>A`m8RJ6)RaH6b ztTPHX=q*40HNjAjgBLB}utN{!*T4QP*<6lnF2}_eozJMzqj>qHS9#&Z7in!B#j<6` z)7O_^*REXzgF$pdXZ*NvRT;Em8v1|xrU)^D`C$Zo|3z_VVnibtRC#NUmB(@ez^vDU z?=5QLqQl1eKnFN-|504$NkR|t??VAH1?bJmLU*79qCo}WTE2j9Nw;MUur}=azX9~^ zdH-)L^8E4+p8=85@BZ#rg(g}SD(dmU8c`HklFjsD~U&5|M@Fs z5FH!Gwy`Y>%gU0=X2_(Hq?3Ild%NlD-b2rx4mvw`v3Au)x;vgD(c6RL*jSd0=h#Go z2JvW!cq~dZ8YL156AT7fzWfvxEm}x89NMd6bN>gV2$Pv4rZzlwHxi1lr+W{rO|2-3 zQf!ia;J<2rhE5Td4X8PD_F=~KsT_O!aYSQbuKn5#Rl$`IaN+sqGI#ErK>>^q0!`JB zp2Tq+o_p>E3`3`-wUuZrN;n+m;*Xur)G3pB^|h5mqESBc*-x_a_0|0Cfq!t~@yD^^ z@yGe-xo7j*s@M7Z{r_P9{pND*bvLm5w3Au=#@n2F$};xdcR&H(^E_UAbtO+c`80KP zah5GR5yx@Zw0SeCqF@*%bLP%QQ#Bmhp)Zl}-PJ?E{7pPy+wlJiNK+JiW$vNUUPCc4 z)u?aav`G>EbJB^g3*A$|f?(cBPahDZX5Bt~$17Je{qH=&$W&Ef@GGLQ4#6FY& zFr`S%PH@cVAYc2?3?_|=pa?i&UK@CD#RFUDat0CcAL_XfWUR^*p@xf9Tn9J^*pxL~ z0{YW%CBaXWUiXruov6-|C9P6@o}i(klJn2^uy0vWrEx=)H2@4e+}k+gN!Z?#W$o4! zK@B3NN+_TbGF1YGidm$?);|Z8cz5n~DTNPo4a2C&E|e^-W%27We-8bh{aFOr56p@{ zT0b!BFFy7>51D7L`k67e2#A${v7+bwuenYU=qP^dm8LdRsc!lbd)TtY!FHWIfa?d` z3Yw;27$#;OWSXW)zzBc}8#ir0Q&d!48}WQN6u^>rBzt@K<@dkJlYhSlE0bcsB}a1J z7p`L3z6TXjd;ZU%i2+H`wa;G%PfEP}F*~-6ZClt@7Au#-%4NxBGFaIR*>sY0I!WiY z&76DgMcjDf4>;|#Q%1~Wsj5~ib-<1tJJ2+p<}w>QAq3mEx3gzYSH1=PcV3L!8J6U(s*nrlT2*82~zs*R>dIKmgccnP6Uh(}jE&Z<>! zRCsVHLU8^CXLHPPM-59QHXI3)=u0qW%xE-K<;ka?BM=Jksf#bdFm%G9kYC|16dr%# zNp^R3BBh6-DA;z6_VyjDTeltotXjE>0}t4bdGqG6eEDfip0bMPUwnyKvt|~oODxOc z5BL6&FI{#iTer1y_dWM<^idz+XE*(vbI$rO&%f{ru~>wO6DP7_#S^@?awU7Zd-&Le zAH|cBKiu<2ni?B8_uR8s{l;4)`udnWX(GW;5LHnK21CT-ae8`s2!(=VvpM4N*n7TM zp69V=PZy1i4SADR8(r6iycr~Zxbr+Z}L|@$L~Li zu4I<4Ji4QhlpLig)YVnew()?@^g4s5J92x;qErvoof)^HgQd$RvsG!$?`5aFxKXECNBR0M1VC(Lg{ zQ9Qo<_lZ)&W_uaq8GzWHK%a*NNc;P4LNhC<7lk|4>6yBRUbrO>%O`@%>jnSi9X=-Ysp`o4+ zeBkgB+p)nj0bYfX_F$W-8>BO70!9FB0IU4V>~gB)B2i?6)K*s){z$HR~C^{fAr&aN*0aL*q(;kaW+r_-GA z=}*wz-NPdfKg@@gpTb5j$y-+4F39QA>M+3-*dR$d@rgovW-HAzJvUKj}w3>qatcAv3z zgyc?=t`7hLF4PB1(mAJ~xZUqc(>5xIw>B}L`?S|{*g&xE$hmm3)HX;}1fxPa+uz$q zSG-)lyFme}2MJ~1y~$CVAAjO$3?s|6e^|mJ8{_0n83AxTr)pZ)k+PC#8w$JRFVjVH z>-p@mSv1E2?CeUiwJXa(QyN*<-pA;=0LL9P4gq}O?;A)s-iXJAi6mpGl>iGjpYt3f z(KkrDYFN0O(bmh%h8z>xUGC|K76GY|rLQwif7eyMNLp1eJ&UxbP+b#j0AdvfR#Bck zq`WtDfOp#)9_fwtKCXX0O+v4y&QJkKTqt=MGw|uYnYv(;1Huu|FE3HN#E?F7WP2_- z&&BZ^6wgJ$A&g7C>d|OOnhaQ3A;VN=&}=L|Hn>-cUaZ8w}VFL+OBbUn+>X`aFBQ47=04zmOxc>SdbLb(5^X+ec8!05|RGPj- zAH6-jboX@A)zw8$PY=Dlz3lGj=KlL1X49rETy)WSH5=thvJ|TB3!aMMfhM&5kuZ5Az9kgpNY3tA+RNSG~KwvbAth()99?(QZS z43W!bnUZIa(y27LT&~c%Yv=}+ZI`r=DvF@7v61D=PXPhP9(ObW(#I2hvL75`-1xUu~G{s+nBEHqtb z#*Ar9ojPS$gJU>1=<*Mp!ip77aPmnfvUbfooWA^2q?B}YbfPEHExaaY1EXp$Is*Ers+1 z_w0&P2WUf#g_KvSzO88jy;`nZRtxf!q$>fkQjn0)tO#7H6$%R6y=WtRWo?RXA{d@v zux6Bs9+a{!&?0mW3Ych^=mj@P7wAOL3A|$q=mC0s5M#ZauVdoyMd9@9#_Zm@qm&W|^2;O_0)_|pOVu_Ke^ zlG}d5>findIcFaGEk2wRKJqadM~yB4T6;Qn@rRqf$9KQ`4Vs#oxcoo9%AzArptWs0 zIosW@8T|IQzu@nGe}MM(ot%IEImBWy8X6in>7J4`s>03%TJ( zKcTg`8N)O<;e_Kzr_y+yhpuZl6#z>i6bh2Fa!eRMo{o;)gu~&2OT1~CWOKg$P-|-o z7oB$wx~}7T9^GBtWHK3~lmr64varAxrb{MM)Ya87efo4>dF53mjBi6#H5BDvSD)23 zrVYoodF{1T%$_}ya5%))t=stPU;j>XYbzf-;aI}qaK$B6inKtek!c!nx-7r#OjvyP zuWys`{8gD?L{AFOi~3 zTC*A$8+g3kli03TnxYoa6w&<}3^@obRpnR>RdU7g?{ehAmHhVaOS%1}7Jh#E2G0NB zy*O@|aPY%i`_Iu_y8LCPk9`4vt1sG3=MT=LJFT;L?wfvvnS?P-Z*lDfV_EpkLy6_b zhU?0z3>NM%(xyeHq(KvW<%l-UJYog`Lu1Y6PQG;4>pa|%Vd=hgNI=yEUwd^2wsg4c zw7DERe;hv*@VP&)qsz$~+sXkvCCXHlinZ^vwk%=sR7F7(l0peqO@LOJMvMxNvnHh2 zr^zYNN?STEiR;lS_^sgI?t2 zX*n);Jm0}j*9Qn|t-h|6C6E@#gv60xOTYNMAGnypBaBN_kwjIGi0TnmJtCS%Nb?A4 zl91*RG9YX~B%l%vDntSr;eZd)>LNx--R4j=HMO6sgI)kBOCQ(jNPjQw3&jA-37_SZzQVt%(Uo#|bwi3*cY`5SBAO&< zO2)S8ES(fUQ;Tc8WWfYIKee^I?*OZoSB_~0IQgVyC94L}f6@1HM}om1lO|29czwx| zMTPHBRh1=+7qevXVqDil2p=ph```yTcu66Fi!O`kS}AKmyfzHsSh|K-K+ilVT1$wI#LA6IhoPkx9Hf?d0I z)6~?&{DTf4m$Rw>EPp}kU}IHbW<}IvWQhksM|G2&q@rk_~RY}jw`{b2QtW6OEchJhB>cDes zz~hW#o?>*vHva4U1aEEn2p>3bE4u2StG%3i!eiX`!iQ+7-%|LDmWIt7vEO#?ey#~k zq)R@3%9yQ;HdCZ5E$`#yR_wsAO9}G(XiNC?qBhPxavwBB@Y*{&_|n~Pva;6#DRFEU ziC>70>+;i;yRdARuY6>Gj-EG`n^cF--SZB+Y_Em{L21x;fvl~Skb#N z0BS0)^=}cy^_$k@)~ZG=#>zTMaHqyEH@x2H>8A!)9=3(1qe~{X+MAbg`+X%ELzI!`HN8%6`?33 z`+9l$!9ViTuYHP3I6%Q~01XPtxu8ZSIOa;QKMp%W9O`6PM&CT4k zbu0IM`!ZgA<}oh3{2R1Qo<@DsC_eX{TR7{i^Zi9xYa7RZd@5!jh~r5tYwrM->$wG8 zu532T+`04l$3Om3(qOjlzH_n&VhBz1(~AAhGkFH9`Ck#Q2WPMb zsmS_wb!U@M!pyTP&r}JM|UQy_7(KL;(e&uqc zl(e)oaq1~2``~TaiLChN6Fl_LqfDJKjezOvaRCGZCPyE8G~f8fcL)Xp^!BB2U6(17 zCnH^tSYC~O&6;-@H*Oq}NcdlJP9{&9#6B~o5{*Uj`R)*#wrruUv4MjZEv&vGP(XNY z6&dv+GGNGcS|v-+Vi+{Xg8syXKvTigRU#ps#j{5-=JD-p?6Z(H(k3DwwCf^yYbAGt zw8$x>e3unaiyN` z!1b6suARn}O{8-Xgiufv2ZV=ibg*wjmglzn#phlXT3!(nyeu`9&&yJUnt&(X+0D{9 zEp&Dz`08KQvnlHpFlxVVpq9UPJPAL0qZ8MCnJ<52e-7VoBA?rt;hGhjD6L(u&Z7AY zmRE6aMKll3v#SU6GN2|9M1|zc2|4DpIAk37>w1%JTjP+iHYr>1=;jb-&q{H`1Pjj- z{CRh%q*Y_EA)An37XvI+!B8bw-Z1G1|Cjc!)A|0HGii?dDV!4*w2{p@ocoW>G>Fn_ zEY}&?7?yx41X(9LV8%WOgH^I1k^>!-p67#{I#tl)$YI^d71u`yT&ZH)E})kL3JVjx zxPhS}*D*LFEEz;?BtM=)svxBHKMV7Z?hx${@8SAWnu(YL`;)Op6KSsQ>6Zda_LtVGA1Yk); zAcFw{`8sFY(EU&B&(uiCv~YwgXU^h-qegS-^DFrN7q{@quU*H?0~YgvWglk3lo@Q< zu!ixIW-xW`0rd5B;YxvJNU0ofqn6Ggb2m~+;165Voxnn1H-*p$~oO8x7Sxl8byx7CdTVlkG2J$Do zP<<=}L^O?F5$BR;Gkj=EALs6;<2o*iqTqQhs;c#;2;XOb^}pPlxmfKMprOHMSb~87 zvt|wW!X2N_{q`g1Pkrj*0^K|Bzyp|n&_Q%|c5vHmx8pbtnyxW^!Z_;d>-~<6Oq$+A z;$H@^G)*HC2^T<1EEc0a9_N@NkEngD{j1gC)H2s(2V{l+uc@dtKT=l(hGvuSvgn!| zg2B|$G>??!QSSIvl|`e5bzM6*Ld~}M%+*ZgqaQ`}m2f8E&hAcb@ zrsDBMPNZy1R+fnF`}R=$LBK&wO51QAUuTz7#&AJB(jgDs#JWX}MH z-|ugsBGHf-LZaa@F<|liQ`BLnDF=@?DhQ>d+pd3eU56(h_!D>j=o&u%h0k;5S!ZGx z2G-cIY(4ceC%mcuwpTC&pZpSyu!{eUy9S!MQG(Jf^Tg=BvX)Y z@;RWcjt7?<%ysM5a?{s7&!?{bA+zT#Vdnk|n6dA?LiS13bcCXk&1Oe@Y{hEv{&-RO z;ukNesKu62a?CMD@xTNB;Lhv5%;Pe1blnRJqa<{gBpsyzJ23R+rP2?YGr?!1Ez`j@hPLI@^Jo?OV4 zj~?AhOKUSX-~3C?Jo9ww>+7rB+|{6i7<>jF;yn+TIf${Xp{q=Y7(CyRVRUS8W!<`{ z!Q`-HRnDrhd&83&6-6bqKzwAC#5#*IM2e6~h^dz6r2 zp{W{{)xeJKMvmUn#;1NUk1k8CS{S`I>l*{XhNMHR3<(QQVq1R2w~qXi`qzs?QjIgilBtb;t<+!FDm>I}U;>uo0}exhh?G3v zry<{jv-WW~db024@VDJYN!zom@)a2%lXFY@w@T%h5!Qr|fl?PZt45T}C4RmZ$ZrQ?Hh$6|6vIS9o zJ!VPh^CX6VxFRarGisw;|2%wSH2fD1o9>@8Dow;tuMvT! zfh?!pBzskir6>xqShS*35MaZbuW|1$ujhdM=Q4l6d^$Qh3h6dI9w*b>gmvtp*z@M$ zH8vo0pRo#V^{sZYu^9HWsr1gDN3y#IbLA?+e|`upmGl9)rty^-GZF8s;l`^!&*eY( z4U=ciDS)f~xTfg_>2#(7Fby}8P+VJ8tI@5lF3trPe3ZW63!J@hOhE+L@xb;Zw(I}f z*4@h~H*VpBA3VNheO>WBrgILzeYp!oiDKoun1vX)ud7826~Xg;VeWpRkMj;`BAZDN z@KxYj-!FjW{Y&`J|DSC8?z=DJ$B)O#Su{2_psFh4$F;F^$)W*axqopw)$=^gKKsl< z;l8SBoP5$UQmGW7P-qZvXjh@I#1J5+b~Q*u5qw}yGYygI=HrQ!#rEDDpWLUBpgFii z#rVbuN3_LR*|EFE+$C#JR+V#~%+KyQ%d417L#F0;iws8Pm3brTLLy}jO#{3Pb&(XK zqYm}aZD{!}`k8G#q_dLI^?e}wfZc?{f?2JL2!*<7jrRjbhoG^Wcw{%z$F1ewCnj^x z>L$EuU4(+7qGwU1V{ByIO^%bV!BP}LRqpLxXAtH@R)1nUUP(oY53mHDWBX~mA@o*P zCIt7bft(93C;cE!J}5gL=&B?rJaQ6VN~$=kJI}bRgi;_kVx4jQ(9|S z!*g>bWzQv7JWm`(RKfR8oyDSAt!&!S!)14^qP5P%@gzo2q?XremDg&FZ|PP7$M=#k35P?tPAS++_4V-Q+is$L;~LsG zuHmVto~roUS-~KU&rYRb`~>Rj>WIf<#9}ep+jsc)p>5;3F0a125>3-ETU!X7d=xGB z{1r2i!ciU5{|VVa~;sgW=G84%wdO8Zhu$(S)? z_*G^xx8AgZx}ZiwSfe4N(h%}fwy}WU(KltzRBYQJ5GbC<93FV!Au^c^GiT0Vzy0PS z1iZ1mkJSkU6uWeG7u6OlrO&T^%VFQ~y-bWd5Cve``vI^d!{{Qc7Vwdv6xBry)g|!1 zWm6S}#)gKH*XGRG=Y9X)a_4eIQHVyPwQuhJ?r&$Xw4WTdqIX8Z1=AWhed&~{-)A{4 zcdmGo-N_W^A2Ek;U~r*0MF>tH-FqtCZ}Q>q0E(;kdO@dXlmANu(Pss#z+%X1Ov=n)1t2ZTc@2 zKhK9B4=g8#M53w^Q@Yr)N)Qqwx%0ttWW|a;7Ep_AA&0nTlBf6dzcnzXZ6yz|6bML* zeiG`{1msr2Zrj80a%Cr`Qg%Zi=uSB$EArNuh9&*$T5Fssz$J^uaQJ=`*w)$0Ww*V? zi(NSu2|>>Bs1NJBlgRP$U%brEFP_KePnm;lzruH3-Gk@qBcDf9f#v3~ykdC*Q8QWI ze~2n@&&ED(UEfQyrf}o|qX~u$ROwI^35h{aW&gPIWQ9V%qCil3;JDPTt1AU>x{zFX z%oq-t*}^@~ZDC4ln5#~mO6sn+xqowN1h=&B7*HHj3{4=UO->F}@aFT6bJ>?JA(%08VM@L5iU|E*mDgWzV-^xoby-aU!AE{KjB+zR@ zVC0XiciUDT`Qz=JcH!qx^AbXes$!S{5{cx<87%xpx8VRR@Xf5h^u^C{>4gt-`Nt0= zm32uZZ4zmlu8hmZM2`Dbbo1kzeq5+!?%%q)y14GT8~E;bzscp7e}y0Z@LFcgp2gc+ zGB}=#CUewoUJ(`J6rcscy|480>7@loH0$5MU{xRWp6B`ET)^fn+j#!D7f=LDpEZ*? zvuE<|yPHU*(zLd=GInemrfKkh+kfLGhp49;0dOgdzJSUphfJk2X|bz2jVAo!c2n0d zbd9&ScJQ;8+qv$fSxg@{yl#>GC%5pWBgSy~ijC-UD3mvNs?dN6m2rRNt6~TR%av7b zxa!zqT-0IdKD!F%X2mPxi8k&kOy1Ii&V)2kl2w+t*9-e^PUfRmcv0?u3^d|nfJA(@B zOy$Vf4)KsdP)J_x$#LngU*g9X&ExbVX7KwrUclR{E zs?3pdyi&2$BEgLT=vHpdE)bq1opUS3Vo-7Y!7hfwatb1v!n83lUV3{cUw?c%VF7=< zcrNG8Z{?wl>u_W>a9_4c$g^r0yY%CAO+oWYL8Kg<%w%p%sBF z)j_YXD-&KF*jBH8lP8{d8q2cKb)D<3`wq74`wr%E7TIiubS8uQ#51_}KSYn?(qmh! zNhG-I)}OHW11B(c>WuvUsRV){`uh6zj%*NlKR-KffmfvcXxlbjUEMtT=nA%N+fH4b zuOn%>P!}_qI>96y@GYSXL&3H^USInX4Gj(XQW#NC4OqW^BMTPHXTgGb9DVeWy!qza z%$PZo2REltU3Gvbs+F9P)$z?8?Jg&DNGAHa-BaFofF%%BS3xURuH?4c?qKtlZCIAY z%$d^}J-UTIfA2abP8iRdZ?9pW*)v(Qb_1t>=v2-=>mvkA^Z$U(e;>XosHXp`w#}By zAD`JoT}VR_kntq0r}+9-S(g{z?O|bahy}C9va>sdWjP4x>v82A2Nd69EglRIG&K}e zLDy8yIbs&iyuF*hZS7ZfmqX|%RDWGi+2PhdF`KF+SuEfwYXi5eE4cW`tu(~CaoiZ2 zcC_-hryIEO@)d=fvoGDst^a7_nhReqxoLNFPUi3L2Dzp_S94dF?6U{gnOfD0&}SWG z^@AHp0L}+2Kb12$P5v;#ROpE4@?&PYJTajhbG&QjK;1ilHXq>BW$ z2evCP4G4%*_GKig8U@(hXP4}EW7P2Lq(oIJr?72vT+aXf>jTwf0yd{?(piVPfKFK0 zIr)~r!RxLng1j7Hl^sW-DgxaF=?oFbjL>H@s|=W>^XJB}I8*m#g1J-D8aENS%_ww-?-F8j`W-SC9* z)FqSX>o)oGn&;xIT*+U4cN3qu@>;aK4`3h|rnk3u?*OE#Af?Ccx8KXgjqh^JHUCw3 z@4ox~%uV0>GRuydKyPoBwR=+R>derWRyh3PrwNz};h@OtpD6?lmA5vg`0QuDz^G9z zM59q+u^6YFb~59~k0TzB@$;Ymnm68fi=|7Kpeh2HbFn;U;2ae@3dmYZi-A|0QFwH% z$D#X56d_vPFMuUWlNhC2M`tH@-gzIR$BgFObI)YYo-PhL=s?2ZFoz#@7{C10t$gzv zS22CsR5oqe%+*(ali9PTvv|>>A$P`gU2NOIG>yVZN+go>^z_iyHfBT~L;tr?aib}2 zKgC}?ol-gJR<}0k@g%=IYBI+ynND5QAY8;yN(pP*_i*7Y&+^*t6j%K6X&lYZ|3_RG zS4wgSY{gIEbV7=tD}N4G?y&$11>X;CuNbT%9jsx~SVf>B>-lwds-mFb_<)T;>X2mh zRG*NL%DR+GA_f#O__39pPYbwlWqUzJqET0v(h}y4t$Rq@xk6JwMgONLu8Z;kTc1@L zi!@DON~d%IQf(aP-=3f;Bprv_pL~~_U+==rSbYAJSxh%2>r+mRbJXuEIkKChmPL@N zDg;c^uffW{|L&Ww<=Jk#6g;^uW?dMeRX2O?=;-A2*H`oCqbmUT%U}M+x^?S0`sgEx zMk7V@v3~-bx;T9&ok;zUZb5Mz0*cCo6DM)rvn$x$zJ)OprXUoBU^q;7ch6qc4XcWZ z?Kqrw-q|H;@InY&*X8r)@586hm{|xEo+oi!iQ{-!jz`Y+|7CM7Im;z$x#V&#xm=d4 zohF@a=iPt4$n`5n^Ru7cz^YZRGjZa0X3d&`5Q4EGmDPRO8a?N=<5@{;OKQFqlqS^n z_Kl%2VRYC|>zy2mS-SSIrxc++uv&lp<$*ZreWXzb+?<)XFr_-paifJ0; za#q3F`+v*kGgvM;?9wShmSw0VmFb|ewJK6Fs@|lnshTM%q!L-4?aXrH@zXeM;Ut8n z5-@clhF0hp=@%IFB)G0ePcq9h>v!|#SGMxb)*f0lh1`2=4#-qV5o(%(shOp<{)40l zXT)8;_lf5T2KS)g@#LBh^T_i}tb6xF(EG@G4u5)X91mXe0+t^ zZ?1R|a}bG&a3ISS=f1+v?wMXSML2jGZ20HL0RFsY2OF-xA4kHDY3^QF zOTGR8LZ*uJhCa800=K+Wl_~@QtxD-&@$naplWO>6XUZ-Cf#HA#(#COojW8hw18$|@ z4bLN)&eGf(C!kb6puJBK+DK7qAyb@ut=ia7T=UoOUZ8+h@Pi!r(nOKIEl&A}2&gg- z+RA_$)y=pIEUXkLz(-~_FseSt4S(GMo;S2&OwmX6<`h4To?monih>~=a;{zF+Ep@Y zX-DwId)N348Lp%=WuYj7i0UEp$5aB=`_HSVl*GWnGPvn*O!&02La#0Ev@@?bVVssLlGFdLTH%ZVcQ;?w?B^K*c^WNp@mv8Az)&? zj@*{0UYSsyewJ0{Iw9!E`Bqo?D#|us-TTU5m2b_>jqJPcY@T`QX{Jt^L}PPPQH_-- z0Yc$$n6H2RD*pNSXx8GUIyaV?~N=a)=Gshi! zG^(l={E2F<5Z+5+{fd7+Nh};@@zTZIcE??u`oR-vXl!8n_I5^%8ilUEcQ3*JZU#%_ z8Oh<_I<`PO_6ehK08DB5>{lhIRoR(%(<7T@1CgQlTv)dzSsc5Q4ER>`<)=hoX zW9r0J9KGb2>Hy0tI)IU+N~^rzZM!_)-siW^i;-OS+HYlCqYO|;LZ*uEp(2L|+^PVF zoPc!BpN!3tW#8cEq1v8zWE?zCqT~Tlz|e>&Vxajz)&g!-@S&9SCX)om)f2+PajeqC zhXBtFj6680fb_^w*+n>ltwgfnqe7+!=b1Q19OidI4 zEJieo%xenrnG11GBI<8u|rl~n~2wr;eW!7!!z!)tDaJB3&pAgY4l;2)z6n0tl)qhc`E~;?K9U;IN|!2E&9SQM%t0{W?(7={87M|y)uzi+amX6^n#^Kc#$dlSy=J&WBW9P12 z)Wz!v1_K4q6p4hHJ7+F8-|`#UckHSOu)4c@*t)%)bIv-0x88hi?Bb3) z?&8u*KEu14H*?3Ge;{C*oPE|um@r{{A*iogzk!!te2M0kW9X39OvOVx8CX+=|Rn9y6Of*eHdXjtZ`4eZI{SiiuYW=sV z*S|ji%lA90x@;U_ipUgj-^zBD9WtASXsBW`^$@;LpDISYkE#$fM1stm*g)o`EhtoP zax4javKr?mN#&d>flOc+rY|-sYB4nfk2ho#{_?~=oPN|3SPp2WMLg1tY4{UKqOXCY z<|erQ(iOxby&%#!F8uSQb9wFU2w(iku>{bF8WJs#MJOH_OJKPI%T}pVO-41RIdHC9 zHAN^rr>sQ{M>*S`FB(vDYApdT>Qimt#B;dmb_@SC@xabt#E89`;=^$@Aj z;(g4yIIhIVPwcuT7_AAmIzu04#Z;^ay8ANdno7`6i_?pe(#@4g-Q??`(qNY`jq6iFACpz~CW}NwT6h%dPuK&+M?0s%}jK-A3CbLq(Sik> zbjk-22%dfRIik@Rt6qPdmZo~fjcu#V6ztrE>$x1fbTK#HcoREz>}2%lQD~YeZ{+zN?du zp7jx)dFELjd+eVGp|E)ILXJK5Xaa!%J$t(FJdbkhd1}} zhsWRM!sGYH(9{yvWm;>L7kh1XbS9Y6vUiRHrmmpC2pG4@RY@}IP~Iw{DFWRzph}fc zwJjjvM|X{9-s}lXYTL}5(Kg#VnwZ?ygLB|Gg~?Z|9QcB=Fizk zEV`LUNEQx8N`dDoxSok^*Rx@J1FP0fsbF9g;R_@R>Fs5QLM_AWT4|l(=JN*L%Q&UX z0@Cl))IDmKjt!HA>$d!VjG&jY+OIf{h2we{c{OfTQE1jZwx+U!0JZApO9k3H6QnX0 zAx%N{ufmHa>%B=4Y6^LW0lRjWUQLiK3aHeva`_r87aY6d_+%NQHSn>e;53;l1&IO( z=ziK>l<0GnUi4DcNd4ulWBiPa$i$#KL;v-e?Y~ zNY|+lKCOz5@x40V=(3pg{l__NLX4X~c?jpewSyn8+>Kt*QQA*OswG6M7$Qrc>pEU8 zgPlsCm?0EZ12urqRn$m5A`mPnxqDJ#+ZJ25Zsn3oE*W%uTzTaceEj1VvVQ#r%<%^j z88^ECu8NO6I(9#r4nCc)eC2Dnu17c=!Y~X>)4(tc4A-N@wF#zDn2JKq^N=~4?vCBm zH8v5BL|M0fBcJ~C7pe}z^UptrZ+`RYs^v4Ps$x4<)%}k|BJ}iTa6E~Q!0|j@eXWZV zKYkTvAV4OaCX-Iln@W;SCP{ZD$Rzs6B$I64u#t~{)Z*A9T6~?oNPw=c?uzedikcig zHNvV_cltG^Rjyib+l{QUAQ&6%7fA--J=Y}-Ez?lrP9HyE9Or%XEN;2w*W7;RA4vA~ zF=^@)9(?FgRy^?(rlzv3eJAmFjMmm>KKq$Z)7Cbo=D>XMl~lO|7M?6|S~>Y8tJ zz<&Gk=wpvDdD295UB_{p{}BMo^E__*{hcg7Wmye?m9K}`n_yJ~dVl|+)ilLSPFgY( zqbP;i)>OyLsNk)4wy}8T*a9Uy>|>FVp6(QmD+k0NMYWab;6b`C>sDQ5>Vc7Uw7$Aq z=b~>M!cQ-cuynyDe)FfaRb02URo>M7mVV22 zhT6;F(`I6ruUC0)yDoN-KcJ#Oy{QeEE~vKYzz?2S$2~7^W>eBal(r-Km)f-$sob~H z-$f{GhEi{@d9YHla?LjCR6%z(2htrrYgm>}Nm_0h;1>jR1?gI4>`m#u%CgkQSrg-& zapW9cTi1^6xSTUCO2&3s(_^tF?NkM6wKO17*;2}}HL8>L?1Hva?U5$1keoiNnfa5N zxa@&7{B3g=XRq1LvHOkYJ1=b~t_?^t6fa2pPFq<8z*Uc9o+nAJeu$N;A1Xs18kliN z@4_1o53?IN|URcrgJwJxn%K$KEJ0kwc2SayN1 z?`!rwxi@z^>&$#UzdvTqe$Kt;+*~wT=kd7roS8Fc&dg^%^Lf8MulM`?dXvdy&{|{L z7FsK$QCn+G7$(uaL)h}r5SL&6@y0-a9cFZR4~Qj1<1NTY8%JF6ZK8b(QJ(K=_M9v` zAG;OD**%Gy+oGEr~av+L)IF% z*}Q+G#w0~@{&BPT*-OK0pU6%=R@9ipIKa|@R)0bpcs6GmV3k#?^Q%i!mkwOJ_7vvK znahR^8wrO)9KB*WzG5iHC7WUuRR-lF7OJM4>^ z&>9Jmb*U+VRS8n^>knW$IU!VS7a>fqSe2gSR_dv-iKqe4%K=;P>^cgkBD2ggB@r~ae7sJ>?A27k zRie)J$=rsJHN2{GY_ZIeiE533cap{#brjEyWGa2sC6k@$1PBYz3NHXfH3^j|Tzg^Q z8;@_~n~!g-Q@C9;z*_t3shnFi_D3vVNK%$-W=wi(dpbizERz$C803V*2SNA~ho7u} zmCJwd7+IyKIL~77qS2&V5>qMYX|Zr!Fomw)pMr){8br?J{iiPB-sg63@AfekbS2oZ zYXp=-R>_*@UoN>Z`G9DeCSU&Y-;+$H$Ye5PG8xk8G|6O|bUH;UmF8zZyA9>~E<(!= z)6qMNj`j|&xbljEP_zc@@lhguo#;RvJ)bnz-`|h3^EJk{JWp5GoGQSlwIVaLleX3t zK6?2d;(3ZxswhyJPNm?*m(lx%akXO1ae2gb$z?O3Arg-x(B!fi!ooz@A!OLV6q0D? zTvFp3>xRnsF2dRdCKR$6O+^ZEkESJv#{IH91vl{S-E4T}B_fe1hb}piP&A4Zg4VWn zc1}3{?`lCy+-7Xkc+KBg(3jxKlLz_q&tE|n!Yf3H4G|Tt!s4rEnw)z~FRGY0(Y9m9 z1~D)&f7-D@O~+tWcER0y_VC0LPqN_9g;=J=tl0xx_TEdH3OL`nb2q6}n$P~lr!h^F ziSY@(@y&l{=gu9(6A3(}P@WH-oSaj2gCpSxj_Z-j=71a7?PX3luq+ZdcXo3H-M*Kk~ia5(JG641n=5wcl-rWOuI3W~UEPdS;N{_J*4 z(>UmY-iz53b+R;N5a6n2;>U_FL!RPKZ-1HV9^K4^OL`gXP7t;&Uf(vtiz7My_PPi8 z|1N(k?JbSviMXEPzwUXOd$*5GgJmnJH@)az z$K_vNOmd=y3*Po1m!0!EfB&6jT=V%|#G@ma#sr5i-pwm-%wpw|7aHa5sw}${0(6E+ zQ}RS(FsYVqwQdGc*SQ5bPvf{1g@Fx8NJz43>HzI>g0j}#&{dZynmBC)(_7MsTZ#&Vo1Vrs9d3_I$y|9UIUA~q~&LI{F@ueFd!N&8IZOcHJ|9mLVE7+T=!Z&@!vdh0%hCRwYq1`G7A0VND#fBlAHfPo&{`9T#1USGP2as7 z8EOGL0#+DdhH;Z4EIevXU4SJGSyf@A6nv)K7TkbImQoOl*<{j16@*t`c$RN`{wi|W z3?KiSzvtvL&h*)@Sd_7eVkU4rYLZH)YT7#?1Q(q+$cF7heB-G-Xys5XpIl>}CIlZ{ z($CU4UF;v(m$#>Hii>bkkFyY>pyIBS=DXj$nvY%nVIFz(G48$Ze%^k@>4p6oUH0tR z%`q#EqNm4?t7>a&WA(|ac;d;YIPKK6D5da}hhZ2blgX+ZEQH|16OZH8TYt)&d2@N~ zwT-Mfc{P3gtqcth@$@s#^3sd1kPc{8%eHZqALzb&?>?NILpT&7oz9?@CKiwT%$I;z zJW48+LI@Zb7+}+ejSS8nAQTEstDL}_wOE!#Hs?$_?8zy?N)vhXr88$Kcx8WvFFd%p z>|+7^=#_og|9KyOd)X>_J0@rRa<0dt&u!$Zx4l3%ryDz^No?NUj92v#3IUyQ3xrbw zT&6l$wXxgpzz4t6&)07`mlKZK!}B{0zIe@veD(wP6OSdi@`5)w_p`^c_QXMEb#HAD zV2NrQqbLdLX|k_PD}a5f7`%!$QEnM{@m&Rii1dSjbu%ZZ8}DatE|w$ADk!R}lN!q6s&vC#W#L)$Wf6*> z#B2lYQ3#$FlK{FrSl+MTp%J$xQCU{8q|yslBaMD&JXZv88rtI~c$M{4>$_ElJi)qu zzn?!_F^dJg3GRGl55L$nf}HH$mNHlkh&4}U4}=idwuLwDGgw+{+Pk{(q{R(4+`vaZ z@)5txjMliZ1YRnI8IM=F+P?kmuk*2weS%kh@E6QJ^)kX;a}m-Yx$OnE-g_Numh^Gv znWq;@)(BA)e>J2ew0}QVP}Z*9w&^rX;w^1}CKQd()!D(~K-5FcOI}KH-%Ctci(a zT|&V$B$ux0As!9!rH3~`E?wg>D4lg1oIZDei;qoUnG(0iV9jFkh{ywEun<*4PR>2|9G-geX25TqP3| zvI32#B5O4~mgMFKUf|2Oy~Hj@HBMel^7+oJD$5?rFP(84v=In9PUcse`nh^?pWvyx zd(ps`Z*OPg)^+^VN1kO)-!9HQewb@+Uc#q8vcNI9}N(WJ*C;YVb03ja@yp`9{EP>8ma??X?H~r1r%NOM7TEVv^O3PAeOQ z-TtdrqdwzQ%Rpy{KU&tt*B+Z7mr64A0h*xnM6-{)M9OLxVKf9tjdrs&+Pgv*t04w( z(#}u>Y{AFAB7aegp*3dtU_^U00dXz2sttVYiH&udvHCoer^-Ro0oK>GEDO)e7S3zV zp+_<>|8O>J*ii9U8RW*27}01Ii#2!dT>j%fzQK=wd<$Rs$M>L33tWemM3@WDIgcx^ z{3!G0&8-Rc$uu6w|VqKYt#*y}eCcn;~U=c1sGvu{N@f zS7^p~%p{dc6@cl(_xys#e)$WmaG1G=E#e&)y&KcA2uC7}k2?juy-3(#WMp(wkQ)u# zeDJin9M%`*d-reQzC9!0X8bWf=;H{3cqq&}5AElQx6LJC1$trIU;&iLgWPL$ zP|x$&vT-Xrckkl-bI;+*D?ZFU_uR{pBah(ZlUGmA4%E0QhG7(dRJ;Vm_x9FK5sgKo zoOIF&D5coHf0#@ri`H<=ilbO@^zt$=*4xv=r#|(^Wxp+i;G>uSA*N|?;t9tUDBF4S z=JGdJ{RPpe?;2|F>|plnSqLF$Z*M1)bq zT?xAOz%`lO6x9xcpKZ_b_;>GS^}J5rx#AG|yW)gx8>KW4zP5v3KDmi|c2D?mVhsbj z$r-0zj)&tGv&ZtEb;NDZa>m@H`BV0Q8=i{s@TZPv)nQq}w&vW&pmFh{DoyvYBiNvD3b4dcTqGs=+*&$Z-BzS0Bs^T0(6ZfTYmbLso80?!U z7sri;4UphE4wIEZZyYvP^BcZ${mgkOEX%@ki*CnwOAE)YUdNNaxRKqvcQb3&te}pk zz%ecCi6myFXecl^IGay=;!4gr=WPD&@BV?-))wCPzW10$Cb&qnk2s)ACSNcB3t>;`$f&aQ*YUi$*OFMv<~w%_h$viAikeq+_;g zl64iaiqG4k76@Zz8ofrFY@U#8elk)pdRP2sAFuB?jgMUPH1lWgDzksdw9S2w9>w*y zb@GpYRc@pg54Lde(l);NcnUW;S|Rc{S#vx{Xi_7FXLbqbg=Sl$%$`0n>%m%9uGhKFz20jUcvS# zJ4AMT6eAWz7)DJHF@OF%`uqEcL?RqrLL}506O6rkh&=p6;TlFAhc}WFEM5Cf!U2h4 z**3zo$>p4B_2C+5ztD1tc#KqLcM)JkO~%K@3%eh7#1R~J_z_k2DH4s6N@{YBA`&(* zO^M|UPw9@$AELWG3L_&VLPk)3EXb75id;BaaF^yoenNH#&-3zX^qs)YnFLsRDqs>% z#Oq$r!2qz zxK7FYs&sf&6P!$XZDxdX=eIK0WtFStn}V~JwejHYeR!!cYP+na&|hnWl@kqalqRF8 zY?-Qmd)xqN2C@iE_B}m0x>KH_`7n1sc4V-xlg`#S*=z>Sb>+^|4$Nv2= zMOJDg62WyKomR9a{6gOy;Za=Itt!b=Jdfh!pe+#rPx}3% zl>e%<4;oa!a%iRSq-M<_Eu6oin~v7<36~)y>z4QO@zE?ld~Pp$NB0LzNf7p)2XVR% zsuq>mu6p|YPYAlBQQBK&*$tiFXLD3{3s3LbUH#pvQZmi;LGJ)YP$?wwXoPrBi*>Sz zYproE-@f_JiomSiUnxKnn3hQ-94cWW%9lhm%!);WEbJdAo6Vp-H~7sWu*(N<7yt6$ z&VS8=Ku`OLQeL4CQ|QC_y7Vq4($FlP+e%McYt@*1{G!=>MQR>=xfREexSogSX*^Hk zD&M63G3i`Xx@THX^^zDmfnRsqFz_P3m zYuR}=|!PxK!UY%#*z3+WDpxLrz3vYSLnKk#BB?RqK zlCVRxm?qmYX?jn33v&)#R5IT+u|r`TCpRq{DTFM@N>sL6I1(mV&_09K7K>}Y^Y6U$ z=>3GEF~YGJp-7Z)G)g!UAr$;smW_ubnRI~=QbKQ=LpGZu9Ink48?tyFiC73kma>eE z;8{+(ehjc_8i6E^#xzZ`xkCKtGT?zX1z-swrpyES{qkD^uq4Qtl4+RKwlxr0-Hhgz zX!wU~F3D^~NTG&k*aXv>X5HiiquMl(3;xRDO}t#qqZo#yzq^yJwpLuv4H%75<4C!Y zEcsmJnGdDW$}6%Q`E6Pi-YaxKe)%BCw=a34>4Ulado3iwuxM$CFuSK4%cveky4%}$ z&uY!e*!C_m z52XUPqz78lm5A`37=FiQsrhWY^Pac zp073dW_lDtmQ8nO=d`Y&68QP-bxA)h>9;B-f<7|{?S62Vgn*LCqck87^^KBJ?4(D%T=0RR2p*Wox0*-VDy z-aRC9nv8~AE{EK@g~$WH;=ZAMybS#1yFW_2wY_A#F|a~mGMVhOuFo)JDf?6I`HICE z4_x&EIPRDZ{zyYEw+qMBxUR-^mH&Q3;qFtUf^F+g?Vu$dsQ61kZ)cQ=iHW*elv4WV zA*I9)S;Rv|&CxjNc!4;opLnG_AC#47*)2Vw`#mYZsv+>`1;}0qQ5aWB{hhU9H-4LI z`29|SEFpMPgP`>c@7K%^*SsvRO8priVjBqC`pr)rN>0G@RDCIeAidkhYT*7({(HL4 zEWFh4RWct{ObEqz55BSS39k-2gcKKd75;tOB+Jg)0<)>&s^+ja@{9!EM3rt1)j z8klWu2qBm~tDoJwcNc2@ty!}QFPS2n%-|>k6|xJ=yE#0J$a&oL)1Pq0#UEnn39HJ> zb4dfs4wFu2rUxjDe2iJO$Z{ePXMCSi=*y9?$9Ma!`;P=aKY>>mxzzFD)1_zAE zT!{zS-K;r=Dkjp^0L!)vdP6q5^uco(YLeKeoU7S4o&!%Ig+NLlz=+^gilWwyl%g={ z5v3EL!u$M0NR%WB6w8E6K3S>_*d}9BVvz{38l{^WF}C%Xk8%bi?{cca+64n`Bpj~! zTk%Mk6PL_o@vKpDxojc6DL>}=8fT{AVlDB>nLGAOFj!s{zyd#e?JehCLS|x|FMs(fXstQx zth37EjFe@OGff<&Fm~+01a!tBl}eKtPa(#~@uY!ghf!uEUmvZ|4m(_z&u!nv*vi$s z_x)EAiN-5{p1=-;$z;+^>pW_$eE?afTuvepXLNJ6!S)q(+geCyNrc$DcW>QuG)17xO*=&}O9V)#)9S5T3K4qz#f^M9Eja&EdkN0nE+VDNL zWk27z;&ejx!KHrwe`yKXg0q*j^32c(IyEw*(5?3BWI7N{##z-Jw5JGumV${)uEs12 z+Cmn)Ds`F~x`rm=#hR$=mv@I$E<;I&|9)(UpKelQWx{uplmxL$G*W9MehCwUU>h2N zLJBa^zM&Ri35_W=meAM|EQ$YW2to$fhQKz!HiiE_c(qK4Z3=%PWeO}yGSD4iR$Hj< zK&XLK)}JBffuNM4P%cGKEbd!ssLNYNlxLF$JC()=8OHPtU&ylQ>F%Bs+%;-kN?+wP zPUz)bNxt;IqdbvJkgy||!mQH^^D_foGV3pQeR+YK%+vmR7mcI+KdpnncO3-K7uW(t zuaV}jj5(EM%XrA`pQ@M$*n)(uRr(KELgCh*e8WR z3j;Trz!L%)jWa%;WIU^|6YW)rD)}0RkFS56?|kPwjN~LA{j0yGf9`@B;6-AG!z7cb zX$ff?hKcLBH9u=OvF<*FEYZ&N^!E4n8qSH!~O6LmS zNv6kXZD}p7sTc`x(zK%fn+kFl`N%{=OlfkD>WY(0WqCE_@Y442pvYtOpmeZgAO5Z{ zwrTR#<=t!>&vDC(Hv1<=psvGF83Euk&=>&#G(;W*7XJ(a_C{#m z@CG2!kp8Q0n03KGTLxHx(e@3wAR09}W?^fc7z{rSY|ltG_zhp_+Gllq5GSQ?a>M#zUdXhPu>A4d)y|ZCyy|UmJ~HSgMTl1VH`%e`eEHcF+sF5C z`I;W=iXiW&wv6)^_e?NqbR(sS@C3s1lQA2edel7Spnnw$n-~2mOUs=Rf~>mK?v9%Rl`$ zEIe{K+Vj}Gb1R!(eTlgX7STO0=!YYO!c0s|O!NAD7ievOm0%*3Ma=-fibYL!y^Zo3+J-hev#FJ0(mbbj6rW*NVOEQ_nG)+RG z5Win))8=z}x_JLdu(Zc!+rAz=Pxv}JTKkzhp2ku5>z*$!;CKpG2LZ_%9Hsp~?Z4&} zjnOvQdPtD^P7|0xJ6)xBSGYiR|R$(tCH5Z{Ddeek2=}c zZ8OeRVtnye!wj?~Iif#Sw%hLU9RGOlIB$6U7^Xp{Fi9&TUrNOC#gqhMHN@8?Zl)re zqtJeZAv7r`#Tl>c<4;a&V|H7ptc}x-;)X}}@mDX4V4_-tmN7J8;cpEIMOZ*c;IlOn zLQ)eB40Peo&{z`s;*$5RX~Q%c??btq;wL*K5!-Ac5k)t-y+NZOEN*;FbNZq*iw0sP zeN=P(<714{iqsx>URg16U9W!~i28{DVTXAjX_38S7hgKBk64Lq*q2Q6_xFyol@81T z2x?MB{B-@WGE`ha;SN?z>sAcsVy;{WZSxpVxBNop*7;g%_}P?OHlJ zI}1R|wrrBgWGU+cz}Br>x$S>$)^pTx~aCJRWCkB8ls14ycr`hG@iO-`>4-Co+{F zv^7y*n{L;hQCK2^;@&El@D?7z1b#qSa>fBxB}FI=S?pkeKx8GjdiT<~{LKf>VBzd; zb`6bkXitKd-`HED!o235U*5~UJ-fN`kFLNl3?6xGJ>S3X`y)X{7^?(jiAcRt)P*v)v-4{&w^X#!XILCsF^no~h~cV4(rX;RA9 zqe4|=ujQkyb?G)Q0Fx!}mGWcZwEwDPtZLxSrgIF7Fg-fgoKc#VC7Z<6S!Z1U6GoJ8 zKQzQYpC2uomHy(n5nj&42wPApgsdwPXY^#}p_{ojQ3etX{G{wwE5Sn(QQ98d%coB7 zAyT61|LE(ZeEroZ^FoP9&%_Hx*JQ~_3y*Sr=Mrqb(raGLT?z;(5S}yjJ!@zJ(4fn^ z&i7m+&e()grX3~(?3<9jdsgcPk2w=TR({dxN5*1o-koLfU=d)ge=W)D*$7cnqj6{8 zIjQ)%0mT5}4_t|XL`uor zMN9bD=l+@3p1YL0ZoZDcx$19Ny?QkrogEx<$RV71>Z$A-+Q-Pq2wS#nArgu3v!DJ9 zr4+Z{aXVYLY~{3b-^-<+dKX6=a{{5DA_*GqzU6x?J9IW5|JpzBzylBQ!|T7paVMWn zI2@U@6wTxSOI88B{1S~u*|cRp$+Sx(bYPj8rY#sB8?7k`QS?-pC5%_7W|258VAHOV zLO+*zOjAq*iUHQN&vPmUtMuV8f-JOmFYaU2;dA)6JD%i~AWO>$=3EQBFAFINDlUNKPcl<#N36!b>==Lq~f%3l_{L zolf({8yhf8lSnwsA&1N>&SKLUcI?M%YT-4 zrmpCMmAK6cAX62AWLbK* z0+knWtdZqb`s(G^OS0Z9(?C>YYXO<9ZEB=FIE5xFK*2dGQ(8Y=bYNvrR#t}jV}z5F&eb!Q7qH6{} zH%m}yV6&%50G-D48eeElWv0Fqf`p+Umz$)&OjmD3OnDqrnv74lWh7Emf{XAcE|p)^ z&4J3An>8~U7Lbp@5-wmmbae zANVBCKmH)Qwr=5$|9zN${p!CK_PyZz3jkPj)CmmCJCsu|{6m(Va0+u496>D6QtsN6 zJ~KYCcY@yD9)u7K@7YBrJwYfOVPtsQw60G|!!L1DV`*(|VgB(~aKr8Y%W+G4F-(CJ zexikt0wbTKBa88xQczqMGKi;x=U*RVY$Af^d3DEl+p-JxG8(b#K02>&A1&Ar+q6+y zVH##0yoIQh5;F?mP-@AtmX_xn{n9o%oJd^&eR(9+g z;U9l+C*S_n>!btAlxLyJ09HIsTYDRuw``-ozn6V`_cGAmhf<1%ANm!8g9CJT_i+97 z|IH^paRm=P@F165`UiwVA?~>C=Uj5>#XR`X!}Rs_kWOcK<>glxm^F*5|MOZdx%6Ug zz4a$tcG-J*_PH0>zGEk?Epgs>{SE&3k3U%eE;ruvV+LmR^2GY5_`nC>&yMXo(AuS^ zr;mH@dw>&9JdRX4Lo%6S-_Q_0zV&Ccwzjb1sH0eU%u#5q$!4=$ea&?s4HnFw$C}lv z`1>z@neMJm2KxKC=)&{4@4g3k{D~(xcI8S|tvZn}eDN#9V^NM>c?@gTtS*42d+)uE zXPZ;pL84Sgf09Swzu^!8M{80!GevaB{r0A2};S3BcO6#=I% zN);5;xRpi-s$5D!F!L$-Z-SIYM$0NC{#Z!jxSELZCf{(;*on8u5Xq8^Qmr9jOJCht zdoy|tS_z=Jaye3fpKtyZY)S`Rb^%XJ-;@>sI+L_Yi%|I9CLx|)YR_XU=(I-N5vz6`^x zt=SZfw=jS4G8QaZP9~LNc+U<}$qAfX4yD{6wn-9eX{T@S5bTg$K3-KUr@Z4rzJApM zeDH%G<+az};J9_?5^wJ$6p6BXcz>16Zq$zCGkGg*hh1big z?jgSNgFE?;M>pc+Z)%`4U3nu6L-39>*75oq8^~tUtUT^Go_gX5(&;qg;}fi2y^44u z&i%0{L&HP#_4jh#!IP?&XIp!EPY}mx` z{t+g|##w#R@gx!nHf`8cb{=QG{cS{}QTFWI%h0}kghDnWqe(*H5aSaQ4D|QY+tWp7 zR|gN={}AWA;|zNHdinnMZ(#YdC77nk_}B#V24}PGZR_~aO*fOxW@t$y_{blAkn3;w zA!B3XJo)5PT=B7waLu(pVCAvLfKq(ugO_o`4L{`AV~-&kjp8^twrt(bWtY8&|M{QW z85$nugyU9{PN#Y8wbvLQA7|&TU2NaJgZcC3;VF-nXoBaTe*wpFuubFtyyjT5fKZg8 znS%^iN-5CF0k1KE%W1m@r(G=C|9wwammG}R25z4Ado!D|!R{Uw2FYxBoN7Gu<_Pcl zWJ+@vE=0g!O_Erl8@S*Rt$FXUJuF?&jtmR5^6Gb=DJCkZoLLcbB#2v@oY$Pn_qc*j zF74rCryWu(qO3K4{)6ZF(dN{oz_Gj;G(!`jEOezMYNFk7vcjt49j$%bm=v79q=gHX zcXR!{JNVJIbTw!Myvj_v1D0tp7}~X+iIGt{d-^%!;>$R0?b~pi9Ep~8S~@z*nDm02 zO2xeiMItq`0GqhM9JXvFfBMC5^Wa^#u>38poOaHogu)RlJH)H|n)Qebx2 zVGCKX;7YEz;-f{+K#Al^zT8t$enk~zSV~1#ZQG`!qkYozvn{*CMQGzGT~j_~IO*WH z9;Rtv8vavgTQ=ETHV?2C0qbW9V3pS*)a4ZM&aB7fSKrOQIWFg%b{wZ1yM$FoA3?}A z*|2jj|MdMk`S-^+l@9|!<5UeOrb$;GL?U6bnJnRO7}M}wb@@6_zDrH;>~k-W znn*G_Hby3sC6P$@$FprxsWejhF$Y>JJkQ0pLPVocT-V{T_3PQUcOL@-1H@wqY}=-P zpr1W^_xPDeror67+3eZ9o4tF7xZ{qy@Eixvb!lly5DJBe#bcz>8KTiBxtv2wJVr}A z!5_TqA|AN^LApA-h{a>va_g-uTegh-`$uSLX<=-9oIQK?l1`=RXwNct-W+I6U|ANw zUw$_hDFSOf8N+fA;AuCnoLvgA!Umq3DH&p#sVCUzPNHGZD1lUks(;MJpC#ADLesOR zT8pOdixgm?pk@Y^Xt-%k?+S79;%>4z7gGqLN==gfH2L+Vveo@AW>wd7n+ot}m8R2@ zY~GjT-|pFr=lR#WerLvyaVqV|V)CxOcf9XRWMcrA=q|A*5{(5aMXP+>K2VdU9 zP{zTl^NcB7L#kk!&z#np!wx%?70Zs`+h6(&r=9&SqOI*nX&|LU$ju1h$6iS(5kexQ z5xC8az*QD}CZ%t~f_;7WS#g^XvS8!#+hu;6pAw4@lD579&U)XKh5dGJeuGz^ebTRm z=`|0qCS$NlL0CQJX(ks#8mPc^91YuuT*lX>sT#i^lXZxjMlh-M%jG1~g-pt$fgj8i z!1C(#rhH@X%6fd_x_imyTrPau350BmH@5HQi`V^}YoFR$-T$<%l4&U1Xf#J3brd^p zzmr+B27E9jC9~%aa{FC(v1G{+xiiHSgJ-zJ$% zF?Zfvo_ywMLeUVJY>pL2AMNXHI1blb^F5Xxy_BuncW~s=#pJR%Mn}ilJG7sr%a+pL z-^Nwc*T;?>JD5FZ5T)RV z!x!<5Z+w%}PCJdZwl)%NZJd14@x&rAMn*^3yKiqp(idYHkMU&Am)$7QASxB0EUuSm z$57OcL6m41m5i;Wx<;krW#xBENuzSX%kphyv(OrKT1Ca+-mFP1j~AYNF5UdNs_Smn zjSg17CJc2T6LVLKs@T7XE%CJ5P+QCxO*P3^1dz&AfIwTIJ!i%VHsuL4ktP9_z!oZS zi%jo2hk*AUKO5~Sp58i2SKJ~j92_;h_DklfCu>m)(AlPLl~xdy3eWZU{;NYoTwR<% zG|>YEuzRASpM^}nzG@R*-u95m=__XQ&D&q$U!NGB^p`y?%c2Jkl-Qm%tDj3R{R3{h z?GC>BnGgR4XKxlpD2g2lVcK>fR#ENhJq^_~|gi_gK%oX4O2*8?OoS(YzZz}Ij5Uw-() zjynBZl%8zCc$|CoJ85rkr?s_}*48#!TUt2#tTTy3!W_GD1p*i!o!~u}yo+!+%&L=4 zEXXjdT)7g{GMPPlHpyg)L_Egg#fvcvgQJf+%9kaWGY8uaamXQadG)o|dGwL>zDQfi zjN-UsS8(rr4-g7P2!(9=`ud24Biwu61I(E-h+!D4J?&K1KmG)#ow}9{8#ZzC%|GG1 z^Ufw53PHfcoxElZ|Mg!#WWj>@bar&&d72x4bThF?g!Z;J&O84cZoBi1784B5Qt&sHERMMqt)V)UR8toAEeauu5*2n+ z!tCxy8HFu{U!*x}G-+_BVFbhhATAeC@`-e<{dCCespv@WQY ziy1ht{ET=yH^2n6H+}1L$zYu04(s9P>$fs{pq1W)O+>@EtDC>6z(ls%)f2GOXIGd`Tk`O(G~3GxvFnD8xnn|=F-jpz(qpLdAonSjw;$3%*7dmUg&~fL z3SLWlr0TW1tc4umD7C}{XumO)?CVpp!ZpC}}yz9AyM5we2PumyU zoY1J0m=vF{ovz}uKYEmbpFP2gX{Y`dYcN;{@S$RhvT?C8A9k;TKUOncR z6@~TVk3ZIbcw@yh{57YX48Xc|ZvkNG(j$GwW^4@GGB{+xJhItLG08-07A{=Kf&~l8 zI><#AUywg-q!cVYatTK+S&WpD(@$Sl^iAgnW+7O5 z7=~od;25|r|@5rq(3bkPME zhJg@*cfb2$9LL47OoXV;Y^=1qukTLrkN1tU+3h84n^Q72lUWx1COk%>k(qi8*{jkI z@{hNd%<<$;NBGQJ5-jPD);!!TPYm&$=S@;Z7p5?)%T$+u6kG3>l`%5Ky=%ZWj!Hm88BaY)$V*KWFg)`6a+*|Wj7Q>S&g)(d3Dqwr>DMa z4hpZL9m2K&o`aTC^%F7kJ*bYmFPW)u5rz%+IT<=8aaU;k7$UDQK`5OpP!t|5*`9N! zBhw%-g(9b%#@eP*BTU1E$ImC7&GH|=+RRnwEJ7M_ESV!ajUavvjAug?*P#hnf*je# z4p7ogIjNb|9p|ebIEtukuzB|wSA72&o*TM;I#%i)ZQHS9gB%!`-*m+0lv#vD zVMjm3zb9<4qh#hWtTe;vDLQx9cr#*28(w0u7)zEMNhXuwsHID*{J-^TR~6NoMaec% z(|?=~+Rt~cb?e?jEEdBk(F!Zg?#pklbuOiGRFxTl<;N)ZWl!cWcU;BwkB{g4Nbqb;*wT{f3e`KKG;7d3<>4fMy4cSHS>;EE$MJ z$zOk0sMB1d8C9n16b+f=R2F1?S4f*F_}nSIw1tg=B!@2OyOn6a1+@>A_Dc{MM)S0t zB{aG!Kv*<%@6Vgx%FzpZxaon{*^_c{91lYZ!hrVFw3=`%qblk_LfDol*K7K@d~(x% zdY;(C&FgnC*kbd^vybHCr_ABPn_r==iKg19z;!jYB?>HWe@O6p(rNhl-8G)2BVqHa z7svVG{crHevlsJs>t^$bJ2q5x9Y4rjmAB0ASRRp>L1AS-oJ1TH080pg<2XdZ5kRn@ zuayUC04z^KIw+STg(RB|*sNkXE(2c=t7-MshFydj=;}!DXJ;(op2s$z990;?wJy~R zs`##e(~g}-Z&&MYtf39VU~q8uuk|+%J#@jr^%QB?u+PCZCDT;>|8;RyGk4#G;K9)_ z>8wknv?@I?I-220$7Y_PW@Nn72YCIy7pFqFR|MI4s)564un=^{Y+Azyp6HMWn{=~XOHr*5t|{i&1>?=Q>sJzJbQ#W+%g9GVhA%`mNvMgZ z;H(wB47SFaU<4F<_iif$*fz>wS!htXrtej!DR|%NS-7stFP_`Zk#U8(6Ou$Bp8*yWH&tGBOt1LBBPBI|G%uA>I zPJuN)m|kghP@GH7bqbwfPJb)<=^fQsnZQIcQ}|9cmknZ!MJY~dJ79nnAWv1#41{fy zi`E{=g=?17?!Wci*pjBR5q`hSJf<;_h=wfo@6M8wCYc(3cfU5B=L=yTBsfv)aM?kn z6h)Qz1{T-x3VJRFx=4JW(};Ug3veq8lVwQS(UWAH)ds|0K4T8YE$9ehC(7dk%cPbB zT>H>AzV+x(!#}YvrOL*ruxrTd)C^8v^XnXVfsx7DYXdW7~IQGz4M8g(0fBJ2~ zq*5ZK;OakK$5(&&D1ZCt4$LN9KckMX)n=4@FJ#K5&(Q;p?}{*#aoITG5Yq74_EC;K zayEUo!S?Y+CVWM>opn6oC8n!0YBbf)UfG+(loBmKD9syNM>+lYg|wQ2@v5;x{GXS; zX?9RFq%mXT&;gBMLgKn^fNNl&yQOZ7>d?qUf!%gJw-Q7fKnJjOW*Mw}M14tMpA=%s zV$Z){4oZB5ME_sHRscAjAYCI^HySqllz8*tIL}(yg8mH3ZI}kix+ZDIBjR}2rhyQU zb5*s05ViV;2-r>kJFcg&3>O-Rx6x?a3OAHx2wJ4WSQBD}O8fVvx4p3pyg6NA43Vvh z|Ejm_$tYBigaN)AGhw(;sFYaUK%P=eq;mx(M^C}ZO?PAz0!*RNZno*8yt3cnudn`P zL8w*=!J3r|IqvX2uKwxc{Nnk&NY81GcM&j_wWgqMam}T)E4xEh3w0x5xKq*)ul51yQ{F*wGI_}efR46A-Ceiu9WPc$5wak@8)W61z_eU&4ahW5 z6(lkpME~1f$M1Jxkq1wL$FJ|25u`G1S?moE)WSM=(59*pYE?+cQH@+DJh&^vpWg61 ztuc$ge#c?-wMV%2{!OgkG*XrlU+YPXM=k#L+#|3I$>06-B{uC#^Yo4sqJiI50-TD} zIm3{|gar~K-!HYFVZ$)-lzUK|j!{y6EFKGEirR`E8+R3JFWQ0LrVK<=4L@Kye!u{$zyA=u zW5)(vI;$;x*d15#%ctJp7mvJ#m-WhGB#O1-O3R4&?t|l(4|3rtM-mI$zwdy*$&N2{ zAX@qB0K0ky4>4UiaE;I&^i0JU387wj;};WXzQ*2aoO-F5p#&hhxf4KLw%3d@je+?nF8P2j3^ z-ny_V!9i)w-~H$%(z)sNDN|^0Gt=tpMtK1{oNOAY1!3tS+|0DjXSZwDjIG0Sn$qhs zfgioFouhv7G#9Quf{(m?Ij?LV;-7AOn2?)o?mC4eT>-*lVH3P;Q|I%sJ71u;J;JBX zKZd=dNxpRBugKIqhA2xs5HmEi{Vp%2Y2v!xL2)j&Z5Ois!y${96pYnyU%s?!qA&pu z*&#g7!;l6!H%G*X0QAfhgH_g>N@x9J6Dhv>KhN;YNOKRxtvg;~$?Q&6E}8rL-uIir zS6U#^Z;G(uLCs)k#aO!fVYf_4uW)gGgEOs=Auxqt!c{d>34M0N4OorF0b5S1f-H(* zc(lY!dOPEF%f&gahbbKYI|3}jAww3Utf%Nn+8A<9d4`@8f|%)%Z6cvUYDi|&4euWd zgC&Qfa|$YI#RA(eHerTt~f zpaI2!&09RJx%J^U*zo#p)^8h|HXz8lsw%cFWJ-V5+~hG+p61VQdy#M7^9pfOvNP+k zBj*LWdd&bVUB+O6pRAx&{Zibumax)X@`J~)u6q<0fs&Jm`RfY6^?QU>zk6zpWth00 zQ!|^eSQe*vuXF?byQH9ulemzK)c}7l4drlL7t=7XEgMgHSf)iX zl_V01z%;e68gmhrEaS<>2F!)=Fo}rCi~Evf9gj?=wx7MUgibSo@UH6yrEip9N}$Gw z<~R<9Va!N?eIp9#rOVLJFo{GQ+dfEGyMr`zZeGN7Vpb0T03ZNKL_t*Gi2ew>M{_(k zoWq&nvC9BPQ(o0bX&QnqOR)3T;3cdj^Vnlc{`T#&=!n}~`@l{f*p{jqTl`WvDk%2X z`0sfRg_tN?z<>X0GmmW?Dkeh(Y;%6yQ<~iqKEM)y4dAMVi4;#j#!*$^FlGq1{} zPmoMGgqs#z6n+&C&ugMb)n6Xj1;=h1H3$O;0#cz zg5`{c3_O*qhzo1%naTIIx~_0tA=B_XI6KwNb**}kr%>_3FikS4>Pbs3mt%B%6gN;; zudciyN-ArJf=XjP_Oa$?!6{p&Noz}M)eQ>SA-tgai)ETbP2sB_SDl3)&-ELlq!+)7iGY2s@OPLW8$d~*eXWlj1KteN?^2*M;D{j{Lenq;z7VMwM za@e5BvhEO{z2GQ+VpnD;1UKIO5~=L}&)$27$#Gq0-oJY*b()@>k#o)eK@vF+fC-q`vC`c?s-~xV zx+j64*8bM@JpEM1>Z)5eyyrdVyvHFLo!Wg1g51G(oe6a@)Ktdmy8$zrhch}mG-R+G z*MCpvjq#3@$&F&LB08=w-;=l>Z3AXFf)>;orm03bU2zKw}1hJm3Q^bPb=Usp$O zZy%oL;dw62&CN(DNu^SFp2y;a3y4@2zUOn~=uxuS9EPFM-rf$t?mc@M92{cq+&LUP zc!<01yqmVxHfGM6QCPsbyL&ir;2UVDw>$NN~eY$-LhwdAr{9LM3Y$2a479%r3-I)-WR z&&por{L|k-{$o<-el&C>8x6{k~{9Y7l2FOcQMaB z_Z$~pw24O^eT;L@Ig7_0e}b;AE-ty`5~>n$s;jFjGTjo$d!v~+by8->l&?rBMZFY+ z8h|(o&Tp~!AjTK(ou9y=B&>DO3-uUeB-P}K7PS$0ICxQ`J1PX zv9`+K!j+8$HR`5ni$A%z9hK`YTXf3Ze1lXp0~>~*T&i`QzI&!pcdUE|6rhqfmcdV8`r^~#5oG+ z9!Q~U63@5EWO9Ye4HnNJINcCFnS7px=+uLuH7SBtKjAF3ll(j1D~qKubqNx@f}=yd z$LFWYIO%jYKZ?N$>RTz#E?St>NjZHQn-tR75>+~FM(cy1Pcvrm?oKA7ERMwzkV%wJI~{fZ)V!GR_4x~$KQSXJN(Vp{+yd{ zz9k6I@O(}`<22T-TZfbq-}ia-)z_FiXEynk7XJPFKVsF&AejOn+-gsjx z@pz1`u1@C8or@WXVnwV%!{u^$ZvNS=Y}l}lJMX@ikKJ?w+unK`P1hJ2OtE{e_0yZQI7tW5=kgtK-SdPx1cuU5rwSR4T=DFTBL2O&huYfd^T-bP4H9mYq9x zk;`S7Gj}$RKKdAI)~@DQS2w4gvW}x2N7(Z6E1bIF6dru&QC6;6NlkS%p6BtzlTUN? zRUhD)=U!mz)@@8{YhnI^`Mmbp>$J7C@x~il*}wk)oO2d~g9CiviYxf#?RWC=n{F6; z0v8IU@>7m`m}rY=g3qt2Wo3Je-@Mt&JqI!f;Pg6^Z(K2x`R&QT9atYBcl%DB?a6a$ zYn-{wRRxd%P#x8|U|BUkdaDQ9J4t#@0tWJ4nP4J7b>Is-G2>pqhZZJL%IEf7DXKNW zpIy?0R?8)$@Ti<3^+T;CeTQI|PvK!Bt!HYZl=yQCcqpG@3uaDAkqQ6sQi{lFUbeHE&bD?Fv>9LnK%0Z1~nsksP&vbY!oM0GJGeIf;< zbME8;maY-kCa=pR74&D^lK)G@^hsq(BH(C$CcO8Oe|UHYnv^3oD8m|)UA<{$wpSx+ z^(o;b0hop#oa7V(zuzl=(To}$HLA>xX~5bBi&qXgm4Tpok4|Q|ogxvc5~3vDuP&+c z!CBSZvpqG1nuKa{-;osnmV%ufDL(a*O-rnihO)&{orK0v6Zr5{0dVf{<2<~zj~mWz z;_m%ENznmDw?b7crruyicguvTZYS^E0=sjjIeKFZTImPblR!LXFHrb(hP1Nth&c}nOTNENV&KRkcx z`mmQMapcHey{&D|lopIBxd;UT!1}|hPvffd*7Lz_d-%ieJ;1Ajc~;fN`Rf}mmB2-E-f8Jc)e*0~{_3eM)!VAyml=bV0L?XDJ8w%wGuCsVN z#yRJlNi-Vco_l`9+O=!LO4%N9zICKct^++UQELwCXb#?XJ zfB%D=dg`gv*CeU0uN#>#OoQLM{#xSk7;kQUi@|{*suBtExjdF-k7hfuy^aA=Saa2P{dHkqMR;J2=>#&H}>Bk(C-e(C$zw(TvdtCF;~wD8pC zrnwn%a`Fx(Y-rB)H{}8_Cj$Hx$J&M6HB>cg;20nk`94td)<=lEA_wV5! zw-0gM>IUYvB@5r3-%`aD>l=CH;SQG6nStdwYHO{JGdrrWBXx4Hs$vXX(h?^; z*KC>@=dVAw07H|sJh+QzcMoyqq9z0|vmwUyXSVVECp)lAy~O%oHZ#tP2h(L$4|GkI z0l*VgHt|CjAqaF$@>ee%A@zL6xbtjdTn}A@0h>70zs}@K(*=bJ%jHb8}xG5*?Qj7ro>C%1`w=}d#;6SCIqd%CK+o~gc;j-04B6_LSFW}J8K3>{+6s9Go zeC_Mz#z^jnGuW3OlZ~DFqB+q*J%;-=mf-58)znp$a>?%NlQa+|>lF4R+0TgOm6a&3SAA6jc?bEPr zhkQOqJP{|K&rwrTOE#NDlUiW$dp^2h;Mh(8@LZ34K1Vv0CK`*9N@oB?E|(`3k8h5Cm(@#@dQ^)j~Gg!ZVEp>Hu1;259eLbm6hTh}H z@jQ<`hjue-?kuvoJne0*3=IxaTU$eYT^);;EauYpT@?D6^>Nu8Rf)=Z7u&R`#-(eT z166EbMtz*$JH3^E+&)BA%qUCsU)f$wgMNe>OUJB``O#J#VOC6M$B=u{yb43M!1q<4 zj9&PPB4Nq#Q#!`@ZwI(!aXrbXi4gGq)h)bwFjEq{v|&~?x2Yo}BRZb13eqJr>tp=- z&3=CT#9r*2i|6}zJ_udo;)U9ztg;CK76e&t1Tk0F3$HAPQgVer@Sza)~`~4 zWr%=Ln9OB_lVCQN$MJk7BQ>f?L0k_qW5+u;HDaVPm@SR*vMdeFcW}IkN+u}|_XYr~ zxys`4mv3=YRLT27 zl)9^mUKdpsqSn(*A)MW!Se}XKIttm><78K$LfV zqySSn2(LKr_~ZaB6^*e)VgB@g{1Nxwdmr0(?4-G=k;fi?j1OIN z4VtE*>qcdORaox@?M>BqZ*`WfOA<(>N0?(b42;(`z4(~ZPX@pmlQ0)Tph@`ZEl(n) z;QeQ><+N1``NiyZYLanW*XPbBw(#}ao?%D2)XzCu>Dl*v-gx~@bjx7b(j}aI_Sro7 z8wUFY6PIBaxUL&S_YYsVuH(5bk%&bmouRpO~+BJAeF=zH1q?Fi>&2NAE1kXMf1UkAkAM0z zI(vF(Y-l7BiE!I(chWwsl}I$k{1tO~ARRSzM)I#SCoEF9cW$psm`XK?t^XX1VjlL!@&KIXe)5v94XoXGn zB*%~~@cgj!O6gZ)CZL=t)98*;G{q%7sXR&rK+Q5dUfv!ITwf{jj?b}7hCjRgO$KvL zAaE%q+q$wWs5OzwXHH{`s)$4>L2u5%F#Iw=jPIdJ&T$gwCp28g4_Qlr@7wrZWw*uf ztE|wm!`~QE;CZFu5aWe`D=O<(MRbW>6dyGiuH|?-OK&PuP+(T5Q31q((G|pNIe0>m z^}R{6vqO2eB!1M=C7J+x676~1K7w z1edRw#>`rS?Hx6sbfgLdOGjLhi~t8AionANU>JE$$@8*3qrL|SO~)`LtqpOeH#Zg+ zye(`si3I1an8AXU1o@l|UVaRKGE$Iv7~qK_Ktthq2>wFmsPNli21*EoW?)64R97Vn zI%XyAV$)#RoHk}QrEzQ z7G6@5##rivpqd>xiZJlWhYXgga0FjLr>lrcsF5QJ!BFV+tCfNqmsXQX<+*MDh%2pM zD1LN7D?fX+m)CmpW1O8}$R0^{DJ>MP@O=*<1bcSv#kOs(zUoSn$*RKllu~pZ>ty}9 zbu={8lT23OOG#&EC++QR0jnq_P0dYo_w=xT|9%!NT7(|D@eJK4yK05P^ZmkToZeiE zrxZp7<29Aa7QmDj5<;UC2xb8#B21^#)YMiJk43okmv^#n{{dXrC6P#=2w1VE#s;L6oPEyO zJonrSTz>ic(KQ`S(|G^;HuC&)FH&FMfUfJzm@$pryY|r8)x)x7OE7eu%PzZ=uC6YY zFJH!*)vM|5I?k0JyrPiFXXpl3Uv(w>_wVPbD?dn6Qxm71wt-|a$@SNLgx+S}WR zMj~8){dJ_%X=>|giC7jbEiC{f5+g`{)~uQQ{>MLt5CX$6xaxzK2X(>1*t4~3*A~9J zYSl_suU=K?q+_|t0ws5s@q<9sl!ms3B9ph--(`mjpW^tCO|#+i!tNg4I@rgc9mLhd z42|x=9Ea@;4OzvOy^6-TiKz*6O)!*oNey_+Y0%j{lwrs{Io6lstBPWjF;iBKRhZy! z>!je3t)0AepdWze4-V0gFxb6C|8`X(L3^F-~bHDXGe{jJZ z*3B;${_O7Vz%42pBEnSv{1gkP=9G^UPAZxv$tot)?#ZLD!!fGs8XgnqwTx=6RKA=6 zvP_8!OvO?7+R-#$_?IWpWq`3=U*Y-z0C$zb^Mgz&4{$ui{=7FO*LODOl~}o^Au%Vz z6e{S+IOOs!$(Y4iOWIktd}f7^6vc1fJaR()RFjgHh8p5gofR_zpb!M`k1$Q5h^-Qc zqCngcFj5LAioi+;U`7CjK**xs34xFrhOQHhMoLt$N6#fSi8zU9BwUEp$Z-*)&Y^ri z5lbt^il|oO_hMbssjaT&z1)Nl;D>wVVvoa~uCFmknt~_0^F=P`6A8YbSn|VheT0x0 z!ox34EEz>a&rj$)aMfJiIWWK0$BWMJT1v zG>!RlXL0c0A?D4S%gmY6dH(qq*}h{Jr=NNXPe1uI7o2x);eT{pub?F;f_SiSE^TS5 z31TQJ#CY}&W=D0mAba0eJ~Eia+NSQl9S>j$N&?eFNXG&k%6okA=TDKhT`oRr4UfO_ zHh*&S6YS4bj-46JU;(tXwep!ye}YUV%V`@nP*+!nl#gr_0fn2PiH4JXY_OMKV3dC@>o6E@(bCE#S^ZEOSc3>Dfrm5q&K3nz; zFe7d?f`PNP$KO5L$43^|@`Wpw5HpREtQl3HyFKE!Z{w%idMlsll=9TU z7F4WP7qukHoqB7`i|c&(vPINYMG!);_tw|>(5da5GOsaAe^xxby_dzUNoF?0OJYUl zMD;P%%119YC+x{pBLU4&r_)>MMDhw|k$4QuAZ+7`xp0g zGmx4_B0BY4SWQZ5s*==HB`1Bai={Dsmz%C>71^YB?~YRcan;hpJ{BaP_+tjuE8v<_ z8kt#d@zU*k7;?&a3p>0_Gjv4`%iZZ=RCkh!#GK^^;dBa((3f#&Wo&tsNps6N; z713#Vx`U&(PrWH=Z%$AZ(TU>lloDkk zqk@sRtVkrnJ3DsrKmPPDu(Nqqu3o_x{@drUEQ^R~kjZ2VBuqm?J;!@{&@_$fuKh3% zKKL+;7A_K{!PknvqcWY~FODF0`r0n@H zlQq0~p2vX$2iUWBKXYf#qP4ZP)E7I(^O10diLI^w?3*S8%2Sh!iJAB-Em4jCece)K zw^bLY{m#K0U;fD(eCq7!oUx*HBndebk*qU1Xp5U9qhkxOTDr#cYIBr2^NDY^06(y&u$~IMM$<*CxttwwN@S z9FxiM0vB@Op#t{P_d@v+PlaGOkPdP^h3g0JJD$RI6^=LZ+VK?Y=2z2P8yO)T3QU$0 zu9m8zOVD%k2xTBWyC~!#_;5j$!6()?5;ZmMe7&1zIrS9d^49^vWco>73p-kgpBCw>IyDAR{T%I2*|3ciWXIEA7wxtPviSR%${i&*p7{%8)4F!dGY}kWq^pX0;ayF zxNUd$gn#6}$8&(DX`FfH8Ju<2nUiC5{vX=}!M&SGvrObHG<8WdVqoecR;-~(q$Y8F zzeIvzxc|7QAmeOY8Xjt521CjxIu3=U#yPv)Z+@J{X(R{|pA;*yfm0Rf{>X3aC=#u*l@R4Np`4BJH?Pbxz|U&>`*C_lpB`9&_= z;pZWsaSNXjz79m|-GUof1fa(seox?p&mA9Z50r4(xHQTsbE+{a_=WfOs6T&%WWJ%K_8W*~wu4AVaAX58VF{o>E+L(MDFR zT#jGCQ>JTr;N}yOh-uPfN(L*e2V48|L6K*vW9lZ3<6xN?R;ufm+H=t&P@Yu5O{LI~Pwbh6~IMz0bfD!QnnrWOctPC<9oRj{HV zN+guS=o`xMW>*HSNFHM_W3#t6$0u7$Db%#r001BWNklV#u*At0|}poJ_>kpL0XXKbWj_ zDM*-lDZ?f)7IxOa|b_~CQ?{G!VurbR#q z42H7^18|~+AVn0%d=>XdQH~JRIL4IYJKXnFioZ9ZSn*zUPM;R$v;D z5}mBqU*F1x(@$gj_IG&yrI%1uRmHD!(RH14E`tz)ykif$Jf|!+I;9|YQ`h;}#j81IX**H{IyAbb1=fxx!#F94 zCMB9CLLt83qGHkiAT{~^AKs({f1J|6Q(doSMlIse(k|rM9z7YCL{)jB{ZP&(mvX48 zo)};>)>pC6(CN&*`>O1oQaBZ;^@ybffe&)>^lFtZxc8rda=^z1ZGQQDH}@QpD6JYzXbfkysbPaw zQFvZnMNy31l0sDGf3;H6%2z&r|4yDayLn| z=3E6Ino?8hpHhLPMfs;!2UyycV{X&P_}YCe$CiNzhVD}_qvc)DhZS^23k;T0-k5#C zb;CNj!}UZ7nD3Uj!NLA4$5VN5Jl;Ok$9YRy*fW$TozAmnUL84K@#@d4xlPt4~L6}O$jND_x{O1 zVdbCoyMd-xan4}G&_WldeNutpq@h@aHN7M6VLLvt$VeNvRGHY5kn5T(?DNJ0594fu zIh%idx`+F_sxZt5QixHEMR@dbtbb>a53H>(T#giiEqgM& zJ{ZL^fcK#O-$dJfFUHZXObNg;Q0USM+r5%Tf|?k}S7<{QP)aK>Si^H!;C*$+7WGu% zx_KlX!n0wxz_C(+WIc;Zye^ja~IQ>%5wYBG=Jjyn1&#gbubJGuFHY$ zepby$(z2@yGooQ-HGI#;_REeQz9GrvJS?e)V#h@QOVjW@pQffpX3Utzop;>LdFP$O zJ$L_#Wh<9s7zVX9HJo+!S^V_oTiAHsxjg*vZ~5$}KQVHjb%RSUy_7^E!G=>#;a~sl z`^=p?m+8}|1vLacr!2tU)J?M4P(&0#U0kDLJwn~5yQiP&?M)@oB1Ok*IQb0LIF?%3 zf*={w3iSWWb@zXL(}p|EyF@GsSXCF{!)MJwD+CZL za}~{t+d0rR$j{#F;@Q^^@yo%TNK@ljf1U%qd0OidYNCr|+;?RsSiRhB8ilelVfQ1Ikb zkDG|j^vT*DHH9`7v?h%rzU4$f=IHOqDW9(p@XFpazd0nZB6^^IcG53?YFpflbLiMW z*@C5P4?~NN06sNYOIwXW`Aq`G7Av$3qGjya z*#oH@j_YITl61}qjX+*PbfD=U|yYkDB9 z6pir*pZ^R$`2LUilRy1S)~;W}HCJAN3_V^qTz?&R+;JDbe&9i_y6SRPtzI#53|(X4 zg83+=XlZHT+K+sQp`jFu7cUykHWmFwFX&nc0m;}HAu5{WXjktDhz{|MVH5;R^&?02 zCfnNP44xE#HLS>5+=iLF!=Yoxv2zZd7jz=W^>JMfXZYcGIF5_$df1MK5s$F(lm#?Y z$NB%`HhKb@@_H94L2H`!o}QE4Wz~$Xj7gK1cJVP z8_kH9FI?&b*+n%*d#TCw7y)FQ^6y7Y37(CbWaiT7zl%tS2*IFI1%0T}!oZ_{U+QG^ z6bxp)GBEEem%Nf=Txa<;S^~a!Y6BlVV>;=)%P%$`;JaG~$`{095G95e-+;Z#dzI@( z2J!DcwN+8Rbp9-aQs|n-%kLcHo_9LAWL+QMxNa?fn6asg7<}#amr1!EcfH-s7l$(J zJlap^V4k-QbQ6_=j*JtM6qWl$#`QyhCGlN9pdl-OpS*zQx9+EVAkEXqQ~db8mw5BY zAowAw(g~8=nekh%G3X^0-@p?Q>ixHWH;aU$>npzqA^mb6kT0C%$zv` zO_L`CmO46)uzkmNHePVS30(^WwdaH=Q=Too*@6nn?=l}=q-a>!Y!}dJ( z59Zj?k>C$FuC~9OS1jckt!2XVc!0#PR%KAoz;BA_&I^a$(yGy3#I7X4J51 z_K0Zcfvz++p3=sbE?--yFW57f#a4nHM^iL4RPlu?Rxzuw3SHCCG!d$A3;OzwVcWS9 zRzsI#@>eHwWSk&OD_Rsirz}&`)MdcHsoW(0R{aiw-+czsPLT^hQJ*xy6TgEtotR

a`<$|M_kXW~b(66pRSlilV-z`)-h6Fj-@%-r}aSXL9EYhlm;)pT1}w&mMe} zSNrUeh8eBrRET_2s=SD$8W|f$jtwx-JHQz;YH^%^Y&dMf!E~OF{^&Wrbow;vVKSWND-=-%N^~A8t#4`) zbr6g1jqm$dMx^XFBTD_j^JF55r^;*d>H>QDQl%YD1OTf@3v1Cy1z4&CSSX&~vX8Ib za3N={Su TU_p7xEmIoe0yshH{bQ-d%8sI+qaL_*47futkI49#_Mlj7zQn^Ej<6+ z3%vi*_f6?PHgA54l`B_b7&@Dud6tVdZe;W3r!WnJnKOd~gQ1}z?!N0DZn*LHLa-B- zi79Fj-}iAG7uR(#EepdiIC}ILhYlU4v9W<@G)l*jqjVfT!lFg3Tw-0}2oe)!mS8fv1{piu05NnoL5%7T$h4rrr@AGIkH3m|MKi%EnO$L9TWJ})F#lhkujh=58KJ}&Ci_2+}7HnG942yBo^RS%pFqWfRjm5 zE|ZDdndAzuJhvQR89^%igq4(kw{$bTL%EW3uSw{j8;n78)Ajchl%J({LkIEQR5HSS8w<`qL zkKbzZY7GA3@_BUhW%%_g9bCO(8daL$OOGC5D&E-uU{Mn8U>FkVc}4mYqJkkXa!^kx z7B$7e_xbwfL-e_d*XGr7`N~>0KYDu_Y1U=ezm})g<2;v?m2@hCDB*;c3b+F0MSWM2%%MsnM;ZD!f-2 z->C}4x%)FgSv%KrOS-bAY1ocakW82eFb%Jnqf73Tg0SIoT0R4VgCrA`1$sph@labG z$5EdhBM-NTngNIQW>n06ZI4=HAxIzpY-60StgEKzDVYB zIez?;pAm^f$Yyh#eb#9#S+ZnY7G^B>+yf6h#D_n84Y63PKq(H_lN!DegF{33o=;0_ zD~AsqDq*owsT7Xm;y4aXO#vg(-Q7cHR~IeK&FH$uqmTTSe9q>~Gf$_ss)}Qsojmj0 zOPq7o8F-$DrfKZnvzOzQ?roR_bc& zxNzeIJp0Uxg{t6}U3MvV-fGI3dXn{X8u{Sr6*MHHh0Iea!^-wD04C|Y!=auO zLql1T`})|?ouw=1O;E2(jj;$S1~YD%%$24InoPj~&mMJzv7&JlTL*J|?bhe`n;Xtx zc55x$x(DevKE$+!s*v8c*m|V5q^PzO0>ksLbgfJqY;<29{o2GQJ&}&pe*pZVe7{Tz z!w9PN{%)8zH5uy~s^T$B(<}L;vBqRWOARj^JUl8MPmQ;djL9gtV(KnJ6*5?^mk-Nw zO#b&i&=`*}r#*%iX3RRCkL^0lYN??slO^wam3(g#ZbJ?w281FgFC=}1r^LioN!Ugn zaOLb8qL$8&A3wxx`-W&v=&W1V!2G8=*p+ss(7_d1I|$|;HdPEwVksMxHYu>?_=;G> zpg-#%93R*9d3<{}8y7c_esC{wtq4^3<=RscFqH}uJ1R52E|98V#HdkyM~w}A!gEmL z+C>V;IXbSVLieo~%12D*c26{hidaZ79!p69@eX7hG)>3z+_L$sCRt5y@9{v@9lxNv zRyd9rS+_-@CZr5>%4E^=a9{kWt*$L`H5LQ0;<>f4E*Vg|dih+O$=G} z5M_XGf$z&BfcI;$uaENKs+mV{i)6YDIWm&9Ww}ys>23~vZb+*2_ zjk?-eF1~mZrfD)bFo>>eIF3_jc%>A#-F6qf1HA}eaq-2Qm^W`ezxd_t%$_@!M;`qx zAOF~mOrJ4>+S(d~6g>0HvwUIA8Wt^H$f}jg3v}nAg$tNJZw|BP%wp@-H(9t~9&_f* z=I*3;Sf;xHs3Gzd#qbA;{j50$LY-o(~ zLRwH16Ff!Ztgtqp6cS4c zA~M)pQesLCQ=GSK>S3B1t)WIQJ@(( zZVpWbG6$m%Zx|-^b@gEZ=2C!E>V~cCvKX`0t{6XYR|;A1VAR(o107Gj-1r;FIfav$31i$If`YP*mgbyd~SgX6he?l#MrQ59r1XA#~yov z)|OUg&zQmcFTRjx6LF6B^w8ecN+cEu(@i~;@(X~g*sp9Ffo?}Sm8QMDouBUQ#(32bJZ+jAyX!W!1i3S`FxqRkjvZb zOlSDYyjt37Pb|qH5iwZNUQOneBbX;P?CH;X6$fR*M5^jz45NE@_wnf7=g?93LJ*5b z_{h0SSUkO+X$=W}_4Hd@ziBm63QR+1;jCJA>^;iTnT?Z<{SyK#sRB2f^55OW#}p@R zH5uR&3~0@Wa_PJzwTaTUv<%57Hq>)?FvH>QV^fGNDxP3Npo2tc0n4dLi6%n5J)s2; zDbb{c)HI}!!CsRXQWDiA5lynR39eq>OhYnWW&obOY&x|O!GX>OObM3mV`u_H3l?uJ zB;zzuz+RyO_(*ufu%M=tl6XW+`5tLPpj>xU5z0x(3xrabEu)(7l6j3(SsM4e*@=dI zLaH7^PPu@rsR@J^xMfNUFslkY&B*?ZBmI0xDK^cD@m9|u%Ni{PQaN@ErOAzEX(zw| zLwTd*EnO2BQsKIj>ti~w?cfleuef%78&$6zGMJ<0WmT$6&@0#AR#4jDOk~z}n*>eyQ_%A1Pqn$`LwpSa;)zmq2D(z<289%+GMANYx4hoLhtEFF@>wmRMXRy8 zy_#cP{kWcAQaVSIB8WZk)w_ZRSuZHXGG^Gv1Q&5U?N+pY>SFq+au;fX{mA#yMMLb5 zfAuPUgXJhCZU%X@)ANcNXIeq0UTI;JPId0&R*)hJ~ zr{m|-Q;V@uQ@NvR{I8WLZimPsEHz@p;#@Mjkq@q|Cq7C{SW3xh3!C`koXzd8>%83O zQzJDJnjo%A;+i0)3u1;Oss(#XhlnnS=mIl*7<#a%8=64Zg4nrX@8j@8ijlnx;|+`V znh_z9h|ySIS1|!49W{H;U?8M-D!;W=ZtD2l@pP9%Xwli(|dVlA;r zt%<7KFwzCAnpe-RqXWFvoh67ZR#bvRr5Svsf7tH?W4D-(({+jG+2oa)5TF%r4;>if z!Z$kje{gTmyD#wwNXbRi=QHH%`bvX&Y_rwYl}tx43T8 zQa*h4JPsXCGnjR#);(~G*k)Cpc`XF!c;MUbVpf~zV>JfLCBiJha7-E&AD!1gZCp?t zwfMxc7Jjk)7?$s0NQo{rbRjWh5RReCVL|XMCX?kHmj_-w%HAV+Qnn(U_eeV)8OJB4L?Q-KRE%ux%(ytN zOB4%T)5+y?L?cn$k>LC!LAd+L0$8dHV0lxtrllsaeN{%`4KrfH#UVW}sEO6v-^cX! zX&8pV+`04EyKf(ZgM%cis?aoz#->L4`unl02wvFOhHl`wE}E{PQ0RtECTEk&=eTgw z1VDODq~KshuRHq8t5>b&k;fiq*Pgx1nKPS+6)6C$J$n!Glbdg4 z=8WlBmc_ieb5TmMYGt7Lanp_0v+b?7x#+@;)YjJWfe&1PuIqg8gI5r-EUvxw!yG?; zoOnEeX_{Pn-G>9E-B@f~fHfh4p2T)E=kl+=-pW@$8mFbMiin|e)`DjK`yCzZJJ!d- zX(M`U5zAmk)TC!1gEz_&p7d0t6t5iUMfW^TL=9X3Jz1wBJ6;phI2n0*SzqzPx4QV= z+g;3x=yc~@KJ}w#_`^-dx#rvz%xr7m(s>Ph@4hYk@pb1Atr#a)+BOkGd)>>IFo zWKS2^DJV{T7NWrLjO33MS(YIP3e!tNYjfmvwI)eONlXhKQ7xEQgNas#04JDyO+5fO zrY11-;k`!0^jS7D&Vm^&XtEr*)Fi67V8wJ6wZyS)7wPAbLWOSPfc=zG6hMp|1}IX7 z&jXMnWC&`)I1D)qeB>C_kPw#P(q@ z7YIQPq_S8Mo#iuYaX1j@8mMuMhfxMYf8GdX3q+yq8X^+qI}?Q7j|9NG!2kEeUS8eX zLqk-<)eSy(`3kyiyF@^>ILkN)DG30^#qA=cutFj0gvc#HJ(5ot31Hqi45a@j*rw)?J+Gr@G8p$#}Q4&wbXV1|-{^IUk{PYtsnyRB^#-1P6khCn5NWvgj z!QejTc-Xd6V6gJ(RH(025HPJFsN!y)9Dp?{i)t7UP3hvL#P(E~btHs9Xj*~6I@a06 zjA`v?Qqt4YgHno~|=*Vi~4s;5u%h0S_GNz;-=6&!f4e znPgQQ-LOavr5H*NVHgIPOr{`6RxC;ui$%%Xc?=_vmM{#1B}6jZc33 z2BOiRBYfyXSL6GBNwMm)&pM+Jpg(6$5Fp>y)>`oQs|fItQGII0v|yw6}B25rTlqsaS$zq_K5#_FlXVQEs}cpk3cU3rTf;F_h)T3`}6iV-m zBr{Mw25y=(z*7H*z4wl@>?rTNzg2a@O&w=?@{A@Z=Y&WS7%YOwutW=ZZNN5$wOQNi zWij@yjoDq}HRfFm*cf;*8ALK5gCr0NAb|pkGfJbG(TpbcOy`?UsH*pmI`{UC9cD(@ z{;ZEaSJQpF``&ZUsjBB!&+~hJzlF-N$5SFyN)ct5rmnP|wLG!+2_AWDClg1;S+{N- zwR(-u{^J)YM>TeA-@)5|GYgVsjcX3biwN|Vc<;ndAc;u1C zc+G2Gg;I()zTtKJ^tPW-EEYKToI#33!{t|8j^}w?{pPF5=jLz1rI%jpf~4>Bu6O-5 zp6BtLE1u1Bu6XwR4mS*W(;HupwU*~U|5vhfW2u`nR4h^|7Mnls{2eJJ=bd|Qmvlqt zWIox()l!ITQPfK)i7kvca=<_C*w3B&k8<_XPT{nztGMWlmHgGU+gUM?X+LNON* z28zosI)%@D<|q7Q`(9r9^fOS)=n{=n&G&!$5O>W0UqGP0MC7Dca>=Cg`=hZ&>vn); zvCd0TixV>EUGSP)xP83B?LXd?Wu+wV{^v)z>&Y43`I7TFbK@#^yF?L|b9!>1K`Fl5H}Kby6{|Jm12>$be6jIPg=8G}Xws(nD;iM22!=5rN|M zmyNJtI7bf*$L){L@XhAI;S`Z{r{~jk>_kLZS6w>=CDiLUX7HRuA}8j3yLItjJ|!_*p9oyzJ7A zyz25Z`S90&j?!)%(js2j8V(y=*v;$5cc=z1>8#AcbF)(o_5 z&MgOs+?W?=>zE9Ywj`-D^o|otJ+;&m!-ZQd8*=WHCud{+;fIHrs~P4Z&1|fhO$;-! zVJg)eON~QUMw7jP<9OP}2seb*;A0WCkzukOrPkKW%ly}mj|=|nn<@YBTbDX2O$UK( z-{C5%Hb=Kr&B=m6Sx;!q^G0p852rb98)yLb1S`u6_eULxT(t5Alw-{W{fZm1kad z8Ka}42m$YU=R2_05(ELh?{oR(&uT94S6=!2Ht|g%1glrC;y=9RmF*deLD!kK>6A@v z&$niOyafZn$r%VQed$%lEp&R^gHM8M9zHpSgi^pGvk~vV@i9hj+KFc^lNR20{ln}& zJk1+la3N=JT*$sHi zA-T1yF{#d4)5#WS(ITSPk^K=Z-8da{ZYdd|?$TJV^4NSSYq4XZoN#QqP84bCi33CR z*icJcfT*X=u(qB;q#@G6J&d5PC3P!^O!lvpL{_*5lGq9oy!nz$wrf{HxQsxSiHmj2 z?bpun{^zD#ys3TDvwyPAU;ZrNC~HtcE+22(c|MbEmdTdK$dOWjj!!7qSm4~TBIj-# z&uVlU(OSe@Y~&xAsiL*v)O7<~duWc5k|^JC zOOs5`YpLzQbz`W<9da9kKDOx%*lSL9zn~KE7jJkrV`GDS{iX-`$~}9XzEvBZFl||e z#w!%_Ig;TqYEkOQ*NrStVu@no#&y!jcv=Vg6Psmypq!*sQmAS{RSRlX5?hI}5-lVe zNs2^EiD{I@o8?B)SP4jU%ta4R@!wxE!f;XXk?%ahHy=9SL~C2N1kJMja>v(Vdv4PT z$1Srnb+mDbgigDhLg?e^lOUbEK$2@}F7E0obkv^&vYg7=6$8CjeIYn-c%s?2;7Qe_ zAZ6J&35)_0C!E3RwL}OhFnal2gputACrT+^_Oh#b0+>~+#=0zMI{8JdWYyy(mi|i} z{}Sga7veu1uMHcH`7@*E7wQPhNA5bv4G$gVS*Nb#nOjEjh2WMWRX+InpYW$|y@Inh zuUV9j^~1Y%@)y_K&4EZGPH^@aof4;(&H`mFPfXmy3A0N zmBwOi9Uw{|O05G$Dbx~(tmg95^IWoJ$f-#8I37J*<&(Ef^VP|aP!&)@5M=TPz7Tjq zx{`;bWjEiQ5NSe~Mj}(Rmu45kKfVk(V0}LMlY@NtKjbOpRP$#y?3m@rv_!$TnIz<5 zd6b1Mr7R(BWc8)aPrJbD_W(wnWw04-c**(OsHZ9S?KzBTTDjOI_9J#a;mSi@080vz z#Vma~e!hMG4BMYL%y6K@DA(FE@hb*=XTXf< z^Fg~`M*|=F@@-VL;ijoNp0ORir?$)KL1dWqz_A*CdE*ohmh)KYXMjjF|D`D?EVKDJ zzX_7G@Sobfq`OYs{kR)6HqJBf1V4@Q+_iItE6yI`bGs%PPNJoQr6nbh7K6|8-&d1* zQ%kDz+T}wJYbBx;w4P-DuJM_uTU1(k&2pc$mX*V$K7kpY*gx*F=f>iB9u`aB`=n{w zNW^Rfb{;RlYR`vulH8BOcQ3V;dS)TBoQ#nDcZ2AYoWaU`_kIbN)dwD{Bs_TULH_=p zgWw5rz<2h|vH#;Y@jEX(lNVfe8Y87Vp+7$iV{JGvKFPJWJ;dMrcqhB-x@Eyzns!g; z_tt_zYyGvIv8>11{FGd}9*V`CM?EoAYL0i3>V}Y{aR4YQ6V&6zj=8Z* zw(gNw<`O6;P)-G9BPeS@1wqA1432 zY)no8HeP-}>i8WkkFVmaq`;aOZS`@nQ2@3SJTBU{nu)0@U)(jl@QL*5H0>%m8lt4T z(aEhP=@P)^{P)uu{_;z=@%EQq$d#9FW@5I=Uw`eVeCN@l^JCxkJD+Y2*-Ryw&s10# zF8bLyr9G~apet{i0o3b`xO?8P73$hJb(CJLu+(DBhi{tX*6Ij_AZ*KTd4Sgjgf$C^ z-!ASwxj6Xntw$}c;wi~WAu?akg+|YEC?R%PV5kSKk_Ny!AGrR+0aiD-Lj{suhbOq8 zQbP(?#<5u|Wui4{k`kvWNst77@bBxK}=+!P{WIWPoTX z4A^$gSwp?pW}>kJi=4g5vS0lceI-M3VZh%$c#Jbwm3j7QgUx#)1>Cu-!o9P3^0`JK zw%>JFu0{0{f4#@o8lNa>zt$rKiP4z?#mP91%PI$qZDfWPdd)s)-&$U@VSp`bNBGAd z?Vw&u$cg2E(O&P_UW#j+XW-#F?ZhJI)xpR5{{C5h^vPQovXYQFy7a<6qcF`6-dHuaybN#)L8g%C3Z8E_{ zBSCnQyssz*ibALu8Ore=UwJ9Hz~|qOf5{A1MFZcV z@`$X(6JpU|*2Yolm2op*tLUpwj+a-B?cBvVt_#-0|QZLXxE?eY-x( z{5`C9fKe%+=t-=JdWJv7Y^j+Q8f1zgj~Qj12*DXZEOUfdKO^{(ogCFcvI zktZ&`w%nE2_77~v8Y;E+zZ@-jl#?1o<(>G=JkF+6DTV7*Y-CJ&j>o%hD07?U6F7cYskL1Vvwx7&{+x7sxi*Wsg_e|FbrpQUO!-_L~?6lJiGP z+b;u@<)QU*&gL#2dVF6N(qI>uM-DfZnMTflmT4eK9f&G07TJ+dpd z1h_8gTDxa5QL3p%nvsI)x^_8VVTIq_XLS-Ce0EnO;?xj!&=q{&Z|ZWDN`)@r^TrVy zOB6YPC9_V*4*atEqya3^srBP2Hm_ar??~okf})0ip=g_ZP2s}s9k^wDDyAMK&2FrE zVu=#VP|@eYZ3BHWSdN1gn|}#=yQODDSS}rRNq{HqBI|-vr4I1=ri*`>N2mOWHkKbg zRwL&ZT?S~Om1nuUjpHV}_CKmgxA}3-6K$rvJ>SeOupRB$;b!}9pO==-WVYJwUp8Fw ziA)WYJ+7=m>uG9xe3wy*%(GD^EUg6Jk!!NBtCp~$+NGoHnk_RmGnHM(#A8q&_EzUJ zNw#&3hj(AJf|p&el8Zj`2y2vB5M)aW^~4Ej7L-J5gF&!jXpW~n{a%Xsn9I((kDKp% zCQlwMajY`RbY0*DPW69CxeRDd!86w?O3q8k5+{bFg`8Z;bbDrNhS|Ddx@MWGYcALv@`AHR7|g3| z_YF7hnC88AMi?zgGPZtJ&01`tbJ{1>ZjEjN3zq`d#~0Ksx%D&1TX zH)+L!vK-3-kNxU(eM?I1f7i*u5`Z+$e-C|sFDEN@~A@m{i!1tWxixQ$K@+pL1bTnw2lVn|l3XRoC*XI|& zb5`fMV0Dg9?U<&Xx^eO8E7njf`uxH5``NfMhnFUp)HvRso%ib1IQthxN-6I_8gp1% zRw#ilS}#t!TSYx}z^~vd$3qi>2M&~Y_eY-187mV$`p4sZ@tX7b=A%V6tg5cQ;@8;YJQ09_H`<{M$^;l=#y1=MX1?SHAEz4o(!g^0^aKl4o+`FUI)L z@7}@vJ4cBkpa1r*TiNxeFW{ades(T~*=mAPVOIt#^d$KHl4k0=pS72JA791xiIBXX z^5?I9kiWh5T%N3|9&2mM-zF6*^_1a~-?5qYS^!qw35)drSXE=GM-CVYDI7>Fv{e&* zpwwRWI8K1|f6HN8w}DnPOB~L0(q)o-Pj-=DE3xL@-DRd`>de**(>23P-7pgi*R^FN zHKRzZBoQ8oP*|ZL`&SErL1L|FHr_UvEyfydcrfDLgGYJ)i&v5NB@Z8}@WHz*Ie&GQ z6>zP_Ium5n3mEn}nFftZ*Bn3hYS~!qUj;C*JpqvZwC+_&UWWZI8j6c{qAf;za+n@@8vYGm4$32k(E;wbF7o4?{FFbmbdaMz`vSoFS!GS!JNu5vJ`~(KqZD=i= zQS>-_IAC`<;hYtDZaq*XNfVS3y!ZSeo^$#r*X=mQw;!7&X}Q+6MSrcHx++NClb|CI z5(7-7P^}rXwiLsJP&!}MRb#tZGrEQN@jQM|VRRs3&puZY`^RrSgOC4sjAxvGh+jOg zg?D~x3!i!CUS50UZVo*;LYO_W)RiT0P3HIj?Z71`usns== zNK>sF%8_wx?UALDKsAAymef)~%}6RnVq~4yot@)_=ZrWM4wNIqKiqnZ&+PNa`zxGx zQ?^hxOCniDy62i_d+ZoHLWfj}?~UiU=z(coebETFJW{4&3xp=>nR>Tc0%7kGp~wK1 zP5uo4qT>j|wtv=0ghgWAtqr53;5l0Z?mGhX(~db#z$CLS6i+Dv>1Bb$cZ<5`5%@ks zzG5g)42O~+EcCf&Edxg^1bX@rm47*zqe|+sH=+$-3ADA%jmbhup#{MbZlhDPP!P7I zta5zZvm@oS?di~$tdrVFRvZWVGYE$Kl#$SoKhEnbrN#O{R9^(tE_56F$s5={9ci|A zHo)^K4X)r#7ml!b?Qqw-Y+gIcJ1?)Yp``fA6JWY z^U(|a%uXgV3|0;6n9M3hWfeTf=@kwLWe?8}Ddh8%O2wXC(E=DQl^7^Ej!iEQ%GR%! zD+Sb&PeZkmwL6BG){ZwNjH?-2;hvL9uv%E&_mZv5Ow@VLE&F-Vs*wNo>a!4@V5VH> zw6()beD!`RNy5-T$V)F>&0HmK#=!67sXpHPc0H?Eh&Z? zn_6a!CDk57#e`ZM5J!^1T%D+%l4!-jy?H9Nn0llLg^x}mcI^vz<|P%dHD;=k#Kat` zD|Q{sQ!14)CUl%@ZJ8=3nLUke)3a1cvNq>4n=ahJlo+^Vqve7#9%RJZhQ?BfBA)xS zds+G8)%XIYBGr}H2k=e8Y!5YeAtg2=-3Nik`k{~mQ8zavu~4nnn`0$umN{)}25Vp` zqQuo_rMAi9MSvpL@YM!I2#p)Fy~qv*@7HD$J*^0UY0n4FHO#AFJ&Fq^<^BA87D zvsyA^1k*+`ooW7fB0ve(L6#GeAk+JqKQGa?&?iaCf4{p-luYrei$_sHaN~|iKEJQP zP*9@1t+%1)yjW?-E@_iokO7Z8IfcDwgtV>+g$I4?iWYJ)l8sJz&A*~!spQi>L31gf zK}gP6ImFhr`5qZ8$!ngzo<}DWu7CUpMCFY9*f2*{8CSz|59J=Ar&t##R{Dz3P%<1U zhC)dx6qG_qAr$0&7fiy;m#pCd=*`nUT!}Jk5Lq?sb<7ok5*pIzmxgv1%hxQ_05O+1 z%^=Z|<_&yF*%)$G_9-7NEt6`oyliuki`N(U!6P%=GZCNA8g#I%+dh}?N!IzWKV9O+ zqhsvFI7RN&5(+{emxkX^QSz2;1AJloEX4JN%W6%t9$fp2nuJBDWo@Woj$!_de1Ju;c;>Cd&9`?&r1GkZ4IUUqjn~*%abfF<7cm zPXp>PlnN0^WJpuVKwg73)T=&&#Rw8Z5(%tL&=nZW$E+*GY(MI|vTK-dlR{?R1jw z2y!^ruwym7^5gVUN z_~^|?xo$ipAFf1-Oqm%m-});oc<#IgvchSz1e z$@>l0`gxv4=s69bCSX#c={VmABq|FYvNez>g^~)T8iA$T1F(12ad`u2IfU%RG{zQ` ztncyaWlS~>=Rb?D1Xf3&P7Kx8tmPFKuHvfmS2I`J$=wqZy>m@VlV{^#&8gTovLI5x zm=F7-#ja9s?Jf<}5`iZnC!^!yU=0^TUUBgX#_O7&?LEqDwc<$cNOyu6Av=_cl9CjZ zM?op_o+9*oa=s$)6oD@(WZa{?FDd$hLLi!)qkKSfOgD|dJ+h1|Naf)NAp-*?Mu&&{ z>gN^nIZofS))9g;P$OF&y$rnVahBEXGS`a6a?sqv+6Fhy@nReCDb-H6H%bgq7L&?# z&1_XORn<&Z4Hs@I@XWIYyN16MmPDuB<4r(n4C_V;T>JX7ozb%=SwA+wvAGJ`7<8KA zOCU`-W30&b15?~_w9NL|8vjM7_%b0*9MGF8S1`ULic<#j0&OBEC(@NQ^E2L~=j0>g z{M@ZYmNZe6a)~ot*Me%rXRuVq)Qd#1q*SPr#tCr(#as;x)T)9_n~t(|WSCRdPcbnK zdnYxsvqQY`rF+@*z#!Y!PxHlZDm-hNvKtfS7%3dUY6Y|s!Rmp4xTV9SbH=3>UUuOO zXKsF!?YqwB!HVR~XH;0X@(?psf%H?x%Zm5D`4?Pw?ZUo%`O<_IlCMwT}DnRC4jLL$zZh*d3v-lYQy&ZRrVdKFqd(T zX6uHT*zID=sia~hk&z@Q5}`=5jtwci%u8urAh7|8n!w002tm1fFo@wR2NJd)JH`jD zTEY6^9Eq`f@4iW{J334dpoP|aPpQnG2}+8#*kNx2-V!-8>9P}Hxo)H3F6Ch{mC z+x;yBxt6|Tn9~NWU52hTGbHVC^7&f6jtnGqgOY-h?~$giO?=@Ov3+6X!B~@OOW@7l zw-up*a&%nhYAsY^i4u@k=D0Xmo~Jl}^D6$Mv|PN}V`47rWb>gIKt2%UeaQK?Sz>Es zL#3F1H2f(W0H*U9fnwe1tXaXqBY95WwvTtc&~p0bNgjM; zlq9hvsi2TIpe>bZz-ika;uG&b%Gq0H`0}?e=7DL!KYZaFe&bC$c*ezhx#kDkxb~hr zsWqh50-9r$*v0tlKhXjw#s&hk?P#}Zi9u%%CcOD2x1nU2`yX8eHO-q|xP#E2McOU= z{D|hQXU41=J;1M?I?F?M478yXVGZSKy+?vUIzPgk1MC~uuE=!Ey65!11IL;ftH2L1 z#$ zDmjVyRWLIrRZ`+h$3^m0$I^(BKDv2`ePq}G8@Pz<0D2=al`Rcd69Tp7YP zgUbBBSy1s5VOU^baDahAVZlW?@I6+qSOF`u-ZFc9evv2B-brK`tXOv&w)O2F;h?Z=q*PWk52+Cz`~3n6XTOD0azf7Z5MH0a0>J(NE%C}7J;>tLQ7=g z4r|8cf&N+Jc$tAW{~{xygjQ1S63(~vUCXg_Bx7YczF{CJ<@21ic`a*3i_~j1OzK+Z zU1n5eAjxaVgnCU9_dGCirMb=wQZF9TFUyWhw9-Oa%5F`LY~nl*Yq8T%s?<{|HO*Yz zRXEDAb@Y!|P{;71vkP3dZMY{-`HnqveCXC1yUY-I<>QHt<|H*gZ!(MNEJJ2m!e5IH zmQ^$b7sPz_K?w_K(sSaP#4uNh`G=qFV|=;}Sf0IZfc0ZVgm%s+IVnIV)ao&(tjOV; z1Z}kQz_W&OTt{HZlaeHcRHp<=6PbAa{KU4pFP+n2Rj;J+Ott$1JFXn{FRu*W=HkQj&2* z=UsFMLRcQ%KT2gLWZR}AqUOCdmRcjnOpFBDr z^Zfv=HJ;~DtyRf|d4RJ|QU;4A0!@wOd-qTB$%lOi#wfIGDXd+{Q+*);z@_UM`6A$v z!*fnA$QYi8JvOV8$U3nLb&fua+~|6;mf6Vtv>@YldzEF5 zgF-GO7p`oQv|Gnx=a@cTfON8em4(b7)5*@nsdG$l=HP}}q@6crXx|(rt6le zNH7({L@JojlA}g4he8U4FLM;6q9A1^Lo?qv6zhoZ-BRZLa}&Js!qGO<_?ddlCx2e% zh+M&d1hQ_mHjTNZyRP)f5IgXquugfuWh31fFJ(!j@D&lJrA+O9 z{)Mld#^jU_GR9c=;bVfs|MgOo73?WPO$#EM@c;a;4NebErF{1RAFL0e9T5OLQWkxw z8#A@KYj|n!mRk7M!^NQQ#ed_O6<&J99VBUv&wl#~4wWUJe%<}#!!lZjTzm65lyZh= zoqqr+5=Kh`ZD|Ks0w(8bJ=gbCXYwr8GCDHYmooF<{^=%v%=dhZHH0d388CO8d%OUv zTh${IJUuiO^Nk&KtT&3ZQ6GNBQBc`O|xeo*o-O7iaYG5qTKYME8{m~|V%7{;zPdYLDs`cMrtbc% zq)vP+Nzq%n<9Nn?XOng7KGJcM=H+OdPM-ryp060pdwu;GjfIB~Rrs4*r+9K!F=Z98 zRaoI+r6N=Tp;UO;T(&}X-5V>6>zwp0D}WVUt){o40 zO+WHvomZ`?h?)fdh3w6kwV8^y6X z={Q9l4P!@UdIKzL=2wDZv5?)X?n`iZvPKjqgn^Gzs;TC#=Q(%VPBeqnHB0ODgvaBM zyf2=j^3r0NE=!uFmVG6h+(6oYcR%O}p0_q+ZOJDRaQ&Vt2WzG)T)b#qjtfs8;?Hk7 zGVj|&?@lR$V6N^iQQjx>%d38taTTE)W^hC~G*t6sL|LTaUDB)~IQwtA@#n=4iz*UbT$ZVLX)_ z)rwenSmE@43R2-qi4+Pe;G?Sr8@oz`JxEx~-ng`n%`{Ci(x$}|Df7NyC#cb3ElJw` zH=YtmdXxy4XyZ69PbZkEx$e9m=g66Hb9`6=>Es|%Yv{=x>>%u0=(2z*h7z0VMf*T} zX*p-5Ve>GAGUf|A117a#HW6q8g}{xKU)quJR;_V1K*rF_C`E~;7HO)HVXl@kS4)|x zx-mLcH%!+pv$5;8u4)I6A{3F;oKdXv`b!46;?$w8Qk(_u-(TSaH?J#$(@eqKf96t^M#9n+L7W?398DZmqI zi8H=;iLLhyUHYP~g$s5{2};8BElL8MGwku!7p~*(M`jrt4LEy4i9fjEFo|)2(#tH; zq67x>9#@Wq%p``N9E*DLzyLgJnX7BCt}Dmddfx?kO2evRz~|m{Dv7py@cVnI#fGtrne1q`-jnx$yB5IXa( zjwvZz2Fom`4{&jyl$aP}4N6*kY3SJ*VVC(mE^!*C-5D%jIFkB8S*7{!-2aC{$y}t} z)v``Zccxau0J*>eTgPaT0Up7}Uw#Hjobt!l?Pe-joKqG+mjz5IC(&(pptrQCHgL`3 zlDD2|IB(4Ic49vL7*tZnnJxMn?1}N(Qf-M7oprZm+@!juQrDCtO}VC-i!9~HGMCBI zR8mPLm6Wy9?yFfv-Ad|6B0MaC+cae&no2lQexu>mws^J}40pwvowrZ%0jYV$siSS{ zTrJjIbJqk1^eCP*SQDM3>cs;3Tpe*lSWCIX@@OFMLpqo7ta@zL?EJQ^A*W+o>}{GO z(ZciBh5XKQH}KG|!)-yjspKwz9$kb6_|}7mx#7VhOt)l_KDpx<>^O!1Za!Fc^8>he ztiXrgb~)P*OmOO&VP@yb-1Ycjq}52#Y3n?HuC^nAlw>8sFi;L)rYA@(SkP2)0sThh zGgxo}!=6-_PQ&NWBe0SvHEq=zEi9>tdE($&Zh17|3%~amL#1P2;cM5Q&-J@3e{=ON zEVrIdtWK*{R^umZ_!xx&bZvq@?Qrh3Y2 zP^P?t2X_yzTeo%kcuIt}U)ow2?dr~byrwJ=SxYYaT!DaXCB+jJL&10T(&-+g+Qp1m znk}40I2!>eDB%`v+f^dWbU_l$bS>fYcOPY2N%6K9uBRvxP95?1qZe#MNWtfBJ4mHk z=e&(YtVmfuoFjMLKCVAp>)8e_1(ai#@+|}sYdXrfE!nm?W0{&uxbB|A>=>`|&{WJ% zcTVuSvq$li+Xu^aVV*r5MQCdzqLa&YH_U#TB8i7Gcno7P>E8?HO*`-A+egLoi;)->~GO9 z7im6y>o}j;2?u_x?lp!NhHc#{RoO1O1KcPj7*K{e6SvKch3EyZ-8#g7ef7C~uoR*Sdb1KX}G^UV7PPW~(uqZr{)3M6XRx`xz^s7IgwFMP%Z6Pc_@0 zAG&i6KJ_5H;~Y3+%<`MS*LFgpA@B7SiC)ricsAyH_f7FnJ5%ONj%h2IMxju6GQbm( zymT6VUL(`odWyngRcj8Zky*0cr>nNj@~D(oU=k87I&a|h2oZ4I|SInFok*~gRh7BSJD{LI!TTo8yqbR?=K{?k=#fefQb?^>^0u!mTx4_rkjo!Z0;A%7?yi9`#iA zOmK`>>qLpc_hj3B%lQGu8YGe+@G11m9R!Nm*-FcrnPvb>HSUSPnLaNYV09$(MHAr* z0n+MuVqcHroFT;@{px!D@}@&PJe9Dmr1(!S-pF6yaDYqJh14y4^N})%g>hpE5e#M5 zU|0#(2a^xMTMWZ@GLk_db4qryMRPtjsCC^|LAd@a60Ob%UfH=GKm*U@^v(nVNj1*iehoOm*LN z7d1*9bJc{IYQkhSWulreUQan(PdO5&u9Z3CA*h1So6Z{LcVD=bjicT68roRCea{46 ze6qk`zCg3}pan1)djggtz>p`nWYpu_%|%A@9yZq8eW1z>`>Mpo?Z!Jb%!F`R)@A!L zE@JtZr0(-HxN_Rk7JzhyWJO!!iluj_Z_8qDy8)IIfALgAeJ`*Y6Tem;XgA?U>o~2#DXxMfGtbx4m zIAlvq*zT*tCwIVap980j!5cF=$WR`N;qh%A#>)vGyX6?)IZ~qJ7f@0%01VK1FWjBd zoeJ#ME^AyYn(32@gH_-0ki7QNZw^V+Aj8>iZtH@9N5J|};!DAD=VkjwuvdPa4Jxl08E|+7|nh|{8 z@t4w$EMMSD0zc?E_y6X5tN72a-p{~5OfH;pWc;6=$=<5sQ*U^Pf#PAbf$!Y(41VxX z3DGBBQj00q66fXE`rcvKtf&OOPp)5eMhIqR%gwJF$Cv6Jbmt5| zn2CAQ#j6p@kR+P9IO51eh1150ZsPP=BdUp;;)PIAwVI&wCbeD|Z8&Fbk%2%lSxxx) z;W~SdR=DYr33LiKZ$HYPUA2{oO3a^rcX!k1wRQh#vBbi1bT&px!N!8+6Zah;Wxlzi zLDYN8rhIdw@zjH)*5$^w8C`2@U6wi{%+3QQ#|f#_Q)a6vGu4FYa>7J8;b|(LWj0PBb&A5mYNR#ftwC9XupL3P<$Q)a0YMqQanCekImNrLI-Nq;KI|)z=Gw<% z0yzL_xjm`LWDUq$uS5&O!4QGsU(fR@Y^42FECvd5O*+A3@u%uwn zmn?1&F~7_I*iF0HxH8Yv&sfJFzxD!3xd-^fo%^Z8fcUKubGFYDWSwCi6ILFZ~9jeK*^-t(29yTV$_aQ1IKA zuHenj+JLr#A3bo058t{>xsa?(cXUp71aHAsX_;>G2<+=z*>h68>--hG{IU(M47GoX z9gk0P+SrONG%SU?XT8B&kBx|3fF{$rhMA?7Pg^5-z@_U32|deM>jPf<%**)3Jr96T z6v7;%VUD4Eo`GDRQa+@R3(4m~N;#iWsIrHk7-pJlKID7|{8m9_(IzGn*iWuGE^hCCTJCoI`+ZM8LI+4b!ES z2wTM6tTCCOXZMmGD!5|v0FUjTVe`6x{Jk-W)(D{yL|ndg2s!BU^TV_J)^ko_suGjb zEN_0+D#nl0@I83%w|DWLU){_rw+!&5M`ya`LLywZixOG4PQBN;xbJI;WU?Ibcegyj z?wN?ce*IaTJtRoAq2N0~G;ItfNyzzuihw)!O!4DGF@O7mhuBq4NU(h3-u>M8@FAvC!@`^S;aDYMqM9;UPpQNyNu0X& z?KCAa8fy&Jn0b}owrq$?_)9FqJ??3Hg4HgZZD{$moQ99weV8{q^At9%ZXfp2TFN?) z5dF-Z`|&^)E^iwwFFU2cU%Yx7g-~$k;TFrCL-N<`h zem*&0@`L*h5vPVwDb|-l{^T_muxaHW59}G|&;Dr#m2`RNqg>N%{GDPhvwX0P4y;a* zhK8M2dq?8VDtzXC_>J@6lo6GIrR4*xT4eb2_5>jYmSAVqe*LtyOc_VbSfyah7mS61 zRRzVWqGDyyV|2i0r06kN@bP@XH}4ten~&G%cdCs~S+|gO04ym5At|w*Z#9@drT(AY zSa{tz!@T2HHgo-bhlpasYo5N51Cw<=_KT?wx}jaLd?m0PDYt8mDJfVR8m3#7ycfV# z#?B{FH{kPZpP_E9uTqfDzWG9-?VDxwZR$m25DFxD| z=pN}21DrbOlX{X{@1Nv3=dENzC`pX7bx{aXZOKbP!B=b@$?=vOp2Sb#ywxGEJbRb| zimT5WWktbb%b*83>6#sh&=>+nhhg)e*g0IoUx|FHMbui(4yI%YCHa4Pn|SFAyi;uVktV9DD&t1&Kvh+qHoTI zVn7IfKA~GOaNoICELbzSBu)TqA>-S>0YL3e)e{{TG zwMsQIJtmzbPr`Jnpof}U_a4~J6Zcz68LbPXwQ%vU&--4w2~S!6;+v21l}G0s+1tV` zz%>ueaOFLd{P8Qc^4?dS#$6BW>dC>fw!WYpW3TMuZ(Xv6Uwi)PJa4MTz&}647q%ap z=P~N6L?{HllFqr_!j)_Dy#F=luxV_7-A88GHC}dFK3(v!zbiu2k%bTfhJvMa=QZyK zuzfn>_rG!<|NHfZ=UuRg-?{2M1`C19VEKyQz3NP!amHH4XDa;Fx9{hX*|_EP`f=@k|@SEqs+Cj-o)v#vSB|=Lz0-0_8+63|FuOBFY zmv74RuIH~~Who#G6rr#1z4-=})EMH-@IFcno~L-v>O6OT@?jpY>h4vpr4)xvyY$VZ z6y$_y2CKefvO`dMJT<)d>{0d{F7rRH-^cwm&8;g#UViafzH-k|jyCx^c7eLe{OcaB zwEI2^DHsa`56|^lxorzLc5VhAynG#JZ5Zb2uRp}F5PaZOXR~fafm9nl^TWruZtonI ztQ_pQu1IMd7fC1GBN>p zr{o`cF016V7-UN+2y;c&tyzhm*}$B+bvi^OcvsdTfTX*3Yqd%-PGd z#WE=fg3$4eMel*LXU_7o?Q4;;3M%H*wJB1j-1o@2eChU)g=eM(bj-1tsKLTbGm13Bqeht z7lNWEnwy(m6TE6Ip(l9z6&p#B>_1%Q?um#G|7b7o`PGe_wPqzB{qY|5)*`-h+b)h( z6ZSnh!51H!#0p1Lv^^NVwNzn^rI1r#491AQ!GAc*B_|dtiDgd*RM< zlWi-VjF%P0T1E;IbnhLS$<%zs0^w}eky*a+vx9v1;VBN*wG*^UwG)H1E?eSb32~rF zbf&voCPk4&Y;_hAl3kW7%OV|gz3hg%em$ld>7E;h9ERBH7NhPyJR|H9K8w><`|Zou zFg6hKKfb<$&p$Mi-51-Ocrli1_tlBN^)MfK>ji9DJ3y-_)qJPY@&dI&kYK6Q6Sk}# z;JvRtm*K)A{Qu;=ca)~rS>^jX=gnWLT-90KEp@8^qCj20Tk2L04w6T*<(!T2z`(UJ zV8Fi2g<&xa2Crd&YhZw33|wG&FgDECm}Glw*^-yB{o}k} zj@6P4m;0?%>h4n27v6Br^X$E!y+85L8CDWalq6|^1&*x=b;J!5J|BGBC0w#)jC0E+ z{_FpKm^+TN<^2t+Iy6+G&H^j%uV3*kfy2d!fB)(4@rO~&Yp>qPPu_BA-DmAh*X*EJ ziTIPxKg_L%&Y2v}Ht}%pe>@VhX99kH<~;nW zguu~?NJRr)zR6`A&7Qo?FTY_6fot>3nKf1`G0WwM#d6GIDQ2M@vsg)3sV1z1igK)Y z*ZxV~|B7vl*@{@leLrJaLDWwDBJhPa&7&R=P1altS}>M%m|HG!sv0sW;DJMn{PZg) zm~aJiRo!FhXdkOE-#b%DNR+OdjS2)4zNV@w-E-iZP_|diWO(nZ_mT@-{>ia;`s6a# z>^5cbJx`wGcfR$UVK{WAT@3-it1r#*%-ke*oms92Xa|nXM#mINV`&I{!L!JwLGW2u zl5vgcvhN67TjMqP30juGmIAAuacb3LjV#NUunK9Rg+ysVoS4CiFot8Z5yi>^YgNT+ z*<|~!R$;jkvsg_y7Yfcrl5>gVl(MJ_8!0?IVc|(LIN_v2JuM7@)i}RFvpsgJp<2tY zc$UvZ6gkU_PR}MpU(1*E2nw*$fAK$r6x{dEFm~oGGpSGjXNZv#hb6%$XY4l z*nF8!fA1W7rZNaic7imRc%?WoC`r~fE@7>NNyGYcInn&}m!HB0POOGJwh|F4#Uo4b zzJEH1Koh3MkRST?iO%Gn9-DnR6$uBf)v#jk1FL8>x6B0m+FLGVdNiPr^*A!O$_M`D zKAv2S>QiO?HZTFqSB%IvZyZj$GX|>v!v5^+D!+f*bA0)!IkHJYpjCR)z`zVg!QgIn zsDi2YJety)vNp6`Ap7_kty`C(L76f4&H@WEA~IwDeZ!7>Wi@sdf7^VU8}>}{;4`!Q z_XG2cG$nhExstP?#!gI;^Y=$ey!O81yy?10%BAIw;%^}T+4eqSt@)b=j}ygJ{=*wD zW7AlUUwqT01$m&87 z0^~hwfSyD*Ez+&NXD8P*zx?+PQL4tg{bjrB8)>W*pZWGv{N)43iO$moWUkm6@8LLt zi#>~@VXt#PSkrT~3UjC7|787Ky#O4cjX=9izf?OW?ev=^1@F3Yf{DD(AAIo{{_e>Y zGa)KrEpE_fffT%S#^uOdNHNhYteOTbYlM1jx~taDSkXy`{f3a>OVye(pa+WtFY+Wx z2(pfaiZvE6w^%V#;U2^*G41-(I-1tyIZtSaVuj^e_3w=ZR=N)M_(}&dijm~pN{M{N z<%a#6dC4Ukv83R{xmEttKR!m3He z#1+K@hnD!ISMDSXLmofA%0E0d&%1Bf$nU>nH_y$kap$3>)O(`!X0vG&SQ$rCrP6or z`MV>lkn-%!!+ueVs&JS+x^Y;F3X(+QyAnjwR?S1Vk>_hJ+(5<=Jn{TlW*1BB+cm@P ziGYld?B5XZsi&4&fr>7RNu{btlp^a}265^nu1FHQE$FDJFbre9bpJ`d{L~3@aWs^6 zX?;{2{kvG*d;DE%v$^aZt8nA)H7c><3y)5+5LyGMrGChkYDKuT?p|OaOfeTHt-sS7 z%+xw65x~s=J zc3e|p zy#3k@eEZ-WpLt@Hv!UV__l@zI%f|We?MHcdF~Sm>U$}mTAGu*0e}3DueC)sim1-4% zAZsUSk<^=(FKd$%*lsWFT8%xq6=~9426fE8VkM}=FS!BHjbY=z&Fm6>Lccz@>&REL6jJ3vf3u_tG&fU zsh-{O@>;}a56qJZlfgq>ec}FYsFLpA!S>Q30)f_CziXcNz3L>F?s%ST<}9wQxaPYr z;def}k5eVPNek3tEPaUAb5%mI8h1T7zO5P_WO}&IP}??Ci@w8{!oFfxfkZ35{@ff@ zWl+i=yLgPBevO%8R9d6skT-t%AfuM#=xW4rDI{ZcqC&%Xn{|7{TJwp==UA;g#IL;l z3U+TE%~B z{H$jY>Rx)g;poC+<(LnB;Q(Q*xay(}{O7-anA7E$?hzjS$ic?nPn05*(sh(j2*IYj z184N`^k9=uQPZ48YxdnbKBv=833r%oHeNXI2!8w}8;K&tUw`{3bD{D7+Au1)diNxM zn05HA&p*S?X`lDpbOBEvU*>DiEr3c0qu6-)*|Ie&M0Z}}N~MK!Q*|K_xHd#O>}sLV z3-yQ)l*5?Gf{(8gDjJqcRiqSTZJp|J+9w-(Kc5nkYNW|G{jZ#FcSj)G5K@Wet`i|Y z|FOIIIss+*ou zYgjHNNNIJX8VD&E&-he3N_O3|L4I;U^XH$rkjc?vTDAQOrGlnye5cK=s%nBT}#u!(TixU)N9Bz-&b`I{;EjQb$ZZa)f`Z_PD^#! zyA!1ubp-QkRb#!7BC(fm$<-|)q!8@eJ`N%T1*J$(jZ{a0C0~GHrP;JKpLu41)lWab zhu(Q5`?gQ<)@ygvySf|pY#>pZuReT;-~Pg5EL0NuxL@@>^%|%|Nyov>de%BnCf#*& z6ll(tV}9*_Kf>0$$74&SR3CQ!DFFwou@TM7#`~MeIRj#SdTAwF)fMLz_ACUBP-qpk zW~O#QmlW_5myC1$t_l9`+lRRCYz13sYz=?-oiij#@ZMML=n>O??fpRs*b0vX}s3e-@vXNS3 zEg(sTTTgW3K5x&I%=i{b({x|&>)2dhcb-}0Xa4eA{Ki}N^WiT&j<4cYYm+t~r`mIz zU99rEcP#Lg@(6+D<4I#oT+bu5+Sa`EtE+}-z3Xi+eW>m~5Ybo3s#}rA1~uFNIeWd| zg>qsdakT1a_9t=OY@5b?T6}Y17W?`BQ|=6_x;tm}-}U`_O#ML-VDU@1IS_rbo4? zqe-?Fb!TQV)TZ3}mSSpg9KvKG*5K^{meU(E4m+mveB#zeIJHpbOcmBPj>u}X+7i4-P8RB0%d zBQ{MH2orGHQK6=$S zN8EB@g=;T=j+?G{1|_N-IerPBxb;T<>i!WU4%ix7}?1tnE(@%Za{9Sr>3rZb*fDPjph-q!UgqhqtH zEs*t6v0}#eEE9*E^=#Ucm-}k4+BHngQ6O#T((Q+>4S|;?9_V58O#Ls$`)9R8#83ALX1*(yKsv2RoC zf;_4&1p)&8_P%-Ut>l<=U4t-bdS@T@Et+%>w6fRw)>0z&DQ$Iq5Vd)CinUI)>wPG{ zfx4?cF?i|F$9zd6giJq5W8D)1CUR~g<7g1`p&R%9qjUDKHxo<6)votpbCKnFE;E76 z*)GFRO!%yo%ZxLMMk8&bX>)A1`SZ*G$JR>`wrQ}M5v-0qU?A+h$&pNXlIe`YOwQrh zTF6(<7IB5{PtSF^VU-YsDT3uY5{C4f5z6FeedIeQI1?EJ<(gxQC@px?RT~K$i}&5I zmG^z|X$pcCnohM9PAf`Mt|nMgFzHDi?-k$JBs?!wV+t7$qJ&kg`1@}@#fGUohtI9@ z^RL;*?GGNtQkA}+p^^xyu`=R%Av+ykNu#lJcM+BpMhl0c=Xh*SPa!G@@mb$8LBvYIf4h5vwenT`(J$Q2 zPru&fuK#hlnOr(wG)HSnm6U>LgIRK(=}=@h?52-)tlK8yYdC&(mC>xn{^<vojBerlD< z-#y3&-xl$zE4Cwr;NbCje(Rqe;<2Sl_eQR7+!j6OzJU${w|?(F&czQ+Ny z1BtnhN3u@+4j;`rom6ofxS(~XQma6b8)LI~{CHMl2|nttbPdq&tYnc-WHpWt}8 zOjW6t_q;3TaovSel&i*K;eD^Un8lR}pL}M8L@TOsf>OpK$+UnyXn#N`(RKPZa0DvR zSc6Vl8@e(#yNGwyHZB~uIdWo^%g4tkM==ZKGEvft8_8=6o z?H*oJx{C*%LU%#cga#F99AWn`C+?$V>Kj5msD;&C5hqe3*H~+W&;)=lpqdt?djp$M zUo!67Ok`~ioUL%*a@;BJ(EUllftu8&frPn|YUHxEd`7`U-i1W2dqR3W&HuvMS}K`o zZO0tfF>yIU;<_$ZUbK-ro;cC*Y*%j>VRUS?PAh6A06W)PV0BW2O`X0a z29Y$4ze_Y9yzv6wbMqduzLR=U2_AX=EDwGBK9K`$@}==JFdd>pqj$ry~cc%fKt`KpA)`iG%|fg zm4()ns#Qkw9&g^{vSTvKr8}nyk=%ap6yJFG5TAbhbYp6($F*G1Cipc!YMW&|Y3Ar_ z9ZS@&s81p46u~-AEfWm(iL!u6FXEO<7kTH)7ud1w0HfIw-+XKfzxtriQ1 zt1T(0z8LPY=`!=J*&@Y%c$iWpX7APse(xV14ZyuZH#!Kh8 zcK1f!w(}I9e0s5#r@*$1&4=Hc{>WH?icPLRjY2(M(LL4 zZ9IcQ69^M67a>@R6^VxZ1&8-tGs%WApOKtP#O-Gk@a3*w;h+UoMSvY)?Gm9J`Hedu{gWBMi^;=w%Dq` z_o;>784zGLp<$U>x6CGFAYj4<3ArqKmt`v3}ljAyWN<9Lw2e|WvQH1FSFvem@ z6E)SJn#;SA>vv7@U*XH}W?hd>gJ~V@t{Zy!~O0mlc2Z(CPF<^!JgeC{x&Zj)mud z3acH9K~j&}>E0n*MhQ=^2}<3gYoh7KYW;iTrxRs7S@uqqc>k+Ua?90c2!fO7WCOR} zyPL0lcN>qM^_UH1eZ#LKZ|T$Aa^W&R^ZFxPf5}P4MxViV&EoGlRi>n7DW(%b@4MkP z|5H(}bU#;xz$R3r;h*i(ZjItew-{FT5cO(!c(%y%C+2zO6+3y`-G{mD_@bc+)kf2F8t4iQ#cEs1gfP@^NwvBK>KDWwt%0wY>anaH$%p=IlENhFYi3Y=Z+S+csk(bt2glVgR?w%dX>de$al{y zvti6-wG#51Uwno`=c-g9#d4_9uT!%f+Y^6daj2UTB??T4UvamEy;Q0vPwXb?PKY!vZfBM;b&1kHE*X`ZJ zn{K(W{yW8TiSaRG+-_TTa|3l@zxU9q!0PJkRQDVkl9tn{58byPJ;8r_*vQu>1B+|+ ztuh_hT(e`GEfYE3{qk+R@AFSHYPH3Gw4C}{&uPTKX493V!`}nw0!r?v z*P3rUc!=1t_}l}}@w2bo%VS4pAubQGs|i-iF$lqkZ>OR=(X&?Ts7C+*AOJ~3K~&`x zXb#V<@xU`D*uQ0x<+T#C3#;7z;Ir5|#1_q;w{yd2@aTfIQiN+uF7zA@EO$ZpRR0BB z3Q_kBYAH)~cjRxF;8rPMcQ)bLJqx_~hGSg0>kOqz!tvAF`Q%*}@u`QWh^jW8rCW+< zt&MfTbrUf!+kcMN-|!rl?>J~%!>%qCg}{P1 zqAFEux7D|J>7^-xg;4W*pM8Lj|KjWU@c(fw#gBf2FVB|nrKnR}v4&W{@4xMGF1u(m z4?OxLJ2$n4QA;VhqqLeKpnTmEDLGt%bMYX8@^fLo8QvHR->`M=(B zCI8{oyEypi$CwWlcRsy{{rQLaUk{%ln+^zk{^>dH`QvYLwwjn3ti*T`dN!!I+K)&j zMzGd~UB-^ra!8u9QXh5KJc4&Ji&cWo@8^@<-nO$?mky)0P-DPO#M-dQn|Ij z3S6V`jS`I-3QKAm^KYxbbUFpx9$+E`Y1lRWi-L7GLOn}1-f>}$pS)=+Uw`-nPo6FD z_NzDXfmd$ho1Z#J7{#oVLO$}%qa0j}5L)937!54qM00GZ!efgis#-HH+k>_H@1G1P z_&YKzHOwiCDA8C}t5t*6kk8nr!>$*>!xv6NKf;K$QpC)7&`J^74z^_zMaD4Ha~wYK z6Yt<?lp6(!fBY?%V5X*uKat;S(Roeog(aP?*x(i_tj3lnU zsA;-)FyZiX-yT-WpNDhrir)T22wj@k6c|Ycj7gc%L<)^s$ zx+mCs!3m^LUG9+#PaV5}&wp(nixtsh7u5q`k(&)?ngFhB9;>-e*ue>I=@;v;&tXI{OZo37r)Lr)#$ z=*d}jZrahZjY$9%b*fx#&JiIfMZK+k+cqFbYrJ=e=E=7K6O7D zp&h~ytd`n0XNiL(dV$&y#rbHkOt9`yIfUuK`o#Umxoq1gH(#}r54?PykACY2Crc$h z^;m^m#^Q=Gml5A)JaCxIc}(SerVBn>rwiD&#Yz~Nu(4jKy*9zn#cI+~WCX5dM4w&m z+un4qdEQd2`NwDHP+DV)RO#DA|J8nNblinnvsR8;9r<13$e%>M`>O78;oHCsyC-=5)C&LiT_-6gibu|_@E1RJ1vk&wl)?xh z1fHeXBtr@oJYQ85BL^u3Z`hINT|08*e4GFB?UNK^)#U}7?Qm2NCV)O7{njEej1*GZ z9dS7s&j#B8#rN-#L@ca^T-0UgWTY_4+`=rQ_NX~#w!`&T?c*g^@9X&4h2=%YM#t)F znvgA%h~uYD9TJ;1?bPQ-5jNo}bq!Av_o3w)C`^PTP7-VjDj1%4!>Grmu^fp~XeFq` z3QG!9l$i6`wF_u{OD2v(G3z6oJA3TLy z*MjNZ7hSq}ES1c-f7Z8vPO7f?&)WA-#%c&HNB@rP+)5QoNVXQ7u4Z~kqWe;WCI+F0 z6Y0>}7~Mo0E8cL;X?AUy$yf2y^UGLTlgoPeo|&Zi>itjh8=t<1U$}XDCpstv zed0maK^G3HREF?98${D-Gi}yBV`1A87fGB9tK?eGebGgyGjuns4HDf zsTy!?^eCK#WTjM1BjVG^Fh_FTgv0&EqSg&u_t9ZB7nnkVu#GvD<)ZCu$9k!2^nD!n zS&#JaYpQN{)l=!tqv|M1LBi@1-6u^gI#s7KF+1dimwF`vihO5}WpkN(JIc($Mv z#=PgR9wdq*JV)@#D>iUuxx(CX8BL`l;->Gq*5!CL=Xy5p{mqzLB~sXyl@_V3_u07b zvG8IRRPCog#LO<0p<`^q(0n8LQD)E0GBrL`%NA^tC2LCM57$ z$@vvnqIKFz3PniV`+PJ{v?UNH3R?>}jl***{Pay1^VErXD3{vu zVtPMni@0OU)`_A%*LRp`9)9K&SMQo3i4zt|RZcIg@P!ATN9qV)&_kus#@A~|5GeA!f{>UCw(x3w4)TQ9^t!uphwdZ)nl_%J|@oDmzYRCIb5{qJanr}R`g)e<$ zI}bdU<%v~^MPiDpZkb|T3R_xk_NLokXjUrat|pM#zydA1)H2=AS#5D?^aQ$Lpe?xCE2`~30x_O2SR5(?uql%U<`anhhnugP9yLH7fp`Wu ze&Ofea~K_wE#G!*$p>CG#p#t2#~0?!0;FkjM7K;xv+J0<36-@(+Z^9gyFgsoES#mWGR!EX$x(vJTQ7atxZHv z6jg}ggl|51is#R)Ft=LeM6tw0j!&^1^2c9!ngUH1#$oLtiCudk#S-`h_JkQ0p z>=b#6SS_uP39^jlM`;I~n)Z;1l(9d*0;^++kS3i^uYlcJ^(_o7XG_JH2$`@X8v>iR z+_;Oceezx&KeEcpFP`F4Uq6U%^;qD$EU4wQn{sT4R-#Q4)*Xh`Xg+fHll<}B2dP8` zO-rOeq?#DrRzwYoyI3s6Xq|R(^q>d_d7`XygK%t%nK5HzdEM?jd%lYadIPCrBbJ_wbla&%XY1&>OO(l zQ`=%DJPW?D&1m+YvTea=5Hu`>y4ghZoXj6$kvzgl!Vu5(nhUI+CJ4ic+-r0YAZeP;81O-rmPCo-rt5cc&E*%6 z%XkF7OCj(OTJy-c3cvKX51TwOJuE!{rO=#c#}ZgXByChwyG~NoXu|piA{(gTFnWhJ zofE)fB{XBsu7%KH!z<;**dSUK*7P-{#pN3|a^3E6l+s+Zd4vz#xQS0aXPf35IZx6tSw6Iy`uGQ8vBarSO2w7etRvbbsAMr;zkc%VSm^4OS@OyvaQ zSwX=!{!fk#b}h`;k~p@7 z+W)H+&dsjazAHh3N+NpdoET6%)fa2kVEvnC(@7MOSdeML?MpUIF5tkxY&+^ zZQIzEjb&L_wuKb3uHmS;RiBs9C}2y`Y6aglrJ&ot8y7~u>!ZJtq6eNK1eG{6_hr*o z;=6*Wg2&vsCAyA3cgP=f=f<6eA|qTQd2n4azQ<)bj~$}{TSk30jQUI#JjU`a`HVv@ zu*rBfzANxttByRiA4|u!doRN;!oxH_YC!R{jvKOv>wN86T0?X1lgD}A>-O{7Egpv# zL*Dmqwxg8h_Cxbrn)gz7eo3g6F(=T9D3(;K<~k;+cAxYdLT1yqSZqS@>PViDl&T4q z^oWzFg;|jjwr!n;0|h894Cc-aT>{cVxE`LLBa;~=lN-a&j*!jg*_aF1RB+f>aM(1e zxN`Rf^1(VA9c`TZwbmp_LKugH)sSjjC5dA^$7g(Oyg5MH1@b`gg;Rvk*q|A-=|G}2 zpS$N7h$_Tk$hpN5vr8o&IkU>?O4!20cXU#^$7DK!Qe-q(mMySoHZbhR_;=}S&sWbO zBo~ZJ(3;5+iyJnLa_5m!UHsp&khF^@scALLVlwV~?9F>@9|_nr8ZbGME+#pTk(@&z zW0Uo50$1WXvJp1`WCNdU;5W1Zf>v*)E{l$ofUcxy$uON$)49;yO+`yp*@=|3PZkNm z(bJRMdgsO5_wY2gKIxbYGP$1Osh3yEu&9;>%cfkdVur<=3M@#!wnF_V)_WCbG`LB*y}qmW>GY5G8ILmE^(_3{d;Ll9P@W3|nw^>)u? zL*OuxaTv)sj0QHN8Oew*$or7B(^%+vn-ZOfqoWn@gA?I88o@E+nDe8!m(%%>U_&gq> zj>4D;-+q8YHx#ig%BpQ}q3715HFrFIikI!#zz2WyWgsQRQiVVH!b23xWmc@1C!RUM zxurEM71n?G#7e@4{^~BCDn_V850ALh{k`gTy=l8_qDJGQC|6@FE7M`tDuv)JFWt%` zr?2LF2cCeH)8_Zw0Q>?3V~`nvY@UmASuQB}Y$>?R6dcBLHX|8H))V-Sv95CLRO{*3 zxL!amn`2}o-&_dQDN3akNsa> zne(Fvo5K+WSRKN??$S4ni4*wx=_S5)>r%5{X}uuQ>qeZ+>lH&&VcJrdY`t0@;n1|# z`M{8k38Af{qr7h4D3%mVjb!+D*Nsz(BJMvk4`B?B&8X|J)%V$u^_j@|jOKhM3qDf? zpXm`Jpd8OTp<^Iku78?!JI~?w{f-M=dHzdXdT=TSE(7 z&>t}wiaM%o)>3lQh1&?+&YQ%tByYcZlINEyeCO00R7z%pkgoZ1TqZn+oq@yVtiyE9 zW;|;#7D)2GB#i#B-K3Se3!AnW-?$;yh-ABsMjap~0)~UVV6_WkaW4!8;F)T~A(drJbzhatDDZcq^2CJ&c2RoISuJW^=yoYz~o?yh1+jg}$I2A&$f9Ev6@`k;9W9uZN@LDth` zTuc#Vn?2ID?WVQVXirHPZ6N~KJk#3Zpo>7=eXlR_XZ%TUg)M>dniw(OxB zDJewVojy)9VU%0~Jn-TmSOOq2_H}Iqlj@-@USFr(wm@{zx)dX0{AODQ!6H#Fuz>0_ zcCFJ-E(OxE**-qbk6ks*{_PX>4f4jlo7p_-add7A6ZsrdBQ9e(muz6++7`Bzo;cB; z<5x<9XeywRgeZ>cm9{CM6qc}X90%9+aBK(P^RWV}w4rpmzls}W7c9rRx+8BjAx(_K*klgspd&aqp7i^#BppKr>1*y z4TWd77Ou^--M{pQnIaT~2)YW-Y1b*O<2vX^)#4ezc=sy|CFfX1FfLLpixAz0mU?z1_a zJeeAG*fil2_>DQVkz9r=cWvX!U9Aq*?X*J;eM+<qDK| zp=RB_AhkRD)wCSK&=HmcZh+@!8Oh`+ju92Y!~OEVrj@*Z19eKwBzOcgvP z3N9mAoAH9pMBc-5yW39Kmc-8ZL-P;+njTV`R1DdKU=3A}tV{3Iy~x&0{#bPr*1iBo zb8}V$E>xGy(RDOf0)&ucEsKKVl5;$=en39!vpMf`(=MMqTSq8YDojsKQ!K7gD2%iq z$GN~KvuP%sRu%PPum&!KQOH`k*Z>!#ow~1^!Ykus8Y}>!ugtUgerzr|lu|^oX004E zzZ!CSzRI!rh(n7pCrXl~*kuiu&~k}{OPtQ23lu_X=2_dj-U3Ut^UdaO1|iV{3#S)@ z-s%3xdM>Zo?IDG++kfvBBmCFz6j@nb1QoYwo>IC2C)H}W;JNJ0c(OEiB6z{{?=A zT-L&pHOfLXO}Xg)3wiq5N@=24Q3(@Dm4wMrufs^Q1>RJHZe$o3sM)qKl!0smYG>`-5tXb;tSQybJ37uzuV5*4^|@>3@W5=$%r{Q^s}JR@Xea%#3PY zvwxi3Tc*3x)2?l^WAii<1)plA0@@f5)@jok%rC8hwCRgo#ICn^BJFPDL{W_tt!FQo3Wd7f)>nNVDFlrb}}igy(Xx@3A@S zu_5m>k@r)rlgD`8Wi00~lCjBWY%-pe8j*@7`r}_l!TQftAUDpjInTapb!BBK!uR$J@0_+VtYQ9WPL6i@z^;Yuw}w$ z!%p+=u@H?FHBK~@Fkz(_F~1UWb}8h{a?F`kn6F6Ysy4HU!<@2M(l)kmu%*DQ zCD+(Z$5$l{*>HMD9bs*W*HK{g!7FPTtjaoKHO^-<=&}(D!14JvJEnN)#gj-W@TAQv z_f4@hg;Oi)WU5@H z6)G*D5|xm|rhtl*1eF+ARth7Ma~wk#WipwTO=DPy64CJIN|L6lYw_Znrc@ZwPJHOh9t>c4} zH6lkp51Bk8*(^J98MfqoX7U~rIh(PpLm?34JW1ecJlmikwp|mB+vX;93_tJKF0N;~ z@Iktp??+K3F!2h_#c-(-vr>v#Tn#z58gp(nVcS%|OZF7nx@2V)t6pUaz*R@Zzh%{h)Z zu@Lh7Ld>BR&BfyZzx>7tESZ7~=`ANk>Ug7uVQxA@pX*}r9;|<_=%RHOPaQ>94R}bc zVQd$Cmn*X#I|@FV#{y<*z(c`fEbFAxn^rolF0f^TO)#1T0%^A4DDwKcu^EQ9@)_C0rR&&Oa$s*LCWEV4mbi7BROJ zabmH`k%gF}D{!)EQB)2^>4D{-rH8H`FpaP^Sxe!1qOZS;kfixxa>xRz%ec7iCq{4k z87WN%WVzsEz|DZ4g-nj^*&H*utZ`7z28`xhMl&{}fu!IIa=s?xfR~DwZA+xOCkrbL z>~!ihk`X`F=(`^jb=2G`)z4#8Lle^?s+cghl5lD{;mES)xi!JT$YL2A%W{~o0|Lw9 zKV@Xcp&!Xgc8}(H^7LxznoVER$CAT5!?^EJxUZKCh&mg7EbG4ap&s1;FBq9|7t%f*PfjaakFe5 z4cIVNYZ6`Z8H2F9j>NX4@pqCP085w8{Qo~h%G{HRN~l;VMx0x&a(Xf3_+rG#70ubQ zWI1+O#-WHq8HYr;2(n0_krFO+x;2~{Aq0v9tEPFqa(e zn{RE}pj?evDMie$M9eN#IkgmXW>qs+kt~HabIM^w+pK7d1P389W>QjUgwu90s2I^j zlcD=bb%e%}31mj0v@%4OME7y|X6mR0BikOhKDM7_ER$y>Q=pK`n{nA}z(m$%DrYf~ zk&I?wBru|J&q;?BQX@c_7Eq4u)CG>N>$Ys-HK_Opfq=9mt!Yi7nu_5{!b&M(b~)nI zLd21Ui079zM=BOe${~~<(s6Nwg|6FcD6kb{wq~rc(?hIK$|AMotiRrl4H@3BH_uWy z!Re(1h*E8i5TXjU}lUt+s6$ zp?(eZa~!NDzo&NE?q4p&Bhtm$+;i11U6j{C=9VMoRw8CsHFG7wxr)V^$YL(BnbQ^# zKDG$(q`;8^A$7wqE4?nO!?(AYJULSdu{>wGx2&Cbo!Y~M7+TVB$bh-@z8 z`PU6H4M*eEM(!1aaYC`2uv`pTSdBQh5;3=?m|cUplH_#N;#6dDQdyLQi!XcvOW@Ux zt8Ab_QY-V%Ce}_RqOD66b&4=a;*`DU117ZSNcHdyQdf$&VrkfZYvhnEvhlr5GMhoW#vEEgpLw8%6HT}P3%HQD-MYSjRwKwH18 z>J*A-q1n55vNc;oskY&On(ai3#3FtFmR3H9%z6qe)k>G>6pRqOZeM{%=GJ)ZWEJ9S z8YR)Ld9s>N3zwt% zlTt=F9>s>!jpH~Kj_Z_Hmv!{Rwrm4U=JJh+BZk*})U;H!QOzXLhDNBytP~@b)*=?x zVgpmI!r7AGcv*5hlsvC&qS6Aw%QGEJ;>#N2pTd-AT+viXE4su8^oEMZ@-~jseg0Vr zxay*DZhd|$9DU3nS-rZXnxBnjf#o9o431yG3r6rVBe$?V9hC*RyyUhNk;|As`yk^O>+#ic`+M%8A8@6HAKICBb63%Ch!Zb4I9Q6Q#Lx zHH26AAhgD--?1@5_0T*ti%k>VT3`Vq*?_lRF~wv?a@TV{)v{nBa2XAZMZ`!TQ@T`; zaW%fJ>qV=Xbd*@qs!ul7#+z-sVHaV>o5i|xPyZZ`W_^$mrYg!|La}U+!lh!&{A$AN zs^;{n=IEN>a8+_Ju~5Q>)p^E7Hc@cB#yyuh?B{eFx*m7i;MxW*YI&3z-nYNN?ir5{ z-+7MZNE^SQ^L$uRc3@vx54$1%>(D^e=(8GqSE`!xyj+U;f7^TWXiLuWy!ZEgHSK+d zK0QjU)_^9&B!R$SFkr{CK@!NrwU@nev+nXuZ0E)|xv>KnLu?XHF>3C$ox75C<0Kf{ zNjwB6SjfgU#=!vu0!c_ckEgrO&}W|ZymwW7@BO2y_O7a3wa;k{NP<&qL7&z+z4t!# z)%Sky`@GNdyz7mSm0G~UMw`nGkBe>1Dc_=rjcvK?wZ|CKdN9~t4A{by2vg}bHs$n& z>s`e`4^C|PNMHe8A8bfYL>&+27UMI_Z`>*GDV2ovsZScE9W3o&IUb(paoc!>+xB?e zy05}b`zu_(x5B|Gm#J}=iHa2sDUXe&GmiDilP(5hgfR5!bo~tf$ryvyDvlGe?SWV6gNPC^am_E1c$_MEH@r#<;TH<4dc4wk4ZNq9SvmtSNOdr_Bs`SXdY@PO#W% zf+fS7J9?n*zI8u8`OO_ZbK2z#i#4vp;)byb2PZuCO;$KK8KF)GW1pv~afivOO|@c0 zPUCU!wums^Po5ZfbC`ITW#02COt??+_jN2Sc5J)f+qEq_(=OTx;*lngC%xq$6nsAl z=B-Y&$=B)u%UdC{n}$m@VY;n271#vI!L?oXTH|>AHf6j(j^Re2=G#~*pekW%0!k78 z%nY^T%HhgLS90Wljc03&2@3=F+wVTa-(9xtW6!6ls%E^R7;_Y!BREzx+QYJvaUu4A_vE+(vSOUr=24KHtjTj3v{3^N zRJ$9p)$-Y>^;oI-tkgr68xgXx)Uml5SS*D$YuI?o#np<6jyP=fa21VWTw5T5E#dIa z*+DX#pMM!4Sh)>q+1zsdAu5i=8*Uy)i=d^4r6d~v5qmw^3G(U;P^kQU-$~;1LM2vd z^=;DDi9BYaeOGS-B>v+TMlYH<`E)#~P(2Gm!sFQ#RN|GlT7G052a@r1fF87Xm+`6a2O;c5_-|KN` zsuCNoM(yBXA zTf5kn2YM_WE>NCu#Fb2zJ?QghH@YUir(sY48yCz{lwm`-Og5cb_$M#+XurLJ=cvN= z$?Z2B;P1ZG=k6nWId$bm_KZ)luNpbyPF55XuEec7!Lg#@vsTXYDXDUz1O1t!AkRq) zFQ@tmO_B^p%C34`@vhcG7HfvNnsBM5xY)CpF*Zuuj9C@-+8QSrfGrW>(b2-;^ky>& z;Gyxu9t0-04!HzsL^3=mE(U?ZNHK@Wbu4Z;bbtd>lNe+A3e;<9+r6j|srXigF*?!g zM8wqP%^vd`J!UpSW*fp{*QRM48rsEZ2cuj}yhaK^IYPyeD6-`^P(?MPg@pc7_M%ID%j{}j{emQhsP}5{Y^LGYGG}8Z8w{W@1Gw={Fz$QXSE)o7jqjv^IL|6 zw#8;(Qxlg~!gEuVKBYlxK~)3?aQYcgfQrp*B?zK6dEWc3$kTA-8V}Z4L|EOdbNj)= zJoLl2@%w*$aVSj`fjyOwmrd>A%Em@K#X}7QJGR4N&*P@5$MqAD+4O1;LQ}#G+KQ;-d0v?ov5P&j~ zwY3ChFfE`U2_CY1OOkXMtfAxtKMO74lV7^RKlt94^J_nJJOAS2XZg%R8zqL)3HPLt zEs0f}(jTEC!{P-?D{Ei)Oc1O}r9!P%BM5?6I;okO9A}Dh1GzNsX_))ei-~cu>P~AM zD?YUCh(KGdRtx8QU2Cb7kk=F9aWjS}SGIaAZuVH%3R!Fls~wBYR*N;Nw4A-P@eoyw zN4~^!c;i03(_e_7d`6w*$opigDUG2Q`j{}tZ1Uvckoqa>@D+X#;yJ~+ zbH%N2*DXglFj?j8ckRQ30m=kuYv7XWI!T{B@*hgtsL$3k^VuRBCgxnE+Xl5(z*@~` zVWZ2;y3eJ$X1b-g8anvO!PpMtRwX4w5YPtg3Ad&XSrd{au$8MKEitr>4`FvG8SZcR z)CMiBiX>gjgh*(OY#UW8l@~oaLE1Vbj7DYDnm+5b9?M$+OEsUR2CTLfYh8<_R*Pk0 z(e@5t)HqsA;3$QyK{OOniM8w#yxM3`&B zKmGW59(uRo9dEda;}enp?Dji$58b0gwgy$Br+a{?ZP;g`R-1b)a*-S-N9{CjRi z1sna}-*Y@Voi=yBY=ZZ_{V)%op5V~f+E+ zE@C-Yx)SqB2LQvtJit)Y#w+AP#p@S#5v4O-vm|*kxkPw4mgZXd@t=VR4}EcwRy*LI zJorj}{XJJX|C6OR_g&P4Z})P zvDjA3ccZq?oLE?@LdA;u^sbIN{_B1Z&(@4v8aG+=!og5G^BWo7=mX>;Fwivty}tCm zc%v5{8pT7Z`mY~`qlcL)1!JCzcilmZkv??169dz)1qzbzF1o&<*$!B*N4_QV8$NTJ zA#+Vw?ZxUYjf^5c3J{2*8-{d)?+dAEVdMn;{jmU0dxgjhx6tiu`OwZziu`tSEOjnq& zEvkLewoo$xMnd*lD*KEFBibz`F64Q|mg(=g=$j!BhCa6HF(l?-o7XSkB};r@CkNzA z(BmI{{3IXs;Ptofr&e2i$+hqL_AoJe5g0?a7bVJ#b`Y;~$a0Jb&(`5mOLH->STPzJ z3ry~N8G9W!vV=*vrM6H(sHE4?lq66iB=Li_jS6T#G#F(P>}i`dEE8c3udgTYYhPNT z=ZE~m`(IA0KH#lUe5h*CFTvQzWYgXFVj>P-#2~pOh51m0v}@x z5OoRcSX|}U4rA4EtnpNr<{9|mrA1cBer>elBzUXK)eWD8TF7EkvDUNM2yE7IX<^Z& z%F^Z%hxfe>`{bJ;5Q#% zqTB89-XDG~zx-qOu<-96<0~uq@j)etTj9PRAX)~&IQFZaF$Zg`I)+x7W~)iPQO8J# zi4Ud(mb7E;(|C0(}C zpNukrf(6a+by693KdCaQ%pQ!{S)yub3rl|u4`&9*MlUu+tu=ktV|CYZEnulGth5!Y zU5h2(W=(81#YU8ir4??1Y}i=@K@(ytAv6XRhULV^5@o9lwej**Zw{(90frC>yCag} zJg+YOwu4rLNxnu97gpoO9 zQSdKl6ZFTR#Osu86Quu9^qv!z#lgK*YOUUjG=WMz~9X}?KHv?9-e6DWzT-ge_ zR1+?DG^^qeC>LeBj9E5HrTC?Gq~aPA!(2zRR~f8?msH4uGQ*>+atT!bStMr_kaINm z!*1;Bmq&%Ae2vqEY5(!aA{fbg9sTkgufJo0*WP6Jx`SgsqEnu^7i zVzz5>HME%*3r~+x(H7%cV<%ZtOeEJLR54geVTV3SR5@C_U9pn^80aTXQs9wjOb>;k z+zO~Ho~F%NP44f5&-6d0SNVx%7X|bJKbm2j9k!TzO_O@|OdMNCC4cG9Id;!Z6RaU@ zTPa1gTE+9cKB4^CaG%nsKorbPTn&fRngJ`d9*dhkvl{_dYKED%W;w9ws>rV1v&Qb-zDMvU^)!aO3aoYip+YXI!(}6Ku*X9=< zndY&DR%+i##${V2g<%k6KHG3bYWj)Q@TqJ{_>WLkiuZrtUEFcQJ|6kP3EpzoYy=JsacC%)P$wLyWR9SqszNo>HVp@faxQ^WfF$bV z5*}1Gd5YFpE6~bdBTQJ}XyIxnRXoaY%QkwiUYuZ+qZkw<$VN;q@(!=B5#igfALHIT z4iR+LGx*W?*f@@D({6WITVIW4;KgDS*YOyyj$bp-P{e^6ctHuhAWRue2dvgY7PkWC zw+xpWFx`$6vr0L5c9kj1!b^)jEWxr2x8#xi5ivDdOGVxTF*9mLpe;f(E_kl96fg7O z)-laZdu)7xPh4seiYYM?H)td-Sao4MB~|o_n4zSq@O(@ml?M37-*pEEr^fiufBrI$ zFE=8C_Ox?;s_>N}L^WUZWjkB1xE2JfkUVfLMuN#m9b<$bkVpyC^jWX>Sl;qk*zzNp zW-H=iY#EnL9D2&8r^frUg|rg13%G(Uf}J8dZadgiiVWPcn|u(^6}}1Sh0$j0!<4Cq zDiq-dZy)F9@4uZrV{YFK-b&2=6tw-2gHJ4=;sc{-qZUNy-r`zsvTU*YYq5n(<}Appf0R@O$rmb9rN~AQ>M6T6df)J*Qmay=-E{5+JZk?0u5E+T) zxphNR%0CQ5_|dy2_~5(lWX!Ys2AgR!;abOMssbwXOCfzh2r%?aHx)n&hMpJgxgvxs z732dk{KzX0@Qyd#&S#&#%+-Zecpeh0v_*_b6kKsTJ@J8B&T*iYyRjlR=0Mr1f~_^K z23y7K@zh#bl+Yt6;H2eRtVz;Sj$lN4WuF7D+h=pv0hikkR=M#&h3lp&?459#s5)F) zZSlYT-YM34VJRwXrOC~bI(*ZAPaV#sd$9x^xzV$D&%0iO>)3RgA$AV(cim`E`4m&z zy5yGv4KhfCqp1N=0<~U`{PpHHe6DN+Txlp~dln7j(9tg1_HeX42+%}gfR|+w|D6;( zWukycDHw)6I!<~_zIcoapEn<{dD|^x+5tg=l`n}zF(sUxxtVgor#${Wgkg}_k_n0qgGHu{NTc|0*`@i*e-gMUyKJmE|yyedEZDOa4D0(DD zj3c0-*7RA6xupx60at5=#g<~-x7jofTR72B;aF&uh^r=8R0W zWRu^h8~TI3G7J^^W47?)-*yY{y7zEyE^lN2YtUR>X<~v1DN859CY=mhLRWfmjVxBWa_Mc`Iya5yz_20>n%R=r(b2W+fEhFQk=V`&;I0fNfe#wR%aYbg6Y4K>4#jqgW=SLoR7g~H>vqmr3YR7XHd{0OdHN6 zlf&EHka{~(cdgWXmTCb@^^m2eV!dmz8ak{Qo2H74G_}%b1&)e7`k>lPD%Y~jF2fJ( zPBuH+7{QU<2s+`l1%4?4p#@gxcI_Vk03ZNKL_t()9Zt`zbK{{&{`$#TLIaZ(i}8w0 zs06?3^NG_dghq1h1IZl93L6oBpk|WtgE?tAnS3>!L01i8f__WD?;orojdnafsUEPj z6*5;dTy6+gx)#%+O{i=f%VQ!&3I{C#K*vbo$b*&4eXS@V6u~#95P>Qk8&Rg5%(Ucl zZ61lojF?U-7s^I>^x_8p@h{Ktw!07W_}Nunee)isCOy2W&EiIlwapq=o9*FtUTS|R z6_0HS{er?p3fD}A+8M>%p|w`X#(Ita^686wX0FBqcTSE*gBft${2qKZv^_pms&QXs(CfmKWrlT7>zNJ#>tVlGYA zKr{P1m{=qd8rW>KS>9-~-srGa>oK$5=ACc4nGgK&3Fcd!3_6^DIFydNTbX2z(&Ds_ zHplJ1?DIAld8wz7;GBqIVQzJs^tr%#C{q>d-u~kPi z@7pXHi&bo@%EPfVRjnf=F$FYe1UIk5do~46sj9N9z>jD%V*K3mlKndH6?1D%*6TfH zR~lSej3$Is9E*!94ZimcNBGbuPO;SSOOV7Q4(N!2W5N*tLsH~Of!$5f_`T@wuRJ`- zjr%9~^*{O?UtF#aoceRm|KO}moxf@IX%YE7`Ha1;2D2ZSADLjS)OtLAcGE0wh0Jb+ z%rs!Ot64V=J>?Ku4pnOmOY6bBSVwRjGvGiaWY#b&4&<2~Y=&-*0N;6?%lE(O5WoAy zRi0ey_51ZnFgH>J`BK3CFH3T=n^B30f=4p;ppO<25t`#g{mM$4SDh5@y>kjxftoff zY&L0hdfZgCsk#ay-P9ruLzbWr8^SQ+GNd1v;iSam9)u#Saqv5bO4zKoX?LAi_2aW% zkI;>!hOpd#`L<%NXE7hztSXzTa;aDr<5s-U`_gH_MMkSCOH^J{7QFee%cBcD8lf4Y zNSJ<`NHU3KF?3&`^vVU70WZoQN_3KtVnq1t+!oF!PVz5)>>j*|=APRR((*&r8XdOQ z>+EqYwDbrvP~gnqPY75x#h_&VM>lqaCJak)@x}GPEv_J{DD> zga4$GAQ?(7G0k!ik8i;7X~o;`IY>u`%(OeSHXAhBJzjO7O4U@WBVvnK?|sOd{#kRjn`QrNa#n%Xh|=m zL&*R07w37|l*5I^I&Xc&b=)zvmz!@8mY$p;3_I9Cm%#K2o*zkZ>MV?94FnRY!#7P< z&*DpIdjOL~>{37Svv*2P%q_TS02Z2_xs^2|Kee$t1%G=m4?D zmMRs0w8ZeMpT5Z5hbzpjw|Mg_BP6Td^*Ob?i4d^g4iV`Mt2R?xPumKkK;rYa7+}}| zFKP&l68`keGWKsh!k=GQi_ZBp5-J13P#F@)$k1yIhC?S)PGZAY+ifD@zHJk%*S_MF z;=KQ_<@%|c}sYy`QVbL2C!c8fVhBaMH>j zN0@L76PZKBlpq@bWflA|y3qmN^QL|L;J4hsM?bf~Z$Gh)AMRwc7bH<)MyM;va%q(G z&1ns$fDaY@i&h)763#4bqFflWEykQkCFD6enq!qCI+`@J4G0e1&_|mfS1c4f?^2-d zNGW8ZKw|jhlIF8kh4JcMEGIJ3?6>cdmOyFSv4969rWh$KM1En)h7Ww#^?dtl4iTDw zj~!bj2#fB2KG7{ehzrRE39>vOlLr`#7J5Nkkj^9kj6QfrObGxOx8PrW?+s|n;v;{v$hlfD_#Fxn z3<~}<<%nd#epE5mY>Y{@g3>0C(N||Tg;u+b7N5U3a~0dxRBeluW{c1W2P%Suz1+N2 zNhN{N>xPz&pPdq9xTvTpT;nWV#6$RJe|Z82xZSh((4SmkzUwg;*tEoVytv5{YYkxk==NCGe0&dCup z1_gvfNaH94t%%U=cCmEGr%%nZw`#M;b8)SRgMGkLND%g0-{cB5BZfc;p>3lw!l7#i z7zVr23|#IJ{_xB~)(0)~d{8!#doX*_vIWQM;#HeC)dr3?hh?7t{bi6R5V?#owH>Jl z9mLoYY!k?fq4MpWth06l*+Un`Ea6w)aU1vCyoX~KSNV%$s~F$x2!Go~T`Y!5$A zZWRTQmZ3M252b)sCqOA!Sl;52XE8D6QgLm%e#n$(5&B)an$Z>k2~j`rhb!ZZd#%Y< zmdOE?Hb+c--Zt=5S95q`A4gRBcNmov%MQc=1^GeYP)y-}f7Jv(_N_N!A%oAy8&01YxtqTaV&1yS49V1 zx|u*yjM7Ex*WHE;nM#HeL^O@UrZ>H9;b5?bB<|#jlhFt3(4HG=w+@2Nb4<$Q4Tt`Z#Gp(h;KNKZIM1XFA`D1q9H97%W!R+ED`#g*Bs>`17 z3R~-SDz2sxbRvFAnNOY3z$B75ftMYynb?si&`4RLm zB<|_IPgtOeEmByG=0TOA7hN%Y=v%Mjd+)uTxz##;*d;VUPPifE2!9dRr6{(hkN`ml zwV@{l-B-jGzkXMQPN&CM)!|6hWz4ncbOKh5!4E?AkJ<4Ak=$COUMJEVx|pz6jtmze zZbNH4{AaSpKEm0K&ElrZzCG82V~8|Y$@>Hat=M8Tu@I3T0W>6^r74D=d-FlQ@AcQS zR&TM~Y)0z7ZP3IaAE$!nEX`e#oKtxi)8l*-mVg-1d-wwFuFsg~P*EYBR*(7BItwdJ z{NOPAtBPLOOFg&4=Z#VlAwfZxjD>k_@OB#8sd)m zSneX0bsVL?j8ada^aYgO0@VW3<)Qn-?Rb@T31QC+U`rWU2|O!KMlPXnweX8?zmac! z%^_x%>iqLhoab`0Tasm$dqZWDHwt^cLmVun!E%u>9wb@x`tfUayU~+(U~iQ@dn+t& zHd&afLm*uLvIF3EqdQxg0LGi#2r3M+2Vc4moG27V8IDSBjkJn*L7~}36Y^TYx6M?U2hq{O(&Ab2K0QtMhznx`qx-_Op&mqD+=pp5ZN(tR)6SA-IU?CcN$8 z)@;0ny>6s(8ux5od)Hw)en6w^^VPG9xQ@mN{o$T_4pmgiFzhhf_s>Gl^b_I?A+oIX zXiJ15ny{pBDLz<}R%`lCNhh&Vgi>U`e&1{M@*{7*g-*xk|Nhf+d~UHhxQ~Tmi=red z#T6_f9A^r%ME)5;?Gl=(tCVW#NDhf?#lC=JRfn!JT)Dc+(t3l#d#c>9eKtQ45dU=N@w4AJs0%1pB0IY$fdis7`dW2`htv>Z5pxY1L%TUW7c@AVXt($hFoL z!vA&8UVh*$M`*OV{Q4)(F}>MI32MytiE>Uogs_+^7V#e^1|!LGmMTTWcq8f7nHfgoi&{dKj*!J6 z7w4U$iTUnoo=jfqG7tQtS4{GwZ@YSbAq>{u_ljH2Ai=AuaMr9IQ zqB)R`3vLx0Pq5upEc+bVK8|IbK-=e0)>V*2kWD^(U+`>Hzjmq5LCTi~vQ|WcUzRM{ zu?(W5B+E|S5Ci=EyZ7^hZ@Yy?tH-~7v z`0@;-|39G1Ae#h=-UOfdTYFzrSu} zsA{hp{r!JDc8*WYY|)VjJb2$*ZlTrbMaoYZE(FpD2qN@MTD4d*{z52j*DE3~Fxxgb zl`igB3#Zb+c4yJn36y#Q_$p#vEnCJdT#R#AwZC)&e zJd+(MES0Sht>PG-jRE;tea&W@BZnsWgU_8pOvvJTi(^YoKK4`J#(2ew{RzuDHG{Jx zG`%dPri>d^r1%pV>`!fj6Bj$SyM^s8V0$yz&P6QyG)kWV&LeV_hwgjcT!9M{tWYq$ zaIiSpB#LX~LXB$uB=0Bu&~0P<NGN`Ds3Ob{Q>{Z1ijCB@Z|>gMp0<J8tKdw@mTG*(HAd&o1HnerjAvl6nrzDw3-@o(_SQ~6tu-yiZ zw}S00V!M~H>@y(BH}Xr}z+~HarM$vt+8P+_iM#h$eDDWe!43PWJpAYdKJw@cVJHM6 z5yS0$*1dtYiovZKoN5!xo<&>7qIQ8g7VSB`g`$m-4o6chgZF&$CSv1T zDQwvm%^n@Wg~}gBL!7wi%Qx+J`S}N5$-zAyAOG8FKK$5X-(P6>aLgl71#SBs@E_9% zi7^_Z72U8qtb9%tAIb=gW{Zk_ke~hUPe(ok@vnF9W7AA8ZpA2k7L79L#5{Hw?-{?3 zNRG0)8M5`UY;e2?&9Ey0wzGm|pG8|wqx3PfeF3c&5Nw6{JjUN&YW=gFFkmRYmXP;T zTkchp7Vo|P{1y7mqDwWVAAV#3UD2HBuVntqn%bP@Nd67OC`46=o-UEKJg^e>n(^oHKdAO6DPz8?+p~b>7@|-qL@lw|=|*n$n7@NHc&{j+gIkFu4k6!0 zNPpJAkJcdSS>`*T+*njl^hj)M1rVXlBPZjk2T21$>o!+YDMg zgB6iA79|u{1ytqGlTo|YhO5zEe0`JbJF3W zP{n_hzF$^0Nmfa5nyjzEcGj@m8Ej`7?VQK5&Z6`*sLP01E<`il`^a^H5!rtB=(8(& z(&ywJOZbHcZs(rc_H%Y-jSqhE9LwF{Spf~1@m!x_{o%Z{X-N<(#` ziF3;$wmXaMTteIDQ2HE7T?CoI$RWG{ygkG%u1&O z;V605^9V=igF7aSO&HuUiBZKlv~@ftL_UpDm(Y3>R0}bk?KizLq`lY*lZ4{Kb=bqH zh_{v%7$^}weR_e{eQ}Zp-+Vhi_|`kHE#Wu+>H_DR0h(d|nLH<=Fc~QERx0F0CDQ)B z#YWcO#$=G5=rzNUNM{Za&^ksAon+s&m^!q=)S;_b?v;ptp-+Q4hsb5LZ1C&%KNnT5 zG2$b}+TJo|1fg6q!i8Zzl%xbjcO04ERYYn$bf3?Q{3@SC7=|N``k%2A}L2-U&46QL(#0iqNF5Gf>zOBEz6GDdbZcb zt<-TUTiDJl%07)&$AIIAT*R$zptN}oq030yC*2V$pkeeO?^2ytSq}Lcr26!Lkp#V z&mvqSAF3ePov!ux=bt>qdcDKn`;J%gzr5`gR6U2^__GsyWup_3dxsFi5lK`TZ&1=| z%3Q%>489m7Z4z4~qb_O{^!bQMyTCEHUKgj@!l~4--K%KpG)g}OJPmRI+%=RApXZi= ziO{m{HVWA+AIg-?MJv3)gL|a}o|xC-vbeo8|j5Kt(*8sQbG87Qlq%wP=@^_OLX?SbufvE6lS?`qVdwa;N$F~Y$mFw4&){A>aV@r~Ib z*;sZ&Do^v*2K#LgEEfXdS3iA3Hg#kJY#ol`*ZS|6tZ8L;__mz1z8(n_pU3c@wJ8s~EKkPF8@K^bR(<_lzUOtW$ z2#(5TFXpKdd0tdBpVL8zWcgB5T$dyzm=woXTLW&CQ!&`?29|v(5)tU9(fTw>&!Y4O zVrrn<&p{HkO@bvtm|sgX6juvr3_B@$a!8Z_UzpwEXa3-E{^f(O;oDz(3;*Z4?q%Gw z`2RjX&3rd3N25eW?A74}O!|{1NLdQf4w^R!lkPp#Q*_xWyD^H+!EORRP$?;m|DzoGVdLjJA=P$BcYw*t={3hP^ zsvGJ0KF5Cd3(Plr#R)Ox%CG*WPm>{scu{Fnt~kc#(APd16{)|#_Ifzg7H*}9?JZ$h z=i`>%Q;3`a7E!wU0+1pl6cbIIXVl1 zm^unvm>A(@57h1 z`6x#fp>Kp`LWXRc`f*i*?FddKi1|@%EO##Ao5qS-)J3$~1l0raUo8Bn7qCSrMkFyA z9L1rLzDg)vu@2988bvVAZg348UvKmN|N2$VTv_8YPtW1^{Fo17hEyB*d38GqR2d>9 z18$Tks7`?EHL%=8Y-bkjT*R`@q4haXmqF$*vcb{kwPJeqJwoxH8N!iNGx0*=g^@yW8?H>=n{8Ne$8<6sS21 znT+2M#fammHMRrd0eyp(khZ~b4Yt?9scd38}8upIs>)1yXy)Kr!6bS^Z;}J(nUx@ip8;Gg%(EUEU*C-B_6e^L-wn!Ako)v`^ zlMMBKC4P;$Mu%Vdn^Q5rE}v27!c_$G5^vn`x7eB*SH`}-p5t9u?^7I{$ zA&Zi7%O0q#7t$;M017QhL_t))oJxr8tmAmoxRo=E?>~XoXHnJ+O09xy@Zop1UIGhe z#6$+P8Sl4Il5CODgI`P6i7XP;?}7-w^Yl#W){j69w`~=~6>em}DcD{Yr_#i&Y+*SI zSoS%TJ`NnmmUF-oN=H!VOTT3h2^LJSEma~*VK6!5x#0OvyHA(IRwMA(e4P*c{-abY z7LU$v^(Q|JT(8M+X@~i5W#~&jDTw)Ru4|}_`zYPxy4xDDt;I={eiGyuFpaV{03Reo z#Joh-Ir7{|tCM9XU_*`Euqu@N?u}6GRAx*T8aT(fU-((KrU`B1)}+@5=t1)!=$i{J~&)U_FZ9%Aj^v~4E9~t(6XR-8G(2X z5^pu|jdCg>ZZ*L5I#}*v9F(7qRa|FKYB?exi;qa~yz>!X$YfbS!Yl$cIDk`!^AOrN zdWyi%2&LRQCwnmv;nC%8Zs_p{8<|n6*>qdatqN{Mu)QXhJr^TU$58qNN=*YRR3_?( zX?>j_88OFu2a4Scx@fL3uBM9~`U!E8sLi#7nRYue-K9imvK`P62?Y|)X^7*sa4K6k z-U^m;8KqCgMb9b3%y9I98oSqXoM3^8DlbzyJE^$sR=m+A9^oNrLUN%a@CY?Y5rScR z2~R_?-CDfa&!DUmXmtwJ=SFQIrumHmTMA-&iPV25B*-!(B30RD<@#kk{AYqJlBmDH zaYO7%sam;v_2JWcsYs4WncrPtVd!P3u;NPaKI@zrfb?I8OymU97Zoki*MD0Kx`z?cn=e*MQ)BPIeJh6;>4 zRbo4^p-c>ta-n}tP(>24Km;_nRUfC4Llt>CLKXFTA65JY;zzw;30A+wRAfn?^KTiF zTuT95IZ82B+6Gct1S2wvt7AEfSk4TVeKCS9^?6V;z*WR-yu^4K&tHy}82xR#*G5ZI7Uh|LbTQ4D*JCAJ4n6`YFTcx^0aArcAb6KH)5^aZqD1ZuGeYnLDO z!X{XV7!ysL&!88ihyw}_qV-aYEbeajp+Fv} z;hBvTqZB(KP8Xtv2_MmkNUPC2y-jR)5p7>U=~K}mE9Ved0Gb?qKz5htTGle3EDs|X z*>xsoYmuKO0NZ&mW!@uc2RWXJR9@8{j@QO^7h==Kr-5TpY*mXW)d51pn6Km3?K4}; zM5UYo8*=Dzii#ma!kyf#+3kv+^uCUq%oA=DIBtOLuEjvZG}=BB#aDF+n8(NpNAKG$ zdS1i{mI*>X8jDaSQw?yv9(JWZ=;5oUf#bkMlv;_oQNcG9g7I8M z1Hp*t#lv$+DFVsNgWBrC)%Sr4ec4yCW6R2`8fV!FEt^Nyiq5fLe#r$Lr?B37F9IVg-zB6VOu! zv`QSzV_uX~5iEBrPNE_NL#dM}J&jh&pb{eF?&13!ms`CcIwu)r_E(5r}k&&Z6~f#Eqhkgq;_OHO1F$f)$Fv^oKo{dCy%7|1DG0^st@P$dk{$7>fzc zq4i~80WoVlbboVq8J?@6RiqdA7@jFNDk*3g&?Ou%#H|E4)h>=#!*XWgz4}xPHcX?` zI;bG#NA2#{uL}e#@?*%&Aj&-)g8`ZnaiiQtEc*)Dx)8(9=TT}FWGNy-?jjgp%ix|M zSUXl-I$mrRSMhNw9V~Y_PNI&{ZzC{|(#;6vFlKkdKOea<5Hc*q@3+zW=8QcocOA=~ zA8@1eS(HxN1j`(~ufBUrU#LqPkx(S;s^MZLU(_W3QDqY;+wI|awP><{yAUN(`gFvN z;sPS`9KC;cji2|r2N7jNOs9Aq({VNLujs^7iN5O6xr$|-LFp5qj-yn>j}p}Y)7}Le zz7Z0v#D5_nnLAz>wSn9%9Crn6&&EC9)1c0ST#C6--Q8RIA~~jwMEs8-l*5yV5b1TX zoK>_v9V_)tpwyXY1cll_Xd+>kqYvz=O1_pWr<97^=H1wF-fP5dg2i~Pk^}ZUV&)Lp zdXbtle!~|zeS%~EFqUj0<#>YQ1vu4S+`3KnV|4h!DUcbIu0?6L>=rdITtpQ@7#dxa zK^7~?sI65jd!}zCqx4ynPE?oc9KFB2drQBO6D(~lbNwA(MCmgqbsSV=zNyqQs7@3- zc8QQL-r`xo_}*x;yzOj6Ej{~Ege+QT(fT5A6=Vey);apF-Jt!VIFiFQ)yYp$oje2j z7|3a02BkOS19rDf@RCZF5iEN^mvAaRma~RsUyeis`b1o$UO}sMgjURr+Eqfo=q?40 zofN4)wpZ^XiDV>uo=cAE7`XWj#L`99M@2>GnX)VRzjXlcY zJ3kp0J|}@oDSp&0vbcNgUc1-swR`PeyVve@&DVP$ad__|YWGI$Uc1-swR`PeyVvfu wd+lDk*Y34@?Owar?zMaEUc1-s_4RZ8|4bEzBn*CuF#rGn07*qoM6N<$f_Z^?MgRZ+ literal 40589 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 HdmHv&hqQfH From 08bba6f306bb035a4774d3b65813f0b4c149baed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 22 Mar 2024 10:10:47 +0100 Subject: [PATCH 267/350] image align left --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f4a50f397..1b049f3f6 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -12,7 +12,7 @@ LVGL Graphics embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.11 `__. .. figure:: /components/images/lvgl_main_screenshot.png - :align: center + :align: left In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. From 9514d36cd4f95212c1080fc6b6844ce73538299e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 22 Mar 2024 10:13:21 +0100 Subject: [PATCH 268/350] Update lvgl.rst --- components/lvgl.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1b049f3f6..afc962168 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -12,7 +12,6 @@ LVGL Graphics embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.11 `__. .. figure:: /components/images/lvgl_main_screenshot.png - :align: left In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. From 757e0458271c840c42f07799f2ee445e184592b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 25 Mar 2024 12:04:39 +0100 Subject: [PATCH 269/350] change animimg example pic --- components/images/lvgl_animimg.gif | Bin 483 -> 7025 bytes components/lvgl.rst | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/images/lvgl_animimg.gif b/components/images/lvgl_animimg.gif index a9ca99b7f8885985104abd11e6bed7ceab3a5ce0..9f6bce8bee17d7b8d415e4436d93d16152327b82 100644 GIT binary patch literal 7025 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

YrQaDu@zRonb)p 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 T5D=Ag;J}f zdZsnyk8QB;ij%L3_HEF5+Y|lC?}$v%kvEL}S5v>;oV(0#YUs~va&7h(B=;SzZ{4nT z!|g|!guA)=)urE`ORT6+pV_{HedmrA%acD+SN^Qr{L<4hBC4Wl#;hO0M~t&>X^Ak* z@U)IT{qxr5-M7-8R!L_`&+*net^J1EE1X9=agG4*-x`CpRab(hubq4JtkBokUfp{; zi~HuS+js8Xx;U^WdC@!>gyP9Pzxmr9c}#oOx$M=cZSS~`fAYEht@rt_bKn2*a&Wb~ zFs$hik(+!%b@GcEt@t2~tyX_Cx8GU!otv-w_>)aPd;C^kfAeiIR%@d1TEpXTeVgq4 zU%c<_F8qGk Date: Tue, 26 Mar 2024 14:41:28 +0100 Subject: [PATCH 270/350] Update lvgl_boxmodel.png --- components/images/lvgl_boxmodel.png | Bin 18948 -> 9027 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_boxmodel.png b/components/images/lvgl_boxmodel.png index 0368fa99a620bf1bab8bab9cd9aace6db25e0d36..ef926c45036062ffb42aa33c2d11ddcb7c0188ef 100644 GIT binary patch literal 9027 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 Date: Tue, 26 Mar 2024 14:43:29 +0100 Subject: [PATCH 271/350] Update lvgl_boxmodel.png --- components/images/lvgl_boxmodel.png | Bin 9027 -> 9038 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_boxmodel.png b/components/images/lvgl_boxmodel.png index ef926c45036062ffb42aa33c2d11ddcb7c0188ef..1331b1e91e2f09205820ca8a184c387f707a3fe2 100644 GIT binary patch literal 9038 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 Date: Tue, 26 Mar 2024 14:47:05 +0100 Subject: [PATCH 272/350] Update lvgl.rst --- components/lvgl.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4f19b346e..309345ba1 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -237,9 +237,7 @@ LVGL follows CSS's `border-box model Date: Tue, 26 Mar 2024 15:31:48 +0100 Subject: [PATCH 273/350] animated_spinner --- components/images/lvgl_spinner.gif | Bin 0 -> 36060 bytes components/images/lvgl_spinner.png | Bin 2756 -> 0 bytes components/lvgl.rst | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 components/images/lvgl_spinner.gif delete mode 100644 components/images/lvgl_spinner.png diff --git a/components/images/lvgl_spinner.gif b/components/images/lvgl_spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..cf4b1640f388df5d3a365836dd573a115c9012fc GIT binary patch literal 36060 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 H#$XKq@`m>x literal 0 HcmV?d00001 diff --git a/components/images/lvgl_spinner.png b/components/images/lvgl_spinner.png deleted file mode 100644 index ea4e37d474e2183e98317e62b89694e7c66155cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2756 zcmV;#3On_QP)iz}H000V$Nkl zO=uiP7RR5L9(V;~=mrgFz=9RTunGx8LvpZTAvPF-NG|c7tm7V~qTGCxZrR&z zE&=-xm@F(Pfq?Cka&Q>sV35Fv5saZ5W}qI-fcDVMtahe9UR76r&D8H?MkUYa{pY=U z^}6cSt?TP+u+*DBRQ&-g*;tVpfEB3$SdkilQ}qW>MouLFzzhI@h{6|XLa~FfjnO|4 z0ir)wv_!$5(J;5_pWQ{O5YUX0#83s>hz1=2>K&^}k))JC z5QKSJt#QD0T_Gxysv40RBhO8$ld5cy>KxoSR1yG770Dm_Ri$laK^MK-UTJSvl1OqY zgR8n^Zl-WI-Ev&243T`_Z*F``2ixd*g}YR-A{FRBPE?MY7v+|})N(3smiUOMpj4%3 zmnu*sDP{1^oI(yDMg_M#7Ky4&Gcv20yHQ}`SCmM`LL5f5wIaT%Q3;9&jC|61048?I>5yO3(<}$*PgKmsccBg&c4< zN~)=tLQZAyPRFJ4>y%3*J%t+NK+EX4R8F08?Yq+`X}cS4a}@#r&-2_3SM|4Y*8cT9 zN%=d~zz~;&M(E2EKQui_O1ZWQ0f1-;cf(cMSxOUm69aftFgHcH0i ziWHWFnS<9&p%5jVC{PG`T#@)w5w@|;Rqa9%Ld=h?Wx_WpOC*J*s{@U$`sBy+xJd+m zdCL-seO|IxaU5*%|8#jk4hw;5ZJl*nVQIFUFLlFjQBVdi+T z#*Yz+W;WIp0xROh89z=WMo|?VE0QuCqs1D3Q6%mb7ORm4Jfkg3pqV(>2}uKOqb-TV zc@EpWX5zJhW4a{?bUevs4ch3LZc(J7n{Zn)S(dYOX1EIPm9E7%oN@B z;w#pZO6Aw9>@ho?#aEU@(t31gVKN+NkJ`q)8l^Btj2d1q^N}OJ1kJ)b1a@GJzp2Vsv$WWuk}gB^o?YByPk@I52Gq8H{A+qgY6d zb&$SJV)j0?GgAuBerFly%e!eprY>fgIiC9E3v0q)B)>anjePP!+E3F&;`h|EGgB-l zuSm|a4cP0%uVLq8l!dq=k^VJXtIFA1)@%d-Pd>^RmLU?iMTAO&_ch@gUQ*Y^w3Hzv zyTHnCovd+v)2edv(&wy=0N~)0>|xm=3Bh$Hn?ZyOM)Kq}Yh)K`|HJI14(m|`zcIV^ z9rdfkS3k4z1>m_6Fhx?hac1p<-qA1IK-cTA+z9v&{gkc+TH8$T^g{mQHP=uFA9F`? zMG`H+Z(JO_3)XOQ8jR%Of4J+#y={89%{@P>@c7)jt#GN!y6H3=%flbJQ;~4!=u?I5 z+-iFq+)eh?F0=JYA`bseoP8!CUq3)k<^B~lkrXap0Du|zqqRsP4u0S!3jlDxo4tBn zKzX;2(oI%GG#m|8-=bOUKlhpC9{>;z9e<{LZbfHHmqO4309s{#I{3lo>@b;g{75a( zg=ls}QMzD}h=#-Aiscc*v3&f!f)4?}!7lJKx|`^Bj#Rl&6(GtZRz|16NbWx;{yYQ# zy$=2Do~h1}Y&_3XI~F*D;3`;wb?)hf{L6ENTn+%X+w|?{X8VG((YTi*o4P z^NIx8IssrCn{qYn$xHv_wVDHkJbeVJtDj9Wx?99-ROX5#8F|4LBIdlUJmaWZ&fI&tOC$Fenn_h%=59stFt?!&F2fLtM^~t0_k-)?hm537^&WTD>aW|t4M)GO` z0C0Xq{tSM-g5elAJxP=h4jn&2y~-(*Vnqru7W$I8*>tu{?sw_JkL&{B#}b=v2XnR#r{tfD73dtN1qn%KyylMIqlu{Bubi)spyy9bhZe39Xj|J zA8wagaxA+qxM&IC35hZYg8Y5+@~k>l=^`C`g8Lsvw0O7+(uL;)BvnV4dB1Wr7!c7xEuWd0000< KMNUMnLSTYU@FKYY diff --git a/components/lvgl.rst b/components/lvgl.rst index 309345ba1..d2e58a8fb 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1349,7 +1349,7 @@ Check out :ref:`lvgl-cook-keypad` in the Cookbook for an example how to change t The Spinner widget is a spinning arc over a ring. -.. figure:: /components/images/lvgl_spinner.png +.. figure:: /components/images/lvgl_spinner.gif :align: center **Specific options:** From 71167ff44f8e8c80ba112db358da0aef8280c3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Apr 2024 14:53:15 +0200 Subject: [PATCH 274/350] Update lvgl.rst --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d2e58a8fb..9d4017f6c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1024,7 +1024,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can # Example action: on_...: then: - - lvgl.arc.update + - lvgl.arc.update: id: arc_id knob: bg_color: 0x00FF00 @@ -1331,7 +1331,7 @@ The Led widgets are rectangle-like (or circle) widget whose brightness can be ad on_...: then: - lvgl.led.update: - id: lvgl_led + id: led_id color: 0x00FF00 The ``led`` can be also integrated as :doc:`/components/light/lvgl`. From 43a0d49a563ace12960556f4fff52fa45ea4cf28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Apr 2024 16:10:57 +0200 Subject: [PATCH 275/350] animimg correction and example --- components/lvgl.rst | 6 +- cookbook/images/lvgl_cook_animimg_batt.gif | Bin 0 -> 8109 bytes cookbook/lvgl.rst | 76 +++++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 cookbook/images/lvgl_cook_animimg_batt.gif diff --git a/components/lvgl.rst b/components/lvgl.rst index 9d4017f6c..573db6f1a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1225,7 +1225,7 @@ The animation image is similar to the normal ``img`` widget. The main difference - **src** (**Required**, list of :ref:`images `): A list of IDs of existing image configurations to be loaded as frames of the animation. - **auto_start** (*Optional*, boolean): Start the animation playback automatically at boot and when updating the widget. Defaults to ``true``. - **repeat_count** (*Optional*, int16 or *forever*): How many times to repeat the playback. Defaults to ``forever``. -- **duration** (**Required**, :ref:`Time `): Duration of one image frame. +- **duration** (**Required**, :ref:`Time `): Total duration of an animation cycle (frames are displayed equally in time). - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. @@ -1247,7 +1247,7 @@ Currently ``RGB565`` type images are supported, with transparency using the opti align: CENTER id: anim_id src: [ cat_image, cat_image_bowtie ] - duration: 600ms + duration: 1000ms # Example actions: on_...: @@ -1255,7 +1255,7 @@ Currently ``RGB565`` type images are supported, with transparency using the opti - lvgl.animimg.update: id: anim_id repeat_count: 100 - duration: 75ms + duration: 300ms .. _lvgl-wgt-lin: diff --git a/cookbook/images/lvgl_cook_animimg_batt.gif b/cookbook/images/lvgl_cook_animimg_batt.gif new file mode 100644 index 0000000000000000000000000000000000000000..a1ec7806d9f4eba88f68f784037efe8f1383581a GIT binary patch literal 8109 zcmZ?wbhEHblwnX}s9<1F{Lk&@8WQa67~pE8XTZ$J02KPk!Xg5sb%2-wq-;5efg3P_ z0TUAwGcz*_3kxeND?2+o2L}fi7Z(o?4?jP@kdTmwh={njxP*j+q@<*jl$5lzw2X|5 ztgNh@oSeM8yn=#)qN1Xbl9IBrvWkj|s;a7*nwq-0x`u{^rlzKrmX@}*wvLXDuCA`0 zo}RwGzJY;(p`oFXk&&^nv5AR^si~=%nVGq{xrK#=rKP2nm6f%%wT+F9t*xz{ot?eC zy@P{;qobpflasTvvx|$1tE;PCcvmzTGBeM3V-V`F1eQ&V$ub4yE0 zYiny;TU&d3dq+n{XJ=CQh6C&akmMvSpeEEtMD^{*txoXv_)vH&pS+i#C+O_M}ty{l-{e}%2Hg4RwY15|7n>TOS zvSsVmt=qP3+rEAKjvYI8?%cU+*RK8h_n$s}`tIGk@87@w{{8!(KY#uWS@8e=e~xs9 z|C}-&8x|aF<`CA3Ik92k;dTLKuQ?tYl@2mV7)PC1QK)phpH-#liH1>%V~;BDqMjX} z7I}8)vL7q4_#E%sW}2^e=I1BH^HbETFNtJL*6>?oCEE9fqj=@TxqiA{bG^2%y1F`I zBO41S?=gV$9yfy+0~-S)p}dDXSE9%Ob0{Q#0y8HkCnp~tpRlknFgF5o;Aq|(W_fS- z?%jL#?Ag0_@4kKefcfyifddB*9z1mD(BZ>}j~qF2^ytxJ$BrF8e*DCV6DLoeJay_6 zFr%J1bLQ;Xv**s8JAeNCg$oxhUc7ke(xuCnFJHNGgPoF(|_Wb$t7cXACeEIU# zt5>gIzkc)P&D*zc-@SVWEDk<=`0(-L$4{R=eg6FU%a<=-zkdDp?HjO+`0?Y%&!0bk z{rdI$_itc%@%QgvV2J_Bdu$Bi95NCD$XP>lG;54jOJr0_BOq%C1G5Gbm1+%O6#}d{ zfUUaGT4UI^*oIry;9!vCknspea6qm%ghuO)(RyRF-oVzR5**DMqgi7#YhcS7{G&~( z(X26=H8`*~srW|gjnT|8nmMr58@!`gV>D}wW({mvgJ(2rjAo6|tbxcH|3rNgQ&JVm VGfOfQf|H9` showing battery levels: + +.. code-block:: yaml + + image: + - file: mdi:battery-10 + id: batt_10 + resize: 20x20 + - file: mdi:battery-20 + id: batt_20 + resize: 20x20 + - file: mdi:battery-30 + id: batt_30 + resize: 20x20 + - file: mdi:battery-40 + id: batt_40 + resize: 20x20 + - file: mdi:battery-50 + id: batt_50 + resize: 20x20 + - file: mdi:battery-60 + id: batt_60 + resize: 20x20 + - file: mdi:battery-70 + id: batt_70 + resize: 20x20 + - file: mdi:battery-80 + id: batt_80 + resize: 20x20 + - file: mdi:battery-90 + id: batt_90 + resize: 20x20 + - file: mdi:battery + id: batt_full + resize: 20x20 + - file: mdi:battery-outline + id: batt_empty + resize: 20x20 + + lvgl: + ... + pages: + - id: battery_page + widgets: + - animimg: + align: TOP_RIGHT + y: 41 + x: -10 + id: batt_charging + src: [ + batt_empty, + batt_10, + batt_20, + batt_30, + batt_40, + batt_50, + batt_60, + batt_70, + batt_80, + batt_90, + batt_full + ] + duration: 2200ms + +.. tip:: + + You can use both battery examples above placed on top of each other, and switch their ``hidden`` flag based on if the charger is connected or not. + .. _lvgl-cook-clock: An analog clock From 988ae4b3c818c477b6d389a68e00913f860a81fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Apr 2024 16:26:18 +0200 Subject: [PATCH 276/350] some notes to tips --- components/lvgl.rst | 6 ++++-- cookbook/images/lvgl_cook_font_batt.png | Bin 250 -> 243 bytes cookbook/lvgl.rst | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 573db6f1a..4b28a0b7e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -668,7 +668,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row items: bg_color: 0xf0f0f0 -.. note:: +.. tip:: The Button Matrix widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. Check out :ref:`lvgl-cook-keypad` for an example. @@ -1257,6 +1257,8 @@ Currently ``RGB565`` type images are supported, with transparency using the opti repeat_count: 100 duration: 300ms +See :ref:`lvgl-cook-animbatt` in the Cookbook for a more detailed example. + .. _lvgl-wgt-lin: ``line`` @@ -1465,7 +1467,7 @@ The configured message boxes are hidden by default. One can show them with ``lvg then: - lvgl.widget.hide: message_box -.. note:: +.. tip:: You can create your own more complex dialogs with a full-screen sized, half-opaque ``obj`` with any child widgets on it, and the ``hidden`` flag set to ``true`` by default. For non-modal dialogs, simply set the ``clickable`` flag to ``false`` on it. diff --git a/cookbook/images/lvgl_cook_font_batt.png b/cookbook/images/lvgl_cook_font_batt.png index 58d8843bc4fc6ca1a15ed5bc77fa9beb84786e46..6803ee049bae1b86ed99f7393698c631da4950eb 100644 GIT binary patch delta 229 zcmV447cC{nP(?*W1_lO62}v~Z=P#Z!FfiP|e;=1d0^XODkUVxA z-LY1dRuFS>fuWP61|pq)`0`=xJLa{Rg7|e2j(uDJPwWq!Fda3NzJ^-aT9F~efIpp* f4TeXUjsQaexd}OAYzLbc00000NkvXXu0mjfJ4IOm delta 236 zcmVJF zK~zYIWBmXBKLd>c6Rj;6wSy$ULcG#*m(R_eJ{QhS&P+DaHKMW|_aEHfwtX9%>*VP~ zq#caJq}}Ma=wpYEVU@D7wOYDpDHZHcR8(YOV33rML=%7h;yD8Y!~OgB@oOhGtRy8Q zj~z$%ij}1m#2WlyxTM{|ls`UvLiw1w#d$EY1c&<-nGD>9_u mfT;XIAs94aHEIXl>;M4jkvU^8w1@8i0000L diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 5105f0a93..4f59ba7a5 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -764,7 +764,7 @@ In the example below we use the default set of glyphs from RobotoCondensed-Regul text_font: roboto_icons_42 -.. note:: +.. tip:: Follow these steps to choose your MDI icons: @@ -1003,7 +1003,7 @@ To have an animation illustrating a battery charging, you can use :ref:`lvgl-wgt .. tip:: - You can use both battery examples above placed on top of each other, and switch their ``hidden`` flag based on if the charger is connected or not. + You can use both battery examples above placed on top of each other, and switch their ``hidden`` flag depending if the charger is connected or not. Use ``x``, ``y``, ``align`` for precise widget positioning. .. _lvgl-cook-clock: From b3b988175c59bc49c934086767a3e8e755b7ecb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Apr 2024 16:49:00 +0200 Subject: [PATCH 277/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4b28a0b7e..985faaadb 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1224,8 +1224,8 @@ The animation image is similar to the normal ``img`` widget. The main difference - **src** (**Required**, list of :ref:`images `): A list of IDs of existing image configurations to be loaded as frames of the animation. - **auto_start** (*Optional*, boolean): Start the animation playback automatically at boot and when updating the widget. Defaults to ``true``. +- **duration** (**Required**, :ref:`Time `): Total duration of a playback cycle (frames are displayed equally in time). - **repeat_count** (*Optional*, int16 or *forever*): How many times to repeat the playback. Defaults to ``forever``. -- **duration** (**Required**, :ref:`Time `): Total duration of an animation cycle (frames are displayed equally in time). - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. From bbc711b079998786f3400618322b7c730b674ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 2 Apr 2024 17:27:16 +0200 Subject: [PATCH 278/350] show/hide example --- cookbook/lvgl.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 4f59ba7a5..751c29a09 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -985,7 +985,7 @@ To have an animation illustrating a battery charging, you can use :ref:`lvgl-wgt align: TOP_RIGHT y: 41 x: -10 - id: batt_charging + id: ani_battery_charging src: [ batt_empty, batt_10, @@ -1003,7 +1003,23 @@ To have an animation illustrating a battery charging, you can use :ref:`lvgl-wgt .. tip:: - You can use both battery examples above placed on top of each other, and switch their ``hidden`` flag depending if the charger is connected or not. Use ``x``, ``y``, ``align`` for precise widget positioning. + You can use both battery examples above placed on top of each other, and switch their ``hidden`` flag depending if the charger is connected or not: + + .. code-block:: yaml + + binary_sensor: + - platform: ... + id: charger_connected + on_press: + then: + - lvgl.widget.show: ani_battery_charging + - lvgl.widget.hide: lbl_battery_status + on_release: + then: + - lvgl.widget.show: lbl_battery_status + - lvgl.widget.hide: ani_battery_charging + + Use ``x``, ``y``, ``align`` widget properties for precise positioning. .. _lvgl-cook-clock: From 0060c5365ac4c90350f619b5ef8edc21124a391e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 13:44:04 +0200 Subject: [PATCH 279/350] add lvgl.bar.update --- components/lvgl.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 985faaadb..4b9e6f19b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -878,6 +878,10 @@ Not only the end, but also the start value of the bar can be set, which changes - **anim_time** (*Optional*, :ref:`Time `): Sets the animation time if the value is set with ``animated: true``. - Style options from :ref:`lvgl-styling`. The background of the bar and it uses the typical background style properties. Adding padding will make the indicator smaller or larger. +**Specific actions:** + +``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + **Example:** .. code-block:: yaml @@ -891,6 +895,12 @@ Not only the end, but also the start value of the bar can be set, which changes min_value: 1 max_value: 100 + # Example action: + on_...: + then: + - lvgl.bar.update: + id: bar_id + value: 55 The ``bar`` can be also integrated as :doc:`/components/number/lvgl`. From 167a35a298bfc57f2b37818d0ebf4b74f9048ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 14:36:44 +0200 Subject: [PATCH 280/350] spinbox --- components/lvgl.rst | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4b9e6f19b..b3db37497 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1066,12 +1066,12 @@ The Spinbox contains a number (as text) which can be increased or decreased with **Specific options:** -- **value** (*Optional*, float): Actual value to be shown by the spinbox at start. -- **range_from** (**Required**, float): The maximum value allowded to set the spinbox to. -- **range_to** (**Required**, float): The minimum value allowded to set the spinbox to. -- **step** (*Optional*, int8): ???? sets which digits to change on increment/decrement. Only multiples of ten can be set, and not for example 3. -- **digits** (*Optional*, int8): The number of digits excluding the decimal separator and the sign. -- **decimal_places** (*Optional*, int8): The number of digits after the decimal point. If ``0``, no decimal point is displayed. +- **value** (**Required**, float): Actual value to be shown by the spinbox at start. +- **range_from** (*Optional*, float): The maximum value allowded to set the spinbox to. Defaults to ``0``. +- **range_to** (*Optional*, float): The minimum value allowded to set the spinbox to. Defaults to ``100``. +- **step** (*Optional*, float): The granularity with which the value can be set. Defaults to ``1.0``. +- **digits** (*Optional*, 1..10): The number of digits (excluding the decimal separator and the sign characters). Defaults to ``4``. +- **decimal_places** (*Optional*, 0..6): The number of digits after the decimal point. If ``0``, no decimal point is displayed. Defaults to ``0``. - **rollover** (*Optional*, boolean): While increasing or decreasing the value, if either the minimum or maximum value is reached with this option enabled, the value will change to the other limit. If disabled, the value will remain at the minimum or maximum value. Defaults to ``false``. - **anim_time** (*Optional*, :ref:`Time `): Sets the cursor's blink time. @@ -1079,6 +1079,9 @@ The Spinbox contains a number (as text) which can be increased or decreased with ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. +``lvgl.spinbox.increment`` :ref:`action ` increases the value by one ``step`` configured above. + **Specific triggers:** ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the value in ``x``. @@ -1089,9 +1092,32 @@ The Spinbox contains a number (as text) which can be increased or decreased with # Example widget: - spinbox: - x: 10 - y: 10 + id: spinbox_id + text_align: center + range_from: -10 + range_to: 40 + step: 0.5 + digits: 3 + decimal_places: 1 + # Example actions: + on_...: + then: + - lvgl.spinbox.decrement: spinbox_id + on_...: + then: + - lvgl.spinbox.update: + id: spinbox_id + value: 25.5 + + # Example trigger: + - spinbox: + ... + on_value: + then: + - logger.log: + format: "Spinbox value is %f" + args: [ x ] The ``spinbox`` can be also integrated as :doc:`/components/number/lvgl`. From 0224e86d48ab2d17853f3fca64bcbb1193778802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 15:04:13 +0200 Subject: [PATCH 281/350] spinbox --- components/lvgl.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b3db37497..da5dd737e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1062,7 +1062,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use ``spinbox`` *********** -The Spinbox contains a number (as text) which can be increased or decreased with two buttons or physical keys. +The Spinbox contains a numeric value (as text) which can be increased or decreased through actions. You could use some plus or minus buttons to call them as required. **Specific options:** @@ -1075,6 +1075,10 @@ The Spinbox contains a number (as text) which can be increased or decreased with - **rollover** (*Optional*, boolean): While increasing or decreasing the value, if either the minimum or maximum value is reached with this option enabled, the value will change to the other limit. If disabled, the value will remain at the minimum or maximum value. Defaults to ``false``. - **anim_time** (*Optional*, :ref:`Time `): Sets the cursor's blink time. +.. note:: + + The sign characer will only be shown if ``range_from`` is negative. + **Specific actions:** ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. From 6a09dad0138bc809172b8af0fa5058686688b590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 15:58:13 +0200 Subject: [PATCH 282/350] spinbox climate cookbook --- components/images/lvgl_spinbox.png | Bin 0 -> 799 bytes components/lvgl.rst | 7 ++- cookbook/images/lvgl_cook_climate.png | Bin 0 -> 1672 bytes cookbook/lvgl.rst | 74 ++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 components/images/lvgl_spinbox.png create mode 100644 cookbook/images/lvgl_cook_climate.png diff --git a/components/images/lvgl_spinbox.png b/components/images/lvgl_spinbox.png new file mode 100644 index 0000000000000000000000000000000000000000..72ebee3c895c238ca3255c9073268124a7d6216a GIT binary patch literal 799 zcmV+)1K|9LP)U{R^st z5H}G;2Q6I#4J1KJ-#|m&8-zH#@p8FeCPyxpgM7&JT;99SJ$diBH_y8=7z~gQuEi}d z1xwdxNRsPnz%g+pOw%+?a}FMa5JCuDqXFMp@vH+vi0(xRb}f8fY~#J5RRi` zu5ykNCGsCV07@xQh$UlZaE*pV8Ja_Mp%2Aar>563_cNNNrMJ@M zo$}@7WpG@g>HVW0eaERZ-5GJ?_L+3P?jP(M$40SGOy5p-njQU6FBMBC?@#>V_OXPZ z-Vm=&=a^S}!j4`aX__V@esL>>-+uLLU;3Ip_6d>KDdwwtO(P?Iaf_4!{wGu-#|c@p z^g}&g$WItoDc#FpF9QJIe~agz@u?Z+qG4Qf4|6J0s|VFdPE^lUfHQog{q3W`xOAPo2cBQ0O}2q`yfQ9vM~D3-EOu4Y~0)ka~gj_ zuU*_eNm>si$u;uzYlwBKA4$sV(lr{KuI`RkEO=^+Ts>PIapBnna=G>v!?hRaYW3c|_TmGu-4m#b`8oD@{u1n#P zsU1>$o;;PfL*SYrGzG(TXs`q|iP6ZR6QhwsCq^TOPK-tlofwTAIx!kKreqiJ2<_~{ z_CD+#0)3N?2s{PV3$Q#3OS9luIGvRO(AP8!!!QifT44+bA%qYBG@qaZCwQkc^w#$$<}jL$4mo{J`?xkFn!!7-n!6w)^TSXK7-M9hp%_8(^_gX)=W&VY9_DsT z9n#u??x9d<=`cgVab25>1RcKC{Gl&P_~bKPxo}5Eql<42DHqhEhJW z@Pu&_v&~r`7nBl{F3NU|Cybkzy~9adTo*(sG3lag*LcFXiJ@^z?HW&* z^qt6};XF8f0_fdUV!||e^wSO+Idoz)aun#O)Oyg`_;thY`PjhM7q741TaPZz^4f>2 zFT$U%pZlx%RS^I9Sey2VhJWRt}`(cd`!fR)T8OMa@`|#(%O}u5JFa#SDcEo@n}P&JpxZ<^72PoZ0*6;-r%!af$kBU)pMn#O&Dfh z1)^94{ouyeH#&cGqDJSUV;bhE?Ia-XS8nsCX8p=??Gm(K!0r)X1hq>50PTMU)0zTO zlzB{hv+ehM0BC&M7&f{$U8n4v+Frj?#|E|xtFZ$BuzV5f3m5=89$k4tRUUP+hWqx3 zYL_)f-ud$nd;qX#>~y!A_)est9@TtiIkk@kx*nrR1)Ug;97UPOB&M*>!SK*yj7AQf z7>yj<#9&b9iDjk4q>Hj$;|b#?#xWG?iMSZq_v14{T!vCUv+#s*6LZB%HGWCRkUl+P?YVcf)2OV*r`PhqeV%o#zo zG`d{Fum&9=+1#`hW+*_UES@?(v&4ALO^j)pw;d&3A;0bTrfG_NGjX+_6k)3#iF{uj zpIKr&=btNKTrDAYrk9y2A>5f>wIo_Wh^_XM%Sb~Ak*#{9h|etXp2uB}u}gNXOy{y$sFjIblDN5OS=OL-OF#4vd_u?s#v4j0A;drMlNG_s-Dj4Oo{y-U===WOE5G&9 z?gm0*Y>LdALA~Nv%eHMx-;O?W)md}&nMK6&(X}>rU+#weu>H!~Iw+;Bkc&IhtCa~d z&|GCM@k-8C1?XISW)bv!bYkd#)Z6#Me(3e#7th}9XZs_VGlJWW?-+m#QAnqf1%}Wu!YfvIb(+`+0KhIKIT(EaWa=|Z zV$UV2%#+u|@A)S#k%e!@9rMxDJ9Z!g*(KXLpL4y;9LdOMmT^3nNK6E!GzbFH9~8$< zD>2AGmSLIZxJCUx7*h9{WgO3?6Qe0O`uP}*96B)?Idoz)a_Gcp Date: Wed, 17 Apr 2024 16:02:52 +0200 Subject: [PATCH 283/350] Update lvgl.rst --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 5ed984483..0a7732307 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -343,7 +343,7 @@ First we import from Home Assistant the current target temperature of the climat lvgl: ... pages: - - id: meter_page + - id: thermostat_control widgets: - obj: align: BOTTOM_MID From 471b53992be877559af72d7c36ed2c49cc9af4d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 17:15:05 +0200 Subject: [PATCH 284/350] cookboog gauge --- cookbook/images/lvgl_cook_gauge.png | Bin 0 -> 4105 bytes cookbook/lvgl.rst | 102 +++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 cookbook/images/lvgl_cook_gauge.png diff --git a/cookbook/images/lvgl_cook_gauge.png b/cookbook/images/lvgl_cook_gauge.png new file mode 100644 index 0000000000000000000000000000000000000000..9213799642d6e56d297368ab3dff2082d8586037 GIT binary patch literal 4105 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 Hu0mjfFgo5F literal 0 HcmV?d00001 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 0a7732307..b3c3c5c7d 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -237,12 +237,112 @@ The ``adv_hittest`` option ensures that accidental touches to the screen won't c Keep in mind that ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heatpump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. +.. _lvgl-cook-gauge: + +Semicircle gauge +---------------- + +A gauge similar to what Home Assistant shows in the Energy Dashboard can acomplished with :ref:`lvgl-wgt-mtr` widget and :ref:`lvgl-wgt-lbl`: + +.. figure:: images/lvgl_cook_gauge.png + :align: center + +The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widgets as children. We place a :ref:`lvgl-wgt-mtr` in the middle, which is made from an indicator ``line`` and two ``arc``s. We use another, smaller :ref:`lvgl-wgt-obj` on top of it, to hide the indicator central parts, and place some :ref:`lvgl-wgt-lbl` widgets to show numeric information: + +.. code-block:: yaml + + sensor: + - platform: ... + id: values_between_-10_and_10 + on_value: + - lvgl.indicator.line.update: + id: needle + value: !lambda return x; + - lvgl.label.update: + id: val_text + text: + format: "%.0f" + args: [ 'x' ] + lvgl: + ... + pages: + - id: gauge_page + widgets: + - obj: + height: 240 + width: 240 + align: CENTER + bg_opa: TRANSP + border_width: 0 + outline_width: 0 + shadow_width: 0 + pad_all: 4 + widgets: + - meter: # Gradient color arc + height: 100% + width: 100% + border_width: 0 + outline_width: 0 + align: center + scales: + angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right + range_to: 10 + range_from: -10 + ticks: + count: 0 + indicators: + - line: + id: needle + width: 8 + r_mod: 12 # sets line length by this much difference from the scale default radius + value: -2 + - arc: + color: 0xFF3000 + r_mod: 10 # radius difference from the scale default radius + width: 32 + start_value: -10 + end_value: 0 + - arc: + color: 0x00FF00 + r_mod: 10 # radius difference from the scale default radius + width: 32 + start_value: 0 + end_value: 10 + + - obj: # to erase middle part of meter indicator line + height: 146 + width: 146 + align: center + border_width: 0 + outline_width: 0 + shadow_width: 0 + pad_all: 0 + radius: 73 + - label: # lower range indicator + text_font: montserrat_18 + align: center + y: 8 + x: -90 + text: "-10" + - label: # higher range indicator + text_font: montserrat_18 + align: center + y: 8 + x: 90 + text: "+10" + - label: # gauge numeric indicator + id: val_text + text_font: montserrat_48 + align: center + y: -5 + text: "0" + .. _lvgl-cook-thermometer: Thermometer ----------- -A thermometer with a gauge acomplished with :ref:`lvgl-wgt-mtr` widget and a numeric display with :ref:`lvgl-wgt-lbl`: +A thermometer with a precise gauge also made from a :ref:`lvgl-wgt-mtr` widget and a numeric display using :ref:`lvgl-wgt-lbl`: .. figure:: images/lvgl_cook_thermometer.png :align: center From 78fbd155d11b6c4aea2de8979ed8d1c32e73010a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 17:16:22 +0200 Subject: [PATCH 285/350] ref to gauge example --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c7a60234b..8a64dd8ec 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1213,7 +1213,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee id: temperature_needle value: 3 -See :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clock` in the Cookbook for examples how to effectively use this widget. +See :ref:`lvgl-cook-gauge`, :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clock` in the Cookbook for examples how to effectively use this widget. .. _lvgl-wgt-img: From 2b62e4047be24ba5eefdfa522f6103e1ebee59d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 17:19:45 +0200 Subject: [PATCH 286/350] Update lvgl.rst --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index b3c3c5c7d..9abebd634 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -247,7 +247,7 @@ A gauge similar to what Home Assistant shows in the Energy Dashboard can acompli .. figure:: images/lvgl_cook_gauge.png :align: center -The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widgets as children. We place a :ref:`lvgl-wgt-mtr` in the middle, which is made from an indicator ``line`` and two ``arc``s. We use another, smaller :ref:`lvgl-wgt-obj` on top of it, to hide the indicator central parts, and place some :ref:`lvgl-wgt-lbl` widgets to show numeric information: +The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widgets as children. We place a :ref:`lvgl-wgt-mtr` in the middle, which is made from an indicator ``line`` and two ``arc`` widgets. We use another, smaller :ref:`lvgl-wgt-obj` on top of it, to hide the indicator central parts, and place some :ref:`lvgl-wgt-lbl` widgets to show numeric information: .. code-block:: yaml From 7b20acb95558852e05c7e88b3d2e5181d5c5bb23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 17:20:59 +0200 Subject: [PATCH 287/350] cosmetics --- cookbook/images/lvgl_cook_gauge.png | Bin 4105 -> 4154 bytes cookbook/lvgl.rst | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/images/lvgl_cook_gauge.png b/cookbook/images/lvgl_cook_gauge.png index 9213799642d6e56d297368ab3dff2082d8586037..11379cb9d92fb2804f266c5d22b6591b3c4844df 100644 GIT binary patch literal 4154 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 Hu0mjfFgo5F diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 9abebd634..18102c2ba 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -299,13 +299,13 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg - arc: color: 0xFF3000 r_mod: 10 # radius difference from the scale default radius - width: 32 + width: 31 start_value: -10 end_value: 0 - arc: color: 0x00FF00 r_mod: 10 # radius difference from the scale default radius - width: 32 + width: 31 start_value: 0 end_value: 10 From 9c574df9d2074251af22e627d5b556796b6d2e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 18:57:22 +0200 Subject: [PATCH 288/350] correction --- components/lvgl.rst | 4 ++-- cookbook/lvgl.rst | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 8a64dd8ec..e97dc59e1 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1070,8 +1070,8 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas **Specific options:** - **value** (**Required**, float): Actual value to be shown by the spinbox at start. -- **range_from** (*Optional*, float): The maximum value allowded to set the spinbox to. Defaults to ``0``. -- **range_to** (*Optional*, float): The minimum value allowded to set the spinbox to. Defaults to ``100``. +- **range_from** (*Optional*, float): The minimum value allowded to set the spinbox to. Defaults to ``0``. +- **range_to** (*Optional*, float): The maximum value allowded to set the spinbox to. Defaults to ``100``. - **step** (*Optional*, float): The granularity with which the value can be set. Defaults to ``1.0``. - **digits** (*Optional*, 1..10): The number of digits (excluding the decimal separator and the sign characters). Defaults to ``4``. - **decimal_places** (*Optional*, 0..6): The number of digits after the decimal point. If ``0``, no decimal point is displayed. Defaults to ``0``. diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 18102c2ba..faba64e5b 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -242,7 +242,7 @@ The ``adv_hittest`` option ensures that accidental touches to the screen won't c Semicircle gauge ---------------- -A gauge similar to what Home Assistant shows in the Energy Dashboard can acomplished with :ref:`lvgl-wgt-mtr` widget and :ref:`lvgl-wgt-lbl`: +A gauge similar to what Home Assistant shows in the Energy Dashboard can acomplished with :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets: .. figure:: images/lvgl_cook_gauge.png :align: center @@ -256,7 +256,7 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg id: values_between_-10_and_10 on_value: - lvgl.indicator.line.update: - id: needle + id: val_needle value: !lambda return x; - lvgl.label.update: id: val_text @@ -292,7 +292,7 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg count: 0 indicators: - line: - id: needle + id: val_needle width: 8 r_mod: 12 # sets line length by this much difference from the scale default radius value: -2 From 2c108e466434623d94c9882b8b9db27a804e0d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 19:30:31 +0200 Subject: [PATCH 289/350] radius tip --- cookbook/lvgl.rst | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index faba64e5b..9cda55abc 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -312,12 +312,18 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg - obj: # to erase middle part of meter indicator line height: 146 width: 146 + radius: 73 align: center border_width: 0 outline_width: 0 shadow_width: 0 pad_all: 0 - radius: 73 + - label: # gauge numeric indicator + id: val_text + text_font: montserrat_48 + align: center + y: -5 + text: "0" - label: # lower range indicator text_font: montserrat_18 align: center @@ -330,12 +336,10 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg y: 8 x: 90 text: "+10" - - label: # gauge numeric indicator - id: val_text - text_font: montserrat_48 - align: center - y: -5 - text: "0" + +.. tip:: + + The ``obj`` used to hide middle part of meter indicator line has ``radius`` equal to half of the ``width`` and ``height``. This results in a circle - which is actually a square with extralarge rounded corners. .. _lvgl-cook-thermometer: From 7be20af461209aac9d4078ea37cf963d8c6403e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Apr 2024 19:37:17 +0200 Subject: [PATCH 290/350] fixes --- components/lvgl.rst | 2 +- cookbook/lvgl.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index e97dc59e1..3db125a3b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1080,7 +1080,7 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas .. note:: - The sign characer will only be shown if ``range_from`` is negative. + The sign characer will only be shown if there are negatives in range. **Specific actions:** diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 9cda55abc..0e7965007 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -339,7 +339,7 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg .. tip:: - The ``obj`` used to hide middle part of meter indicator line has ``radius`` equal to half of the ``width`` and ``height``. This results in a circle - which is actually a square with extralarge rounded corners. + The ``obj`` used to hide the middle part of meter indicator line has ``radius`` equal to half of the ``width`` and ``height``. This results in a circle - which is actually a square with extralarge rounded corners. .. _lvgl-cook-thermometer: From 1a7dee1d030a929c759e72635f331c48e7aa6656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Apr 2024 09:53:37 +0200 Subject: [PATCH 291/350] updates --- components/lvgl.rst | 2 +- cookbook/lvgl.rst | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 3db125a3b..5410fcfb6 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1080,7 +1080,7 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas .. note:: - The sign characer will only be shown if there are negatives in range. + The sign character will only be shown if the set range contains negatives. **Specific actions:** diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 0e7965007..215ffda3f 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -11,11 +11,11 @@ Here are a couple recipes for various interesting things you can do with :ref:`l .. note:: - The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of ``240x320px``, you have to adjust them to your screen in order to obtain expected results. + Many examples below call services in Home Assistant, but by default these are not allowed out of the box. For an ESPHome device to call services, you must explicitly enable this setting in Home Assistant for each device, either during adoption of it, or using the `Configure` option in the devices list of the integration. .. note:: - Many examples below call services in Home Assistant, but by default these are not allowed out of the box. For an ESPHome device to call services, you must explicitly enable this setting in Home Assistant for each device, either during adoption of it, or using the `Configure` option in the devices list of the integration. + The examples below assume you've set up LVGL correctly with your display and its input device, and you have the knowledge to set up various components in ESPHome. Some examples use absolute positioning for a screen width of ``240x320px``, you have to adjust them to your screen in order to obtain expected results. .. _lvgl-cook-outbin: @@ -274,15 +274,12 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg align: CENTER bg_opa: TRANSP border_width: 0 - outline_width: 0 - shadow_width: 0 pad_all: 4 widgets: - - meter: # Gradient color arc + - meter: height: 100% width: 100% border_width: 0 - outline_width: 0 align: center scales: angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right @@ -296,27 +293,24 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg width: 8 r_mod: 12 # sets line length by this much difference from the scale default radius value: -2 - - arc: + - arc: # first half of the scale background color: 0xFF3000 r_mod: 10 # radius difference from the scale default radius width: 31 start_value: -10 end_value: 0 - - arc: + - arc: # second half of the scale background color: 0x00FF00 - r_mod: 10 # radius difference from the scale default radius + r_mod: 10 width: 31 start_value: 0 end_value: 10 - - obj: # to erase middle part of meter indicator line height: 146 width: 146 radius: 73 align: center border_width: 0 - outline_width: 0 - shadow_width: 0 pad_all: 0 - label: # gauge numeric indicator id: val_text From b1f75c0d56b7997ec5a6a2dd38a63ea81172316c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Apr 2024 12:01:19 +0200 Subject: [PATCH 292/350] update meter info --- components/lvgl.rst | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 5410fcfb6..ee4ea1d5f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1146,12 +1146,12 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **range_from** (**Required**): The minimum value of the tick scale. - **range_to** (**Required**): The maximum value of the tick scale. - **angle_range** (**Required**): The angle between start and end of the tick scale. - - **rotation** (**Required**): The rotation angle offset of the tick scale. - - **ticks** (**Required**, list): A scale has minor and major ticks and labels on the major ticks. To add the minor ticks: + - **rotation** (*Optional*): The rotation angle offset of the tick scale. + - **ticks** (**Required**, list): A scale can have minor and major ticks and labels on the major ticks. To add the minor ticks: - **count** (**Required**): How many ticks to be on the scale - - **width** (**Required**): Tick line width in pixels - - **length** (**Required**): Tick line length in pixels - - **color** (**Required**): ID or hex code for the ticks :ref:`color ` + - **width** (*Optional*): Tick line width in pixels. Required if ``count`` is greater than ``0`` + - **length** (*Optional*): Tick line length in pixels. Required if ``count`` is greater than ``0`` + - **color** (*Optional*): ID or hex code for the ticks :ref:`color `. Required if ``count`` is greater than ``0`` - **major** (*Optional*, list): If you want major ticks, value labels displayed too: - **stride**: How many minor ticks to skip when adding major ticks - **width**: Tick line width in pixels @@ -1160,12 +1160,31 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-wgt-lin` and :ref:`lvgl-wgt-lbl` text style properties. - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their ``value`` is interpreted in the range of the scale (see the *action* below): - - **line** (*Optional*): Add a needle line to a Scale. By default, the length of the line is the same as the scale's radius. + - **line** (*Optional*): Add a needle line to the meter (you can add multiple). By default, the length of the line is the same as the scale's radius. - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. + - **value**: The value in the scale range to show at start. Can be updated with ``lvgl.indicator.line.update`` :ref:`action ` (see below). + - **start_value**: The minimum value in the scale range the needle can show. + - **end_value**: The maximum value in the scale range the needle can show. - **width**: Needle line width in pixels. - - **color**: ID or hex code for the ticks :ref:`color `. - - **r_mod**: Adjust the length of the needle with this amount (can be negative). + - **color**: ID or hex code for the needle line :ref:`color `. + - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. + - **arc** (*Optional*): Add a background arc the scale (you can add multiple). + - **start_value**: The value in the scale range to start drawing the arc from. + - **end_value**: The value in the scale range to end drawing the arc to. + - **width**: Arc width in pixels. + - **color**: ID or hex code for the arc :ref:`color `. + - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). + - Style options for the *arc* using the :ref:`lvgl-wgt-arc` style properties. + - **ticks** (**Optional**): Add an indicator that modifies the ticks lines specified above. + - **start_value**: The value in the scale range to modify the ticks from. + - **end_value**: The value in the scale range to modify the ticks to. + - **color_start**: ID or hex code for the gradient start :ref:`color ` of the ticks. + - **color_end**: ID or hex code for the gradient end :ref:`color ` of the ticks. + - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the indicator's start and end value range. If ``false``, ``color_start`` and ``color_end`` will be mapped to the start and end value of the entire scale (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). + - **width_mod**: modifies the ``width`` of the tick lines. + + - Style options from :ref:`lvgl-styling` for the background of the meter, using the typical background properties. .. note:: From e02d8860e0ad5dc6f602722f49d407cfa9ad0b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Apr 2024 16:05:36 +0200 Subject: [PATCH 293/350] Update lvgl.rst --- components/lvgl.rst | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ee4ea1d5f..81bb8cee9 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1160,15 +1160,6 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-wgt-lin` and :ref:`lvgl-wgt-lbl` text style properties. - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their ``value`` is interpreted in the range of the scale (see the *action* below): - - **line** (*Optional*): Add a needle line to the meter (you can add multiple). By default, the length of the line is the same as the scale's radius. - - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - - **value**: The value in the scale range to show at start. Can be updated with ``lvgl.indicator.line.update`` :ref:`action ` (see below). - - **start_value**: The minimum value in the scale range the needle can show. - - **end_value**: The maximum value in the scale range the needle can show. - - **width**: Needle line width in pixels. - - **color**: ID or hex code for the needle line :ref:`color `. - - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). - - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - **arc** (*Optional*): Add a background arc the scale (you can add multiple). - **start_value**: The value in the scale range to start drawing the arc from. - **end_value**: The value in the scale range to end drawing the arc to. @@ -1181,10 +1172,21 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **end_value**: The value in the scale range to modify the ticks to. - **color_start**: ID or hex code for the gradient start :ref:`color ` of the ticks. - **color_end**: ID or hex code for the gradient end :ref:`color ` of the ticks. - - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the indicator's start and end value range. If ``false``, ``color_start`` and ``color_end`` will be mapped to the start and end value of the entire scale (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). - - **width_mod**: modifies the ``width`` of the tick lines. - - + - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the indicator's start and end value range. If ``false``, ``color_start`` and ``color_end`` will be mapped to the start and end value of the entire scale (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). Defaults to ``false``. + - **width_mod**: ??? modifies the ``width`` of the tick lines. + - **line** (*Optional*): Add a needle line to the meter (you can add multiple). By default, the length of the line is the same as the scale's radius. + - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. + - **width**: Needle line width in pixels. + - **color**: ID or hex code for the needle line :ref:`color `. + - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). + - **value**: The value in the scale range to show at start. Can be updated at runtime with ``lvgl.indicator.line.update`` :ref:`action ` (see below). + - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. + - **img** (*Optional*): Add a rotating needle image to the meter (you can add multiple). + - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. + - **src**: The ID of an existing image configuration, represennting a needle pointing to the right like ``-o--->``. + - **pivot_x**: Horizontal position of the pivot point of rotation relative to the top left corner of the image. Defaults to ``50%`` (center of image). + - **pivot_y**: Vertical position of the pivot point of rotation relative to the top left corner of the image.. Defaults to ``50%`` (center of image). + - **value**: The value in the scale range to show at start. Can be updated at runtime with ``lvgl.indicator.img.update`` :ref:`action ` (see below). - Style options from :ref:`lvgl-styling` for the background of the meter, using the typical background properties. .. note:: @@ -1194,6 +1196,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee **Specific actions:** ``lvgl.indicator.line.update`` :ref:`action ` updates the indicator needle ``value``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.indicator.img.update`` :ref:`action ` updates the indicator needle ``value``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** From 5642f4a47c3e17ff9f4d4d5769ce9871a8fb8e2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 18 Apr 2024 16:43:53 +0200 Subject: [PATCH 294/350] more meter docs --- components/lvgl.rst | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 81bb8cee9..6456c4311 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1143,29 +1143,29 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee **Specific options:** - **scales** (**Required**, list): A list with (any number of) scales to be added to meter. - - **range_from** (**Required**): The minimum value of the tick scale. - - **range_to** (**Required**): The maximum value of the tick scale. - - **angle_range** (**Required**): The angle between start and end of the tick scale. - - **rotation** (*Optional*): The rotation angle offset of the tick scale. + - **range_from** (**Required**): The minimum value of the tick scale. Defaults to ``0``. + - **range_to** (**Required**): The maximum value of the tick scale. Defaults to ``100``. + - **angle_range** (**Required**): The angle between start and end of the tick scale. Defaults to ``270``. + - **rotation** (*Optional*): The rotation angle offset of the tick scale. - **ticks** (**Required**, list): A scale can have minor and major ticks and labels on the major ticks. To add the minor ticks: - - **count** (**Required**): How many ticks to be on the scale - - **width** (*Optional*): Tick line width in pixels. Required if ``count`` is greater than ``0`` - - **length** (*Optional*): Tick line length in pixels. Required if ``count`` is greater than ``0`` - - **color** (*Optional*): ID or hex code for the ticks :ref:`color `. Required if ``count`` is greater than ``0`` - - **major** (*Optional*, list): If you want major ticks, value labels displayed too: - - **stride**: How many minor ticks to skip when adding major ticks - - **width**: Tick line width in pixels - - **length**: Tick line length in pixels - - **color**: ID or hex code for the ticks :ref:`color ` - - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. + - **count** (**Required**): How many ticks to be on the scale. Defaults to ``12``. + - **width** (*Optional*): Tick line width in pixels. Required if ``count`` is greater than ``0``. Defaults to ``2``. + - **length** (*Optional*): Tick line length in pixels. Required if ``count`` is greater than ``0``. Defaults to ``10``. + - **color** (*Optional*): ID or hex code for the ticks :ref:`color `. Required if ``count`` is greater than ``0``. Defaults to ``0x808080``. + - **major** (*Optional*, list): If you want major ticks and value labels displayed: + - **stride**: How many minor ticks to skip when adding major ticks. Defaults to ``3``. + - **width**: Tick line width in pixels. Defaults to ``5``. + - **length**: Tick line length in pixels or percentage. Defaults to ``15%``. + - **color**: ID or hex code for the ticks :ref:`color `. Defaults to ``0``. + - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. Defaults to ``4``. - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-wgt-lin` and :ref:`lvgl-wgt-lbl` text style properties. - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their ``value`` is interpreted in the range of the scale (see the *action* below): - **arc** (*Optional*): Add a background arc the scale (you can add multiple). - **start_value**: The value in the scale range to start drawing the arc from. - **end_value**: The value in the scale range to end drawing the arc to. - - **width**: Arc width in pixels. - - **color**: ID or hex code for the arc :ref:`color `. - - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). + - **width**: Arc width in pixels. Defaults to ``4``. + - **color**: ID or hex code for the arc :ref:`color `. Defaults to ``0``. + - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). Defaults to ``0``. - Style options for the *arc* using the :ref:`lvgl-wgt-arc` style properties. - **ticks** (**Optional**): Add an indicator that modifies the ticks lines specified above. - **start_value**: The value in the scale range to modify the ticks from. @@ -1176,9 +1176,9 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **width_mod**: ??? modifies the ``width`` of the tick lines. - **line** (*Optional*): Add a needle line to the meter (you can add multiple). By default, the length of the line is the same as the scale's radius. - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - - **width**: Needle line width in pixels. - - **color**: ID or hex code for the needle line :ref:`color `. - - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). + - **width**: Needle line width in pixels. Defaults to ``4``. + - **color**: ID or hex code for the needle line :ref:`color `. Defaults to ``0``. + - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). Defaults to ``0``. - **value**: The value in the scale range to show at start. Can be updated at runtime with ``lvgl.indicator.line.update`` :ref:`action ` (see below). - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - **img** (*Optional*): Add a rotating needle image to the meter (you can add multiple). From 17c9431a61af90e4c17495bcf041d8b978b0a071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Apr 2024 09:00:58 +0200 Subject: [PATCH 295/350] ticks -> tick_style --- components/lvgl.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 6456c4311..a57585095 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1167,21 +1167,21 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **color**: ID or hex code for the arc :ref:`color `. Defaults to ``0``. - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). Defaults to ``0``. - Style options for the *arc* using the :ref:`lvgl-wgt-arc` style properties. - - **ticks** (**Optional**): Add an indicator that modifies the ticks lines specified above. + - **tick_style** (**Optional**): Add an indicator that modifies tick styles (you can add multiple). - **start_value**: The value in the scale range to modify the ticks from. - **end_value**: The value in the scale range to modify the ticks to. - **color_start**: ID or hex code for the gradient start :ref:`color ` of the ticks. - **color_end**: ID or hex code for the gradient end :ref:`color ` of the ticks. - - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the indicator's start and end value range. If ``false``, ``color_start`` and ``color_end`` will be mapped to the start and end value of the entire scale (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). Defaults to ``false``. - - **width_mod**: ??? modifies the ``width`` of the tick lines. - - **line** (*Optional*): Add a needle line to the meter (you can add multiple). By default, the length of the line is the same as the scale's radius. + - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the start and end values specified here. If ``false``, ``color_start`` and ``color_end`` will be mapped to the start and end value of the entire scale (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). Defaults to ``false``. + - **width**: Modifies the ``width`` of the tick lines. + - **line** (*Optional*): Add a needle line to the scale (you can add multiple). By default, the length of the line is the same as the scale's radius. - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **width**: Needle line width in pixels. Defaults to ``4``. - **color**: ID or hex code for the needle line :ref:`color `. Defaults to ``0``. - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). Defaults to ``0``. - **value**: The value in the scale range to show at start. Can be updated at runtime with ``lvgl.indicator.line.update`` :ref:`action ` (see below). - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - - **img** (*Optional*): Add a rotating needle image to the meter (you can add multiple). + - **img** (*Optional*): Add a rotating needle image to the scale (you can add multiple). - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **src**: The ID of an existing image configuration, represennting a needle pointing to the right like ``-o--->``. - **pivot_x**: Horizontal position of the pivot point of rotation relative to the top left corner of the image. Defaults to ``50%`` (center of image). @@ -1195,8 +1195,8 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee **Specific actions:** -``lvgl.indicator.line.update`` :ref:`action ` updates the indicator needle ``value``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -``lvgl.indicator.img.update`` :ref:`action ` updates the indicator needle ``value``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.indicator.line.update`` :ref:`action ` updates the indicator line needle ``value``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.indicator.img.update`` :ref:`action ` updates the indicator image needle ``value``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** From 02b745e787df983b9e9911bfc6d74333adda90b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Apr 2024 09:52:58 +0200 Subject: [PATCH 296/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a57585095..1c3c15989 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1172,7 +1172,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **end_value**: The value in the scale range to modify the ticks to. - **color_start**: ID or hex code for the gradient start :ref:`color ` of the ticks. - **color_end**: ID or hex code for the gradient end :ref:`color ` of the ticks. - - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the start and end values specified here. If ``false``, ``color_start`` and ``color_end`` will be mapped to the start and end value of the entire scale (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). Defaults to ``false``. + - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the start and end values specified above. If ``false``, ``color_start`` and ``color_end`` will be mapped to the entire scale range (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). Defaults to ``false``. - **width**: Modifies the ``width`` of the tick lines. - **line** (*Optional*): Add a needle line to the scale (you can add multiple). By default, the length of the line is the same as the scale's radius. - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. From 0a3373f7adee06fae1e560c57faaed9a90d4a1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Apr 2024 15:06:30 +0200 Subject: [PATCH 297/350] lvgl.indicator.line.update -> lvgl.indicator.update --- components/lvgl.rst | 11 +++++------ cookbook/lvgl.rst | 8 ++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1c3c15989..2405d9a3d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1179,14 +1179,14 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **width**: Needle line width in pixels. Defaults to ``4``. - **color**: ID or hex code for the needle line :ref:`color `. Defaults to ``0``. - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). Defaults to ``0``. - - **value**: The value in the scale range to show at start. Can be updated at runtime with ``lvgl.indicator.line.update`` :ref:`action ` (see below). + - **value**: The value in the scale range to show at start. - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - **img** (*Optional*): Add a rotating needle image to the scale (you can add multiple). - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - - **src**: The ID of an existing image configuration, represennting a needle pointing to the right like ``-o--->``. + - **src**: The ID of an existing image configuration, represennting a needle pointing to the right like ``-o--->``. Cannot be updated at runtime with ``lvgl.indicator.update``. - **pivot_x**: Horizontal position of the pivot point of rotation relative to the top left corner of the image. Defaults to ``50%`` (center of image). - **pivot_y**: Vertical position of the pivot point of rotation relative to the top left corner of the image.. Defaults to ``50%`` (center of image). - - **value**: The value in the scale range to show at start. Can be updated at runtime with ``lvgl.indicator.img.update`` :ref:`action ` (see below). + - **value**: The value in the scale range to show at start. - Style options from :ref:`lvgl-styling` for the background of the meter, using the typical background properties. .. note:: @@ -1195,8 +1195,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee **Specific actions:** -``lvgl.indicator.line.update`` :ref:`action ` updates the indicator line needle ``value``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -``lvgl.indicator.img.update`` :ref:`action ` updates the indicator image needle ``value``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.indicator.update`` :ref:`action ` updates indicator options, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1231,7 +1230,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee # Example action: on_...: then: - - lvgl.indicator.line.update: + - lvgl.indicator.update: id: temperature_needle value: 3 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 215ffda3f..358383877 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -255,7 +255,7 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg - platform: ... id: values_between_-10_and_10 on_value: - - lvgl.indicator.line.update: + - lvgl.indicator.update: id: val_needle value: !lambda return x; - lvgl.label.update: @@ -353,7 +353,7 @@ Whenever a new value comes from the sensor, we update the needle indicator, and - platform: ... id: outdoor_temperature on_value: - - lvgl.indicator.line.update: + - lvgl.indicator.update: id: temperature_needle value: !lambda return x * 10; - lvgl.label.update: @@ -1293,11 +1293,11 @@ The script runs every minute to update the hand line positions and the texts. script: - id: time_update then: - - lvgl.indicator.line.update: + - lvgl.indicator.update: id: minute_hand value: !lambda |- return id(time_comp).now().minute; - - lvgl.indicator.line.update: + - lvgl.indicator.update: id: hour_hand value: !lambda |- auto now = id(time_comp).now(); From 9818b8184ed5cc7719dee8bd12c43c7a0dd2163e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Apr 2024 15:12:17 +0200 Subject: [PATCH 298/350] meter upd --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2405d9a3d..9d23f7d99 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1159,7 +1159,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **color**: ID or hex code for the ticks :ref:`color `. Defaults to ``0``. - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. Defaults to ``4``. - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-wgt-lin` and :ref:`lvgl-wgt-lbl` text style properties. - - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their ``value`` is interpreted in the range of the scale (see the *action* below): + - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their values are interpreted in the range of the scale: - **arc** (*Optional*): Add a background arc the scale (you can add multiple). - **start_value**: The value in the scale range to start drawing the arc from. - **end_value**: The value in the scale range to end drawing the arc to. @@ -1167,7 +1167,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **color**: ID or hex code for the arc :ref:`color `. Defaults to ``0``. - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). Defaults to ``0``. - Style options for the *arc* using the :ref:`lvgl-wgt-arc` style properties. - - **tick_style** (**Optional**): Add an indicator that modifies tick styles (you can add multiple). + - **tick_style** (**Optional**): Add tick style modifications (you can add multiple). - **start_value**: The value in the scale range to modify the ticks from. - **end_value**: The value in the scale range to modify the ticks to. - **color_start**: ID or hex code for the gradient start :ref:`color ` of the ticks. From afd0c0bc1f285166c9629fbacef7412019cb3ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Apr 2024 15:15:48 +0200 Subject: [PATCH 299/350] meter upd --- components/lvgl.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9d23f7d99..5c4b887c9 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1159,29 +1159,29 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **color**: ID or hex code for the ticks :ref:`color `. Defaults to ``0``. - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. Defaults to ``4``. - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-wgt-lin` and :ref:`lvgl-wgt-lbl` text style properties. - - **indicators** (**Required**, list): A list with indicators to be added to the scale. Their values are interpreted in the range of the scale: - - **arc** (*Optional*): Add a background arc the scale (you can add multiple). + - **indicators** (**Required**, list): A list with indicators to be added to the scale. Multiple of each can be added. Their values are interpreted in the range of the scale: + - **arc** (*Optional*): Add a background arc the scale: - **start_value**: The value in the scale range to start drawing the arc from. - **end_value**: The value in the scale range to end drawing the arc to. - **width**: Arc width in pixels. Defaults to ``4``. - **color**: ID or hex code for the arc :ref:`color `. Defaults to ``0``. - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). Defaults to ``0``. - Style options for the *arc* using the :ref:`lvgl-wgt-arc` style properties. - - **tick_style** (**Optional**): Add tick style modifications (you can add multiple). + - **tick_style** (**Optional**): Add tick style modifications: - **start_value**: The value in the scale range to modify the ticks from. - **end_value**: The value in the scale range to modify the ticks to. - **color_start**: ID or hex code for the gradient start :ref:`color ` of the ticks. - **color_end**: ID or hex code for the gradient end :ref:`color ` of the ticks. - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the start and end values specified above. If ``false``, ``color_start`` and ``color_end`` will be mapped to the entire scale range (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). Defaults to ``false``. - **width**: Modifies the ``width`` of the tick lines. - - **line** (*Optional*): Add a needle line to the scale (you can add multiple). By default, the length of the line is the same as the scale's radius. + - **line** (*Optional*): Add a needle line to the scale. By default, the length of the line is the same as the scale's radius: - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **width**: Needle line width in pixels. Defaults to ``4``. - **color**: ID or hex code for the needle line :ref:`color `. Defaults to ``0``. - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). Defaults to ``0``. - **value**: The value in the scale range to show at start. - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - - **img** (*Optional*): Add a rotating needle image to the scale (you can add multiple). + - **img** (*Optional*): Add a rotating needle image to the scale: - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **src**: The ID of an existing image configuration, represennting a needle pointing to the right like ``-o--->``. Cannot be updated at runtime with ``lvgl.indicator.update``. - **pivot_x**: Horizontal position of the pivot point of rotation relative to the top left corner of the image. Defaults to ``50%`` (center of image). From 2e2e48c08e7aab7e1e3c999ccc72e0dee8680447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 12:33:12 +0200 Subject: [PATCH 300/350] clean up meter example --- components/lvgl.rst | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 5c4b887c9..a4044e2bf 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1205,27 +1205,28 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - meter: align: center scales: - - ticks: - width: 1 - count: 81 - length: 5 - color: 0x000000 - major: - stride: 10 + range_from: -10 + range_to: 40 + angle_range: 240 + rotation: 150 + ticks: + count: 51 + length: 3 + major: + stride: 5 + length: 13 + label_gap: 13 + indicators: + - line: + id: temperature_needle width: 2 - length: 8 - color: 0xC0C0C0 - label_gap: 8 - range_from: -30 - range_to: 50 - angle_range: 240 - rotation: 150 - indicators: - - line: - id: temperature_needle - width: 2 - color: 0xFF0000 - r_mod: -4 + color: 0xFF0000 + r_mod: -4 + - tick_style: + start_value: -10 + end_value: 40 + color_start: 0x0000bd #FF0000 + color_end: 0xbd0000 #0000FF # Example action: on_...: From 7f9afcb17cd8e8b42a189956a7f0b716b2746507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 12:46:58 +0200 Subject: [PATCH 301/350] Update lvgl.rst --- components/lvgl.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index a4044e2bf..d2691266a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -58,6 +58,10 @@ Some widgets integrate in ESPHome also as components: These are useful to make :ref:`automations ` triggered by actions performed at the screen. +.. note:: + + LVGL only supports **integers** for numeric values. Visualizer widgets can't display floats directly, but they allow scaling by 10s. Some examples in the :doc:`Cookbook ` cover how to do that. + Main Component -------------- From 393934b32cd14272537a36b21a386b87f3edd2b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 12:49:20 +0200 Subject: [PATCH 302/350] Thermometer fix --- cookbook/lvgl.rst | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 358383877..5cf50b25e 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -381,17 +381,12 @@ Whenever a new value comes from the sensor, we update the needle indicator, and width: 2 color: 0xFF0000 r_mod: -4 - - ticks: - start_value: -10 - end_value: 40 - color_start: 0x0000bd - color_end: 0xbd0000 - range_from: -10 # scale for the value labels range_to: 40 angle_range: 240 rotation: 150 ticks: - width: 2 + width: 1 count: 51 length: 10 color: 0x000000 From c7971c2738e5eb9aabc4ff8a809dca1a48e8b92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 13:38:49 +0200 Subject: [PATCH 303/350] Thermometer fix2 --- cookbook/lvgl.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 5cf50b25e..f87725ce9 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -381,6 +381,12 @@ Whenever a new value comes from the sensor, we update the needle indicator, and width: 2 color: 0xFF0000 r_mod: -4 + - tick_style: + start_value: -10 + end_value: 40 + color_start: 0x0000bd + color_end: 0xbd0000 + width: 1 - range_from: -10 # scale for the value labels range_to: 40 angle_range: 240 @@ -392,10 +398,10 @@ Whenever a new value comes from the sensor, we update the needle indicator, and color: 0x000000 major: stride: 5 - width: 4 + width: 2 length: 10 color: 0x404040 - label_gap: 13 + label_gap: 10 widgets: - label: id: temperature_text From a567b76e73cde57afe03ae124d0857024630f642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 14:24:45 +0200 Subject: [PATCH 304/350] Clock explanation added --- cookbook/lvgl.rst | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index f87725ce9..4b5b962bc 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1204,6 +1204,8 @@ Using the :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets, we can create an .. figure:: images/lvgl_cook_clock.png :align: center +The :ref:`lvgl-wgt-mtr` has three scales: one for minutes ticks and hand, ranged between ``0`` and ``60``; one for the hour ticks and the labels as majors, ranged between ``1`` and ``12``; and a higher resolution scale for the hour hand, ranged between ``1`` and ``720``, to be able to position naturally the hour hand in between the hours. The second scale doesn't have an indicator, while the third scale doesn't have ticks nor labels. + The script runs every minute to update the hand line positions and the texts. .. code-block:: yaml @@ -1213,7 +1215,7 @@ The script runs every minute to update the hand line positions and the texts. pages: - id: clock_page widgets: - - obj: # Clock container + - obj: # clock container height: size_content width: 240 align: CENTER @@ -1221,22 +1223,22 @@ The script runs every minute to update the hand line positions and the texts. border_width: 0 bg_color: 0xFFFFFF widgets: - - meter: # Clock face + - meter: # clock face height: 220 width: 220 align: center bg_opa: TRANSP text_color: 0x000000 scales: - - ticks: # minutes scale + - range_from: 0 # minutes scale + range_to: 60 + angle_range: 360 + rotation: 270 + ticks: width: 1 count: 61 length: 10 color: 0x000000 - range_from: 0 - range_to: 60 - angle_range: 360 - rotation: 270 indicators: - line: id: minute_hand @@ -1244,31 +1246,33 @@ The script runs every minute to update the hand line positions and the texts. color: 0xa6a6a6 r_mod: -4 value: 0 - - ticks: # hours scale + - range_from: 1 # hours scale for labels + range_to: 12 + angle_range: 330 + rotation: 300 + ticks: width: 1 count: 12 length: 1 major: stride: 1 width: 4 - length: 8 + length: 10 color: 0xC0C0C0 label_gap: 12 - angle_range: 330 - rotation: 300 - range_from: 1 - range_to: 12 - - indicators: + - range_from: 0 # hi-res hours scale for hand + range_to: 720 + angle_range: 360 + rotation: 270 + ticks: + count: 0 + indicators: - line: id: hour_hand width: 5 color: 0xa6a6a6 r_mod: -30 value: 0 - angle_range: 360 - rotation: 270 - range_from: 0 - range_to: 720 - label: styles: date_style id: day_label @@ -1276,7 +1280,7 @@ The script runs every minute to update the hand line positions and the texts. - label: id: date_label styles: date_style - y: +30 + y: 30 time: - platform: homeassistant @@ -1315,8 +1319,7 @@ The script runs every minute to update the hand line positions and the texts. id: day_label text: !lambda |- static const char * const day_names[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}; - return day_names[id(time_comp).now().day_of_week-1]; - + return day_names[id(time_comp).now().day_of_week - 1]; .. _lvgl-cook-keypad: From 3092a532cb7c8cc6588239033429eed23d8414f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 14:36:40 +0200 Subject: [PATCH 305/350] Update lvgl_cook_clock.png --- cookbook/images/lvgl_cook_clock.png | Bin 11500 -> 8115 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cookbook/images/lvgl_cook_clock.png b/cookbook/images/lvgl_cook_clock.png index 631d41fe84037d761d8706b0c94e7f1a828ba596..85dd627b6392a220cd7b1cf7b75eb86ab1f48fbd 100644 GIT binary patch literal 8115 zcmX|`1yodBxP}Lj21zMtkdhD>kj@!8hmr(N`8fihgYe2fB6{K^R0cns<>5#nV zzjv*>*2FqzoxS(j^?vX7>}XAO1p-`ZTo4FEpri7efGEt_9lKKhg;|XEEeI}2%dXTcsV|16>>JnONr5=_eGeI5Kh+DQD zV)4${iUal+gCi#M&JI?gvuA3Q;8a}DASJnw+DcJOMGe)2!}eRM$e^kI zV}4dI><5<}*p8yTmC`YalC6VR_^IC+q*+kn_YQa3NYs~rf4Ld2lt{v1kxRt5;gDF( zrzKRx{)%)lg-#;6X3d80#^3r!pUuX@MU79_WkvK(s)M=fO(q>uYWVR%%{FX$K< zo((*I#e!14f;L9JNT`R^5Q044xh=A3XkA>`P2(=}cmXveSXcJ)f5Y$K^-a z5&I^5XcUFSZf$K_fmx=b_A=T~n&Nav{wj-q>(=x@(p+?;+@8P_V-5{-qh|rFMQ)r* z7Uaa02Cjky<%*t4|Yf4%k_KtctRgEwt@x1v1;N?1Mk^t zVsq)^!%l3B_Z&3Q8=IT;d;;FNGo>o0>efXM;ULyKDg3b_v7oW@2`v*hHqclYoNOw} zil2$F(&Ix_0fdP-KCCw{5-)aUW+qV{qC@cF#f!B2w9VOiJFTO>We8J&6*pdbdN#HK zWG{QjDj!o(`Q`oB+gsi%3Och}q@gfLnjcJ})>7`P+vi2m0hWw!6PPYNWB#XDy%H|x z=H%aw)QEe_k6`rpz34|f@A=<52mQUd*ne2L#fue=U%09YOp=nvttub1CC=SO18Jg% zy;(2KS-UqUK)@w_odr}Q6O>_#eqBEoybD~;@3jyu{_6gr-l3c`HB3J7SALy^(BD#R z%R%2dHKotx42g(9A0IPqldZ)Vz|v)hz|~Fia4NBbOkL-{PYhQaE&DFUIl1aim8Igd zXrsX+y!f0AuKUL4L1f}{;<7YM#Rn(Ug-9=K(8sq#$BSDkqDmC;o&LP%%7ReOuwX=j zL9I9%8YrD5oj}2-F{fajt4R35Ip5XZi@N^usqu$&tyKe7}!*}5iEw|{gA-xLEDowC1 ziL=zp8h9BgWv`-y1tP2Q{|K9&?HYB?q8^}+J57ky0j5vzS&F(b!gCSnMmr0A+`~9c z`ZVi?734M6`nLagO;r{AW(?XDb!;zrOXBi#to_tQA!6{%CA<4}XeslBQkz{Q2t+#| z>Pkc3Dg=A`#VN)vqI&2@u_lkh zil1tYh;i?aS_zC=jRw)yzx=X46x#781ELY{+G{3CVN2&}8SL1sZ@p@dwV58Qybehm(9WgTd+oSFy9&n4 zQbKwWE`j*kwV7qS&h217(-FheCnNPUpMafxfOk?(GM3NoaDI=dGm9I_7I^r1eg4^s zD0K}eN(NO35?PbnOtX(`>s%6_c>j->EZo`v&_V1_l(97E<6r%DHp%QnzCl1bp2VVY z2VPA)mx5{mds=9$D`3wW0aplt2j>o}lT6ddNbi1VyG{N3jdWz*s%kou;E}sqwM9K* z5b?gK`~1!HI)^{Mw$IDKZQO;cz>EsYWDGvaxL zXq2Nd>vJCF30ZR)R}gNV&+>>L1g@Z10{g`%dpOCipqI=@iOYbvFSiM{Q+6hSoo@|&C_x7mXSN(by%8@cu z+!8hI2kFAt^DV*x<>$WF>FdJpef`M&`0velY`-U^-N(r>3v$PuZMnTAsL3NyOyPr3 z&=rSwrkYDg)bvfLwE=K(^=io>__X2{K4#PKn6`4oD~S;CMNiGQZ(A>k5AntXU++5b z{kGuG*m54%Qc`BEiwz0IenNeFk={{IMV8s0PhdjD-@BFj+aKJ%-W*j~{y3INI&xE$KVpWjfi?xFvu1kMv&U39wKB~+hSAXH)q~(kwsW~m!xDE7B#3dnS%`XVrnSQ#9dr$*H;Vx(e*3vv?RPDg zN+9$^eBw-ez{AGp%r@`VdsoMqFdElD8XQ;{LPzwO=mBS<)F5{q4RlO5i=P1mZf-m4 zCB@AXxgAq7`PGhRx(w~hebO#J+W*XcdV6zX^N#uldPhmcO2?C+y>Ax09mRAo`R^H$ z1$3~a670w8$KSz!pI!%b+!#0Dj<#lcXEn?b%t}vs#}wtcXwB?6{h}tOuP5^=osn|QSF%MNP);-u z1+U2{-3jkaLJPf%*!;|yAz^AU&y`te@)w&7a5HD%*PH%efo0$}LRM4B;kxq=AgOqB zXn^A1$%wzPe(443&4MJq(^cQ)Ido;=YSQ>9-imjeD9_@}w~RU`1Lf<*?l+UPsuU0O z4}d^$sgj<&$TDYjH8rVwZ!w?tFR7@OPb~`xEh{gN(tP&$Z}_o8tIfLOX@B%fQPw#2 z8pRZ*>y}=PjX9}_O5|vwlfA{aN^qswHapiQ+!vd!yxdUhBdvP+kKXDoR`@Lz2sDc? zwvat8RCf3I{(Q9Y5M$v-JGyDjZwrc*=F&uduvK3b5R~s*?vhFdyIcaI z6)JlwoX3%%`|<-Py%z2ROQCD~*Vk^Z+bgN#*AIi2oFx+TBqU;M(fYi0%kZ1`sVYE39JV$ z|B^a$D#e-7UgVx_#UFCSFde0YzD&nDdBTX~(wBEuNhu*C*zEe28ex|i&jp=2&@L0W zUjeth2p_9GhBa6@8NSEd6$)+yZZ!HS(!bt{v$kP@XK`q% z;(G$iIpzAhl718UG}G%8^OyW^GY)u}o8^kt`?|wGEALMOnaS|m0OOe}y}b3?ctD;u z<2NdQ#TYFlG}#($sm-7PD<@)bI6w!tFz}4@mY@7uj^P!958*)oVz*WdMWlJGUb`Jf zcSd)1?b5$F!3F2VTgDk5n;2V6|H+lU-8c}~Q)Qrs>LFGjAABleNc;Sk>L!eLyDd&!eoO&c|*CiIjpW z^wPS;!{RugE$zr4a3ulF0F)jA=k+L6nFa@z+Lq=xjpNRHb{t+iSbifE)BusgYSj5J=6 zLPq6!`1euqi!0|j8=)5Ixv%oxKqd=znXgM^3y7$gww=eLIgMa)Gy}j~5HHi4MX#%U zUvh3~nmzDpfBrkC>1UP436>k;%WWc#d%#3N3o!vu8yB>mmd`5m*v6R9hGxJGQNm8e zBzGli6}91OYNr5{Ji}5)m{}?X8eF#ZJW@sM`c~O)d~F+fu8IWvCXmtpTgT-J)e4hE zVhy-;;QUsy+zmivsFxjjwHHnQsTET`Vbp&|SjPpJ*!N91+2Wy#CB{jd7>ub=ip6g` z=N<}Cood`MpI;?2L}i}$kwKwpOcRiprrC<@10;@-ww$yOwvwg3Rqjv?JyL@h75Z5E<$B`%&Ro_6Wk$RnES>ncOtP=O? z!P9P^!%rL2rHi_h3w?CMavb_rUAsl=ihLKdrPL&eW`tBGF*iZmu>qIhtdEBnS^LG6 zXB$X$aVgk0^`56FX$t~qVN#b$p!dV!GZd(a{yqJ_zNm3-Wi5S{M?tB72rG+RCD6yF zA<@g9>E`B=62ok)!;2v$kaFLUxChuE6RPo}*W$pdUbDG1;lP*A2TN z437rHFsPX-4E%7lUigGWnz(VBO`|0g)x9gH^(C<$3zTSsG|4fEsR`DF$;ryU`FpZ8 zC4=Ni*={W3fo;}tsVp-i9Yy`5MBkWMc?e(Oc;6B(?7xBmkv{-2^!jt6rH0HekAcCO zYqtP1aVSBSjm33_HT*UH_LeYGz@}l&7e!?jt?^*#);9pZR?PYkj_)x8W49(Ev&mal$X z_oR%7TzN6BLS-bO>`=b`c3|~*b@O3l<+}gP<>3MaZg|IbhkTcZggLV#UPyRI3l@MJ zjJm6iRU3M47YI89YU}Ef6j=Z({?6>z)b0nNnk*ToUEvwTnIGXloS|?04}EJ&`^pN7 zbjkHT$`Hy4ZL-bV9F0K_BZXPhTI)br{%t$$j6JwH>8*QrV4r(79xxUBy*88)MJfnH zWs#G@f}iP;)+M>ay67%vMZsbx=tKPN7qKpqBi|~l26LTc>c=tRsi+S$`J@Yi7YcfJ!ZyVa$Tp#;|O7Hj5r;g7HJY~G?9y-2fO zf8|#2k7%BlktWS%2gu&S*I9~q1sC^9}I{sB~igBVZgZTd=Ex!yEk@F!qG=hTFvc9G&_s?b{GF%}i;@lP)x8NNLc%{!H|BvAK%hPZLf4OA`Bcvn*svMp09TfX+FVe~w z)=CtlAK7EG7igh~X)_y>Wm2H<#t@tSgL1iJiL; zq{lom=-W~hWWn#(T3yBqfi7SAESvCqKiW%@nM@}#OIIJFWdi@84ItaF;m;`C-cRgd zOT8f)zIQ!ch7F&zF(fG(({?J;Fs&{f|Jn$<8|tIyO;zS#%4uq9Iym(&M?1|utFEfj z4W26;v@1F9-sCmC_xyrk4>4vli81C(Reni=^UtHvzqz@{NfR9`BuO402DsaNOl+6_ z=`Q=$6}P^XPSnsm-k|4H$xp1TSg!;u5akQ{kuI{CKkr?&sR9+7G&V0~ZipvWj~P%P zd*lyW#9y2f8yc7X@Cd#n#YS2u(p+}St3uhnwx3$MB6e9%p_?z;?iy8Gl7 zzaEpv3B_m|vEsK}w*-(G&}Z2ZgD*hkAZh2`hUR8W@EtItn2}f|T`NEW@VE>>wX19j zd&mv%RT&J9``6S|41)ZyQqtuj`8YNR`xQJwe<%FbjWz2-n-9`j^S|vD#{6e781(Vy zpP#NQ#$d+LDad9 zFiCD^t}HciIaB9)#B@Q31A4;U)Y$xC{-%9{LXJvvKWB zcp*H)6Rf&e}e$CTbFhT8(o=?y-iCe>hKYq>LJa#TqH@lzNtOWT1?Q<*tRwWTbvV9Gco0O}Ec)&M z4P?h`n31GY5W$2{Eclp@IXIYH8jL%Z!1Ws6h%jv_L}&R~AN_{o#XSwt<>#tZ7^Yyz zy0Am4vcSao`(KQOq0fqY#Q)heP&s@ID=l9Wn#_+#S7qHtdlg%Y(${bz$=!a{AkEnV zZ}p5kI=vQ@WfB6mgsvKLX2+GfU9TLlN6USS7Ouy8`~9Mh*w&D?4n|fcpQ75-SI~ zcf&u$WZ)?8C(5NWI*@3n5(~*M#x<{FuZypM6m0RRl9KD%*N!R@9NTnUy{nJ4IH@U20+1+x&c-Rq#vgQ{5 z3s|OizSssf0F*@6qQ8G2<^h}2h>VTloBQY(y4Dd0gxZ<^o9sQkk1JGR{EC|} zl<8q*MD6<&c0_ZPDEdrH9b@gQiuL>Eu;5f8eyZgbghsF`T>XE9YojwZMjM^LvwPm@eckR# zJaHk?(u^GpFUG-D$NUn~e`xx+`S37u&(9XdYymJ+n~NmbmfSK`R%REBQW%G>foTtfT`T%)jM} z)upv`mbBh7X2P4u#HCJmSc25jBS`zzLJ5iNAs^NzMy>b($_O{O+CwBou(GlhZ+VkM zhxPAHhl4d+J0n~nBQ88CLtMdK9hYoLb=&TaR4)CV$pH#=vk9EheU?Q>2@#K!JX|EO zsmaR5G`u;-Fzz?#_T&QJ`Z$*tOUlJ3vaU8(P%%aTmd}0M{kOX^6SR;c^*A>Xq_-~$ zieHcK{&1I9{fIpC&*SBalZuk^J$(u~zIY56dp+uGbu})v0+*>8t^MczxLG4$RwHHb zc+fEM(0uE1CE4x0O53ETuu*?wRyo%+s*x-1`*$LD;ew+5bi9sOXr+U9tn_`?P&Lox z+5rGB8_WY;Vtn>@Bf+VQ#xWq~+KZ1~R8SxXyj|Y2)T098W%lLgyLXT*$0q<5=%g5v zkZmLhCwM(lADKXt3z&oju2)U}$%SojfY;yBLE%uN?ZT^~RwYhOBO=oTO+pUQR*@9; zR4Ub3wu)votwTW;^oy5J0g=2SjJ`|BGZA;17TuS9K;~5l|?AZ&+2nl~`(GYU!I9^s3Hz)vwMg3px_;8#c;ttqr_R zi-!K{w>4FL<@7N-iSNjJw0wQUCwIIxo2YSiP&6+lf`@=d%qno@Ej#vGQ1Z~Ms0V>} zMGlDt-7i)(d18UGw$7tudScxihSQeX#o7ciufv$KsOmIh6}`S8t`u&0qOeSJ?oSNV za_&oHkihafq4I2)I}ka{xU=Jbyyo$^^jOV1mi?Ucx4bSvJ57i4d3+eOjIgYSe3pi{E_LZ8tQ;4&vD}DX@ zYEC|CYFCq;rKBU)#f0nkG#EH@33zGhvnW5i_R3AmSLEPXWKD>YOPRT6Qt zvg@7a8cUAxK;+seT5Q8INMzr#fR}&-6ZE>aPXFLa|1#0P>_E7L7fs%({@v;z@R2)s zsU)&Sg=4Qf{O%G@P71+a#%$c?f+G;~3 zlAY2TaM8&TK^mhAsYHLLYBI5hZuw1lxB<=1Gumbebdl8f=;l0|gHbD&ApvTn0-V3} z6G64eM`3>tH^5fjiHyVo#^xIo%&nvr7vpJD0G2OAV|lV60c&JN2ffDEmJwq?ezl?Y4E6=Spe~H+@370Lz6f8&4CD*~xKoGow1p}BhLWS!a=HmTEwayy_EgcMk zPpW2^pjpYGr4}tQ7Shlik;9)^!?`iCT8-O+L#b&C5NYXcK08d$pF$3i_&PoRcYY0| e5&v2I)8Hp@DI}=;0|nqP9;5_Shg8d&hyD*LUdE{a literal 11500 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 Date: Mon, 22 Apr 2024 14:37:02 +0200 Subject: [PATCH 306/350] Update lvgl.rst --- cookbook/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 4b5b962bc..89f9232a4 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1228,6 +1228,7 @@ The script runs every minute to update the hand line positions and the texts. width: 220 align: center bg_opa: TRANSP + border_width: 0 text_color: 0x000000 scales: - range_from: 0 # minutes scale From 3bbb5e4e081a4fa3545dfacdb85a6c239ee09bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 15:19:31 +0200 Subject: [PATCH 307/350] Clock description --- cookbook/lvgl.rst | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 89f9232a4..e70feef7a 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1204,9 +1204,9 @@ Using the :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets, we can create an .. figure:: images/lvgl_cook_clock.png :align: center -The :ref:`lvgl-wgt-mtr` has three scales: one for minutes ticks and hand, ranged between ``0`` and ``60``; one for the hour ticks and the labels as majors, ranged between ``1`` and ``12``; and a higher resolution scale for the hour hand, ranged between ``1`` and ``720``, to be able to position naturally the hour hand in between the hours. The second scale doesn't have an indicator, while the third scale doesn't have ticks nor labels. +The :ref:`lvgl-wgt-mtr` has three scales: one for minutes ticks and hand, ranged between ``0`` and ``60``; one for the hour ticks and the labels as majors, ranged between ``1`` and ``12``; and a higher resolution scale for the hour hand, ranged between ``0`` and ``720``, to be able to naturally position the hand in between the hours. The second scale doesn't have an indicator, while the third scale doesn't have ticks nor labels. -The script runs every minute to update the hand line positions and the texts. +The script runs at the beginning of every minute to update the hand line positions and the texts. .. code-block:: yaml @@ -1286,13 +1286,11 @@ The script runs every minute to update the hand line positions and the texts. time: - platform: homeassistant id: time_comp - - interval: - - interval: 1min - then: - if: - condition: - time.has_time: + on_time_sync: + - script.execute: time_update + on_time: + - minutes: '*' + seconds: 0 then: - script.execute: time_update From 4aa13ddd912daa7ed1ff8d705979fed6ff671639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 15:34:25 +0200 Subject: [PATCH 308/350] re-order gauge parameters --- cookbook/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index e70feef7a..7cdd24353 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -282,9 +282,9 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg border_width: 0 align: center scales: - angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right - range_to: 10 range_from: -10 + range_to: 10 + angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right ticks: count: 0 indicators: From 74a05cd0836ddbe1160304d50767ef34fbc3e836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 15:38:20 +0200 Subject: [PATCH 309/350] Update lvgl.rst --- cookbook/lvgl.rst | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 7cdd24353..d7aff2c8f 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -282,29 +282,29 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg border_width: 0 align: center scales: - range_from: -10 - range_to: 10 - angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right - ticks: - count: 0 - indicators: - - line: - id: val_needle - width: 8 - r_mod: 12 # sets line length by this much difference from the scale default radius - value: -2 - - arc: # first half of the scale background - color: 0xFF3000 - r_mod: 10 # radius difference from the scale default radius - width: 31 - start_value: -10 - end_value: 0 - - arc: # second half of the scale background - color: 0x00FF00 - r_mod: 10 - width: 31 - start_value: 0 - end_value: 10 + - range_from: -10 + range_to: 10 + angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right + ticks: + count: 0 + indicators: + - line: + id: val_needle + width: 8 + r_mod: 12 # sets line length by this much difference from the scale default radius + value: -2 + - arc: # first half of the scale background + color: 0xFF3000 + r_mod: 10 # radius difference from the scale default radius + width: 31 + start_value: -10 + end_value: 0 + - arc: # second half of the scale background + color: 0x00FF00 + r_mod: 10 + width: 31 + start_value: 0 + end_value: 10 - obj: # to erase middle part of meter indicator line height: 146 width: 146 From 83358d095d45e5d2f4b2bf1d90e2472f072d629f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 15:54:52 +0200 Subject: [PATCH 310/350] version bumps --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d2691266a..f80bf8016 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -9,7 +9,7 @@ LVGL Graphics `LVGL `__ (Light and Versatile Graphics Library) is a free and open-source -embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8.3.11 `__. +embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8 `__. .. figure:: /components/images/lvgl_main_screenshot.png @@ -1831,5 +1831,5 @@ See Also - :doc:`/components/display/index` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` -- `LVGL 8.3 docs `__ +- `LVGL docs `__ - :ghedit:`Edit` From eb8a6e9001437569f86d3268833c347456bc8fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 22 Apr 2024 16:28:50 +0200 Subject: [PATCH 311/350] Update lvgl.rst --- components/lvgl.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f80bf8016..de4e97111 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -24,10 +24,12 @@ Check out a few detailed examples :ref:`in the Cookbook ` to see a co Basics ------ -In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` to see the full list of available LVGL widgets in ESPHome. +In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` to see the full list of available LVGL widgets in ESPHome. Not all of them are implemented, just the most commonly used ones. Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. -The child widget moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within their parent's bounding area. In other words, the parts of the children outside the parent are clipped. +The child widget moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within their parent's bounding area. In other words, the areas of the children outside the parent are clipped. + +Some more complex widgets are internally made up from the simpler ones, these are known as parts - which can have separate properties from the main widget. Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent. There is always one active page on a display. From dd5650bf8369ae8034115ba51ec2a7bcd1428503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Apr 2024 12:48:49 +0200 Subject: [PATCH 312/350] Update index.rst --- index.rst | 532 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 308 insertions(+), 224 deletions(-) diff --git a/index.rst b/index.rst index ba0a4b456..99d26c100 100644 --- a/index.rst +++ b/index.rst @@ -121,41 +121,113 @@ ESPHome is a system to control your microcontrollers by simple yet powerful conf .. _devices: -Platforms ---------- +Supported Microcontrollers +-------------------------- .. imgtable:: - ESP8266, components/esp8266, esp8266.svg ESP32, components/esp32, esp32.svg + ESP8266, components/esp8266, esp8266.svg RP2040, components/rp2040, rp2040.svg BK72xx, components/libretiny, bk72xx.svg RTL87xx, components/libretiny, rtl87xx.svg -Core Components ---------------- +Microcontroller Peripherals +--------------------------- + +Peripherals which directly support the operation of the microcontroller's processor(s). + +.. imgtable:: + + PSRAM, components/psram, psram.svg + Deep Sleep, components/deep_sleep, hotel.svg, dark-invert + +ESPHome Components +------------------ + +ESPHome-specific components or components supporting ESPHome device provisioning post-installation. .. imgtable:: Core, components/esphome, cloud-circle.svg, dark-invert - PSRAM, components/psram, psram.svg - WiFi, components/wifi, network-wifi.svg, dark-invert - Network, components/network, network-wifi.svg, dark-invert - - I²C Bus, components/i2c, i2c.svg - SPI Bus, components/spi, spi.svg - UART Bus, components/uart, uart.svg - CAN Bus, components/canbus, canbus.svg - - MQTT, components/mqtt, mqtt.png - OTA Updates, components/ota, system-update.svg, dark-invert - Logger, components/logger, file-document-box.svg, dark-invert - Web Server, components/web_server, http.svg, dark-invert - - Native API, components/api, server-network.svg, dark-invert - Power Supply, components/power_supply, power.svg, dark-invert - Deep Sleep, components/deep_sleep, hotel.svg, dark-invert + Captive Portal, components/captive_portal, wifi-strength-alert-outline.svg, dark-invert + Copy, components/copy, content-copy.svg, dark-invert + Demo, components/demo, description.svg, dark-invert External Components, components/external_components, external_components.svg, dark-invert + Improv via BLE, components/esp32_improv, improv.svg, dark-invert + Improv via Serial, components/improv_serial, improv.svg, dark-invert + +Network Hardware +---------------- + +.. imgtable:: + + WiFi, components/wifi, network-wifi.svg, dark-invert + ESP32 Ethernet, components/ethernet, ethernet.svg, dark-invert + +Network Protocols +----------------- + +.. imgtable:: + + Network Core, components/network, server-network.svg, dark-invert + Native API, components/api, server-network.svg, dark-invert + MQTT, components/mqtt, mqtt.png + HTTP Request, components/http_request, connection.svg, dark-invert + mDNS, components/mdns, radio-tower.svg, dark-invert + WireGuard, components/wireguard, wireguard_custom_logo.svg + +Bluetooth/BLE +------------- + +.. imgtable:: + + ESP32 BLE Beacon, components/esp32_ble_beacon, bluetooth.svg, dark-invert + ESP32 BLE Client, components/ble_client, bluetooth.svg, dark-invert + ESP32 BLE Tracker, components/esp32_ble_tracker, bluetooth.svg, dark-invert + Bluetooth Proxy, components/bluetooth_proxy, bluetooth.svg, dark-invert + Improv via BLE, components/esp32_improv, improv.svg, dark-invert + +Management and Monitoring +------------------------- + +.. imgtable:: + + Debug, components/debug, bug-report.svg, dark-invert + Logger, components/logger, file-document-box.svg, dark-invert + OTA Updates, components/ota, system-update.svg, dark-invert + Prometheus, components/prometheus, prometheus.svg + Web Server, components/web_server, http.svg, dark-invert + ESP32 Camera Web Server, components/esp32_camera_web_server, camera.svg, dark-invert + +Hardware Peripheral Interfaces/Busses +------------------------------------- + +.. imgtable:: + + CAN Bus, components/canbus, canbus.svg + I²C Bus, components/i2c, i2c.svg + I²S Audio, components/i2s_audio, i2s_audio.svg + SPI Bus, components/spi, spi.svg + UART, components/uart, uart.svg + +I/O Expanders/Multiplexers +-------------------------- + +.. imgtable:: + + MAX6956 - I²C Bus, components/max6956, max6956.jpg + MCP230XX - I²C Bus, components/mcp230xx, mcp230xx.svg + MCP23SXX - SPI Bus, components/mcp23Sxx, mcp230xx.svg + PCA6416A, components/pca6416a, pca6416a.svg + PCA9554, components/pca9554, pca9554a.jpg + PCF8574, components/pcf8574, pcf8574.jpg + SN74HC165, components/sn74hc165, sn74hc595.jpg + SN74HC595, components/sn74hc595, sn74hc595.jpg + SX1509, components/sx1509, sx1509.jpg + TCA9548A I²C Multiplexer, components/tca9548a, tca9548a.jpg + WeiKai SPI/I²C UART/IO Expander, components/weikai, wk2168.jpg + XL9535, components/xl9535, xl9535.svg Sensor Components ----------------- @@ -164,19 +236,19 @@ Sensors are split into categories. If a sensor fits into more than one category, Core **** + .. imgtable:: Sensor Core, components/sensor/index, folder-open.svg, dark-invert + Template Sensor, components/sensor/template, description.svg, dark-invert Home Assistant, components/sensor/homeassistant, home-assistant.svg, dark-invert MQTT Subscribe, components/sensor/mqtt_subscribe, mqtt.png Uptime Sensor, components/sensor/uptime, timer.svg, dark-invert WiFi Signal Strength, components/sensor/wifi_signal, network-wifi.svg, dark-invert - Template Sensor, components/sensor/template, description.svg, dark-invert - Custom Sensor, components/sensor/custom, language-cpp.svg, dark-invert - Air Quality *********** + .. imgtable:: AGS10, components/sensor/ags10, ags10.jpg, Volatile Organic Compound Sensor @@ -186,18 +258,19 @@ Air Quality ENS160, components/sensor/ens160, ens160.jpg, CO2 & Air Quality GCJA5, components/sensor/gcja5, gcja5.svg, Particulate HM3301, components/sensor/hm3301, hm3301.jpg, Particulate + iAQ-Core, components/sensor/iaqcore, iaqcore.jpg, CO2 & Volatile organics MH-Z19, components/sensor/mhz19, mhz19.jpg, CO2 & Temperature MiCS-4514, components/sensor/mics_4514, mics_4514.jpg, Gas concentration PM1006 Sensor, components/sensor/pm1006, pm1006.jpg, Particulate PMSA003I, components/sensor/pmsa003i, pmsa003i.jpg, Particulate PMSX003, components/sensor/pmsx003, pmsx003.svg, Particulate RadonEye BLE, components/sensor/radon_eye_ble, radon_eye_logo.png, Radon + SCD30, components/sensor/scd30, scd30.jpg, CO2 & Temperature & Humidity + SCD4X, components/sensor/scd4x, scd4x.jpg, CO2 & Temperature & Humidity SDS011 Sensor, components/sensor/sds011, sds011.jpg, Particulate SEN0321, components/sensor/sen0321, sen0321.jpg, Ozone SEN5x, components/sensor/sen5x, sen54.jpg, Temperature & Humidity, Volatile organics and NOx SenseAir, components/sensor/senseair, senseair_s8.jpg, CO2 - SCD30, components/sensor/scd30, scd30.jpg, CO2 & Temperature & Humidity - SCD4X, components/sensor/scd4x, scd4x.jpg, CO2 & Temperature & Humidity SFA30, components/sensor/sfa30, sfa30.jpg, Formaldehyde SGP30, components/sensor/sgp30, sgp30.jpg, CO2 & Volatile organics SGP4x, components/sensor/sgp4x, sgp40.jpg, Volatile organics and NOx @@ -205,11 +278,10 @@ Air Quality SPS30, components/sensor/sps30, sps30.jpg, Particulate T6613/15, components/sensor/t6615, t6615.jpg, CO2 ZyAura, components/sensor/zyaura, zgm053.jpg, CO2 & Temperature & Humidity - iAQ-Core, components/sensor/iaqcore, iaqcore.jpg, CO2 & Volatile organics - Analogue ******** + .. imgtable:: ADC, components/sensor/adc, flash.svg, ESP internal, dark-invert @@ -221,25 +293,25 @@ Analogue MCP3204 / MCP3208, components/sensor/mcp3204, mcp3204.jpg, 4-channel ADC Resistance, components/sensor/resistance, omega.svg, dark-invert - Bluetooth Low Energy (BLE) ************************** + .. imgtable:: + Alpha3, components/sensor/alpha3, alpha3.jpg AM43, components/sensor/am43, am43.jpg, Lux & Battery level BLE Client Sensor, components/sensor/ble_client, bluetooth.svg, dark-invert BLE RSSI, components/sensor/ble_rssi, bluetooth.svg, dark-invert + HHCCJCY10 (MiFlora Pink), components/sensor/xiaomi_hhccjcy10, xiaomi_hhccjcy10.jpg, Soil moisture & Temperature & Light Inkbird IBS-TH1 Mini, components/sensor/inkbird_ibsth1_mini, inkbird_isbth1_mini.jpg, Temperature & Humidity Mopeka Pro Check LP, components/sensor/mopeka_pro_check, mopeka_pro_check.jpg, tank level Mopeka Standard Check LP, components/sensor/mopeka_std_check, mopeka_std_check.jpg, tank level RuuviTag, components/sensor/ruuvitag, ruuvitag.jpg, Temperature & Humidity & Accelerometer Xiaomi BLE, components/sensor/xiaomi_ble, xiaomi_mijia_logo.jpg, Various - HHCCJCY10 (MiFlora Pink), components/sensor/xiaomi_hhccjcy10, xiaomi_hhccjcy10.jpg, Soil moisture & Temperature & Light - Alpha3, components/sensor/alpha3, alpha3.jpg - Digital Signals *************** + .. imgtable:: Duty Cycle, components/sensor/duty_cycle, percent.svg, dark-invert @@ -247,22 +319,23 @@ Digital Signals Pulse Meter, components/sensor/pulse_meter, pulse.svg, dark-invert Pulse Width, components/sensor/pulse_width, pulse.svg, dark-invert - Distance ******** + .. imgtable:: A01NYUB, components/sensor/a01nyub, a01nyub.jpg, Acoustic distance A02YYUW, components/sensor/a02yyuw, a02yyuw.jpg, Acoustic distance HRXL MaxSonar WR, components/sensor/hrxl_maxsonar_wr, hrxl_maxsonar_wr.jpg, Acoustic distance + JSN-SR04T, components/sensor/jsn_sr04t, jsn-sr04t-v3.jpg, Acoustic distance TOF10120, components/sensor/tof10120, tof10120.jpg, IR optical distance Ultrasonic Sensor, components/sensor/ultrasonic, ultrasonic.jpg, Acoustic distance VL53L0x, components/sensor/vl53l0x, vl53l0x.jpg, IR optical distance Zio Ultrasonic Sensor, components/sensor/zio_ultrasonic, zio_ultrasonic.jpg, Acoustic distance - JSN-SR04T, components/sensor/jsn_sr04t, jsn-sr04t-v3.jpg, Acoustic distance Electricity *********** + .. imgtable:: ADE7880, components/sensor/ade7880, ade7880.svg, Voltage & Current & Power @@ -293,7 +366,6 @@ Electricity Teleinfo, components/sensor/teleinfo, teleinfo.jpg, Electrical counter Total Daily Energy, components/sensor/total_daily_energy, sigma.svg, dark-invert - Environmental ************* @@ -304,14 +376,14 @@ Environmental AirThings BLE, components/sensor/airthings_ble, airthings_logo.png, Temperature & Humidity & Pressure AM2315C, components/sensor/am2315c, am2315c.jpg, Temperature & Humidity AM2320, components/sensor/am2320, am2320.jpg, Temperature & Humidity + b-parasite, components/sensor/b_parasite, b_parasite.jpg, Moisture & Temperature & Humidity & Light BME280, components/sensor/bme280, bme280.jpg, Temperature & Humidity & Pressure - BME680, components/sensor/bme680, bme680.jpg, Temperature & Humidity & Pressure & Gas BME680 via BSEC, components/sensor/bme680_bsec, bme680.jpg, Temperature & Humidity & Pressure & Gas + BME680, components/sensor/bme680, bme680.jpg, Temperature & Humidity & Pressure & Gas BMP085, components/sensor/bmp085, bmp180.jpg, Temperature & Pressure BMP280, components/sensor/bmp280, bmp280.jpg, Temperature & Pressure BMP388 and BMP390, components/sensor/bmp3xx, bmp388.jpg, Temperature & Pressure BMP581, components/sensor/bmp581, bmp581.jpg, Temperature & Pressure - b-parasite, components/sensor/b_parasite, b_parasite.jpg, Moisture & Temperature & Humidity & Light Dallas DS18B20, components/sensor/dallas, dallas.jpg, Temperature DHT, components/sensor/dht, dht.jpg, Temperature & Humidity DHT12, components/sensor/dht12, dht12.jpg, Temperature & Humidity @@ -321,13 +393,14 @@ Environmental ENS210, components/sensor/ens210, ens210.jpg, Temperature & Humidity HDC1080, components/sensor/hdc1080, hdc1080.jpg, Temperature & Humidity HHCCJCY10 (MiFlora Pink), components/sensor/xiaomi_hhccjcy10, xiaomi_hhccjcy10.jpg, Soil moisture & Temperature & Light - HTE501, components/sensor/hte501, HTE501.png, Temperature & Humidity Honeywell ABP, components/sensor/honeywellabp, honeywellabp.jpg, Pressure & Temperature Honeywell ABP2 I2C, components/sensor/honeywellabp2_i2c, honeywellabp.jpg, Pressure & Temperature Honeywell HIH I2C, components/sensor/honeywell_hih_i2c, honeywellhih.jpg, Temperature & Humidity + HTE501, components/sensor/hte501, HTE501.png, Temperature & Humidity HTU21D / Si7021 / SHT21, components/sensor/htu21d, htu21d.jpg, Temperature & Humidity HTU31D, components/sensor/htu31d, htu31d.jpg, Temperature & Humidity Hydreon Rain Sensor, components/sensor/hydreon_rgxx, hydreon_rg9.jpg, Rain + HYT271, components/sensor/hyt271, hyt271.jpg, Temperature & Humidity Inkbird IBS-TH1 Mini, components/sensor/inkbird_ibsth1_mini, inkbird_isbth1_mini.jpg, Temperature & Humidity Internal Temperature, components/sensor/internal_temperature, thermometer.svg, Temperature, dark-invert MCP9808, components/sensor/mcp9808, mcp9808.jpg, Temperature @@ -352,14 +425,13 @@ Environmental STS3X, components/sensor/sts3x, sts3x.jpg, Temperature TEE501, components/sensor/tee501, TEE501.png, Temperature TMP102, components/sensor/tmp102, tmp102.jpg, Temperature - TMP117, components/sensor/tmp117, tmp117.jpg, Temperature TMP1075, components/sensor/tmp1075, tmp1075.jpg, Temperature - HYT271, components/sensor/hyt271, hyt271.jpg, Temperature & Humidity + TMP117, components/sensor/tmp117, tmp117.jpg, Temperature XGZP68xx Series, components/sensor/xgzp68xx, 6897d.jpg, Differential Pressure - Light ***** + .. imgtable:: AM43, components/sensor/am43, am43.jpg, Lux @@ -375,65 +447,65 @@ Light VEML6030, components/sensor/veml7700, veml6030.jpg, Lux VEML7700, components/sensor/veml7700, veml7700.jpg, Lux - Magnetic ******** + .. imgtable:: - ESP32 Hall Sensor, components/sensor/esp32_hall, magnet.svg, ESP internal, dark-invert AS5600, components/sensor/as5600, as5600.jpg, 12-Bit Magnetic Position Sensor + ESP32 Hall Sensor, components/sensor/esp32_hall, magnet.svg, ESP internal, dark-invert HMC5883L, components/sensor/hmc5883l, hmc5883l.jpg, 3-Axis magnetometer + MLX90393, components/sensor/mlx90393, mlx90393.jpg, 3-Axis magnetometer MMC5603, components/sensor/mmc5603, mmc5603.jpg, 3-Axis magnetometer MMC5983, components/sensor/mmc5983, mmc5983.jpg, 3-Axis magnetometer - MLX90393, components/sensor/mlx90393, mlx90393.jpg, 3-Axis magnetometer QMC5883L, components/sensor/qmc5883l, qmc5883l.jpg, 3-Axis magnetometer - Miscellaneous ************* + .. imgtable:: AS3935, components/sensor/as3935, as3935.jpg, Storm lightning - Binary Sensor Map, components/sensor/binary_sensor_map, binary_sensor_map.jpg, Map binary to value b-parasite, components/sensor/b_parasite, b_parasite.jpg, Moisture & Temperature & Humidity & Light + Binary Sensor Map, components/sensor/binary_sensor_map, binary_sensor_map.jpg, Map binary to value Combination, components/sensor/combination, function.svg, dark-invert Duty Time, components/sensor/duty_time, timer-play-outline.svg, dark-invert EZO sensor circuits, components/sensor/ezo, ezo-ph-circuit.png, (pH) FS3000, components/sensor/fs3000, fs3000.jpg, Air velocity + Growatt Solar, components/sensor/growatt_solar, growatt.jpg, Solar rooftop Havells Solar, components/sensor/havells_solar, havellsgti5000d_s.jpg, Solar rooftop Integration, components/sensor/integration, sigma.svg, dark-invert - Growatt Solar, components/sensor/growatt_solar, growatt.jpg, Solar rooftop + Kuntze pool sensor, components/sensor/kuntze, kuntze.jpg + MicroNova pellet stove, components/micronova, pellet.svg Modbus Sensor, components/sensor/modbus_controller, modbus.png Nextion, components/sensor/nextion, nextion.jpg, Sensors from display + Person Sensor (SEN21231), components/sensor/sen21231, sen21231.png + Resol VBus, components/vbus, resol_deltasol_bs_plus.jpg Rotary Encoder, components/sensor/rotary_encoder, rotary_encoder.jpg SMT100, components/sensor/smt100, smt100.jpg, Moisture & Temperature Tuya Sensor, components/sensor/tuya, tuya.png TX20, components/sensor/tx20, tx20.jpg, Wind speed & Wind direction uFire EC sensor, components/sensor/ufire_ec, ufire_ec.png, EC & Temperature uFire ISE sensor, components/sensor/ufire_ise, ufire_ise.png, pH & Temperature - Resol VBus, components/vbus, resol_deltasol_bs_plus.jpg - Person Sensor (SEN21231), components/sensor/sen21231, sen21231.png - Kuntze pool sensor, components/sensor/kuntze, kuntze.jpg WireGuard, components/wireguard, wireguard_custom_logo.svg - MicroNova pellet stove, components/micronova, pellet.svg - Motion ****** + .. imgtable:: APDS9960, components/sensor/apds9960, apds9960.jpg, Colour & Gesture BMI160, components/sensor/bmi160, bmi160.jpg, Accelerometer & Gyroscope LD2410, components/sensor/ld2410, ld2410.jpg, Motion & Presence LD2420, components/sensor/ld2420, ld2420.jpg, Motion & Presence - Seeed Studio MR24HPC1 mmWave, components/seeed_mr24hpc1, seeed-mr24hpc1.jpg, Motion & Presence MPU6050, components/sensor/mpu6050, mpu6050.jpg, Accelerometer & Gyroscope MPU6886, components/sensor/mpu6886, mpu6886.jpg, Accelerometer & Gyroscope RuuviTag, components/sensor/ruuvitag, ruuvitag.jpg, Temperature & Humidity & Accelerometer - + Seeed Studio MR24HPC1 mmWave, components/seeed_mr24hpc1, seeed-mr24hpc1.jpg, Motion & Presence Thermocouple ************ + .. imgtable:: KMeterISO, components/sensor/kmeteriso, kmeteriso.jpg, K-Type, @@ -443,9 +515,9 @@ Thermocouple MAX6675, components/sensor/max6675, max6675.jpg, K-Type, MCP9600, components/sensor/mcp9600, mcp9600.jpg, All types - Weight ****** + .. imgtable:: HX711, components/sensor/hx711, hx711.jpg, Load cell amplifier @@ -464,17 +536,18 @@ Binary Sensors are split into categories. If a sensor fits into more than one ca Core **** + .. imgtable:: Binary Sensor Core, components/binary_sensor/index, folder-open.svg, dark-invert - Custom Binary Sensor, components/binary_sensor/custom, language-cpp.svg, dark-invert + Template Binary Sensor, components/binary_sensor/template, description.svg, dark-invert GPIO, components/binary_sensor/gpio, pin.svg, dark-invert Home Assistant, components/binary_sensor/homeassistant, home-assistant.svg, dark-invert Status, components/binary_sensor/status, server-network.svg, dark-invert - Template Binary Sensor, components/binary_sensor/template, description.svg, dark-invert Capacitive Touch **************** + .. imgtable:: CAP1188 Capacitive Touch Sensor, components/binary_sensor/cap1188, cap1188.jpg @@ -484,14 +557,15 @@ Capacitive Touch Mechanical ********** + .. imgtable:: Matrix Keypad, components/matrix_keypad, matrix_keypad.jpg TM1637, components/display/tm1637, tm1637.jpg TM1638, components/display/tm1638, tm1638.jpg -NFC/RFID Components -******************* +NFC/RFID +******** Often known as "tag" or "card" readers within the community. @@ -503,30 +577,34 @@ Often known as "tag" or "card" readers within the community. PN716X, components/pn7160, pn716x.jpg RC522, components/binary_sensor/rc522, rc522.jpg RDM6300, components/binary_sensor/rdm6300, rdm6300.jpg + Wiegand Reader, components/wiegand, wiegand.jpg Touchscreen *********** + .. imgtable:: + Nextion Binary Sensor, components/binary_sensor/nextion, nextion.jpg LVGL widget, components/binary_sensor/lvgl, lvgl_c_bns.png - Nextion, components/binary_sensor/nextion, nextion.jpg Touchscreen, components/touchscreen/index, touch.svg, dark-invert TT21100, components/touchscreen/tt21100, esp32-s3-korvo-2-lcd.png FT5X06, components/touchscreen/ft5x06, indicator.jpg GT911, components/touchscreen/gt911, esp32_s3_box_3.png - + Presence Detection ****************** + .. imgtable:: - DFRobot mmWave Radar, components/dfrobot_sen0395, dfrobot_sen0395.jpg AT581X, components/at581x, at581x.png + DFRobot mmWave Radar, components/dfrobot_sen0395, dfrobot_sen0395.jpg LD2410, components/sensor/ld2410, ld2410.jpg LD2420, components/sensor/ld2420, ld2420.jpg Seeed Studio MR24HPC1 mmWave, components/seeed_mr24hpc1, seeed-mr24hpc1.jpg Miscellaneous ************* + .. imgtable:: Analog Threshold, components/binary_sensor/analog_threshold, analog_threshold.svg, dark-invert @@ -547,36 +625,35 @@ Output Components .. imgtable:: Output Core, components/output/index, folder-open.svg, dark-invert - ESP8266 Software PWM, components/output/esp8266_pwm, pwm.png - Slow PWM, components/output/slow_pwm, pwm.png - GPIO Output, components/output/gpio, pin.svg, dark-invert + Template Output, components/output/template, description.svg, dark-invert + AC Dimmer, components/output/ac_dimmer, ac_dimmer.svg, dark-invert + BLE Binary Output, components/output/ble_client, bluetooth.svg, dark-invert + BP1658CJ, components/output/bp1658cj, bp1658cj.svg + BP5758D, components/output/bp5758d, bp5758d.svg + DAC7678, components/output/dac7678, dac7678.svg + EMC2101, components/emc2101, emc2101.jpg ESP32 DAC, components/output/esp32_dac, dac.svg ESP32 LEDC, components/output/ledc, pwm.png + ESP8266 Software PWM, components/output/esp8266_pwm, pwm.png + GP8403, components/output/gp8403, gp8403.svg + GPIO Output, components/output/gpio, pin.svg, dark-invert LibreTiny PWM, components/output/libretiny_pwm, pwm.png - AC Dimmer, components/output/ac_dimmer, ac_dimmer.svg, dark-invert - PCA9685, components/output/pca9685, pca9685.jpg - TLC59208F, components/output/tlc59208f, tlc59208f.jpg - TLC5947, components/output/tlc5947, tlc5947.jpg - TLC5971, components/output/tlc5971, tlc5971.jpg + MCP4725, components/output/mcp4725, mcp4725.jpg + MCP4728, components/output/mcp4728, mcp4728.jpg + MCP47A1, components/output/mcp47a1, mcp47a1.svg + Modbus Output, components/output/modbus_controller, modbus.png MY9231/MY9291, components/output/my9231, my9231.svg + PCA9685, components/output/pca9685, pca9685.jpg + Sigma-Delta Output, components/output/sigma_delta_output, sigma-delta.svg, dark-invert + Slow PWM, components/output/slow_pwm, pwm.png SM16716, components/output/sm16716, sm16716.svg SM2135, components/output/sm2135, sm2135.svg SM2235, components/output/sm2235, sm2235.svg SM2335, components/output/sm2335, sm2335.svg - MCP4725, components/output/mcp4725, mcp4725.jpg - MCP4728, components/output/mcp4728, mcp4728.jpg - MCP47A1, components/output/mcp47a1, mcp47a1.svg - DAC7678, components/output/dac7678, dac7678.svg - BLE Binary Output, components/output/ble_client, bluetooth.svg, dark-invert - Modbus Output, components/output/modbus_controller, modbus.png - Custom Output, components/output/custom, language-cpp.svg, dark-invert - Sigma-Delta Output, components/output/sigma_delta_output, sigma-delta.svg, dark-invert - Template Output, components/output/template, description.svg, dark-invert - BP1658CJ, components/output/bp1658cj, bp1658cj.svg - BP5758D, components/output/bp5758d, bp5758d.svg + TLC59208F, components/output/tlc59208f, tlc59208f.jpg + TLC5947, components/output/tlc5947, tlc5947.jpg + TLC5971, components/output/tlc5971, tlc5971.jpg X9C Potentiometer, components/output/x9c, x9c.jpg - GP8403, components/output/gp8403, gp8403.svg - EMC2101, components/emc2101, emc2101.jpg Light Components ---------------- @@ -585,34 +662,30 @@ Light Components Light Core, components/light/index, folder-open.svg, dark-invert Binary Light, components/light/binary, lightbulb.svg, dark-invert - Status Led, components/light/status_led, led-on.svg, dark-invert - Monochromatic Light, components/light/monochromatic, brightness-medium.svg, dark-invert - Cold+Warm White Light, components/light/cwww, brightness-medium.svg, dark-invert Color Temperature Light, components/light/color_temperature, brightness-medium.svg, dark-invert + ESP32 RMT, components/light/esp32_rmt_led_strip, color_lens.svg, dark-invert + FastLED Light, components/light/fastled, color_lens.svg, dark-invert + H-bridge Light, components/light/hbridge, brightness-medium.svg, dark-invert + Light Partition, components/light/partition, color_lens.svg, dark-invert + LightWaveRF, components/lightwaverf, brightness-medium.svg + LVGL widget, components/light/lvgl, lvgl_c_lig.png + Monochromatic Light, components/light/monochromatic, brightness-medium.svg, dark-invert + NeoPixelBus Light, components/light/neopixelbus, color_lens.svg, dark-invert RGB Light, components/light/rgb, rgb.png + RGBCT Light, components/light/rgbct, rgbw.png RGBW Light, components/light/rgbw, rgbw.png RGBWW Light, components/light/rgbww, rgbw.png - RGBCT Light, components/light/rgbct, rgbw.png - - ESP32 RMT, components/light/esp32_rmt_led_strip, color_lens.svg, dark-invert RP2040 PIO, components/light/rp2040_pio_led_strip, color_lens.svg, dark-invert - FastLED Light, components/light/fastled, color_lens.svg, dark-invert - NeoPixelBus Light, components/light/neopixelbus, color_lens.svg, dark-invert - Light Partition, components/light/partition, color_lens.svg, dark-invert - SPI LED Strips, components/light/spi_led_strip, apa102.jpg - - Tuya Dimmer, components/light/tuya, tuya.png Shelly Dimmer, components/light/shelly_dimmer, shellydimmer2.jpg - Custom Light, components/light/custom, language-cpp.svg, dark-invert - LightWaveRF, components/lightwaverf, brightness-medium.svg - - H-bridge Light, components/light/hbridge, brightness-medium.svg, dark-invert Sonoff D1 Dimmer, components/light/sonoff_d1, sonoff_d1.jpg - LVGL widget, components/light/lvgl, lvgl_c_lig.png + SPI LED Strips, components/light/spi_led_strip, apa102.jpg + Status Led, components/light/status_led, led-on.svg, dark-invert + Tuya Dimmer, components/light/tuya, tuya.png -Looking for WS2811 and similar individually addressable lights? Have a look at the -:doc:`FastLED Light `. +**Looking for WS2811 and similar individually addressable lights?** For the ESP32 and its variants, we +recommend the :doc:`components/light/esp32_rmt_led_strip` or :doc:`components/light/spi_led_strip`; for +other processors, have a look at the :doc:`FastLED Light `. Switch Components ----------------- @@ -620,20 +693,19 @@ Switch Components .. imgtable:: Switch Core, components/switch/index, folder-open.svg, dark-invert + Template Switch, components/switch/template, description.svg, dark-invert + BLE Client Switch, components/switch/ble_client, bluetooth.svg, dark-invert + Factory Reset Switch, components/switch/factory_reset, restart-alert.svg, dark-invert + Generic Output Switch, components/switch/output, upload.svg, dark-invert GPIO Switch, components/switch/gpio, pin.svg, dark-invert + LVGL Widget, components/switch/lvgl, lvgl_c_swi.png + Modbus Switch, components/switch/modbus_controller, modbus.png + Nextion Switch, components/switch/nextion, nextion.jpg Restart Switch, components/switch/restart, restart.svg, dark-invert Safe Mode Switch, components/switch/safe_mode, restart-alert.svg, dark-invert Shutdown Switch, components/switch/shutdown, power_settings.svg, dark-invert - Factory Reset Switch, components/switch/factory_reset, restart-alert.svg, dark-invert - Generic Output Switch, components/switch/output, upload.svg, dark-invert - Template Switch, components/switch/template, description.svg, dark-invert - UART Switch, components/switch/uart, uart.svg - Custom Switch, components/switch/custom, language-cpp.svg, dark-invert Tuya Switch, components/switch/tuya, tuya.png - Modbus Switch, components/switch/modbus_controller, modbus.png - BLE Client Switch, components/switch/ble_client, bluetooth.svg, dark-invert - Nextion Switch, components/switch/nextion, nextion.jpg - LVGL Widget, components/switch/lvgl, lvgl_c_swi.png + UART Switch, components/switch/uart, uart.svg Button Components ----------------- @@ -642,14 +714,21 @@ Button Components Button Core, components/button/index, folder-open.svg, dark-invert Template Button, components/button/template, description.svg, dark-invert + Factory Reset Button, components/button/factory_reset, restart-alert.svg, dark-invert Generic Output Button, components/button/output, upload.svg, dark-invert Restart Button, components/button/restart, restart.svg, dark-invert Safe Mode Button, components/button/safe_mode, restart-alert.svg, dark-invert Shutdown Button, components/button/shutdown, power_settings.svg, dark-invert - Factory Reset Button, components/button/factory_reset, restart-alert.svg, dark-invert - Wake-on-LAN, components/button/wake_on_lan, power_settings.svg, dark-invert UART Button, components/button/uart, uart.svg + Wake-on-LAN, components/button/wake_on_lan, power_settings.svg, dark-invert +Event Components +----------------- + +.. imgtable:: + + Event Core, components/event/index, folder-open.svg, dark-invert + Template Event, components/event/template, description.svg, dark-invert Fan Components -------------- @@ -657,11 +736,11 @@ Fan Components .. imgtable:: Fan Core, components/fan/index, folder-open.svg, dark-invert + Template Fan, components/fan/template, description.svg, dark-invert Binary Fan, components/fan/binary, fan.svg, dark-invert H-bridge Fan, components/fan/hbridge, fan.svg, dark-invert Speed Fan, components/fan/speed, fan.svg, dark-invert Tuya Fan, components/fan/tuya, tuya.png - Template Fan, components/fan/template, description.svg, dark-invert Display Components ------------------ @@ -669,8 +748,18 @@ Display Components .. imgtable:: Display Core, components/display/index, folder-open.svg, dark-invert + Display Menu Core, components/display_menu/index, folder-open.svg, dark-invert Font Renderer, components/display/fonts, format-font.svg, dark-invert + Graphical Display Menu, components/display_menu/graphical_display_menu, graphical_display_menu.png + LCD Menu, components/display_menu/lcd_menu, lcd_menu.png LVGL Graphics, components/lvgl, lvgl.png + +Display Hardware Platforms +-------------------------- + +.. imgtable:: + +>>>>>>> next Addressable Light, components/display/addressable_light, addressable_light.jpg ILI9xxx, components/display/ili9xxx, ili9341.jpg ILI9341, components/display/ili9xxx, ili9341.svg @@ -681,12 +770,12 @@ Display Components WSPICOLCD, components/display/ili9xxx, ili9488.svg Inkplate, components/display/inkplate6, inkplate6.jpg LCD Display, components/display/lcd_display, lcd.jpg - MAX7219, components/display/max7219, max7219.jpg MAX7219 Dot Matrix, components/display/max7219digit, max7219digit.jpg + MAX7219, components/display/max7219, max7219.jpg Nextion, components/display/nextion, nextion.jpg PCD8544 (Nokia 5110/ 3310), components/display/pcd8544, pcd8544.jpg - Quad SPI AMOLED, components/display/qspi_amoled, t4-s3.jpg PVVX MiThermometer, components/display/pvvx_mithermometer, ../components/sensor/images/xiaomi_lywsd03mmc.jpg + Quad SPI AMOLED, components/display/qspi_amoled, t4-s3.jpg RPI_DPI_RGB, components/display/rpi_dpi_rgb, waveshare_touch-s3.jpg SSD1306, components/display/ssd1306, ssd1306.jpg SSD1322, components/display/ssd1322, ssd1322.jpg @@ -695,14 +784,15 @@ Display Components SSD1331, components/display/ssd1331, ssd1331.jpg SSD1351, components/display/ssd1351, ssd1351.jpg ST7567, components/display/st7567, st7567.jpg - ST7735, components/display/st7735, st7735.jpg ST7701S, components/display/st7701s, indicator.jpg + ST7735, components/display/st7735, st7735.jpg ST7789V, components/display/st7789v, st7789v.jpg ST7796, components/display/ili9xxx, st7796.svg ST7920, components/display/st7920, st7920.jpg TM1621, components/display/tm1621, tm1621.jpg TM1637, components/display/tm1637, tm1637.jpg TM1638, components/display/tm1638, tm1638.jpg + TM1651 Battery Display, components/tm1651, tm1651_battery_display.jpg Waveshare E-Paper, components/display/waveshare_epaper, waveshare_epaper.jpg Touchscreen Components @@ -711,14 +801,14 @@ Touchscreen Components .. imgtable:: Touchscreen Core, components/touchscreen/index, folder-open.svg, dark-invert + CST226, components/touchscreen/cst226, t4-s3.jpg CST816, components/touchscreen/cst816, cst816.jpg EKTF2232, components/touchscreen/ektf2232, ektf2232.svg, Inkplate 6 Plus + FT63X6, components/touchscreen/ft63x6, wt32-sc01.png + GT911, components/touchscreen/gt911, esp32_s3_box_3.png Lilygo T5 4.7", components/touchscreen/lilygo_t5_47, lilygo_t5_47_touch.jpg TT21100, components/touchscreen/tt21100, esp32-s3-korvo-2-lcd.png XPT2046, components/touchscreen/xpt2046, xpt2046.jpg - CST226, components/touchscreen/cst226, t4-s3.jpg - GT911, components/touchscreen/gt911, esp32_s3_box_3.png - FT63X6, components/touchscreen/ft63x6, wt32-sc01.png Cover Components ---------------- @@ -727,14 +817,21 @@ Cover Components Cover Core, components/cover/index, folder-open.svg, dark-invert Template Cover, components/cover/template, description.svg, dark-invert - Feedback Cover, components/cover/feedback, feedback_cover.svg, dark-invert - Endstop Cover, components/cover/endstop, electric-switch.svg, dark-invert - Current-Based Cover, components/cover/current_based, flash.svg, dark-invert - Time-Based Cover, components/cover/time_based, timer.svg, dark-invert - Custom Cover, components/cover/custom, language-cpp.svg, dark-invert AM43 Cover, components/cover/am43, am43.jpg - Tuya Cover, components/cover/tuya, tuya.png + Current-Based Cover, components/cover/current_based, flash.svg, dark-invert + Endstop Cover, components/cover/endstop, electric-switch.svg, dark-invert + Feedback Cover, components/cover/feedback, feedback_cover.svg, dark-invert HE60R Cover, components/cover/he60r, he60r.jpg + Time-Based Cover, components/cover/time_based, timer.svg, dark-invert + Tuya Cover, components/cover/tuya, tuya.png + +Text Components +--------------- + +.. imgtable:: + + Text Core, components/text/index, folder-open.svg, dark-invert + Template Text, components/text/template, description.svg, dark-invert Valve Components ---------------- @@ -750,20 +847,19 @@ Text Sensor Components .. imgtable:: Text Sensor Core, components/text_sensor/index, folder-open.svg, dark-invert - Home Assistant, components/text_sensor/homeassistant, home-assistant.svg, dark-invert - MQTT Subscribe Text, components/text_sensor/mqtt_subscribe, mqtt.png - Version, components/text_sensor/version, new-box.svg, dark-invert - WiFi Info, components/text_sensor/wifi_info, network-wifi.svg, dark-invert - Ethernet Info, components/text_sensor/ethernet_info, ethernet.svg, dark-invert - BLE Scanner, components/text_sensor/ble_scanner, bluetooth.svg, dark-invert - Modbus Text Sensor, components/text_sensor/modbus_controller, modbus.png Template Text Sensor, components/text_sensor/template, description.svg, dark-invert - Custom Text Sensor, components/text_sensor/custom, language-cpp.svg, dark-invert + BLE Scanner, components/text_sensor/ble_scanner, bluetooth.svg, dark-invert + Ethernet Info, components/text_sensor/ethernet_info, ethernet.svg, dark-invert + Home Assistant, components/text_sensor/homeassistant, home-assistant.svg, dark-invert + LibreTiny, components/text_sensor/libretiny, libretiny.svg + Modbus Text Sensor, components/text_sensor/modbus_controller, modbus.png + MQTT Subscribe Text, components/text_sensor/mqtt_subscribe, mqtt.png Nextion Text Sensor, components/text_sensor/nextion, nextion.jpg Tuya Text Sensor, components/text_sensor/tuya, tuya.png - WL-134 Pet Tag Sensor , components/text_sensor/wl_134, fingerprint.svg, dark-invert - LibreTiny, components/text_sensor/libretiny, libretiny.svg + Version, components/text_sensor/version, new-box.svg, dark-invert + WiFi Info, components/text_sensor/wifi_info, network-wifi.svg, dark-invert WireGuard, components/wireguard, wireguard_custom_logo.svg + WL-134 Pet Tag Sensor , components/text_sensor/wl_134, fingerprint.svg, dark-invert Climate Components ------------------ @@ -771,16 +867,15 @@ Climate Components .. imgtable:: Climate Core, components/climate/index, folder-open.svg, dark-invert - Bang Bang Controller, components/climate/bang_bang, air-conditioner.svg, dark-invert - Thermostat Controller, components/climate/thermostat, air-conditioner.svg, dark-invert - Custom Climate, components/climate/custom, language-cpp.svg, dark-invert - PID Controller, components/climate/pid, function.svg, dark-invert - IR Remote Climate, components/climate/climate_ir, air-conditioner-ir.svg, dark-invert - Tuya Climate, components/climate/tuya, tuya.png - Midea, components/climate/midea, midea.svg Anova Cooker, components/climate/anova, anova.png + Bang Bang Controller, components/climate/bang_bang, air-conditioner.svg, dark-invert BedJet Climate System, components/climate/bedjet, bedjet.png Haier Climate, components/climate/haier, haier.svg + IR Remote Climate, components/climate/climate_ir, air-conditioner-ir.svg, dark-invert + Midea, components/climate/midea, midea.svg + PID Controller, components/climate/pid, function.svg, dark-invert + Thermostat Controller, components/climate/thermostat, air-conditioner.svg, dark-invert + Tuya Climate, components/climate/tuya, tuya.png Uponor Smatrix Base Pulse Underfloor Heating, components/uponor_smatrix, uponor.svg Number Components @@ -789,9 +884,9 @@ Number Components .. imgtable:: Number Core, components/number/index, folder-open.svg, dark-invert + Template Number, components/number/template, description.svg, dark-invert LVGL widget Number, components/number/lvgl, lvgl_c_num.png Modbus Number, components/number/modbus_controller, modbus.png - Template Number, components/number/template, description.svg, dark-invert Tuya Number, components/number/tuya, tuya.png Select Components @@ -811,16 +906,8 @@ Lock Components .. imgtable:: Lock Core, components/lock/index, folder-open.svg, dark-invert - Generic Output Lock, components/lock/output, upload.svg, dark-invert Template Lock, components/lock/template, description.svg, dark-invert - -Text Components ---------------- - -.. imgtable:: - - Text Core, components/text/index, folder-open.svg, dark-invert - Template Text, components/text/template, description.svg, dark-invert + Generic Output Lock, components/lock/output, upload.svg, dark-invert Media Player Components ----------------------- @@ -828,6 +915,7 @@ Media Player Components .. imgtable:: Media Player Core, components/media_player/index, folder-open.svg, dark-invert + DFPlayer, components/dfplayer, dfplayer.svg, dark-invert I2S Audio, components/media_player/i2s_audio, i2s_audio.svg Microphone Components @@ -852,24 +940,26 @@ Time Components .. imgtable:: Time Core, components/time/index, clock-outline.svg, dark-invert - Home Assistant Time, components/time/homeassistant, home-assistant.svg, dark-invert - SNTP, components/time/sntp, clock-outline.svg, dark-invert - GPS Time, components/time/gps, crosshairs-gps.svg, dark-invert DS1307 RTC, components/time/ds1307, clock-outline.svg, dark-invert - PCF8563 RTC, components/time/pcf8563, clock-outline.svg, dark-invert + GPS Time, components/time/gps, crosshairs-gps.svg, dark-invert + Home Assistant Time, components/time/homeassistant, home-assistant.svg, dark-invert PCF85063 RTC, components/time/pcf85063, clock-outline.svg, dark-invert + PCF8563 RTC, components/time/pcf8563, clock-outline.svg, dark-invert + SNTP, components/time/sntp, clock-outline.svg, dark-invert -Home Assistant Companion Components ------------------------------------ +Home Assistant Components +------------------------- + +Components specifically for interacting with Home Assistant. .. imgtable:: + Binary Sensor, components/binary_sensor/homeassistant, home-assistant.svg, dark-invert Bluetooth Proxy, components/bluetooth_proxy, bluetooth.svg, dark-invert - Voice Assistant, components/voice_assistant, voice-assistant.svg, dark-invert micro Wake Word, components/micro_wake_word, voice-assistant.svg, dark-invert Sensor, components/sensor/homeassistant, home-assistant.svg, dark-invert Text Sensor, components/text_sensor/homeassistant, home-assistant.svg, dark-invert - Binary Sensor, components/binary_sensor/homeassistant, home-assistant.svg, dark-invert + Voice Assistant, components/voice_assistant, voice-assistant.svg, dark-invert Alarm Control Panel Components @@ -888,81 +978,75 @@ Datetime Components Datetime Core, components/datetime/index, clock-outline.svg, dark-invert Template Datetime, components/datetime/template, description.svg, dark-invert +Energy/Solar Management +----------------------- + +.. imgtable:: + + PipSolar-compatible PV Inverter, components/pipsolar, pipsolar.jpg + Power Supply, components/power_supply, power.svg, dark-invert + Resol VBus, components/vbus, resol_deltasol_bs_plus.jpg + SML, components/sml, sml.svg + SUN-GTIL2 inverter, components/sun_gtil2, sun_1000g2.png + +Electromechanical +----------------- + +.. imgtable:: + + Atlas Scientific Peristaltic Pump, components/ezo_pmp, ezo-pmp.jpg + Grove TB6612FNG, components/grove_tb6612fng, motor.png + Matrix Keypad, components/matrix_keypad, matrix_keypad.jpg + RTTTL Buzzer, components/rtttl, buzzer.jpg + Servo, components/servo, servo.svg + Stepper, components/stepper/index, stepper.svg + +Wireless Communication +---------------------- + +Wireless communication that is **not Wi-Fi.** + +.. imgtable:: + + IR Remote Climate, components/climate/climate_ir, air-conditioner-ir.svg, dark-invert + Remote Receiver, components/remote_receiver, remote.svg, dark-invert + Remote Transmitter, components/remote_transmitter, remote.svg, dark-invert + RF Bridge, components/rf_bridge, rf_bridge.jpg + SIM800L, components/sim800l, sim800l.jpg + Miscellaneous Components ------------------------ .. imgtable:: - Remote Receiver, components/remote_receiver, remote.svg, dark-invert - Remote Transmitter, components/remote_transmitter, remote.svg, dark-invert - Status LED, components/status_led, led-on.svg, dark-invert - Display Menu Core, components/display_menu/index, folder-open.svg, dark-invert - LCD Menu, components/display_menu/lcd_menu, lcd_menu.png - Graphical Display Menu, components/display_menu/graphical_display_menu, graphical_display_menu.jpg - Matrix Keypad, components/matrix_keypad, matrix_keypad.jpg - Wiegand Reader, components/wiegand, wiegand.jpg - HTTP Request, components/http_request, connection.svg, dark-invert - mDNS, components/mdns, radio-tower.svg, dark-invert - - Sun, components/sun, weather-sunny.svg, dark-invert - GPS, components/gps, crosshairs-gps.svg, dark-invert - - Bluetooth Proxy, components/bluetooth_proxy, bluetooth.svg, dark-invert - ESP32 BLE Client, components/ble_client, bluetooth.svg, dark-invert - ESP32 BLE Tracker, components/esp32_ble_tracker, bluetooth.svg, dark-invert - ESP32 BLE Beacon, components/esp32_ble_beacon, bluetooth.svg, dark-invert - - ESP32 Ethernet, components/ethernet, ethernet.svg, dark-invert ESP32 Camera, components/esp32_camera, camera.svg, dark-invert - ESP32 Camera Web Server, components/esp32_camera_web_server, camera.svg, dark-invert - - I²S Audio, components/i2s_audio, i2s_audio.svg - - Stepper, components/stepper/index, stepper.svg - Servo, components/servo, servo.svg - Sprinkler, components/sprinkler, sprinkler-variant.svg, dark-invert - Grove TB6612FNG, components/grove_tb6612fng, motor.png - - PCA6416A I/O Expander, components/pca6416a, pca6416a.svg - PCA9554 I/O Expander, components/pca9554, pca9554a.jpg - PCF8574 I/O Expander, components/pcf8574, pcf8574.jpg - MAX6956 I/O expander - I²C Bus, components/max6956, max6956.jpg - MCP230XX I/O Expander - I²C Bus, components/mcp230xx, mcp230xx.svg - TCA9548A I²C Multiplexer, components/tca9548a, tca9548a.jpg - MCP23SXX I/O Expander - SPI Bus, components/mcp23Sxx, mcp230xx.svg - SX1509 I/O Expander, components/sx1509, sx1509.jpg - SN74HC165 I/O Expander, components/sn74hc165, sn74hc595.jpg - SN74HC595 I/O Expander, components/sn74hc595, sn74hc595.jpg - XL9535 I/O Expander, components/xl9535, xl9535.svg - SIM800L, components/sim800l, sim800l.jpg - DFPlayer, components/dfplayer, dfplayer.svg, dark-invert - Captive Portal, components/captive_portal, wifi-strength-alert-outline.svg, dark-invert - Improv via BLE, components/esp32_improv, improv.svg, dark-invert - Improv via Serial, components/improv_serial, improv.svg, dark-invert - Debug Component, components/debug, bug-report.svg, dark-invert - TM1651 Battery Display, components/tm1651, tm1651_battery_display.jpg - RF Bridge, components/rf_bridge, rf_bridge.jpg - Tuya MCU, components/tuya, tuya.png - Modbus Controller, components/modbus_controller, modbus.png Exposure Notifications, components/exposure_notifications, exposure_notifications.png - RTTTL Buzzer, components/rtttl, buzzer.jpg - Prometheus, components/prometheus, prometheus.svg - PipSolar - compatible PV Inverter, components/pipsolar, pipsolar.jpg + GPS, components/gps, crosshairs-gps.svg, dark-invert Grow Fingerprint Reader, components/fingerprint_grow, fingerprint.svg, dark-invert - SML, components/sml, sml.svg - SUN-GTIL2 inverter, components/sun_gtil2, sun_1000g2.png - Atlas Scientific Peristaltic Pump, components/ezo_pmp, ezo-pmp.jpg - Resol VBus, components/vbus, resol_deltasol_bs_plus.jpg - WireGuard, components/wireguard, wireguard_custom_logo.svg - Demo, components/demo, description.svg, dark-invert - Copy, components/copy, content-copy.svg, dark-invert + Modbus Controller, components/modbus_controller, modbus.png + Sprinkler, components/sprinkler, sprinkler-variant.svg, dark-invert + Status LED, components/status_led, led-on.svg, dark-invert + Sun, components/sun, weather-sunny.svg, dark-invert + Tuya MCU, components/tuya, tuya.png -Additional Custom Components ----------------------------- +Custom Components +----------------- + +**Note: Custom Components are deprecated in favor of** :doc:`components/external_components`! .. imgtable:: Generic Custom Component, custom/custom_component, language-cpp.svg, dark-invert + + Custom Binary Sensor, components/binary_sensor/custom, language-cpp.svg, dark-invert + Custom Climate, components/climate/custom, language-cpp.svg, dark-invert + Custom Cover, components/cover/custom, language-cpp.svg, dark-invert + Custom Light, components/light/custom, language-cpp.svg, dark-invert + Custom Output, components/output/custom, language-cpp.svg, dark-invert + Custom Sensor, components/sensor/custom, language-cpp.svg, dark-invert + Custom Switch, components/switch/custom, language-cpp.svg, dark-invert + Custom Text Sensor, components/text_sensor/custom, language-cpp.svg, dark-invert + Custom I²C Component, custom/i2c, language-cpp.svg, dark-invert Custom SPI Component, custom/spi, language-cpp.svg, dark-invert Custom UART Component, custom/uart, language-cpp.svg, dark-invert From 9d5864a25cc109b1468f7af2548f1c936489b17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Apr 2024 13:00:19 +0200 Subject: [PATCH 313/350] Update index.rst --- index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.rst b/index.rst index 5799bad31..fb45e8de9 100644 --- a/index.rst +++ b/index.rst @@ -1058,6 +1058,7 @@ Cookbook .. imgtable:: Lambda Magic: Tips and Tricks, cookbook/lambda_magic, head-lightbulb-outline.svg, dark-invert + LVGL Graphic recipes, cookbook/lvgl, lvgl.png Garage Door Template Cover, cookbook/garage-door, garage-variant.svg, dark-invert Time & Temperature on OLED Display, cookbook/display_time_temp_oled, display_time_temp_oled_2.jpg ESP32 Water Leak Detector, cookbook/leak-detector-m5stickC, leak-detector-m5stickC_main_index.jpg @@ -1067,7 +1068,6 @@ Cookbook Arduino Port Extender, cookbook/arduino_port_extender, arduino_logo.svg EHMTX a matrix status/text display, cookbook/ehmtx, ehmtx.jpg Share data directly between ESPHome nodes, cookbook/http_request_sensor, connection.svg, dark-invert - LVGL Graphics: Tips and Tricks, cookbook/lvgl, lvgl.png Do you have other awesome automations or cool setups? Please feel free to add them to the documentation for others to copy. See :doc:`Contributing `. From 9f0f66e8ee8cd8f38fa92915661ae8f773eeda66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Apr 2024 13:59:00 +0200 Subject: [PATCH 314/350] add tileview doc --- components/lvgl.rst | 70 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index de4e97111..42204b37b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1490,6 +1490,76 @@ You can use it as a parent for other widgets, like background shape. By default, widgets: - ... +``tileview`` +************ + +The tileview is a container object whose elements (called tiles) can be arranged in grid form. A user can navigate between the tiles by dragging or swiping. Any direction can be disabled on the tiles individually to not allow moving from one tile to another. + +If the Tile view is screen sized, the user interface resembles what you may have seen on smartwatches. + +A typical application would probably use an ``obj`` container as a tile, to display multiple child widgets. + +**Specific options:** + +- **tiles** (**Required**, list): A list with (any number of) tiles to be added to meter. + - *widget* (**Required**): Any kind of widget to be used as tile container. + - **tile_id** (**Required**): An ID to be used with ``lvgl.tileview.select`` action + - **dir** (*Optional*): Enable moving to the adjacent tiles into the given direction by swiping/dragging. One or multiple of ``LEFT``, ``RIGHT`, ``TOP`, ``BOTTOM`, ``HOR`, ``VER`, ``ALL``. Defaults to ``ALL``. + - **row** (**Required**): Horrizontal position of the tile in the tileview matrix. + - **column** (**Required**): Vertical position of the tile in the tileview matrix. + - Style options from the widget used as container. + +**Specific actions:** + +``lvgl.tileview.select`` :ref:`action ` jumps the ``tileview`` to the desired tile. + +- **id** (**Required**): The ID of the ``tileview`` which receives this action +- **tile_id** (*Optional*): The ID of the tile from within it, to which to jump. Required if not specifying ``row`` and ``column``. +- **row** (*Optional*): Horrizontal position of the tile to which to jump. Required if not specifying ``tile_id``. +- **column** (*Optional*): Vertical position of the tile to which to jump. Required if not specifying ``tile_id``. +- **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. + +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated when displayed tile changes. The new value is returned in the variable ``tile``, as the ID of the newly visilbe tile. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - tileview: + id: tv_id + tiles: + - obj: + row: 0 + column: 0 + tile_id: cat_tile + dir: VER + widgets: + - img: + src: cat_image + - ... + + # Example action: + on_...: + then: + - lvgl.tileview.select: + id: tv_id + row: 0 + column: 0 + animated: true + + # Example trigger: + - slider: + ... + on_value: + - if: + condition: + lambda: return tile == id(cat_tile); + then: + - logger.log: "Cat tile is now showing" + .. _lvgl-wgt-msg: ``msgboxes`` From 8ff2b1c30ccd34900fcc35fbdb1ab73ac702ef13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Apr 2024 14:03:41 +0200 Subject: [PATCH 315/350] Update lvgl.rst --- components/lvgl.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 42204b37b..83151b7bc 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -94,7 +94,7 @@ Configuration variables: - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessarry. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, defaults to ``big_endian``. -- **default_font** (*Optional*, enum): The C array name of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. +- **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. @@ -476,7 +476,7 @@ A label is the basic widget type that is used to display text. - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` - **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) -- **text_font**: (*Optional*, :ref:`font `): The ID or the C array name of the font used to render the text or symbol. +- **text_font**: (*Optional*, :ref:`font `): The ID or the ID of the font used to render the text or symbol. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. - **text_line_space** (*Optional*, int16): Line spacing of the text. - **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. @@ -1471,7 +1471,7 @@ The Base Object is just a simple, empty widget. By default, it's nothing more th .. figure:: /components/images/lvgl_baseobj.png :align: center -You can use it as a parent for other widgets, like background shape. By default, it catches touches. +You can use it as a parent container for other widgets. By default, it catches touches. **Specific options:** @@ -1497,7 +1497,7 @@ The tileview is a container object whose elements (called tiles) can be arranged If the Tile view is screen sized, the user interface resembles what you may have seen on smartwatches. -A typical application would probably use an ``obj`` container as a tile, to display multiple child widgets. +A typical application would probably use an ``obj`` container widget as a tile, to display multiple child widgets, but any widget can be used directly too. **Specific options:** @@ -1539,6 +1539,7 @@ A typical application would probably use an ``obj`` container as a tile, to disp widgets: - img: src: cat_image + - ... - ... # Example action: From b39ba366f5dfce1deca462fe025f968435c3797e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Apr 2024 14:13:58 +0200 Subject: [PATCH 316/350] Update lvgl.rst --- components/lvgl.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 83151b7bc..8661e8595 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1490,10 +1490,12 @@ You can use it as a parent container for other widgets. By default, it catches t widgets: - ... +.. _lvgl-wgt-tiv: + ``tileview`` ************ -The tileview is a container object whose elements (called tiles) can be arranged in grid form. A user can navigate between the tiles by dragging or swiping. Any direction can be disabled on the tiles individually to not allow moving from one tile to another. +The tileview is a container object whose elements, called tiles, can be arranged in grid form. A user can navigate between the tiles by dragging or swiping. Any direction can be disabled on the tiles individually to not allow moving from one tile to another. If the Tile view is screen sized, the user interface resembles what you may have seen on smartwatches. @@ -1505,13 +1507,13 @@ A typical application would probably use an ``obj`` container widget as a tile, - *widget* (**Required**): Any kind of widget to be used as tile container. - **tile_id** (**Required**): An ID to be used with ``lvgl.tileview.select`` action - **dir** (*Optional*): Enable moving to the adjacent tiles into the given direction by swiping/dragging. One or multiple of ``LEFT``, ``RIGHT`, ``TOP`, ``BOTTOM`, ``HOR`, ``VER`, ``ALL``. Defaults to ``ALL``. - - **row** (**Required**): Horrizontal position of the tile in the tileview matrix. - - **column** (**Required**): Vertical position of the tile in the tileview matrix. + - **row** (**Required**): Horrizontal position of the tile in the tileview grid. + - **column** (**Required**): Vertical position of the tile in the tileview grid. - Style options from the widget used as container. **Specific actions:** -``lvgl.tileview.select`` :ref:`action ` jumps the ``tileview`` to the desired tile. +``lvgl.tileview.select`` :ref:`action ` jumps the ``tileview`` to the desired tile: - **id** (**Required**): The ID of the ``tileview`` which receives this action - **tile_id** (*Optional*): The ID of the tile from within it, to which to jump. Required if not specifying ``row`` and ``column``. @@ -1529,7 +1531,7 @@ A typical application would probably use an ``obj`` container widget as a tile, # Example widget: - tileview: - id: tv_id + id: tiv_id tiles: - obj: row: 0 @@ -1546,13 +1548,13 @@ A typical application would probably use an ``obj`` container widget as a tile, on_...: then: - lvgl.tileview.select: - id: tv_id + id: tiv_id row: 0 column: 0 animated: true # Example trigger: - - slider: + - tileview: ... on_value: - if: From f845ae3aa4572392e36ef94b95cd77a4a6c380fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Apr 2024 14:40:00 +0200 Subject: [PATCH 317/350] Update lvgl.rst --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 8661e8595..32604867b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -306,7 +306,7 @@ In ESPHome LVGL offers two font choices: the internal fonts offered by the libra **Internal fonts** -The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and 60 symbols from the `FontAwesome `__ font (see below). Choose one of the names below when specifying the ``text_font`` parameter: +The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and 60 symbols from the `FontAwesome `__ font (see below). Use one of the IDs below when specifying the ``text_font`` parameter: - ``montserrat_8``: 8px font - ``montserrat_10``: 10px font @@ -350,7 +350,7 @@ In addition to the above, the following special fonts are available from LVGL as **ESPHome fonts** -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters of your choice, for any language, from any TrueType/OpenType font. +In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters of your choice, for any language, from any TrueType/OpenType font, using less flash space because you don't need to include all glyphs for all sizes you wish to use. Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples how to play with texts and icons using various TrueType/OpenType fonts. From e938d5781f7b6cd7efe109e32fb3892e18901440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 26 Apr 2024 18:11:30 +0200 Subject: [PATCH 318/350] Update lvgl.rst --- components/lvgl.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 32604867b..02d6950dd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -24,7 +24,7 @@ Check out a few detailed examples :ref:`in the Cookbook ` to see a co Basics ------ -In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` to see the full list of available LVGL widgets in ESPHome. Not all of them are implemented, just the most commonly used ones. +In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` for a list of the available ones in ESPHome. Not all LVGL widgets are implemented, just the ones having most common usecases. Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. The child widget moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within their parent's bounding area. In other words, the areas of the children outside the parent are clipped. @@ -33,7 +33,9 @@ Some more complex widgets are internally made up from the simpler ones, these ar Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent. There is always one active page on a display. -Some widgets integrate in ESPHome also as components: +Widgets can be assigned with an :ref:`config-id` so that they can be referenced in :ref:`automations `. + +Some widgets integrate also as native ESPHome components: .. list-table:: :header-rows: 1 From b3d777de7e9f8193ac60f8a19d6d248e65e2da9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 2 May 2024 11:13:29 +0200 Subject: [PATCH 319/350] background color/image --- components/lvgl.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 02d6950dd..689d676d6 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -96,7 +96,9 @@ Configuration variables: - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessarry. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, defaults to ``big_endian``. -- **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. +- **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. +- **disp_bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a color to fill the bacground. +- **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as a backround wallpaper. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. From 334c35ba4e8d1175c8496c6a1bce929e1c4cd070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 2 May 2024 11:36:56 +0200 Subject: [PATCH 320/350] reorder items --- components/lvgl.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 689d676d6..a8e274bcc 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -96,22 +96,11 @@ Configuration variables: - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessarry. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, defaults to ``big_endian``. -- **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. - **disp_bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a color to fill the bacground. -- **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as a backround wallpaper. +- **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as backround wallpaper. +- **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. -- **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. -- **flex_flow** (*Optional*, string): In case of ``FLEX`` layout, choose one of the following options. Defaults to ``ROW_WRAP``: - - ``ROW`` to place the children in a row without wrapping - - ``COLUMN`` to place the children in a column without wrapping - - ``ROW_WRAP`` to place the children in a row with wrapping - - ``COLUMN_WRAP`` to place the children in a column with wrapping - - ``ROW_REVERSE`` to place the children in a row without wrapping but in reversed order - - ``COLUMN_REVERSE`` to place the children in a column without wrapping but in reversed order - - ``ROW_WRAP_REVERSE`` to place the children in a row with wrapping but in reversed order - - ``COLUMN_WRAP_REVERSE`` to place the children in a column with wrapping but in reversed order -- All other options from :ref:`lvgl-styling` to be commonly apply to the widgets directly. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. Not possible if you configure ``pages``. - **pages** (*Optional*, list): A list of page IDs, where each page acts as a parent for widgets placed on it. Only if no ``widgets`` are configured at this level! Options for each page: - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. @@ -125,6 +114,17 @@ Configuration variables: - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. - All other options from :ref:`lvgl-styling` to be applied to this page. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. +- **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. +- **flex_flow** (*Optional*, string): In case of ``FLEX`` layout, choose one of the following options. Defaults to ``ROW_WRAP``: + - ``ROW`` to place the children in a row without wrapping + - ``COLUMN`` to place the children in a column without wrapping + - ``ROW_WRAP`` to place the children in a row with wrapping + - ``COLUMN_WRAP`` to place the children in a column with wrapping + - ``ROW_REVERSE`` to place the children in a row without wrapping but in reversed order + - ``COLUMN_REVERSE`` to place the children in a column without wrapping but in reversed order + - ``ROW_WRAP_REVERSE`` to place the children in a row with wrapping but in reversed order + - ``COLUMN_WRAP_REVERSE`` to place the children in a column with wrapping but in reversed order +- All other options from :ref:`lvgl-styling` to be commonly apply to the widgets directly. **Example:** From 93c907418149b2652ad58c9307d6b413028e52ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 2 May 2024 14:43:25 +0200 Subject: [PATCH 321/350] color reference correction --- components/lvgl.rst | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a8e274bcc..e333ba128 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -96,7 +96,7 @@ Configuration variables: - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessarry. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, defaults to ``big_endian``. -- **disp_bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a color to fill the bacground. +- **disp_bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a color to fill the bacground. - **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as backround wallpaper. - **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. @@ -251,8 +251,8 @@ The border is drawn inside the bounding box. Padding sets the space on the inner You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each of them. Some widgets allow for more complex styling, effectively changing the appearance of their parts. -- **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background of the widget. -- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to make the background gradually fade to. +- **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background of the widget. +- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to make the background gradually fade to. - **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. - **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. - **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. @@ -261,9 +261,9 @@ You can adjust the appearance of widgets by changing the foreground, background - **opa** (*Optional*, enum or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **opa_layered** (*Optional*, enum or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **bg_img_opa** (*Optional*, enum or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to mix with every pixel of the image. +- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to mix with every pixel of the image. - **bg_img_recolor_opa** (*Optional*, enum or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **border_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw borders of the widget. +- **border_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw borders of the widget. - **border_opa** (*Optional*, enum or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. - **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be chosen): @@ -276,7 +276,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **border_width** (*Optional*, int16): Set the width of the border in pixels. - **radius** (*Optional*, uint16): The radius of the rounded corners of the widget. 0 = no radius i.e. square corners; 65535 = pill shaped widget (true circle if it has same width and height). - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. -- **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw an outline around the widget. +- **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw an outline around the widget. - **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. - **outline_width** (*Optional*, int16): Set the width of the outline in pixels. @@ -287,7 +287,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. - **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. - **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. -- **shadow_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to create a drop shadow under the widget. +- **shadow_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to create a drop shadow under the widget. - **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels - **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels - **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. @@ -358,6 +358,13 @@ In ESPHome you can also use a :ref:`font configured in the normal way`, or directly represennting them in hexadecimal format. Eg. ``0xFF0000`` for red. + .. _lvgl-widgets: Widgets @@ -478,7 +485,7 @@ A label is the basic widget type that is used to display text. - **text** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` -- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. +- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) - **text_font**: (*Optional*, :ref:`font `): The ID or the ID of the font used to render the text or symbol. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. @@ -1006,7 +1013,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. - **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. +- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws a handle on the end of the indicator using all background properties and padding values. With zero padding the knob size is the same as the indicator's width. Larger padding makes it larger, smaller padding makes it smaller. @@ -1161,12 +1168,12 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **count** (**Required**): How many ticks to be on the scale. Defaults to ``12``. - **width** (*Optional*): Tick line width in pixels. Required if ``count`` is greater than ``0``. Defaults to ``2``. - **length** (*Optional*): Tick line length in pixels. Required if ``count`` is greater than ``0``. Defaults to ``10``. - - **color** (*Optional*): ID or hex code for the ticks :ref:`color `. Required if ``count`` is greater than ``0``. Defaults to ``0x808080``. + - **color** (*Optional*): ID or hex code for the ticks :ref:`color `. Required if ``count`` is greater than ``0``. Defaults to ``0x808080``. - **major** (*Optional*, list): If you want major ticks and value labels displayed: - **stride**: How many minor ticks to skip when adding major ticks. Defaults to ``3``. - **width**: Tick line width in pixels. Defaults to ``5``. - **length**: Tick line length in pixels or percentage. Defaults to ``15%``. - - **color**: ID or hex code for the ticks :ref:`color `. Defaults to ``0``. + - **color**: ID or hex code for the ticks :ref:`color `. Defaults to ``0``. - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. Defaults to ``4``. - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-wgt-lin` and :ref:`lvgl-wgt-lbl` text style properties. - **indicators** (**Required**, list): A list with indicators to be added to the scale. Multiple of each can be added. Their values are interpreted in the range of the scale: @@ -1174,20 +1181,20 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **start_value**: The value in the scale range to start drawing the arc from. - **end_value**: The value in the scale range to end drawing the arc to. - **width**: Arc width in pixels. Defaults to ``4``. - - **color**: ID or hex code for the arc :ref:`color `. Defaults to ``0``. + - **color**: ID or hex code for the arc :ref:`color `. Defaults to ``0``. - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). Defaults to ``0``. - Style options for the *arc* using the :ref:`lvgl-wgt-arc` style properties. - **tick_style** (**Optional**): Add tick style modifications: - **start_value**: The value in the scale range to modify the ticks from. - **end_value**: The value in the scale range to modify the ticks to. - - **color_start**: ID or hex code for the gradient start :ref:`color ` of the ticks. - - **color_end**: ID or hex code for the gradient end :ref:`color ` of the ticks. + - **color_start**: ID or hex code for the gradient start :ref:`color ` of the ticks. + - **color_end**: ID or hex code for the gradient end :ref:`color ` of the ticks. - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the start and end values specified above. If ``false``, ``color_start`` and ``color_end`` will be mapped to the entire scale range (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). Defaults to ``false``. - **width**: Modifies the ``width`` of the tick lines. - **line** (*Optional*): Add a needle line to the scale. By default, the length of the line is the same as the scale's radius: - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **width**: Needle line width in pixels. Defaults to ``4``. - - **color**: ID or hex code for the needle line :ref:`color `. Defaults to ``0``. + - **color**: ID or hex code for the needle line :ref:`color `. Defaults to ``0``. - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). Defaults to ``0``. - **value**: The value in the scale range to show at start. - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. @@ -1353,7 +1360,7 @@ The Line widget is capable of drawing straight lines between a set of points. - **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). - **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). - **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. +- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. - Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. By default, the Line widget width and height dimensions are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts of the line may not be visible. @@ -1387,7 +1394,7 @@ The Led widgets are rectangle-like (or circle) widget whose brightness can be ad **Specific options:** -- **color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background, border, and shadow of the widget. +- **color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background, border, and shadow of the widget. - **brightness** (*Optional*, percentage): The brightness of the LED color, where ``0%`` corresponds to black, and ``100%`` corresponds to the full brightness of the color specified above. - Style options from :ref:`lvgl-styling`, using all the typical background style properties. @@ -1436,7 +1443,7 @@ The Spinner widget is a spinning arc over a ring. - **spin_time** (**Required**, :ref:`Time `): Duration of one cycle of the spin. - **arc_length** (**Required**, 0-360): Length of the spinning arc in degrees. - **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. +- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws *another arc using the arc style* properties. Its padding values are interpreted relative to the background arc. From fbe043cb233159c85b0280cba3d05f44784f76d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 2 May 2024 14:52:51 +0200 Subject: [PATCH 322/350] Update lvgl.rst --- components/lvgl.rst | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index e333ba128..13ab0247e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -66,6 +66,9 @@ These are useful to make :ref:`automations ` triggered by actions pe LVGL only supports **integers** for numeric values. Visualizer widgets can't display floats directly, but they allow scaling by 10s. Some examples in the :doc:`Cookbook ` cover how to do that. + Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. + + Main Component -------------- @@ -96,7 +99,7 @@ Configuration variables: - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessarry. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, defaults to ``big_endian``. -- **disp_bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a color to fill the bacground. +- **disp_bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a color to fill the bacground. - **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as backround wallpaper. - **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. @@ -251,8 +254,8 @@ The border is drawn inside the bounding box. Padding sets the space on the inner You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each of them. Some widgets allow for more complex styling, effectively changing the appearance of their parts. -- **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background of the widget. -- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to make the background gradually fade to. +- **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color for the background of the widget. +- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to make the background gradually fade to. - **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. - **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. - **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. @@ -261,9 +264,9 @@ You can adjust the appearance of widgets by changing the foreground, background - **opa** (*Optional*, enum or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **opa_layered** (*Optional*, enum or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **bg_img_opa** (*Optional*, enum or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to mix with every pixel of the image. +- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to mix with every pixel of the image. - **bg_img_recolor_opa** (*Optional*, enum or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **border_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw borders of the widget. +- **border_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw borders of the widget. - **border_opa** (*Optional*, enum or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. - **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be chosen): @@ -276,7 +279,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **border_width** (*Optional*, int16): Set the width of the border in pixels. - **radius** (*Optional*, uint16): The radius of the rounded corners of the widget. 0 = no radius i.e. square corners; 65535 = pill shaped widget (true circle if it has same width and height). - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. -- **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to draw an outline around the widget. +- **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw an outline around the widget. - **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. - **outline_width** (*Optional*, int16): Set the width of the outline in pixels. @@ -287,7 +290,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. - **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. - **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. -- **shadow_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to create a drop shadow under the widget. +- **shadow_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to create a drop shadow under the widget. - **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels - **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels - **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. @@ -485,7 +488,7 @@ A label is the basic widget type that is used to display text. - **text** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` -- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to render the text in. +- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) - **text_font**: (*Optional*, :ref:`font `): The ID or the ID of the font used to render the text or symbol. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. @@ -1013,7 +1016,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. - **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. +- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws a handle on the end of the indicator using all background properties and padding values. With zero padding the knob size is the same as the indicator's width. Larger padding makes it larger, smaller padding makes it smaller. @@ -1269,8 +1272,6 @@ Images are the basic widgets to display images. - **src** (**Required**, :ref:`image `): The ID of an existing image configuration. - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. -Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. - **Specific actions:** ``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. @@ -1312,8 +1313,6 @@ The animation image is similar to the normal ``img`` widget. The main difference - **repeat_count** (*Optional*, int16 or *forever*): How many times to repeat the playback. Defaults to ``forever``. - Some style options from :ref:`lvgl-styling` for the background rectangle that uses the typical background style properties and the image itself using the image style properties. -Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. - **Specific actions:** ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. @@ -1360,7 +1359,7 @@ The Line widget is capable of drawing straight lines between a set of points. - **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). - **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). - **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the line. +- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color for the line. - Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. By default, the Line widget width and height dimensions are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts of the line may not be visible. @@ -1394,7 +1393,7 @@ The Led widgets are rectangle-like (or circle) widget whose brightness can be ad **Specific options:** -- **color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color for the background, border, and shadow of the widget. +- **color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color for the background, border, and shadow of the widget. - **brightness** (*Optional*, percentage): The brightness of the LED color, where ``0%`` corresponds to black, and ``100%`` corresponds to the full brightness of the color specified above. - Style options from :ref:`lvgl-styling`, using all the typical background style properties. @@ -1443,7 +1442,7 @@ The Spinner widget is a spinning arc over a ring. - **spin_time** (**Required**, :ref:`Time `): Duration of one cycle of the spin. - **arc_length** (**Required**, 0-360): Length of the spinning arc in degrees. - **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or a hexadecimal representation of a RGB color to use to draw the arcs. +- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to use to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws *another arc using the arc style* properties. Its padding values are interpreted relative to the background arc. From aacf79bdfd2dd375eea4bebae6b0b859f91970f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 2 May 2024 15:46:18 +0200 Subject: [PATCH 323/350] Update lvgl.rst --- components/lvgl.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 13ab0247e..ecfbd463f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -68,7 +68,6 @@ These are useful to make :ref:`automations ` triggered by actions pe Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. - Main Component -------------- @@ -111,7 +110,7 @@ Configuration variables: - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. - All other options from :ref:`lvgl-styling` to be applied to this page. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. -- **page_wrap** (*Optional*, boolean): Wrap pages around when navigating between them with :ref:`lvgl-pgnx-act`. ``true`` if not specified. +- **page_wrap** (*Optional*, boolean): Wrap pages around when navigating between them with :ref:`lvgl-pgnx-act`. Defaults to ``true`` if not specified. - **top_layer** (*Optional*, list): A special kind of *Always on Top* page, which acts as a parent for widgets placed on it. It's shown above all the pages - useful for widgets which need to be always visible, regardless of the pages. Only of no ``widgets`` are configured at this level. Options: - **layout** (*Optional*, string): Layout to be applied to this page. Same option as above. - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. From 97704a2465cddcbec0dbb8061b3e8648a0c5f220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 2 May 2024 16:06:20 +0200 Subject: [PATCH 324/350] Update lvgl.rst --- components/lvgl.rst | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ecfbd463f..a184b94f5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -439,7 +439,6 @@ To apply styles to the states, you need to specify them one level above, for exa checked: bg_color: 0x00FF00 # here you apply styles to be used when in the respective state - The state itself can be can be changed by interacting with the widget, or :ref:`programatically ` with ``lvgl.widget.update`` action. See :ref:`lvgl-cook-cover` for a cookbook example how to play with styling and properties to show different states of a Home Assistant entity. @@ -585,7 +584,6 @@ To have a button with a text label on it, add a :ref:`lvgl-wgt-lbl` widget as ch align: center text: "Light" - A notable state is ``checked`` (boolean) which can have different styles applied. The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. @@ -871,7 +869,6 @@ Roller allows you to simply select one option from a list by scrolling. The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. - .. _lvgl-wgt-bar: ``bar`` @@ -1075,7 +1072,6 @@ The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider (or an arc) to control entities in Home Assistant. - .. _lvgl-wgt-spb: ``spinbox`` @@ -1515,7 +1511,7 @@ A typical application would probably use an ``obj`` container widget as a tile, - **tiles** (**Required**, list): A list with (any number of) tiles to be added to meter. - *widget* (**Required**): Any kind of widget to be used as tile container. - **tile_id** (**Required**): An ID to be used with ``lvgl.tileview.select`` action - - **dir** (*Optional*): Enable moving to the adjacent tiles into the given direction by swiping/dragging. One or multiple of ``LEFT``, ``RIGHT`, ``TOP`, ``BOTTOM`, ``HOR`, ``VER`, ``ALL``. Defaults to ``ALL``. + - **dir** (*Optional*): Enable moving to the adjacent tiles into the given direction by swiping/dragging. One or multiple of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. - **row** (**Required**): Horrizontal position of the tile in the tileview grid. - **column** (**Required**): Vertical position of the tile in the tileview grid. - Style options from the widget used as container. @@ -1733,7 +1729,6 @@ This :ref:`action ` resumes the activity of LVGL, including rende then: - lvgl.resume: - .. _lvgl-pgnx-act: ``lvgl.page.next``, ``lvgl.page.previous`` @@ -1744,7 +1739,6 @@ This :ref:`action ` changes page to the next following in the con - **animation** (*Optional*): The page change with one of these animations: ``NONE``, ``OVER_LEFT``, ``OVER_RIGHT``, ``OVER_TOP``, ``OVER_BOTTOM``, ``MOVE_LEFT``, ``MOVE_RIGHT``, ``MOVE_TOP``, ``MOVE_BOTTOM``, ``FADE_IN``, ``FADE_OUT``, ``OUT_LEFT``, ``OUT_RIGHT``, ``OUT_TOP``, ``OUT_BOTTOM``. Defaults to ``NONE`` if not specified. - **time** (*Optional*, :ref:`Time `): Duration of the page change animation. Defaults to ``50ms``. - .. code-block:: yaml on_...: From 62b4e03cc122fa1cd91408ba675faae9525c1f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 2 May 2024 16:29:23 +0200 Subject: [PATCH 325/350] Update lvgl.rst --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a184b94f5..d633d54dd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -365,7 +365,7 @@ Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-co Colors ****** -Colors can be specified anywehere in the LVGL configuartion either by referencing a preconfigured :ref:`ESPHome color `, or directly represennting them in hexadecimal format. Eg. ``0xFF0000`` for red. +Colors can be specified anywehere in the LVGL configuartion either by referencing a preconfigured :ref:`ESPHome color `, or directly represennted in hexadecimal format. Eg. ``0xFF0000`` for red. .. _lvgl-widgets: From 8479913aeee5ca21325f6a8a15bccf91437b51e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 2 May 2024 21:10:24 +0200 Subject: [PATCH 326/350] Update lvgl.rst --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d633d54dd..a73ff4d82 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -77,9 +77,9 @@ At the highest level of the LVGL object hierarchy is the display which represent The widget is at the next level, and it allows main styling. It can have sub-parts, which may be styled separately. Usually styles are inherited, but this depends on widget specifics or functionality. The widget and the parts have states, and the different styling can be set for different states. -By default, LVGL draws new widgets on top of old widgets, including their children. If widgets are children of other widgets (they have the parentid property set), property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Inheritance takes place at run time too. +By default, LVGL draws new widgets on top of old widgets, including their children. When widgets have children, property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. -Configuration variables: +**Configuration options:** - **displays** (**Required**, list): A list of displays where to render this entire LVGL configuration: - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. From 2a2e1aea62861ea3cba7fe820b57f07b973f3cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 10:12:09 +0200 Subject: [PATCH 327/350] general review --- components/lvgl.rst | 35 +++++++++++++++++------------------ index.rst | 2 ++ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a73ff4d82..82dbd7ae9 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -13,9 +13,9 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t .. figure:: /components/images/lvgl_main_screenshot.png -In order to be able to drive a display with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. +In order to be able to drive a :ref:`display ` with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended. -The display itself should have ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should be configured with an :ref:`config-id` which will be referenced in the main LGVL component configuration. +The display itself has to be a graphical binary type, should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should also have an :ref:`config-id` set, which will be referenced in the main LGVL component configuration. For interactivity, a :ref:`Touchscreen ` (capacitive highly prefered) or a :doc:`/components/sensor/rotary_encoder` can be used. @@ -24,12 +24,9 @@ Check out a few detailed examples :ref:`in the Cookbook ` to see a co Basics ------ -In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` for a list of the available ones in ESPHome. Not all LVGL widgets are implemented, just the ones having most common usecases. +In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` for a list of the available ones in ESPHome. Not all LVGL widgets are implemented, just the ones having most common usecases in home automation. -Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. -The child widget moves with the parent and if the parent is hidden the children will be hidden too. Children can be visible only within their parent's bounding area. In other words, the areas of the children outside the parent are clipped. - -Some more complex widgets are internally made up from the simpler ones, these are known as parts - which can have separate properties from the main widget. +Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. Some more complex widgets are internally made up from the simpler ones, these are known as parts - which can have separate properties from the main widget. Pages in ESPHome are implemented as LVGL screens, which are special objects which have no parent. There is always one active page on a display. @@ -68,16 +65,18 @@ These are useful to make :ref:`automations ` triggered by actions pe Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. -Main Component --------------- +Configuration +------------- Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome this is simplified to a hierarchy. -At the highest level of the LVGL object hierarchy is the display which represents the driver for a display device (physical display). A display can have one or more pages associated with it. Each page contains a hierarchy of objects for graphical widgets representing a layout that covers the entire display. +At the highest level of the LVGL object hierarchy is the display which represents the driver for the display hardware. A display can have one or more pages associated with it. Each page contains a hierarchy of objects for graphical widgets representing a layout that covers the entire display. -The widget is at the next level, and it allows main styling. It can have sub-parts, which may be styled separately. Usually styles are inherited, but this depends on widget specifics or functionality. The widget and the parts have states, and the different styling can be set for different states. +The widget is at the next level, and it allows main styling. It can have sub-parts, which may be styled separately. Usually styles are inherited, but this depends on widget specifics or functionality. The widget and its parts have states, and the different styling can be set for different states. -By default, LVGL draws new widgets on top of old widgets, including their children. When widgets have children, property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. Inheritance is applied only at first draw. In this case, if the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for the property. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. +Widgets can have children, which can be any other widgets. Think of this as a nested structure. The child widgets move with the parent and if the parent is hidden the children will be hidden too. + +By default, LVGL draws new widgets on top of old widgets, including their children. When widgets have children, property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for it. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. **Configuration options:** @@ -208,7 +207,7 @@ And then you apply these selected styles to two labels, and only change very spe styles: date_style y: +20 -Additionally, you can change the styles based on the state of the widgets or their parts. If you want to set a property for all states (e.g. red background color) just set it for the default state, at the root of the widget. If the widget can't find a property for its current state it will fall back to the default state's property. +Additionally, you can change the styles based on the ``state`` property of the widgets or their parts. If you want to set a property for all states (e.g. red background color) just set it for the default state at the root of the widget. If the widget can't find a property for its current state it will fall back to this. In the example below, you have an ``arc`` with some styles set here. Note how you change the ``arc_color`` of the ``indicator`` part, based on state changes: @@ -230,9 +229,9 @@ So the inheritance happens like this: state based styles override the locally sp The precedence (value) of states is quite intuitive, and it's something the user would expect naturally. E.g. if a widget is focused the user will still want to see if it's pressed, therefore the pressed state has a higher precedence. If the focused state had a higher precedence it would overwrite the pressed color. -Some properties (e.g. text color) can be inherited from a parent(s) if it's not specified in the widget. +Feel free to experiment to discover inheritance of the styles based on states between the nested widgets. -See :ref:`lvgl-cook-theme` in the Cookbook for an example how to easily implement a gradient style for your widgets. +:ref:`lvgl-cook-theme` in the Cookbook shows an example how to easily implement a gradient style for your widgets. .. _lvgl-styling: @@ -247,7 +246,7 @@ LVGL follows CSS's `border-box model ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. The ``slider`` can be also integrated as :doc:`/components/number/lvgl`. @@ -1066,7 +1065,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can .. note:: - The ``on_value`` trigger is sent while the arc knob is being dragged or changed with keys. The event is sent *continuously* while the knob is being dragged, this can affect performance and have negative effects on the actions to be performed. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. + The ``on_value`` trigger is sent while the arc knob is being dragged or changed with keys. The event is sent *continuously* while the knob is being dragged, this can affect performance and have negative effects on the actions to be performed. In such cases use a :ref:`universal event trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. The ``arc`` can be also integrated as :doc:`/components/number/lvgl`. diff --git a/index.rst b/index.rst index fb45e8de9..8235737a9 100644 --- a/index.rst +++ b/index.rst @@ -754,6 +754,8 @@ Display Components LCD Menu, components/display_menu/lcd_menu, lcd_menu.png LVGL Graphics, components/lvgl, lvgl.png +.. _display-hw: + Display Hardware Platforms -------------------------- From c59344e0c6f0cce169702d598c8771e0cfa75c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 10:40:53 +0200 Subject: [PATCH 328/350] Update lvgl.rst --- components/lvgl.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 82dbd7ae9..6c4e03e3b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -72,11 +72,7 @@ Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome thi At the highest level of the LVGL object hierarchy is the display which represents the driver for the display hardware. A display can have one or more pages associated with it. Each page contains a hierarchy of objects for graphical widgets representing a layout that covers the entire display. -The widget is at the next level, and it allows main styling. It can have sub-parts, which may be styled separately. Usually styles are inherited, but this depends on widget specifics or functionality. The widget and its parts have states, and the different styling can be set for different states. - -Widgets can have children, which can be any other widgets. Think of this as a nested structure. The child widgets move with the parent and if the parent is hidden the children will be hidden too. - -By default, LVGL draws new widgets on top of old widgets, including their children. When widgets have children, property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for it. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. +The following configuration options apply to the main ``lvgl`` component, in order to establish the principal operating conditions. Some :ref:`styling options ` can be set at this level too, but only for inheritance purposes. **Configuration options:** @@ -371,6 +367,12 @@ Colors can be specified anywehere in the LVGL configuartion either by referencin Widgets ------- +At the next level of the LVGL object hierarchy are the widgets, which support styling directly. It can have sub-parts, which may be styled separately. Usually styles are inherited, but this depends on widget specifics or functionality. The widget and its parts have states, and the different styling can be set for different states. + +Widgets can have children, which can be any other widgets. Think of this as a nested structure. The child widgets move with the parent and if the parent is hidden the children will be hidden too. + +By default, LVGL draws new widgets on top of old widgets, including their children. When widgets have children, property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for it. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. + Common properties ***************** From abc32a73f30599baaa58a13a74f688cd8db5a888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 10:45:43 +0200 Subject: [PATCH 329/350] Update lvgl.rst --- components/lvgl.rst | 132 ++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 6c4e03e3b..c379a0125 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -142,10 +142,74 @@ The following configuration options apply to the main ``lvgl`` component, in ord See :ref:`lvgl-cook-navigator` in the Cookbook for an example how to easily implement a page navigation bar at the bottom of the screen. +.. _lvgl-color: + +Colors +****** + +Colors can be specified anywehere in the LVGL configuartion either by referencing a preconfigured :ref:`ESPHome color `, or directly represennted in hexadecimal format. Eg. ``0xFF0000`` for red. + +.. _lvgl-fonts: + +Fonts +***** + +In ESPHome LVGL offers two font choices: the internal fonts offered by the library or :ref:`fonts configured in the normal way`. + +**Internal fonts** + +The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and 60 symbols from the `FontAwesome `__ font (see below). Use one of the IDs below when specifying the ``text_font`` parameter: + +- ``montserrat_8``: 8px font +- ``montserrat_10``: 10px font +- ``montserrat_12``: 12px font +- ``montserrat_14``: 14px font (**default**) +- ``montserrat_16``: 16px font +- ``montserrat_18``: 18px font +- ``montserrat_20``: 20px font +- ``montserrat_22``: 22px font +- ``montserrat_24``: 24px font +- ``montserrat_26``: 26px font +- ``montserrat_28``: 28px font +- ``montserrat_30``: 30px font +- ``montserrat_32``: 32px font +- ``montserrat_34``: 34px font +- ``montserrat_36``: 36px font +- ``montserrat_38``: 38px font +- ``montserrat_40``: 40px font +- ``montserrat_42``: 42px font +- ``montserrat_44``: 44px font +- ``montserrat_46``: 46px font +- ``montserrat_48``: 48px font + +You can display the embedded symbols among the text by their codepoint address preceeded by ``\u``, eg. ``\uF00C``: + +.. figure:: /components/images/lvgl_symbols.png + :align: center + +.. note:: + + The ``text_font`` parameter affects the size of symbols, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. If you set ``text_font`` on a widget to a custom ESPHome font, these symbols will likely not display, unles you include them manually from a FontAwesome OpenType file. + + For escape sequences to work, you have to put them in strings enclosed in double quotes. + +In addition to the above, the following special fonts are available from LVGL as built-in: + +- ``unscii_8``: 8 px pixel perfect font with only ASCII characters. +- ``unscii_16``: 16 px pixel perfect font with only ASCII characters. +- ``simsun_16_cjk``: 16 px font with normal range + 1000 most common `CJK Radicals `__. +- ``dejavu_16_persian_hebrew``: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms. + +**ESPHome fonts** + +In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters of your choice, for any language, from any TrueType/OpenType font, using less flash space because you don't need to include all glyphs for all sizes you wish to use. + +Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples how to play with texts and icons using various TrueType/OpenType fonts. + .. _lvgl-theme: -Theming and Styling -------------------- +Theming +******* The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. @@ -298,70 +362,6 @@ You can adjust the appearance of widgets by changing the foreground, background - **translate_x** (*Optional*, int16 or percentage): Move of the widget with this value in horizontal direction. - **translate_y** (*Optional*, int16 or percentage): Move of the widget with this value in vertical direction. -.. _lvgl-fonts: - -Fonts -***** - -In ESPHome LVGL offers two font choices: the internal fonts offered by the library or :ref:`fonts configured in the normal way`. - -**Internal fonts** - -The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and 60 symbols from the `FontAwesome `__ font (see below). Use one of the IDs below when specifying the ``text_font`` parameter: - -- ``montserrat_8``: 8px font -- ``montserrat_10``: 10px font -- ``montserrat_12``: 12px font -- ``montserrat_14``: 14px font (**default**) -- ``montserrat_16``: 16px font -- ``montserrat_18``: 18px font -- ``montserrat_20``: 20px font -- ``montserrat_22``: 22px font -- ``montserrat_24``: 24px font -- ``montserrat_26``: 26px font -- ``montserrat_28``: 28px font -- ``montserrat_30``: 30px font -- ``montserrat_32``: 32px font -- ``montserrat_34``: 34px font -- ``montserrat_36``: 36px font -- ``montserrat_38``: 38px font -- ``montserrat_40``: 40px font -- ``montserrat_42``: 42px font -- ``montserrat_44``: 44px font -- ``montserrat_46``: 46px font -- ``montserrat_48``: 48px font - -You can display the embedded symbols among the text by their codepoint address preceeded by ``\u``, eg. ``\uF00C``: - -.. figure:: /components/images/lvgl_symbols.png - :align: center - -.. note:: - - The ``text_font`` parameter affects the size of symbols, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. If you set ``text_font`` on a widget to a custom ESPHome font, these symbols will likely not display, unles you include them manually from a FontAwesome OpenType file. - - For escape sequences to work, you have to put them in strings enclosed in double quotes. - -In addition to the above, the following special fonts are available from LVGL as built-in: - -- ``unscii_8``: 8 px pixel perfect font with only ASCII characters. -- ``unscii_16``: 16 px pixel perfect font with only ASCII characters. -- ``simsun_16_cjk``: 16 px font with normal range + 1000 most common `CJK Radicals `__. -- ``dejavu_16_persian_hebrew``: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms. - -**ESPHome fonts** - -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters of your choice, for any language, from any TrueType/OpenType font, using less flash space because you don't need to include all glyphs for all sizes you wish to use. - -Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples how to play with texts and icons using various TrueType/OpenType fonts. - -.. _lvgl-color: - -Colors -****** - -Colors can be specified anywehere in the LVGL configuartion either by referencing a preconfigured :ref:`ESPHome color `, or directly represennted in hexadecimal format. Eg. ``0xFF0000`` for red. - .. _lvgl-widgets: Widgets From fc49b1f2e874e7942ab280ad3949be9209757210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 10:51:40 +0200 Subject: [PATCH 330/350] Update lvgl.rst --- components/lvgl.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c379a0125..0aeb707e7 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -59,14 +59,8 @@ Some widgets integrate also as native ESPHome components: These are useful to make :ref:`automations ` triggered by actions performed at the screen. -.. note:: - - LVGL only supports **integers** for numeric values. Visualizer widgets can't display floats directly, but they allow scaling by 10s. Some examples in the :doc:`Cookbook ` cover how to do that. - - Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. - -Configuration -------------- +Main Configuration +------------------ Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome this is simplified to a hierarchy. @@ -142,6 +136,12 @@ The following configuration options apply to the main ``lvgl`` component, in ord See :ref:`lvgl-cook-navigator` in the Cookbook for an example how to easily implement a page navigation bar at the bottom of the screen. +.. note:: + + LVGL only supports **integers** for numeric values. Visualizer widgets can't display floats directly, but they allow scaling by 10s. Some examples in the :doc:`Cookbook ` cover how to do that. + + Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. + .. _lvgl-color: Colors @@ -367,7 +367,7 @@ You can adjust the appearance of widgets by changing the foreground, background Widgets ------- -At the next level of the LVGL object hierarchy are the widgets, which support styling directly. It can have sub-parts, which may be styled separately. Usually styles are inherited, but this depends on widget specifics or functionality. The widget and its parts have states, and the different styling can be set for different states. +At the next level of the LVGL object hierarchy are the widgets, which support styling directly. They can have sub-parts, which may be styled separately. Usually styles are inherited, but this depends on widget specifics or functionality. The widget and its parts have states, and the different styling can be set for different states. Widgets can have children, which can be any other widgets. Think of this as a nested structure. The child widgets move with the parent and if the parent is hidden the children will be hidden too. From 79c87f4acdaeaf2415ab7ce34d7223a93266ae94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 10:53:57 +0200 Subject: [PATCH 331/350] Update lvgl.rst --- components/lvgl.rst | 142 ++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 0aeb707e7..98374bca3 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -206,10 +206,79 @@ In ESPHome you can also use a :ref:`font configured in the normal way`__. A widget's *box* is built from the following parts: + +.. figure:: /components/images/lvgl_boxmodel.png + :align: center + +- **bounding box**: the width/height of the elements. +- **border width**: the width of the border. +- **padding**: space between the sides of the widget and its children. +- **content**: the content area which is the size of the bounding box reduced by the border width and padding (it's what's referenced as the ``size_content`` option of certain widgets). + +The border is drawn inside the bounding box. Padding sets the space on the inner sides of the border. It means *I don't want my children too close to my sides, so keep this space*. The outline is drawn outside the bounding box. + +You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each of them. Some widgets allow for more complex styling, effectively changing the appearance of their parts. + +- **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color for the background of the widget. +- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to make the background gradually fade to. +- **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. +- **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. +- **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. +- **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. +- **bg_opa** (*Optional*, enum or percentage): Opacity of the background. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **opa** (*Optional*, enum or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **opa_layered** (*Optional*, enum or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **bg_img_opa** (*Optional*, enum or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to mix with every pixel of the image. +- **bg_img_recolor_opa** (*Optional*, enum or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **border_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw borders of the widget. +- **border_opa** (*Optional*, enum or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. +- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be chosen): + - ``NONE`` + - ``TOP`` + - ``BOTTOM`` + - ``LEFT`` + - ``RIGHT`` + - ``INTERNAL`` +- **border_width** (*Optional*, int16): Set the width of the border in pixels. +- **radius** (*Optional*, uint16): The radius of the rounded corners of the widget. 0 = no radius i.e. square corners; 65535 = pill shaped widget (true circle if it has same width and height). +- **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. +- **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw an outline around the widget. +- **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. +- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. +- **pad_all** (*Optional*, int16): Set the padding in all directions, in pixels. +- **pad_top** (*Optional*, int16): Set the padding on the top, in pixels. +- **pad_bottom** (*Optional*, int16): Set the padding on the bottom, in pixels. +- **pad_left** (*Optional*, int16): Set the padding on the left, in pixels. +- **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. +- **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. +- **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. +- **shadow_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to create a drop shadow under the widget. +- **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels +- **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels +- **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **shadow_spread** (*Optional*, int16): Spread of the shadow, in pixels. +- **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. +- **transform_angle** (*Optional*, 0-360): Trannsformation angle of the widget (eg. rotation) +- **transform_height** (*Optional*, int16 or percentage): Trannsformation height of the widget (eg. stretching) +- **transform_pivot_x** (*Optional*, int16 or percentage): Horizontal anchor point of the transformation. Relative to the widget's top left corner. +- **transform_pivot_y** (*Optional*, int16 or percentage): Vertical anchor point of the transformation. Relative to the widget's top left corner. +- **transform_zoom** (*Optional*, 0.1-10): Trannsformation zoom of the widget (eg. resizing) +- **translate_x** (*Optional*, int16 or percentage): Move of the widget with this value in horizontal direction. +- **translate_y** (*Optional*, int16 or percentage): Move of the widget with this value in vertical direction. + .. _lvgl-theme: -Theming -******* +Themes +****** The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. @@ -293,75 +362,6 @@ Feel free to experiment to discover inheritance of the styles based on states be :ref:`lvgl-cook-theme` in the Cookbook shows an example how to easily implement a gradient style for your widgets. -.. _lvgl-styling: - -Style properties -**************** - -LVGL follows CSS's `border-box model `__. A widget's *box* is built from the following parts: - -.. figure:: /components/images/lvgl_boxmodel.png - :align: center - -- **bounding box**: the width/height of the elements. -- **border width**: the width of the border. -- **padding**: space between the sides of the widget and its children. -- **content**: the content area which is the size of the bounding box reduced by the border width and padding (it's what's referenced as the ``size_content`` option of certain widgets). - -The border is drawn inside the bounding box. Padding sets the space on the inner sides of the border. It means *I don't want my children too close to my sides, so keep this space*. The outline is drawn outside the bounding box. - -You can adjust the appearance of widgets by changing the foreground, background and/or border color, font of each of them. Some widgets allow for more complex styling, effectively changing the appearance of their parts. - -- **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color for the background of the widget. -- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to make the background gradually fade to. -- **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. -- **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. -- **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. -- **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. -- **bg_opa** (*Optional*, enum or percentage): Opacity of the background. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **opa** (*Optional*, enum or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **opa_layered** (*Optional*, enum or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **bg_img_opa** (*Optional*, enum or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to mix with every pixel of the image. -- **bg_img_recolor_opa** (*Optional*, enum or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **border_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw borders of the widget. -- **border_opa** (*Optional*, enum or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. -- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be chosen): - - ``NONE`` - - ``TOP`` - - ``BOTTOM`` - - ``LEFT`` - - ``RIGHT`` - - ``INTERNAL`` -- **border_width** (*Optional*, int16): Set the width of the border in pixels. -- **radius** (*Optional*, uint16): The radius of the rounded corners of the widget. 0 = no radius i.e. square corners; 65535 = pill shaped widget (true circle if it has same width and height). -- **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. -- **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw an outline around the widget. -- **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. -- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. -- **pad_all** (*Optional*, int16): Set the padding in all directions, in pixels. -- **pad_top** (*Optional*, int16): Set the padding on the top, in pixels. -- **pad_bottom** (*Optional*, int16): Set the padding on the bottom, in pixels. -- **pad_left** (*Optional*, int16): Set the padding on the left, in pixels. -- **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. -- **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. -- **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. -- **shadow_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to create a drop shadow under the widget. -- **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels -- **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels -- **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **shadow_spread** (*Optional*, int16): Spread of the shadow, in pixels. -- **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. -- **transform_angle** (*Optional*, 0-360): Trannsformation angle of the widget (eg. rotation) -- **transform_height** (*Optional*, int16 or percentage): Trannsformation height of the widget (eg. stretching) -- **transform_pivot_x** (*Optional*, int16 or percentage): Horizontal anchor point of the transformation. Relative to the widget's top left corner. -- **transform_pivot_y** (*Optional*, int16 or percentage): Vertical anchor point of the transformation. Relative to the widget's top left corner. -- **transform_zoom** (*Optional*, 0.1-10): Trannsformation zoom of the widget (eg. resizing) -- **translate_x** (*Optional*, int16 or percentage): Move of the widget with this value in horizontal direction. -- **translate_y** (*Optional*, int16 or percentage): Move of the widget with this value in vertical direction. - .. _lvgl-widgets: Widgets From de36628beb2b624f9f810c56885420a5c22fb1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 11:03:40 +0200 Subject: [PATCH 332/350] state property ref test --- components/lvgl.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 98374bca3..25b1188fb 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -417,6 +417,9 @@ The properties below are common to all widgets. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Same configuration option as at the main component. - **flex_flow** (*Optional*, string): Option for ``FLEX`` layout, similar configuration as at the main component. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn as children of this widget. Same configuration option as at the main component. + +.. _lvgl-wgtprop-state: + - **state** (*Optional*, enum): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden within style definitions or locally set. Can be one of: - **default** (*Optional*, boolean): Normal, released state. - **disabled** (*Optional*, boolean): Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``). From 321ff32594c8235cea7bc9ff030740556e4516a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 11:16:36 +0200 Subject: [PATCH 333/350] emphasis on state --- components/lvgl.rst | 6 +++--- cookbook/lvgl.rst | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 25b1188fb..4221e39bb 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -282,7 +282,7 @@ Themes The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. -You can configure a global theme for all the widgets at the top level with the ``theme`` configuration option. In the example below, all the ``arc``, ``slider`` and ``btn`` widgets will use the styles and properties predefined by default here. A combination of styles and states can be chosen for every widget. +You can configure a global theme for all the widgets at the top level with the ``theme`` configuration option. In the example below, all the ``arc``, ``slider`` and ``btn`` widgets will use the styles and properties predefined by default here. A combination of styles and :ref:`states ` can be chosen for every widget. .. code-block:: yaml @@ -336,7 +336,7 @@ And then you apply these selected styles to two labels, and only change very spe styles: date_style y: +20 -Additionally, you can change the styles based on the ``state`` property of the widgets or their parts. If you want to set a property for all states (e.g. red background color) just set it for the default state at the root of the widget. If the widget can't find a property for its current state it will fall back to this. +Additionally, you can change the styles based on the :ref:`state ` property of the widgets or their parts. If you want to set a property for all states (e.g. red background color) just set it for the default state at the root of the widget. If the widget can't find a property for its current state it will fall back to this. In the example below, you have an ``arc`` with some styles set here. Note how you change the ``arc_color`` of the ``indicator`` part, based on state changes: @@ -371,7 +371,7 @@ At the next level of the LVGL object hierarchy are the widgets, which support st Widgets can have children, which can be any other widgets. Think of this as a nested structure. The child widgets move with the parent and if the parent is hidden the children will be hidden too. -By default, LVGL draws new widgets on top of old widgets, including their children. When widgets have children, property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for it. The parents will use their own state to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. +By default, LVGL draws new widgets on top of old widgets, including their children. When widgets have children, property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for it. The parents will use their own :ref:`state ` to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Common properties ***************** diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index d7aff2c8f..d5579304e 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -620,7 +620,8 @@ Since LVGL uses inheritance to apply styles across the widgets, it's possible to .. figure:: images/lvgl_cook_gradient_styles.png :align: center -In this example we prepare a set of gradient styles in the *theme*, and make some modifications in a *style_definition* which can be applied in a batch to the desired widgets. Theme is applied automatically, the style definition is applied manually (read further to see how). +In this example we prepare a set of gradient styles in the *theme*, and make some modifications in a *style_definition* which can be applied in a batch to the desired widgets. Theme is applied automatically, and can be overridden manually with style definitions (read further to see how). + .. code-block:: yaml From 7edbd0c51a5946006545ae2c5f58f7bb1f0a6c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 11:52:39 +0200 Subject: [PATCH 334/350] brushup --- components/lvgl.rst | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4221e39bb..3c19f6925 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -489,16 +489,16 @@ A label is the basic widget type that is used to display text. **Specific options:** - **text** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. -- **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO`` +- **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO``. - **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to render the text in. -- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be chosen) +- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be specified). - **text_font**: (*Optional*, :ref:`font `): The ID or the ID of the font used to render the text or symbol. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. - **text_line_space** (*Optional*, int16): Line spacing of the text. - **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped. (Default) + - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped (Default). - ``DOT``: Replaces the last 3 characters from bottom right corner of the label with dots. - ``SCROLL``: If the text is wider than the label scroll it horizontally back and forth. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. - ``SCROLL_CIRCULAR``: If the text is wider than the label scroll it horizontally continuously. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. @@ -507,7 +507,9 @@ A label is the basic widget type that is used to display text. - **selected** (*Optional*, list): Settings for the the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. -Newline escape sequences are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``"line1\nline2\n\nline4"``. **Note**: For escape sequences like newline to be translated, enclose the string in double quotes. +.. note:: + + Newline escape sequences are handled automatically by the label widget. You can use ``\n`` to make a line break. For example: ``"line1\nline2\n\nline4"``. For escape sequences like newline to be translated, *enclose the string in double quotes*. **Specific actions:** @@ -608,21 +610,21 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **rows** (**Required**, list): A list for the button rows: - **buttons** (**Required**, list): A list of buttons in a row: - - **id** (*Optional*): An ID for a button + - **id** (*Optional*): An ID for the button in the matrix. - **text** (*Optional*): Text or built-in :ref:`symbol ` to display on the button. - **key_code** (*Optional*, string): One character be sent as the key code to a :ref:`key_collector` instead of ``text`` when the button is pressed. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1`` (eg. in a line with two buttons: one ``width: 1`` and another one ``width: 2``, the first will be ``33%`` wide while the second will be ``66%`` wide). - **selected** (*Optional*, boolean): Set the button as the most recently released or focused. Defaults to ``false``. - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): - - **hidden** (*Optional*, boolean): makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). + - **hidden** (*Optional*, boolean): Make a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). - **no_repeat** (*Optional*, boolean): Disable repeating when the button is long pressed. - - **disabled** (*Optional*, boolean): applies *disabled* styles and properties to the button. + - **disabled** (*Optional*, boolean): Apply ``disabled`` styles to the button. - **checkable** (*Optional*, boolean): Enable toggling of a button, ``checked`` state will be added/removed as the button is clicked. - - **checked** (*Optional*, boolean): make the button checked. It will use the styles of the ``checked`` state. - - **click_trig** (*Optional*, boolean): Controls how to :ref:`trigger ` ``on_value`` : if ``true`` on *click*, if ``false`` on *press*. - - **popover** (*Optional*, boolean): show the button label in a popover when pressing this key. + - **checked** (*Optional*, boolean): Make the button checked. Apply ``checked`` styles to the button. + - **click_trig** (*Optional*, boolean): Control how to :ref:`trigger ` ``on_value`` : if ``true`` on *click*, if ``false`` on *press*. + - **popover** (*Optional*, boolean): Show the button label in a popover when pressing this button. - **recolor** (*Optional*, boolean): Enable recoloring of button texts with #. E.g. ``It's #ff0000 red#`` - - **custom_1** and **custom_2** (*Optional*, boolean): custom free to use flags + - **custom_1** and **custom_2** (*Optional*, boolean): Custom, free to use flags. - **items** (*Optional*, list): Settings for the items *part*, the buttons all use the text and typical background style properties except translations and transformations. - **one_checked** (*Optional*, boolean): Allow only one button to be checked at a time (aka. radio buttons). Defaults to ``false``. @@ -776,7 +778,7 @@ The ``checkbox`` can be also integrated as a :doc:`/components/switch/lvgl`. The Dropdown widget allows the user to select one value from a list. -The dropdown list is closed by default and displays a single value or a predefined text. When activated (by click on the drop-down list), a list is drawn from which the user may select one option. When the user selects a new value, the list is deleted from the screen. +The dropdown list is closed by default and displays a single value. When activated (by clicking on the drop-down list), a list is drawn from which the user may select one option. When the user selects a new value, the list is deleted from the screen. .. figure:: /components/images/lvgl_dropdown.png :align: center @@ -842,7 +844,7 @@ Roller allows you to simply select one option from a list by scrolling. - **visible_row_count** (*Optional*, int8): The number of visible rows. - **selected** (*Optional*, list): Settings for the selected *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-wgt-lbl` text style properties to change the appearance of the text in the selected area. - **selected_index** (*Optional*, int8): The index of the item you wish to be selected. -- **anim_time** (*Optional*, :ref:`Time `): When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in ``anim_time`` milliseconds as specified in the style. +- **anim_time** (*Optional*, :ref:`Time `): When the Roller is scrolled and doesn't stop exactly on an option it will scroll to the nearest valid option automatically in this amount of time. - Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-wgt-lbl` style properties. ``text_line_space`` adjusts the space between the options. **Specific actions:** @@ -878,7 +880,7 @@ The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. ``bar`` ******* -The bar widget has a background and an indicator on it. The width of the indicator is set according to the current value of the bar. +The bar widget has a background and an indicator on it. The size of the indicator is set according to the current ``value`` of the bar. .. figure:: /components/images/lvgl_bar.png :align: center @@ -1202,7 +1204,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - **img** (*Optional*): Add a rotating needle image to the scale: - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - - **src**: The ID of an existing image configuration, represennting a needle pointing to the right like ``-o--->``. Cannot be updated at runtime with ``lvgl.indicator.update``. + - **src**: The ID of an existing image configuration, represennting a needle pointing to the right like ``-o--->``. - **pivot_x**: Horizontal position of the pivot point of rotation relative to the top left corner of the image. Defaults to ``50%`` (center of image). - **pivot_y**: Vertical position of the pivot point of rotation relative to the top left corner of the image.. Defaults to ``50%`` (center of image). - **value**: The value in the scale range to show at start. @@ -1214,7 +1216,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee **Specific actions:** -``lvgl.indicator.update`` :ref:`action ` updates indicator options, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +``lvgl.indicator.update`` :ref:`action ` updates indicator options, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` cannot be updated at runtime. **Example:** @@ -1514,7 +1516,7 @@ A typical application would probably use an ``obj`` container widget as a tile, - **tiles** (**Required**, list): A list with (any number of) tiles to be added to meter. - *widget* (**Required**): Any kind of widget to be used as tile container. - - **tile_id** (**Required**): An ID to be used with ``lvgl.tileview.select`` action + - **tile_id** (**Required**): A tile ID to be used with ``lvgl.tileview.select`` action. - **dir** (*Optional*): Enable moving to the adjacent tiles into the given direction by swiping/dragging. One or multiple of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. - **row** (**Required**): Horrizontal position of the tile in the tileview grid. - **column** (**Required**): Vertical position of the tile in the tileview grid. From 8cab38a3b5f5249f208320fa0e6c1b110dc63584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 14:05:32 +0200 Subject: [PATCH 335/350] remove linespaces --- components/lvgl.rst | 10 ---------- cookbook/lvgl.rst | 5 ----- 2 files changed, 15 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 3c19f6925..51caf2cbd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -56,7 +56,6 @@ Some widgets integrate also as native ESPHome components: * - ``led`` - :doc:`Light ` - These are useful to make :ref:`automations ` triggered by actions performed at the screen. Main Configuration @@ -321,7 +320,6 @@ In the example below, you defined ``date_style``: radius: 4 pad_all: 2 - And then you apply these selected styles to two labels, and only change very specific stlye ``y`` locally: .. code-block:: yaml @@ -1381,7 +1379,6 @@ By default, the Line widget width and height dimensions are set to ``size_conten line_color: 0x0000FF line_rounded: true - .. _lvgl-wgt-led: ``led`` @@ -1704,7 +1701,6 @@ This :ref:`action ` redraws the entire screen, or optionally only then: - lvgl.widget.redraw: - .. _lvgl-pause-act: ``lvgl.pause`` @@ -1721,7 +1717,6 @@ This :ref:`action ` pauses the activity of LVGL, including render - lvgl.pause: show_snow: true - .. _lvgl-resume-act: ``lvgl.resume`` @@ -1759,7 +1754,6 @@ This :ref:`action ` changes page to the next following in the con animation: OUT_RIGHT time: 300ms - .. _lvgl-pgsh-act: ``lvgl.page.show`` @@ -1771,7 +1765,6 @@ This :ref:`action ` shows a specific page (even the ones with ``s - **animation** (*Optional*): The page change with one of these animations: ``NONE``, ``OVER_LEFT``, ``OVER_RIGHT``, ``OVER_TOP``, ``OVER_BOTTOM``, ``MOVE_LEFT``, ``MOVE_RIGHT``, ``MOVE_TOP``, ``MOVE_BOTTOM``, ``FADE_IN``, ``FADE_OUT``, ``OUT_LEFT``, ``OUT_RIGHT``, ``OUT_TOP``, ``OUT_BOTTOM``. Defaults to ``NONE`` if not specified. - **time** (*Optional*, :ref:`Time `): Duration of the page change animation. Defaults to ``50ms``. - .. code-block:: yaml on_...: @@ -1783,7 +1776,6 @@ This :ref:`action ` shows a specific page (even the ones with ``s then: - lvgl.page.show: secret_page # shorthand version - Conditions ---------- @@ -1809,7 +1801,6 @@ This :ref:`condition ` checks if since the last touch event, t id: display_backlight transition_length: 3s - .. _lvgl-paused-cond: ``lvgl.is_paused`` @@ -1898,7 +1889,6 @@ The ``on_idle`` :ref:`triggers ` are activated when inactivity time - light.turn_off: display_backlight - lvgl.pause: - See :ref:`lvgl-cook-idlescreen` example how to implement screen saving with idle settings. .. _lvgl-seealso: diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index d5579304e..91fc902ca 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -90,7 +90,6 @@ In case your local light implements as a different platform than GPIO, you can u on_click: light.toggle: room_light - .. _lvgl-cook-binent: Remote light button @@ -622,7 +621,6 @@ Since LVGL uses inheritance to apply styles across the widgets, it's possible to In this example we prepare a set of gradient styles in the *theme*, and make some modifications in a *style_definition* which can be applied in a batch to the desired widgets. Theme is applied automatically, and can be overridden manually with style definitions (read further to see how). - .. code-block:: yaml lvgl: @@ -937,7 +935,6 @@ In the example below we use the default set of glyphs from RobotoCondensed-Regul text_align: center text_font: roboto_icons_42 - .. tip:: Follow these steps to choose your MDI icons: @@ -947,7 +944,6 @@ In the example below we use the default set of glyphs from RobotoCondensed-Regul - To use the desired icon, prepend the copied codepoint with ``\U000``. The unicode character escape sequence has to start with capital ``\U`` and have exactly 8 hexadecimal digits. - To translate the escape sequence into the real glyph, make sure you enclose your strings in double quotes. - .. _lvgl-cook-iconstat: Toggle state icon button @@ -1505,7 +1501,6 @@ LVGL has a notion of screen inactivity, i.e. how long did the user not interact step: 5 mode: box - .. _lvgl-cook-antiburn: Prevent burn-in of LCD From 1b779bbbf7276988acf86752937a11ec9faadab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 14:30:42 +0200 Subject: [PATCH 336/350] styling infos --- components/lvgl.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 51caf2cbd..175469cd7 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -7,7 +7,6 @@ LVGL Graphics :description: LVGL - ESPHome Displays showing contents created with Light and Versatile Graphics Library :image: /images/lvgl.png - `LVGL `__ (Light and Versatile Graphics Library) is a free and open-source embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 8 `__. @@ -215,15 +214,16 @@ LVGL follows CSS's `border-box model `): The ID of a configured color, or hexadecimal representation of a RGB color for the background of the widget. - **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to make the background gradually fade to. - **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. @@ -236,6 +236,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **bg_img_opa** (*Optional*, enum or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to mix with every pixel of the image. - **bg_img_recolor_opa** (*Optional*, enum or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **border_width** (*Optional*, int16): Set the width of the border in pixels. - **border_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw borders of the widget. - **border_opa** (*Optional*, enum or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. @@ -246,13 +247,12 @@ You can adjust the appearance of widgets by changing the foreground, background - ``LEFT`` - ``RIGHT`` - ``INTERNAL`` -- **border_width** (*Optional*, int16): Set the width of the border in pixels. - **radius** (*Optional*, uint16): The radius of the rounded corners of the widget. 0 = no radius i.e. square corners; 65535 = pill shaped widget (true circle if it has same width and height). - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. +- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. - **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw an outline around the widget. - **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. -- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. - **pad_all** (*Optional*, int16): Set the padding in all directions, in pixels. - **pad_top** (*Optional*, int16): Set the padding on the top, in pixels. - **pad_bottom** (*Optional*, int16): Set the padding on the bottom, in pixels. @@ -381,7 +381,7 @@ The properties below are common to all widgets. .. note:: - By default, the ``x`` and ``y`` coordinates are measured from the *top left corner* of the parent's content area. Important: content area starts *after the padding* thus if the parent has a non-zero padding value, position will be shifted with that. Percentage values are calculated from the parent's content area size. + By default, the ``x`` and ``y`` coordinates are measured from the *top left corner* of the parent's content area. :ref:`Important `: content area starts *after the padding* thus if the parent has a non-zero padding value, position will be shifted with that. Percentage values are calculated from the parent's content area size. - **width** (*Optional*): Width of the widget in pixels or a percentage, or ``size_content`` (see note below). - **height** (*Optional*): Height of the widget in pixels or a percentage, or ``size_content`` (see note below). From 04465f03c29913ef2c2dd6e830b68fc39a222d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 14:33:21 +0200 Subject: [PATCH 337/350] Update lvgl.rst --- components/lvgl.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 175469cd7..fa41ec030 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -214,9 +214,9 @@ LVGL follows CSS's `border-box model `): The ID of a configured color, or hexadecimal representation of a RGB color to draw borders of the widget. - **border_opa** (*Optional*, enum or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. -- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be chosen): +- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be specified): - ``NONE`` - ``TOP`` - ``BOTTOM`` From 2e83370aee49a0e0fdd25575eaa1b8e5a7df85f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 14:38:24 +0200 Subject: [PATCH 338/350] Update lvgl.rst --- components/lvgl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index fa41ec030..47a3a7234 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -214,7 +214,7 @@ LVGL follows CSS's `border-box model Date: Fri, 3 May 2024 16:15:19 +0200 Subject: [PATCH 339/350] Update lvgl.rst --- components/lvgl.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 47a3a7234..ea7ec41e5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -136,8 +136,6 @@ See :ref:`lvgl-cook-navigator` in the Cookbook for an example how to easily impl .. note:: - LVGL only supports **integers** for numeric values. Visualizer widgets can't display floats directly, but they allow scaling by 10s. Some examples in the :doc:`Cookbook ` cover how to do that. - Currently ``RGB565`` type images are supported, with transparency using the optional parameter ``use_transparency`` set to ``true``. See :ref:`display-image` for how to load an image for rendering in ESPHome. .. _lvgl-color: @@ -474,6 +472,10 @@ In addition to visual stilyng, each widget supports some boolean **flags** to in - **widget_1**, **widget_2** (*Optional*, boolean): custom flags, free to use by widget. - **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): custom flags, free to use by user. +.. note:: + + LVGL only supports only **integers** for numeric ``value``. Visualizer widgets can't display floats directly, but they allow scaling by 10s. Some examples in the :doc:`Cookbook ` cover how to do that. + .. _lvgl-wgt-lbl: ``label`` From a6445196ca15ebc9244bc503dc91cf75d08ac06e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 3 May 2024 18:54:35 +0200 Subject: [PATCH 340/350] simplify color --- components/lvgl.rst | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ea7ec41e5..7784d7c85 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -85,7 +85,7 @@ The following configuration options apply to the main ``lvgl`` component, in ord - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessarry. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, defaults to ``big_endian``. -- **disp_bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a color to fill the bacground. +- **disp_bg_color** (*Optional*, :ref:`color `): Solid color to fill the bacground. - **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as backround wallpaper. - **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. @@ -143,7 +143,7 @@ See :ref:`lvgl-cook-navigator` in the Cookbook for an example how to easily impl Colors ****** -Colors can be specified anywehere in the LVGL configuartion either by referencing a preconfigured :ref:`ESPHome color `, or directly represennted in hexadecimal format. Eg. ``0xFF0000`` for red. +Colors can be specified anywehere in the LVGL configuartion either by referencing a preconfigured :ref:`ESPHome color ` ID, or by represennting directly in hexadecimal format. Eg. ``0xFF0000`` for red. .. _lvgl-fonts: @@ -222,8 +222,8 @@ You can adjust the appearance of widgets by changing the foreground, background **Styling options:** -- **bg_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color for the background of the widget. -- **bg_grad_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to make the background gradually fade to. +- **bg_color** (*Optional*, :ref:`color `): Color for the background of the widget. +- **bg_grad_color** (*Optional*, :ref:`color `): Color to make the background gradually fade to. - **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. - **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. - **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. @@ -232,10 +232,10 @@ You can adjust the appearance of widgets by changing the foreground, background - **opa** (*Optional*, enum or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **opa_layered** (*Optional*, enum or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **bg_img_opa** (*Optional*, enum or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **bg_img_recolor** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to mix with every pixel of the image. +- **bg_img_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the image. - **bg_img_recolor_opa** (*Optional*, enum or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **border_width** (*Optional*, int16): Set the width of the border in pixels. -- **border_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw borders of the widget. +- **border_color** (*Optional*, :ref:`color `): Color to draw borders of the widget. - **border_opa** (*Optional*, enum or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. - **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be specified): @@ -248,7 +248,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **radius** (*Optional*, uint16): The radius of the rounded corners of the widget. 0 = no radius i.e. square corners; 65535 = pill shaped widget (true circle if it has same width and height). - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. - **outline_width** (*Optional*, int16): Set the width of the outline in pixels. -- **outline_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to draw an outline around the widget. +- **outline_color** (*Optional*, :ref:`color `): Color to draw an outline around the widget. - **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. - **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. - **pad_all** (*Optional*, int16): Set the padding in all directions, in pixels. @@ -258,7 +258,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. - **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. - **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. -- **shadow_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to create a drop shadow under the widget. +- **shadow_color** (*Optional*, :ref:`color `): Color to create a drop shadow under the widget. - **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels - **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels - **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. @@ -490,7 +490,7 @@ A label is the basic widget type that is used to display text. - **text** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO``. -- **text_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to render the text in. +- **text_color** (*Optional*, :ref:`color `): Color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be specified). - **text_font**: (*Optional*, :ref:`font `): The ID or the ID of the font used to render the text or symbol. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. @@ -1018,7 +1018,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. - **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to use to draw the arcs. +- **arc_color** (*Optional*, :ref:`color `): Color used to draw the arc. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - **knob** (*Optional*, list): Settings for the knob *part* to control the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws a handle on the end of the indicator using all background properties and padding values. With zero padding the knob size is the same as the indicator's width. Larger padding makes it larger, smaller padding makes it smaller. @@ -1172,12 +1172,12 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **count** (**Required**): How many ticks to be on the scale. Defaults to ``12``. - **width** (*Optional*): Tick line width in pixels. Required if ``count`` is greater than ``0``. Defaults to ``2``. - **length** (*Optional*): Tick line length in pixels. Required if ``count`` is greater than ``0``. Defaults to ``10``. - - **color** (*Optional*): ID or hex code for the ticks :ref:`color `. Required if ``count`` is greater than ``0``. Defaults to ``0x808080``. + - **color** (*Optional*, :ref:`color `): Color to draw the ticks. Required if ``count`` is greater than ``0``. Defaults to ``0x808080``. - **major** (*Optional*, list): If you want major ticks and value labels displayed: - **stride**: How many minor ticks to skip when adding major ticks. Defaults to ``3``. - **width**: Tick line width in pixels. Defaults to ``5``. - **length**: Tick line length in pixels or percentage. Defaults to ``15%``. - - **color**: ID or hex code for the ticks :ref:`color `. Defaults to ``0``. + - **color**: :ref:`Color ` to draw the major ticks. Defaults to ``0`` (black). - **label_gap**: Label distance from the ticks with text proportionally to the values of the tick line. Defaults to ``4``. - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-wgt-lin` and :ref:`lvgl-wgt-lbl` text style properties. - **indicators** (**Required**, list): A list with indicators to be added to the scale. Multiple of each can be added. Their values are interpreted in the range of the scale: @@ -1185,20 +1185,20 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **start_value**: The value in the scale range to start drawing the arc from. - **end_value**: The value in the scale range to end drawing the arc to. - **width**: Arc width in pixels. Defaults to ``4``. - - **color**: ID or hex code for the arc :ref:`color `. Defaults to ``0``. + - **color**: :ref:`Color ` to draw the arc. Defaults to ``0`` (black). - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). Defaults to ``0``. - Style options for the *arc* using the :ref:`lvgl-wgt-arc` style properties. - **tick_style** (**Optional**): Add tick style modifications: - **start_value**: The value in the scale range to modify the ticks from. - **end_value**: The value in the scale range to modify the ticks to. - - **color_start**: ID or hex code for the gradient start :ref:`color ` of the ticks. - - **color_end**: ID or hex code for the gradient end :ref:`color ` of the ticks. + - **color_start**: :ref:`Color ` for the gradient start of the ticks. + - **color_end**: :ref:`Color ` for the gradient end of the ticks. - **local**: If ``true`` the ticks' color will be faded from ``color_start`` to ``color_end`` in the start and end values specified above. If ``false``, ``color_start`` and ``color_end`` will be mapped to the entire scale range (and only a *slice* of that color gradient will be visible in the indicator's start and end value range). Defaults to ``false``. - **width**: Modifies the ``width`` of the tick lines. - **line** (*Optional*): Add a needle line to the scale. By default, the length of the line is the same as the scale's radius: - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **width**: Needle line width in pixels. Defaults to ``4``. - - **color**: ID or hex code for the needle line :ref:`color `. Defaults to ``0``. + - **color**: :ref:`Color ` for the needle line. Defaults to ``0`` (black). - **r_mod**: Adjust the length of the needle from the scale radius with this amount (can be negative). Defaults to ``0``. - **value**: The value in the scale range to show at start. - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. @@ -1360,7 +1360,7 @@ The Line widget is capable of drawing straight lines between a set of points. - **line_dash_width** (*Optional*, int16): Set the width of the dashes in the line (in pixels). - **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). - **line_rounded** (*Optional*, boolean): Make the end points of the line rounded. ``true`` rounded, ``false`` perpendicular line ending. -- **line_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color for the line. +- **line_color** (*Optional*, :ref:`color `): Color for the line. - Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. By default, the Line widget width and height dimensions are set to ``size_content``. This means it will automatically set its size to fit all the points. If the size is set explicitly, parts of the line may not be visible. @@ -1393,7 +1393,7 @@ The Led widgets are rectangle-like (or circle) widget whose brightness can be ad **Specific options:** -- **color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color for the background, border, and shadow of the widget. +- **color** (*Optional*, :ref:`color `): Color for the background, border, and shadow of the widget. - **brightness** (*Optional*, percentage): The brightness of the LED color, where ``0%`` corresponds to black, and ``100%`` corresponds to the full brightness of the color specified above. - Style options from :ref:`lvgl-styling`, using all the typical background style properties. @@ -1442,7 +1442,7 @@ The Spinner widget is a spinning arc over a ring. - **spin_time** (**Required**, :ref:`Time `): Duration of one cycle of the spin. - **arc_length** (**Required**, 0-360): Length of the spinning arc in degrees. - **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **arc_color** (*Optional*, :ref:`color `): The ID of a configured color, or hexadecimal representation of a RGB color to use to draw the arcs. +- **arc_color** (*Optional*, :ref:`color `): Color to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. - **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. Draws *another arc using the arc style* properties. Its padding values are interpreted relative to the background arc. From b0d4b620aa3f776d1f516e88bda3d4cf8f5633f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 6 May 2024 09:21:37 +0200 Subject: [PATCH 341/350] font reorg --- components/lvgl.rst | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7784d7c85..9eb2434d3 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -150,16 +150,22 @@ Colors can be specified anywehere in the LVGL configuartion either by referencin Fonts ***** -In ESPHome LVGL offers two font choices: the internal fonts offered by the library or :ref:`fonts configured in the normal way`. +There are two font choices for LVGL here: -**Internal fonts** +**ESPHome fonts** -The library offers by default the ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and 60 symbols from the `FontAwesome `__ font (see below). Use one of the IDs below when specifying the ``text_font`` parameter: +You can use :ref:`fonts configured normally`, the glyphs will be rendered while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters of your choice, for any language, from any TrueType/OpenType font, allowing a more optimal flash space usage because you don't need to include all glyphs for all sizes you wish to use. + +Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples how to play with texts and icons using various TrueType/OpenType fonts. + +**Library fonts** + +The LVGL library offers by default pre-rendered sets with ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and 60 symbols from the `FontAwesome `__ font (see below). You can use the IDs below when specifying the ``text_font`` parameter: - ``montserrat_8``: 8px font - ``montserrat_10``: 10px font - ``montserrat_12``: 12px font -- ``montserrat_14``: 14px font (**default**) +- ``montserrat_14``: 14px font (**default**, included if ``default_font`` option is missing) - ``montserrat_16``: 16px font - ``montserrat_18``: 18px font - ``montserrat_20``: 20px font @@ -178,6 +184,8 @@ The library offers by default the ASCII characters (``0x20-0x7F``) the degree s - ``montserrat_46``: 46px font - ``montserrat_48``: 48px font +The binary will only include any of the above if used in the configuration. + You can display the embedded symbols among the text by their codepoint address preceeded by ``\u``, eg. ``\uF00C``: .. figure:: /components/images/lvgl_symbols.png @@ -196,12 +204,6 @@ In addition to the above, the following special fonts are available from LVGL as - ``simsun_16_cjk``: 16 px font with normal range + 1000 most common `CJK Radicals `__. - ``dejavu_16_persian_hebrew``: 16 px font with normal range + Hebrew, Arabic, Persian letters and all their forms. -**ESPHome fonts** - -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. This has the advantage that you can define custom sets of glyphs of any size, with icons or diacritic characters of your choice, for any language, from any TrueType/OpenType font, using less flash space because you don't need to include all glyphs for all sizes you wish to use. - -Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples how to play with texts and icons using various TrueType/OpenType fonts. - .. _lvgl-styling: Style properties @@ -488,11 +490,11 @@ A label is the basic widget type that is used to display text. **Specific options:** -- **text** (**Required**, string): The text or built-in :ref:`symbol ` to display. To display an empty label, specify ``""``. +- **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display. To display an empty label, specify ``""``. - **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO``. - **text_color** (*Optional*, :ref:`color `): Color to render the text in. - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be specified). -- **text_font**: (*Optional*, :ref:`font `): The ID or the ID of the font used to render the text or symbol. +- **text_font**: (*Optional*, :ref:`font `): The ID of the font used to render the text or symbol. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. - **text_line_space** (*Optional*, int16): Line spacing of the text. - **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. @@ -611,7 +613,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **rows** (**Required**, list): A list for the button rows: - **buttons** (**Required**, list): A list of buttons in a row: - **id** (*Optional*): An ID for the button in the matrix. - - **text** (*Optional*): Text or built-in :ref:`symbol ` to display on the button. + - **text** (*Optional*): Text (or built-in :ref:`symbol ` codepoint) to display on the button. - **key_code** (*Optional*, string): One character be sent as the key code to a :ref:`key_collector` instead of ``text`` when the button is pressed. - **width** (*Optional*): Width relative to the other buttons in the same row. A value between ``1`` and ``15`` range, default ``1`` (eg. in a line with two buttons: one ``width: 1`` and another one ``width: 2``, the first will be ``33%`` wide while the second will be ``66%`` wide). - **selected** (*Optional*, boolean): Set the button as the most recently released or focused. Defaults to ``false``. @@ -1594,7 +1596,7 @@ The text will be broken into multiple lines automatically and the height will be - **text** (**Required**, string): The string to be displayed in the body of the message box. Can be shorthanded if no further options are specified. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. - **buttons** (**Required**, enum): A list of buttons to show at the bottom of the message box: - - **text** (**Required**, string): The text or built-in :ref:`symbol ` to display on the button. + - **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display on the button. **Specific actions:** From b5774ac4f6381fba6e83b03787b519d9b2a60e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 6 May 2024 10:33:37 +0200 Subject: [PATCH 342/350] layout added and opacities simplified --- components/lvgl.rst | 100 +++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 28 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9eb2434d3..196b54820 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -93,26 +93,19 @@ The following configuration options apply to the main ``lvgl`` component, in ord - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. Not possible if you configure ``pages``. - **pages** (*Optional*, list): A list of page IDs, where each page acts as a parent for widgets placed on it. Only if no ``widgets`` are configured at this level! Options for each page: - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. - - **layout** (*Optional*, string): Layout to be applied to this page. Same option as above. - - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. + - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. + - **flex_flow** (*Optional*, string): See :ref:`flex layout ` options. - All other options from :ref:`lvgl-styling` to be applied to this page. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. - **page_wrap** (*Optional*, boolean): Wrap pages around when navigating between them with :ref:`lvgl-pgnx-act`. Defaults to ``true`` if not specified. - **top_layer** (*Optional*, list): A special kind of *Always on Top* page, which acts as a parent for widgets placed on it. It's shown above all the pages - useful for widgets which need to be always visible, regardless of the pages. Only of no ``widgets`` are configured at this level. Options: - - **layout** (*Optional*, string): Layout to be applied to this page. Same option as above. - - **flex_flow** (*Optional*, string): Same option as above, for the ``FLEX`` layout on this page. + - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. + - **flex_flow** (*Optional*, string): See :ref:`flex layout ` options. - All other options from :ref:`lvgl-styling` to be applied to this page. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. -- **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. LVGL supports two styles of layouts, ``FLEX`` and ``GRID``. ``FLEX`` can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item fill the remaining space with respect to min/max width and height. ``GRID`` can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. With these layouts the widgets can be placed automatically, and there's no need to specify the ``x`` and the ``y`` positional coordinates for each. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. -- **flex_flow** (*Optional*, string): In case of ``FLEX`` layout, choose one of the following options. Defaults to ``ROW_WRAP``: - - ``ROW`` to place the children in a row without wrapping - - ``COLUMN`` to place the children in a column without wrapping - - ``ROW_WRAP`` to place the children in a row with wrapping - - ``COLUMN_WRAP`` to place the children in a column with wrapping - - ``ROW_REVERSE`` to place the children in a row without wrapping but in reversed order - - ``COLUMN_REVERSE`` to place the children in a column without wrapping but in reversed order - - ``ROW_WRAP_REVERSE`` to place the children in a row with wrapping but in reversed order - - ``COLUMN_WRAP_REVERSE`` to place the children in a column with wrapping but in reversed order +- **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. +- **flex_flow** (*Optional*, string): See :ref:`flex layout ` options. + - All other options from :ref:`lvgl-styling` to be commonly apply to the widgets directly. **Example:** @@ -145,6 +138,13 @@ Colors Colors can be specified anywehere in the LVGL configuartion either by referencing a preconfigured :ref:`ESPHome color ` ID, or by represennting directly in hexadecimal format. Eg. ``0xFF0000`` for red. +.. _lvgl-opa: + +Opacity +******* + +Various parts of the widgets (like bacground, borders etc.) support opacity. It can be overridden with a string: ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. Actual default values depend on widgget specifics. + .. _lvgl-fonts: Fonts @@ -230,15 +230,15 @@ You can adjust the appearance of widgets by changing the foreground, background - **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. - **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. - **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. -- **bg_opa** (*Optional*, enum or percentage): Opacity of the background. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **opa** (*Optional*, enum or percentage): Opacity of the entire widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **opa_layered** (*Optional*, enum or percentage): Opacity of the entire layer the widget is on. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. -- **bg_img_opa** (*Optional*, enum or percentage): Opacity of the background image of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **bg_opa** (*Optional*, :ref:`opacity `): Opacity of the widget background. +- **opa** (*Optional*, :ref:`opacity `): Opacity of the entire widget. +- **opa_layered** (*Optional*, :ref:`opacity `): Opacity of the entire layer the widget is on. +- **bg_img_opa** (*Optional*, :ref:`opacity `): Opacity of the background image (if such option is supported) of the widget. - **bg_img_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the image. -- **bg_img_recolor_opa** (*Optional*, enum or percentage): Opacity of the recoloring. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **bg_img_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring. - **border_width** (*Optional*, int16): Set the width of the border in pixels. - **border_color** (*Optional*, :ref:`color `): Color to draw borders of the widget. -- **border_opa** (*Optional*, enum or percentage): Opacity of the borders of the widget. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **border_opa** (*Optional*, :ref:`opacity `): Opacity of the borders of the widget. - **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. - **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be specified): - ``NONE`` @@ -251,7 +251,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. - **outline_width** (*Optional*, int16): Set the width of the outline in pixels. - **outline_color** (*Optional*, :ref:`color `): Color to draw an outline around the widget. -- **outline_opa** (*Optional*, string or percentage): Opacity of the outline. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **outline_opa** (*Optional*, :ref:`opacity `): Opacity of the outline of the widget. - **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. - **pad_all** (*Optional*, int16): Set the padding in all directions, in pixels. - **pad_top** (*Optional*, int16): Set the padding on the top, in pixels. @@ -263,7 +263,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **shadow_color** (*Optional*, :ref:`color `): Color to create a drop shadow under the widget. - **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels - **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels -- **shadow_opa** (*Optional*, string or percentage): Opacity of the shadow. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **shadow_opa** (*Optional*, :ref:`opacity `): Opacity of the shadow. - **shadow_spread** (*Optional*, int16): Spread of the shadow, in pixels. - **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. - **transform_angle** (*Optional*, 0-360): Trannsformation angle of the widget (eg. rotation) @@ -360,6 +360,50 @@ Feel free to experiment to discover inheritance of the styles based on states be :ref:`lvgl-cook-theme` in the Cookbook shows an example how to easily implement a gradient style for your widgets. +.. _lvgl-layouts: + +Layouts +******* + +Layouts help positioning the widgets automatically, without the need to manually specify the ``x`` and the ``y`` positional coordinates for each. This is a great way to simplify the configuration, allowing you to even omit alignment options. + +The layout configuration options are applied to any parent widget or page, which influence the appearance of the children. + +.. _lvgl-layouts-flex: + +**Flex** + +The Flex layout in LVGL is a subset implementation of `CSS Flexbox `__. + +It can arrange items into rows or columns (tracks), handle wrapping, adjust the spacing between the items and tracks, handle grow to make the item(s) fill the remaining space with respect to min/max width and height. + +Terms used: + +- *tracks*: the rows or columns main direction: row or column, the direction in which the items are placed. +- *cross direction*: perpendicular to the main direction +- *wrap*: if there is no more space in the track a new track is started +- *grow*: if set on an item it will grow to fill the remaining space on the track. The available space will be distributed among items respective to their grow value (larger value means more space) +- *gap*: the space between the rows and columns or the items on a track + +In a Flex layout, use the following options in the ``flex_flow`` configuartion parameter to select the arrangement of the children widgets: + +- ``ROW``: place the children in a row without wrapping. +- ``COLUMN``: place the children in a column without wrapping. +- ``ROW_WRAP``: place the children in a row with wrapping (default). +- ``COLUMN_WRAP``: place the children in a column with wrapping. +- ``ROW_REVERSE``: place the children in a row without wrapping but in reversed order. +- ``COLUMN_REVERSE``: place the children in a column without wrapping but in reversed order. +- ``ROW_WRAP_REVERSE``: place the children in a row with wrapping but in reversed order. +- ``COLUMN_WRAP_REVERSE``: place the children in a column with wrapping but in reversed order. + +.. _lvgl-layouts-grid: + +**Grid** + +The Grid layout in LVGL is a subset implementation of `CSS Flexbox `__. + +It can arrange items into a 2D "table" that has rows or columns (tracks). The item can span through multiple columns or rows. The track's size can be set in pixel, to the largest item or in "Free unit" to distribute the free space proportionally. + .. _lvgl-widgets: Widgets @@ -412,8 +456,8 @@ The properties below are common to all widgets. - **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused widget which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. - **styles** (*Optional*, :ref:`config-id`): The ID of a *style definition* from the main component configuration to override the theme styles. - **theme** (*Optional*, list): A list of styles to apply to the widget and children. Same configuration option as at the main component. -- **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Same configuration option as at the main component. -- **flex_flow** (*Optional*, string): Option for ``FLEX`` layout, similar configuration as at the main component. +- **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. +- **flex_flow** (*Optional*, string): See :ref:`flex layout ` options. - **widgets** (*Optional*, list): A list of LVGL widgets to be drawn as children of this widget. Same configuration option as at the main component. .. _lvgl-wgtprop-state: @@ -467,7 +511,7 @@ In addition to visual stilyng, each widget supports some boolean **flags** to in - **event_bubble** (*Optional*, boolean): propagate the events to the parent too. - **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent. - **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. E.g. Accounting for rounded corners. -- **ignore_layout** (*Optional*, boolean): make the widget positionable by the layouts. +- **ignore_layout** (*Optional*, boolean): do not make the widget positionable by the layouts. - **floating** (*Optional*, boolean): do not scroll the widget when the parent scrolls and ignore layout. - **overflow_visible** (*Optional*, boolean): do not clip the children's content to the parent's boundary. - **layout_1**, **layout_2** (*Optional*, boolean): custom flags, free to use by layouts. @@ -497,7 +541,7 @@ A label is the basic widget type that is used to display text. - **text_font**: (*Optional*, :ref:`font `): The ID of the font used to render the text or symbol. - **text_letter_space** (*Optional*, int16): Characher spacing of the text. - **text_line_space** (*Optional*, int16): Line spacing of the text. -- **text_opa** (*Optional*, string or percentage): Opacity of the text. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **text_opa** (*Optional*, :ref:`opacity `): Opacity of the text. - **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped (Default). @@ -1019,7 +1063,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator - **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. - **mode** (*Optional*, string): ``NORMAL``: the indicator is drawn from the minimum value to the current. ``REVERSE``: the indicator is drawn counter-clockwise from the maximum value to the current. ``SYMMETRICAL``: the indicator is drawn from the middle point to the current value. Defaults to ``NORMAL``. - **change_rate** (*Optional*, int8): If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is defined in degree/second. Defaults to ``720``. -- **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **arc_opa** (*Optional*, :ref:`opacity `): Opacity of the arc. - **arc_color** (*Optional*, :ref:`color `): Color used to draw the arc. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. @@ -1443,7 +1487,7 @@ The Spinner widget is a spinning arc over a ring. - **spin_time** (**Required**, :ref:`Time `): Duration of one cycle of the spin. - **arc_length** (**Required**, 0-360): Length of the spinning arc in degrees. -- **arc_opa** (*Optional*, enum or percentage): Opacity of the arcs. ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. +- **arc_opa** (*Optional*, :ref:`opacity `): Opacity of the arc. - **arc_color** (*Optional*, :ref:`color `): Color to draw the arcs. - **arc_rounded** (*Optional*, boolean): Make the end points of the arcs rounded. ``true`` rounded, ``false`` perpendicular line ending. - **arc_width** (*Optional*, int16): Set the width of the arcs in pixels. From bdbceb1729d84f4d825f2b6c0abc0edf467c37f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 6 May 2024 10:59:57 +0200 Subject: [PATCH 343/350] Update lvgl_boxmodel.png --- components/images/lvgl_boxmodel.png | Bin 9038 -> 9051 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_boxmodel.png b/components/images/lvgl_boxmodel.png index 1331b1e91e2f09205820ca8a184c387f707a3fe2..98251f41698f40b98077c1fdb5907c6e0a83eb10 100644 GIT binary patch literal 9051 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 AumAu6 literal 9038 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 Date: Mon, 6 May 2024 11:15:01 +0200 Subject: [PATCH 344/350] Update lvgl.rst --- components/lvgl.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 196b54820..ce0129452 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -88,7 +88,7 @@ The following configuration options apply to the main ``lvgl`` component, in ord - **disp_bg_color** (*Optional*, :ref:`color `): Solid color to fill the bacground. - **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as backround wallpaper. - **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. -- **style_definitions** (*Optional*, list): A batch of style definitions to use with selected LVGL widgets. See :ref:`below ` for more details. +- **style_definitions** (*Optional*, list): A batch of style definitions to use in LVGL widgets ``styles`` configuration. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. Not possible if you configure ``pages``. - **pages** (*Optional*, list): A list of page IDs, where each page acts as a parent for widgets placed on it. Only if no ``widgets`` are configured at this level! Options for each page: @@ -143,7 +143,7 @@ Colors can be specified anywehere in the LVGL configuartion either by referencin Opacity ******* -Various parts of the widgets (like bacground, borders etc.) support opacity. It can be overridden with a string: ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or an integer between ``0%`` and ``100%`` for percentage. Actual default values depend on widgget specifics. +Various parts of the widgets (like bacground, borders etc.) support opacity. It can be overridden with a string: ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or percentage between ``0%`` and ``100%``. Actual default values depend on widgget specifics. .. _lvgl-fonts: @@ -230,11 +230,11 @@ You can adjust the appearance of widgets by changing the foreground, background - **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. - **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. - **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. -- **bg_opa** (*Optional*, :ref:`opacity `): Opacity of the widget background. - **opa** (*Optional*, :ref:`opacity `): Opacity of the entire widget. +- **bg_opa** (*Optional*, :ref:`opacity `): Opacity of the widget background. - **opa_layered** (*Optional*, :ref:`opacity `): Opacity of the entire layer the widget is on. - **bg_img_opa** (*Optional*, :ref:`opacity `): Opacity of the background image (if such option is supported) of the widget. -- **bg_img_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the image. +- **bg_img_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the background image (if such option is supported) of the widget - **bg_img_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring. - **border_width** (*Optional*, int16): Set the width of the border in pixels. - **border_color** (*Optional*, :ref:`color `): Color to draw borders of the widget. From af135e36a091576ab0f9a9d039dd37bc17205fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 6 May 2024 11:53:25 +0200 Subject: [PATCH 345/350] some defaults and inheritants --- components/lvgl.rst | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ce0129452..b813aea90 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -224,23 +224,23 @@ You can adjust the appearance of widgets by changing the foreground, background **Styling options:** -- **bg_color** (*Optional*, :ref:`color `): Color for the background of the widget. -- **bg_grad_color** (*Optional*, :ref:`color `): Color to make the background gradually fade to. -- **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. -- **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. +- **bg_color** (*Optional*, :ref:`color `): Color for the background of the widget. Defaults to ``0xFFFFFF`` (white). +- **bg_grad_color** (*Optional*, :ref:`color `): Color to make the background gradually fade to. Defaults to ``0`` (black). +- **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. Defaults to ``NONE``. +- **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. Defaults to ``NONE``. - **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. - **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. -- **opa** (*Optional*, :ref:`opacity `): Opacity of the entire widget. +- **opa** (*Optional*, :ref:`opacity `): Opacity of the entire widget. Inherited from parent. Defaults to ``COVER``. - **bg_opa** (*Optional*, :ref:`opacity `): Opacity of the widget background. -- **opa_layered** (*Optional*, :ref:`opacity `): Opacity of the entire layer the widget is on. +- **opa_layered** (*Optional*, :ref:`opacity `): Opacity of the entire layer the widget is on. Inherited from parent. Defaults to ``COVER``. - **bg_img_opa** (*Optional*, :ref:`opacity `): Opacity of the background image (if such option is supported) of the widget. -- **bg_img_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the background image (if such option is supported) of the widget +- **bg_img_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the background image (if such option is supported) of the widget. - **bg_img_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring. -- **border_width** (*Optional*, int16): Set the width of the border in pixels. -- **border_color** (*Optional*, :ref:`color `): Color to draw borders of the widget. -- **border_opa** (*Optional*, :ref:`opacity `): Opacity of the borders of the widget. -- **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. -- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be specified): +- **border_width** (*Optional*, int16): Set the width of the border in pixels. Defaults to ``0``. +- **border_color** (*Optional*, :ref:`color `): Color to draw borders of the widget. Defaults to ``0`` (black). +- **border_opa** (*Optional*, :ref:`opacity `): Opacity of the borders of the widget. Defaults to ``COVER``. +- **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. Defaults to ``false`` +- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be specified, defaults to ``NONE``): - ``NONE`` - ``TOP`` - ``BOTTOM`` @@ -249,10 +249,10 @@ You can adjust the appearance of widgets by changing the foreground, background - ``INTERNAL`` - **radius** (*Optional*, uint16): The radius of the rounded corners of the widget. 0 = no radius i.e. square corners; 65535 = pill shaped widget (true circle if it has same width and height). - **clip_corner** (*Optional*, boolean): Enable to clip off the overflowed content on the rounded (``radius`` > ``0``) corners of a widget. -- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. -- **outline_color** (*Optional*, :ref:`color `): Color to draw an outline around the widget. -- **outline_opa** (*Optional*, :ref:`opacity `): Opacity of the outline of the widget. -- **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. +- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. Defaults to ``0``. +- **outline_color** (*Optional*, :ref:`color `): Color to draw an outline around the widget. Defaults to ``0`` (black). +- **outline_opa** (*Optional*, :ref:`opacity `): Opacity of the outline of the widget. Defaults to ``COVER``. +- **outline_pad** (*Optional*, int16): Distance between the outline and the widget itself. Defaults to ``0``. - **pad_all** (*Optional*, int16): Set the padding in all directions, in pixels. - **pad_top** (*Optional*, int16): Set the padding on the top, in pixels. - **pad_bottom** (*Optional*, int16): Set the padding on the bottom, in pixels. @@ -260,12 +260,12 @@ You can adjust the appearance of widgets by changing the foreground, background - **pad_right** (*Optional*, int16): Set the padding on the right, in pixels. - **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. - **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. -- **shadow_color** (*Optional*, :ref:`color `): Color to create a drop shadow under the widget. -- **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels -- **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels -- **shadow_opa** (*Optional*, :ref:`opacity `): Opacity of the shadow. -- **shadow_spread** (*Optional*, int16): Spread of the shadow, in pixels. -- **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. +- **shadow_color** (*Optional*, :ref:`color `): Color to create a drop shadow under the widget. Defaults to ``0`` (black). +- **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels. Defaults to ``0``. +- **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels. Defaults to ``0``. +- **shadow_opa** (*Optional*, :ref:`opacity `): Opacity of the shadow. Defaults to ``COVER``. +- **shadow_spread** (*Optional*, int16): Spread of the shadow, in pixels. Defaults to ``0``. +- **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. Defaults to ``0``. - **transform_angle** (*Optional*, 0-360): Trannsformation angle of the widget (eg. rotation) - **transform_height** (*Optional*, int16 or percentage): Trannsformation height of the widget (eg. stretching) - **transform_pivot_x** (*Optional*, int16 or percentage): Horizontal anchor point of the transformation. Relative to the widget's top left corner. @@ -535,13 +535,13 @@ A label is the basic widget type that is used to display text. **Specific options:** - **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display. To display an empty label, specify ``""``. -- **text_align** (*Optional*, enum): Alignment of the text in the widget. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO``. -- **text_color** (*Optional*, :ref:`color `): Color to render the text in. -- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be specified). -- **text_font**: (*Optional*, :ref:`font `): The ID of the font used to render the text or symbol. -- **text_letter_space** (*Optional*, int16): Characher spacing of the text. -- **text_line_space** (*Optional*, int16): Line spacing of the text. -- **text_opa** (*Optional*, :ref:`opacity `): Opacity of the text. +- **text_align** (*Optional*, enum): Alignment of the text in the widget - it doesn't align the object itself, only the lines inside the object. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO``. Inherited from parent. Defaults to ``AUTO``, which detects the text base direction and uses left or right alignment accordingly. +- **text_color** (*Optional*, :ref:`color `): Color to render the text in. Inherited from parent. Defaults to ``0`` (black). +- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be specified). Inherited from parent. Defaults to ``NONE`` +- **text_font**: (*Optional*, :ref:`font `): The ID of the font used to render the text or symbol. Inherited from parent. +- **text_letter_space** (*Optional*, int16): Extra characher spacing of the text. Inherited from parent. Defaults to ``0``. +- **text_line_space** (*Optional*, int16): Line spacing of the text. Inherited from parent. Defaults to ``0`` +- **text_opa** (*Optional*, :ref:`opacity `): Opacity of the text. Inherited from parent. Defaults to ``COVER``. - **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped (Default). From 660f3e4ce8e23d0cea7390ab277319deeaaa6a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 6 May 2024 13:08:41 +0200 Subject: [PATCH 346/350] Update lvgl.rst --- components/lvgl.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b813aea90..c45cbc2b8 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -367,7 +367,7 @@ Layouts Layouts help positioning the widgets automatically, without the need to manually specify the ``x`` and the ``y`` positional coordinates for each. This is a great way to simplify the configuration, allowing you to even omit alignment options. -The layout configuration options are applied to any parent widget or page, which influence the appearance of the children. +The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. .. _lvgl-layouts-flex: @@ -380,10 +380,10 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust the Terms used: - *tracks*: the rows or columns main direction: row or column, the direction in which the items are placed. -- *cross direction*: perpendicular to the main direction -- *wrap*: if there is no more space in the track a new track is started -- *grow*: if set on an item it will grow to fill the remaining space on the track. The available space will be distributed among items respective to their grow value (larger value means more space) -- *gap*: the space between the rows and columns or the items on a track +- *cross direction*: perpendicular to the main direction. +- *wrap*: if there is no more space in the track a new track is started. +- *grow*: if set on an item it will grow to fill the remaining space on the track. The available space will be distributed among items respective to their grow value (larger value means more space). +- *gap*: the space between the rows and columns or the items on a track. In a Flex layout, use the following options in the ``flex_flow`` configuartion parameter to select the arrangement of the children widgets: From 681c6426a1920fbfaf3c12c057deeb2af71fbe79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 7 May 2024 09:25:24 +0200 Subject: [PATCH 347/350] fix an astonishing amount of spell errors --- components/lvgl.rst | 109 ++++++++++++++++++------------------- components/number/lvgl.rst | 2 +- cookbook/lvgl.rst | 54 +++++++++--------- 3 files changed, 81 insertions(+), 84 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c45cbc2b8..002d789fd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -16,14 +16,14 @@ In order to be able to drive a :ref:`display ` with LVGL under ESPHo The display itself has to be a graphical binary type, should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should also have an :ref:`config-id` set, which will be referenced in the main LGVL component configuration. -For interactivity, a :ref:`Touchscreen ` (capacitive highly prefered) or a :doc:`/components/sensor/rotary_encoder` can be used. +For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred) or a :doc:`/components/sensor/rotary_encoder` can be used. Check out a few detailed examples :ref:`in the Cookbook ` to see a couple ways to integrate LVGL through ESPHome with your environment. Basics ------ -In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` for a list of the available ones in ESPHome. Not all LVGL widgets are implemented, just the ones having most common usecases in home automation. +In LVGL, graphical elements like Buttons, Labels, Sliders etc. are called widgets or objects. See :ref:`lvgl-widgets` for a list of the available ones in ESPHome. Not all LVGL widgets are implemented, just the ones having most common use cases in home automation. Every widget has a parent object where it is created. For example, if a label is created on a button, the button is the parent of label. Some more complex widgets are internally made up from the simpler ones, these are known as parts - which can have separate properties from the main widget. @@ -71,22 +71,22 @@ The following configuration options apply to the main ``lvgl`` component, in ord - **displays** (**Required**, list): A list of displays where to render this entire LVGL configuration: - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. - **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. Can be omitted if there's at least a rotary encoder configured. - - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a dsisplay. + - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a display. - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen above, delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the touchscreen above, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. - **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. Can be omitted if there's at least a touchscreen configured. - **sensor:** (**Required**, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets. - **binary_sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, usually used as a push button within the rotary encoder used to interact with the widgets. - - **group** (*Optional*, string): A name for a group of widgets whics will interact with the the rotary encoder. See the :ref:`common properties ` of the widgets for more information on groups. + - **group** (*Optional*, string): A name for a group of widgets which will interact with the the rotary encoder. See the :ref:`common properties ` of the widgets for more information on groups. - **long_press_time** (*Optional*, :ref:`Time `): For the encoder above, delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the encoder above, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. - **color_depth** (*Optional*, enum): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. -- **buffer_size** (*Optional*, percentage): The percentage of scren size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. -- **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessarry. Defaults to ``1s``. +- **buffer_size** (*Optional*, percentage): The percentage of screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM recommended value is ``25%``. +- **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessary. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, defaults to ``big_endian``. -- **disp_bg_color** (*Optional*, :ref:`color `): Solid color to fill the bacground. -- **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as backround wallpaper. +- **disp_bg_color** (*Optional*, :ref:`color `): Solid color to fill the background. +- **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as background wallpaper. - **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use in LVGL widgets ``styles`` configuration. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. @@ -136,14 +136,14 @@ See :ref:`lvgl-cook-navigator` in the Cookbook for an example how to easily impl Colors ****** -Colors can be specified anywehere in the LVGL configuartion either by referencing a preconfigured :ref:`ESPHome color ` ID, or by represennting directly in hexadecimal format. Eg. ``0xFF0000`` for red. +Colors can be specified anywhere in the LVGL configuration either by referencing a preconfigured :ref:`ESPHome color ` ID, or by representing directly in hexadecimal format. Eg. ``0xFF0000`` for red. .. _lvgl-opa: Opacity ******* -Various parts of the widgets (like bacground, borders etc.) support opacity. It can be overridden with a string: ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or percentage between ``0%`` and ``100%``. Actual default values depend on widgget specifics. +Various parts of the widgets (like background, borders etc.) support opacity. It can be overridden with a string: ``TRANSP`` for fully transparent, ``COVER`` for fully opaque, or percentage between ``0%`` and ``100%``. Actual default values depend on widget specifics. .. _lvgl-fonts: @@ -160,7 +160,7 @@ Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-co **Library fonts** -The LVGL library offers by default pre-rendered sets with ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and 60 symbols from the `FontAwesome `__ font (see below). You can use the IDs below when specifying the ``text_font`` parameter: +The LVGL library offers by default prerendered sets with ASCII characters (``0x20-0x7F``) the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from the `Montserrat `__ Medium font, and 60 symbols from the `FontAwesome `__ font (see below). You can use the IDs below when specifying the ``text_font`` parameter: - ``montserrat_8``: 8px font - ``montserrat_10``: 10px font @@ -186,14 +186,14 @@ The LVGL library offers by default pre-rendered sets with ASCII characters (``0x The binary will only include any of the above if used in the configuration. -You can display the embedded symbols among the text by their codepoint address preceeded by ``\u``, eg. ``\uF00C``: +You can display the embedded symbols among the text by their codepoint address preceded by ``\u``, eg. ``\uF00C``: .. figure:: /components/images/lvgl_symbols.png :align: center .. note:: - The ``text_font`` parameter affects the size of symbols, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. If you set ``text_font`` on a widget to a custom ESPHome font, these symbols will likely not display, unles you include them manually from a FontAwesome OpenType file. + The ``text_font`` parameter affects the size of symbols, since all the built-in font arrays based on Montserrat include these symbols at the respective sizes. If you set ``text_font`` on a widget to a custom ESPHome font, these symbols will likely not display, unless you include them manually from a FontAwesome OpenType file. For escape sequences to work, you have to put them in strings enclosed in double quotes. @@ -214,7 +214,7 @@ LVGL follows CSS's `border-box model `): Color for the background of the widget. Defaults to ``0xFFFFFF`` (white). - **bg_grad_color** (*Optional*, :ref:`color `): Color to make the background gradually fade to. Defaults to ``0`` (black). -- **bg_dither_mode** (*Optional*, enum): Set ditherhing of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. Defaults to ``NONE``. +- **bg_dither_mode** (*Optional*, enum): Set dithering of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. Defaults to ``NONE``. - **bg_grad_dir** (*Optional*, enum): Choose the direction of the background gradient: ``NONE``, ``HOR``, ``VER``. Defaults to ``NONE``. - **bg_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``0``. - **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = at left/top most position, ``128`` = in the center, ``255`` = at right/bottom most position. Defaults to ``255``. @@ -261,16 +261,16 @@ You can adjust the appearance of widgets by changing the foreground, background - **pad_row** (*Optional*, int16): Set the padding between the rows of the children elements, in pixels. - **pad_column** (*Optional*, int16): Set the padding between the columns of the children elements, in pixels. - **shadow_color** (*Optional*, :ref:`color `): Color to create a drop shadow under the widget. Defaults to ``0`` (black). -- **shadow_ofs_x** (*Optional*, int16): Horrizontal offset of the shadow, in pixels. Defaults to ``0``. +- **shadow_ofs_x** (*Optional*, int16): Horizontal offset of the shadow, in pixels. Defaults to ``0``. - **shadow_ofs_y** (*Optional*, int16): Vertical offset of the shadow, in pixels. Defaults to ``0``. - **shadow_opa** (*Optional*, :ref:`opacity `): Opacity of the shadow. Defaults to ``COVER``. - **shadow_spread** (*Optional*, int16): Spread of the shadow, in pixels. Defaults to ``0``. - **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. Defaults to ``0``. -- **transform_angle** (*Optional*, 0-360): Trannsformation angle of the widget (eg. rotation) -- **transform_height** (*Optional*, int16 or percentage): Trannsformation height of the widget (eg. stretching) +- **transform_angle** (*Optional*, 0-360): Transformation angle of the widget (eg. rotation) +- **transform_height** (*Optional*, int16 or percentage): Transformation height of the widget (eg. stretching) - **transform_pivot_x** (*Optional*, int16 or percentage): Horizontal anchor point of the transformation. Relative to the widget's top left corner. - **transform_pivot_y** (*Optional*, int16 or percentage): Vertical anchor point of the transformation. Relative to the widget's top left corner. -- **transform_zoom** (*Optional*, 0.1-10): Trannsformation zoom of the widget (eg. resizing) +- **transform_zoom** (*Optional*, 0.1-10): Transformation zoom of the widget (eg. resizing) - **translate_x** (*Optional*, int16 or percentage): Movement of the widget with this value in horizontal direction. - **translate_y** (*Optional*, int16 or percentage): Movement of the widget with this value in vertical direction. @@ -305,7 +305,7 @@ You can configure a global theme for all the widgets at the top level with the ` focused: border_color: 0x00FF00 -Naturally, you can override these at the indivdual configuration level of each widget. This can be done in batches, using ``style_definitions`` configuration option of the main component. +Naturally, you can override these at the individual configuration level of each widget. This can be done in batches, using ``style_definitions`` configuration option of the main component. In the example below, you defined ``date_style``: .. code-block:: yaml @@ -320,14 +320,14 @@ In the example below, you defined ``date_style``: radius: 4 pad_all: 2 -And then you apply these selected styles to two labels, and only change very specific stlye ``y`` locally: +And then you apply these selected styles to two labels, and only change very specific style ``y`` locally: .. code-block:: yaml widgets: - label: id: day_label - styles: date_style # apply the definiton here by the ID chosen above + styles: date_style # apply the definition here by the ID chosen above y: -20 - label: id: date_label @@ -385,7 +385,7 @@ Terms used: - *grow*: if set on an item it will grow to fill the remaining space on the track. The available space will be distributed among items respective to their grow value (larger value means more space). - *gap*: the space between the rows and columns or the items on a track. -In a Flex layout, use the following options in the ``flex_flow`` configuartion parameter to select the arrangement of the children widgets: +In a Flex layout, use the following options in the ``flex_flow`` configuration parameter to select the arrangement of the children widgets: - ``ROW``: place the children in a row without wrapping. - ``COLUMN``: place the children in a column without wrapping. @@ -413,15 +413,15 @@ At the next level of the LVGL object hierarchy are the widgets, which support st Widgets can have children, which can be any other widgets. Think of this as a nested structure. The child widgets move with the parent and if the parent is hidden the children will be hidden too. -By default, LVGL draws new widgets on top of old widgets, including their children. When widgets have children, property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for it. The parents will use their own :ref:`state ` to detemine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. +By default, LVGL draws new widgets on top of old widgets, including their children. When widgets have children, property inheritance takes place. Some properties (typically that are related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the property's value will be searched in the parents too until an object specifies a value for it. The parents will use their own :ref:`state ` to determine the value. So for example if a button is pressed, and the text color comes from here, the pressed text color will be used. Common properties ***************** The properties below are common to all widgets. -- **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to top left of parent or screen). If layouts are used, or if specfiyng ``align``, it is used as an offset to the calculated position (can also be negative). -- **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to to top left of the parent or screen). If layouts are used, or if specfiyng ``align``, it is used as an offset to the calculated position (can also be negative). +- **x** (*Optional*, int16 or percentage): Horizontal position of the widget (anchored in the top left corner, relative to top left of parent or screen). If layouts are used, or if specifying ``align``, it is used as an offset to the calculated position (can also be negative). +- **y** (*Optional*, int16 or percentage): Vertical position of the widget (anchored in the top left corner, relative to to top left of the parent or screen). If layouts are used, or if specifying ``align``, it is used as an offset to the calculated position (can also be negative). .. note:: @@ -437,9 +437,9 @@ The properties below are common to all widgets. Similarly to CSS, LVGL also supports ``min_width``, ``max_width``, ``min_height`` and ``max_height``. These are limits preventing a widget's size from becoming smaller/larger than these values. They are especially useful if the size is set by percentage or ``size_content``. - **min_width**, **max_width**, **min_height**, **max_height** (*Optional*, int16 or percentage): Sets a minimal/maximal width or a minimal/maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area. Defaults to ``0%``. -- **scrollbar_mode** (*Optional*, string): If a child widget is outside its parent content area (the size without padding), the parent can become scrollable (see the ``scrollable`` :ref:`flag `). The widget can either be scrolled horizontally or vertically in one stroke. Scrollbars can appear depending on the setting: - - ``"OFF"``: Never show the scrollbars (use the double quotes!). - - ``"ON"``: Always show the scrollbars (use the double quotes!). +- **scrollbar_mode** (*Optional*, string): If a child widget is outside its parent content area (the size without padding), the parent can become scrollable (see the ``scrollable`` :ref:`flag `). The widget can either be scrolled horizontally or vertically in one stroke. Scroll bars can appear depending on the setting: + - ``"OFF"``: Never show the scroll bars (use the double quotes!). + - ``"ON"``: Always show the scroll bars (use the double quotes!). - ``"ACTIVE"``: Show scroll bars while a widget is being scrolled. - ``"AUTO"``: Show scroll bars when the content is large enough to be scrolled (default). @@ -462,14 +462,14 @@ The properties below are common to all widgets. .. _lvgl-wgtprop-state: -- **state** (*Optional*, enum): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overriden within style definitions or locally set. Can be one of: +- **state** (*Optional*, enum): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from theme, but can be locally overridden within style definitions or locally set. Can be one of: - **default** (*Optional*, boolean): Normal, released state. - **disabled** (*Optional*, boolean): Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``). - **pressed** (*Optional*, boolean): Being pressed. - **checked** (*Optional*, boolean): Toggled or checked state. - **scrolled** (*Optional*, boolean): Being scrolled. - - **focused** (*Optional*, boolean): Focused via keypad or encoder or clicked via touchpad/mouse. - - **focus_key** (*Optional*, boolean): Focused via keypad or encoder but not via touchpad/mouse. + - **focused** (*Optional*, boolean): Focused via keypad or encoder or clicked via touch screen. + - **focus_key** (*Optional*, boolean): Focused via keypad or encoder but *not* via touch screen. - **edited** (*Optional*, boolean): Edit by an encoder. - **user_1**, **user_2**, **user_3**, **user_4** (*Optional*, boolean): Custom states. @@ -485,13 +485,13 @@ To apply styles to the states, you need to specify them one level above, for exa checked: bg_color: 0x00FF00 # here you apply styles to be used when in the respective state -The state itself can be can be changed by interacting with the widget, or :ref:`programatically ` with ``lvgl.widget.update`` action. +The state itself can be can be changed by interacting with the widget, or through :ref:`actions ` with ``lvgl.widget.update``. See :ref:`lvgl-cook-cover` for a cookbook example how to play with styling and properties to show different states of a Home Assistant entity. .. _lvgl-objupdflag-act: -In addition to visual stilyng, each widget supports some boolean **flags** to influence the behavior: +In addition to visual styling, each widget supports some boolean **flags** to influence the behavior: - **hidden** (*Optional*, boolean): make the widget hidden (like it wasn't there at all), also usable with :ref:`shorthand ` actions ``lvgl.widget.show`` and ``lvgl.widget.hide``. Defaults to ``false``. - **checkable** (*Optional*, boolean): toggle checked state when the widget is clicked. @@ -499,7 +499,7 @@ In addition to visual stilyng, each widget supports some boolean **flags** to in - **scrollable** (*Optional*, boolean): the widget can become scrollable. Defaults to ``true`` (also see the ``scrollbar_mode`` property). - **scroll_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed. - **scroll_momentum** (*Optional*, boolean): make the widget scroll further when "thrown". -- **scroll_one** (*Optional*, boolean): allow scrolling only one snappable children. +- **scroll_one** (*Optional*, boolean): allow scrolling only on ``snappable`` children. - **scroll_chain_hor** (*Optional*, boolean): allow propagating the horizontal scroll to a parent. - **scroll_chain_ver** (*Optional*, boolean): allow propagating the vertical scroll to a parent. - **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor | scroll_chain_ver``). @@ -539,17 +539,17 @@ A label is the basic widget type that is used to display text. - **text_color** (*Optional*, :ref:`color `): Color to render the text in. Inherited from parent. Defaults to ``0`` (black). - **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be specified). Inherited from parent. Defaults to ``NONE`` - **text_font**: (*Optional*, :ref:`font `): The ID of the font used to render the text or symbol. Inherited from parent. -- **text_letter_space** (*Optional*, int16): Extra characher spacing of the text. Inherited from parent. Defaults to ``0``. +- **text_letter_space** (*Optional*, int16): Extra character spacing of the text. Inherited from parent. Defaults to ``0``. - **text_line_space** (*Optional*, int16): Line spacing of the text. Inherited from parent. Defaults to ``0`` - **text_opa** (*Optional*, :ref:`opacity `): Opacity of the text. Inherited from parent. Defaults to ``COVER``. -- **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text indvidually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. +- **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text individually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. - ``WRAP``: Wrap too long lines. If the height is ``size_content`` the label's height will be expanded, otherwise the text will be clipped (Default). - ``DOT``: Replaces the last 3 characters from bottom right corner of the label with dots. - ``SCROLL``: If the text is wider than the label scroll it horizontally back and forth. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. - ``SCROLL_CIRCULAR``: If the text is wider than the label scroll it horizontally continuously. If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence. - ``CLIP``: Simply clip the parts of the text outside the label. -- **scrollbar** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scrollbar that is shown when the text is larger than the widget's size. +- **scrollbar** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The scroll bar that is shown when the text is larger than the widget's size. - **selected** (*Optional*, list): Settings for the the style of the selected text. Only ``text_color`` and ``bg_color`` style properties can be used. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. The padding values can be used to add space between the text and the background. @@ -776,7 +776,7 @@ See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local ``checkbox`` ************ -The Checkbox widget is made internally from a "tick box" and a label. When the Checkbox is clicked the tick box is ``checked`` state toggled. +The Checkbox widget is made internally from a *tick box* and a label. When the Checkbox is clicked the tick box's ``checked`` state will be toggled. .. figure:: /components/images/lvgl_checkbox.png :align: center @@ -784,7 +784,7 @@ The Checkbox widget is made internally from a "tick box" and a label. When the C **Specific options:** - **indicator** (*Optional*, list): Settings for the indicator *part* to show the value. Supports a list of :ref:`styles ` and state-based styles to customize. The "tick box" is a square that uses all the typical background style properties. By default, its size is equal to the height of the main part's font. Padding properties make the tick box larger in the respective directions. -- Style options from :ref:`lvgl-styling` for the background of the widget and it uses the text and all the typical background style properties. ``pad_column`` adjusts the spacing between the tickbox and the label. +- Style options from :ref:`lvgl-styling` for the background of the widget and it uses the text and all the typical background style properties. ``pad_column`` adjusts the spacing between the tick box and the label. **Specific actions:** @@ -1129,7 +1129,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use ``spinbox`` *********** -The Spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can use for example buttons labelled with plus and minus to call them as required. +The Spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can use for example buttons labeled with plus and minus to call them as required. .. figure:: /components/images/lvgl_spinbox.png :align: center @@ -1137,8 +1137,8 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas **Specific options:** - **value** (**Required**, float): Actual value to be shown by the spinbox at start. -- **range_from** (*Optional*, float): The minimum value allowded to set the spinbox to. Defaults to ``0``. -- **range_to** (*Optional*, float): The maximum value allowded to set the spinbox to. Defaults to ``100``. +- **range_from** (*Optional*, float): The minimum value allowed to set the spinbox to. Defaults to ``0``. +- **range_to** (*Optional*, float): The maximum value allowed to set the spinbox to. Defaults to ``100``. - **step** (*Optional*, float): The granularity with which the value can be set. Defaults to ``1.0``. - **digits** (*Optional*, 1..10): The number of digits (excluding the decimal separator and the sign characters). Defaults to ``4``. - **decimal_places** (*Optional*, 0..6): The number of digits after the decimal point. If ``0``, no decimal point is displayed. Defaults to ``0``. @@ -1152,7 +1152,6 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas **Specific actions:** ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - ``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. ``lvgl.spinbox.increment`` :ref:`action ` increases the value by one ``step`` configured above. @@ -1250,7 +1249,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - Style options for the *needle line* using the :ref:`lvgl-wgt-lin` style properties, as well as the background properties from :ref:`lvgl-styling` to draw a square (or circle) on the pivot of the needles. Padding makes the square larger. - **img** (*Optional*): Add a rotating needle image to the scale: - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - - **src**: The ID of an existing image configuration, represennting a needle pointing to the right like ``-o--->``. + - **src**: The ID of an existing image configuration, representing a needle pointing to the right like ``-o--->``. - **pivot_x**: Horizontal position of the pivot point of rotation relative to the top left corner of the image. Defaults to ``50%`` (center of image). - **pivot_y**: Vertical position of the pivot point of rotation relative to the top left corner of the image.. Defaults to ``50%`` (center of image). - **value**: The value in the scale range to show at start. @@ -1363,9 +1362,7 @@ The animation image is similar to the normal ``img`` widget. The main difference **Specific actions:** ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. - ``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. - ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. **Example:** @@ -1563,7 +1560,7 @@ A typical application would probably use an ``obj`` container widget as a tile, - *widget* (**Required**): Any kind of widget to be used as tile container. - **tile_id** (**Required**): A tile ID to be used with ``lvgl.tileview.select`` action. - **dir** (*Optional*): Enable moving to the adjacent tiles into the given direction by swiping/dragging. One or multiple of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. - - **row** (**Required**): Horrizontal position of the tile in the tileview grid. + - **row** (**Required**): Horizontal position of the tile in the tileview grid. - **column** (**Required**): Vertical position of the tile in the tileview grid. - Style options from the widget used as container. @@ -1573,13 +1570,13 @@ A typical application would probably use an ``obj`` container widget as a tile, - **id** (**Required**): The ID of the ``tileview`` which receives this action - **tile_id** (*Optional*): The ID of the tile from within it, to which to jump. Required if not specifying ``row`` and ``column``. -- **row** (*Optional*): Horrizontal position of the tile to which to jump. Required if not specifying ``tile_id``. +- **row** (*Optional*): Horizontal position of the tile to which to jump. Required if not specifying ``tile_id``. - **column** (*Optional*): Vertical position of the tile to which to jump. Required if not specifying ``tile_id``. - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. **Specific triggers:** -``on_value`` :ref:`trigger ` is activated when displayed tile changes. The new value is returned in the variable ``tile``, as the ID of the newly visilbe tile. +``on_value`` :ref:`trigger ` is activated when displayed tile changes. The new value is returned in the variable ``tile``, as the ID of the newly visible tile. **Example:** @@ -1635,7 +1632,7 @@ The text will be broken into multiple lines automatically and the height will be - **msgboxes** (*Optional*, enum): A list of message boxes to use. This option has to be added to the top level of the LVGL component configuration. - **close_button** (**Required**, boolean): Controls the appearance of the close button to the top right of the message box. - - **title** (**Required**, string): A string to display at the top of the meessage box. + - **title** (**Required**, string): A string to display at the top of the message box. - **body** (**Required**, enum): The content of body of the message box: - **text** (**Required**, string): The string to be displayed in the body of the message box. Can be shorthanded if no further options are specified. - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. @@ -1656,9 +1653,9 @@ The configured message boxes are hidden by default. One can show them with ``lvg msgboxes: - id: message_box close_button: true - title: Messagebox + title: Message box body: - text: "This is a sample messagebox." + text: "This is a sample message box." bg_color: 0x808080 buttons: - id: msgbox_apply @@ -1676,7 +1673,7 @@ The configured message boxes are hidden by default. One can show them with ``lvg Actions ------- -Specific actions are available for cetrain widgets, they are described above in their respective section. Some universal actions are available for all the widgets or for LVGL itself: +Specific actions are available for certain widgets, they are described above in their respective section. Some universal actions are available for all the widgets or for LVGL itself: .. _lvgl-objupd-act: @@ -1756,7 +1753,7 @@ This :ref:`action ` redraws the entire screen, or optionally only This :ref:`action ` pauses the activity of LVGL, including rendering. -- **show_snow** (*Optional*, boolean): During paused, display random coloured pixels across the entire screen in order to minimize screen burn-in, to relief the tension put on each individual pixel. See :ref:`lvgl-cook-antiburn` for an example how to use this. +- **show_snow** (*Optional*, boolean): During paused, display random colored pixels across the entire screen in order to minimize screen burn-in, to relief the tension put on each individual pixel. See :ref:`lvgl-cook-antiburn` for an example how to use this. .. code-block:: yaml @@ -1869,7 +1866,7 @@ This :ref:`condition ` checks if LVGL is in paused state or no Triggers -------- -Specific triggers like ``on_value`` are available for cetrain widgets, they are described above in their respective section. Some universal triggers are available for all the widgets or for LVGL itself: +Specific triggers like ``on_value`` are available for certain widgets, they are described above in their respective section. Some universal triggers are available for all the widgets or for LVGL itself: .. _lvgl-event-trg: diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 72f882dac..b0e4b2776 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -18,7 +18,7 @@ Configuration options: - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **name** (**Required**, string): The name of the number. - **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the number. -- **animated** (*Optional*, boolean): Wether to set the value of the widget with an animation (if supported by the widget). Defaults to ``true``. +- **animated** (*Optional*, boolean): Whether to set the value of the widget with an animation (if supported by the widget). Defaults to ``true``. - All other options from :ref:`Number `. Example: diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 91fc902ca..da2ab7410 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -145,7 +145,7 @@ Light brightness slider You can use a :ref:`slider ` or an :ref:`arc ` to control the the brightness of a dimmable light. -We can use a sensor to retrieve the current brightness of a light, which is stored in Home Assistant as an attribute of the entity, as an integer value between ``0`` (min) and ``255`` (max). It's conveninent to set the slider's ``min_value`` and ``max_value`` accordingly. +We can use a sensor to retrieve the current brightness of a light, which is stored in Home Assistant as an attribute of the entity, as an integer value between ``0`` (min) and ``255`` (max). It's convenient to set the slider's ``min_value`` and ``max_value`` accordingly. .. code-block:: yaml @@ -194,7 +194,7 @@ Media player volume slider Similarly, you can use a :ref:`slider ` or an :ref:`arc ` to control the volume level of a media player, which uses float values. -With a sensor we retrieve the current volume level of the media player, which is stored in Home Assistant as an attribute of the entity, and is a float value between ``0`` (min) and ``1`` (max). Since LVGL only handles integers, it's conveninent to set the slider's possible values to be between ``0`` and ``100``. Thus a conversion is needed back and forth, meaning that when we read the value from Home Assistant we have to multiply it by ``100``, and when we set the volume through the service call, we have to divide it by ``100``: +With a sensor we retrieve the current volume level of the media player, which is stored in Home Assistant as an attribute of the entity, and is a float value between ``0`` (min) and ``1`` (max). Since LVGL only handles integers, it's convenient to set the slider's possible values to be between ``0`` and ``100``. Thus a conversion is needed back and forth, meaning that when we read the value from Home Assistant we have to multiply it by ``100``, and when we set the volume through the service call, we have to divide it by ``100``: .. code-block:: yaml @@ -234,14 +234,14 @@ The ``adv_hittest`` option ensures that accidental touches to the screen won't c .. note:: - Keep in mind that ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heatpump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. + Keep in mind that ``on_value`` is triggered *continuously* by the slider while it's being dragged. This can affect performance and have negative effects on the actions to be performed. For example, you shouldn't use this trigger to set the target temperature of a heat pump via Modbus, or set the position of motorized covers, because it will likely cause malfunctions. In such cases use a universal widget trigger like ``on_release``, to get the ``x`` variable once after the interaction has completed. .. _lvgl-cook-gauge: Semicircle gauge ---------------- -A gauge similar to what Home Assistant shows in the Energy Dashboard can acomplished with :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets: +A gauge similar to what Home Assistant shows in the Energy Dashboard can accomplished with :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets: .. figure:: images/lvgl_cook_gauge.png :align: center @@ -332,7 +332,7 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg .. tip:: - The ``obj`` used to hide the middle part of meter indicator line has ``radius`` equal to half of the ``width`` and ``height``. This results in a circle - which is actually a square with extralarge rounded corners. + The ``obj`` used to hide the middle part of meter indicator line has ``radius`` equal to half of the ``width`` and ``height``. This results in a circle - which is actually a square with extra large rounded corners. .. _lvgl-cook-thermometer: @@ -424,7 +424,7 @@ Climate control .. figure:: images/lvgl_cook_climate.png :align: center -First we import from Home Assistant the current target temperature of the climate component, and we update the value of the spinbox with it whenever it changes. We use two buttons labelled with minus and plus to control the spinbox, and whenever we change its value, we just simply call a Home Assistant service to set the new target temperature of the climate. +First we import from Home Assistant the current target temperature of the climate component, and we update the value of the spinbox with it whenever it changes. We use two buttons labeled with minus and plus to control the spinbox, and whenever we change its value, we just simply call a Home Assistant service to set the new target temperature of the climate. .. code-block:: yaml @@ -494,7 +494,7 @@ To make a nice user interface for controlling Home Assistant covers you could us .. figure:: images/lvgl_cook_cover.png :align: center -Just as in the previous examples, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrive the current movement state of it. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. +Just as in the previous examples, we need to get the states of the cover first. With a numeric sensor we retrieve the current position of the cover, and with a text sensor we retrieve the current movement state of it. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label on the middle to show *STOP*. Otherwise, this button label will show the actual percentage of the opening. Additionally, we'll change the opacity of the labels on the *UP* and *DOWN* buttons depending on if the cover is fully open or close. .. code-block:: yaml @@ -614,7 +614,7 @@ Just as in the previous examples, we need to get the states of the cover first. Theme and style definitions --------------------------- -Since LVGL uses inheritance to apply styles across the widgets, it's possible to apply them at the top level, and only make modifications on demand, if necessarry. +Since LVGL uses inheritance to apply styles across the widgets, it's possible to apply them at the top level, and only make modifications on demand, if necessary. .. figure:: images/lvgl_cook_gradient_styles.png :align: center @@ -632,7 +632,7 @@ In this example we prepare a set of gradient styles in the *theme*, and make som bg_color: 0x2F8CD8 bg_grad_color: 0x005782 bg_grad_dir: VER - bg_opa: cover + bg_opa: COVER border_color: 0x0077b3 border_width: 1 text_color: 0xFFFFFF @@ -644,16 +644,16 @@ In this example we prepare a set of gradient styles in the *theme*, and make som bg_grad_color: 0x03324A text_color: 0xfff300 btnmatrix: - bg_opa: transp + bg_opa: TRANSP border_color: 0x0077b3 border_width: 0 text_color: 0xFFFFFF pad_all: 0 - items: # set all your btnmatrix buttins to use your custom defined styles and font + items: # set all your btnmatrix buttons to use your custom defined styles and font bg_color: 0x2F8CD8 bg_grad_color: 0x005782 bg_grad_dir: VER - bg_opa: cover + bg_opa: COVER border_color: 0x0077b3 border_width: 1 text_color: 0xFFFFFF @@ -669,17 +669,17 @@ In this example we prepare a set of gradient styles in the *theme*, and make som bg_color: 0xC0C0C0 bg_grad_color: 0xb0b0b0 bg_grad_dir: VER - bg_opa: cover + bg_opa: COVER checked: bg_color: 0x1d5f96 bg_grad_color: 0x03324A bg_grad_dir: VER - bg_opa: cover + bg_opa: COVER knob: bg_color: 0xFFFFFF bg_grad_color: 0xC0C0C0 bg_grad_dir: VER - bg_opa: cover + bg_opa: COVER slider: border_width: 1 border_opa: 15% @@ -689,12 +689,12 @@ In this example we prepare a set of gradient styles in the *theme*, and make som bg_color: 0x1d5f96 bg_grad_color: 0x03324A bg_grad_dir: VER - bg_opa: cover + bg_opa: COVER knob: bg_color: 0x2F8CD8 bg_grad_color: 0x005782 bg_grad_dir: VER - bg_opa: cover + bg_opa: COVER border_color: 0x0077b3 border_width: 1 text_color: 0xFFFFFF @@ -703,7 +703,7 @@ In this example we prepare a set of gradient styles in the *theme*, and make som bg_color: 0x2F8CD8 bg_grad_color: 0x005782 bg_grad_dir: VER - bg_opa: cover + bg_opa: COVER border_width: 0 radius: 0 pad_all: 0 @@ -762,7 +762,7 @@ For the navigation bar we can use a button matrix. Note how the *header_footer* then: lvgl.page.next: -For this example to look correctly, use the theme and style options from :ref:`above ` amd LVGL's built-in fonts. +For this example to look correctly, use the theme and style options from :ref:`above ` and LVGL's own library :ref:`fonts `. .. _lvgl-cook-statico: @@ -818,7 +818,7 @@ Each page can have its own title bar: .. figure:: images/lvgl_cook_titlebar.png :align: center -To put a titlebar behind the status icon, we need to add it to each page, also containing the label with a unique title: +To put a title bar behind the status icon, we need to add it to each page, also containing the label with a unique title: .. code-block:: yaml @@ -901,7 +901,7 @@ To display a boot image which disappears automatically after a few moments or on MDI icons in text ----------------- -ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your texts. This is very flexiblle because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. +ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your texts. This is very flexible because you can prepare various sets of fonts at different sizes with a different number of glyphs which is extremely convenient when we're talking about flash space. One example is when you'd like some MDI icons to be used in line with the text (similarly how LVGL's internal fonts and symbols coexist). You can use a font of your choice, choose the symbols you want and mix them in a single sized set with icons from MDI. @@ -941,7 +941,7 @@ In the example below we use the default set of glyphs from RobotoCondensed-Regul - To lookup your icons, use the `Pictogrammers `_ site. Click on the desired icon, and note down / copy the codepoint of it (it's the hexadecimal number near the download options). - To get the TrueType font with all the icons in it, head on to the `Pictogrammers GitHub repository `_ and from a recent version folder, download the ``materialdesignicons-webfont.ttf`` file and place it in your ESPHome config directory under a folder named ``fonts`` (to match the example above). - - To use the desired icon, prepend the copied codepoint with ``\U000``. The unicode character escape sequence has to start with capital ``\U`` and have exactly 8 hexadecimal digits. + - To use the desired icon, prepend the copied codepoint with ``\U000``. The Unicode character escape sequence has to start with capital ``\U`` and have exactly 8 hexadecimal digits. - To translate the escape sequence into the real glyph, make sure you enclose your strings in double quotes. .. _lvgl-cook-iconstat: @@ -952,7 +952,7 @@ Toggle state icon button .. figure:: images/lvgl_cook_font_binstat.png :align: left -A good example for using icons is for showing a different icon on a checkable (toggle) button based on the state of the switch or light it is linked to. To put an icon on a button you use a :ref:`lvgl-wgt-lbl` widget as the child of the :ref:`lvgl-wgt-btn`. The coloring can alredy be different thanks to the :ref:`lvgl-cook-theme` where you can set a different color for the ``checked`` state. Additionally, by using a ``text_sensor`` to import the state from Home Assistant, we can not only track the ``on`` state, but also the ``unavailable`` or ``unknown`` to apply *disabled styles* for these cases. +A good example for using icons is for showing a different icon on a checkable (toggle) button based on the state of the switch or light it is linked to. To put an icon on a button you use a :ref:`lvgl-wgt-lbl` widget as the child of the :ref:`lvgl-wgt-btn`. The coloring can already be different thanks to the :ref:`lvgl-cook-theme` where you can set a different color for the ``checked`` state. Additionally, by using a ``text_sensor`` to import the state from Home Assistant, we can not only track the ``on`` state, but also the ``unavailable`` or ``unknown`` to apply *disabled styles* for these cases. If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like this: @@ -1506,13 +1506,13 @@ LVGL has a notion of screen inactivity, i.e. how long did the user not interact Prevent burn-in of LCD ---------------------- -You can use this to protect and prolonge the lifetime of the LCD screens, thus being more green and generating less hazardous waste. +You can use this to protect and prolong the lifetime of the LCD screens, thus being more green and generating less hazardous waste. Wall mounted LCD screens' main problem is that they display the same picture 99.999% of the time. Even if somebody turns off backlight during the night or dark periods, the LCD screen keeps showing the same picture, seen by nobody. There are high chances that this will lead to screen picture burn-in after a few years of operation. -One way to mitigate this is to *train* the pixels periodically with completely different other content. ``show_snow`` option during LVGL paused state was developed in this scope, to display random coloured pixels across the entire screen in order to minimize screen burn-in, to relief the tension put on each individual pixel. +One way to mitigate this is to *train* the pixels periodically with completely different other content. ``show_snow`` option during LVGL paused state was developed in this scope, to display random colored pixels across the entire screen in order to minimize screen burn-in, to relief the tension put on each individual pixel. -In the example below pixel traning is done four times for a half an hour every night, can also be stopped by touching the screen. +In the example below pixel training is done four times for a half an hour every night, can also be stopped by touching the screen. .. code-block:: yaml @@ -1548,7 +1548,7 @@ In the example below pixel traning is done four times for a half an hour every n - lvgl.pause: show_snow: true turn_off_action: - - logger.log: "Stoping Antiburn" + - logger.log: "Stopping Antiburn" - if: condition: lvgl.is_paused then: From 8e9ed92914705fa33c122959a6604b228a871192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 7 May 2024 09:47:47 +0200 Subject: [PATCH 348/350] add missing dots --- components/lvgl.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 002d789fd..7d803bf04 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -62,7 +62,7 @@ Main Configuration Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome this is simplified to a hierarchy. -At the highest level of the LVGL object hierarchy is the display which represents the driver for the display hardware. A display can have one or more pages associated with it. Each page contains a hierarchy of objects for graphical widgets representing a layout that covers the entire display. +At the highest level of the LVGL object hierarchy is the display represented the hardware driver. A display can have one or more pages associated with it. Each page contains a hierarchy of objects for graphical widgets representing a layout that covers the entire display. The following configuration options apply to the main ``lvgl`` component, in order to establish the principal operating conditions. Some :ref:`styling options ` can be set at this level too, but only for inheritance purposes. @@ -239,7 +239,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **border_width** (*Optional*, int16): Set the width of the border in pixels. Defaults to ``0``. - **border_color** (*Optional*, :ref:`color `): Color to draw borders of the widget. Defaults to ``0`` (black). - **border_opa** (*Optional*, :ref:`opacity `): Opacity of the borders of the widget. Defaults to ``COVER``. -- **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. Defaults to ``false`` +- **border_post** (*Optional*, boolean): If ``true`` the border will be drawn after all children of the widget have been drawn. Defaults to ``false``. - **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be specified, defaults to ``NONE``): - ``NONE`` - ``TOP`` @@ -453,7 +453,7 @@ The properties below are common to all widgets. .. figure:: /components/images/lvgl_align.png :align: center -- **group** (*Optional*, string): Widgets can be grouped together for interaction with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused widget which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. +- **group** (*Optional*, string): The name of the group of widgets which will interact with a :doc:`/components/sensor/rotary_encoder`. In every group there is always one focused widget which receives the encoder actions. You need to associate an input device with a group. An input device can send key events to only one group but a group can receive data from more than one input device. - **styles** (*Optional*, :ref:`config-id`): The ID of a *style definition* from the main component configuration to override the theme styles. - **theme** (*Optional*, list): A list of styles to apply to the widget and children. Same configuration option as at the main component. - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. @@ -537,10 +537,10 @@ A label is the basic widget type that is used to display text. - **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display. To display an empty label, specify ``""``. - **text_align** (*Optional*, enum): Alignment of the text in the widget - it doesn't align the object itself, only the lines inside the object. One of ``LEFT``, ``CENTER``, ``RIGHT``, ``AUTO``. Inherited from parent. Defaults to ``AUTO``, which detects the text base direction and uses left or right alignment accordingly. - **text_color** (*Optional*, :ref:`color `): Color to render the text in. Inherited from parent. Defaults to ``0`` (black). -- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be specified). Inherited from parent. Defaults to ``NONE`` +- **text_decor** (*Optional*, list): Choose decorations for the text: ``NONE``, ``UNDERLINE``, ``STRIKETHROUGH`` (multiple can be specified). Inherited from parent. Defaults to ``NONE``. - **text_font**: (*Optional*, :ref:`font `): The ID of the font used to render the text or symbol. Inherited from parent. - **text_letter_space** (*Optional*, int16): Extra character spacing of the text. Inherited from parent. Defaults to ``0``. -- **text_line_space** (*Optional*, int16): Line spacing of the text. Inherited from parent. Defaults to ``0`` +- **text_line_space** (*Optional*, int16): Line spacing of the text. Inherited from parent. Defaults to ``0``. - **text_opa** (*Optional*, :ref:`opacity `): Opacity of the text. Inherited from parent. Defaults to ``COVER``. - **recolor** (*Optional*, boolean): Enable recoloring of button texts with ``#``. This makes it possible to set the color of characters in the text individually, just prefix the text to be re-colored with a ``#RRGGBB`` hexadecimal color code and a *space*, and close with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **long_mode** (*Optional*, list): By default, the width and height of the label is set to ``size_content``. Therefore, the size of the label is automatically expanded to the text size. Otherwise, if the ``width`` or ``height`` are explicitly set (or by a ``layout``), the lines wider than the label's width can be manipulated according to the long mode policies below. These policies can be applied if the height of the text is greater than the height of the label. From 9e90d7fc82fe74300e80288fe3fb582b7f5836ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 7 May 2024 13:16:19 +0200 Subject: [PATCH 349/350] lvgl.update for disp_bg_color and disp_bg_image --- components/lvgl.rst | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7d803bf04..6ef5e1ad4 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -85,8 +85,8 @@ The following configuration options apply to the main ``lvgl`` component, in ord - **update_interval**: (*Optional*, :ref:`Time `): The interval to re-draw the screen if necessary. Defaults to ``1s``. - **log_level** (*Optional*, enum): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, enum): The byte order of the data outputted by lvgl, ``big_endian`` or ``little_endian``. If not specified, defaults to ``big_endian``. -- **disp_bg_color** (*Optional*, :ref:`color `): Solid color to fill the background. -- **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as background wallpaper. +- **disp_bg_color** (*Optional*, :ref:`color `): Solid color to fill the background. Can be changed a runtime with ``lvgl.update`` action. +- **disp_bg_image** (*Optional*, :ref:`image `): The ID of an existing image configuration, to be used as background wallpaper. To change the image at runtime use the ``lvgl.update`` action. - **default_font** (*Optional*, enum): The ID of the :ref:`font ` used by default to render the text or symbols. Defaults to LVGL's internal ``montserrat_14`` if not specified. - **style_definitions** (*Optional*, list): A batch of style definitions to use in LVGL widgets ``styles`` configuration. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to commonly apply to the widgets. See :ref:`below ` for more details. @@ -1673,6 +1673,21 @@ The configured message boxes are hidden by default. One can show them with ``lvg Actions ------- +``lvgl.update`` +*************** + +This :ref:`action ` allows changing on the fly the ``disp_bg_color`` or ``disp_bg_image`` configuration options of the main component, making it possible to use change the background color or wallpaper at any time. + +.. code-block:: yaml + + # Examples: + on_...: + then: + - lvgl.update: + disp_bg_color: 0x0000FF + - lvgl.update: + disp_bg_image: cat_image + Specific actions are available for certain widgets, they are described above in their respective section. Some universal actions are available for all the widgets or for LVGL itself: .. _lvgl-objupd-act: From e2b1f83256ad5560e1f76718ad4f70602e55c205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 7 May 2024 16:59:07 +0200 Subject: [PATCH 350/350] Update lvgl.rst --- components/lvgl.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 6ef5e1ad4..cbf4929ce 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1673,21 +1673,6 @@ The configured message boxes are hidden by default. One can show them with ``lvg Actions ------- -``lvgl.update`` -*************** - -This :ref:`action ` allows changing on the fly the ``disp_bg_color`` or ``disp_bg_image`` configuration options of the main component, making it possible to use change the background color or wallpaper at any time. - -.. code-block:: yaml - - # Examples: - on_...: - then: - - lvgl.update: - disp_bg_color: 0x0000FF - - lvgl.update: - disp_bg_image: cat_image - Specific actions are available for certain widgets, they are described above in their respective section. Some universal actions are available for all the widgets or for LVGL itself: .. _lvgl-objupd-act: @@ -1790,6 +1775,21 @@ This :ref:`action ` resumes the activity of LVGL, including rende then: - lvgl.resume: +``lvgl.update`` +*************** + +This :ref:`action ` allows changing on the fly the ``disp_bg_color`` or ``disp_bg_image`` configuration options of the main component, making it possible to use change the background color or wallpaper at any time. + +.. code-block:: yaml + + # Examples: + on_...: + then: + - lvgl.update: + disp_bg_color: 0x0000FF + - lvgl.update: + disp_bg_image: cat_image + .. _lvgl-pgnx-act: ``lvgl.page.next``, ``lvgl.page.previous``