Привет Habr! Продолжаем серию статей о LVGL в ESPHome. В третьей части статьи речь пойдет о создании своего пользовательского виджета, который может быть подключен к проекту. И не только к данному проекту, а вообще даст небольшое представление как делать виджеты в ESPHome. Итак, Создавать будем виджет умной розетки с индикацией мощности, напряжения и силы тока. Поехали...

Структура виджета

Создадим в нашем проекте в папке widgets папку socket, а в ней файл socket.yaml.
В нашем примере виджет будет состоять из 4 основных блоков:


substitutions:     # Замены, попросту говоря, статичные переменные, константы
sensor:            # Числовые датчики от Home Assistant
text_sensor:       # Текстовые датчики от Home Assistant
lvgl:              # Визуальный интерфейс

Substitutions - замены/подстановки/константы

Назначение: Делают виджет переиспользуемым с разными параметрами.

Так как в коде мы много где указываем одни и теже данные, проще использовать одну константу и указывать её далее везде в коде.

Для начала нам нужно название сущности из Home Assistant. В моем случает это switch.rozetka_test_socket, а также 3 сенсора с мощностью, напряжением и силой тока. В моем случае это:

sensor.rozetka_test_power   # Мощность
sensor.rozetka_test_voltage # Напряжение
sensor.rozetka_test_current # Сила тока

Добавляем переменную socket_entity чтобы дальше использовать её вместо switch.rozetka_test_socket и три наших сенсора

substitutions:

  socket_entity:  "switch.rozetka_test_socket"
  socket_power:   "sensor.rozetka_test_power"   # Мощность
  socket_voltage: "sensor.rozetka_test_voltage" # Напряжение
  socket_current: "sensor.rozetka_test_current" # Сила тока

Также нам потребуются 4 иконки из набора MDI и наш блок substitutions уже будет выглядеть так:

substitutions:

  socket_entity:  "switch.rozetka_test_socket"
  socket_power:   "sensor.rozetka_test_power"   # Мощность
  socket_voltage: "sensor.rozetka_test_voltage" # Напряжение
  socket_current: "sensor.rozetka_test_current" # Сила тока

  socket_icon:          "\U000F1107"
  socket_current_icon:  "\U000F1480"
  socket_voltage_icon:  "\U000F095B"
  socket_power_icon:    "\U000F0241"

Чтобы иконки отображались их надо добавить в шрифты fonts.yaml

- file: "fonts/materialdesignicons-webfont.ttf"
  id: mdi_icons_40
  size: 40
  bpp: 4
  glyphs: [
    "\U000F1107", # socket
    "\U000F1480", # current
    "\U000F095B", # voltage
    "\U000F0241", # power
    "\U000F068A", # shield home
    "\U000F1828", # shield moon
    "\U000F099D", # shield lock
    "\U000F06BB", # shield plane
    "\U000F099E", # shield off
    "\U000F0498", # shield
  ]

- file: "fonts/materialdesignicons-webfont.ttf"
  id: mdi_icons_160
  size: 160
  bpp: 4
  glyphs: [
    "\U000F1107", # socket
  ]

Text Sensors - текстовые датчики

Назначение: Получают текстовые данные от Home Assistant.

Для получения информации с текстовых датчиков Home Assistant нам потребуется создать текстовые датчики text_sensor.
Нам нужно получить:

  • состояние объекта

  • название объекта

  • единицы измерения мощности, напряжения и силы тока

Состояние объекта

text_sensor:

  # Состояние розетки
  - platform: homeassistant        # Указываем платформу Home Assistant
    id: socket_sensor_state        # Придумываем уникальный индификатор для связи в коде
    entity_id: "${socket_entity}"  # Указываем константу нашей сущности из substitutions

Название объекта

  # Имя розетки
  - platform: homeassistant
    id: socket_sensor_name
    entity_id: "${socket_entity}"
    attribute: friendly_name      # Указываем атрибут сущности

Единицы измерения мощности, напряжения и силы тока

    # Единицы измерения мощности
  - platform: homeassistant
    id: socket_sensor_power_uom
    entity_id: "${socket_power}"
    attribute: unit_of_measurement

    # Единицы измерения напряжения
  - platform: homeassistant
    id: socket_sensor_voltage_uom
    entity_id: "${socket_voltage}"
    attribute: unit_of_measurement

    # Единицы измерения силы тока
  - platform: homeassistant
    id: socket_sensor_current_uom
    entity_id: "${socket_current}"
    attribute: unit_of_measurement

