mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	[lvgl] Fix compile error when using encoder with buttons only. (#7203)
This commit is contained in:
		| @@ -23,9 +23,9 @@ from esphome.helpers import write_file_if_changed | |||||||
| from . import defines as df, helpers, lv_validation as lvalid | from . import defines as df, helpers, lv_validation as lvalid | ||||||
| from .automation import disp_update, update_to_code | from .automation import disp_update, update_to_code | ||||||
| from .defines import CONF_SKIP | from .defines import CONF_SKIP | ||||||
|  | from .encoders import ENCODERS_CONFIG, encoders_to_code | ||||||
| from .lv_validation import lv_bool, lv_images_used | from .lv_validation import lv_bool, lv_images_used | ||||||
| from .lvcode import LvContext, LvglComponent | from .lvcode import LvContext, LvglComponent | ||||||
| from .rotary_encoders import ROTARY_ENCODER_CONFIG, rotary_encoders_to_code |  | ||||||
| from .schemas import ( | from .schemas import ( | ||||||
|     DISP_BG_SCHEMA, |     DISP_BG_SCHEMA, | ||||||
|     FLEX_OBJ_SCHEMA, |     FLEX_OBJ_SCHEMA, | ||||||
| @@ -256,7 +256,7 @@ async def to_code(config): | |||||||
|  |  | ||||||
|     async with LvContext(lv_component): |     async with LvContext(lv_component): | ||||||
|         await touchscreens_to_code(lv_component, config) |         await touchscreens_to_code(lv_component, config) | ||||||
|         await rotary_encoders_to_code(lv_component, config) |         await encoders_to_code(lv_component, config) | ||||||
|         await theme_to_code(config) |         await theme_to_code(config) | ||||||
|         await styles_to_code(config) |         await styles_to_code(config) | ||||||
|         await set_obj_properties(lv_scr_act, config) |         await set_obj_properties(lv_scr_act, config) | ||||||
| @@ -336,7 +336,7 @@ CONFIG_SCHEMA = ( | |||||||
|                 {cv.Optional(name): obj_schema(w) for name, w in WIDGET_TYPES.items()} |                 {cv.Optional(name): obj_schema(w) for name, w in WIDGET_TYPES.items()} | ||||||
|             ), |             ), | ||||||
|             cv.GenerateID(df.CONF_TOUCHSCREENS): touchscreen_schema, |             cv.GenerateID(df.CONF_TOUCHSCREENS): touchscreen_schema, | ||||||
|             cv.GenerateID(df.CONF_ROTARY_ENCODERS): ROTARY_ENCODER_CONFIG, |             cv.GenerateID(df.CONF_ENCODERS): ENCODERS_CONFIG, | ||||||
|         } |         } | ||||||
|     ) |     ) | ||||||
|     .extend(DISP_BG_SCHEMA) |     .extend(DISP_BG_SCHEMA) | ||||||
|   | |||||||
| @@ -388,6 +388,7 @@ CONF_DEFAULT = "default" | |||||||
| CONF_DEFAULT_FONT = "default_font" | CONF_DEFAULT_FONT = "default_font" | ||||||
| CONF_DIR = "dir" | CONF_DIR = "dir" | ||||||
| CONF_DISPLAYS = "displays" | CONF_DISPLAYS = "displays" | ||||||
|  | CONF_ENCODERS = "encoders" | ||||||
| CONF_END_ANGLE = "end_angle" | CONF_END_ANGLE = "end_angle" | ||||||
| CONF_END_VALUE = "end_value" | CONF_END_VALUE = "end_value" | ||||||
| CONF_ENTER_BUTTON = "enter_button" | CONF_ENTER_BUTTON = "enter_button" | ||||||
| @@ -441,7 +442,6 @@ CONF_RECOLOR = "recolor" | |||||||
| CONF_RIGHT_BUTTON = "right_button" | CONF_RIGHT_BUTTON = "right_button" | ||||||
| CONF_ROLLOVER = "rollover" | CONF_ROLLOVER = "rollover" | ||||||
| CONF_ROOT_BACK_BTN = "root_back_btn" | CONF_ROOT_BACK_BTN = "root_back_btn" | ||||||
| CONF_ROTARY_ENCODERS = "rotary_encoders" |  | ||||||
| CONF_ROWS = "rows" | CONF_ROWS = "rows" | ||||||
| CONF_SCALE_LINES = "scale_lines" | CONF_SCALE_LINES = "scale_lines" | ||||||
| CONF_SCROLLBAR_MODE = "scrollbar_mode" | CONF_SCROLLBAR_MODE = "scrollbar_mode" | ||||||
|   | |||||||
| @@ -5,25 +5,26 @@ import esphome.config_validation as cv | |||||||
| from esphome.const import CONF_GROUP, CONF_ID, CONF_SENSOR | from esphome.const import CONF_GROUP, CONF_ID, CONF_SENSOR | ||||||
| 
 | 
 | ||||||
