diff --git a/Doxygen b/Doxygen
index 1b7b146f0e..04b6079c4c 100644
--- a/Doxygen
+++ b/Doxygen
@@ -38,7 +38,7 @@ PROJECT_NAME = "ESPHome"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 2024.8.3
+PROJECT_NUMBER = 2024.9.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/Makefile b/Makefile
index 1683244729..9b0a8d1ed9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
ESPHOME_PATH = ../esphome
-ESPHOME_REF = 2024.8.3
+ESPHOME_REF = 2024.9.0
PAGEFIND_VERSION=1.1.0
PAGEFIND=pagefind
NET_PAGEFIND=../pagefindbin/pagefind
diff --git a/_static/changelog-2024.9.0.png b/_static/changelog-2024.9.0.png
new file mode 100644
index 0000000000..8a086d85f2
Binary files /dev/null and b/_static/changelog-2024.9.0.png differ
diff --git a/_static/version b/_static/version
index 1e08ca9ca6..bf1b3fd37a 100644
--- a/_static/version
+++ b/_static/version
@@ -1 +1 @@
-2024.8.3
\ No newline at end of file
+2024.9.0
\ No newline at end of file
diff --git a/changelog/2024.9.0.rst b/changelog/2024.9.0.rst
new file mode 100644
index 0000000000..9739ce790f
--- /dev/null
+++ b/changelog/2024.9.0.rst
@@ -0,0 +1,227 @@
+ESPHome 2024.9.0 - 18th September 2024
+======================================
+
+.. seo::
+ :description: Changelog for ESPHome 2024.9.0.
+ :image: /_static/changelog-2024.9.0.png
+ :author: Jesse Hills
+ :author_twitter: @jesserockz
+
+.. imgtable::
+ :columns: 3
+
+ UDP, components/udp, udp.svg
+ StatsD, components/statsd, connection.svg
+ BL0906, components/sensor/bl0906, bl0906.png
+ CH422G, components/ch422g, ch422g.svg
+ BMP280 SPI, components/sensor/bmp280, bmp280.jpg
+ LTR501 & LTR301 & LTR558, components/sensor/ltr501, ltr501.jpg
+
+UDP & StatsD Components
+-----------------------
+
+This release brings two new data driven components to ESPHome.
+
+The first is the :doc:`UDP Component ` which allows direct communication between ESPHome
+devices over the local network. To start off, only sensor and binary sensor data can be transmitted, and
+hopefully more entity types will be supported in the future.
+
+Next is the :doc:`StatsD Component ` which allows you to send sensor data
+directly to a statsd server for monitoring.
+
+
+Breaking Changes
+----------------
+
+There are a few breaking changes this release that will require changes in YAML if you are
+using the affected components. Please make sure to check the list below for details about each one.
+The documentation is always the best place to find the most up-to-date information on configuration for
+any given component found in ESPHome.
+
+
+Thank you for your support
+--------------------------
+
+Did you know that Jesse and Keith both are employed at `Nabu Casa `__ to work full-time on ESPHome?
+Yep, that's possible thanks to everyone who subscribes to Home Assistant Cloud. Thank you!
+
+
+Full list of changes
+--------------------
+
+New Components
+^^^^^^^^^^^^^^
+
+- Add support for BL0906 energy meter :esphomepr:`7339` by :ghuser:`tarontop` (new-integration)
+- [udp] Implement UDP sensor broadcast :esphomepr:`6865` by :ghuser:`clydebarrow` (new-integration)
+- CH422G support :esphomepr:`7356` by :ghuser:`jesterret` (new-integration)
+- Add StatsD component :esphomepr:`6642` by :ghuser:`Links2004` (new-integration)
+- Add support for using BMP280 with SPI :esphomepr:`7053` by :ghuser:`ademuri` (new-integration) (breaking-change)
+- LTR-501, LTR-301, LTR-558 Series of Lite-On Light (ALS) and Proximity(PS) sensors :esphomepr:`6262` by :ghuser:`latonita` (new-integration)
+
+Breaking Changes
+^^^^^^^^^^^^^^^^
+
+- [ili9xxx] Make `invert_colors` required :esphomepr:`7292` by :ghuser:`gvdhoven` (breaking-change)
+- Add support for using BMP280 with SPI :esphomepr:`7053` by :ghuser:`ademuri` (new-integration) (breaking-change)
+- Move I2S config settings the the base i2sAudio files. Phase 1 :esphomepr:`7183` by :ghuser:`nielsnl68` (breaking-change)
+- [i2s_audio] Add more options to speakers and microphones :esphomepr:`7306` by :ghuser:`pyos` (breaking-change)
+
+Beta Changes
+^^^^^^^^^^^^
+
+- [voice-assistant] Dont error on ``no_wake_word`` timeout error with streaming wake word :esphomepr:`7435` by :ghuser:`jesserockz`
+- Improve manufacturer data tracing to identify BLE devices a bit easie… :esphomepr:`7332` by :ghuser:`tomer-w`
+- Add sample_bytes to media player supported format :esphomepr:`7451` by :ghuser:`synesthesiam`
+- [docker] Bump git from 1:2.39.2-1.1 to 1:2.39.5-0+deb12u1 :esphomepr:`7452` by :ghuser:`jesserockz`
+- Add voice assistant configuration messages :esphomepr:`7445` by :ghuser:`synesthesiam`
+- Dont replace project name spaces with underlines :esphomepr:`7455` by :ghuser:`jesserockz`
+- Add voice assistant methods for configuration :esphomepr:`7459` by :ghuser:`synesthesiam`
+
+All changes
+^^^^^^^^^^^
+
+- [code-quality] fix performance-unnecessary-value-param :esphomepr:`7274` by :ghuser:`tomaszduda23`
+- [code-quality] fix clang-tidy prometheus :esphomepr:`7284` by :ghuser:`tomaszduda23`
+- [code-quality] fix clang-tidy ota :esphomepr:`7282` by :ghuser:`tomaszduda23`
+- [code-quality] fix clang-tidy e131 :esphomepr:`7281` by :ghuser:`tomaszduda23`
+- [code-quality] fix clang-tidy wireguard :esphomepr:`7287` by :ghuser:`tomaszduda23`
+- [code-quality] fix clang-tidy improv_serial :esphomepr:`7283` by :ghuser:`tomaszduda23`
+- [code-quality] fix clang-tidy captive_portal :esphomepr:`7280` by :ghuser:`tomaszduda23`
+- Add HMAC-MD5 support for authenticating OTA updates :esphomepr:`7200` by :ghuser:`dwmw2` (new-integration)
+- [const] Add UNIT_LITRE :esphomepr:`7317` by :ghuser:`Roving-Ronin`
+- [code-quality] fix clang-tidy socket :esphomepr:`7285` by :ghuser:`tomaszduda23`
+- [code-quality] fix clang-tidy cstddef :esphomepr:`7324` by :ghuser:`tomaszduda23`
+- Add output source priority "hybrid" :esphomepr:`7322` by :ghuser:`syssi`
+- Enable verbose mode from env ESPHOME_VERBOSE or --verbose :esphomepr:`6987` by :ghuser:`ptr727`
+- Tuya Number: allow to set hidden datapoints :esphomepr:`7024` by :ghuser:`szupi-ipuzs`
+- feat: Expand ByteBuffer :esphomepr:`7316` by :ghuser:`Rapsssito`
+- [ledc] Tweak fix in #6997 :esphomepr:`7336` by :ghuser:`kbx81`
+- [ledc] Fix maximum brightness on ESP-IDF 5.1 :esphomepr:`7342` by :ghuser:`clydebarrow`
+- [lvgl] Bug fixes: :esphomepr:`7341` by :ghuser:`clydebarrow`
+- [const] Move ``CONF_LINE_FREQUENCY`` to const.py :esphomepr:`7351` by :ghuser:`jesserockz`
+- bl0942: Fix init sequence, add address and line_frequency options :esphomepr:`7250` by :ghuser:`dwmw2`
+- Add supported formats to media player :esphomepr:`7318` by :ghuser:`synesthesiam`
+- Add reset to esp32_rmt_led_strip :esphomepr:`7354` by :ghuser:`angelnu`
+- [ili9xxx] Make `invert_colors` required :esphomepr:`7292` by :ghuser:`gvdhoven` (breaking-change)
+- Add WS2811 to esp32_rmt_led_strip :esphomepr:`7353` by :ghuser:`angelnu`
+- [lvgl] Add lvgl.widget.focus action and related triggers. :esphomepr:`7315` by :ghuser:`clydebarrow`
+- esp32_can: suppress compiler warning :esphomepr:`7372` by :ghuser:`mrk-its`
+- Add support for BL0906 energy meter :esphomepr:`7339` by :ghuser:`tarontop` (new-integration)
+- [platformio] Add environments for ESP-IDF 5.3 for development :esphomepr:`7371` by :ghuser:`clydebarrow`
+- [lvgl] Bug fixes :esphomepr:`7370` by :ghuser:`clydebarrow`
+- [bytebuffer] Use existing bit_cast operations. :esphomepr:`7374` by :ghuser:`clydebarrow`
+- Bump actions/setup-python from 5.1.0 to 5.2.0 :esphomepr:`7375` by :ghuser:`dependabot[bot]`
+- Bump actions/setup-python from 5.1.1 to 5.2.0 in /.github/actions/restore-python :esphomepr:`7376` by :ghuser:`dependabot[bot]`
+- [gt911] Add reset pin config :esphomepr:`7373` by :ghuser:`clydebarrow`
+- [st7701s] Add delay feature in init sequences :esphomepr:`7343` by :ghuser:`clydebarrow`
+- Add now required `invert_colors` option to test files referencing ili9xxx :esphomepr:`7367` by :ghuser:`clydebarrow`
+- esp32_can: make queue lengths configurable :esphomepr:`7361` by :ghuser:`mrk-its`
+- [code-quality] fix clang-tidy web_server and web_server_base :esphomepr:`7286` by :ghuser:`tomaszduda23`
+- Update MiCS Values :esphomepr:`7173` by :ghuser:`TrevorSchirmer`
+- Tuya Number: allow restoring value of hidden datapoints :esphomepr:`7346` by :ghuser:`szupi-ipuzs`
+- [udp] Implement UDP sensor broadcast :esphomepr:`6865` by :ghuser:`clydebarrow` (new-integration)
+- update logs for bluetooth proxy :esphomepr:`7382` by :ghuser:`tomaszduda23`
+- [font] Make display an auto-load, not a dependency :esphomepr:`7366` by :ghuser:`clydebarrow`
+- CH422G support :esphomepr:`7356` by :ghuser:`jesterret` (new-integration)
+- [rpi_dpi_rgb] Add enable_pin and reset_display method to driver :esphomepr:`7383` by :ghuser:`lboue`
+- Bump actions/upload-artifact from 4.3.4 to 4.4.0 :esphomepr:`7379` by :ghuser:`dependabot[bot]`
+- Fix build for esp32h2 using esp-idf 5.3 :esphomepr:`7393` by :ghuser:`mrene`
+- Bump mDNS and follow ruff's suggestions :esphomepr:`7308` by :ghuser:`HeMan`
+- Bump rp2040 Arduino platform and framework :esphomepr:`7134` by :ghuser:`HeMan`
+- [gree] Add support for YX1FF remote :esphomepr:`7298` by :ghuser:`dangreco`
+- [modbus_controller] Allow duplicate command config :esphomepr:`7311` by :ghuser:`0x3333`
+- Better support for task blocking ring buffer reads and writes :esphomepr:`7390` by :ghuser:`kahrendt`
+- Bump pypa/gh-action-pypi-publish from 1.9.0 to 1.10.0 :esphomepr:`7395` by :ghuser:`dependabot[bot]`
+- [api] Remove id from ``MediaPlayerSupportedFormat`` :esphomepr:`7406` by :ghuser:`jesserockz`
+- Drop max BLE client connections limitation :esphomepr:`7088` by :ghuser:`syssi`
+- [bl0942] loop and overflow cleanup :esphomepr:`7358` by :ghuser:`dwmw2`
+- Bump peter-evans/create-pull-request from 6.1.0 to 7.0.0 :esphomepr:`7405` by :ghuser:`dependabot[bot]`
+- Bump pypa/gh-action-pypi-publish from 1.10.0 to 1.10.1 :esphomepr:`7404` by :ghuser:`dependabot[bot]`
+- Voice assist improvement - configurable conversation_id timeout :esphomepr:`7385` by :ghuser:`jeffc`
+- Support BL0942 calibration :esphomepr:`7299` by :ghuser:`dwmw2`
+- [micro_wake_word] Remove duplicated download code :esphomepr:`7401` by :ghuser:`jesserockz`
+- Add StatsD component :esphomepr:`6642` by :ghuser:`Links2004` (new-integration)
+- [homeassistant-switch] Support different entity domains :esphomepr:`7331` by :ghuser:`jesserockz`
+- Add support for using BMP280 with SPI :esphomepr:`7053` by :ghuser:`ademuri` (new-integration) (breaking-change)
+- Add voice assistant announce :esphomepr:`7377` by :ghuser:`synesthesiam`
+- [lvgl] Msgbox fixes and enhancements :esphomepr:`7380` by :ghuser:`clydebarrow`
+- libretiny: Allow specifying version of explicitly imported sources :esphomepr:`7408` by :ghuser:`dwmw2`
+- [libretiny] Report version 1.7.0 for 'dev' and 'latest' :esphomepr:`7415` by :ghuser:`dwmw2`
+- LTR-501, LTR-301, LTR-558 Series of Lite-On Light (ALS) and Proximity(PS) sensors :esphomepr:`6262` by :ghuser:`latonita` (new-integration)
+- Fix armv7 container builds :esphomepr:`7426` by :ghuser:`jesserockz`
+- [gh-actions] Don't produce docker build summaries :esphomepr:`7430` by :ghuser:`jesserockz`
+- Add BK72xx support to require_framework_version() :esphomepr:`7409` by :ghuser:`dwmw2`
+- Switch IPv6 platform check to use require_framework_version() :esphomepr:`7410` by :ghuser:`dwmw2`
+- [bl0942] Improve energy reporting :esphomepr:`7428` by :ghuser:`dwmw2`
+- [rpi_dpi_rgb] Add bounce_buffer config for ESP-IDF 5.x :esphomepr:`7423` by :ghuser:`clydebarrow`
+- [LVGL] Add color gradients :esphomepr:`7427` by :ghuser:`clydebarrow`
+- [dsmr] Add internal 'telegram' text_sensor to support bridging :esphomepr:`6841` by :ghuser:`marcovaneck`
+- Pull in new AsyncTCP for IPv6 on BK72xx :esphomepr:`7431` by :ghuser:`dwmw2`
+- Bump LibreTiny recommended version to 1.7.0 :esphomepr:`7432` by :ghuser:`dwmw2`
+- Enable IPv6 support for BK72xx :esphomepr:`7398` by :ghuser:`dwmw2`
+- Move I2S config settings the the base i2sAudio files. Phase 1 :esphomepr:`7183` by :ghuser:`nielsnl68` (breaking-change)
+- Implement all supported thermocouple types for MAX31856 :esphomepr:`7218` by :ghuser:`ArkanStasarik`
+- [i2s_audio] Add more options to speakers and microphones :esphomepr:`7306` by :ghuser:`pyos` (breaking-change)
+- [uponor_smatrix] Modifies sending algorithm :esphomepr:`7326` by :ghuser:`skasi7`
+- User configurable frame buffer. :esphomepr:`7360` by :ghuser:`ajwahab`
+- [Modbus Controller] Added preference to change command retries :esphomepr:`7312` by :ghuser:`0x3333`
+- [voice-assistant] Dont error on ``no_wake_word`` timeout error with streaming wake word :esphomepr:`7435` by :ghuser:`jesserockz`
+- Improve manufacturer data tracing to identify BLE devices a bit easie… :esphomepr:`7332` by :ghuser:`tomer-w`
+- Add sample_bytes to media player supported format :esphomepr:`7451` by :ghuser:`synesthesiam`
+- [docker] Bump git from 1:2.39.2-1.1 to 1:2.39.5-0+deb12u1 :esphomepr:`7452` by :ghuser:`jesserockz`
+- Add voice assistant configuration messages :esphomepr:`7445` by :ghuser:`synesthesiam`
+- Dont replace project name spaces with underlines :esphomepr:`7455` by :ghuser:`jesserockz`
+- Add voice assistant methods for configuration :esphomepr:`7459` by :ghuser:`synesthesiam`
+
+Past Changelogs
+---------------
+
+- :doc:`2024.8.0`
+- :doc:`2024.7.0`
+- :doc:`2024.6.0`
+- :doc:`2024.5.0`
+- :doc:`2024.4.0`
+- :doc:`2024.3.0`
+- :doc:`2024.2.0`
+- :doc:`2023.12.0`
+- :doc:`2023.11.0`
+- :doc:`2023.10.0`
+- :doc:`2023.9.0`
+- :doc:`2023.8.0`
+- :doc:`2023.7.0`
+- :doc:`2023.6.0`
+- :doc:`2023.5.0`
+- :doc:`2023.4.0`
+- :doc:`2023.3.0`
+- :doc:`2023.2.0`
+- :doc:`2022.12.0`
+- :doc:`2022.11.0`
+- :doc:`2022.10.0`
+- :doc:`2022.9.0`
+- :doc:`2022.8.0`
+- :doc:`2022.6.0`
+- :doc:`2022.5.0`
+- :doc:`2022.4.0`
+- :doc:`2022.3.0`
+- :doc:`2022.2.0`
+- :doc:`2022.1.0`
+- :doc:`2021.12.0`
+- :doc:`2021.11.0`
+- :doc:`2021.10.0`
+- :doc:`2021.9.0`
+- :doc:`2021.8.0`
+- :doc:`v1.20.0`
+- :doc:`v1.19.0`
+- :doc:`v1.18.0`
+- :doc:`v1.17.0`
+- :doc:`v1.16.0`
+- :doc:`v1.15.0`
+- :doc:`v1.14.0`
+- :doc:`v1.13.0`
+- :doc:`v1.12.0`
+- :doc:`v1.11.0`
+- :doc:`v1.10.0`
+- :doc:`v1.9.0`
+- :doc:`v1.8.0`
+- :doc:`v1.7.0`
diff --git a/changelog/index.rst b/changelog/index.rst
index 0d8b249826..614356b809 100644
--- a/changelog/index.rst
+++ b/changelog/index.rst
@@ -2,7 +2,7 @@ Changelog
=========
.. redirect::
- :url: /changelog/2024.8.0.html
+ :url: /changelog/2024.9.0.html
.. toctree::
:glob:
diff --git a/components/binary_sensor/udp.rst b/components/binary_sensor/udp.rst
new file mode 100644
index 0000000000..a4122ed56d
--- /dev/null
+++ b/components/binary_sensor/udp.rst
@@ -0,0 +1,49 @@
+UDP Binary Sensor
+=================
+
+.. seo::
+ :description: Instructions for setting up a UDP binary sensor.
+ :image: udp.svg
+
+The ``udp`` binary sensor platform allows you to receive binary sensor data directly from another ESPHome node.
+
+.. code-block:: yaml
+
+ # Example configuration entry
+ binary_sensor:
+ - platform: udp
+ id: switch_status
+ provider: light-switch
+ remote_id: light_switch
+
+Configuration variables
+-----------------------
+
+- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation.
+- **provider** (**Required**, string): The name of the provider node.
+- **remote_id** (*Optional*, :ref:`config-id`): The ID of the original binary sensor in the provider device. If not specified defaults to the ID configured with ``id:``.
+- **name** (*Optional*, string): The name of the binary sensor.
+- **internal** (*Optional*, boolean): Whether the sensor should be exposed via API (e.g. to Home Assistant.) Defaults to ``true`` if name is not set, required if name is provided.
+- All other options from :ref:`Binary Sensor `.
+
+At least one of ``id`` and ``remote_id`` must be configured.
+
+Publishing to Home Assistant
+----------------------------
+
+Typically this type of binary sensor would be used for internal automation purposes rather than having it published back to
+Home Assistant, since it would be a duplicate of the original sensor.
+
+If it *is* desired to expose the binary sensor to Home Assistant, then the ``internal:`` configuration setting needs to be explicitly
+set to ``false`` and a name provided.
+Only the state (i.e. binary value) of the remote sensor is received by the consumer, so any other attributes must be explicitly
+configured.
+
+See Also
+--------
+
+- :doc:`/components/udp`
+- :doc:`/components/sensor/index`
+- :ref:`automation`
+- :apiref:`udp/udp_component.h`
+- :ghedit:`Edit`
diff --git a/components/canbus/esp32_can.rst b/components/canbus/esp32_can.rst
index bc973f08e2..2dbd41d33b 100644
--- a/components/canbus/esp32_can.rst
+++ b/components/canbus/esp32_can.rst
@@ -26,6 +26,8 @@ Configuration variables:
- **rx_pin** (**Required**, :ref:`Pin `): Receive pin.
- **tx_pin** (**Required**, :ref:`Pin `): Transmit pin.
+- **rx_queue_len** (**Optional**, int): Length of RX queue.
+- **tx_queue_len** (**Optional**, int): Length of TX queue, 0 to disable.
- All other options from :ref:`Canbus `.
.. _esp32-can-bit-rate:
diff --git a/components/ch422g.rst b/components/ch422g.rst
new file mode 100644
index 0000000000..6e01234d10
--- /dev/null
+++ b/components/ch422g.rst
@@ -0,0 +1,67 @@
+CH422G I/O Expander
+====================
+
+.. seo::
+ :description: Instructions for setting up CH422G digital port expanders in ESPHome.
+ :image: ch422g.svg
+
+
+The CH422G component allows you to use the **CH422G** I/O expander in ESPHome.
+It uses an :ref:`I²C Bus ` for communication.
+
+Once configured, you can use any of the 8 available GPIO pins for your projects.
+Within ESPHome they can be used in place of internal GPIO pins in many of ESPHome's components such as the GPIO Binary Sensor or GPIO Switch. They are not usable for PWM or other situations requiring an internal GPIO pin.
+
+.. note::
+
+ This I/O Expander chip is used in the *Waveshare ESP32-S3-Touch-LCD-4.3*
+
+.. code-block:: yaml
+
+ # Example configuration entry
+ ch422g:
+ - id: ch422g_hub
+ address: 0x24
+
+ # Individual outputs
+ switch:
+ - platform: gpio
+ name: CH422G Pin 0
+ pin:
+ ch422g: ch422g_hub
+ number: 0
+ mode:
+ output: true
+ inverted: false
+
+
+Configuration variables:
+************************
+
+- **id** (**Required**, :ref:`config-id`): The id to use for this ``ch422g`` component.
+- **address** (*Optional*, int): The I²C address of the driver.
+ Defaults to ``0x24``.
+- **restore_value** (*Optional*, boolean): Writes default flags on setup, overriding values from chips cache.
+ Defaults to ``false``.
+
+
+
+Pin configuration variables:
+****************************
+
+- **ch422g** (**Required**, :ref:`config-id`): The id of the ``ch422g`` component of the pin.
+- **number** (**Required**, int): The pin number. Valid numbers are 0-7.
+- **inverted** (*Optional*, boolean): If all read and written values
+ should be treated as inverted. Defaults to ``false``.
+- **mode** (*Optional*, string): A pin mode to set the pin at. One of ``INPUT`` or ``OUTPUT``.
+
+
+See Also
+--------
+
+- :ref:`i2c`
+- :doc:`switch/gpio`
+- :doc:`binary_sensor/gpio`
+- `CH422G datasheet `__
+- :apiref:`ch422g/ch422g.h`
+- :ghedit:`Edit`
diff --git a/components/climate/climate_ir.rst b/components/climate/climate_ir.rst
index 38c062bde6..a6e6764df3 100644
--- a/components/climate/climate_ir.rst
+++ b/components/climate/climate_ir.rst
@@ -162,6 +162,7 @@ The Daikin ARC remotes (``daikin_arc`` climate, ``daikin_arc417``, ``daikin_arc4
- ``yaa``
- ``yac``
- ``yac1fb9``
+ - ``yx1ff``
.. code-block:: yaml
diff --git a/components/display/ili9xxx.rst b/components/display/ili9xxx.rst
index 7b729c2b81..4962e63d9f 100644
--- a/components/display/ili9xxx.rst
+++ b/components/display/ili9xxx.rst
@@ -60,9 +60,10 @@ beyond the basic SPI connections, and a reasonable amount of RAM, it is not well
- platform: ili9xxx
model: ili9341
dc_pin: GPIOXX
+ reset_pin: GPIOXX
+ invert_colors: false
show_test_card: true
-
Configuration variables:
************************
@@ -103,7 +104,7 @@ All :ref:`graphical display configuration` options are av
- **offset_width** (*Optional*, int): Specify an offset for the x-direction of the display, typically used when an LCD is smaller than the maximum supported by the driver chip. Default is 0
- **offset_height** (*Optional*, int): Specify an offset for the y-direction of the display. Default is 0.
-- **invert_colors** (*Optional*): With this boolean option you can invert the display colors.
+- **invert_colors** (**Required**): Specifies whether the display colors should be inverted. Options are ``true`` or ``false`` - if you are unsure, use ``false`` and change if the colors are not as expected.
- **pixel_mode** (*Optional*): Allows forcing the display into 18 or 16 bit mode. Options are ``18bit`` or ``16bit``. If unspecified, the pixel mode will be determined by the model choice. Not all displays will work in both modes.
- **rotation** (*Optional*): Rotate the display presentation in software. Choose one of ``0°``, ``90°``, ``180°``, or ``270°``. This option cannot be used with ``transform``.
- **transform** (*Optional*): Transform the display presentation using hardware. All defaults are ``false``. This option cannot be used with ``rotation``.
@@ -267,6 +268,7 @@ This config rotates the display into landscape mode using the driver chip.
mirror_x: false
mirror_y: true
color_order: bgr
+ invert_colors: true
data_rate: 80MHz
cs_pin: GPIOXX
dc_pin: GPIO13
diff --git a/components/display/rpi_dpi_rgb.rst b/components/display/rpi_dpi_rgb.rst
index 2b5ae9526f..5a52cc232d 100644
--- a/components/display/rpi_dpi_rgb.rst
+++ b/components/display/rpi_dpi_rgb.rst
@@ -77,6 +77,7 @@ Configuration variables:
- **pclk_pin** (**Required**, :ref:`Pin Schema `): The PCLK pin.
- **hsync_pin** (**Required**, :ref:`Pin Schema `): The Horizontal sync pin.
- **vsync_pin** (**Required**, :ref:`Pin Schema `): The Vertical sync pin.
+- **enable_pin** (*Optional*, :ref:`Pin Schema `): The ENABLE pin.
- **reset_pin** (*Optional*, :ref:`Pin Schema `): The RESET pin.
- **hsync_pulse_width** (*Optional*, int): The horizontal sync pulse width.
- **hsync_front_porch** (*Optional*, int): The horizontal front porch length.
diff --git a/components/display/st7701s.rst b/components/display/st7701s.rst
index f098b2d35f..2ce5dcfac8 100644
--- a/components/display/st7701s.rst
+++ b/components/display/st7701s.rst
@@ -125,6 +125,8 @@ The ``init_sequence`` requires a list of elements, one of which may be a single
sequence (the default and currently the only sequence is 1), the remainder must be byte arrays providing additional
init commands, each consisting of a command byte followed by zero or more data bytes.
+A delay may be specified with ``delay ms``
+
These will be collected and sent to the display via SPI during initialisation.
Example configurations
@@ -160,6 +162,7 @@ Seeed Sensecap Indicator
pclk_pin: 21
init_sequence:
- 1 # select canned init sequence number 1
+ - delay 5ms
- [ 0xE0, 0x1F ] # Set sunlight readable enhancement
data_pins:
red:
diff --git a/components/esp32_camera.rst b/components/esp32_camera.rst
index cc146c7a71..9402af34d3 100644
--- a/components/esp32_camera.rst
+++ b/components/esp32_camera.rst
@@ -74,6 +74,8 @@ Frame Settings:
Up to 60Hz is possible (with reduced frame sizes), but beware of overheating. Defaults to ``10 fps``.
- **idle_framerate** (*Optional*, float): The framerate to capture images at when no client
is requesting a full stream. Defaults to ``0.1 fps``.
+- **frame_buffer_count** (*Optional*, int): The number of frame buffers to use when reading from the camera sensor.
+ Must be between 1 and 2. Defaults to ``1``.
Image Settings:
diff --git a/components/light/esp32_rmt_led_strip.rst b/components/light/esp32_rmt_led_strip.rst
index cb19142449..fc27cc4863 100644
--- a/components/light/esp32_rmt_led_strip.rst
+++ b/components/light/esp32_rmt_led_strip.rst
@@ -34,6 +34,7 @@ Configuration variables
"ESP32-C3", "0, 1"
- **chipset** (**Required**, enum): The chipset to apply known timings from. Not used if specifying the timings manually, see below.
+ - ``WS2811``
- ``WS2812``
- ``SK6812``
- ``APA106``
@@ -67,6 +68,10 @@ please consider adding support to the codebase and add it to the list above.
- **bit0_low** (*Optional*, :ref:`config-time`): The time to hold the data line low for a ``0`` bit.
- **bit1_high** (*Optional*, :ref:`config-time`): The time to hold the data line high for a ``1`` bit.
- **bit1_low** (*Optional*, :ref:`config-time`): The time to hold the data line low for a ``1`` bit.
+- **reset_high** (*Optional*, :ref:`config-time`): The time to hold the data line high after writing
+ the state. Defaults to ``0 us``.
+- **reset_low** (*Optional*, :ref:`config-time`): The time to hold the data line low after writing
+ the state. Defaults to ``0 us``.
See Also
--------
diff --git a/components/lvgl/index.rst b/components/lvgl/index.rst
index f55b8b1003..86a0a5651d 100644
--- a/components/lvgl/index.rst
+++ b/components/lvgl/index.rst
@@ -10,12 +10,13 @@ embedded graphics library to create beautiful UIs for any MCU, MPU and display t
.. figure:: /components/lvgl/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.
+To use LVGL with a :ref:`display ` in ESPHome, you'll need an ESP32 or RP2040. PSRAM is not a strict requirement but it is generally recommended, especially for large color 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 :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.
+Check out the detailed examples in :ref:`the Cookbook ` which demonstrate a number of ways you can integrate your environment with LVGL and ESPHome.
Basics
------
@@ -113,6 +114,7 @@ The following configuration variables apply to the main ``lvgl`` component, in o
- **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.
+- **gradients** (*Optional*, list): A list of gradient definitions to use in *bg_grad* styles. 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 :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:
@@ -145,6 +147,7 @@ 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 which demonstrates how to implement a page navigation bar at the bottom of the screen.
.. _lvgl-color:
@@ -175,6 +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-cookbook-icontext`, :ref:`lvgl-cookbook-iconstat` and :ref:`lvgl-cookbook-iconbatt` in the Cookbook for examples which demonstrate how to use icons and text with TrueType/OpenType fonts.
**Library fonts**
@@ -243,6 +247,7 @@ You can adjust the appearance of widgets by changing their foreground, backgroun
**Styling variables:**
- **bg_color** (*Optional*, :ref:`color `): Color for the background of the widget. Defaults to ``0xFFFFFF`` (white).
+- **bg_grad** (*Optional*, :ref:`gradient `): A gradient to apply to the background.
- **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``.
@@ -376,6 +381,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-cookbook-theme` The Cookbook contains an example which demonstrates how to implement a gradient style for your widgets.
.. _lvgl-layouts:
@@ -386,6 +392,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.
+Check out :ref:`lvgl-cookbook-flex`, :ref:`lvgl-cookbook-grid` and :ref:`lvgl-cookbook-weather` in the Cookbook for examples which demonstrate 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.
@@ -519,6 +526,46 @@ Values for use with ``grid_column_align``, ``grid_row_align``, ``grid_cell_x_ali
To visualize real, calculated sizes of transparent widgets you can temporarily set ``outline_width: 1`` on them.
+.. _lvgl-gradients:
+
+Gradients
+*********
+
+A gradient is a sequence of colors which can be applied to an object using the ``bg_grad`` style option. Gradients are defined in the *gradients* section of the LVGL configuration by providing two or more color stop points.
+ Each entry has the following options:
+
+- **id** (**Required**, :ref:`config-id`): The ID with which you will be able to reference the gradient later.
+- **direction** (*Optional*, string): The direction of the gradient. Possible options are ``none`` (the default) ``hor`` or ``ver``.
+- **dither** (*Optional*, string): A dithering selection. Possible options are ``none`` (the default) ``err_diff`` or ``ordered``.
+- **stops** (**Required**, list): A list of at least 2 color stop points. Each stop point has the following options:
+ - **color** (**Required**, :ref:`Color `): The color of the stop point.
+ - **position** (**Required**, float): The position of the stop point. Must be a float between 0.0 and 1.0, a percentage between 0% and 100%, or an integer between 0 and 255.
+
+.. code-block:: yaml
+
+ # Example gradient showing full hue range.
+
+ gradients:
+ - id: color_bar
+ direction: hor
+ dither: none
+ stops:
+ - color: 0xFF0000
+ position: 0
+ - color: 0xFFFF00
+ position: 42
+ - color: 0x00FF00
+ position: 84
+ - color: 0x00FFFF
+ position: 127
+ - color: 0x0000FF
+ position: 169
+ - color: 0xFF00FF
+ position: 212
+ - color: 0xFF0000
+ position: 255
+
+
Widgets
*******
@@ -552,7 +599,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.
+- **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 which demonstrates how to use this.
.. code-block:: yaml
@@ -635,6 +682,56 @@ This :ref:`action ` shows a specific page (including pages with
then:
- lvgl.page.show: secret_page # shorthand version
+.. _lvgl-widget-focus-action:
+
+``lvgl.widget.focus``
+*********************
+
+This :ref:`action ` moves the input focus to the nominated widget. Used mainly with encoder inputs
+to select a specific widget to receive input events. It may also allow the focus to be frozen on that widget,
+or can be used to move the focus to the next or previous widget in the focus group.
+
+The required config options take one of several forms:
+
+- **id** (**Required**): The ID of the widget to be given focus.
+- **freeze** (*Optional*, boolean): If true will lock the focus to this widget.
+- **editing** (*Optional*, boolean): Sets the editing mode of the widget, i.e. encoder rotation will change the value
+ of the widget, not move the focus. Defaults to false.
+
+or
+
+- **action** (**Required**): Should be one of ``next``, ``previous``, ``mark`` or ``restore``.
+- **group** (*Optional*): The ID of the group within which to move the focus. The default group will be used if not specified
+- **freeze** (*Optional*, boolean): If true will lock the focus to the now selected widget.
+
+
+The ``next`` and ``previous`` actions will move the focus to the next or previous widget within the group.
+The ``mark`` action will save the currently focused widget within the group, and restore it when the ``restore`` action is triggered.
+
+.. code-block:: yaml
+
+ on_...:
+ then:
+ - lvgl.widget.focus:
+ id: my_button
+ freeze: true
+
+ on_...:
+ then:
+ - lvgl.widget.focus: my_button
+
+ on_...:
+ then:
+ - lvgl.widget.focus:
+ group: encoder_group
+ direction: next
+ freeze: true
+
+ on_...:
+ then:
+ - lvgl.widget.focus: previous
+
+
.. _lvgl-conditions:
Conditions
@@ -709,6 +806,7 @@ 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 which demonstrates how to implement screen saving with idle settings.
See Also
--------
@@ -719,6 +817,7 @@ 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 173406ec8d..1909bebcf8 100644
--- a/components/lvgl/widgets.rst
+++ b/components/lvgl/widgets.rst
@@ -40,7 +40,7 @@ The properties below are common to all widgets.
- ``"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** (*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**, string): Desired alignment (one of the values starting with ``OUT_``).
@@ -83,6 +83,8 @@ 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 which demonstrates how to use styling and properties to show different states of a Home Assistant entity.
+
.. _lvgl-widget-flags:
In addition to visual styling, each widget supports some boolean **flags** to influence the behavior:
@@ -114,7 +116,41 @@ 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.
+ 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-widget-parts:
+
+Widget parts
+------------
+
+Widgets can have multiple parts, each of which can be styled independently. For example, a checkbox has a *main* part that styles the background and text label, and an *indicator* part that styles the tick box. All widgets have a *main* part, the available parts for other widgets are specified in the widget description.
+
+The possible parts are:
+
+- **main** (*Optional*, dict): The main part of the widget, i.e. the background. Any style properties applied at the top level of the widget are assumed to apply to this part, but may also be specified under the *main* config key.
+- **scrollbar** (*Optional*, dict): The scrollbar styles.
+- **indicator** (*Optional*, dict): The indicator part of the widget. The indicator part may be used to show tick boxes or other visual indicators in slider, bar or arc.
+- **knob** (*Optional*, dict): The knob part of the widget e.g. a draggable item in slider, bar or arc.
+- **selected** (*Optional*, dict): The currently selected part of the widget, e.g. text or the selected item in a roller.
+- **items** (*Optional*, dict): The items part of the widget, e.g. the items in a roller.
+- **ticks** (*Optional*, dict): Ticks on scales for a meter.
+- **cursor** (*Optional*, dict): The cursor part of the widget, e.g. the cursor in a spinbox.
+
+.. code-block:: yaml
+
+ # Example slider with knob and indicator styling
+ - slider:
+ # main (background) styles
+ bg_opa: cover
+ bg_grad: color_bar
+ radius: 0
+ indicator:
+ bg_opa: transp # Makes the indicator part invisible
+ knob:
+ radius: 1
+ width: 4
+ height: 10%
+ bg_color: 0x000000
Widget-specific properties
--------------------------
@@ -230,6 +266,8 @@ 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-arc:
``arc``
@@ -311,7 +349,9 @@ If the ``adv_hittest`` :ref:`flag ` is enabled the arc can be
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.
+The ``arc`` can be also integrated as a :doc:`Number ` or :doc:`Sensor ` component.
+
+See :ref:`lvgl-cookbook-bright` and :ref:`lvgl-cookbook-volume` for examples which demonstrate how to use a slider (or an arc) to control entities in Home Assistant.
.. _lvgl-widget-bar:
@@ -432,6 +472,8 @@ 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 which demonstrates how to use a checkable button to act on a Home Assistant service.
+
.. _lvgl-widget-buttonmatrix:
``buttonmatrix``
@@ -562,7 +604,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.
+ 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-checkbox:
@@ -622,7 +664,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.
+ 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` for how to easily resolve this.
The ``checkbox`` can be also integrated as a :doc:`Switch ` component.
@@ -776,8 +818,8 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-widget
**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.
+- **textarea** (*Optional*): The ID of a ``textarea`` to associate with the keyboard. If provided, all key entries are recorded in the ``textarea``.
+- **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.
@@ -785,9 +827,9 @@ For styling, the ``keyboard`` widget uses the same settings as :ref:`lvgl-widget
**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.
+- ``lvgl.keyboard.update`` :ref:`action ` updates the properties from the specific options above, plus any from :ref:`lvgl.widget.update `.
+ - **id** (**Required**): The ID or a list of IDs of keyboard widgets which you want to update.
+ - Styles or properties to be updated.
**Triggers:**
@@ -851,7 +893,7 @@ A label is the basic widget type that is used to display text.
- **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_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 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.
@@ -954,6 +996,8 @@ 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 which demonstrates how to change the ``led`` styling properties from an automation.
+
.. _lvgl-widget-line:
``line``
@@ -1050,6 +1094,9 @@ The meter widget can visualize data in very flexible ways. It can use arcs, need
- **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.
+- **ticks** (*Optional*, dict): Styling options for the ticks *part*, which will be applied to the tick lines and labels using standard *line* and *label* styles.
+- **indicator** (*Optional*, dict): Styling options for the indicator *part*, which will be applied to the needle line or image using standard *line* and *image* styles.
+- **items** (*Optional*, dict): Settings for the items *part*, which will be applied to arcs.
.. note::
@@ -1102,6 +1149,8 @@ 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 which demonstrate how to effectively use this widget.
+
.. _lvgl-widget-msgbox:
``msgboxes``
@@ -1116,7 +1165,7 @@ The text will be broken into multiple lines automatically and the height will be
**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.
+- **msgboxes** (*Optional*, list): A list of message boxes to use. This option is available only at the top level of the LVGL component configuration. Each list entry may have the following options:
- **title** (**Required**, string): A string to display at the top of the message box.
- **body** (*Optional*, dict): The content of the body of the message box:
- **text** (*Optional*, :ref:`text-property`): The text to display in the body of the message box.
@@ -1124,11 +1173,12 @@ The text will be broken into multiple lines automatically and the height will be
- **buttons** (*Optional*, list): A list of buttons to show at the bottom of the message box:
- **text** (*Optional*, :ref:`text-property`): Text to display on the button.
- See :ref:`lvgl-widget-buttonmatrix` for other options for the buttons.
- - **close_button** (*Optional*, boolean): Controls the appearance of the close button to the top right of the message box.
+ - **button_style** (*Optional*, dict): A style to apply to the buttons. Uses all the typical style properties. Buttons cannot be individually styled since they are part of a ``buttonmatrix``.
+ - **close_button** (*Optional*, boolean): Controls the presence of the close button to the top right of the message box. Defaults to true
**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. They can be shown and hidden using ``lvgl.widget.show`` and ``lvgl.widget.hide`` respectively :ref:`actions `.
**Example:**
@@ -1203,7 +1253,7 @@ Roller allows you to simply select one option from a list by scrolling.
**Configuration variables:**
- **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``.
+- **mode** (*Optional*, enum): 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.
@@ -1324,6 +1374,8 @@ 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 which demonstrate how to use a slider to control entities in Home Assistant.
+
.. _lvgl-widget-spinbox:
``spinbox``
@@ -1399,7 +1451,9 @@ 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:`Number ` or :doc:`Sensor ` component.
+The ``spinbox`` can be also integrated as a :doc:`Number ` or :doc:`Sensor ` component.
+
+See :ref:`lvgl-cookbook-climate` for an example which demonstrates how to implement a thermostat control using the spinbox.
.. _lvgl-widget-spinner:
@@ -1493,6 +1547,8 @@ 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 which demonstrates how to use a switch to act on a local component.
+
.. _lvgl-widget-tabview:
``tabview``
@@ -1507,14 +1563,14 @@ The tabs are indexed (zero-based) in the order they appear in the configuration
**Configuration variables:**
-- **position** (*Optional*, string): Position of the tab selector buttons. One of ``TOP``, ``BOTTOM``, ``LEFT``, ``RIGHT``. Defaults to ``TOP``.
+- **position** (*Optional*, enum): 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 :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.
+ - **items** (*Optional*, dict): Settings for the items *part*, the buttons all use the text and typical background style properties except translations and transformations.
**Actions:**
@@ -1743,6 +1799,7 @@ 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 which demonstrates how to use a template to update the state.
.. _lvgl-automation-shorthands:
@@ -1807,9 +1864,15 @@ ESPHome implements as universal triggers the following interaction events genera
- ``on_scroll``: The widget was scrolled.
- ``on_focus``: The widget is focused.
- ``on_defocus``: The widget is unfocused.
+- ``on_all_events``: Will be triggered on any event sent to the widget - this is useful for debugging.
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.
+Each trigger also deliver an ``event`` parameter, which is a pointer to the LVGL C type ``lv_event_t``. This may be used in lambdas defined within those triggers. Refer to the `LVGL documentation `_ for more information.
+
+There are additional triggers for pages - each page may have an ``on_load`` and ``on_unload`` trigger. These will be called
+when the page becomes active or inactive respectively.
+
.. code-block:: yaml
# Example triggers:
diff --git a/components/microphone/i2s_audio.rst b/components/microphone/i2s_audio.rst
index 42aa8f3898..952a23c0fa 100644
--- a/components/microphone/i2s_audio.rst
+++ b/components/microphone/i2s_audio.rst
@@ -40,13 +40,14 @@ Configuration variables:
- ``external``: Use an external ADC connected to the I²S bus.
- ``internal``: Use the internal ADC of the ESP32. Only supported on ESP32, no variant support.
-- **channel** (*Optional*, enum): The channel of the microphone. One of ``left`` or ``right``. Defaults to ``right``.
+- **channel** (*Optional*, enum): The channel of the microphone. One of ``left``, ``right``, or ``stereo``. If ``stereo``, the output data will
+ be twice as big, with each right sample followed by a left sample. Defaults to ``right``.
- **sample_rate** (*Optional*, positive integer): I2S sample rate. Defaults to ``16000``.
-- **bits_per_sample** (*Optional*, enum): The bit depth of the audio samples. Note that while set to ``32bit``, the samples
- will be scaled down to 16bit before being forwarded.
- One of ``16bit`` or ``32bit``. Defaults to ``32bit``.
+- **bits_per_sample** (*Optional*, enum): The bit depth of the audio samples. Note that while set to ``24bit`` or ``32bit``, the samples
+ will be scaled down to 16bit before being forwarded. One of ``8bit``, ``16bit``, ``24bit``, or ``32bit``. Defaults to ``32bit``.
+- **bits_per_channel** (*Optional*, enum): The bit depth of the audio channels. See the datasheet of your I2S device for details. Defaults to ``bits_per_sample``.
- **use_apll** (*Optional*, boolean): I2S using APLL as main I2S clock, enable it to get accurate clock. Defaults to ``false``.
-- **i2s_mode** (*Optional*, enum): The I²S mode to use. One of ``primary`` or ``secondary``. Defaults to ``primary``.
+- **i2s_mode** (*Optional*, enum): The I²S mode to use. One of ``primary`` (clock driven by the host) or ``secondary`` (clock driven by the attached device). Defaults to ``primary``.
- **i2s_audio_id** (*Optional*, :ref:`config-id`): The ID of the :ref:`I²S Audio ` you wish to use for this microphone.
- All other options from :ref:`Microphone `
@@ -54,7 +55,7 @@ External ADC
------------
- **i2s_din_pin** (**Required**, :ref:`Pin Schema `): The GPIO pin to use for the I²S ``DIN/SDIN`` *(Data In)* signal, also referred to as ``SD/SDATA`` *(Serial Data)* or ``ADCDAT`` *(Analog to Digital Converter Data)*.
-- **pdm** (**Required**, boolean): Set this to ``true`` if your external ADC uses PDM (Pulse Density Modulation) instead of I²S.
+- **pdm** (*Optional*, boolean): Set this to ``true`` if your external ADC uses PDM (Pulse Density Modulation) instead of I²S. Defaults to ``false``.
.. note::
diff --git a/components/modbus_controller.rst b/components/modbus_controller.rst
index 264f078379..8e2ea4e688 100644
--- a/components/modbus_controller.rst
+++ b/components/modbus_controller.rst
@@ -54,7 +54,9 @@ Configuration variables:
- **modbus_id** (*Optional*, :ref:`config-id`): Manually specify the ID of the ``modbus`` hub.
-- **address** (**Required**, :ref:`config-id`): The Modbus address of the slave device
+- **address** (**Required**, :ref:`config-id`): The Modbus address of the slave device.
+
+- **allow_duplicate_commands** (*Optional*, boolean): Whether to allow duplicate commands in the queue. Defaults to ``false``.
- **command_throttle** (*Optional*, :ref:`config-time`): minimum time in between 2 requests to the device. Default is ``0ms``.
Some Modbus slave devices limit the rate of requests from the master, so this allows the interval between requests to be altered.
@@ -67,6 +69,8 @@ Configuration variables:
slaves, this avoids waiting for timeouts allowing to read other slaves in the same bus. When the slave
responds to a command, it'll be marked online again.
+- **max_cmd_retries** (*Optional*, integer): How many times a command will be retried if no response is received. It doesn't include the initial transmition. Defaults to 4.
+
- **server_registers** (*Optional*): A list of registers that are responded to when acting as a server.
- **address** (**Required**, integer): start address of the first register in a range
- **value_type** (*Optional*): datatype of the mod_bus register data. The default data type for ModBUS is a 16 bit integer in big endian format (MSB first)
diff --git a/components/number/tuya.rst b/components/number/tuya.rst
index bf05ac960f..97a7b0a603 100644
--- a/components/number/tuya.rst
+++ b/components/number/tuya.rst
@@ -61,6 +61,27 @@ For instance, assume we have a pH sensor that reads from 0.00 to 15.00 with a sc
max_value: 15.00
multiply: 100
+Hidden datapoints:
+------------------
+The above configurations will work fine as long as Tuya device publishes the datapoint value (along with its type) at initialization.
+However this is not always the case. To be able to use such "hidden" datapoints as Number, you need to specify additional ``datapoint_hidden`` configuration block.
+This block allows to specify the missing datapoint type and, optionally, the value that should be written to the datapoint at initialization.
+
+TuyaMCU restores the state of all its datapoints after reboot, but with the hidden datapoints there is no way to know what their values are.
+Therefore there is also an option to store them on the ESPHome side and they will be set at initialization. To use this feature, set the ``restore_value`` yaml key to True.
+
+.. code-block:: yaml
+
+ - platform: "tuya"
+ name: "Alarm at maximum"
+ number_datapoint: 116
+ min_value: 0
+ max_value: 100
+ datapoint_hidden:
+ datapoint_type: int
+ initial_value: 85
+ restore_value: yes
+
Configuration variables:
------------------------
@@ -69,6 +90,11 @@ Configuration variables:
- **max_value** (**Required**, float): The maximum value this number can be.
- **step** (*Optional*, float): The granularity with which the number can be set. Defaults to 1.
- **multiply** (*Optional*, float): multiply the new value with this factor before sending the requests.
+- **datapoint_hidden** (*Optional*): Specify information required for hidden datapoints.
+
+ - **datapoint_type** (**Required**, string): The datapoint type, one of *int*, *uint*, *enum*.
+ - **initial_value** (*Optional*, float): The value to be written at initialization. Must be between ``min_value`` and ``max_value``.
+ - **restore_value** (*Optional*, boolean): Saves and loads the state to RTC/Flash. Defaults to ``false``.
- All other options from :ref:`Number `.
diff --git a/components/pipsolar.rst b/components/pipsolar.rst
index 466be5ab39..b6cb09678b 100644
--- a/components/pipsolar.rst
+++ b/components/pipsolar.rst
@@ -242,6 +242,8 @@ Not all possible switches are exposed as they lead to the possibility to make se
name: inverter0_output_source_priority_solar
output_source_priority_battery:
name: inverter0_output_source_priority_battery
+ output_source_priority_hybrid:
+ name: inverter0_output_source_priority_hybrid
input_voltage_range:
name: inverter0_input_voltage_range
pv_ok_condition_for_parallel:
@@ -256,6 +258,7 @@ All sensors are normal text sensors... so all text sensor variables are working
- **output_source_priority_utility** (*Optional*): output source priority utility
- **output_source_priority_solar** (*Optional*): output source priority solar
- **output_source_priority_battery** (*Optional*): output source priority battery
+- **output_source_priority_hybrid** (*Optional*): output source priority hybrid
- **input_voltage_range** (*Optional*): input voltage range
- **pv_ok_condition_for_parallel** (*Optional*): pv ok condition for parallel
- **pv_power_balance** (*Optional*): pv power balance
diff --git a/components/sensor/atm90e32.rst b/components/sensor/atm90e32.rst
index 251f4cba58..c878fe857d 100644
--- a/components/sensor/atm90e32.rst
+++ b/components/sensor/atm90e32.rst
@@ -79,6 +79,31 @@ Configuration variables:
- **update_interval** (*Optional*, :ref:`config-time`): The interval to check the sensor. Defaults to ``60s``.
- **spi_id** (*Optional*, :ref:`config-id`): Manually specify the ID of the :ref:`SPI Component ` if you want
to use multiple SPI buses.
+- **enable_offset_calibration** (*Optional*, boolean): If true it enables fine grained offset noise 0 level calibration for voltage and
+ current sensors. Buttons are required to operate the calibration feature. With multiple atm90e32 sensors each one is enabled
+ individually and it's buttons are mapped using an id value pair. e.g. ``id: chip1`` when more than one is defined. Offset calibration should only be used
+ when DC supply noise causes non 0 current or voltage readings. Calibration can only be performed when all voltage and current inputs are at a 0 value.
+
+Button
+------
+
+.. code-block:: yaml
+
+ button:
+ - platform: atm90e32
+ id: chip1
+ run_offset_calibration:
+ name: "Chip1 - Run Offset Calibration"
+ clear_offset_calibration:
+ name: "Chip1 - Clear Offset Calibration"
+
+Configuration variables:
+
+- **id** (*Optional*, :ref:`config-id`): The ID of the atm90e32 defined above. Required if there are multiple atm90e32 configured.
+- **run_offset_calibration** (*Optional*): A button to run the offset calibration.
+ All options from :ref:`Button `.
+- **clear_offset_calibration** (*Optional*): A button to clear the offset calibration.
+ All options from :ref:`Button `.
Calibration
-----------
@@ -258,6 +283,7 @@ Additional Examples
sensor:
- platform: atm90e32
cs_pin: 5
+ id: chip1 #Optional
phase_a:
voltage:
name: "EMON Line Voltage A"
@@ -287,8 +313,10 @@ Additional Examples
current_phases: 3
gain_pga: 1X
update_interval: 60s
+ enable_offset_calibration: True
- platform: atm90e32
cs_pin: 4
+ id: chip2 #Optional
phase_a:
current:
name: "EMON CT4 Current"
@@ -315,6 +343,14 @@ Additional Examples
gain_pga: 1X
update_interval: 60s
+ button:
+ - platform: atm90e32
+ id: chip1
+ run_offset_calibration:
+ name: "Chip1 - Run Offset Calibration"
+ clear_offset_calibration:
+ name: "Chip1 - Clear Offset Calibration"
+
.. code-block:: yaml
diff --git a/components/sensor/bl0906.rst b/components/sensor/bl0906.rst
new file mode 100644
index 0000000000..0006beb95c
--- /dev/null
+++ b/components/sensor/bl0906.rst
@@ -0,0 +1,207 @@
+Belling BL0906 Energy Monitor
+=============================
+
+.. seo::
+ :description: Instructions for setting up BL0906 energy monitor for the Athom Energy Meter
+ :image: bl0906.png
+ :keywords: bl0906, Athom EM2 Energy Meter, Athom EM6 Energy Meter, Athom Energy Meter, ESP32C3 Energy Meter Main Board, Split Single Phase Real Time Whole House Energy Meter
+
+The ``bl0906`` sensor platform allows you to use your BL0906 voltage/current/power and energy
+sensors with ESPHome. This sensor is commonly found in `Athom EM2 Energy Meter `__ and `Athom EM6 Energy Meter `__
+
+.. note::
+
+ The current ratio of the current CT clamp must be 2000:1
+
+As the communication with the BL0906 done using UART, you need
+to have an :ref:`UART bus ` in your configuration with the ``tx_pin`` and ``rx_pin`` connected to the BL0906.
+Additionally, you need to set the baud rate to 19200.
+
+The `Athom EM2 Energy Meter `__ can read 1 voltage channel and 2 Current channels.
+
+.. figure:: images/athom-em2.png
+ :align: center
+ :width: 20.0%
+
+ Athom Single Phase 2 channels Real Time Whole House Energy Meter.
+
+The `Athom EM6 Energy Meter `__ can read 1 voltage channel and 6 Current channels.
+
+.. figure:: images/athom-em6.png
+ :align: center
+ :width: 30.0%
+
+ Athom Single Phase 6 channels Real Time Whole House Energy Meter.
+
+Configuration variables:
+------------------------
+
+- **frequency** (*Optional*): The AC line frequency of the supply voltage. All options from
+ :ref:`Sensor `.
+- **temperature** (*Optional*): Chip internal temperature. All options from
+ :ref:`Sensor `.
+- **voltage** (*Optional*): Use the voltage value of the sensor in V. All options from
+ :ref:`Sensor `.
+- **channel_1** (*Optional*): Use channel 1.
+
+ - **current** (*Optional*): The current value of the channel 1 in amperes. All options from
+ :ref:`Sensor `.
+ - **power** (*Optional*): The Power value of the channel 1 in watts. All options from
+ :ref:`Sensor `.
+ - **energy** (*Optional*): The energy value of the channel 1 in kWh. All options from
+ :ref:`Sensor `.
+- **channel_2** (*Optional*): Use channel 2.
+
+ - **current** (*Optional*): The current value of the channel 2 in amperes. All options from
+ :ref:`Sensor `.
+ - **power** (*Optional*): The Power value of the channel 2 in watts. All options from
+ :ref:`Sensor `.
+ - **energy** (*Optional*): The energy value of the channel 2 in kWh. All options from
+ :ref:`Sensor `.
+- **channel_3** (*Optional*): Use channel 3.
+
+ - **current** (*Optional*): The current value of the channel 3 in amperes. All options from
+ :ref:`Sensor `.
+ - **power** (*Optional*): The Power value of the channel 3 in watts. All options from
+ :ref:`Sensor `.
+ - **energy** (*Optional*): The energy value of the channel 3 in kWh. All options from
+ :ref:`Sensor `.
+- **channel_4** (*Optional*): Use channel 4.
+
+ - **current** (*Optional*): The current value of the channel 4 in amperes. All options from
+ :ref:`Sensor `.
+ - **power** (*Optional*): The Power value of the channel 4 in watts. All options from
+ :ref:`Sensor `.
+ - **energy** (*Optional*): The energy value of the channel 4 in kWh. All options from
+ :ref:`Sensor `.
+- **channel_5** (*Optional*): Use channel 5.
+
+ - **current** (*Optional*): The current value of the channel 5 in amperes. All options from
+ :ref:`Sensor `.
+ - **power** (*Optional*): The Power value of the channel 5 in watts. All options from
+ :ref:`Sensor `.
+ - **energy** (*Optional*): The energy value of the channel 5 in kWh. All options from
+ :ref:`Sensor `.
+- **channel_6** (*Optional*): Use channel 6.
+
+ - **current** (*Optional*): The current value of the channel 6 in amperes. All options from
+ :ref:`Sensor `.
+ - **power** (*Optional*): The Power value of the channel 6 in watts. All options from
+ :ref:`Sensor `.
+ - **energy** (*Optional*): The energy value of the channel 6 in kWh. All options from
+ :ref:`Sensor `.
+- **total_energy** (*Optional*): The total energy value of all channels in kWh. All options from
+ :ref:`Sensor `.
+- **total_power** (*Optional*): The total power value of all channels in watts. All options from
+ :ref:`Sensor `.
+- **update_interval** (*Optional*, :ref:`config-time`): The interval to check the
+ sensor. Defaults to ``60s``.
+- **uart_id** (*Optional*, :ref:`config-id`): Manually specify the ID of the :ref:`UART Component ` if you want
+ to use multiple UART buses.
+
+Example configuration
+---------------------
+
+2 Channel
+^^^^^^^^^^^^^^^^^^
+
+.. code-block:: yaml
+
+ # Example configuration entry
+ sensor:
+ - platform: bl0906
+ frequency:
+ name: 'Frequency'
+ temperature:
+ name: 'Temperature'
+ voltage:
+ name: 'Voltage'
+ channel_1:
+ current:
+ name: 'Current_1'
+ power:
+ name: 'Power_1'
+ energy:
+ name: 'Energy_1'
+ channel_2:
+ current:
+ name: 'Current_2'
+ power:
+ name: 'Power_2'
+ energy:
+ name: 'Energy_2'
+ total_energy:
+ name: 'Total_Energy'
+ total_power:
+ name: 'Total_Power'
+
+6 Channel
+^^^^^^^^^^^^^^^^^^
+
+.. code-block:: yaml
+
+ # Example configuration entry
+ sensor:
+ - platform: bl0906
+ frequency:
+ name: 'Frequency'
+ temperature:
+ name: 'Temperature'
+ voltage:
+ name: 'Voltage'
+ channel_1:
+ current:
+ name: 'Current_1'
+ power:
+ name: 'Power_1'
+ energy:
+ name: 'Energy_1'
+ channel_2:
+ current:
+ name: 'Current_2'
+ power:
+ name: 'Power_2'
+ energy:
+ name: 'Energy_2'
+ channel_3:
+ current:
+ name: 'Current_3'
+ power:
+ name: 'Power_3'
+ energy:
+ name: 'Energy_3'
+ channel_4:
+ current:
+ name: 'Current_4'
+ power:
+ name: 'Power_4'
+ energy:
+ name: 'Energy_4'
+ channel_5:
+ current:
+ name: 'Current_5'
+ power:
+ name: 'Power_5'
+ energy:
+ name: 'Energy_5'
+ channel_6:
+ current:
+ name: 'Current_6'
+ power:
+ name: 'Power_6'
+ energy:
+ name: 'Energy_6'
+ total_energy:
+ name: 'Total_Energy'
+ total_power:
+ name: 'Total_Power'
+
+See Also
+--------
+
+- :ref:`sensor-filters`
+- :doc:`cse7761`
+- :doc:`bl0939`
+- :doc:`bl0940`
+- :apiref:`bl0906/bl0906.h`
+- :ghedit:`Edit`
diff --git a/components/sensor/bl0942.rst b/components/sensor/bl0942.rst
index 7918747fbf..2774493a21 100644
--- a/components/sensor/bl0942.rst
+++ b/components/sensor/bl0942.rst
@@ -46,6 +46,75 @@ Configuration variables:
sensor. Defaults to ``60s``.
- **uart_id** (*Optional*, :ref:`config-id`): Manually specify the ID of the :ref:`UART Component ` if you want
to use multiple UART buses.
+- **line_frequency** (*Optional*, string): The nominal AC line frequency of the supply voltage. One of ``50Hz``, ``60Hz``. Defaults to ``50Hz``.
+- **address** (*Optional*, int): The address of the BL0942 from its strapping pins. Defaults to ``0``.
+- **reset** (*Optional*, boolean): Whether to reset the BL0942 chip on startup, resetting all internal counters. Defaults to ``true``.
+- **current_reference** (*Optional*, float): The calibration parameter for current readings. Defaults to ``251213.46469622``.
+- **voltage_reference** (*Optional*, float): The calibration parameter for voltage readings. Defaults to ``15873.35944299``.
+- **power_reference** (*Optional*, float): The calibration parameter for power readings. Defaults to ``596.0`` unless either ``current_reference`` or ``voltage_reference`` are explicitly set, in which case it is calculated. See :ref:`bl0942-calibration` for more details.
+- **energy_reference** (*Optional*, float): The calibration parameter for cumulative energy readings. Defaults to ``3304.61127328`` unless any of ``current_reference``, ``voltage_reference`` or ``power_reference`` are explicitly set, in which case it is calculated. See :ref:`bl0942-calibration` for more details.
+
+
+.. _bl0942-calibration:
+
+Calibration
+-----------
+
+There are two fundamental calibration parameters which are dependent on the hardware: ``voltage_reference`` and ``current_reference``. These can be determined by using an accurate voltage and current meter with a simple resistive load.
+
+The ``power_reference`` value can be derived from those, and will be roughly ``voltage_reference`` * ``current_reference`` * 3537 / (305978 * 73989).
+
+The ``energy_reference`` value can be derived as roughly ``power_reference`` * 3600000 / 419430.4.
+
+For compatibility with existing configurations, if no reference values are set then the original defaults will be used, despite the power and energy calibration not being entirely consistent.
+
+If converting Tuya devices, the factory calibration values can often be obtained from the original firmware. For example, they may be found in DPS parameters 22-25, or the `voltage_coe` and related options.
+
+An example from a Tongou DIN rail power meter unit. The result from ``tinytuya wizard`` included:
+
+.. code-block:: json
+
+ {
+ "code": "voltage_coe",
+ "value": 15968
+ },
+ {
+ "code": "electric_coe",
+ "value": 12418
+ },
+ {
+ "code": "power_coe",
+ "value": 3091
+ },
+ {
+ "code": "electricity_coe",
+ "value": 2653
+ },
+
+
+Noting that the ``electric_coe`` value (DPS 23) should be multiplied by ten, and the ``power_coe`` value should be divided by ten, this results in the following configuration:
+
+.. code-block:: yaml
+
+ voltage_reference: 15968 # DPS 21
+ current_reference: 124180 # DPS 22 * 10
+ power_reference: 309.1 # DPS 23 / 10
+ energy_reference: 2653 # DPS 24
+
+Alternatively, the values may be found on the flash of the unit without obtaining
+the Tuya keys for local communication. They can be found in the "key value store"
+partition. The same device as in the above example had the following (before
+flashing ESPHome) at offset ``0x001d5000``:
+
+.. code-block::
+
+ 001d5000 60 3e 00 00 82 30 00 00 13 0c 00 00 5d 0a 00 00 |`>...0......]...|
+
+The hex values 0x3e60, 0x3082, 0xc13 and 0xa5d seen there correspond to the four
+DPS values reported by the running Tuya firmware.
+
+The formulas above for deriving ``power_reference`` and ``energy_reference`` can be
+used as a sanity check for the values found from the firmware.
See Also
--------
diff --git a/components/sensor/bmp280.rst b/components/sensor/bmp280.rst
index ff0c6abbc5..e5385c842f 100644
--- a/components/sensor/bmp280.rst
+++ b/components/sensor/bmp280.rst
@@ -8,7 +8,7 @@ BMP280 Temperature+Pressure Sensor
The ``bmp280`` sensor platform allows you to use your BMP280
(`datasheet `__,
-`Adafruit`_) temperature and pressure sensors with ESPHome. The :ref:`I²C ` is
+`Adafruit`_) temperature and pressure sensors with ESPHome. The :ref:`I²C ` or :ref:`SPI ` is
required to be set up in your configuration for this sensor to work.
.. figure:: images/bmp280-full.jpg
@@ -21,9 +21,9 @@ required to be set up in your configuration for this sensor to work.
.. code-block:: yaml
- # Example configuration entry
+ # Example configuration entry I2C
sensor:
- - platform: bmp280
+ - platform: bmp280_i2c
temperature:
name: "Outside Temperature"
oversampling: 16x
@@ -32,6 +32,17 @@ required to be set up in your configuration for this sensor to work.
address: 0x77
update_interval: 60s
+ # Example configuration entry SPI
+ sensor:
+ - platform: bmp280_spi
+ temperature:
+ name: "Outside Temperature"
+ oversampling: 16x
+ pressure:
+ name: "Outside Pressure"
+ cs_pin: GPIO5
+ update_interval: 60s
+
Configuration variables:
------------------------
@@ -48,13 +59,22 @@ Configuration variables:
See :ref:`Oversampling Options `.
- All other options from :ref:`Sensor `.
-- **address** (*Optional*, int): Manually specify the I²C address of
- the sensor. Defaults to ``0x77``. Another address can be ``0x76``.
- **iir_filter** (*Optional*): Set up an Infinite Impulse Response filter to increase accuracy. One of
``OFF``, ``2x``, ``4x``, ``16x``. Defaults to ``OFF``.
- **update_interval** (*Optional*, :ref:`config-time`): The interval to check the
sensor. Defaults to ``60s``.
+
+I²C Configuration variables:
+
+- **address** (*Optional*, int): Manually specify the I²C address of
+ the sensor. Defaults to ``0x77``. Another address can be ``0x76``.
+
+SPI Configuration variables:
+
+- **cs_pin** (*Optional*, :ref:`Pin Schema `): The CS pin of the BMP280 sensor.
+
+
.. figure:: images/bmp280-full.jpg
:align: center
:width: 60.0%
diff --git a/components/sensor/dsmr.rst b/components/sensor/dsmr.rst
index 4d5fb1fc2f..200ab7f614 100644
--- a/components/sensor/dsmr.rst
+++ b/components/sensor/dsmr.rst
@@ -256,6 +256,11 @@ Configuration variables:
- All options from :ref:`Text Sensor `.
+- **telegram** (*Optional*): The (decrypted) unparsed telegram, marked as internal sensor.
+ Can also be used to trigger an action based on the last values.
+
+ - All other options from :ref:`Text Sensor `.
+
Belgium
- **p1_version_be** (*Optional*): DSMR Version Belgium
@@ -384,6 +389,42 @@ actually make it work, serial logging must be disabled to keep the hardware UART
pin: GPIO13
baud_rate: 115200
+Bridging support / raw telegram logging
+---------------------------------------
+
+You can use another uart to supply another P1 receiver with the same telegram. See configuration sample as used for bridging.
+
+.. code-block:: yaml
+
+ # define multiple uart's
+ uart:
+ - id: p1_uart
+ rx_pin:
+ number: 4
+ inverted: true
+ baud_rate: 115200
+ rx_buffer_size: 1700
+ - id: p1_bridge_uart
+ tx_pin:
+ number: 10
+ baud_rate: 115200
+
+ # link input uart to dsmr
+ dsmr:
+ uart_id: p1_uart
+ max_telegram_length: 1700
+
+ # log the telegram and pass telegram to p1_bridge_uart
+ text_sensor:
+ - platform: dsmr
+ telegram:
+ name: "telegram"
+ on_value:
+ then:
+ - lambda: |-
+ ESP_LOGV("dsrm", "telegram: %s", x.c_str());
+ p1_bridge_uart->write_str(x.c_str());
+
See Also
--------
diff --git a/components/sensor/images/athom-em2.png b/components/sensor/images/athom-em2.png
new file mode 100644
index 0000000000..7a58a6195c
Binary files /dev/null and b/components/sensor/images/athom-em2.png differ
diff --git a/components/sensor/images/athom-em6.png b/components/sensor/images/athom-em6.png
new file mode 100644
index 0000000000..fddc701fd7
Binary files /dev/null and b/components/sensor/images/athom-em6.png differ
diff --git a/components/sensor/images/ltr501-full.jpg b/components/sensor/images/ltr501-full.jpg
new file mode 100644
index 0000000000..fef6751fe1
Binary files /dev/null and b/components/sensor/images/ltr501-full.jpg differ
diff --git a/components/sensor/images/ltr501-ui.png b/components/sensor/images/ltr501-ui.png
new file mode 100644
index 0000000000..18b60c8843
Binary files /dev/null and b/components/sensor/images/ltr501-ui.png differ
diff --git a/components/sensor/ltr501.rst b/components/sensor/ltr501.rst
new file mode 100644
index 0000000000..9b01e18478
--- /dev/null
+++ b/components/sensor/ltr501.rst
@@ -0,0 +1,193 @@
+Lite-On Ambient Light & Proximity Sensors
+=========================================
+
+.. seo::
+ :description: Instructions for setting up LTR301, LTR501, LTR558 ambient light sensors/proximity sensors with ESPHome.
+ :image: ltr501.jpg
+ :keywords: LTR-301, LTR-501, LTR-558
+
+
+.. figure:: images/ltr501-full.jpg
+ :align: center
+ :width: 60.0%
+
+ LTR-501 on a breadboard from Olimex
+
+.. figure:: images/ltr501-ui.png
+ :align: center
+ :width: 60.0%
+
+ LTR-501 Sensor in Home Assistant UI.
+
+The ``ltr501`` sensor platform allows you to use a range of LiteOn ambient light and proximity sensors
+with ESPHome.
+
+The supported family of sensors includes:
+
+- Ambient Light Sensor **LTR-301ALS**
+- Integrated Ambient Light and Proximity Sensors **LTR-501ALS** and **LTR-558ALS**
+
+The LTR-501 device is available on a breakout board from `Olimex`_.
+
+The sensors are very similar and share the same datasheet. The :ref:`I²C Bus ` is required to be set up in your
+configuration for this sensor to work. I²C address is ``0x23``.
+
+Proximity sensors are the same sort of sensors that you find in phones and tablets to disable the screen when you hold
+the device up to your ear. They might be useful for automated turning on or off of displays and control panels.
+
+.. _Olimex: https://www.olimex.com/Products/Modules/Sensors/MOD-LTR-501ALS/open-source-hardware
+
+Ambient light sensing
+---------------------
+
+These sensors have a linear response over a wide dynamic range from 0.01 lux to 64k lux and are well suited
+to applications under high ambient brightness. There are two gain settings (1X, 150X) available for use.
+Use higher gain for dimmer areas.
+
+These devices consist of two photodiodes: a *CH0* diode that is sensitive to both visible and infrared light and
+a *CH1* diode that is sensitive only to infrared light.
+
+**Note**: These sensors do not have internal data checking and do not indicate any errors if
+data is not reliable. The sensors can be easily saturated if the gain is too high or the integration time is too long. In this
+case, readings can be very strange. It's recommended to use automatic mode with a starting gain of 1X (default) and a starting
+integration time of 100ms (default) or even 50ms (if the sensor is in a very bright environment). Automatic mode with starting
+gain of 150X is not recommended; use it only if you are sure brightness will never exceed 200-300 lx.
+
+
+Ambient light illuminance calculation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Excerpt from the datasheet:
+
+.. code-block::
+
+ RATIO = CH1/(CH0+CH1)
+ IF (RATIO < 0.45)
+ ALS_LUX = (1.7743 * CH0 + 1.1059 * CH1) / ALS_GAIN / ALS_INT
+ ELSEIF (RATIO < 0.64 && RATIO >= 0.45)
+ ALS_LUX = (3.7725 * CH0 – 1.3363 * CH1) / ALS_GAIN / ALS_INT
+ ELSEIF (RATIO < 0.85 && RATIO >= 0.64)
+ ALS_LUX = (1.6903 * CH0 - 0.1693 * CH1) / ALS_GAIN / ALS_INT
+ ELSE
+ ALS_LUX = 0
+ END
+
+
+where:
+
+- ``CH0`` and ``CH1`` are the sensor values (measurement counts) for Visible + IR (Ch0) and IR only (Ch1) sensors respectively.
+- ``ALS_GAIN`` is the gain multiplier
+- ``ALS_INT`` is the integration time in ms/100
+
+
+ALS Gain levels
+^^^^^^^^^^^^^^^
+
+The table lists gain values and corresponding illuminance range:
+
+ ========= ================================
+ Gain Illuminance range
+ ========= ================================
+ ``1X`` 2 lux to 64k lux (default)
+ ``150X`` 0.01 lux to 320 lux
+ ========= ================================
+
+
+This Wikipedia `article `__ has a table of some lux values for comparison.
+
+
+The following table lists possible gain and integration time combinations:
+
+ ================== ======== =============== ======== ========
+ Gain / Int.time 50 ms 100 ms 200 ms 400 ms
+ ================== ======== =============== ======== ========
+ ``1X`` ✓ ✓ (default)
+ ``150X`` ✓ ✓ ✓
+ ================== ======== =============== ======== ========
+
+
+Proximity sensing
+-----------------
+
+The proximity sensor has a built-in emitter and detector. The sensor detects reflected IR light from the emitter and
+gives a raw count value inversely exponential to the distance. A decrease in the count value means an object is getting
+further away from the sensor (and vice-versa). Neither of the datasheets provide any information on how to convert
+the raw count value to distance. The only way to do so is to test the sensor yourself and select the threshold
+according to your needs and environment. Exact values will depend on the type of the object, its color and
+reflectivity.
+
+
+Example configuration
+---------------------
+
+.. code-block:: yaml
+
+ sensor:
+ - platform: ltr501
+ type: ALS_PS # .. or ALS or PS
+ ambient_light: "Ambient light"
+ # PS only section
+ ps_cooldown: 5 s
+ ps_high_threshold: 500
+ on_ps_high_threshold:
+ then:
+ - .... # do something - light up the screen for example
+ ps_counts:
+ name: "Proximity counts"
+
+
+Configuration variables
+-----------------------
+
+- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation.
+- **address** (*Optional*, int): Manually specify the I²C address of the sensor. Default is ``0x23``.
+- **type** (*Optional*, string): The type of the sensor. Valid values are ``ALS_PS`` *(default)* for
+ integrated sensors, ``ALS`` for ambient light only or ``PS`` for proximity only devices.
+- **auto_mode** (*Optional*, boolean): Automatic gain and integration time selection. Defaults to True.
+- **gain** (*Optional*, string): The gain the device will use. Higher values are better in low-light conditions.
+ Valid values are ``1X`` *(default)*, ``150X``.
+- **integration_time** (*Optional*, :ref:`config-time`):
+ The amount of time sensors are exposed. Longer means more accurate values.
+ Valid values are: ``50ms``, ``100ms`` *(default)*, ``200ms``, ``400ms``.
+- **glass_attenuation_factor** (*Optional*, float): The attenuation factor of glass if it's behind some glass
+ or plastic facia. Default is ``1.0`` means ``100%`` transmissivity. ``2`` means ``50%`` transmissivity etc.
+- **update_interval** (*Optional*, :ref:`config-time`): The interval for checking the sensors.
+ Defaults to ``60s``.
+- **ps_cooldown** (*Optional*, :ref:`config-time`): The "cooldown" period after the proximity sensor is triggered.
+ Helps to avoid multiple calls. Defaults to ``5s``.
+- **ps_gain** (*Optional*, string): The gain the device will use for proximity sensor. Higher values are better in low-light conditions.
+ Valid values are ``1X`` *(default)*, ``4X``, ``8X``, ``16X``.
+- **ps_high_threshold** (*Optional*, int): The threshold for the proximity sensor to trigger on object getting closer.
+ Defaults to ``65535``, which implies it will never be triggered.
+- **ps_low_threshold** (*Optional*, int): The threshold for the proximity sensor to trigger on object getting further away.
+ Defaults to ``0``, which implies it will never be triggered.
+- **on_ps_high_threshold** (*Optional*): Actions to perform when the proximity sensor is triggered
+ on object getting closer.
+- **on_ps_low_threshold** (*Optional*): Actions to perform when the proximity sensor is triggered
+ on object getting further away.
+
+Sensors
+^^^^^^^
+
+This component offers five sensors for ALS-equipped devices and one sensor for PS-equipped devices.
+You can configure all or any subset of these sensors. Each configured sensor is reported separately
+on each ``update_interval``. Each is an ESPHome :ref:`sensor ` and may be configured
+accordingly; if you don’t need to configure additional :ref:`sensor ` variables, you
+may simply use the shorthand syntax for the sensor. For example: ``ambient_light: "Ambient light"``
+
+- **ambient_light** (*Optional*): Illuminance of ambient light, close to human eye spectre, lx.
+- **infrared_counts** (*Optional*): Sensor counts from the IR-sensitive sensor (*CH1*), counts.
+- **full_spectrum_counts** (*Optional*): Sensor counts from the sensor sensitive to both visible light and IR (*CH0*), counts.
+- **actual_gain** (*Optional*): Gain value used to measure data, multiplier. Particularly useful when "auto_mode" is selected.
+- **actual_integration_time** (*Optional*): Integration time used to measure data, ms. Particularly useful when "auto_mode" is selected.
+- **ps_counts** (*Optional*) - Raw 11-bit reading from proximity sensor, counts.
+
+
+See Also
+--------
+
+- `LTR-501ALS datasheet `__
+- `LTR-558ALS datasheet `__
+- `LTR-301ALS datasheet `__
+- :apiref:`ltr501/ltr501.h`
+- :ghedit:`Edit`
diff --git a/components/sensor/max31856.rst b/components/sensor/max31856.rst
index 1a571fbffe..0a1b31e5f4 100644
--- a/components/sensor/max31856.rst
+++ b/components/sensor/max31856.rst
@@ -45,6 +45,7 @@ Configuration variables:
- **cs_pin** (**Required**, :ref:`Pin Schema `): The Chip Select pin of the SPI interface.
- **update_interval** (*Optional*, :ref:`config-time`): The interval to check the sensor. Defaults to ``60s``.
- **mains_filter** (*Optional*, string): The mains power frequency to reject (``50 Hz`` or ``60 Hz``). Defaults to ``60 Hz``.
+- **thermocouple_type** (*Optional*, string): The type of thermocouple used. MAX31856 supports: B, E, J, K, N, R, S, and T . Defaults to ``K``.
- **spi_id** (*Optional*, :ref:`config-id`): Manually specify the ID of the :ref:`SPI Component ` if you want to use multiple SPI buses.
- All other options from :ref:`Sensor `.
diff --git a/components/sensor/udp.rst b/components/sensor/udp.rst
new file mode 100644
index 0000000000..7d5d798c06
--- /dev/null
+++ b/components/sensor/udp.rst
@@ -0,0 +1,49 @@
+UDP Sensor
+==========
+
+.. seo::
+ :description: Instructions for setting up a UDP sensor.
+ :image: udp.svg
+
+The ``udp`` sensor platform allows you to receive numeric sensor data directly from another ESPHome node.
+
+.. code-block:: yaml
+
+ # Example configuration entry
+ sensor:
+ - platform: udp
+ id: temperature_id
+ provider: thermometer
+ remote_id: temp_id
+
+Configuration variables
+-----------------------
+
+- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation.
+- **provider** (**Required**, string): The name of the provider node.
+- **remote_id** (*Optional*, :ref:`config-id`): The ID of the original sensor in the provider node. If not specified defaults to the ID configured with ``id:``.
+- **name** (*Optional*, string): The name of the sensor.
+- **internal** (*Optional*, boolean): Whether the sensor should be exposed via API (e.g. to Home Assistant.) Defaults to ``true`` if name is not set, required if name is provided.
+- All other options from :ref:`Sensor `.
+
+At least one of ``id`` and ``remote_id`` must be configured.
+
+Publishing to Home Assistant
+----------------------------
+
+Typically this type of sensor would be used for internal automation purposes rather than having it published back to
+Home Assistant, since it would be a duplicate of the original sensor.
+
+If it *is* desired to expose the sensor to Home Assistant, then the ``internal:`` configuration setting needs to be explicitly
+set to ``false`` and a name provided.
+Only the state (i.e. numeric value) of the remote sensor is received by the consumer, so any other attributes must be explicitly
+configured.
+
+See Also
+--------
+
+- :doc:`/components/udp`
+- :doc:`/components/binary_sensor/index`
+- :ref:`automation`
+- :apiref:`udp/udp_component.h`
+- :ghedit:`Edit`
diff --git a/components/speaker/i2s_audio.rst b/components/speaker/i2s_audio.rst
index 92023ab371..f1ba0d190a 100644
--- a/components/speaker/i2s_audio.rst
+++ b/components/speaker/i2s_audio.rst
@@ -24,7 +24,6 @@ This platform only works on ESP32 based chips.
- platform: i2s_audio
dac_type: external
i2s_dout_pin: GPIOXX
- mode: mono
Configuration variables:
------------------------
@@ -34,12 +33,21 @@ Configuration variables:
- ``external``: Use an external DAC, for example the NS4168, or UDA1334A.
- ``internal``: Use the internal DAC
+- **channel** (*Optional*, enum): The channel of the speaker. One of ``left``, ``right``, ``mono``, or ``stereo``. If ``stereo``, the input data should be twice as big,
+ with each right sample followed by a left sample. ``left`` and ``right`` mute the unused channel, while ``mono`` plays the same samples on both. Defaults to ``mono``.
+- **sample_rate** (*Optional*, positive integer): I2S sample rate. Defaults to ``16000``.
+- **bits_per_sample** (*Optional*, enum): The bit depth of the audio samples. Note that while set to ``24bit`` or ``32bit``, the samples
+ will be scaled up from 16bit before being forwarded. One of ``8bit``, ``16bit``, ``24bit``, or ``32bit``. Defaults to ``16bit``.
+- **bits_per_channel** (*Optional*, enum): The bit depth of the audio channels. See the datasheet of your I2S device for details. Defaults to ``bits_per_sample``.
+- **use_apll** (*Optional*, boolean): I2S using APLL as main I2S clock, enable it to get accurate clock. Defaults to ``false``.
+- **i2s_mode** (*Optional*, enum): The I²S mode to use. One of ``primary`` (clock driven by the host) or ``secondary`` (clock driven by the attached device). Defaults to ``primary``.
+- **i2s_audio_id** (*Optional*, :ref:`config-id`): The ID of the :ref:`I²S Audio ` you wish to use for this speaker.
+- **timeout** (*Optional*, :ref:`config-time`): How long to wait after finishing playback before releasing the bus. Defaults to ``100ms``.
+
External DAC
************
- **i2s_dout_pin** (**Required**, :ref:`Pin Schema `): The GPIO pin to use for the I²S DOUT (Data Out) signal.
-- **mode** (*Optional*, string): The mode of the I²S bus. Can be ``mono`` or ``stereo``. Defaults to ``mono``.
-- **i2s_audio_id** (*Optional*, :ref:`config-id`): The ID of the :ref:`I²S Audio ` you wish to use for this speaker.
For best results, keep the wires as short as possible.
diff --git a/components/statsd.rst b/components/statsd.rst
new file mode 100644
index 0000000000..47881c92fe
--- /dev/null
+++ b/components/statsd.rst
@@ -0,0 +1,53 @@
+.. _statsd:
+
+StatsD
+========
+
+.. seo::
+ :description: Instructions for setting up a StatsD
+ :keywords: StatsD, metrics
+
+StatsD is a `protocol `_ to send metrics to a Daemon to store and aggregate them.
+Today there are many monitoring solutions that support receiving metrics via the StatsD protocol.
+
+
+.. code-block:: yaml
+
+ # Example configuration entry
+ statsd:
+ host: REPLACEME
+ sensors:
+ id: some_sensor
+ name: test1.sensor
+
+ sensor:
+ platform: ...
+ id: some_sensor
+
+
+This example will generate a metric named `test1.sensor` with the value of the `some_sensor` sensor.
+
+
+Configuration variables:
+------------------------
+
+- **host** (**Required**, ip): The Host IP of your StatsD Server.
+- **post** (*Optional*, uint16): The Port of your StatsD Server. Defaults to ``8125``.
+- **prefix** (*Optional*, string): The prefix to automatically prepend every metric with. Defaults to ``""``.
+- **update_interval** (*Optional*, uint16): How often to send the metrics. Defaults to ``10s``.
+- **sensor** (*Optional*, :ref:`sensors`): A list of sensors to generate metrics for.
+- **binary_sensor** (*Optional*, :ref:`sensors`): A list of binary sensors to generate metrics for.
+
+.. _sensors:
+
+Sensor list
+-----------
+
+- **id** (**Required**, :ref:`config-id`): The ID of the sensor.
+- **name** (**Required**, name): The Name of the metric the sensor value is send as. (Prefix is added to this name).
+
+See Also
+--------
+
+- :apiref:`statsd/statsd.h`
+- :ghedit:`Edit`
diff --git a/components/switch/homeassistant.rst b/components/switch/homeassistant.rst
index 177adb3af6..502ae3a1db 100644
--- a/components/switch/homeassistant.rst
+++ b/components/switch/homeassistant.rst
@@ -22,6 +22,20 @@ Configuration variables:
- **entity_id** (**Required**, string): The entity ID to import / control from Home Assistant.
- All other options from :ref:`Switch `.
+Supported domains
+-----------------
+
+The following entity domains from Home Assistant are supported by this platform.
+
+- ``automation``
+- ``fan``
+- ``humidifier``
+- ``input_boolean``
+- ``light``
+- ``remote``
+- ``siren``
+- ``switch``
+
See Also
--------
diff --git a/components/touchscreen/gt911.rst b/components/touchscreen/gt911.rst
index 484660afd0..97cced192c 100644
--- a/components/touchscreen/gt911.rst
+++ b/components/touchscreen/gt911.rst
@@ -34,6 +34,7 @@ Configuration variables:
- **id** (*Optional*, :ref:`config-id`): Manually set the ID of this touchscreen.
- **interrupt_pin** (*Optional*, :ref:`Pin Schema `): The touch detection pin.
+- **reset_pin** (*Optional*, :ref:`Pin Schema `): The reset pin.
- All other options from :ref:`Touchscreen `.
diff --git a/components/tuya.rst b/components/tuya.rst
index d941b8cf6c..57596d6dd2 100644
--- a/components/tuya.rst
+++ b/components/tuya.rst
@@ -140,5 +140,6 @@ See Also
- :doc:`/components/binary_sensor/tuya`
- :doc:`/components/sensor/tuya`
- :doc:`/components/text_sensor/tuya`
+- :doc:`/components/number/tuya`
- :apiref:`tuya/tuya.h`
- :ghedit:`Edit`
diff --git a/components/udp.rst b/components/udp.rst
new file mode 100644
index 0000000000..59a92fd322
--- /dev/null
+++ b/components/udp.rst
@@ -0,0 +1,300 @@
+.. _udp:
+
+UDP Component
+=============
+
+.. seo::
+ :description: Instructions for setting up a UDP component on ESPHome
+ :image: udp.svg
+ :keywords: UDP
+
+The purpose of this component is to allow ESPHome nodes to directly communicate with each over an IP network.
+It permits the state of sensors and binary sensors to be broadcast via UDP packets
+to other nodes on the same LAN, or to specific IP addresses (which may be in remote, but reachable networks).
+
+Nodes may be *providers* which broadcast sensor data, or *consumers* which receive sensor data from one or more
+providers. A node may be both a provider and a consumer. Optional security is provided by one or more of:
+
+- encryption using a shared secret key
+- a rolling code
+- a challenge-response (ping-pong) key
+
+.. code-block:: yaml
+
+ # Example configuration entry
+ udp:
+ update_interval: 5s
+ encryption: "REPLACEME"
+ rolling_code_enable: true
+ binary_sensors:
+ - binary_sensor_id1
+ sensors:
+ - sensor_id1
+ - id: sensor_id2
+ broadcast_id: different_id
+
+ providers:
+ - name: some-device-name
+ encryption: "REPLACEME with some key"
+
+ sensor:
+ - platform: udp
+ provider: some-device-name
+ id: local_sensor_id
+ remote_id: some_sensor_id
+
+ binary_sensor:
+ - platform: udp
+ provider: unencrypted-device
+ id: other_binary_sensor_id # also used as remote_id
+
+Configuration variables:
+------------------------
+
+- **id** (*Optional*, :ref:`config-id`): Manually specify the ID used for code generation.
+- **update_interval** (*Optional*, :ref:`config-time`): Interval between full broadcasts. Defaults to 15s.
+- **port** (*Optional*, int): The destination UDP port number to use. Defaults to ``18511``.
+- **addresses** (*Optional*, list of IPv4 addresses): One or more IP addresses to broadcast data to. Defaults to ``255.255.255.255``
+ which is the local network broadcast address.
+- **sensors** (*Optional*, list): A list of sensor IDs to be broadcast. Each entry may be just the sensor id, or may set a different id to be broadcast.
+
+ - **id** (**Required**, :ref:`config-id`): The id of the sensor to be used
+ - **broadcast_id** (*Optional*, string): The id to be used for this sensor in the broadcast. Defaults to the same as the internal id.
+
+- **binary_sensors** (*Optional*, list): A list of binary sensor IDs to be broadcast.
+
+ - **id** (**Required**, :ref:`config-id`): The id of the binary sensor to be used
+ - **broadcast_id** (*Optional*, string): The id to be used for this binary sensor in the broadcast. Defaults to the same as the internal id.
+
+- **encryption** (*Optional*, string): The encryption key to use when broadcasting. Default is no encryption. This may be
+ any string, and will be hashed to form a 256 bit key.
+- **rolling_code_enable** (*Optional*, boolean): Enables a rolling code to be included in all broadcasts. Requires ``encryption`` to be set. Defaults to ``false``. Can be set only on the provider side.
+- **ping_pong_enable** (*Optional*, boolean): When set, requires encrypted providers to include a *nonce* generated by this device in broadcasts. Defaults to ``false``. Can be set only on the consumer side.
+- **ping_pong_recycle_time** (*Optional*, :ref:`config-time`): Controls how often the ping-pong key is regenerated. Requires ``ping_pong_enable`` to be set. Defaults to 10 minutes. Can be set only on the consumer side.
+- **providers** (*Optional*, list): A list of provider device names and optionally their secret encryption keys.
+
+ - **name** (**Required**, string): The device name of the provider.
+ - **encryption** (*Optional*, string): The provider's encryption key.
+
+Wherever a provider name is required, this should be the node name configured in the ``esphome:`` block.
+
+This component supports multiple configurations, making it possible to differentiate between consumers when providing data to them.
+When receiving data in such a configuration, sensors need an ``udp_id`` configuration item to know where to expect data to come from.
+
+Reliability
+-----------
+
+UDP, like any other network protocol, does not provide a guarantee that data will be delivered, but unlike TCP it does not
+even provide any indication whether data has been successfully delivered or not. When any of the configured sensors changes state,
+the component will broadcast that sensor's state, but since this may not be delivered to a consumer, the UDP component
+also broadcasts *all* sensor data on a timed schedule, set by ``update_interval``. Even this does not guarantee
+delivery, but in practice unless the network has failed, updates will eventually be delivered, albeit possibly after
+some delay.
+
+Security
+--------
+
+By default there is no security - all data is transmitted in clear text on the network. This would be appropriate
+for non-sensitive sensor data or perhaps on a fully secured wired network. For other cases the data can be encrypted
+by providing an encryption key, which is shared between the provider and consumer.
+
+Encryption alone ensures that data cannot be read in transit and protects against spoofing of data, but does not protect
+against replay attacks (where a threat actor records a transmission and replays it later, e.g. to repeat an action.)
+
+A rolling code can be enabled which mitigates replay attacks - each transmission contains a 64 bit value which is
+guaranteed to monotonically increase, so the consumer will reject any data which contains a rolling code
+already seen. The rolling code also ensures that the data in every packet is different, which makes brute-force
+attacks on the encryption much more difficult. This is enabled in the provider configuration and adds minor overhead.
+
+.. note::
+
+ The rolling code's upper 32 bit field is incremented and written to flash *once* at reboot on the provider node.
+ It's also incremented and written to flash when the lower 32 bit field overflows, which can only happen after
+ a very long time. The consumer side does not store the d rolling codes in flash.
+
+For further protection a ``ping-pong`` (or challenge-response) facility is available, which can be enabled in the
+consumer configuration. The consumer periodically generates a 32 bit random number (a *nonce* aka "Number used Once")
+and broadcasts it as a *ping*. Any provider receiving this nonce will include it in any future encrypted broadcasts as
+*pong*. The consumer expects to get back its most recently transmitted *ping* in any packets it receives, and will reject
+any that do not contain it.
+
+Use of the ping-pong feature will add to network traffic and the size of the transmitted packets (a single packet may
+include up to 4 nonces from different devices) but provides a high level of protection against replay attacks. It does
+require a 2-way network connection, and it only works on local networks because the consumer can only *broadcast* the
+nonce to the providers.
+
+.. note::
+
+ Occasionally a ``Ping key not seen`` warning message may appear in the device log. This is expected, because it may
+ happen that while the consumer has regenerated the *ping* key, it subsequently received a *pong* with the previous key,
+ most likely because the messages crossed in transit. In such a case, the message will be rejected, but the next message
+ will contain the correct *pong*.
+
+ Because of this, ``ping-pong`` is only recommended to be used for state transmissions, which are updated periodically
+ at ``update_interval``.
+
+**Security considerations**
+
+The encryption used is `XXTEA `_ which is fast and compact. Although XXTEA is known
+to be susceptible to a chosen-plaintext attack, such an attack is not possible with this application, and it otherwise
+has no published weaknesses [#f1]_. The implementation used here has been modified slightly to use a 256 bit key which
+will strengthen security compared to the original 128 bit key.
+
+When encryption is used, all data is encrypted except the sender node name, and the initial request for a ping-pong key.
+Broadcasting names does not compromise security, since this information would already be available via mDNS.
+Requesting a key in clear text does not reduce the security of the key, since it is the ability to encrypt this key
+with the shared secret key that provides the security assurance.
+
+This does mean however that there is a possible Denial of Service attack by a malicious node overwriting a valid
+ping-pong key, which will result in packets being rejected by the legitimate consumer.
+
+Configuration examples
+----------------------
+
+This example couples two light switches in two different devices, so that switching either one on or off will cause
+the other to follow suit. In each case a template binary_sensor is used to mirror the switch state.
+
+.. code-block:: yaml
+
+ # Device 1
+ esphome:
+ name: device-1
+
+ udp:
+ binary_sensors:
+ - relay1_sensor
+
+ switch:
+ - platform: gpio
+ pin: GPIO6
+ id: relay1
+ name: "Device 1 switch"
+
+ binary_sensor:
+ - platform: template
+ id: relay1_sensor
+ lambda: "return id(relay1).state;"
+
+ - platform: udp
+ provider: device-2
+ id: relay2_sensor
+ on_press:
+ switch.turn_on: relay1
+ on_release:
+ switch.turn_off: relay1
+
+
+ # Device 2
+ esphome:
+ name: device-2
+
+ udp:
+ binary_sensors:
+ - relay2_sensor
+
+ switch:
+ - platform: gpio
+ pin: GPIO6
+ id: relay2
+ name: "Device 2 switch"
+
+ binary_sensor:
+ - platform: template
+ id: relay2_sensor
+ lambda: "return id(relay2).state;"
+
+ - platform: udp
+ provider: device-1
+ id: relay1_sensor
+ on_press:
+ switch.turn_on: relay2
+ on_release:
+ switch.turn_off: relay2
+
+The following example shows a device using encryption to read a sensor and two binary sensors from two different
+devices, one with encryption and ping-pong and one without. It also rebroadcasts one of those binary sensors with its own
+encryption and a rolling code to a remote host.
+
+.. code-block:: yaml
+
+ udp:
+ update_interval: 60s
+ addresses: ["10.87.135.110"]
+ ping_pong_enable: true
+ rolling_code_enable: true
+ encryption: "Muddy Waters"
+ binary_sensors:
+ - tick_tock
+ providers:
+ - name: st7735s
+ encryption: "Blind Willie Johnson"
+ # - name: room-lights # Not required here since no encryption
+
+ binary_sensor:
+ - platform: udp
+ provider: st7735s
+ id: tick_tock
+ - platform: udp
+ provider: room-lights
+ id: relay1_sensor
+
+ sensor:
+ - platform: udp
+ provider: st7735s
+ id: wifi_signal_sensor
+
+The example below shows a provider device separating data sent to different consumers. There are two provider confgurations, with different IDs.
+The ``udp_internal`` provider broadcasts the selected sensor states in plain every 10 seconds to all the network members, while the ``udp_external``
+provider sends other sensors data to an external IP address and port, with encryption. The node also listens to data from a ``remote-node`` through
+the port specified in the ``udp_external`` configuration:
+
+.. code-block:: yaml
+
+ udp:
+ - id: udp_internal
+ update_interval: 10s
+ sensors:
+ - temp_outdoor
+ - temp_rooma
+ - temp_roomb
+ - temp_roomc
+ - temp_garage
+ - temp_water
+ - humi_rooma
+ - humi_roomb
+ - humi_roomc
+
+ - id: udp_external
+ update_interval: 60s
+ encryption: "Muddy Waters"
+ ping_pong_enable: true
+ rolling_code_enable: true
+ port: 38512
+ addresses:
+ - 10.87.135.110
+ binary_sensors:
+ - binary_sensor_door
+ sensors:
+ - temp_outdoor
+
+ binary_sensor:
+ - platform: udp
+ id: binary_sensor_unlock
+ udp_id: udp_external
+ provider: remote-node
+ remote_id: binary_sensor_unlock_me
+ on_press:
+ - lambda: |-
+ ESP_LOGI("main", "d command to binary_sensor_unlock");
+
+
+.. [#f1] As known in 2024.06.
+
+See Also
+--------
+
+- :doc:`/components/binary_sensor/udp`
+- :doc:`/components/sensor/udp`
+- :ref:`automation`
+- :apiref:`udp/udp_component.h`
+- :ghedit:`Edit`
diff --git a/components/voice_assistant.rst b/components/voice_assistant.rst
index a52cee8986..a2d1cac08a 100644
--- a/components/voice_assistant.rst
+++ b/components/voice_assistant.rst
@@ -37,6 +37,8 @@ Configuration:
- **media_player** (*Optional*, :ref:`config-id`): The :doc:`media_player ` to use
to output the response. Cannot be used with ``speaker`` above.
- **use_wake_word** (*Optional*, boolean): Enable wake word on the assist pipeline. Defaults to ``false``.
+- **conversation_timeout** (*Optional*, :ref:`config-time`): How long to wait before resetting the ``conversation_id``
+ sent to the voice assist pipeline, which contains the context of the current assist pipeline. Defauls to ``300s``.
- **on_intent_start** (*Optional*, :ref:`Automation `): An automation to perform when intent processing starts.
- **on_intent_end** (*Optional*, :ref:`Automation `): An automation to perform when intent processing ends.
- **on_listening** (*Optional*, :ref:`Automation `): An automation to
diff --git a/conf.py b/conf.py
index e3185207f3..17f0213747 100644
--- a/conf.py
+++ b/conf.py
@@ -67,9 +67,9 @@
# built documents.
#
# The short X.Y version.
-version = "2024.8"
+version = "2024.9"
# The full version, including alpha/beta/rc tags.
-release = "2024.8.3"
+release = "2024.9.0"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/cookbook/images/lvgl_cook_animimg_batt.gif b/cookbook/images/lvgl_cook_animimg_batt.gif
new file mode 100644
index 0000000000..a1ec7806d9
Binary files /dev/null and b/cookbook/images/lvgl_cook_animimg_batt.gif differ
diff --git a/cookbook/images/lvgl_cook_climate.png b/cookbook/images/lvgl_cook_climate.png
new file mode 100644
index 0000000000..a3baccb93b
Binary files /dev/null and b/cookbook/images/lvgl_cook_climate.png differ
diff --git a/cookbook/images/lvgl_cook_clock.png b/cookbook/images/lvgl_cook_clock.png
new file mode 100644
index 0000000000..85dd627b63
Binary files /dev/null and b/cookbook/images/lvgl_cook_clock.png differ
diff --git a/cookbook/images/lvgl_cook_cover.png b/cookbook/images/lvgl_cook_cover.png
new file mode 100644
index 0000000000..5c9fe29871
Binary files /dev/null and b/cookbook/images/lvgl_cook_cover.png differ
diff --git a/cookbook/images/lvgl_cook_flex_layout.png b/cookbook/images/lvgl_cook_flex_layout.png
new file mode 100644
index 0000000000..8cca59c077
Binary files /dev/null and b/cookbook/images/lvgl_cook_flex_layout.png differ
diff --git a/cookbook/images/lvgl_cook_font_batt.png b/cookbook/images/lvgl_cook_font_batt.png
new file mode 100644
index 0000000000..6803ee049b
Binary files /dev/null and b/cookbook/images/lvgl_cook_font_batt.png differ
diff --git a/cookbook/images/lvgl_cook_font_binstat.png b/cookbook/images/lvgl_cook_font_binstat.png
new file mode 100644
index 0000000000..4315ba8cce
Binary files /dev/null and b/cookbook/images/lvgl_cook_font_binstat.png differ
diff --git a/cookbook/images/lvgl_cook_font_roboto_mdi.png b/cookbook/images/lvgl_cook_font_roboto_mdi.png
new file mode 100644
index 0000000000..2ca6aa1c90
Binary files /dev/null and b/cookbook/images/lvgl_cook_font_roboto_mdi.png differ
diff --git a/cookbook/images/lvgl_cook_gauge.png b/cookbook/images/lvgl_cook_gauge.png
new file mode 100644
index 0000000000..11379cb9d9
Binary files /dev/null and b/cookbook/images/lvgl_cook_gauge.png differ
diff --git a/cookbook/images/lvgl_cook_gradient_styles.png b/cookbook/images/lvgl_cook_gradient_styles.png
new file mode 100644
index 0000000000..9130b348a2
Binary files /dev/null and b/cookbook/images/lvgl_cook_gradient_styles.png differ
diff --git a/cookbook/images/lvgl_cook_keypad.png b/cookbook/images/lvgl_cook_keypad.png
new file mode 100644
index 0000000000..8fdff19166
Binary files /dev/null and b/cookbook/images/lvgl_cook_keypad.png differ
diff --git a/cookbook/images/lvgl_cook_pagenav.png b/cookbook/images/lvgl_cook_pagenav.png
new file mode 100644
index 0000000000..db7b3b55f0
Binary files /dev/null and b/cookbook/images/lvgl_cook_pagenav.png differ
diff --git a/cookbook/images/lvgl_cook_remligbut.png b/cookbook/images/lvgl_cook_remligbut.png
new file mode 100644
index 0000000000..ee0e77b8d5
Binary files /dev/null and b/cookbook/images/lvgl_cook_remligbut.png differ
diff --git a/cookbook/images/lvgl_cook_statico.png b/cookbook/images/lvgl_cook_statico.png
new file mode 100644
index 0000000000..b09edd29c0
Binary files /dev/null and b/cookbook/images/lvgl_cook_statico.png differ
diff --git a/cookbook/images/lvgl_cook_thermometer.png b/cookbook/images/lvgl_cook_thermometer.png
new file mode 100644
index 0000000000..ee38819578
Binary files /dev/null and b/cookbook/images/lvgl_cook_thermometer.png differ
diff --git a/cookbook/images/lvgl_cook_thermometer_gauge.png b/cookbook/images/lvgl_cook_thermometer_gauge.png
new file mode 100644
index 0000000000..6976d767d2
Binary files /dev/null and b/cookbook/images/lvgl_cook_thermometer_gauge.png differ
diff --git a/cookbook/images/lvgl_cook_titlebar.png b/cookbook/images/lvgl_cook_titlebar.png
new file mode 100644
index 0000000000..dd7f2e3038
Binary files /dev/null and b/cookbook/images/lvgl_cook_titlebar.png differ
diff --git a/cookbook/images/lvgl_cook_volume.png b/cookbook/images/lvgl_cook_volume.png
new file mode 100644
index 0000000000..3d42748c97
Binary files /dev/null and b/cookbook/images/lvgl_cook_volume.png differ
diff --git a/cookbook/images/lvgl_cook_weather.png b/cookbook/images/lvgl_cook_weather.png
new file mode 100644
index 0000000000..52bdc94f15
Binary files /dev/null and b/cookbook/images/lvgl_cook_weather.png differ
diff --git a/cookbook/lvgl.rst b/cookbook/lvgl.rst
new file mode 100644
index 0000000000..bd90892926
--- /dev/null
+++ b/cookbook/lvgl.rst
@@ -0,0 +1,2242 @@
+.. _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 :doc:`/components/lvgl/index` 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_state:
+ - lvgl.widget.update:
+ id: light_switch
+ state:
+ checked: !lambda return id(local_light).current_values.is_on();
+
+ 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
+--------
+
+- :doc:`/components/lvgl/index`
+- :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/guides/cli.rst b/guides/cli.rst
index 37910334ca..7dc145a681 100644
--- a/guides/cli.rst
+++ b/guides/cli.rst
@@ -39,6 +39,7 @@ ESPHome's command line interface always has the following format
.. option:: -v|--verbose
Enable verbose esphome logs.
+ Can also be enabled via environment variable ``ESPHOME_VERBOSE=true``.
``--quiet`` Option
------------------
diff --git a/guides/supporters.rst b/guides/supporters.rst
index 2a7385f247..7a8bd0e222 100644
--- a/guides/supporters.rst
+++ b/guides/supporters.rst
@@ -49,6 +49,7 @@ Contributors
- `Chris Byrne (@adapt0) `__
- `Attila Darazs (@adarazs) `__
- `ADeadPixel (@ADeadPixel) `__
+- `Adam DeMuri (@ademuri) `__
- `adezerega (@adezerega) `__
- `Eugen (@Adminius) `__
- `Andrea Donno (@adonno) `__
@@ -141,6 +142,7 @@ Contributors
- `arantius (@arantius) `__
- `Ryan DeShone (@ardichoke) `__
- `Ariff Saad (@arffsaad) `__
+- `ArkanStasarik (@ArkanStasarik) `__
- `arturo182 (@arturo182) `__
- `arunderwood (@arunderwood) `__
- `Arya (@Arya11111) `__
@@ -198,6 +200,7 @@ Contributors
- `Ben Hoff (@benhoff) `__
- `Benoît Leforestier (@Benichou34) `__
- `Benjamin Aigner (@benjaminaigner) `__
+- `benklop (@benklop) `__
- `benniju (@benniju) `__
- `Benno Pütz (@bennop) `__
- `Benny H (@benny-aus) `__
@@ -260,6 +263,7 @@ Contributors
- `brianrjones69 (@brianrjones69) `__
- `Ben Brooks (@brooksben11) `__
- `brtchip-tuannguyen (@brtchip-tuannguyen) `__
+- `Vaclav (@bruxy70) `__
- `buddydvd (@buddydvd) `__
- `bulburDE (@bulburDE) `__
- `Justin Bunton (@Bunton33) `__
@@ -583,6 +587,7 @@ Contributors
- `Daniel Dunn (@EternityForest) `__
- `EtienneMD (@EtienneMD) `__
- `etzisim (@etzisim) `__
+- `EvanC-Au (@EvanC-Au) `__
- `Evan Coleman (@evandcoleman) `__
- `Clemens Kirchgatterer (@everslick) `__
- `Everything Smart Home (@EverythingSmartHome) `__
@@ -680,6 +685,7 @@ Contributors
- `git2212 (@git2212) `__
- `GitforZhangXL (@GitforZhangXL) `__
- `github-actions[bot] (@github-actions[bot]) `__
+- `GitJRS (@GitJRS) `__
- `gitolicious (@gitolicious) `__
- `The Gitter Badger (@gitter-badger) `__
- `Frederik Gladhorn (@gladhorn) `__
@@ -843,6 +849,7 @@ Contributors
- `JasperPlant (@JasperPlant) `__
- `Jas Strong (@jasstrong) `__
- `Alex Boyd (@javawizard) `__
+- `JayElDubya (@JayElDubya) `__
- `Jay Greco (@jaygreco) `__
- `Jay Newstrom (@JayNewstrom) `__
- `Jeff (@jazzmonger) `__
@@ -978,6 +985,7 @@ Contributors
- `kghandi (@kghandi) `__
- `Khoi Hoang (@khoih-prog) `__
- `AngeloGioacchino Del Regno (@kholk) `__
+- `Albert Gouws (@KiLLeRRaT) `__
- `Kilowatt (@Kilowatt-W) `__
- `kimonm (@kimonm) `__
- `Kip (@kipwittchen) `__
@@ -990,6 +998,7 @@ Contributors
- `Kevin Lewis (@kll) `__
- `kmoulton (@kmoulton) `__
- `KNXBroker (@KNXBroker) `__
+- `KodinLanewave (@KodinLanewave) `__
- `KoenBreeman (@KoenBreeman) `__
- `Koen Vervloesem (@koenvervloesem) `__
- `kokangit (@kokangit) `__
@@ -1461,6 +1470,7 @@ Contributors
- `probonopd (@probonopd) `__
- `Gary Morris (@progrmr) `__
- `Mike Lynch (@Prow7) `__
+- `Prowler2 (@Prowler2) `__
- `Peter Sarossy (@psarossy) `__
- `Peter Stuifzand (@pstuifzand) `__
- `Peter Tatrai (@ptatrai) `__
@@ -1802,6 +1812,7 @@ Contributors
- `tomaszduda23 (@tomaszduda23) `__
- `Tom Brien (@TomBrien) `__
- `Thomas Combriat (@tomcombriat) `__
+- `Tomer (@tomer-w) `__
- `TomFahey (@TomFahey) `__
- `Tom Hartogs (@TomHartogs) `__
- `TomKong666 (@TomKong666) `__
@@ -1872,6 +1883,7 @@ Contributors
- `Vishnu Mohanan (@vishnumaiea) `__
- `VitaliyKurokhtin (@VitaliyKurokhtin) `__
- `voed (@voed) `__
+- `James Vogel (@voglster) `__
- `voibit (@voibit) `__
- `Xuming Feng (@voicevon) `__
- `Manuel Bichler (@votacom) `__
@@ -1943,6 +1955,7 @@ Contributors
- `yousaf465 (@yousaf465) `__
- `Jevgeni Kiski (@yozik04) `__
- `YuanL.Lee (@yuanl) `__
+- `Cj Fraser (@yuniq-neko) `__
- `Yuval Aboulafia (@yuvalabou) `__
- `Z3LIFF (@z3liff) `__
- `ZabojnikM (@ZabojnikM) `__
@@ -1950,6 +1963,7 @@ Contributors
- `zaluthar (@zaluthar) `__
- `david reid (@zathras777) `__
- `Zebble (@Zebble) `__
+- `Wojciech Zelek (@zelo) `__
- `Brynley McDonald (@ZephireNZ) `__
- `ZJY (@zhangjingye03) `__
- `San (@zhujunsan) `__
@@ -1967,4 +1981,4 @@ Contributors
- `Christian Zufferey (@zuzu59) `__
- `Zynth-dev (@Zynth-dev) `__
-*This page was last updated September 3, 2024.*
+*This page was last updated September 18, 2024.*
diff --git a/images/bl0906.png b/images/bl0906.png
new file mode 100644
index 0000000000..e5897e3cf4
Binary files /dev/null and b/images/bl0906.png differ
diff --git a/images/ch422g.svg b/images/ch422g.svg
new file mode 100644
index 0000000000..f94fa67709
--- /dev/null
+++ b/images/ch422g.svg
@@ -0,0 +1 @@
+
diff --git a/images/ltr501.jpg b/images/ltr501.jpg
new file mode 100644
index 0000000000..a8ccbda564
Binary files /dev/null and b/images/ltr501.jpg differ
diff --git a/images/udp.svg b/images/udp.svg
new file mode 100644
index 0000000000..d9e02adc17
--- /dev/null
+++ b/images/udp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/index.rst b/index.rst
index 0f09741f47..e14b79a9f8 100644
--- a/index.rst
+++ b/index.rst
@@ -204,6 +204,8 @@ Network Protocols
HTTP Request, components/http_request, connection.svg, dark-invert
mDNS, components/mdns, radio-tower.svg, dark-invert
WireGuard, components/wireguard, wireguard_custom_logo.svg
+ StatsD, components/statsd, connection.svg
+ UDP, components/udp, udp.svg
Bluetooth/BLE
-------------
@@ -224,6 +226,7 @@ Management and Monitoring
Debug, components/debug, bug-report.svg, dark-invert
Logger, components/logger, file-document-box.svg, dark-invert
Prometheus, components/prometheus, prometheus.svg
+ StatsD, components/statsd, connection.svg
Safe Mode, components/safe_mode, restart-alert.svg
Web Server, components/web_server, http.svg, dark-invert
ESP32 Camera Web Server, components/esp32_camera_web_server, camera.svg, dark-invert
@@ -266,6 +269,7 @@ I/O Expanders/Multiplexers
.. imgtable::
+ CH422G, components/ch422g, ch422g.svg
MAX6956 - I²C Bus, components/max6956, max6956.jpg
MCP230XX - I²C Bus, components/mcp230xx, mcp230xx.svg
MCP23SXX - SPI Bus, components/mcp23Sxx, mcp230xx.svg
@@ -401,6 +405,7 @@ Electricity
ADE7953, components/sensor/ade7953, ade7953.svg, Power
ATM90E26, components/sensor/atm90e26, atm90e26.jpg, Voltage & Current & Power
ATM90E32, components/sensor/atm90e32, atm90e32.jpg, Voltage & Current & Power
+ BL0906, components/sensor/bl0906, bl0906.png, Voltage & Current & Power & Energy
BL0939, components/sensor/bl0939, bl0939.png, Voltage & Current & Power & Energy
BL0940, components/sensor/bl0940, bl0940.png, Voltage & Current & Power
BL0942, components/sensor/bl0942, bl0942.png, Voltage & Current & Power
@@ -504,11 +509,14 @@ Light
APDS9960, components/sensor/apds9960, apds9960.jpg, Colour & Gesture
AS7341, components/sensor/as7341, as7341.jpg, Spectral Color Sensor
BH1750, components/sensor/bh1750, bh1750.jpg, Lux
+ LTR301, components/sensor/ltr501, ltr501.jpg, Lux
LTR303, components/sensor/ltr_als_ps, ltr303.jpg, Lux
LTR329, components/sensor/ltr_als_ps, ltr329.jpg, Lux
LTR390, components/sensor/ltr390, ltr390.jpg, Lux & UV
+ LTR501, components/sensor/ltr501, ltr501.jpg, Lux & Proximity
LTR553, components/sensor/ltr_als_ps, ltr-ps.jpg, Lux & Proximity
LTR556, components/sensor/ltr_als_ps, ltr-ps.jpg, Lux & Proximity
+ LTR558, components/sensor/ltr501, ltr501.jpg, Lux & Proximity
LTR559, components/sensor/ltr_als_ps, ltr559.jpg, Lux & Proximity
LTR659, components/sensor/ltr_als_ps, ltr-ps.jpg, Proximity
MAX44009, components/sensor/max44009, max44009.svg, Lux
@@ -1147,6 +1155,7 @@ Cookbook
.. imgtable::
Lambda Magic: Tips and Tricks, cookbook/lambda_magic, head-lightbulb-outline.svg, dark-invert
+ LVGL 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
@@ -1155,7 +1164,6 @@ Cookbook
Sonoff Fishpond Pump, cookbook/sonoff-fishpond-pump, cookbook-sonoff-fishpond-pump.jpg
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
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 `.
diff --git a/lint.py b/lint.py
index 106a4017aa..390cdf95a4 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):