Итак, у нас теперь получается вот такая секция text_sensor (но мы к ней ещё вернемся):

text_sensor:

  # Состояние розетки
  - platform: homeassistant
    id: socket_sensor_state
    entity_id: "${socket_entity}"

  # Имя розетки
  - platform: homeassistant
    id: socket_sensor_name
    entity_id: "${socket_entity}"
    attribute: friendly_name

  # Единицы измерения мощности
  - platform: homeassistant
    id: socket_sensor_power_uom
    entity_id: "${socket_power}"
    attribute: unit_of_measurement

  # Единицы измерения напряжения
  - platform: homeassistant
    id: socket_sensor_voltage_uom
    entity_id: "${socket_voltage}"
    attribute: unit_of_measurement

  # Единицы измерения силы тока
  - platform: homeassistant
    id: socket_sensor_current_uom
    entity_id: "${socket_current}"
    attribute: unit_of_measurement

Sensors - числовые датчики

Назначение: Получают числовые данные от Home Assistant.

Для получения информации с числовых датчиков Home Assistant нам потребуется создать числовые датчики sensor
Нам нужно получить значения с датчиков мощности, напряжения и силы тока:

sensor:
    # Значение мощности
  - platform: homeassistant
    id: socket_sensor_power
    entity_id: "${socket_power}"

    # Значение напряжения
  - platform: homeassistant
    id: socket_sensor_voltage
    entity_id: "${socket_voltage}"

    # Значение силы тока
  - platform: homeassistant
    id: socket_sensor_current
    entity_id: "${socket_current}"

К ним мы также позже вернемся чтобы определить действия при получении значений с датчиков.

LVGL интерфейс

Назначение: Создает визуальный интерфейс виджета.

Структура страницы:

Чтобы соответствовать дизайну нашей прошивки, мы создадим страницу в которой будет 7 блоков:

lvgl:
  pages:
    - id: socket_page                 # Уникальный индификатор страницы
      bg_color: color_slate_blue_gray # Цвет фона
      widgets:                        # Список виджетов

        # Объект с состоянием
        - obj:
            id: socket_state
            x: 20
            y: 20
            width: 440
            height: 60
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10

        # Объект с кнопкой включения/выключения розетки 
        - obj:
            id: socket_icon_bg
            x: 20
            y: 100
            width: 210
            height: 280
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10

        # Объект с идикатором мощности
        - obj:
            id: socket_power_bg
            x: 250
            y: 100
            width: 210
            height: 80
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10

        # Объект с идикатором напряжения
        - obj:
            id: socket_voltage_bg
            x: 250
            y: 200
            width: 210
            height: 80
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10

        # Объект с идикатором силы тока
        - obj:
            id: socket_current_bg
            x: 250
            y: 300
            width: 210
            height: 80
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10

        # Кнопка выхода
        - obj:
            id: socket_back_bg
            x: 20
            y: 400
            width: 60
            height: 60
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10

        # Имя
        - obj:
            id: socket_name_bg
            x: 100
            y: 400
            width: 360
            height: 60
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10

Все объекты имеют одинаковую структуру, но разные размеры и координаты, например:

- obj:
    id: socket_state             # Уникальный идентификатор виджета
    x: 20                        # Координата X
    y: 20                        # Координата Y
    width: 440                   # Ширина виджета в пикселях
    height: 60                   # Высота виджета в пикселях
    align: top_left              # Выравнивание (вверху слева)
    pad_all: 0                   # Убираем все отступы
    bg_color: color_steel_blue   # Цвет фона
    bg_opa: 20%                  # Прозрачность фона
    border_opa: transp           # Прозрачность обводки (полная)
    border_width: 0              # Толщина обводки
    shadow_opa: transp           # Прозрачность тени (полная)
    radius: 10                   # Скругляем края

Теперь нам надо наполнить наши блоки контентом

Блок состояния

Добавляем в наш блок текст, который будет отображать состояние розетки (включена или выключена):

