mirror of
https://github.com/esphome/esphome.git
synced 2025-10-05 11:23:47 +01:00
Merge branch 'dev' into multi_device
This commit is contained in:
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -220,7 +220,7 @@ jobs:
|
|||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
pytest -vv --cov-report=xml --tb=native tests
|
pytest -vv --cov-report=xml --tb=native tests
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@v5
|
uses: codecov/codecov-action@v5.4.0
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
|
@@ -311,6 +311,10 @@ APIError APINoiseFrameHelper::state_action_() {
|
|||||||
const std::string &name = App.get_name();
|
const std::string &name = App.get_name();
|
||||||
const uint8_t *name_ptr = reinterpret_cast<const uint8_t *>(name.c_str());
|
const uint8_t *name_ptr = reinterpret_cast<const uint8_t *>(name.c_str());
|
||||||
msg.insert(msg.end(), name_ptr, name_ptr + name.size() + 1);
|
msg.insert(msg.end(), name_ptr, name_ptr + name.size() + 1);
|
||||||
|
// node mac, terminated by null byte
|
||||||
|
const std::string &mac = get_mac_address();
|
||||||
|
const uint8_t *mac_ptr = reinterpret_cast<const uint8_t *>(mac.c_str());
|
||||||
|
msg.insert(msg.end(), mac_ptr, mac_ptr + mac.size() + 1);
|
||||||
|
|
||||||
aerr = write_frame_(msg.data(), msg.size());
|
aerr = write_frame_(msg.data(), msg.size());
|
||||||
if (aerr != APIError::OK)
|
if (aerr != APIError::OK)
|
||||||
|
@@ -30,8 +30,12 @@ void AXS15231Touchscreen::setup() {
|
|||||||
this->interrupt_pin_->setup();
|
this->interrupt_pin_->setup();
|
||||||
this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE);
|
this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE);
|
||||||
}
|
}
|
||||||
this->x_raw_max_ = this->display_->get_native_width();
|
if (this->x_raw_max_ == 0) {
|
||||||
this->y_raw_max_ = this->display_->get_native_height();
|
this->x_raw_max_ = this->display_->get_native_width();
|
||||||
|
}
|
||||||
|
if (this->y_raw_max_ == 0) {
|
||||||
|
this->y_raw_max_ = this->display_->get_native_height();
|
||||||
|
}
|
||||||
ESP_LOGCONFIG(TAG, "AXS15231 Touchscreen setup complete");
|
ESP_LOGCONFIG(TAG, "AXS15231 Touchscreen setup complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +48,7 @@ void AXS15231Touchscreen::update_touches() {
|
|||||||
err = this->read(data, sizeof(data));
|
err = this->read(data, sizeof(data));
|
||||||
ERROR_CHECK(err);
|
ERROR_CHECK(err);
|
||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
if (data[0] != 0) // no touches
|
if (data[0] != 0 || data[1] == 0) // no touches
|
||||||
return;
|
return;
|
||||||
uint16_t x = encode_uint16(data[2] & 0xF, data[3]);
|
uint16_t x = encode_uint16(data[2] & 0xF, data[3]);
|
||||||
uint16_t y = encode_uint16(data[4] & 0xF, data[5]);
|
uint16_t y = encode_uint16(data[4] & 0xF, data[5]);
|
||||||
|
@@ -274,8 +274,10 @@ SUPPORTED_PLATFORMIO_ESP_IDF_5X = [
|
|||||||
# pioarduino versions that don't require a release number
|
# pioarduino versions that don't require a release number
|
||||||
# List based on https://github.com/pioarduino/esp-idf/releases
|
# List based on https://github.com/pioarduino/esp-idf/releases
|
||||||
SUPPORTED_PIOARDUINO_ESP_IDF_5X = [
|
SUPPORTED_PIOARDUINO_ESP_IDF_5X = [
|
||||||
|
cv.Version(5, 5, 0),
|
||||||
cv.Version(5, 4, 1),
|
cv.Version(5, 4, 1),
|
||||||
cv.Version(5, 4, 0),
|
cv.Version(5, 4, 0),
|
||||||
|
cv.Version(5, 3, 3),
|
||||||
cv.Version(5, 3, 2),
|
cv.Version(5, 3, 2),
|
||||||
cv.Version(5, 3, 1),
|
cv.Version(5, 3, 1),
|
||||||
cv.Version(5, 3, 0),
|
cv.Version(5, 3, 0),
|
||||||
|
@@ -4,6 +4,7 @@ from esphome import automation
|
|||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_ACTION, CONF_GROUP, CONF_ID, CONF_TIMEOUT
|
from esphome.const import CONF_ACTION, CONF_GROUP, CONF_ID, CONF_TIMEOUT
|
||||||
|
from esphome.core import Lambda
|
||||||
from esphome.cpp_generator import TemplateArguments, get_variable
|
from esphome.cpp_generator import TemplateArguments, get_variable
|
||||||
from esphome.cpp_types import nullptr
|
from esphome.cpp_types import nullptr
|
||||||
|
|
||||||
@@ -64,7 +65,14 @@ async def action_to_code(
|
|||||||
action_id,
|
action_id,
|
||||||
template_arg,
|
template_arg,
|
||||||
args,
|
args,
|
||||||
|
config=None,
|
||||||
):
|
):
|
||||||
|
# Ensure all required ids have been processed, so our LambdaContext doesn't get context-switched.
|
||||||
|
if config:
|
||||||
|
for lamb in config.values():
|
||||||
|
if isinstance(lamb, Lambda):
|
||||||
|
for id_ in lamb.requires_ids:
|
||||||
|
await get_variable(id_)
|
||||||
await wait_for_widgets()
|
await wait_for_widgets()
|
||||||
async with LambdaContext(parameters=args, where=action_id) as context:
|
async with LambdaContext(parameters=args, where=action_id) as context:
|
||||||
for widget in widgets:
|
for widget in widgets:
|
||||||
@@ -84,7 +92,9 @@ async def update_to_code(config, action_id, template_arg, args):
|
|||||||
lv.event_send(widget.obj, UPDATE_EVENT, nullptr)
|
lv.event_send(widget.obj, UPDATE_EVENT, nullptr)
|
||||||
|
|
||||||
widgets = await get_widgets(config[CONF_ID])
|
widgets = await get_widgets(config[CONF_ID])
|
||||||
return await action_to_code(widgets, do_update, action_id, template_arg, args)
|
return await action_to_code(
|
||||||
|
widgets, do_update, action_id, template_arg, args, config
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_condition(
|
@automation.register_condition(
|
||||||
@@ -348,4 +358,6 @@ async def obj_update_to_code(config, action_id, template_arg, args):
|
|||||||
await set_obj_properties(widget, config)
|
await set_obj_properties(widget, config)
|
||||||
|
|
||||||
widgets = await get_widgets(config[CONF_ID])
|
widgets = await get_widgets(config[CONF_ID])
|
||||||
return await action_to_code(widgets, do_update, action_id, template_arg, args)
|
return await action_to_code(
|
||||||
|
widgets, do_update, action_id, template_arg, args, config
|
||||||
|
)
|
||||||
|
@@ -18,6 +18,7 @@ from .helpers import lvgl_components_required, requires_component
|
|||||||
from .lvcode import lv, lv_add, lv_assign, lv_expr, lv_Pvariable
|
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_group_t, lv_indev_type_t, lv_key_t
|
from .types import lv_group_t, lv_indev_type_t, lv_key_t
|
||||||
|
from .widgets import get_widgets
|
||||||
|
|
||||||
ENCODERS_CONFIG = cv.ensure_list(
|
ENCODERS_CONFIG = cv.ensure_list(
|
||||||
ENCODER_SCHEMA.extend(
|
ENCODER_SCHEMA.extend(
|
||||||
@@ -76,5 +77,5 @@ async def encoders_to_code(var, config, default_group):
|
|||||||
async def initial_focus_to_code(config):
|
async def initial_focus_to_code(config):
|
||||||
for enc_conf in config[CONF_ENCODERS]:
|
for enc_conf in config[CONF_ENCODERS]:
|
||||||
if default_focus := enc_conf.get(CONF_INITIAL_FOCUS):
|
if default_focus := enc_conf.get(CONF_INITIAL_FOCUS):
|
||||||
obj = await cg.get_variable(default_focus)
|
widget = await get_widgets(default_focus)
|
||||||
lv.group_focus_obj(obj)
|
lv.group_focus_obj(widget[0].obj)
|
||||||
|
@@ -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(),
|
||||||
lvgl_static.add_event_cb(
|
await value.get_lambda(),
|
||||||
widget.obj, await event.get_lambda(), UPDATE_EVENT, event_code
|
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(
|
||||||
|
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);
|
this->publish_state(value);
|
||||||
} else {
|
if (this->restore_)
|
||||||
this->initial_state_ = value;
|
this->pref_.save(&value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
std::function<void(float)> control_lambda_{};
|
std::function<void(float)> control_lambda_;
|
||||||
optional<float> initial_state_{};
|
std::function<float()> value_lambda_;
|
||||||
|
lv_event_code_t event_;
|
||||||
|
bool restore_;
|
||||||
|
ESPPreferenceObject pref_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lvgl
|
} // namespace lvgl
|
||||||
|
@@ -81,7 +81,9 @@ ENCODER_SCHEMA = cv.Schema(
|
|||||||
cv.declare_id(LVEncoderListener), requires_component("binary_sensor")
|
cv.declare_id(LVEncoderListener), requires_component("binary_sensor")
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_GROUP): cv.declare_id(lv_group_t),
|
cv.Optional(CONF_GROUP): cv.declare_id(lv_group_t),
|
||||||
cv.Optional(df.CONF_INITIAL_FOCUS): cv.use_id(lv_obj_t),
|
cv.Optional(df.CONF_INITIAL_FOCUS): cv.All(
|
||||||
|
LIST_ACTION_SCHEMA, cv.Length(min=1, max=1)
|
||||||
|
),
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
@@ -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(
|
await select.register_select(selector, config, options=options)
|
||||||
widget.var,
|
await cg.register_component(selector, config)
|
||||||
literal("LV_ANIM_ON" if config[CONF_ANIMATED] else "LV_ANIM_OFF"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
@@ -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_);
|
this->publish();
|
||||||
} else {
|
|
||||||
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
|
||||||
|
@@ -250,7 +250,7 @@ async def button_update_to_code(config, action_id, template_arg, args):
|
|||||||
widgets = await get_widgets(config[CONF_ID])
|
widgets = await get_widgets(config[CONF_ID])
|
||||||
assert all(isinstance(w, MatrixButton) for w in widgets)
|
assert all(isinstance(w, MatrixButton) for w in widgets)
|
||||||
|
|
||||||
async def do_button_update(w: MatrixButton):
|
async def do_button_update(w):
|
||||||
if (width := config.get(CONF_WIDTH)) is not None:
|
if (width := config.get(CONF_WIDTH)) is not None:
|
||||||
lv.btnmatrix_set_btn_width(w.obj, w.index, width)
|
lv.btnmatrix_set_btn_width(w.obj, w.index, width)
|
||||||
if config.get(CONF_SELECTED):
|
if config.get(CONF_SELECTED):
|
||||||
@@ -275,5 +275,5 @@ async def button_update_to_code(config, action_id, template_arg, args):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return await action_to_code(
|
return await action_to_code(
|
||||||
widgets, do_button_update, action_id, template_arg, args
|
widgets, do_button_update, action_id, template_arg, args, config
|
||||||
)
|
)
|
||||||
|
@@ -97,7 +97,7 @@ async def canvas_fill(config, action_id, template_arg, args):
|
|||||||
async def do_fill(w: Widget):
|
async def do_fill(w: Widget):
|
||||||
lv.canvas_fill_bg(w.obj, color, opa)
|
lv.canvas_fill_bg(w.obj, color, opa)
|
||||||
|
|
||||||
return await action_to_code(widget, do_fill, action_id, template_arg, args)
|
return await action_to_code(widget, do_fill, action_id, template_arg, args, config)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
@@ -145,7 +145,9 @@ async def canvas_set_pixel(config, action_id, template_arg, args):
|
|||||||
x, y = point
|
x, y = point
|
||||||
lv.canvas_set_px_opa(w.obj, x, y, opa_var)
|
lv.canvas_set_px_opa(w.obj, x, y, opa_var)
|
||||||
|
|
||||||
return await action_to_code(widget, do_set_pixels, action_id, template_arg, args)
|
return await action_to_code(
|
||||||
|
widget, do_set_pixels, action_id, template_arg, args, config
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
DRAW_SCHEMA = cv.Schema(
|
DRAW_SCHEMA = cv.Schema(
|
||||||
@@ -181,7 +183,9 @@ async def draw_to_code(config, dsc_type, props, do_draw, action_id, template_arg
|
|||||||
lv_assign(getattr(dsc, mapped_prop), value)
|
lv_assign(getattr(dsc, mapped_prop), value)
|
||||||
await do_draw(w, x, y, dsc_addr)
|
await do_draw(w, x, y, dsc_addr)
|
||||||
|
|
||||||
return await action_to_code(widget, action_func, action_id, template_arg, args)
|
return await action_to_code(
|
||||||
|
widget, action_func, action_id, template_arg, args, config
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
RECT_PROPS = {
|
RECT_PROPS = {
|
||||||
|
@@ -297,7 +297,9 @@ async def indicator_update_to_code(config, action_id, template_arg, args):
|
|||||||
async def set_value(w: Widget):
|
async def set_value(w: Widget):
|
||||||
await set_indicator_values(w.var, w.obj, config)
|
await set_indicator_values(w.var, w.obj, config)
|
||||||
|
|
||||||
return await action_to_code(widget, set_value, action_id, template_arg, args)
|
return await action_to_code(
|
||||||
|
widget, set_value, action_id, template_arg, args, config
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def set_indicator_values(meter, indicator, config):
|
async def set_indicator_values(meter, indicator, config):
|
||||||
|
@@ -26,7 +26,7 @@ CONFIG_SCHEMA = cv.Schema(
|
|||||||
esp32_arduino=cv.Version(0, 0, 0),
|
esp32_arduino=cv.Version(0, 0, 0),
|
||||||
esp8266_arduino=cv.Version(0, 0, 0),
|
esp8266_arduino=cv.Version(0, 0, 0),
|
||||||
rp2040_arduino=cv.Version(0, 0, 0),
|
rp2040_arduino=cv.Version(0, 0, 0),
|
||||||
bk72xx_libretiny=cv.Version(1, 7, 0),
|
bk72xx_arduino=cv.Version(1, 7, 0),
|
||||||
),
|
),
|
||||||
cv.boolean_false,
|
cv.boolean_false,
|
||||||
),
|
),
|
||||||
|
@@ -441,9 +441,10 @@ void AudioPipeline::decode_task(void *params) {
|
|||||||
pdFALSE, // Wait for all the bits,
|
pdFALSE, // Wait for all the bits,
|
||||||
portMAX_DELAY); // Block indefinitely until bit is set
|
portMAX_DELAY); // Block indefinitely until bit is set
|
||||||
|
|
||||||
|
xEventGroupClearBits(this_pipeline->event_group_,
|
||||||
|
EventGroupBits::DECODER_MESSAGE_FINISHED | EventGroupBits::READER_MESSAGE_LOADED_MEDIA_TYPE);
|
||||||
|
|
||||||
if (!(event_bits & EventGroupBits::PIPELINE_COMMAND_STOP)) {
|
if (!(event_bits & EventGroupBits::PIPELINE_COMMAND_STOP)) {
|
||||||
xEventGroupClearBits(this_pipeline->event_group_,
|
|
||||||
EventGroupBits::DECODER_MESSAGE_FINISHED | EventGroupBits::READER_MESSAGE_LOADED_MEDIA_TYPE);
|
|
||||||
InfoErrorEvent event;
|
InfoErrorEvent event;
|
||||||
event.source = InfoErrorSource::DECODER;
|
event.source = InfoErrorSource::DECODER;
|
||||||
|
|
||||||
|
@@ -70,6 +70,9 @@ WaveshareEPaper4P2InBV2 = waveshare_epaper_ns.class_(
|
|||||||
WaveshareEPaper4P2InBV2BWR = waveshare_epaper_ns.class_(
|
WaveshareEPaper4P2InBV2BWR = waveshare_epaper_ns.class_(
|
||||||
"WaveshareEPaper4P2InBV2BWR", WaveshareEPaperBWR
|
"WaveshareEPaper4P2InBV2BWR", WaveshareEPaperBWR
|
||||||
)
|
)
|
||||||
|
WaveshareEPaper5P65InF = waveshare_epaper_ns.class_(
|
||||||
|
"WaveshareEPaper5P65InF", WaveshareEPaper7C
|
||||||
|
)
|
||||||
WaveshareEPaper5P8In = waveshare_epaper_ns.class_(
|
WaveshareEPaper5P8In = waveshare_epaper_ns.class_(
|
||||||
"WaveshareEPaper5P8In", WaveshareEPaper
|
"WaveshareEPaper5P8In", WaveshareEPaper
|
||||||
)
|
)
|
||||||
@@ -150,6 +153,7 @@ MODELS = {
|
|||||||
"4.20in": ("b", WaveshareEPaper4P2In),
|
"4.20in": ("b", WaveshareEPaper4P2In),
|
||||||
"4.20in-bv2": ("b", WaveshareEPaper4P2InBV2),
|
"4.20in-bv2": ("b", WaveshareEPaper4P2InBV2),
|
||||||
"4.20in-bv2-bwr": ("b", WaveshareEPaper4P2InBV2BWR),
|
"4.20in-bv2-bwr": ("b", WaveshareEPaper4P2InBV2BWR),
|
||||||
|
"5.65in-f": ("b", WaveshareEPaper5P65InF),
|
||||||
"5.83in": ("b", WaveshareEPaper5P8In),
|
"5.83in": ("b", WaveshareEPaper5P8In),
|
||||||
"5.83inv2": ("b", WaveshareEPaper5P8InV2),
|
"5.83inv2": ("b", WaveshareEPaper5P8InV2),
|
||||||
"7.30in-f": ("b", WaveshareEPaper7P3InF),
|
"7.30in-f": ("b", WaveshareEPaper7P3InF),
|
||||||
|
@@ -258,6 +258,47 @@ void WaveshareEPaper7C::fill(Color color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void WaveshareEPaper7C::send_buffers_() {
|
||||||
|
if (this->buffers_[0] == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Buffer unavailable!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS;
|
||||||
|
uint8_t byte_to_send;
|
||||||
|
for (auto &buffer : this->buffers_) {
|
||||||
|
for (uint32_t buffer_pos = 0; buffer_pos < small_buffer_length; buffer_pos += 3) {
|
||||||
|
std::bitset<24> triplet =
|
||||||
|
buffer[buffer_pos + 0] << 16 | buffer[buffer_pos + 1] << 8 | buffer[buffer_pos + 2] << 0;
|
||||||
|
// 8 bitset<3> are stored in 3 bytes
|
||||||
|
// |aaabbbaa|abbbaaab|bbaaabbb|
|
||||||
|
// | byte 1 | byte 2 | byte 3 |
|
||||||
|
byte_to_send = ((triplet >> 17).to_ulong() & 0b01110000) | ((triplet >> 18).to_ulong() & 0b00000111);
|
||||||
|
this->data(byte_to_send);
|
||||||
|
|
||||||
|
byte_to_send = ((triplet >> 11).to_ulong() & 0b01110000) | ((triplet >> 12).to_ulong() & 0b00000111);
|
||||||
|
this->data(byte_to_send);
|
||||||
|
|
||||||
|
byte_to_send = ((triplet >> 5).to_ulong() & 0b01110000) | ((triplet >> 6).to_ulong() & 0b00000111);
|
||||||
|
this->data(byte_to_send);
|
||||||
|
|
||||||
|
byte_to_send = ((triplet << 1).to_ulong() & 0b01110000) | ((triplet << 0).to_ulong() & 0b00000111);
|
||||||
|
this->data(byte_to_send);
|
||||||
|
}
|
||||||
|
App.feed_wdt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void WaveshareEPaper7C::reset_() {
|
||||||
|
if (this->reset_pin_ != nullptr) {
|
||||||
|
this->reset_pin_->digital_write(true);
|
||||||
|
delay(20);
|
||||||
|
this->reset_pin_->digital_write(false);
|
||||||
|
delay(1);
|
||||||
|
this->reset_pin_->digital_write(true);
|
||||||
|
delay(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, Color color) {
|
void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, Color color) {
|
||||||
if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0)
|
if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0)
|
||||||
return;
|
return;
|
||||||
@@ -3307,6 +3348,175 @@ void WaveshareEPaper7P5In::dump_config() {
|
|||||||
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||||
LOG_UPDATE_INTERVAL(this);
|
LOG_UPDATE_INTERVAL(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Waveshare 5.65F ========================================================
|
||||||
|
|
||||||
|
namespace cmddata_5P65InF {
|
||||||
|
// WaveshareEPaper5P65InF commands
|
||||||
|
// https://www.waveshare.com/wiki/5.65inch_e-Paper_Module_(F)
|
||||||
|
|
||||||
|
// R00H (PSR): Panel setting Register
|
||||||
|
// UD(1): scan up
|
||||||
|
// SHL(1) shift right
|
||||||
|
// SHD_N(1) DC-DC on
|
||||||
|
// RST_N(1) no reset
|
||||||
|
static const uint8_t R00_CMD_PSR[] = {0x00, 0xEF, 0x08};
|
||||||
|
|
||||||
|
// R01H (PWR): Power setting Register
|
||||||
|
// internal DC-DC power generation
|
||||||
|
static const uint8_t R01_CMD_PWR[] = {0x01, 0x07, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
// R02H (POF): Power OFF Command
|
||||||
|
static const uint8_t R02_CMD_POF[] = {0x02};
|
||||||
|
|
||||||
|
// R03H (PFS): Power off sequence setting Register
|
||||||
|
// T_VDS_OFF (00) = 1 frame
|
||||||
|
static const uint8_t R03_CMD_PFS[] = {0x03, 0x00};
|
||||||
|
|
||||||
|
// R04H (PON): Power ON Command
|
||||||
|
static const uint8_t R04_CMD_PON[] = {0x04};
|
||||||
|
|
||||||
|
// R06h (BTST): Booster Soft Start
|
||||||
|
static const uint8_t R06_CMD_BTST[] = {0x06, 0xC7, 0xC7, 0x1D};
|
||||||
|
|
||||||
|
// R07H (DSLP): Deep sleep#
|
||||||
|
// Note Documentation @ Waveshare shows cmd code as 0x10 in table, but
|
||||||
|
// 0x10 is DTM1.
|
||||||
|
static const uint8_t R07_CMD_DSLP[] = {0x07, 0xA5};
|
||||||
|
|
||||||
|
// R10H (DTM1): Data Start Transmission 1
|
||||||
|
|
||||||
|
static const uint8_t R10_CMD_DTM1[] = {0x10};
|
||||||
|
|
||||||
|
// R11H (DSP): Data Stop
|
||||||
|
static const uint8_t R11_CMD_DSP[] = {0x11};
|
||||||
|
|
||||||
|
// R12H (DRF): Display Refresh
|
||||||
|
static const uint8_t R12_CMD_DRF[] = {0x12};
|
||||||
|
|
||||||
|
// R13H (IPC): Image Process Command
|
||||||
|
static const uint8_t R13_CMD_IPC[] = {0x13, 0x00};
|
||||||
|
|
||||||
|
// R30H (PLL): PLL Control
|
||||||
|
// 0x3C = 50Hz
|
||||||
|
static const uint8_t R30_CMD_PLL[] = {0x30, 0x3C};
|
||||||
|
|
||||||
|
// R41H (TSE): Temperature Sensor Enable
|
||||||
|
// TSE(0) enable, TO(0000) +0 degree offset
|
||||||
|
static const uint8_t R41_CMD_TSE[] = {0x41, 0x00};
|
||||||
|
|
||||||
|
// R50H (CDI) VCOM and Data interval setting
|
||||||
|
// CDI(0111) 10
|
||||||
|
// DDX(1), VBD(001) Border output "White"
|
||||||
|
static const uint8_t R50_CMD_CDI[] = {0x50, 0x37};
|
||||||
|
|
||||||
|
// R60H (TCON) Gate and Source non overlap period command
|
||||||
|
// S2G(10) 12 units
|
||||||
|
// G2S(10) 12 units
|
||||||
|
static const uint8_t R60_CMD_TCON[] = {0x60, 0x22};
|
||||||
|
|
||||||
|
// R61H (TRES) Resolution Setting
|
||||||
|
// 0x258 = 600
|
||||||
|
// 0x1C0 = 448
|
||||||
|
static const uint8_t R61_CMD_TRES[] = {0x61, 0x02, 0x58, 0x01, 0xC0};
|
||||||
|
|
||||||
|
// RE3H (PWS) Power Savings
|
||||||
|
static const uint8_t RE3_CMD_PWS[] = {0xE3, 0xAA};
|
||||||
|
} // namespace cmddata_5P65InF
|
||||||
|
|
||||||
|
void WaveshareEPaper5P65InF::initialize() {
|
||||||
|
if (this->buffers_[0] == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Buffer unavailable!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->reset_();
|
||||||
|
delay(20);
|
||||||
|
this->wait_until_(IDLE);
|
||||||
|
|
||||||
|
using namespace cmddata_5P65InF;
|
||||||
|
|
||||||
|
this->cmd_data(R00_CMD_PSR, sizeof(R00_CMD_PSR));
|
||||||
|
this->cmd_data(R01_CMD_PWR, sizeof(R01_CMD_PWR));
|
||||||
|
this->cmd_data(R03_CMD_PFS, sizeof(R03_CMD_PFS));
|
||||||
|
this->cmd_data(R06_CMD_BTST, sizeof(R06_CMD_BTST));
|
||||||
|
this->cmd_data(R30_CMD_PLL, sizeof(R30_CMD_PLL));
|
||||||
|
this->cmd_data(R41_CMD_TSE, sizeof(R41_CMD_TSE));
|
||||||
|
this->cmd_data(R50_CMD_CDI, sizeof(R50_CMD_CDI));
|
||||||
|
this->cmd_data(R60_CMD_TCON, sizeof(R60_CMD_TCON));
|
||||||
|
this->cmd_data(R61_CMD_TRES, sizeof(R61_CMD_TRES));
|
||||||
|
this->cmd_data(RE3_CMD_PWS, sizeof(RE3_CMD_PWS));
|
||||||
|
|
||||||
|
delay(100); // NOLINT
|
||||||
|
this->cmd_data(R50_CMD_CDI, sizeof(R50_CMD_CDI));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Display initialized successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
void HOT WaveshareEPaper5P65InF::display() {
|
||||||
|
// INITIALIZATION
|
||||||
|
ESP_LOGI(TAG, "Initialise the display");
|
||||||
|
this->initialize();
|
||||||
|
|
||||||
|
using namespace cmddata_5P65InF;
|
||||||
|
|
||||||
|
// COMMAND DATA START TRANSMISSION
|
||||||
|
ESP_LOGI(TAG, "Sending data to the display");
|
||||||
|
this->cmd_data(R61_CMD_TRES, sizeof(R61_CMD_TRES));
|
||||||
|
this->cmd_data(R10_CMD_DTM1, sizeof(R10_CMD_DTM1));
|
||||||
|
this->send_buffers_();
|
||||||
|
|
||||||
|
// COMMAND POWER ON
|
||||||
|
ESP_LOGI(TAG, "Power on the display");
|
||||||
|
this->cmd_data(R04_CMD_PON, sizeof(R04_CMD_PON));
|
||||||
|
this->wait_until_(IDLE);
|
||||||
|
|
||||||
|
// COMMAND REFRESH SCREEN
|
||||||
|
ESP_LOGI(TAG, "Refresh the display");
|
||||||
|
this->cmd_data(R12_CMD_DRF, sizeof(R12_CMD_DRF));
|
||||||
|
this->wait_until_(IDLE);
|
||||||
|
|
||||||
|
// COMMAND POWER OFF
|
||||||
|
ESP_LOGI(TAG, "Power off the display");
|
||||||
|
this->cmd_data(R02_CMD_POF, sizeof(R02_CMD_POF));
|
||||||
|
this->wait_until_(BUSY);
|
||||||
|
|
||||||
|
if (this->deep_sleep_between_updates_) {
|
||||||
|
ESP_LOGI(TAG, "Set the display to deep sleep");
|
||||||
|
this->cmd_data(R07_CMD_DSLP, sizeof(R07_CMD_DSLP));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int WaveshareEPaper5P65InF::get_width_internal() { return 600; }
|
||||||
|
int WaveshareEPaper5P65InF::get_height_internal() { return 448; }
|
||||||
|
uint32_t WaveshareEPaper5P65InF::idle_timeout_() { return 35000; }
|
||||||
|
|
||||||
|
void WaveshareEPaper5P65InF::dump_config() {
|
||||||
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
||||||
|
ESP_LOGCONFIG(TAG, " Model: 5.65in-F");
|
||||||
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||||
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
||||||
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||||
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WaveshareEPaper5P65InF::wait_until_(WaitForState busy_state) {
|
||||||
|
if (this->busy_pin_ == nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t start = millis();
|
||||||
|
while (busy_state != this->busy_pin_->digital_read()) {
|
||||||
|
if (millis() - start > this->idle_timeout_()) {
|
||||||
|
ESP_LOGE(TAG, "Timeout while displaying image!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
App.feed_wdt();
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void WaveshareEPaper7P3InF::initialize() {
|
void WaveshareEPaper7P3InF::initialize() {
|
||||||
if (this->buffers_[0] == nullptr) {
|
if (this->buffers_[0] == nullptr) {
|
||||||
ESP_LOGE(TAG, "Buffer unavailable!");
|
ESP_LOGE(TAG, "Buffer unavailable!");
|
||||||
@@ -3411,11 +3621,6 @@ void WaveshareEPaper7P3InF::initialize() {
|
|||||||
ESP_LOGI(TAG, "Display initialized successfully");
|
ESP_LOGI(TAG, "Display initialized successfully");
|
||||||
}
|
}
|
||||||
void HOT WaveshareEPaper7P3InF::display() {
|
void HOT WaveshareEPaper7P3InF::display() {
|
||||||
if (this->buffers_[0] == nullptr) {
|
|
||||||
ESP_LOGE(TAG, "Buffer unavailable!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// INITIALIZATION
|
// INITIALIZATION
|
||||||
ESP_LOGI(TAG, "Initialise the display");
|
ESP_LOGI(TAG, "Initialise the display");
|
||||||
this->initialize();
|
this->initialize();
|
||||||
@@ -3423,29 +3628,7 @@ void HOT WaveshareEPaper7P3InF::display() {
|
|||||||
// COMMAND DATA START TRANSMISSION
|
// COMMAND DATA START TRANSMISSION
|
||||||
ESP_LOGI(TAG, "Sending data to the display");
|
ESP_LOGI(TAG, "Sending data to the display");
|
||||||
this->command(0x10);
|
this->command(0x10);
|
||||||
uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS;
|
this->send_buffers_();
|
||||||
uint8_t byte_to_send;
|
|
||||||
for (auto &buffer : this->buffers_) {
|
|
||||||
for (uint32_t buffer_pos = 0; buffer_pos < small_buffer_length; buffer_pos += 3) {
|
|
||||||
std::bitset<24> triplet =
|
|
||||||
buffer[buffer_pos + 0] << 16 | buffer[buffer_pos + 1] << 8 | buffer[buffer_pos + 2] << 0;
|
|
||||||
// 8 bitset<3> are stored in 3 bytes
|
|
||||||
// |aaabbbaa|abbbaaab|bbaaabbb|
|
|
||||||
// | byte 1 | byte 2 | byte 3 |
|
|
||||||
byte_to_send = ((triplet >> 17).to_ulong() & 0b01110000) | ((triplet >> 18).to_ulong() & 0b00000111);
|
|
||||||
this->data(byte_to_send);
|
|
||||||
|
|
||||||
byte_to_send = ((triplet >> 11).to_ulong() & 0b01110000) | ((triplet >> 12).to_ulong() & 0b00000111);
|
|
||||||
this->data(byte_to_send);
|
|
||||||
|
|
||||||
byte_to_send = ((triplet >> 5).to_ulong() & 0b01110000) | ((triplet >> 6).to_ulong() & 0b00000111);
|
|
||||||
this->data(byte_to_send);
|
|
||||||
|
|
||||||
byte_to_send = ((triplet << 1).to_ulong() & 0b01110000) | ((triplet << 0).to_ulong() & 0b00000111);
|
|
||||||
this->data(byte_to_send);
|
|
||||||
}
|
|
||||||
App.feed_wdt();
|
|
||||||
}
|
|
||||||
|
|
||||||
// COMMAND POWER ON
|
// COMMAND POWER ON
|
||||||
ESP_LOGI(TAG, "Power on the display");
|
ESP_LOGI(TAG, "Power on the display");
|
||||||
@@ -3464,9 +3647,11 @@ void HOT WaveshareEPaper7P3InF::display() {
|
|||||||
this->data(0x00);
|
this->data(0x00);
|
||||||
this->wait_until_idle_();
|
this->wait_until_idle_();
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Set the display to deep sleep");
|
if (this->deep_sleep_between_updates_) {
|
||||||
this->command(0x07);
|
ESP_LOGI(TAG, "Set the display to deep sleep");
|
||||||
this->data(0xA5);
|
this->command(0x07);
|
||||||
|
this->data(0xA5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int WaveshareEPaper7P3InF::get_width_internal() { return 800; }
|
int WaveshareEPaper7P3InF::get_width_internal() { return 800; }
|
||||||
int WaveshareEPaper7P3InF::get_height_internal() { return 480; }
|
int WaveshareEPaper7P3InF::get_height_internal() { return 480; }
|
||||||
|
@@ -94,7 +94,10 @@ class WaveshareEPaper7C : public WaveshareEPaperBase {
|
|||||||
void draw_absolute_pixel_internal(int x, int y, Color color) override;
|
void draw_absolute_pixel_internal(int x, int y, Color color) override;
|
||||||
uint32_t get_buffer_length_() override;
|
uint32_t get_buffer_length_() override;
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
|
||||||
void init_internal_7c_(uint32_t buffer_length);
|
void init_internal_7c_(uint32_t buffer_length);
|
||||||
|
void send_buffers_();
|
||||||
|
void reset_();
|
||||||
|
|
||||||
static const int NUM_BUFFERS = 10;
|
static const int NUM_BUFFERS = 10;
|
||||||
uint8_t *buffers_[NUM_BUFFERS];
|
uint8_t *buffers_[NUM_BUFFERS];
|
||||||
@@ -683,6 +686,29 @@ class WaveshareEPaper5P8InV2 : public WaveshareEPaper {
|
|||||||
int get_height_internal() override;
|
int get_height_internal() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WaveshareEPaper5P65InF : public WaveshareEPaper7C {
|
||||||
|
public:
|
||||||
|
void initialize() override;
|
||||||
|
|
||||||
|
void display() override;
|
||||||
|
|
||||||
|
void dump_config() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int get_width_internal() override;
|
||||||
|
|
||||||
|
int get_height_internal() override;
|
||||||
|
|
||||||
|
uint32_t idle_timeout_() override;
|
||||||
|
|
||||||
|
void deep_sleep() override { ; }
|
||||||
|
|
||||||
|
enum WaitForState { BUSY = true, IDLE = false };
|
||||||
|
bool wait_until_(WaitForState state);
|
||||||
|
|
||||||
|
bool deep_sleep_between_updates_{true};
|
||||||
|
};
|
||||||
|
|
||||||
class WaveshareEPaper7P3InF : public WaveshareEPaper7C {
|
class WaveshareEPaper7P3InF : public WaveshareEPaper7C {
|
||||||
public:
|
public:
|
||||||
void initialize() override;
|
void initialize() override;
|
||||||
@@ -703,17 +729,6 @@ class WaveshareEPaper7P3InF : public WaveshareEPaper7C {
|
|||||||
bool wait_until_idle_();
|
bool wait_until_idle_();
|
||||||
|
|
||||||
bool deep_sleep_between_updates_{true};
|
bool deep_sleep_between_updates_{true};
|
||||||
|
|
||||||
void reset_() {
|
|
||||||
if (this->reset_pin_ != nullptr) {
|
|
||||||
this->reset_pin_->digital_write(true);
|
|
||||||
delay(20);
|
|
||||||
this->reset_pin_->digital_write(false);
|
|
||||||
delay(1);
|
|
||||||
this->reset_pin_->digital_write(true);
|
|
||||||
delay(20);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaveshareEPaper7P5In : public WaveshareEPaper {
|
class WaveshareEPaper7P5In : public WaveshareEPaper {
|
||||||
|
@@ -57,7 +57,6 @@ from esphome.const import (
|
|||||||
KEY_CORE,
|
KEY_CORE,
|
||||||
KEY_FRAMEWORK_VERSION,
|
KEY_FRAMEWORK_VERSION,
|
||||||
KEY_TARGET_FRAMEWORK,
|
KEY_TARGET_FRAMEWORK,
|
||||||
KEY_TARGET_PLATFORM,
|
|
||||||
PLATFORM_ESP32,
|
PLATFORM_ESP32,
|
||||||
PLATFORM_ESP8266,
|
PLATFORM_ESP8266,
|
||||||
PLATFORM_RP2040,
|
PLATFORM_RP2040,
|
||||||
@@ -1993,70 +1992,28 @@ def platformio_version_constraint(value):
|
|||||||
|
|
||||||
def require_framework_version(
|
def require_framework_version(
|
||||||
*,
|
*,
|
||||||
esp_idf=None,
|
|
||||||
esp32_arduino=None,
|
|
||||||
esp8266_arduino=None,
|
|
||||||
rp2040_arduino=None,
|
|
||||||
bk72xx_libretiny=None,
|
|
||||||
host=None,
|
|
||||||
max_version=False,
|
max_version=False,
|
||||||
extra_message=None,
|
extra_message=None,
|
||||||
|
**kwargs,
|
||||||
):
|
):
|
||||||
def validator(value):
|
def validator(value):
|
||||||
core_data = CORE.data[KEY_CORE]
|
core_data = CORE.data[KEY_CORE]
|
||||||
framework = core_data[KEY_TARGET_FRAMEWORK]
|
framework = core_data[KEY_TARGET_FRAMEWORK]
|
||||||
if framework == "esp-idf":
|
|
||||||
if esp_idf is None:
|
|
||||||
msg = "This feature is incompatible with esp-idf"
|
|
||||||
if extra_message:
|
|
||||||
msg += f". {extra_message}"
|
|
||||||
raise Invalid(msg)
|
|
||||||
required = esp_idf
|
|
||||||
elif CORE.is_bk72xx and framework == "arduino":
|
|
||||||
if bk72xx_libretiny is None:
|
|
||||||
msg = "This feature is incompatible with BK72XX"
|
|
||||||
if extra_message:
|
|
||||||
msg += f". {extra_message}"
|
|
||||||
raise Invalid(msg)
|
|
||||||
required = bk72xx_libretiny
|
|
||||||
elif CORE.is_esp32 and framework == "arduino":
|
|
||||||
if esp32_arduino is None:
|
|
||||||
msg = "This feature is incompatible with ESP32 using arduino framework"
|
|
||||||
if extra_message:
|
|
||||||
msg += f". {extra_message}"
|
|
||||||
raise Invalid(msg)
|
|
||||||
required = esp32_arduino
|
|
||||||
elif CORE.is_esp8266 and framework == "arduino":
|
|
||||||
if esp8266_arduino is None:
|
|
||||||
msg = "This feature is incompatible with ESP8266"
|
|
||||||
if extra_message:
|
|
||||||
msg += f". {extra_message}"
|
|
||||||
raise Invalid(msg)
|
|
||||||
required = esp8266_arduino
|
|
||||||
elif CORE.is_rp2040 and framework == "arduino":
|
|
||||||
if rp2040_arduino is None:
|
|
||||||
msg = "This feature is incompatible with RP2040"
|
|
||||||
if extra_message:
|
|
||||||
msg += f". {extra_message}"
|
|
||||||
raise Invalid(msg)
|
|
||||||
required = rp2040_arduino
|
|
||||||
elif CORE.is_host and framework == "host":
|
|
||||||
if host is None:
|
|
||||||
msg = "This feature is incompatible with host platform"
|
|
||||||
if extra_message:
|
|
||||||
msg += f". {extra_message}"
|
|
||||||
raise Invalid(msg)
|
|
||||||
required = host
|
|
||||||
else:
|
|
||||||
raise Invalid(
|
|
||||||
f"""
|
|
||||||
Internal Error: require_framework_version does not support this platform configuration
|
|
||||||
platform: {core_data[KEY_TARGET_PLATFORM]}
|
|
||||||
framework: {framework}
|
|
||||||
|
|
||||||
Please report this issue on GitHub -> https://github.com/esphome/issues/issues/new?template=bug_report.yml.
|
if CORE.is_host and framework == "host":
|
||||||
"""
|
key = "host"
|
||||||
)
|
elif framework == "esp-idf":
|
||||||
|
key = "esp_idf"
|
||||||
|
else:
|
||||||
|
key = CORE.target_platform + "_" + framework
|
||||||
|
|
||||||
|
if key not in kwargs:
|
||||||
|
msg = f"This feature is incompatible with {CORE.target_platform.upper()} using {framework} framework"
|
||||||
|
if extra_message:
|
||||||
|
msg += f". {extra_message}"
|
||||||
|
raise Invalid(msg)
|
||||||
|
|
||||||
|
required = kwargs[key]
|
||||||
|
|
||||||
if max_version:
|
if max_version:
|
||||||
if core_data[KEY_FRAMEWORK_VERSION] > required:
|
if core_data[KEY_FRAMEWORK_VERSION] > required:
|
||||||
|
@@ -13,8 +13,8 @@ platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile
|
|||||||
esptool==4.8.1
|
esptool==4.8.1
|
||||||
click==8.1.7
|
click==8.1.7
|
||||||
esphome-dashboard==20250212.0
|
esphome-dashboard==20250212.0
|
||||||
aioesphomeapi==29.9.0
|
aioesphomeapi==29.10.0
|
||||||
zeroconf==0.146.3
|
zeroconf==0.146.4
|
||||||
puremagic==1.28
|
puremagic==1.28
|
||||||
ruamel.yaml==0.18.10 # dashboard_import
|
ruamel.yaml==0.18.10 # dashboard_import
|
||||||
esphome-glyphsets==0.2.0
|
esphome-glyphsets==0.2.0
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
pylint==3.3.6
|
pylint==3.3.6
|
||||||
flake8==7.2.0 # also change in .pre-commit-config.yaml when updating
|
flake8==7.2.0 # also change in .pre-commit-config.yaml when updating
|
||||||
ruff==0.11.4 # also change in .pre-commit-config.yaml when updating
|
ruff==0.11.5 # also change in .pre-commit-config.yaml when updating
|
||||||
pyupgrade==3.19.1 # also change in .pre-commit-config.yaml when updating
|
pyupgrade==3.19.1 # also change in .pre-commit-config.yaml when updating
|
||||||
pre-commit
|
pre-commit
|
||||||
|
|
||||||
|
@@ -21,6 +21,8 @@ pre-commit install
|
|||||||
|
|
||||||
script/platformio_install_deps.py platformio.ini --libraries --tools --platforms
|
script/platformio_install_deps.py platformio.ini --libraries --tools --platforms
|
||||||
|
|
||||||
|
mkdir .temp
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo
|
echo
|
||||||
echo "Virtual environment created. Run 'source $location' to use it."
|
echo "Virtual environment created. Run 'source $location' to use it."
|
||||||
|
@@ -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
|
||||||
|
@@ -71,5 +71,6 @@ lvgl:
|
|||||||
sensor: encoder
|
sensor: encoder
|
||||||
enter_button: pushbutton
|
enter_button: pushbutton
|
||||||
group: general
|
group: general
|
||||||
|
initial_focus: lv_roller
|
||||||
|
|
||||||
<<: !include common.yaml
|
<<: !include common.yaml
|
||||||
|
@@ -541,6 +541,26 @@ display:
|
|||||||
lambda: |-
|
lambda: |-
|
||||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||||
|
|
||||||
|
# 5.65 inch displays
|
||||||
|
- platform: waveshare_epaper
|
||||||
|
id: epd_5_65
|
||||||
|
model: 5.65in-f
|
||||||
|
spi_id: spi_waveshare_epaper
|
||||||
|
cs_pin:
|
||||||
|
allow_other_uses: true
|
||||||
|
number: ${cs_pin}
|
||||||
|
dc_pin:
|
||||||
|
allow_other_uses: true
|
||||||
|
number: ${dc_pin}
|
||||||
|
busy_pin:
|
||||||
|
allow_other_uses: true
|
||||||
|
number: ${busy_pin}
|
||||||
|
reset_pin:
|
||||||
|
allow_other_uses: true
|
||||||
|
number: ${reset_pin}
|
||||||
|
lambda: |-
|
||||||
|
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||||
|
|
||||||
# 5.83 inch displays
|
# 5.83 inch displays
|
||||||
- platform: waveshare_epaper
|
- platform: waveshare_epaper
|
||||||
id: epd_5_83
|
id: epd_5_83
|
||||||
|
@@ -284,3 +284,93 @@ def test_split_default(framework, platform, variant, full, idf, arduino, simple)
|
|||||||
assert schema({}).get("idf") == idf
|
assert schema({}).get("idf") == idf
|
||||||
assert schema({}).get("arduino") == arduino
|
assert schema({}).get("arduino") == arduino
|
||||||
assert schema({}).get("simple") == simple
|
assert schema({}).get("simple") == simple
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"framework, platform, message",
|
||||||
|
[
|
||||||
|
("esp-idf", PLATFORM_ESP32, "ESP32 using esp-idf framework"),
|
||||||
|
("arduino", PLATFORM_ESP32, "ESP32 using arduino framework"),
|
||||||
|
("arduino", PLATFORM_ESP8266, "ESP8266 using arduino framework"),
|
||||||
|
("arduino", PLATFORM_RP2040, "RP2040 using arduino framework"),
|
||||||
|
("arduino", PLATFORM_BK72XX, "BK72XX using arduino framework"),
|
||||||
|
("host", PLATFORM_HOST, "HOST using host framework"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_require_framework_version(framework, platform, message):
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from esphome.const import (
|
||||||
|
KEY_CORE,
|
||||||
|
KEY_FRAMEWORK_VERSION,
|
||||||
|
KEY_TARGET_FRAMEWORK,
|
||||||
|
KEY_TARGET_PLATFORM,
|
||||||
|
)
|
||||||
|
|
||||||
|
CORE.data[KEY_CORE] = {}
|
||||||
|
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = platform
|
||||||
|
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = framework
|
||||||
|
CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = config_validation.Version(1, 0, 0)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
config_validation.require_framework_version(
|
||||||
|
esp_idf=config_validation.Version(0, 5, 0),
|
||||||
|
esp32_arduino=config_validation.Version(0, 5, 0),
|
||||||
|
esp8266_arduino=config_validation.Version(0, 5, 0),
|
||||||
|
rp2040_arduino=config_validation.Version(0, 5, 0),
|
||||||
|
bk72xx_arduino=config_validation.Version(0, 5, 0),
|
||||||
|
host=config_validation.Version(0, 5, 0),
|
||||||
|
extra_message="test 1",
|
||||||
|
)("test")
|
||||||
|
== "test"
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
vol.error.Invalid,
|
||||||
|
match="This feature requires at least framework version 2.0.0. test 2",
|
||||||
|
):
|
||||||
|
config_validation.require_framework_version(
|
||||||
|
esp_idf=config_validation.Version(2, 0, 0),
|
||||||
|
esp32_arduino=config_validation.Version(2, 0, 0),
|
||||||
|
esp8266_arduino=config_validation.Version(2, 0, 0),
|
||||||
|
rp2040_arduino=config_validation.Version(2, 0, 0),
|
||||||
|
bk72xx_arduino=config_validation.Version(2, 0, 0),
|
||||||
|
host=config_validation.Version(2, 0, 0),
|
||||||
|
extra_message="test 2",
|
||||||
|
)("test")
|
||||||
|
|
||||||
|
assert (
|
||||||
|
config_validation.require_framework_version(
|
||||||
|
esp_idf=config_validation.Version(1, 5, 0),
|
||||||
|
esp32_arduino=config_validation.Version(1, 5, 0),
|
||||||
|
esp8266_arduino=config_validation.Version(1, 5, 0),
|
||||||
|
rp2040_arduino=config_validation.Version(1, 5, 0),
|
||||||
|
bk72xx_arduino=config_validation.Version(1, 5, 0),
|
||||||
|
host=config_validation.Version(1, 5, 0),
|
||||||
|
max_version=True,
|
||||||
|
extra_message="test 3",
|
||||||
|
)("test")
|
||||||
|
== "test"
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
vol.error.Invalid,
|
||||||
|
match="This feature requires framework version 0.5.0 or lower. test 4",
|
||||||
|
):
|
||||||
|
config_validation.require_framework_version(
|
||||||
|
esp_idf=config_validation.Version(0, 5, 0),
|
||||||
|
esp32_arduino=config_validation.Version(0, 5, 0),
|
||||||
|
esp8266_arduino=config_validation.Version(0, 5, 0),
|
||||||
|
rp2040_arduino=config_validation.Version(0, 5, 0),
|
||||||
|
bk72xx_arduino=config_validation.Version(0, 5, 0),
|
||||||
|
host=config_validation.Version(0, 5, 0),
|
||||||
|
max_version=True,
|
||||||
|
extra_message="test 4",
|
||||||
|
)("test")
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
vol.error.Invalid, match=f"This feature is incompatible with {message}. test 5"
|
||||||
|
):
|
||||||
|
config_validation.require_framework_version(
|
||||||
|
extra_message="test 5",
|
||||||
|
)("test")
|
||||||
|
Reference in New Issue
Block a user