| from .defines import ( | from .defines import ( | ||||||
|  |     CONF_ENCODERS, | ||||||
|     CONF_ENTER_BUTTON, |     CONF_ENTER_BUTTON, | ||||||
|     CONF_LEFT_BUTTON, |     CONF_LEFT_BUTTON, | ||||||
|     CONF_LONG_PRESS_REPEAT_TIME, |     CONF_LONG_PRESS_REPEAT_TIME, | ||||||
|     CONF_LONG_PRESS_TIME, |     CONF_LONG_PRESS_TIME, | ||||||
|     CONF_RIGHT_BUTTON, |     CONF_RIGHT_BUTTON, | ||||||
|     CONF_ROTARY_ENCODERS, |  | ||||||
| ) | ) | ||||||
| from .helpers import lvgl_components_required | from .helpers import lvgl_components_required, requires_component | ||||||
| from .lvcode import lv, lv_add, lv_expr | from .lvcode import lv, lv_add, lv_assign, lv_expr, lv_Pvariable | ||||||
| from .schemas import ENCODER_SCHEMA | from .schemas import ENCODER_SCHEMA | ||||||
| from .types import lv_indev_type_t | from .types import lv_group_t, lv_indev_type_t | ||||||
| from .widgets import add_group |  | ||||||
| 
 | 
 | ||||||