# Объект с состоянием
- obj:
    id: socket_state
    x: 20
    y: 20
    width: 440
    height: 60
    align: top_left
    pad_all: 0
    bg_color: color_steel_blue
    bg_opa: 20%
    border_opa: transp
    border_width: 0
    shadow_opa: transp
    radius: 10
    widgets:
      - label:                           # Виджет текст
          id: socket_state_label         # Уникальный идентификатор
          align: center                  # Выравнивание относительно нашего блока, а не страницы
          text_font: nunito_18           # Шрифт (размер)
          text_color: color_misty_blue   # Цвет шрифта
          text: " "                      # Тест (оставляем пустым, передадим через действие)

Теперь возвращаемя к сенсору, который отвечает за состояние. Добавляем ему действие (что надо сделать при получении значения в сенсор):

text_sensor:

  # Состояние розетки
  - platform: homeassistant
    id: socket_sensor_state
    entity_id: "${socket_entity}"
    on_value:
      - lvgl.label.update:
          id: socket_state_label
          text: !lambda return x;

      - if:
          condition:
            lambda: 'return x == "on";'
          then:
            - lvgl.label.update:
                id: socket_icon_label
                text_color: color_yellow
          else:
            - lvgl.label.update:
                id: socket_icon_label
                text_color: color_misty_blue

Добавляем on_value (при получении значения), указываем сделать два действия:

  • Обновить виджет с id socket_state_label. Передать ему в text значение x (сырое значение сенсора) вместо пустого, что мы установили

  • Обновить виджет с id socket_icon_label. Передать ему цвет в зависимости от состояния. Иными словами, тут условие, если сенсор состояния получает значение on, то значок становится желтым цветом, в противном случае цвет будет color_misty_blue

Блок-кнопка с индикацией

Добавляем в наш блок текст (значок), c индикацией состояние розетки (включена или выключена):

# Объект с кнопкой включения/выключения розетки 
- obj:
    id: socket_icon_bg
    x: 20
    y: 100
    width: 210
    height: 280
    align: top_left
    pad_all: 0
    bg_color: color_steel_blue
    bg_opa: 20%
    border_opa: transp
    border_width: 0
    shadow_opa: transp
    radius: 10
    widgets:
      - label:
          id: socket_icon_label 
          align: center
          text_font: mdi_icons_160
          text_color: color_misty_blue
          text: "${socket_icon}"

Делаем из блока кнопку, вызывая службу home assistant switch.toggle

# Объект с кнопкой включения/выключения розетки 
- obj:
    id: socket_icon_bg
    x: 20
    y: 100
    width: 210
    height: 280
    align: top_left
    pad_all: 0
    bg_color: color_steel_blue
    bg_opa: 20%
    border_opa: transp
    border_width: 0
    shadow_opa: transp
    radius: 10
    widgets:
      - label:
          id: socket_icon_label
          align: center
          text_font: mdi_icons_160
          text_color: color_misty_blue
          text: "${socket_icon}"
    on_click:                               # Действие по клику
      - homeassistant.action:               # Вызываем службу Home Assistant
          action: switch.toggle             # Название службы (переключение выключателя)
          data:
            entity_id: "${socket_entity}".  # Наша сущность

В предыдущем разделе мы уже добавили действие этому виджету со сменой цвета значка.

Блоки с индикацией мощности, напряжения и силы тока

Добавляем в наш блок мощности 3 текста:

  • значок

  • значение

  • единицы измерения

# Объект с идикатором мощности
- obj:
    id: socket_power_bg
    x: 250
    y: 100
    width: 210
    height: 80
    align: top_left
    pad_all: 0
    bg_color: color_steel_blue
    bg_opa: 20%
    border_opa: transp
    border_width: 0
    shadow_opa: transp
    radius: 10
    widgets:
      - label:
          id: socket_power_icon_label
          x: 10                             # Делаем небольшой отступ слева
          align: left_mid
          text_font: mdi_icons_40           # Иконочный шрифт
          text_color: color_misty_blue
          text: "${socket_power_icon}"      # Иконка из substitutions
      - label:
          id: socket_power_state_label
          x: 70                             # Делаем отступ от значка
          align: left_mid
          text_font: nunito_18
          text_color: color_misty_blue
          text: " "                         # Пустое поле, передадим действием
      - label:
          id: socket_power_state_uom_label
          x: 140                            # Делаем отступ от значка
          align: left_mid
          text_font: nunito_18
          text_color: color_misty_blue
          text: " "                         # Пустое поле, передадим действием

