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/564] 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/564] 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 61ff599a86..3f370b98da 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/564] Update index.rst --- index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/index.rst b/index.rst index 0bcdd3e792..d78bdd10eb 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/564] 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/564] 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 3f370b98da..ececf69222 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/564] 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 ececf69222..999e83a011 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/564] 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 999e83a011..15e1e3b6d8 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/564] 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 15e1e3b6d8..7a21aa00b7 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/564] 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 7a21aa00b7..e8a96b121d 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/564] Update lvgl.rst --- components/lvgl.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index e8a96b121d..e8b7b8fca9 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/564] 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 e8b7b8fca9..5fe5f8d448 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/564] 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 5fe5f8d448..3473ccc91a 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/564] 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 3473ccc91a..18473973e2 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/564] 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 18473973e2..ff7ef8e73d 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/564] Update lvgl.rst --- components/lvgl.rst | 78 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ff7ef8e73d..2e652ced65 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/564] 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 2e652ced65..064cdd5e89 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/564] 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 064cdd5e89..ad99852fd6 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/564] 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 ad99852fd6..cd76aa3013 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/564] 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 cd76aa3013..b6e220ae59 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/564] 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 b6e220ae59..e47bfc944b 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/564] 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 12fdee505c..5ee443f198 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/564] 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 5ee443f198..fc028c318e 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/564] 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 0000000000..a7d9d035ac --- /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 e47bfc944b..13443432ec 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 d78bdd10eb..e000530674 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/564] 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 a7d9d035ac..1247cef6ce 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/564] 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 1247cef6ce..e23323c7ab 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/564] 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 e23323c7ab..881f77ee9b 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 13443432ec..97ee09a2ee 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 0000000000..4c9272945b --- /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 0000000000..f2a8f81fb9 --- /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 e000530674..cc1f7b9a78 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/564] 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 881f77ee9b..1521a68468 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 4c9272945b..548af26583 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 f2a8f81fb9..865f1149dd 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 cc1f7b9a78..d1fdadb155 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/564] 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 97ee09a2ee..cca26a4cd8 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/564] 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 1521a68468..5f852a6141 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 cca26a4cd8..5a91b409c5 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 548af26583..d7688fe0c6 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 865f1149dd..600b7b674a 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 26ea94196c..6119f826c7 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/564] 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 5a91b409c5..708d79a2e9 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/564] 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 708d79a2e9..9194fad51d 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/564] 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 9194fad51d..ed9aaf63d2 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/564] 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 ed9aaf63d2..06853f330c 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/564] 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 06853f330c..2c26ce3c19 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/564] 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 2c26ce3c19..9580c5f115 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/564] 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 9580c5f115..3a935cc0d4 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 +------------------- + +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. In the example below, all the ``arc``, ``slider`` +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/564] 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 3a935cc0d4..d80b7ef45f 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/564] 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 d80b7ef45f..bea11b2ef0 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/564] 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 bea11b2ef0..339bd0a5b8 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/564] 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 339bd0a5b8..06b07dc7cc 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/564] 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 06b07dc7cc..3083df47bb 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/564] xxx --- components/images/lvgl_align.png | Bin 0 -> 11061 bytes components/lvgl.rst | 168 ++++++++++++++++++++----------- 2 files changed, 107 insertions(+), 61 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 zcmeHtXIPWjx^^5?kS+o$NK=Y*q!$5U5D+O6dLKY(l2Ahl%|ekung~co>0PN(0!lB2 zh!7AWp@W1TgwQz)ojH5<`Tm{jJOB3jkwC61@B6NmXWh?TR^&Zh4H`-oN(cl(b4ODR z3W1PafBev+`QMwT9m*yA$QbN4E@qq#`UyW9jA{s_=JRYaBLOTy_v28b55+zUe`Qw zSI<48>*EnZKfWT)DZ4Wrqn0~6xpOPmRNQOo-s~{BXZAD8_qQ@GBxbwgv`)t)QYr=I zB+6Iy9Nu~c{4LJI2?|+<|HXECbmA8Y%>ho-Pzdz1*kLl zgQ>XSE*Oz&Z{WM%zdOZ|saS+I6m-mZOdKPw@Fi*$;qw~a_|}Enc57XTY(HN?8^b_2 z8g#ll!8uhscm-EiHCh@dd*eoY-(1u0(6X8u zDX!3^hMb%naIbLN>gv(>M0}&K-Vv&<&JkC;)DX+ANEv*Oum}}merU+Pe#<@3cFlRt zb5s(o$^Ayl6$c-3t+5zEBqt|pXlUHcdy)F+HP`YXUw2Zm{GcRFTO8fU@Ng4KcmLAB z6a|zk3A2EjQN0?k$<2`TfQFh{a(6^9Cvrws^_i38m{Xs68k?CjH$yxoy2CEq)-(wV zjf3hbSKgd_Jh{_~AEa*UUf8Uvsv=H({P=Nm0mCYV!woV-stGYy2`xo%1UpqL#xQOl zUAW&DsFa0vz&aPGT^;z&nA~~eP1`$lfzsOA+EDuDSnsD#pAI+;`7$k23rbP9A;vGb zQ0sQdeRs}xhP%0~t*-V)>;~d}b?VOzN?MH=VQ!c7s~pRD-ZisY*A4Ru=VUU*x=67^ z4<~8l47k*col9iDa%FaN_wnP$NyTqr3cIXp8V%}mvd#uPF@%8V^i zH>ulX>#r%2!1eU6biIQ$wzMc~BEXEu$;pXsYwL;Hym}%k)7tLNqNOY}zZ0^&SNQlw z5V8I=N8MUs^tG^(GuO$;$m%W2^8}h6zHTam8O9{|C?QjwQ~Ub*EG#T)VSTqHKGv68 z_!_IzFJvG4)h(~Bi84p26bEcCk4{czAK>cR2P;dNY0t97f{A!;EfI;8qzT77XpwOV zk<8#GJIOjWE-N}lj^m11(K_{IM6x^^{|*a(dW_fLVCCp?d%N0Ac9TI1`ia2JXxmGH z9(p*r@5(M<#ch0f48{pffo&H#&R{M-F?=@XDc4u&Kq&$!IVp|#V{N?*{3!SI-oV}aYZ9zk2w>OToWd10gCL)<~E0K}s{Bs!BNY(c5 zOp6RFVU3m|GA;UAtb(vR^_C*ZeT3Id0e@D!H5ID$K7#OZEi3Bm?k!csepBDN)h0H* z@xEzf$U~r`eo+||Y8u)+X=~hfLaGAns$?x5Wd9kDlOEwXel{Hi_PEWR70rPZ1&#Ng z2i>py;PB>r!U%yp;)RER-jN+C1zl+0C#_912kmdK;M&^SeAn<92rtkt5n%ZGl75^F z%Lebo(zK`cQ(y4@>+|Teki#XLSw09wa(Q`qtn$$gajwsCoc{aFbHn$jkmDn4iAl@R zUJ3p5Q#z%c!?lp(0SyjttSJ z>-i-P4$^psO)yo%FEDC&(Q`isoq8p^u5)bdYzuOWfKHQ17O~o!;W*yu;maCY<$!#C z2XOE(HsoODaG#VcYIF2sP|s-h4h9*W&omMG9j1Ph9pg|{dAVjYU%**>&_AO+)X!Me zUA-7uWSWH7--h|~p|tYEZ`_zVG+S#J9v%**FJFp@i4hSNcK&u}*w-Kgu~a)oe1wo1 zTka+^lv-U`8LeGuC_h-)sB@cW_TN;e@R;jm>Zc~V^*xZ-!)Ik>bxaC5CV}+@%a&bG zppo8NI^tx$0Y!`H42n_jy2D^)yDLzPi|WnaxhS9j1NN`-0(iMu@x_Xfh5D`L}p5TSf9m24C2 zzeT_Tc=B8Pl4tO0i=Zpm3?uFaN~akWWPr=Z4Jtc|bFq&WU%)QbDSsUsV^H0(d*2kX zyt{L1#hC8i;fIBm0d?^(T+f7`yU*`x(Vyk<{Pa=GGaVHQV&z z_LnYX81L=xM|He$d)k2Z+g?uD+c22$wC$@jce!OXc42yy@Pm_Qgdi#^8Zhw|;6|D8 zgC{XvGmVXngpi)MmNH*z1$J19W@L$wu!0uk(nTfmv88zh8`_7M(EsnzVWG@2iJ)&v_<20K1@fq#RoGvTx2(gm1!cP||I@K}tbE zK~~nZ%ov7)H(#j`>GBv_)S5CoZDQfakjjzm#4_H{Ab&V51ew&te>`AxP?RcTjOs8H zkP;Vvp~)SH+ev+gLIqJ$y@-+E%1op`&0qid(=R+SiG&vAt_qxw>d?x20mIFCn(db} z%y|MlDv2N(GdH)|y(`ppt~J>tI}NeCULdx_|4;C71G_~uQLDzk1l20b6+RQ5z9KFu zIV)JSB5zx?G}o7``V6DAUmCrC8j_xv6>?;DQu~S0tDBOJsD8K3bM>YwgqvKNr#|?5 zGN@1%JYtdt@RUjc82kVBwE@#`N>;+8!n#cO06>vi&3T>r zk6*ujouAJ?P+*SA8(aj~G%|kt^{c5sVrptC@r2?C3JL}V1tI!CwXoLEvn?_18HuO- zIJD{VD7R|N-+Mvu!;iCsdu-05dwP1Bo13NC1Y?#Mk#}>1gUDXiHQX1MQ&bc#DPij} zypzy5qspaeWx2Gpq)O4{5grj?Vr+ah{+W=Cl@ew|NXWEK0THijg?`K z^p1{>si~>3urpFTGp-q`Zs#iVis7D~;tY}95fdTDL7O)sPEj(b5T;+8>-4y?TgP&S z{ifd}+uOaLLp()WJ|hXIcJ=)3H$2|DO$>Z+S4B(lu$!nZtj4Dh7X08+XIli_!uD%Z~a;h|md+2V=o?&Qa(i;K>Pv7(BKiUIy|&gib& zZ7lo;vC+{qT%n{-ar9R+bi3?sOytS%Geo{G573JK-KnO|Mn^{n=IXk>+CyYm305Zl0Z=+DC{r&ysR`5vREBS+qNyXP0 zDNRBWdhW*vb;*6k2Qx*g<>%*9hCQLTv$wYo32DhQ`z-bxu&qhl%*%|=*JovQU*FTr zg90`J*1Nb*LDC9^tbxC3yWN?mco1tUWUOF#j%%Al!jiYEzUEvI<5H8)$V^FbE}~pB zzrNP94pmbt4Cd3P!l`S1fXj64>+6-FONHC(M>>OfKlU0?; zm(}m;3WdQ>4XWK|p+95n(n<;3%PS!-iy{Wxz*`xGAh`6 z6-sv~!Pm^K9)yXx*tbA4m4cA7(#0)37xanN23DJN?y@f1r_ z)9ftH?7I~K)CL@+u2=B?u&l@T+)AdY%G<&6)`?AFp!tW(#eP=fXzzLopZEBAfys{K;O7HI5b3x(R%fzeI-a{`PQg72Bx2O_SfoY|n)*4|e6?Z>u@&9%ua13~f@=)1RwdB~Fnh zLM8$~om+$;C=D`G&9=9UJylQ+`Q;VPlmH0L(`-8i(k z0X=N3ECtGvcdhV~V$2K$*P8*SO;U3?5Z|o^n_vONsjp>WO1OjF-PaFxH#uQISp!B| zS;`T-^Sa}AXB}<^eFObX&)s|Men8vClOL^5wbj?l?Yf7Agn-#;vVxw33sKwfM44@a|lEw6bHBEj`!!YCa6l z-iw{d$v-4n#_@Qi9CfxR=Ty*k3Dx(NvP=}Ey1lGMR?-bpg;P>f$G(2OxA1{ODX=iS zgA;?WN~Q|rx?0iXr^k5arEbCC;txP50&o{1)htI~Yf1w?hzZ`&r*#La0FBm(9#a61ImeIjxPq$% z4fd&|y^oJETaGWgHg5uwt76l!jZ@X#xk7(U-^~k_>SJYMf7?*_q#x35e59*%a?`^9f#HNOnlMCZ=5Uzm{h^z3X6!qU0oR|!#Ex1QI;cR0eMUr{6IeY zmzU3vFD?!igzWa&{3asrTwQX~b#HU22_!;IV4wA40@DcFc^w_MYvTIrG<9d}Gl$NR z4J~T>10w>f33xz<-3?8NOvM0cS=sBy+ht6(LM3@;ud^w!o<09W0_w@1vUZm;Q7g~9 zte2iGwhP5ax^E5dixRBp)@nX;8PR9)0`0)Z%Nt5xY;$%4Ei-W`98lgL0yLV|N69WG zZ-$cUWZ{@IgrDk}6Upy^5}j{yf@g?(;P*xKIi|Mcm;c*?wU>25io zbR$29LD7)MQO&d(+pcuYP;!ifd?f9qY+c9RMsUHglVJ|Fz<8oIB5i6egM3c4B#C7b z+jCN$ve$V2B@qrRiVS<_JVlZd)=Mdcm zjnuTXBBG)kmp>S>&XO3x!WauAj(w#D7U_S<+O-|k3^aW+gh)gx>Ke$=@g4bM@QF}r)l$E zWMrw6S$u+>Z(vMrvXyq&HKx~`OoYB!3yMqMi1%#@=FpTUuoqzI5>dbGuM`pk)itf zZB^Aw0~{#B^z3C32S!y)a^_F-_Q^;{M$t-5Zve5?ystf2HcpBK` zLqmoMWam}83r2*2!vG&Llsx|h|K)%mzdEZ3>^wNWNls4A%(w2Mfu_PE7cU{^y9I-U z#pd{S3peqUbU=@{hG}Jsb5~#Acwu=fJ-*?4en9~+RZcvY5E~ntShcHwFjWQuyUx!~ zmN`l>XwUn>1D+IZKtp^zJoG8v0bvG4W#!dSQ!_I&(mIp$M69H;@|tW+-5tHmn**|O zJw12a?hX~2Ti^?eWTBS=?%vhYN6i7`4Yvh5#Ld;Unn;=9WxEU^D4zIx1OfptESEa{ zt$sARth6*2TBOZ8Q&Px$?HqT%rpk$OoB)?Z)Xsl=N-iNG0RSPMZvP+RGD~Id`XCM` zm?eT`mL84$)+zQJNH%b>9vaYmOiWC+VpM}<;nw)vLs{r|BzT;S?IbXV|JIjhgAgK* zJ|iGonSiOVgva;X2dripcXB_#gb39JHa1ynO(s^)x#MK7g&n&ACXu2|$u(QxE|q=< zU>tMQZuv{8i}#fc3=CLVS%Eb`oB|RmD0$^`O6wPkn8A-g!&w4vJE{+9P8E54DeW>*-R?XRc2{&i%UrvU1toX2bTpnhP;+a z0;TaOe(p1UC*JcDt;3~GAXnE{Fm+-+kPeS@)z@)ac~6G+0W~u!A{ACxqsE}}?YBSV zp`w6fhX$Sg_U#+!9e^3WGc8@Ec;C{pw%_#C^26c3H_o9YBKtGam4F;iCkkgbIbCuu zD;egfnjbH{gr2iy-@D#D$rB2cEur#{P2|Ok7Y7%s4{!lPsuW7GA0s577c(qxagNt} z@ug@3N4K}4#BaoplFQh{gpQWhMHwS?K2RBGPhjVj)2q^0cgfMa{o!IrOEa}1jAUE> zTZ!_6`fz#YFOc|Whh5FnTjNMnlLlJsiFtbblY2J0picyDOrIDW^wS$NT`AhYV%G>} zw6LvQ@vH?r@HFRlEC zzcIeoOy+bMmu49DHgLDxJ?L{)|LmCm-`iZjEV2e%bJzH|6|R=Fy=^(NvbH9pvk9DW z;)xPV$(IuseZe&&Yg;#WBXUFd*`!TUk6ov6TN%@3@g%20?LMTno zLpUvUk-SD#7LqJ%moDAA5bgG2OZwW+pl|f~SiNcDP{!#t*&bk6KVqtp(=-xb>Z^oL zG-se4=Gr17BP~T1g8Ckom6e_2vK(P!W3w_h7pKm_BG<+n7s^yo7i#8&v59C0V4Mrr z)xiSn?4}#nnjZ$g(%H7L@SE*35=qt>1WLw*uNGFfHw}TP&N4bcrR4rH-B)uoVp*ix zBz4-vX4^ofxc1WflS6v!om#YtKo%w-?G=zEk)aRFKzOBNjZ6u+(sf={EoWff4Qdsy zsTNi+KUX%)BlAq{YQA%Em6;B0RnO5w-Bb}v2!yif7OSsl%6hNvI5e8 zk=Ix*QjYoU)_YU{N%t^_QlcpJiv2slR+1iI&ldeF1)Ngw_d0NR7L#@Vsnf!hrkWa_ z(DmE%AVqYNBs8`&t0!vlu*XJivpK{azRIr$PFG{2AjkZsKeix*)HnfLeUPMlXQPE= zdv$+2@NL;2U&Q2w+rBSf5`2kX7tWQ_&yempJJQbyQofu4Cz!t^OPO&Ath5l&a$vn* z^UCpz9`C*I=uJ?><@?Ivwy*N}F_Lf?%&5d@i{01Pmx?PG0764{UTZ|HadRs8T_UoFf((S)$L=nt}}5|awa^3dNP^1a}% zPss?$!Z^^MRSLRJIS_uXzG)&vO8R!@9T7 zBEu4+6rY)m_wtW=c9xi0`Q>TN9I!lbl3eViEkFAn^eMWCeeD_-hB(FPhg3 zJsQjK9^+=UOuLx2@K?b2ptICa0Hlq{eLXTgl4y%MIJ&=|mX_AI1ZcZ7(TtKlk1Gfl zeZS!vEOTwxpZs8X0s;cW%cYe+P5!p(=bLz3(%+sY;|ApGMXvUOtYGBg7ak7*i6V1XYawR9Kf1d$SLzOf&_EiOTWKKz*%Ux2 z%yaT2d-RCj=nas5sl|i9gadO^Akh^E!pG(SlhY>PeXbHfBIA@GNHUT2U%CQ_5-id4 zo^t*|XgZ1allv!$tqm>9{z!a__OYDU|ZmZ0!0A;$!)V7=DH zzlVu^u~Lvnx|=|MfzZ+h#EDtQ2L%U}cnyxATwRSClZa1nwlB{we5qHV{D=Zpzs>Pp zGD(^n@~D3Vi{0Aj;;53oHbn71($C)+m>}Mjparh3u4bMLb`j1{wqK_zT13F9o9swn zF+#G7&~?fm_;KUoHLw6TH@)C@gOWO19sNH~RG@q_Q9q&fWgXjQyl?#aWsptcw^~4y zp4?Xy;4M`wpQ3%%wW+kahwFK4Y!^5%ArrvXbtexBPBS~<2^m5z ztoEHjW$5USx5de?7hA7th8g8de1!i97(u$?bdS_C8Qko#D%w>LanHN-Nji=%YqyL4AL^8|GVjO~^_viTw z&ktT?F*Ah{gx0F`s@nA@U}?{<^B3FnxUDD#Yy;e_@upx46VXrp2OPqTx3P^VlvU$P z$^|ABf%e&}TDwek{#}e~CKdlWk+BaCVMr&X`$)2&=R7@+(IxN^F25kq2TzgA{)Wfi z=@WPy` 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. -Main Component --------------- +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 @@ -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/564] 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 133a21a695..d3ded2afbf 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/564] 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/564] 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 6db6b03bc2..06f2e5934a 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/564] Update lvgl.rst --- components/lvgl.rst | 257 +++++++++++++++++++++++++++++--------------- 1 file changed, 169 insertions(+), 88 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 06f2e5934a..a1b2dfbfe4 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-objupd-act: -``lvgl.is_paused`` Condition ----------------------------- +``lvgl.obj.update`` Action +-------------------------- -This :ref:`condition ` checks if LVGL is in paused 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_paused - then: - - lvgl.resume: - - light.turn_on: - id: display_backlight + - lvgl.obj.update: + id: btn_relay_1 + state: + disabled: true -.. _lvgl-idle-cond: -``lvgl.is_idle`` Condition --------------------------- +.. _lvgl-objupdflag-act: + +In addition to visual stilyng, each widget supports some flags to influence the behavior: -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.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/564] 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 a1b2dfbfe4..11049c3185 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/564] Update lvgl.rst --- components/lvgl.rst | 109 +++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 11049c3185..52d1bf0421 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. - - .. 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. +- **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:: + + 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/564] 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 5f852a6141..65d68ee6ce 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 52d1bf0421..b42d0a5bbe 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 d7688fe0c6..115180569d 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 600b7b674a..ccaef1a4ad 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 0000000000..a509e63ef5 --- /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/564] 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 b42d0a5bbe..c30f331ef8 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/564] Update lvgl.rst --- components/lvgl.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index c30f331ef8..4031fd8d87 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/564] 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 4031fd8d87..e28ed46f80 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/564] Update lvgl.rst --- components/lvgl.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index e28ed46f80..de3a334275 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/564] update pack --- components/binary_sensor/lvgl.rst | 1 + components/lvgl.rst | 50 +++++++++++++++++-------------- 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, 75 insertions(+), 22 deletions(-) create mode 100644 components/select/lvgl.rst diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 65d68ee6ce..e6b73691e6 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 de3a334275..976d828f26 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 | -+-------------+------------------------+ - -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. ++-------------+-------------------------------+ +| 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. 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 115180569d..dc4fc0f62f 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 0000000000..9952817cb3 --- /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 ccaef1a4ad..7dc8112b8c 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 a509e63ef5..6fa18f84e3 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 d1fdadb155..ae06fd31a7 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/564] 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/564] 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 3e49ce9f1b..cadc015603 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/564] 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 cadc015603..4c9f6dcf78 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/564] 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 4c9f6dcf78..dd20ab88de 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/564] 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 | 274 +++++++++++++++++++++-------- 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, 259 insertions(+), 81 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 e6b73691e6..80543b22ae 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 8378efdda9..8e5c3b0181 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 0000000000..497cdd95f6 --- /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 dd20ab88de..49eb0068fa 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,8 +661,10 @@ 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: @@ -599,17 +674,17 @@ Example: - +``led`` +******** -``meter`` -********* - -The Meter widget can visualize data in very flexible ways. In can show arcs, needles, ticks lines and labels. +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: -- **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. +- **color** (*Required*, list): TODO +- **brightness** (*Required*, list): TODO +- Style options from :ref:`lvgl-styling`, using all the typical background style properties. + Example: @@ -619,17 +694,23 @@ Example: - -``obj`` -******* +The ``led`` can be also integrated as :doc:`/components/light/lvgl`. -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! +``meter`` +********* + +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``. +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. +- 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 dc4fc0f62f..aa25cf54ec 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 9952817cb3..c5015babfa 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 7dc8112b8c..099a171cd7 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 6fa18f84e3..766e2577b4 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 ae06fd31a7..807a5e2410 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/564] 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 49eb0068fa..622bfe542a 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/564] 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 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 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/564] 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 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 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 03a5ca643e..d99b886343 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/564] 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 d99b886343..ec226ee346 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/564] 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 ec226ee346..cb258776a4 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/564] 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/564] 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 cb258776a4..74eacc097d 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/564] add pages --- components/lvgl.rst | 140 ++++++++++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 44 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 74eacc097d..2941cc4cce 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/564] 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 2941cc4cce..695f32d1a5 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 766e2577b4..518c169f38 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/564] 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 695f32d1a5..d59ea75c29 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/564] 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 80543b22ae..6fb0b59f55 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 d59ea75c29..ff5bedd0ba 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 099a171cd7..db67db79bc 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 518c169f38..be966744cc 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/564] 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 ff5bedd0ba..4f7f604b70 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/564] 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 4f7f604b70..ee3ec2f09a 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/564] 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 ee3ec2f09a..9f85564348 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/564] 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 9f85564348..516d9ef605 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/564] 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 516d9ef605..ffeab34ac3 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/564] 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 ffeab34ac3..379032ce96 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/564] 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 7b5edec3df..5437735ea2 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 379032ce96..81723965a1 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 be966744cc..34786fa46a 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/564] 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 5437735ea2..25d8fff4e2 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 81723965a1..6bc5d40b5e 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/564] 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 25d8fff4e2..8e28f3e8d6 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 6bc5d40b5e..daa2189ba8 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/564] 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 6fb0b59f55..211ecb00e0 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 8e28f3e8d6..4a54b3fc2f 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 daa2189ba8..d64ee80190 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 aa25cf54ec..9a7b799dad 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 c5015babfa..5fd6e9d705 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 db67db79bc..2df218257f 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 34786fa46a..99c4066b2d 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/564] 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 d64ee80190..2beb7cdf32 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 2df218257f..0000000000 --- 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 53eeb32011..704bfd117a 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/564] 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 2beb7cdf32..fc3e287957 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/564] 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 211ecb00e0..f2a7763e37 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 4a54b3fc2f..98172eb742 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 9a7b799dad..f1def37136 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 5fd6e9d705..cd56df20a6 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 99c4066b2d..5623ea0cfc 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/564] 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 fc3e287957..acc219cb26 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/564] 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 acc219cb26..c8a388c2e6 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/564] 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 c8a388c2e6..2d2f14f27d 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/564] 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 2d2f14f27d..d0aa2613f1 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/564] 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 d0aa2613f1..210f605673 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/564] 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 98172eb742..e4cd808264 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 210f605673..ce9fafb1e9 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/564] 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 ce9fafb1e9..269c7e8c07 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/564] 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 269c7e8c07..491d1a9255 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/564] Update lvgl.rst --- components/lvgl.rst | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 491d1a9255..01f4b141e9 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/564] Update lvgl.rst --- components/lvgl.rst | 118 +++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 61 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 01f4b141e9..a602918ad4 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,31 +1347,6 @@ This :ref:`condition ` checks if LVGL is in paused state or no id: display_backlight transition_length: 150ms - -.. _lvgl-onidle-trg: - -``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 - - - .. _lvgl-event-trg: Widget Event Triggers @@ -1380,9 +1355,9 @@ 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_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. @@ -1396,21 +1371,42 @@ These triggers can be applied directly to any widget in the lvgl configuration, .. code-block:: yaml - lvgl: - widgets: - btn: - ... - on_released: - then: - - light.turn_off: - id: display_backlight + # Example triggers: + - btn: + ... + on_short_click: + then: + lvgl.page.show: main_page + on_long_press: + then: + light.toggle: display_backlight + +.. _lvgl-onidle-trg: + +``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 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/564] 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 a602918ad4..0c8a105ea3 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. -**Specific options:** +.. figure:: /components/images/lvgl_meter.png + :align: center -TODO !!! +**Specific options:** -- **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/564] 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 0c8a105ea3..0e3438841d 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/564] 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 f2a7763e37..844cc55cd6 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 e4cd808264..7c26363372 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 0e3438841d..cae7e1419d 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 f1def37136..45d81acf71 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 cd56df20a6..44c41b4586 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 5623ea0cfc..b12724ca04 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/564] 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 cae7e1419d..8ccb1ee2f2 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/564] 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 8ccb1ee2f2..b570c74d17 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/564] 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 b570c74d17..2b60a325f8 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/564] 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 2b60a325f8..5909050f17 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/564] 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 5909050f17..abde9df5f0 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 0000000000..2f009bab9e --- /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/564] 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 2f009bab9e..ce76440a09 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/564] 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 ce76440a09..a109c60d30 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 46f446d17b..172bee9cbb 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/564] 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 a109c60d30..22d95caaef 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/564] 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/564] 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 22d95caaef..c6aef7ff77 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/564] 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 c6aef7ff77..b9b067063f 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/564] 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 b9b067063f..c732ef560d 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/564] 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 c732ef560d..7535bfafcc 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/564] 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 7535bfafcc..d956ff6e01 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/564] 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 abde9df5f0..73764097a7 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 d956ff6e01..bea6e45745 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/564] 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 bea6e45745..0e4dfe52c3 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/564] Update lvgl.rst --- cookbook/lvgl.rst | 66 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 0e4dfe52c3..351ef04150 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/564] 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 351ef04150..98cbba376a 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/564] 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 98cbba376a..e9cf8579e8 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

drH39q^ys~Zzx=K9!@(}|U6pL#`{1emFiz66b7%(Tda~A~6|aA$Xr z_~8QQY1&^S%B9BqE|UUE5^60?wu=5nCN;~O-Ys=qG0otNsPW{(cP)S8xvM((rK>~B zoG;3DxS5=LZGFy>D~~*UZTn`s6(70lh>+vK7AKY$n;WC++Bh89f#!9NPjx$ojvvax44qUvvdiCm>YtOVIz3ZTNV{O$k&GpS@ z@yyhH_Z)co&#sQ+{Mbo$_WbpehgM9>7>+2^4a;#H!))WxrS1NB_onZ3mpV}^MG;G@ z$6mdbOlc6n_ztAo{aa|dfe&Bze8W*D1k^)E?e5`Ytrld%GK<@3!BH8u7cK$dHN<`;qucE*01^UJ20$qQ z=E}^nv{Ivl*sotX}SXIZJzDU5Sw>83GR@0TyVkdLdVXh$wOubvy7SqdL`h%UYy zJ4QUWc<8QWKi2j0H+RmT-wmWW*V9ffE$zIzcJ%G{UB5UC<_-o^`qoRAF1@@}pXhkK zNa)r)&4n{_G9C>R+Kp4$36Cz$T{`>Z;KFMFh_G)(@phi9Ar2@BWkQ-jrNzx|k+nSC zfx-QbE0HJF2G{h!)3TOnf^TePn^$iH!HTH`hGsUEyf7F(`oMB9yK->r9JQ&aa!_a5 z(7yHUmyew6vKn{g`q>LNHV27ygO4^=7w3Ac8XY-0Rc4c&)#|8mJkTRyMmt$@@KDsO zroP96NUO8mXTS1VKdS+YQ0`mNyPapV&BGSLf=`~Bv_Ssyw_e=%$TU$eYiim>H{8y4 z`$W`nL*B5h-J*gX&K!i-J21U4$kt!@&TxJ{IC5lG=el9ohMn9zck`9Y>xb_>vbEDb z{`iT(@T$aL z>${`8+)amWGCaic2W?q0ci@wKb#o4ZqXSEndXQUdmc z*+)N14upbK5LMO)l{3n_&cQTmb{nBbi>|>9&WG#6a{FpMsbshe_p``|q%&FRD2FaL4fk_H#Z_AQFvvHp?pOsEo2 zNMJ2H+H&MuU`Ak~VhMK0;u*t*&Dh}L$l?2T<5k(u&YbFXtU0UGtLtk$A4g8jm8RK_ z5YC-0lL5E2s8cJglyg=uvWj@ptDnT#rC*tM+U-Q&k++{GnZ^M>PA7aM24U5u`e z-~I4|Bo&oq!Hh;3?bXd!29qm^vW!~`nYZQvytv9h5E8j)KKFCW?|5itqZx_GYBEZg z9ZW?BHaACxG37*9-+2D|rH${rTC6MuosRaik1rlM)!ki%(HePdwh(pzr4G#>oz`hx z$(b;U@@CvLn2W$7Wp~5z=Jwf_&rhtG13}=Zs!h$)Cl(DqPcLkX)*eY=TCL?3gc>@bRB2-j)xye8n)XXNh6eEeCcMQoA!xAb1yx&=J@L;?+UN(7UQgpC+y-YtIze7 zsUsq!CHQ`Ozqj+mWu^cnVFS~VGI%U1Hyf^Ut}zxQ@j4fx+!sadWlkEBHjA=H}zA5pmnLio1XOfrE2RzklV$ z7vfy9(7=%y8CTnL^9!tIovA5nxmt(WasdQT;IyfQUZvx%1 zUN9U~g=a!)nD@fPkSE!uHZfD4Ch-mm1ie`yWjwI2ujilqneer2?u8qN9{H~y`{tLv zx@bN57{fD9t^Uj-b7Eo(cQ#gvRbY0g4R5YbbhPb?d91eeh5VUc{`IfFGJpkSfCP>> z_{0;_O=l{uwPgFIZWt@aR=$1qie`6aW}@lU$$C8IkwzmYV@$8JjG=6P1RhtH&}>JN zYTKqzqblpxMXC`iMW{vLeQ#@RZN?AASKP({`ThvGrcI?xIV7LOBeBXe;Vgr z7;CMEz$R6*G|{vy7I|Z6`FiY!J`ZOdt^JLE{+;y!K6I2OLUD{a^lj zvYq)+F{#r^H?)IGW>UtJ4YjoB$2IS;;<_v|c>5KqZpj__o06WPgdwFV!zkn}OS6pC z5Z;`-@__BLx=1{$GumArH>1poE^bX;dG#;;-{1cH3*Y^EJTX_6AXSzKppvK%H%Xoq z`7kSnc~*`>f615*U-<6j*DhB7%};6iT}L1Ix5(*Y&_~%P!@5cK_4g%KrW@Vj;-- zwf2E`u+RK#asGM4&XLxrmFY|AM?|uW!w{Zmg==+Y@7`QpKYw{`pUHe48&8)uFKPl>Gzng#&(-iNqE zx5G}~d(Zrl18Y|Y|Mttz6}h2%q=_sUs76tTMdRcq7?c5281Lub?(pFXPzW5O6MEBb zU@CA;qLQi<#E5zN#`bG#FMYWkmk&Pbe)vO+Uwr29KmNb*jX%Qk&z&ijKk+wz^Op`D z?oB2WMT#12+!U%zr3|E$q#0S-A8lOdEJj~{87Bk$+&dv8k{UmG4?g*0+84h?^G7<# zgrz$yvb4i1bA8dKNm9sSdsOIB%UVVZtOiODuunDQw*5vTnhP9KvgU5cE7$fuemXgH zKm;?hPUxZ1v&p*Qg`=TmOIkP{qDcku4bn``{^@Vg_)1H zhod&x9cGz$@%*Kh8EHD6cKtNxfBMoO)WA5j8bymfZr|d*-QKFICMAR@$KlM;?n33v z>(*;DH6NMvSj$B9MApU%x~{nc87oFzdPEA4xGDse$XG6 z$+pdnG~1dKY>*BjON%QcAOM_@*T`G!7k=*GIk3D8LrUptRmoMAiJEn~s;05iQ{0Za z4i89-+rZ+cW0<{}z@DkAawKYyBru^Xp$9a{$pT18(-X=QmKnMH`lvEoxK4HD%GJj{ z_{(4T_eWm%^WVRGWi?~;!P6%eBYRK=pZ~(2T)eU~XH{v#O`{_cKADIl$DwYhe3$1% zmm#YWO8_u{`Ym||o7a@|q`B*IM^w&%GYj1Bbt7w1#Y(Rg9UZ7)H1E5%UTJ~X+EVqw zh*Sd#fkaJIWG1o5;+%)J!(BgZ8fTYNMwF%qC<={HynX(~-}M$x&mOyfGRgb9WxpT4 z_?;VDalU)`lEKWjr!{C~n@xBacB;#(W9Eb*6KiRlHb?*tgdD;^J$Wl0&F?|U(D1jj zemY#O2A$2coI4PNr8(Z&rFMhrFm5JN`IhgbmUJtIMuQ=tQXqtxL2*`?B=fA449!WiqsI z{@UtYhr&V0b>1v0C=*f#fcPzW;&`kka-al zrZhd<88hbbRMia(A7)CNC%L618);pEfj~^_bhOSmzetWjmY|wtS>70Z=FE+=#BDEV zvYC{YVKCm{#)Va4Au$#9yzykblfj^DX=&=kD}zaqT}fCipxf|tND20%Yfin z1rf}UkxeunmxLzmSggBp=<1Wj^Z(c94}SFi14mCM&GyA-o}FxM2%jyUJk*q`wRy*M zM-$20g=i`qj<>~lusmJwWObGruUzN{dOo*enX|5Ba(2P1hq~va%L|?wQjwR^fYhN% zB>Ujp!SllPD-1Xg8q+I>Hk10=we3n2^Numix&~S$F)GK>5J9`GqFykw+z=&gMwO-$ zkwuvxrf|N8}ar!pIy{huyo>( zxY>E_#iyzyDH8ZPJiqbuMoK5}mYQ)q=nJRg*J&;^8JVsZlCNU`L~XWn2hZ*C^ibE; zEERpS4qe;&2{Uf zdhK_u)5}^<3=kp7tgLP{gr#|l@r_B zF}1sKslt$TdWVHd0H&IFJmxW+yH7u?O^&5%N`99fg`A7y{RW9+`u2bmqj@px3+JooL(zTVwB+3`H{*uo)S`GY1VFl~}% zC865ly05EdlO|NfjO(mUh-ln$qZm|OFM98h@R5hc*{&fRM%Ij_r0_Xfr7Ts(OtT|X z+Zm_3tJ|7tvwV}a2CJJ^z3Mq?{@Qm`Vdkn1`AMGoP&%Ua1F9KcjIK8HJmxj)oH@r zepW&c%I&zy*2!2-$`K6VF=t%4%U%TkNYW$)OP5zxCfk=cwuZU`-eQ~xvYN1akWA4` zFwXU@erEeiGgHH&KWYF2$ST-A)IQtWZ{+C%^-HTdNy9cE)lx6CEO%x}zj1A+!~8>s zOw+alvuQ=3R00JM5wUSq5pA(5%S%lcMOJ8<)F!(d+x_h{Rpxrn4t!M%s#f^YEo{pX z#`&(pMSy~pk zqd@z?>|<|+$EnlIr*^ABU1^2f+3o|tT-R;kHD#s%f(K-`jsJH4Htq4y>?mE1M&lp| zm5K*_dHC?u+wQx6c}m=W>Y!`r1+}3;qcUX;Cn6#aN_fLEL0X|@BG*Kc38ocV)~3AX z<7%v=60W-(%{PwiIj)?Hlmap0jAeriHsnMpDdDRqSO!E^L*9gces&o000O+NklB{wOrgeRH)~V8M;o7VX1jZ~u%_7EPfYsPL${>aG zG|4%o%yCI^i_5mnY63^-D5-iwuQoS&x^+mqFHJaYU?QQvYM4~w$_Zw;qc7i z#f{zK`t@9i>bC8KL6PbE)pzdj*A@qql%lQMqj#M=6h$wuu3o>nrUCb#To?|v6Ej|k zW;wG{1&#oernO=q+FQAQ?+k`w%7_(X0;+}Q=>%dz4W*KjNhzdn1WIeiQU*OQj$61c zZ_>ErmZaUxSiijS%+;65fjoBV$nrw=?6aHS3pRWEKDG{5p??R@?ezm!hs~u)-lO-O z?AY{&-+KDo%{9Zok%P;xTv`3%SHG2I#O!cS8w5$FPnIMCK&Tli#u!hVEUk0KG*)v4 z78&GAC8ZQn`cnCZl)4W?LP?THCI|yWpeX8SEn6EVWtr4qQs~!5)t`Lj)k&6r@V(3S z8^@^tY3|c7cDsI>yi}5%x_3cN#^1fTwYR1{G}8+LW#;N#Z-3W;l>n7WheT>(nT z5Gn(u1Y(4=W?G{&mZmMI8nBd7ikO57Lqx)m$_O9?pg<8ZLCDf3Af9IHsbvsvIrK=I z#_Z_O+VIAp96$BaU}iJ@(0d>F;&;zw#p{OGfYd(o=XU)x5_g|kN-KKx;^vg6`>;%= zRowaZOKZ$FqR22O<)|29GFB?yYit)7`{rJw3{Qv?abjsA3Z8Fe#TL&?o=;d-5a%&5 zVgwKvp(fU5X`X39&xc!jQ4~VU`m7rUQp)(+wHvF~7zZZ@z|L;{rLUiR?181Ft_8pW z7?AIm@7&IFa4|{{zIx$R-PJ(kIPJ{rT)eyf*vZ}p-f<6XR$GqSUGjQ?@B`m~ui&e_ zB3B4Ph#26g2o*y`0HFrz1dLGzxUpE zzwgX~(@A-0lC)Xh1V%44A*s7jDjWP%j2no>Dd z1Y)E>up(I^GFQfOh^AefU&!i_r7Y_9x^C~vAib@~_VhEaojQ3myRsJ7`zHu*h^JGG zh6(_D+wr87no8U1!R7f6eB|Lny#>(3wq@H=W5AP4ssv^yA_ZbGWvnSUGgyC?xDnIpyoEQXWhRC6(dBQZy0FTw>L5A_%5+{c7=hfBNUw*Vb;^ zm=A!vPaprzxl4Py4C+n#{onWA_X3C*_@rP!+X|-XOG`b^?{IEfmQyp&aa~vQ0?!LP zH_)1X+laRDTeofMCawBS)zo#vcAC0z8qsjoaMkdjaea>mo-6%U%2xPZD|Ju#z7kSu zzG#KlxJ}m9`PIhtN^)4O&n>7&P9BW7bDIg}z>U?lQ!_Sz2TmS)Gkg2wr~ceFm<>~{%cGW$e8t+9uvbnnpem+V7MM$%X`MQY>x_87YL+yq zSI1N-`A4(E|N|2>M9x4GPVFb#Mfl?!-LenG2q?8Pj zTT$MO>dLUezx36w|Jl=jv74ij0O0MN7yuMd-(hUG>j%I;`1N1<%&-0<0G1{0Kecr5 z*y4rD&#TL<>)JDm&h*Nh<+0=nKCq_P_l*ZV;EN<5unGQP)QYOQW-5F;7lbIl8WV7 zGLhVA;!#_;T5xBn`iC8x-7iN4lv3|IvmA=H$VyRNU<18#@Lp?S&ZdzvU1=;VSz%J; z#5g7)>NrV;;|T(@0~;_EYF`;iXhp198Yim^LK;%4Kq&>p3J45AP_IvKQif700>p5l zay8T>!C$4ulkeu^0rQyfp{~C82yJrPO_? z`%)KDieV{6m6KJJh-@U;Kae@hweYNI3Ibh!~D``e(BABu;I@&iX{|N9RV>BK><(- z0U%*2r~r_+DiGf<)F?m^)VNZ-rnDL7Ef>s;OL@IteBx*R`bU5A@i!mpkHqu;FZs{y h_YeLH&wtwT{{i`>V$(^}Fb)6!002ovPDHLkV1hCap#%T` literal 6573 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 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/564] 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/564] cookies --- cookbook/images/lvgl_cook_clock.png | Bin 11469 -> 11500 bytes cookbook/lvgl.rst | 62 ++++++++++++++-------------- 2 files changed, 30 insertions(+), 32 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 e9cf8579e8..3fef258fdb 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. @@ -32,12 +32,12 @@ If you have a display device with a local light configured, you can simply creat light.is_on: room_light then: - lvgl.widget.update: - id: light_btn + id: light_switch state: checked: true else: - lvgl.widget.update: - id: light_btn + id: light_switch state: checked: false lvgl: @@ -45,22 +45,18 @@ If you have a display device with a local light configured, you can simply creat pages: - id: main_page widgets: - - btn: - id: light_btn + - switch: align: center - width: 100 - height: 70 - checkable: true - widgets: - - label: - align: center - text: 'Room light' + id: light_switch on_click: - light.toggle: room_light + - homeassistant.service: + service: light.toggle + data: + entity_id: light.remote_light .. _lvgl-cook-binent: -Toggle remote light +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: @@ -78,12 +74,12 @@ If you'd like to control a remote light, which appears as an entity in Home Assi lambda: return x; then: - lvgl.widget.update: - id: light_switch + id: light_btn state: checked: true else: - lvgl.widget.update: - id: light_switch + id: light_btn state: checked: false @@ -92,26 +88,30 @@ If you'd like to control a remote light, which appears as an entity in Home Assi pages: - id: main_page widgets: - - switch: + - btn: + id: light_btn align: center - id: light_switch + width: 100 + height: 70 + checkable: true + widgets: + - label: + align: center + text: 'Room light' on_click: - - homeassistant.service: - service: light.toggle - data: - entity_id: light.remote_light + light.toggle: room_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/564] 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 7d6a491ed8..cfac98157a 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/564] 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 3fef258fdb..0a328dbfa4 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/564] 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 0a328dbfa4..aff4d5fd1d 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 172bee9cbb..ee3dc262e3 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/564] 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 zcmcIp2{@E(_aA#mmPlF0pisl?+lv~r7;CmHh0KP@GK|TReP1dedKE3Cv=K_#jjV}w zMcynWB+*7*QvXNW_kQ2I{J-meUH`eRdFFoZ=bYa;_c_0Fp8I(w-OkorMoL8r1Omxe z(8vxTkkA%jynB^6aCB%`EC+rhgJ^CcAdvLhm9G%!SmAnLj>>Uz<-6Kg6PVlpLpqDg zU>k-91Od_@knz^=AUe~J%?C5sKAb=k$ZUNx1k7QXKwQu^Fq6$@CYut<4&-b9Fc##?<#R)Pxqsu^&&&VjA&dFbV9;Kk|JU%a zm_}@Wb^w4K0?5L@`WHkX@z``em*>Rg`u|9j-4Bak1h8tbo(m_C#SIJ5U-9U>0-H?d zvrQlf7y<@`p`Zw)6AVW{Ur+0sqS`iR;hh*>G7vbdi6Yw;+-1cwBFeKX4($!Q2dNK_Ow_cnk)LFoZ+EEGEI5 z%L||bMB@a|eb`1pfj%p=2iyRbOXGw9Iga>VNRI5_?<0Q>_$xaJbmmG?m_V2-Y+$n> z-={f$5$6AHLEm7*eAxi#Kd|JRSP0jfA4cb~i9SF|{#OEXz zih}{rV*auK z|Jyvk|JV(_DgDP{j8+=!H-;JgC;9%x@*kB#1ZsGNnjznFYDV|@nO##j8HItPsR%O^ z5stv%;7BSGjUf_Aa4c~1KvQwXUv2qw{-uF}BZ)W!jDkX9(P%u1NP@voXgm=`MkBCj z6qfuK8bmV~77Ih*C=>(g!5*7XzHq3|^1Pq45p)h1ThDaX1#r zn}vlU=r9Hpk4CLDCoBSr047lkG#!tpGyaVAqY>eda3%|d!a^Br6wuIEz<~}&;Gj$< zlI@K{(AjV#?C-TnXbc_(gW+LRGzt!<;D}TN2?s=hLIv6?p7IyD_+ghqMxZeiA{<7= zP$+mf90$W;aTGX-h)0r9Fe3KvZ8Ct?i)G*dXOT<>6o*Ekp*T7M4rK$~7mH!RnHVhm z587YZ@Qpx5|ID;IS3>-V?ic5 zg%`d)9>I6tq29UmaP`rfI?yv)*l*931$Y=ZT-c^`FR^NsL!P?WdCR;6aKS#sE$3>~ zGK&>`<^7e&l#A1lQ;PZp6878t&jdUX4$#xJIJ^;Mb$FrE=oYRq48a|5TpB9)J^J=d zt>`e`u+eC5*v#_N;hgnqYGivw-8D{00dd88mQClp^fMGxohlS5=`sec8O3elN?R!Q zj6|s;#d?)R2A%!<5!VqpFGyAp!yYv$^avCyt|1zlKKFGEzdtV66}KE89rrYT-`FxH%{WY*6dEAzDf~#t zX!UZKAiiwiAt+=3jR40d&HIN2WTjiT7+_!QPE~^$9}Rx3GvYlqT4moe%+Yv5X`Ne= zG_RPKIO5jPB;@|$c5bnSa5E{U)V~~zYk9Kvt)GUN+A3?^uqdYCzPK;K+eJPK%Zdb; z_UFs$kGY*g9#FR;i(Yisep(;@;P=={;TrWC)X37YRhwaRp(7Eu`rWpbk#=Rg2=8I^ zNx4tFZ#0P0jvoeJEZ&th!4Xg1uhcahx$#}gwJ6^i)tlTGySF3?LT~lkN_@PtpQm&w zR(QKxN6h~E?bQ`8C1Sic6bMIk7eU*zK!z0uprmV_F;6EHN8qd-QHYj0hk5ZPkg?Ej zGHUBa8X3e|DQBz9O2bo6^R(ngFm0(m&(xlc8Z5{?)9g8`>Q=PSA`#y#)ZEdVv8jM5 zf4#+_&B*zP;+3d_NXIN}@y!9_4R5V-rJ-F%#uZxo)y5o`ZMziyd+Vf;@0>i>esxk zBky_zky(znTT?$D-+wdh(5pegi-;%A3b_}(gg&kRoxdx?*mp@-S;Qxa<3zh;?yOz9 zp<^7PrP*HYl)y0M>7496EI3W+S<)YCtAQVSYgk=$tYKuD2;)Qru2y3*zCl( zs%>Ic8@%Nr8}5^*Hy^E_LCimI45X?Jc^;K^-`e3raZHMLGJe!MG;pgcoZ@D7S!EE71tb_}9H>#pJhK?h%cNUyi<;o;I&bo80eLmu;5w zKI`G}gK4hlWG^dUmXz~$UuQl0BIPA1CL!o5X&294GHL)3s`{p`^LGb98EsW!`Z}F8 zQ`a>nWD?E@f@!QT$Fc%~ZO?iQIG}RhJ#(JsE?llb=}2gThJ0#BEqi*Ie0p{E>xb`R8d7)nP_NZ*424L(I}}mq zD4CXhxbpF?ozAF|2Uq;|?8y`#N{TJ@-XR#2GiT>UfisR5!~vx)evUC&_qwfH>_Ij( zJKaw@e^#RZSuFxlpm%sz3mA(;C1y&{;`yz%N;2x*|Vzm=Sm)M?vsXP zcWVy!)9PYA45QI!ai-o7Q&3s|hUk=5Ve9yk)*bSmJdU0Cdw5vLK9yPBrbE+6mP)5o=#7DK+feL5XCa!6(V#FHCL>Ta4_h34VydRPDVXI+aPt;CfWbQ3u&i zU;X;l^3-o}ZWRtRTnjs}SIA3t`b@*+mc@rVYx{YP62VjEXD?+y4y<}~b;#2o3mtp! zt&I9>9nV2w!7X$jI6*8Y=5C5kw86dc;I=SiCk!LIpf$f}K@8qF?&D)JBtl7jKX1K- zWGSaF&m>puqZ_~3!Fn}rZv6-|Qg=OYAm?Spw3*mu!_{C@t;1e6)Z*d&Hiq*za6NrH zH&nIy`9D0LFH%~6x6F%mlaCo%RXF+nQ)d9zufT+ZQgBIheBSQSb$$@l+8?E}?aG~O z=qB*q`&T%`cMAe)T~_{qLiiJl(PmgN5UM#xJcn(1+A zgNjs*Pb!f@W~#GP+Z#6hF}rnz0m{LS6U4<8M9PBwnu=K!ijm-#wVD1n(U815F;W-x z_SL*tq=uHgzf4ZEZjsuv0o8vwLCI%lCAZczfuA9%vMXshTJcB`{1z`-H(A$ab7qi3 z8PUbHazeaE?3qE<6MG^;W+9(_DQnw3gOd7#k{%uuHKi@OnvWQ>ufh;57>a8g-tNO} zxU8bsOEPnh1SU=Nq=9@#y4PIu3_8Ly9sHOPs(PSPqsMJaBx8-InA@C^gFRofr~1{P z{uKvkFxkb`vgwjw=vJ_4Z9QALdqe)_jKFP{>y;DAczdKBjuO*hz&%>IywZJGQ(t*{ zlf{VDkxI7WjN0|Sh9{YilJ*;~T%HksO zb^al22o|dG=9KJ5-0JfN$80o{lMyV&MS-2iSc74HM(zDQ16Ru*LyMl}LHh?S)zk5_ zcQ;>Kwb*PI#qrve!#5dExny7bnAhmvJyJ8EaKS52Wk0OhVvk^8tAmuW__qTwiQxW~rZ0{32GI_PNj%mlcz z&oSy){n{EO*8jb<7%dszglb2o`6oAK*@Zi; z4L4#zl0K^v24PDB^CG4apHQck3@BOp>y8UPCf40+ee7|k?@&4Gdhp(dXB{p+c&_SF zIyFT*<4}@gp`xlnJCjqAqn~q=0F2LVKSO(@YjGwA=&ZjFO?j2{E&h_Q=#lH;Dq7fH z{?^fAtoKW`+SXr0Vt3t{xD}oDrT1a_gu+;>v-Sz?l*8^f)CKZJO`$%(B8q>~HiZ z$iYyXVp}k0-bC4xHg`1}b*)rxYckca{&{DG6_L7Do)OVos^F;q9;Z@})> z{#qL9i-^$Rsc^7k#Z>k&YD{R1XHS+aW0N+$dv6yBajSHR55jKWd3{EbDt1xXt>(N} z?Q{8(+l!GhOldixZrh>dEfuMwa|M-~T$e0<3DO;Rrc3G+GS(=lUtVEAoyNj}JMT}% z84LW7<;$yP;RI&zROZ>U1JyiVkV>J7_;Qy)_d^AL!u@kttPD{F&fW@o9+%iR7_R4{z71rf4Xb)dXv2c$PanF zpwafN(2ZePQ)+G7mB%fcvaWgSQf{g(eMF;MPVI3P?N1VAA6w9Ih#B8VrY?SH?cQGRr{VEIVpcCT_;U53{? zx5jtkyt?RH>n}$t=j43QQRwAL-O)=SWxt-=TA_?qI~#rAZBEfuQNQD5Y|k-$%5a;E z#_r~{$y|*oV$P|{UC*np$k8J-+$4`%(D7Akvvl5U&h8szrpaYi&wVm=xCf!tiJaKV zEhN{~7aKJt%*C*7YHqw3w?DdYmRMpp)MM?CjIkL4mm!xsVDVwHHGOIZyGoi{_)pbulDfd zYUO86GHaW!2rp*sIIN#xTu_kZK(-&#V6|V7J5S3#)O>EuTa#W;=KR13VoAvz>`f!F z$FkM~(&e?ve5-Q@7}AAXQU*8FFL)|D2;;l`DfjoU5t&(iFS9H#P8a^R%$;CfD9qk7Z+3$@0w-_nI;?6jXq_ zP<`E++B%rr`sE_WAJntU{L)WCPow(N_12VnyP( z{%BO&R-{<0Gx4~xU5kUF fF6JNKBaFsM`0ZzQC{nUl{xPzk*pkc5yb}HgW26-Q diff --git a/index.rst b/index.rst index ee3dc262e3..327052a602 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/564] 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 zcmcI}2{_bU`#+VCWalAUBeD&%Zw$?hu?wZFVKzH6jWvq0mnd11qHL9vP?juZsZ`3E zvSy2rog`WQUp+m~`}}_I^FIIg`d`<7u50Ex-}AlC=f2N8$t>jkIpVFMyZVYBoE@UX*`U`F8JD89(IM&SaUd0B?G zz8oBULR(+XFuGGB(AVm2W#eaKW{RURy)`IwCY7NP3EPe(hOq8A~D?D4TIT?Bf*EPXu+N|EFGk)Bd;BV0|2}keiZp2Z!aHT zTo4}g6Bh@xx4Jb!@;^oVJnK!CKL{aKyeTh4vCik^#K9e*mM`%VLkm{x_~D<$j#4>h11jw3=Gr=gljO_u9{FR z7QldM!eC%P0_=Oz$Bz;O_VHEt13{1BOJlpU{M?y7@>_@$D%0N&4+1RxeG1;JKVf}* zf4K>8m}U@#r3ux5Y)$D8K{K;|7WMZ2Q`*;$8~|wfW$)ht`&yl3F*FY|e3|}i8iO3b z@bOdlLmA7B>BsbSWBv!*{(SvEETq%^RLJsYd;N3|ou^VviL)zJPeq%yt1{s51kq4tFmR$uK^4_iXQ_HfnFjS78(wg0zBQaZof42KgVtOuD`hug9eMZ+T*C z{O`1-Gid4IxWdIpg6ZHQ+ng5RN|2~<&U4Z{>9H4*A2EPybUz5??O02&# zO!I$}?_VtcW2F#)HM~Vl-(N8$Qe6Lxt`1ZWfr29SVMGK03PWL_aD6xuMIex%Xkha| z>SMHj>hf~`*9Zg@PQbt*WCR?IL}C#H5(I)kVhIR6Bn*v2p!NP{1c3-aqaiR1nG7Q# zNF*`_iPA%2v2Y9$4kZz>|2_hvPekjX;6!~QiHOjH5{Pv0LlOE&A`t__La+#kKJ4Fh{C!G-VlZ@s3mpxHQ6N+>7KxyPu?#c} z3j8_zpkNdff&%$>tUr<(1Pa3d zp`nB6G{6W3Ff%Zgg2I5QSQLbTc5%T_8MOaA8Uu&Y=m-QFOl2S#U??5ufduEV6)yKg%?R50E+7KoJJLs-@1sAy#0dN3aTV zobKnfIePR1$DrcPY|PoKBcHt(cJeMB!?75S^YRfeWsm&WycCi1c6OUiS9eWrB9(bS zH_s@jMjS~!-JI$Y&LHNECJ&#vb9OyYrcAD{>EpOebIoV=hu($`TW&cGkot0W$aHDJ zdd{{;!NXiO#hW6;*zTN2eV%-na+VPB?rvkZ$V;jb!czNkU*G)MomuHMa>Xh1Y)#0w zx^qbfvIbo^Z4Q?j#HS-~ntgfSdfQxXyuX*r%iFsLh&PFdbfK_(;vZP%0_95x? zBUcJpi(_WuwmYv+&3^6iY`tTturgZDwK7vR+ZFOmTq8|jr12sxG2l=Jj$il2rsUoH zjS$nX;631Ubc`%MxJc`T@7fCQ%T1)y^y0}ko&FpMx7IV{v7sMFZV#?~Ule=tgkMIA zxVf?3CG%ZWLV^?;s&ifIo5~S0aS679{TO`my?Zkq$JG z%vk+8%{M>qX-n7cExX-d&orYYR$hg>*1nrlQ9rDsj+PpnR8kZ&>$q(mQGS%kt_WSn zomzZLSedNl#Q2UG93?g-=`U2)M%@nZ?yWb`e7d7>`_6+cnfRNb>#I{W3zhy~#H)L1 z4)i?@yV0-m5QW;gbN6@)h>?}CO%>_+K5~3qxs)EQjmOJ_K;h)*miJq88XouXxcf+us!GTv<$oIzND}ob-{pjICS|ZMKuV+A>c5p@$1)Z za(&WN^CiEOXXo46+c%6`=Gf$F=x$oSeEE`|STaO1@G@18d-wf&f)$>PD>Bqw!S!}@ z)Vb!~P&JAst|rKo9O`hW2^PDYgs$b8O@xHje_?$Zw_KK8_)QTZ77{YwXEEJVn&s19 zseX60$mX}tf+ycA?oWHZe>sa3GxTnvLtQmOVYs%oO})KkNWq}CMVI5_Dc^KUebaQ- zUh2VGw=^hC+~LWotNn_A&8($;tArZ%=y`-DRb^^=x~{SD8hMh{Rx7Q~b>hT)Uswyl z$EUT-+g^NPY^J}eXs+fPWocX<6EKCT`r+r%d6x@p_vq63;uCGR&1XNhmYd53O_yf2 z`*DZ*^r%-44nUD${^*dCBo`O)D$j1^tbAv1ccnkC`r&fwsOro!x1-|1();60PwF`x z$b0z~&;4V0)-|zmaPVM2-d^>#`LBGJgq51F;dv9LPAr^yaUn2|oQbb`=sfVTzsR>S zpsQjZudwj&QKuG+;UVM5`}U~yZ|nBuKG6cY4!bu(pUgc7TaP=9fUf1m`FfdL0lNmO zODG~-+J>JOd7Tt>s1CBU8>*AL5cn};pV>=0skMD<-@PwE{uRk#L-kzZD(2L~m#x@0 zc?}NsSNhWumsuMSi1Kf2HoHrvI1?XY9CA9))zwHXoOy`<%CW)|eoA&cL`+O~5ryQg zgT^THq^f`4Q38YK=EfZ1#MBqOIWMM08GB&%j8b>I_F%Q9eBds)*#@m>sxL{Bps9*m35o z3C8tS3p?cK+(MIPT|u}If9ihc1&j3LWYHN_+BMXDN~=6t+@1T&4u!Gif+Zo5&(G%O z=bJQjA_|XZbRTc<{7@)!YGK~sZeu6^;MAKind>o&QaTsNsWHM*L-lP}?>O=$=?4en z;*vSTgcJ)xTTgCVTfebV@ggZDgFi8m&*mBW#PHrr=_Q2pL3FCM9}`8^vZ|`d|YNTus1ocE|upA^UIoE zE-r>b-gG4OLuDLzh z@9f?}3K^>y3anXdVf^KNiOJOAg0dA<4Ei?_c9@}5oZ9&3r>vz*NoA;#TDTXS`}E#XQL!+_vBr_s)**?+8BV@`6TwwtbHs($XW$9{`f63ZQ`q|R zndG`kjJl#_wy{Y1byho4d(G_O?1~33FMkcv8|T$qmO*B)h^J;Vz1-g4ldPgSWIx!K zn&CB2mSS&mApB`{WAwr%xXM3-3*f7@-S%TCX`V#5ZTC)DZnQ32HZHb3YR94kH)|VS z<*Jj$KJ*&Jr1#M|@}yo=UCQ_2rp_s2ndav;n;(gBMlNG-=)C;EeU6=}r>t)bS5Ee0 zg+AG616e71yB;O?Yw1dTm3iL#zyam>Q!6}MnRe9}d@FW=SEMH=d|QRM5T^uQdoa7I z>LW93=T2f<`9R4<$6a#P%2`*r@A>cImuUiMfemgtHj*hA?d$SIBnimh7-fquJw?;K z?T@QC=SCu<%&0<^I0~^!`vjTJ;`BNo_l;@|DdukiU-l&KE$T(YAXx=#=t{ef$5_55VsMc`O z@0*4w@3Bj<3*9|E#6h=EgWiX(E%j%&J3TaX#9Xe=*rnYNBOrphBl_yqt0-VkE;j6U zs~fnYoCL`_n)D@CQYz&tQdifBlI49$`)O!X>!HlGgkDAQD)$`;@1H14XEnrhr{MYy zz02c!iqx`HI`O`p9W|c+>g$Pfmd*y9i8^ZrmCQY|k#N`MB10WdDzz&GcQ5S&Bc@3} zcdq5w^TYhdQKcdsiSEDY-z^y&boR+1o)R@RzFZ!;{hG;4Z{w`tUR>%^H%mz`5&sSC zr{e9lBchP(Q^~Ed?~Bah$8S1ne>ZFVdwARP6{f|GE<8Va$Sg?qOkVjg)Bu1zH1`g4 zpw9NzxpPJ-nWzV9Ugw&>7{=AC;_=!xxiXfYk8Ae`YIzDS5_#jtz3L-R0Bq8!XShf$ zTTuIcyHTW*NS>UVb3T4xmW*$inwqpQKM2vM(LhO?_S%4|f|{n!$$*0%ek` zrKB|Z`;Q;Rh9LqwWSl(iUcOouLO3^JNmRf!SXvtLJUt6aWlC$`dD3Yn#~YsMDl0p) z;I|5iphq9q*S|2AKUe1aS!4Ntx_}}gTVhtov0ne?iTU{{W8EOTA8k2}HdZfQywJD1 z-Wn6{yf3SwVz@igIO)a}P5;TxQ&p$PPma3e0k!qg!W(!C&qcF_`xeodWSd9Z>+-BM zYwXSAP{kwJJ7;UDiusNix{a=Pw8{7?jdEIoEXj~`z$-3l*I@yCfp)5M4u!+yk%xf{|zYcYMYxAfMh3Y z_DC{wYsqy=zIXs`k14Iezhj@ESmqmv4BRxUJ<2mv@JXy^ILF?huS2Yd3M8bw&d7em zi^#c)9Ua_-epIu)0zR>y{YT_q@7H$w?Z>9XJv%OemK&~tOSC*=yRYF9b;~K%T^TUU zy+*s7fv~4M&lRJwZrcT>D(0HFF#fBL?k&ovvRjK#W6klA&vMTnfDIkXzi?bD>#d0X zDCJ0f9?1gn^~(o=;gJ;u^y#61ER~@nz}8X|#pm2tVIi&(GycQ1?Z>Q9>DkqrNgZOl zLRwnV@!X-S6RrV`Mao%6{bu^i2Zyj1>~+P(QIcbCGM{IkZ!QQu3v3#ZG1tvT(%wMw zUvU~xB4R3h%`bcOJmRIhOkM7|sK%@K=)CEZ*D7dr#o91uhbV;?^J|MOgc~|Fwz(P% z+OBfZ5vbSDTN4+}Co9>LwAbHAk#YQlvuoRrZLBTA)GwZQ5we8Et*A8WM`Fy07e0UG zUGp}wQCCZMYt$?E-~03u$|A+<(?*`CsHk%Miy)Tn#D{@X4WMkRl;*7d3klKOx6SwF zMm88D9hi`lur8d|L#@0G71i)-YS#7ZA_sOa;=WE2PIn3%xzFyUvPwN(S_H0qcWuxO zXjeGkWMss= zYrf)=(J7PjS)Ii+3)0uL@C^-(=qwUmIZLv8?5+Labl^uuVr5qva&QuNhMX7mh-9^? zUp*r|bfn(-{k^N|mnD>_PER=~=XeiM?wQA0KYOhW_&k!fQZ+F#^_peu^D#0zg4;G% z>QerbbA0@LcO`+MLtsV*QwyT1rlpZ{B;N`rO!Zeie)Xog5VeDwyVx+)MruJ_?gQBp(X{i<{Bydvpd(=km~ECx$WA1q#+M1!GVQ~jK6+iY@Y2FnLFzF7>v_IL*@ zTUB#|9%JW=r7sOPXb0*KRntg~bt!7rT{79C!?wpB3#X4YrcC(Xk*kJXkP@rCU*EXD zEWq1cxB;KEa*J1j^F@5e1BLsA;Su4g;Nj;jA9S5XrFGbm{ZJh>&p4Zoj$Nn8vGT}T6;R#d)oGW~0OX};1X?RzSsqU&P{gx7UKR+vbGUw~~7-Z)?PZXIkJeT0e z>8MamX-vpyKVNyhXfCK{seGSbU(k$-4UYs$T?|0dQa?Z4Tdo=Rj=^A@(CR5;4#@7@ z^C_?nspKHNvi2}6;^IYgRl}8QA$#g?KjBrVuAz*)5S^L4sdMN$MrAr^eok7$EBL!j zf3Sad%4k;Pt%L86vV8XMx2ZB4&HF5>oKq?)i>W@{Tf7u9yg5Uw_$7iB zDT+0(Zodsag;=zT*I=`6^u4dlnharXKEYc&)!F0_Inq-VC|CV$12mIqE@W?S@79(b zwG_Q~v3T8bdq_y9Hc3hV|VU zm&{$xB!e%8Kg*>jwO9{%=#+V-Lr0Fg8$@MUrM4zJ&u4$5?7mHc;n~6(mXv%Q;4UDu z>$(v794*dU(Q|x|BThmy{9ST94BjNO!$ z=7zQdmjPrldFpjh5m}&F<=hT#t`fDyp{c3eYS}sRT56z(UTcVAKxpm<5SZh&%XFzJe?R}CaKbEJRH`WZrCEveJ zDX7reZdc}^;(f1hSCw|5W6dtt<~1JOOuX9tQ)8pY&j5!sllc87gbpq??(zJ{`r6uD zn6PA%5C_u?nB`z~g8 zrae{?c6EBZJ7ZVVdC~Hkw!3h7+s!f-2(5AgzdLp43yG)gVv*N~C4sYVWvQb*se>PK zzMdXEDpl&>(3Nqxed4gmmHLS5(hb!Ks_vb9yM~pF)q872N*2S`Q$lzOc@Ax$neTU3 zejDF&+Unfp$|2!w(|X{>bKjVLwemrpeJ;^|xdi>o-RQQ#O-_%yJ;LLDH Date: Mon, 22 Jan 2024 20:38:21 +0100 Subject: [PATCH 129/564] Update index.rst --- index.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.rst b/index.rst index 327052a602..14eab0e0eb 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/564] 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 cfac98157a..7006ab1e5c 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/564] 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/564] 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 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%0D1FikzWIVS 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 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/564] 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 2163e64ff1..b8a1b33661 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 aff4d5fd1d..bb3bc9a3ef 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/564] 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 bb3bc9a3ef..3bc644841b 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/564] 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 3bc644841b..00520660b4 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/564] 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 00520660b4..7fcf3b35be 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/564] 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 7fcf3b35be..a3a0f4f1ab 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/564] Update lvgl.rst --- components/lvgl.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index b8a1b33661..66c35dc8c6 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/564] 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 a3a0f4f1ab..dda4841a6a 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/564] 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 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 diff --git a/components/lvgl.rst b/components/lvgl.rst index 66c35dc8c6..6d5df25bea 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/564] 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 6d5df25bea..862934adf6 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 dda4841a6a..2ba4ebed6a 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/564] 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 862934adf6..ab35aaa57a 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 2ba4ebed6a..f623f78452 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/564] 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/564] 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 ab35aaa57a..4a7105cafe 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,23 +1295,51 @@ 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`` + +You can display the embedded symbols easily on supported widgets using the ``symbol`` configuration option: -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 `__. +.. figure:: /components/images/lvgl_symbols.png + :align: center -In ESPHome you can also use a :ref:`font configured in the normal way`, conversion will be done while building the binary. +.. note:: -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: + 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 -.. figure:: /components/images/lvgl_symbols.png - :align: center +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/564] 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 4a7105cafe..f528313918 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/564] 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 f528313918..4eb1c73585 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/564] 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 4eb1c73585..de993aabca 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/564] 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/564] 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/564] 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 de993aabca..24d38c2fd1 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`` +**************** + +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. -LVLG supports numeric properties only as integer values with variable minimums and maximums. Certain widget properties also support negative values. +.. code-block:: yaml -- ``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. + 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/564] 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 24d38c2fd1..45781f6c80 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/564] 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 45781f6c80..98def38ffa 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/564] 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 98def38ffa..9b1f22ef3e 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/564] 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 f623f78452..d734592ff7 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/564] 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 9b1f22ef3e..cce1e5c19c 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/564] 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 cce1e5c19c..3dcb9d36e1 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 d734592ff7..0444ecc659 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/564] 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 3dcb9d36e1..359f7b4efb 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 0444ecc659..2097e75cc1 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/564] 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 359f7b4efb..1b37d4191f 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/564] 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 1b37d4191f..9be088a382 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/564] 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 9be088a382..a10a47354c 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/564] 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/564] 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 f7e69b0e44..750b91fbe7 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/564] 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 a10a47354c..308f66ff52 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/564] 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 308f66ff52..bd96d77474 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/564] Update lvgl.rst --- cookbook/lvgl.rst | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 750b91fbe7..7f74e364cd 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/564] 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 7f74e364cd..6f41ce76bd 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/564] 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 bd96d77474..af6a0d32f8 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/564] 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 6f41ce76bd..4080732df7 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/564] 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 4080732df7..4aaf042979 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/564] 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 af6a0d32f8..2caae1099c 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 4aaf042979..c9ebb11fcc 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/564] 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/564] 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 2caae1099c..cca32f6941 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 c9ebb11fcc..3cf2adebcc 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/564] 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 cca32f6941..311075c003 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/564] 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 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�mC--jru?QR%Z-ks^7g4MdQAtNoYtSXsU9g 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 TWwwh?U;qM7S3j3^P6EpQe* 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�rqIG)qoz_`$^SBHI&#hi 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 diff --git a/components/lvgl.rst b/components/lvgl.rst index 311075c003..2776a5d722 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 3cf2adebcc..bd8313b4a2 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/564] 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 2776a5d722..091c8fd02b 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/564] 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 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^P6 Date: Mon, 29 Jan 2024 11:57:03 +0100 Subject: [PATCH 177/564] Update lvgl.rst --- components/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 05605d95af..a75bc7aae1 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/564] 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 bd8313b4a2..072f4215cb 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/564] 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 072f4215cb..17c93339e8 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/564] 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 a75bc7aae1..033ec8cde1 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/564] 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 033ec8cde1..7233a43612 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/564] Update lvgl.rst --- components/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7233a43612..9e71526505 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/564] Update lvgl.rst --- cookbook/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 17c93339e8..c6404a9cac 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/564] 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 75bc582462..5f07a00246 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 9e71526505..7337eeb5e0 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 c6404a9cac..adc2684e6f 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/564] 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 5f07a00246..52520d7ad3 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/564] 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 52520d7ad3..aa1b82bd68 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 7337eeb5e0..3cd522fcd2 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/564] 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 aa1b82bd68..51b44aa374 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/564] 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 adc2684e6f..b395dd8f82 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/564] 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 51b44aa374..491810bbf1 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/564] 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 491810bbf1..278ad946d8 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 3cd522fcd2..e795b61475 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/564] 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 278ad946d8..f06bf8cb65 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/564] 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 f06bf8cb65..29cd3961d6 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/564] 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 29cd3961d6..598c66ff07 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 e795b61475..4eb1216fd9 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/564] Update lvgl.rst --- cookbook/lvgl.rst | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index b395dd8f82..3e848b84a6 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/564] 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 4eb1216fd9..3e0db80977 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 3e848b84a6..d43f65a16f 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/564] 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 d43f65a16f..a6702d404d 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/564] 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/564] 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/564] 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 3e0db80977..476cb8bcab 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/564] 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/564] 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 476cb8bcab..45ba0d710b 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/564] 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/564] 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 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 literal 0 HcmV?d00001 diff --git a/index.rst b/index.rst index 14eab0e0eb..8c2d887213 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/564] 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 45ba0d710b..6aa4a3dbce 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 d9c90b67dc..94a0f7ca2f 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/564] 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 844cc55cd6..97e844617a 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 7c26363372..42a9287fef 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 45d81acf71..a7f9c05316 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 44c41b4586..e677557e43 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 b12724ca04..2041d368a7 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/564] Update lvgl.rst --- cookbook/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 94a0f7ca2f..05cba64d87 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/564] 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 0000000000..53c292573d --- /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 05cba64d87..f2b0505cbd 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 0000000000..8ae4d41d23 --- /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 8c2d887213..e1b9c34cd2 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/564] 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 598c66ff07..8b0ca091b3 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/564] 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 53c292573d..b4a0f04d47 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/564] 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 8b0ca091b3..24d645212c 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/564] 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 24d645212c..4ea101926e 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 f2b0505cbd..283c8d90b0 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/564] 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 283c8d90b0..bb9f955118 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/564] 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 6aa4a3dbce..26b27f60a6 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 2041d368a7..43c412d1af 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 bb9f955118..81bac27d52 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/564] 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 b4a0f04d47..41c815ccb4 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/564] 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 41c815ccb4..7ca667d4e4 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 26b27f60a6..f3d18952da 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/564] 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 7ca667d4e4..087195bc4e 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 43c412d1af..912ad92b30 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/564] 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 f3d18952da..1e206d6eaa 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/564] 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 1e206d6eaa..8e20a6e6ca 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/564] 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 97e844617a..7c0ace7879 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 8e20a6e6ca..a91499c360 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 a7f9c05316..e1c3f94920 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 e677557e43..5571c77360 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 912ad92b30..dacd8d0fc0 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/564] 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 a91499c360..951f11d45b 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 81bac27d52..d4ba73d4fd 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/564] 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 951f11d45b..b9e9242d93 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/564] 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 b9e9242d93..1e9b779e92 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/564] 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 1e9b779e92..ee90b6118a 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/564] float thermometer --- cookbook/lvgl.rst | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index d4ba73d4fd..99e8016a74 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/564] scrollbar_mode --- components/lvgl.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index ee90b6118a..bdc77e1592 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/564] 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 bdc77e1592..1e3ee6a6e6 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 99e8016a74..34a950decd 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/564] 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/564] 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 34a950decd..3a961e1a84 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: - then: - - lvgl.widget.update: - id: btn_lightbulb - state: - checked: true - - lvgl.label.update: - id: lbl_lightbulb - text: "\U000F0335" # mdi-lightbulb - on_release: + on_value: then: - lvgl.widget.update: id: btn_lightbulb state: - checked: false + 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: "\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/564] 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 3a961e1a84..2a6cff2012 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/564] 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 1e3ee6a6e6..e361d645b0 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/564] 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 e361d645b0..ed3b1c520f 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/564] 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 ed3b1c520f..4f23b99e6a 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: + - lvgl.page.show: main_page + - timeout: 60s then: - - logger.log: "LVGL is idle" + - 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/564] 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 2a6cff2012..375c649ac7 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/564] 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 375c649ac7..9623f55828 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/564] 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 4f23b99e6a..0b81aa7b42 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/564] 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 0b81aa7b42..b01a4ae1a8 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/564] 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 9623f55828..e3b753dc14 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/564] Update lvgl.rst --- cookbook/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index e3b753dc14..e01b73c75a 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/564] Update lvgl.rst --- components/lvgl.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b01a4ae1a8..55ab4710e6 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/564] 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 55ab4710e6..788223984d 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 e01b73c75a..3853c264dd 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/564] reorder widgets --- components/lvgl.rst | 749 ++++++++++++++++++++------------------------ 1 file changed, 347 insertions(+), 402 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 788223984d..c397d0c1dd 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. - - -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:: +- **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. - 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. - -**Specific triggers:** +``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. -``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`` +********** -Images are the basic widgets to display images. +Roller allows you to simply select one option from a list by scrolling. -.. figure:: /components/images/lvgl_image.png +.. figure:: /components/images/lvgl_roller.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. +- **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.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.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: - - img: + - roller: align: CENTER - src: cat_image - id: img_id - radius: 11 - clip_corner: true + id: roller_id + options: + - Violin + - Piano + - Bassoon + - Chello + - Drums # Example action: on_...: then: - - lvgl.img.update: - id: img_id - src: dog_image + - lvgl.roller.update: + id: roller_id + selected_index: 5 -.. _lvgl-wgt-lbl: +The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. -``label`` -********* -A label is the basic widget type that is used to display text. +.. _lvgl-wgt-bar: -.. figure:: /components/images/lvgl_label.png - :align: center +``bar`` +******* -**Specific options:** +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. -- **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. +.. figure:: /components/images/lvgl_bar.png + :align: center -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. +Vertical bars can be created if the width is smaller than the height. -**Specific actions:** +Not only the end, but also the start value of the bar can be set, which changes the start position of the indicator. -``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 options:** -- **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. +- **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: - - label: - align: CENTER - id: lbl_id - recolor: true - text: "#FF0000 write# #00FF00 colored# #0000FF text#" + - bar: + x: 10 + y: 100 + id: bar_id + value: 75 + min_value: 1 + max_value: 100 - - 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()' ] +The ``bar`` can be also integrated as :doc:`/components/number/lvgl`. -.. _lvgl-wgt-led: +.. _lvgl-wgt-sli: -``led`` -******** +``slider`` +********** -The Led widgets are rectangle-like (or circle) widget whose brightness can be adjusted. With lower brightness the colors become darker. +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_led.png +.. figure:: /components/images/lvgl_slider.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. +- **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.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. +``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: - - led: - id: led_id - align: CENTER - color: 0xFF0000 - brightness: 70% + - slider: + x: 10 + y: 10 + width: 220 + id: slider_id + value: 75 + min_value: 0 + max_value: 100 # Example action: on_...: then: - - lvgl.led.update: - id: lvgl_led - color: 0x00FF00 + - lvgl.slider.update: + id: slider_id + knob: + bg_color: 0x00FF00 + value: 55 -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,176 +1126,132 @@ 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-msg: +.. _lvgl-wgt-img: -``msgboxes`` -************ +``img`` +******* -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. +Images are the basic widgets to display images. -.. figure:: /components/images/lvgl_msgbox.png +.. figure:: /components/images/lvgl_image.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): 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: - - **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. +- **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:** -The configured message boxes are hidden by default. One can show them with ``lvgl.widget.show`` and ``lvgl.widget.hide`` :ref:`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: - 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 - text: "\uF00D" - on_click: - then: - - lvgl.widget.hide: message_box - -.. note:: - - 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. + - 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-rol: +.. _lvgl-wgt-lin: -``roller`` -********** +``line`` +******** -Roller allows you to simply select one option from a list by scrolling. +The Line widget is capable of drawing straight lines between a set of points. -.. figure:: /components/images/lvgl_roller.png +.. figure:: /components/images/lvgl_line.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. +- **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. -**Specific actions:** +TODO invert_y ??? -``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. +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: - - 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 + - line: + points: + - 5, 5 + - 70, 70 + - 120, 10 + - 180, 60 + - 230, 15 + line_width: 8 + line_color: 0x0000FF + line_rounded: true -The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. -.. _lvgl-wgt-sli: +.. _lvgl-wgt-led: -``slider`` -********** +``led`` +******** -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. +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_slider.png +.. figure:: /components/images/lvgl_led.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. +- **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.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``. +``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: - - slider: - x: 10 - y: 10 - width: 220 - id: slider_id - value: 75 - min_value: 0 - max_value: 100 + - led: + id: led_id + align: CENTER + color: 0xFF0000 + brightness: 70% # Example action: on_...: then: - - lvgl.slider.update: - id: slider_id - knob: - bg_color: 0x00FF00 - value: 55 + - lvgl.led.update: + id: lvgl_led + color: 0x00FF00 - # Example trigger: - - slider: - ... - on_value: - - logger.log: - format: "Slider value is: %.0f" - args: [ 'x' ] +The ``led`` can be also integrated as :doc:`/components/light/lvgl`. .. 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`. + If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. -See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider to control entities in Home Assistant. +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: @@ -1326,20 +1297,20 @@ The Spinner widget is a spinning arc over a ring. id: spinner_id arc_color: 0x31de70 -.. _lvgl-wgt-swi: +.. _lvgl-wgt-obj: -``switch`` -********** +``obj`` +******* -The Switch looks like a little slider and can be used to turn something on and off. +The Base Object can be directly used as a simple, empty widget. It is nothing more than a (rounded) rectangle. -.. figure:: /components/images/lvgl_switch.png +.. 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:** -- **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:** @@ -1347,93 +1318,67 @@ The Switch looks like a little slider and can be used to turn something on and o .. code-block:: yaml # Example widget: - - switch: + - obj: 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`. + width: 220 + height: 300 + widgets: + - ... -See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local component. +.. _lvgl-wgt-msg: -.. _lvgl-wgt-tbl: +``msgboxes`` +************ -``table`` -********* +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. -Tables, as usual, are built from rows, columns, and cells containing texts. +.. figure:: /components/images/lvgl_msgbox.png + :align: center -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. +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:** -- **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. +- **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. + - **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** (**Required**, string): The text or built-in :ref:`symbol ` to display on the button. -**Specific options:** +**Specific actions:** -- **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`. +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-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:** + 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 + text: "\uF00D" + on_click: + then: + - lvgl.widget.hide: message_box -.. code-block:: yaml +.. note:: - # Example widget: - - obj: - x: 10 - y: 10 - width: 220 - height: 300 - widgets: - - ... + 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. 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/564] animimg --- components/lvgl.rst | 54 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c397d0c1dd..7e9853714b 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/564] 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 7e9853714b..020adf5db6 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/564] 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 020adf5db6..9e3fc99415 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/564] 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 9e3fc99415..2cb69baf8a 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/564] 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 2cb69baf8a..b3f5711e69 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/564] 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 b3f5711e69..1585784723 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/564] 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 1585784723..2de5bf9a30 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/564] 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 2de5bf9a30..ae5ffff559 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/564] 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 ae5ffff559..4a052c7b25 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/564] 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 4a052c7b25..f10490ddd6 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/564] Update lvgl.rst --- components/lvgl.rst | 47 ++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f10490ddd6..0be12cd435 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 - - * - 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:: + :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 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/564] 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 0be12cd435..2024602f81 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/564] 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 2024602f81..d374817cae 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/564] 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 d374817cae..982ca3cab6 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/564] 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 982ca3cab6..4a45d958b2 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`` - - :doc:`/components/number/lvgl` - - * - ``arc`` + * - ``slider``, ``arc``, ``spinbox`` - :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/564] 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 4a45d958b2..83cf798087 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/564] 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 7c0ace7879..77eee53ccc 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 83cf798087..5983b51fb2 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 e1c3f94920..014a1f5e1d 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/564] animimg updates --- components/lvgl.rst | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 5983b51fb2..a296847525 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/564] 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/564] 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 014a1f5e1d..72f882dacc 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 5571c77360..baff5427c4 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 dacd8d0fc0..17bf232d19 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/564] scrollable flag --- components/lvgl.rst | 64 ++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 75742856b8..eaeeded7b6 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/564] 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 eaeeded7b6..0354767cca 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/564] 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 0354767cca..bde88f42aa 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/564] 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 bde88f42aa..f4a50f397c 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/564] 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) 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 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/564] 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 f4a50f397c..1b049f3f6a 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/564] Update lvgl.rst --- components/lvgl.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1b049f3f6a..afc9621684 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/564] 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/564] 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/564] 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/564] 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 4f19b346e7..309345ba1f 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/564] 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 309345ba1f..d2e58a8fb4 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/564] 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 d2e58a8fb4..9d4017f6ce 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/564] 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 9d4017f6ce..573db6f1a3 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/564] 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 573db6f1a3..4b28a0b7ed 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 5105f0a93b..4f59ba7a54 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/564] 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 4b28a0b7ed..985faaadba 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/564] 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 4f59ba7a54..751c29a097 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/564] add lvgl.bar.update --- components/lvgl.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 985faaadba..4b9e6f19b4 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/564] spinbox --- components/lvgl.rst | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4b9e6f19b4..b3db374975 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/564] spinbox --- components/lvgl.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b3db374975..da5dd737e4 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/564] 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/564] 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 5ed984483c..0a77323074 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/564] 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 0a77323074..b3c3c5c7d9 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/564] 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 c7a60234b7..8a64dd8ec1 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/564] 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 b3c3c5c7d9..9abebd634a 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/564] 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 9abebd634a..18102c2baa 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/564] 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 8a64dd8ec1..e97dc59e1c 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 18102c2baa..faba64e5b8 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/564] radius tip --- cookbook/lvgl.rst | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index faba64e5b8..9cda55abc3 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/564] 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 e97dc59e1c..3db125a3ba 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 9cda55abc3..0e7965007d 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/564] 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 3db125a3ba..5410fcfb64 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 0e7965007d..215ffda3f2 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/564] 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 5410fcfb64..ee4ea1d5f9 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/564] 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 ee4ea1d5f9..81bb8cee9c 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/564] 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 81bb8cee9c..6456c4311a 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/564] 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 6456c4311a..a575850953 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/564] 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 a575850953..1c3c159890 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/564] 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 1c3c159890..2405d9a3d6 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 215ffda3f2..358383877c 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/564] meter upd --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2405d9a3d6..9d23f7d997 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/564] meter upd --- components/lvgl.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9d23f7d997..5c4b887c97 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/564] 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 5c4b887c97..a4044e2bf1 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/564] Update lvgl.rst --- components/lvgl.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index a4044e2bf1..d2691266a7 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/564] Thermometer fix --- cookbook/lvgl.rst | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 358383877c..5cf50b25ef 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/564] Thermometer fix2 --- cookbook/lvgl.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 5cf50b25ef..f87725ce9a 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/564] 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 f87725ce9a..4b5b962bcb 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/564] 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 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 literal 11500 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 Date: Mon, 22 Apr 2024 14:37:02 +0200 Subject: [PATCH 306/564] Update lvgl.rst --- cookbook/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 4b5b962bcb..89f9232a45 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/564] Clock description --- cookbook/lvgl.rst | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 89f9232a45..e70feef7a0 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/564] 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 e70feef7a0..7cdd243537 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/564] 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 7cdd243537..d7aff2c8f0 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/564] version bumps --- components/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d2691266a7..f80bf8016b 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/564] 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 f80bf8016b..de4e97111d 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/564] Update index.rst --- index.rst | 508 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 296 insertions(+), 212 deletions(-) diff --git a/index.rst b/index.rst index ba0a4b456f..99d26c1009 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:: - Core, components/esphome, cloud-circle.svg, dark-invert 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 + 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 - Network, components/network, network-wifi.svg, dark-invert + ESP32 Ethernet, components/ethernet, ethernet.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 +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 - OTA Updates, components/ota, system-update.svg, dark-invert + 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 - 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 - External Components, components/external_components, external_components.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 - MY9231/MY9291, components/output/my9231, my9231.svg - 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 + 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 - Template Output, components/output/template, description.svg, dark-invert - BP1658CJ, components/output/bp1658cj, bp1658cj.svg - BP5758D, components/output/bp5758d, bp5758d.svg + 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 + 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 + AM43 Cover, components/cover/am43, am43.jpg 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 - Custom Cover, components/cover/custom, language-cpp.svg, dark-invert - AM43 Cover, components/cover/am43, am43.jpg Tuya Cover, components/cover/tuya, tuya.png - HE60R Cover, components/cover/he60r, he60r.jpg + +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 + Template Text Sensor, components/text_sensor/template, description.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 - Template Text Sensor, components/text_sensor/template, description.svg, dark-invert - Custom Text Sensor, components/text_sensor/custom, language-cpp.svg, dark-invert + 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 Components +------------------------- -Home Assistant Companion 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 -Miscellaneous Components ------------------------- +Energy/Solar Management +----------------------- .. 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 + 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 - Sun, components/sun, weather-sunny.svg, dark-invert - GPS, components/gps, crosshairs-gps.svg, dark-invert +Electromechanical +----------------- - 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 +.. imgtable:: - 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 + 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 - I²S Audio, components/i2s_audio, i2s_audio.svg +Wireless Communication +---------------------- - 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 +Wireless communication that is **not Wi-Fi.** - 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 +.. 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 - Tuya MCU, components/tuya, tuya.png - Modbus Controller, components/modbus_controller, modbus.png + SIM800L, components/sim800l, sim800l.jpg + +Miscellaneous Components +------------------------ + +.. imgtable:: + + ESP32 Camera, components/esp32_camera, camera.svg, dark-invert 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 + +Custom Components +----------------- -Additional 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/564] Update index.rst --- index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.rst b/index.rst index 5799bad310..fb45e8de97 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/564] add tileview doc --- components/lvgl.rst | 70 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index de4e97111d..42204b37b1 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/564] 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 42204b37b1..83151b7bc9 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/564] 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 83151b7bc9..8661e8595c 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/564] 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 8661e8595c..32604867be 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/564] 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 32604867be..02d6950dde 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/564] 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 02d6950dde..689d676d6f 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/564] reorder items --- components/lvgl.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 689d676d6f..a8e274bcc9 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/564] 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 a8e274bcc9..e333ba1288 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/564] 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 e333ba1288..13ab0247e2 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/564] 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 13ab0247e2..ecfbd463f8 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/564] 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 ecfbd463f8..a184b94f53 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/564] 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 a184b94f53..d633d54ddc 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/564] 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 d633d54ddc..a73ff4d826 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/564] 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 a73ff4d826..82dbd7ae91 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 its 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. +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. 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. +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 fb45e8de97..8235737a9d 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/564] 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 82dbd7ae91..6c4e03e3b0 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/564] 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 6c4e03e3b0..c379a01252 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/564] 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 c379a01252..0aeb707e7e 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/564] 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 0aeb707e7e..98374bca3e 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/564] state property ref test --- components/lvgl.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 98374bca3e..25b1188fbf 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/564] 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 25b1188fbf..4221e39bba 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 d7aff2c8f0..d5579304ee 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/564] brushup --- components/lvgl.rst | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4221e39bba..3c19f6925a 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/564] 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 3c19f6925a..51caf2cbd9 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 d5579304ee..91fc902ca9 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/564] styling infos --- components/lvgl.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 51caf2cbd9..175469cd7f 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/564] 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 175469cd7f..fa41ec0308 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/564] 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 fa41ec0308..47a3a7234a 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/564] 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 47a3a7234a..ea7ec41e50 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/564] simplify color --- components/lvgl.rst | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ea7ec41e50..7784d7c856 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/564] font reorg --- components/lvgl.rst | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7784d7c856..9eb2434d31 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** + +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 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: +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/564] 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 9eb2434d31..196b548200 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/564] 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/564] 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 196b548200..ce01294525 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/564] 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 ce01294525..b813aea908 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/564] 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 b813aea908..c45cbc2b8a 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/564] 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 c45cbc2b8a..002d789fde 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 72f882dacc..b0e4b27761 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 91fc902ca9..da2ab74101 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/564] 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 002d789fde..7d803bf049 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/564] 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 7d803bf049..6ef5e1ad4c 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/564] 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 6ef5e1ad4c..cbf4929ce9 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`` From 4cd3c988c01350ed3a6ec476bf81a8e298c5733e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 8 May 2024 13:44:26 +0200 Subject: [PATCH 351/564] gradient gauge --- .../images/lvgl_cook_thermometer_gauge.png | Bin 0 -> 5872 bytes cookbook/lvgl.rst | 77 +++++++++++++++++- 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 cookbook/images/lvgl_cook_thermometer_gauge.png diff --git a/cookbook/images/lvgl_cook_thermometer_gauge.png b/cookbook/images/lvgl_cook_thermometer_gauge.png new file mode 100644 index 0000000000000000000000000000000000000000..6976d767d2e7529d13ab324c3c1f08f833a9107e GIT binary patch literal 5872 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 Date: Wed, 8 May 2024 13:50:32 +0200 Subject: [PATCH 352/564] Update lvgl.rst --- cookbook/lvgl.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 841f4499ab..72234bc84b 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -271,7 +271,7 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg height: 240 width: 240 align: CENTER - bg_opa: TRANSP + bg_color: 0xFFFFFF border_width: 0 pad_all: 4 widgets: @@ -279,6 +279,7 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg height: 100% width: 100% border_width: 0 + bg_opa: TRANSP align: center scales: - range_from: -10 @@ -310,6 +311,7 @@ The trick here is to have parent :ref:`lvgl-wgt-obj`, which holds the other widg radius: 73 align: center border_width: 0 + bg_color: 0xFFFFFF pad_all: 0 - label: # gauge numeric indicator id: val_text @@ -431,7 +433,7 @@ If you change the size of the widget, to obtain uniform gradient make sure to in width: 240 align: CENTER y: -18 - bg_opa: TRANSP + bg_color: 0xFFFFFF border_width: 0 pad_all: 14 widgets: From b3d173390db69fe2b7cd5677d3656c21a40b5af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 10:25:35 +0200 Subject: [PATCH 353/564] lvgl sensor --- components/binary_sensor/lvgl.rst | 1 + components/light/lvgl.rst | 4 +-- components/lvgl.rst | 12 ++++----- components/number/lvgl.rst | 2 +- components/select/lvgl.rst | 3 ++- components/sensor/lvgl.rst | 44 +++++++++++++++++++++++++++++++ components/switch/lvgl.rst | 1 + index.rst | 3 +++ 8 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 components/sensor/lvgl.rst diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 77eee53ccc..491a72a22a 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -34,6 +34,7 @@ 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 42a9287fef..febf82b3f4 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -36,13 +36,13 @@ Example: To have linear brightness control, ``gamma_correct`` of the light is set by default to ``0``. - See Also -------- - :ref:`LVGL Main component ` - :ref:`LED widget ` - :doc:`/components/binary_sensor/lvgl` -- :doc:`/components/switch/lvgl` +- :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 cbf4929ce9..8ccae4720a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -14,7 +14,7 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t 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 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. +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 have an :ref:`config-id` set, which will be referenced in the main LGVL component configuration. For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred) or a :doc:`/components/sensor/rotary_encoder` can be used. @@ -970,7 +970,7 @@ Not only the end, but also the start value of the bar can be set, which changes id: bar_id value: 55 -The ``bar`` can be also integrated as :doc:`/components/number/lvgl`. +The ``bar`` can be also integrated as :doc:`/components/number/lvgl` or :doc:`/components/sensor/lvgl`. .. _lvgl-wgt-sli: @@ -1038,7 +1038,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking 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 :ref:`universal event 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`. +The ``slider`` can be also integrated as :doc:`/components/number/lvgl` or :doc:`/components/sensor/lvgl`. See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider to control entities in Home Assistant. @@ -1120,7 +1120,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can 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`. +The ``arc`` can be also integrated as :doc:`/components/number/lvgl` or :doc:`/components/sensor/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. @@ -1192,7 +1192,7 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas format: "Spinbox value is %f" args: [ x ] -The ``spinbox`` can be also integrated as :doc:`/components/number/lvgl`. +The ``spinbox`` can be also integrated as :doc:`/components/number/lvgl` or :doc:`/components/sensor/lvgl`. See :ref:`lvgl-cook-climate` for an example how to implement a thermostat control using the spinbox. @@ -1959,7 +1959,7 @@ See Also - :doc:`Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/switch/lvgl` -- :doc:`/components/number/lvgl` +- :doc:`/components/number/lvgl` or :doc:`/components/sensor/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` - :doc:`/components/display/index` diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index b0e4b27761..b8788992af 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -30,7 +30,6 @@ Example: widget: slider_id name: LVGL Slider - See Also -------- - :ref:`LVGL Main component ` @@ -39,6 +38,7 @@ See Also - :ref:`Slider widget ` - :ref:`Spinbox 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 baff5427c4..7abe12b5d7 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -36,7 +36,8 @@ See Also - :ref:`Roller widget ` - :ref:`Dropdown widget ` - :doc:`/components/binary_sensor/lvgl` -- :doc:`/components/switch/lvgl` +- :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` - :doc:`/components/light/lvgl` - :ghedit:`Edit` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst new file mode 100644 index 0000000000..727b63951b --- /dev/null +++ b/components/sensor/lvgl.rst @@ -0,0 +1,44 @@ +.. _lvgl-sns: + +LVGL Sensor +=========== + +.. seo:: + :description: Instructions for setting up a LVGL widget sensor component. + :image: ../images/lvgl_c_num.png + +The ``lvgl`` sensor platform creates a semsor 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 sensor supports a single widget, thus you need to choose among which one's state you want to use. + +Configuration options: +---------------------- + +- **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 supported widget configured in LVGL, which will reflect the state of the sensor. +- All other options from :ref:`Sensor `. + +Example: + +.. code-block:: yaml + + sensor: + - platform: lvgl + widget: slider_id + name: LVGL Slider + +See Also +-------- +- :ref:`LVGL Main component ` +- :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` +- :doc:`/components/light/lvgl` +- :doc:`/components/number/lvgl` +- :ghedit:`Edit` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 17bf232d19..c38bf7bcbc 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -40,6 +40,7 @@ See Also - :ref:`Switch widget ` - :ref:`Checkbox widget ` - :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` diff --git a/index.rst b/index.rst index 8235737a9d..9b03946898 100644 --- a/index.rst +++ b/index.rst @@ -476,6 +476,7 @@ Miscellaneous Havells Solar, components/sensor/havells_solar, havellsgti5000d_s.jpg, Solar rooftop Integration, components/sensor/integration, sigma.svg, dark-invert Kuntze pool sensor, components/sensor/kuntze, kuntze.jpg + LVGL widget, components/sensor/lvgl, lvgl_c_num.png MicroNova pellet stove, components/micronova, pellet.svg Modbus Sensor, components/sensor/modbus_controller, modbus.png Nextion, components/sensor/nextion, nextion.jpg, Sensors from display @@ -833,6 +834,7 @@ Text Components Text Core, components/text/index, folder-open.svg, dark-invert Template Text, components/text/template, description.svg, dark-invert + LVGL textarea Text, components/text/lvgl, lvgl_c_txt.png Valve Components ---------------- @@ -853,6 +855,7 @@ Text Sensor Components 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 + LVGL textarea Text Sensor, components/text_sensor/lvgl, lvgl_c_txt.png 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 From d03275897df41f03af8c593d8f18e48f96ee2bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 10:41:46 +0200 Subject: [PATCH 354/564] text annd text_sensor components --- components/binary_sensor/lvgl.rst | 2 ++ components/light/lvgl.rst | 6 ++-- components/number/lvgl.rst | 2 ++ components/select/lvgl.rst | 2 ++ components/sensor/lvgl.rst | 2 ++ components/switch/lvgl.rst | 2 ++ components/text/lvgl.rst | 45 ++++++++++++++++++++++++++++++ components/text_sensor/lvgl.rst | 45 ++++++++++++++++++++++++++++++ images/lvgl_c_txt.png | Bin 0 -> 1516 bytes 9 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 components/text/lvgl.rst create mode 100644 components/text_sensor/lvgl.rst create mode 100644 images/lvgl_c_txt.png diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 491a72a22a..5da6499faa 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -39,4 +39,6 @@ See Also - :doc:`/components/switch/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` - :ghedit:`Edit` diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index febf82b3f4..7660955551 100644 --- a/components/light/lvgl.rst +++ b/components/light/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 light. -- **led** (**Required**): The ID of a ``led`` widget configured in LVGL, which will reflect the state of the light. +- **widget** (**Required**): The ID of a ``led`` widget configured in LVGL, which will reflect the state of the light. - All other options from :ref:`light `. @@ -29,7 +29,7 @@ Example: light: - platform: lvgl - led: led_id + widget: led_id name: LVGL light .. note:: @@ -45,4 +45,6 @@ See Also - :doc:`/components/number/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/select/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` - :ghedit:`Edit` diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index b8788992af..cf284a5417 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -42,4 +42,6 @@ See Also - :doc:`/components/switch/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` - :ghedit:`Edit` diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 7abe12b5d7..2e4fa7365d 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -40,4 +40,6 @@ See Also - :doc:`/components/number/lvgl` - :doc:`/components/switch/lvgl` - :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` - :ghedit:`Edit` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 727b63951b..3c6d567812 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -41,4 +41,6 @@ See Also - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` - :doc:`/components/number/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` - :ghedit:`Edit` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index c38bf7bcbc..e76e3ee4d8 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -45,4 +45,6 @@ See Also - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` - :doc:`/components/output/index` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` - :ghedit:`Edit` diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst new file mode 100644 index 0000000000..68bb1f07da --- /dev/null +++ b/components/text/lvgl.rst @@ -0,0 +1,45 @@ +.. _lvgl-txt: + +LVGL Text +========= + +.. seo:: + :description: Instructions for setting up a LVGL textarea Text component. + :image: ../images/lvgl_c_txt.png + +The ``lvgl`` text platform creates an editable text component from a LVGL textarea widget +and requires :ref:`LVGL ` to be configured. + +Supported widget is :ref:`lvgl-wgt-txt`. A single text component supports +a single widget, thus you need to choose among which one's state you want to use. + + +Configuration options: +---------------------- + +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. +- **name** (**Required**, string): The name of the text component. +- **widget** (**Required**): The ID of a ``textarea`` widget configured in LVGL, which will reflect the state of the text component. +- All other options from :ref:`Text `. + +Example: + +.. code-block:: yaml + + text: + - platform: lvgl + widget: textarea_id + name: "Textarea 1 text" + +See Also +-------- +- :ref:`LVGL Main component ` +- :ref:`Textarea widget ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/select/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :ghedit:`Edit` diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst new file mode 100644 index 0000000000..4ecc7e3beb --- /dev/null +++ b/components/text_sensor/lvgl.rst @@ -0,0 +1,45 @@ +.. _lvgl-txs: + +LVGL Text Sensor +================ + +.. seo:: + :description: Instructions for setting up a LVGL textarea Text Sensor. + :image: ../images/lvgl_c_txt.png + +The ``lvgl`` text platform creates a Text Sensor from a LVGL textarea widget +and requires :ref:`LVGL ` to be configured. + +Supported widget is :ref:`lvgl-wgt-txt`. A single Text Sensor supports +a single widget, thus you need to choose among which one's state you want to use. + + +Configuration options: +---------------------- + +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. +- **name** (**Required**, string): The name of the text sensor. +- **widget** (**Required**): The ID of a ``textarea`` widget configured in LVGL, which will reflect the state of the text sensor. +- All other options from :ref:`Text Sensor `. + +Example: + +.. code-block:: yaml + + text_sensor: + - platform: lvgl + widget: textarea_id + name: "Textarea 1 text" + +See Also +-------- +- :ref:`LVGL Main component ` +- :ref:`Textarea widget ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/select/lvgl` +- :doc:`/components/text/lvgl` +- :ghedit:`Edit` diff --git a/images/lvgl_c_txt.png b/images/lvgl_c_txt.png new file mode 100644 index 0000000000000000000000000000000000000000..2691af6de1b636f07cb93885c9eaf28f01e77cb2 GIT binary patch literal 1516 zcmZvcYd8}M7{`aoJ=a(^C3G^kv*nhsk-N0br8;!X?NAK4gf3bxeiWlwhjyW6Id%K*UsC-znruGb4cF=>Glc3|NpPeoyW^EjE` zEOajsRFX6}^|~H}+Y@lh5|vR?RPF6}xaB%tJ1AKkL_8xUrcc}_*>Ap2Pug-FTC293 z!nUX2J?J`#SXA1nHXD87T;CSRTeUspNu7OYO3hX_s zEd0T2mXScCjKGeT@v;*|6+)8wJ{=)~Z>VLQJRxvPaq6Bo=R6m^fDEuwmsV6M4KuP{;#dXaYGFq<-MPqi4K#E7q(lzUi>Boz|dq7zN0}yn$ETQ@6p^)G~Sy z!fD(qswc~ba%z|;jvg%PQ@3EdM2#5L zSRA+wRQkF7xD89fIepx(Tq4Q$lsSr{16%WGJf}~TH__;T&ny)I6UjudiH24#P+TkT z5GNWPngf{BHh_hJUx&5#>%~Xs`Tk(KVE^aLR@CCzx)x2!K}uT~|3jR0*y34~M>VqT zEBRmye}PSBe=-WLFe>fXY`_HCrJDtla$TiFj^U%eaJ)k2`I<%)a$7>#hn}(<^lV`1 zOx-|l!YnglOTaJ816^`gx)Sy(3zeza4+0+{5?sr zRY+U^%aWH-@2)C0lKLDWIbd}ntVJPgXR#G>j#N+|`_X!D#kEkyA;&11&^PRS8NsJw7rTDIN|}Nm8#Xi>+QEj817P0q6W!x zwV(5upwqv`NX*3c@j|Fq&@5`S;2Qm2vF&ZNXLcsk)`VS zh{n@L$6le!^IvwO9b|^M<6P#Goi|d+=KY@g!=tdh7QCn;+Ww~ax3H^y2OXNk_E zZTfFTZcTZ1Z|Anv8Qhv4UCHQRfG}y-G7y>18=RcvW6~xNRx5MUg+uur4DPHx?r@rU znPO$Lrt)I7Y%J%SoS!XGu_N z&KWEHt?9MOM}FgMq(G)2ZLS};@%3n?2Rl-NF8EIf2b@`2-UC~5U0|UQ(-Rc7^7Q*O zmc=q2*l9EsXN$XfakVHbCQ_FXWv))I2sSDYSV3 Date: Thu, 9 May 2024 11:39:49 +0200 Subject: [PATCH 355/564] textarea widget --- components/images/lvgl_textarea.png | Bin 0 -> 4749 bytes components/lvgl.rst | 60 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 components/images/lvgl_textarea.png diff --git a/components/images/lvgl_textarea.png b/components/images/lvgl_textarea.png new file mode 100644 index 0000000000000000000000000000000000000000..1382f7e10061ed79797ee3b8ef067dd5b6a9b662 GIT binary patch literal 4749 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 and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. + +**Specific actions:** + +``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. + +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated on every keystroke, the variable ``text`` containing the entire contents of the textarea. +``on_ready`` :ref:`trigger ` is activated in case of ``one_line`` configured as ``true``, when the New Line character is receicved (Enter key on the keyboard). + +**Example:** + +.. code-block:: yaml + + # Example widget: + - textarea: + id: textarea_id + one_line: true + placeholder_text: "Enter text here" + + # Example action: + on_...: + then: + - lvgl.textarea.update: + id: textarea_id + text: "Hello World!" + + + # Example trigger: + - textarea: + ... + on_value: + then: + - logger.log: + format: "textarea changed to: %s" + args: [ text ] + on_ready: + then: + - logger.log: + format: "textarea ready: %s" + args: [ text ] + .. _lvgl-wgt-spi: ``spinner`` From 767d23806413ed76cdcf06af03ac8019ad8f10ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 11:44:20 +0200 Subject: [PATCH 356/564] Update lvgl.rst --- components/lvgl.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 73d0e2bb32..78b7087efd 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1475,7 +1475,7 @@ Check out :ref:`lvgl-cook-keypad` in the Cookbook for an example how to change t ``textarea`` ************ -The Text Area is a widget allowing to input text and displays a cursor. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. +The Textarea is a widget allowing to input text and displays a cursor. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. .. figure:: /components/images/lvgl_textarea.png :align: center @@ -1522,14 +1522,16 @@ The Text Area is a widget allowing to input text and displays a cursor. Long lin on_value: then: - logger.log: - format: "textarea changed to: %s" + format: "Textarea changed to: %s" args: [ text ] on_ready: then: - logger.log: - format: "textarea ready: %s" + format: "Textarea ready: %s" args: [ text ] +The ``textarea`` can be also integrated as :doc:`/components/text/lvgl` or :doc:`/components/text_sensor/lvgl`. + .. _lvgl-wgt-spi: ``spinner`` From 6ef4f46da3f038f65d19b39049f4f7a622507d2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 15:43:16 +0200 Subject: [PATCH 357/564] Update components/binary_sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/binary_sensor/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 5da6499faa..5cf0fcfbae 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -4,7 +4,7 @@ LVGL Binary Sensor ================== .. seo:: - :description: Instructions for setting up a LVGL widget binary sensor. + :description: Instructions for setting up an LVGL widget binary sensor. :image: ../images/lvgl_c_bns.png The ``lvgl`` binary sensor platform creates a binary sensor from a LVGL widget From f7374e5561c14c4b995249ce7d07bf95e693e206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 15:43:29 +0200 Subject: [PATCH 358/564] Update components/binary_sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/binary_sensor/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 5cf0fcfbae..55ed3532f7 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -7,7 +7,7 @@ LVGL Binary Sensor :description: Instructions for setting up an LVGL widget binary sensor. :image: ../images/lvgl_c_bns.png -The ``lvgl`` binary sensor platform creates a binary sensor from a LVGL widget +The ``lvgl`` binary sensor platform creates a binary sensor from an LVGL widget and requires :ref:`LVGL ` to be configured. Supported widget is :ref:`lvgl-wgt-btn`. A single binary sensor supports From 46f82090dcbccc91cd6b2384b19a0f54592d18e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 15:45:29 +0200 Subject: [PATCH 359/564] Update components/binary_sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/binary_sensor/lvgl.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 55ed3532f7..245a69055d 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -16,8 +16,6 @@ a single widget, thus you need to choose among which one's state you want to use 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 supported widget configured in LVGL, which will reflect the state of the binary sensor. - All other options from :ref:`Binary Sensor `. From 011796c2d971d61af8fb76e8a84d09d6ec91e88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 15:46:06 +0200 Subject: [PATCH 360/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 78b7087efd..9774e23053 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -229,7 +229,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **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``. +- **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``255``. - **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. Inherited from parent. Defaults to ``COVER``. From f6789c91ee3241e83654e6052681eeac3fe03c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 15:47:02 +0200 Subject: [PATCH 361/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9774e23053..ea4fe2acdc 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -247,7 +247,7 @@ You can adjust the appearance of widgets by changing the foreground, background - ``LEFT`` - ``RIGHT`` - ``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). +- **radius** (*Optional*, uint16): The radius to be used to form the widget's rounded corners. 0 = no radius (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. Defaults to ``0``. - **outline_color** (*Optional*, :ref:`color `): Color to draw an outline around the widget. Defaults to ``0`` (black). From 6567005d8e286ccd78695a90c5f8ba15d841ebe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 15:47:33 +0200 Subject: [PATCH 362/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ea4fe2acdc..3b3e3072a3 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -248,7 +248,7 @@ You can adjust the appearance of widgets by changing the foreground, background - ``RIGHT`` - ``INTERNAL`` - **radius** (*Optional*, uint16): The radius to be used to form the widget's rounded corners. 0 = no radius (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. +- **clip_corner** (*Optional*, boolean): If set to ``true``, overflowing content will be clipped off by the widget's rounded corners (``radius`` > ``0``). - **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``. From 6f62a904260cf00c0dadfc524329bc7e1c734d10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 15:47:43 +0200 Subject: [PATCH 363/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 3b3e3072a3..f4af9ad0f0 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -250,7 +250,7 @@ You can adjust the appearance of widgets by changing the foreground, background - **radius** (*Optional*, uint16): The radius to be used to form the widget's rounded corners. 0 = no radius (square corners); 65535 = pill shaped widget (true circle if it has same width and height). - **clip_corner** (*Optional*, boolean): If set to ``true``, overflowing content will be clipped off by the widget's rounded corners (``radius`` > ``0``). - **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_color** (*Optional*, :ref:`color `): Color used 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. From d5ae9a3fe772c5d6610af05b11410bf54ffd83bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 15:47:54 +0200 Subject: [PATCH 364/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f4af9ad0f0..580055ef0b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -260,7 +260,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 `): Color to create a drop shadow under the widget. Defaults to ``0`` (black). +- **shadow_color** (*Optional*, :ref:`color `): Color used to create a drop shadow under the widget. Defaults to ``0`` (black). - **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``. From f181012f4469586ccc692b50a328d632642a00ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 15:48:27 +0200 Subject: [PATCH 365/564] Update components/display/fonts.rst Co-authored-by: Keith Burzinski --- components/display/fonts.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/display/fonts.rst b/components/display/fonts.rst index 1bb5799c2d..cb86b0fb24 100644 --- a/components/display/fonts.rst +++ b/components/display/fonts.rst @@ -85,8 +85,8 @@ Next, create a ``font:`` section in your configuration: # ... -Configuration options: ----------------------- +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: From ec1810e161de01eb869e191e405ee35e6000e931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 16:00:17 +0200 Subject: [PATCH 366/564] Update lvgl.rst --- components/switch/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index e76e3ee4d8..499b2b5157 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -44,7 +44,7 @@ See Also - :doc:`/components/number/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` -- :doc:`/components/output/index` - :doc:`/components/text/lvgl` - :doc:`/components/text_sensor/lvgl` +- :doc:`/components/output/index` - :ghedit:`Edit` From 16e60f6e3e030eb5a3cc070c2623929190362663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 9 May 2024 17:11:40 +0200 Subject: [PATCH 367/564] Update lvgl.rst --- components/lvgl.rst | 77 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 580055ef0b..53b4ab683f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -607,6 +607,12 @@ 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. +A notable state is ``checked`` (boolean) which can have different styles applied. + +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated after clicking, in case of ``checkable`` configured as ``true``, the variable ``x`` returning a boolean representing the checked state. + **Example:** .. code-block:: yaml @@ -636,7 +642,14 @@ 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. + # Example trigger: + - btn: + ... + on_value: + then: + - logger.log: + format: "Button checked state: %d" + args: [ x ] The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. @@ -757,6 +770,10 @@ 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`. +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated when toggling the switch, the variable ``x`` returning a boolean representing the checked state. + **Example:** .. code-block:: yaml @@ -767,7 +784,16 @@ The Switch looks like a little slider and can be used to turn something on and o y: 10 id: switch_id -The ``switch`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. + # Example trigger: + - switch: + ... + on_value: + then: + - logger.log: + format: "Switch state: %d" + args: [ x ] + +The ``switch`` can be also integrated 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. @@ -795,6 +821,10 @@ The Checkbox widget is made internally from a *tick box* and a label. When the C - **args** (*Optional*, list of :ref:`lambda `): The optional arguments for the format message. +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated when toggling the checkbox, the variable ``x`` returning a boolean representing the checked state. + **Example:** .. code-block:: yaml @@ -815,6 +845,15 @@ The Checkbox widget is made internally from a *tick box* and a label. When the C checked: true text: Checked + # Example trigger: + - checkbox: + ... + on_value: + then: + - logger.log: + format: "Checkbox state: %d" + args: [ x ] + The ``checkbox`` can be also integrated as a :doc:`/components/switch/lvgl`. .. _lvgl-wgt-drp: @@ -847,6 +886,11 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( ``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. +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. +``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. + **Example:** .. code-block:: yaml @@ -869,7 +913,19 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( then: - lvgl.dropdown.update: id: dropdown_id - selected_index: 5 + selected_index: 4 + + # Example trigger: + - dropdown: + ... + on_value: + - logger.log: + format: "Selected index is: %d" + args: [ x ] + on_cancel: + - logger.log: + format: "Dropdown closed. Selected index is: %d" + args: [ x ] The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. @@ -897,6 +953,10 @@ Roller allows you to simply select one option from a list by scrolling. ``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. +**Specific triggers:** + +``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. + **Example:** .. code-block:: yaml @@ -917,7 +977,15 @@ Roller allows you to simply select one option from a list by scrolling. then: - lvgl.roller.update: id: roller_id - selected_index: 5 + selected_index: 4 + + # Example trigger: + - roller: + ... + on_value: + - logger.log: + format: "Selected index is: %d" + args: [ x ] The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. @@ -1515,7 +1583,6 @@ The Textarea is a widget allowing to input text and displays a cursor. Long line id: textarea_id text: "Hello World!" - # Example trigger: - textarea: ... From 0348fec2758c48e692cf3ea8ac7bb504ad009ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 06:51:50 +0200 Subject: [PATCH 368/564] Update components/sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/sensor/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 3c6d567812..d16e2d2703 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -4,7 +4,7 @@ LVGL Sensor =========== .. seo:: - :description: Instructions for setting up a LVGL widget sensor component. + :description: Instructions for setting up an LVGL widget sensor component. :image: ../images/lvgl_c_num.png The ``lvgl`` sensor platform creates a semsor component from a LVGL widget From 24d4d4023da5d1ffc7e8ef884a3f468d029e16a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 06:52:11 +0200 Subject: [PATCH 369/564] Update components/sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/sensor/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index d16e2d2703..328008eb66 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -7,7 +7,7 @@ LVGL Sensor :description: Instructions for setting up an LVGL widget sensor component. :image: ../images/lvgl_c_num.png -The ``lvgl`` sensor platform creates a semsor component from a LVGL widget +The ``lvgl`` sensor platform creates a semsor component from an 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 sensor supports a single widget, thus you need to choose among which one's state you want to use. From 66a3cda04126493b9103ec7e943f64ea3342f5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 06:52:40 +0200 Subject: [PATCH 370/564] Update components/text/lvgl.rst Co-authored-by: Keith Burzinski --- components/text/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index 68bb1f07da..ee3923970e 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -4,7 +4,7 @@ LVGL Text ========= .. seo:: - :description: Instructions for setting up a LVGL textarea Text component. + :description: Instructions for setting up an LVGL textarea Text component. :image: ../images/lvgl_c_txt.png The ``lvgl`` text platform creates an editable text component from a LVGL textarea widget From 7dc7536957af96998fa250930d06aa806e66767d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:04:46 +0200 Subject: [PATCH 371/564] Update components/binary_sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/binary_sensor/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 245a69055d..d83293e8af 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -11,7 +11,7 @@ The ``lvgl`` binary sensor platform creates a binary sensor from an LVGL widget 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. +only a single widget; it is not possible to have a single binary sensor respond to multiple widgets. Configuration options: ---------------------- From e38c3728f9444944884fb2facb2989eab6a51927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:05:07 +0200 Subject: [PATCH 372/564] Update components/sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/sensor/lvgl.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 328008eb66..33f91b4bc3 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -15,8 +15,6 @@ Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar`, :ref:`lvgl-wgt-s Configuration options: ---------------------- -- **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 supported widget configured in LVGL, which will reflect the state of the sensor. - All other options from :ref:`Sensor `. From 1b6b8b1df6fe6ee784c24f55d95210a2a2299aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:05:37 +0200 Subject: [PATCH 373/564] Update components/sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/sensor/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 33f91b4bc3..6aa77441c8 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -10,7 +10,7 @@ LVGL Sensor The ``lvgl`` sensor platform creates a semsor component from an 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 sensor supports a single widget, thus you need to choose among which one's state you want to use. +Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar`, :ref:`lvgl-wgt-sli` and :ref:`lvgl-wgt-spb`. A single sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with an ESPHome sensor. Configuration options: ---------------------- From 544a9d0b12e50b3362fde2412a746cae49dfca6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:06:03 +0200 Subject: [PATCH 374/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 53b4ab683f..09721c71e1 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -611,7 +611,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied **Specific triggers:** -``on_value`` :ref:`trigger ` is activated after clicking, in case of ``checkable`` configured as ``true``, the variable ``x`` returning a boolean representing the checked state. +``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. **Example:** From 9eef2191c15d734a3833c1755987782c75e18954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:06:39 +0200 Subject: [PATCH 375/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 09721c71e1..f69bb97f1d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -625,7 +625,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied height: 30 id: btn_id -To have a button with a text label on it, add a :ref:`lvgl-wgt-lbl` widget as child to it: +To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget to it: .. code-block:: yaml From 29d034e88ecb980dbd6b74e866fc73341eb92412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:06:58 +0200 Subject: [PATCH 376/564] Update components/text/lvgl.rst Co-authored-by: Keith Burzinski --- components/text/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index ee3923970e..22fcdd7268 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -7,7 +7,7 @@ LVGL Text :description: Instructions for setting up an LVGL textarea Text component. :image: ../images/lvgl_c_txt.png -The ``lvgl`` text platform creates an editable text component from a LVGL textarea widget +The ``lvgl`` text platform creates an editable text component from an LVGL textarea widget and requires :ref:`LVGL ` to be configured. Supported widget is :ref:`lvgl-wgt-txt`. A single text component supports From cbbf074cf77787b468c5e1b7180264c5744f0b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:07:20 +0200 Subject: [PATCH 377/564] Update components/text/lvgl.rst Co-authored-by: Keith Burzinski --- components/text/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index 22fcdd7268..51163c3190 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -10,8 +10,8 @@ LVGL Text The ``lvgl`` text platform creates an editable text component from an LVGL textarea widget and requires :ref:`LVGL ` to be configured. -Supported widget is :ref:`lvgl-wgt-txt`. A single text component supports -a single widget, thus you need to choose among which one's state you want to use. +Supported widget is :ref:`lvgl-wgt-txt`. A text component supports +only a single widget; it is not possible for multiple widgets to be associated with a single text component. Configuration options: From e6fe7942bff0ab18bba62aefee472ffc90b2f130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:07:53 +0200 Subject: [PATCH 378/564] Update components/display/index.rst Co-authored-by: Keith Burzinski --- components/display/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index ae4087321f..94c88da62b 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -24,8 +24,8 @@ For graphical binary displays, there are two options: 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. +ESPHome's own powerful rendering engine can handle many common tasks such as drawing basic shapes, printing text with fonts of your choice, +or even rendering 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 From 3aad18b6dd6d35c0fe769ee10522422cc1df2860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:08:10 +0200 Subject: [PATCH 379/564] Update components/text/lvgl.rst Co-authored-by: Keith Burzinski --- components/text/lvgl.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index 51163c3190..7003a41ef6 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -17,8 +17,6 @@ only a single widget; it is not possible for multiple widgets to be associated w Configuration options: ---------------------- -- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **name** (**Required**, string): The name of the text component. - **widget** (**Required**): The ID of a ``textarea`` widget configured in LVGL, which will reflect the state of the text component. - All other options from :ref:`Text `. From 5a2874ab325c5d39af5bfc637a8ffba71f882f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:08:31 +0200 Subject: [PATCH 380/564] Update components/text_sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/text_sensor/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index 4ecc7e3beb..ee24511201 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -4,7 +4,7 @@ LVGL Text Sensor ================ .. seo:: - :description: Instructions for setting up a LVGL textarea Text Sensor. + :description: Instructions for setting up an LVGL textarea Text Sensor. :image: ../images/lvgl_c_txt.png The ``lvgl`` text platform creates a Text Sensor from a LVGL textarea widget From ebd765d23dfcde4d7939efe88660f16430ca913e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:09:00 +0200 Subject: [PATCH 381/564] Update components/text_sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/text_sensor/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index ee24511201..9eb28d7e26 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -7,7 +7,7 @@ LVGL Text Sensor :description: Instructions for setting up an LVGL textarea Text Sensor. :image: ../images/lvgl_c_txt.png -The ``lvgl`` text platform creates a Text Sensor from a LVGL textarea widget +The ``lvgl`` text platform creates a Text Sensor from an LVGL textarea widget and requires :ref:`LVGL ` to be configured. Supported widget is :ref:`lvgl-wgt-txt`. A single Text Sensor supports From 95dadb1bb2354f727a1890b549a054e80a87c71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:09:19 +0200 Subject: [PATCH 382/564] Update components/text_sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/text_sensor/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index 9eb28d7e26..963966484a 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -10,8 +10,8 @@ LVGL Text Sensor The ``lvgl`` text platform creates a Text Sensor from an LVGL textarea widget and requires :ref:`LVGL ` to be configured. -Supported widget is :ref:`lvgl-wgt-txt`. A single Text Sensor supports -a single widget, thus you need to choose among which one's state you want to use. +Supported widget is :ref:`lvgl-wgt-txt`. A text sensor supports +only a single widget; it is not possible for multiple widgets to be associated with a single text sensor. Configuration options: From b4950ef4ade220626c3eb9c69aac6929a6bf5c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:09:37 +0200 Subject: [PATCH 383/564] Update components/text_sensor/lvgl.rst Co-authored-by: Keith Burzinski --- components/text_sensor/lvgl.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index 963966484a..6c5e62ec32 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -17,8 +17,6 @@ only a single widget; it is not possible for multiple widgets to be associated w Configuration options: ---------------------- -- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **name** (**Required**, string): The name of the text sensor. - **widget** (**Required**): The ID of a ``textarea`` widget configured in LVGL, which will reflect the state of the text sensor. - All other options from :ref:`Text Sensor `. From 4a8a3745ed3a96379d6405367a82061f8ed0941d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:10:32 +0200 Subject: [PATCH 384/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f69bb97f1d..ee879dddb3 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -281,7 +281,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 :ref:`states ` can be chosen for every widget. +You can configure a global theme for all widgets at the top level with the ``theme`` configuration variable. In the example below, all the ``arc``, ``slider`` and ``btn`` widgets will, by default, use the styles and properties defined here. A combination of styles and :ref:`states ` can be chosen for every widget. .. code-block:: yaml From 2846eefe1a894e7146aecf7c7155dc0ca81cd5da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:10:50 +0200 Subject: [PATCH 385/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ee879dddb3..64239a0465 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -651,7 +651,7 @@ To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget format: "Button checked state: %d" args: [ x ] -The ``btn`` can be also integrated as :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. +The ``btn`` can be also integrated as a :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. See :ref:`lvgl-cook-binent` for an example how to use a checkable button to act on a Home Assistant service. From 950ef8698d023270d1d8af0fe9ea26e7ffbcac2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:11:03 +0200 Subject: [PATCH 386/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 64239a0465..9843690ed4 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -653,7 +653,7 @@ To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget The ``btn`` can be also integrated as a :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. -See :ref:`lvgl-cook-binent` for an example how to use a checkable button to act on a Home Assistant service. +See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable button to act on a Home Assistant service. .. _lvgl-wgt-bmx: From d5e20d8ec1005942ebfd42a306a1cd6ce6a4ac3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:15:27 +0200 Subject: [PATCH 387/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9843690ed4..ce264841d4 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -354,7 +354,7 @@ 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. +The precedence (value) of states is quite intuitive and it's something the user would expect naturally. For example, 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 override the "pressed" color, defeating its purpose.) Feel free to experiment to discover inheritance of the styles based on states between the nested widgets. From 96330243c573cf52fb3b6de19d3d30e9f49c403c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:16:08 +0200 Subject: [PATCH 388/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index ce264841d4..f8bd433981 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -358,7 +358,7 @@ The precedence (value) of states is quite intuitive and it's something the user Feel free to experiment to discover inheritance of the styles based on states between the nested widgets. -:ref:`lvgl-cook-theme` in the Cookbook shows an example how to easily implement a gradient style for your widgets. +:ref:`lvgl-cook-theme` The Cookbook contains an example illustrating how to easily implement a gradient style for your widgets. .. _lvgl-layouts: From 30c44f552e16a9b4742f4325e504d4e3db86ce33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:16:40 +0200 Subject: [PATCH 389/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f8bd433981..be54988bc4 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -365,7 +365,7 @@ Feel free to experiment to discover inheritance of the styles based on states be 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. +Layouts aim to position widgets automatically, eliminating the need to specify ``x`` and ``y`` coordinates to position each widget. This is a great way to simplify your configuration as it allows you to omit alignment options. The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. From af552a6a7e661f6f2a243f4c95acead8a856aa6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:17:13 +0200 Subject: [PATCH 390/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index be54988bc4..d2a847703a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -375,7 +375,7 @@ The layout configuration options are applied to any parent widget or page, influ 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. +It can arrange items into rows or columns (tracks), handle wrapping, adjust spacing between items and tracks and even handle growing the layout to make the item(s) fill the remaining space with respect to minimum/maximum width and height. Terms used: From 97c534a0ede2efdcd0c7cb6fbc328a764601d02c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:17:32 +0200 Subject: [PATCH 391/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d2a847703a..5a887f7d00 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -402,7 +402,7 @@ In a Flex layout, use the following options in the ``flex_flow`` configuration p 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. +It can arrange items into a 2D "table" that has rows or columns (tracks). The item(s) can span through multiple columns or rows. The track's size can be set in pixels, to the largest item or in "free units" to distribute the free space proportionally. .. _lvgl-widgets: From dd4c969b25e25620b66e14cbc185150e735a9cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:17:53 +0200 Subject: [PATCH 392/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 5a887f7d00..2a8ab59bd5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -409,7 +409,7 @@ It can arrange items into a 2D "table" that has rows or columns (tracks). The it Widgets ------- -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. +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 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 a1c922fcdda29153a63fd543c036788bdbd91b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:18:14 +0200 Subject: [PATCH 393/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2a8ab59bd5..1f5ee78ed2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -411,7 +411,7 @@ Widgets 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 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. +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, its children will also be hidden. 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. From eb93ce7219cb8737975a7e5f12f3f1620b3c1a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:19:29 +0200 Subject: [PATCH 394/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1f5ee78ed2..d969c1c117 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -413,7 +413,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, its children will also be hidden. -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. +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 those related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the parent will be searched for an object which specifies a value for the property. The parents will use their own :ref:`state ` to determine the value. For example, if a button is pressed and the text color is defined by the "pressed" state, this "pressed" text color will be used. Common properties ***************** From b8050b94a8eba731d616864d9cc2daa7993251f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:20:32 +0200 Subject: [PATCH 395/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d969c1c117..24345bf1c9 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -462,7 +462,7 @@ 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 overridden 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 the theme, but can be locally set or overridden within style definitions. 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. From 627e7f8d1f9046e199f3ce0b2067d4599e2d11bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:20:51 +0200 Subject: [PATCH 396/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 24345bf1c9..14e7d36dac 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -487,7 +487,7 @@ To apply styles to the states, you need to specify them one level above, for exa 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. +See :ref:`lvgl-cook-cover` for a cookbook example illustrating how to use styling and properties to show different states of a Home Assistant entity. .. _lvgl-objupdflag-act: From 39b60a06ba2ff3c0c2720588d35e0b728bc7b006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:22:00 +0200 Subject: [PATCH 397/564] Update components/light/lvgl.rst Co-authored-by: Keith Burzinski --- components/light/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 7660955551..aab213d38e 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -4,7 +4,7 @@ LVGL Light ========== .. seo:: - :description: Instructions for setting up a LVGL widget light. + :description: Instructions for setting up an LVGL widget light. :image: ../images/lvgl_c_lig.png The ``lvgl`` light platform creates a light from a LVGL widget From b0b29a875d9f82c70bb9a53bb5375d34edda4852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:22:49 +0200 Subject: [PATCH 398/564] Update components/light/lvgl.rst Co-authored-by: Keith Burzinski --- components/light/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index aab213d38e..39c6789941 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -7,7 +7,7 @@ LVGL Light :description: Instructions for setting up an LVGL widget light. :image: ../images/lvgl_c_lig.png -The ``lvgl`` light platform creates a light from a LVGL widget +The ``lvgl`` light platform creates a light from an LVGL widget and requires :ref:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-wgt-led`. A single light supports From 829a5c3bb8c8706ca7ad3c25c485e71f234afc8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:23:45 +0200 Subject: [PATCH 399/564] Update components/light/lvgl.rst Co-authored-by: Keith Burzinski --- components/light/lvgl.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 39c6789941..467459a52b 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -17,8 +17,6 @@ a single widget, thus you need to choose among which one's state you want to use Configuration options: ---------------------- -- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **name** (**Required**, string): The name of the light. - **widget** (**Required**): The ID of a ``led`` widget configured in LVGL, which will reflect the state of the light. - All other options from :ref:`light `. From de1fcbafc47f0a915d269b910dfd8d499b14a903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:24:52 +0200 Subject: [PATCH 400/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 14e7d36dac..dbcc986154 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -23,7 +23,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` 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. +In LVGL, graphical elements like buttons, labels, sliders, etc. are called widgets or objects. See :ref:`lvgl-widgets` for a complete list of widgets supported within ESPHome. Not all LVGL widgets are implemented, just those commonly used to support home automation needs/tasks. 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. From 8a9fd55e674b5a058f6e0c6dfbf344488fbd4274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:25:52 +0200 Subject: [PATCH 401/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index dbcc986154..82b7d84cd5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -25,7 +25,7 @@ Basics In LVGL, graphical elements like buttons, labels, sliders, etc. are called widgets or objects. See :ref:`lvgl-widgets` for a complete list of widgets supported within ESPHome. Not all LVGL widgets are implemented, just those commonly used to support home automation needs/tasks. -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. +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 the label. Complex widgets internally consist of several smaller/simpler widgets; these are known as parts, each of 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 75710efd398af7d574a4320dabba1b00a4d4a07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:26:40 +0200 Subject: [PATCH 402/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 82b7d84cd5..503e88f45b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -60,7 +60,7 @@ These are useful to make :ref:`automations ` triggered by actions pe Main Configuration ------------------ -Although LVGL is a complex matrix of objects-parts-states-styles, in ESPHome this is simplified to a hierarchy. +Although LVGL is a complex matrix of objects-parts-states-styles, ESPHome simplifies this into a hierarchy. 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. From 7fe9dae78e181f2ebff3671288fe1ff69613bf78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:27:24 +0200 Subject: [PATCH 403/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 503e88f45b..9015a1b7cb 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, ESPHome simplifies this into a hierarchy. -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. +At the highest level of the LVGL object hierarchy is the display (represented by 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 to be presented on the 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. From a52ad0ba24b959cc4c878c188b7c8f57a3467cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:29:31 +0200 Subject: [PATCH 404/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9015a1b7cb..e5adf6eef0 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -68,7 +68,7 @@ The following configuration options apply to the main ``lvgl`` component, in ord **Configuration options:** -- **displays** (**Required**, list): A list of displays where to render this entire LVGL configuration: +- **displays** (**Required**, list): A list of displays where LVGL should perform rendering based on its 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 display. From 10b305460e8b7c34f7dbe8efe1243e275186619b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:30:00 +0200 Subject: [PATCH 405/564] Update components/number/lvgl.rst Co-authored-by: Keith Burzinski --- components/number/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index cf284a5417..93f02cf7ec 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -4,7 +4,7 @@ LVGL Number =========== .. seo:: - :description: Instructions for setting up a LVGL widget number component. + :description: Instructions for setting up an LVGL widget number component. :image: ../images/lvgl_c_num.png The ``lvgl`` number platform creates a number component from a LVGL widget From 550f79e830b487a577f9d2a0975a93ac4c2d8133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:30:55 +0200 Subject: [PATCH 406/564] Update components/number/lvgl.rst Co-authored-by: Keith Burzinski --- components/number/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 93f02cf7ec..5019099a7c 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -7,7 +7,7 @@ LVGL Number :description: Instructions for setting up an LVGL widget number component. :image: ../images/lvgl_c_num.png -The ``lvgl`` number platform creates a number component from a LVGL widget +The ``lvgl`` number platform creates a number component from an 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. From 19e639f5f330170c4c24f35f04c68351f066e1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:43:11 +0200 Subject: [PATCH 407/564] Apply suggestions from code review Co-authored-by: Keith Burzinski --- components/lvgl.rst | 64 +++++++++++++++++++------------------- components/number/lvgl.rst | 2 -- components/select/lvgl.rst | 6 ++-- components/switch/lvgl.rst | 6 ++-- 4 files changed, 36 insertions(+), 42 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index e5adf6eef0..6ec8b4c5aa 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -70,43 +70,43 @@ The following configuration options apply to the main ``lvgl`` component, in ord - **displays** (**Required**, list): A list of displays where LVGL should perform rendering based on its 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. +- **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. May be omitted if a rotary encoder is configured (see below). - **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. +- **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. May be omitted if a touchscreen is configured (as above). - **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 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 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``. +- **buffer_size** (*Optional*, percentage): The percentage of screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. +- **update_interval**: (*Optional*, :ref:`Time `): The interval at which the screen should be redrawn (when 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. Can be changed a runtime with ``lvgl.update`` action. +- **byte_order** (*Optional*, enum): The byte order of the data LVGL outputs; either ``big_endian`` or ``little_endian``. Defaults to ``big_endian``. +- **disp_bg_color** (*Optional*, :ref:`color `): Solid color used to fill the background. Can be changed at runtime with the ``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. -- **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: +- **style_definitions** (*Optional*, list): A batch of style definitions to use in LVGL widget's ``styles`` configuration. See :ref:`below ` for more details. +- **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. +- **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. May not be used if ``pages`` (below) is configured. +- **pages** (*Optional*, list): A list of page IDs. Each page acts as a parent for widgets placed on it. May not be used with ``widgets`` (above). Options for each page: - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. - - **layout** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. + - **layout** (*Optional*, string): One of ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. Defaults to ``NONE`` which disables layouts (each widget will then require 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): ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. +- **page_wrap** (*Optional*, boolean): Wrap pages around when navigating between them with :ref:`lvgl-pgnx-act`. Defaults to ``true``. +- **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, which may be useful for widgets which always need to be visible. May not be used with ``widgets`` (above). Options: + - **layout** (*Optional*, string): One of ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. Defaults to ``NONE`` which disables layouts (each widget will then require 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``. See :ref:`layouts `. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. +- **layout** (*Optional*, string): One of ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. Defaults to ``NONE`` which disables layouts (each widget will then require 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. +- All other options from :ref:`lvgl-styling` to be applied to all widgets directly. **Example:** @@ -125,7 +125,7 @@ The following configuration options apply to the main ``lvgl`` component, in ord align: CENTER text: 'Hello World!' -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. +See :ref:`lvgl-cook-navigator` in the Cookbook for an example illustrating how to easily implement a page navigation bar at the bottom of the screen. .. note:: @@ -136,7 +136,7 @@ See :ref:`lvgl-cook-navigator` in the Cookbook for an example how to easily impl Colors ****** -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. +Colors can be specified anywhere in the LVGL configuration either by referencing a preconfigured :ref:`ESPHome color ` ID or by representing the color in the common hexadecimal notation. For example, ``0xFF0000`` would be red. .. _lvgl-opa: @@ -150,13 +150,13 @@ Various parts of the widgets (like background, borders etc.) support opacity. It Fonts ***** -There are two font choices for LVGL here: +Two font choices are available: **ESPHome fonts** 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. +Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples illustrating how to use icons and text with TrueType/OpenType fonts. **Library fonts** @@ -186,7 +186,7 @@ The LVGL library offers by default prerendered sets with ASCII characters (``0x2 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 preceded by ``\u``, eg. ``\uF00C``: +You can display the embedded symbols among the text by their codepoint address preceded by ``\u``. For example: ``\uF00C``: .. figure:: /components/images/lvgl_symbols.png :align: center @@ -220,7 +220,7 @@ LVGL follows CSS's `border-box model `): Color to make the background gradually fade to. Defaults to ``0`` (black). - **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_main_stop** (*Optional*, 0-255): Specify where the gradient should start: ``0`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``0``. - **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``255``. - **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. @@ -508,9 +508,9 @@ In addition to visual styling, each widget supports some boolean **flags** to in - **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. +- **event_bubble** (*Optional*, boolean): propagate the events to the parent. - **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. +- **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. For example, may help by accounting for rounded corners. - **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. @@ -520,7 +520,7 @@ In addition to visual styling, each widget supports some boolean **flags** to in .. 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 only supports **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: @@ -542,12 +542,12 @@ A label is the basic widget type that is used to display text. - **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 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). +- **recolor** (*Optional*, boolean): Enable recoloring of button text with ``#``. This makes it possible to set the color of characters in the text individually by prefixing the text to be re-colored with a ``#RRGGBB`` hexadecimal color code followed by a *space*, and finally closed 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 set 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 lines which are too long. 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. + - ``SCROLL``: If the text is wider than the label, scroll the text horizontally back and forth. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. + - ``SCROLL_CIRCULAR``: If the text is wider than the label, continuously scroll the text horizontally. If it's higher, scroll vertically. Text will scroll in only one direction; 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 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. @@ -559,7 +559,7 @@ A label is the basic widget type that is used to display text. **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 the :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 `. diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 5019099a7c..7728d93de8 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -15,8 +15,6 @@ Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar`, :ref:`lvgl-wgt-s 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): 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 `. diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 2e4fa7365d..2b2de77ede 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -4,10 +4,10 @@ LVGL Select =========== .. seo:: - :description: Instructions for setting up a LVGL widget select. + :description: Instructions for setting up an LVGL widget select. :image: ../images/lvgl_c_sel.png -The ``lvgl`` switch platform creates a select from a LVGL widget +The ``lvgl`` switch platform creates a select from an 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 @@ -16,8 +16,6 @@ a single widget, thus you need to choose among which one's state you want to use Configuration options: ---------------------- -- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **name** (**Required**, string): The name 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 `. diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 499b2b5157..cea9ea2e1f 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -4,10 +4,10 @@ LVGL Switch =========== .. seo:: - :description: Instructions for setting up a LVGL widget switch. + :description: Instructions for setting up an LVGL widget switch. :image: ../images/lvgl_c_swi.png -The ``lvgl`` switch platform creates a switch from a LVGL widget +The ``lvgl`` switch platform creates a switch from an 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. @@ -16,8 +16,6 @@ Supported widgets are :ref:`lvgl-wgt-btn` (with ``checkable`` option enabled), : 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 ``checked`` state of the configured widget. - All other options from :ref:`Switch `. From 3e53c9bada8f12269a8d3a016b0a674f054b391c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 09:58:15 +0200 Subject: [PATCH 408/564] The one to one relation between widget and component :-) --- components/binary_sensor/lvgl.rst | 3 +-- components/light/lvgl.rst | 3 +-- components/number/lvgl.rst | 2 +- components/select/lvgl.rst | 3 +-- components/sensor/lvgl.rst | 2 +- components/switch/lvgl.rst | 3 +-- components/text/lvgl.rst | 3 +-- components/text_sensor/lvgl.rst | 4 +--- 8 files changed, 8 insertions(+), 15 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index d83293e8af..03d87a6d43 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -10,8 +10,7 @@ LVGL Binary Sensor The ``lvgl`` binary sensor platform creates a binary sensor from an LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widget is :ref:`lvgl-wgt-btn`. A single binary sensor supports -only a single widget; it is not possible to have a single binary sensor respond to multiple widgets. +Supported widget is :ref:`lvgl-wgt-btn`. A single binary sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome binary sensor component. Configuration options: ---------------------- diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 467459a52b..43e688a36e 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -10,8 +10,7 @@ LVGL Light The ``lvgl`` light platform creates a light from an LVGL widget and requires :ref:`LVGL ` to be configured. -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. +Supported widgets are :ref:`lvgl-wgt-led`. A single light supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome light component. Configuration options: diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 7728d93de8..88a8b9019b 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 an 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. +Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar`, :ref:`lvgl-wgt-sli` and :ref:`lvgl-wgt-spb`. A single number supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome number component. Configuration options: ---------------------- diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 2b2de77ede..9a2c07fe52 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -10,8 +10,7 @@ LVGL Select The ``lvgl`` switch platform creates a select from an 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. +Supported widgets are :ref:`lvgl-wgt-drp` and :ref:`lvgl-wgt-rol`. A single select supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome select component. Configuration options: ---------------------- diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 6aa77441c8..7b1f1d90db 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -10,7 +10,7 @@ LVGL Sensor The ``lvgl`` sensor platform creates a semsor component from an 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 sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with an ESPHome sensor. +Supported widgets are :ref:`lvgl-wgt-arc`, :ref:`lvgl-wgt-bar`, :ref:`lvgl-wgt-sli` and :ref:`lvgl-wgt-spb`. A single sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome sensor. Configuration options: ---------------------- diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index cea9ea2e1f..3e841736db 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -10,8 +10,7 @@ LVGL Switch The ``lvgl`` switch platform creates a switch from an 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 only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome switch component. Configuration options: ---------------------- diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index 7003a41ef6..9c39b07de5 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -10,8 +10,7 @@ LVGL Text The ``lvgl`` text platform creates an editable text component from an LVGL textarea widget and requires :ref:`LVGL ` to be configured. -Supported widget is :ref:`lvgl-wgt-txt`. A text component supports -only a single widget; it is not possible for multiple widgets to be associated with a single text component. +Supported widget is :ref:`lvgl-wgt-txt`. A single text supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text component. Configuration options: diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index 6c5e62ec32..f8d9b0a37e 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -10,9 +10,7 @@ LVGL Text Sensor The ``lvgl`` text platform creates a Text Sensor from an LVGL textarea widget and requires :ref:`LVGL ` to be configured. -Supported widget is :ref:`lvgl-wgt-txt`. A text sensor supports -only a single widget; it is not possible for multiple widgets to be associated with a single text sensor. - +Supported widget is :ref:`lvgl-wgt-txt`. A single text sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text sensor component. Configuration options: ---------------------- From 8fa2e67476fd821f0ef545b965045c3c67a14d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 10:27:17 +0200 Subject: [PATCH 409/564] Update lvgl.rst --- components/lvgl.rst | 89 +++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 6ec8b4c5aa..76f99c07c7 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -559,11 +559,10 @@ A label is the basic widget type that is used to display text. **Specific actions:** -``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 +- ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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:** @@ -611,7 +610,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied **Specific triggers:** -``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. +- ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. **Example:** @@ -691,9 +690,8 @@ 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. - -``lvgl.btnmatrix.update`` :ref:`action ` updates the items styles and properties specified in the specific ``state``, ``items`` options. +- ``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:** @@ -772,7 +770,7 @@ The Switch looks like a little slider and can be used to turn something on and o **Specific triggers:** -``on_value`` :ref:`trigger ` is activated when toggling the switch, the variable ``x`` returning a boolean representing the checked state. +- ``on_value`` :ref:`trigger ` is activated when toggling the switch, the variable ``x`` returning a boolean representing the checked state. **Example:** @@ -814,12 +812,10 @@ 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 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. +- ``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. **Specific triggers:** @@ -884,12 +880,12 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( **Specific actions:** -``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. +- ``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. **Specific triggers:** -``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. -``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. +- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. +- ``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. **Example:** @@ -951,11 +947,11 @@ 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 from the specific options above, just like :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. **Specific triggers:** -``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. +- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. **Example:** @@ -1016,7 +1012,7 @@ Not only the end, but also the start value of the bar can be set, which changes **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. +- ``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:** @@ -1065,11 +1061,11 @@ 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 from the specific options above, just like :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:** -``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``. +- ``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:** @@ -1147,11 +1143,11 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can **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.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``. +- ``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:** @@ -1219,13 +1215,13 @@ 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. +- ``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``. +- ``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:** @@ -1329,7 +1325,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. ``src`` cannot be updated at runtime. +- ``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:** @@ -1388,7 +1384,7 @@ Images are the basic widgets to display images. **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. +- ``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:** @@ -1429,9 +1425,9 @@ 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. +- ``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:** @@ -1510,7 +1506,7 @@ The Led widgets are rectangle-like (or circle) widget whose brightness can be ad **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. +- ``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:** @@ -1563,8 +1559,8 @@ The Textarea is a widget allowing to input text and displays a cursor. Long line **Specific triggers:** -``on_value`` :ref:`trigger ` is activated on every keystroke, the variable ``text`` containing the entire contents of the textarea. -``on_ready`` :ref:`trigger ` is activated in case of ``one_line`` configured as ``true``, when the New Line character is receicved (Enter key on the keyboard). +- ``on_value`` :ref:`trigger ` is activated on every keystroke, the variable ``text`` containing the entire contents of the textarea. +- ``on_ready`` :ref:`trigger ` is activated in case of ``one_line`` configured as ``true``, when the New Line character is receicved (Enter key on the keyboard). **Example:** @@ -1621,7 +1617,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 widgets), 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:** @@ -1695,17 +1691,16 @@ A typical application would probably use an ``obj`` container widget as a tile, **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*): 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``. +- ``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*): 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 visible 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:** From f54b3601e69cac9b5a46a9ef06d6a70a8e3a33f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 10:29:31 +0200 Subject: [PATCH 410/564] 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 76f99c07c7..3c745fd89e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -2082,10 +2082,13 @@ See Also - :doc:`Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` - :doc:`/components/switch/lvgl` -- :doc:`/components/number/lvgl` or :doc:`/components/sensor/lvgl` - :doc:`/components/select/lvgl` - :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` - :doc:`/components/display/index` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` From e906760234de8ebc74aa0d5a203a8b2e24da35ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 10:30:58 +0200 Subject: [PATCH 411/564] 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 3c745fd89e..5380c7eaef 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -562,8 +562,7 @@ A label is the basic widget type that is used to display text. - ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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. + - **args** (*Optional*, list of :ref:`lambda `): The optional arguments for the format message. **Example:** From d0bc87bf8e32d523f87ecada69a6e187a41e6ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 10:37:37 +0200 Subject: [PATCH 412/564] Update lvgl_c_txt.png --- images/lvgl_c_txt.png | Bin 1516 -> 1623 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/lvgl_c_txt.png b/images/lvgl_c_txt.png index 2691af6de1b636f07cb93885c9eaf28f01e77cb2..72f1d05113a88968343a9c2f48a9c14ffc658a7f 100644 GIT binary patch literal 1623 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 Date: Fri, 10 May 2024 11:47:24 +0200 Subject: [PATCH 413/564] keyboard widget --- components/images/lvgl_keyboard.png | Bin 0 -> 8996 bytes components/key_collector.rst | 13 ++-- components/lvgl.rst | 96 ++++++++++++++++++++++++++++ cookbook/lvgl.rst | 2 +- 4 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 components/images/lvgl_keyboard.png diff --git a/components/images/lvgl_keyboard.png b/components/images/lvgl_keyboard.png new file mode 100644 index 0000000000000000000000000000000000000000..a9b009d310b9e2617b9205df246dae67333a710a GIT binary patch literal 8996 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 -or :ref:`LVGL Button Matrix widget `. It allows you to process -key sequences and treat them as one, for example to allow inputting of -a PIN code or a passkey. The component outputs the result of the keypress -sequence as a variable usable in automations. - - +or LVGL :ref:`Button Matrix `, :ref:`Keyboard ` +widgets. It allows you to process key sequences and treat them as one, for +example to allow inputting of a PIN code or a passkey. The component outputs +the result of the keypress sequence as a variable usable in automations. Component --------- @@ -45,8 +43,6 @@ Component format: "input timeout: '%s', started by '%c'" args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] - - Configuration variables: - **id** (*Optional*, :ref:`config-id`): Set the ID of this entry for use in lambdas. @@ -96,4 +92,5 @@ See Also - :doc:`/components/matrix_keypad` - :doc:`/components/wiegand` - :ref:`LVGL Button Matrix widget ` +- :ref:`LVGL Keyboard widget ` - :ghedit:`Edit` diff --git a/components/lvgl.rst b/components/lvgl.rst index 5380c7eaef..60b37e5978 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -420,6 +420,7 @@ Common properties The properties below are common to all widgets. +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **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). @@ -692,6 +693,11 @@ The Button Matrix widget 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. - ``lvgl.btnmatrix.update`` :ref:`action ` updates the items styles and properties specified in the specific ``state``, ``items`` options. +**Specific triggers:** + +- ``on_value`` and :ref:`universal ` triggers can be configured for each button, is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. +- The :ref:`universal ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). + **Example:** .. code-block:: yaml @@ -747,6 +753,30 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row items: bg_color: 0xf0f0f0 + # Example trigger: + - btnmatrix: + ... + rows: + - buttons: + ... + - id: button_2 + ... + control: + checkable: true + on_value: # Trigger for the individual button, returning the checked state + then: + - logger.log: + format: "Button 2 checked: %d" + args: [ x ] + on_press: # Triggers for the matrix, to determine which button was pressed + logger.log: + format: "Matrix button pressed: %d" + args: ["*x"] + on_click: + logger.log: + format: "Matrix button clicked: %d, is button_2 = %u" + args: ["*x", "id(button_2) == x"] + .. 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. @@ -1793,6 +1823,72 @@ 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-kbd: + +``keyboard`` +************ + +The Keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type texts into a :ref:`lvgl-wgt-txt`. + +.. figure:: /components/images/lvgl_keyboard.png + :align: center + +From styling point of view, it uses the same settings as :ref:`lvgl-wgt-bmx`. + +**Specific options:** + +- **textarea** (*Optional*): The ID of the ``textarea`` which to receive the keystrokes. +- **mode** (*Optional*, enum): Keyboard layout to use. The ``TEXT_`` modes' layout contains buttons to change between each other. + - ``TEXT_LOWER``: Display lower case letters (default). + - ``TEXT_UPPER``: Display upper case letters. + - ``TEXT_SPECIAL``: Display special characters. + - ``NUMBER``: Display numbers, +/- sign, and decimal dot. + +**Specific actions:** + +- ``lvgl.keyboard.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_ready`` :ref:`trigger ` is activated ckeckmark key is pressed. +- ``on_cancel`` :ref:`trigger ` is activated key representing a keyboard icon is pressed. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - keyboard: + id: keyboard_id + textarea: textarea_1 + mode: TEXT_UPPER + + # Example actions: + on_focus: + then: + - lvgl.keyboard.update: + id: keyboard_id + mode: number + textarea: textarea_2 + + # Example trigger: + - keyboard: + ... + on_ready: + then: + - logger.log: Keyboard is ready + on_cancel: + then: + - logger.log: Keyboard cancelled + +.. tip:: + + The Keyboard widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. + +.. note:: + + The Keyboard widget doesn't support popovers or custom layouts. + Actions ------- diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 72234bc84b..296b11254c 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -801,7 +801,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 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: +For the navigation bar we can use a :ref:`lvgl-wgt-bmx`. 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 fb86bf35cada7458619e55f8412cb660995a8e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 11:51:12 +0200 Subject: [PATCH 414/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 60b37e5978..b83824f4be 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -305,7 +305,7 @@ You can configure a global theme for all widgets at the top level with the ``the focused: border_color: 0x00FF00 -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. +Naturally, you can override these at the individual configuration level of each widget. This can be done in batches, using the ``style_definitions`` configuration variable of the main component. In the example below, you defined ``date_style``: .. code-block:: yaml From 3323a48fe7ae1a936a14ed69a01825eef09496b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 12:06:44 +0200 Subject: [PATCH 415/564] Apply suggestions from code review Co-authored-by: Keith Burzinski --- components/lvgl.rst | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b83824f4be..e4f633c1ec 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -659,7 +659,7 @@ See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable b ``btnmatrix`` ************* -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. +The Button Matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. .. figure:: /components/images/lvgl_btnmatrix.png :align: center @@ -671,7 +671,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **id** (*Optional*): An ID for the button in the matrix. - **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). + - **width** (*Optional*): Width relative to the other buttons in the same row. Must be a value between ``1`` and ``15``; the default is ``1`` (for example, given a line with two buttons, one with ``width: 1`` and another one with ``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): Make a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable). @@ -681,7 +681,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **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#`` + - **recolor** (*Optional*, boolean): Enable recoloring of button text with ``#``. For example: ``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. @@ -841,14 +841,14 @@ 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 from the specific options above, just like :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 the :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. **Specific triggers:** -``on_value`` :ref:`trigger ` is activated when toggling the checkbox, the variable ``x`` returning a boolean representing the checked state. +``on_value`` :ref:`trigger ` is activated when toggling the checkbox. The boolean variable ``x``, representing the checkbox's state, may be used by lambdas within this trigger. **Example:** @@ -900,16 +900,16 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( - **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. +- **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 those built-in or from your own customized font. - **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. +- 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`` can be used to set the font of the button part, including the symbol. **Specific actions:** -- ``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. +- ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Specific triggers:** @@ -976,7 +976,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 from the specific options above, just like :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Specific triggers:** @@ -1035,13 +1035,13 @@ Not only the end, but also the start value of the bar can be set, which changes - **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``. +- **animated** (*Optional*, boolean): Animate the indicator when the 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. **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. +- ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1070,7 +1070,7 @@ The ``bar`` can be also integrated as :doc:`/components/number/lvgl` or :doc:`/c ``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. +The Slider widget looks like a bar supplemented with a knob. The user can drag the knob to set a value. Just like Bar, Slider can be vertical or horizontal. .. figure:: /components/images/lvgl_slider.png :align: center @@ -1080,9 +1080,9 @@ The Slider widget looks like a bar supplemented with a knob. The knob can be dra - **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``. +- **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) is 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. +- **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 shows the current state of the slider. Also uses all the typical background style properties. +- **animated** (*Optional*, boolean): Animate the indicator when the 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. @@ -1090,11 +1090,11 @@ 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 from the specific options above, just like :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 the :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``. +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. 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:** @@ -1129,11 +1129,11 @@ 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. In such cases use a :ref:`universal event trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. + The ``on_value`` trigger is sent as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal event 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` or :doc:`/components/sensor/lvgl`. -See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples how to use a slider to control entities in Home Assistant. +See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider to control entities in Home Assistant. .. _lvgl-wgt-arc: From c6b8e97e2db10d03fa2ebc560491526e16b15be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 12:14:38 +0200 Subject: [PATCH 416/564] Update lvgl.rst --- components/lvgl.rst | 112 ++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index e4f633c1ec..0930e719b0 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -64,9 +64,9 @@ Although LVGL is a complex matrix of objects-parts-states-styles, ESPHome simpli At the highest level of the LVGL object hierarchy is the display (represented by 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 to be presented on the 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. +The following configuration variables 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:** +**Configuration variables:** - **displays** (**Required**, list): A list of displays where LVGL should perform rendering based on its configuration: - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. @@ -222,7 +222,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). @@ -420,6 +420,8 @@ Common properties The properties below are common to all widgets. +**Configuration variables:** + - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. - **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). @@ -533,7 +535,7 @@ A label is the basic widget type that is used to display text. .. figure:: /components/images/lvgl_label.png :align: center -**Specific options:** +**Configuration variables:** - **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. @@ -558,7 +560,7 @@ A label is the basic widget type that is used to display text. 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:** +**Actions:** - ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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`). @@ -601,14 +603,14 @@ Simple push or toggle button. .. figure:: /components/images/lvgl_button.png :align: center -**Specific options:** +**Configuration variables:** - **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. A notable state is ``checked`` (boolean) which can have different styles applied. -**Specific triggers:** +**Triggers:** - ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. @@ -664,7 +666,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row .. figure:: /components/images/lvgl_btnmatrix.png :align: center -**Specific options:** +**Configuration variables:** - **rows** (**Required**, list): A list for the button rows: - **buttons** (**Required**, list): A list of buttons in a row: @@ -688,12 +690,12 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row - **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:** +**Actions:** - ``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. -**Specific triggers:** +**Triggers:** - ``on_value`` and :ref:`universal ` triggers can be configured for each button, is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. - The :ref:`universal ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). @@ -791,13 +793,13 @@ 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:** +**Configuration variables:** - **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`. -**Specific triggers:** +**Triggers:** - ``on_value`` :ref:`trigger ` is activated when toggling the switch, the variable ``x`` returning a boolean representing the checked state. @@ -834,19 +836,19 @@ The Checkbox widget is made internally from a *tick box* and a label. When the C .. figure:: /components/images/lvgl_checkbox.png :align: center -**Specific options:** +**Configuration variables:** - **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 tick box and the label. -**Specific actions:** +**Actions:** - ``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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. -**Specific triggers:** +**Triggers:** ``on_value`` :ref:`trigger ` is activated when toggling the checkbox. The boolean variable ``x``, representing the checkbox's state, may be used by lambdas within this trigger. @@ -895,7 +897,7 @@ The dropdown list is closed by default and displays a single value. When activat 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:** +**Configuration variables:** - **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``. @@ -907,11 +909,11 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( - **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`` can be used to set the font of the button part, including the symbol. -**Specific actions:** +**Actions:** - ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -**Specific triggers:** +**Triggers:** - ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. - ``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. @@ -964,7 +966,7 @@ Roller allows you to simply select one option from a list by scrolling. .. figure:: /components/images/lvgl_roller.png :align: center -**Specific options:** +**Configuration variables:** - **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``. @@ -974,11 +976,11 @@ Roller allows you to simply select one option from a list by scrolling. - **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:** +**Actions:** - ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -**Specific triggers:** +**Triggers:** - ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. @@ -1028,7 +1030,7 @@ 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:** +**Configuration variables:** - **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``. @@ -1039,7 +1041,7 @@ 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:** +**Actions:** - ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. @@ -1075,7 +1077,7 @@ The Slider widget looks like a bar supplemented with a knob. The user can drag t .. figure:: /components/images/lvgl_slider.png :align: center -**Specific options:** +**Configuration variables:** - **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``. @@ -1088,11 +1090,11 @@ The Slider widget looks like a bar supplemented with a knob. The user can drag t 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:** +**Actions:** - ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. -**Specific triggers:** +**Triggers:** - ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. 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``. @@ -1145,7 +1147,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator .. figure:: /components/images/lvgl_arc.png :align: center -**Specific options:** +**Configuration variables:** - **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``. @@ -1170,11 +1172,11 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can 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:** +**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:** +**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``. @@ -1227,7 +1229,7 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas .. figure:: /components/images/lvgl_spinbox.png :align: center -**Specific options:** +**Configuration variables:** - **value** (**Required**, float): Actual value to be shown by the spinbox at start. - **range_from** (*Optional*, float): The minimum value allowed to set the spinbox to. Defaults to ``0``. @@ -1242,13 +1244,13 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas The sign character will only be shown if the set range contains negatives. -**Specific actions:** +**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. -**Specific triggers:** +**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``. @@ -1299,7 +1301,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee .. figure:: /components/images/lvgl_meter.png :align: center -**Specific options:** +**Configuration variables:** - **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. Defaults to ``0``. @@ -1352,7 +1354,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee 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:** +**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. ``src`` cannot be updated at runtime. @@ -1406,12 +1408,12 @@ Images are the basic widgets to display images. .. figure:: /components/images/lvgl_image.png :align: center -**Specific options:** +**Configuration variables:** - **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. -**Specific actions:** +**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. @@ -1444,7 +1446,7 @@ The animation image is similar to the normal ``img`` widget. The main difference .. figure:: /components/images/lvgl_animimg.gif :align: center -**Specific options:** +**Configuration variables:** - **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``. @@ -1452,7 +1454,7 @@ 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. -**Specific actions:** +**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. @@ -1489,7 +1491,7 @@ The Line widget is capable of drawing straight lines between a set of points. .. figure:: /components/images/lvgl_line.png :align: center -**Specific options:** +**Configuration variables:** - **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. @@ -1527,13 +1529,13 @@ The Led widgets are rectangle-like (or circle) widget whose brightness can be ad .. figure:: /components/images/lvgl_led.png :align: center -**Specific options:** +**Configuration variables:** - **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. -**Specific actions:** +**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. @@ -1573,7 +1575,7 @@ The Textarea is a widget allowing to input text and displays a cursor. Long line .. figure:: /components/images/lvgl_textarea.png :align: center -**Specific options:** +**Configuration variables:** - **placeholder_text** (*Optional*, string): A placeholder text can be specified, which is displayed when the Text area is empty. - **accepted_chars** (*Optional*, string): You can set a list of accepted characters, so other characters will be ignored. @@ -1582,11 +1584,11 @@ The Textarea is a widget allowing to input text and displays a cursor. Long line - **max_length** (*Optional*, int): Limit the maximum number of characters to this value. - any :ref:`Styling ` and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. -**Specific actions:** +**Actions:** ``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. -**Specific triggers:** +**Triggers:** - ``on_value`` :ref:`trigger ` is activated on every keystroke, the variable ``text`` containing the entire contents of the textarea. - ``on_ready`` :ref:`trigger ` is activated in case of ``one_line`` configured as ``true``, when the New Line character is receicved (Enter key on the keyboard). @@ -1634,7 +1636,7 @@ The Spinner widget is a spinning arc over a ring. .. figure:: /components/images/lvgl_spinner.gif :align: center -**Specific options:** +**Configuration variables:** - **spin_time** (**Required**, :ref:`Time `): Duration of one cycle of the spin. - **arc_length** (**Required**, 0-360): Length of the spinning arc in degrees. @@ -1644,7 +1646,7 @@ The Spinner widget is a spinning arc over a ring. - **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:** +**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 widgets), just like :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. @@ -1680,7 +1682,7 @@ The Base Object is just a simple, empty widget. By default, it's nothing more th You can use it as a parent container for other widgets. By default, it catches touches. -**Specific options:** +**Configuration variables:** - Style options from :ref:`lvgl-styling`. @@ -1708,7 +1710,7 @@ If the Tile view is screen sized, the user interface resembles what you may have 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:** +**Configuration variables:** - **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. @@ -1718,7 +1720,7 @@ A typical application would probably use an ``obj`` container widget as a tile, - **column** (**Required**): Vertical position of the tile in the tileview grid. - Style options from the widget used as container. -**Specific actions:** +**Actions:** - ``lvgl.tileview.select`` :ref:`action ` jumps the ``tileview`` to the desired tile: - **id** (**Required**): The ID of the ``tileview`` which receives this action @@ -1727,7 +1729,7 @@ A typical application would probably use an ``obj`` container widget as a tile, - **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:** +**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 visible tile. @@ -1781,7 +1783,7 @@ The Message boxes act as pop-ups. They are built from a background container, a 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:** +**Configuration variables:** - **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. @@ -1792,7 +1794,7 @@ The text will be broken into multiple lines automatically and the height will be - **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 ` codepoint) to display on the button. -**Specific actions:** +**Actions:** The configured message boxes are hidden by default. One can show them with ``lvgl.widget.show`` and ``lvgl.widget.hide`` :ref:`actions `. @@ -1835,7 +1837,7 @@ The Keyboard widget is a special Button matrix with predefined keymaps and other From styling point of view, it uses the same settings as :ref:`lvgl-wgt-bmx`. -**Specific options:** +**Configuration variables:** - **textarea** (*Optional*): The ID of the ``textarea`` which to receive the keystrokes. - **mode** (*Optional*, enum): Keyboard layout to use. The ``TEXT_`` modes' layout contains buttons to change between each other. @@ -1844,11 +1846,11 @@ From styling point of view, it uses the same settings as :ref:`lvgl-wgt-bmx`. - ``TEXT_SPECIAL``: Display special characters. - ``NUMBER``: Display numbers, +/- sign, and decimal dot. -**Specific actions:** +**Actions:** - ``lvgl.keyboard.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:** +**Triggers:** - ``on_ready`` :ref:`trigger ` is activated ckeckmark key is pressed. - ``on_cancel`` :ref:`trigger ` is activated key representing a keyboard icon is pressed. From 947e8415638451f1000979141933953535ca9f80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 13:16:58 +0200 Subject: [PATCH 417/564] Update index.rst --- index.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/index.rst b/index.rst index 9b03946898..3825b1ef9a 100644 --- a/index.rst +++ b/index.rst @@ -827,6 +827,14 @@ Cover Components Time-Based Cover, components/cover/time_based, timer.svg, dark-invert Tuya Cover, components/cover/tuya, tuya.png +Valve Components +---------------- + +.. imgtable:: + + Valve Core, components/valve/index, folder-open.svg, dark-invert + Template Valve, components/valve/template, description.svg, dark-invert + Text Components --------------- @@ -836,14 +844,6 @@ Text Components Template Text, components/text/template, description.svg, dark-invert LVGL textarea Text, components/text/lvgl, lvgl_c_txt.png -Valve Components ----------------- - -.. imgtable:: - - Valve Core, components/valve/index, folder-open.svg, dark-invert - Template Valve, components/valve/template, description.svg, dark-invert - Text Sensor Components ---------------------- From 9431a61480390b9d89cdc72c9505a1a58a16de68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 13:26:44 +0200 Subject: [PATCH 418/564] 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 0930e719b0..79c90f548f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -693,7 +693,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row **Actions:** - ``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. +- ``lvgl.btnmatrix.update`` :ref:`action ` updates the item styles and properties specified in the specific ``state``, ``items`` options. **Triggers:** @@ -801,7 +801,7 @@ The Switch looks like a little slider and can be used to turn something on and o **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when toggling the switch, the variable ``x`` returning a boolean representing the checked state. +- ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. **Example:** From ba89b56ddc5703969751bc0332937d9fb378cf80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 14:38:37 +0200 Subject: [PATCH 419/564] 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 79c90f548f..420bd69c82 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -47,7 +47,7 @@ Some widgets integrate also as native ESPHome components: - :doc:`Switch ` * - ``slider``, ``arc``, ``spinbox`` - - :doc:`Number ` + - :doc:`Number `, :doc:`Sensor ` * - ``dropdown``, ``roller`` - :doc:`Select ` @@ -55,6 +55,10 @@ Some widgets integrate also as native ESPHome components: * - ``led`` - :doc:`Light ` + * - ``textarea`` + - :doc:`Text `, :doc:`Text Sensor ` + + These are useful to make :ref:`automations ` triggered by actions performed at the screen. Main Configuration From 66fde5080a5cb2e460135f28ea03555f369b1611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 14:50:22 +0200 Subject: [PATCH 420/564] options > variables --- components/binary_sensor/lvgl.rst | 6 +++--- components/lvgl.rst | 7 +++---- components/number/lvgl.rst | 6 +++--- components/select/lvgl.rst | 6 +++--- components/sensor/lvgl.rst | 6 +++--- components/switch/lvgl.rst | 6 +++--- components/text/lvgl.rst | 10 ++++------ components/text_sensor/lvgl.rst | 6 +++--- 8 files changed, 25 insertions(+), 28 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 03d87a6d43..b0b1f4b9a6 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -12,11 +12,11 @@ and requires :ref:`LVGL ` to be configured. Supported widget is :ref:`lvgl-wgt-btn`. A single binary sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome binary sensor component. -Configuration options: ----------------------- +Configuration variables: +------------------------ - **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 `. +- All other variables from :ref:`Binary Sensor `. Example: diff --git a/components/lvgl.rst b/components/lvgl.rst index 420bd69c82..ca14aeee1b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -41,7 +41,7 @@ Some widgets integrate also as native ESPHome components: - ESPHome component * - ``btn`` - - :doc:`Binary Sensor `, :doc:`Switch ` + - :doc:`Switch `, :doc:`Binary Sensor ` * - ``switch``, ``checkbox`` - :doc:`Switch ` @@ -52,12 +52,11 @@ Some widgets integrate also as native ESPHome components: * - ``dropdown``, ``roller`` - :doc:`Select ` - * - ``led`` - - :doc:`Light ` - * - ``textarea`` - :doc:`Text `, :doc:`Text Sensor ` + * - ``led`` + - :doc:`Light ` These are useful to make :ref:`automations ` triggered by actions performed at the screen. diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 88a8b9019b..0387c919a1 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -12,12 +12,12 @@ 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 only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome number component. -Configuration options: ----------------------- +Configuration variables: +------------------------ - **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the number. - **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 `. +- All other variables from :ref:`Number `. Example: diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 9a2c07fe52..162db81b70 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -12,11 +12,11 @@ and requires :ref:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-wgt-drp` and :ref:`lvgl-wgt-rol`. A single select supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome select component. -Configuration options: ----------------------- +Configuration variables: +------------------------ - **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 `. +- All other variables from :ref:`Select `. Example: diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 7b1f1d90db..0e427efff6 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -12,11 +12,11 @@ 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 sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome sensor. -Configuration options: ----------------------- +Configuration variables: +------------------------ - **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the sensor. -- All other options from :ref:`Sensor `. +- All other variables from :ref:`Sensor `. Example: diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 3e841736db..7625beb791 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -12,12 +12,12 @@ 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 only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome switch component. -Configuration options: ----------------------- +Configuration variables: +------------------------ - **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 ``checked`` state of the configured widget. -- All other options from :ref:`Switch `. +- All other variables from :ref:`Switch `. Example: diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index 9c39b07de5..d62de4c8ec 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -7,17 +7,15 @@ LVGL Text :description: Instructions for setting up an LVGL textarea Text component. :image: ../images/lvgl_c_txt.png -The ``lvgl`` text platform creates an editable text component from an LVGL textarea widget -and requires :ref:`LVGL ` to be configured. +The ``lvgl`` text platform creates an editable text component from an LVGL textarea widget and requires :ref:`LVGL ` to be configured. Supported widget is :ref:`lvgl-wgt-txt`. A single text supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text component. - -Configuration options: ----------------------- +Configuration variables: +------------------------ - **widget** (**Required**): The ID of a ``textarea`` widget configured in LVGL, which will reflect the state of the text component. -- All other options from :ref:`Text `. +- All other variables from :ref:`Text `. Example: diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index f8d9b0a37e..300d471e03 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -12,11 +12,11 @@ and requires :ref:`LVGL ` to be configured. Supported widget is :ref:`lvgl-wgt-txt`. A single text sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text sensor component. -Configuration options: ----------------------- +Configuration variables: +------------------------ - **widget** (**Required**): The ID of a ``textarea`` widget configured in LVGL, which will reflect the state of the text sensor. -- All other options from :ref:`Text Sensor `. +- All other variables from :ref:`Text Sensor `. Example: From b980893dad3048e9f1d84a30ce2a28276ef87a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 10 May 2024 21:04:23 +0200 Subject: [PATCH 421/564] 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 ca14aeee1b..03c1492e10 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -442,7 +442,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 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%``. +- **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 dimensions 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. 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!). From 21d240d01dae2a6ebe15d0298d3ed26bf4c53a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 11 May 2024 13:46:31 +0200 Subject: [PATCH 422/564] Update index.rst --- components/display/index.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index 94c88da62b..d623c1740f 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -8,10 +8,9 @@ Display Component 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:`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 `, +- Character displays like :doc:`7-Segment ` or :doc:`LCD `. +- Serial displays like :doc:`nextion` that have their own processors for graphics rendering. +- Graphical displays which can toggle ON/OFF any pixel, like :doc:`E-Paper `, :doc:`OLED ` or :doc:`TFT ` displays. For graphical binary displays, there are two options: @@ -24,8 +23,8 @@ For graphical binary displays, there are two options: Display Rendering Engine ------------------------ -ESPHome's own powerful rendering engine can handle many common tasks such as drawing basic shapes, printing text with fonts of your choice, -or even rendering images. +ESPHome's own powerful rendering engine can handle many common tasks such as drawing basic shapes, +printing text with fonts of your choice, or even rendering 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 From edd3659c90cba7ef70649556e043be78443fef73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 11 May 2024 13:56:43 +0200 Subject: [PATCH 423/564] Update index.rst --- components/display/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index d623c1740f..ecd41c2cbd 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -13,9 +13,9 @@ engine. Fundamentally, there are these types of displays: - Graphical displays which can toggle ON/OFF any pixel, like :doc:`E-Paper `, :doc:`OLED ` or :doc:`TFT ` displays. -For graphical binary displays, there are two options: +For graphical displays, which offer the greatest flexibility, there are two options: -- ESPHome's :ref:`own powerful rendering engine ` +- ESPHome's :ref:`own rendering engine ` - :ref:`LVGL ` - Light and Versatile Graphics Library .. _display-engine: From 63bdf6296d3e834a078067e7497f802eba9c85b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 11 May 2024 14:07:14 +0200 Subject: [PATCH 424/564] 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 03c1492e10..e4dd0263ea 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -14,7 +14,7 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t 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 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 have an :ref:`config-id` set, which will be referenced in the main LGVL component configuration. +The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should have an :ref:`config-id` set, which will be referenced in the main LGVL component configuration. For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred) or a :doc:`/components/sensor/rotary_encoder` can be used. From 2b582a3efb7c47915858412062f254ca85d6de2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 11 May 2024 14:44:38 +0200 Subject: [PATCH 425/564] 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 e4dd0263ea..48f5b8c16a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -14,7 +14,7 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t 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 graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should have an :ref:`config-id` set, which will be referenced in the main LGVL component configuration. +The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should have an :ref:`config-id` configured, which will be referenced by the main LGVL component. For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred) or a :doc:`/components/sensor/rotary_encoder` can be used. @@ -1892,7 +1892,7 @@ From styling point of view, it uses the same settings as :ref:`lvgl-wgt-bmx`. .. note:: - The Keyboard widget doesn't support popovers or custom layouts. + The Keyboard widget in ESPHome doesn't support popovers or custom layouts. Actions ------- From ee43433f9dde6013965862dd9fc7b978928e53ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 12 May 2024 13:11:58 +0200 Subject: [PATCH 426/564] Apply suggestions from code review Co-authored-by: Keith Burzinski --- components/lvgl.rst | 38 +++++++++++++++++++------------------- components/switch/lvgl.rst | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 48f5b8c16a..49246ca9c9 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1173,11 +1173,11 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can .. 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. + The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. **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.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Triggers:** @@ -1216,18 +1216,18 @@ 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 :ref:`universal event trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. + The ``on_value`` trigger is sent as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using 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` or :doc:`/components/sensor/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. +See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider (or an arc) to control entities in Home Assistant. .. _lvgl-wgt-spb: ``spinbox`` *********** -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. +The Spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. .. figure:: /components/images/lvgl_spinbox.png :align: center @@ -1249,7 +1249,7 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas **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.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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. @@ -1292,21 +1292,21 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas The ``spinbox`` can be also integrated as :doc:`/components/number/lvgl` or :doc:`/components/sensor/lvgl`. -See :ref:`lvgl-cook-climate` for an example how to implement a thermostat control using the spinbox. +See :ref:`lvgl-cook-climate` for an example illustrating how to implement a thermostat control using the spinbox. .. _lvgl-wgt-mtr: ``meter`` ********* -The Meter widget can visualize data in very flexible ways. In can show arcs, needles, ticks lines and labels. +The Meter widget can visualize data in very flexible ways. It can use arcs, needles, ticks, lines and/or labels. .. figure:: /components/images/lvgl_meter.png :align: center **Configuration variables:** -- **scales** (**Required**, list): A list with (any number of) scales to be added to meter. +- **scales** (**Required**, list): A list with (any number of) scales to be added to the meter. - **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``. @@ -1321,7 +1321,7 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee - **width**: Tick line width in pixels. Defaults to ``5``. - **length**: Tick line length in pixels or percentage. Defaults to ``15%``. - **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``. + - **label_gap**: Label distance from the ticks with text proportional 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: - **arc** (*Optional*): Add a background arc the scale: @@ -1355,11 +1355,11 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee .. 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. + The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. **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. ``src`` cannot be updated at runtime. +- ``lvgl.indicator.update`` :ref:`action ` updates indicator options, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` cannot be updated at runtime. **Example:** @@ -1399,26 +1399,26 @@ The Meter widget can visualize data in very flexible ways. In can show arcs, nee id: temperature_needle value: 3 -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. +See :ref:`lvgl-cook-gauge`, :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clock` in the Cookbook for examples illustrating how to effectively use this widget. .. _lvgl-wgt-img: ``img`` ******* -Images are the basic widgets to display images. +Images are the basic widgets used to display images. .. figure:: /components/images/lvgl_image.png :align: center **Configuration variables:** -- **src** (**Required**, :ref:`image `): The ID of an existing image configuration. +- **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. **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. +- ``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. **Example:** @@ -1453,15 +1453,15 @@ 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 a playback cycle (each frame is displayed for an equal amount of time). +- **repeat_count** (*Optional*, int16 or *forever*): The number of times playback should be repeated. 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. **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. +- ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. **Example:** diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 7625beb791..420ff7f46f 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -28,7 +28,7 @@ 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. +Check out :ref:`lvgl-cook-outbin` in the Cookbook for an example illustrating how to set up a LVGL Switch component to interact directly with a GPIO. See Also -------- From b175fdbe55db625c878b2f0c8fdb579ceb816b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 12 May 2024 15:29:14 +0200 Subject: [PATCH 427/564] feature updates --- components/lvgl.rst | 14 ++++++++------ components/number/lvgl.rst | 4 ++++ components/select/lvgl.rst | 4 ++++ components/sensor/lvgl.rst | 4 ++++ components/text/lvgl.rst | 11 ++++++++--- components/text_sensor/lvgl.rst | 11 ++++++++--- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 49246ca9c9..6b7559e734 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -52,7 +52,7 @@ Some widgets integrate also as native ESPHome components: * - ``dropdown``, ``roller`` - :doc:`Select ` - * - ``textarea`` + * - ``label``, ``textarea`` - :doc:`Text `, :doc:`Text Sensor ` * - ``led`` @@ -243,7 +243,7 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **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``): +- **border_side** (*Optional*, list): Select which borders of the widgets to show (multiple can be specified as a YAML list, defaults to ``NONE``): - ``NONE`` - ``TOP`` - ``BOTTOM`` @@ -543,7 +543,7 @@ 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 as YAML list). 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``. @@ -596,6 +596,8 @@ A label is the basic widget type that is used to display text. format: "%.0fdBm" args: [ 'id(wifi_signal_db).get_state()' ] +The ``label`` can be also integrated as :doc:`/components/text/lvgl` or :doc:`/components/text_sensor/lvgl`. + .. _lvgl-wgt-btn: ``btn`` @@ -1593,8 +1595,8 @@ The Textarea is a widget allowing to input text and displays a cursor. Long line **Triggers:** -- ``on_value`` :ref:`trigger ` is activated on every keystroke, the variable ``text`` containing the entire contents of the textarea. -- ``on_ready`` :ref:`trigger ` is activated in case of ``one_line`` configured as ``true``, when the New Line character is receicved (Enter key on the keyboard). +- ``on_value`` :ref:`trigger ` is activated on every keystroke, the variable ``text`` (``std::string`` type) containing the entire contents of the textarea. +- ``on_ready`` :ref:`trigger ` is activated in case of ``one_line`` configured as ``true``, when the New Line character is receicved (Enter/Ready key on the keyboard), the variable ``text`` (``std::string`` type) containing the entire contents of the textarea. **Example:** @@ -1718,7 +1720,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**): 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``. + - **dir** (*Optional*): Enable moving to the adjacent tiles into the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. - **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. diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 0387c919a1..2f65555aee 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -28,6 +28,10 @@ Example: widget: slider_id name: LVGL Slider +.. note:: + + Widget-specific actions (``lvgl.arc.update``, ``lvgl.bar.update``, ``lvgl.slider.update``, ``lvgl.spinbox.update``, ``lvgl.spinbox.decrement``, ``lvgl.spinbox.increment``) will trigger correspponding component updates to be sent to Home Assistant. + See Also -------- - :ref:`LVGL Main component ` diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 162db81b70..c0ddac6077 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -27,6 +27,10 @@ Example: widget: dropdown_id name: LVGL Dropdown +.. note:: + + Widget-specific actions (``lvgl.dropdown.update``, ``lvgl.roller.update``) will trigger correspponding component updates to be sent to Home Assistant. + See Also -------- - :ref:`LVGL Main component ` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 0e427efff6..7519338103 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -27,6 +27,10 @@ Example: widget: slider_id name: LVGL Slider +.. note:: + + Widget-specific actions (``lvgl.arc.update``, ``lvgl.bar.update``, ``lvgl.slider.update``, ``lvgl.spinbox.update``, ``lvgl.spinbox.decrement``, ``lvgl.spinbox.increment``) will trigger correspponding component updates to be sent to Home Assistant. + See Also -------- - :ref:`LVGL Main component ` diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index d62de4c8ec..76b394a6c5 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -4,12 +4,12 @@ LVGL Text ========= .. seo:: - :description: Instructions for setting up an LVGL textarea Text component. + :description: Instructions for setting up an LVGL Text component. :image: ../images/lvgl_c_txt.png -The ``lvgl`` text platform creates an editable text component from an LVGL textarea widget and requires :ref:`LVGL ` to be configured. +The ``lvgl`` text platform creates an editable text component from an LVGL textual widget and requires :ref:`LVGL ` to be configured. -Supported widget is :ref:`lvgl-wgt-txt`. A single text supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text component. +Supported widgets are :ref:`lvgl-wgt-lbl` and :ref:`lvgl-wgt-txt`. A single text supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text component. Configuration variables: ------------------------ @@ -26,9 +26,14 @@ Example: widget: textarea_id name: "Textarea 1 text" +.. note:: + + Widget-specific actions (``lvgl.label.update``, ``lvgl.textarea.update``) will trigger correspponding component updates to be sent to Home Assistant. + See Also -------- - :ref:`LVGL Main component ` +- :ref:`Label widget ` - :ref:`Textarea widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index 300d471e03..2953dcccba 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -4,13 +4,13 @@ LVGL Text Sensor ================ .. seo:: - :description: Instructions for setting up an LVGL textarea Text Sensor. + :description: Instructions for setting up an LVGL Text Sensor. :image: ../images/lvgl_c_txt.png -The ``lvgl`` text platform creates a Text Sensor from an LVGL textarea widget +The ``lvgl`` text platform creates a Text Sensor from an LVGL textual widget and requires :ref:`LVGL ` to be configured. -Supported widget is :ref:`lvgl-wgt-txt`. A single text sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text sensor component. +Supported widgets are :ref:`lvgl-wgt-lbl` and :ref:`lvgl-wgt-txt`. A single text sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text sensor component. Configuration variables: ------------------------ @@ -27,9 +27,14 @@ Example: widget: textarea_id name: "Textarea 1 text" +.. note:: + + Widget-specific actions (``lvgl.label.update``, ``lvgl.textarea.update``) will trigger correspponding component updates to be sent to Home Assistant. + See Also -------- - :ref:`LVGL Main component ` +- :ref:`Label widget ` - :ref:`Textarea widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` From 85db60545d9c48fd3b3ff2cbf027c46464267779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 09:16:09 +0200 Subject: [PATCH 428/564] added missing img options --- components/lvgl.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 6b7559e734..9fc314fd85 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1159,7 +1159,7 @@ The Arc consists of a background and a foreground arc. The foreground (indicator - **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``. +- **rotation** (*Optional*, 0-360): 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``. @@ -1416,6 +1416,13 @@ Images are the basic widgets used to display images. **Configuration variables:** - **src** (**Required**, :ref:`image `): The ID of an existing image configuration. +- **angle** (*Optional*, 0-360): Rotation of the image. Defaults to ``0.0``. +- **zoom** (*Optional*, 0.1-10): Zoom of the image. +- **pivot_x** (*Optional*): 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** (*Optional*): Vertical position of the pivot point of rotation relative to the top left corner of the image.. Defaults to ``50%`` (center of image). +- **antialias** (*Optional*): The quality of the angle or zoom transformation. With enabled anti-aliasing the transformations are higher quality but slower. Defaults to ``false``. +- **mode** (*Optional*): ``VIRTUAL``: when the image is zoomed or rotated the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. ``REAL`` if the width/height of the object is set to ``size_content`` the object's size will be set to the zoomed and rotated size. If an explicit size is set then the overflowing content will be cropped. Defaults to ``VIRTUAL``. +- **offset_x**, **offset_y** (*Optional*): Add offset to the displayed image. Useful if the widget size is smaller than the image source size. Using the offset parameter a *running image* effect can be created by animating these values. - 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. **Actions:** From 5f26d80f2dd719c1da31f4ec8722e8f002ac6568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 10:32:36 +0200 Subject: [PATCH 429/564] Update lvgl.rst --- components/lvgl.rst | 68 +++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9fc314fd85..fbf3f9ff3b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -96,19 +96,15 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. May not be used if ``pages`` (below) is configured. - **pages** (*Optional*, list): A list of page IDs. Each page acts as a parent for widgets placed on it. May not be used with ``widgets`` (above). Options for each page: - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. - - **layout** (*Optional*, string): One of ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. Defaults to ``NONE`` which disables layouts (each widget will then require manual positioning). - - **flex_flow** (*Optional*, string): See :ref:`flex layout ` options. + - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - 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``. - **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, which may be useful for widgets which always need to be visible. May not be used with ``widgets`` (above). Options: - - **layout** (*Optional*, string): One of ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. Defaults to ``NONE`` which disables layouts (each widget will then require manual positioning). - - **flex_flow** (*Optional*, string): See :ref:`flex layout ` options. + - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - 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): One of ``FLEX``, ``GRID`` or ``NONE``. See :ref:`layouts `. Defaults to ``NONE`` which disables layouts (each widget will then require manual positioning). -- **flex_flow** (*Optional*, string): See :ref:`flex layout ` options. - +- **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - All other options from :ref:`lvgl-styling` to be applied to all widgets directly. **Example:** @@ -355,11 +351,9 @@ 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. - -The precedence (value) of states is quite intuitive and it's something the user would expect naturally. For example, 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 override the "pressed" color, defeating its purpose.) +So the precedence 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 value precedence of states is quite intuitive and it's something the user would expect naturally. For example, 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 override the *pressed* color, defeating its purpose.) -Feel free to experiment to discover inheritance of the styles based on states between the nested widgets. +Feel free to experiment to discover inheritance and precedence of the styles based on states between the nested widgets. :ref:`lvgl-cook-theme` The Cookbook contains an example illustrating how to easily implement a gradient style for your widgets. @@ -372,6 +366,12 @@ Layouts aim to position widgets automatically, eliminating the need to specify ` The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. +**Configuration variables:** + +- **layout** (*Optional*, string): A dictionary describing the layout configuration: + - *type* (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. + - Further options from below depending on the chosen type. + .. _lvgl-layouts-flex: **Flex** @@ -380,24 +380,39 @@ The Flex layout in LVGL is a subset implementation of `CSS Flexbox `. If not specified, defaults to ``NONE``, which disables layouts each widget needing manual positioning. -- **flex_flow** (*Optional*, string): See :ref:`flex layout ` options. +- **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - **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: @@ -549,7 +563,7 @@ A label is the basic widget type that is used to display text. - **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 text with ``#``. This makes it possible to set the color of characters in the text individually by prefixing the text to be re-colored with a ``#RRGGBB`` hexadecimal color code followed by a *space*, and finally closed 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 set 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. +- **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 set by :ref:`lvgl-layouts`), 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 lines which are too long. 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 the text horizontally back and forth. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. @@ -1422,7 +1436,7 @@ Images are the basic widgets used to display images. - **pivot_y** (*Optional*): Vertical position of the pivot point of rotation relative to the top left corner of the image.. Defaults to ``50%`` (center of image). - **antialias** (*Optional*): The quality of the angle or zoom transformation. With enabled anti-aliasing the transformations are higher quality but slower. Defaults to ``false``. - **mode** (*Optional*): ``VIRTUAL``: when the image is zoomed or rotated the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. ``REAL`` if the width/height of the object is set to ``size_content`` the object's size will be set to the zoomed and rotated size. If an explicit size is set then the overflowing content will be cropped. Defaults to ``VIRTUAL``. -- **offset_x**, **offset_y** (*Optional*): Add offset to the displayed image. Useful if the widget size is smaller than the image source size. Using the offset parameter a *running image* effect can be created by animating these values. +- **offset_x**, **offset_y** (*Optional*): Add an offset to the displayed image. Useful if the widget size is smaller than the image source size. Tip: a *running image* effect can be created by animating these values. - 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. **Actions:** From 542cc5782d0406d6dd1be0c5fb5d7c0ee84d6a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 10:43:48 +0200 Subject: [PATCH 430/564] Apply suggestions from code review Co-authored-by: Keith Burzinski --- components/lvgl.rst | 78 ++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index fbf3f9ff3b..70db4d4df2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1434,8 +1434,8 @@ Images are the basic widgets used to display images. - **zoom** (*Optional*, 0.1-10): Zoom of the image. - **pivot_x** (*Optional*): 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** (*Optional*): Vertical position of the pivot point of rotation relative to the top left corner of the image.. Defaults to ``50%`` (center of image). -- **antialias** (*Optional*): The quality of the angle or zoom transformation. With enabled anti-aliasing the transformations are higher quality but slower. Defaults to ``false``. -- **mode** (*Optional*): ``VIRTUAL``: when the image is zoomed or rotated the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. ``REAL`` if the width/height of the object is set to ``size_content`` the object's size will be set to the zoomed and rotated size. If an explicit size is set then the overflowing content will be cropped. Defaults to ``VIRTUAL``. +- **antialias** (*Optional*): The quality of the angle or zoom transformation. When anti-aliasing is enabled, the transformations are higher quality but slower. Defaults to ``false``. +- **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is zoomed or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``size_content``, the object's size will be set to the zoomed and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. - **offset_x**, **offset_y** (*Optional*): Add an offset to the displayed image. Useful if the widget size is smaller than the image source size. Tip: a *running image* effect can be created by animating these values. - 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. @@ -1550,7 +1550,7 @@ By default, the Line widget width and height dimensions are set to ``size_conten ``led`` ******** -The Led widgets are rectangle-like (or circle) widget whose brightness can be adjusted. With lower brightness the colors become darker. +The LED widgets are either circular or rectangular widgets whose brightness can be adjusted. As their brightness decreases, the colors become darker. .. figure:: /components/images/lvgl_led.png :align: center @@ -1563,7 +1563,7 @@ The Led widgets are rectangle-like (or circle) widget whose brightness can be ad **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. +- ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1589,14 +1589,14 @@ 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` in the Cookbook 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 illustrating how to change the ``led`` styling properties from an automation. .. _lvgl-wgt-txt: ``textarea`` ************ -The Textarea is a widget allowing to input text and displays a cursor. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. +The Textarea is a widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. .. figure:: /components/images/lvgl_textarea.png :align: center @@ -1616,8 +1616,10 @@ The Textarea is a widget allowing to input text and displays a cursor. Long line **Triggers:** -- ``on_value`` :ref:`trigger ` is activated on every keystroke, the variable ``text`` (``std::string`` type) containing the entire contents of the textarea. -- ``on_ready`` :ref:`trigger ` is activated in case of ``one_line`` configured as ``true``, when the New Line character is receicved (Enter/Ready key on the keyboard), the variable ``text`` (``std::string`` type) containing the entire contents of the textarea. +- ``on_value`` :ref:`trigger ` is activated on every keystroke. +- ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). + +For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. **Example:** @@ -1674,7 +1676,7 @@ The Spinner widget is a spinning arc over a ring. **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 widgets), 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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1740,8 +1742,8 @@ 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**): 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 as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. + - **tile_id** (**Required**): A tile ID to be used with the ``lvgl.tileview.select`` action. + - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. - **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. @@ -1750,14 +1752,14 @@ A typical application would probably use an ``obj`` container widget as a 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``. + - **tile_id** (*Optional*): The ID of the tile (from within the tileview) to which to jump. Required if not specifying ``row`` and ``column``. - **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``. **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 visible 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 now-visible tile. **Example:** @@ -1814,7 +1816,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 message box. - - **body** (**Required**, enum): The content of body of the message box: + - **body** (**Required**, enum): The content of the 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: @@ -1856,17 +1858,17 @@ The configured message boxes are hidden by default. One can show them with ``lvg ``keyboard`` ************ -The Keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type texts into a :ref:`lvgl-wgt-txt`. +The Keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-wgt-txt`. .. figure:: /components/images/lvgl_keyboard.png :align: center -From styling point of view, it uses the same settings as :ref:`lvgl-wgt-bmx`. +For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bmx`. **Configuration variables:** -- **textarea** (*Optional*): The ID of the ``textarea`` which to receive the keystrokes. -- **mode** (*Optional*, enum): Keyboard layout to use. The ``TEXT_`` modes' layout contains buttons to change between each other. +- **textarea** (*Optional*): The ID of the ``textarea`` from which to receive the keystrokes. +- **mode** (*Optional*, enum): Keyboard layout to use. Each ``TEXT_`` layout contains a button to allow the user to iterate through the ``TEXT_`` layouts. - ``TEXT_LOWER``: Display lower case letters (default). - ``TEXT_UPPER``: Display upper case letters. - ``TEXT_SPECIAL``: Display special characters. @@ -1874,12 +1876,12 @@ From styling point of view, it uses the same settings as :ref:`lvgl-wgt-bmx`. **Actions:** -- ``lvgl.keyboard.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.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Triggers:** -- ``on_ready`` :ref:`trigger ` is activated ckeckmark key is pressed. -- ``on_cancel`` :ref:`trigger ` is activated key representing a keyboard icon is pressed. +- ``on_ready`` :ref:`trigger ` is activated when the checkmark key is pressed. +- ``on_cancel`` :ref:`trigger ` is activated when the key containing the keyboard icon is pressed. **Example:** @@ -1920,14 +1922,15 @@ From styling point of view, it uses the same settings as :ref:`lvgl-wgt-bmx`. Actions ------- -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: +As outlined in the sections above, each widget type supports several of its own, unique actions. +Several universal actions are also available for all widgets and/or for LVGL itself; these are outlined below. .. _lvgl-objupd-act: ``lvgl.widget.update`` ********************** -This powerful :ref:`action ` allows changing on the fly any common :ref:`style property `, state (templatable) or :ref:`flag ` of any widget. +This powerful :ref:`action ` allows changing/updating any widget's common :ref:`style property `, state (templatable) or :ref:`flag ` on the fly. .. code-block:: yaml @@ -1947,7 +1950,7 @@ 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. +Check out in the Cookbook :ref:`lvgl-cook-binent` for an example illustrating how to use a template to update the state. .. _lvgl-objupd-shorthands: @@ -1985,7 +1988,7 @@ These :ref:`actions ` are shorthands for toggling the ``disabled` This :ref:`action ` redraws the entire screen, or optionally only a widget on it. -- **id** (*Optional*): The ID of a widget configured in LVGL, which you want to redraw. Entire screen if omitted. +- **id** (*Optional*): The ID of a widget configured in LVGL which you want to redraw; if omitted, the entire screen will be redrawn. .. code-block:: yaml @@ -2025,7 +2028,7 @@ This :ref:`action ` resumes the activity of LVGL, including rende ``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. +This :ref:`action ` allows changing/updating the ``disp_bg_color`` or ``disp_bg_image`` configuration variables of the main component, making it possible to change the background color or wallpaper at any time. .. code-block:: yaml @@ -2042,9 +2045,9 @@ This :ref:`action ` allows changing on the fly the ``disp_bg_colo ``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. +This :ref:`action ` changes the page to the next/previous based on the configuration (pages with their ``skip`` option enabled are...skipped). Page changes will wrap 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. +- **animation** (*Optional*): Animate page changes as specified. One of: ``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``. - **time** (*Optional*, :ref:`Time `): Duration of the page change animation. Defaults to ``50ms``. .. code-block:: yaml @@ -2066,10 +2069,10 @@ This :ref:`action ` changes page to the next following in the con ``lvgl.page.show`` ****************** -This :ref:`action ` shows a specific page (even the ones with ``skip`` option enabled). +This :ref:`action ` shows a specific page (including pages with their ``skip`` option enabled). - **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. +- **animation** (*Optional*): Animate page changes as specified. One of: ``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``. - **time** (*Optional*, :ref:`Time `): Duration of the page change animation. Defaults to ``50ms``. .. code-block:: yaml @@ -2091,9 +2094,9 @@ Conditions ``lvgl.is_idle`` **************** -This :ref:`condition ` checks if since the last touch event, the amount of time specified here has passed or not. +This :ref:`condition ` checks if the amount of time specified has passed since the last touch event. -- **timeout** (**Required**, :ref:`templatable `, int): :ref:`Time ` to check against the time that has elapsed since the last touch event. +- **timeout** (**Required**, :ref:`templatable `, int): Amount of :ref:`time ` expected since the last touch event. .. code-block:: yaml @@ -2113,7 +2116,7 @@ This :ref:`condition ` checks if since the last touch event, t ``lvgl.is_paused`` ****************** -This :ref:`condition ` checks if LVGL is in paused state or not. +This :ref:`condition ` checks if LVGL is in the paused state or not. .. code-block:: yaml @@ -2128,7 +2131,8 @@ This :ref:`condition ` checks if LVGL is in paused state or no Triggers -------- -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: +Specific triggers like ``on_value`` are available for certain widgets; they are described above in their respective section. + Some universal triggers are also available for all of the widgets and/or for LVGL itself: .. _lvgl-event-trg: @@ -2149,7 +2153,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. For the widgets having a value, the triggers return the current value in variable ``x``. +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``; this variable may be used in lambdas defined within those triggers. .. code-block:: yaml @@ -2177,7 +2181,7 @@ These triggers can be applied directly to any widget in the lvgl configuration, ``lvgl.on_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). Every use of an input device (touchscreen, rotary encoder) counts as an activity and resets the inactivity counter. +LVGL has a notion of screen inactivity -- in other words, the time since the last user interaction with the screen is tracked. This can be used 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:`triggers ` are activated when inactivity time becomes longer than the specified ``timeout``. You can configure any desired number of timeouts with different actions. @@ -2196,7 +2200,7 @@ 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. +See :ref:`lvgl-cook-idlescreen` for an example illustrating how to implement screen saving with idle settings. .. _lvgl-seealso: From 0a6f6204e6f36d7f5c600fb6e43d6dbb5462010a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 10:48:59 +0200 Subject: [PATCH 431/564] 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 fbf3f9ff3b..c1164d2f38 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1738,7 +1738,7 @@ A typical application would probably use an ``obj`` container widget as a tile, **Configuration variables:** -- **tiles** (**Required**, list): A list with (any number of) tiles to be added to meter. +- **tiles** (**Required**, list): A list with (any number of) tiles to be added to tileview. - *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 as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. @@ -2000,7 +2000,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 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. +- **show_snow** (*Optional*, boolean): When 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 illustrating how to use this. .. code-block:: yaml From 03abaa76fcdab1d818ed55f56bc95b6f61480e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 11:07:30 +0200 Subject: [PATCH 432/564] 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 5e272b7c0b..f1e5b8b9d2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1605,7 +1605,7 @@ The Textarea is a widget which displays a cursor and allows the user to input te - **placeholder_text** (*Optional*, string): A placeholder text can be specified, which is displayed when the Text area is empty. - **accepted_chars** (*Optional*, string): You can set a list of accepted characters, so other characters will be ignored. -- **one_line** (*Optional*, boolean): The Text area can be configured to be on a single line when the height is set automatically to show only one line, line break characters are ignored, and word wrap is disabled. +- **one_line** (*Optional*, boolean): The text area can be limited to only allow a single line of text. In this case the height will set automatically to fit only one line, line break characters will be ignored, and word wrap will be disabled. - **password_mode** (*Optional*, boolean): The text area supports password mode. By default, if the ``•`` (bullet, ``0x2022``) glyph exists in the font, the entered characters are converted to it after some time or when a new character is entered. If ``•`` is missing from the font, ``*`` (asterisk) will be used. - **max_length** (*Optional*, int): Limit the maximum number of characters to this value. - any :ref:`Styling ` and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. From 7de1ae50f85b2693a9289c2e9ff669280da0bc73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 11:29:16 +0200 Subject: [PATCH 433/564] 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 f1e5b8b9d2..34053cf6c8 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -369,7 +369,7 @@ The layout configuration options are applied to any parent widget or page, influ **Configuration variables:** - **layout** (*Optional*, string): A dictionary describing the layout configuration: - - *type* (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. + - **type** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. - Further options from below depending on the chosen type. .. _lvgl-layouts-flex: @@ -402,7 +402,9 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac - **flex_align_main** (*Optional*, string): Determines how to distribute the items in their track on the *main* axis. For example, flush the items to the right on with ``flex_flow: ROW_WRAP`` (known as *justify-content* in CSS). Possible options below. - **flex_align_cross** (*Optional*, string): Determines how to distribute the items in their track on the *cross* axis .For example, if the items have different height place them to the bottom of the track (known as *align-items* in CSS). Possible options below. - - **flex_align_track** (*Optional*, string): Determines how to distribute the tracks (known as *align-content* in CSS). Possible options below: + - **flex_align_track** (*Optional*, string): Determines how to distribute the tracks (known as *align-content* in CSS). Possible options below. + + Applicable to ``flex_align_main``, ``flex_align_cross``, ``flex_align_track``: - ``START``: means left horizontally and top vertically (default). - ``END``: means right horizontally and bottom vertically. - ``CENTER``: simply center. From 02c3e32d6e5bac547e15aaa346935c5039fc619a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 11:43:37 +0200 Subject: [PATCH 434/564] Apply suggestions from code review Co-authored-by: Keith Burzinski --- cookbook/lvgl.rst | 56 +++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 296b11254c..f30456b412 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:: - 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. + Many of the examples below call services in Home Assistant; however, Home Assistant does not allow such service calls by default. For each ESPHome device which will call services, you must explicitly enable this setting in Home Assistant. This may be done when the device is initially adopted or by using the `Configure` option in the "devices" list of the ESPHome integration. .. 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 with dimensions of ``240x320px``; if your display's dimensions differ, you'll need to adjust them in order to obtain the expected results. .. _lvgl-cook-outbin: @@ -143,7 +143,7 @@ Light brightness slider .. 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. +You can use a :ref:`slider ` or an :ref:`arc ` to control 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 convenient to set the slider's ``min_value`` and ``max_value`` accordingly. @@ -182,7 +182,7 @@ We can use a sensor to retrieve the current brightness of a light, which is stor 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``. +This is applicable to service calls like ``fan.set_percentage`` or ``valve.set_valve_position``, too; the only difference is that ``max_value`` has to be ``100``. .. _lvgl-cook-volume: @@ -234,7 +234,7 @@ 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 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. + Keep in mind that ``on_value`` is triggered *continuously* by the slider while it's being dragged. This generally has a negative effect on performance. 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. To mitigate this, consider using a universal widget trigger like ``on_release`` to get the ``x`` variable once after the interaction has completed. .. _lvgl-cook-gauge: @@ -246,7 +246,7 @@ A gauge similar to what Home Assistant shows in the Energy Dashboard can accompl .. 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`` 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: +The trick here is to have a parent :ref:`lvgl-wgt-obj` which contains 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's central parts and place some :ref:`lvgl-wgt-lbl` widgets to display numeric information: .. code-block:: yaml @@ -334,7 +334,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 extra large rounded corners. + The ``obj`` used to hide the middle part of the 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: @@ -346,7 +346,7 @@ A thermometer with a precise gauge also made from a :ref:`lvgl-wgt-mtr` widget a .. 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. 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. +Whenever a new value comes from the sensor, we update the needle indicator as well as the text in the :ref:`lvgl-wgt-lbl`. Since LVGL only handles integer values on the :ref:`lvgl-wgt-mtr` scale, but the sensor's value is a ``float``, we use the same approach as in the examples above; we multiply the sensor's values by ``10`` and feed this value to the :ref:`lvgl-wgt-mtr`. It's essentially two scales on top of each other: one to set the needle based on the multiplied value and the other to show sensor's original value in the :ref:`lvgl-wgt-lbl`. .. code-block:: yaml @@ -414,12 +414,12 @@ Whenever a new value comes from the sensor, we update the needle indicator, and align: CENTER y: 65 -And here's for the same sensor configuration a semicircle gauge with a gradient background drawn by a multitude of ticks: +And here's the same sensor configuration, but instead with a semicircle gauge with a gradient background drawn by a multitude of ticks: .. figure:: images/lvgl_cook_thermometer_gauge.png :align: center -If you change the size of the widget, to obtain uniform gradient make sure to increase or decrease the ticks count accordingly. +If you change the size of the widget, to obtain a uniform gradient, be sure to increase or decrease the ticks count accordingly. .. code-block:: yaml @@ -567,7 +567,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 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. +Just as in the previous examples, we need to get the state of the cover first. We'll use a numeric sensor to retrieve the current position of the cover and a text sensor to retrieve its current movement. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label in 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 closed. .. code-block:: yaml @@ -835,7 +835,7 @@ For the navigation bar we can use a :ref:`lvgl-wgt-bmx`. Note how the *header_fo then: lvgl.page.next: -For this example to look correctly, use the theme and style options from :ref:`above ` and LVGL's own library :ref:`fonts `. +For this example to appear correctly, use the theme and style options from :ref:`above ` and LVGL's own library :ref:`fonts `. .. _lvgl-cook-statico: @@ -847,7 +847,7 @@ The top layer is useful to show status icons visible on all pages: .. figure:: images/lvgl_cook_statico.png :align: center -In the example below we only show the icon when connection with Home Assistant is established: +In the example below, we only show the icon when the connection with Home Assistant is established: .. code-block:: yaml @@ -879,7 +879,10 @@ In the example below we only show the icon when connection with Home Assistant i 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. +Of note: + +- The widget starts *hidden* at boot and it's only shown when triggered by connection with the API. +- 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: @@ -974,14 +977,14 @@ 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 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. +ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your text. This is very flexible because you can prepare various sets of fonts at different sizes each with a different number of glyphs; this is important as it may help to conserve flash memory 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. +One example is when you'd like some MDI icons to be used in line with the text (similar to 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: +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 @@ -1012,7 +1015,7 @@ In the example below we use the default set of glyphs from RobotoCondensed-Regul 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 lookup your icons, use the `Pictogrammers `_ site. Click on the desired icon and note its codepoint (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. @@ -1025,7 +1028,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 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. +A common use case for icons is a status display. For example, a checkable (toggle) button will display different icons based on the status of a light or switch. 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`` states to apply *disabled styles* for these cases. If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like this: @@ -1276,7 +1279,7 @@ Using the :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets, we can create an 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 at the beginning of every minute to update the hand line positions and the texts. +The script runs at the beginning of every minute to update the line positions for each hand as well as the respective text. .. code-block:: yaml @@ -1526,14 +1529,19 @@ 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. +Of note: + +- A base object ``obj`` is used as a parent for the label; this allows proper centering of the label as well as emphasizing it with shadows independently of the label's dimensions. +- ``align_to`` is used to align the label to the ``led`` vertically. +- Changing the background color of the buttons in ``pressed`` state. +- Use of the ``key_code`` configuration to send a different character to ``key_collector`` instead of the displayed symbol. .. _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 used 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 (it's important to use the ``on_release`` trigger). With a template number you can make the timeout settable by the users. +LVGL has a notion of screen inactivity -- in other words, the time since the last user interaction with the screen is tracked. This can be used 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. Note that it's important to use the ``on_release`` trigger to accomplish this task. With a template number you can make the timeout adjustable by the users. .. code-block:: yaml @@ -1581,9 +1589,9 @@ Prevent burn-in of LCD 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. +A common problem with wall-mounted LCD screens is that they display the same picture 99.999% of the time. Even if somebody turns off the backlight during the night or dark periods, the LCD screen keeps showing the same picture, but seen by nobody. This scenario is likely to lead to 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 colored 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 *exercise* the pixels periodically by displaying different content. ``show_snow`` option during LVGL paused state was developed with this in mind; it displays randomly colored pixels across the entire screen in order to minimize screen burn-in by exercising each individual pixel. 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. From c1682e66ff62377efb1c2e88d3873f5b98f385fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 11:45:12 +0200 Subject: [PATCH 435/564] train --- 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 34053cf6c8..9225a31f2a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -369,7 +369,7 @@ The layout configuration options are applied to any parent widget or page, influ **Configuration variables:** - **layout** (*Optional*, string): A dictionary describing the layout configuration: - - **type** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. + - **type** (*Optional*, string): ``flex``, ``grid`` or ``none``. Defaults to ``none``. - Further options from below depending on the chosen type. .. _lvgl-layouts-flex: diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 296b11254c..7b82678de6 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1585,7 +1585,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 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 training 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; it can be stopped by touching the screen. .. code-block:: yaml From f52b8b2067e7f9eec92c4b89c9f09aa806806ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 14:50:42 +0200 Subject: [PATCH 436/564] new tileview syntax --- components/lvgl.rst | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9225a31f2a..df15b4b6fe 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1738,17 +1738,14 @@ 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 widget as a tile, to display multiple child widgets, but any widget can be used directly too. - **Configuration variables:** - **tiles** (**Required**, list): A list with (any number of) tiles to be added to tileview. - - *widget* (**Required**): Any kind of widget to be used as tile container. - - **tile_id** (**Required**): A tile ID to be used with the ``lvgl.tileview.select`` action. - - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. - - **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. + - **id** (**Required**): A tile ID to be used with the ``lvgl.tileview.select`` action. + - **row** (**Required**): Horizontal position of the tile in the tileview grid. + - **column** (**Required**): Vertical position of the tile in the tileview grid. + - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. + - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the tile. **Actions:** @@ -1771,15 +1768,14 @@ A typical application would probably use an ``obj`` container widget as a tile, - tileview: id: tiv_id tiles: - - obj: - row: 0 - column: 0 - tile_id: cat_tile - dir: VER - widgets: - - img: - src: cat_image - - ... + - id: cat_tile + row: 0 + column: 0 + dir: VER + widgets: + - img: + src: cat_image + - ... - ... # Example action: @@ -1787,10 +1783,10 @@ A typical application would probably use an ``obj`` container widget as a tile, then: - lvgl.tileview.select: id: tiv_id - row: 0 - column: 0 + tile_id: cat_tile animated: true + # Example trigger: - tileview: ... From a55eebf1beb48b814f836215a9e98d950c1048ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 15:41:20 +0200 Subject: [PATCH 437/564] adding tabview --- components/images/lvgl_tabview.png | Bin 0 -> 7993 bytes components/lvgl.rst | 72 ++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 components/images/lvgl_tabview.png diff --git a/components/images/lvgl_tabview.png b/components/images/lvgl_tabview.png new file mode 100644 index 0000000000000000000000000000000000000000..ae18acf31a59a254690b250414f57bdadb3fc6b4 GIT binary patch literal 7993 zcmai3cTiK^x4jf0L6DA-UV>Bwl-{c(QUw)|4kEpTAR!>VN-xquKoIalKxqP@qaZCb z>0N|?bV9E$-*4vq@n+teH+SwmbI%`l_BnU$b=F?{t-h`%6$LW|002~Qn7RRB+$P*H zAY#IEz4k#40B`_sb(N<+Ia|4UrMwgVxK{S~MZbJzY%pJG$i%LbLvY2Hw#uXkuh2HP zF445%pt=5z$FG<^xm5v()um%qmeuMjFG|}&F-VXbpQ~hX;Hi4G2)XJ9Q zE5FmD!`l_tSAl1jWrG$93u=v%UPKF*;CT$Sv&Ythfa3SPAcaGn4em=`Pf$duJ7vKP#UtU|mrJ>Je(WW5k zaH>qovhj4>vgNRUbg=1+yz>1qt-0~l%%Bz3)k#b}B8Y|jWJ_(fF)|;o_&HE8A@>~$ zeaa%TaJE!FFlW?q_;{wyb*5#%+(?qz`?#?(V5Q7;Cg4!W(tm5F(!ACCQa=8`uqT&& z;=cQiMfuWOMAAMgAT~QNbm5G{2hWG+X~iov;fWqCtuEx}DXte@hRa*D?BB`iqY6T> zHXm2|pVy*Vj&;4|uXarXL5qj(t+y7(lzeLC)-A59CnWxkU0*mEO5yza^SEtP4PAF+ zf48=XFI-_0_O=z8&WO*z?(-@e9?L*w;2rl%N|f)#Ub=4cuGrGoG|#)*?S9v*mQAPA z9L?VNkJ&(#ljZf%#+G(Gdx~I04ols z6d~JXyKUw2Gp2RJGAlRo&GM0+d!zth%vOQjo4gObUJ>%y>piL%Ic4h=8L)Lt?RF$x z6r9M-iMFlpB?4_E?)c)APHi!eH}4*W?yl;2lxSXvM@i$2O;?uYfi}OuN1vx47zHEs zi?T(u(;-vX!Z~It-RF>e?a{@0`rc7%C=SiG*uDHUZQnHTaGU@a5(klQfZL^2{Hxik z9#>#1Ae&pG)PlI|{bqqauUsJW zz_Umpp|{$k<695+-J1!3AC$lBSMl?}VRKD)=6z3c2h+Rj>MC#gEYD3rEHSa}0oDN* z*r1&YP@zZR4^g5vjzC%IwZ zr2_Fv7prKFCrfYY^>20AY9T}wiP$%+%nEk<42#U_IT-|Q-v|9Lx`H}fH=XoeZ!(nq z_oPN|_{|Pnz!g3(?^uk1qLnQA+5evI{|f{Bzf&i_P<&?+`y$t4J8!SNjyHcowMj~j zGdi%#Aq6AF-Mrrt+)s>k>IOdHkjUdD7K{kd{CVs3&hndnjba!&2KWdvCRTk(JQDP& z(D$yu&2az@czeZ~-*~uyHumPwoO;~%W3Q}v&_0@b#T*6*bOcdk_!i%SYZL1_YMp5O z^I)>{Z1~!DwU)X$)m!`W2&~b~p_8&8Do3`6HpY+(1QyLN;3JAnVJ{f1K|UJQ zq()wVG)7z^LtS3GupcJxH!G;i@S1|)!G;OqoN+K!V$M52ez1g#vxQ&Fpa zHY`hL)06uK4U5!SAr)T4raOa-e}z8YZg5lNh;0&T`RbeXJti2lzKP%`rlBP3OvLDss~bl!m&{u$_#THDb4uH!{ya< zqsr@N>3NT6$lkLOkr4$gT}Xl-<5l%d5n7y_%(NCVKG&M@tP*#Kd6lM?MDjEyMT%DesE3vPp^Lo%Xib9Ek z-e&1Z;=Y+Hh9u^5I(iQa@Brc$XSa<+TJ*IjR7C3$o{zn0`@5h7 z>X0Et_gMiyG?;XgL(8#si`nM0>TiL{Jemu3E(e3fI=c+bQB!e$b? zm@QIX;XhBs$90!mK${!!W$;*cHD<|HdNz+J`W$D*8_iNn{BN2> z7wm)S+9#{NMp9=FU-V?;wyONG1W2-` z*f|1P?u-vVpMQ=`hR*Sh3?=K#@go$cJ5-bQZ#l;24_E{ffi-Jh&n1f4TS7U(%n}2N zVlvqdJ7%W#w(_P^hAuVEl4Q>S94Ml_>+izF#MaX2fCru9=Q7rH$0mvS4ihz_(?)L@ zSV*MO%0q30XdSF1CweLz#(9tKvvpWvJ}KsHJ#U+_K@sooTKjCba_R8uzAAH;9O>*M zaZSlKJ2kPTF63ctr!Rziy=UrpXj7Zy3zTK&D@(Nyz;B?~*>owkBR^>Kni03S-6U-r zrs2(#@o?Qis3gpr!!_=Bd)1ZU{uHd_+mj%Am*?N;k8^LMw^m+B#=vEKHV14ZxIn6;_NIP5ZCB9Ng=EJXGhjw< zI+c*~kdIw^Qmx*(5ucZioggu!P!`&cyb{z5FxyP}>%MQ_)MW0+K_0Bc#lDf!48(n8 zqE8Kd%*VVb-yRxuHD}=M_dZKg8Dj7(Qq1++ z(MwL1lrLuHeJp7b3j)1W?vYRxQBF8r#MBsQ^s^xIbZ?S+GCQfdqtsBEnhSV>nq{zj zb@e8XBj4?J=pSiDaY1eYd-+qyUKww2OI6De;i@Y7$m1O{B&V|SThv|P`6&Y?DN^P@ zOBM%@c)j?Zk7oSxg1QSEqXdQ{Pv2TMFVt*ouR#ib+MOr9T88%D_t6dV{yrvBGjVHU z+ikaYWnC}5AiT(x!6cbIwrySfT2LbBRh6Hzq@TK-7%Bg1sfl=1NGxg6)Vto1 z4%#l0&asw_N>O|3?_t)UEyZ(Ao!%phWFEMM|9Ief!_k_3Gdsv{h#}Fe67iOq9&AmK zT(4e*93Nf<-OS`(NqF_CEk&6G^4QwquTB)G?l;{R`dBL~p-9rAB*t4t_qEq{I+fPD z73#{B&aAw!5j5~JM=!s5;xd2s%g;BD3!UX@9Oc1~$$yBXZ~23Wz_6r)&-q2A39z1P z7sH}A5w4|NeHsRo3X8MB={E5k4_yQIs`tgYO2##AfMuYu)WeD^No$inkz@Zj9$gI2 z1+Z#9uZeP$!ELr=mAka*ave9SRS| zYz3jWspKDu#Wbgk?}<^9+IBelu3SpqU)kbv=ZVJ zD>H$QfPjds5NNQmbA9De6*X5FqCb50Fom@fWJTG&HKDV0R*~}Oc&M`b)nH10Pv7Y% zqbf|rFu#C@2$rbQdMkdCjOr#pAgbY}W65&}@w=h%@i8huC-fcal*Ta3^ZIs@x~evX zfpJ3qjUnpaRp)aSb#u*0<1@V)U;)8k#zJV1L<@Bxd(io3XFe`chiLr#O_&;1Hm!1Q zxJOiXTIbHamygZReRWRElTev2zni{M67l@g5CGLxi1qXker(N*Nom0(1jHdmq~mKK zC1ToH$IXVM48;}#L-`GxoeVklhH~mMg8>j;ANyRAPcjODbWG`NWL|4$7BSTLsG^U9 zqCW)PO{)CTT7i(Oce0HWpo0I5kx01ka)`_lA8&@?6cH0{TTw zG2Z8v_f%$2to392d%iOg3B-wV;>^Dx2%A%cDhh?hCI|Ln6uN)$tWeq0tu@Z?3<$Vg z%EnT2kLyxDLiKQK;O>0>UEcc3-t z*`>5(<`cE9GskRgrC;}+CKs}W8f#=li3^%g0qb!^(z;dS@dCoMYF~|UY|)iXYO;oQ zP`a`b)@0SSAkcRj;>6A_Rz3j@NA+mz@J>=h)+2kBckR`*>}KTm$^Xk&^4rQyNY|E=qr;16xqTLXg)#%uQbkj91twXERsB!Q#;r@iPjc*$VZIA@bhtQ%7K+7Tyf7- zCk|iRm`Y*MEAgVEYk$cOmLqfPObUOrOKT+Un|M!qRZrP2J0LaSAvD&U`P9UVX7t5R zQfArxQ`KJWrw?t)CBll_cdcHICDD>`-jk`|S=BYu(!Tej7~wU~{8*V{j@)4AFGWyJ zB{{DH1d|`oYqxX?8pJUuynmO1h;SA0V{SSLF*V=IPwbjak2}d0XND+HJd3(4p`5yvB}Ii1}$R> z{Ks)~sSP9%T*U|mz{gONB&)FXa{dYG!Gt?Wsk24vs_-59-wZ%KpE=4si0d9sE5umV zrGFl2ozA^-4>^#-Rn4WNPgfMh+Urs0hTMYzIjuS+s6bB0aKw|fiIX#Y6c@MHIV3Tt zv5RLr?E5j}VP;cd@&SNdc@+IO>3jxTzrVGm z|GQVNsKMQ3{%K(p2_Dr==>nw;uDIjV{!_oG=BIdi@z%x4EX?8G4o z3K?-=YitYXSQ;IIf_;JhU^y)<4U^F6mHlV3p%*17kv;q}PA%i?9uhI~dIEIu^TufSh%b#HP$+ zh8y4i&q7>4t)RErtvN?oTMPYu`zchLAFk z$PB42OaJ+<+ZSDCKR2vr`r&%6QXpL~lK$v;X3W}87NIllV-1Ceic*T}3W)o)oipDS zt0NC8z`In|45*Ce#i9bT{1QlJY!n~ey9bGh=lB3SrTwD_!TZo|x;%n}4QYLq@hNV$ zar|3&JQZ2-2{f^v@4qKC&Fh)&Z|C|*3K$X>JoxM)wR=|GxFE9XMZ zM#)tleMmTBq*fL4t%<491DNv;rcP=Ibk2*aAy32^aggnPgnP64T4IhK zk195Q@Tc_}M+YI2w^I&~uab!=jluMy;bKiO;Ig`__Jpn(&CWv{;%6#1vP95vb_I!dK(PZu@so|<&(wLQ8<9B^o!m?Ej*HWDAe6~-$IW6tjU9twY{2am zi&?Xq*jQ0Tm?dh$mon`wU5s>&M@>6LLB?aXl`h)yXM4E;kjzeWKD)9iLkW$ z&O;kzZYS2Ag<|)tx*H53P`2DKgu&Xmyq}=yEGT)%cfR&*mgz%Ja6tO^b8~|5$n>{! zhNOtb`7VYG{W%yA;MRb$5JBnQ1rI#VEs^!WDj0Y_38TIt&GkKJ49x#lAZ!Tnw`wm< z{FZ+PKr$g67sI0Fqe>>eHqk!F5}>7i>XoueOd!5OvwmS7<|@?;RZ2x&QljeDA+~fy zE-9{VPSPkgWrkf&;aYY;m?#QQ?-?-5pnRLxA;(XW1O__pWYwt1kaBSNle-Z?bN66$ zRvfWx#DGE*IEc-Yr!IOtacm@s7 zSq(g%QKmo-)ba}!coeJ`<$0_GcKA2Vd3Z|pC(pU0>Ocb64P#P_*A6dd&X|Z&xR>+6?0z)U}1IpjA7JL{&B*`X7y5y z&zz5`ZB!`>>3+^i%Mjxe*@JcFI?x|aRrrCm3ETQgc|O6M?3_Y|r(xU8GB zf4_!o;C-L7#K$4F$S>Zoc{xA*38q*)yQg=&CgdikRZ2N6(RWg9mDH7gmQp3}3#k&r zn8<>1ZyHenD_tIa@5qQ)OFnx%jw(DGiX*bVliy71HN`#kF(>w(+u#iWZRV21XA*pj zcjCEZ`CI}BvRcD>^oU;hSA8b+hp_zF;^#qDvk#7q9v{?*D&7ST%an+Q(coGv2wXFU zpT5tfjaGisM%Vsxy!rDfmVg#JNQbmg0`O)9R;8*$syXpXhJ!sjUNAF*9QS9}b8$i2zXh1)v3(xf;|^+&0P3Wh};%`bu%cRAg~vD8qBPcar%t^`Dl)3 zPK@}M)INc%x%^EPaUD*!*y?Qc7<45|+iZ~#icVE^-l;&Pm0e~fhe{~gLrcq_2E+yH zMLx=L&M~|tI+!XPQAiV>p$h6nn&Z!?+cJgz`IlUclKzNsFEhZppkSS?tZ6uH50}6y z`%wvVKUn!zTERYymK4rA6_&y95rkew(o+fFZrkJ=;)bhmdTOAyKhNeKXmU^zG>Iqx zN^w|}eE3x>aD{+ny_B?E&;!gr^D@j4uh&#?!m&s)#JAenkyK&;bXPFxr<)hHJ0nj> zqX@($!UPu##@-th_ymPF$TZM3`gM9dSiOjgyYak3w8zyIX-%lCv=UdjY+lV9IXk7} z_s$PtzJKb}BXUv{($fy4SDLVDPX`_x`a62JvtlOi(5wl*5|N%+7k1NOX6*3wVl=U4 z6*ofUDgJVG#}Ee*JW0ui>_nXH6SakG9nulXh29I1qQnk4d8TDAEtd)pUV1->Ui~)r za&VAQs5ethmEES{fW6z}0sGuWS8Waw+PGX!v?~Abqff8BzyL{IB69u?)l6s>8EV^m zP88U$*q&G(CU5Y1XNs)c|V*MPetP9 zXYn#=MLs$=fF%3kl?K0{hJ$_f3-rW`EcH&%cj)tj^qhBmxdS#-Bg1nAQ^?mEt^qgx zbyR*^ZK@_-iuSh$H%L>Ig&ysGan0%6)Q)*&;+5(8f>jj5B+6MTpG`i)&U{+u%@jDb zRg7q$&q3+JVMX|g{W+R1^u_uFVJ-f;T%50v$(uk*!E2HEc9M4h$glXaXQR^Ta%04D z*ouN1UtUs^%zo{rb*z^CGot;|O{rHnFx$?ZmncG8U)2y(7Fm`*najHKh+r#66nt`~ zQiI3HsUbwM`RFupAn2u`AI{8;2}r>(tzg6Y1$Kc=8-HASX4F9A5YQEp*5!Fe_Yv`{ zh6mb5+WU4iX>^R^5=P{4g>uzZh8+-9^VAy)CehF4={`20lc?VF%uLt1ZXnNN8iYl# z#S-af1Gj=cBLEizv;OMj3^`s~c)A+t)+cK}lkNyns})H-CM%%{@p)OB=`+Y_s&z8b zYnD<`2q2hdFxl6Nly6eIC4#_3H>{D$_qNV3_?V=dUj}kUwdn+?*L%iqYa?4TT*-b^ zjV6^m8#Ga^K?h>yDyb{Q5fp0D7}`SkO97}1p>!+c8s5ey zRpE;!eTnQJ5N5A#H}h={9nnQLUYN91MVYBn-+UCLv%Gme;}uixO`nLiZu|xV=#h{gtPwmQUYG4bmt`(=X1%(+_YBfCi=XeN@+QtmIOVoWW>(!~wvVoeM(i+u^52+hTxuPPmzNNChJM%IR$2Jvc3 z;NM_e|ASBaYB3C{hJPv3?=prZNvM0ytj_n{W&4tPc!9>qV#jBNZS$+huYUe17l$2mcX z4B%1p0+F)P#6Ep(PH$HFVW0RINh(3k(@cFaQ7m literal 0 HcmV?d00001 diff --git a/components/lvgl.rst b/components/lvgl.rst index df15b4b6fe..2757d51105 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1729,6 +1729,74 @@ You can use it as a parent container for other widgets. By default, it catches t widgets: - ... +.. _lvgl-wgt-tab: + +``tabview`` +*********** + +The Tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-wgt-bmx`. + +.. figure:: /components/images/lvgl_tabview.png + :align: center + +A new tab can be selected either by clicking on a tab button or by sliding horizontally on the content. + +**Configuration variables:** + +- **position** (*Optional*, string): Position of the tab selector buttons. One of ``TOP``, ``BOTTOM``, ``LEFT``, ``RIGHT``. Defaults to ``TOP``. +- **size** (*Optional*, percentage): The height (in case of ``TOP``, ``BOTTOM``) or width (in case of ``LEFT``, ``RIGHT``) tab buttons. Defaults to ``10%``. +- **tabs** (**Required**, list): A list with (any number of) tabs to be added to tabview. + - **id** (*Optional*): A tab ID to be used with the ``lvgl.tabview.select`` action. + - **name** (**Required**): The text to be shown on the button corresponding to the tab. + - **widgets** (**Required**, list): A list of :ref:`lvgl-widgets` to be drawn on the tab, as children. + +**Actions:** + +- ``lvgl.tabview.select`` :ref:`action ` jumps the view to the desired tab: + - **id** (**Required**): The ID of the ``tabview`` which receives this action. + - **tab_id** (*Optional*): The ID of the tab to which to jump. + - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated when displayed tab changes. The new value is returned in the variable ``tab`` as the ID of the now-visible tab. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - tabview: + id: tabview_id + position: top + tabs: + - name: Dog + id: tabview_tab_1 + widgets: + - img: + src: dog_img + ... + ... + + # Example action: + on_...: + then: + - lvgl.tabview.select: + id: tabview_id + tab_id: tabview_tab_1 + animated: true + + # Example trigger: + - tabview: + ... + on_value: + then: + - if: + condition: + lambda: return tab == id(tabview_tab_1); + then: + - logger.log: "Dog tab is now showing" + .. _lvgl-wgt-tiv: ``tileview`` @@ -1745,12 +1813,12 @@ If the Tile view is screen sized, the user interface resembles what you may have - **row** (**Required**): Horizontal position of the tile in the tileview grid. - **column** (**Required**): Vertical position of the tile in the tileview grid. - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. - - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the tile. + - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the tile, as children. **Actions:** - ``lvgl.tileview.select`` :ref:`action ` jumps the ``tileview`` to the desired tile: - - **id** (**Required**): The ID of the ``tileview`` which receives this action + - **id** (**Required**): The ID of the ``tileview`` which receives this action. - **tile_id** (*Optional*): The ID of the tile (from within the tileview) to which to jump. Required if not specifying ``row`` and ``column``. - **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``. From 72ab067730d1550f83d86d4ae75877bc0806a6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 16:08:43 +0200 Subject: [PATCH 438/564] Grid layout added --- components/lvgl.rst | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 2757d51105..f322090dd4 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -374,7 +374,7 @@ The layout configuration options are applied to any parent widget or page, influ .. _lvgl-layouts-flex: -**Flex** +*Flex* The Flex layout in LVGL is a subset implementation of `CSS Flexbox `__. @@ -418,12 +418,33 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac .. _lvgl-layouts-grid: -**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(s) can span through multiple columns or rows. The track's size can be set in pixels, to the largest item or in "free units" to distribute the free space proportionally. +**Terms used:** + +- *tracks*: the rows or columns. +- *gap*: the space between the rows and columns or the items on a track. + +**Configuration variables:** + + - **grid_rows** (**Required**): The number of rows in the grid. + - **grid_columns** (**Required**): The number of columns in the grid. + - **grid_column_align** (*Optional*, string): How to align the widget within the column. Possible options below. + - **grid_row_align** (*Optional*, string): How to align the widget within the row. Possible options below. + + Applicable to ``grid_column_align``, ``grid_row_align``: + + - ``START``: means left horizontally and top vertically (default). + - ``END``: means right horizontally and bottom vertically. + - ``CENTER``: simply center. + - ``SPACE_EVENLY``: items are distributed so that the spacing between any two items (and the space to the edges) is equal. + - ``SPACE_AROUND``: items are evenly distributed in the track with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. + - ``SPACE_BETWEEN``: items are evenly distributed in the track: first item is on the start line, last item on the end line. + .. _lvgl-widgets: Widgets @@ -1809,7 +1830,7 @@ If the Tile view is screen sized, the user interface resembles what you may have **Configuration variables:** - **tiles** (**Required**, list): A list with (any number of) tiles to be added to tileview. - - **id** (**Required**): A tile ID to be used with the ``lvgl.tileview.select`` action. + - **id** (*Optional*): A tile ID to be used with the ``lvgl.tileview.select`` action. - **row** (**Required**): Horizontal position of the tile in the tileview grid. - **column** (**Required**): Vertical position of the tile in the tileview grid. - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. @@ -1854,7 +1875,6 @@ If the Tile view is screen sized, the user interface resembles what you may have tile_id: cat_tile animated: true - # Example trigger: - tileview: ... From 798058214a977273373e36969cc60845f808cb96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 16:47:23 +0200 Subject: [PATCH 439/564] Flex layout cookbook example --- components/lvgl.rst | 7 +- cookbook/images/lvgl_cook_flex_layout.png | Bin 0 -> 5015 bytes cookbook/lvgl.rst | 141 +++++++++++++++++++++- 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 cookbook/images/lvgl_cook_flex_layout.png diff --git a/components/lvgl.rst b/components/lvgl.rst index f322090dd4..c2b781289a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -401,7 +401,7 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac - ``COLUMN_WRAP_REVERSE``: place the children in a column with wrapping but in reversed order. - **flex_align_main** (*Optional*, string): Determines how to distribute the items in their track on the *main* axis. For example, flush the items to the right on with ``flex_flow: ROW_WRAP`` (known as *justify-content* in CSS). Possible options below. - - **flex_align_cross** (*Optional*, string): Determines how to distribute the items in their track on the *cross* axis .For example, if the items have different height place them to the bottom of the track (known as *align-items* in CSS). Possible options below. + - **flex_align_cross** (*Optional*, string): Determines how to distribute the items in their track on the *cross* axis. For example, if the items have different height place them to the bottom of the track (known as *align-items* in CSS). Possible options below. - **flex_align_track** (*Optional*, string): Determines how to distribute the tracks (known as *align-content* in CSS). Possible options below. Applicable to ``flex_align_main``, ``flex_align_cross``, ``flex_align_track``: @@ -416,6 +416,8 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. - **flex_grow** (*Optional*, int16): Flex grow can be used to make one or more children fill the available space on the track. When more children have grow parameters, the available space will be distributed proportionally to the grow values. Defaults to ``0``, which disables growing. +Checkout :ref:`lvgl-cook-flex` in the Cookbook for an example illustrating how to save a lot of manual widget positioning. + .. _lvgl-layouts-grid: *Grid* @@ -445,6 +447,9 @@ It can arrange items into a 2D "table" that has rows or columns (tracks). The it - ``SPACE_AROUND``: items are evenly distributed in the track with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. - ``SPACE_BETWEEN``: items are evenly distributed in the track: first item is on the start line, last item on the end line. + - **pad_row** (*Optional*, int16): Set the padding between the rows, in pixels. + - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. + .. _lvgl-widgets: Widgets diff --git a/cookbook/images/lvgl_cook_flex_layout.png b/cookbook/images/lvgl_cook_flex_layout.png new file mode 100644 index 0000000000000000000000000000000000000000..8cca59c07754ca13acd2ab3fc0ec783d61c35de8 GIT binary patch literal 5015 zcmds5c{r5)*SC}{+aOy>Bx39-R704u4YCc!-eliuER#Kzo#PR-?xNJM8=Y7 z438SJ43Z&)ck1~)%lpUg{k{Lb?{$68^*#4@Ip@C4eLkOat~>UQp*9&~)%!G}bavBwVZ?Ejrzw*s;6cb6>s^QB zolR&^uUvo;l)d=cL?)m?p1#ImF|R2YZE3!i{`Esnw^6rnNOJ1?;f<7~67A9MK)=PI z6d$HXpTF5m(9+Cv=s5K-|2v5&+CnKivqauKwm+<)oR{Tc1~yw@#7kHr7pUtQNyt!D zm;5^+EnSOm%YHb)>tUC8uGrS+R1@q1Nt4q-$JfHE%&S2x1(phL#$w-a$?ZGdS z%9#d%I;!ic^au_qR3xiuR8(*{t?k8-b87gOtx?mIv=SCMzV#n&LqQi;^60>VsWGK9 zo-m{4=BC)v+D0vKMzw&D)?VXT$A^bcXQ9;u8!4W+nvQ)umW(3CXH<{a15dN`mkpIA zjz|Fv3=C(FJq^4(A~lU?O|{s^PZq-EHNJpky6x9d#l_G|JV52NAja+Hvx_w->Uh)Z zz5C#;JGy@f_)$|$ZbQu*@cgv^=gCvkw}K_eot_N>=XR0bB6sox0mS}w#A z*0v8vr=*odgLXU5WMHa@?WSjeP+~=C@XFw>+PPf*w7La+_*}D86gv6s(z%fRylL>c zZp#L|AvJ97jj+8#1a(wFS4S87KH$A>;L&Y2?1F-;VHJbrvz3?P%z?^HD_eo8yG9qN zF$7OQC;h}_SVRHl-m+Jk0t#ei@=RJ`6}$T(P;)SN#M#$7pluW3xV4p~Nv=QEPRrxw7tX73Ol&^RG zj$e7%SdW*Xeh|bSVP`Jjv8jq|pBAEhR=i+#Q0A5~&#l@Ffhp5fbfWf|&fi8zzGuS2 z%7vYWFh4-HNj7TA%GbR>yov>s`J?da9pOTM*419uu+P0E97UB%VYQZFB|LX@y3Vud zd2mdhtFDY(KsaiEu66d$?t7AvJ@N+N9{_PrkKX^H)VF*XxzC!;?C;n38lQd{Dfb+FGdGPi7EId07Ra#zV2>) zW+aL8d5E32=j2Cn)0Gg%WgRB%}qq(r-$(?OOv0Z6$G!EnAIs zUB)R@{Ea*uFN2Vc@A-0w3jGkgqPr)k%0D2(KoskIQB==m9F_$;C81@U>R#n-J_Huy zkeq~N?|f|Uqyue&&LV~wCZSW;osYHUGf`j-h|Bnya3ZIj!z9es%VR1$;ZlsVcK6rc zw+L%~^)qX1=6X-88mlIcVd}lxdN*~Rn8@Z@AKjl>bG6dNKWuRHOIYYv5Eabjw{Hzj zasvN;vMC7Z6mpkP-otZi#xlJ02aGs_pCRJkk$ewI;H~ z{R2B2e7XMei{C$38mq~rRi_zU&F1Aq9yKVbDs&-s?WlQ0scPFc?swOFF(+x2_-dT8 zr4!aL-ES2V9O3kIoPzka3YANetPU`=l(hU%gQ|j+O^;qEz$RjK!uGKe2=!``l6ztiZy|B`1Zz|_)HJXnzHI251ZJj zuRrKp6ZGozzbDYAq|uUzFGA=m%Z7~WHPlBs9g#BYaLrs0?&$b3gXS6=oRw6zpNnXn zH1^8inG}Z%6&r|GTWBK4z=7*IAjBc!f_#2$3D?XV;S^5nZu${;Jl(~L?gZ^qh7F9N{zmID>+T~-3GfuuIpLud&;1kfY|*YJ=?dlVo|(C5x5&ZK zQMXT&d8)p>3**Iwq$xo9#MZop;bw=2G16+b^s@2GD;wHzNaS#-AVMB=ML~hB5gN8X z1KJ(#WZhC__mDpUYKS%u8_8d!K%-2r=EP{^Ht~A6Rns)UMG6+AFlC z8xg#e7l<9Dc}9cjKr>haFW;W5V9Yi@OrJ_A&tx2_5w96|>~^g19E~rjTOJe^LUi2^ zE-B7*o&&8hJlCBVA2}609J|L81(YWZOq4;d8tx6Ejk~XHRr+d8HXhQm+v!g>o@zdG zxJaqEkdS?qmE*d4PbxR=CLSw&i&AlNFY9~#x2mZ9PRF^anQ-GnV$1!CIh#s*neSr* z2uA8F?axsoyW%5+m`bX=91~-9n7n5l`JqYNafQ^GpT3`qMd|l}mZp&S&5?3#ms94- zQ9e-XInd#dxO6r?-S1s;}s$p|YKtkM!(9!v#R|T4C)wMm`z8|=NE5JrP*WG8x~+UNLSQ5H}pB&U4y1PkO) z1Yx@Cc97?~z8p6ET7m{0#el~?;!dW@-7#`JFEy9lsU6dIT1GVDm*xu87P{%W=`DDO zZE=l|RL+Z_RiQ0oRq1s*@rgfpRO~GETwACyBd1_TX2G9(vZ!|P;O3&||xRrM~+OBDNM`m$mH51J9>K!v}%H7u=?h+p$ znb6`KE~f3Uz&jb|M6uY^xK-ITI~@fq7N=Fjs%IG8qvY6am&yFXO zWIAUYnGY@@4KBiEKcBSHajCab_%t;e;ikCh;GT03s<7ftYf}OJQxMK{e#_*e!t@O96^vVmy!c3m zpWkQsM0Gm|*>nc+j-_tbIH$!iAhC&ftuDba<2=E@%cQmV44<0YMf}Vw#p5l5nPqEc zOl)8O1m>ef^|Ca|u)#Vx0E5bs1ks zf1JQNr}67gz_?xhCOX0cA%B|u-ge1<(j1uLORlBGbUcFnk$Jx|Frf3exTlkPu7Lf# z(nIC`r0m{Q?lI`!$;|1{Y{aE=6rCa`?HTG*{!D-9kRCHA@($yTw8{N#Zn1bA9kS3Y zHwk;2S)TOu1S15*Rq8gZEw9N$j}hTE<97wp8{U+nH;mc!v}bbcQMyNWioQ{C{;8#$ zgr>zMtF%qc`;I5}eaR&^VgcALHhH#hVze0yGf*{>Zkt-@Fe8<(=mZ-AbAk)mmS(?8dO(5-Tf3M#6h2FPLaoc13dR93I|08FtoA~ z*GRgSc0Ma3%3zQIjU)yPac&(h&&VW?+Bhus-;k@CesO%h*gv2)5L8%2 zz4{j%MaIY++_Vr?+S#sBdL}la!TW#Na!AA4rkE^`U0{wf!;^XKsg;Y-G}8=vq9B1Y z1e~7?;Bh&P7XK|FkI8Rw?CsUruKpXrp(!yTcvTTilLUV2;p^+{w7Ac|d%9ZyIrMN^ zV5@W!iQ_AuzUclR#bUA7|356A*z+aFQVZ~Z#v)-|l=)d?yvf&&o8ZYB3d!KgZ~U)l zG5G)ksiitiL#|kz4Nk!5Nmkrg4->=u)0no<*)GQS0oo2L2YVM3Z&k6Xh?E0Z>o+tS zKpyD*up?K9@t=t7^%S1V&M&P#O`d#Drk{TeuFrb&CAbG^!9+DbG1{oF37Z7vy#D&~ zQ`YC#Jrh6$Wq(%(KO>684^+#+-~z$t-XQ#jjmNt3*1B+fzkO^8>mri_HoolGi?k5< zfXs1Hv>d`Znm8nJeTaazN#_?YXjJEkTY|SOi9wQXjbV;T5Icm?_W7*gj-`i+PI9W3m!$m>*f`}TDk3Vn%R+<6iRpH`V=4yBlvyz$ZPhO(?TiF3 zZFuy{8Qxg!Sdaf^tY7E2l8(+~P`OoS;(?lO4mQ%~i{_KyDS7e)!G02r=c;piSs!|C zgxj`_R~~fpJ0@a|(~0@)cj!v=lkvt!Zb>>2udw*f!aigc%&2LSFB~ySh&-R=KakVm zzj=(O!<2}?aL2(O-+QWeMZCgW>Sl_%Mr&nA6t7kJ?g!-QzU`vdBT5}4@Z0J|5`|2< znUzFCy#vMM%Wl~aJ$H8bgTUr(y|lPZgFd^OkPlhiKfS(j1i#$wn#-F0`G5xdYE4j^ zmsPI!X|j+|Q3UQyle!I&z`V~zd{pKG_J|8U_`BVG?I4^$Z4Bh{ezLsqeQGoNOKU>> zL0{izyX;vAf3*f8rDTp2`v1sNhVcI-PyLuv74iIcJf$$(iszQRZ50?4ld3Va%!w9f zwZJX$@m32xbeos%RN2&u8x}Gxs;A$Er?tfjzHv-=>MN#$)AG9oD6UKn^6uHWi56$z zz+4R;06d>kz>@>?m0vV(J4at!DDMrdfOK0eoI!nI=B$`oJx^`Id6tC0b77C&D!)3fyui|kF%9p~ k{#9xItT_LizlSHMq?|5Y3VK8R;YOo-%Me_x>G1f!0DPpI0RR91 literal 0 HcmV?d00001 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index d64dcaa82f..d7f4f76785 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -928,12 +928,139 @@ To put a title bar behind the status icon, we need to add it to each page, also For this example to work, use the theme and style options from :ref:`above `. +.. _lvgl-cook-flex: + +Positioning with Flex layout +---------------------------- + +:ref:`lvgl-layouts` aim to position widgets automatically, eliminating the need to specify coordinates to position each widget. This is a great way to simplify your configuration containing many widgets as it allows you to even omit alignment options. + +.. figure:: images/lvgl_cook_flex_layout.png + :align: center + +This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefere full featured individual buttons, as they offer wider customization possibilities as seen in the :ref:`lvgl-cook-cover` example. + +.. code-block:: yaml + + lvgl: + ... + pages: + - id: room_page + widgets: + - obj: # a coontainer object for all these controls + align: CENTER + width: 240 + height: 260 + x: 4 + y: 4 + pad_all: 3 + pad_row: 6 + pad_column: 8 + bg_opa: transp + border_width: 0 + layout: # enable the FLEX layout for the children widgets + type: FLEX + flex_flow: COLUMN_WRAP # the order of the widgets starts top left + flex_align_cross: CENTER # they sould be centered + widgets: + - label: + text: "East" + - btn: + id: but_cov_up_east + width: 70 # choose the button dimensions so + height: 68 # they fill the columns nincely as they flow + widgets: + - label: + id: cov_up_east + align: center + text: "\uE05D" #UP + - btn: + id: but_cov_stop_east + width: 70 + height: 68 + widgets: + - label: + id: cov_stop_east + align: center + text: "\uE4DB" #STOP + - btn: + id: but_cov_down_east + width: 70 + height: 68 + widgets: + - label: + id: cov_down_east + align: center + text: "\uE045" #DOWN + + - label: + text: "South" + - btn: + id: but_cov_up_south + width: 70 + height: 68 + widgets: + - label: + id: cov_up_south + align: center + text: "\uE05D" #UP + - btn: + id: but_cov_stop_south + width: 70 + height: 68 + widgets: + - label: + id: cov_stop_south + align: center + text: "\uE4DB" #STOP + - btn: + id: but_cov_down_south + width: 70 + height: 68 + widgets: + - label: + id: cov_down_south + align: center + text: "\uE045" #DOWN + + - label: + text: "West" + - btn: + id: but_cov_up_west + width: 70 + height: 68 + widgets: + - label: + id: cov_up_west + align: center + text: "\uE05D" #UP + - btn: + id: but_cov_stop_west + width: 70 + height: 68 + widgets: + - label: + id: cov_stop_west + align: center + text: "\uE4DB" #STOP + - btn: + id: but_cov_down_west + width: 70 + height: 68 + widgets: + - label: + id: cov_down_west + align: center + text: "\uE045" #DOWN + +This saved you from a considerable amount of manual calculation of widget positioning, if you wanted to place each of them manually with ``x`` and ``y``! + .. _lvgl-cook-btlg: ESPHome boot bogo ----------------- -To display a boot image which disappears automatically after a few moments or on touch of the screen you can use the *top layer*. The trick is to put a base :ref:`lvgl-wgt-obj` full screen and child :ref:`lvgl-wgt-img` widget in its middle as the last item of the widgets list, so they draw on top of all the others. To make it automatically disappear afer boot, you use ESPHome's ``on_boot`` trigger: +To display a boot image with a spinner animation which disappears automatically after a few moments or on touch of the screen you can use the *top layer*. The trick is to put a base :ref:`lvgl-wgt-obj` full screen and child :ref:`lvgl-wgt-img` widget in its middle as the last item of the widgets list, so they draw on top of all the others. To make it automatically disappear afer boot, you use ESPHome's ``on_boot`` trigger: .. code-block:: yaml @@ -969,6 +1096,18 @@ To display a boot image which disappears automatically after a few moments or on - img: align: center src: boot_logo + y: -40 + - spinner: + align: center + y: 95 + height: 50 + width: 50 + spin_time: 1s + arc_length: 60deg + arc_width: 8 + indicator: + arc_color: 0x404040 + arc_width: 8 on_press: - lvgl.widget.hide: boot_screen From d570317e45f700495c63d32934d4679182cae5e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 16:52:05 +0200 Subject: [PATCH 440/564] 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 d7f4f76785..b8447cb7bd 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -938,7 +938,7 @@ Positioning with Flex layout .. figure:: images/lvgl_cook_flex_layout.png :align: center -This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefere full featured individual buttons, as they offer wider customization possibilities as seen in the :ref:`lvgl-cook-cover` example. +This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer full featured individual buttons, as they offer wider customization possibilities as seen in the :ref:`lvgl-cook-cover` example. .. code-block:: yaml From f67bd7c96647aa887cec82eddb54943f878a1363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 16:59:05 +0200 Subject: [PATCH 441/564] 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 b8447cb7bd..b08a2fb5d8 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -947,7 +947,7 @@ This example illustrates a control panel for three covers, made up of labels and pages: - id: room_page widgets: - - obj: # a coontainer object for all these controls + - obj: # a properly placed coontainer object for all these controls align: CENTER width: 240 height: 260 @@ -973,7 +973,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: id: cov_up_east align: center - text: "\uE05D" #UP + text: "\U000F005D" # mdi:arrow-up - btn: id: but_cov_stop_east width: 70 @@ -982,7 +982,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: id: cov_stop_east align: center - text: "\uE4DB" #STOP + text: "\U000F04DB" # mdi:stop - btn: id: but_cov_down_east width: 70 @@ -991,7 +991,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: id: cov_down_east align: center - text: "\uE045" #DOWN + text: "\U000F0045" # mdi:arrow-down - label: text: "South" @@ -1003,7 +1003,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: id: cov_up_south align: center - text: "\uE05D" #UP + text: "\U000F005D" - btn: id: but_cov_stop_south width: 70 @@ -1012,7 +1012,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: id: cov_stop_south align: center - text: "\uE4DB" #STOP + text: "\U000F04DB" - btn: id: but_cov_down_south width: 70 @@ -1021,7 +1021,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: id: cov_down_south align: center - text: "\uE045" #DOWN + text: "\U000F0045" - label: text: "West" @@ -1033,7 +1033,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: id: cov_up_west align: center - text: "\uE05D" #UP + text: "\U000F005D" - btn: id: but_cov_stop_west width: 70 @@ -1042,7 +1042,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: id: cov_stop_west align: center - text: "\uE4DB" #STOP + text: "\U000F04DB" - btn: id: but_cov_down_west width: 70 @@ -1051,9 +1051,9 @@ This example illustrates a control panel for three covers, made up of labels and - label: id: cov_down_west align: center - text: "\uE045" #DOWN + text: "\U000F0045" -This saved you from a considerable amount of manual calculation of widget positioning, if you wanted to place each of them manually with ``x`` and ``y``! +This saved you from a considerable amount of manual calculation of widget positioning, if you wanted to place each of them manually with ``x`` and ``y``! (:ref:`lvgl-cook-icontext` below shows how to use custom icons) .. _lvgl-cook-btlg: From 5cb1ad653bc484b67d61e5fc86ca33450ba83d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 17:01:12 +0200 Subject: [PATCH 442/564] 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 b08a2fb5d8..938dfe0135 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1057,8 +1057,8 @@ This saved you from a considerable amount of manual calculation of widget positi .. _lvgl-cook-btlg: -ESPHome boot bogo ------------------ +ESPHome boot screen +------------------- To display a boot image with a spinner animation which disappears automatically after a few moments or on touch of the screen you can use the *top layer*. The trick is to put a base :ref:`lvgl-wgt-obj` full screen and child :ref:`lvgl-wgt-img` widget in its middle as the last item of the widgets list, so they draw on top of all the others. To make it automatically disappear afer boot, you use ESPHome's ``on_boot`` trigger: From a7980fee0bc997209188bcb66ede77795f5fbe4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 13 May 2024 18:27:00 +0200 Subject: [PATCH 443/564] 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 938dfe0135..57a1cd0e1d 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1053,7 +1053,7 @@ This example illustrates a control panel for three covers, made up of labels and align: center text: "\U000F0045" -This saved you from a considerable amount of manual calculation of widget positioning, if you wanted to place each of them manually with ``x`` and ``y``! (:ref:`lvgl-cook-icontext` below shows how to use custom icons) +This saved you from a considerable amount of manual calculation of widget positioning, if you wanted to place each of them manually with ``x`` and ``y``! You only need to decide for a common width of your widgets, and a height which will distribute them the way you like it. (:ref:`lvgl-cook-icontext` below shows how to use custom icons) .. _lvgl-cook-btlg: From c577ca53d33f4b779792b350fe6f88a6574094d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 09:31:21 +0200 Subject: [PATCH 444/564] Apply suggestions from code review Co-authored-by: Keith Burzinski --- components/lvgl.rst | 4 ++-- cookbook/lvgl.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c2b781289a..c6156001ff 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -416,7 +416,7 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. - **flex_grow** (*Optional*, int16): Flex grow can be used to make one or more children fill the available space on the track. When more children have grow parameters, the available space will be distributed proportionally to the grow values. Defaults to ``0``, which disables growing. -Checkout :ref:`lvgl-cook-flex` in the Cookbook for an example illustrating how to save a lot of manual widget positioning. +Checkout :ref:`lvgl-cook-flex` in the Cookbook for an example illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration. .. _lvgl-layouts-grid: @@ -438,7 +438,7 @@ It can arrange items into a 2D "table" that has rows or columns (tracks). The it - **grid_column_align** (*Optional*, string): How to align the widget within the column. Possible options below. - **grid_row_align** (*Optional*, string): How to align the widget within the row. Possible options below. - Applicable to ``grid_column_align``, ``grid_row_align``: + Values for use with ``grid_column_align``, ``grid_row_align``: - ``START``: means left horizontally and top vertically (default). - ``END``: means right horizontally and bottom vertically. diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 57a1cd0e1d..bc1e1b0860 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -938,7 +938,7 @@ Positioning with Flex layout .. figure:: images/lvgl_cook_flex_layout.png :align: center -This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer full featured individual buttons, as they offer wider customization possibilities as seen in the :ref:`lvgl-cook-cover` example. +This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer fully-featured individual buttons, as they offer a wider range of customization possibilities as seen in the :ref:`lvgl-cook-cover` example. .. code-block:: yaml @@ -1053,7 +1053,7 @@ This example illustrates a control panel for three covers, made up of labels and align: center text: "\U000F0045" -This saved you from a considerable amount of manual calculation of widget positioning, if you wanted to place each of them manually with ``x`` and ``y``! You only need to decide for a common width of your widgets, and a height which will distribute them the way you like it. (:ref:`lvgl-cook-icontext` below shows how to use custom icons) +This saved you from a considerable amount of manual calculation of widget positioning which would otherwise be required to place them manually with ``x`` and ``y``! You only need to determine a common width and height for your widgets to distribute them on the page as you prefer. (:ref:`lvgl-cook-icontext` below shows how to use custom icons.) .. _lvgl-cook-btlg: From a439bf3f608f0b6bb0ff06f9def175710076348d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 12:36:27 +0200 Subject: [PATCH 445/564] grid layout --- components/lvgl.rst | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c6156001ff..a728e6eee0 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -369,7 +369,7 @@ The layout configuration options are applied to any parent widget or page, influ **Configuration variables:** - **layout** (*Optional*, string): A dictionary describing the layout configuration: - - **type** (*Optional*, string): ``flex``, ``grid`` or ``none``. Defaults to ``none``. + - **type** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. - Further options from below depending on the chosen type. .. _lvgl-layouts-flex: @@ -382,11 +382,11 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac **Terms used:** -- *tracks*: the rows or columns *main* direction: row or column, the direction in which the items are placed. +- *track*: the rows or columns *main* direction flow: row or column in the direction in which the items are placed one after the other. - *cross direction*: perpendicular to the main direction. - *wrap*: if there is no more space in the track a new track is started. - *gap*: the space between the rows and columns or the items on a track. -- *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). For example, if there is 400 px available space and 4 widgets are set: A with ``flex_grow: 1``, B with ``flex_grow: 1``, C with ``flex_grow: 2``, A and B will have 100 px size, and C will have 200 px size. +- *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). It dictates what amount of the available space the widget should take up. For example if all items on the track have a ``grow`` set to ``1``, the space in the track will be distributed equally to all of them. If one of the items has a value of 2, that one would take up twice as much of the space as either one of the others. **Configuration variables:** @@ -404,7 +404,8 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac - **flex_align_cross** (*Optional*, string): Determines how to distribute the items in their track on the *cross* axis. For example, if the items have different height place them to the bottom of the track (known as *align-items* in CSS). Possible options below. - **flex_align_track** (*Optional*, string): Determines how to distribute the tracks (known as *align-content* in CSS). Possible options below. - Applicable to ``flex_align_main``, ``flex_align_cross``, ``flex_align_track``: + Values for use with ``flex_align_main``, ``flex_align_cross``, ``flex_align_track``: + - ``START``: means left horizontally and top vertically (default). - ``END``: means right horizontally and bottom vertically. - ``CENTER``: simply center. @@ -424,31 +425,47 @@ Checkout :ref:`lvgl-cook-flex` in the Cookbook for an example illustrating how t 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(s) can span through multiple columns or rows. The track's size can be set in pixels, to the largest item or in "free units" to distribute the free space proportionally. +It can arrange items into a 2D "table" that has rows or columns (tracks). The item(s) can span through multiple columns or rows. The track's size can be set in pixels, to the largest item of the track (``CONTENT``) or in "free units" to distribute the free space proportionally. **Terms used:** -- *tracks*: the rows or columns. +- *tracks*: the rows or the columns. - *gap*: the space between the rows and columns or the items on a track. +- *free unit (FR)*: a proportional distribution unit for the space available on the track. It accepts a unitless value that serves as a proportion. It dictates what amount of the available space the widget should take up. For example if all items on the track have a ``FR`` set to ``1``, the space in the track will be distributed equally to all of them. If one of the items has a value of 2, that one would take up twice as much of the space as either one of the others. **Configuration variables:** - - **grid_rows** (**Required**): The number of rows in the grid. - - **grid_columns** (**Required**): The number of columns in the grid. - - **grid_column_align** (*Optional*, string): How to align the widget within the column. Possible options below. - - **grid_row_align** (*Optional*, string): How to align the widget within the row. Possible options below. + - **grid_rows** (**Required**): The number of rows in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional unitless value). + - **grid_columns** (**Required**): The number of columns in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional unitless value). + - **grid_column_align** (*Optional*, string): How to align the widgets within the column. Possible options below. + - **grid_row_align** (*Optional*, string): How to align the widgets within the row. Possible options below. + - **pad_row** (*Optional*, int16): Set the padding between the rows, in pixels. + - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. - Values for use with ``grid_column_align``, ``grid_row_align``: +In a grid layout, *all the widgets placed on the grid* will get some additional configuration variables to help with placement: + + - **grid_cell_row_pos** (**Required**, int16): Position of the widget, in which row to appear (0 based count). + - **grid_cell_column_pos** (**Required**, int16): Position of the widget, in which column to appear (0 based count). + - **grid_cell_x_align** (*Optional*, string): How to align the widget horizontally within the cell. Possible options below. + - **grid_cell_y_align** (*Optional*, string): How to align the widget vertically within the cell. Possible options below. + - **grid_cell_row_span** (*Optional*, int16): How many rows to span across the widget. Defaults to ``1``. + - **grid_cell_column_span** (*Optional*, int16): How many columns to span across the widget. . Defaults to ``1``. + + .. note:: + + These ``grid_cell_`` variables apply to widget configuations! + +Values for use with ``grid_column_align``, ``grid_row_align``, ``grid_cell_x_align``, ``grid_cell_y_align``: - ``START``: means left horizontally and top vertically (default). - ``END``: means right horizontally and bottom vertically. - ``CENTER``: simply center. + - ``STRETCH``: stretch the widget to the cell in the respective direction. Does not apply to ``grid_column_align``, ``grid_row_align``. - ``SPACE_EVENLY``: items are distributed so that the spacing between any two items (and the space to the edges) is equal. - ``SPACE_AROUND``: items are evenly distributed in the track with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. - ``SPACE_BETWEEN``: items are evenly distributed in the track: first item is on the start line, last item on the end line. - - **pad_row** (*Optional*, int16): Set the padding between the rows, in pixels. - - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. + .. _lvgl-widgets: From a9b4e49b7fba6c7780f5d71f34f3eb757d7b02ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 13:00:03 +0200 Subject: [PATCH 446/564] grid to cookbook --- components/lvgl.rst | 12 ++-- cookbook/lvgl.rst | 156 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 158 insertions(+), 10 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a728e6eee0..b339347572 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -366,6 +366,8 @@ Layouts aim to position widgets automatically, eliminating the need to specify ` The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. +Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. + **Configuration variables:** - **layout** (*Optional*, string): A dictionary describing the layout configuration: @@ -417,8 +419,6 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. - **flex_grow** (*Optional*, int16): Flex grow can be used to make one or more children fill the available space on the track. When more children have grow parameters, the available space will be distributed proportionally to the grow values. Defaults to ``0``, which disables growing. -Checkout :ref:`lvgl-cook-flex` in the Cookbook for an example illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration. - .. _lvgl-layouts-grid: *Grid* @@ -431,12 +431,12 @@ It can arrange items into a 2D "table" that has rows or columns (tracks). The it - *tracks*: the rows or the columns. - *gap*: the space between the rows and columns or the items on a track. -- *free unit (FR)*: a proportional distribution unit for the space available on the track. It accepts a unitless value that serves as a proportion. It dictates what amount of the available space the widget should take up. For example if all items on the track have a ``FR`` set to ``1``, the space in the track will be distributed equally to all of them. If one of the items has a value of 2, that one would take up twice as much of the space as either one of the others. +- *free unit (FR)*: a proportional distribution unit for the space available on the track. It accepts a unitless integer value that serves as a proportion. It dictates what amount of the available space the widget should take up. For example if all items on the track have a ``FR`` set to ``1``, the space in the track will be distributed equally to all of them. If one of the items has a value of 2, that one would take up twice as much of the space as either one of the others. **Configuration variables:** - - **grid_rows** (**Required**): The number of rows in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional unitless value). - - **grid_columns** (**Required**): The number of columns in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional unitless value). + - **grid_rows** (**Required**): The number of rows in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional integer value). + - **grid_columns** (**Required**): The number of columns in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional integer value). - **grid_column_align** (*Optional*, string): How to align the widgets within the column. Possible options below. - **grid_row_align** (*Optional*, string): How to align the widgets within the row. Possible options below. - **pad_row** (*Optional*, int16): Set the padding between the rows, in pixels. @@ -465,8 +465,6 @@ Values for use with ``grid_column_align``, ``grid_row_align``, ``grid_cell_x_ali - ``SPACE_AROUND``: items are evenly distributed in the track with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. - ``SPACE_BETWEEN``: items are evenly distributed in the track: first item is on the start line, last item on the end line. - - .. _lvgl-widgets: Widgets diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index bc1e1b0860..ed06062954 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -930,15 +930,15 @@ For this example to work, use the theme and style options from :ref:`above Date: Wed, 15 May 2024 13:03:12 +0200 Subject: [PATCH 447/564] 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 b339347572..655dd652a5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -374,10 +374,10 @@ Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for exa - **type** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. - Further options from below depending on the chosen type. -.. _lvgl-layouts-flex: - *Flex* +.. _lvgl-layouts-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 spacing between items and tracks and even handle growing the layout to make the item(s) fill the remaining space with respect to minimum/maximum width and height. @@ -419,10 +419,10 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. - **flex_grow** (*Optional*, int16): Flex grow can be used to make one or more children fill the available space on the track. When more children have grow parameters, the available space will be distributed proportionally to the grow values. Defaults to ``0``, which disables growing. -.. _lvgl-layouts-grid: - *Grid* +.. _lvgl-layouts-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(s) can span through multiple columns or rows. The track's size can be set in pixels, to the largest item of the track (``CONTENT``) or in "free units" to distribute the free space proportionally. From 7a0dbde0a2b7d18c66b77e7d55f696c510b935c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 13:51:49 +0200 Subject: [PATCH 448/564] 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 655dd652a5..5191bfa59c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -374,10 +374,10 @@ Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for exa - **type** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. - Further options from below depending on the chosen type. -*Flex* - .. _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 spacing between items and tracks and even handle growing the layout to make the item(s) fill the remaining space with respect to minimum/maximum width and height. @@ -419,10 +419,10 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. - **flex_grow** (*Optional*, int16): Flex grow can be used to make one or more children fill the available space on the track. When more children have grow parameters, the available space will be distributed proportionally to the grow values. Defaults to ``0``, which disables growing. -*Grid* - .. _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(s) can span through multiple columns or rows. The track's size can be set in pixels, to the largest item of the track (``CONTENT``) or in "free units" to distribute the free space proportionally. From 481e50acf3e2612fcd7b8a0025dcfe66b0c83169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 14:00:38 +0200 Subject: [PATCH 449/564] 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 5191bfa59c..1a1e5cf5f2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -376,7 +376,8 @@ Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for exa .. _lvgl-layouts-flex: -#### Flex #### +Flex +#### The Flex layout in LVGL is a subset implementation of `CSS Flexbox `__. @@ -421,7 +422,8 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac .. _lvgl-layouts-grid: -#### Grid #### +Grid +#### The Grid layout in LVGL is a subset implementation of `CSS Flexbox `__. From 1d7eb4851893ff8b1c042b5e501a3c1fdc6b9355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 14:14:31 +0200 Subject: [PATCH 450/564] Update lvgl.rst --- components/lvgl.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1a1e5cf5f2..5191bfa59c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -376,8 +376,7 @@ Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for exa .. _lvgl-layouts-flex: -Flex -#### +#### Flex #### The Flex layout in LVGL is a subset implementation of `CSS Flexbox `__. @@ -422,8 +421,7 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac .. _lvgl-layouts-grid: -Grid -#### +#### Grid #### The Grid layout in LVGL is a subset implementation of `CSS Flexbox `__. From 654ceafeb697a6e2d09fe0de85bc38aaf4d7825c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 14:16:35 +0200 Subject: [PATCH 451/564] 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 5191bfa59c..fc0473ec44 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -376,7 +376,8 @@ Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for exa .. _lvgl-layouts-flex: -#### Flex #### +Flex +>>>> The Flex layout in LVGL is a subset implementation of `CSS Flexbox `__. @@ -421,7 +422,8 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac .. _lvgl-layouts-grid: -#### Grid #### +Grid +>>>> The Grid layout in LVGL is a subset implementation of `CSS Flexbox `__. From 1bb898c1041066ecb4e2dd631da3dca80ef9061d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 15:02:13 +0200 Subject: [PATCH 452/564] Update lvgl.rst --- components/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index fc0473ec44..484cf230ae 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -378,6 +378,7 @@ Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for exa Flex >>>> +[TOC] The Flex layout in LVGL is a subset implementation of `CSS Flexbox `__. From 3e02f2bb097c6bd0a471127ade073c3785c253c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 15:13:03 +0200 Subject: [PATCH 453/564] flex / grid crosslinx --- components/lvgl.rst | 11 ++--------- cookbook/lvgl.rst | 4 ++-- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 484cf230ae..40933a4875 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -374,11 +374,7 @@ Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for exa - **type** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. - Further options from below depending on the chosen type. -.. _lvgl-layouts-flex: - -Flex ->>>> -[TOC] +**Flex** The Flex layout in LVGL is a subset implementation of `CSS Flexbox `__. @@ -421,10 +417,7 @@ It can arrange items into rows or columns (tracks), handle wrapping, adjust spac - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. - **flex_grow** (*Optional*, int16): Flex grow can be used to make one or more children fill the available space on the track. When more children have grow parameters, the available space will be distributed proportionally to the grow values. Defaults to ``0``, which disables growing. -.. _lvgl-layouts-grid: - -Grid ->>>> +**Grid** The Grid layout in LVGL is a subset implementation of `CSS Flexbox `__. diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index ed06062954..1dffbacf04 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -938,7 +938,7 @@ Flex layout positioning .. figure:: images/lvgl_cook_flex_layout.png :align: center -This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer fully-featured individual buttons, as they offer a wider range of customization possibilities as seen in the :ref:`lvgl-cook-cover` example. Here we use the :ref:`lvgl-layouts-flex` layout: +This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer fully-featured individual buttons, as they offer a wider range of customization possibilities as seen in the :ref:`lvgl-cook-cover` example. Here we use the **Flex** layout: .. code-block:: yaml @@ -1060,7 +1060,7 @@ This saved you from a considerable amount of manual calculation of widget positi Grid layout positioning ----------------------- -But there's even more! With :ref:`lvgl-layouts-grid` layout, you don't even need to give specific widths and height to your widgets. All you have to do is split the space in proportional rows and columns, and drop the widgets in the cells, all stretched to the cell sizes. The same task from above, in a fully automated grid, looks like this: +But there's even more! With **Grid** layout, you don't even need to give specific widths and height to your widgets. All you have to do is split the space in proportional rows and columns, and drop the widgets in the cells, all stretched to the cell sizes. The same task from above, in a fully automated grid, looks like this: .. code-block:: yaml From 91aaf67fe08f9052ec4a1b634d649011722025be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 15:52:00 +0200 Subject: [PATCH 454/564] 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 1dffbacf04..c93ed3ee48 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1099,7 +1099,7 @@ But there's even more! With **Grid** layout, you don't even need to give specifi - label: id: cov_up_east align: center - text: "\U000F005D" # mdi:arrow-up + text: "\U000F005D" - btn: id: but_cov_stop_east grid_cell_row_pos: 2 @@ -1110,7 +1110,7 @@ But there's even more! With **Grid** layout, you don't even need to give specifi - label: id: cov_stop_east align: center - text: "\U000F04DB" # mdi:stop + text: "\U000F04DB" - btn: id: but_cov_down_east grid_cell_row_pos: 3 @@ -1121,7 +1121,7 @@ But there's even more! With **Grid** layout, you don't even need to give specifi - label: id: cov_down_east align: center - text: "\U000F0045" # mdi:arrow-down + text: "\U000F0045" - label: text: "South" From 462467a741d6bb73ef50f1fa271549597471ffe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 15 May 2024 16:10:48 +0200 Subject: [PATCH 455/564] Update lvgl.rst --- cookbook/lvgl.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index c93ed3ee48..c8264da13c 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1079,20 +1079,20 @@ But there's even more! With **Grid** layout, you don't even need to give specifi bg_opa: transp border_width: 0 layout: # enable the GRID layout for the children widgets - type: GRID # split the rows and the columns in proportional areas + type: GRID # split the rows and the columns proportionally grid_columns: [FR(1), FR(1), FR(1) ] # equal grid_rows: [FR(10), FR(30), FR(30), FR(30)] # like percents widgets: - label: text: "East" - grid_cell_row_pos: 0 # place the widget in - grid_cell_column_pos: 0 # the corresponding cell + grid_cell_column_pos: 0 # place the widget in + grid_cell_row_pos: 0 # the corresponding cell grid_cell_x_align: stretch grid_cell_y_align: stretch - btn: id: but_cov_up_east - grid_cell_row_pos: 1 grid_cell_column_pos: 0 + grid_cell_row_pos: 1 grid_cell_x_align: stretch grid_cell_y_align: stretch widgets: @@ -1102,8 +1102,8 @@ But there's even more! With **Grid** layout, you don't even need to give specifi text: "\U000F005D" - btn: id: but_cov_stop_east - grid_cell_row_pos: 2 grid_cell_column_pos: 0 + grid_cell_row_pos: 2 grid_cell_x_align: stretch grid_cell_y_align: stretch widgets: @@ -1113,8 +1113,8 @@ But there's even more! With **Grid** layout, you don't even need to give specifi text: "\U000F04DB" - btn: id: but_cov_down_east - grid_cell_row_pos: 3 grid_cell_column_pos: 0 + grid_cell_row_pos: 3 grid_cell_x_align: stretch grid_cell_y_align: stretch widgets: @@ -1125,14 +1125,14 @@ But there's even more! With **Grid** layout, you don't even need to give specifi - label: text: "South" - grid_cell_row_pos: 0 grid_cell_column_pos: 1 + grid_cell_row_pos: 0 grid_cell_x_align: stretch grid_cell_y_align: stretch - btn: id: but_cov_up_south - grid_cell_row_pos: 1 grid_cell_column_pos: 1 + grid_cell_row_pos: 1 grid_cell_x_align: stretch grid_cell_y_align: stretch widgets: @@ -1142,8 +1142,8 @@ But there's even more! With **Grid** layout, you don't even need to give specifi text: "\U000F005D" - btn: id: but_cov_stop_south - grid_cell_row_pos: 2 grid_cell_column_pos: 1 + grid_cell_row_pos: 2 grid_cell_x_align: stretch grid_cell_y_align: stretch widgets: @@ -1153,8 +1153,8 @@ But there's even more! With **Grid** layout, you don't even need to give specifi text: "\U000F04DB" - btn: id: but_cov_down_south - grid_cell_row_pos: 3 grid_cell_column_pos: 1 + grid_cell_row_pos: 3 grid_cell_x_align: stretch grid_cell_y_align: stretch widgets: @@ -1165,14 +1165,14 @@ But there's even more! With **Grid** layout, you don't even need to give specifi - label: text: "West" - grid_cell_row_pos: 0 grid_cell_column_pos: 2 + grid_cell_row_pos: 0 grid_cell_x_align: stretch grid_cell_y_align: stretch - btn: id: but_cov_up_west - grid_cell_row_pos: 1 grid_cell_column_pos: 2 + grid_cell_row_pos: 1 grid_cell_x_align: stretch grid_cell_y_align: stretch widgets: @@ -1182,8 +1182,8 @@ But there's even more! With **Grid** layout, you don't even need to give specifi text: "\U000F005D" - btn: id: but_cov_stop_west - grid_cell_row_pos: 2 grid_cell_column_pos: 2 + grid_cell_row_pos: 2 grid_cell_x_align: stretch grid_cell_y_align: stretch widgets: @@ -1193,8 +1193,8 @@ But there's even more! With **Grid** layout, you don't even need to give specifi text: "\U000F04DB" - btn: id: but_cov_down_west - grid_cell_row_pos: 3 grid_cell_column_pos: 2 + grid_cell_row_pos: 3 grid_cell_x_align: stretch grid_cell_y_align: stretch widgets: @@ -1203,7 +1203,7 @@ But there's even more! With **Grid** layout, you don't even need to give specifi align: center text: "\U000F0045" -The big advantage here is that whenever you need to add, for example, an extra columns of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. Their sizes and positions will automatically be calculated to fit in. +The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. Their sizes and positions will automatically be calculated to fit in. .. _lvgl-cook-btlg: From 360fa717beead3a1f067ad0b44faeeff20dd20d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 17 May 2024 10:55:03 +0200 Subject: [PATCH 456/564] removal of binary_output config from the lvgl switch platform --- components/switch/lvgl.rst | 3 -- cookbook/lvgl.rst | 67 +++++++++----------------------------- 2 files changed, 16 insertions(+), 54 deletions(-) diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 420ff7f46f..621e8afd38 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -16,7 +16,6 @@ Configuration variables: ------------------------ - **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 ``checked`` state of the configured widget. - All other variables from :ref:`Switch `. Example: @@ -28,8 +27,6 @@ Example: widget: checkbox_id name: LVGL switch -Check out :ref:`lvgl-cook-outbin` in the Cookbook for an example illustrating how to set up a LVGL Switch component to interact directly with a GPIO. - See Also -------- - :ref:`LVGL Main component ` diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index c8264da13c..4d22c74c80 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -17,38 +17,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 with dimensions of ``240x320px``; if your display's dimensions differ, you'll need to adjust them in order to obtain the 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: Local light switch @@ -57,28 +25,25 @@ Local light switch .. figure:: /components/images/lvgl_switch.png :align: left -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: +The easiest way to integrate a LVGL :ref:`lvgl-wgt-swi` widget and a switch or light on your display board is by using :ref:`automations ` to link together triggers and states of them: .. 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_switch - state: - checked: true - else: - - lvgl.widget.update: - id: light_switch - state: - checked: false + id: local_light + name: 'Local light' + on_turn_on: + - lvgl.widget.update: + id: light_switch + state: + checked: true + on_turn_off: + - lvgl.widget.update: + id: light_switch + state: + checked: false + lvgl: ... pages: @@ -88,7 +53,7 @@ In case your local light implements as a different platform than GPIO, you can u align: center id: light_switch on_click: - light.toggle: room_light + light.toggle: local_light .. _lvgl-cook-binent: @@ -1060,7 +1025,7 @@ This saved you from a considerable amount of manual calculation of widget positi Grid layout positioning ----------------------- -But there's even more! With **Grid** layout, you don't even need to give specific widths and height to your widgets. All you have to do is split the space in proportional rows and columns, and drop the widgets in the cells, all stretched to the cell sizes. The same task from above, in a fully automated grid, looks like this: +But there's even more! With **Grid** layout, you don't need to give specific widths and height to your widgets. All you have to do is split the space in proportional rows and columns, and drop the widgets in the cells, all stretched to the cell sizes. The same task from above, in a fully automated grid, looks like this: .. code-block:: yaml From 146bfa898663c6c48bd8ac323482d89a02041af8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 17 May 2024 14:27:00 +0200 Subject: [PATCH 457/564] Update lvgl.rst --- cookbook/lvgl.rst | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 4d22c74c80..028b5642f9 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1058,8 +1058,6 @@ But there's even more! With **Grid** layout, you don't need to give specific wid id: but_cov_up_east grid_cell_column_pos: 0 grid_cell_row_pos: 1 - grid_cell_x_align: stretch - grid_cell_y_align: stretch widgets: - label: id: cov_up_east @@ -1069,8 +1067,6 @@ But there's even more! With **Grid** layout, you don't need to give specific wid id: but_cov_stop_east grid_cell_column_pos: 0 grid_cell_row_pos: 2 - grid_cell_x_align: stretch - grid_cell_y_align: stretch widgets: - label: id: cov_stop_east @@ -1080,8 +1076,6 @@ But there's even more! With **Grid** layout, you don't need to give specific wid id: but_cov_down_east grid_cell_column_pos: 0 grid_cell_row_pos: 3 - grid_cell_x_align: stretch - grid_cell_y_align: stretch widgets: - label: id: cov_down_east @@ -1098,8 +1092,6 @@ But there's even more! With **Grid** layout, you don't need to give specific wid id: but_cov_up_south grid_cell_column_pos: 1 grid_cell_row_pos: 1 - grid_cell_x_align: stretch - grid_cell_y_align: stretch widgets: - label: id: cov_up_south @@ -1109,8 +1101,6 @@ But there's even more! With **Grid** layout, you don't need to give specific wid id: but_cov_stop_south grid_cell_column_pos: 1 grid_cell_row_pos: 2 - grid_cell_x_align: stretch - grid_cell_y_align: stretch widgets: - label: id: cov_stop_south @@ -1120,8 +1110,6 @@ But there's even more! With **Grid** layout, you don't need to give specific wid id: but_cov_down_south grid_cell_column_pos: 1 grid_cell_row_pos: 3 - grid_cell_x_align: stretch - grid_cell_y_align: stretch widgets: - label: id: cov_down_south @@ -1138,8 +1126,6 @@ But there's even more! With **Grid** layout, you don't need to give specific wid id: but_cov_up_west grid_cell_column_pos: 2 grid_cell_row_pos: 1 - grid_cell_x_align: stretch - grid_cell_y_align: stretch widgets: - label: id: cov_up_west @@ -1149,8 +1135,6 @@ But there's even more! With **Grid** layout, you don't need to give specific wid id: but_cov_stop_west grid_cell_column_pos: 2 grid_cell_row_pos: 2 - grid_cell_x_align: stretch - grid_cell_y_align: stretch widgets: - label: id: cov_stop_west @@ -1160,8 +1144,6 @@ But there's even more! With **Grid** layout, you don't need to give specific wid id: but_cov_down_west grid_cell_column_pos: 2 grid_cell_row_pos: 3 - grid_cell_x_align: stretch - grid_cell_y_align: stretch widgets: - label: id: cov_down_west From de4a42fa9517683d3b46bb5f8fe81b58f82f4567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 19 May 2024 11:52:22 +0200 Subject: [PATCH 458/564] Apply suggestions from code review Co-authored-by: Keith Burzinski --- cookbook/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 028b5642f9..fbfb731427 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -25,7 +25,7 @@ Local light switch .. figure:: /components/images/lvgl_switch.png :align: left -The easiest way to integrate a LVGL :ref:`lvgl-wgt-swi` widget and a switch or light on your display board is by using :ref:`automations ` to link together triggers and states of them: +The easiest way to integrate an LVGL :ref:`lvgl-wgt-swi` widget and a switch or light is with :ref:`automations `: .. code-block:: yaml @@ -1025,7 +1025,7 @@ This saved you from a considerable amount of manual calculation of widget positi Grid layout positioning ----------------------- -But there's even more! With **Grid** layout, you don't need to give specific widths and height to your widgets. All you have to do is split the space in proportional rows and columns, and drop the widgets in the cells, all stretched to the cell sizes. The same task from above, in a fully automated grid, looks like this: +But there's even more! With the **Grid** layout, you don't need to specify width and height for your widgets. All you have to do is divide the space into rows and columns; the widgets will automatically be sized to fit into cells defined by these rows and columns. The same task from above, in a fully automated grid, looks like this: .. code-block:: yaml From d585852c6feaea25919d991c407751320cd42c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 19 May 2024 12:08:58 +0200 Subject: [PATCH 459/564] 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 fbfb731427..c79d54fe5c 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1045,7 +1045,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width border_width: 0 layout: # enable the GRID layout for the children widgets type: GRID # split the rows and the columns proportionally - grid_columns: [FR(1), FR(1), FR(1) ] # equal + grid_columns: [FR(1), FR(1), FR(1)] # equal grid_rows: [FR(10), FR(30), FR(30), FR(30)] # like percents widgets: - label: From d573f539cbfff343d08824eda5d0d4af72c02098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 19 May 2024 12:09:52 +0200 Subject: [PATCH 460/564] 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 c79d54fe5c..44b280a133 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1025,7 +1025,7 @@ This saved you from a considerable amount of manual calculation of widget positi Grid layout positioning ----------------------- -But there's even more! With the **Grid** layout, you don't need to specify width and height for your widgets. All you have to do is divide the space into rows and columns; the widgets will automatically be sized to fit into cells defined by these rows and columns. The same task from above, in a fully automated grid, looks like this: +But there's even more! With the **Grid** layout, you don't need to specify width and height for your widgets. All you have to do is divide the space into rows and columns; the widgets can be automatically be sized to fit into cells defined by these rows and columns. The same task from above, in a fully automated grid, looks like this: .. code-block:: yaml From 3fdc31741fc1ffe36379f2eefe4b2e24722b6dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 20 May 2024 12:27:09 +0200 Subject: [PATCH 461/564] Update lvgl.rst --- cookbook/lvgl.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 44b280a133..728e3a2698 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -921,7 +921,6 @@ This example illustrates a control panel for three covers, made up of labels and pad_all: 3 pad_row: 6 pad_column: 8 - bg_opa: transp border_width: 0 layout: # enable the FLEX layout for the children widgets type: FLEX @@ -1041,7 +1040,6 @@ But there's even more! With the **Grid** layout, you don't need to specify width pad_all: 6 pad_row: 6 pad_column: 8 - bg_opa: transp border_width: 0 layout: # enable the GRID layout for the children widgets type: GRID # split the rows and the columns proportionally From 0b02b4e58b7720f9cc76371f07569f53c0d93e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 21 May 2024 09:45:42 +0200 Subject: [PATCH 462/564] 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 40933a4875..82fad08175 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1684,12 +1684,12 @@ For both triggers above, when triggered, the variable ``text`` (``std::string`` then: - logger.log: format: "Textarea changed to: %s" - args: [ text ] + args: [ text.c_str() ] on_ready: then: - logger.log: format: "Textarea ready: %s" - args: [ text ] + args: [ text.c_str() ] The ``textarea`` can be also integrated as :doc:`/components/text/lvgl` or :doc:`/components/text_sensor/lvgl`. From 63bfb7b9c14147ede880094ee01b972561912848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 21 May 2024 13:54:38 +0200 Subject: [PATCH 463/564] Update lvgl.rst --- cookbook/lvgl.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 728e3a2698..6d049ff837 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -915,13 +915,14 @@ This example illustrates a control panel for three covers, made up of labels and - obj: # a properly placed coontainer object for all these controls align: CENTER width: 240 - height: 260 + height: 256 x: 4 y: 4 pad_all: 3 pad_row: 6 pad_column: 8 - border_width: 0 + bg_opa: TRANSP + border_opa: TRANSP layout: # enable the FLEX layout for the children widgets type: FLEX flex_flow: COLUMN_WRAP # the order of the widgets starts top left @@ -1036,11 +1037,12 @@ But there's even more! With the **Grid** layout, you don't need to specify width - obj: # a properly placed coontainer object for all these controls align: CENTER width: 240 - height: 260 + height: 256 pad_all: 6 pad_row: 6 pad_column: 8 - border_width: 0 + bg_opa: TRANSP + border_opa: TRANSP layout: # enable the GRID layout for the children widgets type: GRID # split the rows and the columns proportionally grid_columns: [FR(1), FR(1), FR(1)] # equal From 4779f195a9be319f39d38cb7c4b58e44f7753f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 21 May 2024 14:06:43 +0200 Subject: [PATCH 464/564] rotary_encoder changes --- components/lvgl.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 82fad08175..92fb47d0c7 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -77,10 +77,12 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **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. May be omitted if a touchscreen is configured (as above). - - **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 which will interact with the the rotary encoder. See the :ref:`common properties ` of the widgets for more information on groups. +- **rotary_encoders** (*Optional*, list): A list of rotary encoders or keypads interacting with the LVGL widgets on the display. May be omitted if a touchscreen is configured (as above). + - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. + - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a push button within the input device used to interact with the widgets. + - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets; or a list with buttons for left/right navigation: + - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a left push button within the input device. + - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a right push button within the input device. - **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``. From ecf8a87c5421817a00daf2802a6a1ba234096fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 21 May 2024 14:11:52 +0200 Subject: [PATCH 465/564] 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 6d049ff837..1333514ca7 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1052,8 +1052,8 @@ But there's even more! With the **Grid** layout, you don't need to specify width text: "East" grid_cell_column_pos: 0 # place the widget in grid_cell_row_pos: 0 # the corresponding cell - grid_cell_x_align: stretch - grid_cell_y_align: stretch + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH - btn: id: but_cov_up_east grid_cell_column_pos: 0 @@ -1086,8 +1086,8 @@ But there's even more! With the **Grid** layout, you don't need to specify width text: "South" grid_cell_column_pos: 1 grid_cell_row_pos: 0 - grid_cell_x_align: stretch - grid_cell_y_align: stretch + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH - btn: id: but_cov_up_south grid_cell_column_pos: 1 @@ -1120,8 +1120,8 @@ But there's even more! With the **Grid** layout, you don't need to specify width text: "West" grid_cell_column_pos: 2 grid_cell_row_pos: 0 - grid_cell_x_align: stretch - grid_cell_y_align: stretch + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH - btn: id: but_cov_up_west grid_cell_column_pos: 2 From 002a998766796b169bc7659a7e60dfab05b1a03f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 09:18:07 +0200 Subject: [PATCH 466/564] capitals for special values --- components/lvgl.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 92fb47d0c7..c0c34f42ac 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -219,7 +219,7 @@ LVGL follows CSS's `border-box model `: 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). +- **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 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. + 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 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``. + 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 dimensions 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. Scroll bars can appear depending on the setting: @@ -604,8 +604,8 @@ A label is the basic widget type that is used to display text. - **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 text with ``#``. This makes it possible to set the color of characters in the text individually by prefixing the text to be re-colored with a ``#RRGGBB`` hexadecimal color code followed by a *space*, and finally closed 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 set by :ref:`lvgl-layouts`), 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 lines which are too long. If the height is ``size_content``, the label's height will be expanded, otherwise the text will be clipped (default). +- **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 set by :ref:`lvgl-layouts`), 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 lines which are too long. 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 the text horizontally back and forth. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. - ``SCROLL_CIRCULAR``: If the text is wider than the label, continuously scroll the text horizontally. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. @@ -1476,7 +1476,7 @@ Images are the basic widgets used to display images. - **pivot_x** (*Optional*): 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** (*Optional*): Vertical position of the pivot point of rotation relative to the top left corner of the image.. Defaults to ``50%`` (center of image). - **antialias** (*Optional*): The quality of the angle or zoom transformation. When anti-aliasing is enabled, the transformations are higher quality but slower. Defaults to ``false``. -- **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is zoomed or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``size_content``, the object's size will be set to the zoomed and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. +- **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is zoomed or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``SIZE_CONTENT``, the object's size will be set to the zoomed and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. - **offset_x**, **offset_y** (*Optional*): Add an offset to the displayed image. Useful if the widget size is smaller than the image source size. Tip: a *running image* effect can be created by animating these values. - 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. @@ -1568,7 +1568,7 @@ The Line widget is capable of drawing straight lines between a set of points. - **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. +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 e0c7cb9d6e6dc621cc09c22c8f02b46628aa0da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 09:18:42 +0200 Subject: [PATCH 467/564] cookbook capitals and additions --- cookbook/lvgl.rst | 122 +++++++++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 51 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 1333514ca7..db72d13f77 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -50,7 +50,7 @@ The easiest way to integrate an LVGL :ref:`lvgl-wgt-swi` widget and a switch or - id: main_page widgets: - switch: - align: center + align: CENTER id: light_switch on_click: light.toggle: local_light @@ -86,13 +86,13 @@ If you'd like to control a remote light which appears as an entity in Home Assis widgets: - btn: id: light_btn - align: center + align: CENTER width: 100 height: 70 checkable: true widgets: - label: - align: center + align: CENTER text: 'Remote light' on_click: - homeassistant.service: @@ -245,7 +245,7 @@ The trick here is to have a parent :ref:`lvgl-wgt-obj` which contains the other width: 100% border_width: 0 bg_opa: TRANSP - align: center + align: CENTER scales: - range_from: -10 range_to: 10 @@ -274,25 +274,25 @@ The trick here is to have a parent :ref:`lvgl-wgt-obj` which contains the other height: 146 width: 146 radius: 73 - align: center + align: CENTER border_width: 0 bg_color: 0xFFFFFF pad_all: 0 - label: # gauge numeric indicator id: val_text text_font: montserrat_48 - align: center + align: CENTER y: -5 text: "0" - label: # lower range indicator text_font: montserrat_18 - align: center + align: CENTER y: 8 x: -90 text: "-10" - label: # higher range indicator text_font: montserrat_18 - align: center + align: CENTER y: 8 x: 90 text: "+10" @@ -406,7 +406,7 @@ If you change the size of the widget, to obtain a uniform gradient, be sure to i height: 100% width: 100% border_width: 0 - align: center + align: CENTER bg_opa: TRANSP scales: - range_from: -15 @@ -437,7 +437,7 @@ If you change the size of the widget, to obtain a uniform gradient, be sure to i height: 123 width: 123 radius: 73 - align: center + align: CENTER border_width: 0 pad_all: 0 bg_color: 0xFFFFFF @@ -484,10 +484,12 @@ First we import from Home Assistant the current target temperature of the climat - obj: align: BOTTOM_MID y: -50 - layout: flex - flex_flow: row - width: size_content - height: size_content + layout: + type: FLEX + flex_flow: ROW + flex_align_cross: CENTER + width: SIZE_CONTENT + height: SIZE_CONTENT widgets: - btn: id: spin_down @@ -498,8 +500,8 @@ First we import from Home Assistant the current target temperature of the climat text: "-" - spinbox: id: spinbox_id - align: center - text_align: center + align: CENTER + text_align: CENTER width: 50 range_from: 15 range_to: 35 @@ -597,7 +599,7 @@ Just as in the previous examples, we need to get the state of the cover first. W y: 6 width: 70 text: "My room" - text_align: center + text_align: CENTER - btn: x: 10 y: 30 @@ -606,7 +608,7 @@ Just as in the previous examples, we need to get the state of the cover first. W widgets: - label: id: cov_up_myroom - align: center + align: CENTER text: "\uF077" on_press: then: @@ -622,7 +624,7 @@ Just as in the previous examples, we need to get the state of the cover first. W widgets: - label: id: cov_stop_myroom - align: center + align: CENTER text: STOP on_press: then: @@ -638,7 +640,7 @@ Just as in the previous examples, we need to get the state of the cover first. W widgets: - label: id: cov_down_myroom - align: center + align: CENTER text: "\uF078" on_press: then: @@ -874,8 +876,8 @@ To put a title bar behind the status icon, we need to add it to each page, also widgets: - label: text: "ESPHome LVGL Display" - align: center - text_align: center + align: CENTER + text_align: CENTER text_color: 0xFFFFFF ... - id: second_page @@ -886,8 +888,8 @@ To put a title bar behind the status icon, we need to add it to each page, also widgets: - label: text: "A second page" - align: center - text_align: center + align: CENTER + text_align: CENTER text_color: 0xFFFFFF ... @@ -937,7 +939,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: id: cov_up_east - align: center + align: CENTER text: "\U000F005D" # mdi:arrow-up - btn: id: but_cov_stop_east @@ -946,7 +948,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: id: cov_stop_east - align: center + align: CENTER text: "\U000F04DB" # mdi:stop - btn: id: but_cov_down_east @@ -955,7 +957,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: id: cov_down_east - align: center + align: CENTER text: "\U000F0045" # mdi:arrow-down - label: @@ -967,7 +969,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: id: cov_up_south - align: center + align: CENTER text: "\U000F005D" - btn: id: but_cov_stop_south @@ -976,7 +978,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: id: cov_stop_south - align: center + align: CENTER text: "\U000F04DB" - btn: id: but_cov_down_south @@ -985,7 +987,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: id: cov_down_south - align: center + align: CENTER text: "\U000F0045" - label: @@ -997,7 +999,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: id: cov_up_west - align: center + align: CENTER text: "\U000F005D" - btn: id: but_cov_stop_west @@ -1006,7 +1008,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: id: cov_stop_west - align: center + align: CENTER text: "\U000F04DB" - btn: id: but_cov_down_west @@ -1015,7 +1017,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: id: cov_down_west - align: center + align: CENTER text: "\U000F0045" This saved you from a considerable amount of manual calculation of widget positioning which would otherwise be required to place them manually with ``x`` and ``y``! You only need to determine a common width and height for your widgets to distribute them on the page as you prefer. (:ref:`lvgl-cook-icontext` below shows how to use custom icons.) @@ -1058,28 +1060,34 @@ But there's even more! With the **Grid** layout, you don't need to specify width id: but_cov_up_east grid_cell_column_pos: 0 grid_cell_row_pos: 1 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH widgets: - label: id: cov_up_east - align: center + align: CENTER text: "\U000F005D" - btn: id: but_cov_stop_east grid_cell_column_pos: 0 grid_cell_row_pos: 2 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH widgets: - label: id: cov_stop_east - align: center + align: CENTER text: "\U000F04DB" - btn: id: but_cov_down_east grid_cell_column_pos: 0 grid_cell_row_pos: 3 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH widgets: - label: id: cov_down_east - align: center + align: CENTER text: "\U000F0045" - label: @@ -1092,28 +1100,34 @@ But there's even more! With the **Grid** layout, you don't need to specify width id: but_cov_up_south grid_cell_column_pos: 1 grid_cell_row_pos: 1 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH widgets: - label: id: cov_up_south - align: center + align: CENTER text: "\U000F005D" - btn: id: but_cov_stop_south grid_cell_column_pos: 1 grid_cell_row_pos: 2 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH widgets: - label: id: cov_stop_south - align: center + align: CENTER text: "\U000F04DB" - btn: id: but_cov_down_south grid_cell_column_pos: 1 grid_cell_row_pos: 3 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH widgets: - label: id: cov_down_south - align: center + align: CENTER text: "\U000F0045" - label: @@ -1126,31 +1140,37 @@ But there's even more! With the **Grid** layout, you don't need to specify width id: but_cov_up_west grid_cell_column_pos: 2 grid_cell_row_pos: 1 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH widgets: - label: id: cov_up_west - align: center + align: CENTER text: "\U000F005D" - btn: id: but_cov_stop_west grid_cell_column_pos: 2 grid_cell_row_pos: 2 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH widgets: - label: id: cov_stop_west - align: center + align: CENTER text: "\U000F04DB" - btn: id: but_cov_down_west grid_cell_column_pos: 2 grid_cell_row_pos: 3 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH widgets: - label: id: cov_down_west - align: center + align: CENTER text: "\U000F0045" -The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. Their sizes and positions will automatically be calculated to fit in. +The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. With ``STRETCH`` their sizes and positions will automatically be calculated to fill in the cells, while the parent's ``pad_all``, ``pad_row`` and ``pad_column`` can help with spacing between them. .. _lvgl-cook-btlg: @@ -1185,17 +1205,17 @@ To display a boot image with a spinner animation which disappears automatically width: 100% height: 100% bg_color: 0xFFFFFF - bg_opa: cover + bg_opa: COVER radius: 0 pad_all: 0 border_width: 0 widgets: - img: - align: center + align: CENTER src: boot_logo y: -40 - spinner: - align: center + align: CENTER y: 95 height: 50 width: 50 @@ -1244,7 +1264,7 @@ In the example below, we use the default set of glyphs from RobotoCondensed-Regu - label: text: "Just\U000f05d4here. Already\U000F02D1this." align: CENTER - text_align: center + text_align: CENTER text_font: roboto_icons_42 .. tip:: @@ -1319,7 +1339,7 @@ If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like t widgets: - label: id: lbl_lightbulb - align: center + align: CENTER text_font: mdi_42 text: "\U000F0336" # mdi-lightbulb-outline on_short_click: @@ -1525,7 +1545,7 @@ The script runs at the beginning of every minute to update the line positions fo - id: clock_page widgets: - obj: # clock container - height: size_content + height: SIZE_CONTENT width: 240 align: CENTER pad_all: 0 @@ -1535,7 +1555,7 @@ The script runs at the beginning of every minute to update the line positions fo - meter: # clock face height: 220 width: 220 - align: center + align: CENTER bg_opa: TRANSP border_width: 0 text_color: 0x000000 @@ -1677,7 +1697,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c id: lvgl_label align: CENTER text: "Enter code and \uF00C" - text_align: center + text_align: CENTER - btnmatrix: id: lvgl_keypad x: 20 From 9a9c60e9d265d77b268bd7578b49ee09dfe26799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 09:44:33 +0200 Subject: [PATCH 468/564] adding keypads config --- components/lvgl.rst | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c0c34f42ac..c7d6a47688 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -73,18 +73,32 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **displays** (**Required**, list): A list of displays where LVGL should perform rendering based on its 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. May be omitted if a rotary encoder is configured (see below). +- **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. May be omitted if a rotary encoder or a keypad is configured. - **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 or keypads interacting with the LVGL widgets on the display. May be omitted if a touchscreen is configured (as above). +- **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. May be omitted if a touchscreen or keypad is configured. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a push button within the input device used to interact with the widgets. - - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder` used to interact with the widgets; or a list with buttons for left/right navigation: - - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a left push button within the input device. - - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a right push button within the input device. + - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as the ``ENTER`` key. + - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: + - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``LEFT`` key. + - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``RIGHT`` key. - **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``. +- **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. May be omitted if a touchscreen or a rotary encoder is configured. + - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. + - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as an ``UP`` key. + - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``DOWN`` key. + - **right** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``RIGHT`` key. + - **left** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``LEFT`` key. + - **esc** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``ESC`` key. + - **del** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``DEL`` key. + - **backspace** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``BACKSPACE`` key. + - **enter** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``ENTER`` key. + - **next** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``NEXT`` key. + - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``PREV`` key. + - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``HOME`` key. + - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as an ``END`` key. - **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 screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. - **update_interval**: (*Optional*, :ref:`Time `): The interval at which the screen should be redrawn (when necessary). Defaults to ``1s``. @@ -99,16 +113,20 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **pages** (*Optional*, list): A list of page IDs. Each page acts as a parent for widgets placed on it. May not be used with ``widgets`` (above). Options for each page: - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - - 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. + - All other options from :ref:`lvgl-styling` to be applied to this page. - **page_wrap** (*Optional*, boolean): Wrap pages around when navigating between them with :ref:`lvgl-pgnx-act`. Defaults to ``true``. - **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, which may be useful for widgets which always need to be visible. May not be used with ``widgets`` (above). Options: - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - - 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. + - All other options from :ref:`lvgl-styling` to be applied to this page. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - All other options from :ref:`lvgl-styling` to be applied to all widgets directly. +.. tip:: + + When using binary sensors (from physical keys) to interact with LVGL, if there are only 3 keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With 4 or more keys, a keypad configuration suits better. For example a 5-key keypad might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``: ``PREV``/``NEXT`` can select a widget within the group, ``UP``/``DOWN`` changes the value, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. + **Example:** .. code-block:: yaml From 208de0cf0fbc997b334b54783fbe4213d908fdba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 09:56:13 +0200 Subject: [PATCH 469/564] Update lvgl.rst --- components/lvgl.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c7d6a47688..258a72889f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -83,13 +83,13 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``LEFT`` key. - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``RIGHT`` key. - - **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``. + - **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``. Can be disabled with ``never``. + - **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``. Can be disabled with ``never``. - **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. May be omitted if a touchscreen or a rotary encoder is configured. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as an ``UP`` key. - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``DOWN`` key. - - **right** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``RIGHT`` key. + - **right** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``RIGHT`` key. - **left** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``LEFT`` key. - **esc** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``ESC`` key. - **del** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``DEL`` key. @@ -99,6 +99,8 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``PREV`` key. - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``HOME`` key. - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as an ``END`` key. + - **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``. Can be disabled with ``never``. + - **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``. Can be disabled with ``never``. - **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 screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. - **update_interval**: (*Optional*, :ref:`Time `): The interval at which the screen should be redrawn (when necessary). Defaults to ``1s``. @@ -126,6 +128,8 @@ The following configuration variables apply to the main ``lvgl`` component, in o .. tip:: When using binary sensors (from physical keys) to interact with LVGL, if there are only 3 keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With 4 or more keys, a keypad configuration suits better. For example a 5-key keypad might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``: ``PREV``/``NEXT`` can select a widget within the group, ``UP``/``DOWN`` changes the value, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. + + The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. **Example:** From f31a67296f6aa5afa3490c44ab3c6548c62778bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 09:59:46 +0200 Subject: [PATCH 470/564] Update lvgl.rst --- components/lvgl.rst | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 258a72889f..4080080551 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -79,26 +79,26 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **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. May be omitted if a touchscreen or keypad is configured. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as the ``ENTER`` key. + - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as the ``ENTER`` key. - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: - - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``LEFT`` key. - - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``RIGHT`` key. + - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``LEFT`` key. + - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``RIGHT`` key. - **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``. Can be disabled with ``never``. - **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``. Can be disabled with ``never``. - **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. May be omitted if a touchscreen or a rotary encoder is configured. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as an ``UP`` key. - - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``DOWN`` key. + - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as an ``UP`` key. + - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``DOWN`` key. - **right** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``RIGHT`` key. - - **left** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``LEFT`` key. - - **esc** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``ESC`` key. - - **del** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``DEL`` key. - - **backspace** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``BACKSPACE`` key. - - **enter** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``ENTER`` key. - - **next** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``NEXT`` key. - - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``PREV`` key. - - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as a ``HOME`` key. - - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/binary_sensor/index`, to be used as an ``END`` key. + - **left** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``LEFT`` key. + - **esc** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``ESC`` key. + - **del** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``DEL`` key. + - **backspace** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``BACKSPACE`` key. + - **enter** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``ENTER`` key. + - **next** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``NEXT`` key. + - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``PREV`` key. + - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``HOME`` key. + - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as an ``END`` key. - **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``. Can be disabled with ``never``. - **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``. Can be disabled with ``never``. - **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``. From 855df83287abf1710eab53aa8a62da535df6c609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 10:10:13 +0200 Subject: [PATCH 471/564] 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 4080080551..b9d85a742a 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -79,26 +79,26 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **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. May be omitted if a touchscreen or keypad is configured. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as the ``ENTER`` key. + - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: - - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``LEFT`` key. - - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``RIGHT`` key. + - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. + - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. - **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``. Can be disabled with ``never``. - **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``. Can be disabled with ``never``. - **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. May be omitted if a touchscreen or a rotary encoder is configured. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as an ``UP`` key. - - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``DOWN`` key. - - **right** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``RIGHT`` key. - - **left** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``LEFT`` key. - - **esc** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``ESC`` key. - - **del** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``DEL`` key. - - **backspace** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``BACKSPACE`` key. - - **enter** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``ENTER`` key. - - **next** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``NEXT`` key. - - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``PREV`` key. - - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as a ``HOME`` key. - - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as an ``END`` key. + - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``UP`` key. + - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``DOWN`` key. + - **right** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. + - **left** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. + - **esc** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ESC`` key. + - **del** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``DEL`` key. + - **backspace** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``BACKSPACE`` key. + - **enter** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. + - **next** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``NEXT`` key. + - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``PREV`` key. + - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``HOME`` key. + - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``END`` key. - **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``. Can be disabled with ``never``. - **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``. Can be disabled with ``never``. - **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``. From 2ce20b7044d9f484c91d42d5ed597c555231b757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 13:14:33 +0200 Subject: [PATCH 472/564] Update lvgl_msgbox.png --- components/images/lvgl_msgbox.png | Bin 5162 -> 4971 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/components/images/lvgl_msgbox.png b/components/images/lvgl_msgbox.png index dfbbc51a52326e4e7788d8f4d696f5a6ec7348b2..101a40c8b4f71430581d95d0cdfc91a562c905e3 100644 GIT binary patch literal 4971 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 literal 5162 zcmbtYXEh7buN5nZ$wqj#eBUMEBg(S?M_2&0ac=$#-#L=Yl+O&E2= zMDL6+M*a4CUGKThIX}+#{Ww3?-q&8wex9}Wv+lLly`DHd9aU-y7773WsMXbA2H+hJ zN-2aCyc$7y>;ZsbPaUT4IM8|v>*dO@)_P_47kvyBEF+R4C!RxiElA=3@V-_wj3%C3r$+0U=)^c{qzHah6 zhv~!Mt#-x+$w+GHNWsO{!0BE|^x@Agu#}3iAID*S2Np;O3lqZ%@h-b16jxe-ldUG&{DY%TB-~BVKH#58oY> z+?!GXE5+3c-ka$NVB4bGiSI@5@XaRp-~V|MDgJXzfxi)|NUe2lq*G+bn;a)UB+xr| z1^56}E7s;^=&#Fg8-ta;VC=8sX*qqG>o;}+e4Tr8=Sn8CEIQ`h zyqkta>adE^#JjJ-j5o?V8X*rcrQ2zkCEcCK%1qj-9XEv*P+=d@`UC%E!e{>r!wgehh{R=WuIE`-<&AUQ6z52Bs&HI2{~Iyja`y`)PnqV+2UHbpF*!q7 z3!icsWJhC44LDHolI%JO3!YmI?U4#UblN*s6+f=P-WDf9bfd=+Gt=;&zqAC<-)VAe zSS=7`6&(zAcn5GsQTwW5%7UbmrjP63T0zKf-DxDn;}Nx(T4xKh8EJ9@Q&Q81B4>^_U!S&C8T z5@L$&UT7T-)mUiXo1aH1*cr?R2kp4kWDm7GzAi1wHOHV{CB!%K%5|dq{_UFc{qy<2 zk)JzUgETfQybm<6R#?#Lj(jMPXsQeTcb*3qp5YdI+_mlC&2prQv9YmrYakK-z2CE! zw17mlWPupJ!W6%>m)u=AGP(wNL#~KRJSY{*8bnU7Jjkse{FeV+KeahF$QS=TKZSve zQf#?k-;wpl(PoZWk^A9L<#&73XQ`qwCK*5REPq0Cm1Hf_yNfIpEcfAysl0pq5Y-6kUcE<_y3p5wL)mc9hW^D{4-E>^Vz#B*$&=`c061X*-zr6dSQ0ab^LPN-OAkh+7rmR z?@Y<^$*fD`%#|zT*w80hW$C0PkhX&|b^=EF6Q|_ryqTM_9?Eziw@}l1D!71?MawAkIC=Vp-K@I;c3df9KrnHqK3TXAa_-2R0*0- zl;3w85q>1MF0C3w|y&WSoFCI27z)9*uixkqk&|M%*Qap9Gi zhB`e@I)iFwgqXWEo(U2}D0x?`aU87>m+4Ozl}YN+=NjKY~jxiN9z0QNl|^Qg3HD zPV2a=rqz{H;&SL7tB#Sp_E?xVyY__0p~{ezULl+ADSS>?``|SR``J z{_!`{f@6Cc;SusUm#YN3-cVE0h=DZgVfggBe%XnxhgbSJB7rWJ7LoylF2AvqX)Sd= zzU0w$a2v(Gx zPGM8ZSpZe{_46B^eR)NLu-ag{AZ{t_9(F##WFEL3#or~JJ(Cb(z=Uon zvxQFK`#NzIwSr9rwPz+0#BL7fo04%69rM+g(E|oXdzBjArgsFbw`=Z=!zt4K^4&XCuFGz~J|W~DmWMlV zH{R-}O;?&wOp>OjbkTp1QB~ZwE?%BjcZKWtu82Qj&I*qnf8rmysZn`HbRiji!~!G^ zeJW^Cs^=|I;bW~Zf!GabotKw?XBnMJ5;oL;tMpOXuoyGl-`HMnK+kka=?BT?4UCNq zFcOW{GFCw(b6YZtZpeZW_*+)r?Ahx|pMWL&^#e-w@>G`Y%zLsLi7xl|v{*e_)1mB8 zG;c_J7#)vCi#KMmOh5bSUzh8W(T)E%F7vvZ6v7n$}UQ@hwqYKFs zq#MlM&Gzhjb382*xE1T>`L^6en`())>_% ztG@i5{DyKU^1i95r@bf;eWzo+3%(_OAZA&sv@+pdoC#|B*6vcPFz2&%^I0I3n6u{) zhm(DMef`W2Y+3_Rf~e+S@LJQ^vu)z)DOmA0^eYN}+R3`-e3lY}=0GJyY->$(+X8jO zIV45qSN#U&P@$)bPi;j(HAoYtJP$!y!4!X+kw!KQA9y&l`4tsuAF~*n=N-#7G`i+Z zXin|wJ=`B9>Pb5Oy}$h+%>XL`xgZl|Sv66h zwvjQBh-D#B$M^O5#MCx$p!t94V6zQg@nsE~zcp8<>G7?B$z%1? zECXB*uC`GB%sI7uO1i#JH{W-4bBOQD^8<~tCHddIUixA6i_9uS%;*{?j^o%zjSq(S zE6zWLP^FojP$|;;X`XF0Dn`%IUewL`2&;^+ARkx!bLMW~jn;!P%FC{H=!(Z~w z>EOi+@}2wg7Y6@D6CP+6i5nK`A$hXRrZf1P9Pj0v^EmK&(fGA@*fSKUFRW9-4knIY zfo?ABO-O2r{Y()cx5@qARefJxG>!#E{oI57(f3E?*2J zEA)evZ9juS1d%C?0l5P1^Lr}u+0bowIbuV+>=!1|rQ~@k@aFUuij0sl zqEC`v(<&B}xzpJXlo;MdqmWBh=ic;k5b9FAX@48*=^Bqg79Ww2ugfn7L6qT5U4Gnz zCn>CDm+7Roi%y`7={K~#<&=2!NQ9IfLb*qz40HHjxK)c($zaB9@WDF4*-**-3vY*S zqu@ySG=1xJP~jCGZeg{`iVy7x&zMy!r`%XYWV=;8rr%hvl(o>5(fm+Vxjdyv?4jUq zuTWU3#ZwdQ-`e|_cd6FAclX*gx)&llK)^SMTO6rO&b+fAYnNE`fWw^z2DX}Je9V`p zKjHSjVZ=T7&=eDQ?wDe0W{ere4DOKN`9`E$I7Wp?5FmN@io)d+Tcu%Ql^-}a@H zxa=?JRIE6mIHXg89(;r!hfH*7hi6&DXtkwrwh8u8{@L2`s;}}4E1833=M3TEo0y?} zT6V?$n+lahA9;r2G=8mZ5kLfL3TXC`ClJ`y?^HHd1QSPn;?NYW=_Z&_h838uO?|*P z#U8Y20xBi=VAe*@D1TzJeKON8KhsFpr8Vnmz;fEP>fFX(8^@jKLr?AL6eO$qk8p_x zJ_rclDWJI>miRQF{+&qD&V4(c|Bladb%`D^vrM%fL4Uh&E)O1r{Ll#i#cL&or zIh>i3&Gh-eEf-JJcyn;UL2!RVeV5~n-kOOpOT%hTZD)q?FHOVM9CLn^-%s+h)5aU+ z0AM=8VmtWuyzyodS$wJo z%!f=JiM8}PZ+YnT2=lYCnDQ{E+S+8--FtU{6YzWH?+c$ztuW~kl(93=v)NjkDBtTQ z3YgS4M3*1OJwb6yJ)nK0&;<3=LX^8GhVox!;PEJH93sn9D|#PRcNt@ zg|f{mD^a0TFy~4hiBZ@K-67FcEoDAIxToh)+wL6<1K7mE{fT}Y)?PW7p|#pT7fqF&J| zI+V*`{3xj{Z0GN!%H(`NpD`a(bX>`MXvE>M4tz&H{Xk}*Aw0RSk*mpfyPe4!o;{>m zv!~#yWrV0gy`cK2@Z0QGa&Mxp?v42%BifWE@dT+){qYa}4*7D^OMq|ULv}GRVH;?; zR}Yh|38A#821f+_;;b0K1W-H;zTqE{Z~EGa^~^fd3io0}j~{BmJ@!Ee(-ZOU~yA_2-i?xjOj$yG?TI=;{Xzbl^N8$$|hSi-ceqbZWY zl58o3QCcBlG&2qxg5ar8pAj*b1QMox~m u-3xmY6!h-mfxrH9uKiEB`0w$Ni%Sbpqru9|g;wAhAfT?S1FKfFjrtclX8}L} From 1b91084ba3e19d5bb35f779b841989a299f005d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 14:26:19 +0200 Subject: [PATCH 473/564] layout clarifications --- components/lvgl.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index b9d85a742a..6862b5fcf4 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -388,10 +388,12 @@ Layouts Layouts aim to position widgets automatically, eliminating the need to specify ``x`` and ``y`` coordinates to position each widget. This is a great way to simplify your configuration as it allows you to omit alignment options. -The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. +The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. The position and size calculated by the layout overwrites the *normal* ``x``, ``y``, ``width``, and ``height`` settings of the children. Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. +The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` can be used on widgets to ignore them in layout calculations. + **Configuration variables:** - **layout** (*Optional*, string): A dictionary describing the layout configuration: @@ -504,8 +506,8 @@ The properties below are common to all widgets. **Configuration variables:** - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **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). +- **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 specifying ``align``, it is used as an offset to the calculated position (can also be negative). Ignored if :ref:`lvgl-layouts` are used. +- **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 specifying ``align``, it is used as an offset to the calculated position (can also be negative). Ignored if :ref:`lvgl-layouts` are used. .. note:: @@ -576,7 +578,7 @@ See :ref:`lvgl-cook-cover` for a cookbook example illustrating how to use stylin 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``. +- **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``. Hidden objects are ignored in layout calculations. 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`` (also see the ``scrollbar_mode`` property). @@ -594,7 +596,7 @@ In addition to visual styling, each widget supports some boolean **flags** to in - **event_bubble** (*Optional*, boolean): propagate the events to the parent. - **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent. - **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. For example, may help by accounting for rounded corners. -- **ignore_layout** (*Optional*, boolean): do not make the widget positionable by the layouts. +- **ignore_layout** (*Optional*, boolean): the widget is simply ignored by the layouts. Its coordinates can be set as usual. - **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. From 8db563eace31664d4e3c86d352cfb0951d315337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 14:35:42 +0200 Subject: [PATCH 474/564] positioning clarifications --- components/lvgl.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 6862b5fcf4..38151fdca0 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -506,15 +506,17 @@ The properties below are common to all widgets. **Configuration variables:** - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **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 specifying ``align``, it is used as an offset to the calculated position (can also be negative). Ignored if :ref:`lvgl-layouts` are used. -- **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 specifying ``align``, it is used as an offset to the calculated position (can also be negative). Ignored if :ref:`lvgl-layouts` are used. +- **x** (*Optional*, int16 or percentage): Horizontal position of the widget. +- **y** (*Optional*, int16 or percentage): Vertical position of the widget. .. note:: 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. + + If specifying ``align``, it is used as an offset to the calculated position (can also be negative). Ignored if :ref:`lvgl-layouts` are used. -- **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). +- **width** (*Optional*): Width of the widget in pixels or a percentage, or ``SIZE_CONTENT``. +- **height** (*Optional*): Height of the widget in pixels or a percentage, or ``SIZE_CONTENT``. .. note:: From 6bfe6ab7730648e84727b989b8011a46ec30f9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 14:58:45 +0200 Subject: [PATCH 475/564] tip --- components/lvgl.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 38151fdca0..95ab8668b4 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -487,6 +487,10 @@ Values for use with ``grid_column_align``, ``grid_row_align``, ``grid_cell_x_ali - ``SPACE_AROUND``: items are evenly distributed in the track with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. - ``SPACE_BETWEEN``: items are evenly distributed in the track: first item is on the start line, last item on the end line. +.. tip:: + + To visualize real, calculated sizes of transparent widgets you can temporarily set ``outline_width: 1`` on them. + .. _lvgl-widgets: Widgets @@ -513,7 +517,7 @@ The properties below are common to all widgets. 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. - If specifying ``align``, it is used as an offset to the calculated position (can also be negative). Ignored if :ref:`lvgl-layouts` are used. + If specifying ``align``, ``x`` and ``y`` can be used as an offset to the calculated position (can also be negative). They are ignored if :ref:`lvgl-layouts` are used on the parent. - **width** (*Optional*): Width of the widget in pixels or a percentage, or ``SIZE_CONTENT``. - **height** (*Optional*): Height of the widget in pixels or a percentage, or ``SIZE_CONTENT``. From 05863cb7a797fea23362d40d36749c6305390c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 15:51:26 +0200 Subject: [PATCH 476/564] cookbook weather panel --- cookbook/images/lvgl_cook_weather.png | Bin 0 -> 8908 bytes cookbook/lvgl.rst | 294 ++++++++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 cookbook/images/lvgl_cook_weather.png diff --git a/cookbook/images/lvgl_cook_weather.png b/cookbook/images/lvgl_cook_weather.png new file mode 100644 index 0000000000000000000000000000000000000000..5b7e98abb8119434cec632ef2e006996c7d111ca GIT binary patch literal 8908 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 of Home Assistant. + +.. figure:: images/lvgl_cook_weather.png + :align: center + +All the information displayed here could be retrieved to local ``platform: homeassistant`` sensors as desribed in several examples in this Cookbook, however, this time we take a different approach. Instead of pulling the data by ESPHome, we'll be pushing it from Home Assistant, to native :doc:`/components/text/lvgl` components. + +The weather condition icons we use from MDI. We import just the ones corresponding to the weather conditions supported by the Weather integration in Home Assistant. For all the other labels you can use any :ref:`font ` of your choice. + +.. code-block:: yaml + + font: + - file: "fonts/materialdesignicons-webfont.ttf" + id: icons_100 + size: 100 + bpp: 4 + glyphs: [ + "\U000F0594", # clear-night + "\U000F0590", # cloudy + "\U000F0F2F", # exceptional + "\U000F0591", # fog + "\U000F0592", # hail + "\U000F0593", # lightning + "\U000F067E", # lightning-rainy + "\U000F0595", # partlycloudy + "\U000F0596", # pouring + "\U000F0597", # rainy + "\U000F0598", # snowy + "\U000F067F", # snowy-rainy + "\U000F0599", # sunny + "\U000F059D", # windy + "\U000F059E", # windy-variant + "\U000F14E4", # sunny-off + ] + + lvgl: + ... + pages: + - id: weather_forecast + widgets: + - obj: + align: CENTER + width: 228 + height: 250 + pad_all: 10 + pad_column: 0 + layout: + type: GRID + grid_rows: [ FR(48), FR(13), FR(13), FR(13), FR(13) ] + grid_columns: [ FR(7), FR(40), FR(43), FR(10) ] + widgets: + - label: + text: "\U000F14E4" + id: lbl_weather_forecast_condition_icon + text_font: icons_100 + text_align: center + grid_cell_row_pos: 0 + grid_cell_column_pos: 0 + grid_cell_column_span: 2 + grid_cell_x_align: CENTER + grid_cell_y_align: START + + - label: + text: "Unknown" + id: lbl_weather_forecast_condition_name + text_align: CENTER + grid_cell_row_pos: 0 + grid_cell_column_pos: 2 + grid_cell_column_span: 2 + grid_cell_x_align: STRETCH + grid_cell_y_align: CENTER + + - label: + text: "Feels like:" + text_align: left + grid_cell_row_pos: 1 + grid_cell_column_pos: 1 + + - label: + text: "--.- °C" + id: lbl_weather_forecast_tempap + text_align: RIGHT + grid_cell_row_pos: 1 + grid_cell_column_pos: 2 + grid_cell_x_align: STRETCH + + - label: + text: "Maximum:" + grid_cell_row_pos: 2 + grid_cell_column_pos: 1 + + - label: + text: "--.- °C" + id: lbl_weather_forecast_temphi + text_align: RIGHT + grid_cell_row_pos: 2 + grid_cell_column_pos: 2 + grid_cell_x_align: STRETCH + + - label: + text: "Minimum:" + grid_cell_row_pos: 3 + grid_cell_column_pos: 1 + + - label: + text: "--.- °C" + id: lbl_weather_forecast_templo + text_align: RIGHT + grid_cell_row_pos: 3 + grid_cell_column_pos: 2 + grid_cell_x_align: STRETCH + + - label: + text: "Now:" + grid_cell_row_pos: 4 + grid_cell_column_pos: 1 + + - label: + text: "--.- °C" + id: lbl_weather_outdnoor_now + text_align: RIGHT + grid_cell_row_pos: 4 + grid_cell_column_pos: 2 + grid_cell_x_align: STRETCH + + text: + - platform: lvgl + name: fr_cond_icon + widget: lbl_weather_forecast_condition_icon + mode: text + - platform: lvgl + name: fr_cond_name + widget: lbl_weather_forecast_condition_name + mode: text + - platform: lvgl + name: fr_tempap + widget: lbl_weather_forecast_tempap + mode: text + - platform: lvgl + name: fr_temphi + widget: lbl_weather_forecast_temphi + mode: text + - platform: lvgl + name: fr_templo + widget: lbl_weather_forecast_templo + mode: text + - platform: lvgl + name: wd_out_now + widget: lbl_weather_outdnoor_now + mode: text + + binary_sensor: + - platform: status + name: Status sensor + +These labels will appear in Home Assistant as `editable text components `__, which makes it very easy to update them with the ``text.set_value`` service. For this purpose, we add the following `automations `__ to Home Assistant: + +.. code-block:: yaml + + - id: weather_cond_now + alias: 'Weather Forecast Condition' + trigger: + - platform: state + entity_id: sensor.openweathermap_forecast_condition + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + action: + - service: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_cond_icon + data: + value: > + {% set d = { + "clear-night": "\U000F0594", + "cloudy": "\U000F0590", + "exceptional": "\U000F0F2F", + "fog": "\U000F0591", + "hail": "\U000F0592", + "lightning": "\U000F0593", + "lightning-rainy": "\U000F067E", + "partlycloudy": "\U000F0595", + "pouring": "\U000F0596", + "rainy": "\U000F0597", + "snowy": "\U000F0598", + "snowy-rainy": "\U000F067F", + "sunny": "\U000F0599", + "windy": "\U000F059D", + "windy-variant": "\U000F059E", + "unknown": "\U000F14E4", + "unavailable": "\U000F14E4", + } %} + {{ d.get( states('sensor.openweathermap_forecast_condition') ) }} + + - service: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_cond_name + data: + value: > + {% set d = { + "clear-night": "Clear Night", + "cloudy": "Cloudy", + "exceptional": "Except ional", + "fog": "Fog", + "hail": "Hail", + "lightning": "Lightning", + "lightning-rainy": "Lightning rainy", + "partlycloudy": "Partly cloudy", + "pouring": "Pouring", + "rainy": "Rainy", + "snowy": "Snowy", + "snowy-rainy": "Snowy rainy", + "sunny": "Sunny", + "windy": "Windy", + "windy-variant": "Windy cloudy", + "unknown": "Unknown", + "unavailable": "Unavai lable", + } %} + {{ d.get( states('sensor.openweathermap_forecast_condition') ) }} + + - id: weather_temp_feels_like + alias: 'Weather Temperature Feels Like' + trigger: + - platform: state + entity_id: sensor.openweathermap_feels_like_temperature + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + + action: + - service: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_tempap + data: + value: "{{states('sensor.openweathermap_feels_like_temperature') | round(1)}}°C" + + - id: weather_temp_forecast_temphi + alias: 'Weather Temperature Forecast Hi' + trigger: + - platform: state + entity_id: sensor.openweathermap_forecast_temperature + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + action: + - service: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_temphi + data: + value: "{{states('sensor.openweathermap_forecast_temperature') | round(1)}}°C" + + - id: weather_temp_forecast_templo + alias: 'Weather Temperature Forecast Lo' + trigger: + - platform: state + entity_id: sensor.openweathermap_forecast_temperature_low + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + action: + - service: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_templo + data: + value: "{{states('sensor.openweathermap_forecast_temperature_low') | round(1)}}°C" + + - id: weather_temp_forecast_tempnow + alias: 'Weather Temperature Now' + trigger: + - platform: state + entity_id: sensor.kinti_homerseklet + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + action: + - service: text.set_value + target: + entity_id: + - text.your_esphome_node_wd_out_now + data: + value: "{{states('sensor.kinti_homerseklet') | round(1)}}°C" + +The automations will be triggered to update the labels every time the corresponding entities change, and when the ESPHome comes alive - the reason you also need the :doc:`/components/binary_sensor/status`. + .. _lvgl-cook-idlescreen: Turn off screen when idle From 26409a8535422aef5746c48c98a994231bdef7b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 16:02:53 +0200 Subject: [PATCH 477/564] weather tweaks --- cookbook/lvgl.rst | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 12123fe23a..6f0fdd307f 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1804,10 +1804,14 @@ Another example relying on the **Grid** layout can be a weather panel showing th All the information displayed here could be retrieved to local ``platform: homeassistant`` sensors as desribed in several examples in this Cookbook, however, this time we take a different approach. Instead of pulling the data by ESPHome, we'll be pushing it from Home Assistant, to native :doc:`/components/text/lvgl` components. -The weather condition icons we use from MDI. We import just the ones corresponding to the weather conditions supported by the Weather integration in Home Assistant. For all the other labels you can use any :ref:`font ` of your choice. +The weather condition icons we use are from MDI. We import just the ones corresponding to the weather conditions supported by the Weather integration in Home Assistant. For all the other labels you can use any :ref:`font ` of your choice. .. code-block:: yaml + binary_sensor: + - platform: status + name: Status sensor + font: - file: "fonts/materialdesignicons-webfont.ttf" id: icons_100 @@ -1948,15 +1952,11 @@ The weather condition icons we use from MDI. We import just the ones correspondi widget: lbl_weather_outdnoor_now mode: text - binary_sensor: - - platform: status - name: Status sensor - These labels will appear in Home Assistant as `editable text components `__, which makes it very easy to update them with the ``text.set_value`` service. For this purpose, we add the following `automations `__ to Home Assistant: .. code-block:: yaml - - id: weather_cond_now + - id: weather_cond_forecast alias: 'Weather Forecast Condition' trigger: - platform: state @@ -2019,7 +2019,7 @@ These labels will appear in Home Assistant as `editable text components `. .. _lvgl-cook-idlescreen: From afe37c3de441b08058bff8fe78bda68672390634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 16:06:45 +0200 Subject: [PATCH 478/564] Update lvgl_cook_weather.png --- cookbook/images/lvgl_cook_weather.png | Bin 8908 -> 8721 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cookbook/images/lvgl_cook_weather.png b/cookbook/images/lvgl_cook_weather.png index 5b7e98abb8119434cec632ef2e006996c7d111ca..63e5940fcc3e2b3c815771645ff6ca7899eb83be 100644 GIT binary patch literal 8721 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 Bhm!yR literal 8908 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 Date: Wed, 22 May 2024 16:21:47 +0200 Subject: [PATCH 479/564] layout crosslink to the cookbook --- 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 95ab8668b4..5480040b4d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -390,7 +390,7 @@ Layouts aim to position widgets automatically, eliminating the need to specify ` The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. The position and size calculated by the layout overwrites the *normal* ``x``, ``y``, ``width``, and ``height`` settings of the children. -Checkout :ref:`lvgl-cook-flex` and :ref:`lvgl-cook-grid` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. +Checkout :ref:`lvgl-cook-flex`, :ref:`lvgl-cook-grid` and :ref:`lvgl-cook-weather` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` can be used on widgets to ignore them in layout calculations. diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 6f0fdd307f..6012aeb04f 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1849,7 +1849,7 @@ The weather condition icons we use are from MDI. We import just the ones corresp pad_column: 0 layout: type: GRID - grid_rows: [ FR(48), FR(13), FR(13), FR(13), FR(13) ] + grid_rows: [ FR(48), FR(13), FR(13), FR(13), FR(13) ] grid_columns: [ FR(7), FR(40), FR(43), FR(10) ] widgets: - label: From 5a85dac5fa47c585abf7269096b997bc0c261d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 16:48:23 +0200 Subject: [PATCH 480/564] Update lvgl_cook_weather.png --- cookbook/images/lvgl_cook_weather.png | Bin 8721 -> 8350 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cookbook/images/lvgl_cook_weather.png b/cookbook/images/lvgl_cook_weather.png index 63e5940fcc3e2b3c815771645ff6ca7899eb83be..fba8672859a2797b19704fb6773241a8dea25652 100644 GIT binary patch literal 8350 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 literal 8721 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 Bhm!yR From b1972bff2ef8e3243a78d236ce00da0a76819211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 16:48:34 +0200 Subject: [PATCH 481/564] 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 6012aeb04f..cc671cc99f 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1849,8 +1849,8 @@ The weather condition icons we use are from MDI. We import just the ones corresp pad_column: 0 layout: type: GRID - grid_rows: [ FR(48), FR(13), FR(13), FR(13), FR(13) ] - grid_columns: [ FR(7), FR(40), FR(43), FR(10) ] + grid_rows: [FR(48), FR(13), FR(13), FR(13), FR(13)] + grid_columns: [FR(10), FR(40), FR(40), FR(10)] widgets: - label: text: "\U000F14E4" From 765882d02c9e8f8218be279546b46ab8a0487db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 22 May 2024 16:55:13 +0200 Subject: [PATCH 482/564] Update lvgl.rst --- cookbook/lvgl.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index cc671cc99f..94badc62af 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1856,7 +1856,7 @@ The weather condition icons we use are from MDI. We import just the ones corresp text: "\U000F14E4" id: lbl_weather_forecast_condition_icon text_font: icons_100 - text_align: center + text_align: CENTER grid_cell_row_pos: 0 grid_cell_column_pos: 0 grid_cell_column_span: 2 @@ -1875,7 +1875,6 @@ The weather condition icons we use are from MDI. We import just the ones corresp - label: text: "Feels like:" - text_align: left grid_cell_row_pos: 1 grid_cell_column_pos: 1 From b5ce25355aab433ff239707a7cd08ae5a2587705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 23 May 2024 09:40:51 +0200 Subject: [PATCH 483/564] final tweaks --- components/light/lvgl.rst | 3 +- components/lvgl.rst | 173 +++++++++++++++++++------------------- cookbook/lvgl.rst | 15 ++-- 3 files changed, 98 insertions(+), 93 deletions(-) diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 43e688a36e..97f9512190 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -10,8 +10,7 @@ LVGL Light The ``lvgl`` light platform creates a light from an LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widgets are :ref:`lvgl-wgt-led`. A single light supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome light component. - +Supported widget is :ref:`lvgl-wgt-led`. A single light supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome light component. Configuration options: ---------------------- diff --git a/components/lvgl.rst b/components/lvgl.rst index 5480040b4d..16e60e3042 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -16,7 +16,7 @@ In order to be able to drive a :ref:`display ` with LVGL under ESPHo The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should have an :ref:`config-id` configured, which will be referenced by the main LGVL component. -For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred) or a :doc:`/components/sensor/rotary_encoder` can be used. +For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred), a :doc:`/components/sensor/rotary_encoder` or a custom keypad made up from discrete :doc:`Binary Sensors ` 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. @@ -58,7 +58,7 @@ 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. +These are useful with `Home Assistant automations `__ interacting directly with the widgets. Main Configuration ------------------ @@ -101,13 +101,20 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``END`` key. - **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``. Can be disabled with ``never``. - **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``. Can be disabled with ``never``. + + .. tip:: + + When using binary sensors (from physical keys) to interact with LVGL, if there are only 3 keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With 4 or more keys, a keypad configuration suits better. For example a 5-key keypad might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``: ``PREV``/``NEXT`` can select a widget within the group, ``UP``/``DOWN`` changes the value, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. + + The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. + - **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 screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. - **update_interval**: (*Optional*, :ref:`Time `): The interval at which the screen should be redrawn (when 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 LVGL outputs; either ``big_endian`` or ``little_endian``. Defaults to ``big_endian``. - **disp_bg_color** (*Optional*, :ref:`color `): Solid color used to fill the background. Can be changed at runtime with the ``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. +- **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. Also see :ref:`lvgl-wgt-img` for a note regarding supported image formats. - **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 widget's ``styles`` configuration. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. @@ -125,11 +132,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - All other options from :ref:`lvgl-styling` to be applied to all widgets directly. -.. tip:: - When using binary sensors (from physical keys) to interact with LVGL, if there are only 3 keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With 4 or more keys, a keypad configuration suits better. For example a 5-key keypad might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``: ``PREV``/``NEXT`` can select a widget within the group, ``UP``/``DOWN`` changes the value, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. - - The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. **Example:** @@ -150,10 +153,6 @@ The following configuration variables apply to the main ``lvgl`` component, in o See :ref:`lvgl-cook-navigator` in the Cookbook for an example illustrating how to easily implement a page navigation bar at the bottom of the screen. -.. note:: - - 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 @@ -681,7 +680,70 @@ A label is the basic widget type that is used to display text. format: "%.0fdBm" args: [ 'id(wifi_signal_db).get_state()' ] -The ``label`` can be also integrated as :doc:`/components/text/lvgl` or :doc:`/components/text_sensor/lvgl`. +The ``label`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. + +.. _lvgl-wgt-txt: + +``textarea`` +************ + +The Textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. + +.. figure:: /components/images/lvgl_textarea.png + :align: center + +**Configuration variables:** + +- **placeholder_text** (*Optional*, string): A placeholder text can be specified, which is displayed when the Text area is empty. +- **accepted_chars** (*Optional*, string): You can set a list of accepted characters, so other characters will be ignored. +- **one_line** (*Optional*, boolean): The text area can be limited to only allow a single line of text. In this case the height will set automatically to fit only one line, line break characters will be ignored, and word wrap will be disabled. +- **password_mode** (*Optional*, boolean): The text area supports password mode. By default, if the ``•`` (bullet, ``0x2022``) glyph exists in the font, the entered characters are converted to it after some time or when a new character is entered. If ``•`` is missing from the font, ``*`` (asterisk) will be used. +- **max_length** (*Optional*, int): Limit the maximum number of characters to this value. +- any :ref:`Styling ` and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. + +**Actions:** + +``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated on every keystroke. +- ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). + +For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - textarea: + id: textarea_id + one_line: true + placeholder_text: "Enter text here" + + # Example action: + on_...: + then: + - lvgl.textarea.update: + id: textarea_id + text: "Hello World!" + + # Example trigger: + - textarea: + ... + on_value: + then: + - logger.log: + format: "Textarea changed to: %s" + args: [ text.c_str() ] + on_ready: + then: + - logger.log: + format: "Textarea ready: %s" + args: [ text.c_str() ] + +The ``textarea`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. .. _lvgl-wgt-btn: @@ -742,7 +804,7 @@ To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget format: "Button checked state: %d" args: [ x ] -The ``btn`` can be also integrated as a :doc:`/components/binary_sensor/lvgl` or as a :doc:`/components/switch/lvgl`. +The ``btn`` can be also integrated as a :doc:`Binary Sensor ` or as a :doc:`Switch ` component. See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable button to act on a Home Assistant service. @@ -912,7 +974,7 @@ The Switch looks like a little slider and can be used to turn something on and o format: "Switch state: %d" args: [ x ] -The ``switch`` can be also integrated as a :doc:`/components/switch/lvgl`. +The ``switch`` can be also integrated as a :doc:`Switch ` component. See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local component. @@ -971,7 +1033,7 @@ The Checkbox widget is made internally from a *tick box* and a label. When the C format: "Checkbox state: %d" args: [ x ] -The ``checkbox`` can be also integrated as a :doc:`/components/switch/lvgl`. +The ``checkbox`` can be also integrated as a :doc:`Switch ` component. .. _lvgl-wgt-drp: @@ -1044,7 +1106,7 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( format: "Dropdown closed. Selected index is: %d" args: [ x ] -The ``dropdown`` can be also integrated as :doc:`/components/select/lvgl`. +The ``dropdown`` can be also integrated as :doc:`Select ` component. .. _lvgl-wgt-rol: @@ -1104,7 +1166,7 @@ Roller allows you to simply select one option from a list by scrolling. format: "Selected index is: %d" args: [ x ] -The ``roller`` can be also integrated as :doc:`/components/select/lvgl`. +The ``roller`` can be also integrated as :doc:`Select ` component. .. _lvgl-wgt-bar: @@ -1155,7 +1217,7 @@ Not only the end, but also the start value of the bar can be set, which changes id: bar_id value: 55 -The ``bar`` can be also integrated as :doc:`/components/number/lvgl` or :doc:`/components/sensor/lvgl`. +The ``bar`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. .. _lvgl-wgt-sli: @@ -1223,7 +1285,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking The ``on_value`` trigger is sent as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal event 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` or :doc:`/components/sensor/lvgl`. +The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider to control entities in Home Assistant. @@ -1305,7 +1367,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can The ``on_value`` trigger is sent as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using 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` or :doc:`/components/sensor/lvgl`. +The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider (or an arc) to control entities in Home Assistant. @@ -1377,7 +1439,7 @@ The Spinbox contains a numeric value (as text) which can be increased or decreas format: "Spinbox value is %f" args: [ x ] -The ``spinbox`` can be also integrated as :doc:`/components/number/lvgl` or :doc:`/components/sensor/lvgl`. +The ``spinbox`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. See :ref:`lvgl-cook-climate` for an example illustrating how to implement a thermostat control using the spinbox. @@ -1533,6 +1595,10 @@ Images are the basic widgets used to display images. id: img_id src: cat_image_bowtie +.. note:: + + 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-wgt-aim: ``animimg`` @@ -1654,7 +1720,7 @@ The LED widgets are either circular or rectangular widgets whose brightness can id: led_id color: 0x00FF00 -The ``led`` can be also integrated as :doc:`/components/light/lvgl`. +The ``led`` can be also integrated as :doc:`Light ` component. .. note:: @@ -1662,69 +1728,6 @@ The ``led`` can be also integrated as :doc:`/components/light/lvgl`. Check out :ref:`lvgl-cook-keypad` in the Cookbook for an example illustrating how to change the ``led`` styling properties from an automation. -.. _lvgl-wgt-txt: - -``textarea`` -************ - -The Textarea is a widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. - -.. figure:: /components/images/lvgl_textarea.png - :align: center - -**Configuration variables:** - -- **placeholder_text** (*Optional*, string): A placeholder text can be specified, which is displayed when the Text area is empty. -- **accepted_chars** (*Optional*, string): You can set a list of accepted characters, so other characters will be ignored. -- **one_line** (*Optional*, boolean): The text area can be limited to only allow a single line of text. In this case the height will set automatically to fit only one line, line break characters will be ignored, and word wrap will be disabled. -- **password_mode** (*Optional*, boolean): The text area supports password mode. By default, if the ``•`` (bullet, ``0x2022``) glyph exists in the font, the entered characters are converted to it after some time or when a new character is entered. If ``•`` is missing from the font, ``*`` (asterisk) will be used. -- **max_length** (*Optional*, int): Limit the maximum number of characters to this value. -- any :ref:`Styling ` and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. - -**Actions:** - -``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. - -**Triggers:** - -- ``on_value`` :ref:`trigger ` is activated on every keystroke. -- ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). - -For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - textarea: - id: textarea_id - one_line: true - placeholder_text: "Enter text here" - - # Example action: - on_...: - then: - - lvgl.textarea.update: - id: textarea_id - text: "Hello World!" - - # Example trigger: - - textarea: - ... - on_value: - then: - - logger.log: - format: "Textarea changed to: %s" - args: [ text.c_str() ] - on_ready: - then: - - logger.log: - format: "Textarea ready: %s" - args: [ text.c_str() ] - -The ``textarea`` can be also integrated as :doc:`/components/text/lvgl` or :doc:`/components/text_sensor/lvgl`. - .. _lvgl-wgt-spi: ``spinner`` diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 94badc62af..10a2dbd9d2 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -451,6 +451,9 @@ If you change the size of the widget, to obtain a uniform gradient, be sure to i align: CENTER y: -6 +.. tip:: + + You can omit the ``obj`` used to hide the middle part of meter indicator line by using a bitmap ``img`` indicator as needle, were only the part hanging above the ticks scale is visible, the rest is transparent. .. _lvgl-cook-climate: @@ -1170,7 +1173,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width align: CENTER text: "\U000F0045" -The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. With ``STRETCH`` their sizes and positions will automatically be calculated to fill in the cells, while the parent's ``pad_all``, ``pad_row`` and ``pad_column`` can help with spacing between them. +The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. With ``STRETCH`` their sizes and positions will automatically be calculated to fill in the cells, while the parent's ``pad_all``, ``pad_row`` and ``pad_column`` can help with spacing between them. See :ref:`lvgl-cook-weather` further down this page for another example relying on **Grid**. .. _lvgl-cook-btlg: @@ -1235,7 +1238,7 @@ MDI icons in text ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your text. This is very flexible because you can prepare various sets of fonts at different sizes each with a different number of glyphs; this is important as it may help to conserve flash memory space. -One example is when you'd like some MDI icons to be used in line with the text (similar to 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. +One example is when you'd like some MDI icons to be used in line with the text (similar to how LVGL's internal fonts and symbols coexist). You can use a font of your choice; choose the symbols/icons from MDI you want and mix them in a single sized set. .. figure:: images/lvgl_cook_font_roboto_mdi.png :align: center @@ -2032,7 +2035,7 @@ These labels will appear in Home Assistant as `editable text components `. From de21933c89db6d56e98aafb9331358eb526224c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 23 May 2024 09:56:50 +0200 Subject: [PATCH 484/564] Update lvgl_cook_weather.png --- cookbook/images/lvgl_cook_weather.png | Bin 8350 -> 8364 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cookbook/images/lvgl_cook_weather.png b/cookbook/images/lvgl_cook_weather.png index fba8672859a2797b19704fb6773241a8dea25652..52bdc94f15cb44edc5541f03f4fabdc270f22340 100644 GIT binary patch literal 8364 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 Rq5m+zP?A%VEdd$_{x1_sDER;Y literal 8350 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 From 24611f21e80e000fcd4192f5dbe498f4de1da1c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 23 May 2024 10:05:27 +0200 Subject: [PATCH 485/564] inclusion in automations guide list --- components/lvgl.rst | 2 ++ guides/automations.rst | 3 +++ 2 files changed, 5 insertions(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 16e60e3042..899655be49 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -2223,6 +2223,8 @@ This :ref:`action ` shows a specific page (including pages with t then: - lvgl.page.show: secret_page # shorthand version +.. _lvgl-cond: + Conditions ---------- diff --git a/guides/automations.rst b/guides/automations.rst index 5dabced224..6603898777 100644 --- a/guides/automations.rst +++ b/guides/automations.rst @@ -351,6 +351,7 @@ All Triggers - :ref:`cover.on_open ` / :ref:`cover.on_closed ` - :ref:`safe_mode.on_safe_mode ` - :ref:`wifi.on_connect / wifi.on_disconnect ` +- :ref:`LVGL event triggers ` All Actions ----------- @@ -412,6 +413,7 @@ All Actions / :ref:`media_player.volume_up ` / :ref:`media_player.volume_down ` / :ref:`media_player.volume_set ` - :ref:`ble_client.ble_write ` - :ref:`wireguard.disable ` / :ref:`wireguard.enable ` +- :ref:`LVGL universal actions ` .. _config-condition: @@ -435,6 +437,7 @@ All Conditions - :ref:`number.in_range ` - :ref:`fan.is_on ` / :ref:`fan.is_off ` - :ref:`wireguard.enabled ` / :ref:`wireguard.peer_online ` +- :ref:`LVGL conditions ` All Lambda Calls ---------------- From 41caf1238439898f82d4e2de2412325cf903d963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 23 May 2024 18:15:31 +0200 Subject: [PATCH 486/564] 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 899655be49..800e84a382 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -75,16 +75,16 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **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. May be omitted if a rotary encoder or a keypad is configured. - **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``. + - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, 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, 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. May be omitted if a touchscreen or keypad is configured. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. - - **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``. Can be disabled with ``never``. - - **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``. Can be disabled with ``never``. + - **long_press_time** (*Optional*, :ref:`Time `): For the rotary encoder, delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the rotary encoder, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. - **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. May be omitted if a touchscreen or a rotary encoder is configured. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``UP`` key. @@ -99,8 +99,8 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``PREV`` key. - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``HOME`` key. - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``END`` key. - - **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``. Can be disabled with ``never``. - - **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``. Can be disabled with ``never``. + - **long_press_time** (*Optional*, :ref:`Time `): For the keypad, delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the keypad, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. .. tip:: From ea9e1d3e8da351ccb34c29e07500930df3571b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 24 May 2024 09:55:34 +0200 Subject: [PATCH 487/564] how to fix the missing checkmark with other font as default --- components/lvgl.rst | 42 +++++++++++++++++++++++------------------- cookbook/lvgl.rst | 30 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 800e84a382..8a17e38a54 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -108,14 +108,14 @@ The following configuration variables apply to the main ``lvgl`` component, in o The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. -- **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``. +- **color_depth** (*Optional*, string): 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 screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. - **update_interval**: (*Optional*, :ref:`Time `): The interval at which the screen should be redrawn (when 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 LVGL outputs; either ``big_endian`` or ``little_endian``. Defaults to ``big_endian``. +- **log_level** (*Optional*, string): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. +- **byte_order** (*Optional*, int16): The byte order of the data LVGL outputs; either ``big_endian`` or ``little_endian``. Defaults to ``big_endian``. - **disp_bg_color** (*Optional*, :ref:`color `): Solid color used to fill the background. Can be changed at runtime with the ``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. Also see :ref:`lvgl-wgt-img` for a note regarding supported image formats. -- **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*, ID): 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 widget's ``styles`` configuration. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. May not be used if ``pages`` (below) is configured. @@ -182,7 +182,7 @@ Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-co **Library fonts** -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: +The LVGL library offers by default prerendered sets with ASCII characters (``0x20-0x7F``), the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from `Montserrat Medium `__, and 60 symbols from `FontAwesome `__ (see below). You can use the IDs below when specifying the ``text_font`` parameter: - ``montserrat_8``: 8px font - ``montserrat_10``: 10px font @@ -248,8 +248,8 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **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 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_dither_mode** (*Optional*, dict): Set dithering of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. Defaults to ``NONE``. +- **bg_grad_dir** (*Optional*, dict): 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`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``0``. - **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``255``. - **opa** (*Optional*, :ref:`opacity `): Opacity of the entire widget. Inherited from parent. Defaults to ``COVER``. @@ -395,7 +395,7 @@ The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``). - **pressed** (*Optional*, boolean): Being pressed. @@ -625,7 +625,7 @@ A label is the basic widget type that is used to display text. **Configuration variables:** - **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_align** (*Optional*, dict): 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 as YAML list). 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. @@ -1033,6 +1033,10 @@ The Checkbox widget is made internally from a *tick box* and a label. When the C format: "Checkbox state: %d" args: [ x ] +.. note:: + + In case you configure ``default_font`` in the main section to a custom font, the checkmark will not be shown correctly when the checkbox is in the checked state. See :ref:`lvgl-cook-ckboxmark` how to easily resolve this. + The ``checkbox`` can be also integrated as a :doc:`Switch ` component. .. _lvgl-wgt-drp: @@ -1052,9 +1056,9 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( **Configuration variables:** - **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``. +- **dir** (*Optional*, dict): 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 those built-in or from your own customized font. +- **symbol** (*Optional*, dict): 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 those built-in or from your own customized font. - **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. @@ -1121,7 +1125,7 @@ Roller allows you to simply select one option from a list by scrolling. **Configuration variables:** - **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``. +- **mode** (*Optional*, dict): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. - **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. @@ -1950,13 +1954,13 @@ The text will be broken into multiple lines automatically and the height will be **Configuration variables:** -- **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. +- **msgboxes** (*Optional*, dict): 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 message box. - - **body** (**Required**, enum): The content of the body of the message box: + - **body** (**Required**, dict): The content of the 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**, dict): A list of buttons to show at the bottom of the message box: - **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display on the button. **Actions:** @@ -2005,7 +2009,7 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bm **Configuration variables:** - **textarea** (*Optional*): The ID of the ``textarea`` from which to receive the keystrokes. -- **mode** (*Optional*, enum): Keyboard layout to use. Each ``TEXT_`` layout contains a button to allow the user to iterate through the ``TEXT_`` layouts. +- **mode** (*Optional*, dict): Keyboard layout to use. Each ``TEXT_`` layout contains a button to allow the user to iterate through the ``TEXT_`` layouts. - ``TEXT_LOWER``: Display lower case letters (default). - ``TEXT_UPPER``: Display upper case letters. - ``TEXT_SPECIAL``: Display special characters. diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 10a2dbd9d2..025283e033 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1279,6 +1279,36 @@ In the example below, we use the default set of glyphs from RobotoCondensed-Regu - 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-ckboxmark: + +Restore checkbox mark +--------------------- + +In case you configure the ``default_font`` used by LVGL to a custom one, which doesn't contain the `FontAwesome `__ symbols, you'll run into the issue that some widgets don't display correctly; specifically :ref:`lvgl-wgt-chk` won't show the checkmark when it's checked. + +This issue can be easily worked around by importing only the ckeckmark symbol in the desired size, and applying it through :ref:`lvgl-cook-theme` to all the checkboxes in the configuration: + +.. code-block:: yaml + + font: + - file: 'fonts/FontAwesome5-Solid+Brands+Regular.woff' + id: fontawesome_checkmark + size: 18 + bpp: 4 + glyphs: [ + "\uF00C", # ckeckmark, for checkbox + ] + + lvgl: + ... + theme: + checkbox: + indicator: + checked: + text_font: fontawesome_checkmark + +You could of course simply apply one of the built-in ``montserrat_`` packs, but that would not be beneficial on the binary size - it would uselessly include the entire set of glyphs in the flash. + .. _lvgl-cook-iconstat: Toggle state icon button From 65bf3682437926ad8584a81fa94074e202e3f95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 24 May 2024 22:11:18 +0200 Subject: [PATCH 488/564] notes based on feedback received on Discord --- components/lvgl.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 8a17e38a54..787718cfd9 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -12,7 +12,7 @@ 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 :ref:`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 for bigger displays. The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should have an :ref:`config-id` configured, which will be referenced by the main LGVL component. @@ -178,6 +178,10 @@ Two font choices are available: 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. +.. tip:: + + For best results, set ``bpp: 4`` to get the glyphs rendered with proper anti-aliasing. + Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples illustrating how to use icons and text with TrueType/OpenType fonts. **Library fonts** From faf9c477be1eb571642ad83de61cd9f2a594cc44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sat, 25 May 2024 10:30:48 +0200 Subject: [PATCH 489/564] 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 787718cfd9..4e78e5b96e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -462,8 +462,8 @@ It can arrange items into a 2D "table" that has rows or columns (tracks). The it - **grid_rows** (**Required**): The number of rows in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional integer value). - **grid_columns** (**Required**): The number of columns in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional integer value). - - **grid_column_align** (*Optional*, string): How to align the widgets within the column. Possible options below. - - **grid_row_align** (*Optional*, string): How to align the widgets within the row. Possible options below. + - **grid_row_align** (*Optional*, string): How to align the row. Works only when ``grid_rows`` is given in pixels. Possible options below. + - **grid_column_align** (*Optional*, string): How to align the column. Works only when ``grid_columns`` is given in pixels. Possible options below. - **pad_row** (*Optional*, int16): Set the padding between the rows, in pixels. - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. From 9d33a4201d75221e2730c60733cfac1f470d8dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 26 May 2024 14:36:45 +0200 Subject: [PATCH 490/564] color_depth correction --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4e78e5b96e..7a6831f2bb 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -108,7 +108,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. -- **color_depth** (*Optional*, string): The color deph at which the contents are generated. Valid values are ``1`` (monochrome), ``8``, ``16`` or ``32``, defaults to ``16``. +- **color_depth** (*Optional*, string): The color deph at which the contents are generated. Currently only ``16`` is supported (RGB565, 2 bytes/pixel), which is the default value. - **buffer_size** (*Optional*, percentage): The percentage of screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. - **update_interval**: (*Optional*, :ref:`Time `): The interval at which the screen should be redrawn (when necessary). Defaults to ``1s``. - **log_level** (*Optional*, string): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. From 284a3467a2dbf9c6b30597fc23507b41cf6593ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 30 May 2024 10:45:31 +0200 Subject: [PATCH 491/564] Update lvgl.rst --- cookbook/lvgl.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 025283e033..9e38dc33b8 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1984,6 +1984,8 @@ The weather condition icons we use are from MDI. We import just the ones corresp widget: lbl_weather_outdnoor_now mode: text +If you look carefully at the ``grid_columns`` variable, you'll notice that there are two thinner columns at left and right (``FR(10)``). Reason is to add some space to the labels from the edges. And that's why we had to use ``grid_cell_column_span`` for the widgets in the first row, to take up the space of multiple columns. + These labels will appear in Home Assistant as `editable text components `__, which makes it very easy to update them with the ``text.set_value`` service. For this purpose, we add the following `automations `__ to Home Assistant: .. code-block:: yaml From 44f9cab022c9b2ecc5b783031e890f1a88d603ea Mon Sep 17 00:00:00 2001 From: clydebarrow <2366188+clydebarrow@users.noreply.github.com> Date: Fri, 31 May 2024 12:43:56 +1000 Subject: [PATCH 492/564] Cleaned up some config option descriptions. --- components/lvgl.rst | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7a6831f2bb..c9456bcb06 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -14,7 +14,7 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t 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 for bigger displays. -The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. It should have an :ref:`config-id` configured, which will be referenced by the main LGVL component. +The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred), a :doc:`/components/sensor/rotary_encoder` or a custom keypad made up from discrete :doc:`Binary Sensors ` can be used. @@ -71,13 +71,13 @@ The following configuration variables apply to the main ``lvgl`` component, in o **Configuration variables:** -- **displays** (**Required**, list): A list of displays where LVGL should perform rendering based on its configuration: +- **displays** (**Required**, list): A list of displays where LVGL should perform rendering based on its configuration. This may be omitted if there is a single display configured, which will be used automatically. - **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. May be omitted if a rotary encoder or a keypad is configured. +- **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a display. - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, 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, 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. May be omitted if a touchscreen or keypad is configured. +- **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: @@ -85,7 +85,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. - **long_press_time** (*Optional*, :ref:`Time `): For the rotary encoder, delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the rotary encoder, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. -- **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. May be omitted if a touchscreen or a rotary encoder is configured. +- **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``UP`` key. - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``DOWN`` key. @@ -110,7 +110,6 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **color_depth** (*Optional*, string): The color deph at which the contents are generated. Currently only ``16`` is supported (RGB565, 2 bytes/pixel), which is the default value. - **buffer_size** (*Optional*, percentage): The percentage of screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. -- **update_interval**: (*Optional*, :ref:`Time `): The interval at which the screen should be redrawn (when necessary). Defaults to ``1s``. - **log_level** (*Optional*, string): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, int16): The byte order of the data LVGL outputs; either ``big_endian`` or ``little_endian``. Defaults to ``big_endian``. - **disp_bg_color** (*Optional*, :ref:`color `): Solid color used to fill the background. Can be changed at runtime with the ``lvgl.update`` action. @@ -124,8 +123,8 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. - All other options from :ref:`lvgl-styling` to be applied to this page. -- **page_wrap** (*Optional*, boolean): Wrap pages around when navigating between them with :ref:`lvgl-pgnx-act`. Defaults to ``true``. -- **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, which may be useful for widgets which always need to be visible. May not be used with ``widgets`` (above). Options: +- **page_wrap** (*Optional*, boolean): Wrap from the last to the first page when navigating between them with :ref:`lvgl-pgnx-act`. Defaults to ``true``. +- **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, which may be useful for widgets which always need to be visible. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. - All other options from :ref:`lvgl-styling` to be applied to this page. @@ -141,9 +140,9 @@ The following configuration variables apply to the main ``lvgl`` component, in o # Example configuration entry lvgl: displays: - - display_id: my_display + - my_display touchscreens: - - touchscreen_id: my_touch + - my_touch pages: - id: main_page widgets: From f92e0a1838b226a485eef7ac4dd948cc7820b43b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 3 Jun 2024 09:36:07 +0200 Subject: [PATCH 493/564] Update lvgl.rst --- components/lvgl.rst | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c9456bcb06..27015b25e8 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -690,7 +690,7 @@ The ``label`` can be also integrated as :doc:`Text ` or : ``textarea`` ************ -The Textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the Text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. +The textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. .. figure:: /components/images/lvgl_textarea.png :align: center @@ -753,7 +753,7 @@ The ``textarea`` can be also integrated as :doc:`Text ` o ``btn`` ******* -Simple push or toggle button. +Simple push (momentary) or toggle (two-states) button. .. figure:: /components/images/lvgl_button.png :align: center @@ -816,7 +816,7 @@ See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable b ``btnmatrix`` ************* -The Button Matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. +The button matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. .. figure:: /components/images/lvgl_btnmatrix.png :align: center @@ -943,7 +943,7 @@ The Button Matrix widget is a lightweight way to display multiple buttons in row ``switch`` ********** -The Switch looks like a little slider and can be used to turn something on and off. +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 @@ -951,7 +951,7 @@ The Switch looks like a little slider and can be used to turn something on and o **Configuration variables:** - **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. +- **indicator** (*Optional*, list): Settings for the indicator *part*, the foreground area underneath the knob shown when the switch is in ``checked`` state. Supports a list of :ref:`styles ` and state-based styles to customize. - Style options from :ref:`lvgl-styling`. **Triggers:** @@ -986,7 +986,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's ``checked`` state will be 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 @@ -1047,7 +1047,7 @@ The ``checkbox`` can be also integrated as a :doc:`Switch ` ``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. +The bar widget has a background and an indicator foreground 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 @@ -1231,7 +1231,7 @@ The ``bar`` can be also integrated as :doc:`Number ` or ``slider`` ********** -The Slider widget looks like a bar supplemented with a knob. The user can drag the knob 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 user can drag the knob to set a value. Just like bar, slider can be vertical or horizontal. The size of the indicator foreground and the knob position is set according to the current ``value`` of the slider. .. figure:: /components/images/lvgl_slider.png :align: center @@ -1301,7 +1301,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustratin ``arc`` ******* -The Arc consists of a background and a foreground arc. The foreground (indicator) can be touch-adjusted with a knob. +The arc consists of a background and a foreground arc. The indicator foreground can be touch-adjusted with a knob. .. figure:: /components/images/lvgl_arc.png :align: center @@ -1383,7 +1383,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustratin ``spinbox`` *********** -The Spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. +The spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. .. figure:: /components/images/lvgl_spinbox.png :align: center @@ -1455,7 +1455,7 @@ See :ref:`lvgl-cook-climate` for an example illustrating how to implement a ther ``meter`` ********* -The Meter widget can visualize data in very flexible ways. It can use arcs, needles, ticks, lines and/or labels. +The meter widget can visualize data in very flexible ways. It can use arcs, needles, ticks, lines and/or labels. .. figure:: /components/images/lvgl_meter.png :align: center @@ -1656,7 +1656,7 @@ See :ref:`lvgl-cook-animbatt` in the Cookbook for a more detailed example. ``line`` ******** -The Line widget 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. .. figure:: /components/images/lvgl_line.png :align: center @@ -1784,7 +1784,7 @@ The Spinner widget is a spinning arc over a ring. ``obj`` ******* -The Base Object is just a simple, empty widget. By default, it's 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 @@ -1813,7 +1813,7 @@ You can use it as a parent container for other widgets. By default, it catches t ``tabview`` *********** -The Tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-wgt-bmx`. +The tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-wgt-bmx`. .. figure:: /components/images/lvgl_tabview.png :align: center @@ -1948,7 +1948,7 @@ If the Tile view is screen sized, the user interface resembles what you may have ``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. +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 @@ -2002,7 +2002,7 @@ The configured message boxes are hidden by default. One can show them with ``lvg ``keyboard`` ************ -The Keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-wgt-txt`. +The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-wgt-txt`. .. figure:: /components/images/lvgl_keyboard.png :align: center From 7ee1787ec1dd17a4c48d8e713f6e1d67a5b9de12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 3 Jun 2024 21:00:20 +0200 Subject: [PATCH 494/564] fix typos in lvgl platforms --- components/select/lvgl.rst | 2 +- components/text_sensor/lvgl.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index c0ddac6077..6690a31427 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -7,7 +7,7 @@ LVGL Select :description: Instructions for setting up an LVGL widget select. :image: ../images/lvgl_c_sel.png -The ``lvgl`` switch platform creates a select from an LVGL widget +The ``lvgl`` select platform creates a select from an 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 only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome select component. diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index 2953dcccba..0bde3b9a3f 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -7,7 +7,7 @@ LVGL Text Sensor :description: Instructions for setting up an LVGL Text Sensor. :image: ../images/lvgl_c_txt.png -The ``lvgl`` text platform creates a Text Sensor from an LVGL textual widget +The ``lvgl`` text sensor platform creates a Text Sensor from an LVGL textual widget and requires :ref:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-wgt-lbl` and :ref:`lvgl-wgt-txt`. A single text sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text sensor component. From 2b2724ab360dfeded00cd6f81b81f1950d692bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 10 Jun 2024 16:32:49 +0200 Subject: [PATCH 495/564] use new logos in boot screen --- cookbook/lvgl.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 9e38dc33b8..2c02885b07 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1191,10 +1191,11 @@ To display a boot image with a spinner animation which disappears automatically - lvgl.widget.hide: boot_screen image: - - file: https://esphome.io/_images/logo.png + - file: https://esphome.io/_static/favicon-512x512.png id: boot_logo resize: 200x200 type: RGB565 + use_transparency: true lvgl: ... @@ -1207,7 +1208,7 @@ To display a boot image with a spinner animation which disappears automatically y: 0 width: 100% height: 100% - bg_color: 0xFFFFFF + bg_color: 0xffffff bg_opa: COVER radius: 0 pad_all: 0 @@ -1226,7 +1227,7 @@ To display a boot image with a spinner animation which disappears automatically arc_length: 60deg arc_width: 8 indicator: - arc_color: 0x404040 + arc_color: 0x18bcf2 arc_width: 8 on_press: - lvgl.widget.hide: boot_screen From 096a1d4d13e9c1595a48c1679bb277566b38535d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 17 Jun 2024 19:32:15 +0200 Subject: [PATCH 496/564] Update automations.rst --- guides/automations.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/guides/automations.rst b/guides/automations.rst index 6603898777..5dabced224 100644 --- a/guides/automations.rst +++ b/guides/automations.rst @@ -351,7 +351,6 @@ All Triggers - :ref:`cover.on_open ` / :ref:`cover.on_closed ` - :ref:`safe_mode.on_safe_mode ` - :ref:`wifi.on_connect / wifi.on_disconnect ` -- :ref:`LVGL event triggers ` All Actions ----------- @@ -413,7 +412,6 @@ All Actions / :ref:`media_player.volume_up ` / :ref:`media_player.volume_down ` / :ref:`media_player.volume_set ` - :ref:`ble_client.ble_write ` - :ref:`wireguard.disable ` / :ref:`wireguard.enable ` -- :ref:`LVGL universal actions ` .. _config-condition: @@ -437,7 +435,6 @@ All Conditions - :ref:`number.in_range ` - :ref:`fan.is_on ` / :ref:`fan.is_off ` - :ref:`wireguard.enabled ` / :ref:`wireguard.peer_online ` -- :ref:`LVGL conditions ` All Lambda Calls ---------------- From 328da5fde7a4abc71a665685a986d986bb824db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 20 Jun 2024 11:04:04 +0200 Subject: [PATCH 497/564] Clarify some `img` settings --- components/lvgl.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 27015b25e8..8f6b8c7150 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1570,13 +1570,14 @@ Images are the basic widgets used to display images. **Configuration variables:** - **src** (**Required**, :ref:`image `): The ID of an existing image configuration. -- **angle** (*Optional*, 0-360): Rotation of the image. Defaults to ``0.0``. +- **offset_x** (*Optional*): Add a horrizontal offset to the image position. +- **offset_y** (*Optional*): Add a vertical offset to the image position. - **zoom** (*Optional*, 0.1-10): Zoom of the image. -- **pivot_x** (*Optional*): 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** (*Optional*): Vertical position of the pivot point of rotation relative to the top left corner of the image.. Defaults to ``50%`` (center of image). +- **angle** (*Optional*, 0-360): Rotation of the image. Defaults to ``0.0``. Needs ``pivot_x`` and ``pivot_y`` to be specified. +- **pivot_x** (*Optional*): Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. +- **pivot_y** (*Optional*): Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. - **antialias** (*Optional*): The quality of the angle or zoom transformation. When anti-aliasing is enabled, the transformations are higher quality but slower. Defaults to ``false``. - **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is zoomed or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``SIZE_CONTENT``, the object's size will be set to the zoomed and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. -- **offset_x**, **offset_y** (*Optional*): Add an offset to the displayed image. Useful if the widget size is smaller than the image source size. Tip: a *running image* effect can be created by animating these values. - 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. **Actions:** @@ -1606,6 +1607,9 @@ Images are the basic widgets used to display images. 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. +.. tip:: + ``offset_x`` and ``offset_y`` can be useful when the widget size is set to be smaller than the image source size. A "running image" effect can be created by animating these values. + .. _lvgl-wgt-aim: ``animimg`` From d014f03573afdcf67aa59714de4f8e42152d3624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 20 Jun 2024 11:09:22 +0200 Subject: [PATCH 498/564] pivots are in pixels --- components/lvgl.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 8f6b8c7150..9bb76f6004 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -293,8 +293,8 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **shadow_width** (*Optional*, int16): Width of the shadow, in pixels. Defaults to ``0``. - **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_pivot_x** (*Optional*, int16): Horizontal anchor point of the transformation. Relative to the widget's top left corner. +- **transform_pivot_y** (*Optional*, int16): Vertical anchor point of the transformation. Relative to the widget's top left corner. - **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. @@ -1504,8 +1504,8 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need - **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, 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). + - **pivot_x**: Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. + - **pivot_y**: Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. - **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. From 9483616b75121d0dd2d0b2aa75335afe1c46f10e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Thu, 20 Jun 2024 11:16:22 +0200 Subject: [PATCH 499/564] Update lvgl.rst --- components/lvgl.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9bb76f6004..a3491565db 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1608,6 +1608,7 @@ Images are the basic widgets used to display images. 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. .. tip:: + ``offset_x`` and ``offset_y`` can be useful when the widget size is set to be smaller than the image source size. A "running image" effect can be created by animating these values. .. _lvgl-wgt-aim: From e7c60a12492cb97073dbe99c3c314e4a7c49a446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 28 Jun 2024 13:24:06 +0200 Subject: [PATCH 500/564] update automation hyperlinks --- components/lvgl.rst | 98 ++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index a3491565db..e37f8be3be 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -652,7 +652,7 @@ A label is the basic widget type that is used to display text. **Actions:** -- ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :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. @@ -706,12 +706,12 @@ The textarea is an extended label widget which displays a cursor and allows the **Actions:** -``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. +``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated on every keystroke. -- ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). +- ``on_value`` :ref:`trigger ` is activated on every keystroke. +- ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. @@ -767,7 +767,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied **Triggers:** -- ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. +- ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. **Example:** @@ -847,8 +847,8 @@ The button matrix widget is a lightweight way to display multiple buttons in row **Actions:** -- ``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 item styles and properties specified in the specific ``state``, ``items`` options. +- ``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 item styles and properties specified in the specific ``state``, ``items`` options. **Triggers:** @@ -956,7 +956,7 @@ The switch looks like a little slider and can be used to turn something on and o **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. +- ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. **Example:** @@ -998,14 +998,14 @@ The checkbox widget is made internally from a *tick box* and a label. When the c **Actions:** -- ``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :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. **Triggers:** -``on_value`` :ref:`trigger ` is activated when toggling the checkbox. The boolean variable ``x``, representing the checkbox's state, may be used by lambdas within this trigger. +``on_value`` :ref:`trigger ` is activated when toggling the checkbox. The boolean variable ``x``, representing the checkbox's state, may be used by lambdas within this trigger. **Example:** @@ -1070,12 +1070,12 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( **Actions:** -- ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. -- ``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. +- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. +- ``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. **Example:** @@ -1137,11 +1137,11 @@ Roller allows you to simply select one option from a list by scrolling. **Actions:** -- ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. +- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. **Example:** @@ -1202,7 +1202,7 @@ Not only the end, but also the start value of the bar can be set, which changes **Actions:** -- ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +- ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1251,11 +1251,11 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking **Actions:** -- ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. 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``. +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. 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:** @@ -1333,11 +1333,11 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can **Actions:** -- ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **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``. +- ``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:** @@ -1405,13 +1405,13 @@ The spinbox contains a numeric value (as text) which can be increased or decreas **Actions:** -- ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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. +- ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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. **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``. +- ``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:** @@ -1515,7 +1515,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need **Actions:** -- ``lvgl.indicator.update`` :ref:`action ` updates indicator options, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` cannot be updated at runtime. +- ``lvgl.indicator.update`` :ref:`action ` updates indicator options, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` cannot be updated at runtime. **Example:** @@ -1582,7 +1582,7 @@ Images are the basic widgets used to display images. **Actions:** -- ``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. +- ``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. **Example:** @@ -1631,9 +1631,9 @@ The animation image is similar to the normal ``img`` widget. The main difference **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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. +- ``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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. **Example:** @@ -1712,7 +1712,7 @@ The LED widgets are either circular or rectangular widgets whose brightness can **Actions:** -- ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1762,7 +1762,7 @@ The Spinner widget is a spinning arc over a ring. **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 widgets), just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Example:** @@ -1836,14 +1836,14 @@ A new tab can be selected either by clicking on a tab button or by sliding horiz **Actions:** -- ``lvgl.tabview.select`` :ref:`action ` jumps the view to the desired tab: +- ``lvgl.tabview.select`` :ref:`action ` jumps the view to the desired tab: - **id** (**Required**): The ID of the ``tabview`` which receives this action. - **tab_id** (*Optional*): The ID of the tab to which to jump. - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when displayed tab changes. The new value is returned in the variable ``tab`` as the ID of the now-visible tab. +- ``on_value`` :ref:`trigger ` is activated when displayed tab changes. The new value is returned in the variable ``tab`` as the ID of the now-visible tab. **Example:** @@ -1901,7 +1901,7 @@ If the Tile view is screen sized, the user interface resembles what you may have **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 the tileview) to which to jump. Required if not specifying ``row`` and ``column``. - **row** (*Optional*): Horizontal position of the tile to which to jump. Required if not specifying ``tile_id``. @@ -1910,7 +1910,7 @@ If the Tile view is screen sized, the user interface resembles what you may have **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 now-visible 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 now-visible tile. **Example:** @@ -2025,12 +2025,12 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bm **Actions:** -- ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +- ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. **Triggers:** -- ``on_ready`` :ref:`trigger ` is activated when the checkmark key is pressed. -- ``on_cancel`` :ref:`trigger ` is activated when the key containing the keyboard icon is pressed. +- ``on_ready`` :ref:`trigger ` is activated when the checkmark key is pressed. +- ``on_cancel`` :ref:`trigger ` is activated when the key containing the keyboard icon is pressed. **Example:** @@ -2079,7 +2079,7 @@ Several universal actions are also available for all widgets and/or for LVGL its ``lvgl.widget.update`` ********************** -This powerful :ref:`action ` allows changing/updating any widget's common :ref:`style property `, state (templatable) or :ref:`flag ` on the fly. +This powerful :ref:`action ` allows changing/updating any widget's common :ref:`style property `, state (templatable) or :ref:`flag ` on the fly. .. code-block:: yaml @@ -2106,7 +2106,7 @@ Check out in the Cookbook :ref:`lvgl-cook-binent` for an example illustrating ho ``lvgl.widget.hide``, ``lvgl.widget.show`` ****************************************** -These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget: +These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget: .. code-block:: yaml @@ -2119,7 +2119,7 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` ``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): +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 @@ -2135,7 +2135,7 @@ These :ref:`actions ` are shorthands for toggling the ``disabled` ``lvgl.widget.redraw`` ********************** -This :ref:`action ` redraws the entire screen, or optionally only a widget on it. +This :ref:`action ` redraws the entire screen, or optionally only a widget on it. - **id** (*Optional*): The ID of a widget configured in LVGL which you want to redraw; if omitted, the entire screen will be redrawn. @@ -2150,7 +2150,7 @@ This :ref:`action ` redraws the entire screen, or optionally only ``lvgl.pause`` ************** -This :ref:`action ` pauses the activity of LVGL, including rendering. +This :ref:`action ` pauses the activity of LVGL, including rendering. - **show_snow** (*Optional*, boolean): When 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 illustrating how to use this. @@ -2166,7 +2166,7 @@ This :ref:`action ` pauses the activity of LVGL, including render ``lvgl.resume`` *************** -This :ref:`action ` resumes the activity of LVGL, including rendering. +This :ref:`action ` resumes the activity of LVGL, including rendering. .. code-block:: yaml @@ -2177,7 +2177,7 @@ This :ref:`action ` resumes the activity of LVGL, including rende ``lvgl.update`` *************** -This :ref:`action ` allows changing/updating the ``disp_bg_color`` or ``disp_bg_image`` configuration variables of the main component, making it possible to change the background color or wallpaper at any time. +This :ref:`action ` allows changing/updating the ``disp_bg_color`` or ``disp_bg_image`` configuration variables of the main component, making it possible to change the background color or wallpaper at any time. .. code-block:: yaml @@ -2194,7 +2194,7 @@ This :ref:`action ` allows changing/updating the ``disp_bg_color` ``lvgl.page.next``, ``lvgl.page.previous`` ****************************************** -This :ref:`action ` changes the page to the next/previous based on the configuration (pages with their ``skip`` option enabled are...skipped). Page changes will wrap around at the end. +This :ref:`action ` changes the page to the next/previous based on the configuration (pages with their ``skip`` option enabled are...skipped). Page changes will wrap around at the end. - **animation** (*Optional*): Animate page changes as specified. One of: ``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``. - **time** (*Optional*, :ref:`Time `): Duration of the page change animation. Defaults to ``50ms``. @@ -2218,7 +2218,7 @@ This :ref:`action ` changes the page to the next/previous based o ``lvgl.page.show`` ****************** -This :ref:`action ` shows a specific page (including pages with their ``skip`` option enabled). +This :ref:`action ` shows a specific page (including pages with their ``skip`` option enabled). - **id** (**Required**): The ID of the page to be shown. - **animation** (*Optional*): Animate page changes as specified. One of: ``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``. @@ -2245,7 +2245,7 @@ Conditions ``lvgl.is_idle`` **************** -This :ref:`condition ` checks if the amount of time specified has passed since the last touch event. +This :ref:`condition ` checks if the amount of time specified has passed since the last touch event. - **timeout** (**Required**, :ref:`templatable `, int): Amount of :ref:`time ` expected since the last touch event. @@ -2267,7 +2267,7 @@ This :ref:`condition ` checks if the amount of time specified ``lvgl.is_paused`` ****************** -This :ref:`condition ` checks if LVGL is in the paused state or not. +This :ref:`condition ` checks if LVGL is in the paused state or not. .. code-block:: yaml From 5c110f21a2ca67f96cee991545ddded77fc01a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 10 Jul 2024 11:52:36 +0200 Subject: [PATCH 501/564] lvgl.indicator.update explanation fix --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index e37f8be3be..1108027aa2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1515,7 +1515,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need **Actions:** -- ``lvgl.indicator.update`` :ref:`action ` updates indicator options, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` cannot be updated at runtime. +- ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can used for the common styles, states or flags of the meter widget (not the indicators). **Example:** From 7ef39f9cde7abbd9ff1ea577d4009def048818ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Jul 2024 11:42:32 +0200 Subject: [PATCH 502/564] tabview index --- components/lvgl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1108027aa2..ab6076b08c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1823,22 +1823,22 @@ The tab view object can be used to organize content in tabs. The tab buttons are .. figure:: /components/images/lvgl_tabview.png :align: center -A new tab can be selected either by clicking on a tab button or by sliding horizontally on the content. +The tabs are indexed (zero based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button or by sliding horizontally on the content. **Configuration variables:** - **position** (*Optional*, string): Position of the tab selector buttons. One of ``TOP``, ``BOTTOM``, ``LEFT``, ``RIGHT``. Defaults to ``TOP``. - **size** (*Optional*, percentage): The height (in case of ``TOP``, ``BOTTOM``) or width (in case of ``LEFT``, ``RIGHT``) tab buttons. Defaults to ``10%``. - **tabs** (**Required**, list): A list with (any number of) tabs to be added to tabview. - - **id** (*Optional*): A tab ID to be used with the ``lvgl.tabview.select`` action. - **name** (**Required**): The text to be shown on the button corresponding to the tab. + - **id** (*Optional*): An ID for the tab itself. - **widgets** (**Required**, list): A list of :ref:`lvgl-widgets` to be drawn on the tab, as children. **Actions:** - ``lvgl.tabview.select`` :ref:`action ` jumps the view to the desired tab: - **id** (**Required**): The ID of the ``tabview`` which receives this action. - - **tab_id** (*Optional*): The ID of the tab to which to jump. + - **index** (**Required**): The the zero based index of the tab to which to jump. - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. **Triggers:** From 51569e707b656a23984a5e0834dda0f8d5da90c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 17 Jul 2024 11:56:23 +0200 Subject: [PATCH 503/564] 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 ab6076b08c..f6f291db43 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1823,7 +1823,7 @@ The tab view object can be used to organize content in tabs. The tab buttons are .. figure:: /components/images/lvgl_tabview.png :align: center -The tabs are indexed (zero based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button or by sliding horizontally on the content. +The tabs are indexed (zero based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button, by sliding horizontally on the content or via ``lvgl.tabview.select`` :ref:`action `, specifying its index. **Configuration variables:** @@ -1867,7 +1867,7 @@ The tabs are indexed (zero based) in the order they appear in the configuration then: - lvgl.tabview.select: id: tabview_id - tab_id: tabview_tab_1 + index: 1 animated: true # Example trigger: From d79ff123100e473f1dfe130d7e178a5a175e2af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Jul 2024 09:31:23 +0200 Subject: [PATCH 504/564] Start migration to LVGL v9 --- components/lvgl.rst | 40 ++++++++++++++-------------- cookbook/lvgl.rst | 64 ++++++++++++++++++++++----------------------- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f6f291db43..8d9c0b374d 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -40,7 +40,7 @@ Some widgets integrate also as native ESPHome components: * - LVGL Widget - ESPHome component - * - ``btn`` + * - ``button`` - :doc:`Switch `, :doc:`Binary Sensor ` * - ``switch``, ``checkbox`` @@ -295,7 +295,7 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **transform_height** (*Optional*, int16 or percentage): Transformation height of the widget (eg. stretching) - **transform_pivot_x** (*Optional*, int16): Horizontal anchor point of the transformation. Relative to the widget's top left corner. - **transform_pivot_y** (*Optional*, int16): Vertical anchor point of the transformation. Relative to the widget's top left corner. -- **transform_zoom** (*Optional*, 0.1-10): Transformation zoom of the widget (eg. resizing) +- **transform_scale** (*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. @@ -306,7 +306,7 @@ Themes The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. -You can configure a global theme for all widgets at the top level with the ``theme`` configuration variable. In the example below, all the ``arc``, ``slider`` and ``btn`` widgets will, by default, use the styles and properties defined here. A combination of styles and :ref:`states ` can be chosen for every widget. +You can configure a global theme for all widgets at the top level with the ``theme`` configuration variable. In the example below, all the ``arc``, ``slider`` and ``button`` widgets will, by default, use the styles and properties defined here. A combination of styles and :ref:`states ` can be chosen for every widget. .. code-block:: yaml @@ -318,7 +318,7 @@ You can configure a global theme for all widgets at the top level with the ``the slider: scroll_on_focus: true group: general - btn: + button: scroll_on_focus: true group: general border_width: 2 @@ -571,7 +571,7 @@ To apply styles to the states, you need to specify them one level above, for exa .. code-block:: yaml - - btn: + - button: checkable: true state: checked: true # here you activate the state to be used at boot @@ -750,7 +750,7 @@ The ``textarea`` can be also integrated as :doc:`Text ` o .. _lvgl-wgt-btn: -``btn`` +``button`` ******* Simple push (momentary) or toggle (two-states) button. @@ -774,7 +774,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied .. code-block:: yaml # Example widget: - - btn: + - button: x: 10 y: 10 width: 50 @@ -786,7 +786,7 @@ To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget .. code-block:: yaml # Example toggle button with text: - - btn: + - button: x: 10 y: 10 width: 70 @@ -799,7 +799,7 @@ To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget text: "Light" # Example trigger: - - btn: + - button: ... on_value: then: @@ -807,18 +807,18 @@ To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget format: "Button checked state: %d" args: [ x ] -The ``btn`` can be also integrated as a :doc:`Binary Sensor ` or as a :doc:`Switch ` component. +The ``button`` can be also integrated as a :doc:`Binary Sensor ` or as a :doc:`Switch ` component. See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable button to act on a Home Assistant service. .. _lvgl-wgt-bmx: -``btnmatrix`` +``buttonmatrix`` ************* The button matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. -.. figure:: /components/images/lvgl_btnmatrix.png +.. figure:: /components/images/lvgl_buttonmatrix.png :align: center **Configuration variables:** @@ -848,7 +848,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row **Actions:** - ``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 item styles and properties specified in the specific ``state``, ``items`` options. +- ``lvgl.buttonmatrix.update`` :ref:`action ` updates the item styles and properties specified in the specific ``state``, ``items`` options. **Triggers:** @@ -860,7 +860,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row .. code-block:: yaml # Example widget: - - btnmatrix: + - buttonmatrix: x: 10 y: 40 width: 220 @@ -903,7 +903,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row selected: true control: checkable: false - - lvgl.btnmatrix.update: + - lvgl.buttonmatrix.update: id: b_matrix state: disabled: true @@ -911,7 +911,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row bg_color: 0xf0f0f0 # Example trigger: - - btnmatrix: + - buttonmatrix: ... rows: - buttons: @@ -1572,12 +1572,12 @@ Images are the basic widgets used to display images. - **src** (**Required**, :ref:`image `): The ID of an existing image configuration. - **offset_x** (*Optional*): Add a horrizontal offset to the image position. - **offset_y** (*Optional*): Add a vertical offset to the image position. -- **zoom** (*Optional*, 0.1-10): Zoom of the image. +- **scale** (*Optional*, 0.1-10): Zoom of the image. - **angle** (*Optional*, 0-360): Rotation of the image. Defaults to ``0.0``. Needs ``pivot_x`` and ``pivot_y`` to be specified. - **pivot_x** (*Optional*): Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. - **pivot_y** (*Optional*): Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. -- **antialias** (*Optional*): The quality of the angle or zoom transformation. When anti-aliasing is enabled, the transformations are higher quality but slower. Defaults to ``false``. -- **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is zoomed or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``SIZE_CONTENT``, the object's size will be set to the zoomed and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. +- **antialias** (*Optional*): The quality of the angle or scale transformation. When anti-aliasing is enabled, the transformations are higher quality but slower. Defaults to ``false``. +- **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is scaled or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``SIZE_CONTENT``, the object's size will be set to the scaled and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. - 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. **Actions:** @@ -2309,7 +2309,7 @@ These triggers can be applied directly to any widget in the LVGL configuration, .. code-block:: yaml # Example triggers: - - btn: + - button: ... on_short_click: then: diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 2c02885b07..712b2438e6 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -84,7 +84,7 @@ If you'd like to control a remote light which appears as an entity in Home Assis pages: - id: room_page widgets: - - btn: + - button: id: light_btn align: CENTER width: 100 @@ -494,7 +494,7 @@ First we import from Home Assistant the current target temperature of the climat width: SIZE_CONTENT height: SIZE_CONTENT widgets: - - btn: + - button: id: spin_down on_click: - lvgl.spinbox.decrement: spinbox_id @@ -519,7 +519,7 @@ First we import from Home Assistant the current target temperature of the climat data: temperature: !lambda return x; entity_id: climate.room_thermostat - - btn: + - button: id: spin_up on_click: - lvgl.spinbox.increment: spinbox_id @@ -603,7 +603,7 @@ Just as in the previous examples, we need to get the state of the cover first. W width: 70 text: "My room" text_align: CENTER - - btn: + - button: x: 10 y: 30 width: 70 @@ -619,7 +619,7 @@ Just as in the previous examples, we need to get the state of the cover first. W service: cover.open data: entity_id: cover.myroom - - btn: + - button: x: 10 y: 103 width: 70 @@ -635,7 +635,7 @@ Just as in the previous examples, we need to get the state of the cover first. W service: cover.stop data: entity_id: cover.myroom - - btn: + - button: x: 10 y: 178 width: 70 @@ -671,7 +671,7 @@ In this example we prepare a set of gradient styles in the *theme*, and make som theme: label: text_font: my_font # set all your labels to use your custom defined font - btn: + button: bg_color: 0x2F8CD8 bg_grad_color: 0x005782 bg_grad_dir: VER @@ -679,20 +679,20 @@ 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: # set some btn colors to be different in pressed state + pressed: # set some button 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 + checked: # set some button colors to be different in checked state bg_color: 0x1d5f96 bg_grad_color: 0x03324A text_color: 0xfff300 - btnmatrix: + buttonmatrix: bg_opa: TRANSP border_color: 0x0077b3 border_width: 0 text_color: 0xFFFFFF pad_all: 0 - items: # set all your btnmatrix buttons to use your custom defined styles and font + items: # set all your buttonmatrix buttons to use your custom defined styles and font bg_color: 0x2F8CD8 bg_grad_color: 0x005782 bg_grad_dir: VER @@ -779,7 +779,7 @@ For the navigation bar we can use a :ref:`lvgl-wgt-bmx`. Note how the *header_fo ... top_layer: widgets: - - btnmatrix: + - buttonmatrix: align: bottom_mid styles: header_footer pad_all: 0 @@ -935,7 +935,7 @@ This example illustrates a control panel for three covers, made up of labels and widgets: - label: text: "East" - - btn: + - button: id: but_cov_up_east width: 70 # choose the button dimensions so height: 68 # they fill the columns nincely as they flow @@ -944,7 +944,7 @@ This example illustrates a control panel for three covers, made up of labels and id: cov_up_east align: CENTER text: "\U000F005D" # mdi:arrow-up - - btn: + - button: id: but_cov_stop_east width: 70 height: 68 @@ -953,7 +953,7 @@ This example illustrates a control panel for three covers, made up of labels and id: cov_stop_east align: CENTER text: "\U000F04DB" # mdi:stop - - btn: + - button: id: but_cov_down_east width: 70 height: 68 @@ -965,7 +965,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: text: "South" - - btn: + - button: id: but_cov_up_south width: 70 height: 68 @@ -974,7 +974,7 @@ This example illustrates a control panel for three covers, made up of labels and id: cov_up_south align: CENTER text: "\U000F005D" - - btn: + - button: id: but_cov_stop_south width: 70 height: 68 @@ -983,7 +983,7 @@ This example illustrates a control panel for three covers, made up of labels and id: cov_stop_south align: CENTER text: "\U000F04DB" - - btn: + - button: id: but_cov_down_south width: 70 height: 68 @@ -995,7 +995,7 @@ This example illustrates a control panel for three covers, made up of labels and - label: text: "West" - - btn: + - button: id: but_cov_up_west width: 70 height: 68 @@ -1004,7 +1004,7 @@ This example illustrates a control panel for three covers, made up of labels and id: cov_up_west align: CENTER text: "\U000F005D" - - btn: + - button: id: but_cov_stop_west width: 70 height: 68 @@ -1013,7 +1013,7 @@ This example illustrates a control panel for three covers, made up of labels and id: cov_stop_west align: CENTER text: "\U000F04DB" - - btn: + - button: id: but_cov_down_west width: 70 height: 68 @@ -1059,7 +1059,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width grid_cell_row_pos: 0 # the corresponding cell grid_cell_x_align: STRETCH grid_cell_y_align: STRETCH - - btn: + - button: id: but_cov_up_east grid_cell_column_pos: 0 grid_cell_row_pos: 1 @@ -1070,7 +1070,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width id: cov_up_east align: CENTER text: "\U000F005D" - - btn: + - button: id: but_cov_stop_east grid_cell_column_pos: 0 grid_cell_row_pos: 2 @@ -1081,7 +1081,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width id: cov_stop_east align: CENTER text: "\U000F04DB" - - btn: + - button: id: but_cov_down_east grid_cell_column_pos: 0 grid_cell_row_pos: 3 @@ -1099,7 +1099,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width grid_cell_row_pos: 0 grid_cell_x_align: STRETCH grid_cell_y_align: STRETCH - - btn: + - button: id: but_cov_up_south grid_cell_column_pos: 1 grid_cell_row_pos: 1 @@ -1110,7 +1110,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width id: cov_up_south align: CENTER text: "\U000F005D" - - btn: + - button: id: but_cov_stop_south grid_cell_column_pos: 1 grid_cell_row_pos: 2 @@ -1121,7 +1121,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width id: cov_stop_south align: CENTER text: "\U000F04DB" - - btn: + - button: id: but_cov_down_south grid_cell_column_pos: 1 grid_cell_row_pos: 3 @@ -1139,7 +1139,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width grid_cell_row_pos: 0 grid_cell_x_align: STRETCH grid_cell_y_align: STRETCH - - btn: + - button: id: but_cov_up_west grid_cell_column_pos: 2 grid_cell_row_pos: 1 @@ -1150,7 +1150,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width id: cov_up_west align: CENTER text: "\U000F005D" - - btn: + - button: id: but_cov_stop_west grid_cell_column_pos: 2 grid_cell_row_pos: 2 @@ -1161,7 +1161,7 @@ But there's even more! With the **Grid** layout, you don't need to specify width id: cov_stop_west align: CENTER text: "\U000F04DB" - - btn: + - button: id: but_cov_down_west grid_cell_column_pos: 2 grid_cell_row_pos: 3 @@ -1363,7 +1363,7 @@ If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like t pages: - id: room_page widgets: - - btn: + - button: x: 110 y: 40 width: 90 @@ -1732,7 +1732,7 @@ If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change c align: CENTER text: "Enter code and \uF00C" text_align: CENTER - - btnmatrix: + - buttonmatrix: id: lvgl_keypad x: 20 y: 85 From 645ace771f1e27d946e60ccdf8e5724b1064c28e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Jul 2024 09:32:22 +0200 Subject: [PATCH 505/564] 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 8d9c0b374d..cb0f988e8c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -8,7 +8,7 @@ LVGL Graphics :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 `__. +embedded graphics library to create beautiful UIs for any MCU, MPU and display type. ESPHome supports `LVGL version 9 `__. .. figure:: /components/images/lvgl_main_screenshot.png From 0ac72ed0051ce1f8dc954a599f5f4c9ddea2650a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Jul 2024 09:37:53 +0200 Subject: [PATCH 506/564] linterfixes --- components/lvgl.rst | 22 +++++++++++----------- cookbook/lvgl.rst | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index cb0f988e8c..bf2cc519e7 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -751,7 +751,7 @@ The ``textarea`` can be also integrated as :doc:`Text ` o .. _lvgl-wgt-btn: ``button`` -******* +********** Simple push (momentary) or toggle (two-states) button. @@ -814,7 +814,7 @@ See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable b .. _lvgl-wgt-bmx: ``buttonmatrix`` -************* +**************** The button matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. @@ -1501,7 +1501,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need - **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: + - **image** (*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, representing a needle pointing to the right like ``-o--->``. - **pivot_x**: Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. @@ -1559,8 +1559,8 @@ See :ref:`lvgl-cook-gauge`, :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clo .. _lvgl-wgt-img: -``img`` -******* +``image`` +********* Images are the basic widgets used to display images. @@ -1582,14 +1582,14 @@ Images are the basic widgets used to display images. **Actions:** -- ``lvgl.img.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. +- ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. **Example:** .. code-block:: yaml # Example widget: - - img: + - image: align: CENTER src: cat_image id: img_id @@ -1599,7 +1599,7 @@ Images are the basic widgets used to display images. # Example action: on_...: then: - - lvgl.img.update: + - lvgl.image.update: id: img_id src: cat_image_bowtie @@ -1616,7 +1616,7 @@ Images are the basic widgets used to display images. ``animimg`` *********** -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. +The animation image is similar to the normal ``image`` 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 @@ -1857,7 +1857,7 @@ The tabs are indexed (zero based) in the order they appear in the configuration - name: Dog id: tabview_tab_1 widgets: - - img: + - image: src: dog_img ... ... @@ -1925,7 +1925,7 @@ If the Tile view is screen sized, the user interface resembles what you may have column: 0 dir: VER widgets: - - img: + - image: src: cat_image - ... - ... diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 712b2438e6..0881d328f6 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -453,7 +453,7 @@ If you change the size of the widget, to obtain a uniform gradient, be sure to i .. tip:: - You can omit the ``obj`` used to hide the middle part of meter indicator line by using a bitmap ``img`` indicator as needle, were only the part hanging above the ticks scale is visible, the rest is transparent. + You can omit the ``obj`` used to hide the middle part of meter indicator line by using a bitmap ``image`` indicator as needle, were only the part hanging above the ticks scale is visible, the rest is transparent. .. _lvgl-cook-climate: @@ -1214,7 +1214,7 @@ To display a boot image with a spinner animation which disappears automatically pad_all: 0 border_width: 0 widgets: - - img: + - image: align: CENTER src: boot_logo y: -40 From e24abdb4a8d5880e57364e7689fb55e0d9fd52f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Jul 2024 09:40:16 +0200 Subject: [PATCH 507/564] rename to lvgl_buttonmatrix.png --- .../{lvgl_btnmatrix.png => lvgl_buttonmatrix.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename components/images/{lvgl_btnmatrix.png => lvgl_buttonmatrix.png} (100%) diff --git a/components/images/lvgl_btnmatrix.png b/components/images/lvgl_buttonmatrix.png similarity index 100% rename from components/images/lvgl_btnmatrix.png rename to components/images/lvgl_buttonmatrix.png From e2e4aec72d6691ac2a2cb4df9f64954e0e2c374e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Fri, 19 Jul 2024 09:46:28 +0200 Subject: [PATCH 508/564] 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 bf2cc519e7..d4c3980c44 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -258,9 +258,9 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **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. 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_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring. +- **bg_image_opa** (*Optional*, :ref:`opacity `): Opacity of the background image (if such option is supported) of the widget. +- **bg_image_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the background image (if such option is supported) of the widget. +- **bg_image_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring. - **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``. From add934fba0f7bd5e48f4e0a05298ab7e89977726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 28 Jul 2024 16:22:49 +0200 Subject: [PATCH 509/564] correct version, it's still 8 --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index d4c3980c44..7d3a41cc8b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -8,7 +8,7 @@ LVGL Graphics :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 9 `__. +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 From b5c8ebe7ba9dd4a108b2aca6472e636040725d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Sun, 28 Jul 2024 16:26:24 +0200 Subject: [PATCH 510/564] 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 7d3a41cc8b..175234be5c 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -295,7 +295,7 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **transform_height** (*Optional*, int16 or percentage): Transformation height of the widget (eg. stretching) - **transform_pivot_x** (*Optional*, int16): Horizontal anchor point of the transformation. Relative to the widget's top left corner. - **transform_pivot_y** (*Optional*, int16): Vertical anchor point of the transformation. Relative to the widget's top left corner. -- **transform_scale** (*Optional*, 0.1-10): Transformation 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. @@ -847,8 +847,8 @@ The button matrix widget is a lightweight way to display multiple buttons in row **Actions:** -- ``lvgl.button.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. - ``lvgl.buttonmatrix.update`` :ref:`action ` updates the item styles and properties specified in the specific ``state``, ``items`` options. +- ``lvgl.matrixbutton.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. **Triggers:** From 96fca5767be3348cd7b175c66f81c508329e9d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jul 2024 12:03:16 +0200 Subject: [PATCH 511/564] Update lvgl.rst --- components/lvgl.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 175234be5c..4ebb7ee7b7 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -258,9 +258,10 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **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. Inherited from parent. Defaults to ``COVER``. -- **bg_image_opa** (*Optional*, :ref:`opacity `): Opacity of the background image (if such option is supported) of the widget. -- **bg_image_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the background image (if such option is supported) of the widget. -- **bg_image_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring. +- **bg_image_src** (*Optional*, :ref:`image `): The ID of an existing image configuration, to show as the background of the widget. +- **bg_image_opa** (*Optional*, :ref:`opacity `): Opacity of the background image of the widget. +- **bg_image_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the background image of the widget. +- **bg_image_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring of the background image of the widget. - **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``. From 9fa204b67b0eec0d86900d552843dffbe83c4939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 29 Jul 2024 12:29:09 +0200 Subject: [PATCH 512/564] Update lvgl.rst --- components/lvgl.rst | 75 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 4ebb7ee7b7..dec54c355e 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -75,16 +75,16 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **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. - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a display. - - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, 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, 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 touchscreen, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the touchscreen, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. - **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. - - **long_press_time** (*Optional*, :ref:`Time `): For the rotary encoder, delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the rotary encoder, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. + - **long_press_time** (*Optional*, :ref:`Time `): For the rotary encoder, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the rotary encoder, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. - **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``UP`` key. @@ -99,8 +99,8 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``PREV`` key. - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``HOME`` key. - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``END`` key. - - **long_press_time** (*Optional*, :ref:`Time `): For the keypad, delay after which the ``on_long_pressed`` :ref:`event trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the keypad, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`event trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. + - **long_press_time** (*Optional*, :ref:`Time `): For the keypad, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the keypad, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. .. tip:: @@ -658,6 +658,10 @@ A label is the basic widget type that is used to display text. - **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. +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + **Example:** .. code-block:: yaml @@ -713,6 +717,7 @@ The textarea is an extended label widget which displays a cursor and allows the - ``on_value`` :ref:`trigger ` is activated on every keystroke. - ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). +- :ref:`interaction ` LVGL event triggers. For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. @@ -769,6 +774,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied **Triggers:** - ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -853,8 +859,8 @@ The button matrix widget is a lightweight way to display multiple buttons in row **Triggers:** -- ``on_value`` and :ref:`universal ` triggers can be configured for each button, is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. -- The :ref:`universal ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). +- ``on_value`` and :ref:`interaction ` triggers can be configured for each button, is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. +- The :ref:`interaction ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). **Example:** @@ -958,6 +964,7 @@ The switch looks like a little slider and can be used to turn something on and o **Triggers:** - ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -1007,6 +1014,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c **Triggers:** ``on_value`` :ref:`trigger ` is activated when toggling the checkbox. The boolean variable ``x``, representing the checkbox's state, may be used by lambdas within this trigger. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -1075,8 +1083,9 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( **Triggers:** -- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. +- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`interaction ` LVGL event triggers also apply, and they also return the selected index in ``x``. - ``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -1142,7 +1151,8 @@ Roller allows you to simply select one option from a list by scrolling. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`universal ` LVGL event triggers also apply, and they also return the selected index in ``x``. +- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the selected index in ``x``. **Example:** @@ -1205,6 +1215,10 @@ Not only the end, but also the start value of the bar can be set, which changes - ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + **Example:** .. code-block:: yaml @@ -1256,7 +1270,8 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. 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``. +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. The new value is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -1291,7 +1306,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking .. note:: - The ``on_value`` trigger is sent as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal event trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. + The ``on_value`` trigger is sent as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. @@ -1338,7 +1353,8 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can **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``. +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -1373,7 +1389,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can .. note:: - The ``on_value`` trigger is sent as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal event trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. + The ``on_value`` trigger is sent as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. @@ -1412,7 +1428,8 @@ The spinbox contains a numeric value (as text) which can be increased or decreas **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``. +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -1518,6 +1535,10 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need - ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can used for the common styles, states or flags of the meter widget (not the indicators). +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + **Example:** .. code-block:: yaml @@ -1585,6 +1606,10 @@ Images are the basic widgets used to display images. - ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + **Example:** .. code-block:: yaml @@ -1636,6 +1661,10 @@ The animation image is similar to the normal ``image`` widget. The main differen - ``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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + **Example:** .. code-block:: yaml @@ -1715,6 +1744,10 @@ The LED widgets are either circular or rectangular widgets whose brightness can - ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + **Example:** .. code-block:: yaml @@ -1765,6 +1798,10 @@ The Spinner widget is a spinning arc over a ring. - ``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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + **Example:** .. code-block:: yaml @@ -1801,6 +1838,10 @@ You can use it as a parent container for other widgets. By default, it catches t - Style options from :ref:`lvgl-styling`. +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + **Example:** .. code-block:: yaml @@ -1845,6 +1886,7 @@ The tabs are indexed (zero based) in the order they appear in the configuration **Triggers:** - ``on_value`` :ref:`trigger ` is activated when displayed tab changes. The new value is returned in the variable ``tab`` as the ID of the now-visible tab. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1912,6 +1954,7 @@ If the Tile view is screen sized, the user interface resembles what you may have **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 now-visible tile. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -2305,7 +2348,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. For the widgets having a value, the triggers return the current value in variable ``x``; this variable may be used in lambdas defined within those triggers. +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``; this variable may be used in lambdas defined within those triggers. .. code-block:: yaml From 690b6035e0d82c87ca9ec6050109fcde187bb052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 31 Jul 2024 11:08:19 +0200 Subject: [PATCH 513/564] add ID option docs to actions --- components/lvgl.rst | 47 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index dec54c355e..063490ce62 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -654,6 +654,7 @@ A label is the basic widget type that is used to display text. **Actions:** - ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. - **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. @@ -711,7 +712,9 @@ The textarea is an extended label widget which displays a cursor and allows the **Actions:** -``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. +- ``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **text** (**Required**): The new text content to be displayed. **Triggers:** @@ -855,7 +858,10 @@ The button matrix widget is a lightweight way to display multiple buttons in row **Actions:** - ``lvgl.buttonmatrix.update`` :ref:`action ` updates the item styles and properties specified in the specific ``state``, ``items`` options. + - **id** (**Required**): The ID or a list of IDs of buttonmatrix widget which you want update. + - ``lvgl.matrixbutton.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. + - **id** (**Required**): The ID or a list of IDs of matrix button which you want update. **Triggers:** @@ -1007,6 +1013,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c **Actions:** - ``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. - **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. @@ -1080,6 +1087,7 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( **Actions:** - ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1148,6 +1156,7 @@ Roller allows you to simply select one option from a list by scrolling. **Actions:** - ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1214,6 +1223,7 @@ Not only the end, but also the start value of the bar can be set, which changes **Actions:** - ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1267,6 +1277,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking **Actions:** - ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1350,6 +1361,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can **Actions:** - ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1423,8 +1435,13 @@ The spinbox contains a numeric value (as text) which can be increased or decreas **Actions:** - ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - ``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - ``lvgl.spinbox.increment`` :ref:`action ` increases the value by one ``step`` configured above. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1534,6 +1551,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need **Actions:** - ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can used for the common styles, states or flags of the meter widget (not the indicators). + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1605,6 +1623,7 @@ Images are the basic widgets used to display images. **Actions:** - ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1658,8 +1677,13 @@ The animation image is similar to the normal ``image`` widget. The main differen **Actions:** - ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - ``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1743,6 +1767,7 @@ The LED widgets are either circular or rectangular widgets whose brightness can **Actions:** - ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -1797,6 +1822,7 @@ The Spinner widget is a spinning arc over a ring. **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 widgets), just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -2070,6 +2096,7 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bm **Actions:** - ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of widgets which you want update. **Triggers:** @@ -2125,6 +2152,9 @@ Several universal actions are also available for all widgets and/or for LVGL its This powerful :ref:`action ` allows changing/updating any widget's common :ref:`style property `, state (templatable) or :ref:`flag ` on the fly. +- **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want update. +- The widget's common :ref:`style property `, state (templatable) or :ref:`flag `. + .. code-block:: yaml # Example for updating styles (in states): @@ -2150,7 +2180,9 @@ Check out in the Cookbook :ref:`lvgl-cook-binent` for an example illustrating ho ``lvgl.widget.hide``, ``lvgl.widget.show`` ****************************************** -These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget: +These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget. + +- **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want to hide or show. .. code-block:: yaml @@ -2165,14 +2197,21 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` 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): +- **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want to disable or enable. + .. code-block:: yaml - on_...: then: - - lvgl.widget.disable: my_button_id + - lvgl.widget.disable: + - my_button_1 + - my_button_2 + - on_...: then: - - lvgl.widget.enable: my_button_id + - lvgl.widget.enable: + - my_button_1 + - my_button_2 .. _lvgl-rfrsh-act: From 3f8cb793a2fcbd6d83fcab9a8706d5a2d879845f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 31 Jul 2024 11:41:17 +0200 Subject: [PATCH 514/564] 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 063490ce62..f74cf7853f 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -861,7 +861,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row - **id** (**Required**): The ID or a list of IDs of buttonmatrix widget which you want update. - ``lvgl.matrixbutton.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. - - **id** (**Required**): The ID or a list of IDs of matrix button which you want update. + - **id** (**Required**): The ID or a list of IDs of matrix buttons which you want update. **Triggers:** From c4bd7126633e20fbd4e873e3f6c93d01078aee86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 31 Jul 2024 11:50:09 +0200 Subject: [PATCH 515/564] Update lvgl.rst --- components/lvgl.rst | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index f74cf7853f..9dbf9e057b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -654,7 +654,7 @@ A label is the basic widget type that is used to display text. **Actions:** - ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of label widgets which you want update. - **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. @@ -713,7 +713,7 @@ The textarea is an extended label widget which displays a cursor and allows the **Actions:** - ``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of textarea widgets which you want update. - **text** (**Required**): The new text content to be displayed. **Triggers:** @@ -858,7 +858,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row **Actions:** - ``lvgl.buttonmatrix.update`` :ref:`action ` updates the item styles and properties specified in the specific ``state``, ``items`` options. - - **id** (**Required**): The ID or a list of IDs of buttonmatrix widget which you want update. + - **id** (**Required**): The ID or a list of IDs of buttonmatrix widgets which you want update. - ``lvgl.matrixbutton.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. - **id** (**Required**): The ID or a list of IDs of matrix buttons which you want update. @@ -1013,7 +1013,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c **Actions:** - ``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of checkbox widgets which you want update. - **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. @@ -1087,7 +1087,7 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( **Actions:** - ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of dropdown widgets which you want update. **Triggers:** @@ -1156,7 +1156,7 @@ Roller allows you to simply select one option from a list by scrolling. **Actions:** - ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of roller widgets which you want update. **Triggers:** @@ -1223,7 +1223,7 @@ Not only the end, but also the start value of the bar can be set, which changes **Actions:** - ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of bar widgets which you want update. **Triggers:** @@ -1277,7 +1277,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking **Actions:** - ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of slider widgets which you want update. **Triggers:** @@ -1361,7 +1361,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can **Actions:** - ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of arc widgets which you want update. **Triggers:** @@ -1435,13 +1435,13 @@ The spinbox contains a numeric value (as text) which can be increased or decreas **Actions:** - ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. - ``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. - ``lvgl.spinbox.increment`` :ref:`action ` increases the value by one ``step`` configured above. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. **Triggers:** @@ -1551,7 +1551,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need **Actions:** - ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can used for the common styles, states or flags of the meter widget (not the indicators). - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of line or image indicators which you want update. **Triggers:** @@ -1623,7 +1623,7 @@ Images are the basic widgets used to display images. **Actions:** - ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of image widgets which you want update. **Triggers:** @@ -1677,13 +1677,13 @@ The animation image is similar to the normal ``image`` widget. The main differen **Actions:** - ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. - ``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. - ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. **Triggers:** @@ -1767,7 +1767,7 @@ The LED widgets are either circular or rectangular widgets whose brightness can **Actions:** - ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of led widgets which you want update. **Triggers:** @@ -1822,7 +1822,7 @@ The Spinner widget is a spinning arc over a ring. **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 widgets), just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of spinner widgets which you want update. **Triggers:** @@ -1905,7 +1905,7 @@ The tabs are indexed (zero based) in the order they appear in the configuration **Actions:** - ``lvgl.tabview.select`` :ref:`action ` jumps the view to the desired tab: - - **id** (**Required**): The ID of the ``tabview`` which receives this action. + - **id** (**Required**): The ID of the tabview which receives this action. - **index** (**Required**): The the zero based index of the tab to which to jump. - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. @@ -1971,7 +1971,7 @@ If the Tile view is screen sized, the user interface resembles what you may have **Actions:** - ``lvgl.tileview.select`` :ref:`action ` jumps the ``tileview`` to the desired tile: - - **id** (**Required**): The ID of the ``tileview`` which receives this action. + - **id** (**Required**): The ID of the tileview which receives this action. - **tile_id** (*Optional*): The ID of the tile (from within the tileview) to which to jump. Required if not specifying ``row`` and ``column``. - **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``. @@ -2096,7 +2096,7 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bm **Actions:** - ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of keyboard widgets which you want update. **Triggers:** From f574e954d7a9456f6844d65b1a298c21e8fef58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 31 Jul 2024 12:00:43 +0200 Subject: [PATCH 516/564] Update lvgl.rst --- components/lvgl.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 9dbf9e057b..388c335910 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -2188,9 +2188,13 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` on_...: then: - - lvgl.widget.hide: my_label_id + - lvgl.widget.hide: my_label_id # a single widget + - lvgl.widget.show: [my_button_1, my_button_2] # a list of widgets - delay: 0.5s - - lvgl.widget.show: my_label_id + - lvgl.widget.show: + -id: my_label_id + - lvgl.widget.hide: + - id: [my_button_1, my_button_2] ``lvgl.widget.disable``, ``lvgl.widget.enable`` *********************************************** @@ -2210,8 +2214,8 @@ These :ref:`actions ` are shorthands for toggling the ``disabled - on_...: then: - lvgl.widget.enable: - - my_button_1 - - my_button_2 + - id: my_button_1 + - id: my_button_2 .. _lvgl-rfrsh-act: From 79cff491fc1435a458ed98a267afe78f8fb36d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 31 Jul 2024 14:08:41 +0200 Subject: [PATCH 517/564] Update lvgl.rst --- components/lvgl.rst | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 388c335910..68d15f1554 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -658,6 +658,7 @@ A label is the basic widget type that is used to display text. - **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. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -859,9 +860,11 @@ The button matrix widget is a lightweight way to display multiple buttons in row - ``lvgl.buttonmatrix.update`` :ref:`action ` updates the item styles and properties specified in the specific ``state``, ``items`` options. - **id** (**Required**): The ID or a list of IDs of buttonmatrix widgets which you want update. + - Widget styles or properties from ``state``, ``items`` options above, which you want update. - ``lvgl.matrixbutton.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. - **id** (**Required**): The ID or a list of IDs of matrix buttons which you want update. + - Widget styles or properties from ``control``, ``width`` and ``selected`` options above, which you want update. **Triggers:** @@ -1017,6 +1020,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c - **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. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -1088,6 +1092,7 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( - ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of dropdown widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -1157,6 +1162,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 from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of roller widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -1224,6 +1230,7 @@ Not only the end, but also the start value of the bar can be set, which changes - ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of bar widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -1278,6 +1285,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 from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of slider widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -1362,6 +1370,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can - ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of arc widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -1436,12 +1445,13 @@ The spinbox contains a numeric value (as text) which can be increased or decreas - ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. - -- ``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. - - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. - ``lvgl.spinbox.increment`` :ref:`action ` increases the value by one ``step`` configured above. - - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. + - **id** (**Required**): The ID of the spinbox widget which you want to increment. + +- ``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. + - **id** (**Required**): The ID of the spinbox widget which you want to decrement. **Triggers:** @@ -1624,6 +1634,7 @@ Images are the basic widgets used to display images. - ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. - **id** (**Required**): The ID or a list of IDs of image widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -1677,13 +1688,14 @@ The animation image is similar to the normal ``image`` widget. The main differen **Actions:** - ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. - - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want start. - ``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. - - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want stop. - ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -1768,6 +1780,7 @@ The LED widgets are either circular or rectangular widgets whose brightness can - ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of led widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -1823,6 +1836,7 @@ The Spinner widget is a spinning arc over a ring. - ``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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of spinner widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -2097,6 +2111,7 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bm - ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of keyboard widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** From cc649b34e9e050b2158f6d60eadafd4decdec335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Aug 2024 09:30:29 +0200 Subject: [PATCH 518/564] Update lvgl.rst --- components/lvgl.rst | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 68d15f1554..1539c0e106 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -883,7 +883,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row items: pressed: bg_color: 0xFFFF00 - id: b_matrix + id: matrix_id rows: - buttons: - id: button_1 @@ -913,14 +913,14 @@ The button matrix widget is a lightweight way to display multiple buttons in row # Example action: on_...: then: - - lvgl.button.update: + - lvgl.matrixbutton.update: id: button_1 width: 1 selected: true control: checkable: false - lvgl.buttonmatrix.update: - id: b_matrix + id: matrix_id state: disabled: true items: @@ -1915,6 +1915,8 @@ The tabs are indexed (zero based) in the order they appear in the configuration - **name** (**Required**): The text to be shown on the button corresponding to the tab. - **id** (*Optional*): An ID for the tab itself. - **widgets** (**Required**, list): A list of :ref:`lvgl-widgets` to be drawn on the tab, as children. +- **tab_style** (*Optional*): Style settings for the tabs + - **items** (*Optional*, list): Settings for the items *part*, the buttons all use the text and typical background style properties except translations and transformations. **Actions:** @@ -1936,6 +1938,11 @@ The tabs are indexed (zero based) in the order they appear in the configuration - tabview: id: tabview_id position: top + tab_style: + border_color: 0x00FF00 + border_width: 6 + items: + text_color: 0x0000FF tabs: - name: Dog id: tabview_tab_1 From 88ac712af2659c9591bfdf83e7810767caa427ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Aug 2024 11:08:01 +0200 Subject: [PATCH 519/564] Update lvgl.rst --- components/lvgl.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 1539c0e106..7417c55052 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -71,8 +71,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o **Configuration variables:** -- **displays** (**Required**, list): A list of displays where LVGL should perform rendering based on its configuration. This may be omitted if there is a single display configured, which will be used automatically. - - **display_id** (**Required**, :ref:`config-id`): The ID of a display configuration. +- **displays** (*Optional*, list, :ref:`config-id`): A list of display IDs where LVGL should perform rendering based on its configuration. This may be omitted if there is a single display configured, which will be used automatically. - **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a display. - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. @@ -941,14 +940,14 @@ The button matrix widget is a lightweight way to display multiple buttons in row - logger.log: format: "Button 2 checked: %d" args: [ x ] - on_press: # Triggers for the matrix, to determine which button was pressed + on_press: # Triggers for the matrix, to determine which button was pressed. logger.log: format: "Matrix button pressed: %d" - args: ["*x"] + args: ["x"] # If x is 65535, it was the container, (or through a disabled button). on_click: logger.log: format: "Matrix button clicked: %d, is button_2 = %u" - args: ["*x", "id(button_2) == x"] + args: ["x", "id(button_2) == x"] .. tip:: @@ -1915,7 +1914,7 @@ The tabs are indexed (zero based) in the order they appear in the configuration - **name** (**Required**): The text to be shown on the button corresponding to the tab. - **id** (*Optional*): An ID for the tab itself. - **widgets** (**Required**, list): A list of :ref:`lvgl-widgets` to be drawn on the tab, as children. -- **tab_style** (*Optional*): Style settings for the tabs +- **tab_style** (*Optional*): Style settings for the tabs. - **items** (*Optional*, list): Settings for the items *part*, the buttons all use the text and typical background style properties except translations and transformations. **Actions:** From 55ff0614795fcdb14130e4c9082eb40f04eb02bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Aug 2024 11:33:51 +0200 Subject: [PATCH 520/564] Apply suggestions from code review Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 7417c55052..1afa6660b6 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1559,7 +1559,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need **Actions:** -- ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can used for the common styles, states or flags of the meter widget (not the indicators). +- ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can be used for the common styles, states or flags of the meter widget (not the indicators). - **id** (**Required**): The ID or a list of IDs of line or image indicators which you want update. **Triggers:** From 5d837e01022a67c67b7f0e452432c5134a01c32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Aug 2024 11:34:33 +0200 Subject: [PATCH 521/564] Update cookbook/lvgl.rst Co-authored-by: Keith Burzinski --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 0881d328f6..9fa645f92c 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1285,7 +1285,7 @@ In the example below, we use the default set of glyphs from RobotoCondensed-Regu Restore checkbox mark --------------------- -In case you configure the ``default_font`` used by LVGL to a custom one, which doesn't contain the `FontAwesome `__ symbols, you'll run into the issue that some widgets don't display correctly; specifically :ref:`lvgl-wgt-chk` won't show the checkmark when it's checked. +If you configure a custom font as the ``default_font`` used by LVGL and this font does not contain the `FontAwesome `__ symbols, you may observe that some widgets won't display correctly; specifically :ref:`lvgl-wgt-chk` won't show the checkmark when it's checked. This issue can be easily worked around by importing only the ckeckmark symbol in the desired size, and applying it through :ref:`lvgl-cook-theme` to all the checkboxes in the configuration: From 2e80a1e2555eb2ab321fe26d9f61dea615e233ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Aug 2024 11:34:50 +0200 Subject: [PATCH 522/564] Update cookbook/lvgl.rst Co-authored-by: Keith Burzinski --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 9fa645f92c..6e70fd2ace 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1287,7 +1287,7 @@ Restore checkbox mark If you configure a custom font as the ``default_font`` used by LVGL and this font does not contain the `FontAwesome `__ symbols, you may observe that some widgets won't display correctly; specifically :ref:`lvgl-wgt-chk` won't show the checkmark when it's checked. -This issue can be easily worked around by importing only the ckeckmark symbol in the desired size, and applying it through :ref:`lvgl-cook-theme` to all the checkboxes in the configuration: +To work around this issue, simply import only the checkmark symbol in the desired size and apply it through :ref:`lvgl-cook-theme` to all the checkboxes in the configuration: .. code-block:: yaml From a1e6d65135fada6fc4c64f615f33ebd50122c509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Aug 2024 15:28:23 +0200 Subject: [PATCH 523/564] remove cookbook --- components/lvgl.rst | 23 +- cookbook/images/lvgl_cook_animimg_batt.gif | Bin 8109 -> 0 bytes cookbook/images/lvgl_cook_climate.png | Bin 1672 -> 0 bytes cookbook/images/lvgl_cook_clock.png | Bin 8115 -> 0 bytes cookbook/images/lvgl_cook_cover.png | Bin 4539 -> 0 bytes cookbook/images/lvgl_cook_flex_layout.png | Bin 5015 -> 0 bytes cookbook/images/lvgl_cook_font_batt.png | Bin 243 -> 0 bytes cookbook/images/lvgl_cook_font_binstat.png | Bin 2715 -> 0 bytes cookbook/images/lvgl_cook_font_roboto_mdi.png | Bin 2278 -> 0 bytes cookbook/images/lvgl_cook_gauge.png | Bin 4154 -> 0 bytes cookbook/images/lvgl_cook_gradient_styles.png | Bin 10498 -> 0 bytes cookbook/images/lvgl_cook_keypad.png | Bin 5951 -> 0 bytes cookbook/images/lvgl_cook_pagenav.png | Bin 1312 -> 0 bytes cookbook/images/lvgl_cook_remligbut.png | Bin 1696 -> 0 bytes cookbook/images/lvgl_cook_statico.png | Bin 700 -> 0 bytes cookbook/images/lvgl_cook_thermometer.png | Bin 11532 -> 0 bytes .../images/lvgl_cook_thermometer_gauge.png | Bin 5872 -> 0 bytes cookbook/images/lvgl_cook_titlebar.png | Bin 2366 -> 0 bytes cookbook/images/lvgl_cook_volume.png | Bin 1264 -> 0 bytes cookbook/images/lvgl_cook_weather.png | Bin 8364 -> 0 bytes cookbook/lvgl.rst | 2247 ----------------- 21 files changed, 1 insertion(+), 2269 deletions(-) delete mode 100644 cookbook/images/lvgl_cook_animimg_batt.gif delete mode 100644 cookbook/images/lvgl_cook_climate.png delete mode 100644 cookbook/images/lvgl_cook_clock.png delete mode 100644 cookbook/images/lvgl_cook_cover.png delete mode 100644 cookbook/images/lvgl_cook_flex_layout.png delete mode 100644 cookbook/images/lvgl_cook_font_batt.png delete mode 100644 cookbook/images/lvgl_cook_font_binstat.png delete mode 100644 cookbook/images/lvgl_cook_font_roboto_mdi.png delete mode 100644 cookbook/images/lvgl_cook_gauge.png delete mode 100644 cookbook/images/lvgl_cook_gradient_styles.png delete mode 100644 cookbook/images/lvgl_cook_keypad.png delete mode 100644 cookbook/images/lvgl_cook_pagenav.png delete mode 100644 cookbook/images/lvgl_cook_remligbut.png delete mode 100644 cookbook/images/lvgl_cook_statico.png delete mode 100644 cookbook/images/lvgl_cook_thermometer.png delete mode 100644 cookbook/images/lvgl_cook_thermometer_gauge.png delete mode 100644 cookbook/images/lvgl_cook_titlebar.png delete mode 100644 cookbook/images/lvgl_cook_volume.png delete mode 100644 cookbook/images/lvgl_cook_weather.png delete mode 100644 cookbook/lvgl.rst diff --git a/components/lvgl.rst b/components/lvgl.rst index 1afa6660b6..20a5bcfade 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -18,8 +18,6 @@ The graphic display should be configured with ``auto_clear_enabled: false`` and For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred), a :doc:`/components/sensor/rotary_encoder` or a custom keypad made up from discrete :doc:`Binary Sensors ` 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 ------ @@ -149,8 +147,6 @@ The following configuration variables apply to the main ``lvgl`` component, in o align: CENTER text: 'Hello World!' -See :ref:`lvgl-cook-navigator` in the Cookbook for an example illustrating how to easily implement a page navigation bar at the bottom of the screen. - .. _lvgl-color: Colors @@ -180,8 +176,6 @@ You can use :ref:`fonts configured normally`, the glyphs will be For best results, set ``bpp: 4`` to get the glyphs rendered with proper anti-aliasing. -Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples illustrating how to use icons and text with TrueType/OpenType fonts. - **Library fonts** The LVGL library offers by default prerendered sets with ASCII characters (``0x20-0x7F``), the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from `Montserrat Medium `__, and 60 symbols from `FontAwesome `__ (see below). You can use the IDs below when specifying the ``text_font`` parameter: @@ -381,8 +375,6 @@ So the precedence happens like this: state based styles override the locally spe Feel free to experiment to discover inheritance and precedence of the styles based on states between the nested widgets. -:ref:`lvgl-cook-theme` The Cookbook contains an example illustrating how to easily implement a gradient style for your widgets. - .. _lvgl-layouts: Layouts @@ -392,8 +384,6 @@ Layouts aim to position widgets automatically, eliminating the need to specify ` The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. The position and size calculated by the layout overwrites the *normal* ``x``, ``y``, ``width``, and ``height`` settings of the children. -Checkout :ref:`lvgl-cook-flex`, :ref:`lvgl-cook-grid` and :ref:`lvgl-cook-weather` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. - The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` can be used on widgets to ignore them in layout calculations. **Configuration variables:** @@ -580,8 +570,6 @@ To apply styles to the states, you need to specify them one level above, for exa 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 illustrating how to use styling and properties to show different states of a Home Assistant entity. - .. _lvgl-objupdflag-act: In addition to visual styling, each widget supports some boolean **flags** to influence the behavior: @@ -613,7 +601,7 @@ In addition to visual styling, each widget supports some boolean **flags** to in .. note:: - LVGL only supports **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 only supports **integers** for numeric ``value``. Visualizer widgets can't display floats directly, but they allow scaling by 10s. .. _lvgl-wgt-lbl: @@ -1604,8 +1592,6 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need id: temperature_needle value: 3 -See :ref:`lvgl-cook-gauge`, :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clock` in the Cookbook for examples illustrating how to effectively use this widget. - .. _lvgl-wgt-img: ``image`` @@ -1719,8 +1705,6 @@ The animation image is similar to the normal ``image`` widget. The main differen repeat_count: 100 duration: 300ms -See :ref:`lvgl-cook-animbatt` in the Cookbook for a more detailed example. - .. _lvgl-wgt-lin: ``line`` @@ -1809,8 +1793,6 @@ The ``led`` can be also integrated as :doc:`Light ` comp 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 illustrating how to change the ``led`` styling properties from an automation. - .. _lvgl-wgt-spi: ``spinner`` @@ -2194,8 +2176,6 @@ This powerful :ref:`action ` allows changing/updating any widget id: my_label_id hidden: true -Check out in the Cookbook :ref:`lvgl-cook-binent` for an example illustrating how to use a template to update the state. - .. _lvgl-objupd-shorthands: ``lvgl.widget.hide``, ``lvgl.widget.show`` @@ -2466,7 +2446,6 @@ See :ref:`lvgl-cook-idlescreen` for an example illustrating how to implement scr See Also -------- -- :doc:`Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/cookbook/images/lvgl_cook_animimg_batt.gif b/cookbook/images/lvgl_cook_animimg_batt.gif deleted file mode 100644 index a1ec7806d9f4eba88f68f784037efe8f1383581a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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|H9Gu-4m#b`8oD@{u1n#P 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 diff --git a/cookbook/images/lvgl_cook_cover.png b/cookbook/images/lvgl_cook_cover.png deleted file mode 100644 index 5c9fe2987167fe988d4d2efe28cfcf0c58a5a55b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4539 zcmcIoXH-*L+D-^fL8^2J3L+S!DIi4x*HBat0wjQ-geFo%%01lBGL^SAZP+Y zL<~ugs&s_Vi!^Bx2)#48GxN=zA9H`qTJ!yQ&N^$a{qD8TyPxNMpM9RfEzOP`mOKmq z0FGR`Xlw%j099GOyRZig+^iGH{MA!f5>$B?(a#J4Jw&VnVOzAL$%IW zX{ynEv;?dx_Fxr?M#g~RiznDwU}K>s2bs0wL0BYFNA)L<^Y)ExN$cfu+#=Z{27SiL zIC>k#Jp-BTaSK^C)9QJ>Tc>_Nxe8aJGR|Eo3v6zwm)MyPhGbKc{iL%qvNAHVg06qt z44dfZxjLWdv-T5D3LGnY91QUjH`RO57V*lrYS$Uov*w}ZvEw{{me<`Us7bSRcdaVI zb*G6x5hww_Ts;8xRBOjQv3V8MWD%+E?O#=jmQT585p_QMmsO7s$rp9a{Djc@Ojm)G z@YA}{{Y8I5v84XFw2LQfU`5J2_Bqf9$6`9pFvs$Qki95j$bq5}cCTl9;B!FS@p*JZ zTf(pdh1rUtURqbQg%x>3Ef0wG-hMZdzUy)(<>K!025S9s9fns)_XiZYJGDsDv^3Cq zo26=C;IOaT%7ZitD{LoqUG@fw_bUd=#`qoMvnrXtnCQISYYqrP{cIYXdc|`#K}G^@4;Wi>|{31IW3m$IlVIU-2*# zcNLAuxEnR@%5-HI{=Rd7>19RTQ~qJDwXYT_2i(kk6JzWm^7KE#YyY;CZBf0}&`|Yu z&cOi;3zeyD)aXnq#F3~cKut#{F;|?&)o$Tel;L#CRz`{U@o?ya;Kdx@ZnKCs=0+^ZIwr|?Uno>@ebGn(T-C4Yu8pTT?F7` z>$NsaIaibOID!#@_wu{Syo-ke#XFqXL^`bNu?0Et1HB9#-Wiqqhrjmz#kT+IbN-w0 znF}Hlg5v1uD8Fe7UYGra+g8|Y@e-Mg-0t@gU8)4<) zoGVi5E}6l>M6V42BL`US;(Ee5giYs$SDgHCcH5YH_4@2Jkp*zZVH4q{>rxBImSJ04 z<-=5R=@}QNJB6`{;51je-JXU9WY!kA*<|xqLlb79=PBef+KXu`rN}8=?8WR#cmdQG zC=o{TMgwm0tAt1~gSb39O-0IqTHr}%n7Ed0!E+PGL&#^&{BWH`SMyQQJLR4jTFQ}oAvJ2mesvczb6DG0t|a#V z2Re9he*4c_Ng;hQ(Ljm<94Ldd*w`Gey^-7huYvQaaLMo>V*cx(lVkhv(0}rwGsdJK zRYBI64u55t7Vpqa$_BFZ$BOTE-^MsI(Fo;9jB}?uql={sMfS6K6Bagr7F6r_L$}J< zsm9J4VG80ZY>#r5Sg}z_XX2#Hq~I3Sz>Z0dO_|i<11hT1&kd(yVwPamCm0;P9dmqy1YUFwzsJq6>p^E(b7UjtY#bjMhfGpux zR;tIo-_U5#?kAEF$go>fD7O94)DChOXvhR8`N2NKQtH}y={*>RS?uE9DHmANRT z<>LruEsYJ{1=Dx>PWhVMV;2V@z_u@TPZP!j%1`e}4JZ!OVsYYH;5KpWTkwLtX{ks@HR4e z1!X87B??fDP-MiXskot4&GQR!t#8y**)aN6-31laeea^_FbC-`r(mGuQTWT-*pgEQ zMR>U|+g5(xSMK;F?#E_{jbT@g)B!bhRRIC>f~HBnMk{5l5`q9F!^QqPe6-khKj!T{ zYocgPg}gW|acFk?b>f~*opM#?RJH<#Q4|N7TlgSm$XjLa#$MXF4bilol25o*fe*0F z_0yISQ}^F&?Kq6UUrk(;sULDm592v|K#4jYC8qM|zRu4PqfW#X{cwS3l!>pItFg>Z zsQiN|uJ=zQTlw6_6pdj@Y4a~nr*#&D9;kjy$^D>-w|d75Xf`>jn4+8LWCCz-tld56 zQCsh*t8hm z)!eRg^npWZc>=cRG@9b?ck2MMWIEK56GX^IMP;AN*#d z5u^O04mM4;CWh7QSR{@*gRd6=s66@w-&^ve#D8&!*m2>#3JfKv{-I>aY6nAB{-_)( z@uiUfhtFJqm;UaN4j{ys#ye2AzSW$of+ETJ;Wz(6I+v1tO1$gbop++h`IWbxG}!*> z!;9XPVRH;ofQJyPb8a1(8bE@_p)?ib>055QpEJNUyCt3wtx)rRwTO@6HDwQ_cY4mV z)OHB4qa|y-`@G&wCdxCBj;eB2!G}_dM}1Z{UPB=IkBWp@MQ9mxjfy-t_3ct`vp9`# za$93V6q^zDQzbq!;VDpSAJTv-rqvmeuzVYWxMp*bW9vSy9$0QxIb!_GJh+*R=+&qHTKjQ|41L&J}t&?|J`7!MbMW2i;kx;$~#Ealk@rMufSns zU0LCJ#S8p7Mr6(FY=wSb5fxq~+iH+@ksM$x6XO4(^~2R7#QEoErTNU(3c+2Zm!uvs zPow*6;F5bHPYY`|Z%fGuI+*;43s)*KE~^m6escC0tR>R^&r*JDU-4%xoD9;w$4M$F zY9ksU^|i>gxW`Ld+}|l-1O?Dxu@(#igdj$<=izl|4{C5b*>$Y;td#_Cue|)t6PLu3Hx6fi*Wie(MNver1n*H~$mZykb$fZtuw^(<1M4@Gm5#ea=X?w_S?hufNDj^vfE~kW53cj~Ro;Y4^h9r?7yx+dmsNFG9^12bCxl=+Z5^(5`#z$wN1KtS4HHFkX5L=@G_evM z$qY~!wr!KvSQChMH(eFkh=7R0KOW->wij&24vgC2M?UQwiVjKhAR^1v^DJ0i@=YwD z+aF(r)Nb~CYr}-M1?WiA^U)T)&OMH(bRfs!yVXCDC$M}I|DLzaD4Y{i$t@#Pj`dRp OaLL5dm~g@6!QTJ{E^!Bx39-R704u4YCc!-eliuER#Kzo#PR-?xNJM8=Y7 z438SJ43Z&)ck1~)%lpUg{k{Lb?{$68^*#4@Ip@C4eLkOat~>UQp*9&~)%!G}bavBwVZ?Ejrzw*s;6cb6>s^QB zolR&^uUvo;l)d=cL?)m?p1#ImF|R2YZE3!i{`Esnw^6rnNOJ1?;f<7~67A9MK)=PI z6d$HXpTF5m(9+Cv=s5K-|2v5&+CnKivqauKwm+<)oR{Tc1~yw@#7kHr7pUtQNyt!D zm;5^+EnSOm%YHb)>tUC8uGrS+R1@q1Nt4q-$JfHE%&S2x1(phL#$w-a$?ZGdS z%9#d%I;!ic^au_qR3xiuR8(*{t?k8-b87gOtx?mIv=SCMzV#n&LqQi;^60>VsWGK9 zo-m{4=BC)v+D0vKMzw&D)?VXT$A^bcXQ9;u8!4W+nvQ)umW(3CXH<{a15dN`mkpIA zjz|Fv3=C(FJq^4(A~lU?O|{s^PZq-EHNJpky6x9d#l_G|JV52NAja+Hvx_w->Uh)Z zz5C#;JGy@f_)$|$ZbQu*@cgv^=gCvkw}K_eot_N>=XR0bB6sox0mS}w#A z*0v8vr=*odgLXU5WMHa@?WSjeP+~=C@XFw>+PPf*w7La+_*}D86gv6s(z%fRylL>c zZp#L|AvJ97jj+8#1a(wFS4S87KH$A>;L&Y2?1F-;VHJbrvz3?P%z?^HD_eo8yG9qN zF$7OQC;h}_SVRHl-m+Jk0t#ei@=RJ`6}$T(P;)SN#M#$7pluW3xV4p~Nv=QEPRrxw7tX73Ol&^RG zj$e7%SdW*Xeh|bSVP`Jjv8jq|pBAEhR=i+#Q0A5~&#l@Ffhp5fbfWf|&fi8zzGuS2 z%7vYWFh4-HNj7TA%GbR>yov>s`J?da9pOTM*419uu+P0E97UB%VYQZFB|LX@y3Vud zd2mdhtFDY(KsaiEu66d$?t7AvJ@N+N9{_PrkKX^H)VF*XxzC!;?C;n38lQd{Dfb+FGdGPi7EId07Ra#zV2>) zW+aL8d5E32=j2Cn)0Gg%WgRB%}qq(r-$(?OOv0Z6$G!EnAIs zUB)R@{Ea*uFN2Vc@A-0w3jGkgqPr)k%0D2(KoskIQB==m9F_$;C81@U>R#n-J_Huy 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 diff --git a/cookbook/images/lvgl_cook_font_batt.png b/cookbook/images/lvgl_cook_font_batt.png deleted file mode 100644 index 6803ee049bae1b86ed99f7393698c631da4950eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 243 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s1SJ3FdmIK*oCO|{#S9F5M?jcysy3fAP;jZI zi(`mKXY!x_|LvK#G74Yyl`);tx}d9g`uVeS?ZnUdp7SxgWV-0eh2Q+|@^A0sJy-gv zL@7fta$C44~A=k!nTEZi|eW$4{&vLWn*LW89hjbZSA!#~$R)^y6gwy2v? o6BUm(*w3BB+vYx_kHML7C#Pj{4*P6zpo1AaUHx3vIVCg!0L2wqhyVZp diff --git a/cookbook/images/lvgl_cook_font_binstat.png b/cookbook/images/lvgl_cook_font_binstat.png deleted file mode 100644 index 4315ba8cceafce83febc3b99d15b3ed9ef839e9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2715 zcmV;M3S{+(P)!;S-kKYRCod}NYDXmm_l6|h{6WO8FGk+ zJ=EJA8k57cw9q88u$#F|C(NNu_pnXpur%FEvkTp{g$~XoB!$gva_Ar*vcv;j;zCLs zXh1mxBxpbnBG7{xI)|ijY^SoEN>3iwA3B8O>FLj}U;qE!um3%L^ybYQXw$|&eiOC; zZCZ`CNwx8rwn??|nTVH0nr=-k>)IBjwiC2K+#o_U6(^&;N=gxZ>{feeOy!E&mPHvr z1byr|G)jyhq~hXeUm|r%uG{=0_u=_m!5CR6QrjUYVgxaQ(MZ%kVMD_yIjqE3iBV<| zAv)ck$f)&|pK)pLW>Ts9tGP{s z2r@xGpW|kOGK<0(nr>zQ0m3_8erIzZzC;n9fz_3gz8UcbJBIp#HQYaz- zWfXu}f2$w<#P82&@ zgK{1IqU}%uTG2=)$|;x%FO_+`y0}3ljxH*l5GT${V$^L?X*tgLk0wvUG8s*uCUaNZ zatfJ$YV*%^LOq2@UyupCHMp4htmx8a?&rkK*|b6V-9bv^flg)aFJ-4*VN&~1k5|t3 z&ILKs;WfcHw`Pnz;dK9KiPepL;&*dwTSteJJHObMpSrr}vGM4m^h_=ps5}R-DB?-w zaO|rHe3Ur^k&lx8`<2oqmm`biIP)*)$`+%J0{|o%?TO>SS#sdOG99uK!$1C8=OP_Y zRwts-5+JYP!HvPivHraG_ET3Em6&yVHXWQuWlD@zj(V%#@gV?*fz-Xh3VWJ(s!uIf zc_6yD2IC7b+AEL$LD~CNmn`19z`mXh+^Rfz=?LQMpalT{7(J&oWKVmH_2;RLQ%jBI z*p30d238r?La0PYcaVd4XE{#h@oJ4dm6=*LGLKg+XWwUJI^=Z62bADQd~8g7nLFOO z6JO>MAM+dP9T0*^-8ruu{5&#ST-mJS6jwIc$ZUB`dieCPVL>1FzM6R-`R;u+!$HWZ zi`Epk1e^`J)LkAPO)Tjv8=ivf$_ATQ(#Ov!03b%AmsFB{Mgx@6BLV9w)luwZG+<-SXi*fiImj1aFg?c~$%! z7sj=n1TAM3HC`(Cn&q+C!ok(DS9;QCW%u^!vvT%I&%r5Uvjq-9HUo^|_z&v)^f3N| z%D6934dJ!1wqf0QTCRc54)si5?mBW@g$UD^yRt)Nd%E*`lb1<~J zNhY6gD#SZXINNO8UMN0TE?ZTmTiJWlQpIpmIT(@yz=P%W+Y7wkSh>N$S(f07>jPHf z(_71iFRl;pk+6!;c5WG)Esj5FV8z_%%<9-|Guaa_7{gD7h8pr!tDEGLp&|YuZ;zT( zC&#rhlTV8i7s^Wp+%Ns`f1K^f%l+V_E5_jSYXi=I9(rv5`L%()^MVt}h4%hZZG0x| zB=K7&E_5CCSicUMV`6v&p$f*ks`L0XpI}YYPgSI$bpa9FuBy6 z=F)ULTuMA#;<_;5cr?rK{8vfy4ey$PN|P!v1}(B_>HEL{>K6f*7(|fs7B|gEjS?zM z3M0U{s|gWC``liRPUQ-`w^WTF)^p!jVoVT$(=7NYWCZ)z8 zZzJP-1Cw!SVz9@h!HRC=Uhu8CLsVmRny7^3MFN!5wjX;avi0Dbf=h$^1}W-%w|^Fi zO5SZ!!`*V;G=T3c)U3BMp>6~JK^*R`v-)&6spKibOSc>BKXpfM{3~-}%5btmR~0X0 z(x(-S@LnTV+@{%l^?r{BWb^CAZN6*O5itVk({*-UNOvX>7)V?-| z;_ad&1%ahIE9RjUTb4PFGx?)-GtXd$t3PipV#=)~etSL@b={lKah%Cn?dEd^`I!%N z>K6e>UcA+b-wsyjs=`Y}qtSs*MI`{FPNikb9z<3N40I~)_O!37q@p5)4lX-`H6a~o z73n~-T36MT2(lzk_bUVugjW8@$I%EPL7eVaWXaPu9Bs_5L4>tMCC;&B~wZA?fh(IKjz;wTY0-ib5z)~iol+A$@hf^t4pwoluyL5H5Nja|_eM@IHTii5m=NSV4n*y_-)bQRIO-ckH zf`B3j1OaX&G5x8G0xEGO`rF1n!&KJQnsNL8CMzNA=wKOOo6s6xy+Q;*0#SyTf)RG( z_fopUO;>IoPcsa|Fbx36ZyVV)R@mA9G+S`O^P|KNK#jqr4oseu0YH{ySw8+wXk}e( z8QFqapui%eb#zstDuGL?l#JKcRh>^fTDz8E8mw~L9iH{+L4cKa8U^$|esZC$t3B$N z)EHEKv#@yh}5Y4Q+H86Zx>zhV@qNrJ7~EXbgp_ zYyt}GGV&qd-m-`1)o5f}R_y$lWc*g4PdpsVGS$>9QTU<_KE?6{QeD;h8YE z%9*AK0BS=`EvCXVVT4d>F;%HnF568vu7;p7mGXe4Of9AmLKoxAC~&JBLP$T*&wC*K zKt~99ytyUf34Vh&jtl^3AGf8V^zQt-x%C`-i&bh$`?w7NN=-?Bm=%W zPIb*-2p{41`G=INo=@!}Dmh=h*-fGbh@<4VIj`r*0POT%$Cf_9Wm;*N+A zvInwKtt8?Jgb)>_ge?JonTRLoc^UwuqSRei(erd_F(qsXYC~-uxA2!<1g$nyJXRu} zaAb7-K*z4)V!#>^e<_tDycu#g_JV$(8%IWFIYamekEOr&(XGV{&xA888N79~kV+EX z*d^i#^&c;%pIgs4f`V=E-@%EX_t^met{Ge+*e?p*`-h&|7@CX7&}u_Xf0#B~W_l?d z@CWz}KDV9&fb2(E?mhpxhps?6mEQv@a&S*{T z?(gqf-|GiDJx@P-_AI@WW^c1fO-a4~N@2s@K70P6L+WeEV$xhVcf#VGHyvwCxh zV819h=%=4QTjJ@&r&S+D2IFFRynCCsSPzU69E9>3jqMW{oA*=6`Dl+1}~K) zHp$|K+T*GZDf^DAi6)uhbRzzb*kFvz)QA#z4Z;VcdVe2txlTIOwMh zkDhdM5gEGOY6E~(Hi%z|yMK0i2wkH=bJ!Ej@WLc0oVTwWfx19@g=|s>A!}YpZKo zL$h*Wa54zCwN+|La3W|)$B}nqb1~z{z$Hq(RwsOfWr?N`&b40H{L|(@n|@JnFoZVT zxrhwS{*IN)GCfbHm(rQ#44OjS)kQx7fk0|8g;z&ysP$T1`A)Hp4z#A0{~{mR>T&4< zz}tbh0pMrzXZ*2!+}4_!hL(aexUQ8@zq)tpA7?m z*)pvqMep=oTYS5y{Jp{^S*@utamM~@W+kKjOB?7a|3}_?_@FBa4o1;NPcA~xbc~js zN)JDJnBUIlxAWu zreiezNZq8An&Q1&aUWf6sO&A4@DZ8iOehqRzLqQr;?(PM#LFgG?jBdK*8{!)cFbWQ zYze8wl*>_L?osYkvlz%(X~V*+p!EZNluIWv6WK5Cs|^*qZX6mT?q}&3Z7Ie(=pAIg zv!9`{g=w1j356rSR?3xANul59pKp8)0Q>Sj4hJrUF}Or=zm0^a!%9^_lL%}Dv>kCr z?5Am~EIwP#RvVsbXsIO8^R)eeCoX*g{!WqS{@_O{NqA3!&8Qi{5k>vg<=6u$uvzI9&1?%KLG&NPFDHumFxTA>O%m~8l5MrBqFtD z=UGwDD?c3yScg~RP{VaaBhP}=Deg1l_t~IsbRIq2LT#SV+f#2YJR(rVK zpynt?7?>oJ-_A>4OCAO7GCGrFw5CQyDJn+EB^fVN>%T2~!vvFHk_ z92q_94Lkfg@Avr&#e#JR*pr?S^p1-*T-Mo*6VGHHWJ5PXBuPeZMt8s5b^N+1Y~o)R z?ksEyn9c@-Fv#nyvL9v8M+b5KFHb|?mgWL-3WzlgkHRO;oX^@EZkWjNz&dk zNs@L~zyIg=*oGuY<~_#p(9zJ{xVu}6-7k0h{eRg-MC9lXnO{#{)0dORoD*t8)tVX|KlK68RbiZ=-xN&Ke7x}(?|-aK*!5$aq2C~+ zqJ$>VzPx|gj+`Uo3_a#rG0xCqt`%cJkGWR-4_MFI`Wj4X!vFvP07*qoM6N<$f;cK# A(f|Me diff --git a/cookbook/images/lvgl_cook_gauge.png b/cookbook/images/lvgl_cook_gauge.png deleted file mode 100644 index 11379cb9d92fb2804f266c5d22b6591b3c4844df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4154 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 TzWxJsFb+^r(3G!~wG8<$^H^HV diff --git a/cookbook/images/lvgl_cook_pagenav.png b/cookbook/images/lvgl_cook_pagenav.png deleted file mode 100644 index db7b3b55f008b75bf4ce25b1dc35119aa73e433c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1312 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 JWt~$(69A@pIDh~E diff --git a/cookbook/images/lvgl_cook_thermometer.png b/cookbook/images/lvgl_cook_thermometer.png deleted file mode 100644 index ee38819578cb9e3f9d0f7f34c11d9df3e0998c09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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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 diff --git a/cookbook/images/lvgl_cook_thermometer_gauge.png b/cookbook/images/lvgl_cook_thermometer_gauge.png deleted file mode 100644 index 6976d767d2e7529d13ab324c3c1f08f833a9107e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5872 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 diff --git a/cookbook/images/lvgl_cook_volume.png b/cookbook/images/lvgl_cook_volume.png deleted file mode 100644 index 3d42748c97934c4cf05925a6fcfc36f17a9d9aa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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*yoeMI0Af$s$8-{2Yu#CZ08iPI<<=(Pnwq?Rje}~n-SbZc^z`&2#riclJo?pt zjrauw;u=_k3!a{Z$Taw%94hVSs#O~8$>HBBr|^PF&tvl&Rn0WNX@*%yyI7GB!?wve z%|6Z>{HMXkij=3$m4HerMc_AS&f8&TJy$e)#6b5G;3qCI%u-J%25r*+vF*P{yhPXn zAe(`ts$*`*%X9jvU+H6F3C;4!RsKbC+Pp^JO770}T#>U;R{IH6R!BAXx|IF7YK2#? zUX2X$9Yn(N^MBPgy7Y(v#})J<%vd#x)^?k{Bt#!}Pe%syMG}hFfB4%->UmnoNQoS+5LV}v`@6;4-h>%#6vHf<~zLzRx$aGz^0>HqLKLom#Q$zvVH}B zU!mEn>A|hGIhy!lpyrSwA=Svv}F(YhKF`p?t8YU@4Wj|BLK6`yMxpk2~H?lD2@#|b{cjP>#L}9AL zfJ-8;;;0yEwLSjvB$?DNa{lb`frC^MCHUZB^4{tmy$B^;?(F&z+3$=Q-LLl7n|Nye za$bMQ4Gy>6rk|0^QZN+%*ps%|yPmjp)|Y=nzBgLqqlGL>gVoVEk2B4-N`n1(HWwRW9AH_YqPZAS)xB#~VY6aY7L)h=V z56)fQQT=YEMRfmJC9o0*-b!W;4yS6oUePMW7`i3j1!BVbdBo%RW z)g5Pg9j(f@FWQMQ8WG1+^yt~1(AB9E&=T+L)Lrr}*%BU%ZsTg$1AJ-W>bf=}iY+f} zF~zUk=N^+8Q=6Et)ZO7s1aEZ=Z)oV2l^sRhgEWiQ=RdiO%qMRO^O!E*d|on$;+Y(0 z{nRt*K6<$CIsaF(-cop0qF%o?sOx(rb?9@=r|E|cFR&!QC$hh|BH=h6Ot%xAMWR_j z&UjqKeV!xTfp|~hrHZv(33m!|x%^j0<|lA}rx-FXdKbL0t3T50yD}TZEH_$pXRe=b zpD&Ih1Q@dKZ>!d{9QPJSG+fWSJA_`~Cv9^Ff&nc&5ZQ|qj?&c-FC53hiB52_>prkU z^twOs&ss@T1U39?u(g&9e+kcfc4F$ZqJ|3RhX8H!5zi6`l}JC*WJbC4sI^uOp~{Q_NPHGp49rt^BJ<+%kcX!54g5t`H{hZ2 zou%xXxr%+`8(u3-vQSBj<9`pU7GwR2Cl759)aCEalWQ4hc+=VCYB6-+FMK~|Y`EC{ z^k+(d^%%TH532n7P+X@>QhAKOarvPe!Fkx~{iQQqhqlv1vS;*bXSd}nzGYv_0l}$uha}^XNTM#guBw~k#hRB-QoXwh zGS@PQ4?mx4i}oe_6c7nhXQ@w|DN@ zNBr(|?|0u3*W#n5P7+0i$XP@4g@^a{0K}CNDv-Vg=~TSGW7F04M{-Ug3HDp7K<@D$ z(|q1p_g5mO=ind+taS%#*Q%9i|zL=RGoQ7Xq;|RUYgcY7)WBEZr2WNmDtM7qryR<>~X?qdr*9y^@6L zLG{c9B09_3ai-$J0Q?Fw)wKphk!Pm+jsxlMqX!I9%)5SiKnN%WAc5;uV3tV{K34gO z{z3P7qnkThCh;G6EeX~XRfKN4=1uyaD5)5!&vLg(B@aNUIlsr92HMkCX@$2Fm4rX{ zM<_B~ZUkIH8h8UOWb4YCD3_j6J6Mp0h;LxgxP_~#qixTrJ2MZFe7m8(H2}4h@ zm1C2a0@)4%Wl)K8V)doEuY}+>r@jtx2Xh?FVU2+-wm&rciuyhJYqDzv7NIj_R-eT* z)4x&ijsqGXR_%5hOR9(_+yYLFZOnB7=re)cy2b&a5{Bz2-w-_eRMac(Qh`9%1-+cs z`A|E1Y%s5{Eg<@O)+Wa!?~_}{Otm!~GTVerq+M^8;R_k4L3E+tFPfd`X;OWBo*L;( zBr@kW&C{!MlGCoT9FfWAw6NFfuk)M~>H!%Qv;gP*${%JB_riz>q zX)aaIjZKa+qI~!5gVorApmm6;24-B@qe`YSL)mp0Q))EKU8RHQ#iMWC0v2$1_|t^5 zFAKRvwPr9Q{0#o&O*N{^79LZ3J!wXAhkCm)FBMy`6%Z=3poYEM4?Of!<1}N@f02RL z`j{zh*`WzF=mU9%{qQiBujZqxWHkG+;jIuYUn!)){lUAkXCEpLGQy_$A+VKYOa&%_ zm=tZYe&l}B`Z!bUhCrU|`$>oBZ%#R7WV~V@cu%3Lt^|)@X|7)#N{AB9|EM395m^JT=6HCZbbi78KZ4PQ&J%VvdnHL_fn?`gG^E9W8=%z(Jwf*WiQ3a`AEbz*pN*E)Y( zN;BUZx>dN^^c1q1@YsH4n<{{JZHSv-vW*`9(#U>_hzahr4wE!{XWZP7)`H)aPtC>a zY1m!^wqZkZo+NV$X zy5s3JqD2lG;Z%Hc%n-K4;vmWo+O5VDlWlzL##qIzQd&l9e3!X9vevBTT^lc1>rwWx z35(fYF^+!!RsOd;k57JxBYz|>ZEbbV2rfx`V3^?ukDZQEXI9gtFGrG}&hFO^tFf)X zP?MEUQWZ--MRa;|TFA+aQBTMKaMLyP;Y?S^G5j?T(y(r#$9u%phECvTWSTl8c$F2w zT?UuauqMzNZ|x?iDhOnVTa;lbkfR$f1od$R3pfLLda1;%eq&{7K6{!U4yS7ru#o{4 zZEv@7c5Ccb;=|&C3*zG_Y&7omH#qTHIq=p!))l@ zW>c@%G=j~_yhR#6Q`J7Use&rLat1C4RIz#`4kStuS37rGuE!AyMZnRr2e+p8e-xy~(Qw8dc5@^c zOY!3dvul0VejHRz${E{jw>^>9_Lx|b**l56H$L1%Kp2P%?}-!n;amF!r_VE4km1gp zk1~f)-rc(s59XBQ-^^eM?N$y8`GGo^p&u&$Bcy@JD!|=of%YT!=HId}f12BEX!He2 zvws{BX43>VjSZZCrkX@|NzM>Nx0?~LbKRJdN@RUBX=a>klO9NCKFnBTAmJOxhTppW(e}x zYuLD)RsKbtxc7B!QB?{U^hh~88C(~W*x7s(1^pM3y$PkXwka5JSx!y0y^aMvX=S)> z&F)uusynIwaKH~WB?#}-q!|r9wp~wEi#l2@U=jGYhhXn2Y z)_ea0uQz@tm#|%%DersR(@cqnyG`Vjzs}XW6NiU}hfNgn@C~Zar6+0NNQ@z3g^^=3 zzS)u~b6>QyA>)44_0|g8ny1< z=YCCiXd_SU4vL81@10VTyGSq_o~F}#2seOEO~!1pM~yc#(jrO>>Z$Ahf`1PB5dU>6 z^}Xo9nj%Jp2CDl;ud2T<(V40h%`7+rIV0p&#k_AZct z0at_XXO=fJU2bE4BtykC*RIzf$@K$nkhf0^>knuz8GICf?CxgZ(cCmAx7!5Q$Ah5^;M}P{`1Sdgb>3NW;|-*_br~V=;N1WYGusw zKLxuMh4Enkmd-#o-LWaZMFQBfOLxCL6LTfd@{j5$jhWDLLq@biL;(!&ujZzq!+wl+ z(Hd8holUyUL)AHEj$*?18w`{J-L#3*m{V5jcHu7yd7MC?7#Ua$oTXr!u9MZ)zc16` zc!q+jy0=HssMyQ1hhCCWP zu8r|qd8G@+DiZ!&Vs$W1(>eSX z3{%$N?{jbT2r}=?n3i89FEujoy?HU#?VA-hB5n0}k`@xZKrL?PW3GQYPpy-S85Ra* z*;Z&a{CfAW_h6g$;MP@N_5wmRUA0;B=1|-da*=F_98I%d13ZHF*lM{@g53@O$kfJMmLPy_&2&E zCX4S;O&1wNH)R9o43Dm&s@JaARjn4Fk;TLaYop=|m5fw4+8i?)VTh?!8Jpr@Z{(nl z1E%SP%$}y|D=Tq?5JGp4B#91k?8LF{#t7p6vxOAa4e^=Jhn(KzoImKtG^g6wvh`LU z9wz^3Ht}*yWz;756)RwGyhF6`Z0YRG_11Tnsb+PPTfRINTme+&OyYTHnuCuf1lry` zUTi1-)c1YIaa=q*d#t_w^LclK!s=#))FE3Hj3dwELbXgKl#JZx}?AU6dcBSk`RdBsxh#}1B|hpqF1K4?oFp^V==nQA0X z>4aXNz539_B8W;Ritc;2USinz{Dz^=Kc&v_U@6$)((yJUYN89;$-~L~+{J%je}DZ?n%_G5 zHGr>7?X=3{H?Co=CwiK14J?A*=y zWYOQ`{F^oBPdhD@AR~s0e@gh*h5|sgzwCZnn(osIn2s&4;Ho49ZWgs`YU<45=brzm z0|f$^x~&C2fOYbhpKNDSk4 z*!}SPbhoxh%X0WOE{>LI2F7VN1APQ-|9MGxHMeKhDbn`|+7CD5cU2Xl&#ReD=#Kts zc6(yj?Fl?2E>2QfF>|{bbB2_YwXug`ia5A_{%brk%4K=UkmkE?ehb1wSO{S)Pd}Fu z@p?FfmoY1kL8C&ox;^*(Cs$p*adgz0_ls_QC$g7;MnXxke*rszIAQ;?@&CPy_kX4C z|L?-mPC)jWCrULHqY~5t-Ih?Rcr^9|uEd3YY2PL#6R3)^5=t6-rYEsO6i)|Ld7 zWEwc4OuULtmc_0dE^30^CCixhLx;?%PMn*Q@k)2qIK=Ry^v4Z3LK9NehzLRRe>y_( zu8O7~(>*ggrlfqasB;KX5LB&;S%`7u#o7SUmj$-7Rk9)h-@3!eAzjvTOP>MA01W{0 z-s;`Ts?Z(f3kxPfJXGI(q-jqj^sHKl(;Os#$ZkAY9A&kj5)>BceP-GDTKS;%?ODsl z;8B{p*NJ2VSFoFtRG%LjsnCd2{a=Vg`5#0&Rvr5gU>fdG`}z|kn-j~+cL9z+&JS&X zJN)Z7Nkt3|O)YGS)hNg^4sumpA4mIOqAM}ts;k%8etTIf7 z(7{9&lc1=Z&}giZ0_^mPm3h|J9uyKY4T0vhb)2_8Bw)2|>^m9s;W%s!zmyBePt}cE{+IdkzjJ*&9setoTfl zFt8?8XcSSE3c!r1i2n$knMZE=sjsZ=NWb_VlLf*-Ix^l8e+E{BK`p6QovFjb8G*OM zj*738g*e9rp^J)uIW4> zO|pr%x2Rt=fS6e?@O|W4gVBc%qQGFJ1D_bHvCiB_05X309*c&Lvc@9~Eew?(dM$Ai zQE~hx;eo`ZtL$>s^!D-X!zeV8hQwph(!cuDt0^>FLs#H;?D5x2YC#7ImHf!}E2}bZ zPAgs=Hyp2f@O1$za#{~uwLSyP#Cak}Pv1%op{9LZbV(Zs>4*T2X) zEdUbpC8xO^)FM=lo(Q)l{flia{4?^ zO-;9tweW=UP6oWZ*);Yt=tpNU??Js0HCqo%J}TnNVohMDZloyyDQ{o|V)D7W&s_Sj zxUhH4+f?c4?;kW}=VD+vPYvQ}pU=H29pKOxEz!}RPt|A#X-y3bw0TICB>3!q9XisT zs@liBfrY;IWy*9ED|Uti;4^zja#~uo?yRa4!i8}QATGL+TQhOa>bZoYKqmajGj0EB;U%SY7M-kJC z!~6sk#I^l+~(I3w|FVJORBnM@$6%QN96)oBQKH9v19ut0j9m)BJEr)5dsb^5CJ&(E&- zajU$k%(aN|_Dbpa53FQHnNY7Qpxt{45=~&%^N$b&=X;$BXpz-)yqVDYVwp_|kVY z4f@(Vnhl4A!@dlYm4bG{3hZX&s02$eHiXDDpKjDlA6&Q=dA4Hd8)#vpXyV%Dlf`Jp zxVe_%UQ514>7C&fMr_GO^fF%`XuCdJrBX;vGAjg8|I=3^ZFG1VsG26-`6ANAvy3~^ zKGbl>kk8IGxO~vU8tgVhW5-}?)%xyjnUkw8&Y9J6niR_9@}O(i6<`)teB8J@;FiZC zu^)7yPCW|@gGSP4DyX*mavtU-lL~TlGQ2oEUUr)lPvapoJDBL$Fda*~nW**j8F3aK zi5k#Ac~9Tw9r_9L4W2uhTrtn3JmfBD;x=2lz%T9&K6b#AY>xr=NwlJ&lTLjQSARMcQ&8W4Sj9b`3<_r4$@Az|d&8{A6)kcDK)RBny3YdTam`JhUQ z;H1O>7sJM)1KTixoof5J9Q38RQW5Ymolq#c`DY1z7x7I?5|6$qg}A`TJ|7VPj@`I& zV5&rBowO(jwTV6Y#y5@N+U1lrAbr!u3|lZr24xchW&<`f{x`l&Qpi1!=;@XIszPnf Rq5m+zP?A%VEdd$_{x1_sDER;Y diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst deleted file mode 100644 index 6e70fd2ace..0000000000 --- a/cookbook/lvgl.rst +++ /dev/null @@ -1,2247 +0,0 @@ -.. _lvgl-cook: - -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. - -.. note:: - - Many of the examples below call services in Home Assistant; however, Home Assistant does not allow such service calls by default. For each ESPHome device which will call services, you must explicitly enable this setting in Home Assistant. This may be done when the device is initially adopted or by using the `Configure` option in the "devices" list of the ESPHome integration. - -.. 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 with dimensions of ``240x320px``; if your display's dimensions differ, you'll need to adjust them in order to obtain the expected results. - -.. _lvgl-cook-relay: - -Local light switch ------------------- - -.. figure:: /components/images/lvgl_switch.png - :align: left - -The easiest way to integrate an LVGL :ref:`lvgl-wgt-swi` widget and a switch or light is with :ref:`automations `: - -.. code-block:: yaml - - light: - - platform: ... - id: local_light - name: 'Local light' - on_turn_on: - - lvgl.widget.update: - id: light_switch - state: - checked: true - on_turn_off: - - lvgl.widget.update: - id: light_switch - state: - checked: false - - lvgl: - ... - pages: - - id: main_page - widgets: - - switch: - align: CENTER - id: light_switch - on_click: - light.toggle: local_light - -.. _lvgl-cook-binent: - -Remote light button -------------------- - -.. figure:: images/lvgl_cook_remligbut.png - :align: right - -If you'd like to control a remote light which appears as an entity in Home Assistant from a checkable (toggle) :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 - - binary_sensor: - - platform: homeassistant - id: remote_light - entity_id: light.remote_light - publish_initial_state: true - on_state: - then: - lvgl.widget.update: - id: light_btn - state: - checked: !lambda return x; - - lvgl: - ... - pages: - - id: room_page - widgets: - - button: - id: light_btn - align: CENTER - width: 100 - height: 70 - checkable: true - widgets: - - label: - align: CENTER - text: 'Remote light' - on_click: - - homeassistant.service: - service: light.toggle - data: - entity_id: light.remote_light - -.. _lvgl-cook-bright: - -Light brightness slider ------------------------ - -.. figure:: images/lvgl_cook_volume.png - :align: left - -You can use a :ref:`slider ` or an :ref:`arc ` to control 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 convenient to set the slider's ``min_value`` and ``max_value`` accordingly. - -.. code-block:: yaml - - sensor: - - platform: homeassistant - id: light_brightness - entity_id: light.your_dimmer - attribute: brightness - on_value: - - lvgl.slider.update: - id: dimmer_slider - value: !lambda return x; - - lvgl: - ... - pages: - - id: room_page - widgets: - - slider: - id: dimmer_slider - x: 20 - y: 50 - width: 30 - height: 220 - pad_all: 8 - min_value: 0 - max_value: 255 - on_release: - - homeassistant.service: - service: light.turn_on - data: - 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`` or ``valve.set_valve_position``, too; the only difference is that ``max_value`` has to be ``100``. - -.. _lvgl-cook-volume: - -Media player volume slider --------------------------- - -.. 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 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 - - 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: mediaplayer_page - widgets: - - slider: - id: slider_media_player - x: 60 - 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.your_room - volume_level: !lambda return (x / 100); - -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 generally has a negative effect on performance. 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. To mitigate this, consider using 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 accomplished with :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets: - -.. figure:: images/lvgl_cook_gauge.png - :align: center - -The trick here is to have a parent :ref:`lvgl-wgt-obj` which contains 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's central parts and place some :ref:`lvgl-wgt-lbl` widgets to display numeric information: - -.. code-block:: yaml - - sensor: - - platform: ... - id: values_between_-10_and_10 - on_value: - - lvgl.indicator.update: - id: val_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_color: 0xFFFFFF - border_width: 0 - pad_all: 4 - widgets: - - meter: - height: 100% - width: 100% - border_width: 0 - bg_opa: TRANSP - 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 - - obj: # to cover the middle part of meter indicator line - height: 146 - width: 146 - radius: 73 - align: CENTER - border_width: 0 - bg_color: 0xFFFFFF - pad_all: 0 - - 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 - y: 8 - x: -90 - text: "-10" - - label: # higher range indicator - text_font: montserrat_18 - align: CENTER - y: 8 - x: 90 - text: "+10" - -.. tip:: - - The ``obj`` used to hide the middle part of the 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: - -Thermometer ------------ - -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 - -Whenever a new value comes from the sensor, we update the needle indicator as well as the text in the :ref:`lvgl-wgt-lbl`. Since LVGL only handles integer values on the :ref:`lvgl-wgt-mtr` scale, but the sensor's value is a ``float``, we use the same approach as in the examples above; we multiply the sensor's values by ``10`` and feed this value to the :ref:`lvgl-wgt-mtr`. It's essentially two scales on top of each other: one to set the needle based on the multiplied value and the other to show sensor's original value in the :ref:`lvgl-wgt-lbl`. - -.. code-block:: yaml - - sensor: - - platform: ... - id: outdoor_temperature - on_value: - - lvgl.indicator.update: - id: temperature_needle - value: !lambda return x * 10; - - lvgl.label.update: - id: temperature_text - text: - format: "%.1f°C" - args: [ 'x' ] - lvgl: - ... - pages: - - id: meter_page - widgets: - - meter: - align: CENTER - height: 180 - width: 180 - scales: - - range_from: -100 # scale for the needle value - range_to: 400 - angle_range: 240 - rotation: 150 - indicators: - - line: - id: temperature_needle - 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 - rotation: 150 - ticks: - width: 1 - count: 51 - length: 10 - color: 0x000000 - major: - stride: 5 - width: 2 - length: 10 - color: 0x404040 - label_gap: 10 - widgets: - - label: - id: temperature_text - text: "-.-°C" - align: CENTER - y: 45 - - label: - text: "Outdoor" - align: CENTER - y: 65 - -And here's the same sensor configuration, but instead with a semicircle gauge with a gradient background drawn by a multitude of ticks: - -.. figure:: images/lvgl_cook_thermometer_gauge.png - :align: center - -If you change the size of the widget, to obtain a uniform gradient, be sure to increase or decrease the ticks count accordingly. - -.. code-block:: yaml - - lvgl: - ... - pages: - - id: meter_page - widgets: - - obj: - height: 240 - width: 240 - align: CENTER - y: -18 - bg_color: 0xFFFFFF - border_width: 0 - pad_all: 14 - widgets: - - meter: - height: 100% - width: 100% - border_width: 0 - align: CENTER - bg_opa: TRANSP - scales: - - range_from: -15 - range_to: 35 - angle_range: 180 - ticks: - count: 70 - width: 1 - length: 31 - indicators: - - tick_style: - start_value: -15 - end_value: 35 - color_start: 0x3399ff - color_end: 0xffcc66 - - range_from: -150 - range_to: 350 - angle_range: 180 - ticks: - count: 0 - indicators: - - line: - id: temperature_needle - width: 8 - r_mod: 2 - value: -150 - - obj: # to cover the middle part of meter indicator line - height: 123 - width: 123 - radius: 73 - align: CENTER - border_width: 0 - pad_all: 0 - bg_color: 0xFFFFFF - - label: - id: temperature_text - text: "--.-°C" - align: CENTER - y: -26 - - label: - text: "Outdoor" - align: CENTER - y: -6 - -.. tip:: - - You can omit the ``obj`` used to hide the middle part of meter indicator line by using a bitmap ``image`` indicator as needle, were only the part hanging above the ticks scale is visible, the rest is transparent. - -.. _lvgl-cook-climate: - -Climate control ---------------- - -:ref:`lvgl-wgt-spb` is the ideal widget to control a thermostat: - -.. 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 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 - - sensor: - - platform: homeassistant - id: room_thermostat - entity_id: climate.room_thermostat - attribute: temperature - on_value: - - lvgl.spinbox.update: - id: spinbox_id - value: !lambda return x; - - lvgl: - ... - pages: - - id: thermostat_control - widgets: - - obj: - align: BOTTOM_MID - y: -50 - layout: - type: FLEX - flex_flow: ROW - flex_align_cross: CENTER - width: SIZE_CONTENT - height: SIZE_CONTENT - widgets: - - button: - id: spin_down - on_click: - - lvgl.spinbox.decrement: spinbox_id - widgets: - - label: - text: "-" - - spinbox: - id: spinbox_id - align: CENTER - text_align: CENTER - width: 50 - range_from: 15 - range_to: 35 - step: 0.5 - rollover: false - digits: 3 - decimal_places: 1 - on_value: - then: - - homeassistant.service: - service: climate.set_temperature - data: - temperature: !lambda return x; - entity_id: climate.room_thermostat - - button: - id: spin_up - on_click: - - lvgl.spinbox.increment: spinbox_id - widgets: - - label: - text: "+" - -.. _lvgl-cook-cover: - -Cover status and control ------------------------- - -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 examples, we need to get the state of the cover first. We'll use a numeric sensor to retrieve the current position of the cover and a text sensor to retrieve its current movement. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label in 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 closed. - -.. 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: 60% - 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: 60% - 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: - format: "%.0f%%" - args: [ 'id(cover_myroom_pos).get_state()' ] - - lvgl: - ... - pages: - - id: room_page - widgets: - - label: - x: 10 - y: 6 - width: 70 - text: "My room" - text_align: CENTER - - button: - x: 10 - y: 30 - width: 70 - height: 68 - widgets: - - label: - id: cov_up_myroom - align: CENTER - text: "\uF077" - on_press: - then: - - homeassistant.service: - service: cover.open - data: - entity_id: cover.myroom - - button: - 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 - - button: - x: 10 - y: 178 - width: 70 - height: 68 - widgets: - - label: - id: cov_down_myroom - align: CENTER - text: "\uF078" - on_press: - then: - - homeassistant.service: - service: cover.close - data: - entity_id: cover.myroom - -.. _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 necessary. - -.. 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, and can be overridden manually with style definitions (read further to see how). - -.. code-block:: yaml - - lvgl: - ... - theme: - label: - text_font: my_font # set all your labels to use your custom defined font - button: - bg_color: 0x2F8CD8 - bg_grad_color: 0x005782 - bg_grad_dir: VER - bg_opa: COVER - border_color: 0x0077b3 - border_width: 1 - text_color: 0xFFFFFF - pressed: # set some button colors to be different in pressed state - bg_color: 0x006699 - bg_grad_color: 0x00334d - checked: # set some button colors to be different in checked state - bg_color: 0x1d5f96 - bg_grad_color: 0x03324A - text_color: 0xfff300 - buttonmatrix: - bg_opa: TRANSP - border_color: 0x0077b3 - border_width: 0 - text_color: 0xFFFFFF - pad_all: 0 - items: # set all your buttonmatrix buttons 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 - 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 - bg_grad_color: 0x005782 - 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 - width: 100% - height: 30 - -Note that style definitions can contain common properties too, like positioning and sizing. - -.. _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.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. - -For the navigation bar we can use a :ref:`lvgl-wgt-bmx`. 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 - - lvgl: - ... - top_layer: - widgets: - - buttonmatrix: - align: bottom_mid - styles: header_footer - pad_all: 0 - outline_width: 0 - id: top_layer - items: - styles: header_footer - rows: - - buttons: - - id: page_prev - text: "\uF053" - on_press: - then: - lvgl.page.previous: - - id: page_home - text: "\uF015" - on_press: - then: - lvgl.page.show: main_page - - id: page_next - text: "\uF054" - on_press: - then: - lvgl.page.next: - -For this example to appear correctly, use the theme and style options from :ref:`above ` and LVGL's own library :ref:`fonts `. - -.. _lvgl-cook-statico: - -API connection status icon --------------------------- - -The top layer is useful to show status icons visible on all pages: - -.. figure:: images/lvgl_cook_statico.png - :align: center - -In the example below, we only show the icon when the connection with Home Assistant is established: - -.. code-block:: yaml - - api: - on_client_connected: - - if: - condition: - lambda: 'return (0 == client_info.find("Home Assistant "));' - then: - - lvgl.widget.show: lbl_hastatus - on_client_disconnected: - - if: - condition: - lambda: 'return (0 == client_info.find("Home Assistant "));' - then: - - lvgl.widget.hide: lbl_hastatus - - lvgl: - ... - top_layer: - widgets: - - label: - text: "\uF1EB" - id: lbl_hastatus - hidden: true - align: top_right - x: -2 - y: 7 - text_align: right - text_color: 0xFFFFFF - -Of note: - -- The widget starts *hidden* at boot and it's only shown when triggered by connection with the API. -- 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.png - :align: center - -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 - - lvgl: - ... - pages: - - id: main_page - widgets: - - obj: - align: TOP_MID - 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 - styles: header_footer - widgets: - - label: - text: "A second page" - align: CENTER - text_align: CENTER - text_color: 0xFFFFFF - ... - -For this example to work, use the theme and style options from :ref:`above `. - -.. _lvgl-cook-flex: - -Flex layout positioning ------------------------ - -:ref:`lvgl-layouts` aim to position widgets automatically, eliminating the need to specify coordinates to position each widget. This is a great way to simplify your configuration containing many widgets as it allows you to even omit alignment options. - -.. figure:: images/lvgl_cook_flex_layout.png - :align: center - -This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer fully-featured individual buttons, as they offer a wider range of customization possibilities as seen in the :ref:`lvgl-cook-cover` example. Here we use the **Flex** layout: - -.. code-block:: yaml - - lvgl: - ... - pages: - - id: room_page - widgets: - - obj: # a properly placed coontainer object for all these controls - align: CENTER - width: 240 - height: 256 - x: 4 - y: 4 - pad_all: 3 - pad_row: 6 - pad_column: 8 - bg_opa: TRANSP - border_opa: TRANSP - layout: # enable the FLEX layout for the children widgets - type: FLEX - flex_flow: COLUMN_WRAP # the order of the widgets starts top left - flex_align_cross: CENTER # they sould be centered - widgets: - - label: - text: "East" - - button: - id: but_cov_up_east - width: 70 # choose the button dimensions so - height: 68 # they fill the columns nincely as they flow - widgets: - - label: - id: cov_up_east - align: CENTER - text: "\U000F005D" # mdi:arrow-up - - button: - id: but_cov_stop_east - width: 70 - height: 68 - widgets: - - label: - id: cov_stop_east - align: CENTER - text: "\U000F04DB" # mdi:stop - - button: - id: but_cov_down_east - width: 70 - height: 68 - widgets: - - label: - id: cov_down_east - align: CENTER - text: "\U000F0045" # mdi:arrow-down - - - label: - text: "South" - - button: - id: but_cov_up_south - width: 70 - height: 68 - widgets: - - label: - id: cov_up_south - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_south - width: 70 - height: 68 - widgets: - - label: - id: cov_stop_south - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_south - width: 70 - height: 68 - widgets: - - label: - id: cov_down_south - align: CENTER - text: "\U000F0045" - - - label: - text: "West" - - button: - id: but_cov_up_west - width: 70 - height: 68 - widgets: - - label: - id: cov_up_west - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_west - width: 70 - height: 68 - widgets: - - label: - id: cov_stop_west - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_west - width: 70 - height: 68 - widgets: - - label: - id: cov_down_west - align: CENTER - text: "\U000F0045" - -This saved you from a considerable amount of manual calculation of widget positioning which would otherwise be required to place them manually with ``x`` and ``y``! You only need to determine a common width and height for your widgets to distribute them on the page as you prefer. (:ref:`lvgl-cook-icontext` below shows how to use custom icons.) - -.. _lvgl-cook-grid: - -Grid layout positioning ------------------------ - -But there's even more! With the **Grid** layout, you don't need to specify width and height for your widgets. All you have to do is divide the space into rows and columns; the widgets can be automatically be sized to fit into cells defined by these rows and columns. The same task from above, in a fully automated grid, looks like this: - -.. code-block:: yaml - - lvgl: - ... - pages: - - id: room_page - widgets: - - obj: # a properly placed coontainer object for all these controls - align: CENTER - width: 240 - height: 256 - pad_all: 6 - pad_row: 6 - pad_column: 8 - bg_opa: TRANSP - border_opa: TRANSP - layout: # enable the GRID layout for the children widgets - type: GRID # split the rows and the columns proportionally - grid_columns: [FR(1), FR(1), FR(1)] # equal - grid_rows: [FR(10), FR(30), FR(30), FR(30)] # like percents - widgets: - - label: - text: "East" - grid_cell_column_pos: 0 # place the widget in - grid_cell_row_pos: 0 # the corresponding cell - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - - button: - id: but_cov_up_east - grid_cell_column_pos: 0 - grid_cell_row_pos: 1 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_up_east - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_east - grid_cell_column_pos: 0 - grid_cell_row_pos: 2 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_stop_east - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_east - grid_cell_column_pos: 0 - grid_cell_row_pos: 3 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_down_east - align: CENTER - text: "\U000F0045" - - - label: - text: "South" - grid_cell_column_pos: 1 - grid_cell_row_pos: 0 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - - button: - id: but_cov_up_south - grid_cell_column_pos: 1 - grid_cell_row_pos: 1 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_up_south - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_south - grid_cell_column_pos: 1 - grid_cell_row_pos: 2 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_stop_south - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_south - grid_cell_column_pos: 1 - grid_cell_row_pos: 3 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_down_south - align: CENTER - text: "\U000F0045" - - - label: - text: "West" - grid_cell_column_pos: 2 - grid_cell_row_pos: 0 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - - button: - id: but_cov_up_west - grid_cell_column_pos: 2 - grid_cell_row_pos: 1 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_up_west - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_west - grid_cell_column_pos: 2 - grid_cell_row_pos: 2 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_stop_west - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_west - grid_cell_column_pos: 2 - grid_cell_row_pos: 3 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_down_west - align: CENTER - text: "\U000F0045" - -The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. With ``STRETCH`` their sizes and positions will automatically be calculated to fill in the cells, while the parent's ``pad_all``, ``pad_row`` and ``pad_column`` can help with spacing between them. See :ref:`lvgl-cook-weather` further down this page for another example relying on **Grid**. - -.. _lvgl-cook-btlg: - -ESPHome boot screen -------------------- - -To display a boot image with a spinner animation which disappears automatically after a few moments or on touch of the screen you can use the *top layer*. The trick is to put a base :ref:`lvgl-wgt-obj` full screen and child :ref:`lvgl-wgt-img` widget in its middle as the last item of the widgets list, so they draw 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/favicon-512x512.png - id: boot_logo - resize: 200x200 - type: RGB565 - use_transparency: true - - 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: - - image: - align: CENTER - src: boot_logo - y: -40 - - spinner: - align: CENTER - y: 95 - height: 50 - width: 50 - spin_time: 1s - arc_length: 60deg - arc_width: 8 - indicator: - arc_color: 0x18bcf2 - arc_width: 8 - 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 text. This is very flexible because you can prepare various sets of fonts at different sizes each with a different number of glyphs; this is important as it may help to conserve flash memory space. - -One example is when you'd like some MDI icons to be used in line with the text (similar to how LVGL's internal fonts and symbols coexist). You can use a font of your choice; choose the symbols/icons from MDI you want and mix them in a single sized set. - -.. 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 - -.. tip:: - - Follow these steps to choose your MDI icons: - - - To lookup your icons, use the `Pictogrammers `_ site. Click on the desired icon and note its codepoint (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-ckboxmark: - -Restore checkbox mark ---------------------- - -If you configure a custom font as the ``default_font`` used by LVGL and this font does not contain the `FontAwesome `__ symbols, you may observe that some widgets won't display correctly; specifically :ref:`lvgl-wgt-chk` won't show the checkmark when it's checked. - -To work around this issue, simply import only the checkmark symbol in the desired size and apply it through :ref:`lvgl-cook-theme` to all the checkboxes in the configuration: - -.. code-block:: yaml - - font: - - file: 'fonts/FontAwesome5-Solid+Brands+Regular.woff' - id: fontawesome_checkmark - size: 18 - bpp: 4 - glyphs: [ - "\uF00C", # ckeckmark, for checkbox - ] - - lvgl: - ... - theme: - checkbox: - indicator: - checked: - text_font: fontawesome_checkmark - -You could of course simply apply one of the built-in ``montserrat_`` packs, but that would not be beneficial on the binary size - it would uselessly include the entire set of glyphs in the flash. - -.. _lvgl-cook-iconstat: - -Toggle state icon button ------------------------- - -.. figure:: images/lvgl_cook_font_binstat.png - :align: left - -A common use case for icons is a status display. For example, a checkable (toggle) button will display different icons based on the status of a light or switch. 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`` states to apply *disabled styles* for these cases. - -If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like this: - -.. code-block:: yaml - - font: - - file: "custom/materialdesignicons-webfont.ttf" - id: mdi_42 - size: 42 - bpp: 4 - glyphs: [ - "\U000F0335", # mdi-lightbulb - "\U000F0336", # mdi-lightbulb-outline - ] - - text_sensor: - - platform: homeassistant - id: ts_remote_light - entity_id: light.remote_light - on_value: - then: - - lvgl.widget.update: - id: btn_lightbulb - state: - 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: !lambda |- - static char buf[10]; - 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: - ... - pages: - - id: room_page - widgets: - - button: - x: 110 - y: 40 - width: 90 - height: 50 - checkable: true - id: btn_lightbulb - widgets: - - label: - id: lbl_lightbulb - align: CENTER - text_font: mdi_42 - text: "\U000F0336" # mdi-lightbulb-outline - on_short_click: - - homeassistant.service: - service: light.toggle - data: - entity_id: light.remote_light - -.. _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: battery_icons_20 - text: "\U000F0091" # start with mdi-battery-unknown - -.. _lvgl-cook-animbatt: - -Battery charging animation --------------------------- - -.. figure:: images/lvgl_cook_animimg_batt.gif - :align: left - -To have an animation illustrating a battery charging, you can use :ref:`lvgl-wgt-aim` with a set of :ref:`images rendered from MDI ` 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: ani_battery_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 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: - -An analog clock ---------------- - -Using the :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets, we can create an analog clock which shows the date too. - -.. 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 ``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 at the beginning of every minute to update the line positions for each hand as well as the respective text. - -.. code-block:: yaml - - lvgl: - ... - pages: - - id: clock_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 - border_width: 0 - text_color: 0x000000 - scales: - - range_from: 0 # minutes scale - range_to: 60 - angle_range: 360 - rotation: 270 - ticks: - width: 1 - count: 61 - length: 10 - color: 0x000000 - indicators: - - line: - id: minute_hand - width: 3 - color: 0xa6a6a6 - r_mod: -4 - value: 0 - - 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: 10 - color: 0xC0C0C0 - label_gap: 12 - - 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 - - label: - styles: date_style - id: day_label - y: -30 - - label: - id: date_label - styles: date_style - y: 30 - - time: - - platform: homeassistant - id: time_comp - on_time_sync: - - script.execute: time_update - on_time: - - minutes: '*' - seconds: 0 - then: - - script.execute: time_update - - script: - - id: time_update - then: - - lvgl.indicator.update: - id: minute_hand - value: !lambda |- - return id(time_comp).now().minute; - - lvgl.indicator.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]; - -.. _lvgl-cook-keypad: - -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 (or ``key_code`` where configured) 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: keypad_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: lvgl_label - align: CENTER - text: "Enter code and \uF00C" - text_align: CENTER - - buttonmatrix: - id: lvgl_keypad - x: 20 - y: 85 - width: 200 - height: 190 - items: - pressed: - bg_color: 0xFFFF00 - 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: "\uF55A" - key_code: "*" - control: - no_repeat: true - - text: 0 - control: - no_repeat: true - - text: "\uF00C" - key_code: "#" - control: - no_repeat: true - - key_collector: - - 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: lvgl_label - text: !lambda 'return x.c_str();' - else: - - lvgl.label.update: - id: lvgl_label - text: "Enter code and \uF00C" - 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 - -Of note: - -- A base object ``obj`` is used as a parent for the label; this allows proper centering of the label as well as emphasizing it with shadows independently of the label's dimensions. -- ``align_to`` is used to align the label to the ``led`` vertically. -- Changing the background color of the buttons in ``pressed`` state. -- Use of the ``key_code`` configuration to send a different character to ``key_collector`` instead of the displayed symbol. - -.. _lvgl-cook-weather: - -Weather forecast panel ----------------------- - -Another example relying on the **Grid** layout can be a weather panel showing the forecast through the `OpenWeatherMap integration `__ of Home Assistant. - -.. figure:: images/lvgl_cook_weather.png - :align: center - -All the information displayed here could be retrieved to local ``platform: homeassistant`` sensors as desribed in several examples in this Cookbook, however, this time we take a different approach. Instead of pulling the data by ESPHome, we'll be pushing it from Home Assistant, to native :doc:`/components/text/lvgl` components. - -The weather condition icons we use are from MDI. We import just the ones corresponding to the weather conditions supported by the Weather integration in Home Assistant. For all the other labels you can use any :ref:`font ` of your choice. - -.. code-block:: yaml - - binary_sensor: - - platform: status - name: Status sensor - - font: - - file: "fonts/materialdesignicons-webfont.ttf" - id: icons_100 - size: 100 - bpp: 4 - glyphs: [ - "\U000F0594", # clear-night - "\U000F0590", # cloudy - "\U000F0F2F", # exceptional - "\U000F0591", # fog - "\U000F0592", # hail - "\U000F0593", # lightning - "\U000F067E", # lightning-rainy - "\U000F0595", # partlycloudy - "\U000F0596", # pouring - "\U000F0597", # rainy - "\U000F0598", # snowy - "\U000F067F", # snowy-rainy - "\U000F0599", # sunny - "\U000F059D", # windy - "\U000F059E", # windy-variant - "\U000F14E4", # sunny-off - ] - - lvgl: - ... - pages: - - id: weather_forecast - widgets: - - obj: - align: CENTER - width: 228 - height: 250 - pad_all: 10 - pad_column: 0 - layout: - type: GRID - grid_rows: [FR(48), FR(13), FR(13), FR(13), FR(13)] - grid_columns: [FR(10), FR(40), FR(40), FR(10)] - widgets: - - label: - text: "\U000F14E4" - id: lbl_weather_forecast_condition_icon - text_font: icons_100 - text_align: CENTER - grid_cell_row_pos: 0 - grid_cell_column_pos: 0 - grid_cell_column_span: 2 - grid_cell_x_align: CENTER - grid_cell_y_align: START - - - label: - text: "Unknown" - id: lbl_weather_forecast_condition_name - text_align: CENTER - grid_cell_row_pos: 0 - grid_cell_column_pos: 2 - grid_cell_column_span: 2 - grid_cell_x_align: STRETCH - grid_cell_y_align: CENTER - - - label: - text: "Feels like:" - grid_cell_row_pos: 1 - grid_cell_column_pos: 1 - - - label: - text: "--.- °C" - id: lbl_weather_forecast_tempap - text_align: RIGHT - grid_cell_row_pos: 1 - grid_cell_column_pos: 2 - grid_cell_x_align: STRETCH - - - label: - text: "Maximum:" - grid_cell_row_pos: 2 - grid_cell_column_pos: 1 - - - label: - text: "--.- °C" - id: lbl_weather_forecast_temphi - text_align: RIGHT - grid_cell_row_pos: 2 - grid_cell_column_pos: 2 - grid_cell_x_align: STRETCH - - - label: - text: "Minimum:" - grid_cell_row_pos: 3 - grid_cell_column_pos: 1 - - - label: - text: "--.- °C" - id: lbl_weather_forecast_templo - text_align: RIGHT - grid_cell_row_pos: 3 - grid_cell_column_pos: 2 - grid_cell_x_align: STRETCH - - - label: - text: "Now:" - grid_cell_row_pos: 4 - grid_cell_column_pos: 1 - - - label: - text: "--.- °C" - id: lbl_weather_outdnoor_now - text_align: RIGHT - grid_cell_row_pos: 4 - grid_cell_column_pos: 2 - grid_cell_x_align: STRETCH - - text: - - platform: lvgl - name: fr_cond_icon - widget: lbl_weather_forecast_condition_icon - mode: text - - platform: lvgl - name: fr_cond_name - widget: lbl_weather_forecast_condition_name - mode: text - - platform: lvgl - name: fr_tempap - widget: lbl_weather_forecast_tempap - mode: text - - platform: lvgl - name: fr_temphi - widget: lbl_weather_forecast_temphi - mode: text - - platform: lvgl - name: fr_templo - widget: lbl_weather_forecast_templo - mode: text - - platform: lvgl - name: wd_out_now - widget: lbl_weather_outdnoor_now - mode: text - -If you look carefully at the ``grid_columns`` variable, you'll notice that there are two thinner columns at left and right (``FR(10)``). Reason is to add some space to the labels from the edges. And that's why we had to use ``grid_cell_column_span`` for the widgets in the first row, to take up the space of multiple columns. - -These labels will appear in Home Assistant as `editable text components `__, which makes it very easy to update them with the ``text.set_value`` service. For this purpose, we add the following `automations `__ to Home Assistant: - -.. code-block:: yaml - - - id: weather_cond_forecast - alias: 'Weather Forecast Condition' - trigger: - - platform: state - entity_id: sensor.openweathermap_forecast_condition - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - service: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_cond_icon - data: - value: > - {% set d = { - "clear-night": "\U000F0594", - "cloudy": "\U000F0590", - "exceptional": "\U000F0F2F", - "fog": "\U000F0591", - "hail": "\U000F0592", - "lightning": "\U000F0593", - "lightning-rainy": "\U000F067E", - "partlycloudy": "\U000F0595", - "pouring": "\U000F0596", - "rainy": "\U000F0597", - "snowy": "\U000F0598", - "snowy-rainy": "\U000F067F", - "sunny": "\U000F0599", - "windy": "\U000F059D", - "windy-variant": "\U000F059E", - "unknown": "\U000F14E4", - "unavailable": "\U000F14E4", - } %} - {{ d.get( states('sensor.openweathermap_forecast_condition') ) }} - - - service: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_cond_name - data: - value: > - {% set d = { - "clear-night": "Clear Night", - "cloudy": "Cloudy", - "exceptional": "Except ional", - "fog": "Fog", - "hail": "Hail", - "lightning": "Lightning", - "lightning-rainy": "Lightning rainy", - "partlycloudy": "Partly cloudy", - "pouring": "Pouring", - "rainy": "Rainy", - "snowy": "Snowy", - "snowy-rainy": "Snowy rainy", - "sunny": "Sunny", - "windy": "Windy", - "windy-variant": "Windy cloudy", - "unknown": "Unknown", - "unavailable": "Unavai lable", - } %} - {{ d.get( states('sensor.openweathermap_forecast_condition') ) }} - - - id: weather_temp_feels_like_forecast - alias: 'Weather Temperature Feels Like' - trigger: - - platform: state - entity_id: sensor.openweathermap_feels_like_temperature - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - service: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_tempap - data: - value: "{{states('sensor.openweathermap_feels_like_temperature') | round(1)}} °C" - - - id: weather_temp_forecast_temphi - alias: 'Weather Temperature Forecast Hi' - trigger: - - platform: state - entity_id: sensor.openweathermap_forecast_temperature - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - service: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_temphi - data: - value: "{{states('sensor.openweathermap_forecast_temperature') | round(1)}} °C" - - - id: weather_temp_forecast_templo - alias: 'Weather Temperature Forecast Lo' - trigger: - - platform: state - entity_id: sensor.openweathermap_forecast_temperature_low - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - service: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_templo - data: - value: "{{states('sensor.openweathermap_forecast_temperature_low') | round(1)}} °C" - - - id: weather_temp_outdoor_now - alias: 'Weather Temperature Now' - trigger: - - platform: state - entity_id: sensor.outdoor_temperature - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - service: text.set_value - target: - entity_id: - - text.your_esphome_node_wd_out_now - data: - value: "{{states('sensor.outdoor_temperature') | round(1)}} °C" - -The automations will be triggered to update the labels every time the corresponding entities change, and when the ESPHome comes alive - the reason you also need the :doc:`/components/binary_sensor/status`. Note that you'll need to adjust the entity IDs corresponding to your ESPHome node depedning on how you :ref:`configured it to use its name`. - -.. _lvgl-cook-idlescreen: - -Turn off screen when idle -------------------------- - -LVGL has a notion of screen inactivity -- in other words, the time since the last user interaction with the screen is tracked. This can be used 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. Note that it's important to use the ``on_release`` trigger to accomplish this task. With a template number you can make the timeout adjustable 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.pause: - - touchscreen: - - platform: ... - on_release: - - 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 - -.. _lvgl-cook-antiburn: - -Prevent burn-in of LCD ----------------------- - -You can use this to protect and prolong the lifetime of the LCD screens, thus being more green and generating less hazardous waste. - -A common problem with wall-mounted LCD screens is that they display the same picture 99.999% of the time. Even if somebody turns off the backlight during the night or dark periods, the LCD screen keeps showing the same picture, but seen by nobody. This scenario is likely to lead to burn-in after a few years of operation. - -One way to mitigate this is to *exercise* the pixels periodically by displaying different content. ``show_snow`` option during LVGL paused state was developed with this in mind; it displays randomly colored pixels across the entire screen in order to minimize screen burn-in by exercising each individual pixel. - -In the example below, pixel training is done four times for a half an hour every night; it can be stopped by touching the screen. - -.. code-block:: yaml - - time: - - platform: ... - on_time: - - hours: 2,3,4,5 - minutes: 5 - seconds: 0 - then: - - switch.turn_on: switch_antiburn - - hours: 2,3,4,5 - minutes: 35 - seconds: 0 - then: - - 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: "Stopping Antiburn" - - if: - condition: lvgl.is_paused - then: - - lvgl.resume: - - lvgl.widget.redraw: - - delay: 1s - - lvgl.pause: - - touchscreen: - - platform: ... - on_release: - then: - - if: - 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. - -See Also --------- - -- :ref:`lvgl-main` -- :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 2139bd02683b6f218f72c02ccc6c92d2cbcb8dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Mon, 5 Aug 2024 15:36:49 +0200 Subject: [PATCH 524/564] Update lvgl.rst --- components/lvgl.rst | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 20a5bcfade..cd4560eba2 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -807,8 +807,6 @@ To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget The ``button`` can be also integrated as a :doc:`Binary Sensor ` or as a :doc:`Switch ` component. -See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable button to act on a Home Assistant service. - .. _lvgl-wgt-bmx: ``buttonmatrix`` @@ -939,7 +937,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row .. 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. + The Button Matrix widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. .. _lvgl-wgt-swi: @@ -983,8 +981,6 @@ The switch looks like a little slider and can be used to turn something on and o The ``switch`` can be also integrated as a :doc:`Switch ` component. -See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local component. - .. _lvgl-wgt-chk: ``checkbox`` @@ -1045,7 +1041,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c .. note:: - In case you configure ``default_font`` in the main section to a custom font, the checkmark will not be shown correctly when the checkbox is in the checked state. See :ref:`lvgl-cook-ckboxmark` how to easily resolve this. + In case you configure ``default_font`` in the main section to a custom font, the checkmark will not be shown correctly when the checkbox is in the checked state. The ``checkbox`` can be also integrated as a :doc:`Switch ` component. @@ -1316,8 +1312,6 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider to control entities in Home Assistant. - .. _lvgl-wgt-arc: ``arc`` @@ -1401,8 +1395,6 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider (or an arc) to control entities in Home Assistant. - .. _lvgl-wgt-spb: ``spinbox`` @@ -1480,8 +1472,6 @@ The spinbox contains a numeric value (as text) which can be increased or decreas The ``spinbox`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -See :ref:`lvgl-cook-climate` for an example illustrating how to implement a thermostat control using the spinbox. - .. _lvgl-wgt-mtr: ``meter`` @@ -2240,7 +2230,7 @@ This :ref:`action ` redraws the entire screen, or optionally onl This :ref:`action ` pauses the activity of LVGL, including rendering. -- **show_snow** (*Optional*, boolean): When 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 illustrating how to use this. +- **show_snow** (*Optional*, boolean): When 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. .. code-block:: yaml @@ -2439,8 +2429,6 @@ The ``on_idle`` :ref:`triggers ` are activated when inactivity time - light.turn_off: display_backlight - lvgl.pause: -See :ref:`lvgl-cook-idlescreen` for an example illustrating how to implement screen saving with idle settings. - .. _lvgl-seealso: See Also From 39aa9a70b108e1c868a876e48d0ce0e0a2202530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 10:38:12 +0200 Subject: [PATCH 525/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index cd4560eba2..c1ca8e84cf 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1876,7 +1876,7 @@ The tab view object can be used to organize content in tabs. The tab buttons are .. figure:: /components/images/lvgl_tabview.png :align: center -The tabs are indexed (zero based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button, by sliding horizontally on the content or via ``lvgl.tabview.select`` :ref:`action `, specifying its index. +The tabs are indexed (zero-based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button, by sliding horizontally on the content or via the ``lvgl.tabview.select`` :ref:`action `, specifying the tab's index. **Configuration variables:** From 816fd75c4d6fb39f76add3dd57ad821cf21ac177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 10:39:12 +0200 Subject: [PATCH 526/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index c1ca8e84cf..155fb546e5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -1893,7 +1893,7 @@ The tabs are indexed (zero-based) in the order they appear in the configuration - ``lvgl.tabview.select`` :ref:`action ` jumps the view to the desired tab: - **id** (**Required**): The ID of the tabview which receives this action. - - **index** (**Required**): The the zero based index of the tab to which to jump. + - **index** (**Required**): The (zero-based) index of the tab to which to jump. - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. **Triggers:** From bedabc5add2b16ab20498e51a95fcecfd3d0c6ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 10:39:28 +0200 Subject: [PATCH 527/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index 155fb546e5..fdc1f6ba4b 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -101,7 +101,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o .. tip:: - When using binary sensors (from physical keys) to interact with LVGL, if there are only 3 keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With 4 or more keys, a keypad configuration suits better. For example a 5-key keypad might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``: ``PREV``/``NEXT`` can select a widget within the group, ``UP``/``DOWN`` changes the value, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. + When using binary sensors (from physical keys) to interact with LVGL, if there are only three keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With four or more keys, a keypad configuration is generally more appropriate. For example, a keypad consisting of five keys might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``; ``PREV``/``NEXT`` are used to select a widget within the group, ``UP``/``DOWN`` changes the selected value and ``ENTER`` generates an ``on_press`` :ref:`trigger `. The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. From c7d2bde6c015ede53a493b30114ec0ca910bd4bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 10:39:47 +0200 Subject: [PATCH 528/564] Update components/lvgl.rst Co-authored-by: Keith Burzinski --- components/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl.rst b/components/lvgl.rst index fdc1f6ba4b..6330af96f5 100644 --- a/components/lvgl.rst +++ b/components/lvgl.rst @@ -12,7 +12,7 @@ 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 :ref:`display ` with LVGL under ESPHome you need an MCU from the ESP32 family. Although PSRAM is not a strict requirement, it is recommended for bigger displays. +To use LVGL with a :ref:`display ` in ESPHome, you'll need an ESP32 or supported ESP32 variant. PSRAM is not a strict requirement but it is generally recommended, especially for color displays with resolutions larger than approximately 240x240 pixels. The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. From 0ed50b58d6f0b088f26fe39d89dc756f76ea33bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 10:40:08 +0200 Subject: [PATCH 529/564] Update components/light/lvgl.rst Co-authored-by: Keith Burzinski --- components/light/lvgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 97f9512190..1c4f85b7af 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -12,8 +12,8 @@ and requires :ref:`LVGL ` to be configured. Supported widget is :ref:`lvgl-wgt-led`. A single light supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome light component. -Configuration options: ----------------------- +Configuration variables: +------------------------ - **widget** (**Required**): The ID of a ``led`` widget configured in LVGL, which will reflect the state of the light. - All other options from :ref:`light `. From 357d06dad5910f21ee0fec8c20ad1e7921b7a718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 11:16:14 +0200 Subject: [PATCH 530/564] LVGL initial, splitted doc --- components/lvgl/images/lvgl_align.png | Bin 0 -> 15911 bytes components/lvgl/images/lvgl_animimg.gif | Bin 0 -> 7025 bytes components/lvgl/images/lvgl_arc.png | Bin 0 -> 2738 bytes components/lvgl/images/lvgl_bar.png | Bin 0 -> 374 bytes components/lvgl/images/lvgl_baseobj.png | Bin 0 -> 730 bytes components/lvgl/images/lvgl_boxmodel.png | Bin 0 -> 9051 bytes components/lvgl/images/lvgl_button.png | Bin 0 -> 1062 bytes components/lvgl/images/lvgl_buttonmatrix.png | Bin 0 -> 2739 bytes components/lvgl/images/lvgl_checkbox.png | Bin 0 -> 1420 bytes components/lvgl/images/lvgl_dropdown.png | Bin 0 -> 2959 bytes components/lvgl/images/lvgl_image.png | Bin 0 -> 10371 bytes components/lvgl/images/lvgl_keyboard.png | Bin 0 -> 8996 bytes components/lvgl/images/lvgl_label.png | Bin 0 -> 1123 bytes components/lvgl/images/lvgl_led.png | Bin 0 -> 1123 bytes components/lvgl/images/lvgl_line.png | Bin 0 -> 1775 bytes .../lvgl/images/lvgl_main_screenshot.png | Bin 0 -> 134021 bytes components/lvgl/images/lvgl_meter.png | Bin 0 -> 7065 bytes components/lvgl/images/lvgl_msgbox.png | Bin 0 -> 4971 bytes components/lvgl/images/lvgl_roller.png | Bin 0 -> 2677 bytes components/lvgl/images/lvgl_slider.png | Bin 0 -> 521 bytes components/lvgl/images/lvgl_spinbox.png | Bin 0 -> 799 bytes components/lvgl/images/lvgl_spinner.gif | Bin 0 -> 36060 bytes components/lvgl/images/lvgl_switch.png | Bin 0 -> 737 bytes components/lvgl/images/lvgl_symbols.png | Bin 0 -> 30832 bytes components/lvgl/images/lvgl_tabview.png | Bin 0 -> 7993 bytes components/lvgl/images/lvgl_textarea.png | Bin 0 -> 4749 bytes components/lvgl/index.rst | 701 +++++ components/lvgl/widgets.rst | 1808 +++++++++++++ cookbook/images/lvgl_cook_animimg_batt.gif | Bin 0 -> 8109 bytes cookbook/images/lvgl_cook_climate.png | Bin 0 -> 1672 bytes cookbook/images/lvgl_cook_clock.png | Bin 0 -> 8115 bytes cookbook/images/lvgl_cook_cover.png | Bin 0 -> 4539 bytes cookbook/images/lvgl_cook_flex_layout.png | Bin 0 -> 5015 bytes cookbook/images/lvgl_cook_font_batt.png | Bin 0 -> 243 bytes cookbook/images/lvgl_cook_font_binstat.png | Bin 0 -> 2715 bytes cookbook/images/lvgl_cook_font_roboto_mdi.png | Bin 0 -> 2278 bytes cookbook/images/lvgl_cook_gauge.png | Bin 0 -> 4154 bytes cookbook/images/lvgl_cook_gradient_styles.png | Bin 0 -> 10498 bytes cookbook/images/lvgl_cook_keypad.png | Bin 0 -> 5951 bytes cookbook/images/lvgl_cook_pagenav.png | Bin 0 -> 1312 bytes cookbook/images/lvgl_cook_remligbut.png | Bin 0 -> 1696 bytes cookbook/images/lvgl_cook_statico.png | Bin 0 -> 700 bytes cookbook/images/lvgl_cook_thermometer.png | Bin 0 -> 11532 bytes .../images/lvgl_cook_thermometer_gauge.png | Bin 0 -> 5872 bytes cookbook/images/lvgl_cook_titlebar.png | Bin 0 -> 2366 bytes cookbook/images/lvgl_cook_volume.png | Bin 0 -> 1264 bytes cookbook/images/lvgl_cook_weather.png | Bin 0 -> 8364 bytes cookbook/lvgl.rst | 2247 +++++++++++++++++ 48 files changed, 4756 insertions(+) create mode 100644 components/lvgl/images/lvgl_align.png create mode 100644 components/lvgl/images/lvgl_animimg.gif create mode 100644 components/lvgl/images/lvgl_arc.png create mode 100644 components/lvgl/images/lvgl_bar.png create mode 100644 components/lvgl/images/lvgl_baseobj.png create mode 100644 components/lvgl/images/lvgl_boxmodel.png create mode 100644 components/lvgl/images/lvgl_button.png create mode 100644 components/lvgl/images/lvgl_buttonmatrix.png create mode 100644 components/lvgl/images/lvgl_checkbox.png create mode 100644 components/lvgl/images/lvgl_dropdown.png create mode 100644 components/lvgl/images/lvgl_image.png create mode 100644 components/lvgl/images/lvgl_keyboard.png create mode 100644 components/lvgl/images/lvgl_label.png create mode 100644 components/lvgl/images/lvgl_led.png create mode 100644 components/lvgl/images/lvgl_line.png create mode 100644 components/lvgl/images/lvgl_main_screenshot.png create mode 100644 components/lvgl/images/lvgl_meter.png create mode 100644 components/lvgl/images/lvgl_msgbox.png create mode 100644 components/lvgl/images/lvgl_roller.png create mode 100644 components/lvgl/images/lvgl_slider.png create mode 100644 components/lvgl/images/lvgl_spinbox.png create mode 100644 components/lvgl/images/lvgl_spinner.gif create mode 100644 components/lvgl/images/lvgl_switch.png create mode 100644 components/lvgl/images/lvgl_symbols.png create mode 100644 components/lvgl/images/lvgl_tabview.png create mode 100644 components/lvgl/images/lvgl_textarea.png create mode 100644 components/lvgl/index.rst create mode 100644 components/lvgl/widgets.rst create mode 100644 cookbook/images/lvgl_cook_animimg_batt.gif create mode 100644 cookbook/images/lvgl_cook_climate.png create mode 100644 cookbook/images/lvgl_cook_clock.png create mode 100644 cookbook/images/lvgl_cook_cover.png create mode 100644 cookbook/images/lvgl_cook_flex_layout.png create mode 100644 cookbook/images/lvgl_cook_font_batt.png create mode 100644 cookbook/images/lvgl_cook_font_binstat.png create mode 100644 cookbook/images/lvgl_cook_font_roboto_mdi.png create mode 100644 cookbook/images/lvgl_cook_gauge.png create mode 100644 cookbook/images/lvgl_cook_gradient_styles.png create mode 100644 cookbook/images/lvgl_cook_keypad.png create mode 100644 cookbook/images/lvgl_cook_pagenav.png create mode 100644 cookbook/images/lvgl_cook_remligbut.png create mode 100644 cookbook/images/lvgl_cook_statico.png create mode 100644 cookbook/images/lvgl_cook_thermometer.png create mode 100644 cookbook/images/lvgl_cook_thermometer_gauge.png create mode 100644 cookbook/images/lvgl_cook_titlebar.png create mode 100644 cookbook/images/lvgl_cook_volume.png create mode 100644 cookbook/images/lvgl_cook_weather.png create mode 100644 cookbook/lvgl.rst diff --git a/components/lvgl/images/lvgl_align.png b/components/lvgl/images/lvgl_align.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a1381ca6e132dea3ac5302df356af8131d754e GIT binary patch literal 15911 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 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_animimg.gif b/components/lvgl/images/lvgl_animimg.gif new file mode 100644 index 0000000000000000000000000000000000000000..9f6bce8bee17d7b8d415e4436d93d16152327b82 GIT binary patch literal 7025 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

YrQaDu@zRonb)p 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 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_baseobj.png b/components/lvgl/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/images/lvgl_boxmodel.png b/components/lvgl/images/lvgl_boxmodel.png new file mode 100644 index 0000000000000000000000000000000000000000..98251f41698f40b98077c1fdb5907c6e0a83eb10 GIT binary patch literal 9051 zcmch7cT^K^w=N2ZR0X692uKm72-2h~p-XSlL7LKAr~#xHKzf(1AQ%WC^w2?iFG}cD zdO{CX0-W&szH`^TcddKYI_s``|Hx$CcjlehZJyct*%PIup+ru?NP>rlN3Nm_(80sI zwTRoFxO)e;P4JC;jQhLgsiX87uWb0?7H&Xb|4RK89$rN}Db|V*HzsydHuA*7BfWp~ zy9MKD2I3~~yi-#G;N{_+;N=Bue!8W99a#!WGQ(0l78@9OMq z>*9qQ;^E1A*jjnn+C1|4;Pw8Il8U;P4ZkfB9v*wX3gDHVuldeA5lBz}N_2mN>v4z{ zmE5CS-&J{T=fBu`q_6y7>nVxoL@ijseN9svuuXFeq#L6lNQ+ax9s1x23CUX?l5pNf zeAVFu%50}Oiy6W;NpH9qlIGsDW9CP;vjcWB>ig`cr95YtJF0I{Qc@aqE6Gw*QYI?U zw*UYDTI(|^++57E8USGP94vr4(Dh#(Fz0#sk`ZiW*_XuG(B0e}%T%BcP5ZaE*{I5{ z_|&}Fzov|h9r_#;b=dcr=BXY;{fpqM$?vmGepN5&?%)6FD1@4>;s$|0_gPutj)!*3 z?VnKoRDS@gfw+5~e>a4i^JwQ2v|Q{;nkBo;Hvmzl9v+ngEE`4YS$calru7~uaVe>X z9<#?Sffps#?7ZeT%OJJ`X;YQ9(K4#s%d^b^KH*?+Nu}@>4fo^6U)9q28^DpDCBXvP zGD&#qDk?uq^r2p{IY&;CKvZ}fv!vY?gJk=Z1gI(tBki$z_YOH@_}8zG2#AQR_m_S~ z#>OJ;ce>+Q<3sR?N<097aDP@msiRT(lHuvW4B@eID|wNJ3twO1;|5B3Z26&``<(qs zad^Pp`Ir8+R4s>74M3=jHMg^E3qmtbrlDJe_?UwErRC31LI)Rdetrtf#)zS`gTzKL zgRq_DRJqkum3=%T#bTq60GNXL^D%l7O$*S|`bS9BwkfsvDnK!;9S}jE2|l zoDty~VlfChG852+nD=JFVzFMaj+F^&{w-#W-d#BT^uDTTadC38ad9akZgXkomfki7 zC@2)yTl>AqlQBa|3}%Vl(=B@QvoD!DF*CEooO`E8Bd5gVzV<7tGpe$hkcgK+l;y^7P6Ht&&4U|1cn)5anbzwtORfhnXKw^Dvt?)POZ)DBof&xQ**yF> zQvUVpBkkS3``&gn4oDr=JCP8}n}Eu|G{G?-cvuRvwDkv$W{qj%6gnZ(?cyX(HI&Xv zqc1?|Jq1ASjnu*!lc|=;3$Sp-YE-32=$j#AJC3a=Eu$bM{SDh*l`ibLJm_IjOJ(q0e~Wg=q5Ko~6u;^Pu);ATIht^AxD;wTMV<%CP5$a$WrT{p**wzTGV_obVxrCoUHb`b|ceDCTzL zzZNaII{co@!qIJN`Zbvu`=KIL6Pc-F#fIZ8CEU$>vkqKSfm0YxcJ@m8j>+4mP6`0P zFwQD~@8t!S%>M$Kx+Pv#fD-z(D3|)@wrBy5LSafj#2gm(ZbLk{9A|`oBhs4Wg2tru z|Bg-CEs4u^JqcBw(^-Xlz7!v#uQgeXa8?5V&bcts+rq3_+}<78qK`W`b}&Q?e*V;ofa9G+iD5fJJtzI}VLSYTH8ncuffBD`=T zdNbWhbPGRElC^rWkPH8S+sY-AVx^N+4ozhBVy9r(=oL6;8GSD=2#(GS?b#m+88loy z+T#0><#Z(R9Ds9O(`@BveZ#7;i)&@#{Gx{8GTM@5fuz)*?!C<2Zstob80^YJYA}xu zFW3d2zvotA=tssOt7`hY^8K0huK4A<)JwY+a_tOXB%Ok@oxizM2Ru;hC=(RuZpVJ0 zb#rQj)!fo+C0Cq{u;R~3;RGRxLURTzcdr*tSZY}eh=U(hQ^uspTc*IvOx8d{+c*!C zZz$jc0D6Lh&?kZ;%%9FLR09-{COaddb~@~Xh18bY=7cN1{7mAX4_!6ciwwfKr-r#V z)3yes9YbRC+9M^)W@a5M%~d`!h){Na%d`A$S|QCp+b`RWUDr36JT1BWl<6meG;k&T zV^I?%9&cKZNh9XI_MJF2y(>sEc+E>rN8y3@t23^$o(ce>D_ug(48r)##f(AOsa+j#`uUaDs}M4i5hD_YUt6dUB z433fK)YbhXORrm$b#G_=8vuat@lV<~?$fCV5Hp4Ar!Dlof}Z#EsjeZ*hQCgnNEdbs z^qaFs@`LE;5ejWQX6A-d*mL1G*K+jpia#N5e_zSyGyUBBt2zHDhfE}^F!V^oc`~Us zq;{ofxs7iJSzeP-jMzTRbin~qWUq(N2Gl>YmWU;TkSzE13)CGBJLW-Fdz69bFQzgr z4mC*e%I6xV4eLa|tt4$&1;0e%X?-z8%txVyc8$=tp`!Q<4r%pk*D?uKYAI4NmrPbu z{sVPM?scfoc`N&gKa7F%9a_hf`gtVhDUhoAj9yMiFkw*A6TuAk^O zyrSDR-g*2sBPD??F2EoX#pbvYNG&5@1z}e7tcL2|_~r#;OwtLPh0m*->7Z9IUvIm# zRwI}%*rNDoKNY6MM=c zVYGp=zm;}vU6`7^SwSutF`SFLND)8^4&oE(E`nw$Y2FXVSE?^|=3HJ!Z$+<4szgC} z-knj=JdaA(DYw0FmpXj?!2HTBtc(w|?1Pk_xjNXK<+wyIMfQr|vIWZh?E;v7dEZKB z{BCkRw^g{RTY_2|htuXk7HA69BZ%U?%z6*TTH=EzUgCmzh zjPMv#DeA}Yxq>ulPfbG&G?sZ_XL3f+hh7I>1_P8U>pP5mIEqQQO z>|c}1CI3y;emQE<>~f`a35@p2tp?hUcfcqmno=2s(odOAy#mHtB~DG5YZaQ2f2{0 zk;{<`Lgo9@62+U#MRR@QCCE{!GpH}FmZ`*ihe*Nt-hNNg`DAD1T^@U{-Ro#2A`Ab+nh|zai514yPD%ilx8JM z(6n1Ni4#NL*2W#Sikf8=ri)y^{a$PdZ_N`xAxplROy6Am>iAR?LaRgjRP3SLO5>0G zH_2jSLHlH9XY>xpT8pSs`AL8R4bF)4zJ4~`F@Yt_4tnIFt*ru#c!!#0?1Rp>v@(X}$Oo19?W1M2UB|k{LI6l)qr_=uJaj>^~ zr+T-iqYfQnM1QR8*d$roSXPLxyg_zXqfJvY4?ZbVIv&lNG!}kvc4qtbWL~B-SG{u@ zlfHjk(oBDX)dB7#qNcOpL8fc-eHOU zBBBZ1PgSr1bP;#_JFWjWB9kOKJx@|v7owzb#YMvF6hBvi)4x>n^f++-G)P%TW}eSP zwC9!@#F{!lRe8UxNq_%P6 z3W_AdV^Bv&hgBxm-;*7vBhJg8S%=SWc#Ofy{lJ}?NjEeMk#EzN1kw6-`|mM2V!qJ_ zUFAJJbj~8-L4Z$00npOA9~u_+{Qc;o?3X~2SSB&WXj(omXpG%(b`+SLiT%+dJaWbt zZP^l@M+}zOvjfy6uBr-eD3W6F-(=HQ!ll9q&xjZK%^ED{>fFy(;$;(3Qo?c7{0bD_ z@)}n;miz3P&-d4)q&)E29DOx3*4@*?fvfjPX`ji(vq+Ci7}^bf39;$`TaDyOD{E*N zOwzyf;+cS3z)kK`Qqr)*cbv}qEH+Q*4r1Nbnok!x8i450MjuzF`39P(sHl=j-o506 zgpbdyyEoIyZa9`>P@~UYT#lqq$)wX<9c6KGab#4~7)&Tr%$23+O-5)kw`PeqZe!rt zhpTq=H`d%gY}ePg+3P{6Mu>jL2M+ zqGE4Kc7&I@Id{kSFHEY{`maJYC=C*)@+4m+qlm);b`B2hLRFfxzkf^2eR5s`^?Y$8 z6OAZNllqO^#(y+XSO;omi{Fx!ZG9%aCeVtdN*AzDbaEcL^lW}pY{%o=uELI4k8Of zZIQspNFM0zdyD1eg5xj~G5LEEm;(P}R0GhU#&NQ{)_HdP-BbHYU$u2FczS&NrD3c8 zaf$!Q9RnhE{4bFZw+FswGG|L+;%-YH8{E6shq8ct<5+Z-YfF?8iyvUJ&U-}qbZM^M zlU~ZVoMaA1e^~u4Qb&mk^rs8JbDP%;Qifmgtc3=Ni>F6tr96G|_Oj2RY2gxxEtrwr ze>-YTZx;MwVe|aX1lFFMYJ?k=Mre=z1M?N%x5Cz9#msc~Nmeoes|+0zm_g**(m8XT zbsgK`(;T0Lu^NWHQI|&V9X%6!>41~Y8^$MI2sKlKuE9$QY^mHcsAZGb_27gS*yin4 zSoe%q$m0Y<)~lxSnvnwQ5mn)rIM!%y@ACD?-P|LXJ4<0czs=6JcM&Ij~~d0AKfbIQtyy_ zzGpdzupT|`E8{V1sSYAcJT7Gf@(vf6C>WImv@9r|Pz(%7+6*LZGw|~moPbEx+|lPj zVmp!`i9@yV4@N}R25})4Dzbsy&C&M!@A_6b&w$hLNLiZr%G809+?7D;UHN*|E$EKe z&~*5Rc#V$D&9O*Hh6o5E|9$`uZK{KQd-KX}S5DZj-VUw0Y4|3h@@nP1ST!?C*2x#% z0isVdx&})<^|F7Ce*WISccc^+M?M<-E?Cc5OTUKl+)v%`*RNmYf#=?(7a-=VxvL+H zN%!hG336D`F=g>SNZ59Ea9Wkp$h$70r*41SK1hkLz4G#}(=7|;)+{s1Rvtl=E7nh8 zj#(7gL9D@8cac*Zg=d0POSMAT=lb1Iif7UHfuW`<3S2U->01;=Oqv(lcY%%1?U3~2 zu7(zq4L(nHskmzL!gYx>wlcj^9Sqw$S-IE+#kH6v+kXrth)zj~1u}$M<&88`1bC z_m&2F1@tv9!a7*L>P_pEz*g*^gUHCTrS3c5LA-K<1pe(wUhGSDq~+c|Pb#+=7K6)N zYzxo%ECxahV40}%38>*cYHp2Z`%8uSDxqS6Jc5%yp9Y!#6~?NaTd!ghA;0q}ZmSY~ z^~TKb^4Lu24ckwwWUy>rdHE3N6YDhpiKJs67u>H{6y~QGj3XPk^NE1XD1362) zetrH3^TcModp?sTX3CA3MJBUr$C=Z`)1_Rw+2@Z@2za~@%>cyQVWlkg`RXy7a!YoM z{4B**+SW^%aY~?T$;zhpDu^4s<{OD-7V}d zHG!=v07DlzL(|<(mN8k&HoTtywcIoxIW=58vpmWUG89e^rT;XEmfyAPWY?etbR^uF~o}VAN ztk$IwVZ}V2mKJ70@h4RS4k1)Ns5o!{9@JZJl%Ga4f06bVrERIxYQ0^@@rOcWghxI% zB3L5kyPAqP7HtK3amMl3Le*dc9#Pp>AuQ4fqpyu-ud|9 zJn+H5f?1LOr^$|ak@> zEI|2fBxUv3jJTtEQG|cvCG?`yNIV+3r^)0e5FXRwlV`gdZowr^LV}w8T!;q>U zjJlp8zCOI3KSQ@Lr9Hb!;*&!%85&Od7_`F)6az&_PFn+I9Tv=WVYU25wU1p~{Ds@| z?)4Pp$&{G*ch8Gdafne7UmJ?^E|^ksV$~j12l0Rd#mVOLP-P~oaojljnc?imTj^6* zNpgBlr5*IAIY;Gx;gfC-;B9qN94u)`N|m{kFEY_TS!`&G%-#ivO7hY~9vY zq~usmmqyv}(G$1qM~vyR+1S9S zA(Lq|%|mbRpMu-h9O1K9bWyc|;T}?w$uA>fnGlbjm8Qz{qkd2p0&$FQ<2g1km%n}; zix5COWCIM%Nl zmhTNs=`e|7=WnspWPklqN` z{t~qqBs|(sLl)L?lG|3OCTICb3(lg|?BDI!8}T`eD5Ui&=^pK2z%81muLJ9NOhnNm z9OBzJB0o*sz5Qyg+-hQpMhG@9ow_pMV%&z9!B~`xnud3igibZ>g;TS_BZ+A_og{nw zDso18T=((9(PqlXf9o*8eD7F1=wa#n%Zuw0=k z*9<~z44U2?*a0qrDUq4Dnu-mE-}JcBlvQqFu}(i%R%FO7FLy?Yi%&M%b$-N2ksXJ$ zEiT@;U8nF(XAk<0sL=TKo@>6X+9UC|>(HGY^n{2OjPX8`;~um94V}xbro69;*GR%) z-`96ypE1Dqrp$j+Xz!`CaYQ&lfI#56hdk`sJqUZ89>|GUId%WnnqIfc!KhrxA5Tpa z0$YTn_?r7Z;sx9@a+P!Mlemk?dY0|c<(J{%lJ>08q2r&MgojV%*|O*v+-rpd_&77Y1dl&pY-njq;I?c;vD5dgASE`C*WEMR)-Z;(J1glrs>A1SK zdj5F!r*d+@fP?L6VlZ~BMPJ20f8b$h$FY-0iQbdT<98T4U1x68#E^MwaO;N)L94H- zG}J)!Ou*^kEjbyUY#C?PG?$5ID*<21Y~>VKR`=-8ME_{*Wkrik@|$^ zLvJn|oxXPFL1<`E`ADp9bBfYoHg0aMzelNd@5^1X7uwLY=AJAGUj@v%+*<$13DqbS z1ZF%PFf@$Cl9`OE-W$JaAyhYT85m(RNqX2C4~G|*Ss==yW?g=h3tQbZfe&NFf}x3G zxV|{0cFTavRL1r{;r^fBdi;Cve`12vZe6oVJ)6+GelW&x^BIeZf(D@MwPomk01j}) AumAu6 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_button.png b/components/lvgl/images/lvgl_button.png new file mode 100644 index 0000000000000000000000000000000000000000..c80d07f2d16b54fcc0b841b1e9d703cec2db3ecf GIT binary patch literal 1062 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 Q4Wj@X%hRYTq|fz#16OP$v;Y7A literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_checkbox.png b/components/lvgl/images/lvgl_checkbox.png new file mode 100644 index 0000000000000000000000000000000000000000..31b63cc7f5eeecdcfb2f5b39df9a530a6e7496b1 GIT binary patch literal 1420 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 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_keyboard.png b/components/lvgl/images/lvgl_keyboard.png new file mode 100644 index 0000000000000000000000000000000000000000..a9b009d310b9e2617b9205df246dae67333a710a GIT binary patch literal 8996 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 WlPM2Y`?diK4+c+HKbLh*2~7ZgofS|3 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_led.png b/components/lvgl/images/lvgl_led.png new file mode 100644 index 0000000000000000000000000000000000000000..0349f1b9cde81373ffe8919880e8e8f01e2de1ab GIT binary patch literal 1123 zcmV-p1f2VcP)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/lvgl/images/lvgl_line.png b/components/lvgl/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/images/lvgl_main_screenshot.png b/components/lvgl/images/lvgl_main_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..a8c971a901e5a2623316069fdd7d6615ebd4520d GIT binary patch literal 134021 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 `-gHYpC9M8$NJbjIk>De*TFYhU9LE=axSr5) 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 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_meter.png b/components/lvgl/images/lvgl_meter.png new file mode 100644 index 0000000000000000000000000000000000000000..1283126cccb54041511b0ec5e9084869e81a5eef GIT binary patch literal 7065 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 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_msgbox.png b/components/lvgl/images/lvgl_msgbox.png new file mode 100644 index 0000000000000000000000000000000000000000..101a40c8b4f71430581d95d0cdfc91a562c905e3 GIT binary patch literal 4971 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 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_roller.png b/components/lvgl/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/images/lvgl_slider.png b/components/lvgl/images/lvgl_slider.png new file mode 100644 index 0000000000000000000000000000000000000000..d2de4030d2fc6ddbf12efd85046016cfbc97f645 GIT binary patch literal 521 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 H#$XKq@`m>x literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_switch.png b/components/lvgl/images/lvgl_switch.png new file mode 100644 index 0000000000000000000000000000000000000000..9864b2b79bb7768789c766ac5f2c10deb94eace9 GIT binary patch literal 737 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 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_tabview.png b/components/lvgl/images/lvgl_tabview.png new file mode 100644 index 0000000000000000000000000000000000000000..ae18acf31a59a254690b250414f57bdadb3fc6b4 GIT binary patch literal 7993 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 literal 0 HcmV?d00001 diff --git a/components/lvgl/images/lvgl_textarea.png b/components/lvgl/images/lvgl_textarea.png new file mode 100644 index 0000000000000000000000000000000000000000..1382f7e10061ed79797ee3b8ef067dd5b6a9b662 GIT binary patch literal 4749 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 (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 `__. + +.. figure:: /components/images/lvgl_main_screenshot.png + +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 for bigger displays. + +The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. + +For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred), a :doc:`/components/sensor/rotary_encoder` or a custom keypad made up from discrete :doc:`Binary Sensors ` 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 complete list of widgets supported within ESPHome. Not all LVGL widgets are implemented, just those commonly used to support home automation needs/tasks. + +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 the label. Complex widgets internally consist of several smaller/simpler widgets; these are known as parts, each of 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. + +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 + :widths: 1 1 + + * - LVGL Widget + - ESPHome component + + * - ``button`` + - :doc:`Switch `, :doc:`Binary Sensor ` + + * - ``switch``, ``checkbox`` + - :doc:`Switch ` + + * - ``slider``, ``arc``, ``spinbox`` + - :doc:`Number `, :doc:`Sensor ` + + * - ``dropdown``, ``roller`` + - :doc:`Select ` + + * - ``label``, ``textarea`` + - :doc:`Text `, :doc:`Text Sensor ` + + * - ``led`` + - :doc:`Light ` + +These are useful with `Home Assistant automations `__ interacting directly with the widgets. + +Main Configuration +------------------ + +Although LVGL is a complex matrix of objects-parts-states-styles, ESPHome simplifies this into a hierarchy. + +At the highest level of the LVGL object hierarchy is the display (represented by 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 to be presented on the display. + +The following configuration variables 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 variables:** + +- **displays** (*Optional*, list, :ref:`config-id`): A list of display IDs where LVGL should perform rendering based on its configuration. This may be omitted if there is a single display configured, which will be used automatically. +- **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. + - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a display. + - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the touchscreen, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. +- **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. + - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. + - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. + - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: + - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. + - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. + - **long_press_time** (*Optional*, :ref:`Time `): For the rotary encoder, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the rotary encoder, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. +- **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. + - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. + - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``UP`` key. + - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``DOWN`` key. + - **right** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. + - **left** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. + - **esc** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ESC`` key. + - **del** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``DEL`` key. + - **backspace** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``BACKSPACE`` key. + - **enter** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. + - **next** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``NEXT`` key. + - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``PREV`` key. + - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``HOME`` key. + - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``END`` key. + - **long_press_time** (*Optional*, :ref:`Time `): For the keypad, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the keypad, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. + + .. tip:: + + When using binary sensors (from physical keys) to interact with LVGL, if there are only 3 keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With 4 or more keys, a keypad configuration suits better. For example a 5-key keypad might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``: ``PREV``/``NEXT`` can select a widget within the group, ``UP``/``DOWN`` changes the value, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. + + The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. + +- **color_depth** (*Optional*, string): The color deph at which the contents are generated. Currently only ``16`` is supported (RGB565, 2 bytes/pixel), which is the default value. +- **buffer_size** (*Optional*, percentage): The percentage of screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. +- **log_level** (*Optional*, string): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. +- **byte_order** (*Optional*, int16): The byte order of the data LVGL outputs; either ``big_endian`` or ``little_endian``. Defaults to ``big_endian``. +- **disp_bg_color** (*Optional*, :ref:`color `): Solid color used to fill the background. Can be changed at runtime with the ``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. Also see :ref:`lvgl-wgt-img` for a note regarding supported image formats. +- **default_font** (*Optional*, ID): 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 widget's ``styles`` configuration. See :ref:`below ` for more details. +- **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. +- **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. May not be used if ``pages`` (below) is configured. +- **pages** (*Optional*, list): A list of page IDs. Each page acts as a parent for widgets placed on it. May not be used with ``widgets`` (above). Options for each page: + - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. + - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. + - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. + - All other options from :ref:`lvgl-styling` to be applied to this page. +- **page_wrap** (*Optional*, boolean): Wrap from the last to the first page when navigating between them with :ref:`lvgl-pgnx-act`. Defaults to ``true``. +- **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, which may be useful for widgets which always need to be visible. + - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. + - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. + - All other options from :ref:`lvgl-styling` to be applied to this page. +- **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. +- All other options from :ref:`lvgl-styling` to be applied to all widgets directly. + +**Example:** + +.. code-block:: yaml + + # Example configuration entry + lvgl: + displays: + - my_display + touchscreens: + - my_touch + pages: + - id: main_page + widgets: + - label: + align: CENTER + text: 'Hello World!' + +See :ref:`lvgl-cook-navigator` in the Cookbook for an example illustrating how to easily implement a page navigation bar at the bottom of the screen. + +.. _lvgl-color: + +Colors +****** + +Colors can be specified anywhere in the LVGL configuration either by referencing a preconfigured :ref:`ESPHome color ` ID or by representing the color in the common hexadecimal notation. For example, ``0xFF0000`` would be red. + +.. _lvgl-opa: + +Opacity +******* + +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: + +Fonts +***** + +Two font choices are available: + +**ESPHome fonts** + +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. + +.. tip:: + + For best results, set ``bpp: 4`` to get the glyphs rendered with proper anti-aliasing. + +Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples illustrating how to use icons and text with TrueType/OpenType fonts. + +**Library fonts** + +The LVGL library offers by default prerendered sets with ASCII characters (``0x20-0x7F``), the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from `Montserrat Medium `__, and 60 symbols from `FontAwesome `__ (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**, included if ``default_font`` option is missing) +- ``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 + +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 preceded by ``\u``. For example: ``\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, 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. + +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. + +.. _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 box defined with ``width`` and ``height`` of the widgets (pixels or parent content area percentage; not drawn, just for calculations). +- *border*: the border line, drawn on the inner side of the bounding box (pixels). +- *outline*: the outline, drawn on the outer side of the bounding box (pixels). +- *padding*: space to keep between the border of the widget and its content or children (*I don't want my children too close to my sides, so keep this space*). +- *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). + +You can adjust the appearance of widgets by changing their foreground, background, border color and/or font. Some widgets allow for more complex styling, effectively changing all or part of their appearance. + +**Styling variables:** + +- **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*, dict): Set dithering of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. Defaults to ``NONE``. +- **bg_grad_dir** (*Optional*, dict): 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`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``0``. +- **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``255``. +- **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. Inherited from parent. Defaults to ``COVER``. +- **bg_image_src** (*Optional*, :ref:`image `): The ID of an existing image configuration, to show as the background of the widget. +- **bg_image_opa** (*Optional*, :ref:`opacity `): Opacity of the background image of the widget. +- **bg_image_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the background image of the widget. +- **bg_image_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring of the background image of the widget. +- **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 as a YAML list, defaults to ``NONE``): + - ``NONE`` + - ``TOP`` + - ``BOTTOM`` + - ``LEFT`` + - ``RIGHT`` + - ``INTERNAL`` +- **radius** (*Optional*, uint16): The radius to be used to form the widget's rounded corners. 0 = no radius (square corners); 65535 = pill shaped widget (true circle if it has same width and height). +- **clip_corner** (*Optional*, boolean): If set to ``true``, overflowing content will be clipped off by the widget's rounded corners (``radius`` > ``0``). +- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. Defaults to ``0``. +- **outline_color** (*Optional*, :ref:`color `): Color used 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. +- **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 `): Color used to create a drop shadow under the widget. Defaults to ``0`` (black). +- **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): 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): Horizontal anchor point of the transformation. Relative to the widget's top left corner. +- **transform_pivot_y** (*Optional*, int16): Vertical anchor point of the transformation. Relative to the widget's top left corner. +- **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. + +.. _lvgl-theme: + +Themes +****** + +The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. + +You can configure a global theme for all widgets at the top level with the ``theme`` configuration variable. In the example below, all the ``arc``, ``slider`` and ``button`` widgets will, by default, use the styles and properties defined here. A combination of styles and :ref:`states ` can be chosen for every widget. + +.. code-block:: yaml + + lvgl: + theme: + arc: + scroll_on_focus: true + group: general + slider: + scroll_on_focus: true + group: general + button: + 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 individual configuration level of each widget. This can be done in batches, using the ``style_definitions`` configuration variable of the main component. +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 style ``y`` locally: + +.. code-block:: yaml + + widgets: + - label: + id: day_label + styles: date_style # apply the definition 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 :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: + +.. 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 precedence 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 value precedence of states is quite intuitive and it's something the user would expect naturally. For example, 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 override the *pressed* color, defeating its purpose.) + +Feel free to experiment to discover inheritance and precedence of the styles based on states between the nested widgets. + +:ref:`lvgl-cook-theme` The Cookbook contains an example illustrating how to easily implement a gradient style for your widgets. + +.. _lvgl-layouts: + +Layouts +******* + +Layouts aim to position widgets automatically, eliminating the need to specify ``x`` and ``y`` coordinates to position each widget. This is a great way to simplify your configuration as it allows you to omit alignment options. + +The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. The position and size calculated by the layout overwrites the *normal* ``x``, ``y``, ``width``, and ``height`` settings of the children. + +Checkout :ref:`lvgl-cook-flex`, :ref:`lvgl-cook-grid` and :ref:`lvgl-cook-weather` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. + +The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` can be used on widgets to ignore them in layout calculations. + +**Configuration variables:** + +- **layout** (*Optional*, dict): A dictionary describing the layout configuration: + - **type** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. + - Further options from below depending on the chosen type. + +**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 spacing between items and tracks and even handle growing the layout to make the item(s) fill the remaining space with respect to minimum/maximum width and height. + +**Terms used:** + +- *track*: the rows or columns *main* direction flow: row or column in the direction in which the items are placed one after the other. +- *cross direction*: perpendicular to the main direction. +- *wrap*: if there is no more space in the track a new track is started. +- *gap*: the space between the rows and columns or the items on a track. +- *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). It dictates what amount of the available space the widget should take up. For example if all items on the track have a ``grow`` set to ``1``, the space in the track will be distributed equally to all of them. If one of the items has a value of 2, that one would take up twice as much of the space as either one of the others. + +**Configuration variables:** + + - **flex_flow** (*Optional*, string): 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. + + - **flex_align_main** (*Optional*, string): Determines how to distribute the items in their track on the *main* axis. For example, flush the items to the right on with ``flex_flow: ROW_WRAP`` (known as *justify-content* in CSS). Possible options below. + - **flex_align_cross** (*Optional*, string): Determines how to distribute the items in their track on the *cross* axis. For example, if the items have different height place them to the bottom of the track (known as *align-items* in CSS). Possible options below. + - **flex_align_track** (*Optional*, string): Determines how to distribute the tracks (known as *align-content* in CSS). Possible options below. + + Values for use with ``flex_align_main``, ``flex_align_cross``, ``flex_align_track``: + + - ``START``: means left horizontally and top vertically (default). + - ``END``: means right horizontally and bottom vertically. + - ``CENTER``: simply center. + - ``SPACE_EVENLY``: items are distributed so that the spacing between any two items (and the space to the edges) is equal. Does not apply to ``flex_align_track``. + - ``SPACE_AROUND``: items are evenly distributed in the track with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. Does not apply to ``flex_align_track``. + - ``SPACE_BETWEEN``: items are evenly distributed in the track: first item is on the start line, last item on the end line. Does not apply to ``flex_align_track``. + + - **pad_row** (*Optional*, int16): Set the padding between the rows, in pixels. + - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. + - **flex_grow** (*Optional*, int16): Flex grow can be used to make one or more children fill the available space on the track. When more children have grow parameters, the available space will be distributed proportionally to the grow values. Defaults to ``0``, which disables growing. + +**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(s) can span through multiple columns or rows. The track's size can be set in pixels, to the largest item of the track (``CONTENT``) or in "free units" to distribute the free space proportionally. + +**Terms used:** + +- *tracks*: the rows or the columns. +- *gap*: the space between the rows and columns or the items on a track. +- *free unit (FR)*: a proportional distribution unit for the space available on the track. It accepts a unitless integer value that serves as a proportion. It dictates what amount of the available space the widget should take up. For example if all items on the track have a ``FR`` set to ``1``, the space in the track will be distributed equally to all of them. If one of the items has a value of 2, that one would take up twice as much of the space as either one of the others. + +**Configuration variables:** + + - **grid_rows** (**Required**): The number of rows in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional integer value). + - **grid_columns** (**Required**): The number of columns in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional integer value). + - **grid_row_align** (*Optional*, string): How to align the row. Works only when ``grid_rows`` is given in pixels. Possible options below. + - **grid_column_align** (*Optional*, string): How to align the column. Works only when ``grid_columns`` is given in pixels. Possible options below. + - **pad_row** (*Optional*, int16): Set the padding between the rows, in pixels. + - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. + +In a grid layout, *all the widgets placed on the grid* will get some additional configuration variables to help with placement: + + - **grid_cell_row_pos** (**Required**, int16): Position of the widget, in which row to appear (0 based count). + - **grid_cell_column_pos** (**Required**, int16): Position of the widget, in which column to appear (0 based count). + - **grid_cell_x_align** (*Optional*, string): How to align the widget horizontally within the cell. Can also be applied through :ref:`lvgl-styling`. Possible options below. + - **grid_cell_y_align** (*Optional*, string): How to align the widget vertically within the cell. Can also be applied through :ref:`lvgl-styling`. Possible options below. + - **grid_cell_row_span** (*Optional*, int16): How many rows to span across the widget. Defaults to ``1``. + - **grid_cell_column_span** (*Optional*, int16): How many columns to span across the widget. . Defaults to ``1``. + + .. note:: + + These ``grid_cell_`` variables apply to widget configuations! + +Values for use with ``grid_column_align``, ``grid_row_align``, ``grid_cell_x_align``, ``grid_cell_y_align``: + + - ``START``: means left horizontally and top vertically (default). + - ``END``: means right horizontally and bottom vertically. + - ``CENTER``: simply center. + - ``STRETCH``: stretch the widget to the cell in the respective direction. Does not apply to ``grid_column_align``, ``grid_row_align``. + - ``SPACE_EVENLY``: items are distributed so that the spacing between any two items (and the space to the edges) is equal. + - ``SPACE_AROUND``: items are evenly distributed in the track with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. + - ``SPACE_BETWEEN``: items are evenly distributed in the track: first item is on the start line, last item on the end line. + +.. tip:: + + To visualize real, calculated sizes of transparent widgets you can temporarily set ``outline_width: 1`` on them. + +Widgets +******* + +LVGL supports a list of :ref:`lvgl-widgets` which can be used to draw interactive objects on the screen. + +Actions +------- + +Several actions are available for LVGL, these are outlined below. + +.. _lvgl-rfrsh-act: + +``lvgl.widget.redraw`` +********************** + +This :ref:`action ` redraws the entire screen, or optionally only a widget on it. + +- **id** (*Optional*): The ID of a widget configured in LVGL which you want to redraw; if omitted, the entire screen will be redrawn. + +.. code-block:: yaml + + on_...: + then: + - lvgl.widget.redraw: + +.. _lvgl-pause-act: + +``lvgl.pause`` +************** + +This :ref:`action ` pauses the activity of LVGL, including rendering. + +- **show_snow** (*Optional*, boolean): When 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 illustrating how to use this. + +.. code-block:: yaml + + on_...: + then: + - lvgl.pause: + show_snow: true + +.. _lvgl-resume-act: + +``lvgl.resume`` +*************** + +This :ref:`action ` resumes the activity of LVGL, including rendering. + +.. code-block:: yaml + + on_...: + then: + - lvgl.resume: + +``lvgl.update`` +*************** + +This :ref:`action ` allows changing/updating the ``disp_bg_color`` or ``disp_bg_image`` configuration variables of the main component, making it possible to 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`` +****************************************** + +This :ref:`action ` changes the page to the next/previous based on the configuration (pages with their ``skip`` option enabled are...skipped). Page changes will wrap around at the end. + +- **animation** (*Optional*): Animate page changes as specified. One of: ``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``. +- **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`` +****************** + +This :ref:`action ` shows a specific page (including pages with their ``skip`` option enabled). + +- **id** (**Required**): The ID of the page to be shown. +- **animation** (*Optional*): Animate page changes as specified. One of: ``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``. +- **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 + +.. _lvgl-cond: + +Conditions +---------- + +.. _lvgl-idle-cond: + +``lvgl.is_idle`` +**************** + +This :ref:`condition ` checks if the amount of time specified has passed since the last touch event. + +- **timeout** (**Required**, :ref:`templatable `, int): Amount of :ref:`time ` expected since the last touch event. + +.. code-block:: yaml + + # In some trigger: + on_...: + then: + - if: + condition: lvgl.is_idle + timeout: 5s + then: + - light.turn_off: + id: display_backlight + transition_length: 3s + +.. _lvgl-paused-cond: + +``lvgl.is_paused`` +****************** + +This :ref:`condition ` checks if LVGL is in the paused state or not. + +.. code-block:: yaml + + # In some trigger: + on_...: + then: + - if: + condition: lvgl.is_paused + then: + - lvgl.resume: + +Triggers +-------- + +.. _lvgl-onidle-trg: + +``lvgl.on_idle`` +**************** + +LVGL has a notion of screen inactivity -- in other words, the time since the last user interaction with the screen is tracked. This can be used 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:`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 + then: + - lvgl.page.show: main_page + - timeout: 60s + then: + - light.turn_off: display_backlight + - lvgl.pause: + +See :ref:`lvgl-cook-idlescreen` for an example illustrating how to implement screen saving with idle settings. + +.. _lvgl-seealso: + +See Also +-------- + +- :doc:`/components/lvgl/widgets` +- :doc:`LVGL Examples in the Cookbook ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :doc:`/components/display/index` +- :doc:`/components/touchscreen/index` +- :doc:`/components/sensor/rotary_encoder` +- `LVGL docs `__ +- :ghedit:`Edit` diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst new file mode 100644 index 0000000000..71af7e280f --- /dev/null +++ b/components/lvgl/widgets.rst @@ -0,0 +1,1808 @@ +.. _lvgl-widgets: + +Widgets +======= + +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 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, its children will also be hidden. + +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 those related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the parent will be searched for an object which specifies a value for the property. The parents will use their own :ref:`state ` to determine the value. For example, if a button is pressed and the text color is defined by the "pressed" state, this "pressed" text color will be used. + +Common properties +***************** + +The properties below are common to all widgets. + +**Configuration variables:** + +- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. +- **x** (*Optional*, int16 or percentage): Horizontal position of the widget. +- **y** (*Optional*, int16 or percentage): Vertical position of the widget. + +.. note:: + + 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. + + If specifying ``align``, ``x`` and ``y`` can be used as an offset to the calculated position (can also be negative). They are ignored if :ref:`lvgl-layouts` are used on the parent. + +- **width** (*Optional*): Width of the widget in pixels or a percentage, or ``SIZE_CONTENT``. +- **height** (*Optional*): Height of the widget in pixels or a percentage, or ``SIZE_CONTENT``. + +.. note:: + + 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 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 dimensions 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. 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). + +- **align** (*Optional*, dict): 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**, string): 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): 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*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. +- **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*, dict): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from the theme, but can be locally set or overridden within style definitions. 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 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. + +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 + + - button: + 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 through :ref:`actions ` with ``lvgl.widget.update``. + +See :ref:`lvgl-cook-cover` for a cookbook example illustrating how to use styling and properties to show different states of a Home Assistant entity. + +.. _lvgl-objupdflag-act: + +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``. Hidden objects are ignored in layout calculations. 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`` (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 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``). +- **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. +- **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent. +- **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. For example, may help by accounting for rounded corners. +- **ignore_layout** (*Optional*, boolean): the widget is simply ignored by the layouts. Its coordinates can be set as usual. +- **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. + +.. note:: + + LVGL only supports **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`` +********* + +A label is the basic widget type that is used to display text. + +.. figure:: /components/images/lvgl_label.png + :align: center + +**Configuration variables:** + +- **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display. To display an empty label, specify ``""``. +- **text_align** (*Optional*, dict): 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 as YAML list). 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_opa** (*Optional*, :ref:`opacity `): Opacity of the text. Inherited from parent. Defaults to ``COVER``. +- **recolor** (*Optional*, boolean): Enable recoloring of button text with ``#``. This makes it possible to set the color of characters in the text individually by prefixing the text to be re-colored with a ``#RRGGBB`` hexadecimal color code followed by a *space*, and finally closed 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 set by :ref:`lvgl-layouts`), 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 lines which are too long. 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 the text horizontally back and forth. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. + - ``SCROLL_CIRCULAR``: If the text is wider than the label, continuously scroll the text horizontally. If it's higher, scroll vertically. Text will scroll in only one direction; 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 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. + +.. 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*. + +**Actions:** + +- ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of label widgets which you want update. + - **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. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + +**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()' ] + +The ``label`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. + +.. _lvgl-wgt-txt: + +``textarea`` +************ + +The textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. + +.. figure:: /components/images/lvgl_textarea.png + :align: center + +**Configuration variables:** + +- **placeholder_text** (*Optional*, string): A placeholder text can be specified, which is displayed when the Text area is empty. +- **accepted_chars** (*Optional*, string): You can set a list of accepted characters, so other characters will be ignored. +- **one_line** (*Optional*, boolean): The text area can be limited to only allow a single line of text. In this case the height will set automatically to fit only one line, line break characters will be ignored, and word wrap will be disabled. +- **password_mode** (*Optional*, boolean): The text area supports password mode. By default, if the ``•`` (bullet, ``0x2022``) glyph exists in the font, the entered characters are converted to it after some time or when a new character is entered. If ``•`` is missing from the font, ``*`` (asterisk) will be used. +- **max_length** (*Optional*, int): Limit the maximum number of characters to this value. +- any :ref:`Styling ` and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. + +**Actions:** + +- ``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. + - **id** (**Required**): The ID or a list of IDs of textarea widgets which you want update. + - **text** (**Required**): The new text content to be displayed. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated on every keystroke. +- ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). +- :ref:`interaction ` LVGL event triggers. + +For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - textarea: + id: textarea_id + one_line: true + placeholder_text: "Enter text here" + + # Example action: + on_...: + then: + - lvgl.textarea.update: + id: textarea_id + text: "Hello World!" + + # Example trigger: + - textarea: + ... + on_value: + then: + - logger.log: + format: "Textarea changed to: %s" + args: [ text.c_str() ] + on_ready: + then: + - logger.log: + format: "Textarea ready: %s" + args: [ text.c_str() ] + +The ``textarea`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. + +.. _lvgl-wgt-btn: + +``button`` +********** + +Simple push (momentary) or toggle (two-states) button. + +.. figure:: /components/images/lvgl_button.png + :align: center + +**Configuration variables:** + +- **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. + +A notable state is ``checked`` (boolean) which can have different styles applied. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - button: + x: 10 + y: 10 + width: 50 + height: 30 + id: btn_id + +To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget to it: + +.. code-block:: yaml + + # Example toggle button with text: + - button: + x: 10 + y: 10 + width: 70 + height: 30 + id: btn_id + checkable: true + widgets: + - label: + align: center + text: "Light" + + # Example trigger: + - button: + ... + on_value: + then: + - logger.log: + format: "Button checked state: %d" + args: [ x ] + +The ``button`` can be also integrated as a :doc:`Binary Sensor ` or as a :doc:`Switch ` component. + +See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable button to act on a Home Assistant service. + +.. _lvgl-wgt-bmx: + +``buttonmatrix`` +**************** + +The button matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. + +.. figure:: /components/images/lvgl_buttonmatrix.png + :align: center + +**Configuration variables:** + +- **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 ` 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. Must be a value between ``1`` and ``15``; the default is ``1`` (for example, given a line with two buttons, one with ``width: 1`` and another one with ``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): 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): 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. 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 text with ``#``. For example: ``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. + +**Actions:** + +- ``lvgl.buttonmatrix.update`` :ref:`action ` updates the item styles and properties specified in the specific ``state``, ``items`` options. + - **id** (**Required**): The ID or a list of IDs of buttonmatrix widgets which you want update. + - Widget styles or properties from ``state``, ``items`` options above, which you want update. + +- ``lvgl.matrixbutton.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. + - **id** (**Required**): The ID or a list of IDs of matrix buttons which you want update. + - Widget styles or properties from ``control``, ``width`` and ``selected`` options above, which you want update. + +**Triggers:** + +- ``on_value`` and :ref:`interaction ` triggers can be configured for each button, is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. +- The :ref:`interaction ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). + +**Example:** + +.. code-block:: yaml + + # Example widget: + - buttonmatrix: + x: 10 + y: 40 + width: 220 + items: + pressed: + bg_color: 0xFFFF00 + id: matrix_id + rows: + - buttons: + - id: button_1 + text: "\uF04B" + control: + checkable: true + - id: button_2 + text: "\uF04C" + 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 + + # Example action: + on_...: + then: + - lvgl.matrixbutton.update: + id: button_1 + width: 1 + selected: true + control: + checkable: false + - lvgl.buttonmatrix.update: + id: matrix_id + state: + disabled: true + items: + bg_color: 0xf0f0f0 + + # Example trigger: + - buttonmatrix: + ... + rows: + - buttons: + ... + - id: button_2 + ... + control: + checkable: true + on_value: # Trigger for the individual button, returning the checked state + then: + - logger.log: + format: "Button 2 checked: %d" + args: [ x ] + on_press: # Triggers for the matrix, to determine which button was pressed. + logger.log: + format: "Matrix button pressed: %d" + args: ["x"] # If x is 65535, it was the container, (or through a disabled button). + on_click: + logger.log: + format: "Matrix button clicked: %d, is button_2 = %u" + args: ["x", "id(button_2) == x"] + +.. 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. + +.. _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 + +**Configuration variables:** + +- **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*, the foreground area underneath the knob shown when the switch is in ``checked`` state. Supports a list of :ref:`styles ` and state-based styles to customize. +- Style options from :ref:`lvgl-styling`. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - switch: + x: 10 + y: 10 + id: switch_id + + # Example trigger: + - switch: + ... + on_value: + then: + - logger.log: + format: "Switch state: %d" + args: [ x ] + +The ``switch`` can be also integrated as a :doc:`Switch ` component. + +See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local component. + +.. _lvgl-wgt-chk: + +``checkbox`` +************ + +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 + +**Configuration variables:** + +- **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 tick box and the label. + +**Actions:** + +- ``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of checkbox widgets which you want update. + - **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. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +``on_value`` :ref:`trigger ` is activated when toggling the checkbox. The boolean variable ``x``, representing the checkbox's state, may be used by lambdas within this trigger. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - checkbox: + x: 10 + y: 10 + id: checkbox_id + text: Checkbox + + # Example action: + on_...: + then: + - lvgl.checkbox.update: + id: checkbox_id + state: + checked: true + text: Checked + + # Example trigger: + - checkbox: + ... + on_value: + then: + - logger.log: + format: "Checkbox state: %d" + args: [ x ] + +.. note:: + + In case you configure ``default_font`` in the main section to a custom font, the checkmark will not be shown correctly when the checkbox is in the checked state. See :ref:`lvgl-cook-ckboxmark` how to easily resolve this. + +The ``checkbox`` can be also integrated as a :doc:`Switch ` component. + +.. _lvgl-wgt-drp: + +``dropdown`` +************ + +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. 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 + +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). + +**Configuration variables:** + +- **options** (**Required**, list): The list of available options in the drop-down. +- **dir** (*Optional*, dict): 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*, dict): 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 those built-in or from your own customized font. +- **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`` can be used to set the font of the button part, including the symbol. + +**Actions:** + +- ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of dropdown widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`interaction ` LVGL event triggers also apply, and they also return the selected index in ``x``. +- ``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - dropdown: + id: dropdown_id + width: 90 + align: CENTER + options: + - Violin + - Piano + - Bassoon + - Chello + - Drums + selected_index: 2 + + # Example action: + on_...: + then: + - lvgl.dropdown.update: + id: dropdown_id + selected_index: 4 + + # Example trigger: + - dropdown: + ... + on_value: + - logger.log: + format: "Selected index is: %d" + args: [ x ] + on_cancel: + - logger.log: + format: "Dropdown closed. Selected index is: %d" + args: [ x ] + +The ``dropdown`` can be also integrated as :doc:`Select ` component. + +.. _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 + +**Configuration variables:** + +- **options** (**Required**, list): The list of available options in the roller. +- **mode** (*Optional*, dict): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. +- **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 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. + +**Actions:** + +- ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of roller widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the selected index in ``x``. + +**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: 4 + + # Example trigger: + - roller: + ... + on_value: + - logger.log: + format: "Selected index is: %d" + args: [ x ] + +The ``roller`` can be also integrated as :doc:`Select ` component. + +.. _lvgl-wgt-bar: + +``bar`` +******* + +The bar widget has a background and an indicator foreground 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 + +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. + +**Configuration variables:** + +- **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): Animate the indicator when the 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. + +**Actions:** + +- ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of bar widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - bar: + x: 10 + y: 100 + id: bar_id + value: 75 + 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:`Number ` or :doc:`Sensor ` component. + +.. _lvgl-wgt-sli: + +``slider`` +********** + +The slider widget looks like a bar supplemented with a knob. The user can drag the knob to set a value. Just like bar, slider can be vertical or horizontal. The size of the indicator foreground and the knob position is set according to the current ``value`` of the slider. + +.. figure:: /components/images/lvgl_slider.png + :align: center + +**Configuration variables:** + +- **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) is 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. +- **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 shows the current state of the slider. Also uses all the typical background style properties. +- **animated** (*Optional*, boolean): Animate the indicator when the 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. + +**Actions:** + +- ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of slider widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. The new value is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which 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 as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. + +The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. + +See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider to control entities in Home Assistant. + +.. _lvgl-wgt-arc: + +``arc`` +******* + +The arc consists of a background and a foreground arc. The indicator foreground can be touch-adjusted with a knob. + +.. figure:: /components/images/lvgl_arc.png + :align: center + +**Configuration variables:** + +- **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``. +- **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. +- **rotation** (*Optional*, 0-360): 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*, :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. +- **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`` :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:: + + The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. + +**Actions:** + +- ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of arc widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**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``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - 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 as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. + +The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. + +See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider (or an arc) to control entities in Home Assistant. + +.. _lvgl-wgt-spb: + +``spinbox`` +*********** + +The spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. + +.. figure:: /components/images/lvgl_spinbox.png + :align: center + +**Configuration variables:** + +- **value** (**Required**, float): Actual value to be shown by the spinbox at start. +- **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``. +- **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 character will only be shown if the set range contains negatives. + +**Actions:** + +- ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +- ``lvgl.spinbox.increment`` :ref:`action ` increases the value by one ``step`` configured above. + - **id** (**Required**): The ID of the spinbox widget which you want to increment. + +- ``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. + - **id** (**Required**): The ID of the spinbox widget which you want to decrement. + +**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``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - spinbox: + 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:`Number ` or :doc:`Sensor ` component. + +See :ref:`lvgl-cook-climate` for an example illustrating how to implement a thermostat control using the spinbox. + +.. _lvgl-wgt-mtr: + +``meter`` +********* + +The meter widget can visualize data in very flexible ways. It can use arcs, needles, ticks, lines and/or labels. + +.. figure:: /components/images/lvgl_meter.png + :align: center + +**Configuration variables:** + +- **scales** (**Required**, list): A list with (any number of) scales to be added to the meter. + - **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. 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*, :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**: :ref:`Color ` to draw the major ticks. Defaults to ``0`` (black). + - **label_gap**: Label distance from the ticks with text proportional 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: + - **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**: :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**: :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**: :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. + - **image** (*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, representing a needle pointing to the right like ``-o--->``. + - **pivot_x**: Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. + - **pivot_y**: Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. + - **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:: + + The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. + +**Actions:** + +- ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can be used for the common styles, states or flags of the meter widget (not the indicators). + - **id** (**Required**): The ID or a list of IDs of line or image indicators which you want update. + +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - meter: + align: center + scales: + 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 + color: 0xFF0000 + r_mod: -4 + - tick_style: + start_value: -10 + end_value: 40 + color_start: 0x0000bd #FF0000 + color_end: 0xbd0000 #0000FF + + # Example action: + on_...: + then: + - lvgl.indicator.update: + id: temperature_needle + value: 3 + +See :ref:`lvgl-cook-gauge`, :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clock` in the Cookbook for examples illustrating how to effectively use this widget. + +.. _lvgl-wgt-img: + +``image`` +********* + +Images are the basic widgets used to display images. + +.. figure:: /components/images/lvgl_image.png + :align: center + +**Configuration variables:** + +- **src** (**Required**, :ref:`image `): The ID of an existing image configuration. +- **offset_x** (*Optional*): Add a horrizontal offset to the image position. +- **offset_y** (*Optional*): Add a vertical offset to the image position. +- **scale** (*Optional*, 0.1-10): Zoom of the image. +- **angle** (*Optional*, 0-360): Rotation of the image. Defaults to ``0.0``. Needs ``pivot_x`` and ``pivot_y`` to be specified. +- **pivot_x** (*Optional*): Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. +- **pivot_y** (*Optional*): Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. +- **antialias** (*Optional*): The quality of the angle or scale transformation. When anti-aliasing is enabled, the transformations are higher quality but slower. Defaults to ``false``. +- **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is scaled or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``SIZE_CONTENT``, the object's size will be set to the scaled and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. +- 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. + +**Actions:** + +- ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. + - **id** (**Required**): The ID or a list of IDs of image widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - image: + align: CENTER + src: cat_image + id: img_id + radius: 11 + clip_corner: true + + # Example action: + on_...: + then: + - lvgl.image.update: + id: img_id + src: cat_image_bowtie + +.. note:: + + 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. + +.. tip:: + + ``offset_x`` and ``offset_y`` can be useful when the widget size is set to be smaller than the image source size. A "running image" effect can be created by animating these values. + +.. _lvgl-wgt-aim: + +``animimg`` +*********** + +The animation image is similar to the normal ``image`` 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 + +**Configuration variables:** + +- **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 (each frame is displayed for an equal amount of time). +- **repeat_count** (*Optional*, int16 or *forever*): The number of times playback should be repeated. 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. + +**Actions:** + +- ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want start. + +- ``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want stop. + +- ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - animimg: + align: CENTER + id: anim_id + src: [ cat_image, cat_image_bowtie ] + duration: 1000ms + + # Example actions: + on_...: + then: + - lvgl.animimg.update: + id: anim_id + repeat_count: 100 + duration: 300ms + +See :ref:`lvgl-cook-animbatt` in the Cookbook for a more detailed example. + +.. _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 + +**Configuration variables:** + +- **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 `): 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. + +**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 either circular or rectangular widgets whose brightness can be adjusted. As their brightness decreases, the colors become darker. + +.. figure:: /components/images/lvgl_led.png + :align: center + +**Configuration variables:** + +- **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. + +**Actions:** + +- ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of led widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - led: + id: led_id + align: CENTER + color: 0xFF0000 + brightness: 70% + + # Example action: + on_...: + then: + - lvgl.led.update: + id: led_id + color: 0x00FF00 + +The ``led`` can be also integrated as :doc:`Light ` component. + +.. 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 illustrating 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.gif + :align: center + +**Configuration variables:** + +- **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*, :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. +- **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. + +**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 widgets), just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of spinner widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + +**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 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 container for other widgets. By default, it catches touches. + +**Configuration variables:** + +- Style options from :ref:`lvgl-styling`. + +**Triggers:** + +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - obj: + x: 10 + y: 10 + width: 220 + height: 300 + widgets: + - ... + +.. _lvgl-wgt-tab: + +``tabview`` +*********** + +The tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-wgt-bmx`. + +.. figure:: /components/images/lvgl_tabview.png + :align: center + +The tabs are indexed (zero based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button, by sliding horizontally on the content or via ``lvgl.tabview.select`` :ref:`action `, specifying its index. + +**Configuration variables:** + +- **position** (*Optional*, string): Position of the tab selector buttons. One of ``TOP``, ``BOTTOM``, ``LEFT``, ``RIGHT``. Defaults to ``TOP``. +- **size** (*Optional*, percentage): The height (in case of ``TOP``, ``BOTTOM``) or width (in case of ``LEFT``, ``RIGHT``) tab buttons. Defaults to ``10%``. +- **tabs** (**Required**, list): A list with (any number of) tabs to be added to tabview. + - **name** (**Required**): The text to be shown on the button corresponding to the tab. + - **id** (*Optional*): An ID for the tab itself. + - **widgets** (**Required**, list): A list of :ref:`lvgl-widgets` to be drawn on the tab, as children. +- **tab_style** (*Optional*): Style settings for the tabs. + - **items** (*Optional*, list): Settings for the items *part*, the buttons all use the text and typical background style properties except translations and transformations. + +**Actions:** + +- ``lvgl.tabview.select`` :ref:`action ` jumps the view to the desired tab: + - **id** (**Required**): The ID of the tabview which receives this action. + - **index** (**Required**): The the zero based index of the tab to which to jump. + - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated when displayed tab changes. The new value is returned in the variable ``tab`` as the ID of the now-visible tab. +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - tabview: + id: tabview_id + position: top + tab_style: + border_color: 0x00FF00 + border_width: 6 + items: + text_color: 0x0000FF + tabs: + - name: Dog + id: tabview_tab_1 + widgets: + - image: + src: dog_img + ... + ... + + # Example action: + on_...: + then: + - lvgl.tabview.select: + id: tabview_id + index: 1 + animated: true + + # Example trigger: + - tabview: + ... + on_value: + then: + - if: + condition: + lambda: return tab == id(tabview_tab_1); + then: + - logger.log: "Dog tab is now showing" + +.. _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. + +If the Tile view is screen sized, the user interface resembles what you may have seen on smartwatches. + +**Configuration variables:** + +- **tiles** (**Required**, list): A list with (any number of) tiles to be added to tileview. + - **id** (*Optional*): A tile ID to be used with the ``lvgl.tileview.select`` action. + - **row** (**Required**): Horizontal position of the tile in the tileview grid. + - **column** (**Required**): Vertical position of the tile in the tileview grid. + - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. + - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the tile, as children. + +**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 the tileview) to which to jump. Required if not specifying ``row`` and ``column``. + - **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``. + +**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 now-visible tile. +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - tileview: + id: tiv_id + tiles: + - id: cat_tile + row: 0 + column: 0 + dir: VER + widgets: + - image: + src: cat_image + - ... + - ... + + # Example action: + on_...: + then: + - lvgl.tileview.select: + id: tiv_id + tile_id: cat_tile + animated: true + + # Example trigger: + - tileview: + ... + on_value: + - if: + condition: + lambda: return tile == id(cat_tile); + then: + - logger.log: "Cat tile is now showing" + +.. _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). + +**Configuration variables:** + +- **msgboxes** (*Optional*, dict): 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 message box. + - **body** (**Required**, dict): The content of the 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**, dict): A list of buttons to show at the bottom of the message box: + - **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display on the button. + +**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: Message box + body: + text: "This is a sample message box." + bg_color: 0x808080 + buttons: + - id: msgbox_apply + text: "Apply" + - id: msgbox_close + text: "\uF00D" + on_click: + then: + - lvgl.widget.hide: message_box + +.. 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. + +.. _lvgl-wgt-kbd: + +``keyboard`` +************ + +The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-wgt-txt`. + +.. figure:: /components/images/lvgl_keyboard.png + :align: center + +For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bmx`. + +**Configuration variables:** + +- **textarea** (*Optional*): The ID of the ``textarea`` from which to receive the keystrokes. +- **mode** (*Optional*, dict): Keyboard layout to use. Each ``TEXT_`` layout contains a button to allow the user to iterate through the ``TEXT_`` layouts. + - ``TEXT_LOWER``: Display lower case letters (default). + - ``TEXT_UPPER``: Display upper case letters. + - ``TEXT_SPECIAL``: Display special characters. + - ``NUMBER``: Display numbers, +/- sign, and decimal dot. + +**Actions:** + +- ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of keyboard widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- ``on_ready`` :ref:`trigger ` is activated when the checkmark key is pressed. +- ``on_cancel`` :ref:`trigger ` is activated when the key containing the keyboard icon is pressed. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - keyboard: + id: keyboard_id + textarea: textarea_1 + mode: TEXT_UPPER + + # Example actions: + on_focus: + then: + - lvgl.keyboard.update: + id: keyboard_id + mode: number + textarea: textarea_2 + + # Example trigger: + - keyboard: + ... + on_ready: + then: + - logger.log: Keyboard is ready + on_cancel: + then: + - logger.log: Keyboard cancelled + +.. tip:: + + The Keyboard widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. + +.. note:: + + The Keyboard widget in ESPHome doesn't support popovers or custom layouts. + +Actions +------- + +As outlined in the sections above, each widget type supports several of its own, unique actions. +Several universal actions are also available for all widgets, these are outlined below. + +.. _lvgl-objupd-act: + +``lvgl.widget.update`` +********************** + +This powerful :ref:`action ` allows changing/updating any widget's common :ref:`style property `, state (templatable) or :ref:`flag ` on the fly. + +- **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want update. +- The widget's common :ref:`style property `, state (templatable) or :ref:`flag `. + +.. code-block:: yaml + + # Example for updating styles (in states): + on_...: + then: + - lvgl.widget.update: + id: my_button_id + bg_color: 0xFF0000 + state: + disabled: true + + # Example for updating flag: + on_...: + then: + - lvgl.widget.update: + id: my_label_id + hidden: true + +Check out in the Cookbook :ref:`lvgl-cook-binent` for an example illustrating how to use a template to update the state. + +.. _lvgl-objupd-shorthands: + +``lvgl.widget.hide``, ``lvgl.widget.show`` +****************************************** + +These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget. + +- **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want to hide or show. + +.. code-block:: yaml + + on_...: + then: + - lvgl.widget.hide: my_label_id # a single widget + - lvgl.widget.show: [my_button_1, my_button_2] # a list of widgets + - delay: 0.5s + - lvgl.widget.show: + -id: my_label_id + - lvgl.widget.hide: + - id: [my_button_1, my_button_2] + +``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): + +- **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want to disable or enable. + +.. code-block:: yaml + + - on_...: + then: + - lvgl.widget.disable: + - my_button_1 + - my_button_2 + + - on_...: + then: + - lvgl.widget.enable: + - id: my_button_1 + - id: my_button_2 + +Triggers +-------- + +.. _lvgl-event-trg: + +Specific triggers like ``on_value`` are available for certain widgets; they are described above in their respective section. +Some universal triggers are also available for all of the widgets: + +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. +- ``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. + +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``; this variable may be used in lambdas defined within those triggers. + +.. code-block:: yaml + + # Example triggers: + - button: + ... + on_short_click: + then: + lvgl.page.show: main_page + on_long_press: + then: + light.toggle: display_backlight + + - slider: + ... + on_release: + then: + - light.turn_on: + id: display_backlight + transition_length: 0ms + brightness: !lambda return x / 100; + +See Also +-------- + +- :doc:`/components/lvgl` +- :doc:`LVGL Examples in the Cookbook ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :doc:`/components/display/index` +- :doc:`/components/touchscreen/index` +- :doc:`/components/sensor/rotary_encoder` +- `LVGL docs `__ +- :ghedit:`Edit` 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|H9Gu-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_Gcpkj@!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 0 HcmV?d00001 diff --git a/cookbook/images/lvgl_cook_cover.png b/cookbook/images/lvgl_cook_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..5c9fe2987167fe988d4d2efe28cfcf0c58a5a55b GIT binary patch literal 4539 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%0D2(KoskIQB==m9F_$;C81@U>R#n-J_Huy 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 literal 0 HcmV?d00001 diff --git a/cookbook/images/lvgl_cook_font_batt.png b/cookbook/images/lvgl_cook_font_batt.png new file mode 100644 index 0000000000000000000000000000000000000000..6803ee049bae1b86ed99f7393698c631da4950eb GIT binary patch literal 243 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s1SJ3FdmIK*oCO|{#S9F5M?jcysy3fAP;jZI zi(`mKXY!x_|LvK#G74Yyl`);tx}d9g`uVeS?ZnUdp7SxgWV-0eh2Q+|@^A0sJy-gv zL@7fta$C44~A=k!nTEZi|eW$4{&vLWn*LW89hjbZSA!#~$R)^y6gwy2v? o6BUm(*w3BB+vYx_kHML7C#Pj{4*P6zpo1AaUHx3vIVCg!0L2wqhyVZp literal 0 HcmV?d00001 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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 A(f|Me literal 0 HcmV?d00001 diff --git a/cookbook/images/lvgl_cook_gauge.png b/cookbook/images/lvgl_cook_gauge.png new file mode 100644 index 0000000000000000000000000000000000000000..11379cb9d92fb2804f266c5d22b6591b3c4844df GIT binary patch literal 4154 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 TzWxJsFb+^r(3G!~wG8<$^H^HV literal 0 HcmV?d00001 diff --git a/cookbook/images/lvgl_cook_pagenav.png b/cookbook/images/lvgl_cook_pagenav.png new file mode 100644 index 0000000000000000000000000000000000000000..db7b3b55f008b75bf4ce25b1dc35119aa73e433c GIT binary patch literal 1312 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 JWt~$(69A@pIDh~E literal 0 HcmV?d00001 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/images/lvgl_cook_thermometer_gauge.png b/cookbook/images/lvgl_cook_thermometer_gauge.png new file mode 100644 index 0000000000000000000000000000000000000000..6976d767d2e7529d13ab324c3c1f08f833a9107e GIT binary patch literal 5872 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 literal 0 HcmV?d00001 diff --git a/cookbook/images/lvgl_cook_volume.png b/cookbook/images/lvgl_cook_volume.png new file mode 100644 index 0000000000000000000000000000000000000000..3d42748c97934c4cf05925a6fcfc36f17a9d9aa1 GIT binary patch literal 1264 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 Rq5m+zP?A%VEdd$_{x1_sDER;Y literal 0 HcmV?d00001 diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst new file mode 100644 index 0000000000..625cf0dfa0 --- /dev/null +++ b/cookbook/lvgl.rst @@ -0,0 +1,2247 @@ +.. _lvgl-cook: + +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. + +.. note:: + + Many of the examples below call service actions in Home Assistant; however, Home Assistant does not allow such action calls by default. For each ESPHome device which will call actions, you must explicitly enable this setting in Home Assistant. This may be done when the device is initially adopted or by using the `Configure` option in the "devices" list of the ESPHome integration. + +.. 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 with dimensions of ``240x320px``; if your display's dimensions differ, you'll need to adjust them in order to obtain the expected results. + +.. _lvgl-cook-relay: + +Local light switch +------------------ + +.. figure:: /components/images/lvgl_switch.png + :align: left + +The easiest way to integrate an LVGL :ref:`lvgl-wgt-swi` widget and a switch or light is with :ref:`automations `: + +.. code-block:: yaml + + light: + - platform: ... + id: local_light + name: 'Local light' + on_turn_on: + - lvgl.widget.update: + id: light_switch + state: + checked: true + on_turn_off: + - lvgl.widget.update: + id: light_switch + state: + checked: false + + lvgl: + ... + pages: + - id: main_page + widgets: + - switch: + align: CENTER + id: light_switch + on_click: + light.toggle: local_light + +.. _lvgl-cook-binent: + +Remote light button +------------------- + +.. figure:: images/lvgl_cook_remligbut.png + :align: right + +If you'd like to control a remote light which appears as an entity in Home Assistant from a checkable (toggle) :ref:`lvgl-wgt-btn`, first you need to import the light state into ESPHome, and then control it using a action call: + +.. code-block:: yaml + + binary_sensor: + - platform: homeassistant + id: remote_light + entity_id: light.remote_light + publish_initial_state: true + on_state: + then: + lvgl.widget.update: + id: light_btn + state: + checked: !lambda return x; + + lvgl: + ... + pages: + - id: room_page + widgets: + - button: + id: light_btn + align: CENTER + width: 100 + height: 70 + checkable: true + widgets: + - label: + align: CENTER + text: 'Remote light' + on_click: + - homeassistant.action: + action: light.toggle + data: + entity_id: light.remote_light + +.. _lvgl-cook-bright: + +Light brightness slider +----------------------- + +.. figure:: images/lvgl_cook_volume.png + :align: left + +You can use a :ref:`slider ` or an :ref:`arc ` to control 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 convenient to set the slider's ``min_value`` and ``max_value`` accordingly. + +.. code-block:: yaml + + sensor: + - platform: homeassistant + id: light_brightness + entity_id: light.your_dimmer + attribute: brightness + on_value: + - lvgl.slider.update: + id: dimmer_slider + value: !lambda return x; + + lvgl: + ... + pages: + - id: room_page + widgets: + - slider: + id: dimmer_slider + x: 20 + y: 50 + width: 30 + height: 220 + pad_all: 8 + min_value: 0 + max_value: 255 + on_release: + - homeassistant.action: + action: light.turn_on + data: + 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`` action call, and since ESPHome uses floats, ``x`` needs to be converted. + +This is applicable to action calls like ``fan.set_percentage`` or ``valve.set_valve_position``, too; the only difference is that ``max_value`` has to be ``100``. + +.. _lvgl-cook-volume: + +Media player volume slider +-------------------------- + +.. 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 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 action call, we have to divide it 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: mediaplayer_page + widgets: + - slider: + id: slider_media_player + x: 60 + y: 50 + width: 30 + height: 220 + pad_all: 8 + min_value: 0 + max_value: 100 + adv_hittest: true + on_value: + - homeassistant.action: + action: media_player.volume_set + data: + entity_id: media_player.your_room + volume_level: !lambda return (x / 100); + +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 generally has a negative effect on performance. 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. To mitigate this, consider using 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 accomplished with :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets: + +.. figure:: images/lvgl_cook_gauge.png + :align: center + +The trick here is to have a parent :ref:`lvgl-wgt-obj` which contains 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's central parts and place some :ref:`lvgl-wgt-lbl` widgets to display numeric information: + +.. code-block:: yaml + + sensor: + - platform: ... + id: values_between_-10_and_10 + on_value: + - lvgl.indicator.update: + id: val_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_color: 0xFFFFFF + border_width: 0 + pad_all: 4 + widgets: + - meter: + height: 100% + width: 100% + border_width: 0 + bg_opa: TRANSP + 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 + - obj: # to cover the middle part of meter indicator line + height: 146 + width: 146 + radius: 73 + align: CENTER + border_width: 0 + bg_color: 0xFFFFFF + pad_all: 0 + - 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 + y: 8 + x: -90 + text: "-10" + - label: # higher range indicator + text_font: montserrat_18 + align: CENTER + y: 8 + x: 90 + text: "+10" + +.. tip:: + + The ``obj`` used to hide the middle part of the 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: + +Thermometer +----------- + +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 + +Whenever a new value comes from the sensor, we update the needle indicator as well as the text in the :ref:`lvgl-wgt-lbl`. Since LVGL only handles integer values on the :ref:`lvgl-wgt-mtr` scale, but the sensor's value is a ``float``, we use the same approach as in the examples above; we multiply the sensor's values by ``10`` and feed this value to the :ref:`lvgl-wgt-mtr`. It's essentially two scales on top of each other: one to set the needle based on the multiplied value and the other to show sensor's original value in the :ref:`lvgl-wgt-lbl`. + +.. code-block:: yaml + + sensor: + - platform: ... + id: outdoor_temperature + on_value: + - lvgl.indicator.update: + id: temperature_needle + value: !lambda return x * 10; + - lvgl.label.update: + id: temperature_text + text: + format: "%.1f°C" + args: [ 'x' ] + lvgl: + ... + pages: + - id: meter_page + widgets: + - meter: + align: CENTER + height: 180 + width: 180 + scales: + - range_from: -100 # scale for the needle value + range_to: 400 + angle_range: 240 + rotation: 150 + indicators: + - line: + id: temperature_needle + 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 + rotation: 150 + ticks: + width: 1 + count: 51 + length: 10 + color: 0x000000 + major: + stride: 5 + width: 2 + length: 10 + color: 0x404040 + label_gap: 10 + widgets: + - label: + id: temperature_text + text: "-.-°C" + align: CENTER + y: 45 + - label: + text: "Outdoor" + align: CENTER + y: 65 + +And here's the same sensor configuration, but instead with a semicircle gauge with a gradient background drawn by a multitude of ticks: + +.. figure:: images/lvgl_cook_thermometer_gauge.png + :align: center + +If you change the size of the widget, to obtain a uniform gradient, be sure to increase or decrease the ticks count accordingly. + +.. code-block:: yaml + + lvgl: + ... + pages: + - id: meter_page + widgets: + - obj: + height: 240 + width: 240 + align: CENTER + y: -18 + bg_color: 0xFFFFFF + border_width: 0 + pad_all: 14 + widgets: + - meter: + height: 100% + width: 100% + border_width: 0 + align: CENTER + bg_opa: TRANSP + scales: + - range_from: -15 + range_to: 35 + angle_range: 180 + ticks: + count: 70 + width: 1 + length: 31 + indicators: + - tick_style: + start_value: -15 + end_value: 35 + color_start: 0x3399ff + color_end: 0xffcc66 + - range_from: -150 + range_to: 350 + angle_range: 180 + ticks: + count: 0 + indicators: + - line: + id: temperature_needle + width: 8 + r_mod: 2 + value: -150 + - obj: # to cover the middle part of meter indicator line + height: 123 + width: 123 + radius: 73 + align: CENTER + border_width: 0 + pad_all: 0 + bg_color: 0xFFFFFF + - label: + id: temperature_text + text: "--.-°C" + align: CENTER + y: -26 + - label: + text: "Outdoor" + align: CENTER + y: -6 + +.. tip:: + + You can omit the ``obj`` used to hide the middle part of meter indicator line by using a bitmap ``image`` indicator as needle, were only the part hanging above the ticks scale is visible, the rest is transparent. + +.. _lvgl-cook-climate: + +Climate control +--------------- + +:ref:`lvgl-wgt-spb` is the ideal widget to control a thermostat: + +.. 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 labeled with minus and plus to control the spinbox, and whenever we change its value, we just simply call a Home Assistant action to set the new target temperature of the climate. + +.. code-block:: yaml + + sensor: + - platform: homeassistant + id: room_thermostat + entity_id: climate.room_thermostat + attribute: temperature + on_value: + - lvgl.spinbox.update: + id: spinbox_id + value: !lambda return x; + + lvgl: + ... + pages: + - id: thermostat_control + widgets: + - obj: + align: BOTTOM_MID + y: -50 + layout: + type: FLEX + flex_flow: ROW + flex_align_cross: CENTER + width: SIZE_CONTENT + height: SIZE_CONTENT + widgets: + - button: + id: spin_down + on_click: + - lvgl.spinbox.decrement: spinbox_id + widgets: + - label: + text: "-" + - spinbox: + id: spinbox_id + align: CENTER + text_align: CENTER + width: 50 + range_from: 15 + range_to: 35 + step: 0.5 + rollover: false + digits: 3 + decimal_places: 1 + on_value: + then: + - homeassistant.action: + action: climate.set_temperature + data: + temperature: !lambda return x; + entity_id: climate.room_thermostat + - button: + id: spin_up + on_click: + - lvgl.spinbox.increment: spinbox_id + widgets: + - label: + text: "+" + +.. _lvgl-cook-cover: + +Cover status and control +------------------------ + +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 examples, we need to get the state of the cover first. We'll use a numeric sensor to retrieve the current position of the cover and a text sensor to retrieve its current movement. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label in 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 closed. + +.. 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: 60% + 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: 60% + 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: + format: "%.0f%%" + args: [ 'id(cover_myroom_pos).get_state()' ] + + lvgl: + ... + pages: + - id: room_page + widgets: + - label: + x: 10 + y: 6 + width: 70 + text: "My room" + text_align: CENTER + - button: + x: 10 + y: 30 + width: 70 + height: 68 + widgets: + - label: + id: cov_up_myroom + align: CENTER + text: "\uF077" + on_press: + then: + - homeassistant.action: + action: cover.open + data: + entity_id: cover.myroom + - button: + x: 10 + y: 103 + width: 70 + height: 68 + widgets: + - label: + id: cov_stop_myroom + align: CENTER + text: STOP + on_press: + then: + - homeassistant.action: + action: cover.stop + data: + entity_id: cover.myroom + - button: + x: 10 + y: 178 + width: 70 + height: 68 + widgets: + - label: + id: cov_down_myroom + align: CENTER + text: "\uF078" + on_press: + then: + - homeassistant.action: + action: cover.close + data: + entity_id: cover.myroom + +.. _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 necessary. + +.. 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, and can be overridden manually with style definitions (read further to see how). + +.. code-block:: yaml + + lvgl: + ... + theme: + label: + text_font: my_font # set all your labels to use your custom defined font + button: + bg_color: 0x2F8CD8 + bg_grad_color: 0x005782 + bg_grad_dir: VER + bg_opa: COVER + border_color: 0x0077b3 + border_width: 1 + text_color: 0xFFFFFF + pressed: # set some button colors to be different in pressed state + bg_color: 0x006699 + bg_grad_color: 0x00334d + checked: # set some button colors to be different in checked state + bg_color: 0x1d5f96 + bg_grad_color: 0x03324A + text_color: 0xfff300 + buttonmatrix: + bg_opa: TRANSP + border_color: 0x0077b3 + border_width: 0 + text_color: 0xFFFFFF + pad_all: 0 + items: # set all your buttonmatrix buttons 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 + 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 + bg_grad_color: 0x005782 + 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 + width: 100% + height: 30 + +Note that style definitions can contain common properties too, like positioning and sizing. + +.. _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.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. + +For the navigation bar we can use a :ref:`lvgl-wgt-bmx`. 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 + + lvgl: + ... + top_layer: + widgets: + - buttonmatrix: + align: bottom_mid + styles: header_footer + pad_all: 0 + outline_width: 0 + id: top_layer + items: + styles: header_footer + rows: + - buttons: + - id: page_prev + text: "\uF053" + on_press: + then: + lvgl.page.previous: + - id: page_home + text: "\uF015" + on_press: + then: + lvgl.page.show: main_page + - id: page_next + text: "\uF054" + on_press: + then: + lvgl.page.next: + +For this example to appear correctly, use the theme and style options from :ref:`above ` and LVGL's own library :ref:`fonts `. + +.. _lvgl-cook-statico: + +API connection status icon +-------------------------- + +The top layer is useful to show status icons visible on all pages: + +.. figure:: images/lvgl_cook_statico.png + :align: center + +In the example below, we only show the icon when the connection with Home Assistant is established: + +.. code-block:: yaml + + api: + on_client_connected: + - if: + condition: + lambda: 'return (0 == client_info.find("Home Assistant "));' + then: + - lvgl.widget.show: lbl_hastatus + on_client_disconnected: + - if: + condition: + lambda: 'return (0 == client_info.find("Home Assistant "));' + then: + - lvgl.widget.hide: lbl_hastatus + + lvgl: + ... + top_layer: + widgets: + - label: + text: "\uF1EB" + id: lbl_hastatus + hidden: true + align: top_right + x: -2 + y: 7 + text_align: right + text_color: 0xFFFFFF + +Of note: + +- The widget starts *hidden* at boot and it's only shown when triggered by connection with the API. +- 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.png + :align: center + +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 + + lvgl: + ... + pages: + - id: main_page + widgets: + - obj: + align: TOP_MID + 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 + styles: header_footer + widgets: + - label: + text: "A second page" + align: CENTER + text_align: CENTER + text_color: 0xFFFFFF + ... + +For this example to work, use the theme and style options from :ref:`above `. + +.. _lvgl-cook-flex: + +Flex layout positioning +----------------------- + +:ref:`lvgl-layouts` aim to position widgets automatically, eliminating the need to specify coordinates to position each widget. This is a great way to simplify your configuration containing many widgets as it allows you to even omit alignment options. + +.. figure:: images/lvgl_cook_flex_layout.png + :align: center + +This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer fully-featured individual buttons, as they offer a wider range of customization possibilities as seen in the :ref:`lvgl-cook-cover` example. Here we use the **Flex** layout: + +.. code-block:: yaml + + lvgl: + ... + pages: + - id: room_page + widgets: + - obj: # a properly placed coontainer object for all these controls + align: CENTER + width: 240 + height: 256 + x: 4 + y: 4 + pad_all: 3 + pad_row: 6 + pad_column: 8 + bg_opa: TRANSP + border_opa: TRANSP + layout: # enable the FLEX layout for the children widgets + type: FLEX + flex_flow: COLUMN_WRAP # the order of the widgets starts top left + flex_align_cross: CENTER # they sould be centered + widgets: + - label: + text: "East" + - button: + id: but_cov_up_east + width: 70 # choose the button dimensions so + height: 68 # they fill the columns nincely as they flow + widgets: + - label: + id: cov_up_east + align: CENTER + text: "\U000F005D" # mdi:arrow-up + - button: + id: but_cov_stop_east + width: 70 + height: 68 + widgets: + - label: + id: cov_stop_east + align: CENTER + text: "\U000F04DB" # mdi:stop + - button: + id: but_cov_down_east + width: 70 + height: 68 + widgets: + - label: + id: cov_down_east + align: CENTER + text: "\U000F0045" # mdi:arrow-down + + - label: + text: "South" + - button: + id: but_cov_up_south + width: 70 + height: 68 + widgets: + - label: + id: cov_up_south + align: CENTER + text: "\U000F005D" + - button: + id: but_cov_stop_south + width: 70 + height: 68 + widgets: + - label: + id: cov_stop_south + align: CENTER + text: "\U000F04DB" + - button: + id: but_cov_down_south + width: 70 + height: 68 + widgets: + - label: + id: cov_down_south + align: CENTER + text: "\U000F0045" + + - label: + text: "West" + - button: + id: but_cov_up_west + width: 70 + height: 68 + widgets: + - label: + id: cov_up_west + align: CENTER + text: "\U000F005D" + - button: + id: but_cov_stop_west + width: 70 + height: 68 + widgets: + - label: + id: cov_stop_west + align: CENTER + text: "\U000F04DB" + - button: + id: but_cov_down_west + width: 70 + height: 68 + widgets: + - label: + id: cov_down_west + align: CENTER + text: "\U000F0045" + +This saved you from a considerable amount of manual calculation of widget positioning which would otherwise be required to place them manually with ``x`` and ``y``! You only need to determine a common width and height for your widgets to distribute them on the page as you prefer. (:ref:`lvgl-cook-icontext` below shows how to use custom icons.) + +.. _lvgl-cook-grid: + +Grid layout positioning +----------------------- + +But there's even more! With the **Grid** layout, you don't need to specify width and height for your widgets. All you have to do is divide the space into rows and columns; the widgets can be automatically be sized to fit into cells defined by these rows and columns. The same task from above, in a fully automated grid, looks like this: + +.. code-block:: yaml + + lvgl: + ... + pages: + - id: room_page + widgets: + - obj: # a properly placed coontainer object for all these controls + align: CENTER + width: 240 + height: 256 + pad_all: 6 + pad_row: 6 + pad_column: 8 + bg_opa: TRANSP + border_opa: TRANSP + layout: # enable the GRID layout for the children widgets + type: GRID # split the rows and the columns proportionally + grid_columns: [FR(1), FR(1), FR(1)] # equal + grid_rows: [FR(10), FR(30), FR(30), FR(30)] # like percents + widgets: + - label: + text: "East" + grid_cell_column_pos: 0 # place the widget in + grid_cell_row_pos: 0 # the corresponding cell + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + - button: + id: but_cov_up_east + grid_cell_column_pos: 0 + grid_cell_row_pos: 1 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + widgets: + - label: + id: cov_up_east + align: CENTER + text: "\U000F005D" + - button: + id: but_cov_stop_east + grid_cell_column_pos: 0 + grid_cell_row_pos: 2 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + widgets: + - label: + id: cov_stop_east + align: CENTER + text: "\U000F04DB" + - button: + id: but_cov_down_east + grid_cell_column_pos: 0 + grid_cell_row_pos: 3 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + widgets: + - label: + id: cov_down_east + align: CENTER + text: "\U000F0045" + + - label: + text: "South" + grid_cell_column_pos: 1 + grid_cell_row_pos: 0 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + - button: + id: but_cov_up_south + grid_cell_column_pos: 1 + grid_cell_row_pos: 1 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + widgets: + - label: + id: cov_up_south + align: CENTER + text: "\U000F005D" + - button: + id: but_cov_stop_south + grid_cell_column_pos: 1 + grid_cell_row_pos: 2 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + widgets: + - label: + id: cov_stop_south + align: CENTER + text: "\U000F04DB" + - button: + id: but_cov_down_south + grid_cell_column_pos: 1 + grid_cell_row_pos: 3 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + widgets: + - label: + id: cov_down_south + align: CENTER + text: "\U000F0045" + + - label: + text: "West" + grid_cell_column_pos: 2 + grid_cell_row_pos: 0 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + - button: + id: but_cov_up_west + grid_cell_column_pos: 2 + grid_cell_row_pos: 1 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + widgets: + - label: + id: cov_up_west + align: CENTER + text: "\U000F005D" + - button: + id: but_cov_stop_west + grid_cell_column_pos: 2 + grid_cell_row_pos: 2 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + widgets: + - label: + id: cov_stop_west + align: CENTER + text: "\U000F04DB" + - button: + id: but_cov_down_west + grid_cell_column_pos: 2 + grid_cell_row_pos: 3 + grid_cell_x_align: STRETCH + grid_cell_y_align: STRETCH + widgets: + - label: + id: cov_down_west + align: CENTER + text: "\U000F0045" + +The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. With ``STRETCH`` their sizes and positions will automatically be calculated to fill in the cells, while the parent's ``pad_all``, ``pad_row`` and ``pad_column`` can help with spacing between them. See :ref:`lvgl-cook-weather` further down this page for another example relying on **Grid**. + +.. _lvgl-cook-btlg: + +ESPHome boot screen +------------------- + +To display a boot image with a spinner animation which disappears automatically after a few moments or on touch of the screen you can use the *top layer*. The trick is to put a base :ref:`lvgl-wgt-obj` full screen and child :ref:`lvgl-wgt-img` widget in its middle as the last item of the widgets list, so they draw 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/favicon-512x512.png + id: boot_logo + resize: 200x200 + type: RGB565 + use_transparency: true + + 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: + - image: + align: CENTER + src: boot_logo + y: -40 + - spinner: + align: CENTER + y: 95 + height: 50 + width: 50 + spin_time: 1s + arc_length: 60deg + arc_width: 8 + indicator: + arc_color: 0x18bcf2 + arc_width: 8 + 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 text. This is very flexible because you can prepare various sets of fonts at different sizes each with a different number of glyphs; this is important as it may help to conserve flash memory space. + +One example is when you'd like some MDI icons to be used in line with the text (similar to how LVGL's internal fonts and symbols coexist). You can use a font of your choice; choose the symbols/icons from MDI you want and mix them in a single sized set. + +.. 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 + +.. tip:: + + Follow these steps to choose your MDI icons: + + - To lookup your icons, use the `Pictogrammers `_ site. Click on the desired icon and note its codepoint (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-ckboxmark: + +Restore checkbox mark +--------------------- + +If you configure a custom font as the ``default_font`` used by LVGL and this font does not contain the `FontAwesome `__ symbols, you may observe that some widgets won't display correctly; specifically :ref:`lvgl-wgt-chk` won't show the checkmark when it's checked. + +To work around this issue, simply import only the checkmark symbol in the desired size and apply it through :ref:`lvgl-cook-theme` to all the checkboxes in the configuration: + +.. code-block:: yaml + + font: + - file: 'fonts/FontAwesome5-Solid+Brands+Regular.woff' + id: fontawesome_checkmark + size: 18 + bpp: 4 + glyphs: [ + "\uF00C", # ckeckmark, for checkbox + ] + + lvgl: + ... + theme: + checkbox: + indicator: + checked: + text_font: fontawesome_checkmark + +You could of course simply apply one of the built-in ``montserrat_`` packs, but that would not be beneficial on the binary size - it would uselessly include the entire set of glyphs in the flash. + +.. _lvgl-cook-iconstat: + +Toggle state icon button +------------------------ + +.. figure:: images/lvgl_cook_font_binstat.png + :align: left + +A common use case for icons is a status display. For example, a checkable (toggle) button will display different icons based on the status of a light or switch. 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`` states to apply *disabled styles* for these cases. + +If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like this: + +.. code-block:: yaml + + font: + - file: "custom/materialdesignicons-webfont.ttf" + id: mdi_42 + size: 42 + bpp: 4 + glyphs: [ + "\U000F0335", # mdi-lightbulb + "\U000F0336", # mdi-lightbulb-outline + ] + + text_sensor: + - platform: homeassistant + id: ts_remote_light + entity_id: light.remote_light + on_value: + then: + - lvgl.widget.update: + id: btn_lightbulb + state: + 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: !lambda |- + static char buf[10]; + 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: + ... + pages: + - id: room_page + widgets: + - button: + x: 110 + y: 40 + width: 90 + height: 50 + checkable: true + id: btn_lightbulb + widgets: + - label: + id: lbl_lightbulb + align: CENTER + text_font: mdi_42 + text: "\U000F0336" # mdi-lightbulb-outline + on_short_click: + - homeassistant.action: + action: light.toggle + data: + entity_id: light.remote_light + +.. _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: battery_icons_20 + text: "\U000F0091" # start with mdi-battery-unknown + +.. _lvgl-cook-animbatt: + +Battery charging animation +-------------------------- + +.. figure:: images/lvgl_cook_animimg_batt.gif + :align: left + +To have an animation illustrating a battery charging, you can use :ref:`lvgl-wgt-aim` with a set of :ref:`images rendered from MDI ` 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: ani_battery_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 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: + +An analog clock +--------------- + +Using the :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets, we can create an analog clock which shows the date too. + +.. 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 ``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 at the beginning of every minute to update the line positions for each hand as well as the respective text. + +.. code-block:: yaml + + lvgl: + ... + pages: + - id: clock_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 + border_width: 0 + text_color: 0x000000 + scales: + - range_from: 0 # minutes scale + range_to: 60 + angle_range: 360 + rotation: 270 + ticks: + width: 1 + count: 61 + length: 10 + color: 0x000000 + indicators: + - line: + id: minute_hand + width: 3 + color: 0xa6a6a6 + r_mod: -4 + value: 0 + - 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: 10 + color: 0xC0C0C0 + label_gap: 12 + - 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 + - label: + styles: date_style + id: day_label + y: -30 + - label: + id: date_label + styles: date_style + y: 30 + + time: + - platform: homeassistant + id: time_comp + on_time_sync: + - script.execute: time_update + on_time: + - minutes: '*' + seconds: 0 + then: + - script.execute: time_update + + script: + - id: time_update + then: + - lvgl.indicator.update: + id: minute_hand + value: !lambda |- + return id(time_comp).now().minute; + - lvgl.indicator.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]; + +.. _lvgl-cook-keypad: + +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 (or ``key_code`` where configured) 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: keypad_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: lvgl_label + align: CENTER + text: "Enter code and \uF00C" + text_align: CENTER + - buttonmatrix: + id: lvgl_keypad + x: 20 + y: 85 + width: 200 + height: 190 + items: + pressed: + bg_color: 0xFFFF00 + 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: "\uF55A" + key_code: "*" + control: + no_repeat: true + - text: 0 + control: + no_repeat: true + - text: "\uF00C" + key_code: "#" + control: + no_repeat: true + + key_collector: + - 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: lvgl_label + text: !lambda 'return x.c_str();' + else: + - lvgl.label.update: + id: lvgl_label + text: "Enter code and \uF00C" + 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 + +Of note: + +- A base object ``obj`` is used as a parent for the label; this allows proper centering of the label as well as emphasizing it with shadows independently of the label's dimensions. +- ``align_to`` is used to align the label to the ``led`` vertically. +- Changing the background color of the buttons in ``pressed`` state. +- Use of the ``key_code`` configuration to send a different character to ``key_collector`` instead of the displayed symbol. + +.. _lvgl-cook-weather: + +Weather forecast panel +---------------------- + +Another example relying on the **Grid** layout can be a weather panel showing the forecast through the `OpenWeatherMap integration `__ of Home Assistant. + +.. figure:: images/lvgl_cook_weather.png + :align: center + +All the information displayed here could be retrieved to local ``platform: homeassistant`` sensors as desribed in several examples in this Cookbook, however, this time we take a different approach. Instead of pulling the data by ESPHome, we'll be pushing it from Home Assistant, to native :doc:`/components/text/lvgl` components. + +The weather condition icons we use are from MDI. We import just the ones corresponding to the weather conditions supported by the Weather integration in Home Assistant. For all the other labels you can use any :ref:`font ` of your choice. + +.. code-block:: yaml + + binary_sensor: + - platform: status + name: Status sensor + + font: + - file: "fonts/materialdesignicons-webfont.ttf" + id: icons_100 + size: 100 + bpp: 4 + glyphs: [ + "\U000F0594", # clear-night + "\U000F0590", # cloudy + "\U000F0F2F", # exceptional + "\U000F0591", # fog + "\U000F0592", # hail + "\U000F0593", # lightning + "\U000F067E", # lightning-rainy + "\U000F0595", # partlycloudy + "\U000F0596", # pouring + "\U000F0597", # rainy + "\U000F0598", # snowy + "\U000F067F", # snowy-rainy + "\U000F0599", # sunny + "\U000F059D", # windy + "\U000F059E", # windy-variant + "\U000F14E4", # sunny-off + ] + + lvgl: + ... + pages: + - id: weather_forecast + widgets: + - obj: + align: CENTER + width: 228 + height: 250 + pad_all: 10 + pad_column: 0 + layout: + type: GRID + grid_rows: [FR(48), FR(13), FR(13), FR(13), FR(13)] + grid_columns: [FR(10), FR(40), FR(40), FR(10)] + widgets: + - label: + text: "\U000F14E4" + id: lbl_weather_forecast_condition_icon + text_font: icons_100 + text_align: CENTER + grid_cell_row_pos: 0 + grid_cell_column_pos: 0 + grid_cell_column_span: 2 + grid_cell_x_align: CENTER + grid_cell_y_align: START + + - label: + text: "Unknown" + id: lbl_weather_forecast_condition_name + text_align: CENTER + grid_cell_row_pos: 0 + grid_cell_column_pos: 2 + grid_cell_column_span: 2 + grid_cell_x_align: STRETCH + grid_cell_y_align: CENTER + + - label: + text: "Feels like:" + grid_cell_row_pos: 1 + grid_cell_column_pos: 1 + + - label: + text: "--.- °C" + id: lbl_weather_forecast_tempap + text_align: RIGHT + grid_cell_row_pos: 1 + grid_cell_column_pos: 2 + grid_cell_x_align: STRETCH + + - label: + text: "Maximum:" + grid_cell_row_pos: 2 + grid_cell_column_pos: 1 + + - label: + text: "--.- °C" + id: lbl_weather_forecast_temphi + text_align: RIGHT + grid_cell_row_pos: 2 + grid_cell_column_pos: 2 + grid_cell_x_align: STRETCH + + - label: + text: "Minimum:" + grid_cell_row_pos: 3 + grid_cell_column_pos: 1 + + - label: + text: "--.- °C" + id: lbl_weather_forecast_templo + text_align: RIGHT + grid_cell_row_pos: 3 + grid_cell_column_pos: 2 + grid_cell_x_align: STRETCH + + - label: + text: "Now:" + grid_cell_row_pos: 4 + grid_cell_column_pos: 1 + + - label: + text: "--.- °C" + id: lbl_weather_outdnoor_now + text_align: RIGHT + grid_cell_row_pos: 4 + grid_cell_column_pos: 2 + grid_cell_x_align: STRETCH + + text: + - platform: lvgl + name: fr_cond_icon + widget: lbl_weather_forecast_condition_icon + mode: text + - platform: lvgl + name: fr_cond_name + widget: lbl_weather_forecast_condition_name + mode: text + - platform: lvgl + name: fr_tempap + widget: lbl_weather_forecast_tempap + mode: text + - platform: lvgl + name: fr_temphi + widget: lbl_weather_forecast_temphi + mode: text + - platform: lvgl + name: fr_templo + widget: lbl_weather_forecast_templo + mode: text + - platform: lvgl + name: wd_out_now + widget: lbl_weather_outdnoor_now + mode: text + +If you look carefully at the ``grid_columns`` variable, you'll notice that there are two thinner columns at left and right (``FR(10)``). Reason is to add some space to the labels from the edges. And that's why we had to use ``grid_cell_column_span`` for the widgets in the first row, to take up the space of multiple columns. + +These labels will appear in Home Assistant as `editable text components `__, which makes it very easy to update them with the ``text.set_value`` action. For this purpose, we add the following `automations `__ to Home Assistant: + +.. code-block:: yaml + + - id: weather_cond_forecast + alias: 'Weather Forecast Condition' + trigger: + - platform: state + entity_id: sensor.openweathermap_forecast_condition + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + action: + - action: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_cond_icon + data: + value: > + {% set d = { + "clear-night": "\U000F0594", + "cloudy": "\U000F0590", + "exceptional": "\U000F0F2F", + "fog": "\U000F0591", + "hail": "\U000F0592", + "lightning": "\U000F0593", + "lightning-rainy": "\U000F067E", + "partlycloudy": "\U000F0595", + "pouring": "\U000F0596", + "rainy": "\U000F0597", + "snowy": "\U000F0598", + "snowy-rainy": "\U000F067F", + "sunny": "\U000F0599", + "windy": "\U000F059D", + "windy-variant": "\U000F059E", + "unknown": "\U000F14E4", + "unavailable": "\U000F14E4", + } %} + {{ d.get( states('sensor.openweathermap_forecast_condition') ) }} + + - action: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_cond_name + data: + value: > + {% set d = { + "clear-night": "Clear Night", + "cloudy": "Cloudy", + "exceptional": "Except ional", + "fog": "Fog", + "hail": "Hail", + "lightning": "Lightning", + "lightning-rainy": "Lightning rainy", + "partlycloudy": "Partly cloudy", + "pouring": "Pouring", + "rainy": "Rainy", + "snowy": "Snowy", + "snowy-rainy": "Snowy rainy", + "sunny": "Sunny", + "windy": "Windy", + "windy-variant": "Windy cloudy", + "unknown": "Unknown", + "unavailable": "Unavai lable", + } %} + {{ d.get( states('sensor.openweathermap_forecast_condition') ) }} + + - id: weather_temp_feels_like_forecast + alias: 'Weather Temperature Feels Like' + trigger: + - platform: state + entity_id: sensor.openweathermap_feels_like_temperature + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + action: + - action: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_tempap + data: + value: "{{states('sensor.openweathermap_feels_like_temperature') | round(1)}} °C" + + - id: weather_temp_forecast_temphi + alias: 'Weather Temperature Forecast Hi' + trigger: + - platform: state + entity_id: sensor.openweathermap_forecast_temperature + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + action: + - action: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_temphi + data: + value: "{{states('sensor.openweathermap_forecast_temperature') | round(1)}} °C" + + - id: weather_temp_forecast_templo + alias: 'Weather Temperature Forecast Lo' + trigger: + - platform: state + entity_id: sensor.openweathermap_forecast_temperature_low + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + action: + - action: text.set_value + target: + entity_id: + - text.your_esphome_node_fr_templo + data: + value: "{{states('sensor.openweathermap_forecast_temperature_low') | round(1)}} °C" + + - id: weather_temp_outdoor_now + alias: 'Weather Temperature Now' + trigger: + - platform: state + entity_id: sensor.outdoor_temperature + - platform: state + entity_id: binary_sensor.your_esphome_node_status_sensor + to: 'on' + action: + - action: text.set_value + target: + entity_id: + - text.your_esphome_node_wd_out_now + data: + value: "{{states('sensor.outdoor_temperature') | round(1)}} °C" + +The automations will be triggered to update the labels every time the corresponding entities change, and when the ESPHome comes alive - the reason you also need the :doc:`/components/binary_sensor/status`. Note that you'll need to adjust the entity IDs corresponding to your ESPHome node depedning on how you :ref:`configured it to use its name`. + +.. _lvgl-cook-idlescreen: + +Turn off screen when idle +------------------------- + +LVGL has a notion of screen inactivity -- in other words, the time since the last user interaction with the screen is tracked. This can be used 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. Note that it's important to use the ``on_release`` trigger to accomplish this task. With a template number you can make the timeout adjustable 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.pause: + + touchscreen: + - platform: ... + on_release: + - 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 + +.. _lvgl-cook-antiburn: + +Prevent burn-in of LCD +---------------------- + +You can use this to protect and prolong the lifetime of the LCD screens, thus being more green and generating less hazardous waste. + +A common problem with wall-mounted LCD screens is that they display the same picture 99.999% of the time. Even if somebody turns off the backlight during the night or dark periods, the LCD screen keeps showing the same picture, but seen by nobody. This scenario is likely to lead to burn-in after a few years of operation. + +One way to mitigate this is to *exercise* the pixels periodically by displaying different content. ``show_snow`` option during LVGL paused state was developed with this in mind; it displays randomly colored pixels across the entire screen in order to minimize screen burn-in by exercising each individual pixel. + +In the example below, pixel training is done four times for a half an hour every night; it can be stopped by touching the screen. + +.. code-block:: yaml + + time: + - platform: ... + on_time: + - hours: 2,3,4,5 + minutes: 5 + seconds: 0 + then: + - switch.turn_on: switch_antiburn + - hours: 2,3,4,5 + minutes: 35 + seconds: 0 + then: + - 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: "Stopping Antiburn" + - if: + condition: lvgl.is_paused + then: + - lvgl.resume: + - lvgl.widget.redraw: + - delay: 1s + - lvgl.pause: + + touchscreen: + - platform: ... + on_release: + then: + - if: + 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. + +See Also +-------- + +- :ref:`lvgl-main` +- :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 490c0fe1b6b50c01bab1d2efb5e6427e79274b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 11:21:39 +0200 Subject: [PATCH 531/564] components --- components/binary_sensor/lvgl.rst | 41 +++++++++++++++++++++++++ components/light/lvgl.rst | 46 ++++++++++++++++++++++++++++ components/select/lvgl.rst | 46 ++++++++++++++++++++++++++++ components/sensor/lvgl.rst | 48 ++++++++++++++++++++++++++++++ components/switch/lvgl.rst | 44 +++++++++++++++++++++++++++ components/text/lvgl.rst | 45 ++++++++++++++++++++++++++++ components/text_sensor/lvgl.rst | 46 ++++++++++++++++++++++++++++ images/lvgl.png | Bin 0 -> 3401 bytes 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 -> 2622 bytes images/lvgl_c_swi.png | Bin 0 -> 1437 bytes images/lvgl_c_txt.png | Bin 0 -> 1623 bytes 14 files changed, 316 insertions(+) create mode 100644 components/binary_sensor/lvgl.rst create mode 100644 components/light/lvgl.rst create mode 100644 components/select/lvgl.rst create mode 100644 components/sensor/lvgl.rst create mode 100644 components/switch/lvgl.rst create mode 100644 components/text/lvgl.rst create mode 100644 components/text_sensor/lvgl.rst create mode 100644 images/lvgl.png 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 create mode 100644 images/lvgl_c_txt.png diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst new file mode 100644 index 0000000000..b0b1f4b9a6 --- /dev/null +++ b/components/binary_sensor/lvgl.rst @@ -0,0 +1,41 @@ +.. _lvgl-bse: + +LVGL Binary Sensor +================== + +.. seo:: + :description: Instructions for setting up an LVGL widget binary sensor. + :image: ../images/lvgl_c_bns.png + +The ``lvgl`` binary sensor platform creates a binary sensor from an LVGL widget +and requires :ref:`LVGL ` to be configured. + +Supported widget is :ref:`lvgl-wgt-btn`. A single binary sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome binary sensor component. + +Configuration variables: +------------------------ + +- **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the binary sensor. +- All other variables from :ref:`Binary Sensor `. + +Example: + +.. code-block:: yaml + + binary_sensor: + - platform: lvgl + 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` +- :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :ghedit:`Edit` diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst new file mode 100644 index 0000000000..97f9512190 --- /dev/null +++ b/components/light/lvgl.rst @@ -0,0 +1,46 @@ +.. _lvgl-lgh: + +LVGL Light +========== + +.. seo:: + :description: Instructions for setting up an LVGL widget light. + :image: ../images/lvgl_c_lig.png + +The ``lvgl`` light platform creates a light from an LVGL widget +and requires :ref:`LVGL ` to be configured. + +Supported widget is :ref:`lvgl-wgt-led`. A single light supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome light component. + +Configuration options: +---------------------- + +- **widget** (**Required**): The ID of a ``led`` widget configured in LVGL, which will reflect the state of the light. +- All other options from :ref:`light `. + + +Example: + +.. code-block:: yaml + + light: + - platform: lvgl + widget: led_id + name: LVGL light + +.. note:: + + To have linear brightness control, ``gamma_correct`` of the light is set by default to ``0``. + +See Also +-------- +- :ref:`LVGL Main component ` +- :ref:`LED widget ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/select/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :ghedit:`Edit` diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst new file mode 100644 index 0000000000..6690a31427 --- /dev/null +++ b/components/select/lvgl.rst @@ -0,0 +1,46 @@ +.. _lvgl-sel: + +LVGL Select +=========== + +.. seo:: + :description: Instructions for setting up an LVGL widget select. + :image: ../images/lvgl_c_sel.png + +The ``lvgl`` select platform creates a select from an 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 only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome select component. + +Configuration variables: +------------------------ + +- **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the select. +- All other variables from :ref:`Select `. + +Example: + +.. code-block:: yaml + + select: + - platform: lvgl + widget: dropdown_id + name: LVGL Dropdown + +.. note:: + + Widget-specific actions (``lvgl.dropdown.update``, ``lvgl.roller.update``) will trigger correspponding component updates to be sent to Home Assistant. + +See Also +-------- +- :ref:`LVGL Main component ` +- :ref:`Roller widget ` +- :ref:`Dropdown widget ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :ghedit:`Edit` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst new file mode 100644 index 0000000000..7519338103 --- /dev/null +++ b/components/sensor/lvgl.rst @@ -0,0 +1,48 @@ +.. _lvgl-sns: + +LVGL Sensor +=========== + +.. seo:: + :description: Instructions for setting up an LVGL widget sensor component. + :image: ../images/lvgl_c_num.png + +The ``lvgl`` sensor platform creates a semsor component from an 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 sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome sensor. + +Configuration variables: +------------------------ + +- **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the sensor. +- All other variables from :ref:`Sensor `. + +Example: + +.. code-block:: yaml + + sensor: + - platform: lvgl + widget: slider_id + name: LVGL Slider + +.. note:: + + Widget-specific actions (``lvgl.arc.update``, ``lvgl.bar.update``, ``lvgl.slider.update``, ``lvgl.spinbox.update``, ``lvgl.spinbox.decrement``, ``lvgl.spinbox.increment``) will trigger correspponding component updates to be sent to Home Assistant. + +See Also +-------- +- :ref:`LVGL Main component ` +- :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` +- :doc:`/components/light/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :ghedit:`Edit` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst new file mode 100644 index 0000000000..621e8afd38 --- /dev/null +++ b/components/switch/lvgl.rst @@ -0,0 +1,44 @@ +.. _lvgl-swi: + +LVGL Switch +=========== + +.. seo:: + :description: Instructions for setting up an LVGL widget switch. + :image: ../images/lvgl_c_swi.png + +The ``lvgl`` switch platform creates a switch from an 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 only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome switch component. + +Configuration variables: +------------------------ + +- **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the switch. +- All other variables from :ref:`Switch `. + +Example: + +.. code-block:: yaml + + switch: + - platform: lvgl + widget: checkbox_id + name: LVGL switch + +See Also +-------- +- :ref:`LVGL Main component ` +- :ref:`Button widget ` +- :ref:`Switch widget ` +- :ref:`Checkbox widget ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :doc:`/components/output/index` +- :ghedit:`Edit` diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst new file mode 100644 index 0000000000..76b394a6c5 --- /dev/null +++ b/components/text/lvgl.rst @@ -0,0 +1,45 @@ +.. _lvgl-txt: + +LVGL Text +========= + +.. seo:: + :description: Instructions for setting up an LVGL Text component. + :image: ../images/lvgl_c_txt.png + +The ``lvgl`` text platform creates an editable text component from an LVGL textual widget and requires :ref:`LVGL ` to be configured. + +Supported widgets are :ref:`lvgl-wgt-lbl` and :ref:`lvgl-wgt-txt`. A single text supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text component. + +Configuration variables: +------------------------ + +- **widget** (**Required**): The ID of a ``textarea`` widget configured in LVGL, which will reflect the state of the text component. +- All other variables from :ref:`Text `. + +Example: + +.. code-block:: yaml + + text: + - platform: lvgl + widget: textarea_id + name: "Textarea 1 text" + +.. note:: + + Widget-specific actions (``lvgl.label.update``, ``lvgl.textarea.update``) will trigger correspponding component updates to be sent to Home Assistant. + +See Also +-------- +- :ref:`LVGL Main component ` +- :ref:`Label widget ` +- :ref:`Textarea widget ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/select/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :ghedit:`Edit` diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst new file mode 100644 index 0000000000..0bde3b9a3f --- /dev/null +++ b/components/text_sensor/lvgl.rst @@ -0,0 +1,46 @@ +.. _lvgl-txs: + +LVGL Text Sensor +================ + +.. seo:: + :description: Instructions for setting up an LVGL Text Sensor. + :image: ../images/lvgl_c_txt.png + +The ``lvgl`` text sensor platform creates a Text Sensor from an LVGL textual widget +and requires :ref:`LVGL ` to be configured. + +Supported widgets are :ref:`lvgl-wgt-lbl` and :ref:`lvgl-wgt-txt`. A single text sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text sensor component. + +Configuration variables: +------------------------ + +- **widget** (**Required**): The ID of a ``textarea`` widget configured in LVGL, which will reflect the state of the text sensor. +- All other variables from :ref:`Text Sensor `. + +Example: + +.. code-block:: yaml + + text_sensor: + - platform: lvgl + widget: textarea_id + name: "Textarea 1 text" + +.. note:: + + Widget-specific actions (``lvgl.label.update``, ``lvgl.textarea.update``) will trigger correspponding component updates to be sent to Home Assistant. + +See Also +-------- +- :ref:`LVGL Main component ` +- :ref:`Label widget ` +- :ref:`Textarea widget ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/number/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/select/lvgl` +- :doc:`/components/text/lvgl` +- :ghedit:`Edit` diff --git a/images/lvgl.png b/images/lvgl.png new file mode 100644 index 0000000000000000000000000000000000000000..a48dd7c4f8f569bb154d6365c0bd6d792e578b6d GIT binary patch literal 3401 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 literal 0 HcmV?d00001 diff --git a/images/lvgl_c_txt.png b/images/lvgl_c_txt.png new file mode 100644 index 0000000000000000000000000000000000000000..72f1d05113a88968343a9c2f48a9c14ffc658a7f GIT binary patch literal 1623 zcma)-e>f8e7{^zR6H`RD{Qgm+2&=n($Q{MVa9h@@GZSIUjfL|ohf-@y+fGW!uV~#u zWPXI1q5Rm&5}TCTQqdSKEH(`1cF%LqbN4*=&;9Yf-{*PX=Y5~|{p0<-*+=0=^mI&g z004j<%m<28D_dRj>Xx9*WaN6fyS z4e`}To(0ZW5s!ySi5s)6^-~(qAlZYxeP28tCrLv+@8tSqR+zKVf`J{BT%=E|4nej{ zusIyNV@GIh1GvP)nzWyV^3+&(v}yWqX2Q8E^U*E!&)q&DR#yFmE;Azq%TsAHZG#e{ zwsb#0$x_)Xy^O<`SQ(j{7C5CR?addnYwc(k-H_p^df9R@PZ!ZM;gs{czovCV!Pd>e zF&6WnmTjKy;`(8%0O&cFBj6w_tsZ6(A~eZ9zzwOxaLo@KB&`#N5nk+%<|5`+erM1Q z|4j|IE((nr?{-3fp4FqWecY|#)J^7mHh3;Bz;}tcN?bEH%aIfjlo? zV=aXNDUiAw$LSf!MA`$pDs)#~osT4W+`@dp?Qx=2Lns9VZ~{60xr<%E3gTr`Ci-6J0bdIAv)m)vc}^Q(!UlnO zab~>9Hl(+#D(~(uQ^*WrM1%Kvs8lU}oMR527{pYl9W1U?_e7(a8y25`4cBBYwjPS-8OBLchS5X1CBRgnQjTg*v_6N1lS)E=DzjtUNs=Xb^R96eSyzji zJ(Ut4((fhdY4u9x{s^?|&EXHx@Tgnug*Da3znP;*coKQGoU}xm8pLz%_oBh8!R)R( zQSaWU#}*s!pCe?FIRs{G)lrPSjFY0aHymC}#h5o3uj3`asn+8eG+T=?FOKIvR;3br3sP~8gr zliCaE=>+vs3)hOa!i~O=Haet*C~(ulr7WaYeIMeL!zV#GXK3w)CA}#!CD(EhS%`UZ zfUJs|7Piz;!l9_ZDsr+^o6_*+g)QS5h9A+uSerssbgyxo*tj{i$|}9U1ToYUwLj*qINsnz%f3cz&6#UYBUJcblW@wx zes{;WI~mM-L85pM?~)P!M9?^B6g*8$egE*$YHzwy7N|tu3=#(>Ue+h2J$Ct2z0y>l z7E=(ErY?>R%$5ZOO~NO8D4-(KBIx$ZKRt8CF|j;5F3*YD*fcRvZei88X86AJGdgU0 z91D#X?X|&QScJ8D3EU4(mMF6>%uf#=E@?f4_~)9XBR33eTV~c#oys0ZV1VZnP5pO^ zcH&0ElvTfkUVZI+%Y^2a!J02o{pOm!C7%nAL^h>n0E1sjHy#TbGA?R0WZ2@;IZ-y-^_BLzS(2pSRUAp?(A6P Date: Tue, 6 Aug 2024 11:36:03 +0200 Subject: [PATCH 532/564] populate index --- index.rst | 27 ++++++++++++++++++--------- lint.py | 1 + 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/index.rst b/index.rst index 54c49ec689..8a64322e21 100644 --- a/index.rst +++ b/index.rst @@ -547,6 +547,7 @@ Miscellaneous Havells Solar, components/sensor/havells_solar, havellsgti5000d_s.jpg, Solar rooftop Integration, components/sensor/integration, sigma.svg, dark-invert Kuntze pool sensor, components/sensor/kuntze, kuntze.jpg + LVGL widget, components/sensor/lvgl, lvgl_c_num.png M5Stack Unit 8 Angle, components/sensor/m5stack_8angle, m5stack_8angle.png MicroNova pellet stove, components/micronova, pellet.svg Modbus Sensor, components/sensor/modbus_controller, modbus.png @@ -662,6 +663,7 @@ Touchscreen GT911, components/touchscreen/gt911, esp32_s3_box_3.png Nextion Binary Sensor, components/binary_sensor/nextion, nextion.jpg TT21100, components/touchscreen/tt21100, esp32-s3-korvo-2-lcd.png + LVGL widget, components/binary_sensor/lvgl, lvgl_c_bns.png Presence Detection ****************** @@ -741,6 +743,7 @@ Light Components 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 @@ -769,6 +772,7 @@ Switch Components 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 @@ -826,6 +830,7 @@ Display Components Display Menu Core, components/display_menu/index, folder-open.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 -------------------------- @@ -905,14 +910,7 @@ Text Components Text Core, components/text/index, folder-open.svg, dark-invert Template Text, components/text/template, description.svg, dark-invert - -Valve Components ----------------- - -.. imgtable:: - - Valve Core, components/valve/index, folder-open.svg, dark-invert - Template Valve, components/valve/template, description.svg, dark-invert + LVGL textarea Text, components/text/lvgl, lvgl_c_txt.png Text Sensor Components ---------------------- @@ -925,6 +923,7 @@ Text Sensor Components 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 + LVGL textarea Text Sensor, components/text_sensor/lvgl, lvgl_c_txt.png 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 @@ -934,6 +933,14 @@ Text Sensor Components WireGuard, components/wireguard, wireguard_custom_logo.svg WL-134 Pet Tag Sensor , components/text_sensor/wl_134, fingerprint.svg, dark-invert +Valve Components +---------------- + +.. imgtable:: + + Valve Core, components/valve/index, folder-open.svg, dark-invert + Template Valve, components/valve/template, description.svg, dark-invert + Climate Components ------------------ @@ -958,6 +965,7 @@ Number Components 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 Tuya Number, components/number/tuya, tuya.png @@ -968,6 +976,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 @@ -1117,7 +1126,6 @@ Custom Components 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 @@ -1130,6 +1138,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 diff --git a/lint.py b/lint.py index 106a4017aa..4ee654312d 100644 --- a/lint.py +++ b/lint.py @@ -396,6 +396,7 @@ def lint_directive_formatting(fname, content): exclude=[ "components/web_server.rst", "components/image.rst", + "cookbook/lvgl.rst", ], ) def lint_esphome_io_link(fname, match): From 905dfab65e13aeea640f0e325919cdd44ea85575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 11:44:33 +0200 Subject: [PATCH 533/564] crosslinx to the others --- components/display/index.rst | 23 ++++++++++++++--------- components/font.rst | 3 ++- components/key_collector.rst | 20 +++++++++----------- components/wiegand.rst | 2 ++ 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/components/display/index.rst b/components/display/index.rst index dc305ca4f0..b83c7a4f10 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -8,14 +8,24 @@ Display Component 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 +- Character displays like :doc:`7-Segment displays ` or :doc:`LCD displays `. -- Graphical serial displays like :doc:`nextion` that have their own processors for rendering. +- Serial displays like :doc:`nextion` that have their own processors for graphics rendering. - Graphical binary 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, which offer the greatest flexibility, there are two options: + +- ESPHome's :ref:`own rendering engine ` +- :ref:`LVGL ` - Light and Versatile Graphics Library + +.. _display-engine: + +Display Rendering Engine +------------------------ + +ESPHome's own powerful rendering engine can handle many common tasks such as drawing basic shapes, +printing text with fonts of your choice, or even rendering 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,11 +34,6 @@ 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. -.. _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. diff --git a/components/font.rst b/components/font.rst index 47ab89461f..1c3dd2a262 100644 --- a/components/font.rst +++ b/components/font.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 `. +These fonts can be used in ESPHome's :ref:`own rendering engine ` or in the :ref:`LVGL Graphics ` component. To use fonts you can either - 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. @@ -155,6 +155,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/key_collector.rst b/components/key_collector.rst index 552522b5bf..2b3e114b5a 100644 --- a/components/key_collector.rst +++ b/components/key_collector.rst @@ -6,12 +6,12 @@ Key collector component .. seo:: :description: Key collector component -The ``key_collector`` component collects key presses from -components like :ref:`matrix_keypad` or ``wiegand``. It allows you to process -key sequences and treat them as one, for example to allow inputting of -a PIN code or a passkey. The component outputs the result of the keypress -sequence as a variable usable in automations. - +The ``key_collector`` component collects key presses from components +like :ref:`matrix_keypad`, :ref:`Wiegand keypad ` +or LVGL :ref:`Button Matrix `, :ref:`Keyboard ` +widgets. It allows you to process key sequences and treat them as one, for +example to allow inputting of a PIN code or a passkey. The component outputs +the result of the keypress sequence as a variable usable in automations. Component --------- @@ -43,8 +43,6 @@ Component format: "input timeout: '%s', started by '%c'" args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] - - Configuration variables: - **id** (*Optional*, :ref:`config-id`): Set the ID of this entry for use in lambdas. @@ -92,7 +90,7 @@ See Also -------- - :doc:`/components/matrix_keypad` - -.. - :doc:`/components/wiegand` - +- :doc:`/components/wiegand` +- :ref:`LVGL Button Matrix widget ` +- :ref:`LVGL Keyboard widget ` - :ghedit:`Edit` diff --git a/components/wiegand.rst b/components/wiegand.rst index 7234006f67..84c809389a 100644 --- a/components/wiegand.rst +++ b/components/wiegand.rst @@ -1,3 +1,5 @@ +.. _wiegand: + Wiegand keypad and tag reader ============================= From 3bc1f094f35fe66010d9a1098f0dbe09c87b2745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 11:50:25 +0200 Subject: [PATCH 534/564] image path fix --- cookbook/lvgl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 625cf0dfa0..6e79623106 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -22,7 +22,7 @@ Here are a couple recipes for various interesting things you can do with :ref:`l Local light switch ------------------ -.. figure:: /components/images/lvgl_switch.png +.. figure:: /components/lvgl/images/lvgl_switch.png :align: left The easiest way to integrate an LVGL :ref:`lvgl-wgt-swi` widget and a switch or light is with :ref:`automations `: From d4200321e1b3524dd0f19b70c0918e3b684e05f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 11:53:25 +0200 Subject: [PATCH 535/564] several image path fixes --- components/lvgl/index.rst | 6 ++--- components/lvgl/widgets.rst | 46 ++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index 6cf01c1a88..37609ec654 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -10,7 +10,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 `__. -.. figure:: /components/images/lvgl_main_screenshot.png +.. figure:: /components/lvgl/images/lvgl_main_screenshot.png 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 for bigger displays. @@ -210,7 +210,7 @@ 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 preceded by ``\u``. For example: ``\uF00C``: -.. figure:: /components/images/lvgl_symbols.png +.. figure:: /components/lvgl/images/lvgl_symbols.png :align: center .. note:: @@ -233,7 +233,7 @@ 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 +.. figure:: /components/lvgl/images/lvgl_boxmodel.png :align: center - *bounding box*: the box defined with ``width`` and ``height`` of the widgets (pixels or parent content area percentage; not drawn, just for calculations). diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 71af7e280f..e735b21f83 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -49,7 +49,7 @@ The properties below are common to all widgets. - **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 +.. figure:: /components/lvgl/images/lvgl_align.png :align: center - **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. @@ -127,7 +127,7 @@ In addition to visual styling, each widget supports some boolean **flags** to in A label is the basic widget type that is used to display text. -.. figure:: /components/images/lvgl_label.png +.. figure:: /components/lvgl/images/lvgl_label.png :align: center **Configuration variables:** @@ -203,7 +203,7 @@ The ``label`` can be also integrated as :doc:`Text ` or : The textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. -.. figure:: /components/images/lvgl_textarea.png +.. figure:: /components/lvgl/images/lvgl_textarea.png :align: center **Configuration variables:** @@ -269,7 +269,7 @@ The ``textarea`` can be also integrated as :doc:`Text ` o Simple push (momentary) or toggle (two-states) button. -.. figure:: /components/images/lvgl_button.png +.. figure:: /components/lvgl/images/lvgl_button.png :align: center **Configuration variables:** @@ -333,7 +333,7 @@ See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable b The button matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. -.. figure:: /components/images/lvgl_buttonmatrix.png +.. figure:: /components/lvgl/images/lvgl_buttonmatrix.png :align: center **Configuration variables:** @@ -465,7 +465,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row The switch looks like a little slider and can be used to turn something on and off. -.. figure:: /components/images/lvgl_switch.png +.. figure:: /components/lvgl/images/lvgl_switch.png :align: center **Configuration variables:** @@ -509,7 +509,7 @@ See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local 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 +.. figure:: /components/lvgl/images/lvgl_checkbox.png :align: center **Configuration variables:** @@ -575,7 +575,7 @@ 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. 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 +.. figure:: /components/lvgl/images/lvgl_dropdown.png :align: center 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). @@ -649,7 +649,7 @@ The ``dropdown`` can be also integrated as :doc:`Select ` The bar widget has a background and an indicator foreground on it. The size of the indicator is set according to the current ``value`` of the bar. -.. figure:: /components/images/lvgl_bar.png +.. figure:: /components/lvgl/images/lvgl_bar.png :align: center Vertical bars can be created if the width is smaller than the height. @@ -769,7 +769,7 @@ The ``bar`` can be also integrated as :doc:`Number ` or The slider widget looks like a bar supplemented with a knob. The user can drag the knob to set a value. Just like bar, slider can be vertical or horizontal. The size of the indicator foreground and the knob position is set according to the current ``value`` of the slider. -.. figure:: /components/images/lvgl_slider.png +.. figure:: /components/lvgl/images/lvgl_slider.png :align: center **Configuration variables:** @@ -842,7 +842,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustratin The arc consists of a background and a foreground arc. The indicator foreground can be touch-adjusted with a knob. -.. figure:: /components/images/lvgl_arc.png +.. figure:: /components/lvgl/images/lvgl_arc.png :align: center **Configuration variables:** @@ -927,7 +927,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustratin The spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. -.. figure:: /components/images/lvgl_spinbox.png +.. figure:: /components/lvgl/images/lvgl_spinbox.png :align: center **Configuration variables:** @@ -1006,7 +1006,7 @@ See :ref:`lvgl-cook-climate` for an example illustrating how to implement a ther The meter widget can visualize data in very flexible ways. It can use arcs, needles, ticks, lines and/or labels. -.. figure:: /components/images/lvgl_meter.png +.. figure:: /components/lvgl/images/lvgl_meter.png :align: center **Configuration variables:** @@ -1118,7 +1118,7 @@ See :ref:`lvgl-cook-gauge`, :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clo Images are the basic widgets used to display images. -.. figure:: /components/images/lvgl_image.png +.. figure:: /components/lvgl/images/lvgl_image.png :align: center **Configuration variables:** @@ -1178,7 +1178,7 @@ Images are the basic widgets used to display images. The animation image is similar to the normal ``image`` 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 +.. figure:: /components/lvgl/images/lvgl_animimg.gif :align: center **Configuration variables:** @@ -1233,7 +1233,7 @@ See :ref:`lvgl-cook-animbatt` in the Cookbook for a more detailed example. The line widget is capable of drawing straight lines between a set of points. -.. figure:: /components/images/lvgl_line.png +.. figure:: /components/lvgl/images/lvgl_line.png :align: center **Configuration variables:** @@ -1271,7 +1271,7 @@ By default, the Line widget width and height dimensions are set to ``SIZE_CONTEN The LED widgets are either circular or rectangular widgets whose brightness can be adjusted. As their brightness decreases, the colors become darker. -.. figure:: /components/images/lvgl_led.png +.. figure:: /components/lvgl/images/lvgl_led.png :align: center **Configuration variables:** @@ -1323,7 +1323,7 @@ Check out :ref:`lvgl-cook-keypad` in the Cookbook for an example illustrating ho The Spinner widget is a spinning arc over a ring. -.. figure:: /components/images/lvgl_spinner.gif +.. figure:: /components/lvgl/images/lvgl_spinner.gif :align: center **Configuration variables:** @@ -1373,7 +1373,7 @@ The Spinner widget is a spinning arc over a ring. 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 +.. figure:: /components/lvgl/images/lvgl_baseobj.png :align: center You can use it as a parent container for other widgets. By default, it catches touches. @@ -1406,7 +1406,7 @@ You can use it as a parent container for other widgets. By default, it catches t The tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-wgt-bmx`. -.. figure:: /components/images/lvgl_tabview.png +.. figure:: /components/lvgl/images/lvgl_tabview.png :align: center The tabs are indexed (zero based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button, by sliding horizontally on the content or via ``lvgl.tabview.select`` :ref:`action `, specifying its index. @@ -1550,7 +1550,7 @@ If the Tile view is screen sized, the user interface resembles what you may have 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 +.. figure:: /components/lvgl/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). @@ -1604,7 +1604,7 @@ The configured message boxes are hidden by default. One can show them with ``lvg The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-wgt-txt`. -.. figure:: /components/images/lvgl_keyboard.png +.. figure:: /components/lvgl/images/lvgl_keyboard.png :align: center For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bmx`. From b33134a44bed69c4c24e9eade3e42a606acb9583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 11:58:02 +0200 Subject: [PATCH 536/564] index fix --- components/lvgl/widgets.rst | 4 ++-- index.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index e735b21f83..2d1b4e5b6f 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -1,7 +1,7 @@ .. _lvgl-widgets: -Widgets -======= +LVGL Widgets +============ 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 different styling can be set for different states. diff --git a/index.rst b/index.rst index 8a64322e21..dbeb1d3d6d 100644 --- a/index.rst +++ b/index.rst @@ -830,7 +830,7 @@ Display Components Display Menu Core, components/display_menu/index, folder-open.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 + LVGL Graphics, components/lvgl/index, lvgl.png Display Hardware Platforms -------------------------- From 92a69ec31cf5bc6b72d021fffef086455b7fc398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 12:01:58 +0200 Subject: [PATCH 537/564] Update index.rst --- components/lvgl/index.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index 37609ec654..5a48312071 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -684,7 +684,12 @@ See :ref:`lvgl-cook-idlescreen` for an example illustrating how to implement scr See Also -------- -- :doc:`/components/lvgl/widgets` +.. toctree:: + :maxdepth: 1 + :glob: + + * + - :doc:`LVGL Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` From 753e9263bf083c85e1958abdb7735203b3717755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 12:06:26 +0200 Subject: [PATCH 538/564] toctree addition --- components/index.rst | 1 + components/lvgl/index.rst | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/components/index.rst b/components/index.rst index f937b80a23..df4c68c255 100644 --- a/components/index.rst +++ b/components/index.rst @@ -26,6 +26,7 @@ Components touchscreen/index lock/index display_menu/index + lvgl/index media_player/index microphone/index speaker/index diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index 5a48312071..37609ec654 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -684,12 +684,7 @@ See :ref:`lvgl-cook-idlescreen` for an example illustrating how to implement scr See Also -------- -.. toctree:: - :maxdepth: 1 - :glob: - - * - +- :doc:`/components/lvgl/widgets` - :doc:`LVGL Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` From 3f5a0aad6d74c6981a0baeee772ac132bb1ce259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 12:22:05 +0200 Subject: [PATCH 539/564] longer anchor names --- components/binary_sensor/lvgl.rst | 4 +- components/light/lvgl.rst | 4 +- components/lvgl/index.rst | 23 +++-- components/lvgl/widgets.rst | 162 +++++++++++++++--------------- components/select/lvgl.rst | 6 +- components/switch/lvgl.rst | 8 +- components/text/lvgl.rst | 6 +- components/text_sensor/lvgl.rst | 6 +- cookbook/lvgl.rst | 40 ++++---- 9 files changed, 132 insertions(+), 127 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index b0b1f4b9a6..8d970b32c1 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -10,7 +10,7 @@ LVGL Binary Sensor The ``lvgl`` binary sensor platform creates a binary sensor from an LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widget is :ref:`lvgl-wgt-btn`. A single binary sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome binary sensor component. +Supported widget is :ref:`lvgl-widget-button`. A single binary sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome binary sensor component. Configuration variables: ------------------------ @@ -30,7 +30,7 @@ Example: See Also -------- - :ref:`LVGL Main component ` -- :ref:`Button widget ` +- :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 97f9512190..6ea3aa12d3 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 an LVGL widget and requires :ref:`LVGL ` to be configured. -Supported widget is :ref:`lvgl-wgt-led`. A single light supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome light component. +Supported widget is :ref:`lvgl-widget-led`. A single light supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome light component. Configuration options: ---------------------- @@ -35,7 +35,7 @@ Example: See Also -------- - :ref:`LVGL Main component ` -- :ref:`LED widget ` +- :ref:`LED widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index 37609ec654..e47e1720f1 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -74,16 +74,16 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **displays** (*Optional*, list, :ref:`config-id`): A list of display IDs where LVGL should perform rendering based on its configuration. This may be omitted if there is a single display configured, which will be used automatically. - **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a display. - - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the touchscreen, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. + - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the touchscreen, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. - **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. - - **long_press_time** (*Optional*, :ref:`Time `): For the rotary encoder, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the rotary encoder, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. + - **long_press_time** (*Optional*, :ref:`Time `): For the rotary encoder, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the rotary encoder, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. - **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``UP`` key. @@ -98,12 +98,12 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``PREV`` key. - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``HOME`` key. - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``END`` key. - - **long_press_time** (*Optional*, :ref:`Time `): For the keypad, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the keypad, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. + - **long_press_time** (*Optional*, :ref:`Time `): For the keypad, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. + - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the keypad, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. .. tip:: - When using binary sensors (from physical keys) to interact with LVGL, if there are only 3 keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With 4 or more keys, a keypad configuration suits better. For example a 5-key keypad might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``: ``PREV``/``NEXT`` can select a widget within the group, ``UP``/``DOWN`` changes the value, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. + When using binary sensors (from physical keys) to interact with LVGL, if there are only 3 keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With 4 or more keys, a keypad configuration suits better. For example a 5-key keypad might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``: ``PREV``/``NEXT`` can select a widget within the group, ``UP``/``DOWN`` changes the value, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. @@ -112,7 +112,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **log_level** (*Optional*, string): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, int16): The byte order of the data LVGL outputs; either ``big_endian`` or ``little_endian``. Defaults to ``big_endian``. - **disp_bg_color** (*Optional*, :ref:`color `): Solid color used to fill the background. Can be changed at runtime with the ``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. Also see :ref:`lvgl-wgt-img` for a note regarding supported image formats. +- **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. Also see :ref:`lvgl-widget-image` for a note regarding supported image formats. - **default_font** (*Optional*, ID): 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 widget's ``styles`` configuration. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. @@ -684,7 +684,12 @@ See :ref:`lvgl-cook-idlescreen` for an example illustrating how to implement scr See Also -------- -- :doc:`/components/lvgl/widgets` +.. toctree:: + :maxdepth: 1 + :glob: + + * + - :doc:`LVGL Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 2d1b4e5b6f..2f6bf9b40e 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -62,7 +62,7 @@ The properties below are common to all widgets. - **state** (*Optional*, dict): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from the theme, but can be locally set or overridden within style definitions. 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. @@ -83,7 +83,7 @@ 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 through :ref:`actions ` with ``lvgl.widget.update``. +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 illustrating how to use styling and properties to show different states of a Home Assistant entity. @@ -91,7 +91,7 @@ See :ref:`lvgl-cook-cover` for a cookbook example illustrating how to use stylin 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``. Hidden objects are ignored in layout calculations. Defaults to ``false``. +- **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``. Hidden objects are ignored in layout calculations. 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`` (also see the ``scrollbar_mode`` property). @@ -120,7 +120,7 @@ In addition to visual styling, each widget supports some boolean **flags** to in LVGL only supports **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: +.. _lvgl-widget-label: ``label`` ********* @@ -157,7 +157,7 @@ A label is the basic widget type that is used to display text. **Actions:** -- ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of label widgets which you want update. - **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 `. @@ -166,7 +166,7 @@ A label is the basic widget type that is used to display text. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -196,7 +196,7 @@ A label is the basic widget type that is used to display text. The ``label`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. -.. _lvgl-wgt-txt: +.. _lvgl-widget-textarea: ``textarea`` ************ @@ -225,7 +225,7 @@ The textarea is an extended label widget which displays a cursor and allows the - ``on_value`` :ref:`trigger ` is activated on every keystroke. - ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. @@ -262,7 +262,7 @@ For both triggers above, when triggered, the variable ``text`` (``std::string`` The ``textarea`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. -.. _lvgl-wgt-btn: +.. _lvgl-widget-button: ``button`` ********** @@ -282,7 +282,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied **Triggers:** - ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -296,7 +296,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied height: 30 id: btn_id -To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget to it: +To have a button with a text label on it, add a child :ref:`lvgl-widget-label` widget to it: .. code-block:: yaml @@ -326,7 +326,7 @@ The ``button`` can be also integrated as a :doc:`Binary Sensor ` ``on_value`` : if ``true`` on *click*, if ``false`` on *press*. + - **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 text with ``#``. For example: ``It's #FF0000 red#`` - **custom_1** and **custom_2** (*Optional*, boolean): Custom, free to use flags. @@ -366,14 +366,14 @@ The button matrix widget is a lightweight way to display multiple buttons in row - **id** (**Required**): The ID or a list of IDs of buttonmatrix widgets which you want update. - Widget styles or properties from ``state``, ``items`` options above, which you want update. -- ``lvgl.matrixbutton.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. +- ``lvgl.matrix.button.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. - **id** (**Required**): The ID or a list of IDs of matrix buttons which you want update. - Widget styles or properties from ``control``, ``width`` and ``selected`` options above, which you want update. **Triggers:** -- ``on_value`` and :ref:`interaction ` triggers can be configured for each button, is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. -- The :ref:`interaction ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). +- ``on_value`` and :ref:`interaction ` triggers can be configured for each button, is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. +- The :ref:`interaction ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). **Example:** @@ -417,7 +417,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row # Example action: on_...: then: - - lvgl.matrixbutton.update: + - lvgl.matrix.button.update: id: button_1 width: 1 selected: true @@ -458,7 +458,7 @@ 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: +.. _lvgl-widget-switch: ``switch`` ********** @@ -477,7 +477,7 @@ The switch looks like a little slider and can be used to turn something on and o **Triggers:** - ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -502,7 +502,7 @@ The ``switch`` can be also integrated as a :doc:`Switch ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of checkbox widgets which you want update. - **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 `. @@ -529,7 +529,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c **Triggers:** ``on_value`` :ref:`trigger ` is activated when toggling the checkbox. The boolean variable ``x``, representing the checkbox's state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -566,7 +566,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c The ``checkbox`` can be also integrated as a :doc:`Switch ` component. -.. _lvgl-wgt-drp: +.. _lvgl-widget-dropdown: ``dropdown`` ************ @@ -590,19 +590,19 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( - **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`` can be used to set the font of the button part, including the symbol. +- Style options from :ref:`lvgl-styling` for the background of the button and the list. Uses the typical background properties and :ref:`lvgl-widget-label` text properties for the text on it. ``max_height`` can be used to limit the height of the list. ``text_font`` can be used to set the font of the button part, including the symbol. **Actions:** -- ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of dropdown widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`interaction ` LVGL event triggers also apply, and they also return the selected index in ``x``. +- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`interaction ` LVGL event triggers also apply, and they also return the selected index in ``x``. - ``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -642,7 +642,7 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( The ``dropdown`` can be also integrated as :doc:`Select ` component. -.. _lvgl-wgt-rol: +.. _lvgl-widget-roller: ``roller`` ********** @@ -657,21 +657,21 @@ 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*, dict): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. - **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** (*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-widget-label` 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 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. +- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-widget-label` style properties. ``text_line_space`` adjusts the space between the options. **Actions:** -- ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of roller widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** - ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the selected index in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the selected index in ``x``. **Example:** @@ -705,7 +705,7 @@ Roller allows you to simply select one option from a list by scrolling. The ``roller`` can be also integrated as :doc:`Select ` component. -.. _lvgl-wgt-bar: +.. _lvgl-widget-bar: ``bar`` ******* @@ -732,13 +732,13 @@ Not only the end, but also the start value of the bar can be set, which changes **Actions:** -- ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +- ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of bar widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -762,7 +762,7 @@ Not only the end, but also the start value of the bar can be set, which changes The ``bar`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -.. _lvgl-wgt-sli: +.. _lvgl-widget-slider: ``slider`` ********** @@ -787,14 +787,14 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking **Actions:** -- ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of slider widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** - ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. The new value is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -829,13 +829,13 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking .. note:: - The ``on_value`` trigger is sent as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. + The ``on_value`` trigger is sent as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider to control entities in Home Assistant. -.. _lvgl-wgt-arc: +.. _lvgl-widget-arc: ``arc`` ******* @@ -872,14 +872,14 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can **Actions:** -- ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of arc widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **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``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -914,13 +914,13 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can .. note:: - The ``on_value`` trigger is sent as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. + The ``on_value`` trigger is sent as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider (or an arc) to control entities in Home Assistant. -.. _lvgl-wgt-spb: +.. _lvgl-widget-spinbox: ``spinbox`` *********** @@ -947,7 +947,7 @@ The spinbox contains a numeric value (as text) which can be increased or decreas **Actions:** -- ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +- ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. - Widget styles or properties from the specific options above, which you want update. @@ -960,7 +960,7 @@ The spinbox contains a numeric value (as text) which can be increased or decreas **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``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -999,7 +999,7 @@ The ``spinbox`` can be also integrated as :doc:`Number See :ref:`lvgl-cook-climate` for an example illustrating how to implement a thermostat control using the spinbox. -.. _lvgl-wgt-mtr: +.. _lvgl-widget-meter: ``meter`` ********* @@ -1027,7 +1027,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need - **length**: Tick line length in pixels or percentage. Defaults to ``15%``. - **color**: :ref:`Color ` to draw the major ticks. Defaults to ``0`` (black). - **label_gap**: Label distance from the ticks with text proportional 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. + - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-widget-line` and :ref:`lvgl-widget-label` 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: - **arc** (*Optional*): Add a background arc the scale: - **start_value**: The value in the scale range to start drawing the arc from. @@ -1035,7 +1035,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need - **width**: Arc width in pixels. Defaults to ``4``. - **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. + - Style options for the *arc* using the :ref:`lvgl-widget-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. @@ -1049,7 +1049,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need - **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. + - Style options for the *needle line* using the :ref:`lvgl-widget-line` 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. - **image** (*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, representing a needle pointing to the right like ``-o--->``. @@ -1064,12 +1064,12 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need **Actions:** -- ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can be used for the common styles, states or flags of the meter widget (not the indicators). +- ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can be used for the common styles, states or flags of the meter widget (not the indicators). - **id** (**Required**): The ID or a list of IDs of line or image indicators which you want update. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1111,7 +1111,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need See :ref:`lvgl-cook-gauge`, :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clock` in the Cookbook for examples illustrating how to effectively use this widget. -.. _lvgl-wgt-img: +.. _lvgl-widget-image: ``image`` ********* @@ -1136,13 +1136,13 @@ Images are the basic widgets used to display images. **Actions:** -- ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. +- ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. - **id** (**Required**): The ID or a list of IDs of image widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1171,7 +1171,7 @@ Images are the basic widgets used to display images. ``offset_x`` and ``offset_y`` can be useful when the widget size is set to be smaller than the image source size. A "running image" effect can be created by animating these values. -.. _lvgl-wgt-aim: +.. _lvgl-widget-animimg: ``animimg`` *********** @@ -1197,13 +1197,13 @@ The animation image is similar to the normal ``image`` widget. The main differen - ``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want stop. -- ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. +- ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1226,7 +1226,7 @@ The animation image is similar to the normal ``image`` widget. The main differen See :ref:`lvgl-cook-animbatt` in the Cookbook for a more detailed example. -.. _lvgl-wgt-lin: +.. _lvgl-widget-line: ``line`` ******** @@ -1264,7 +1264,7 @@ By default, the Line widget width and height dimensions are set to ``SIZE_CONTEN line_color: 0x0000FF line_rounded: true -.. _lvgl-wgt-led: +.. _lvgl-widget-led: ``led`` ******** @@ -1282,13 +1282,13 @@ The LED widgets are either circular or rectangular widgets whose brightness can **Actions:** -- ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of led widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1316,7 +1316,7 @@ The ``led`` can be also integrated as :doc:`Light ` comp Check out :ref:`lvgl-cook-keypad` in the Cookbook for an example illustrating how to change the ``led`` styling properties from an automation. -.. _lvgl-wgt-spi: +.. _lvgl-widget-spinner: ``spinner`` *********** @@ -1338,13 +1338,13 @@ The Spinner widget is a spinning arc over a ring. **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 widgets), just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of spinner widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1366,7 +1366,7 @@ The Spinner widget is a spinning arc over a ring. id: spinner_id arc_color: 0x31de70 -.. _lvgl-wgt-obj: +.. _lvgl-widget-obj: ``obj`` ******* @@ -1384,7 +1384,7 @@ You can use it as a parent container for other widgets. By default, it catches t **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1399,12 +1399,12 @@ You can use it as a parent container for other widgets. By default, it catches t widgets: - ... -.. _lvgl-wgt-tab: +.. _lvgl-widget-tabview: ``tabview`` *********** -The tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-wgt-bmx`. +The tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-widget-buttonmatrix`. .. figure:: /components/lvgl/images/lvgl_tabview.png :align: center @@ -1432,7 +1432,7 @@ The tabs are indexed (zero based) in the order they appear in the configuration **Triggers:** - ``on_value`` :ref:`trigger ` is activated when displayed tab changes. The new value is returned in the variable ``tab`` as the ID of the now-visible tab. -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1475,7 +1475,7 @@ The tabs are indexed (zero based) in the order they appear in the configuration then: - logger.log: "Dog tab is now showing" -.. _lvgl-wgt-tiv: +.. _lvgl-widget-tileview: ``tileview`` ************ @@ -1505,7 +1505,7 @@ If the Tile view is screen sized, the user interface resembles what you may have **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 now-visible tile. -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1543,7 +1543,7 @@ If the Tile view is screen sized, the user interface resembles what you may have then: - logger.log: "Cat tile is now showing" -.. _lvgl-wgt-msg: +.. _lvgl-widget-msgbox: ``msgboxes`` ************ @@ -1568,7 +1568,7 @@ The text will be broken into multiple lines automatically and the height will be **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:** @@ -1597,17 +1597,17 @@ 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-kbd: +.. _lvgl-widget-keyboard: ``keyboard`` ************ -The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-wgt-txt`. +The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-widget-textarea`. .. figure:: /components/lvgl/images/lvgl_keyboard.png :align: center -For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bmx`. +For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-widget-buttonmatrix`. **Configuration variables:** @@ -1620,7 +1620,7 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bm **Actions:** -- ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. +- ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of keyboard widgets which you want update. - Widget styles or properties from the specific options above, which you want update. @@ -1671,7 +1671,7 @@ Actions As outlined in the sections above, each widget type supports several of its own, unique actions. Several universal actions are also available for all widgets, these are outlined below. -.. _lvgl-objupd-act: +.. _lvgl-automation-actions: ``lvgl.widget.update`` ********************** @@ -1701,7 +1701,7 @@ This powerful :ref:`action ` allows changing/updating any widget Check out in the Cookbook :ref:`lvgl-cook-binent` for an example illustrating how to use a template to update the state. -.. _lvgl-objupd-shorthands: +.. _lvgl-automation-shorthands: ``lvgl.widget.hide``, ``lvgl.widget.show`` ****************************************** @@ -1746,7 +1746,7 @@ These :ref:`actions ` are shorthands for toggling the ``disabled Triggers -------- -.. _lvgl-event-trg: +.. _lvgl-automation-triggers: Specific triggers like ``on_value`` are available for certain widgets; they are described above in their respective section. Some universal triggers are also available for all of the widgets: diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 6690a31427..78d5d894cd 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -10,7 +10,7 @@ LVGL Select The ``lvgl`` select platform creates a select from an 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 only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome select component. +Supported widgets are :ref:`lvgl-widget-dropdown` and :ref:`lvgl-widget-roller`. A single select supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome select component. Configuration variables: ------------------------ @@ -34,8 +34,8 @@ Example: See Also -------- - :ref:`LVGL Main component ` -- :ref:`Roller widget ` -- :ref:`Dropdown widget ` +- :ref:`Roller widget ` +- :ref:`Dropdown widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 621e8afd38..062ed15cb3 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 an 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 only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome switch component. +Supported widgets are :ref:`lvgl-widget-button` (with ``checkable`` option enabled), :ref:`lvgl-widget-switch` and :ref:`lvgl-widget-checkbox`. A single switch supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome switch component. Configuration variables: ------------------------ @@ -30,9 +30,9 @@ Example: See Also -------- - :ref:`LVGL Main component ` -- :ref:`Button widget ` -- :ref:`Switch widget ` -- :ref:`Checkbox widget ` +- :ref:`Button widget ` +- :ref:`Switch widget ` +- :ref:`Checkbox widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index 76b394a6c5..d05964e653 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -9,7 +9,7 @@ LVGL Text The ``lvgl`` text platform creates an editable text component from an LVGL textual widget and requires :ref:`LVGL ` to be configured. -Supported widgets are :ref:`lvgl-wgt-lbl` and :ref:`lvgl-wgt-txt`. A single text supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text component. +Supported widgets are :ref:`lvgl-widget-label` and :ref:`lvgl-widget-textarea`. A single text supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text component. Configuration variables: ------------------------ @@ -33,8 +33,8 @@ Example: See Also -------- - :ref:`LVGL Main component ` -- :ref:`Label widget ` -- :ref:`Textarea widget ` +- :ref:`Label widget ` +- :ref:`Textarea widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index 0bde3b9a3f..cf0054d8a3 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -10,7 +10,7 @@ LVGL Text Sensor The ``lvgl`` text sensor platform creates a Text Sensor from an LVGL textual widget and requires :ref:`LVGL ` to be configured. -Supported widgets are :ref:`lvgl-wgt-lbl` and :ref:`lvgl-wgt-txt`. A single text sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text sensor component. +Supported widgets are :ref:`lvgl-widget-label` and :ref:`lvgl-widget-textarea`. A single text sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text sensor component. Configuration variables: ------------------------ @@ -34,8 +34,8 @@ Example: See Also -------- - :ref:`LVGL Main component ` -- :ref:`Label widget ` -- :ref:`Textarea widget ` +- :ref:`Label widget ` +- :ref:`Textarea widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 6e79623106..2bc7dc7ae1 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -25,7 +25,7 @@ Local light switch .. figure:: /components/lvgl/images/lvgl_switch.png :align: left -The easiest way to integrate an LVGL :ref:`lvgl-wgt-swi` widget and a switch or light is with :ref:`automations `: +The easiest way to integrate an LVGL :ref:`lvgl-widget-switch` widget and a switch or light is with :ref:`automations `: .. code-block:: yaml @@ -63,7 +63,7 @@ Remote light button .. figure:: images/lvgl_cook_remligbut.png :align: right -If you'd like to control a remote light which appears as an entity in Home Assistant from a checkable (toggle) :ref:`lvgl-wgt-btn`, first you need to import the light state into ESPHome, and then control it using a action call: +If you'd like to control a remote light which appears as an entity in Home Assistant from a checkable (toggle) :ref:`lvgl-widget-button`, first you need to import the light state into ESPHome, and then control it using a action call: .. code-block:: yaml @@ -108,7 +108,7 @@ Light brightness slider .. figure:: images/lvgl_cook_volume.png :align: left -You can use a :ref:`slider ` or an :ref:`arc ` to control the brightness of a dimmable light. +You can use a :ref:`slider ` or an :ref:`arc ` to control 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 convenient to set the slider's ``min_value`` and ``max_value`` accordingly. @@ -157,7 +157,7 @@ Media player volume slider .. 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. +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 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 action call, we have to divide it by ``100``: @@ -195,7 +195,7 @@ 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); -The ``adv_hittest`` option 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:: @@ -206,12 +206,12 @@ 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 accomplished 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-widget-meter` and :ref:`lvgl-widget-label` widgets: .. figure:: images/lvgl_cook_gauge.png :align: center -The trick here is to have a parent :ref:`lvgl-wgt-obj` which contains 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's central parts and place some :ref:`lvgl-wgt-lbl` widgets to display numeric information: +The trick here is to have a parent :ref:`lvgl-widget-obj` which contains the other widgets as children. We place a :ref:`lvgl-widget-meter` in the middle, which is made from an indicator ``line`` and two ``arc`` widgets. We use another, smaller :ref:`lvgl-widget-obj` on top of it to hide the indicator's central parts and place some :ref:`lvgl-widget-label` widgets to display numeric information: .. code-block:: yaml @@ -306,12 +306,12 @@ The trick here is to have a parent :ref:`lvgl-wgt-obj` which contains the other Thermometer ----------- -A thermometer with a precise gauge also made from a :ref:`lvgl-wgt-mtr` widget and a numeric display using :ref:`lvgl-wgt-lbl`: +A thermometer with a precise gauge also made from a :ref:`lvgl-widget-meter` widget and a numeric display using :ref:`lvgl-widget-label`: .. figure:: images/lvgl_cook_thermometer.png :align: center -Whenever a new value comes from the sensor, we update the needle indicator as well as the text in the :ref:`lvgl-wgt-lbl`. Since LVGL only handles integer values on the :ref:`lvgl-wgt-mtr` scale, but the sensor's value is a ``float``, we use the same approach as in the examples above; we multiply the sensor's values by ``10`` and feed this value to the :ref:`lvgl-wgt-mtr`. It's essentially two scales on top of each other: one to set the needle based on the multiplied value and the other to show sensor's original value in the :ref:`lvgl-wgt-lbl`. +Whenever a new value comes from the sensor, we update the needle indicator as well as the text in the :ref:`lvgl-widget-label`. Since LVGL only handles integer values on the :ref:`lvgl-widget-meter` scale, but the sensor's value is a ``float``, we use the same approach as in the examples above; we multiply the sensor's values by ``10`` and feed this value to the :ref:`lvgl-widget-meter`. It's essentially two scales on top of each other: one to set the needle based on the multiplied value and the other to show sensor's original value in the :ref:`lvgl-widget-label`. .. code-block:: yaml @@ -460,7 +460,7 @@ If you change the size of the widget, to obtain a uniform gradient, be sure to i Climate control --------------- -:ref:`lvgl-wgt-spb` is the ideal widget to control a thermostat: +:ref:`lvgl-widget-spinbox` is the ideal widget to control a thermostat: .. figure:: images/lvgl_cook_climate.png :align: center @@ -747,7 +747,7 @@ In this example we prepare a set of gradient styles in the *theme*, and make som bg_grad_color: 0x005782 bg_grad_dir: VER bg_opa: COVER - border_width: 0 + border_opa: TRANSP radius: 0 pad_all: 0 pad_row: 0 @@ -771,7 +771,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 can use a :ref:`lvgl-wgt-bmx`. 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 :ref:`lvgl-widget-buttonmatrix`. 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 @@ -1180,7 +1180,7 @@ The big advantage here is that whenever you need to add, for example, an extra c ESPHome boot screen ------------------- -To display a boot image with a spinner animation which disappears automatically after a few moments or on touch of the screen you can use the *top layer*. The trick is to put a base :ref:`lvgl-wgt-obj` full screen and child :ref:`lvgl-wgt-img` widget in its middle as the last item of the widgets list, so they draw on top of all the others. To make it automatically disappear afer boot, you use ESPHome's ``on_boot`` trigger: +To display a boot image with a spinner animation which disappears automatically after a few moments or on touch of the screen you can use the *top layer*. The trick is to put a base :ref:`lvgl-widget-obj` full screen and child :ref:`lvgl-widget-image` widget in its middle as the last item of the widgets list, so they draw on top of all the others. To make it automatically disappear afer boot, you use ESPHome's ``on_boot`` trigger: .. code-block:: yaml @@ -1285,7 +1285,7 @@ In the example below, we use the default set of glyphs from RobotoCondensed-Regu Restore checkbox mark --------------------- -If you configure a custom font as the ``default_font`` used by LVGL and this font does not contain the `FontAwesome `__ symbols, you may observe that some widgets won't display correctly; specifically :ref:`lvgl-wgt-chk` won't show the checkmark when it's checked. +If you configure a custom font as the ``default_font`` used by LVGL and this font does not contain the `FontAwesome `__ symbols, you may observe that some widgets won't display correctly; specifically :ref:`lvgl-widget-checkbox` won't show the checkmark when it's checked. To work around this issue, simply import only the checkmark symbol in the desired size and apply it through :ref:`lvgl-cook-theme` to all the checkboxes in the configuration: @@ -1318,7 +1318,7 @@ Toggle state icon button .. figure:: images/lvgl_cook_font_binstat.png :align: left -A common use case for icons is a status display. For example, a checkable (toggle) button will display different icons based on the status of a light or switch. 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`` states to apply *disabled styles* for these cases. +A common use case for icons is a status display. For example, a checkable (toggle) button will display different icons based on the status of a light or switch. To put an icon on a button you use a :ref:`lvgl-widget-label` widget as the child of the :ref:`lvgl-widget-button`. 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`` states to apply *disabled styles* for these cases. If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like this: @@ -1473,7 +1473,7 @@ Battery charging animation .. figure:: images/lvgl_cook_animimg_batt.gif :align: left -To have an animation illustrating a battery charging, you can use :ref:`lvgl-wgt-aim` with a set of :ref:`images rendered from MDI ` showing battery levels: +To have an animation illustrating a battery charging, you can use :ref:`lvgl-widget-animimg` with a set of :ref:`images rendered from MDI ` showing battery levels: .. code-block:: yaml @@ -1562,12 +1562,12 @@ To have an animation illustrating a battery charging, you can use :ref:`lvgl-wgt An analog clock --------------- -Using the :ref:`lvgl-wgt-mtr` and :ref:`lvgl-wgt-lbl` widgets, we can create an analog clock which shows the date too. +Using the :ref:`lvgl-widget-meter` and :ref:`lvgl-widget-label` widgets, we can create an analog clock which shows the date too. .. 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 ``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 :ref:`lvgl-widget-meter` 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 at the beginning of every minute to update the line positions for each hand as well as the respective text. @@ -1688,12 +1688,12 @@ The script runs at the beginning of every minute to update the line positions fo 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 (or ``key_code`` where configured) to the key collector. +The :ref:`lvgl-widget-buttonmatrix` 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 -If you key in the correct sequence, the :ref:`lvgl-wgt-led` widget will change color accordingly: +If you key in the correct sequence, the :ref:`lvgl-widget-led` widget will change color accordingly: .. code-block:: yaml From dbffdeb8e60a087234a43a6966d1c933c99e1782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 12:29:25 +0200 Subject: [PATCH 540/564] number also --- components/number/lvgl.rst | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 components/number/lvgl.rst diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst new file mode 100644 index 0000000000..aa311b0518 --- /dev/null +++ b/components/number/lvgl.rst @@ -0,0 +1,49 @@ +.. _lvgl-num: + +LVGL Number +=========== + +.. seo:: + :description: Instructions for setting up an LVGL widget number component. + :image: ../images/lvgl_c_num.png + +The ``lvgl`` number platform creates a number component from an LVGL widget +and requires :ref:`LVGL ` to be configured. + +Supported widgets are :ref:`lvgl-widget-arc`, :ref:`lvgl-widget-bar`, :ref:`lvgl-widget-slider` and :ref:`lvgl-widget-spinbox`. A single number supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome number component. + +Configuration variables: +------------------------ + +- **widget** (**Required**): The ID of a supported widget configured in LVGL, which will reflect the state of the number. +- **animated** (*Optional*, boolean): Whether to set the value of the widget with an animation (if supported by the widget). Defaults to ``true``. +- All other variables from :ref:`Number `. + +Example: + +.. code-block:: yaml + + number: + - platform: lvgl + widget: slider_id + name: LVGL Slider + +.. note:: + + Widget-specific actions (``lvgl.arc.update``, ``lvgl.bar.update``, ``lvgl.slider.update``, ``lvgl.spinbox.update``, ``lvgl.spinbox.decrement``, ``lvgl.spinbox.increment``) will trigger correspponding component updates to be sent to Home Assistant. + +See Also +-------- +- :ref:`LVGL Main component ` +- :ref:`Arc widget ` +- :ref:`Bar widget ` +- :ref:`Slider widget ` +- :ref:`Spinbox widget ` +- :doc:`/components/binary_sensor/lvgl` +- :doc:`/components/sensor/lvgl` +- :doc:`/components/switch/lvgl` +- :doc:`/components/select/lvgl` +- :doc:`/components/light/lvgl` +- :doc:`/components/text/lvgl` +- :doc:`/components/text_sensor/lvgl` +- :ghedit:`Edit` From 50b396b61037168b408d370e156b779058de3779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 13:13:39 +0200 Subject: [PATCH 541/564] longer anchor names --- components/key_collector.rst | 6 +++--- components/sensor/lvgl.rst | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/key_collector.rst b/components/key_collector.rst index 2b3e114b5a..44cc38c29f 100644 --- a/components/key_collector.rst +++ b/components/key_collector.rst @@ -8,7 +8,7 @@ Key collector component The ``key_collector`` component collects key presses from components like :ref:`matrix_keypad`, :ref:`Wiegand keypad ` -or LVGL :ref:`Button Matrix `, :ref:`Keyboard ` +or LVGL :ref:`Button Matrix `, :ref:`Keyboard ` widgets. It allows you to process key sequences and treat them as one, for example to allow inputting of a PIN code or a passkey. The component outputs the result of the keypress sequence as a variable usable in automations. @@ -91,6 +91,6 @@ See Also - :doc:`/components/matrix_keypad` - :doc:`/components/wiegand` -- :ref:`LVGL Button Matrix widget ` -- :ref:`LVGL Keyboard widget ` +- :ref:`LVGL Button Matrix widget ` +- :ref:`LVGL Keyboard widget ` - :ghedit:`Edit` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 7519338103..d8253b2bf9 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -10,7 +10,7 @@ LVGL Sensor The ``lvgl`` sensor platform creates a semsor component from an 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 sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome sensor. +Supported widgets are :ref:`lvgl-widget-arc`, :ref:`lvgl-widget-bar`, :ref:`lvgl-widget-slider` and :ref:`lvgl-widget-spinbox`. A single sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome sensor. Configuration variables: ------------------------ @@ -34,10 +34,10 @@ Example: See Also -------- - :ref:`LVGL Main component ` -- :ref:`Arc widget ` -- :ref:`Bar widget ` -- :ref:`Slider widget ` -- :ref:`Spinbox widget ` +- :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 7fb451ae73ea3918d66c4dc9dacb293d13356b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 13:20:18 +0200 Subject: [PATCH 542/564] rotary_encoders is now just encoders --- components/lvgl/index.rst | 10 +--------- components/lvgl/widgets.rst | 3 --- index.rst | 2 ++ 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index e47e1720f1..b6b4cfb569 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -76,7 +76,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a display. - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the touchscreen, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. -- **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. +- **encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: @@ -691,14 +691,6 @@ See Also * - :doc:`LVGL Examples in the Cookbook ` -- :doc:`/components/binary_sensor/lvgl` -- :doc:`/components/sensor/lvgl` -- :doc:`/components/number/lvgl` -- :doc:`/components/switch/lvgl` -- :doc:`/components/select/lvgl` -- :doc:`/components/light/lvgl` -- :doc:`/components/text/lvgl` -- :doc:`/components/text_sensor/lvgl` - :doc:`/components/display/index` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 2f6bf9b40e..588b005285 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -1801,8 +1801,5 @@ See Also - :doc:`/components/light/lvgl` - :doc:`/components/text/lvgl` - :doc:`/components/text_sensor/lvgl` -- :doc:`/components/display/index` -- :doc:`/components/touchscreen/index` -- :doc:`/components/sensor/rotary_encoder` - `LVGL docs `__ - :ghedit:`Edit` diff --git a/index.rst b/index.rst index dbeb1d3d6d..a41bb1aa38 100644 --- a/index.rst +++ b/index.rst @@ -832,6 +832,8 @@ Display Components LCD Menu, components/display_menu/lcd_menu, lcd_menu.png LVGL Graphics, components/lvgl/index, lvgl.png +.. _display-hw: + Display Hardware Platforms -------------------------- From e453ef4ff1301a93aee36eabd6d5ea4bbf59c584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 13:28:46 +0200 Subject: [PATCH 543/564] TOC optimizations --- components/lvgl/widgets.rst | 54 ++++++++++++++++---------------- components/touchscreen/index.rst | 2 ++ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 588b005285..760f5ac724 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -10,7 +10,7 @@ Widgets can have children, which can be any other widgets. Think of this as a ne 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 those related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the parent will be searched for an object which specifies a value for the property. The parents will use their own :ref:`state ` to determine the value. For example, if a button is pressed and the text color is defined by the "pressed" state, this "pressed" text color will be used. Common properties -***************** +----------------- The properties below are common to all widgets. @@ -123,7 +123,7 @@ In addition to visual styling, each widget supports some boolean **flags** to in .. _lvgl-widget-label: ``label`` -********* +--------- A label is the basic widget type that is used to display text. @@ -199,7 +199,7 @@ The ``label`` can be also integrated as :doc:`Text ` or : .. _lvgl-widget-textarea: ``textarea`` -************ +------------ The textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. @@ -265,7 +265,7 @@ The ``textarea`` can be also integrated as :doc:`Text ` o .. _lvgl-widget-button: ``button`` -********** +---------- Simple push (momentary) or toggle (two-states) button. @@ -329,7 +329,7 @@ See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable b .. _lvgl-widget-buttonmatrix: ``buttonmatrix`` -**************** +---------------- The button matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. @@ -461,7 +461,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row .. _lvgl-widget-switch: ``switch`` -********** +---------- The switch looks like a little slider and can be used to turn something on and off. @@ -505,7 +505,7 @@ See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local .. _lvgl-widget-checkbox: ``checkbox`` -************ +------------ 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. @@ -569,7 +569,7 @@ The ``checkbox`` can be also integrated as a :doc:`Switch ` .. _lvgl-widget-bar: ``bar`` -******* +------- The bar widget has a background and an indicator foreground on it. The size of the indicator is set according to the current ``value`` of the bar. @@ -765,7 +765,7 @@ The ``bar`` can be also integrated as :doc:`Number ` or .. _lvgl-widget-slider: ``slider`` -********** +---------- The slider widget looks like a bar supplemented with a knob. The user can drag the knob to set a value. Just like bar, slider can be vertical or horizontal. The size of the indicator foreground and the knob position is set according to the current ``value`` of the slider. @@ -838,7 +838,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustratin .. _lvgl-widget-arc: ``arc`` -******* +------- The arc consists of a background and a foreground arc. The indicator foreground can be touch-adjusted with a knob. @@ -923,7 +923,7 @@ See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustratin .. _lvgl-widget-spinbox: ``spinbox`` -*********** +----------- The spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. @@ -1002,7 +1002,7 @@ See :ref:`lvgl-cook-climate` for an example illustrating how to implement a ther .. _lvgl-widget-meter: ``meter`` -********* +--------- The meter widget can visualize data in very flexible ways. It can use arcs, needles, ticks, lines and/or labels. @@ -1114,7 +1114,7 @@ See :ref:`lvgl-cook-gauge`, :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clo .. _lvgl-widget-image: ``image`` -********* +--------- Images are the basic widgets used to display images. @@ -1174,7 +1174,7 @@ Images are the basic widgets used to display images. .. _lvgl-widget-animimg: ``animimg`` -*********** +----------- The animation image is similar to the normal ``image`` 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. @@ -1229,7 +1229,7 @@ See :ref:`lvgl-cook-animbatt` in the Cookbook for a more detailed example. .. _lvgl-widget-line: ``line`` -******** +-------- The line widget is capable of drawing straight lines between a set of points. @@ -1267,7 +1267,7 @@ By default, the Line widget width and height dimensions are set to ``SIZE_CONTEN .. _lvgl-widget-led: ``led`` -******** +------- The LED widgets are either circular or rectangular widgets whose brightness can be adjusted. As their brightness decreases, the colors become darker. @@ -1319,7 +1319,7 @@ Check out :ref:`lvgl-cook-keypad` in the Cookbook for an example illustrating ho .. _lvgl-widget-spinner: ``spinner`` -*********** +----------- The Spinner widget is a spinning arc over a ring. @@ -1369,7 +1369,7 @@ The Spinner widget is a spinning arc over a ring. .. _lvgl-widget-obj: ``obj`` -******* +------- The base object is just a simple, empty widget. By default, it's nothing more than a rounded rectangle: @@ -1402,7 +1402,7 @@ You can use it as a parent container for other widgets. By default, it catches t .. _lvgl-widget-tabview: ``tabview`` -*********** +----------- The tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-widget-buttonmatrix`. @@ -1478,7 +1478,7 @@ The tabs are indexed (zero based) in the order they appear in the configuration .. _lvgl-widget-tileview: ``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. @@ -1546,7 +1546,7 @@ If the Tile view is screen sized, the user interface resembles what you may have .. _lvgl-widget-msgbox: ``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. @@ -1600,7 +1600,7 @@ The configured message boxes are hidden by default. One can show them with ``lvg .. _lvgl-widget-keyboard: ``keyboard`` -************ +------------ The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-widget-textarea`. @@ -1666,7 +1666,7 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-widget The Keyboard widget in ESPHome doesn't support popovers or custom layouts. Actions -------- +======= As outlined in the sections above, each widget type supports several of its own, unique actions. Several universal actions are also available for all widgets, these are outlined below. @@ -1744,7 +1744,7 @@ These :ref:`actions ` are shorthands for toggling the ``disabled - id: my_button_2 Triggers --------- +======== .. _lvgl-automation-triggers: @@ -1789,7 +1789,7 @@ These triggers can be applied directly to any widget in the LVGL configuration, brightness: !lambda return x / 100; See Also --------- +======== - :doc:`/components/lvgl` - :doc:`LVGL Examples in the Cookbook ` diff --git a/components/touchscreen/index.rst b/components/touchscreen/index.rst index bf2c19af51..62b24db684 100644 --- a/components/touchscreen/index.rst +++ b/components/touchscreen/index.rst @@ -1,3 +1,5 @@ +.. _touchscreen-main: + Touchscreen Components ====================== From 8669619811f6b8ac5f71f4d6fcce02a3c2c99fbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 13:30:49 +0200 Subject: [PATCH 544/564] Update widgets.rst --- components/lvgl/widgets.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 760f5ac724..6a7e5b4d80 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -1666,7 +1666,7 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-widget The Keyboard widget in ESPHome doesn't support popovers or custom layouts. Actions -======= +------- As outlined in the sections above, each widget type supports several of its own, unique actions. Several universal actions are also available for all widgets, these are outlined below. @@ -1744,7 +1744,7 @@ These :ref:`actions ` are shorthands for toggling the ``disabled - id: my_button_2 Triggers -======== +-------- .. _lvgl-automation-triggers: @@ -1789,7 +1789,7 @@ These triggers can be applied directly to any widget in the LVGL configuration, brightness: !lambda return x / 100; See Also -======== +-------- - :doc:`/components/lvgl` - :doc:`LVGL Examples in the Cookbook ` From 3d4f44a5d4b5e4317f2581e305f06ef89e4ff6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 13:32:50 +0200 Subject: [PATCH 545/564] Update widgets.rst --- components/lvgl/widgets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 6a7e5b4d80..7daa91505b 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -1791,7 +1791,7 @@ These triggers can be applied directly to any widget in the LVGL configuration, See Also -------- -- :doc:`/components/lvgl` +- :ref:`LVGL Main component ` - :doc:`LVGL Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` From 2ee8827452b5ff6b159ec521681265f0886da1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 13:40:44 +0200 Subject: [PATCH 546/564] action links --- components/lvgl/index.rst | 3 +++ components/lvgl/widgets.rst | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index b6b4cfb569..c06d148293 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -499,6 +499,7 @@ LVGL supports a list of :ref:`lvgl-widgets` which can be used to draw interactiv Actions ------- +Widgets support :ref:`general or specific ` actions. Several actions are available for LVGL, these are outlined below. .. _lvgl-rfrsh-act: @@ -653,6 +654,8 @@ This :ref:`condition ` checks if LVGL is in the paused state Triggers -------- +Widget level :ref:`interaction triggers ` can be configured universally, or depending on the widtget functionality. + .. _lvgl-onidle-trg: ``lvgl.on_idle`` diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 7daa91505b..55aed0de04 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -1665,14 +1665,14 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-widget The Keyboard widget in ESPHome doesn't support popovers or custom layouts. +.. _lvgl-automation-actions: + Actions ------- As outlined in the sections above, each widget type supports several of its own, unique actions. Several universal actions are also available for all widgets, these are outlined below. -.. _lvgl-automation-actions: - ``lvgl.widget.update`` ********************** From c2a5b377b288c6915852dde86c7c1b4ff84af2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 13:52:14 +0200 Subject: [PATCH 547/564] Apply suggestions from code review --- components/light/lvgl.rst | 4 ++-- components/lvgl/index.rst | 4 ++-- components/lvgl/widgets.rst | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 6ea3aa12d3..b0f980aa25 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -12,8 +12,8 @@ and requires :ref:`LVGL ` to be configured. Supported widget is :ref:`lvgl-widget-led`. A single light supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome light component. -Configuration options: ----------------------- +Configuration variables: +------------------------ - **widget** (**Required**): The ID of a ``led`` widget configured in LVGL, which will reflect the state of the light. - All other options from :ref:`light `. diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index c06d148293..916c97bc17 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -12,7 +12,7 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t .. figure:: /components/lvgl/images/lvgl_main_screenshot.png -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 for bigger displays. +To use LVGL with a :ref:`display ` in ESPHome, you'll need an ESP32 or supported ESP32 variant. PSRAM is not a strict requirement but it is generally recommended, especially for color displays with resolutions larger than approximately 240x240 pixels. The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. @@ -103,7 +103,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o .. tip:: - When using binary sensors (from physical keys) to interact with LVGL, if there are only 3 keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With 4 or more keys, a keypad configuration suits better. For example a 5-key keypad might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``: ``PREV``/``NEXT`` can select a widget within the group, ``UP``/``DOWN`` changes the value, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. + When using binary sensors (from physical keys) to interact with LVGL, if there are only three keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With four or more keys, a keypad configuration is generally more appropriate. For example, a keypad consisting of five keys might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``; ``PREV``/``NEXT`` are used to select a widget within the group, ``UP``/``DOWN`` changes the selected value and ``ENTER`` generates an ``on_press`` :ref:`trigger `. The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 55aed0de04..2ba205a0f3 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -1409,7 +1409,7 @@ The tab view object can be used to organize content in tabs. The tab buttons are .. figure:: /components/lvgl/images/lvgl_tabview.png :align: center -The tabs are indexed (zero based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button, by sliding horizontally on the content or via ``lvgl.tabview.select`` :ref:`action `, specifying its index. +The tabs are indexed (zero-based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button, by sliding horizontally on the content or via the ``lvgl.tabview.select`` :ref:`action `, specifying the tab's index. **Configuration variables:** @@ -1426,7 +1426,7 @@ The tabs are indexed (zero based) in the order they appear in the configuration - ``lvgl.tabview.select`` :ref:`action ` jumps the view to the desired tab: - **id** (**Required**): The ID of the tabview which receives this action. - - **index** (**Required**): The the zero based index of the tab to which to jump. + - **index** (**Required**): The (zero-based) index of the tab to which to jump. - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. **Triggers:** From 488f714f1c8a04a219d0c9da91597e3e52d4e2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 14:27:04 +0200 Subject: [PATCH 548/564] longer anchors --- components/binary_sensor/lvgl.rst | 2 +- components/light/lvgl.rst | 2 +- components/lvgl/index.rst | 14 +++---- components/lvgl/widgets.rst | 30 +++++++------- components/select/lvgl.rst | 2 +- components/switch/lvgl.rst | 2 +- components/text/lvgl.rst | 2 +- components/text_sensor/lvgl.rst | 2 +- cookbook/lvgl.rst | 68 +++++++++++++++---------------- 9 files changed, 62 insertions(+), 62 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 8d970b32c1..74c11c8525 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -1,4 +1,4 @@ -.. _lvgl-bse: +.. _lvgl-binary-sensor: LVGL Binary Sensor ================== diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index b0f980aa25..44aac083e8 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -1,4 +1,4 @@ -.. _lvgl-lgh: +.. _lvgl-light: LVGL Light ========== diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index 916c97bc17..525608db7d 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -18,7 +18,7 @@ The graphic display should be configured with ``auto_clear_enabled: false`` and For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred), a :doc:`/components/sensor/rotary_encoder` or a custom keypad made up from discrete :doc:`Binary Sensors ` 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. +Check out a few detailed examples :ref:`in the Cookbook ` to see a couple ways to integrate LVGL through ESPHome with your environment. Basics ------ @@ -147,7 +147,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o align: CENTER text: 'Hello World!' -See :ref:`lvgl-cook-navigator` in the Cookbook for an example illustrating how to easily implement a page navigation bar at the bottom of the screen. +See :ref:`lvgl-cookbook-navigator` in the Cookbook for an example illustrating how to easily implement a page navigation bar at the bottom of the screen. .. _lvgl-color: @@ -178,7 +178,7 @@ You can use :ref:`fonts configured normally`, the glyphs will be For best results, set ``bpp: 4`` to get the glyphs rendered with proper anti-aliasing. -Check out :ref:`lvgl-cook-icontext`, :ref:`lvgl-cook-iconstat` and :ref:`lvgl-cook-iconbatt` in the Cookbook for examples illustrating how to use icons and text with TrueType/OpenType fonts. +Check out :ref:`lvgl-cookbook-icontext`, :ref:`lvgl-cookbook-iconstat` and :ref:`lvgl-cookbook-iconbatt` in the Cookbook for examples illustrating how to use icons and text with TrueType/OpenType fonts. **Library fonts** @@ -379,7 +379,7 @@ So the precedence happens like this: state based styles override the locally spe Feel free to experiment to discover inheritance and precedence of the styles based on states between the nested widgets. -:ref:`lvgl-cook-theme` The Cookbook contains an example illustrating how to easily implement a gradient style for your widgets. +:ref:`lvgl-cookbook-theme` The Cookbook contains an example illustrating how to easily implement a gradient style for your widgets. .. _lvgl-layouts: @@ -390,7 +390,7 @@ Layouts aim to position widgets automatically, eliminating the need to specify ` The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. The position and size calculated by the layout overwrites the *normal* ``x``, ``y``, ``width``, and ``height`` settings of the children. -Checkout :ref:`lvgl-cook-flex`, :ref:`lvgl-cook-grid` and :ref:`lvgl-cook-weather` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. +Checkout :ref:`lvgl-cookbook-flex`, :ref:`lvgl-cookbook-grid` and :ref:`lvgl-cookbook-weather` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` can be used on widgets to ignore them in layout calculations. @@ -524,7 +524,7 @@ This :ref:`action ` redraws the entire screen, or optionally onl This :ref:`action ` pauses the activity of LVGL, including rendering. -- **show_snow** (*Optional*, boolean): When 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 illustrating how to use this. +- **show_snow** (*Optional*, boolean): When 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-cookbook-antiburn` for an example illustrating how to use this. .. code-block:: yaml @@ -680,7 +680,7 @@ The ``on_idle`` :ref:`triggers ` are activated when inactivity time - light.turn_off: display_backlight - lvgl.pause: -See :ref:`lvgl-cook-idlescreen` for an example illustrating how to implement screen saving with idle settings. +See :ref:`lvgl-cookbook-idlescreen` for an example illustrating how to implement screen saving with idle settings. .. _lvgl-seealso: diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 2ba205a0f3..b5b0c9fd2e 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -85,7 +85,7 @@ To apply styles to the states, you need to specify them one level above, for exa 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 illustrating how to use styling and properties to show different states of a Home Assistant entity. +See :ref:`lvgl-cookbook-cover` for a cookbook example illustrating how to use styling and properties to show different states of a Home Assistant entity. .. _lvgl-objupdflag-act: @@ -324,7 +324,7 @@ To have a button with a text label on it, add a child :ref:`lvgl-widget-label` w The ``button`` can be also integrated as a :doc:`Binary Sensor ` or as a :doc:`Switch ` component. -See :ref:`lvgl-cook-binent` for an example illustrating how to use a checkable button to act on a Home Assistant service. +See :ref:`lvgl-cookbook-binent` for an example illustrating how to use a checkable button to act on a Home Assistant service. .. _lvgl-widget-buttonmatrix: @@ -456,7 +456,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row .. 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. + 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-cookbook-keypad` for an example. .. _lvgl-widget-switch: @@ -500,7 +500,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 a :doc:`Switch ` component. -See :ref:`lvgl-cook-relay` for an example how to use a switch to act on a local component. +See :ref:`lvgl-cookbook-relay` for an example how to use a switch to act on a local component. .. _lvgl-widget-checkbox: @@ -562,7 +562,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c .. note:: - In case you configure ``default_font`` in the main section to a custom font, the checkmark will not be shown correctly when the checkbox is in the checked state. See :ref:`lvgl-cook-ckboxmark` how to easily resolve this. + In case you configure ``default_font`` in the main section to a custom font, the checkmark will not be shown correctly when the checkbox is in the checked state. See :ref:`lvgl-cookbook-ckboxmark` how to easily resolve this. The ``checkbox`` can be also integrated as a :doc:`Switch ` component. @@ -833,7 +833,7 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider to control entities in Home Assistant. +See :ref:`lvgl-cookbook-bright` and :ref:`lvgl-cookbook-volume` for examples illustrating how to use a slider to control entities in Home Assistant. .. _lvgl-widget-arc: @@ -918,7 +918,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -See :ref:`lvgl-cook-bright` and :ref:`lvgl-cook-volume` for examples illustrating how to use a slider (or an arc) to control entities in Home Assistant. +See :ref:`lvgl-cookbook-bright` and :ref:`lvgl-cookbook-volume` for examples illustrating how to use a slider (or an arc) to control entities in Home Assistant. .. _lvgl-widget-spinbox: @@ -997,7 +997,7 @@ The spinbox contains a numeric value (as text) which can be increased or decreas The ``spinbox`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -See :ref:`lvgl-cook-climate` for an example illustrating how to implement a thermostat control using the spinbox. +See :ref:`lvgl-cookbook-climate` for an example illustrating how to implement a thermostat control using the spinbox. .. _lvgl-widget-meter: @@ -1109,7 +1109,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need id: temperature_needle value: 3 -See :ref:`lvgl-cook-gauge`, :ref:`lvgl-cook-thermometer` and :ref:`lvgl-cook-clock` in the Cookbook for examples illustrating how to effectively use this widget. +See :ref:`lvgl-cookbook-gauge`, :ref:`lvgl-cookbook-thermometer` and :ref:`lvgl-cookbook-clock` in the Cookbook for examples illustrating how to effectively use this widget. .. _lvgl-widget-image: @@ -1224,7 +1224,7 @@ The animation image is similar to the normal ``image`` widget. The main differen repeat_count: 100 duration: 300ms -See :ref:`lvgl-cook-animbatt` in the Cookbook for a more detailed example. +See :ref:`lvgl-cookbook-animbatt` in the Cookbook for a more detailed example. .. _lvgl-widget-line: @@ -1314,7 +1314,7 @@ The ``led`` can be also integrated as :doc:`Light ` comp 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 illustrating how to change the ``led`` styling properties from an automation. +Check out :ref:`lvgl-cookbook-keypad` in the Cookbook for an example illustrating how to change the ``led`` styling properties from an automation. .. _lvgl-widget-spinner: @@ -1699,7 +1699,7 @@ This powerful :ref:`action ` allows changing/updating any widget id: my_label_id hidden: true -Check out in the Cookbook :ref:`lvgl-cook-binent` for an example illustrating how to use a template to update the state. +Check out in the Cookbook :ref:`lvgl-cookbook-binent` for an example illustrating how to use a template to update the state. .. _lvgl-automation-shorthands: @@ -1743,11 +1743,11 @@ These :ref:`actions ` are shorthands for toggling the ``disabled - id: my_button_1 - id: my_button_2 +.. _lvgl-automation-triggers: + Triggers -------- -.. _lvgl-automation-triggers: - Specific triggers like ``on_value`` are available for certain widgets; they are described above in their respective section. Some universal triggers are also available for all of the widgets: @@ -1792,7 +1792,7 @@ See Also -------- - :ref:`LVGL Main component ` -- :doc:`LVGL Examples in the Cookbook ` +- :doc:`Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 78d5d894cd..5e62113bde 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -1,4 +1,4 @@ -.. _lvgl-sel: +.. _lvgl-select: LVGL Select =========== diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 062ed15cb3..a50a3d48cb 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -1,4 +1,4 @@ -.. _lvgl-swi: +.. _lvgl-switch: LVGL Switch =========== diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index d05964e653..d583e42fdf 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -1,4 +1,4 @@ -.. _lvgl-txt: +.. _lvgl-text: LVGL Text ========= diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index cf0054d8a3..95bfdad83d 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -1,4 +1,4 @@ -.. _lvgl-txs: +.. _lvgl-text-sensor: LVGL Text Sensor ================ diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst index 2bc7dc7ae1..cce37138db 100644 --- a/cookbook/lvgl.rst +++ b/cookbook/lvgl.rst @@ -1,4 +1,4 @@ -.. _lvgl-cook: +.. _lvgl-cookbook: LVGL: Tips and Tricks ===================== @@ -17,7 +17,7 @@ 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 with dimensions of ``240x320px``; if your display's dimensions differ, you'll need to adjust them in order to obtain the expected results. -.. _lvgl-cook-relay: +.. _lvgl-cookbook-relay: Local light switch ------------------ @@ -55,7 +55,7 @@ The easiest way to integrate an LVGL :ref:`lvgl-widget-switch` widget and a swit on_click: light.toggle: local_light -.. _lvgl-cook-binent: +.. _lvgl-cookbook-binent: Remote light button ------------------- @@ -100,7 +100,7 @@ If you'd like to control a remote light which appears as an entity in Home Assis data: entity_id: light.remote_light -.. _lvgl-cook-bright: +.. _lvgl-cookbook-bright: Light brightness slider ----------------------- @@ -149,7 +149,7 @@ Note that Home Assistant expects an integer at the ``brightness`` parameter of t This is applicable to action calls like ``fan.set_percentage`` or ``valve.set_valve_position``, too; the only difference is that ``max_value`` has to be ``100``. -.. _lvgl-cook-volume: +.. _lvgl-cookbook-volume: Media player volume slider -------------------------- @@ -201,7 +201,7 @@ 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 generally has a negative effect on performance. 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. To mitigate this, consider using a universal widget trigger like ``on_release`` to get the ``x`` variable once after the interaction has completed. -.. _lvgl-cook-gauge: +.. _lvgl-cookbook-gauge: Semicircle gauge ---------------- @@ -301,7 +301,7 @@ The trick here is to have a parent :ref:`lvgl-widget-obj` which contains the oth The ``obj`` used to hide the middle part of the 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: +.. _lvgl-cookbook-thermometer: Thermometer ----------- @@ -455,7 +455,7 @@ If you change the size of the widget, to obtain a uniform gradient, be sure to i You can omit the ``obj`` used to hide the middle part of meter indicator line by using a bitmap ``image`` indicator as needle, were only the part hanging above the ticks scale is visible, the rest is transparent. -.. _lvgl-cook-climate: +.. _lvgl-cookbook-climate: Climate control --------------- @@ -527,7 +527,7 @@ First we import from Home Assistant the current target temperature of the climat - label: text: "+" -.. _lvgl-cook-cover: +.. _lvgl-cookbook-cover: Cover status and control ------------------------ @@ -652,7 +652,7 @@ Just as in the previous examples, we need to get the state of the cover first. W data: entity_id: cover.myroom -.. _lvgl-cook-theme: +.. _lvgl-cookbook-theme: Theme and style definitions --------------------------- @@ -759,7 +759,7 @@ In this example we prepare a set of gradient styles in the *theme*, and make som Note that style definitions can contain common properties too, like positioning and sizing. -.. _lvgl-cook-navigator: +.. _lvgl-cookbook-navigator: Page navigation footer ---------------------- @@ -805,9 +805,9 @@ For the navigation bar we can use a :ref:`lvgl-widget-buttonmatrix`. Note how th then: lvgl.page.next: -For this example to appear correctly, use the theme and style options from :ref:`above ` and LVGL's own library :ref:`fonts `. +For this example to appear correctly, use the theme and style options from :ref:`above ` and LVGL's own library :ref:`fonts `. -.. _lvgl-cook-statico: +.. _lvgl-cookbook-statico: API connection status icon -------------------------- @@ -854,7 +854,7 @@ Of note: - The widget starts *hidden* at boot and it's only shown when triggered by connection with the API. - 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: +.. _lvgl-cookbook-titlebar: Title bar for each page ----------------------- @@ -896,9 +896,9 @@ To put a title bar behind the status icon, we need to add it to each page, also text_color: 0xFFFFFF ... -For this example to work, use the theme and style options from :ref:`above `. +For this example to work, use the theme and style options from :ref:`above `. -.. _lvgl-cook-flex: +.. _lvgl-cookbook-flex: Flex layout positioning ----------------------- @@ -908,7 +908,7 @@ Flex layout positioning .. figure:: images/lvgl_cook_flex_layout.png :align: center -This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer fully-featured individual buttons, as they offer a wider range of customization possibilities as seen in the :ref:`lvgl-cook-cover` example. Here we use the **Flex** layout: +This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer fully-featured individual buttons, as they offer a wider range of customization possibilities as seen in the :ref:`lvgl-cookbook-cover` example. Here we use the **Flex** layout: .. code-block:: yaml @@ -1023,9 +1023,9 @@ This example illustrates a control panel for three covers, made up of labels and align: CENTER text: "\U000F0045" -This saved you from a considerable amount of manual calculation of widget positioning which would otherwise be required to place them manually with ``x`` and ``y``! You only need to determine a common width and height for your widgets to distribute them on the page as you prefer. (:ref:`lvgl-cook-icontext` below shows how to use custom icons.) +This saved you from a considerable amount of manual calculation of widget positioning which would otherwise be required to place them manually with ``x`` and ``y``! You only need to determine a common width and height for your widgets to distribute them on the page as you prefer. (:ref:`lvgl-cookbook-icontext` below shows how to use custom icons.) -.. _lvgl-cook-grid: +.. _lvgl-cookbook-grid: Grid layout positioning ----------------------- @@ -1173,9 +1173,9 @@ But there's even more! With the **Grid** layout, you don't need to specify width align: CENTER text: "\U000F0045" -The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. With ``STRETCH`` their sizes and positions will automatically be calculated to fill in the cells, while the parent's ``pad_all``, ``pad_row`` and ``pad_column`` can help with spacing between them. See :ref:`lvgl-cook-weather` further down this page for another example relying on **Grid**. +The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. With ``STRETCH`` their sizes and positions will automatically be calculated to fill in the cells, while the parent's ``pad_all``, ``pad_row`` and ``pad_column`` can help with spacing between them. See :ref:`lvgl-cookbook-weather` further down this page for another example relying on **Grid**. -.. _lvgl-cook-btlg: +.. _lvgl-cookbook-btlg: ESPHome boot screen ------------------- @@ -1232,7 +1232,7 @@ To display a boot image with a spinner animation which disappears automatically on_press: - lvgl.widget.hide: boot_screen -.. _lvgl-cook-icontext: +.. _lvgl-cookbook-icontext: MDI icons in text ----------------- @@ -1280,14 +1280,14 @@ In the example below, we use the default set of glyphs from RobotoCondensed-Regu - 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-ckboxmark: +.. _lvgl-cookbook-ckboxmark: Restore checkbox mark --------------------- If you configure a custom font as the ``default_font`` used by LVGL and this font does not contain the `FontAwesome `__ symbols, you may observe that some widgets won't display correctly; specifically :ref:`lvgl-widget-checkbox` won't show the checkmark when it's checked. -To work around this issue, simply import only the checkmark symbol in the desired size and apply it through :ref:`lvgl-cook-theme` to all the checkboxes in the configuration: +To work around this issue, simply import only the checkmark symbol in the desired size and apply it through :ref:`lvgl-cookbook-theme` to all the checkboxes in the configuration: .. code-block:: yaml @@ -1310,7 +1310,7 @@ To work around this issue, simply import only the checkmark symbol in the desire You could of course simply apply one of the built-in ``montserrat_`` packs, but that would not be beneficial on the binary size - it would uselessly include the entire set of glyphs in the flash. -.. _lvgl-cook-iconstat: +.. _lvgl-cookbook-iconstat: Toggle state icon button ------------------------ @@ -1318,9 +1318,9 @@ Toggle state icon button .. figure:: images/lvgl_cook_font_binstat.png :align: left -A common use case for icons is a status display. For example, a checkable (toggle) button will display different icons based on the status of a light or switch. To put an icon on a button you use a :ref:`lvgl-widget-label` widget as the child of the :ref:`lvgl-widget-button`. 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`` states to apply *disabled styles* for these cases. +A common use case for icons is a status display. For example, a checkable (toggle) button will display different icons based on the status of a light or switch. To put an icon on a button you use a :ref:`lvgl-widget-label` widget as the child of the :ref:`lvgl-widget-button`. The coloring can already be different thanks to the :ref:`lvgl-cookbook-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`` states to apply *disabled styles* for these cases. -If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like this: +If we take our previous :ref:`lvgl-cookbook-binent` example, we can modify it like this: .. code-block:: yaml @@ -1382,7 +1382,7 @@ If we take our previous :ref:`lvgl-cook-binent` example, we can modify it like t data: entity_id: light.remote_light -.. _lvgl-cook-iconbatt: +.. _lvgl-cookbook-iconbatt: Battery status icon ------------------- @@ -1465,7 +1465,7 @@ Another example for using MDI icons is to display battery percentage in 10 steps text_font: battery_icons_20 text: "\U000F0091" # start with mdi-battery-unknown -.. _lvgl-cook-animbatt: +.. _lvgl-cookbook-animbatt: Battery charging animation -------------------------- @@ -1557,7 +1557,7 @@ To have an animation illustrating a battery charging, you can use :ref:`lvgl-wid Use ``x``, ``y``, ``align`` widget properties for precise positioning. -.. _lvgl-cook-clock: +.. _lvgl-cookbook-clock: An analog clock --------------- @@ -1683,7 +1683,7 @@ The script runs at the beginning of every minute to update the line positions fo 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: +.. _lvgl-cookbook-keypad: A numeric input keypad ---------------------- @@ -1826,7 +1826,7 @@ Of note: - Changing the background color of the buttons in ``pressed`` state. - Use of the ``key_code`` configuration to send a different character to ``key_collector`` instead of the displayed symbol. -.. _lvgl-cook-weather: +.. _lvgl-cookbook-weather: Weather forecast panel ---------------------- @@ -2120,7 +2120,7 @@ These labels will appear in Home Assistant as `editable text components `. -.. _lvgl-cook-idlescreen: +.. _lvgl-cookbook-idlescreen: Turn off screen when idle ------------------------- @@ -2166,7 +2166,7 @@ LVGL has a notion of screen inactivity -- in other words, the time since the las step: 5 mode: box -.. _lvgl-cook-antiburn: +.. _lvgl-cookbook-antiburn: Prevent burn-in of LCD ---------------------- From f0f8b63129dc179093644cd23ea336edfd3e5d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 14:32:32 +0200 Subject: [PATCH 549/564] further anchor names extended --- components/lvgl/index.rst | 6 +++--- components/lvgl/widgets.rst | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index 525608db7d..f52ff907b6 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -304,7 +304,7 @@ Themes The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. -You can configure a global theme for all widgets at the top level with the ``theme`` configuration variable. In the example below, all the ``arc``, ``slider`` and ``button`` widgets will, by default, use the styles and properties defined here. A combination of styles and :ref:`states ` can be chosen for every widget. +You can configure a global theme for all widgets at the top level with the ``theme`` configuration variable. In the example below, all the ``arc``, ``slider`` and ``button`` widgets will, by default, use the styles and properties defined here. A combination of styles and :ref:`states ` can be chosen for every widget. .. code-block:: yaml @@ -357,7 +357,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 :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. +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: @@ -392,7 +392,7 @@ The layout configuration options are applied to any parent widget or page, influ Checkout :ref:`lvgl-cookbook-flex`, :ref:`lvgl-cookbook-grid` and :ref:`lvgl-cookbook-weather` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. -The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` can be used on widgets to ignore them in layout calculations. +The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` can be used on widgets to ignore them in layout calculations. **Configuration variables:** diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index b5b0c9fd2e..fded6eaa69 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -7,7 +7,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, its children will also be hidden. -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 those related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the parent will be searched for an object which specifies a value for the property. The parents will use their own :ref:`state ` to determine the value. For example, if a button is pressed and the text color is defined by the "pressed" state, this "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 those related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the parent will be searched for an object which specifies a value for the property. The parents will use their own :ref:`state ` to determine the value. For example, if a button is pressed and the text color is defined by the "pressed" state, this "pressed" text color will be used. Common properties ----------------- @@ -36,7 +36,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 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 dimensions 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. Scroll bars 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. 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. @@ -58,7 +58,7 @@ The properties below are common to all widgets. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - **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: +.. _lvgl-widgetproperty-state: - **state** (*Optional*, dict): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from the theme, but can be locally set or overridden within style definitions. Can be one of: - **default** (*Optional*, boolean): Normal, released state. @@ -87,7 +87,7 @@ The state itself can be can be changed by interacting with the widget, or throug See :ref:`lvgl-cookbook-cover` for a cookbook example illustrating how to use styling and properties to show different states of a Home Assistant entity. -.. _lvgl-objupdflag-act: +.. _lvgl-widget-flags: In addition to visual styling, each widget supports some boolean **flags** to influence the behavior: @@ -274,7 +274,7 @@ Simple push (momentary) or toggle (two-states) button. **Configuration variables:** -- **checkable** (*Optional*, boolean): A significant :ref:`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. A notable state is ``checked`` (boolean) which can have different styles applied. @@ -864,7 +864,7 @@ The arc consists of a background and a foreground arc. The indicator foreground - **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`` :ref:`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:: @@ -1676,10 +1676,10 @@ Several universal actions are also available for all widgets, these are outlined ``lvgl.widget.update`` ********************** -This powerful :ref:`action ` allows changing/updating any widget's common :ref:`style property `, state (templatable) or :ref:`flag ` on the fly. +This powerful :ref:`action ` allows changing/updating any widget's common :ref:`style property `, state (templatable) or :ref:`flag ` on the fly. - **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want update. -- The widget's common :ref:`style property `, state (templatable) or :ref:`flag `. +- The widget's common :ref:`style property `, state (templatable) or :ref:`flag `. .. code-block:: yaml @@ -1706,7 +1706,7 @@ Check out in the Cookbook :ref:`lvgl-cookbook-binent` for an example illustratin ``lvgl.widget.hide``, ``lvgl.widget.show`` ****************************************** -These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget. +These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget. - **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want to hide or show. From 6998d223b0768866b110597d8988103f3b5a41fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Tue, 6 Aug 2024 14:45:00 +0200 Subject: [PATCH 550/564] TOC fixes --- components/lvgl/widgets.rst | 46 ++++++++++++++++++------------------- components/number/lvgl.rst | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index fded6eaa69..119eafcbc2 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -123,7 +123,7 @@ In addition to visual styling, each widget supports some boolean **flags** to in .. _lvgl-widget-label: ``label`` ---------- +********* A label is the basic widget type that is used to display text. @@ -199,7 +199,7 @@ The ``label`` can be also integrated as :doc:`Text ` or : .. _lvgl-widget-textarea: ``textarea`` ------------- +************ The textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. @@ -265,7 +265,7 @@ The ``textarea`` can be also integrated as :doc:`Text ` o .. _lvgl-widget-button: ``button`` ----------- +********** Simple push (momentary) or toggle (two-states) button. @@ -329,7 +329,7 @@ See :ref:`lvgl-cookbook-binent` for an example illustrating how to use a checkab .. _lvgl-widget-buttonmatrix: ``buttonmatrix`` ----------------- +**************** The button matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. @@ -461,7 +461,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row .. _lvgl-widget-switch: ``switch`` ----------- +********** The switch looks like a little slider and can be used to turn something on and off. @@ -505,7 +505,7 @@ See :ref:`lvgl-cookbook-relay` for an example how to use a switch to act on a lo .. _lvgl-widget-checkbox: ``checkbox`` ------------- +************ 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. @@ -569,7 +569,7 @@ The ``checkbox`` can be also integrated as a :doc:`Switch ` .. _lvgl-widget-bar: ``bar`` -------- +******* The bar widget has a background and an indicator foreground on it. The size of the indicator is set according to the current ``value`` of the bar. @@ -765,7 +765,7 @@ The ``bar`` can be also integrated as :doc:`Number ` or .. _lvgl-widget-slider: ``slider`` ----------- +********** The slider widget looks like a bar supplemented with a knob. The user can drag the knob to set a value. Just like bar, slider can be vertical or horizontal. The size of the indicator foreground and the knob position is set according to the current ``value`` of the slider. @@ -838,7 +838,7 @@ See :ref:`lvgl-cookbook-bright` and :ref:`lvgl-cookbook-volume` for examples ill .. _lvgl-widget-arc: ``arc`` -------- +******* The arc consists of a background and a foreground arc. The indicator foreground can be touch-adjusted with a knob. @@ -923,7 +923,7 @@ See :ref:`lvgl-cookbook-bright` and :ref:`lvgl-cookbook-volume` for examples ill .. _lvgl-widget-spinbox: ``spinbox`` ------------ +*********** The spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. @@ -1002,7 +1002,7 @@ See :ref:`lvgl-cookbook-climate` for an example illustrating how to implement a .. _lvgl-widget-meter: ``meter`` ---------- +********* The meter widget can visualize data in very flexible ways. It can use arcs, needles, ticks, lines and/or labels. @@ -1114,7 +1114,7 @@ See :ref:`lvgl-cookbook-gauge`, :ref:`lvgl-cookbook-thermometer` and :ref:`lvgl- .. _lvgl-widget-image: ``image`` ---------- +********* Images are the basic widgets used to display images. @@ -1174,7 +1174,7 @@ Images are the basic widgets used to display images. .. _lvgl-widget-animimg: ``animimg`` ------------ +*********** The animation image is similar to the normal ``image`` 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. @@ -1229,7 +1229,7 @@ See :ref:`lvgl-cookbook-animbatt` in the Cookbook for a more detailed example. .. _lvgl-widget-line: ``line`` --------- +******** The line widget is capable of drawing straight lines between a set of points. @@ -1267,7 +1267,7 @@ By default, the Line widget width and height dimensions are set to ``SIZE_CONTEN .. _lvgl-widget-led: ``led`` -------- +******* The LED widgets are either circular or rectangular widgets whose brightness can be adjusted. As their brightness decreases, the colors become darker. @@ -1319,7 +1319,7 @@ Check out :ref:`lvgl-cookbook-keypad` in the Cookbook for an example illustratin .. _lvgl-widget-spinner: ``spinner`` ------------ +*********** The Spinner widget is a spinning arc over a ring. @@ -1369,7 +1369,7 @@ The Spinner widget is a spinning arc over a ring. .. _lvgl-widget-obj: ``obj`` -------- +******* The base object is just a simple, empty widget. By default, it's nothing more than a rounded rectangle: @@ -1402,7 +1402,7 @@ You can use it as a parent container for other widgets. By default, it catches t .. _lvgl-widget-tabview: ``tabview`` ------------ +*********** The tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-widget-buttonmatrix`. @@ -1478,7 +1478,7 @@ The tabs are indexed (zero-based) in the order they appear in the configuration .. _lvgl-widget-tileview: ``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. @@ -1546,7 +1546,7 @@ If the Tile view is screen sized, the user interface resembles what you may have .. _lvgl-widget-msgbox: ``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. @@ -1600,7 +1600,7 @@ The configured message boxes are hidden by default. One can show them with ``lvg .. _lvgl-widget-keyboard: ``keyboard`` ------------- +************ The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-widget-textarea`. diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index aa311b0518..e7eef43a16 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -1,4 +1,4 @@ -.. _lvgl-num: +.. _lvgl-number: LVGL Number =========== From 0b6063b472f8ee0983fefb75d6a77a2bf60689f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=2E=20=C3=81rkosi=20R=C3=B3bert?= Date: Wed, 7 Aug 2024 00:04:22 +0200 Subject: [PATCH 551/564] Delete lvgl.rst --- components/lvgl.rst | 2449 ------------------------------------------- 1 file changed, 2449 deletions(-) delete mode 100644 components/lvgl.rst diff --git a/components/lvgl.rst b/components/lvgl.rst deleted file mode 100644 index 6330af96f5..0000000000 --- a/components/lvgl.rst +++ /dev/null @@ -1,2449 +0,0 @@ -.. _lvgl-main: - -LVGL Graphics -============= - -.. seo:: - :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 `__. - -.. figure:: /components/images/lvgl_main_screenshot.png - -To use LVGL with a :ref:`display ` in ESPHome, you'll need an ESP32 or supported ESP32 variant. PSRAM is not a strict requirement but it is generally recommended, especially for color displays with resolutions larger than approximately 240x240 pixels. - -The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. - -For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred), a :doc:`/components/sensor/rotary_encoder` or a custom keypad made up from discrete :doc:`Binary Sensors ` can be used. - -Basics ------- - -In LVGL, graphical elements like buttons, labels, sliders, etc. are called widgets or objects. See :ref:`lvgl-widgets` for a complete list of widgets supported within ESPHome. Not all LVGL widgets are implemented, just those commonly used to support home automation needs/tasks. - -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 the label. Complex widgets internally consist of several smaller/simpler widgets; these are known as parts, each of 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. - -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 - :widths: 1 1 - - * - LVGL Widget - - ESPHome component - - * - ``button`` - - :doc:`Switch `, :doc:`Binary Sensor ` - - * - ``switch``, ``checkbox`` - - :doc:`Switch ` - - * - ``slider``, ``arc``, ``spinbox`` - - :doc:`Number `, :doc:`Sensor ` - - * - ``dropdown``, ``roller`` - - :doc:`Select ` - - * - ``label``, ``textarea`` - - :doc:`Text `, :doc:`Text Sensor ` - - * - ``led`` - - :doc:`Light ` - -These are useful with `Home Assistant automations `__ interacting directly with the widgets. - -Main Configuration ------------------- - -Although LVGL is a complex matrix of objects-parts-states-styles, ESPHome simplifies this into a hierarchy. - -At the highest level of the LVGL object hierarchy is the display (represented by 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 to be presented on the display. - -The following configuration variables 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 variables:** - -- **displays** (*Optional*, list, :ref:`config-id`): A list of display IDs where LVGL should perform rendering based on its configuration. This may be omitted if there is a single display configured, which will be used automatically. -- **touchscreens** (*Optional*, list): A list of touchscreens interacting with the LVGL widgets on the display. - - **touchscreen_id** (**Required**, :ref:`config-id`): ID of a touchscreen configuration related to a display. - - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the touchscreen, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. -- **rotary_encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. - - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. - - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: - - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. - - **right_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. - - **long_press_time** (*Optional*, :ref:`Time `): For the rotary encoder, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the rotary encoder, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. -- **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. - - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. See the :ref:`common properties ` of the widgets for more information on groups. - - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``UP`` key. - - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``DOWN`` key. - - **right** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. - - **left** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. - - **esc** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ESC`` key. - - **del** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``DEL`` key. - - **backspace** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``BACKSPACE`` key. - - **enter** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. - - **next** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``NEXT`` key. - - **prev** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``PREV`` key. - - **home** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``HOME`` key. - - **end** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``END`` key. - - **long_press_time** (*Optional*, :ref:`Time `): For the keypad, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. - - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the keypad, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. - - .. tip:: - - When using binary sensors (from physical keys) to interact with LVGL, if there are only three keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With four or more keys, a keypad configuration is generally more appropriate. For example, a keypad consisting of five keys might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``; ``PREV``/``NEXT`` are used to select a widget within the group, ``UP``/``DOWN`` changes the selected value and ``ENTER`` generates an ``on_press`` :ref:`trigger `. - - The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. - -- **color_depth** (*Optional*, string): The color deph at which the contents are generated. Currently only ``16`` is supported (RGB565, 2 bytes/pixel), which is the default value. -- **buffer_size** (*Optional*, percentage): The percentage of screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. -- **log_level** (*Optional*, string): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. -- **byte_order** (*Optional*, int16): The byte order of the data LVGL outputs; either ``big_endian`` or ``little_endian``. Defaults to ``big_endian``. -- **disp_bg_color** (*Optional*, :ref:`color `): Solid color used to fill the background. Can be changed at runtime with the ``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. Also see :ref:`lvgl-wgt-img` for a note regarding supported image formats. -- **default_font** (*Optional*, ID): 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 widget's ``styles`` configuration. See :ref:`below ` for more details. -- **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. -- **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. May not be used if ``pages`` (below) is configured. -- **pages** (*Optional*, list): A list of page IDs. Each page acts as a parent for widgets placed on it. May not be used with ``widgets`` (above). Options for each page: - - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. - - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. - - All other options from :ref:`lvgl-styling` to be applied to this page. -- **page_wrap** (*Optional*, boolean): Wrap from the last to the first page when navigating between them with :ref:`lvgl-pgnx-act`. Defaults to ``true``. -- **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, which may be useful for widgets which always need to be visible. - - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. - - All other options from :ref:`lvgl-styling` to be applied to this page. -- **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. -- All other options from :ref:`lvgl-styling` to be applied to all widgets directly. - - - -**Example:** - -.. code-block:: yaml - - # Example configuration entry - lvgl: - displays: - - my_display - touchscreens: - - my_touch - pages: - - id: main_page - widgets: - - label: - align: CENTER - text: 'Hello World!' - -.. _lvgl-color: - -Colors -****** - -Colors can be specified anywhere in the LVGL configuration either by referencing a preconfigured :ref:`ESPHome color ` ID or by representing the color in the common hexadecimal notation. For example, ``0xFF0000`` would be red. - -.. _lvgl-opa: - -Opacity -******* - -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: - -Fonts -***** - -Two font choices are available: - -**ESPHome fonts** - -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. - -.. tip:: - - For best results, set ``bpp: 4`` to get the glyphs rendered with proper anti-aliasing. - -**Library fonts** - -The LVGL library offers by default prerendered sets with ASCII characters (``0x20-0x7F``), the degree symbol (``0xB0``), the bullet symbol (``0x2022``) from `Montserrat Medium `__, and 60 symbols from `FontAwesome `__ (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**, included if ``default_font`` option is missing) -- ``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 - -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 preceded by ``\u``. For example: ``\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, 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. - -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. - -.. _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 box defined with ``width`` and ``height`` of the widgets (pixels or parent content area percentage; not drawn, just for calculations). -- *border*: the border line, drawn on the inner side of the bounding box (pixels). -- *outline*: the outline, drawn on the outer side of the bounding box (pixels). -- *padding*: space to keep between the border of the widget and its content or children (*I don't want my children too close to my sides, so keep this space*). -- *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). - -You can adjust the appearance of widgets by changing their foreground, background, border color and/or font. Some widgets allow for more complex styling, effectively changing all or part of their appearance. - -**Styling variables:** - -- **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*, dict): Set dithering of the background gradient. One of ``NONE``, ``ORDERED``, ``ERR_DIFF``. Defaults to ``NONE``. -- **bg_grad_dir** (*Optional*, dict): 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`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``0``. -- **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``255``. -- **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. Inherited from parent. Defaults to ``COVER``. -- **bg_image_src** (*Optional*, :ref:`image `): The ID of an existing image configuration, to show as the background of the widget. -- **bg_image_opa** (*Optional*, :ref:`opacity `): Opacity of the background image of the widget. -- **bg_image_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the background image of the widget. -- **bg_image_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring of the background image of the widget. -- **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 as a YAML list, defaults to ``NONE``): - - ``NONE`` - - ``TOP`` - - ``BOTTOM`` - - ``LEFT`` - - ``RIGHT`` - - ``INTERNAL`` -- **radius** (*Optional*, uint16): The radius to be used to form the widget's rounded corners. 0 = no radius (square corners); 65535 = pill shaped widget (true circle if it has same width and height). -- **clip_corner** (*Optional*, boolean): If set to ``true``, overflowing content will be clipped off by the widget's rounded corners (``radius`` > ``0``). -- **outline_width** (*Optional*, int16): Set the width of the outline in pixels. Defaults to ``0``. -- **outline_color** (*Optional*, :ref:`color `): Color used 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. -- **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 `): Color used to create a drop shadow under the widget. Defaults to ``0`` (black). -- **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): 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): Horizontal anchor point of the transformation. Relative to the widget's top left corner. -- **transform_pivot_y** (*Optional*, int16): Vertical anchor point of the transformation. Relative to the widget's top left corner. -- **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. - -.. _lvgl-theme: - -Themes -****** - -The widgets support lots of :ref:`lvgl-styling` to customize their appearance and behavior. - -You can configure a global theme for all widgets at the top level with the ``theme`` configuration variable. In the example below, all the ``arc``, ``slider`` and ``button`` widgets will, by default, use the styles and properties defined here. A combination of styles and :ref:`states ` can be chosen for every widget. - -.. code-block:: yaml - - lvgl: - theme: - arc: - scroll_on_focus: true - group: general - slider: - scroll_on_focus: true - group: general - button: - 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 individual configuration level of each widget. This can be done in batches, using the ``style_definitions`` configuration variable of the main component. -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 style ``y`` locally: - -.. code-block:: yaml - - widgets: - - label: - id: day_label - styles: date_style # apply the definition 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 :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: - -.. 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 precedence 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 value precedence of states is quite intuitive and it's something the user would expect naturally. For example, 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 override the *pressed* color, defeating its purpose.) - -Feel free to experiment to discover inheritance and precedence of the styles based on states between the nested widgets. - -.. _lvgl-layouts: - -Layouts -******* - -Layouts aim to position widgets automatically, eliminating the need to specify ``x`` and ``y`` coordinates to position each widget. This is a great way to simplify your configuration as it allows you to omit alignment options. - -The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. The position and size calculated by the layout overwrites the *normal* ``x``, ``y``, ``width``, and ``height`` settings of the children. - -The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` can be used on widgets to ignore them in layout calculations. - -**Configuration variables:** - -- **layout** (*Optional*, dict): A dictionary describing the layout configuration: - - **type** (*Optional*, string): ``FLEX``, ``GRID`` or ``NONE``. Defaults to ``NONE``. - - Further options from below depending on the chosen type. - -**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 spacing between items and tracks and even handle growing the layout to make the item(s) fill the remaining space with respect to minimum/maximum width and height. - -**Terms used:** - -- *track*: the rows or columns *main* direction flow: row or column in the direction in which the items are placed one after the other. -- *cross direction*: perpendicular to the main direction. -- *wrap*: if there is no more space in the track a new track is started. -- *gap*: the space between the rows and columns or the items on a track. -- *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). It dictates what amount of the available space the widget should take up. For example if all items on the track have a ``grow`` set to ``1``, the space in the track will be distributed equally to all of them. If one of the items has a value of 2, that one would take up twice as much of the space as either one of the others. - -**Configuration variables:** - - - **flex_flow** (*Optional*, string): 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. - - - **flex_align_main** (*Optional*, string): Determines how to distribute the items in their track on the *main* axis. For example, flush the items to the right on with ``flex_flow: ROW_WRAP`` (known as *justify-content* in CSS). Possible options below. - - **flex_align_cross** (*Optional*, string): Determines how to distribute the items in their track on the *cross* axis. For example, if the items have different height place them to the bottom of the track (known as *align-items* in CSS). Possible options below. - - **flex_align_track** (*Optional*, string): Determines how to distribute the tracks (known as *align-content* in CSS). Possible options below. - - Values for use with ``flex_align_main``, ``flex_align_cross``, ``flex_align_track``: - - - ``START``: means left horizontally and top vertically (default). - - ``END``: means right horizontally and bottom vertically. - - ``CENTER``: simply center. - - ``SPACE_EVENLY``: items are distributed so that the spacing between any two items (and the space to the edges) is equal. Does not apply to ``flex_align_track``. - - ``SPACE_AROUND``: items are evenly distributed in the track with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. Does not apply to ``flex_align_track``. - - ``SPACE_BETWEEN``: items are evenly distributed in the track: first item is on the start line, last item on the end line. Does not apply to ``flex_align_track``. - - - **pad_row** (*Optional*, int16): Set the padding between the rows, in pixels. - - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. - - **flex_grow** (*Optional*, int16): Flex grow can be used to make one or more children fill the available space on the track. When more children have grow parameters, the available space will be distributed proportionally to the grow values. Defaults to ``0``, which disables growing. - -**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(s) can span through multiple columns or rows. The track's size can be set in pixels, to the largest item of the track (``CONTENT``) or in "free units" to distribute the free space proportionally. - -**Terms used:** - -- *tracks*: the rows or the columns. -- *gap*: the space between the rows and columns or the items on a track. -- *free unit (FR)*: a proportional distribution unit for the space available on the track. It accepts a unitless integer value that serves as a proportion. It dictates what amount of the available space the widget should take up. For example if all items on the track have a ``FR`` set to ``1``, the space in the track will be distributed equally to all of them. If one of the items has a value of 2, that one would take up twice as much of the space as either one of the others. - -**Configuration variables:** - - - **grid_rows** (**Required**): The number of rows in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional integer value). - - **grid_columns** (**Required**): The number of columns in the grid, expressed a list of values in pixels, ``CONTENT`` or ``FR(n)`` (free units, where ``n`` is a proportional integer value). - - **grid_row_align** (*Optional*, string): How to align the row. Works only when ``grid_rows`` is given in pixels. Possible options below. - - **grid_column_align** (*Optional*, string): How to align the column. Works only when ``grid_columns`` is given in pixels. Possible options below. - - **pad_row** (*Optional*, int16): Set the padding between the rows, in pixels. - - **pad_column** (*Optional*, int16): Set the padding between the columns, in pixels. - -In a grid layout, *all the widgets placed on the grid* will get some additional configuration variables to help with placement: - - - **grid_cell_row_pos** (**Required**, int16): Position of the widget, in which row to appear (0 based count). - - **grid_cell_column_pos** (**Required**, int16): Position of the widget, in which column to appear (0 based count). - - **grid_cell_x_align** (*Optional*, string): How to align the widget horizontally within the cell. Can also be applied through :ref:`lvgl-styling`. Possible options below. - - **grid_cell_y_align** (*Optional*, string): How to align the widget vertically within the cell. Can also be applied through :ref:`lvgl-styling`. Possible options below. - - **grid_cell_row_span** (*Optional*, int16): How many rows to span across the widget. Defaults to ``1``. - - **grid_cell_column_span** (*Optional*, int16): How many columns to span across the widget. . Defaults to ``1``. - - .. note:: - - These ``grid_cell_`` variables apply to widget configuations! - -Values for use with ``grid_column_align``, ``grid_row_align``, ``grid_cell_x_align``, ``grid_cell_y_align``: - - - ``START``: means left horizontally and top vertically (default). - - ``END``: means right horizontally and bottom vertically. - - ``CENTER``: simply center. - - ``STRETCH``: stretch the widget to the cell in the respective direction. Does not apply to ``grid_column_align``, ``grid_row_align``. - - ``SPACE_EVENLY``: items are distributed so that the spacing between any two items (and the space to the edges) is equal. - - ``SPACE_AROUND``: items are evenly distributed in the track with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies. - - ``SPACE_BETWEEN``: items are evenly distributed in the track: first item is on the start line, last item on the end line. - -.. tip:: - - To visualize real, calculated sizes of transparent widgets you can temporarily set ``outline_width: 1`` on them. - -.. _lvgl-widgets: - -Widgets -------- - -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 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, its children will also be hidden. - -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 those related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the parent will be searched for an object which specifies a value for the property. The parents will use their own :ref:`state ` to determine the value. For example, if a button is pressed and the text color is defined by the "pressed" state, this "pressed" text color will be used. - -Common properties -***************** - -The properties below are common to all widgets. - -**Configuration variables:** - -- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **x** (*Optional*, int16 or percentage): Horizontal position of the widget. -- **y** (*Optional*, int16 or percentage): Vertical position of the widget. - -.. note:: - - 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. - - If specifying ``align``, ``x`` and ``y`` can be used as an offset to the calculated position (can also be negative). They are ignored if :ref:`lvgl-layouts` are used on the parent. - -- **width** (*Optional*): Width of the widget in pixels or a percentage, or ``SIZE_CONTENT``. -- **height** (*Optional*): Height of the widget in pixels or a percentage, or ``SIZE_CONTENT``. - -.. note:: - - 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 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 dimensions 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. 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). - -- **align** (*Optional*, dict): 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**, string): 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): 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*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. -- **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*, dict): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from the theme, but can be locally set or overridden within style definitions. 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 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. - -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 - - - button: - 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 through :ref:`actions ` with ``lvgl.widget.update``. - -.. _lvgl-objupdflag-act: - -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``. Hidden objects are ignored in layout calculations. 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`` (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 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``). -- **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. -- **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent. -- **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. For example, may help by accounting for rounded corners. -- **ignore_layout** (*Optional*, boolean): the widget is simply ignored by the layouts. Its coordinates can be set as usual. -- **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. - -.. note:: - - LVGL only supports **integers** for numeric ``value``. Visualizer widgets can't display floats directly, but they allow scaling by 10s. - -.. _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 - -**Configuration variables:** - -- **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display. To display an empty label, specify ``""``. -- **text_align** (*Optional*, dict): 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 as YAML list). 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_opa** (*Optional*, :ref:`opacity `): Opacity of the text. Inherited from parent. Defaults to ``COVER``. -- **recolor** (*Optional*, boolean): Enable recoloring of button text with ``#``. This makes it possible to set the color of characters in the text individually by prefixing the text to be re-colored with a ``#RRGGBB`` hexadecimal color code followed by a *space*, and finally closed 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 set by :ref:`lvgl-layouts`), 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 lines which are too long. 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 the text horizontally back and forth. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. - - ``SCROLL_CIRCULAR``: If the text is wider than the label, continuously scroll the text horizontally. If it's higher, scroll vertically. Text will scroll in only one direction; 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 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. - -.. 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*. - -**Actions:** - -- ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of label widgets which you want update. - - **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. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- :ref:`interaction ` LVGL event triggers. - -**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()' ] - -The ``label`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. - -.. _lvgl-wgt-txt: - -``textarea`` -************ - -The textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. - -.. figure:: /components/images/lvgl_textarea.png - :align: center - -**Configuration variables:** - -- **placeholder_text** (*Optional*, string): A placeholder text can be specified, which is displayed when the Text area is empty. -- **accepted_chars** (*Optional*, string): You can set a list of accepted characters, so other characters will be ignored. -- **one_line** (*Optional*, boolean): The text area can be limited to only allow a single line of text. In this case the height will set automatically to fit only one line, line break characters will be ignored, and word wrap will be disabled. -- **password_mode** (*Optional*, boolean): The text area supports password mode. By default, if the ``•`` (bullet, ``0x2022``) glyph exists in the font, the entered characters are converted to it after some time or when a new character is entered. If ``•`` is missing from the font, ``*`` (asterisk) will be used. -- **max_length** (*Optional*, int): Limit the maximum number of characters to this value. -- any :ref:`Styling ` and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. - -**Actions:** - -- ``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. - - **id** (**Required**): The ID or a list of IDs of textarea widgets which you want update. - - **text** (**Required**): The new text content to be displayed. - -**Triggers:** - -- ``on_value`` :ref:`trigger ` is activated on every keystroke. -- ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). -- :ref:`interaction ` LVGL event triggers. - -For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - textarea: - id: textarea_id - one_line: true - placeholder_text: "Enter text here" - - # Example action: - on_...: - then: - - lvgl.textarea.update: - id: textarea_id - text: "Hello World!" - - # Example trigger: - - textarea: - ... - on_value: - then: - - logger.log: - format: "Textarea changed to: %s" - args: [ text.c_str() ] - on_ready: - then: - - logger.log: - format: "Textarea ready: %s" - args: [ text.c_str() ] - -The ``textarea`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. - -.. _lvgl-wgt-btn: - -``button`` -********** - -Simple push (momentary) or toggle (two-states) button. - -.. figure:: /components/images/lvgl_button.png - :align: center - -**Configuration variables:** - -- **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. - -A notable state is ``checked`` (boolean) which can have different styles applied. - -**Triggers:** - -- ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - button: - x: 10 - y: 10 - width: 50 - height: 30 - id: btn_id - -To have a button with a text label on it, add a child :ref:`lvgl-wgt-lbl` widget to it: - -.. code-block:: yaml - - # Example toggle button with text: - - button: - x: 10 - y: 10 - width: 70 - height: 30 - id: btn_id - checkable: true - widgets: - - label: - align: center - text: "Light" - - # Example trigger: - - button: - ... - on_value: - then: - - logger.log: - format: "Button checked state: %d" - args: [ x ] - -The ``button`` can be also integrated as a :doc:`Binary Sensor ` or as a :doc:`Switch ` component. - -.. _lvgl-wgt-bmx: - -``buttonmatrix`` -**************** - -The button matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. - -.. figure:: /components/images/lvgl_buttonmatrix.png - :align: center - -**Configuration variables:** - -- **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 ` 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. Must be a value between ``1`` and ``15``; the default is ``1`` (for example, given a line with two buttons, one with ``width: 1`` and another one with ``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): 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): 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. 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 text with ``#``. For example: ``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. - -**Actions:** - -- ``lvgl.buttonmatrix.update`` :ref:`action ` updates the item styles and properties specified in the specific ``state``, ``items`` options. - - **id** (**Required**): The ID or a list of IDs of buttonmatrix widgets which you want update. - - Widget styles or properties from ``state``, ``items`` options above, which you want update. - -- ``lvgl.matrixbutton.update`` :ref:`action ` updates the button styles and properties specified in the specific ``control``, ``width`` and ``selected`` options. - - **id** (**Required**): The ID or a list of IDs of matrix buttons which you want update. - - Widget styles or properties from ``control``, ``width`` and ``selected`` options above, which you want update. - -**Triggers:** - -- ``on_value`` and :ref:`interaction ` triggers can be configured for each button, is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. -- The :ref:`interaction ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). - -**Example:** - -.. code-block:: yaml - - # Example widget: - - buttonmatrix: - x: 10 - y: 40 - width: 220 - items: - pressed: - bg_color: 0xFFFF00 - id: matrix_id - rows: - - buttons: - - id: button_1 - text: "\uF04B" - control: - checkable: true - - id: button_2 - text: "\uF04C" - 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 - - # Example action: - on_...: - then: - - lvgl.matrixbutton.update: - id: button_1 - width: 1 - selected: true - control: - checkable: false - - lvgl.buttonmatrix.update: - id: matrix_id - state: - disabled: true - items: - bg_color: 0xf0f0f0 - - # Example trigger: - - buttonmatrix: - ... - rows: - - buttons: - ... - - id: button_2 - ... - control: - checkable: true - on_value: # Trigger for the individual button, returning the checked state - then: - - logger.log: - format: "Button 2 checked: %d" - args: [ x ] - on_press: # Triggers for the matrix, to determine which button was pressed. - logger.log: - format: "Matrix button pressed: %d" - args: ["x"] # If x is 65535, it was the container, (or through a disabled button). - on_click: - logger.log: - format: "Matrix button clicked: %d, is button_2 = %u" - args: ["x", "id(button_2) == x"] - -.. tip:: - - The Button Matrix widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. - -.. _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 - -**Configuration variables:** - -- **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*, the foreground area underneath the knob shown when the switch is in ``checked`` state. Supports a list of :ref:`styles ` and state-based styles to customize. -- Style options from :ref:`lvgl-styling`. - -**Triggers:** - -- ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - switch: - x: 10 - y: 10 - id: switch_id - - # Example trigger: - - switch: - ... - on_value: - then: - - logger.log: - format: "Switch state: %d" - args: [ x ] - -The ``switch`` can be also integrated as a :doc:`Switch ` component. - -.. _lvgl-wgt-chk: - -``checkbox`` -************ - -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 - -**Configuration variables:** - -- **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 tick box and the label. - -**Actions:** - -- ``lvgl.checkbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of checkbox widgets which you want update. - - **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. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -``on_value`` :ref:`trigger ` is activated when toggling the checkbox. The boolean variable ``x``, representing the checkbox's state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - checkbox: - x: 10 - y: 10 - id: checkbox_id - text: Checkbox - - # Example action: - on_...: - then: - - lvgl.checkbox.update: - id: checkbox_id - state: - checked: true - text: Checked - - # Example trigger: - - checkbox: - ... - on_value: - then: - - logger.log: - format: "Checkbox state: %d" - args: [ x ] - -.. note:: - - In case you configure ``default_font`` in the main section to a custom font, the checkmark will not be shown correctly when the checkbox is in the checked state. - -The ``checkbox`` can be also integrated as a :doc:`Switch ` component. - -.. _lvgl-wgt-drp: - -``dropdown`` -************ - -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. 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 - -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). - -**Configuration variables:** - -- **options** (**Required**, list): The list of available options in the drop-down. -- **dir** (*Optional*, dict): 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*, dict): 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 those built-in or from your own customized font. -- **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`` can be used to set the font of the button part, including the symbol. - -**Actions:** - -- ``lvgl.dropdown.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of dropdown widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`interaction ` LVGL event triggers also apply, and they also return the selected index in ``x``. -- ``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - dropdown: - id: dropdown_id - width: 90 - align: CENTER - options: - - Violin - - Piano - - Bassoon - - Chello - - Drums - selected_index: 2 - - # Example action: - on_...: - then: - - lvgl.dropdown.update: - id: dropdown_id - selected_index: 4 - - # Example trigger: - - dropdown: - ... - on_value: - - logger.log: - format: "Selected index is: %d" - args: [ x ] - on_cancel: - - logger.log: - format: "Dropdown closed. Selected index is: %d" - args: [ x ] - -The ``dropdown`` can be also integrated as :doc:`Select ` component. - -.. _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 - -**Configuration variables:** - -- **options** (**Required**, list): The list of available options in the roller. -- **mode** (*Optional*, dict): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. -- **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 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. - -**Actions:** - -- ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of roller widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the selected index in ``x``. - -**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: 4 - - # Example trigger: - - roller: - ... - on_value: - - logger.log: - format: "Selected index is: %d" - args: [ x ] - -The ``roller`` can be also integrated as :doc:`Select ` component. - -.. _lvgl-wgt-bar: - -``bar`` -******* - -The bar widget has a background and an indicator foreground 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 - -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. - -**Configuration variables:** - -- **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): Animate the indicator when the 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. - -**Actions:** - -- ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of bar widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- :ref:`interaction ` LVGL event triggers. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - bar: - x: 10 - y: 100 - id: bar_id - value: 75 - 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:`Number ` or :doc:`Sensor ` component. - -.. _lvgl-wgt-sli: - -``slider`` -********** - -The slider widget looks like a bar supplemented with a knob. The user can drag the knob to set a value. Just like bar, slider can be vertical or horizontal. The size of the indicator foreground and the knob position is set according to the current ``value`` of the slider. - -.. figure:: /components/images/lvgl_slider.png - :align: center - -**Configuration variables:** - -- **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) is 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. -- **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 shows the current state of the slider. Also uses all the typical background style properties. -- **animated** (*Optional*, boolean): Animate the indicator when the 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. - -**Actions:** - -- ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of slider widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. The new value is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which 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 as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. - -The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. - -.. _lvgl-wgt-arc: - -``arc`` -******* - -The arc consists of a background and a foreground arc. The indicator foreground can be touch-adjusted with a knob. - -.. figure:: /components/images/lvgl_arc.png - :align: center - -**Configuration variables:** - -- **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``. -- **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. -- **rotation** (*Optional*, 0-360): 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*, :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. -- **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`` :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:: - - The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. - -**Actions:** - -- ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of arc widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**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``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - 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 as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. - -The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. - -.. _lvgl-wgt-spb: - -``spinbox`` -*********** - -The spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. - -.. figure:: /components/images/lvgl_spinbox.png - :align: center - -**Configuration variables:** - -- **value** (**Required**, float): Actual value to be shown by the spinbox at start. -- **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``. -- **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 character will only be shown if the set range contains negatives. - -**Actions:** - -- ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -- ``lvgl.spinbox.increment`` :ref:`action ` increases the value by one ``step`` configured above. - - **id** (**Required**): The ID of the spinbox widget which you want to increment. - -- ``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. - - **id** (**Required**): The ID of the spinbox widget which you want to decrement. - -**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``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - spinbox: - 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:`Number ` or :doc:`Sensor ` component. - -.. _lvgl-wgt-mtr: - -``meter`` -********* - -The meter widget can visualize data in very flexible ways. It can use arcs, needles, ticks, lines and/or labels. - -.. figure:: /components/images/lvgl_meter.png - :align: center - -**Configuration variables:** - -- **scales** (**Required**, list): A list with (any number of) scales to be added to the meter. - - **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. 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*, :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**: :ref:`Color ` to draw the major ticks. Defaults to ``0`` (black). - - **label_gap**: Label distance from the ticks with text proportional 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: - - **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**: :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**: :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**: :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. - - **image** (*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, representing a needle pointing to the right like ``-o--->``. - - **pivot_x**: Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. - - **pivot_y**: Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. - - **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:: - - The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. - -**Actions:** - -- ``lvgl.indicator.update`` :ref:`action ` updates indicator options except ``src``, which cannot be updated at runtime. :ref:`lvgl.widget.update ` action can be used for the common styles, states or flags of the meter widget (not the indicators). - - **id** (**Required**): The ID or a list of IDs of line or image indicators which you want update. - -**Triggers:** - -- :ref:`interaction ` LVGL event triggers. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - meter: - align: center - scales: - 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 - color: 0xFF0000 - r_mod: -4 - - tick_style: - start_value: -10 - end_value: 40 - color_start: 0x0000bd #FF0000 - color_end: 0xbd0000 #0000FF - - # Example action: - on_...: - then: - - lvgl.indicator.update: - id: temperature_needle - value: 3 - -.. _lvgl-wgt-img: - -``image`` -********* - -Images are the basic widgets used to display images. - -.. figure:: /components/images/lvgl_image.png - :align: center - -**Configuration variables:** - -- **src** (**Required**, :ref:`image `): The ID of an existing image configuration. -- **offset_x** (*Optional*): Add a horrizontal offset to the image position. -- **offset_y** (*Optional*): Add a vertical offset to the image position. -- **scale** (*Optional*, 0.1-10): Zoom of the image. -- **angle** (*Optional*, 0-360): Rotation of the image. Defaults to ``0.0``. Needs ``pivot_x`` and ``pivot_y`` to be specified. -- **pivot_x** (*Optional*): Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. -- **pivot_y** (*Optional*): Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. -- **antialias** (*Optional*): The quality of the angle or scale transformation. When anti-aliasing is enabled, the transformations are higher quality but slower. Defaults to ``false``. -- **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is scaled or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``SIZE_CONTENT``, the object's size will be set to the scaled and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. -- 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. - -**Actions:** - -- ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. - - **id** (**Required**): The ID or a list of IDs of image widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- :ref:`interaction ` LVGL event triggers. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - image: - align: CENTER - src: cat_image - id: img_id - radius: 11 - clip_corner: true - - # Example action: - on_...: - then: - - lvgl.image.update: - id: img_id - src: cat_image_bowtie - -.. note:: - - 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. - -.. tip:: - - ``offset_x`` and ``offset_y`` can be useful when the widget size is set to be smaller than the image source size. A "running image" effect can be created by animating these values. - -.. _lvgl-wgt-aim: - -``animimg`` -*********** - -The animation image is similar to the normal ``image`` 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 - -**Configuration variables:** - -- **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 (each frame is displayed for an equal amount of time). -- **repeat_count** (*Optional*, int16 or *forever*): The number of times playback should be repeated. 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. - -**Actions:** - -- ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. - - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want start. - -- ``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. - - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want stop. - -- ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. - - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- :ref:`interaction ` LVGL event triggers. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - animimg: - align: CENTER - id: anim_id - src: [ cat_image, cat_image_bowtie ] - duration: 1000ms - - # Example actions: - on_...: - then: - - lvgl.animimg.update: - id: anim_id - repeat_count: 100 - duration: 300ms - -.. _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 - -**Configuration variables:** - -- **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 `): 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. - -**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 either circular or rectangular widgets whose brightness can be adjusted. As their brightness decreases, the colors become darker. - -.. figure:: /components/images/lvgl_led.png - :align: center - -**Configuration variables:** - -- **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. - -**Actions:** - -- ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of led widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- :ref:`interaction ` LVGL event triggers. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - led: - id: led_id - align: CENTER - color: 0xFF0000 - brightness: 70% - - # Example action: - on_...: - then: - - lvgl.led.update: - id: led_id - color: 0x00FF00 - -The ``led`` can be also integrated as :doc:`Light ` component. - -.. note:: - - If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. - -.. _lvgl-wgt-spi: - -``spinner`` -*********** - -The Spinner widget is a spinning arc over a ring. - -.. figure:: /components/images/lvgl_spinner.gif - :align: center - -**Configuration variables:** - -- **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*, :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. -- **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. - -**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 widgets), just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of spinner widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- :ref:`interaction ` LVGL event triggers. - -**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 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 container for other widgets. By default, it catches touches. - -**Configuration variables:** - -- Style options from :ref:`lvgl-styling`. - -**Triggers:** - -- :ref:`interaction ` LVGL event triggers. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - obj: - x: 10 - y: 10 - width: 220 - height: 300 - widgets: - - ... - -.. _lvgl-wgt-tab: - -``tabview`` -*********** - -The tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-wgt-bmx`. - -.. figure:: /components/images/lvgl_tabview.png - :align: center - -The tabs are indexed (zero-based) in the order they appear in the configuration file. A new tab can be selected either by clicking on a tab button, by sliding horizontally on the content or via the ``lvgl.tabview.select`` :ref:`action `, specifying the tab's index. - -**Configuration variables:** - -- **position** (*Optional*, string): Position of the tab selector buttons. One of ``TOP``, ``BOTTOM``, ``LEFT``, ``RIGHT``. Defaults to ``TOP``. -- **size** (*Optional*, percentage): The height (in case of ``TOP``, ``BOTTOM``) or width (in case of ``LEFT``, ``RIGHT``) tab buttons. Defaults to ``10%``. -- **tabs** (**Required**, list): A list with (any number of) tabs to be added to tabview. - - **name** (**Required**): The text to be shown on the button corresponding to the tab. - - **id** (*Optional*): An ID for the tab itself. - - **widgets** (**Required**, list): A list of :ref:`lvgl-widgets` to be drawn on the tab, as children. -- **tab_style** (*Optional*): Style settings for the tabs. - - **items** (*Optional*, list): Settings for the items *part*, the buttons all use the text and typical background style properties except translations and transformations. - -**Actions:** - -- ``lvgl.tabview.select`` :ref:`action ` jumps the view to the desired tab: - - **id** (**Required**): The ID of the tabview which receives this action. - - **index** (**Required**): The (zero-based) index of the tab to which to jump. - - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. - -**Triggers:** - -- ``on_value`` :ref:`trigger ` is activated when displayed tab changes. The new value is returned in the variable ``tab`` as the ID of the now-visible tab. -- :ref:`interaction ` LVGL event triggers. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - tabview: - id: tabview_id - position: top - tab_style: - border_color: 0x00FF00 - border_width: 6 - items: - text_color: 0x0000FF - tabs: - - name: Dog - id: tabview_tab_1 - widgets: - - image: - src: dog_img - ... - ... - - # Example action: - on_...: - then: - - lvgl.tabview.select: - id: tabview_id - index: 1 - animated: true - - # Example trigger: - - tabview: - ... - on_value: - then: - - if: - condition: - lambda: return tab == id(tabview_tab_1); - then: - - logger.log: "Dog tab is now showing" - -.. _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. - -If the Tile view is screen sized, the user interface resembles what you may have seen on smartwatches. - -**Configuration variables:** - -- **tiles** (**Required**, list): A list with (any number of) tiles to be added to tileview. - - **id** (*Optional*): A tile ID to be used with the ``lvgl.tileview.select`` action. - - **row** (**Required**): Horizontal position of the tile in the tileview grid. - - **column** (**Required**): Vertical position of the tile in the tileview grid. - - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. - - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the tile, as children. - -**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 the tileview) to which to jump. Required if not specifying ``row`` and ``column``. - - **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``. - -**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 now-visible tile. -- :ref:`interaction ` LVGL event triggers. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - tileview: - id: tiv_id - tiles: - - id: cat_tile - row: 0 - column: 0 - dir: VER - widgets: - - image: - src: cat_image - - ... - - ... - - # Example action: - on_...: - then: - - lvgl.tileview.select: - id: tiv_id - tile_id: cat_tile - animated: true - - # Example trigger: - - tileview: - ... - on_value: - - if: - condition: - lambda: return tile == id(cat_tile); - then: - - logger.log: "Cat tile is now showing" - -.. _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). - -**Configuration variables:** - -- **msgboxes** (*Optional*, dict): 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 message box. - - **body** (**Required**, dict): The content of the 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**, dict): A list of buttons to show at the bottom of the message box: - - **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display on the button. - -**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: Message box - body: - text: "This is a sample message box." - bg_color: 0x808080 - buttons: - - id: msgbox_apply - text: "Apply" - - id: msgbox_close - text: "\uF00D" - on_click: - then: - - lvgl.widget.hide: message_box - -.. 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. - -.. _lvgl-wgt-kbd: - -``keyboard`` -************ - -The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-wgt-txt`. - -.. figure:: /components/images/lvgl_keyboard.png - :align: center - -For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-wgt-bmx`. - -**Configuration variables:** - -- **textarea** (*Optional*): The ID of the ``textarea`` from which to receive the keystrokes. -- **mode** (*Optional*, dict): Keyboard layout to use. Each ``TEXT_`` layout contains a button to allow the user to iterate through the ``TEXT_`` layouts. - - ``TEXT_LOWER``: Display lower case letters (default). - - ``TEXT_UPPER``: Display upper case letters. - - ``TEXT_SPECIAL``: Display special characters. - - ``NUMBER``: Display numbers, +/- sign, and decimal dot. - -**Actions:** - -- ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of keyboard widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- ``on_ready`` :ref:`trigger ` is activated when the checkmark key is pressed. -- ``on_cancel`` :ref:`trigger ` is activated when the key containing the keyboard icon is pressed. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - keyboard: - id: keyboard_id - textarea: textarea_1 - mode: TEXT_UPPER - - # Example actions: - on_focus: - then: - - lvgl.keyboard.update: - id: keyboard_id - mode: number - textarea: textarea_2 - - # Example trigger: - - keyboard: - ... - on_ready: - then: - - logger.log: Keyboard is ready - on_cancel: - then: - - logger.log: Keyboard cancelled - -.. tip:: - - The Keyboard widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. - -.. note:: - - The Keyboard widget in ESPHome doesn't support popovers or custom layouts. - -Actions -------- - -As outlined in the sections above, each widget type supports several of its own, unique actions. -Several universal actions are also available for all widgets and/or for LVGL itself; these are outlined below. - -.. _lvgl-objupd-act: - -``lvgl.widget.update`` -********************** - -This powerful :ref:`action ` allows changing/updating any widget's common :ref:`style property `, state (templatable) or :ref:`flag ` on the fly. - -- **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want update. -- The widget's common :ref:`style property `, state (templatable) or :ref:`flag `. - -.. code-block:: yaml - - # Example for updating styles (in states): - on_...: - then: - - lvgl.widget.update: - id: my_button_id - bg_color: 0xFF0000 - state: - disabled: true - - # Example for updating flag: - on_...: - then: - - lvgl.widget.update: - id: my_label_id - hidden: true - -.. _lvgl-objupd-shorthands: - -``lvgl.widget.hide``, ``lvgl.widget.show`` -****************************************** - -These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget. - -- **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want to hide or show. - -.. code-block:: yaml - - on_...: - then: - - lvgl.widget.hide: my_label_id # a single widget - - lvgl.widget.show: [my_button_1, my_button_2] # a list of widgets - - delay: 0.5s - - lvgl.widget.show: - -id: my_label_id - - lvgl.widget.hide: - - id: [my_button_1, my_button_2] - -``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): - -- **id** (**Required**): The ID or a list of IDs of widgets configured in LVGL which you want to disable or enable. - -.. code-block:: yaml - - - on_...: - then: - - lvgl.widget.disable: - - my_button_1 - - my_button_2 - - - on_...: - then: - - lvgl.widget.enable: - - id: my_button_1 - - id: my_button_2 - -.. _lvgl-rfrsh-act: - -``lvgl.widget.redraw`` -********************** - -This :ref:`action ` redraws the entire screen, or optionally only a widget on it. - -- **id** (*Optional*): The ID of a widget configured in LVGL which you want to redraw; if omitted, the entire screen will be redrawn. - -.. code-block:: yaml - - on_...: - then: - - lvgl.widget.redraw: - -.. _lvgl-pause-act: - -``lvgl.pause`` -************** - -This :ref:`action ` pauses the activity of LVGL, including rendering. - -- **show_snow** (*Optional*, boolean): When 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. - -.. code-block:: yaml - - on_...: - then: - - lvgl.pause: - show_snow: true - -.. _lvgl-resume-act: - -``lvgl.resume`` -*************** - -This :ref:`action ` resumes the activity of LVGL, including rendering. - -.. code-block:: yaml - - on_...: - then: - - lvgl.resume: - -``lvgl.update`` -*************** - -This :ref:`action ` allows changing/updating the ``disp_bg_color`` or ``disp_bg_image`` configuration variables of the main component, making it possible to 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`` -****************************************** - -This :ref:`action ` changes the page to the next/previous based on the configuration (pages with their ``skip`` option enabled are...skipped). Page changes will wrap around at the end. - -- **animation** (*Optional*): Animate page changes as specified. One of: ``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``. -- **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`` -****************** - -This :ref:`action ` shows a specific page (including pages with their ``skip`` option enabled). - -- **id** (**Required**): The ID of the page to be shown. -- **animation** (*Optional*): Animate page changes as specified. One of: ``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``. -- **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 - -.. _lvgl-cond: - -Conditions ----------- - -.. _lvgl-idle-cond: - -``lvgl.is_idle`` -**************** - -This :ref:`condition ` checks if the amount of time specified has passed since the last touch event. - -- **timeout** (**Required**, :ref:`templatable `, int): Amount of :ref:`time ` expected since the last touch event. - -.. code-block:: yaml - - # In some trigger: - on_...: - then: - - if: - condition: lvgl.is_idle - timeout: 5s - then: - - light.turn_off: - id: display_backlight - transition_length: 3s - -.. _lvgl-paused-cond: - -``lvgl.is_paused`` -****************** - -This :ref:`condition ` checks if LVGL is in the paused state or not. - -.. code-block:: yaml - - # In some trigger: - on_...: - then: - - if: - condition: lvgl.is_paused - then: - - lvgl.resume: - -Triggers --------- - -Specific triggers like ``on_value`` are available for certain widgets; they are described above in their respective section. - Some universal triggers are also available for all of the widgets and/or for LVGL itself: - -.. _lvgl-event-trg: - -Interaction 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. -- ``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. - -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``; this variable may be used in lambdas defined within those triggers. - -.. code-block:: yaml - - # Example triggers: - - button: - ... - on_short_click: - then: - lvgl.page.show: main_page - on_long_press: - then: - light.toggle: display_backlight - - - slider: - ... - on_release: - then: - - light.turn_on: - id: display_backlight - transition_length: 0ms - brightness: !lambda return x / 100; - -.. _lvgl-onidle-trg: - -``lvgl.on_idle`` -**************** - -LVGL has a notion of screen inactivity -- in other words, the time since the last user interaction with the screen is tracked. This can be used 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:`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 - then: - - lvgl.page.show: main_page - - timeout: 60s - then: - - light.turn_off: display_backlight - - lvgl.pause: - -.. _lvgl-seealso: - -See Also --------- - -- :doc:`/components/binary_sensor/lvgl` -- :doc:`/components/sensor/lvgl` -- :doc:`/components/number/lvgl` -- :doc:`/components/switch/lvgl` -- :doc:`/components/select/lvgl` -- :doc:`/components/light/lvgl` -- :doc:`/components/text/lvgl` -- :doc:`/components/text_sensor/lvgl` -- :doc:`/components/display/index` -- :doc:`/components/touchscreen/index` -- :doc:`/components/sensor/rotary_encoder` -- `LVGL docs `__ -- :ghedit:`Edit` From 351f537b07f488388d72262f31fdf698fd1d2166 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 7 Aug 2024 08:29:22 +0000 Subject: [PATCH 552/564] Remove cookbook --- components/lvgl/index.rst | 9 +- components/lvgl/widgets.rst | 17 +- cookbook/images/lvgl_cook_animimg_batt.gif | Bin 8109 -> 0 bytes cookbook/images/lvgl_cook_climate.png | Bin 1672 -> 0 bytes cookbook/images/lvgl_cook_clock.png | Bin 8115 -> 0 bytes cookbook/images/lvgl_cook_cover.png | Bin 4539 -> 0 bytes cookbook/images/lvgl_cook_flex_layout.png | Bin 5015 -> 0 bytes cookbook/images/lvgl_cook_font_batt.png | Bin 243 -> 0 bytes cookbook/images/lvgl_cook_font_binstat.png | Bin 2715 -> 0 bytes cookbook/images/lvgl_cook_font_roboto_mdi.png | Bin 2278 -> 0 bytes cookbook/images/lvgl_cook_gauge.png | Bin 4154 -> 0 bytes cookbook/images/lvgl_cook_gradient_styles.png | Bin 10498 -> 0 bytes cookbook/images/lvgl_cook_keypad.png | Bin 5951 -> 0 bytes cookbook/images/lvgl_cook_pagenav.png | Bin 1312 -> 0 bytes cookbook/images/lvgl_cook_remligbut.png | Bin 1696 -> 0 bytes cookbook/images/lvgl_cook_statico.png | Bin 700 -> 0 bytes cookbook/images/lvgl_cook_thermometer.png | Bin 11532 -> 0 bytes .../images/lvgl_cook_thermometer_gauge.png | Bin 5872 -> 0 bytes cookbook/images/lvgl_cook_titlebar.png | Bin 2366 -> 0 bytes cookbook/images/lvgl_cook_volume.png | Bin 1264 -> 0 bytes cookbook/images/lvgl_cook_weather.png | Bin 8364 -> 0 bytes cookbook/lvgl.rst | 2247 ----------------- index.rst | 1 - 23 files changed, 4 insertions(+), 2270 deletions(-) delete mode 100644 cookbook/images/lvgl_cook_animimg_batt.gif delete mode 100644 cookbook/images/lvgl_cook_climate.png delete mode 100644 cookbook/images/lvgl_cook_clock.png delete mode 100644 cookbook/images/lvgl_cook_cover.png delete mode 100644 cookbook/images/lvgl_cook_flex_layout.png delete mode 100644 cookbook/images/lvgl_cook_font_batt.png delete mode 100644 cookbook/images/lvgl_cook_font_binstat.png delete mode 100644 cookbook/images/lvgl_cook_font_roboto_mdi.png delete mode 100644 cookbook/images/lvgl_cook_gauge.png delete mode 100644 cookbook/images/lvgl_cook_gradient_styles.png delete mode 100644 cookbook/images/lvgl_cook_keypad.png delete mode 100644 cookbook/images/lvgl_cook_pagenav.png delete mode 100644 cookbook/images/lvgl_cook_remligbut.png delete mode 100644 cookbook/images/lvgl_cook_statico.png delete mode 100644 cookbook/images/lvgl_cook_thermometer.png delete mode 100644 cookbook/images/lvgl_cook_thermometer_gauge.png delete mode 100644 cookbook/images/lvgl_cook_titlebar.png delete mode 100644 cookbook/images/lvgl_cook_volume.png delete mode 100644 cookbook/images/lvgl_cook_weather.png delete mode 100644 cookbook/lvgl.rst diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index f52ff907b6..bacdf279a5 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -18,7 +18,6 @@ The graphic display should be configured with ``auto_clear_enabled: false`` and For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred), a :doc:`/components/sensor/rotary_encoder` or a custom keypad made up from discrete :doc:`Binary Sensors ` 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 ------ @@ -147,7 +146,6 @@ The following configuration variables apply to the main ``lvgl`` component, in o align: CENTER text: 'Hello World!' -See :ref:`lvgl-cookbook-navigator` in the Cookbook for an example illustrating how to easily implement a page navigation bar at the bottom of the screen. .. _lvgl-color: @@ -178,7 +176,6 @@ You can use :ref:`fonts configured normally`, the glyphs will be For best results, set ``bpp: 4`` to get the glyphs rendered with proper anti-aliasing. -Check out :ref:`lvgl-cookbook-icontext`, :ref:`lvgl-cookbook-iconstat` and :ref:`lvgl-cookbook-iconbatt` in the Cookbook for examples illustrating how to use icons and text with TrueType/OpenType fonts. **Library fonts** @@ -379,7 +376,6 @@ So the precedence happens like this: state based styles override the locally spe Feel free to experiment to discover inheritance and precedence of the styles based on states between the nested widgets. -:ref:`lvgl-cookbook-theme` The Cookbook contains an example illustrating how to easily implement a gradient style for your widgets. .. _lvgl-layouts: @@ -390,7 +386,6 @@ Layouts aim to position widgets automatically, eliminating the need to specify ` The layout configuration options are applied to any parent widget or page, influencing the appearance of the children. The position and size calculated by the layout overwrites the *normal* ``x``, ``y``, ``width``, and ``height`` settings of the children. -Checkout :ref:`lvgl-cookbook-flex`, :ref:`lvgl-cookbook-grid` and :ref:`lvgl-cookbook-weather` in the Cookbook for examples illustrating how to automate widget positioning, potentially reducing the size of your device's YAML configuration, and saving you from lots of manual calculations. The ``hidden``, ``ignore_layout`` and ``floating`` :ref:`flags ` can be used on widgets to ignore them in layout calculations. @@ -524,7 +519,7 @@ This :ref:`action ` redraws the entire screen, or optionally onl This :ref:`action ` pauses the activity of LVGL, including rendering. -- **show_snow** (*Optional*, boolean): When 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-cookbook-antiburn` for an example illustrating how to use this. +- **show_snow** (*Optional*, boolean): When 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. .. code-block:: yaml @@ -680,7 +675,6 @@ The ``on_idle`` :ref:`triggers ` are activated when inactivity time - light.turn_off: display_backlight - lvgl.pause: -See :ref:`lvgl-cookbook-idlescreen` for an example illustrating how to implement screen saving with idle settings. .. _lvgl-seealso: @@ -693,7 +687,6 @@ See Also * -- :doc:`LVGL Examples in the Cookbook ` - :doc:`/components/display/index` - :doc:`/components/touchscreen/index` - :doc:`/components/sensor/rotary_encoder` diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 119eafcbc2..51ce885164 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -85,7 +85,6 @@ To apply styles to the states, you need to specify them one level above, for exa The state itself can be can be changed by interacting with the widget, or through :ref:`actions ` with ``lvgl.widget.update``. -See :ref:`lvgl-cookbook-cover` for a cookbook example illustrating how to use styling and properties to show different states of a Home Assistant entity. .. _lvgl-widget-flags: @@ -118,7 +117,7 @@ In addition to visual styling, each widget supports some boolean **flags** to in .. note:: - LVGL only supports **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 only supports **integers** for numeric ``value``. Visualizer widgets can't display floats directly, but they allow scaling by 10s. .. _lvgl-widget-label: @@ -324,7 +323,6 @@ To have a button with a text label on it, add a child :ref:`lvgl-widget-label` w The ``button`` can be also integrated as a :doc:`Binary Sensor ` or as a :doc:`Switch ` component. -See :ref:`lvgl-cookbook-binent` for an example illustrating how to use a checkable button to act on a Home Assistant service. .. _lvgl-widget-buttonmatrix: @@ -456,7 +454,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row .. 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-cookbook-keypad` for an example. + The Button Matrix widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. .. _lvgl-widget-switch: @@ -500,7 +498,6 @@ The switch looks like a little slider and can be used to turn something on and o The ``switch`` can be also integrated as a :doc:`Switch ` component. -See :ref:`lvgl-cookbook-relay` for an example how to use a switch to act on a local component. .. _lvgl-widget-checkbox: @@ -562,7 +559,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c .. note:: - In case you configure ``default_font`` in the main section to a custom font, the checkmark will not be shown correctly when the checkbox is in the checked state. See :ref:`lvgl-cookbook-ckboxmark` how to easily resolve this. + In case you configure ``default_font`` in the main section to a custom font, the checkmark will not be shown correctly when the checkbox is in the checked state. The ``checkbox`` can be also integrated as a :doc:`Switch ` component. @@ -833,7 +830,6 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -See :ref:`lvgl-cookbook-bright` and :ref:`lvgl-cookbook-volume` for examples illustrating how to use a slider to control entities in Home Assistant. .. _lvgl-widget-arc: @@ -918,7 +914,6 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can be The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -See :ref:`lvgl-cookbook-bright` and :ref:`lvgl-cookbook-volume` for examples illustrating how to use a slider (or an arc) to control entities in Home Assistant. .. _lvgl-widget-spinbox: @@ -997,7 +992,6 @@ The spinbox contains a numeric value (as text) which can be increased or decreas The ``spinbox`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -See :ref:`lvgl-cookbook-climate` for an example illustrating how to implement a thermostat control using the spinbox. .. _lvgl-widget-meter: @@ -1109,7 +1103,6 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need id: temperature_needle value: 3 -See :ref:`lvgl-cookbook-gauge`, :ref:`lvgl-cookbook-thermometer` and :ref:`lvgl-cookbook-clock` in the Cookbook for examples illustrating how to effectively use this widget. .. _lvgl-widget-image: @@ -1224,7 +1217,6 @@ The animation image is similar to the normal ``image`` widget. The main differen repeat_count: 100 duration: 300ms -See :ref:`lvgl-cookbook-animbatt` in the Cookbook for a more detailed example. .. _lvgl-widget-line: @@ -1314,7 +1306,6 @@ The ``led`` can be also integrated as :doc:`Light ` comp 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-cookbook-keypad` in the Cookbook for an example illustrating how to change the ``led`` styling properties from an automation. .. _lvgl-widget-spinner: @@ -1699,7 +1690,6 @@ This powerful :ref:`action ` allows changing/updating any widget id: my_label_id hidden: true -Check out in the Cookbook :ref:`lvgl-cookbook-binent` for an example illustrating how to use a template to update the state. .. _lvgl-automation-shorthands: @@ -1792,7 +1782,6 @@ See Also -------- - :ref:`LVGL Main component ` -- :doc:`Examples in the Cookbook ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/cookbook/images/lvgl_cook_animimg_batt.gif b/cookbook/images/lvgl_cook_animimg_batt.gif deleted file mode 100644 index a1ec7806d9f4eba88f68f784037efe8f1383581a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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|H9Gu-4m#b`8oD@{u1n#P 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 diff --git a/cookbook/images/lvgl_cook_cover.png b/cookbook/images/lvgl_cook_cover.png deleted file mode 100644 index 5c9fe2987167fe988d4d2efe28cfcf0c58a5a55b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4539 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%0D2(KoskIQB==m9F_$;C81@U>R#n-J_Huy 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 diff --git a/cookbook/images/lvgl_cook_font_batt.png b/cookbook/images/lvgl_cook_font_batt.png deleted file mode 100644 index 6803ee049bae1b86ed99f7393698c631da4950eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 243 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s1SJ3FdmIK*oCO|{#S9F5M?jcysy3fAP;jZI zi(`mKXY!x_|LvK#G74Yyl`);tx}d9g`uVeS?ZnUdp7SxgWV-0eh2Q+|@^A0sJy-gv zL@7fta$C44~A=k!nTEZi|eW$4{&vLWn*LW89hjbZSA!#~$R)^y6gwy2v? o6BUm(*w3BB+vYx_kHML7C#Pj{4*P6zpo1AaUHx3vIVCg!0L2wqhyVZp diff --git a/cookbook/images/lvgl_cook_font_binstat.png b/cookbook/images/lvgl_cook_font_binstat.png deleted file mode 100644 index 4315ba8cceafce83febc3b99d15b3ed9ef839e9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2715 zcmV;M3S{+(P)!;S-kKYRCod}NYDXmm_l6|h{6WO8FGk+ zJ=EJA8k57cw9q88u$#F|C(NNu_pnXpur%FEvkTp{g$~XoB!$gva_Ar*vcv;j;zCLs zXh1mxBxpbnBG7{xI)|ijY^SoEN>3iwA3B8O>FLj}U;qE!um3%L^ybYQXw$|&eiOC; zZCZ`CNwx8rwn??|nTVH0nr=-k>)IBjwiC2K+#o_U6(^&;N=gxZ>{feeOy!E&mPHvr z1byr|G)jyhq~hXeUm|r%uG{=0_u=_m!5CR6QrjUYVgxaQ(MZ%kVMD_yIjqE3iBV<| zAv)ck$f)&|pK)pLW>Ts9tGP{s z2r@xGpW|kOGK<0(nr>zQ0m3_8erIzZzC;n9fz_3gz8UcbJBIp#HQYaz- zWfXu}f2$w<#P82&@ zgK{1IqU}%uTG2=)$|;x%FO_+`y0}3ljxH*l5GT${V$^L?X*tgLk0wvUG8s*uCUaNZ zatfJ$YV*%^LOq2@UyupCHMp4htmx8a?&rkK*|b6V-9bv^flg)aFJ-4*VN&~1k5|t3 z&ILKs;WfcHw`Pnz;dK9KiPepL;&*dwTSteJJHObMpSrr}vGM4m^h_=ps5}R-DB?-w zaO|rHe3Ur^k&lx8`<2oqmm`biIP)*)$`+%J0{|o%?TO>SS#sdOG99uK!$1C8=OP_Y zRwts-5+JYP!HvPivHraG_ET3Em6&yVHXWQuWlD@zj(V%#@gV?*fz-Xh3VWJ(s!uIf zc_6yD2IC7b+AEL$LD~CNmn`19z`mXh+^Rfz=?LQMpalT{7(J&oWKVmH_2;RLQ%jBI z*p30d238r?La0PYcaVd4XE{#h@oJ4dm6=*LGLKg+XWwUJI^=Z62bADQd~8g7nLFOO z6JO>MAM+dP9T0*^-8ruu{5&#ST-mJS6jwIc$ZUB`dieCPVL>1FzM6R-`R;u+!$HWZ zi`Epk1e^`J)LkAPO)Tjv8=ivf$_ATQ(#Ov!03b%AmsFB{Mgx@6BLV9w)luwZG+<-SXi*fiImj1aFg?c~$%! z7sj=n1TAM3HC`(Cn&q+C!ok(DS9;QCW%u^!vvT%I&%r5Uvjq-9HUo^|_z&v)^f3N| z%D6934dJ!1wqf0QTCRc54)si5?mBW@g$UD^yRt)Nd%E*`lb1<~J zNhY6gD#SZXINNO8UMN0TE?ZTmTiJWlQpIpmIT(@yz=P%W+Y7wkSh>N$S(f07>jPHf z(_71iFRl;pk+6!;c5WG)Esj5FV8z_%%<9-|Guaa_7{gD7h8pr!tDEGLp&|YuZ;zT( zC&#rhlTV8i7s^Wp+%Ns`f1K^f%l+V_E5_jSYXi=I9(rv5`L%()^MVt}h4%hZZG0x| zB=K7&E_5CCSicUMV`6v&p$f*ks`L0XpI}YYPgSI$bpa9FuBy6 z=F)ULTuMA#;<_;5cr?rK{8vfy4ey$PN|P!v1}(B_>HEL{>K6f*7(|fs7B|gEjS?zM z3M0U{s|gWC``liRPUQ-`w^WTF)^p!jVoVT$(=7NYWCZ)z8 zZzJP-1Cw!SVz9@h!HRC=Uhu8CLsVmRny7^3MFN!5wjX;avi0Dbf=h$^1}W-%w|^Fi zO5SZ!!`*V;G=T3c)U3BMp>6~JK^*R`v-)&6spKibOSc>BKXpfM{3~-}%5btmR~0X0 z(x(-S@LnTV+@{%l^?r{BWb^CAZN6*O5itVk({*-UNOvX>7)V?-| z;_ad&1%ahIE9RjUTb4PFGx?)-GtXd$t3PipV#=)~etSL@b={lKah%Cn?dEd^`I!%N z>K6e>UcA+b-wsyjs=`Y}qtSs*MI`{FPNikb9z<3N40I~)_O!37q@p5)4lX-`H6a~o z73n~-T36MT2(lzk_bUVugjW8@$I%EPL7eVaWXaPu9Bs_5L4>tMCC;&B~wZA?fh(IKjz;wTY0-ib5z)~iol+A$@hf^t4pwoluyL5H5Nja|_eM@IHTii5m=NSV4n*y_-)bQRIO-ckH zf`B3j1OaX&G5x8G0xEGO`rF1n!&KJQnsNL8CMzNA=wKOOo6s6xy+Q;*0#SyTf)RG( z_fopUO;>IoPcsa|Fbx36ZyVV)R@mA9G+S`O^P|KNK#jqr4oseu0YH{ySw8+wXk}e( z8QFqapui%eb#zstDuGL?l#JKcRh>^fTDz8E8mw~L9iH{+L4cKa8U^$|esZC$t3B$N z)EHEKv#@yh}5Y4Q+H86Zx>zhV@qNrJ7~EXbgp_ zYyt}GGV&qd-m-`1)o5f}R_y$lWc*g4PdpsVGS$>9QTU<_KE?6{QeD;h8YE z%9*AK0BS=`EvCXVVT4d>F;%HnF568vu7;p7mGXe4Of9AmLKoxAC~&JBLP$T*&wC*K zKt~99ytyUf34Vh&jtl^3AGf8V^zQt-x%C`-i&bh$`?w7NN=-?Bm=%W zPIb*-2p{41`G=INo=@!}Dmh=h*-fGbh@<4VIj`r*0POT%$Cf_9Wm;*N+A zvInwKtt8?Jgb)>_ge?JonTRLoc^UwuqSRei(erd_F(qsXYC~-uxA2!<1g$nyJXRu} zaAb7-K*z4)V!#>^e<_tDycu#g_JV$(8%IWFIYamekEOr&(XGV{&xA888N79~kV+EX z*d^i#^&c;%pIgs4f`V=E-@%EX_t^met{Ge+*e?p*`-h&|7@CX7&}u_Xf0#B~W_l?d z@CWz}KDV9&fb2(E?mhpxhps?6mEQv@a&S*{T z?(gqf-|GiDJx@P-_AI@WW^c1fO-a4~N@2s@K70P6L+WeEV$xhVcf#VGHyvwCxh zV819h=%=4QTjJ@&r&S+D2IFFRynCCsSPzU69E9>3jqMW{oA*=6`Dl+1}~K) zHp$|K+T*GZDf^DAi6)uhbRzzb*kFvz)QA#z4Z;VcdVe2txlTIOwMh zkDhdM5gEGOY6E~(Hi%z|yMK0i2wkH=bJ!Ej@WLc0oVTwWfx19@g=|s>A!}YpZKo zL$h*Wa54zCwN+|La3W|)$B}nqb1~z{z$Hq(RwsOfWr?N`&b40H{L|(@n|@JnFoZVT zxrhwS{*IN)GCfbHm(rQ#44OjS)kQx7fk0|8g;z&ysP$T1`A)Hp4z#A0{~{mR>T&4< zz}tbh0pMrzXZ*2!+}4_!hL(aexUQ8@zq)tpA7?m z*)pvqMep=oTYS5y{Jp{^S*@utamM~@W+kKjOB?7a|3}_?_@FBa4o1;NPcA~xbc~js zN)JDJnBUIlxAWu zreiezNZq8An&Q1&aUWf6sO&A4@DZ8iOehqRzLqQr;?(PM#LFgG?jBdK*8{!)cFbWQ zYze8wl*>_L?osYkvlz%(X~V*+p!EZNluIWv6WK5Cs|^*qZX6mT?q}&3Z7Ie(=pAIg zv!9`{g=w1j356rSR?3xANul59pKp8)0Q>Sj4hJrUF}Or=zm0^a!%9^_lL%}Dv>kCr z?5Am~EIwP#RvVsbXsIO8^R)eeCoX*g{!WqS{@_O{NqA3!&8Qi{5k>vg<=6u$uvzI9&1?%KLG&NPFDHumFxTA>O%m~8l5MrBqFtD z=UGwDD?c3yScg~RP{VaaBhP}=Deg1l_t~IsbRIq2LT#SV+f#2YJR(rVK zpynt?7?>oJ-_A>4OCAO7GCGrFw5CQyDJn+EB^fVN>%T2~!vvFHk_ z92q_94Lkfg@Avr&#e#JR*pr?S^p1-*T-Mo*6VGHHWJ5PXBuPeZMt8s5b^N+1Y~o)R z?ksEyn9c@-Fv#nyvL9v8M+b5KFHb|?mgWL-3WzlgkHRO;oX^@EZkWjNz&dk zNs@L~zyIg=*oGuY<~_#p(9zJ{xVu}6-7k0h{eRg-MC9lXnO{#{)0dORoD*t8)tVX|KlK68RbiZ=-xN&Ke7x}(?|-aK*!5$aq2C~+ zqJ$>VzPx|gj+`Uo3_a#rG0xCqt`%cJkGWR-4_MFI`Wj4X!vFvP07*qoM6N<$f;cK# A(f|Me diff --git a/cookbook/images/lvgl_cook_gauge.png b/cookbook/images/lvgl_cook_gauge.png deleted file mode 100644 index 11379cb9d92fb2804f266c5d22b6591b3c4844df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4154 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 TzWxJsFb+^r(3G!~wG8<$^H^HV diff --git a/cookbook/images/lvgl_cook_pagenav.png b/cookbook/images/lvgl_cook_pagenav.png deleted file mode 100644 index db7b3b55f008b75bf4ce25b1dc35119aa73e433c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1312 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 JWt~$(69A@pIDh~E diff --git a/cookbook/images/lvgl_cook_thermometer.png b/cookbook/images/lvgl_cook_thermometer.png deleted file mode 100644 index ee38819578cb9e3f9d0f7f34c11d9df3e0998c09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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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 diff --git a/cookbook/images/lvgl_cook_thermometer_gauge.png b/cookbook/images/lvgl_cook_thermometer_gauge.png deleted file mode 100644 index 6976d767d2e7529d13ab324c3c1f08f833a9107e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5872 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 diff --git a/cookbook/images/lvgl_cook_volume.png b/cookbook/images/lvgl_cook_volume.png deleted file mode 100644 index 3d42748c97934c4cf05925a6fcfc36f17a9d9aa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1264 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 Rq5m+zP?A%VEdd$_{x1_sDER;Y diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst deleted file mode 100644 index cce37138db..0000000000 --- a/cookbook/lvgl.rst +++ /dev/null @@ -1,2247 +0,0 @@ -.. _lvgl-cookbook: - -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. - -.. note:: - - Many of the examples below call service actions in Home Assistant; however, Home Assistant does not allow such action calls by default. For each ESPHome device which will call actions, you must explicitly enable this setting in Home Assistant. This may be done when the device is initially adopted or by using the `Configure` option in the "devices" list of the ESPHome integration. - -.. 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 with dimensions of ``240x320px``; if your display's dimensions differ, you'll need to adjust them in order to obtain the expected results. - -.. _lvgl-cookbook-relay: - -Local light switch ------------------- - -.. figure:: /components/lvgl/images/lvgl_switch.png - :align: left - -The easiest way to integrate an LVGL :ref:`lvgl-widget-switch` widget and a switch or light is with :ref:`automations `: - -.. code-block:: yaml - - light: - - platform: ... - id: local_light - name: 'Local light' - on_turn_on: - - lvgl.widget.update: - id: light_switch - state: - checked: true - on_turn_off: - - lvgl.widget.update: - id: light_switch - state: - checked: false - - lvgl: - ... - pages: - - id: main_page - widgets: - - switch: - align: CENTER - id: light_switch - on_click: - light.toggle: local_light - -.. _lvgl-cookbook-binent: - -Remote light button -------------------- - -.. figure:: images/lvgl_cook_remligbut.png - :align: right - -If you'd like to control a remote light which appears as an entity in Home Assistant from a checkable (toggle) :ref:`lvgl-widget-button`, first you need to import the light state into ESPHome, and then control it using a action call: - -.. code-block:: yaml - - binary_sensor: - - platform: homeassistant - id: remote_light - entity_id: light.remote_light - publish_initial_state: true - on_state: - then: - lvgl.widget.update: - id: light_btn - state: - checked: !lambda return x; - - lvgl: - ... - pages: - - id: room_page - widgets: - - button: - id: light_btn - align: CENTER - width: 100 - height: 70 - checkable: true - widgets: - - label: - align: CENTER - text: 'Remote light' - on_click: - - homeassistant.action: - action: light.toggle - data: - entity_id: light.remote_light - -.. _lvgl-cookbook-bright: - -Light brightness slider ------------------------ - -.. figure:: images/lvgl_cook_volume.png - :align: left - -You can use a :ref:`slider ` or an :ref:`arc ` to control 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 convenient to set the slider's ``min_value`` and ``max_value`` accordingly. - -.. code-block:: yaml - - sensor: - - platform: homeassistant - id: light_brightness - entity_id: light.your_dimmer - attribute: brightness - on_value: - - lvgl.slider.update: - id: dimmer_slider - value: !lambda return x; - - lvgl: - ... - pages: - - id: room_page - widgets: - - slider: - id: dimmer_slider - x: 20 - y: 50 - width: 30 - height: 220 - pad_all: 8 - min_value: 0 - max_value: 255 - on_release: - - homeassistant.action: - action: light.turn_on - data: - 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`` action call, and since ESPHome uses floats, ``x`` needs to be converted. - -This is applicable to action calls like ``fan.set_percentage`` or ``valve.set_valve_position``, too; the only difference is that ``max_value`` has to be ``100``. - -.. _lvgl-cookbook-volume: - -Media player volume slider --------------------------- - -.. 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 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 action call, we have to divide it 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: mediaplayer_page - widgets: - - slider: - id: slider_media_player - x: 60 - y: 50 - width: 30 - height: 220 - pad_all: 8 - min_value: 0 - max_value: 100 - adv_hittest: true - on_value: - - homeassistant.action: - action: media_player.volume_set - data: - entity_id: media_player.your_room - volume_level: !lambda return (x / 100); - -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 generally has a negative effect on performance. 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. To mitigate this, consider using a universal widget trigger like ``on_release`` to get the ``x`` variable once after the interaction has completed. - -.. _lvgl-cookbook-gauge: - -Semicircle gauge ----------------- - -A gauge similar to what Home Assistant shows in the Energy Dashboard can accomplished with :ref:`lvgl-widget-meter` and :ref:`lvgl-widget-label` widgets: - -.. figure:: images/lvgl_cook_gauge.png - :align: center - -The trick here is to have a parent :ref:`lvgl-widget-obj` which contains the other widgets as children. We place a :ref:`lvgl-widget-meter` in the middle, which is made from an indicator ``line`` and two ``arc`` widgets. We use another, smaller :ref:`lvgl-widget-obj` on top of it to hide the indicator's central parts and place some :ref:`lvgl-widget-label` widgets to display numeric information: - -.. code-block:: yaml - - sensor: - - platform: ... - id: values_between_-10_and_10 - on_value: - - lvgl.indicator.update: - id: val_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_color: 0xFFFFFF - border_width: 0 - pad_all: 4 - widgets: - - meter: - height: 100% - width: 100% - border_width: 0 - bg_opa: TRANSP - 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 - - obj: # to cover the middle part of meter indicator line - height: 146 - width: 146 - radius: 73 - align: CENTER - border_width: 0 - bg_color: 0xFFFFFF - pad_all: 0 - - 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 - y: 8 - x: -90 - text: "-10" - - label: # higher range indicator - text_font: montserrat_18 - align: CENTER - y: 8 - x: 90 - text: "+10" - -.. tip:: - - The ``obj`` used to hide the middle part of the 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-cookbook-thermometer: - -Thermometer ------------ - -A thermometer with a precise gauge also made from a :ref:`lvgl-widget-meter` widget and a numeric display using :ref:`lvgl-widget-label`: - -.. figure:: images/lvgl_cook_thermometer.png - :align: center - -Whenever a new value comes from the sensor, we update the needle indicator as well as the text in the :ref:`lvgl-widget-label`. Since LVGL only handles integer values on the :ref:`lvgl-widget-meter` scale, but the sensor's value is a ``float``, we use the same approach as in the examples above; we multiply the sensor's values by ``10`` and feed this value to the :ref:`lvgl-widget-meter`. It's essentially two scales on top of each other: one to set the needle based on the multiplied value and the other to show sensor's original value in the :ref:`lvgl-widget-label`. - -.. code-block:: yaml - - sensor: - - platform: ... - id: outdoor_temperature - on_value: - - lvgl.indicator.update: - id: temperature_needle - value: !lambda return x * 10; - - lvgl.label.update: - id: temperature_text - text: - format: "%.1f°C" - args: [ 'x' ] - lvgl: - ... - pages: - - id: meter_page - widgets: - - meter: - align: CENTER - height: 180 - width: 180 - scales: - - range_from: -100 # scale for the needle value - range_to: 400 - angle_range: 240 - rotation: 150 - indicators: - - line: - id: temperature_needle - 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 - rotation: 150 - ticks: - width: 1 - count: 51 - length: 10 - color: 0x000000 - major: - stride: 5 - width: 2 - length: 10 - color: 0x404040 - label_gap: 10 - widgets: - - label: - id: temperature_text - text: "-.-°C" - align: CENTER - y: 45 - - label: - text: "Outdoor" - align: CENTER - y: 65 - -And here's the same sensor configuration, but instead with a semicircle gauge with a gradient background drawn by a multitude of ticks: - -.. figure:: images/lvgl_cook_thermometer_gauge.png - :align: center - -If you change the size of the widget, to obtain a uniform gradient, be sure to increase or decrease the ticks count accordingly. - -.. code-block:: yaml - - lvgl: - ... - pages: - - id: meter_page - widgets: - - obj: - height: 240 - width: 240 - align: CENTER - y: -18 - bg_color: 0xFFFFFF - border_width: 0 - pad_all: 14 - widgets: - - meter: - height: 100% - width: 100% - border_width: 0 - align: CENTER - bg_opa: TRANSP - scales: - - range_from: -15 - range_to: 35 - angle_range: 180 - ticks: - count: 70 - width: 1 - length: 31 - indicators: - - tick_style: - start_value: -15 - end_value: 35 - color_start: 0x3399ff - color_end: 0xffcc66 - - range_from: -150 - range_to: 350 - angle_range: 180 - ticks: - count: 0 - indicators: - - line: - id: temperature_needle - width: 8 - r_mod: 2 - value: -150 - - obj: # to cover the middle part of meter indicator line - height: 123 - width: 123 - radius: 73 - align: CENTER - border_width: 0 - pad_all: 0 - bg_color: 0xFFFFFF - - label: - id: temperature_text - text: "--.-°C" - align: CENTER - y: -26 - - label: - text: "Outdoor" - align: CENTER - y: -6 - -.. tip:: - - You can omit the ``obj`` used to hide the middle part of meter indicator line by using a bitmap ``image`` indicator as needle, were only the part hanging above the ticks scale is visible, the rest is transparent. - -.. _lvgl-cookbook-climate: - -Climate control ---------------- - -:ref:`lvgl-widget-spinbox` is the ideal widget to control a thermostat: - -.. 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 labeled with minus and plus to control the spinbox, and whenever we change its value, we just simply call a Home Assistant action to set the new target temperature of the climate. - -.. code-block:: yaml - - sensor: - - platform: homeassistant - id: room_thermostat - entity_id: climate.room_thermostat - attribute: temperature - on_value: - - lvgl.spinbox.update: - id: spinbox_id - value: !lambda return x; - - lvgl: - ... - pages: - - id: thermostat_control - widgets: - - obj: - align: BOTTOM_MID - y: -50 - layout: - type: FLEX - flex_flow: ROW - flex_align_cross: CENTER - width: SIZE_CONTENT - height: SIZE_CONTENT - widgets: - - button: - id: spin_down - on_click: - - lvgl.spinbox.decrement: spinbox_id - widgets: - - label: - text: "-" - - spinbox: - id: spinbox_id - align: CENTER - text_align: CENTER - width: 50 - range_from: 15 - range_to: 35 - step: 0.5 - rollover: false - digits: 3 - decimal_places: 1 - on_value: - then: - - homeassistant.action: - action: climate.set_temperature - data: - temperature: !lambda return x; - entity_id: climate.room_thermostat - - button: - id: spin_up - on_click: - - lvgl.spinbox.increment: spinbox_id - widgets: - - label: - text: "+" - -.. _lvgl-cookbook-cover: - -Cover status and control ------------------------- - -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 examples, we need to get the state of the cover first. We'll use a numeric sensor to retrieve the current position of the cover and a text sensor to retrieve its current movement. We are particularly interested in the moving (*opening* and *closing*) states, because during these we'd like to change the label in 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 closed. - -.. 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: 60% - 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: 60% - 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: - format: "%.0f%%" - args: [ 'id(cover_myroom_pos).get_state()' ] - - lvgl: - ... - pages: - - id: room_page - widgets: - - label: - x: 10 - y: 6 - width: 70 - text: "My room" - text_align: CENTER - - button: - x: 10 - y: 30 - width: 70 - height: 68 - widgets: - - label: - id: cov_up_myroom - align: CENTER - text: "\uF077" - on_press: - then: - - homeassistant.action: - action: cover.open - data: - entity_id: cover.myroom - - button: - x: 10 - y: 103 - width: 70 - height: 68 - widgets: - - label: - id: cov_stop_myroom - align: CENTER - text: STOP - on_press: - then: - - homeassistant.action: - action: cover.stop - data: - entity_id: cover.myroom - - button: - x: 10 - y: 178 - width: 70 - height: 68 - widgets: - - label: - id: cov_down_myroom - align: CENTER - text: "\uF078" - on_press: - then: - - homeassistant.action: - action: cover.close - data: - entity_id: cover.myroom - -.. _lvgl-cookbook-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 necessary. - -.. 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, and can be overridden manually with style definitions (read further to see how). - -.. code-block:: yaml - - lvgl: - ... - theme: - label: - text_font: my_font # set all your labels to use your custom defined font - button: - bg_color: 0x2F8CD8 - bg_grad_color: 0x005782 - bg_grad_dir: VER - bg_opa: COVER - border_color: 0x0077b3 - border_width: 1 - text_color: 0xFFFFFF - pressed: # set some button colors to be different in pressed state - bg_color: 0x006699 - bg_grad_color: 0x00334d - checked: # set some button colors to be different in checked state - bg_color: 0x1d5f96 - bg_grad_color: 0x03324A - text_color: 0xfff300 - buttonmatrix: - bg_opa: TRANSP - border_color: 0x0077b3 - border_width: 0 - text_color: 0xFFFFFF - pad_all: 0 - items: # set all your buttonmatrix buttons 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 - 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 - bg_grad_color: 0x005782 - bg_grad_dir: VER - bg_opa: COVER - border_opa: TRANSP - radius: 0 - pad_all: 0 - pad_row: 0 - 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-cookbook-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.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. - -For the navigation bar we can use a :ref:`lvgl-widget-buttonmatrix`. 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 - - lvgl: - ... - top_layer: - widgets: - - buttonmatrix: - align: bottom_mid - styles: header_footer - pad_all: 0 - outline_width: 0 - id: top_layer - items: - styles: header_footer - rows: - - buttons: - - id: page_prev - text: "\uF053" - on_press: - then: - lvgl.page.previous: - - id: page_home - text: "\uF015" - on_press: - then: - lvgl.page.show: main_page - - id: page_next - text: "\uF054" - on_press: - then: - lvgl.page.next: - -For this example to appear correctly, use the theme and style options from :ref:`above ` and LVGL's own library :ref:`fonts `. - -.. _lvgl-cookbook-statico: - -API connection status icon --------------------------- - -The top layer is useful to show status icons visible on all pages: - -.. figure:: images/lvgl_cook_statico.png - :align: center - -In the example below, we only show the icon when the connection with Home Assistant is established: - -.. code-block:: yaml - - api: - on_client_connected: - - if: - condition: - lambda: 'return (0 == client_info.find("Home Assistant "));' - then: - - lvgl.widget.show: lbl_hastatus - on_client_disconnected: - - if: - condition: - lambda: 'return (0 == client_info.find("Home Assistant "));' - then: - - lvgl.widget.hide: lbl_hastatus - - lvgl: - ... - top_layer: - widgets: - - label: - text: "\uF1EB" - id: lbl_hastatus - hidden: true - align: top_right - x: -2 - y: 7 - text_align: right - text_color: 0xFFFFFF - -Of note: - -- The widget starts *hidden* at boot and it's only shown when triggered by connection with the API. -- 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-cookbook-titlebar: - -Title bar for each page ------------------------ - -Each page can have its own title bar: - -.. figure:: images/lvgl_cook_titlebar.png - :align: center - -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 - - lvgl: - ... - pages: - - id: main_page - widgets: - - obj: - align: TOP_MID - 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 - styles: header_footer - widgets: - - label: - text: "A second page" - align: CENTER - text_align: CENTER - text_color: 0xFFFFFF - ... - -For this example to work, use the theme and style options from :ref:`above `. - -.. _lvgl-cookbook-flex: - -Flex layout positioning ------------------------ - -:ref:`lvgl-layouts` aim to position widgets automatically, eliminating the need to specify coordinates to position each widget. This is a great way to simplify your configuration containing many widgets as it allows you to even omit alignment options. - -.. figure:: images/lvgl_cook_flex_layout.png - :align: center - -This example illustrates a control panel for three covers, made up of labels and discrete buttons. Although a button matrix could also be suitable for this, you might still prefer fully-featured individual buttons, as they offer a wider range of customization possibilities as seen in the :ref:`lvgl-cookbook-cover` example. Here we use the **Flex** layout: - -.. code-block:: yaml - - lvgl: - ... - pages: - - id: room_page - widgets: - - obj: # a properly placed coontainer object for all these controls - align: CENTER - width: 240 - height: 256 - x: 4 - y: 4 - pad_all: 3 - pad_row: 6 - pad_column: 8 - bg_opa: TRANSP - border_opa: TRANSP - layout: # enable the FLEX layout for the children widgets - type: FLEX - flex_flow: COLUMN_WRAP # the order of the widgets starts top left - flex_align_cross: CENTER # they sould be centered - widgets: - - label: - text: "East" - - button: - id: but_cov_up_east - width: 70 # choose the button dimensions so - height: 68 # they fill the columns nincely as they flow - widgets: - - label: - id: cov_up_east - align: CENTER - text: "\U000F005D" # mdi:arrow-up - - button: - id: but_cov_stop_east - width: 70 - height: 68 - widgets: - - label: - id: cov_stop_east - align: CENTER - text: "\U000F04DB" # mdi:stop - - button: - id: but_cov_down_east - width: 70 - height: 68 - widgets: - - label: - id: cov_down_east - align: CENTER - text: "\U000F0045" # mdi:arrow-down - - - label: - text: "South" - - button: - id: but_cov_up_south - width: 70 - height: 68 - widgets: - - label: - id: cov_up_south - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_south - width: 70 - height: 68 - widgets: - - label: - id: cov_stop_south - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_south - width: 70 - height: 68 - widgets: - - label: - id: cov_down_south - align: CENTER - text: "\U000F0045" - - - label: - text: "West" - - button: - id: but_cov_up_west - width: 70 - height: 68 - widgets: - - label: - id: cov_up_west - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_west - width: 70 - height: 68 - widgets: - - label: - id: cov_stop_west - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_west - width: 70 - height: 68 - widgets: - - label: - id: cov_down_west - align: CENTER - text: "\U000F0045" - -This saved you from a considerable amount of manual calculation of widget positioning which would otherwise be required to place them manually with ``x`` and ``y``! You only need to determine a common width and height for your widgets to distribute them on the page as you prefer. (:ref:`lvgl-cookbook-icontext` below shows how to use custom icons.) - -.. _lvgl-cookbook-grid: - -Grid layout positioning ------------------------ - -But there's even more! With the **Grid** layout, you don't need to specify width and height for your widgets. All you have to do is divide the space into rows and columns; the widgets can be automatically be sized to fit into cells defined by these rows and columns. The same task from above, in a fully automated grid, looks like this: - -.. code-block:: yaml - - lvgl: - ... - pages: - - id: room_page - widgets: - - obj: # a properly placed coontainer object for all these controls - align: CENTER - width: 240 - height: 256 - pad_all: 6 - pad_row: 6 - pad_column: 8 - bg_opa: TRANSP - border_opa: TRANSP - layout: # enable the GRID layout for the children widgets - type: GRID # split the rows and the columns proportionally - grid_columns: [FR(1), FR(1), FR(1)] # equal - grid_rows: [FR(10), FR(30), FR(30), FR(30)] # like percents - widgets: - - label: - text: "East" - grid_cell_column_pos: 0 # place the widget in - grid_cell_row_pos: 0 # the corresponding cell - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - - button: - id: but_cov_up_east - grid_cell_column_pos: 0 - grid_cell_row_pos: 1 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_up_east - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_east - grid_cell_column_pos: 0 - grid_cell_row_pos: 2 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_stop_east - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_east - grid_cell_column_pos: 0 - grid_cell_row_pos: 3 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_down_east - align: CENTER - text: "\U000F0045" - - - label: - text: "South" - grid_cell_column_pos: 1 - grid_cell_row_pos: 0 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - - button: - id: but_cov_up_south - grid_cell_column_pos: 1 - grid_cell_row_pos: 1 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_up_south - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_south - grid_cell_column_pos: 1 - grid_cell_row_pos: 2 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_stop_south - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_south - grid_cell_column_pos: 1 - grid_cell_row_pos: 3 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_down_south - align: CENTER - text: "\U000F0045" - - - label: - text: "West" - grid_cell_column_pos: 2 - grid_cell_row_pos: 0 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - - button: - id: but_cov_up_west - grid_cell_column_pos: 2 - grid_cell_row_pos: 1 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_up_west - align: CENTER - text: "\U000F005D" - - button: - id: but_cov_stop_west - grid_cell_column_pos: 2 - grid_cell_row_pos: 2 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_stop_west - align: CENTER - text: "\U000F04DB" - - button: - id: but_cov_down_west - grid_cell_column_pos: 2 - grid_cell_row_pos: 3 - grid_cell_x_align: STRETCH - grid_cell_y_align: STRETCH - widgets: - - label: - id: cov_down_west - align: CENTER - text: "\U000F0045" - -The big advantage here is that whenever you need to add, for example, an extra column of buttons for a new cover, you just simply append it to the ``grid_columns`` variable, and add the corresponding widgets as above. With ``STRETCH`` their sizes and positions will automatically be calculated to fill in the cells, while the parent's ``pad_all``, ``pad_row`` and ``pad_column`` can help with spacing between them. See :ref:`lvgl-cookbook-weather` further down this page for another example relying on **Grid**. - -.. _lvgl-cookbook-btlg: - -ESPHome boot screen -------------------- - -To display a boot image with a spinner animation which disappears automatically after a few moments or on touch of the screen you can use the *top layer*. The trick is to put a base :ref:`lvgl-widget-obj` full screen and child :ref:`lvgl-widget-image` widget in its middle as the last item of the widgets list, so they draw 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/favicon-512x512.png - id: boot_logo - resize: 200x200 - type: RGB565 - use_transparency: true - - 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: - - image: - align: CENTER - src: boot_logo - y: -40 - - spinner: - align: CENTER - y: 95 - height: 50 - width: 50 - spin_time: 1s - arc_length: 60deg - arc_width: 8 - indicator: - arc_color: 0x18bcf2 - arc_width: 8 - on_press: - - lvgl.widget.hide: boot_screen - -.. _lvgl-cookbook-icontext: - -MDI icons in text ------------------ - -ESPHome's :ref:`font renderer ` allows you to use any OpenType/TrueType font file for your text. This is very flexible because you can prepare various sets of fonts at different sizes each with a different number of glyphs; this is important as it may help to conserve flash memory space. - -One example is when you'd like some MDI icons to be used in line with the text (similar to how LVGL's internal fonts and symbols coexist). You can use a font of your choice; choose the symbols/icons from MDI you want and mix them in a single sized set. - -.. 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 - -.. tip:: - - Follow these steps to choose your MDI icons: - - - To lookup your icons, use the `Pictogrammers `_ site. Click on the desired icon and note its codepoint (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-cookbook-ckboxmark: - -Restore checkbox mark ---------------------- - -If you configure a custom font as the ``default_font`` used by LVGL and this font does not contain the `FontAwesome `__ symbols, you may observe that some widgets won't display correctly; specifically :ref:`lvgl-widget-checkbox` won't show the checkmark when it's checked. - -To work around this issue, simply import only the checkmark symbol in the desired size and apply it through :ref:`lvgl-cookbook-theme` to all the checkboxes in the configuration: - -.. code-block:: yaml - - font: - - file: 'fonts/FontAwesome5-Solid+Brands+Regular.woff' - id: fontawesome_checkmark - size: 18 - bpp: 4 - glyphs: [ - "\uF00C", # ckeckmark, for checkbox - ] - - lvgl: - ... - theme: - checkbox: - indicator: - checked: - text_font: fontawesome_checkmark - -You could of course simply apply one of the built-in ``montserrat_`` packs, but that would not be beneficial on the binary size - it would uselessly include the entire set of glyphs in the flash. - -.. _lvgl-cookbook-iconstat: - -Toggle state icon button ------------------------- - -.. figure:: images/lvgl_cook_font_binstat.png - :align: left - -A common use case for icons is a status display. For example, a checkable (toggle) button will display different icons based on the status of a light or switch. To put an icon on a button you use a :ref:`lvgl-widget-label` widget as the child of the :ref:`lvgl-widget-button`. The coloring can already be different thanks to the :ref:`lvgl-cookbook-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`` states to apply *disabled styles* for these cases. - -If we take our previous :ref:`lvgl-cookbook-binent` example, we can modify it like this: - -.. code-block:: yaml - - font: - - file: "custom/materialdesignicons-webfont.ttf" - id: mdi_42 - size: 42 - bpp: 4 - glyphs: [ - "\U000F0335", # mdi-lightbulb - "\U000F0336", # mdi-lightbulb-outline - ] - - text_sensor: - - platform: homeassistant - id: ts_remote_light - entity_id: light.remote_light - on_value: - then: - - lvgl.widget.update: - id: btn_lightbulb - state: - 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: !lambda |- - static char buf[10]; - 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: - ... - pages: - - id: room_page - widgets: - - button: - x: 110 - y: 40 - width: 90 - height: 50 - checkable: true - id: btn_lightbulb - widgets: - - label: - id: lbl_lightbulb - align: CENTER - text_font: mdi_42 - text: "\U000F0336" # mdi-lightbulb-outline - on_short_click: - - homeassistant.action: - action: light.toggle - data: - entity_id: light.remote_light - -.. _lvgl-cookbook-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: battery_icons_20 - text: "\U000F0091" # start with mdi-battery-unknown - -.. _lvgl-cookbook-animbatt: - -Battery charging animation --------------------------- - -.. figure:: images/lvgl_cook_animimg_batt.gif - :align: left - -To have an animation illustrating a battery charging, you can use :ref:`lvgl-widget-animimg` with a set of :ref:`images rendered from MDI ` 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: ani_battery_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 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-cookbook-clock: - -An analog clock ---------------- - -Using the :ref:`lvgl-widget-meter` and :ref:`lvgl-widget-label` widgets, we can create an analog clock which shows the date too. - -.. figure:: images/lvgl_cook_clock.png - :align: center - -The :ref:`lvgl-widget-meter` 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 at the beginning of every minute to update the line positions for each hand as well as the respective text. - -.. code-block:: yaml - - lvgl: - ... - pages: - - id: clock_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 - border_width: 0 - text_color: 0x000000 - scales: - - range_from: 0 # minutes scale - range_to: 60 - angle_range: 360 - rotation: 270 - ticks: - width: 1 - count: 61 - length: 10 - color: 0x000000 - indicators: - - line: - id: minute_hand - width: 3 - color: 0xa6a6a6 - r_mod: -4 - value: 0 - - 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: 10 - color: 0xC0C0C0 - label_gap: 12 - - 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 - - label: - styles: date_style - id: day_label - y: -30 - - label: - id: date_label - styles: date_style - y: 30 - - time: - - platform: homeassistant - id: time_comp - on_time_sync: - - script.execute: time_update - on_time: - - minutes: '*' - seconds: 0 - then: - - script.execute: time_update - - script: - - id: time_update - then: - - lvgl.indicator.update: - id: minute_hand - value: !lambda |- - return id(time_comp).now().minute; - - lvgl.indicator.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]; - -.. _lvgl-cookbook-keypad: - -A numeric input keypad ----------------------- - -The :ref:`lvgl-widget-buttonmatrix` 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 - -If you key in the correct sequence, the :ref:`lvgl-widget-led` widget will change color accordingly: - -.. code-block:: yaml - - lvgl: - ... - pages: - - id: keypad_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: lvgl_label - align: CENTER - text: "Enter code and \uF00C" - text_align: CENTER - - buttonmatrix: - id: lvgl_keypad - x: 20 - y: 85 - width: 200 - height: 190 - items: - pressed: - bg_color: 0xFFFF00 - 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: "\uF55A" - key_code: "*" - control: - no_repeat: true - - text: 0 - control: - no_repeat: true - - text: "\uF00C" - key_code: "#" - control: - no_repeat: true - - key_collector: - - 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: lvgl_label - text: !lambda 'return x.c_str();' - else: - - lvgl.label.update: - id: lvgl_label - text: "Enter code and \uF00C" - 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 - -Of note: - -- A base object ``obj`` is used as a parent for the label; this allows proper centering of the label as well as emphasizing it with shadows independently of the label's dimensions. -- ``align_to`` is used to align the label to the ``led`` vertically. -- Changing the background color of the buttons in ``pressed`` state. -- Use of the ``key_code`` configuration to send a different character to ``key_collector`` instead of the displayed symbol. - -.. _lvgl-cookbook-weather: - -Weather forecast panel ----------------------- - -Another example relying on the **Grid** layout can be a weather panel showing the forecast through the `OpenWeatherMap integration `__ of Home Assistant. - -.. figure:: images/lvgl_cook_weather.png - :align: center - -All the information displayed here could be retrieved to local ``platform: homeassistant`` sensors as desribed in several examples in this Cookbook, however, this time we take a different approach. Instead of pulling the data by ESPHome, we'll be pushing it from Home Assistant, to native :doc:`/components/text/lvgl` components. - -The weather condition icons we use are from MDI. We import just the ones corresponding to the weather conditions supported by the Weather integration in Home Assistant. For all the other labels you can use any :ref:`font ` of your choice. - -.. code-block:: yaml - - binary_sensor: - - platform: status - name: Status sensor - - font: - - file: "fonts/materialdesignicons-webfont.ttf" - id: icons_100 - size: 100 - bpp: 4 - glyphs: [ - "\U000F0594", # clear-night - "\U000F0590", # cloudy - "\U000F0F2F", # exceptional - "\U000F0591", # fog - "\U000F0592", # hail - "\U000F0593", # lightning - "\U000F067E", # lightning-rainy - "\U000F0595", # partlycloudy - "\U000F0596", # pouring - "\U000F0597", # rainy - "\U000F0598", # snowy - "\U000F067F", # snowy-rainy - "\U000F0599", # sunny - "\U000F059D", # windy - "\U000F059E", # windy-variant - "\U000F14E4", # sunny-off - ] - - lvgl: - ... - pages: - - id: weather_forecast - widgets: - - obj: - align: CENTER - width: 228 - height: 250 - pad_all: 10 - pad_column: 0 - layout: - type: GRID - grid_rows: [FR(48), FR(13), FR(13), FR(13), FR(13)] - grid_columns: [FR(10), FR(40), FR(40), FR(10)] - widgets: - - label: - text: "\U000F14E4" - id: lbl_weather_forecast_condition_icon - text_font: icons_100 - text_align: CENTER - grid_cell_row_pos: 0 - grid_cell_column_pos: 0 - grid_cell_column_span: 2 - grid_cell_x_align: CENTER - grid_cell_y_align: START - - - label: - text: "Unknown" - id: lbl_weather_forecast_condition_name - text_align: CENTER - grid_cell_row_pos: 0 - grid_cell_column_pos: 2 - grid_cell_column_span: 2 - grid_cell_x_align: STRETCH - grid_cell_y_align: CENTER - - - label: - text: "Feels like:" - grid_cell_row_pos: 1 - grid_cell_column_pos: 1 - - - label: - text: "--.- °C" - id: lbl_weather_forecast_tempap - text_align: RIGHT - grid_cell_row_pos: 1 - grid_cell_column_pos: 2 - grid_cell_x_align: STRETCH - - - label: - text: "Maximum:" - grid_cell_row_pos: 2 - grid_cell_column_pos: 1 - - - label: - text: "--.- °C" - id: lbl_weather_forecast_temphi - text_align: RIGHT - grid_cell_row_pos: 2 - grid_cell_column_pos: 2 - grid_cell_x_align: STRETCH - - - label: - text: "Minimum:" - grid_cell_row_pos: 3 - grid_cell_column_pos: 1 - - - label: - text: "--.- °C" - id: lbl_weather_forecast_templo - text_align: RIGHT - grid_cell_row_pos: 3 - grid_cell_column_pos: 2 - grid_cell_x_align: STRETCH - - - label: - text: "Now:" - grid_cell_row_pos: 4 - grid_cell_column_pos: 1 - - - label: - text: "--.- °C" - id: lbl_weather_outdnoor_now - text_align: RIGHT - grid_cell_row_pos: 4 - grid_cell_column_pos: 2 - grid_cell_x_align: STRETCH - - text: - - platform: lvgl - name: fr_cond_icon - widget: lbl_weather_forecast_condition_icon - mode: text - - platform: lvgl - name: fr_cond_name - widget: lbl_weather_forecast_condition_name - mode: text - - platform: lvgl - name: fr_tempap - widget: lbl_weather_forecast_tempap - mode: text - - platform: lvgl - name: fr_temphi - widget: lbl_weather_forecast_temphi - mode: text - - platform: lvgl - name: fr_templo - widget: lbl_weather_forecast_templo - mode: text - - platform: lvgl - name: wd_out_now - widget: lbl_weather_outdnoor_now - mode: text - -If you look carefully at the ``grid_columns`` variable, you'll notice that there are two thinner columns at left and right (``FR(10)``). Reason is to add some space to the labels from the edges. And that's why we had to use ``grid_cell_column_span`` for the widgets in the first row, to take up the space of multiple columns. - -These labels will appear in Home Assistant as `editable text components `__, which makes it very easy to update them with the ``text.set_value`` action. For this purpose, we add the following `automations `__ to Home Assistant: - -.. code-block:: yaml - - - id: weather_cond_forecast - alias: 'Weather Forecast Condition' - trigger: - - platform: state - entity_id: sensor.openweathermap_forecast_condition - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - action: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_cond_icon - data: - value: > - {% set d = { - "clear-night": "\U000F0594", - "cloudy": "\U000F0590", - "exceptional": "\U000F0F2F", - "fog": "\U000F0591", - "hail": "\U000F0592", - "lightning": "\U000F0593", - "lightning-rainy": "\U000F067E", - "partlycloudy": "\U000F0595", - "pouring": "\U000F0596", - "rainy": "\U000F0597", - "snowy": "\U000F0598", - "snowy-rainy": "\U000F067F", - "sunny": "\U000F0599", - "windy": "\U000F059D", - "windy-variant": "\U000F059E", - "unknown": "\U000F14E4", - "unavailable": "\U000F14E4", - } %} - {{ d.get( states('sensor.openweathermap_forecast_condition') ) }} - - - action: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_cond_name - data: - value: > - {% set d = { - "clear-night": "Clear Night", - "cloudy": "Cloudy", - "exceptional": "Except ional", - "fog": "Fog", - "hail": "Hail", - "lightning": "Lightning", - "lightning-rainy": "Lightning rainy", - "partlycloudy": "Partly cloudy", - "pouring": "Pouring", - "rainy": "Rainy", - "snowy": "Snowy", - "snowy-rainy": "Snowy rainy", - "sunny": "Sunny", - "windy": "Windy", - "windy-variant": "Windy cloudy", - "unknown": "Unknown", - "unavailable": "Unavai lable", - } %} - {{ d.get( states('sensor.openweathermap_forecast_condition') ) }} - - - id: weather_temp_feels_like_forecast - alias: 'Weather Temperature Feels Like' - trigger: - - platform: state - entity_id: sensor.openweathermap_feels_like_temperature - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - action: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_tempap - data: - value: "{{states('sensor.openweathermap_feels_like_temperature') | round(1)}} °C" - - - id: weather_temp_forecast_temphi - alias: 'Weather Temperature Forecast Hi' - trigger: - - platform: state - entity_id: sensor.openweathermap_forecast_temperature - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - action: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_temphi - data: - value: "{{states('sensor.openweathermap_forecast_temperature') | round(1)}} °C" - - - id: weather_temp_forecast_templo - alias: 'Weather Temperature Forecast Lo' - trigger: - - platform: state - entity_id: sensor.openweathermap_forecast_temperature_low - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - action: text.set_value - target: - entity_id: - - text.your_esphome_node_fr_templo - data: - value: "{{states('sensor.openweathermap_forecast_temperature_low') | round(1)}} °C" - - - id: weather_temp_outdoor_now - alias: 'Weather Temperature Now' - trigger: - - platform: state - entity_id: sensor.outdoor_temperature - - platform: state - entity_id: binary_sensor.your_esphome_node_status_sensor - to: 'on' - action: - - action: text.set_value - target: - entity_id: - - text.your_esphome_node_wd_out_now - data: - value: "{{states('sensor.outdoor_temperature') | round(1)}} °C" - -The automations will be triggered to update the labels every time the corresponding entities change, and when the ESPHome comes alive - the reason you also need the :doc:`/components/binary_sensor/status`. Note that you'll need to adjust the entity IDs corresponding to your ESPHome node depedning on how you :ref:`configured it to use its name`. - -.. _lvgl-cookbook-idlescreen: - -Turn off screen when idle -------------------------- - -LVGL has a notion of screen inactivity -- in other words, the time since the last user interaction with the screen is tracked. This can be used 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. Note that it's important to use the ``on_release`` trigger to accomplish this task. With a template number you can make the timeout adjustable 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.pause: - - touchscreen: - - platform: ... - on_release: - - 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 - -.. _lvgl-cookbook-antiburn: - -Prevent burn-in of LCD ----------------------- - -You can use this to protect and prolong the lifetime of the LCD screens, thus being more green and generating less hazardous waste. - -A common problem with wall-mounted LCD screens is that they display the same picture 99.999% of the time. Even if somebody turns off the backlight during the night or dark periods, the LCD screen keeps showing the same picture, but seen by nobody. This scenario is likely to lead to burn-in after a few years of operation. - -One way to mitigate this is to *exercise* the pixels periodically by displaying different content. ``show_snow`` option during LVGL paused state was developed with this in mind; it displays randomly colored pixels across the entire screen in order to minimize screen burn-in by exercising each individual pixel. - -In the example below, pixel training is done four times for a half an hour every night; it can be stopped by touching the screen. - -.. code-block:: yaml - - time: - - platform: ... - on_time: - - hours: 2,3,4,5 - minutes: 5 - seconds: 0 - then: - - switch.turn_on: switch_antiburn - - hours: 2,3,4,5 - minutes: 35 - seconds: 0 - then: - - 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: "Stopping Antiburn" - - if: - condition: lvgl.is_paused - then: - - lvgl.resume: - - lvgl.widget.redraw: - - delay: 1s - - lvgl.pause: - - touchscreen: - - platform: ... - on_release: - then: - - if: - 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. - -See Also --------- - -- :ref:`lvgl-main` -- :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` diff --git a/index.rst b/index.rst index cd9ca99828..9b9f7aa1e9 100644 --- a/index.rst +++ b/index.rst @@ -1141,7 +1141,6 @@ 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 From 94a91571529acad2beb5b178a38b2c34e422ac08 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 7 Aug 2024 08:32:29 +0000 Subject: [PATCH 553/564] Remove cookbook from `lint.py`, too --- lint.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lint.py b/lint.py index 4ee654312d..106a4017aa 100644 --- a/lint.py +++ b/lint.py @@ -396,7 +396,6 @@ def lint_directive_formatting(fname, content): exclude=[ "components/web_server.rst", "components/image.rst", - "cookbook/lvgl.rst", ], ) def lint_esphome_io_link(fname, match): From 1fe21c4753d18c8fbd0c2f83bbc20fd68b97e672 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 7 Aug 2024 08:51:07 +0000 Subject: [PATCH 554/564] Fix up some labels --- components/lvgl/index.rst | 42 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index bacdf279a5..bd3e0d53a7 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -117,11 +117,11 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. May not be used if ``pages`` (below) is configured. - **pages** (*Optional*, list): A list of page IDs. Each page acts as a parent for widgets placed on it. May not be used with ``widgets`` (above). Options for each page: - - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-pgnx-act`. + - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-page-next-previous-action`. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. - All other options from :ref:`lvgl-styling` to be applied to this page. -- **page_wrap** (*Optional*, boolean): Wrap from the last to the first page when navigating between them with :ref:`lvgl-pgnx-act`. Defaults to ``true``. +- **page_wrap** (*Optional*, boolean): Wrap from the last to the first page when navigating between them with :ref:`lvgl-page-next-previous-action`. Defaults to ``true``. - **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, which may be useful for widgets which always need to be visible. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. @@ -154,7 +154,7 @@ Colors Colors can be specified anywhere in the LVGL configuration either by referencing a preconfigured :ref:`ESPHome color ` ID or by representing the color in the common hexadecimal notation. For example, ``0xFF0000`` would be red. -.. _lvgl-opa: +.. _lvgl-opacity: Opacity ******* @@ -249,16 +249,16 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **bg_grad_dir** (*Optional*, dict): 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`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``0``. - **bg_grad_stop** (*Optional*, 0-255): Specify where the gradient should stop: ``0`` = upper left, ``128`` = in the center, ``255`` = lower right. Defaults to ``255``. -- **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. Inherited from parent. Defaults to ``COVER``. +- **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. Inherited from parent. Defaults to ``COVER``. - **bg_image_src** (*Optional*, :ref:`image `): The ID of an existing image configuration, to show as the background of the widget. -- **bg_image_opa** (*Optional*, :ref:`opacity `): Opacity of the background image of the widget. +- **bg_image_opa** (*Optional*, :ref:`opacity `): Opacity of the background image of the widget. - **bg_image_recolor** (*Optional*, :ref:`color `): Color to mix with every pixel of the background image of the widget. -- **bg_image_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring of the background image of the widget. +- **bg_image_recolor_opa** (*Optional*, :ref:`opacity `): Opacity of the recoloring of the background image of the widget. - **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_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 as a YAML list, defaults to ``NONE``): - ``NONE`` @@ -271,7 +271,7 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **clip_corner** (*Optional*, boolean): If set to ``true``, overflowing content will be clipped off by the widget's rounded corners (``radius`` > ``0``). - **outline_width** (*Optional*, int16): Set the width of the outline in pixels. Defaults to ``0``. - **outline_color** (*Optional*, :ref:`color `): Color used 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_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. @@ -283,7 +283,7 @@ You can adjust the appearance of widgets by changing their foreground, backgroun - **shadow_color** (*Optional*, :ref:`color `): Color used to create a drop shadow under the widget. Defaults to ``0`` (black). - **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_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): Transformation angle of the widget (eg. rotation) @@ -497,7 +497,7 @@ Actions Widgets support :ref:`general or specific ` actions. Several actions are available for LVGL, these are outlined below. -.. _lvgl-rfrsh-act: +.. _lvgl-redraw-action: ``lvgl.widget.redraw`` ********************** @@ -512,7 +512,7 @@ This :ref:`action ` redraws the entire screen, or optionally onl then: - lvgl.widget.redraw: -.. _lvgl-pause-act: +.. _lvgl-pause-action: ``lvgl.pause`` ************** @@ -528,7 +528,7 @@ This :ref:`action ` pauses the activity of LVGL, including rende - lvgl.pause: show_snow: true -.. _lvgl-resume-act: +.. _lvgl-resume-action: ``lvgl.resume`` *************** @@ -556,7 +556,7 @@ This :ref:`action ` allows changing/updating the ``disp_bg_color - lvgl.update: disp_bg_image: cat_image -.. _lvgl-pgnx-act: +.. _lvgl-page-next-previous-action: ``lvgl.page.next``, ``lvgl.page.previous`` ****************************************** @@ -580,7 +580,7 @@ This :ref:`action ` changes the page to the next/previous based animation: OUT_RIGHT time: 300ms -.. _lvgl-pgsh-act: +.. _lvgl-page-show-action: ``lvgl.page.show`` ****************** @@ -602,12 +602,12 @@ This :ref:`action ` shows a specific page (including pages with then: - lvgl.page.show: secret_page # shorthand version -.. _lvgl-cond: +.. _lvgl-conditions: Conditions ---------- -.. _lvgl-idle-cond: +.. _lvgl-is-idle-condition: ``lvgl.is_idle`` **************** @@ -629,7 +629,7 @@ This :ref:`condition ` checks if the amount of time specified id: display_backlight transition_length: 3s -.. _lvgl-paused-cond: +.. _lvgl-is-paused-condition: ``lvgl.is_paused`` ****************** @@ -651,7 +651,7 @@ Triggers Widget level :ref:`interaction triggers ` can be configured universally, or depending on the widtget functionality. -.. _lvgl-onidle-trg: +.. _lvgl-on-idle-trigger: ``lvgl.on_idle`` **************** @@ -676,8 +676,6 @@ The ``on_idle`` :ref:`triggers ` are activated when inactivity time - lvgl.pause: -.. _lvgl-seealso: - See Also -------- From bf14f049ae4aa50392fc874fd62cdfc65acaab67 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 7 Aug 2024 09:45:06 +0000 Subject: [PATCH 555/564] Alphabetize a bunch of stuff --- components/lvgl/widgets.rst | 1434 +++++++++++++++++------------------ 1 file changed, 715 insertions(+), 719 deletions(-) diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 51ce885164..c18670f459 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -26,8 +26,8 @@ The properties below are common to all widgets. If specifying ``align``, ``x`` and ``y`` can be used as an offset to the calculated position (can also be negative). They are ignored if :ref:`lvgl-layouts` are used on the parent. -- **width** (*Optional*): Width of the widget in pixels or a percentage, or ``SIZE_CONTENT``. - **height** (*Optional*): Height of the widget in pixels or a percentage, or ``SIZE_CONTENT``. +- **width** (*Optional*): Width of the widget in pixels or a percentage, or ``SIZE_CONTENT``. .. note:: @@ -53,22 +53,22 @@ The properties below are common to all widgets. :align: center - **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. +- **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - **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*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - **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-widgetproperty-state: - **state** (*Optional*, dict): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from the theme, but can be locally set or overridden within style definitions. Can be one of: + - **checked** (*Optional*, boolean): Toggled or checked state. - **default** (*Optional*, boolean): Normal, released state. - **disabled** (*Optional*, boolean): Disabled state (also usable with :ref:`shorthand ` actions ``lvgl.widget.enable`` and ``lvgl.widget.disable``). + - **edited** (*Optional*, boolean): Edit by an encoder. + - **focus_key** (*Optional*, boolean): Focused via keypad or encoder but *not* via touch screen. + - **focused** (*Optional*, boolean): Focused via keypad or encoder or clicked via touch screen. - **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 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. By default, states are all ``false``, and they are templatable. @@ -85,82 +85,67 @@ To apply styles to the states, you need to specify them one level above, for exa The state itself can be can be changed by interacting with the widget, or through :ref:`actions ` with ``lvgl.widget.update``. - .. _lvgl-widget-flags: 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``. Hidden objects are ignored in layout calculations. Defaults to ``false``. +- **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. For example, may help by accounting for rounded corners. - **checkable** (*Optional*, boolean): toggle checked state when the widget is clicked. +- **click_focusable** (*Optional*, boolean): add focused state to the widget when 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`` (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 on ``snappable`` children. +- **event_bubble** (*Optional*, boolean): propagate the events to the parent. +- **floating** (*Optional*, boolean): do not scroll the widget when the parent scrolls and ignore layout. +- **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent. +- **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``. Hidden objects are ignored in layout calculations. Defaults to ``false``. +- **ignore_layout** (*Optional*, boolean): the widget is simply ignored by the layouts. Its coordinates can be set as usual. +- **layout_1**, **layout_2** (*Optional*, boolean): custom flags, free to use by layouts. +- **overflow_visible** (*Optional*, boolean): do not clip the children's content to the parent's boundary. +- **press_lock** (*Optional*, boolean): keep the widget pressed even if the press slid from the widget. +- **scroll_chain simple** (*Optional*, boolean): packaging for (``scroll_chain_hor | scroll_chain_ver``). - **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_elastic** (*Optional*, boolean): allow scrolling inside but with slower speed. +- **scroll_momentum** (*Optional*, boolean): make the widget scroll further when "thrown". - **scroll_on_focus** (*Optional*, boolean): automatically scroll widget to make it visible when focused. +- **scroll_one** (*Optional*, boolean): allow scrolling only on ``snappable`` children. - **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. +- **scrollable** (*Optional*, boolean): the widget can become scrollable. Defaults to ``true`` (also see the ``scrollbar_mode`` property). - **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. -- **gesture_bubble** (*Optional*, boolean): propagate the gestures to the parent. -- **adv_hittest** (*Optional*, boolean): allow performing more accurate hit (click) test. For example, may help by accounting for rounded corners. -- **ignore_layout** (*Optional*, boolean): the widget is simply ignored by the layouts. Its coordinates can be set as usual. -- **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. +- **widget_1**, **widget_2** (*Optional*, boolean): custom flags, free to use by widget. .. note:: LVGL only supports **integers** for numeric ``value``. Visualizer widgets can't display floats directly, but they allow scaling by 10s. -.. _lvgl-widget-label: +.. _lvgl-widget-animimg: -``label`` -********* +``animimg`` +----------- -A label is the basic widget type that is used to display text. +The animation image is similar to the normal ``image`` 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/lvgl/images/lvgl_label.png +.. figure:: /components/lvgl/images/lvgl_animimg.gif :align: center **Configuration variables:** -- **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display. To display an empty label, specify ``""``. -- **text_align** (*Optional*, dict): 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 as YAML list). 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_opa** (*Optional*, :ref:`opacity `): Opacity of the text. Inherited from parent. Defaults to ``COVER``. -- **recolor** (*Optional*, boolean): Enable recoloring of button text with ``#``. This makes it possible to set the color of characters in the text individually by prefixing the text to be re-colored with a ``#RRGGBB`` hexadecimal color code followed by a *space*, and finally closed 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 set by :ref:`lvgl-layouts`), 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 lines which are too long. 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 the text horizontally back and forth. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. - - ``SCROLL_CIRCULAR``: If the text is wider than the label, continuously scroll the text horizontally. If it's higher, scroll vertically. Text will scroll in only one direction; 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 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. +- **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 (each frame is displayed for an equal amount of time). +- **repeat_count** (*Optional*, int16 or *forever*): The number of times playback should be repeated. 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. -.. note:: +**Actions:** - 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*. +- ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want start. -**Actions:** +- ``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want stop. -- ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of label widgets which you want update. - - **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. +- ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. + - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** @@ -172,115 +157,136 @@ A label is the basic widget type that is used to display text. .. code-block:: yaml # Example widget: - - label: + - animimg: 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" + id: anim_id + src: [ cat_image, cat_image_bowtie ] + duration: 1000ms - # Example action (update label with a value from a sensor): + # Example actions: on_...: then: - - lvgl.label.update: - id: lbl_id - text: - format: "%.0fdBm" - args: [ 'id(wifi_signal_db).get_state()' ] - -The ``label`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. + - lvgl.animimg.update: + id: anim_id + repeat_count: 100 + duration: 300ms -.. _lvgl-widget-textarea: +.. _lvgl-widget-arc: -``textarea`` -************ +``arc`` +------- -The textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. +The arc consists of a background and a foreground arc. The indicator foreground can be touch-adjusted with a knob. -.. figure:: /components/lvgl/images/lvgl_textarea.png +.. figure:: /components/lvgl/images/lvgl_arc.png :align: center **Configuration variables:** -- **placeholder_text** (*Optional*, string): A placeholder text can be specified, which is displayed when the Text area is empty. -- **accepted_chars** (*Optional*, string): You can set a list of accepted characters, so other characters will be ignored. -- **one_line** (*Optional*, boolean): The text area can be limited to only allow a single line of text. In this case the height will set automatically to fit only one line, line break characters will be ignored, and word wrap will be disabled. -- **password_mode** (*Optional*, boolean): The text area supports password mode. By default, if the ``•`` (bullet, ``0x2022``) glyph exists in the font, the entered characters are converted to it after some time or when a new character is entered. If ``•`` is missing from the font, ``*`` (asterisk) will be used. -- **max_length** (*Optional*, int): Limit the maximum number of characters to this value. -- any :ref:`Styling ` and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. +- **adjustable** (*Optional*, boolean): Add a knob that the user can move to change the value. Defaults to ``false``. +- **arc_color** (*Optional*, :ref:`color `): Color used to draw the arc. +- **arc_opa** (*Optional*, :ref:`opacity `): Opacity of 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. +- **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``. +- **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. +- **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. +- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. +- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. +- **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``. +- **rotation** (*Optional*, 0-360): Offset to the 0 degree position. Defaults to ``0.0``. +- **start_angle** (*Optional*, 0-360): start angle of the arc background (see note). Defaults to ``135``. +- **value** (**Required**, int8): Actual value of the indicator at start, in ``0``-``100`` range. Defaults to ``0``. +- 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`` :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:: + + The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. **Actions:** -- ``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. - - **id** (**Required**): The ID or a list of IDs of textarea widgets which you want update. - - **text** (**Required**): The new text content to be displayed. +- ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of arc widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated on every keystroke. -- ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). -- :ref:`interaction ` LVGL event triggers. - -For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** .. code-block:: yaml # Example widget: - - textarea: - id: textarea_id - one_line: true - placeholder_text: "Enter text here" + - arc: + x: 10 + y: 10 + id: arc_id + value: 75 + min_value: 0 + max_value: 100 + adjustable: true # Example action: on_...: then: - - lvgl.textarea.update: - id: textarea_id - text: "Hello World!" + - lvgl.arc.update: + id: arc_id + knob: + bg_color: 0x00FF00 + value: 55 # Example trigger: - - textarea: + - arc: ... on_value: - then: - - logger.log: - format: "Textarea changed to: %s" - args: [ text.c_str() ] - on_ready: - then: - - logger.log: - format: "Textarea ready: %s" - args: [ text.c_str() ] + - logger.log: + format: "Arc value is: %.0f" + args: [ 'x' ] -The ``textarea`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. +.. note:: -.. _lvgl-widget-button: + The ``on_value`` trigger is sent as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. -``button`` -********** +The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. -Simple push (momentary) or toggle (two-states) button. +.. _lvgl-widget-bar: -.. figure:: /components/lvgl/images/lvgl_button.png +``bar`` +------- + +The bar widget has a background and an indicator foreground on it. The size of the indicator is set according to the current ``value`` of the bar. + +.. figure:: /components/lvgl/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. + **Configuration variables:** -- **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. +- **anim_time** (*Optional*, :ref:`Time `): Sets the animation time if the value is set with ``animated: true``. +- **animated** (*Optional*, boolean): Animate the indicator when the bar changes value. Defaults to ``true``. +- **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. +- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. +- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. +- **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``. +- **value** (**Required**, int8): Actual value of the indicator at start, in ``0``-``100`` range. Defaults to ``0``. +- 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. -A notable state is ``checked`` (boolean) which can have different styles applied. +**Actions:** + +- ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of bar widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. - :ref:`interaction ` LVGL event triggers. **Example:** @@ -288,18 +294,62 @@ A notable state is ``checked`` (boolean) which can have different styles applied .. code-block:: yaml # Example widget: - - button: + - bar: x: 10 - y: 10 - width: 50 - height: 30 - id: btn_id + y: 100 + id: bar_id + value: 75 + min_value: 1 + max_value: 100 -To have a button with a text label on it, add a child :ref:`lvgl-widget-label` widget to it: + # Example action: + on_...: + then: + - lvgl.bar.update: + id: bar_id + value: 55 -.. code-block:: yaml +The ``bar`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. - # Example toggle button with text: +.. _lvgl-widget-button: + +``button`` +---------- + +Simple push (momentary) or toggle (two-states) button. + +.. figure:: /components/lvgl/images/lvgl_button.png + :align: center + +**Configuration variables:** + +- **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. + +A notable state is ``checked`` (boolean) which can have different styles applied. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. +- :ref:`interaction ` LVGL event triggers. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - button: + x: 10 + y: 10 + width: 50 + height: 30 + id: btn_id + +To have a button with a text label on it, add a child :ref:`lvgl-widget-label` widget to it: + +.. code-block:: yaml + + # Example toggle button with text: - button: x: 10 y: 10 @@ -323,11 +373,10 @@ To have a button with a text label on it, add a child :ref:`lvgl-widget-label` w The ``button`` can be also integrated as a :doc:`Binary Sensor ` or as a :doc:`Switch ` component. - .. _lvgl-widget-buttonmatrix: ``buttonmatrix`` -**************** +---------------- The button matrix widget is a lightweight way to display multiple buttons in rows and columns. It's lightweight because the buttons are not actually created but instead simply drawn on the fly. This reduces the memory footprint of each button from approximately 200 bytes (for both the button and its label widget) down to only eight bytes. @@ -339,20 +388,20 @@ 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 ` 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. Must be a value between ``1`` and ``15``; the default is ``1`` (for example, given a line with two buttons, one with ``width: 1`` and another one with ``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``. + - **text** (*Optional*): Text (or built-in :ref:`symbol ` codepoint) to display on the button. + - **width** (*Optional*): Width relative to the other buttons in the same row. Must be a value between ``1`` and ``15``; the default is ``1`` (for example, given a line with two buttons, one with ``width: 1`` and another one with ``width: 2``, the first will be ``33%`` wide while the second will be ``66%`` wide). - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): - - **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): 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. 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*. + - **custom_1** and **custom_2** (*Optional*, boolean): Custom, free to use flags. + - **disabled** (*Optional*, boolean): Apply ``disabled`` styles to the button. + - **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. - **popover** (*Optional*, boolean): Show the button label in a popover when pressing this button. - **recolor** (*Optional*, boolean): Enable recoloring of button text with ``#``. For example: ``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``. @@ -456,53 +505,10 @@ 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. -.. _lvgl-widget-switch: - -``switch`` -********** - -The switch looks like a little slider and can be used to turn something on and off. - -.. figure:: /components/lvgl/images/lvgl_switch.png - :align: center - -**Configuration variables:** - -- **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*, the foreground area underneath the knob shown when the switch is in ``checked`` state. Supports a list of :ref:`styles ` and state-based styles to customize. -- Style options from :ref:`lvgl-styling`. - -**Triggers:** - -- ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - switch: - x: 10 - y: 10 - id: switch_id - - # Example trigger: - - switch: - ... - on_value: - then: - - logger.log: - format: "Switch state: %d" - args: [ x ] - -The ``switch`` can be also integrated as a :doc:`Switch ` component. - - .. _lvgl-widget-checkbox: ``checkbox`` -************ +------------ 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. @@ -566,7 +572,7 @@ The ``checkbox`` can be also integrated as a :doc:`Switch ` from those built-in or from your own customized font. -- **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. +- **indicator** (*Optional*, list): Settings for the the parent of ``symbol``. Supports a list of :ref:`styles ` to customize. +- **options** (**Required**, list): The list of available options in the drop-down. - **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. +- **selected_index** (*Optional*, int8): The index of the item you wish to be selected. +- **selected** (*Optional*, list): Settings for the selected item in the list. Supports a list of :ref:`styles ` to customize. +- **symbol** (*Optional*, dict): 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 those built-in 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-widget-label` text properties for the text on it. ``max_height`` can be used to limit the height of the list. ``text_font`` can be used to set the font of the button part, including the symbol. **Actions:** @@ -639,364 +645,302 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( The ``dropdown`` can be also integrated as :doc:`Select ` component. -.. _lvgl-widget-roller: +.. _lvgl-widget-image: -``roller`` -********** +``image`` +--------- -Roller allows you to simply select one option from a list by scrolling. +Images are the basic widgets used to display images. -.. figure:: /components/lvgl/images/lvgl_roller.png +.. figure:: /components/lvgl/images/lvgl_image.png :align: center **Configuration variables:** -- **options** (**Required**, list): The list of available options in the roller. -- **mode** (*Optional*, dict): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. -- **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-widget-label` 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 this amount of time. -- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-widget-label` style properties. ``text_line_space`` adjusts the space between the options. +- **angle** (*Optional*, 0-360): Rotation of the image. Defaults to ``0.0``. Needs ``pivot_x`` and ``pivot_y`` to be specified. +- **antialias** (*Optional*): The quality of the angle or scale transformation. When anti-aliasing is enabled, the transformations are higher quality but slower. Defaults to ``false``. +- **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is scaled or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``SIZE_CONTENT``, the object's size will be set to the scaled and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. +- **offset_x** (*Optional*): Add a horrizontal offset to the image position. +- **offset_y** (*Optional*): Add a vertical offset to the image position. +- **pivot_x** (*Optional*): Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. +- **pivot_y** (*Optional*): Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. +- **scale** (*Optional*, 0.1-10): Zoom of the image. +- **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. **Actions:** -- ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of roller widgets which you want update. +- ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. + - **id** (**Required**): The ID or a list of IDs of image widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the selected index in ``x``. +- :ref:`interaction ` LVGL event triggers. **Example:** .. code-block:: yaml # Example widget: - - roller: + - image: align: CENTER - id: roller_id - options: - - Violin - - Piano - - Bassoon - - Chello - - Drums + src: cat_image + id: img_id + radius: 11 + clip_corner: true # Example action: on_...: then: - - lvgl.roller.update: - id: roller_id - selected_index: 4 + - lvgl.image.update: + id: img_id + src: cat_image_bowtie - # Example trigger: - - roller: - ... - on_value: - - logger.log: - format: "Selected index is: %d" - args: [ x ] +.. note:: -The ``roller`` can be also integrated as :doc:`Select ` component. + 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-widget-bar: +.. tip:: -``bar`` -******* + ``offset_x`` and ``offset_y`` can be useful when the widget size is set to be smaller than the image source size. A "running image" effect can be created by animating these values. -The bar widget has a background and an indicator foreground on it. The size of the indicator is set according to the current ``value`` of the bar. +.. _lvgl-widget-keyboard: -.. figure:: /components/lvgl/images/lvgl_bar.png - :align: center +``keyboard`` +------------ -Vertical bars can be created if the width is smaller than the height. +The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-widget-textarea`. -Not only the end, but also the start value of the bar can be set, which changes the start position of the indicator. +.. figure:: /components/lvgl/images/lvgl_keyboard.png + :align: center + +For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-widget-buttonmatrix`. **Configuration variables:** -- **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): Animate the indicator when the 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. +- **textarea** (*Optional*): The ID of the ``textarea`` from which to receive the keystrokes. +- **mode** (*Optional*, dict): Keyboard layout to use. Each ``TEXT_`` layout contains a button to allow the user to iterate through the ``TEXT_`` layouts. + - ``TEXT_LOWER``: Display lower case letters (default). + - ``TEXT_UPPER``: Display upper case letters. + - ``TEXT_SPECIAL``: Display special characters. + - ``NUMBER``: Display numbers, +/- sign, and decimal dot. **Actions:** -- ``lvgl.bar.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of bar widgets which you want update. +- ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of keyboard widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- ``on_ready`` :ref:`trigger ` is activated when the checkmark key is pressed. +- ``on_cancel`` :ref:`trigger ` is activated when the key containing the keyboard icon is pressed. **Example:** .. code-block:: yaml # Example widget: - - bar: - x: 10 - y: 100 - id: bar_id - value: 75 - min_value: 1 - max_value: 100 + - keyboard: + id: keyboard_id + textarea: textarea_1 + mode: TEXT_UPPER - # Example action: - on_...: + # Example actions: + on_focus: then: - - lvgl.bar.update: - id: bar_id - value: 55 + - lvgl.keyboard.update: + id: keyboard_id + mode: number + textarea: textarea_2 -The ``bar`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. + # Example trigger: + - keyboard: + ... + on_ready: + then: + - logger.log: Keyboard is ready + on_cancel: + then: + - logger.log: Keyboard cancelled -.. _lvgl-widget-slider: +.. tip:: -``slider`` -********** + The Keyboard widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. -The slider widget looks like a bar supplemented with a knob. The user can drag the knob to set a value. Just like bar, slider can be vertical or horizontal. The size of the indicator foreground and the knob position is set according to the current ``value`` of the slider. +.. note:: -.. figure:: /components/lvgl/images/lvgl_slider.png - :align: center + The Keyboard widget in ESPHome doesn't support popovers or custom layouts. -**Configuration variables:** +.. _lvgl-widget-label: -- **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) is 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. -- **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 shows the current state of the slider. Also uses all the typical background style properties. -- **animated** (*Optional*, boolean): Animate the indicator when the 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. +``label`` +--------- -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. +A label is the basic widget type that is used to display text. -**Actions:** +.. figure:: /components/lvgl/images/lvgl_label.png + :align: center -- ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of slider widgets which you want update. +**Configuration variables:** + +- **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 set by :ref:`lvgl-layouts`), 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 lines which are too long. 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 the text horizontally back and forth. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. + - ``SCROLL_CIRCULAR``: If the text is wider than the label, continuously scroll the text horizontally. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. + - ``CLIP``: Simply clip the parts of the text outside the label. +- **recolor** (*Optional*, boolean): Enable recoloring of button text with ``#``. This makes it possible to set the color of characters in the text individually by prefixing the text to be re-colored with a ``#RRGGBB`` hexadecimal color code followed by a *space*, and finally closed with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. +- **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. +- **text_align** (*Optional*, dict): 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 as YAML list). 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_opa** (*Optional*, :ref:`opacity `): Opacity of the text. Inherited from parent. Defaults to ``COVER``. +- **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display. To display an empty label, specify ``""``. +- 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. + +.. 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*. + +**Actions:** + +- ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of label widgets which you want update. + - **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. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. The new value is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers. **Example:** .. code-block:: yaml # Example widget: - - slider: - x: 10 - y: 10 - width: 220 - id: slider_id - value: 75 - min_value: 0 - max_value: 100 + - 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.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 as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. - -The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. + - lvgl.label.update: + id: lbl_id + text: + format: "%.0fdBm" + args: [ 'id(wifi_signal_db).get_state()' ] +The ``label`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. -.. _lvgl-widget-arc: +.. _lvgl-widget-led: -``arc`` -******* +``led`` +------- -The arc consists of a background and a foreground arc. The indicator foreground can be touch-adjusted with a knob. +The LED widgets are either circular or rectangular widgets whose brightness can be adjusted. As their brightness decreases, the colors become darker. -.. figure:: /components/lvgl/images/lvgl_arc.png +.. figure:: /components/lvgl/images/lvgl_led.png :align: center **Configuration variables:** -- **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``. -- **end_angle** (*Optional*, 0-360): end angle of the arc background (see note). Defaults to ``45``. -- **rotation** (*Optional*, 0-360): 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*, :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. -- **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`` :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:: - - The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. +- **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. +- **color** (*Optional*, :ref:`color `): Color for the background, border, and shadow of the widget. +- Style options from :ref:`lvgl-styling`, using all the typical background style properties. **Actions:** -- ``lvgl.arc.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of arc widgets which you want update. +- ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of led widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **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``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers. **Example:** .. code-block:: yaml # Example widget: - - arc: - x: 10 - y: 10 - id: arc_id - value: 75 - min_value: 0 - max_value: 100 - adjustable: true + - led: + id: led_id + align: CENTER + color: 0xFF0000 + brightness: 70% # Example action: on_...: then: - - lvgl.arc.update: - id: arc_id - knob: - bg_color: 0x00FF00 - value: 55 + - lvgl.led.update: + id: led_id + color: 0x00FF00 - # Example trigger: - - arc: - ... - on_value: - - logger.log: - format: "Arc value is: %.0f" - args: [ 'x' ] +The ``led`` can be also integrated as :doc:`Light ` component. .. note:: - The ``on_value`` trigger is sent as the arc knob is dragged or changed with keys. The event is sent *continuously* while the arc knob is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. - -The ``arc`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. - + If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. -.. _lvgl-widget-spinbox: +.. _lvgl-widget-line: -``spinbox`` -*********** +``line`` +-------- -The spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. +The line widget is capable of drawing straight lines between a set of points. -.. figure:: /components/lvgl/images/lvgl_spinbox.png +.. figure:: /components/lvgl/images/lvgl_line.png :align: center **Configuration variables:** -- **value** (**Required**, float): Actual value to be shown by the spinbox at start. -- **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``. -- **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 character will only be shown if the set range contains negatives. - -**Actions:** - -- ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -- ``lvgl.spinbox.increment`` :ref:`action ` increases the value by one ``step`` configured above. - - **id** (**Required**): The ID of the spinbox widget which you want to increment. - -- ``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. - - **id** (**Required**): The ID of the spinbox widget which you want to decrement. - -**Triggers:** +- **line_color** (*Optional*, :ref:`color `): Color for the line. +- **line_dash_gap** (*Optional*, int16): Set the width of the gap between the dashes in the line (in pixels). +- **line_dash_width** (*Optional*, int16): Set the width of 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_width** (*Optional*, int16): Set the width of the line in pixels. +- **points** (**Required**, list): A list of ``x, y`` integer pairs for point coordinates (origin from top left of parent) +- Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. -- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +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: - - spinbox: - 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:`Number ` or :doc:`Sensor ` component. - + - line: + points: + - 5, 5 + - 70, 70 + - 120, 10 + - 180, 60 + - 230, 15 + line_width: 8 + line_color: 0x0000FF + line_rounded: true .. _lvgl-widget-meter: ``meter`` -********* +--------- The meter widget can visualize data in very flexible ways. It can use arcs, needles, ticks, lines and/or labels. @@ -1006,50 +950,50 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need **Configuration variables:** - **scales** (**Required**, list): A list with (any number of) scales to be added to the meter. - - **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. 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*, :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**: :ref:`Color ` to draw the major ticks. Defaults to ``0`` (black). - - **label_gap**: Label distance from the ticks with text proportional 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-widget-line` and :ref:`lvgl-widget-label` 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: - **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**: :ref:`Color ` to draw the arc. Defaults to ``0`` (black). + - **end_value**: The value in the scale range to end drawing the arc to. - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). Defaults to ``0``. + - **start_value**: The value in the scale range to start drawing the arc from. + - **width**: Arc width in pixels. Defaults to ``4``. - Style options for the *arc* using the :ref:`lvgl-widget-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**: :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**: :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-widget-line` 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. - **image** (*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, representing a needle pointing to the right like ``-o--->``. - **pivot_x**: Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. - **pivot_y**: Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. + - **src**: The ID of an existing image configuration, representing a needle pointing to the right like ``-o--->``. - **value**: The value in the scale range to show at start. + - **line** (*Optional*): Add a needle line to the scale. By default, the length of the line is the same as the scale's radius: + - **color**: :ref:`Color ` for the needle line. Defaults to ``0`` (black). + - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. + - **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. + - **width**: Needle line width in pixels. Defaults to ``4``. + - Style options for the *needle line* using the :ref:`lvgl-widget-line` 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. + - **tick_style** (**Optional**): Add tick style modifications: + - **color_end**: :ref:`Color ` for the gradient end of the ticks. + - **color_start**: :ref:`Color ` for the gradient start of the ticks. + - **end_value**: The value in the scale range to modify the ticks to. + - **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``. + - **start_value**: The value in the scale range to modify the ticks from. + - **width**: Modifies the ``width`` of the tick lines. + - **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``. + - **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: + - **color** (*Optional*, :ref:`color `): Color to draw the ticks. Required if ``count`` is greater than ``0``. Defaults to ``0x808080``. + - **count** (**Required**): How many ticks to be on the scale. Defaults to ``12``. + - **length** (*Optional*): Tick line length in pixels. Required if ``count`` is greater than ``0``. Defaults to ``10``. + - **width** (*Optional*): Tick line width in pixels. Required if ``count`` is greater than ``0``. Defaults to ``2``. + - **major** (*Optional*, list): If you want major ticks and value labels displayed: + - **color**: :ref:`Color ` to draw the major ticks. Defaults to ``0`` (black). + - **label_gap**: Label distance from the ticks with text proportional to the values of the tick line. Defaults to ``4``. + - **length**: Tick line length in pixels or percentage. Defaults to ``15%``. + - **stride**: How many minor ticks to skip when adding major ticks. Defaults to ``3``. + - **width**: Tick line width in pixels. Defaults to ``5``. + - Style options from :ref:`lvgl-styling` for the tick *lines* and *labels* using the :ref:`lvgl-widget-line` and :ref:`lvgl-widget-label` text style properties. - Style options from :ref:`lvgl-styling` for the background of the meter, using the typical background properties. .. note:: @@ -1103,35 +1047,75 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need id: temperature_needle value: 3 +.. _lvgl-widget-msgbox: + +``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/lvgl/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). + +**Configuration variables:** + +- **msgboxes** (*Optional*, dict): A list of message boxes to use. This option has to be added to the top level of the LVGL component configuration. + - **body** (**Required**, dict): The content of the 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**, dict): A list of buttons to show at the bottom of the message box: + - **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display on the button. + - **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 message box. + +**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: Message box + body: + text: "This is a sample message box." + bg_color: 0x808080 + buttons: + - id: msgbox_apply + text: "Apply" + - id: msgbox_close + text: "\uF00D" + on_click: + then: + - lvgl.widget.hide: message_box + +.. tip:: -.. _lvgl-widget-image: + 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. -``image`` -********* +.. _lvgl-widget-obj: -Images are the basic widgets used to display images. +``obj`` +------- -.. figure:: /components/lvgl/images/lvgl_image.png - :align: center +The base object is just a simple, empty widget. By default, it's nothing more than a rounded rectangle: -**Configuration variables:** +.. figure:: /components/lvgl/images/lvgl_baseobj.png + :align: center -- **src** (**Required**, :ref:`image `): The ID of an existing image configuration. -- **offset_x** (*Optional*): Add a horrizontal offset to the image position. -- **offset_y** (*Optional*): Add a vertical offset to the image position. -- **scale** (*Optional*, 0.1-10): Zoom of the image. -- **angle** (*Optional*, 0-360): Rotation of the image. Defaults to ``0.0``. Needs ``pivot_x`` and ``pivot_y`` to be specified. -- **pivot_x** (*Optional*): Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. -- **pivot_y** (*Optional*): Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. -- **antialias** (*Optional*): The quality of the angle or scale transformation. When anti-aliasing is enabled, the transformations are higher quality but slower. Defaults to ``false``. -- **mode** (*Optional*): Either ``REAL`` or ``VIRTUAL``. With ``VIRTUAL``, when the image is scaled or rotated, the real coordinates of the image object are not changed. The larger content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations. With ``REAL``, if the width/height of the object is set to ``SIZE_CONTENT``, the object's size will be set to the scaled and rotated size. If an explicit size is set, the overflowing content will be cropped. Defaults to ``VIRTUAL``. -- 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. +You can use it as a parent container for other widgets. By default, it catches touches. -**Actions:** +**Configuration variables:** -- ``lvgl.image.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. Updating the ``src`` option changes the image at runtime. - - **id** (**Required**): The ID or a list of IDs of image widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. +- Style options from :ref:`lvgl-styling`. **Triggers:** @@ -1142,175 +1126,229 @@ Images are the basic widgets used to display images. .. code-block:: yaml # Example widget: - - image: - align: CENTER - src: cat_image - id: img_id - radius: 11 - clip_corner: true - - # Example action: - on_...: - then: - - lvgl.image.update: - id: img_id - src: cat_image_bowtie - -.. note:: - - 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. - -.. tip:: - - ``offset_x`` and ``offset_y`` can be useful when the widget size is set to be smaller than the image source size. A "running image" effect can be created by animating these values. + - obj: + x: 10 + y: 10 + width: 220 + height: 300 + widgets: + - ... -.. _lvgl-widget-animimg: +.. _lvgl-widget-roller: -``animimg`` -*********** +``roller`` +---------- -The animation image is similar to the normal ``image`` 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. +Roller allows you to simply select one option from a list by scrolling. -.. figure:: /components/lvgl/images/lvgl_animimg.gif +.. figure:: /components/lvgl/images/lvgl_roller.png :align: center **Configuration variables:** -- **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 (each frame is displayed for an equal amount of time). -- **repeat_count** (*Optional*, int16 or *forever*): The number of times playback should be repeated. 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. +- **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. +- **mode** (*Optional*, dict): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. +- **options** (**Required**, list): The list of available options in the roller. +- **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. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-widget-label` text style properties to change the appearance of the text in the selected area. +- **visible_row_count** (*Optional*, int8): The number of visible rows. +- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-widget-label` style properties. ``text_line_space`` adjusts the space between the options. **Actions:** -- ``lvgl.animimg.start`` :ref:`action ` starts the animation playback if it was displayed with ``auto_start`` false or after ``repeat_count`` expired. - - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want start. - -- ``lvgl.animimg.stop`` :ref:`action ` stops the animation playback. - - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want stop. - -- ``lvgl.animimg.update`` :ref:`action ` can be used to change ``repeat_count`` and ``duration``, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. ``src`` and ``auto_start`` cannot be updated at runtime. - - **id** (**Required**): The ID or a list of IDs of animimg widgets which you want update. +- ``lvgl.roller.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of roller widgets which you want update. - Widget styles or properties from the specific options above, which you want update. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the selected index in ``x``. **Example:** .. code-block:: yaml # Example widget: - - animimg: + - roller: align: CENTER - id: anim_id - src: [ cat_image, cat_image_bowtie ] - duration: 1000ms + id: roller_id + options: + - Violin + - Piano + - Bassoon + - Chello + - Drums - # Example actions: + # Example action: on_...: then: - - lvgl.animimg.update: - id: anim_id - repeat_count: 100 - duration: 300ms + - lvgl.roller.update: + id: roller_id + selected_index: 4 + # Example trigger: + - roller: + ... + on_value: + - logger.log: + format: "Selected index is: %d" + args: [ x ] -.. _lvgl-widget-line: +The ``roller`` can be also integrated as :doc:`Select ` component. -``line`` -******** +.. _lvgl-widget-slider: -The line widget is capable of drawing straight lines between a set of points. +``slider`` +---------- -.. figure:: /components/lvgl/images/lvgl_line.png +The slider widget looks like a bar supplemented with a knob. The user can drag the knob to set a value. Just like bar, slider can be vertical or horizontal. The size of the indicator foreground and the knob position is set according to the current ``value`` of the slider. + +.. figure:: /components/lvgl/images/lvgl_slider.png :align: center **Configuration variables:** -- **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 `): Color for the line. -- Style options from :ref:`lvgl-styling`, all the typical background properties and line style properties. +- **anim_time** (*Optional*, :ref:`Time `): Sets the animation time if the value is set with ``animated: true``. +- **animated** (*Optional*, boolean): Animate the indicator when the bar changes value. Defaults to ``true``. +- **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 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) is 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. +- **max_value** (*Optional*, int8): Maximum value of the indicator. Defaults to ``100``. +- **min_value** (*Optional*, int8): Minimum value of the indicator. Defaults to ``0``. +- **value** (**Required**, int8): Actual value of the indicator at start, in ``0``-``100`` range. Defaults to ``0``. +- 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. -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. +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. + +**Actions:** + +- ``lvgl.slider.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of slider widgets which you want update. + - Widget styles or properties from the specific options above, which you want update. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. The new value is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which 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 + - slider: + x: 10 + y: 10 + width: 220 + id: slider_id + value: 75 + min_value: 0 + max_value: 100 -.. _lvgl-widget-led: + # Example action: + on_...: + then: + - lvgl.slider.update: + id: slider_id + knob: + bg_color: 0x00FF00 + value: 55 -``led`` -******* + # Example trigger: + - slider: + ... + on_value: + - logger.log: + format: "Slider value is: %.0f" + args: [ 'x' ] -The LED widgets are either circular or rectangular widgets whose brightness can be adjusted. As their brightness decreases, the colors become darker. +.. note:: -.. figure:: /components/lvgl/images/lvgl_led.png + The ``on_value`` trigger is sent as the slider is dragged or changed with keys. The event is sent *continuously* while the slider is being dragged; this generally has a negative effect on performance. To mitigate this, consider using a :ref:`universal interaction trigger ` like ``on_release``, to get the ``x`` variable once after the interaction has completed. + +The ``slider`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. + +.. _lvgl-widget-spinbox: + +``spinbox`` +----------- + +The spinbox contains a numeric value (as text) which can be increased or decreased through actions. You can, for example, use buttons labeled with plus and minus to call actions which increase or decrease the value as required. + +.. figure:: /components/lvgl/images/lvgl_spinbox.png :align: center **Configuration variables:** -- **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. +- **anim_time** (*Optional*, :ref:`Time `): Sets the cursor's blink time. +- **decimal_places** (*Optional*, 0..6): The number of digits after the decimal point. If ``0``, no decimal point is displayed. Defaults to ``0``. +- **digits** (*Optional*, 1..10): The number of digits (excluding the decimal separator and the sign characters). Defaults to ``4``. +- **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``. +- **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``. +- **step** (*Optional*, float): The granularity with which the value can be set. Defaults to ``1.0``. +- **value** (**Required**, float): Actual value to be shown by the spinbox at start. + +.. note:: + + The sign character will only be shown if the set range contains negatives. **Actions:** -- ``lvgl.led.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of led widgets which you want update. +- ``lvgl.spinbox.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. + - **id** (**Required**): The ID or a list of IDs of spinbox widgets which you want update. - Widget styles or properties from the specific options above, which you want update. +- ``lvgl.spinbox.increment`` :ref:`action ` increases the value by one ``step`` configured above. + - **id** (**Required**): The ID of the spinbox widget which you want to increment. + +- ``lvgl.spinbox.decrement`` :ref:`action ` decreases the value by one ``step`` configured above. + - **id** (**Required**): The ID of the spinbox widget which you want to decrement. + **Triggers:** -- :ref:`interaction ` LVGL event 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``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** .. code-block:: yaml # Example widget: - - led: - id: led_id - align: CENTER - color: 0xFF0000 - brightness: 70% + - spinbox: + id: spinbox_id + text_align: center + range_from: -10 + range_to: 40 + step: 0.5 + digits: 3 + decimal_places: 1 - # Example action: + # Example actions: + on_...: + then: + - lvgl.spinbox.decrement: spinbox_id on_...: then: - - lvgl.led.update: - id: led_id - color: 0x00FF00 - -The ``led`` can be also integrated as :doc:`Light ` component. - -.. note:: + - lvgl.spinbox.update: + id: spinbox_id + value: 25.5 - If configured as a light component, ``color`` and ``brightness`` are overridden by the light at startup, according to its ``restore_mode`` setting. + # Example trigger: + - spinbox: + ... + on_value: + then: + - logger.log: + format: "Spinbox value is %f" + args: [ x ] +The ``spinbox`` can be also integrated as :doc:`Number ` or :doc:`Sensor ` component. .. _lvgl-widget-spinner: ``spinner`` -*********** +----------- The Spinner widget is a spinning arc over a ring. @@ -1319,13 +1357,13 @@ The Spinner widget is a spinning arc over a ring. **Configuration variables:** -- **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*, :ref:`opacity `): Opacity of the arc. - **arc_color** (*Optional*, :ref:`color `): Color to draw the arcs. +- **arc_length** (**Required**, 0-360): Length of the spinning arc in degrees. +- **arc_opa** (*Optional*, :ref:`opacity `): Opacity of 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. - **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. +- **spin_time** (**Required**, :ref:`Time `): Duration of one cycle of the spin. **Actions:** @@ -1357,43 +1395,52 @@ The Spinner widget is a spinning arc over a ring. id: spinner_id arc_color: 0x31de70 -.. _lvgl-widget-obj: +.. _lvgl-widget-switch: -``obj`` -******* +``switch`` +---------- -The base object is just a simple, empty widget. By default, it's nothing more than a rounded rectangle: +The switch looks like a little slider and can be used to turn something on and off. -.. figure:: /components/lvgl/images/lvgl_baseobj.png +.. figure:: /components/lvgl/images/lvgl_switch.png :align: center -You can use it as a parent container for other widgets. By default, it catches touches. - **Configuration variables:** +- **indicator** (*Optional*, list): Settings for the indicator *part*, the foreground area underneath the knob shown when the switch is in ``checked`` state. 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. - Style options from :ref:`lvgl-styling`. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** .. code-block:: yaml # Example widget: - - obj: + - switch: x: 10 y: 10 - width: 220 - height: 300 - widgets: - - ... + id: switch_id + + # Example trigger: + - switch: + ... + on_value: + then: + - logger.log: + format: "Switch state: %d" + args: [ x ] + +The ``switch`` can be also integrated as a :doc:`Switch ` component. .. _lvgl-widget-tabview: ``tabview`` -*********** +----------- The tab view object can be used to organize content in tabs. The tab buttons are internally generated with a :ref:`lvgl-widget-buttonmatrix`. @@ -1466,10 +1513,76 @@ The tabs are indexed (zero-based) in the order they appear in the configuration then: - logger.log: "Dog tab is now showing" +.. _lvgl-widget-textarea: + +``textarea`` +------------ + +The textarea is an extended label widget which displays a cursor and allows the user to input text. Long lines are wrapped and when the text becomes long enough the text area can be scrolled. It supports one line mode and password mode, where typed characters are replaced visually with bullets or asterisks. + +.. figure:: /components/lvgl/images/lvgl_textarea.png + :align: center + +**Configuration variables:** + +- **accepted_chars** (*Optional*, string): You can set a list of accepted characters, so other characters will be ignored. +- **max_length** (*Optional*, int): Limit the maximum number of characters to this value. +- **one_line** (*Optional*, boolean): The text area can be limited to only allow a single line of text. In this case the height will set automatically to fit only one line, line break characters will be ignored, and word wrap will be disabled. +- **password_mode** (*Optional*, boolean): The text area supports password mode. By default, if the ``•`` (bullet, ``0x2022``) glyph exists in the font, the entered characters are converted to it after some time or when a new character is entered. If ``•`` is missing from the font, ``*`` (asterisk) will be used. +- **placeholder_text** (*Optional*, string): A placeholder text can be specified, which is displayed when the Text area is empty. +- any :ref:`Styling ` and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. + +**Actions:** + +- ``lvgl.textarea.update`` :ref:`action ` updates the widget's ``text`` property, to replace the entire text content. + - **id** (**Required**): The ID or a list of IDs of textarea widgets which you want update. + - **text** (**Required**): The new text content to be displayed. + +**Triggers:** + +- ``on_value`` :ref:`trigger ` is activated on every keystroke. +- ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). +- :ref:`interaction ` LVGL event triggers. + +For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. + +**Example:** + +.. code-block:: yaml + + # Example widget: + - textarea: + id: textarea_id + one_line: true + placeholder_text: "Enter text here" + + # Example action: + on_...: + then: + - lvgl.textarea.update: + id: textarea_id + text: "Hello World!" + + # Example trigger: + - textarea: + ... + on_value: + then: + - logger.log: + format: "Textarea changed to: %s" + args: [ text.c_str() ] + on_ready: + then: + - logger.log: + format: "Textarea ready: %s" + args: [ text.c_str() ] + +The ``textarea`` can be also integrated as :doc:`Text ` or :doc:`Text Sensor ` component. + .. _lvgl-widget-tileview: ``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. @@ -1478,20 +1591,20 @@ If the Tile view is screen sized, the user interface resembles what you may have **Configuration variables:** - **tiles** (**Required**, list): A list with (any number of) tiles to be added to tileview. - - **id** (*Optional*): A tile ID to be used with the ``lvgl.tileview.select`` action. - - **row** (**Required**): Horizontal position of the tile in the tileview grid. - **column** (**Required**): Vertical position of the tile in the tileview grid. + - **row** (**Required**): Horizontal position of the tile in the tileview grid. - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. + - **id** (*Optional*): A tile ID to be used with the ``lvgl.tileview.select`` action. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the tile, as children. **Actions:** - ``lvgl.tileview.select`` :ref:`action ` jumps the ``tileview`` to the desired tile: + - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. + - **column** (*Optional*): Vertical 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``. - **id** (**Required**): The ID of the tileview which receives this action. - **tile_id** (*Optional*): The ID of the tile (from within the tileview) to which to jump. Required if not specifying ``row`` and ``column``. - - **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``. **Triggers:** @@ -1534,138 +1647,21 @@ If the Tile view is screen sized, the user interface resembles what you may have then: - logger.log: "Cat tile is now showing" -.. _lvgl-widget-msgbox: - -``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/lvgl/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). - -**Configuration variables:** - -- **msgboxes** (*Optional*, dict): 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 message box. - - **body** (**Required**, dict): The content of the 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**, dict): A list of buttons to show at the bottom of the message box: - - **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display on the button. - -**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: Message box - body: - text: "This is a sample message box." - bg_color: 0x808080 - buttons: - - id: msgbox_apply - text: "Apply" - - id: msgbox_close - text: "\uF00D" - on_click: - then: - - lvgl.widget.hide: message_box - -.. 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. - -.. _lvgl-widget-keyboard: - -``keyboard`` -************ - -The keyboard widget is a special Button matrix with predefined keymaps and other features to show an on-screen keyboard usable to type text into a :ref:`lvgl-widget-textarea`. - -.. figure:: /components/lvgl/images/lvgl_keyboard.png - :align: center - -For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-widget-buttonmatrix`. - -**Configuration variables:** - -- **textarea** (*Optional*): The ID of the ``textarea`` from which to receive the keystrokes. -- **mode** (*Optional*, dict): Keyboard layout to use. Each ``TEXT_`` layout contains a button to allow the user to iterate through the ``TEXT_`` layouts. - - ``TEXT_LOWER``: Display lower case letters (default). - - ``TEXT_UPPER``: Display upper case letters. - - ``TEXT_SPECIAL``: Display special characters. - - ``NUMBER``: Display numbers, +/- sign, and decimal dot. - -**Actions:** - -- ``lvgl.keyboard.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - - **id** (**Required**): The ID or a list of IDs of keyboard widgets which you want update. - - Widget styles or properties from the specific options above, which you want update. - -**Triggers:** - -- ``on_ready`` :ref:`trigger ` is activated when the checkmark key is pressed. -- ``on_cancel`` :ref:`trigger ` is activated when the key containing the keyboard icon is pressed. - -**Example:** - -.. code-block:: yaml - - # Example widget: - - keyboard: - id: keyboard_id - textarea: textarea_1 - mode: TEXT_UPPER - - # Example actions: - on_focus: - then: - - lvgl.keyboard.update: - id: keyboard_id - mode: number - textarea: textarea_2 - - # Example trigger: - - keyboard: - ... - on_ready: - then: - - logger.log: Keyboard is ready - on_cancel: - then: - - logger.log: Keyboard cancelled - -.. tip:: - - The Keyboard widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. - -.. note:: +.. _lvgl-automations: - The Keyboard widget in ESPHome doesn't support popovers or custom layouts. +Automations +----------- .. _lvgl-automation-actions: Actions -------- +******* As outlined in the sections above, each widget type supports several of its own, unique actions. Several universal actions are also available for all widgets, these are outlined below. ``lvgl.widget.update`` -********************** +^^^^^^^^^^^^^^^^^^^^^^ This powerful :ref:`action ` allows changing/updating any widget's common :ref:`style property `, state (templatable) or :ref:`flag ` on the fly. @@ -1694,7 +1690,7 @@ This powerful :ref:`action ` allows changing/updating any widget .. _lvgl-automation-shorthands: ``lvgl.widget.hide``, ``lvgl.widget.show`` -****************************************** +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ These :ref:`actions ` are shorthands for toggling the ``hidden`` :ref:`flag ` of any widget. @@ -1713,7 +1709,7 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` - id: [my_button_1, my_button_2] ``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): @@ -1736,7 +1732,7 @@ These :ref:`actions ` are shorthands for toggling the ``disabled .. _lvgl-automation-triggers: Triggers --------- +******** Specific triggers like ``on_value`` are available for certain widgets; they are described above in their respective section. Some universal triggers are also available for all of the widgets: From de2903cae0b3c976530751c4174a59e371fcf708 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Sun, 11 Aug 2024 11:32:55 +1000 Subject: [PATCH 556/564] Add note about default group. --- components/lvgl/widgets.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index c18670f459..1a6b4f6bc4 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -52,7 +52,7 @@ The properties below are common to all widgets. .. figure:: /components/lvgl/images/lvgl_align.png :align: center -- **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. +- **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. If no group is specified for a widget or an encoder, an unnamed default group will be assigned, so in most cases where only one encoder is used it will not be necessary to explicitly specify a group. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - **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 5b33dc69b8bc5f5377a608ab791fbf3fca5344bc Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:25:33 +0000 Subject: [PATCH 557/564] Remove duplicate image files --- components/images/lvgl_align.png | Bin 15911 -> 0 bytes components/images/lvgl_animimg.gif | Bin 7025 -> 0 bytes components/images/lvgl_arc.png | Bin 2738 -> 0 bytes components/images/lvgl_bar.png | Bin 374 -> 0 bytes components/images/lvgl_baseobj.png | Bin 730 -> 0 bytes components/images/lvgl_boxmodel.png | Bin 9051 -> 0 bytes components/images/lvgl_button.png | Bin 1062 -> 0 bytes components/images/lvgl_buttonmatrix.png | Bin 2739 -> 0 bytes components/images/lvgl_checkbox.png | Bin 1420 -> 0 bytes components/images/lvgl_dropdown.png | Bin 2959 -> 0 bytes components/images/lvgl_image.png | Bin 10371 -> 0 bytes components/images/lvgl_keyboard.png | Bin 8996 -> 0 bytes components/images/lvgl_label.png | Bin 1123 -> 0 bytes components/images/lvgl_led.png | Bin 1123 -> 0 bytes components/images/lvgl_line.png | Bin 1775 -> 0 bytes components/images/lvgl_main_screenshot.png | Bin 134021 -> 0 bytes components/images/lvgl_meter.png | Bin 7065 -> 0 bytes components/images/lvgl_msgbox.png | Bin 4971 -> 0 bytes components/images/lvgl_roller.png | Bin 2677 -> 0 bytes components/images/lvgl_slider.png | Bin 521 -> 0 bytes components/images/lvgl_spinbox.png | Bin 799 -> 0 bytes components/images/lvgl_spinner.gif | Bin 36060 -> 0 bytes components/images/lvgl_switch.png | Bin 737 -> 0 bytes components/images/lvgl_symbols.png | Bin 30832 -> 0 bytes components/images/lvgl_tabview.png | Bin 7993 -> 0 bytes components/images/lvgl_textarea.png | Bin 4749 -> 0 bytes 26 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 components/images/lvgl_align.png delete mode 100644 components/images/lvgl_animimg.gif delete mode 100644 components/images/lvgl_arc.png delete mode 100644 components/images/lvgl_bar.png delete mode 100644 components/images/lvgl_baseobj.png delete mode 100644 components/images/lvgl_boxmodel.png delete mode 100644 components/images/lvgl_button.png delete mode 100644 components/images/lvgl_buttonmatrix.png delete mode 100644 components/images/lvgl_checkbox.png delete mode 100644 components/images/lvgl_dropdown.png delete mode 100644 components/images/lvgl_image.png delete mode 100644 components/images/lvgl_keyboard.png delete mode 100644 components/images/lvgl_label.png delete mode 100644 components/images/lvgl_led.png delete mode 100644 components/images/lvgl_line.png delete mode 100644 components/images/lvgl_main_screenshot.png delete mode 100644 components/images/lvgl_meter.png delete mode 100644 components/images/lvgl_msgbox.png delete mode 100644 components/images/lvgl_roller.png delete mode 100644 components/images/lvgl_slider.png delete mode 100644 components/images/lvgl_spinbox.png delete mode 100644 components/images/lvgl_spinner.gif delete mode 100644 components/images/lvgl_switch.png delete mode 100644 components/images/lvgl_symbols.png delete mode 100644 components/images/lvgl_tabview.png delete mode 100644 components/images/lvgl_textarea.png diff --git a/components/images/lvgl_align.png b/components/images/lvgl_align.png deleted file mode 100644 index e7a1381ca6e132dea3ac5302df356af8131d754e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15911 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 diff --git a/components/images/lvgl_animimg.gif b/components/images/lvgl_animimg.gif deleted file mode 100644 index 9f6bce8bee17d7b8d415e4436d93d16152327b82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7025 zcmb`M2U8PDxUkbm4buQfgm^t zi~vDUATS0Dk^zHo5RfbsC=UZEz(I-#kP;HCgoG%eU`iEso90uO=6x~UyFT5!DZ{%Z)4SuecL&?IolS3J2eh(-TG_#^tkC~qcLO`@B4>XM zC$b_drYt9co6D@sKg=(PZ7YoKDr5)>8CMI#`igcB6b20z?!1=oFH+yY02(7#c6h&^(17e zzJH&DLFcpB?^>#zlinxDTHeC&FRR$tjv~|h4|_Pt&E!|;G#LP z8W8|7&}xBJVA#U-pEZ$tU_K7TA0cGr>K@t9grW@ungAq3w3UVo1R@X~Z&sk0BQFb= zQGmR3F<3+B&by-$@^j9fABL@w26(c0NLLNdy@6#W1!CZLDt|&Zu}$oz6d4`i=f2ax z;Q2nQBXLi(6E=l&O#}4RDH(h)B@5}Bt9`0`c{_3^cUypi~a! z2dLk)%=~hpdh+k= zV$x2tBE?aT0y#QI6Y2^v!HUt;X&SZ|kZl}C#cpOrIulX@3u|YN;&ND6UBQOtuda7a z3DZ)hN7$tIeUcpVGFbD6B$vc{R+K{l>m-DZ(Z=gh5pfE-#0b*k672&wOR{mDVBq~K z1_+xbN?nE)?D@t?3>jWUedi;c@I9D)f<>kK*irRwEOg8|O>GsMYYo@NVt>q=Sa$2Y zd@J(1drkU5e^ge$T0>4LH=7tOo>l6hDP&BCtM!sSO%{_d@zWeMi=I!C_?L3>!TL3g zh*ux-Ww|V%h77@>Z$1y`wjyQfUxEy3Tb1cxMHq#4!<>9R7Kih)cJu*qX>DvcnZQx$ zWk5}TF%`<-5Pjut_(S7X#oSG6O^xOqHs{P%;4^bA+Xt1$9G11vYnEV~NRn&)jfx64 z$X3cGfGzTY=+o;UyoihlO)xx=%NkEI@GCN=h?4LkO}Ok!Gk9pd(y#%+=qlXV{##G3 z%lfGLDmgDGTa1b%(6FhJIa((b9iBa=>u-h#@M)9Rzm%iNV&1K9-|1N~hJ^|QMPa?N zic4!T8ml5`Q7RRl$dJ-_FUTXawBY?{ka9i+YLXwZCz&oqd}?8(*wTPF zzUB^$9Akz!)M1_4d7S4=SUouB*gM*tD&Z()VDqfvsFz*fCio$4htp?q+Pj&S9ft+# zmu`CzWUMz?5zek0(l}S)>|s}WfbEnq?LQM6Cr$m-IWZ zzLXiv5#kLE@_l{it6$KZF95=jjA<}`h6X2e%VfeKnhZZHdr?Dqst~O4i{4FuXkpJ{ zv+>!KJ>xa)CaNQc~K@AO7e43DB95Y`Owx%`O z!yA{$B;27S9K+;L3{GQgJYOU0oBz^Icwy|$A)~+cqzgMWe=x#?xzBP^SQEynTE+Xb z%e%`2FElr?P_xd6QV!gCr_{5&WvvBhC@M^SVCnIjX@d07{T7XnT$tT23e;g8xQWSN z!6t5N<0s(I(B1RMa~cDYhP1@krHu#7A0co{p^C;)m&G^sD{;w$D^cn-d8BWmN~aBW zQ^<#+edy=-5x^m%2Xlp#;vke`w6kid5u8dnMt4|bn~&&OCmaqj-=;^E*$}MvMOxKH zP&jgD$*b0IXZ(bqu!tkNQ-QkJC7qBPkzk6HsUANrHq5A`@@&D;bf10t0O2`Io zf^gdVvcJlTQlc$Ctmd_Cf31{PPcy>dkxlBT;aad!6qhGs~RGidga1Y-ZN0#JRF9KnvaE|&AH)p@vbNm?3 zb^52E$nP^BMWu^T9sqXTA+e1A?RJyH(^*RBAGRGQhf$g2JUjc;`F}9))n;q+Y~p~j zsZ(~{Kgo#w#vpk3I_Ls%rPW3d(Jd2hkIR;T8yy@!J~Z>k5>1cfTlCA6$hYdRL?4fW zgB9Be4x|+ZAx5hxs8_4k-{) z&{4lYi{pUFf4+39URS$G8@Yc4uS`}gpGmd zp+@LvT-xy|Mus9Dy)cD58vyI1phpGB!K+9C3z@hg71k={zyLc6PH8eVfeiHyXF2m{ zAS{>$*60Ww-+;ga$#mEW5$hx$mLkdK#d-I_z+?e%+eCsK z-~VV7*qRB6qagbw#r+amzXTkr#kWC?oHVXWP z{3gV&%`ZbA68iv%r+{GQIU%9AWm$q7x1@QccyMF;s35<{z;1+z%AmuN2?!y@?zJqc zhk@#&BjQ(r!(IhD=|PSQfvO+FWe3B_6c9qk-j)TK3q@{NpSvN-A0gY#Ttz*`!zn%X zLOyDci|UtH)&LNCFReGF;+-}?oe#rr_J*5DK+_)JQyySh{8hYV1{x<#ivt{daxDQxZD|J#jmIllzaf5v&lm7!9m4X zc9aw5ZNPGFJHk zuh~YaYlgx)MxozF;WZMf`Z#>P2VO%*7&>1}sRt8Rv`$-C{u*SOcLPnkfqe&|%ZPKr z_QG^m;C#8cVcw1Mma$H6OW!BKhuR>|z^AVICcUOGhGR8|YqjTmUa{ zkL_7H!dJ)Ej#!<`fQB-_>f&wRaZLp_shi#)pd}wXMgzHRJrx

YrQaDu@zRonb)p zZHqcwN8O2Zc!&tRoe#DKR9GoBW%q|?Ml@J4jH)?cDhrAu*6)gMEVXSVUdX8!jAY>ghlg=WEz{k1~ZwmMbudX+xb_*$XPxK-#@UQ0a!Tqvr*cA|-k-T8jnN|;u zlOSpd^&3b6 zMbwROkoSrMCe3@T&|@Q__&Cu&dqLVha02ETAV@|A02uLt>)NzYxNJ9`r&E@f~EZRt9^X>M5#e z-CWVRj<6lNcI_fVibNJ#wSs&$w70GgoB%*%K%%+uzY9=<8^g&bNb^67w?|!H3`Ow+ zNGWC4uGPS808MP$8%x`<%Nv)9s!N0$+k52(q48DW_lrkLX@_55_%qi3&!MBsO9%(m zPN4mb=Ox&Od@#2c%2^rq+I^7Rhx%k~m@!k?hSmIQu;v`9x^}Kd)n4dB5JiPxpE5DQ zqPEjyL^B^X!m<`&D-$1~%06BQRz7!|XTeh*G_S23V%A<{LQI*OtCz-J6k#3E$hZ}~ zlg+53%4m;*@nO+uKVk6D+Z(*^lg!$xIUQsJ3+h-6dG0+FUW;{ji{h_9cCu>6IQG-o zVbi%8)7j|hf>l(bmi#gkGlxa;$usA}W-2mfc(pT?YREYzX2MAR=L+Ur2Bs-&wk2b> zt#-B}V|H0E#s4)cP@99{u>UDFpgrIZz!>lFfJrIArSJ$T zWh7J?1yx1E)G%-j8H5%NsUwThlSgk;z!>ADP1UgGnzEK!a+cci7TOBtI!dOxD#p6% zL|uZRp0=UBj-kGu;Wm9kgKY+eh6aX210vCoXtV{9Xk=t$Y+^#%3e&A1o07?Z z*5206-qzm1&cVUX(b1mb=sEv>Ds zZEbDs?d=^M9hWX$>g??7>gu|D`SO)3R|EnS9^PV`}+F&`}+q5282T4 z;NalU(AH7BHat9h{rdGAH*SbWhQ~$MCdAh!Mz2qdiN?prCnhE)Cnu+-rlzN-XJ%$* zXJ_Z;=5F5HQfIer-@bk4&K-$FGCx0m_wL;-d$zE!aR2`O2M-=ReE4v2aq-ckM~@#r zURqjOUS59kgPyhPsua%XRXV0FkuC6|R{(Q@`y?F8B<;$0^UcFjhUw{4j_1}O0 z{pQV^w{PFRd-v}B`}bQGZewHP!-o$aKYsl5>C@-Wpa1>$-z_iq_3PJf-@bkS{(Vc( z{rvfJ%hCP*{d-HSncp(sQfhw?YVgSal$wmbM;e_?$wTWX{u*FV$BXcqG0W3tTH|L4 zhSENQjg>4eK{+ge)6+c1ChjMm|9@OvA_nn~#oI5d5_XBspRsWX3d1fki&0*W zBQ#|NLr9iCk9kcQx9Vh02pZYsRw2`ZuvX3-a>p zdhHdl*(7Z9%Z%{JPwI7;6hh6E?0r0I*G+e{yr0GKtV>e+o_H+npgH`h{ctA=loBCP zP-QF4$AV5t1s#O}7yUBuz%Qz_$}T;u3huSMsz*#%+Wav;>NlBFXq&vnow;#eWmT0= zrO}z_oES+k2v@Pk#YpAzKH3X}ZX;#n(bqtl?4~o!&2uxrHDTqMl)oZQcUj z7kSpMrDB^GM@4?Q`e|Z5R_d@@oJ0v1@k8UR-vQl&9spV)wgUd7ssv9(LT);VMS9rE z%^jNoFDOk&z5On7)8qUikjW4KM#TNcPde?NetF(z$r}ua0`=i=Dv`{zw_V`fEL>X9 zS|v9Hlt}zb4f^|a2c>_xrOUrZIS{6yWx`o?dbMfMMfs$CUQ8{QZhA@)|GG+a`(rM@ z%?)5c(Y~QPBRem2xcgHU-*95b8g)=Q`=$E>w}m(nM|vB5?9`8Mbvzu-yOwIQ2{xvc zB%ZuDOuDb)CyE=)m}>r$!TZ~1;N>fGw^mQSRtQGb#Y1aB1M+0{Ddv_$h^|VLivdp@ z;o{kaNiX? zBk%(RW6Jem(j1;3CQCKB-U?gp&!QzXEh?WXg&C^h+bP6;il?HrCJw_D%D)O+ zX@8gV7C-TqnOKiH+WBE<@HtL^9%gWVusxdowt%PY2{AxICe00B~!-3 zxI6ouP8%rgi#`_AWU8Ah5X0TLY-kJtgloI_r)41f+pVK8I|@kla;)&0?iveJfLMDF z1C}F8*qCFK-_!0+a5n+_y{cGF__+p>fw4G}SOhwpM}w6fmAa?H6rud!;|8@?bdD2m zYd;>~Ab!XoK3j;tU4G>#!xtoJ@Ms@N{^i-jF@z#k-Me(M6X7lc**W(FO;|p{~81 z2~+JH#OZamLB5GjlFhWJ@LtUVI|A2sEJ$lQ2JXtDvdwzMI(y1`T|<)&A$GgybTG0M z7FW(6{F%2vDxGz+U)?sAP;gT*mAi|iT?Ky@PR7V~pOKhpZT*aCZ7TRiL?0j=KX@#T T5D=Ag;J}f!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 diff --git a/components/images/lvgl_baseobj.png b/components/images/lvgl_baseobj.png deleted file mode 100644 index 5fe7294ce66f7e61a72fe4a3f18a876e81800fc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/components/images/lvgl_boxmodel.png b/components/images/lvgl_boxmodel.png deleted file mode 100644 index 98251f41698f40b98077c1fdb5907c6e0a83eb10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9051 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 AumAu6 diff --git a/components/images/lvgl_button.png b/components/images/lvgl_button.png deleted file mode 100644 index c80d07f2d16b54fcc0b841b1e9d703cec2db3ecf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1062 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 Q4Wj@X%hRYTq|fz#16OP$v;Y7A diff --git a/components/images/lvgl_checkbox.png b/components/images/lvgl_checkbox.png deleted file mode 100644 index 31b63cc7f5eeecdcfb2f5b39df9a530a6e7496b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1420 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 diff --git a/components/images/lvgl_keyboard.png b/components/images/lvgl_keyboard.png deleted file mode 100644 index a9b009d310b9e2617b9205df246dae67333a710a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8996 zcmbW7Wmr_-7w-=sEg>Nw4bmbYjf8-dbf=^sC9UMp;edc3-7PSrfPlmx;m};wB#RNIrAHG{S?MHp{e{c9&tc@A7>(W={62L z9fd#q|9{xW^;ccUzQLr@fRK*vcRJ$lk&mR^+$nnZkZ5ilnE?c|-Uxh?;}>v>P&eb( zCSq7%SL;b0phGRkS&G!$Ea1Xij0nH}jc8lC!!47pxgw*h3^Q=DxUtW{WXMH$zUs=? z-OeAqHPw9^Wil3K8KM5e$(mGBViTcHOJ5;VNdH+Q-+NFqktEV3FKXflQ}~j%dZgZ@ zayn-pLkg&DGk{I$oayi|waT27kFa^!;Qb`X^cw3H^YI#m@`$>#l{qk+kgtce(|+&V z@(Fo#JAHh!JT*R;a#K0|bBs3@Q?8g*y_+m6esVW)MIMsSHj z%c~l{(6i95YpgRhH622+3o9xF(GtZ+6|=8S)HYO4Uy|LeZjo=@;Y5WAP6+lDKfcwS zrR=2Y3}tHdG@sU5bu2n=Wx2@pAB>2U?~fEx!^Fbyi%yvvf5xox4fO&)G|%>#xPZ8X z2siSbv-CqT`p@kSqWOwtvt~~`gjr;Wo1cqsHI+%Qqgb{jDKq1_B=v*^{s`kK?Y=v# z?+WUAD>KshQHSjrJ#?t=HWiU9GF&~v#MZFnMv4~l-8FVotCg@C!_}s6U2N}5y<86z z^btwBVNoJ34|h_60KnrEvUwbiJ4FfE&kLgj9B-j~zhHc@$V^)o+tL#~L>op*7_#&7 z^^dUH_V2?|lH;baeyseY0DuL!=p&DnR(=);(8n4>4WFV)9^yuEvZTxi}Xc~fcZxbEBO$RIv@`je-;$86HINux*x zmqDp@0GPKSMwiv0`YV$=QK7d=@1&7Q8{IBHlf~*@dr}B0sqLIo-4W%QtL!}X27ng# zN!*4e4~+T;JLG6+prn!GWI4%||J8M--@Zni|6rSDyNrtFj{_{g@@npz7cmYF=2(1z z$b#FRi{qJXvZTCX39EUo;gQ7_7La#tGeqPXytdSMc>Ady=}klTFDkmfMs0YmpWMIg zaH-L}&*hbUAygOf=MZhinWk zBdI=i8OtJKR))b{r0v}!!z2CKdiNNYIqGqq=*XL}uQI7ze!P^Etjib^2%)`!1Ok9> zMmSvVYx1bu$DF(`1AVs(k^s}0gCjV78ibcy_v417XTQM+P!r~~@<>G&echZj+eN;; zqX!Px=2EZxeXknK;wTLFL$32^I(>|bw;CtdVZ8{V?jW*TU2_Trg^wTRZ~;J;v}UYZ zC-hbvDxKlG6PZcnvrR{t8KZA*P;@u_!O=|)U#5n(B9liUB^23z-7<&$MM6_QN5Av0 z)jqSKuK`p|=~?5mpyfIVy%54GZ8zo6gx!DJoBJhp zA+j7_N}+3QVH?IB9EP+Q#YKk*agKyXZ`@@Pjn{>+Yw`)g}aYbbC`b%KMc%C&q+_uNmwtFiV?hO zYe0r#owuRdLP9VqhcLr1mSg)Nl*>vORj&2qkBEIC=2hKCY&kgv7(R`hBX@k7cl}Js zy)#I4V!9$#IZg^pU={sY(8e}-HbBjX_0y+My{?vyvX{^{l+=~z5US)(>hGT?>tkCP zA+kfn5z0zW0+?^5uiE?mwqCX<6q8_uB-8S&v~%vq@Q50$4g^y_|5!lXOa~q6S$flG z+P!Y0nIp|5!$Y-C75;kQ!my<`CY6t+?tzuk$3exVjTOb(CT*cs@tOCdNQ;Qa)f~%{ z<{4kr#=qoy=9?L?@kS!Lz?6CuoLr6N##Xgh+BIKEAf=F+o6`9G`;u)g6Q1KIZWjuk z5uV6C!?&o{F<{>4b!7p9S3RD&NsKmM?e_M5?DOB3XO;gG^g9I|z7e_YMoZ(9uDzFW zh>K&$wDr+gV)8Uf2zb%{QqaTY9>7!ykI$klOZBtGL*AO!nT8>{M8&lsqzdkdIYnRX zVJC*Tkk9hOiC{{YeL$MK>P~-oY4Aow$Japnw))aK3-arO74(;o!SM}Oa&hiyY`u^A zC%$g*r2!pgc5#v>6W?zJv(>DbnOh%#;eSXT03DehE^;mUGf_&RavJ63C9-|yTb%zC z#UtS>MI%X@R8cQsK2N^JiY>^@_L|His5e3`KYfcP95I*0CPEcfXW|$AFp%sU%-ApV z!)<5Xw;zc{%Fb^Zt08O11je=e++7a5N!xi}R4Guv+9}>~d6Jo%j|T`=EKGo>8s1i$ zRN}zHVG~cS1m0%${5>jNWOosIba?vkLZRm%Y5(L^Uq-q$9%DjVGVeSe0EE5`OMgyt zRbMNm+f^?uE%Fp1uQ}GYqcX(|w+_&5vIr)UU42JGtg^)Id;8aCO`)dCsfwZCgN_cC}39i6#kO7SstpDWsK%5ddOl9)e;$_L~!6@)7BkS|_a* zaQ!E42>fh9eG7vKdW?FRuY|#;YojAkW^OpvT$kF5uFqnA-Kdj&A^(C7I=7&h0+@e3Cs>KySOgK2NWWxp^Q>+ z8~!#m1PG}Uu)OM#fAqR;v{Z^NhfYg01bfn{`AxuxGsJ}5e_g{k20=z#I-}v0$b&n6 zG{vlJa~RJw7k61{rIxn`V}7;2<@=~0vKRObjW*3Wlb!|ZC(kn~b{O6SuL z1$MDg9;+Cgzg|(+WE3uIFW1meOMFa2N32+-_*h>5OYhW2Jt}E2x=%xhRU(H5md4P{ zM$EQov)Fr4VUJb7lRHf^CCp{DIqm2BXQ z3$^-vQI$Oel=YH;1Bpc{ziG^c+JqR_C#bP9cTi$|oYPh0Tan^FL(* zsWc~HCO1Z?sfTA*bh++MPU>q1YgkwzD~e-kSBlyc>8ffgCM*{U8uR29l0mf>Gg1)p zvhvC%j)$VrgKUc08mdTw0t?Xu9(Ry11czP*(VoFKHdF%wn9&P$2U)yJR175Y5hL3q zQ{AC!p_69N0px(pa<14)@(@#qNBmxdQG6b)NH&&ubE@b-0Q7GEx3_)lE01J*X*}0( zFjs9-Z3=7c-2i}cb;%VOys4i0T0wc993Q@B`K4uy&|BB(xv-G{@0szoDcUsEq=EXD z^BM*OgNx6%&dhbPPw6o2CHaie%B+q=N^jwF8)@7Nzs-&7(lj)DM zVNb}T0Ygx-j9m=cAL5|$l81BQoU{}br7@Ul{yirV$q( z>#Zt=U)3BT$J|p;Jm8F~p`^ys6XBWU#7>pZx7h^2C;5P9&{i?0VYN@nlgCD<7$IOb zYN3u)*4-%Uc)=t>1ryy~L0h@91*Yc76fIwX;;R(o*B#W=wTFd;u`StCRXc8JL8$#t zXx(Vu*!h*TRRli2C!3U;yyLpPOlakpr1P3xqJ!fu+%sGe$#s?cDd(7!xZj>9 z9J_=i$=5&9zteNpu?2WSWmPLa1OULK_s*GOTa&h0bqSb6W$K>Rb84?w(IoT zwBv^rt)dS+JR0#<>dC7{lne4IQ4bF>fQ}bS*#;Y<>G^(z`$xW*VbkG4Cl|**>tw~C zVLA+EP(eD3gs{gq!Po$}wtt)c-h(@v4jqH!an&yS?MpS>$>Eor9;G_?w)~=}({s6} zFa9zjh_VzT{wx(RDuBVtlFFJG3?=ME$Vz1n(aTcwOzLoZb8NJmC(>Q9ys@q8O!WzW z-X?NH$^dlqS5k`U4nh(LE%;OD_a7Jp!V|$j0X_~ZlEYQsNXtx4?xR+TN00s2Zu$$y z3-5d{WwdlnpUTXZiWZGDWY2+*(eWY}xyHN4$nAq26*ev!kG|}^y-&5s8p~%i@Ci&x z)gw+#I#%YR`uby&q&;ZVowMvq|AT6O^W5JU#8U2@n8M-$G@0@FLq4Rvww^~lK4-R+ zbZW~h7b_Y*|z7FKIZjGLzZ0Fh|^ux`33P1;Jl zp$BeC!|fYY8UALf_NTp~eE~T~my)bqtnuj6((7+O0^W)9lXA}UfoNyrDX`4Je1rUb z>Uh0Crfzx@Wpnt}*1@awtjoYlgnM@z|JZ|Ve~gh4te@FNKCk2$U6%7dvt~NvRH^IS zc-ur&RbwzJS{p4lcG`17CBg00t5rx5@Ff3GU$)A+RP)e+m@gL$7Yp-CTeQpKU?rxF zlqq>Z*O9c&qW-Y zmx!ZeQ=af#<)<85`2H?UrEr3{5}(nt)kO!C{(8)qa}%oJjfC}Jimq)=lXMS9bWKtx!&65p?1F!3g{E6ORy+0; zziHFHxNiMx^Ve-mckbK5%S5}g>sD4))_EHZX`jYI;kijIA)*|jhtmW)JaJ%z7@3(2 zR@v>uN(d{mp>?kUimZ6<$#!fcDIyf}T_xBFq)cT=DJs(_eyJgqXD@Z@Tr zkyGE#la#QQzY!9l8n`uNZzoOd94R^E3MKh`I^^Xc-e+bF0H^nOWuzX=yQv51he~Kt zP80MMuO=)zh;GuL^yNR@Gtu`oj9*F11aj^Gx9;|5Ix*>c@LV=!2$ z>&Am-4GtcD{+^#{09h)^T&T1ucAX`jw%Eh^zZV3M#)Y<{U2aW6=EyJY4eb0hP^q*u zKOEjyWP8=MsJGQx@1uxEn{W3GL}c6bF49Tb{wjLcCapXG>oApMMoxvI(F(P5x{ScI zOasJ>ifGH9q~wfzSQh`@g!y5<_x$G53|v_%!Yh=U)#PAGrMEMXD7n||moB-V(Bg0%6{VqQ9{2y(7OEOF6L5yTj=DFE5OpR7J~yS5f`*?X zrNPiAGwBR$p^7FV4b38>u5z%X5$gi|sxrq-J8#ou)17EZS~(G`5*jX-{Px%(#RmaR z&pd6toI&SMdO0@_-)Z(D1k$m7um&o|l;iskf#>~$l=spf+_*4dMI@cY!25Uh-xGsq z-GBY5*t2}<{HG%MDii)4)SspC=URJj`n<)pou89a45ULY)<#f&M@O~nG}g;b7_6>k zd-PP2^rL#Gls(~GRGZ7_-k;w(?1CF``edI;Pzjg$J&>eTdtx-rdV1Y@ENC`Md6}sA zK2Ws9bg29ovc>`#>lhWT(2NbcBcl_4&eHR)OQfV(aunt##k+s6e2QCe@5gaLGIFtS z1P(JVd8ys{%##hmx=_`bU(BdT`f^_b%!l|9ij+Ote=03Qr*oB@8hX?OBdQ4!VW9tG zjy6ST5nHT;y$w5dt*-!!)SSHJFbFGb*39|jszgXu<0;3Q$HsMg^ZhGnaX**(KjwMl znei$idQFCwB{UZiS-rC3J1273Hrf=7sH21d>`jsdG4*3MhByU~Ws*0N=bUJ_Tb>pu z?}MJI9X4Pzat(aj= zP1;4jIKT9?uVug@ZX$kP8GqsJ#P;ryYn2Ynl>yV+;xH!ApJ}_Sl>e5p1Jtfe+ZFom zVOtXOUCJ5l@RG3rqxSFjv7S&6=;s)Y&ev?oJ4=f^dq&ny%C7PZ?VgoxcaC-)fryeS z^A=MeCuz?vIo!pT>f4cn`=s5rMVd(6IzRI5~%L@;9CqY<}Xxwsmd z2ec{Gh4ICeaYk@{R~rK_(B{(De@gT5A75+hnG}P(Woq)?it!r`;n6$L80n11)GK>! zW+LSJQMRy2JLxq1b;)&kMr+RCd>>w@R;589qXNg4%EbZztRAfAlO$77!bej>5^=E)yTrx> zWP$Z=#wKPa;Xm@$_1|fVeQ;z0*U`{OpI3(BVg7f0!W^Pbb9OwI<|NQ9c#!m9?~)0( zO6!P?K^-~FB|6xpCh)KH7j+A9O3Vp2e04F?@&tAMv|^;gl>B-|>dKW=L7<&9K9B+% zz-z(0{n~U_HFb0p{}(i1^Os4*mD#JI2E`@8>XG zCu|+LiX{lA1t^f6$xVARf8^!m?JAfOU=RF44F<{2D$}?k9~Bz7a3R1A$b&t*M<$+aIIXkZI}#E?&+0+f5z-M|z`08Rrl*;Wy?(V&NC!cSoNwLz8AJaM z`Ze?l(HkO7TAX^WlRL3~oD?e}Pt>v(5U&Co^=`W+&M_LGpq15(d@|1$&KF)BWT&I( zC(OGK?JMr0dypCbAh6S|0dz&05N0U#?B;I%)U>&sIY0M>TfVgP9EW{TUMa4G=4|{n zww4SqOfng7}1XAkDC{tL`@Kp=?*pH zI1+tsXmR=&KU6RJZXs&ajnk7ucb+p+F8?sX4W&-MNa;0!3j}jU_rzLX%89j;UfkS% zl%D;7MPnDuRYBP*-4@|02E51OfiK8GLZ@Y64Hx@A>(8;h_Lo~!(-A>NM6axhs+TquzI_&QzI8cM>6j&5ZJg8^Fc;~*tfSZRu z$e^O6m8vS~D}5SAyU^p9ED*dC(`*TfY4=&r9KD!$Lz~~vs73d}mb@vduCtKmPE)uV zE7u*bG!)-0{!cIWr*I=JA@SsEtL~E*pc{ag`R@Xz9e)rE)N;el3eB^VFvcSsEe5T;?*TWlpDCb9m>=)HkCzP zBBGE#%6^Y0V*1G*{JZXijOpA3Ne90AKIs&vfaH24;;MIX_l&C({kq5eP%p=Dkg8xz zvRE?>?Z^>O+Fou#_SvH!7q*viEKB9|u$;p&K)@X0@T4@YIoW~l(afBy?=8bsF1yq+ ze0hRrYqVMGDamJeY#8+WvyeYIvz(d z5A|X9xo;+gcdN!&(D9esjmD)V?psK3BK;(_ZJAmH zgb`E%Q2l*Gn#|3Vbp5oCe&WSk!yH?x+A9*@_V#*#l_WQs2kbvh2I|2m-@ECBPh{=z zH)8>I=%G@NiJu9Li<&+jQN1Lg%L0rNf)o-|WFNvW<>q%e8Ok)-mMDuCOTS9%zT&Ar zK&n5%)@&hAzj8=NQ@*Ry4hQ0f5Zsx`^Vw$m8dcwnWjW_(6_#}okk6-Sg9CzMYx4GD zFJra;R5y;Tz8!n?UeO{`LaArn8Vd_+JSZwM(%MsC3u}}CVN7Y9lGw5x{$k`El`yS8 zJrB!Vv-7ZHw9>=j$Ugc&^Q*R3SJw3l62U!7Ws-*d-@ztT(bp#%7p&^0B$k}?J<@Nw z{w^Q-q(OR*HGPv-$BF)%L!!S`rDelQ7^`#*iO~&LyUjIh4ol!eScFdRBsKv6wj?>D zR}`*UZUMN^VkI;rCu#mmS&=am@K%K~2oBQI4R9^K%r$7Q=1)zZ8*VYqmTaaqYmGO} zO%WYfbr^@BrjBz5jzbUr>pmsjnN2rts}`;1G=Gs*+t*l9ix!QwIS`G_p|zbcI=_wR+%Grxar^Shg+Y((cwQA&a~ zf@@LE;{b;}KCOla^v<+MaRP&_Rc=KkSC$rXHtkiNxlY6JWyZ*OM*`=mq~A|RZNtiw z=J)I?#XRU{ah)xhYEXX9(JJ#kPVX28my7~~j*b=Hh_LM9CH%&_HJj%I3#ydK+_Mm; zp8%lVhNp&Df-mR4q(D`F^nDdle@m7fD}6mtXs)rp&Wzi4kOR2@EieE$#G-o+_G@wq z1~P3+3p8SXoMK6ZE9G-M*@rR|AQmZhB;EFCfn9>*P5{6}{@V*s^TB&4Lc2~HWZbXg z)pvU{*)9X=w+!iV0RusVK&d3G#%Z_lw($^-JVuh;)AlVfi+PD-#cR|lJoIZ3v7P^! zFNS$AOYgrjIm)wTaKlyR)X_sUs2eXdc!z)d-(w>;IB@$8eW=SzO?Ak=vr0TdGd-a) zqx=xzSIB_wINlDw>HHdZv((%95%rhJf?Y0C#mI54-vq@q^nRp&fB?uFv#%dm2f6RE zSOeR#3pLPZ>*-cNYVk4C&z=NnF!i%rKuKkP{hFfW66{b4N)q<9ZQSUQF2-hDkuhEk zE&mmI>Xb`%PgZj@VIbku@e%OZ?A17V{Y@hVp!eghS`Ga)nygy4hGe!6s*<*nz^GFn zhFW!@xqnw#EB$biVZ(EVgx5W%X8t z5afQ)tS*TfzQ5)AyFG}Wu39sgPI8hHTmT7z&%aF;glBIcvybyzjWwRK@$ij)JwAs7 zcTl*VU3uR~cWfX-_EufE3@WE`1&V8IpoJciDd)MZIYrWW_Y>pf_BXoW$a`~+#?%a+ zx(MUASZRe>_(Q1zIQK3=!oY*o)@j0mLevJxcn@>%Ox3@gLtZ!;j^GlJp0w!Gzmcbq z>jRTKz#-Msh)@DE{3H4@zIB&FCRJW*Mvc!Tj!e^3Ct2T^KHIf6e)kCecPc=aHBVbv zel$h`*?#mCCw{%}6Qn~r?bq>%AVWOj@5OA}&-VmAx7(_v{|zkEv(x==V5cTBNgNKr zbBr5HVlPO0;Am*aHG|Stlr)5J+M-7~ON?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 diff --git a/components/images/lvgl_led.png b/components/images/lvgl_led.png deleted file mode 100644 index 0349f1b9cde81373ffe8919880e8e8f01e2de1ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1123 zcmV-p1f2VcP)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 diff --git a/components/images/lvgl_line.png b/components/images/lvgl_line.png deleted file mode 100644 index 6d85c445b4d1abcd49c9ac4f5737c40c9a234036..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/components/images/lvgl_main_screenshot.png b/components/images/lvgl_main_screenshot.png deleted file mode 100644 index a8c971a901e5a2623316069fdd7d6615ebd4520d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134021 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 `-gHYpC9M8$NJbjIk>De*TFYhU9LE=axSr5) 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 diff --git a/components/images/lvgl_meter.png b/components/images/lvgl_meter.png deleted file mode 100644 index 1283126cccb54041511b0ec5e9084869e81a5eef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7065 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 diff --git a/components/images/lvgl_msgbox.png b/components/images/lvgl_msgbox.png deleted file mode 100644 index 101a40c8b4f71430581d95d0cdfc91a562c905e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4971 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 diff --git a/components/images/lvgl_roller.png b/components/images/lvgl_roller.png deleted file mode 100644 index 3eab1039c096540a7710312f2ba2b9f9dfc3b3a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2677 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 diff --git a/components/images/lvgl_slider.png b/components/images/lvgl_slider.png deleted file mode 100644 index d2de4030d2fc6ddbf12efd85046016cfbc97f645..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 521 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 H#$XKq@`m>x diff --git a/components/images/lvgl_switch.png b/components/images/lvgl_switch.png deleted file mode 100644 index 9864b2b79bb7768789c766ac5f2c10deb94eace9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 737 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 diff --git a/components/images/lvgl_tabview.png b/components/images/lvgl_tabview.png deleted file mode 100644 index ae18acf31a59a254690b250414f57bdadb3fc6b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7993 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 diff --git a/components/images/lvgl_textarea.png b/components/images/lvgl_textarea.png deleted file mode 100644 index 1382f7e10061ed79797ee3b8ef067dd5b6a9b662..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4749 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 Date: Sun, 11 Aug 2024 21:53:12 +0000 Subject: [PATCH 558/564] Change ref to doc and remove whitespace --- components/key_collector.rst | 12 ++++++------ components/lvgl/index.rst | 26 +++++++++++++------------- components/touchscreen/index.rst | 2 -- components/wiegand.rst | 2 -- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/components/key_collector.rst b/components/key_collector.rst index 44cc38c29f..7deda5db8a 100644 --- a/components/key_collector.rst +++ b/components/key_collector.rst @@ -6,8 +6,8 @@ Key collector component .. seo:: :description: Key collector component -The ``key_collector`` component collects key presses from components -like :ref:`matrix_keypad`, :ref:`Wiegand keypad ` +The ``key_collector`` component collects key presses from components +like :ref:`matrix_keypad`, :doc:`Wiegand keypad ` or LVGL :ref:`Button Matrix `, :ref:`Keyboard ` widgets. It allows you to process key sequences and treat them as one, for example to allow inputting of a PIN code or a passkey. The component outputs @@ -35,7 +35,7 @@ Component format: "input progress: '%s', started by '%c'" args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] on_result: - - logger.log: + - logger.log: format: "input result: '%s', started by '%c', ended by '%c'" args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] on_timeout: @@ -49,14 +49,14 @@ Configuration variables: - **source_id** (*Optional*, :ref:`config-id`): The ID of the key input device. - **min_length** (*Optional*, integer): The minimal length of the desired key sequence. Below this, ``on_result`` automation will not trigger even if any of the ``end_keys`` was pressed. -- **max_length** (*Optional*, integer): The maximum length of the desired key sequence, after +- **max_length** (*Optional*, integer): The maximum length of the desired key sequence, after which the sequence will trigger the ``on_result`` automation witout having to press any of the ``end_keys`` - **end_keys** (*Optional*, string): Keys used to *enter* the sequence. - **end_key_required** (*Optional*, boolean): Only trigger ``on_result`` automation when one of the ``end_keys`` was pressed. Defaults to ``false``. - **back_keys** (*Optional*, string): Keys used to delete the last pressed key. Like *Backspace* on a keyboard. - **clear_keys** (*Optional*, string): Keys used to entirely clear the sequence, all the pressed keys. -- **allowed_keys** (*Optional*, string): Keys allowed to be used. If not specified, then any otherwise +- **allowed_keys** (*Optional*, string): Keys allowed to be used. If not specified, then any otherwise unused keys will be allowed. - **timeout** (*Optional*, :ref:`config-time`): Timeout after which to cancel building the sequence and delete all the keys. @@ -72,7 +72,7 @@ Automations: and ``start`` holds the start key that activated this sequence or else ``0``. Useful if you want to have a display showing the current value or number of key presses, or a speaker beeping when keys are being pressed. -- **on_result** (*Optional*, :ref:`Automation `): An automation to perform +- **on_result** (*Optional*, :ref:`Automation `): An automation to perform when the sequence has been finished (eg. ``max_length`` has been reached or one of the ``end_keys`` was pressed). The finalized key sequence is placed in a ``vector`` variable ``x``, ``start`` holds the start key that activated this sequence or else ``0``, and diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index bd3e0d53a7..6a36c11142 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -7,7 +7,7 @@ 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 +`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 `__. .. figure:: /components/lvgl/images/lvgl_main_screenshot.png @@ -16,7 +16,7 @@ To use LVGL with a :ref:`display ` in ESPHome, you'll need an ESP32 The graphic display should be configured with ``auto_clear_enabled: false`` and ``update_interval: never``, and should not have any ``lambda`` set. -For interactivity, a :ref:`Touchscreen ` (capacitive highly preferred), a :doc:`/components/sensor/rotary_encoder` or a custom keypad made up from discrete :doc:`Binary Sensors ` can be used. +For interactivity, a :doc:`Touchscreen ` (capacitive highly preferred), a :doc:`/components/sensor/rotary_encoder` or a custom keypad made up from discrete :doc:`Binary Sensors ` can be used. Basics @@ -103,18 +103,18 @@ The following configuration variables apply to the main ``lvgl`` component, in o .. tip:: When using binary sensors (from physical keys) to interact with LVGL, if there are only three keys available, they are best used when configured as a rotary encoder, where ``LEFT`` and ``RIGHT`` act like the rotary wheel, and ``ENTER`` generates an ``on_press`` :ref:`trigger `. With four or more keys, a keypad configuration is generally more appropriate. For example, a keypad consisting of five keys might use ``PREV``, ``NEXT``, ``UP``, ``DOWN`` and ``ENTER``; ``PREV``/``NEXT`` are used to select a widget within the group, ``UP``/``DOWN`` changes the selected value and ``ENTER`` generates an ``on_press`` :ref:`trigger `. - + The ``long_press_time`` and ``long_press_repeat_time`` can be fine-tuned also by setting them to ``never`` and using the ``autorepeat`` filter on each binary sensor separately. - **color_depth** (*Optional*, string): The color deph at which the contents are generated. Currently only ``16`` is supported (RGB565, 2 bytes/pixel), which is the default value. -- **buffer_size** (*Optional*, percentage): The percentage of screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. +- **buffer_size** (*Optional*, percentage): The percentage of screen size to allocate buffer memory. Default is ``100%`` (or ``1.0``). For devices without PSRAM, the recommended value is ``25%``. - **log_level** (*Optional*, string): Set the logger level specifically for the messages of the LVGL library: ``TRACE``, ``INFO``, ``WARN``, ``ERROR``, ``USER``, ``NONE``. Defaults to ``WARN``. - **byte_order** (*Optional*, int16): The byte order of the data LVGL outputs; either ``big_endian`` or ``little_endian``. Defaults to ``big_endian``. - **disp_bg_color** (*Optional*, :ref:`color `): Solid color used to fill the background. Can be changed at runtime with the ``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. Also see :ref:`lvgl-widget-image` for a note regarding supported image formats. - **default_font** (*Optional*, ID): 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 widget's ``styles`` configuration. See :ref:`below ` for more details. -- **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. +- **style_definitions** (*Optional*, list): A batch of style definitions to use in LVGL widget's ``styles`` configuration. See :ref:`below ` for more details. +- **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. May not be used if ``pages`` (below) is configured. - **pages** (*Optional*, list): A list of page IDs. Each page acts as a parent for widgets placed on it. May not be used with ``widgets`` (above). Options for each page: - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-page-next-previous-action`. @@ -166,7 +166,7 @@ Various parts of the widgets (like background, borders etc.) support opacity. It Fonts ***** -Two font choices are available: +Two font choices are available: **ESPHome fonts** @@ -213,7 +213,7 @@ You can display the embedded symbols among the text by their codepoint address p .. 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, 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. In addition to the above, the following special fonts are available from LVGL as built-in: @@ -236,10 +236,10 @@ LVGL follows CSS's `border-box model ` can be confi ``lvgl.on_idle`` **************** -LVGL has a notion of screen inactivity -- in other words, the time since the last user interaction with the screen is tracked. This can be used 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. +LVGL has a notion of screen inactivity -- in other words, the time since the last user interaction with the screen is tracked. This can be used 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:`triggers ` are activated when inactivity time becomes longer than the specified ``timeout``. You can configure any desired number of timeouts with different actions. diff --git a/components/touchscreen/index.rst b/components/touchscreen/index.rst index 62b24db684..bf2c19af51 100644 --- a/components/touchscreen/index.rst +++ b/components/touchscreen/index.rst @@ -1,5 +1,3 @@ -.. _touchscreen-main: - Touchscreen Components ====================== diff --git a/components/wiegand.rst b/components/wiegand.rst index 84c809389a..7234006f67 100644 --- a/components/wiegand.rst +++ b/components/wiegand.rst @@ -1,5 +1,3 @@ -.. _wiegand: - Wiegand keypad and tag reader ============================= From 2f3bcf2e1bc3c301ab5f864d77dc4a2e3f69ea1c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:53:56 +0000 Subject: [PATCH 559/564] Revert valve movement (Should be own PR) --- index.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/index.rst b/index.rst index 9b9f7aa1e9..32b45e8d10 100644 --- a/index.rst +++ b/index.rst @@ -915,6 +915,14 @@ Text Components Template Text, components/text/template, description.svg, dark-invert LVGL textarea Text, components/text/lvgl, lvgl_c_txt.png +Valve Components +---------------- + +.. imgtable:: + + Valve Core, components/valve/index, folder-open.svg, dark-invert + Template Valve, components/valve/template, description.svg, dark-invert + Text Sensor Components ---------------------- @@ -936,13 +944,6 @@ Text Sensor Components WireGuard, components/wireguard, wireguard_custom_logo.svg WL-134 Pet Tag Sensor , components/text_sensor/wl_134, fingerprint.svg, dark-invert -Valve Components ----------------- - -.. imgtable:: - - Valve Core, components/valve/index, folder-open.svg, dark-invert - Template Valve, components/valve/template, description.svg, dark-invert Climate Components ------------------ From 3f9973fbd04d327096737f70a427a2d553fae78d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 11 Aug 2024 22:02:34 +0000 Subject: [PATCH 560/564] Revert unrelated whitespace changes --- index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.rst b/index.rst index 32b45e8d10..ebe17387e2 100644 --- a/index.rst +++ b/index.rst @@ -944,7 +944,6 @@ Text Sensor Components WireGuard, components/wireguard, wireguard_custom_logo.svg WL-134 Pet Tag Sensor , components/text_sensor/wl_134, fingerprint.svg, dark-invert - Climate Components ------------------ @@ -1130,6 +1129,7 @@ Custom Components 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 2c810b551f8e6c51efc9c2e08a63924161016b0c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 11 Aug 2024 22:04:00 +0000 Subject: [PATCH 561/564] Revert unrelated whitespace changes --- components/key_collector.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/key_collector.rst b/components/key_collector.rst index 7deda5db8a..bd4e510d9b 100644 --- a/components/key_collector.rst +++ b/components/key_collector.rst @@ -35,7 +35,7 @@ Component format: "input progress: '%s', started by '%c'" args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] on_result: - - logger.log: + - logger.log: format: "input result: '%s', started by '%c', ended by '%c'" args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] on_timeout: @@ -43,13 +43,15 @@ Component format: "input timeout: '%s', started by '%c'" args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] + + Configuration variables: - **id** (*Optional*, :ref:`config-id`): Set the ID of this entry for use in lambdas. - **source_id** (*Optional*, :ref:`config-id`): The ID of the key input device. - **min_length** (*Optional*, integer): The minimal length of the desired key sequence. Below this, ``on_result`` automation will not trigger even if any of the ``end_keys`` was pressed. -- **max_length** (*Optional*, integer): The maximum length of the desired key sequence, after +- **max_length** (*Optional*, integer): The maximum length of the desired key sequence, after which the sequence will trigger the ``on_result`` automation witout having to press any of the ``end_keys`` - **end_keys** (*Optional*, string): Keys used to *enter* the sequence. - **end_key_required** (*Optional*, boolean): Only trigger ``on_result`` automation when one of @@ -57,7 +59,7 @@ Configuration variables: - **back_keys** (*Optional*, string): Keys used to delete the last pressed key. Like *Backspace* on a keyboard. - **clear_keys** (*Optional*, string): Keys used to entirely clear the sequence, all the pressed keys. - **allowed_keys** (*Optional*, string): Keys allowed to be used. If not specified, then any otherwise - unused keys will be allowed. + unused keys will be allowed. - **timeout** (*Optional*, :ref:`config-time`): Timeout after which to cancel building the sequence and delete all the keys. At least one of ``end_keys`` or ``max_length`` have to be specified. The rest are optional. @@ -72,7 +74,7 @@ Automations: and ``start`` holds the start key that activated this sequence or else ``0``. Useful if you want to have a display showing the current value or number of key presses, or a speaker beeping when keys are being pressed. -- **on_result** (*Optional*, :ref:`Automation `): An automation to perform +- **on_result** (*Optional*, :ref:`Automation `): An automation to perform when the sequence has been finished (eg. ``max_length`` has been reached or one of the ``end_keys`` was pressed). The finalized key sequence is placed in a ``vector`` variable ``x``, ``start`` holds the start key that activated this sequence or else ``0``, and From df26088886cc940bd23a777b3359769b12831c74 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 11 Aug 2024 22:04:32 +0000 Subject: [PATCH 562/564] Revert unrelated whitespace changes --- components/key_collector.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/key_collector.rst b/components/key_collector.rst index bd4e510d9b..0976caf060 100644 --- a/components/key_collector.rst +++ b/components/key_collector.rst @@ -58,8 +58,8 @@ Configuration variables: the ``end_keys`` was pressed. Defaults to ``false``. - **back_keys** (*Optional*, string): Keys used to delete the last pressed key. Like *Backspace* on a keyboard. - **clear_keys** (*Optional*, string): Keys used to entirely clear the sequence, all the pressed keys. -- **allowed_keys** (*Optional*, string): Keys allowed to be used. If not specified, then any otherwise - unused keys will be allowed. +- **allowed_keys** (*Optional*, string): Keys allowed to be used. If not specified, then any otherwise + unused keys will be allowed. - **timeout** (*Optional*, :ref:`config-time`): Timeout after which to cancel building the sequence and delete all the keys. At least one of ``end_keys`` or ``max_length`` have to be specified. The rest are optional. From 6a62fb49d2f7dc19cf7daf12af75b77b4800cbe6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 11 Aug 2024 22:13:44 +0000 Subject: [PATCH 563/564] More ref -> doc More whitespace --- components/binary_sensor/lvgl.rst | 4 +- components/display/index.rst | 6 +- components/font.rst | 4 +- components/light/lvgl.rst | 4 +- components/lvgl/index.rst | 2 - components/lvgl/widgets.rst | 122 +++++++++++++++--------------- components/number/lvgl.rst | 4 +- components/select/lvgl.rst | 4 +- components/sensor/lvgl.rst | 4 +- components/switch/lvgl.rst | 4 +- components/text/lvgl.rst | 4 +- components/text_sensor/lvgl.rst | 4 +- 12 files changed, 82 insertions(+), 84 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 054f4da8dd..6ec6c54526 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -10,7 +10,7 @@ LVGL Binary Sensor :image: ../images/lvgl_c_bns.png The ``lvgl`` binary sensor platform creates a binary sensor from an LVGL widget -and requires :ref:`LVGL ` to be configured. +and requires :doc:`LVGL ` to be configured. Supported widget is :ref:`lvgl-widget-button`. A single binary sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome binary sensor component. @@ -31,7 +31,7 @@ Example: See Also -------- -- :ref:`LVGL Main component ` +- :doc:`LVGL Main component ` - :ref:`Button widget ` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/components/display/index.rst b/components/display/index.rst index ee72043630..5d5c02af12 100644 --- a/components/display/index.rst +++ b/components/display/index.rst @@ -15,10 +15,10 @@ engine. Fundamentally, there are these types of displays: :doc:`OLED ` or :doc:`TFT ` displays. -For graphical displays, which offer the greatest flexibility, there are two options: +For graphical displays, which offer the greatest flexibility, there are two options: - ESPHome's :ref:`own rendering engine ` -- :ref:`LVGL ` - Light and Versatile Graphics Library +- :doc:`LVGL ` - Light and Versatile Graphics Library .. _display-engine: @@ -611,7 +611,7 @@ See Also -------- - :apiref:`display/display_buffer.h` -- :ref:`LVGL ` +- :doc:`LVGL ` - :ref:`Fonts ` - :ref:`Graph Component ` - :ref:`QR Code Component ` diff --git a/components/font.rst b/components/font.rst index 90a112bf7f..8f215822c1 100644 --- a/components/font.rst +++ b/components/font.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 Graphics ` component. +These fonts can be used in ESPHome's :ref:`own rendering engine ` or in the :doc:`LVGL Graphics ` component. To use fonts you can either - 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. @@ -156,7 +156,7 @@ See Also - :apiref:`display/display_buffer.h` - :ref:`display-engine` -- :ref:`lvgl-main` +- :doc:`/components/lvgl/index` - `MDI cheatsheet `_ - `MDI font repository `_ - :ghedit:`Edit` diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index 44aac083e8..e95fc7b618 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -8,7 +8,7 @@ LVGL Light :image: ../images/lvgl_c_lig.png The ``lvgl`` light platform creates a light from an LVGL widget -and requires :ref:`LVGL ` to be configured. +and requires :doc:`LVGL ` to be configured. Supported widget is :ref:`lvgl-widget-led`. A single light supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome light component. @@ -34,7 +34,7 @@ Example: See Also -------- -- :ref:`LVGL Main component ` +- :doc:`LVGL Main component ` - :ref:`LED widget ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index 6a36c11142..ca439fd14b 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -1,5 +1,3 @@ -.. _lvgl-main: - LVGL Graphics ============= diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index 1a6b4f6bc4..bfb0b813f5 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -7,7 +7,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, its children will also be hidden. -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 those related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the parent will be searched for an object which specifies a value for the property. The parents will use their own :ref:`state ` to determine the value. For example, if a button is pressed and the text color is defined by the "pressed" state, this "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 those related to text and opacity) can be inherited from the parent widgets's styles. When the property is inheritable, the parent will be searched for an object which specifies a value for the property. The parents will use their own :ref:`state ` to determine the value. For example, if a button is pressed and the text color is defined by the "pressed" state, this "pressed" text color will be used. Common properties ----------------- @@ -17,13 +17,13 @@ The properties below are common to all widgets. **Configuration variables:** - **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation. -- **x** (*Optional*, int16 or percentage): Horizontal position of the widget. +- **x** (*Optional*, int16 or percentage): Horizontal position of the widget. - **y** (*Optional*, int16 or percentage): Vertical position of the widget. .. note:: - 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. - + 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. + If specifying ``align``, ``x`` and ``y`` can be used as an offset to the calculated position (can also be negative). They are ignored if :ref:`lvgl-layouts` are used on the parent. - **height** (*Optional*): Height of the widget in pixels or a percentage, or ``SIZE_CONTENT``. @@ -32,7 +32,7 @@ The properties below are common to all widgets. .. note:: 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 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 dimensions of the parent's content area. Defaults to ``0%``. @@ -150,7 +150,7 @@ The animation image is similar to the normal ``image`` widget. The main differen **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -204,7 +204,7 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can be .. note:: - The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. + The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. **Actions:** @@ -214,8 +214,8 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can be **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``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -287,7 +287,7 @@ Not only the end, but also the start value of the bar can be set, which changes **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -316,7 +316,7 @@ The ``bar`` can be also integrated as :doc:`Number ` or ``button`` ---------- -Simple push (momentary) or toggle (two-states) button. +Simple push (momentary) or toggle (two-states) button. .. figure:: /components/lvgl/images/lvgl_button.png :align: center @@ -331,7 +331,7 @@ A notable state is ``checked`` (boolean) which can have different styles applied **Triggers:** - ``on_value`` :ref:`trigger ` is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -391,7 +391,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row - **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. - **selected** (*Optional*, boolean): Set the button as the most recently released or focused. Defaults to ``false``. - **text** (*Optional*): Text (or built-in :ref:`symbol ` codepoint) to display on the button. - - **width** (*Optional*): Width relative to the other buttons in the same row. Must be a value between ``1`` and ``15``; the default is ``1`` (for example, given a line with two buttons, one with ``width: 1`` and another one with ``width: 2``, the first will be ``33%`` wide while the second will be ``66%`` wide). + - **width** (*Optional*): Width relative to the other buttons in the same row. Must be a value between ``1`` and ``15``; the default is ``1`` (for example, given a line with two buttons, one with ``width: 1`` and another one with ``width: 2``, the first will be ``33%`` wide while the second will be ``66%`` wide). - **control** (*Optional*): Binary flags to control behavior of the buttons (all ``false`` by default): - **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. Apply ``checked`` styles to the button. @@ -420,7 +420,7 @@ The button matrix widget is a lightweight way to display multiple buttons in row **Triggers:** - ``on_value`` and :ref:`interaction ` triggers can be configured for each button, is activated after clicking. If ``checkable`` is ``true``, the boolean variable ``x``, representing the checked state, may be used by lambdas within this trigger. -- The :ref:`interaction ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). +- The :ref:`interaction ` LVGL event triggers can be configured for the main widget, they pass the ID of the pressed button (or null if nothing pressed) as variable ``x`` (a pointer to a ``uint16_t`` which holds the index number of the button). **Example:** @@ -532,7 +532,7 @@ The checkbox widget is made internally from a *tick box* and a label. When the c **Triggers:** ``on_value`` :ref:`trigger ` is activated when toggling the checkbox. The boolean variable ``x``, representing the checkbox's state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -590,7 +590,7 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( - **indicator** (*Optional*, list): Settings for the the parent of ``symbol``. Supports a list of :ref:`styles ` to customize. - **options** (**Required**, list): The list of available options in the drop-down. - **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. -- **selected_index** (*Optional*, int8): The index of the item you wish to be selected. +- **selected_index** (*Optional*, int8): The index of the item you wish to be selected. - **selected** (*Optional*, list): Settings for the selected item in the list. Supports a list of :ref:`styles ` to customize. - **symbol** (*Optional*, dict): 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 those built-in 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-widget-label` text properties for the text on it. ``max_height`` can be used to limit the height of the list. ``text_font`` can be used to set the font of the button part, including the symbol. @@ -603,9 +603,9 @@ The Dropdown widget is built internally from a *button* part and a *list* part ( **Triggers:** -- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`interaction ` LVGL event triggers also apply, and they also return the selected index in ``x``. +- ``on_value`` :ref:`trigger ` is activated only when you select an item from the list. The new selected index is returned in the variable ``x``. The :ref:`interaction ` LVGL event triggers also apply, and they also return the selected index in ``x``. - ``on_cancel`` :ref:`trigger ` is also activated when you close the dropdown without selecting an item from the list. The currently selected index is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -650,7 +650,7 @@ The ``dropdown`` can be also integrated as :doc:`Select ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -767,7 +767,7 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-widget .. tip:: - The Keyboard widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. + The Keyboard widget supports the :ref:`key_collector` to collect the button presses as key press sequences for further automations. .. note:: @@ -786,16 +786,16 @@ A label is the basic widget type that is used to display text. **Configuration variables:** - **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 set by :ref:`lvgl-layouts`), 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 lines which are too long. If the height is ``SIZE_CONTENT``, the label's height will be expanded, otherwise the text will be clipped (default). + - ``WRAP``: Wrap lines which are too long. 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 the text horizontally back and forth. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. - ``SCROLL_CIRCULAR``: If the text is wider than the label, continuously scroll the text horizontally. If it's higher, scroll vertically. Text will scroll in only one direction; horizontal scrolling has higher precedence. - ``CLIP``: Simply clip the parts of the text outside the label. -- **recolor** (*Optional*, boolean): Enable recoloring of button text with ``#``. This makes it possible to set the color of characters in the text individually by prefixing the text to be re-colored with a ``#RRGGBB`` hexadecimal color code followed by a *space*, and finally closed with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. +- **recolor** (*Optional*, boolean): Enable recoloring of button text with ``#``. This makes it possible to set the color of characters in the text individually by prefixing the text to be re-colored with a ``#RRGGBB`` hexadecimal color code followed by a *space*, and finally closed with a single hash ``#`` tag. For example: ``Write a #FF0000 red# word``. - **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. - **text_align** (*Optional*, dict): 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_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 as YAML list). 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``. @@ -810,7 +810,7 @@ A label is the basic widget type that is used to display text. **Actions:** -- ``lvgl.label.update`` :ref:`action ` updates the widget styles and properties from the specific options above, just like the :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 the :ref:`lvgl.widget.update ` action is used for the common styles, states or flags. - **id** (**Required**): The ID or a list of IDs of label widgets which you want update. - **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 `. @@ -819,7 +819,7 @@ A label is the basic widget type that is used to display text. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -873,7 +873,7 @@ The LED widgets are either circular or rectangular widgets whose brightness can **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -952,7 +952,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need - **scales** (**Required**, list): A list with (any number of) scales to be added to the meter. - **angle_range** (**Required**): The angle between start and end of the tick scale. Defaults to ``270``. - **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: + - **arc** (*Optional*): Add a background arc the scale: - **color**: :ref:`Color ` to draw the arc. Defaults to ``0`` (black). - **end_value**: The value in the scale range to end drawing the arc to. - **r_mod**: Adjust the position of the arc from the scale radius with this amount (can be negative). Defaults to ``0``. @@ -963,7 +963,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need - **id**: Manually specify the :ref:`config-id` used for updating the indicator value at runtime. - **pivot_x**: Horizontal position of the pivot point of rotation, in pixels, relative to the top left corner of the image. - **pivot_y**: Vertical position of the pivot point of rotation, in pixels, relative to the top left corner of the image. - - **src**: The ID of an existing image configuration, representing 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--->``. - **value**: The value in the scale range to show at start. - **line** (*Optional*): Add a needle line to the scale. By default, the length of the line is the same as the scale's radius: - **color**: :ref:`Color ` for the needle line. Defaults to ``0`` (black). @@ -981,7 +981,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need - **width**: Modifies the ``width`` of the tick lines. - **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``. - - **rotation** (*Optional*): The rotation angle offset of the tick scale. + - **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: - **color** (*Optional*, :ref:`color `): Color to draw the ticks. Required if ``count`` is greater than ``0``. Defaults to ``0x808080``. - **count** (**Required**): How many ticks to be on the scale. Defaults to ``12``. @@ -998,7 +998,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need .. note:: - The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. + The zero degree position is at the middle right (3 o'clock) of the widget and the degrees increase in a clockwise direction from there. Angles are specified in the ``0``-``360`` range. **Actions:** @@ -1007,7 +1007,7 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1067,7 +1067,7 @@ The text will be broken into multiple lines automatically and the height will be - Style options from :ref:`lvgl-styling`. Uses all the typical background properties and the text properties. - **buttons** (**Required**, dict): A list of buttons to show at the bottom of the message box: - **text** (**Required**, string): The text (or built-in :ref:`symbol ` codepoint) to display on the button. - - **close_button** (**Required**, boolean): Controls the appearance of the 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 message box. **Actions:** @@ -1119,7 +1119,7 @@ You can use it as a parent container for other widgets. By default, it catches t **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1149,10 +1149,10 @@ Roller allows you to simply select one option from a list by scrolling. - **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. - **mode** (*Optional*, dict): Option to make the roller circular. ``NORMAL`` or ``INFINITE``, defaults to ``NORMAL``. - **options** (**Required**, list): The list of available options in the roller. -- **selected_index** (*Optional*, int8): The index of the item you wish to be selected. +- **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. The selected option in the middle. Besides the typical background properties it uses the :ref:`lvgl-widget-label` text style properties to change the appearance of the text in the selected area. - **visible_row_count** (*Optional*, int8): The number of visible rows. -- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-widget-label` style properties. ``text_line_space`` adjusts the space between the options. +- Style options from :ref:`lvgl-styling`. The background of the roller uses all the typical background properties and :ref:`lvgl-widget-label` style properties. ``text_line_space`` adjusts the space between the options. **Actions:** @@ -1162,8 +1162,8 @@ Roller allows you to simply select one option from a list by scrolling. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the selected index in ``x``. +- ``on_value`` :ref:`trigger ` is activated when you select an item from the list. The new selected index is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the selected index in ``x``. **Example:** @@ -1228,8 +1228,8 @@ Normally, the slider can be adjusted either by dragging the knob, or by clicking **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. The new value is returned in the variable ``x``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the slider. The new value is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -1287,7 +1287,7 @@ The spinbox contains a numeric value (as text) which can be increased or decreas - **range_to** (*Optional*, float): The maximum value allowed to set the spinbox to. Defaults to ``100``. - **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``. - **step** (*Optional*, float): The granularity with which the value can be set. Defaults to ``1.0``. -- **value** (**Required**, float): Actual value to be shown by the spinbox at start. +- **value** (**Required**, float): Actual value to be shown by the spinbox at start. .. note:: @@ -1307,8 +1307,8 @@ The spinbox contains a numeric value (as text) which can be increased or decreas **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``. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- ``on_value`` :ref:`trigger ` is activated when the knob changes the value of the arc. The new value is returned in the variable ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -1373,7 +1373,7 @@ The Spinner widget is a spinning arc over a ring. **Triggers:** -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1414,7 +1414,7 @@ The switch looks like a little slider and can be used to turn something on and o **Triggers:** - ``on_value`` :ref:`trigger ` is activated when toggling the switch. The boolean variable ``x``, representing the switch's state, may be used by lambdas within this trigger. -- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. +- :ref:`interaction ` LVGL event triggers which also return the value in ``x``. **Example:** @@ -1442,7 +1442,7 @@ The ``switch`` can be also integrated as a :doc:`Switch ` jumps the view to the desired tab: - **id** (**Required**): The ID of the tabview which receives this action. - - **index** (**Required**): The (zero-based) index of the tab to which to jump. + - **index** (**Required**): The (zero-based) index of the tab to which to jump. - **animated** (*Optional*, boolean): To animate the movement. Defaults to ``false``. **Triggers:** -- ``on_value`` :ref:`trigger ` is activated when displayed tab changes. The new value is returned in the variable ``tab`` as the ID of the now-visible tab. -- :ref:`interaction ` LVGL event triggers. +- ``on_value`` :ref:`trigger ` is activated when displayed tab changes. The new value is returned in the variable ``tab`` as the ID of the now-visible tab. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1528,7 +1528,7 @@ The textarea is an extended label widget which displays a cursor and allows the - **accepted_chars** (*Optional*, string): You can set a list of accepted characters, so other characters will be ignored. - **max_length** (*Optional*, int): Limit the maximum number of characters to this value. - **one_line** (*Optional*, boolean): The text area can be limited to only allow a single line of text. In this case the height will set automatically to fit only one line, line break characters will be ignored, and word wrap will be disabled. -- **password_mode** (*Optional*, boolean): The text area supports password mode. By default, if the ``•`` (bullet, ``0x2022``) glyph exists in the font, the entered characters are converted to it after some time or when a new character is entered. If ``•`` is missing from the font, ``*`` (asterisk) will be used. +- **password_mode** (*Optional*, boolean): The text area supports password mode. By default, if the ``•`` (bullet, ``0x2022``) glyph exists in the font, the entered characters are converted to it after some time or when a new character is entered. If ``•`` is missing from the font, ``*`` (asterisk) will be used. - **placeholder_text** (*Optional*, string): A placeholder text can be specified, which is displayed when the Text area is empty. - any :ref:`Styling ` and state-based option for the background of the textarea. Uses all the typical background style properties and the text/label related style properties for the text. @@ -1542,7 +1542,7 @@ The textarea is an extended label widget which displays a cursor and allows the - ``on_value`` :ref:`trigger ` is activated on every keystroke. - ``on_ready`` :ref:`trigger ` is activated when ``one_line`` is configured as ``true`` and the newline character is received (Enter/Ready key on the keyboard). -- :ref:`interaction ` LVGL event triggers. +- :ref:`interaction ` LVGL event triggers. For both triggers above, when triggered, the variable ``text`` (``std::string`` type) is available for use in lambdas within these triggers and it will contain the entire contents of the textarea. @@ -1590,7 +1590,7 @@ If the Tile view is screen sized, the user interface resembles what you may have **Configuration variables:** -- **tiles** (**Required**, list): A list with (any number of) tiles to be added to tileview. +- **tiles** (**Required**, list): A list with (any number of) tiles to be added to tileview. - **column** (**Required**): Vertical position of the tile in the tileview grid. - **row** (**Required**): Horizontal position of the tile in the tileview grid. - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. @@ -1608,8 +1608,8 @@ If the Tile view is screen sized, the user interface resembles what you may have **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 now-visible tile. -- :ref:`interaction ` LVGL event 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 now-visible tile. +- :ref:`interaction ` LVGL event triggers. **Example:** @@ -1678,7 +1678,7 @@ This powerful :ref:`action ` allows changing/updating any widget bg_color: 0xFF0000 state: disabled: true - + # Example for updating flag: on_...: then: @@ -1703,9 +1703,9 @@ These :ref:`actions ` are shorthands for toggling the ``hidden`` - lvgl.widget.hide: my_label_id # a single widget - lvgl.widget.show: [my_button_1, my_button_2] # a list of widgets - delay: 0.5s - - lvgl.widget.show: + - lvgl.widget.show: -id: my_label_id - - lvgl.widget.hide: + - lvgl.widget.hide: - id: [my_button_1, my_button_2] ``lvgl.widget.disable``, ``lvgl.widget.enable`` @@ -1777,7 +1777,7 @@ These triggers can be applied directly to any widget in the LVGL configuration, See Also -------- -- :ref:`LVGL Main component ` +- :doc:`LVGL Main component ` - :doc:`/components/binary_sensor/lvgl` - :doc:`/components/sensor/lvgl` - :doc:`/components/number/lvgl` diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index e7eef43a16..5fe0b08afd 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -8,7 +8,7 @@ LVGL Number :image: ../images/lvgl_c_num.png The ``lvgl`` number platform creates a number component from an LVGL widget -and requires :ref:`LVGL ` to be configured. +and requires :doc:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-widget-arc`, :ref:`lvgl-widget-bar`, :ref:`lvgl-widget-slider` and :ref:`lvgl-widget-spinbox`. A single number supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome number component. @@ -34,7 +34,7 @@ Example: See Also -------- -- :ref:`LVGL Main component ` +- :doc:`LVGL Main component ` - :ref:`Arc widget ` - :ref:`Bar widget ` - :ref:`Slider widget ` diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 5e62113bde..67b8858ef4 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -8,7 +8,7 @@ LVGL Select :image: ../images/lvgl_c_sel.png The ``lvgl`` select platform creates a select from an LVGL widget -and requires :ref:`LVGL ` to be configured. +and requires :doc:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-widget-dropdown` and :ref:`lvgl-widget-roller`. A single select supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome select component. @@ -33,7 +33,7 @@ Example: See Also -------- -- :ref:`LVGL Main component ` +- :doc:`LVGL Main component ` - :ref:`Roller widget ` - :ref:`Dropdown widget ` - :doc:`/components/binary_sensor/lvgl` diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 5d10b95dd8..8fa193a808 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -8,7 +8,7 @@ LVGL Sensor :image: ../images/lvgl_c_num.png The ``lvgl`` sensor platform creates a semsor component from an LVGL widget -and requires :ref:`LVGL ` to be configured. +and requires :doc:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-widget-arc`, :ref:`lvgl-widget-bar`, :ref:`lvgl-widget-slider` and :ref:`lvgl-widget-spinbox`. A single sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome sensor. @@ -33,7 +33,7 @@ Example: See Also -------- -- :ref:`LVGL Main component ` +- :doc:`LVGL Main component ` - :ref:`Arc widget ` - :ref:`Bar widget ` - :ref:`Slider widget ` diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index a50a3d48cb..1768b6ea63 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -8,7 +8,7 @@ LVGL Switch :image: ../images/lvgl_c_swi.png The ``lvgl`` switch platform creates a switch from an LVGL widget -and requires :ref:`LVGL ` to be configured. +and requires :doc:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-widget-button` (with ``checkable`` option enabled), :ref:`lvgl-widget-switch` and :ref:`lvgl-widget-checkbox`. A single switch supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome switch component. @@ -29,7 +29,7 @@ Example: See Also -------- -- :ref:`LVGL Main component ` +- :doc:`LVGL Main component ` - :ref:`Button widget ` - :ref:`Switch widget ` - :ref:`Checkbox widget ` diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index d583e42fdf..989bdce1cc 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -7,7 +7,7 @@ LVGL Text :description: Instructions for setting up an LVGL Text component. :image: ../images/lvgl_c_txt.png -The ``lvgl`` text platform creates an editable text component from an LVGL textual widget and requires :ref:`LVGL ` to be configured. +The ``lvgl`` text platform creates an editable text component from an LVGL textual widget and requires :doc:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-widget-label` and :ref:`lvgl-widget-textarea`. A single text supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text component. @@ -32,7 +32,7 @@ Example: See Also -------- -- :ref:`LVGL Main component ` +- :doc:`LVGL Main component ` - :ref:`Label widget ` - :ref:`Textarea widget ` - :doc:`/components/binary_sensor/lvgl` diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index 95bfdad83d..7ff21b5f11 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -8,7 +8,7 @@ LVGL Text Sensor :image: ../images/lvgl_c_txt.png The ``lvgl`` text sensor platform creates a Text Sensor from an LVGL textual widget -and requires :ref:`LVGL ` to be configured. +and requires :doc:`LVGL ` to be configured. Supported widgets are :ref:`lvgl-widget-label` and :ref:`lvgl-widget-textarea`. A single text sensor supports only a single widget; in other words, it's not possible to have multiple widgets associated with a single ESPHome text sensor component. @@ -33,7 +33,7 @@ Example: See Also -------- -- :ref:`LVGL Main component ` +- :doc:`LVGL Main component ` - :ref:`Label widget ` - :ref:`Textarea widget ` - :doc:`/components/binary_sensor/lvgl` From 3d5bb6a0dc34f01a13c416831a7295e02db2540f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 11 Aug 2024 22:24:49 +0000 Subject: [PATCH 564/564] More ref -> doc --- components/binary_sensor/lvgl.rst | 4 ---- components/light/lvgl.rst | 2 -- components/lvgl/index.rst | 14 +++++++------- components/lvgl/widgets.rst | 6 ++---- components/number/lvgl.rst | 2 -- components/select/lvgl.rst | 2 -- components/sensor/lvgl.rst | 2 -- components/switch/lvgl.rst | 2 -- components/text/lvgl.rst | 2 -- components/text_sensor/lvgl.rst | 2 -- 10 files changed, 9 insertions(+), 29 deletions(-) diff --git a/components/binary_sensor/lvgl.rst b/components/binary_sensor/lvgl.rst index 6ec6c54526..e56b9c196c 100644 --- a/components/binary_sensor/lvgl.rst +++ b/components/binary_sensor/lvgl.rst @@ -1,7 +1,3 @@ - -.. _lvgl-binary-sensor: - - LVGL Binary Sensor ================== diff --git a/components/light/lvgl.rst b/components/light/lvgl.rst index e95fc7b618..a4e1d1d3bf 100644 --- a/components/light/lvgl.rst +++ b/components/light/lvgl.rst @@ -1,5 +1,3 @@ -.. _lvgl-light: - LVGL Light ========== diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst index ca439fd14b..f47df9e912 100644 --- a/components/lvgl/index.rst +++ b/components/lvgl/index.rst @@ -20,7 +20,7 @@ For interactivity, a :doc:`Touchscreen ` (capacit Basics ------ -In LVGL, graphical elements like buttons, labels, sliders, etc. are called widgets or objects. See :ref:`lvgl-widgets` for a complete list of widgets supported within ESPHome. Not all LVGL widgets are implemented, just those commonly used to support home automation needs/tasks. +In LVGL, graphical elements like buttons, labels, sliders, etc. are called widgets or objects. See :doc:`/components/lvgl/widgets` for a complete list of widgets supported within ESPHome. Not all LVGL widgets are implemented, just those commonly used to support home automation needs/tasks. 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 the label. Complex widgets internally consist of several smaller/simpler widgets; these are known as parts, each of which can have separate properties from the main widget. @@ -74,7 +74,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **long_press_time** (*Optional*, :ref:`Time `): For the touchscreen, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the touchscreen, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. - **encoders** (*Optional*, list): A list of rotary encoders interacting with the LVGL widgets on the display. - - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. 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 input device. See the :doc:`common properties ` of the widgets for more information on groups. - **enter_button** (**Required**, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``ENTER`` key. - **sensor** (*Optional*, :ref:`config-id`): The ID of a :doc:`/components/sensor/rotary_encoder`; or a list with buttons for left/right interaction with the widgets: - **left_button** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``LEFT`` key. @@ -82,7 +82,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **long_press_time** (*Optional*, :ref:`Time `): For the rotary encoder, delay after which the ``on_long_pressed`` :ref:`interaction trigger ` will be called. Defaults to ``400ms``. Can be disabled with ``never``. - **long_press_repeat_time** (*Optional*, :ref:`Time `): For the rotary encoder, repeated interval after ``long_press_time``, when ``on_long_pressed_repeat`` :ref:`interaction trigger ` will be called. Defaults to ``100ms``. Can be disabled with ``never``. - **keypads** (*Optional*, list): A list of keypads interacting with the LVGL widgets on the display. - - **group** (*Optional*, string): A name for a group of widgets which will interact with the the input device. 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 input device. See the :doc:`common properties ` of the widgets for more information on groups. - **up** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``UP`` key. - **down** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``DOWN`` key. - **right** (*Optional*, :ref:`config-id`): The ID of a :doc:`Binary Sensor `, to be used as ``RIGHT`` key. @@ -113,16 +113,16 @@ The following configuration variables apply to the main ``lvgl`` component, in o - **default_font** (*Optional*, ID): 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 widget's ``styles`` configuration. See :ref:`below ` for more details. - **theme** (*Optional*, list): A list of styles to be applied to all widgets. See :ref:`below ` for more details. -- **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the root display. May not be used if ``pages`` (below) is configured. +- **widgets** (*Optional*, list): A list of :doc:`/components/lvgl/widgets` to be drawn on the root display. May not be used if ``pages`` (below) is configured. - **pages** (*Optional*, list): A list of page IDs. Each page acts as a parent for widgets placed on it. May not be used with ``widgets`` (above). Options for each page: - **skip** (*Optional*, boolean): Option to skip this page when navigating between them with :ref:`lvgl-page-next-previous-action`. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. + - **widgets** (*Optional*, list): A list of :doc:`/components/lvgl/widgets` to be drawn on the page. - All other options from :ref:`lvgl-styling` to be applied to this page. - **page_wrap** (*Optional*, boolean): Wrap from the last to the first page when navigating between them with :ref:`lvgl-page-next-previous-action`. Defaults to ``true``. - **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, which may be useful for widgets which always need to be visible. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the page. + - **widgets** (*Optional*, list): A list of :doc:`/components/lvgl/widgets` to be drawn on the page. - All other options from :ref:`lvgl-styling` to be applied to this page. - **layout** (*Optional*): See :ref:`lvgl-layouts` for details. Defaults to ``NONE``. - All other options from :ref:`lvgl-styling` to be applied to all widgets directly. @@ -487,7 +487,7 @@ Values for use with ``grid_column_align``, ``grid_row_align``, ``grid_cell_x_ali Widgets ******* -LVGL supports a list of :ref:`lvgl-widgets` which can be used to draw interactive objects on the screen. +LVGL supports a list of :doc:`/components/lvgl/widgets` which can be used to draw interactive objects on the screen. Actions ------- diff --git a/components/lvgl/widgets.rst b/components/lvgl/widgets.rst index bfb0b813f5..1700ee2b38 100644 --- a/components/lvgl/widgets.rst +++ b/components/lvgl/widgets.rst @@ -1,5 +1,3 @@ -.. _lvgl-widgets: - LVGL Widgets ============ @@ -1456,7 +1454,7 @@ The tabs are indexed (zero-based) in the order they appear in the configuration - **tabs** (**Required**, list): A list with (any number of) tabs to be added to tabview. - **name** (**Required**): The text to be shown on the button corresponding to the tab. - **id** (*Optional*): An ID for the tab itself. - - **widgets** (**Required**, list): A list of :ref:`lvgl-widgets` to be drawn on the tab, as children. + - **widgets** (**Required**, list): A list of :doc:`/components/lvgl/widgets` to be drawn on the tab, as children. - **tab_style** (*Optional*): Style settings for the tabs. - **items** (*Optional*, list): Settings for the items *part*, the buttons all use the text and typical background style properties except translations and transformations. @@ -1595,7 +1593,7 @@ If the Tile view is screen sized, the user interface resembles what you may have - **row** (**Required**): Horizontal position of the tile in the tileview grid. - **dir** (*Optional*): Enable moving to adjacent tiles in the given direction by swiping/dragging. One (or multiple as YAML list) of ``LEFT``, ``RIGHT``, ``TOP``, ``BOTTOM``, ``HOR``, ``VER``, ``ALL``. Defaults to ``ALL``. - **id** (*Optional*): A tile ID to be used with the ``lvgl.tileview.select`` action. - - **widgets** (*Optional*, list): A list of :ref:`lvgl-widgets` to be drawn on the tile, as children. + - **widgets** (*Optional*, list): A list of :doc:`/components/lvgl/widgets` to be drawn on the tile, as children. **Actions:** diff --git a/components/number/lvgl.rst b/components/number/lvgl.rst index 5fe0b08afd..0183592ccf 100644 --- a/components/number/lvgl.rst +++ b/components/number/lvgl.rst @@ -1,5 +1,3 @@ -.. _lvgl-number: - LVGL Number =========== diff --git a/components/select/lvgl.rst b/components/select/lvgl.rst index 67b8858ef4..711c2509da 100644 --- a/components/select/lvgl.rst +++ b/components/select/lvgl.rst @@ -1,5 +1,3 @@ -.. _lvgl-select: - LVGL Select =========== diff --git a/components/sensor/lvgl.rst b/components/sensor/lvgl.rst index 8fa193a808..b7c13e252b 100644 --- a/components/sensor/lvgl.rst +++ b/components/sensor/lvgl.rst @@ -1,5 +1,3 @@ -.. _lvgl-sensor: - LVGL Sensor =========== diff --git a/components/switch/lvgl.rst b/components/switch/lvgl.rst index 1768b6ea63..37a0478c27 100644 --- a/components/switch/lvgl.rst +++ b/components/switch/lvgl.rst @@ -1,5 +1,3 @@ -.. _lvgl-switch: - LVGL Switch =========== diff --git a/components/text/lvgl.rst b/components/text/lvgl.rst index 989bdce1cc..78b16e11e3 100644 --- a/components/text/lvgl.rst +++ b/components/text/lvgl.rst @@ -1,5 +1,3 @@ -.. _lvgl-text: - LVGL Text ========= diff --git a/components/text_sensor/lvgl.rst b/components/text_sensor/lvgl.rst index 7ff21b5f11..61610f4230 100644 --- a/components/text_sensor/lvgl.rst +++ b/components/text_sensor/lvgl.rst @@ -1,5 +1,3 @@ -.. _lvgl-text-sensor: - LVGL Text Sensor ================