| ROTARY_ENCODER_CONFIG = cv.ensure_list( | ENCODERS_CONFIG = cv.ensure_list( | ||||||
|     ENCODER_SCHEMA.extend( |     ENCODER_SCHEMA.extend( | ||||||
|         { |         { | ||||||
|             cv.Required(CONF_ENTER_BUTTON): cv.use_id(BinarySensor), |             cv.Required(CONF_ENTER_BUTTON): cv.use_id(BinarySensor), | ||||||
|             cv.Required(CONF_SENSOR): cv.Any( |             cv.Required(CONF_SENSOR): cv.Any( | ||||||
|                 cv.use_id(RotaryEncoderSensor), |                 cv.All( | ||||||
|  |                     cv.use_id(RotaryEncoderSensor), requires_component("rotary_encoder") | ||||||
|  |                 ), | ||||||
|                 cv.Schema( |                 cv.Schema( | ||||||
|                     { |                     { | ||||||
|                         cv.Required(CONF_LEFT_BUTTON): cv.use_id(BinarySensor), |                         cv.Required(CONF_LEFT_BUTTON): cv.use_id(BinarySensor), | ||||||
| @@ -36,10 +37,9 @@ ROTARY_ENCODER_CONFIG = cv.ensure_list( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| async def rotary_encoders_to_code(var, config): | async def encoders_to_code(var, config): | ||||||
|     for enc_conf in config.get(CONF_ROTARY_ENCODERS, ()): |     for enc_conf in config.get(CONF_ENCODERS, ()): | ||||||
|         lvgl_components_required.add("KEY_LISTENER") |         lvgl_components_required.add("KEY_LISTENER") | ||||||
|         lvgl_components_required.add("ROTARY_ENCODER") |  | ||||||
|         lpt = enc_conf[CONF_LONG_PRESS_TIME].total_milliseconds |         lpt = enc_conf[CONF_LONG_PRESS_TIME].total_milliseconds | ||||||
|         lprt = enc_conf[CONF_LONG_PRESS_REPEAT_TIME].total_milliseconds |         lprt = enc_conf[CONF_LONG_PRESS_REPEAT_TIME].total_milliseconds | ||||||
|         listener = cg.new_Pvariable( |         listener = cg.new_Pvariable( | ||||||
| @@ -57,7 +57,9 @@ async def rotary_encoders_to_code(var, config): | |||||||
|                 lv_add(listener.set_sensor(sensor_config)) |                 lv_add(listener.set_sensor(sensor_config)) | ||||||
|         b_sensor = await cg.get_variable(enc_conf[CONF_ENTER_BUTTON]) |         b_sensor = await cg.get_variable(enc_conf[CONF_ENTER_BUTTON]) | ||||||
|         cg.add(listener.set_enter_button(b_sensor)) |         cg.add(listener.set_enter_button(b_sensor)) | ||||||
|         if group := add_group(enc_conf.get(CONF_GROUP)): |         if group := enc_conf.get(CONF_GROUP): | ||||||
|  |             group = lv_Pvariable(lv_group_t, group) | ||||||
|  |             lv_assign(group, lv_expr.group_create()) | ||||||
|             lv.indev_set_group(lv_expr.indev_drv_register(listener.get_drv()), group) |             lv.indev_set_group(lv_expr.indev_drv_register(listener.get_drv()), group) | ||||||
|         else: |         else: | ||||||
|             lv.indev_drv_register(listener.get_drv()) |             lv.indev_drv_register(listener.get_drv()) | ||||||
| @@ -127,7 +127,7 @@ void LVTouchListener::update(const touchscreen::TouchPoints_t &tpoints) { | |||||||
| } | } | ||||||
| #endif  // USE_LVGL_TOUCHSCREEN | #endif  // USE_LVGL_TOUCHSCREEN | ||||||
|  |  | ||||||
| #ifdef USE_LVGL_ROTARY_ENCODER | #ifdef USE_LVGL_KEY_LISTENER | ||||||
| LVEncoderListener::LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt) { | LVEncoderListener::LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt) { | ||||||
|   lv_indev_drv_init(&this->drv_); |   lv_indev_drv_init(&this->drv_); | ||||||
|   this->drv_.type = type; |   this->drv_.type = type; | ||||||
| @@ -143,7 +143,7 @@ LVEncoderListener::LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_ | |||||||
|     data->continue_reading = false; |     data->continue_reading = false; | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
| #endif  // USE_LVGL_ROTARY_ENCODER | #endif  // USE_LVGL_KEY_LISTENER | ||||||
|  |  | ||||||
| #ifdef USE_LVGL_BUTTONMATRIX | #ifdef USE_LVGL_BUTTONMATRIX | ||||||
| void LvButtonMatrixType::set_obj(lv_obj_t *lv_obj) { | void LvButtonMatrixType::set_obj(lv_obj_t *lv_obj) { | ||||||
|   | |||||||
| @@ -1,6 +1,13 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "esphome/core/defines.h" | #include "esphome/core/defines.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_LVGL_BINARY_SENSOR | ||||||
|  | #include "esphome/components/binary_sensor/binary_sensor.h" | ||||||
|  | #endif  // USE_LVGL_BINARY_SENSOR | ||||||
|  | #ifdef USE_LVGL_ROTARY_ENCODER | ||||||
|  | #include "esphome/components/rotary_encoder/rotary_encoder.h" | ||||||
|  | #endif  // USE_LVGL_ROTARY_ENCODER | ||||||
|  |  | ||||||
| // required for clang-tidy | // required for clang-tidy | ||||||
| #ifndef LV_CONF_H | #ifndef LV_CONF_H | ||||||
| #define LV_CONF_SKIP 1  // NOLINT | #define LV_CONF_SKIP 1  // NOLINT | ||||||
| @@ -12,12 +19,7 @@ | |||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| #include <lvgl.h> | #include <lvgl.h> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #include <map> | ||||||
| #ifdef USE_LVGL_ROTARY_ENCODER |  | ||||||
| #include "esphome/components/binary_sensor/binary_sensor.h" |  | ||||||
| #include "esphome/components/rotary_encoder/rotary_encoder.h" |  | ||||||
| #endif  // USE_LVGL_ROTARY_ENCODER |  | ||||||
|  |  | ||||||
| #ifdef USE_LVGL_IMAGE | #ifdef USE_LVGL_IMAGE | ||||||
| #include "esphome/components/image/image.h" | #include "esphome/components/image/image.h" | ||||||
| #endif  // USE_LVGL_IMAGE | #endif  // USE_LVGL_IMAGE | ||||||
| @@ -202,7 +204,7 @@ class LVTouchListener : public touchscreen::TouchListener, public Parented<LvglC | |||||||
| }; | }; | ||||||
| #endif  // USE_LVGL_TOUCHSCREEN | #endif  // USE_LVGL_TOUCHSCREEN | ||||||
|  |  | ||||||
| #ifdef USE_LVGL_ROTARY_ENCODER | #ifdef USE_LVGL_KEY_LISTENER | ||||||
| class LVEncoderListener : public Parented<LvglComponent> { | class LVEncoderListener : public Parented<LvglComponent> { | ||||||
|  public: |  public: | ||||||
|   LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt); |   LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt); | ||||||
| @@ -218,9 +220,11 @@ class LVEncoderListener : public Parented<LvglComponent> { | |||||||
|     enter_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_ENTER, state); }); |     enter_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_ENTER, state); }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | #ifdef USE_LVGL_ROTARY_ENCODER | ||||||
|   void set_sensor(rotary_encoder::RotaryEncoderSensor *sensor) { |   void set_sensor(rotary_encoder::RotaryEncoderSensor *sensor) { | ||||||
|     sensor->register_listener([this](int32_t count) { this->set_count(count); }); |     sensor->register_listener([this](int32_t count) { this->set_count(count); }); | ||||||
|   } |   } | ||||||
|  | #endif  // USE_LVGL_ROTARY_ENCODER | ||||||
|  |  | ||||||
|   void event(int key, bool pressed) { |   void event(int key, bool pressed) { | ||||||
|     if (!this->parent_->is_paused()) { |     if (!this->parent_->is_paused()) { | ||||||
| @@ -243,7 +247,8 @@ class LVEncoderListener : public Parented<LvglComponent> { | |||||||
|   int32_t last_count_{}; |   int32_t last_count_{}; | ||||||
|   int key_{}; |   int key_{}; | ||||||
| }; | }; | ||||||
| #endif  // USE_LVGL_ROTARY_ENCODER | #endif  //  USE_LVGL_KEY_LISTENER | ||||||
|  |  | ||||||
| #ifdef USE_LVGL_BUTTONMATRIX | #ifdef USE_LVGL_BUTTONMATRIX | ||||||
| class LvButtonMatrixType : public key_provider::KeyProvider, public LvCompound { | class LvButtonMatrixType : public key_provider::KeyProvider, public LvCompound { | ||||||
|  public: |  public: | ||||||
|   | |||||||
| @@ -16,9 +16,9 @@ from esphome.schema_extractors import SCHEMA_EXTRACT | |||||||
|  |  | ||||||
| from . import defines as df, lv_validation as lvalid, types as ty | from . import defines as df, lv_validation as lvalid, types as ty | ||||||
| from .helpers import add_lv_use, requires_component, validate_printf | from .helpers import add_lv_use, requires_component, validate_printf | ||||||
| from .lv_validation import id_name, lv_color, lv_font, lv_image | from .lv_validation import lv_color, lv_font, lv_image | ||||||
| from .lvcode import LvglComponent | from .lvcode import LvglComponent | ||||||
| from .types import WidgetType | from .types import WidgetType, lv_group_t | ||||||
|  |  | ||||||
| # this will be populated later, in __init__.py to avoid circular imports. | # this will be populated later, in __init__.py to avoid circular imports. | ||||||
| WIDGET_TYPES: dict = {} | WIDGET_TYPES: dict = {} | ||||||
| @@ -61,7 +61,7 @@ ENCODER_SCHEMA = cv.Schema( | |||||||
|         cv.GenerateID(): cv.All( |         cv.GenerateID(): cv.All( | ||||||
|             cv.declare_id(ty.LVEncoderListener), requires_component("binary_sensor") |             cv.declare_id(ty.LVEncoderListener), requires_component("binary_sensor") | ||||||
|         ), |         ), | ||||||
|         cv.Optional(CONF_GROUP): lvalid.id_name, |         cv.Optional(CONF_GROUP): cv.declare_id(lv_group_t), | ||||||
|         cv.Optional(df.CONF_LONG_PRESS_TIME, default="400ms"): PRESS_TIME, |         cv.Optional(df.CONF_LONG_PRESS_TIME, default="400ms"): PRESS_TIME, | ||||||
|         cv.Optional(df.CONF_LONG_PRESS_REPEAT_TIME, default="100ms"): PRESS_TIME, |         cv.Optional(df.CONF_LONG_PRESS_REPEAT_TIME, default="100ms"): PRESS_TIME, | ||||||
|     } |     } | ||||||
| @@ -249,7 +249,7 @@ def obj_schema(widget_type: WidgetType): | |||||||
|             cv.Schema( |             cv.Schema( | ||||||
|                 { |                 { | ||||||
|                     cv.Optional(CONF_STATE): SET_STATE_SCHEMA, |                     cv.Optional(CONF_STATE): SET_STATE_SCHEMA, | ||||||
|                     cv.Optional(CONF_GROUP): id_name, |                     cv.Optional(CONF_GROUP): cv.use_id(lv_group_t), | ||||||
|                 } |                 } | ||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ from esphome.config_validation import Invalid | |||||||
| from esphome.const import CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE | from esphome.const import CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE | ||||||
| from esphome.core import ID, TimePeriod | from esphome.core import ID, TimePeriod | ||||||
| from esphome.coroutine import FakeAwaitable | from esphome.coroutine import FakeAwaitable | ||||||
| from esphome.cpp_generator import AssignmentExpression, CallExpression, MockObj | from esphome.cpp_generator import CallExpression, MockObj | ||||||
|  |  | ||||||
| from ..defines import ( | from ..defines import ( | ||||||
|     CONF_DEFAULT, |     CONF_DEFAULT, | ||||||
| @@ -44,15 +44,7 @@ from ..lvcode import ( | |||||||
|     lv_Pvariable, |     lv_Pvariable, | ||||||
| ) | ) | ||||||
| from ..schemas import ALL_STYLES, STYLE_REMAP, WIDGET_TYPES | from ..schemas import ALL_STYLES, STYLE_REMAP, WIDGET_TYPES | ||||||
| from ..types import ( | from ..types import LV_STATE, LvType, WidgetType, lv_coord_t, lv_obj_t, lv_obj_t_ptr | ||||||
|     LV_STATE, |  | ||||||
|     LvType, |  | ||||||
|     WidgetType, |  | ||||||
|     lv_coord_t, |  | ||||||
|     lv_group_t, |  | ||||||
|     lv_obj_t, |  | ||||||
|     lv_obj_t_ptr, |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| EVENT_LAMB = "event_lamb__" | EVENT_LAMB = "event_lamb__" | ||||||
|  |  | ||||||
| @@ -317,7 +309,8 @@ async def set_obj_properties(w: Widget, config): | |||||||
|                     value = await ALL_STYLES[prop].process(value) |                     value = await ALL_STYLES[prop].process(value) | ||||||
|                 prop_r = STYLE_REMAP.get(prop, prop) |                 prop_r = STYLE_REMAP.get(prop, prop) | ||||||
|                 w.set_style(prop_r, value, lv_state) |                 w.set_style(prop_r, value, lv_state) | ||||||
|     if group := add_group(config.get(CONF_GROUP)): |     if group := config.get(CONF_GROUP): | ||||||
|  |         group = await cg.get_variable(group) | ||||||
|         lv.group_add_obj(group, w.obj) |         lv.group_add_obj(group, w.obj) | ||||||
|     flag_clr = set() |     flag_clr = set() | ||||||
|     flag_set = set() |     flag_set = set() | ||||||
| @@ -404,20 +397,3 @@ async def widget_to_code(w_cnfig, w_type: WidgetType, parent): | |||||||
|  |  | ||||||
| lv_scr_act_spec = LvScrActType() | lv_scr_act_spec = LvScrActType() | ||||||
| lv_scr_act = Widget.create(None, literal("lv_scr_act()"), lv_scr_act_spec, {}) | lv_scr_act = Widget.create(None, literal("lv_scr_act()"), lv_scr_act_spec, {}) | ||||||
|  |  | ||||||
| lv_groups = {}  # Widget group names |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def add_group(name): |  | ||||||
|     if name is None: |  | ||||||
|         return None |  | ||||||
|     fullname = f"lv_esp_group_{name}" |  | ||||||
|     if name not in lv_groups: |  | ||||||
|         gid = ID(fullname, True, type=lv_group_t.operator("ptr")) |  | ||||||
|         lv_add( |  | ||||||
|             AssignmentExpression( |  | ||||||
|                 type_=gid.type, modifier="", name=fullname, rhs=lv_expr.group_create() |  | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
|         lv_groups[name] = literal(fullname) |  | ||||||
|     return lv_groups[name] |  | ||||||
|   | |||||||
| @@ -24,6 +24,33 @@ display: | |||||||
|     invert_colors: false |     invert_colors: false | ||||||
|     update_interval: never |     update_interval: never | ||||||
|  |  | ||||||
|  | binary_sensor: | ||||||
|  |   - platform: gpio | ||||||
|  |     internal: true | ||||||
|  |     id: up_button | ||||||
|  |     pin: | ||||||
|  |       number: GPIO38 | ||||||
|  |       inverted: true | ||||||
|  |   - platform: gpio | ||||||
|  |     internal: true | ||||||
|  |     id: down_button | ||||||
|  |     pin: | ||||||
|  |       number: GPIO37 | ||||||
|  |       inverted: true | ||||||
|  |   - platform: gpio | ||||||
|  |     internal: true | ||||||
|  |     id: select_button | ||||||
|  |     pin: | ||||||
|  |       number: GPIO39 | ||||||
|  |       inverted: true | ||||||
|  | lvgl: | ||||||
|  |   encoders: | ||||||
|  |     group: switches | ||||||
|  |     enter_button: select_button | ||||||
|  |     sensor: | ||||||
|  |       left_button: up_button | ||||||
|  |       right_button: down_button | ||||||
|  |  | ||||||
| packages: | packages: | ||||||
|   lvgl: !include lvgl-package.yaml |   lvgl: !include lvgl-package.yaml | ||||||
|  |  | ||||||
|   | |||||||
| @@ -67,7 +67,7 @@ lvgl: | |||||||
|   displays: |   displays: | ||||||
|     - tft_display |     - tft_display | ||||||
|     - second_display |     - second_display | ||||||
|   rotary_encoders: |   encoders: | ||||||
|     sensor: encoder |     sensor: encoder | ||||||
|     enter_button: pushbutton |     enter_button: pushbutton | ||||||
|     group: general |     group: general | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user