Возвращаемся к нашим сенсорам мощности и добавляем им действия:

text_sensor:
  # Единицы измерения мощности
  - platform: homeassistant
    id: socket_sensor_power_uom
    entity_id: "${socket_power}"
    attribute: unit_of_measurement
    on_value:
      - lvgl.label.update:
          id: socket_power_state_uom_label
          text: !lambda return x;
sensor:
    # Значение мощности
  - platform: homeassistant
    id: socket_sensor_power
    entity_id: "${socket_power}"
    on_value:
      - lvgl.label.update:
          id: socket_power_state_label
          text: !lambda |-
            if (isnan(x)) return "N/A";
            char buf[16];
            snprintf(buf, sizeof(buf), "%.1f", x);
            return buf;

И если с первым сенсором все понятно, то со вторым могут возникнуть вопросы, поясню что здесь происходит:

if (isnan(x)) return "N/A";
char buf[16];
snprintf(buf, sizeof(buf), "%.1f", x);
return buf;
  1. Проверка на нечисловое значение:

    if (isnan(x)) return "N/A";
    
    • isnan(x) - Проверяет, является ли значение x нечисловым (NaN)

    • return "N/A" - Возвращает "N/A" если значение невалидное

  2. Создание буфера:

    char buf[16];
    
    • Создаёт символьный буфер на 16 байт

    • Достаточно для хранения чисел формата -123456.789

  3. Форматированный вывод:

    snprintf(buf, sizeof(buf), "%.1f", x);
    

    Параметр

    Описание

    buf

    Буфер для записи результата

    sizeof(buf)

    Максимальный размер данных (16 байт)

    "%.1f"

    Шаблон форматирования (1 знак после точки)

    x

    Входное значение сенсора

  4. Возврат результата:

    // Возвращает отформатированную строку
    return buf;
    

Для разных сенсоров используйте:

// Для мощности и напряжения (1 знак)
snprintf(buf, sizeof(buf), "%.1f", x);

// Для силы тока (3 знака)
snprintf(buf, sizeof(buf), "%.3f", x);

Примеры преобразования

Входное значение

Формат

Результат

23.456789

%.1f

23.5

0.123456

%.3f

0.123

NaN

-

N/A

С напряжением и силой тока все аналогично

Блок с кнопкой возвращения в меню

Добавляем текст с иконкой и действие при нажатии:

# Кнопка выхода
- obj:
    id: socket_back_bg
    x: 20
    y: 400
    width: 60
    height: 60
    align: top_left
    pad_all: 0
    bg_color: color_steel_blue
    bg_opa: 20%
    border_opa: transp
    border_width: 0
    shadow_opa: transp
    radius: 10
    widgets:
      - label:
          id: socket_back_label
          align: center
          text_font: icons_28
          text_color: color_misty_blue
          text: "${exit_icon}"
    on_press:
      - lvgl.page.show: devices_page           # Показываем страницу Devices вместо текущей
      - lvgl.widget.show: menu_controls_main   # Показываем кнопки меню

Блок с названием сущности

Добавляем текст:

# Имя
- obj:
    id: socket_name_bg
    x: 100
    y: 400
    width: 360
    height: 60
    align: top_left
    pad_all: 0
    bg_color: color_steel_blue
    bg_opa: 20%
    border_opa: transp
    border_width: 0
    shadow_opa: transp
    radius: 10
    widgets:
      - label:
          id: socket_name_label
          align: center
          text_font: nunito_18
          text_color: color_misty_blue
          text: "friendly name"

Возвращаемся к сенсору имени и добавляем действие:

  # Имя розетки
  - platform: homeassistant
    id: socket_sensor_name
    entity_id: "${socket_entity}"
    attribute: friendly_name
    on_value:
      - lvgl.label.update:
          id: socket_name_label
          text: !lambda return x;

Итоговый код нашего виджета

substitutions:

  socket_entity:  "switch.rozetka_test_socket"
  socket_power:   "sensor.rozetka_test_power"   # Мощность
  socket_voltage: "sensor.rozetka_test_voltage" # Напряжение
  socket_current: "sensor.rozetka_test_current" # Сила тока

  socket_icon:          "\U000F1107"
  socket_current_icon:  "\U000F1480"
  socket_voltage_icon:  "\U000F095B"
  socket_power_icon:    "\U000F0241"

