mirror of
https://github.com/esphome/esphome.git
synced 2025-07-27 13:46:48 +00:00
[lvgl] Add restore_value to select and number (#8494)
This commit is contained in:
parent
df4642208e
commit
fb5d697c22
@ -173,7 +173,8 @@ class LambdaContext(CodeContext):
|
|||||||
|
|
||||||
class LvContext(LambdaContext):
|
class LvContext(LambdaContext):
|
||||||
"""
|
"""
|
||||||
Code generation into the LVGL initialisation code (called in `setup()`)
|
Code generation into the LVGL initialisation code, called before setup() and loop()
|
||||||
|
Basically just does cg.add, so now fairly redundant.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
added_lambda_count = 0
|
added_lambda_count = 0
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import number
|
from esphome.components import number
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import CONF_RESTORE_VALUE
|
||||||
from esphome.cpp_generator import MockObj
|
from esphome.cpp_generator import MockObj
|
||||||
|
|
||||||
from ..defines import CONF_ANIMATED, CONF_UPDATE_ON_RELEASE, CONF_WIDGET
|
from ..defines import CONF_ANIMATED, CONF_UPDATE_ON_RELEASE, CONF_WIDGET
|
||||||
@ -10,21 +11,21 @@ from ..lvcode import (
|
|||||||
EVENT_ARG,
|
EVENT_ARG,
|
||||||
UPDATE_EVENT,
|
UPDATE_EVENT,
|
||||||
LambdaContext,
|
LambdaContext,
|
||||||
LvContext,
|
ReturnStatement,
|
||||||
lv,
|
lv,
|
||||||
lv_add,
|
|
||||||
lvgl_static,
|
lvgl_static,
|
||||||
)
|
)
|
||||||
from ..types import LV_EVENT, LvNumber, lvgl_ns
|
from ..types import LV_EVENT, LvNumber, lvgl_ns
|
||||||
from ..widgets import get_widgets, wait_for_widgets
|
from ..widgets import get_widgets, wait_for_widgets
|
||||||
|
|
||||||
LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number)
|
LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number, cg.Component)
|
||||||
|
|
||||||
CONFIG_SCHEMA = number.number_schema(LVGLNumber).extend(
|
CONFIG_SCHEMA = number.number_schema(LVGLNumber).extend(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_WIDGET): cv.use_id(LvNumber),
|
cv.Required(CONF_WIDGET): cv.use_id(LvNumber),
|
||||||
cv.Optional(CONF_ANIMATED, default=True): animated,
|
cv.Optional(CONF_ANIMATED, default=True): animated,
|
||||||
cv.Optional(CONF_UPDATE_ON_RELEASE, default=False): cv.boolean,
|
cv.Optional(CONF_UPDATE_ON_RELEASE, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,32 +33,34 @@ CONFIG_SCHEMA = number.number_schema(LVGLNumber).extend(
|
|||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
widget = await get_widgets(config, CONF_WIDGET)
|
widget = await get_widgets(config, CONF_WIDGET)
|
||||||
widget = widget[0]
|
widget = widget[0]
|
||||||
var = await number.new_number(
|
|
||||||
config,
|
|
||||||
max_value=widget.get_max(),
|
|
||||||
min_value=widget.get_min(),
|
|
||||||
step=widget.get_step(),
|
|
||||||
)
|
|
||||||
|
|
||||||
await wait_for_widgets()
|
await wait_for_widgets()
|
||||||
|
async with LambdaContext([], return_type=cg.float_) as value:
|
||||||
|
value.add(ReturnStatement(widget.get_value()))
|
||||||
async with LambdaContext([(cg.float_, "v")]) as control:
|
async with LambdaContext([(cg.float_, "v")]) as control:
|
||||||
await widget.set_property(
|
await widget.set_property(
|
||||||
"value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED]
|
"value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED]
|
||||||
)
|
)
|
||||||
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
||||||
control.add(var.publish_state(widget.get_value()))
|
|
||||||
async with LambdaContext(EVENT_ARG) as event:
|
|
||||||
event.add(var.publish_state(widget.get_value()))
|
|
||||||
event_code = (
|
event_code = (
|
||||||
LV_EVENT.VALUE_CHANGED
|
LV_EVENT.VALUE_CHANGED
|
||||||
if not config[CONF_UPDATE_ON_RELEASE]
|
if not config[CONF_UPDATE_ON_RELEASE]
|
||||||
else LV_EVENT.RELEASED
|
else LV_EVENT.RELEASED
|
||||||
)
|
)
|
||||||
async with LvContext():
|
var = await number.new_number(
|
||||||
lv_add(var.set_control_lambda(await control.get_lambda()))
|
config,
|
||||||
lv_add(
|
await control.get_lambda(),
|
||||||
|
await value.get_lambda(),
|
||||||
|
event_code,
|
||||||
|
config[CONF_RESTORE_VALUE],
|
||||||
|
max_value=widget.get_max(),
|
||||||
|
min_value=widget.get_min(),
|
||||||
|
step=widget.get_step(),
|
||||||
|
)
|
||||||
|
async with LambdaContext(EVENT_ARG) as event:
|
||||||
|
event.add(var.on_value())
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
cg.add(
|
||||||
lvgl_static.add_event_cb(
|
lvgl_static.add_event_cb(
|
||||||
widget.obj, await event.get_lambda(), UPDATE_EVENT, event_code
|
widget.obj, await event.get_lambda(), UPDATE_EVENT, event_code
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
lv_add(var.publish_state(widget.get_value()))
|
|
||||||
|
@ -3,33 +3,46 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "esphome/components/number/number.h"
|
#include "esphome/components/number/number.h"
|
||||||
#include "esphome/core/automation.h"
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/preferences.h"
|
#include "esphome/core/preferences.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace lvgl {
|
namespace lvgl {
|
||||||
|
|
||||||
class LVGLNumber : public number::Number {
|
class LVGLNumber : public number::Number, public Component {
|
||||||
public:
|
public:
|
||||||
void set_control_lambda(std::function<void(float)> control_lambda) {
|
LVGLNumber(std::function<void(float)> control_lambda, std::function<float()> value_lambda, lv_event_code_t event,
|
||||||
this->control_lambda_ = std::move(control_lambda);
|
bool restore)
|
||||||
if (this->initial_state_.has_value()) {
|
: control_lambda_(std::move(control_lambda)),
|
||||||
this->control_lambda_(this->initial_state_.value());
|
value_lambda_(std::move(value_lambda)),
|
||||||
this->initial_state_.reset();
|
event_(event),
|
||||||
|
restore_(restore) {}
|
||||||
|
|
||||||
|
void setup() override {
|
||||||
|
float value = this->value_lambda_();
|
||||||
|
if (this->restore_) {
|
||||||
|
this->pref_ = global_preferences->make_preference<float>(this->get_object_id_hash());
|
||||||
|
if (this->pref_.load(&value)) {
|
||||||
|
this->control_lambda_(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this->publish_state(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_value() { this->publish_state(this->value_lambda_()); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void control(float value) override {
|
void control(float value) override {
|
||||||
if (this->control_lambda_ != nullptr) {
|
|
||||||
this->control_lambda_(value);
|
this->control_lambda_(value);
|
||||||
} else {
|
this->publish_state(value);
|
||||||
this->initial_state_ = value;
|
if (this->restore_)
|
||||||
|
this->pref_.save(&value);
|
||||||
}
|
}
|
||||||
}
|
std::function<void(float)> control_lambda_;
|
||||||
std::function<void(float)> control_lambda_{};
|
std::function<float()> value_lambda_;
|
||||||
optional<float> initial_state_{};
|
lv_event_code_t event_;
|
||||||
|
bool restore_;
|
||||||
|
ESPPreferenceObject pref_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lvgl
|
} // namespace lvgl
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
from esphome.components import select
|
from esphome.components import select
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_OPTIONS
|
from esphome.const import CONF_ID, CONF_OPTIONS, CONF_RESTORE_VALUE
|
||||||
|
|
||||||
from ..defines import CONF_ANIMATED, CONF_WIDGET, literal
|
from ..defines import CONF_ANIMATED, CONF_WIDGET, literal
|
||||||
from ..lvcode import LvContext
|
|
||||||
from ..types import LvSelect, lvgl_ns
|
from ..types import LvSelect, lvgl_ns
|
||||||
from ..widgets import get_widgets, wait_for_widgets
|
from ..widgets import get_widgets
|
||||||
|
|
||||||
LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select)
|
LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select, cg.Component)
|
||||||
|
|
||||||
CONFIG_SCHEMA = select.select_schema(LVGLSelect).extend(
|
CONFIG_SCHEMA = select.select_schema(LVGLSelect).extend(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_WIDGET): cv.use_id(LvSelect),
|
cv.Required(CONF_WIDGET): cv.use_id(LvSelect),
|
||||||
cv.Optional(CONF_ANIMATED, default=False): cv.boolean,
|
cv.Optional(CONF_ANIMATED, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,12 +22,9 @@ async def to_code(config):
|
|||||||
widget = await get_widgets(config, CONF_WIDGET)
|
widget = await get_widgets(config, CONF_WIDGET)
|
||||||
widget = widget[0]
|
widget = widget[0]
|
||||||
options = widget.config.get(CONF_OPTIONS, [])
|
options = widget.config.get(CONF_OPTIONS, [])
|
||||||
selector = await select.new_select(config, options=options)
|
animated = literal("LV_ANIM_ON" if config[CONF_ANIMATED] else "LV_ANIM_OFF")
|
||||||
await wait_for_widgets()
|
selector = cg.new_Pvariable(
|
||||||
async with LvContext() as ctx:
|
config[CONF_ID], widget.var, animated, config[CONF_RESTORE_VALUE]
|
||||||
ctx.add(
|
|
||||||
selector.set_widget(
|
|
||||||
widget.var,
|
|
||||||
literal("LV_ANIM_ON" if config[CONF_ANIMATED] else "LV_ANIM_OFF"),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
await select.register_select(selector, config, options=options)
|
||||||
|
await cg.register_component(selector, config)
|
||||||
|
@ -11,12 +11,20 @@
|
|||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace lvgl {
|
namespace lvgl {
|
||||||
|
|
||||||
class LVGLSelect : public select::Select {
|
class LVGLSelect : public select::Select, public Component {
|
||||||
public:
|
public:
|
||||||
void set_widget(LvSelectable *widget, lv_anim_enable_t anim = LV_ANIM_OFF) {
|
LVGLSelect(LvSelectable *widget, lv_anim_enable_t anim, bool restore)
|
||||||
this->widget_ = widget;
|
: widget_(widget), anim_(anim), restore_(restore) {}
|
||||||
this->anim_ = anim;
|
|
||||||
|
void setup() override {
|
||||||
this->set_options_();
|
this->set_options_();
|
||||||
|
if (this->restore_) {
|
||||||
|
size_t index;
|
||||||
|
this->pref_ = global_preferences->make_preference<size_t>(this->get_object_id_hash());
|
||||||
|
if (this->pref_.load(&index))
|
||||||
|
this->widget_->set_selected_index(index, LV_ANIM_OFF);
|
||||||
|
}
|
||||||
|
this->publish();
|
||||||
lv_obj_add_event_cb(
|
lv_obj_add_event_cb(
|
||||||
this->widget_->obj,
|
this->widget_->obj,
|
||||||
[](lv_event_t *e) {
|
[](lv_event_t *e) {
|
||||||
@ -24,11 +32,6 @@ class LVGLSelect : public select::Select {
|
|||||||
it->set_options_();
|
it->set_options_();
|
||||||
},
|
},
|
||||||
LV_EVENT_REFRESH, this);
|
LV_EVENT_REFRESH, this);
|
||||||
if (this->initial_state_.has_value()) {
|
|
||||||
this->control(this->initial_state_.value());
|
|
||||||
this->initial_state_.reset();
|
|
||||||
}
|
|
||||||
this->publish();
|
|
||||||
auto lamb = [](lv_event_t *e) {
|
auto lamb = [](lv_event_t *e) {
|
||||||
auto *self = static_cast<LVGLSelect *>(e->user_data);
|
auto *self = static_cast<LVGLSelect *>(e->user_data);
|
||||||
self->publish();
|
self->publish();
|
||||||
@ -37,21 +40,25 @@ class LVGLSelect : public select::Select {
|
|||||||
lv_obj_add_event_cb(this->widget_->obj, lamb, lv_update_event, this);
|
lv_obj_add_event_cb(this->widget_->obj, lamb, lv_update_event, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void publish() { this->publish_state(this->widget_->get_selected_text()); }
|
void publish() {
|
||||||
|
this->publish_state(this->widget_->get_selected_text());
|
||||||
|
if (this->restore_) {
|
||||||
|
auto index = this->widget_->get_selected_index();
|
||||||
|
this->pref_.save(&index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void control(const std::string &value) override {
|
void control(const std::string &value) override {
|
||||||
if (this->widget_ != nullptr) {
|
|
||||||
this->widget_->set_selected_text(value, this->anim_);
|
this->widget_->set_selected_text(value, this->anim_);
|
||||||
} else {
|
this->publish();
|
||||||
this->initial_state_ = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void set_options_() { this->traits.set_options(this->widget_->get_options()); }
|
void set_options_() { this->traits.set_options(this->widget_->get_options()); }
|
||||||
|
|
||||||
LvSelectable *widget_{};
|
LvSelectable *widget_;
|
||||||
optional<std::string> initial_state_{};
|
lv_anim_enable_t anim_;
|
||||||
lv_anim_enable_t anim_{LV_ANIM_OFF};
|
bool restore_;
|
||||||
|
ESPPreferenceObject pref_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lvgl
|
} // namespace lvgl
|
||||||
|
@ -38,6 +38,7 @@ number:
|
|||||||
widget: slider_id
|
widget: slider_id
|
||||||
name: LVGL Slider
|
name: LVGL Slider
|
||||||
update_on_release: true
|
update_on_release: true
|
||||||
|
restore_value: true
|
||||||
- platform: lvgl
|
- platform: lvgl
|
||||||
widget: lv_arc
|
widget: lv_arc
|
||||||
id: lvgl_arc_number
|
id: lvgl_arc_number
|
||||||
|
@ -990,3 +990,13 @@ color:
|
|||||||
green_int: 123
|
green_int: 123
|
||||||
blue_int: 64
|
blue_int: 64
|
||||||
white_int: 255
|
white_int: 255
|
||||||
|
|
||||||
|
select:
|
||||||
|
- platform: lvgl
|
||||||
|
id: lv_roller_select
|
||||||
|
widget: lv_roller
|
||||||
|
restore_value: true
|
||||||
|
- platform: lvgl
|
||||||
|
id: lv_dropdown_select
|
||||||
|
widget: lv_dropdown
|
||||||
|
restore_value: false
|
||||||
|
Loading…
x
Reference in New Issue
Block a user