text_sensor:

  # Состояние розетки
  - platform: homeassistant
    id: socket_sensor_state
    entity_id: "${socket_entity}"
    on_value:
      - lvgl.label.update:
          id: socket_state_label
          text: !lambda return x;

      - if:
          condition:
            lambda: 'return x == "on";'
          then:
            - lvgl.label.update:
                id: socket_icon_label
                text_color: color_yellow
          else:
            - lvgl.label.update:
                id: socket_icon_label
                text_color: color_misty_blue

  # Имя розетки
  - platform: homeassistant
    id: socket_sensor_name
    entity_id: "${socket_entity}"
    attribute: friendly_name
    on_value:
      - lvgl.label.update:
          id: socket_name_label
          text: !lambda return x;

  # Единицы измерения мощности
  - platform: homeassistant
    id: socket_sensor_power_uom
    entity_id: "${socket_power}"
    attribute: unit_of_measurement
    on_value:
      - lvgl.label.update:
          id: socket_power_state_uom_label
          text: !lambda return x;

  # Единицы измерения напряжения
  - platform: homeassistant
    id: socket_sensor_voltage_uom
    entity_id: "${socket_voltage}"
    attribute: unit_of_measurement
    on_value:
      - lvgl.label.update:
          id: socket_voltage_state_uom_label
          text: !lambda return x;

  # Единицы измерения силы тока
  - platform: homeassistant
    id: socket_sensor_current_uom
    entity_id: "${socket_current}"
    attribute: unit_of_measurement
    on_value:
      - lvgl.label.update:
          id: socket_current_state_uom_label
          text: !lambda return x;

sensor:
  # Значение мощности
  - platform: homeassistant
    id: socket_sensor_power
    entity_id: "${socket_power}"
    on_value:
      - lvgl.label.update:
          id: socket_power_state_label
          text: !lambda |-
            if (isnan(x)) return "N/A";
            char buf[16];
            snprintf(buf, sizeof(buf), "%.1f", x);
            return buf;

  # Значение напряжения
  - platform: homeassistant
    id: socket_sensor_voltage
    entity_id: "${socket_voltage}"
    on_value:
      - lvgl.label.update:
          id: socket_voltage_state_label
          text: !lambda |-
            if (isnan(x)) return "N/A";
            char buf[16];
            snprintf(buf, sizeof(buf), "%.1f", x);
            return buf;

  # Значение силы тока
  - platform: homeassistant
    id: socket_sensor_current
    entity_id: "${socket_current}"
    on_value:
      - lvgl.label.update:
          id: socket_current_state_label
          text: !lambda |-
            if (isnan(x)) return "N/A";
            char buf[16];
            snprintf(buf, sizeof(buf), "%.3f", x);
            return buf;


lvgl:
  pages:
    - id: socket_page
      bg_color: color_slate_blue_gray
      widgets:

        # Объект с состоянием
        - obj:
            id: socket_state
            x: 20
            y: 20
            width: 440
            height: 60
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10
            widgets:
              - label:
                  id: socket_state_label
                  align: center
                  text_font: nunito_18
                  text_color: color_misty_blue
                  text: " "

        # Объект с кнопкой включения/выключения розетки 
        - obj:
            id: socket_icon_bg
            x: 20
            y: 100
            width: 210
            height: 280
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10
            widgets:
              - label:
                  id: socket_icon_label
                  align: center
                  text_font: mdi_icons_160
                  text_color: color_misty_blue
                  text: "${socket_icon}"
            on_click:
              - homeassistant.action:
                  action: switch.toggle
                  data:
                    entity_id: "${socket_entity}"

        # Объект с идикатором мощности
        - obj:
            id: socket_power_bg
            x: 250
            y: 100
            width: 210
            height: 80
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10
            widgets:
              - label:
                  id: socket_power_icon_label
                  x: 10
                  align: left_mid
                  text_font: mdi_icons_40
                  text_color: color_misty_blue
                  text: "${socket_power_icon}"
              - label:
                  id: socket_power_state_label
                  x: 70
                  align: left_mid
                  text_font: nunito_18
                  text_color: color_misty_blue
                  text: " "
              - label:
                  id: socket_power_state_uom_label
                  x: 140
                  align: left_mid
                  text_font: nunito_18
                  text_color: color_misty_blue
                  text: " "

        # Объект с идикатором напряжения
        - obj:
            id: socket_voltage_bg
            x: 250
            y: 200
            width: 210
            height: 80
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10
            widgets:
              - label:
                  id: socket_voltage_icon_label
                  x: 10
                  align: left_mid
                  text_font: mdi_icons_40
                  text_color: color_misty_blue
                  text: "${socket_voltage_icon}"
              - label:
                  id: socket_voltage_state_label
                  x: 70
                  align: left_mid
                  text_font: nunito_18
                  text_color: color_misty_blue
                  text: " "
              - label:
                  id: socket_voltage_state_uom_label
                  x: 140
                  align: left_mid
                  text_font: nunito_18
                  text_color: color_misty_blue
                  text: " "

        # Объект с идикатором силы тока
        - obj:
            id: socket_current_bg
            x: 250
            y: 300
            width: 210
            height: 80
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10
            widgets:
              - label:
                  id: socket_current_icon_label
                  x: 10
                  align: left_mid
                  text_font: mdi_icons_40
                  text_color: color_misty_blue
                  text: "${socket_current_icon}"
              - label:
                  id: socket_current_state_label
                  x: 70
                  align: left_mid
                  text_font: nunito_18
                  text_color: color_misty_blue
                  text: " "
              - label:
                  id: socket_current_state_uom_label
                  x: 140
                  align: left_mid
                  text_font: nunito_18
                  text_color: color_misty_blue
                  text: " "

        # Кнопка выхода
        - obj:
            id: socket_back_bg
            x: 20
            y: 400
            width: 60
            height: 60
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10
            widgets:
              - label:
                  id: socket_back_label
                  align: center
                  text_font: icons_28
                  text_color: color_misty_blue
                  text: "${exit_icon}"
            on_press:
              - lvgl.page.show: devices_page
              - lvgl.widget.show: menu_controls_main

        # Имя
        - obj:
            id: socket_name_bg
            x: 100
            y: 400
            width: 360
            height: 60
            align: top_left
            pad_all: 0
            bg_color: color_steel_blue
            bg_opa: 20%
            border_opa: transp
            border_width: 0
            shadow_opa: transp
            radius: 10
            widgets:
              - label:
                  id: socket_name_label
                  align: center
                  text_font: nunito_18
                  text_color: color_misty_blue
                  text: "friendly name"

Кнопка для отображения виджета

Итак, мы создали виджет, но как же его интегрировать в существующую прошивку?
Для этого нам надо подключить наш виджет в devices.yaml и добавить кнопку перехода.

Подключаем виджет

packages:
  media_player: !include media_player/media_player.yaml
  vacuum: !include vacuum/vacuum_widget.yaml
  shutter: !include shutter/shutter_config.yaml
  thermostat: !include thermostat/thermostat_widget.yaml
  air_conditioner: !include air_conditioner/air_conditioner_widget.yaml
  alarm_panel: !include alarm_panel/alarm_panel.yaml
  socket: !include socket/socket_widget.yaml

Подключаем кнопку

              - obj:
                  y: 260
                  width: 440
                  height: 60
                  pad_all: 0
                  align: TOP_MID
                  bg_opa: TRANSP
                  shadow_opa: TRANSP
                  border_opa: TRANSP
                  border_width: 0
                  radius: 10
                  widgets:
                    - button:
                        id: socket_page_btn
                        x: 35
                        align: LEFT_MID
                        width: 370
                        height: 60
                        radius: 10
                        bg_color: color_slate_blue_gray
                        shadow_opa: TRANSP
                        widgets:
                          - label:
                              align: CENTER
                              text_color: color_steel_blue
                              text_font: mdi_icons_40
                              text: "${socket_icon}"
                        on_press:
                          - lvgl.widget.hide: menu_controls_main
                          - lvgl.page.show: 
                              id: socket_page
                              animation: OUT_RIGHT
                              time: 300ms

! ВАЖНО Обратите внимание на количество отступов

Заключение

Данный пример демонстрирует лишь малую часть возможностей LVGL в ESPHome и может служить основой для создания более сложных и функциональных пользовательских интерфейсов.

Комментарии (0)