mirror of
https://github.com/esphome/esphome.git
synced 2025-10-31 23:21:54 +00:00
[epdiy] ePaper display(s)
This commit is contained in:
@@ -139,6 +139,7 @@ esphome/components/ens160_base/* @latonita @vincentscode
|
|||||||
esphome/components/ens160_i2c/* @latonita
|
esphome/components/ens160_i2c/* @latonita
|
||||||
esphome/components/ens160_spi/* @latonita
|
esphome/components/ens160_spi/* @latonita
|
||||||
esphome/components/ens210/* @itn3rd77
|
esphome/components/ens210/* @itn3rd77
|
||||||
|
esphome/components/epdiy/* @jesserockz
|
||||||
esphome/components/es7210/* @kahrendt
|
esphome/components/es7210/* @kahrendt
|
||||||
esphome/components/es7243e/* @kbx81
|
esphome/components/es7243e/* @kbx81
|
||||||
esphome/components/es8156/* @kbx81
|
esphome/components/es8156/* @kbx81
|
||||||
|
|||||||
0
esphome/components/epdiy/__init__.py
Normal file
0
esphome/components/epdiy/__init__.py
Normal file
106
esphome/components/epdiy/display.py
Normal file
106
esphome/components/epdiy/display.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import display, esp32
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_FULL_UPDATE_EVERY,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_LAMBDA,
|
||||||
|
CONF_MODEL,
|
||||||
|
CONF_PAGES,
|
||||||
|
)
|
||||||
|
from esphome.cpp_generator import MockObj
|
||||||
|
|
||||||
|
CODEOWNERS = ["@jesserockz"]
|
||||||
|
DEPENDENCIES = ["esp32", "psram"]
|
||||||
|
|
||||||
|
CONF_POWER_OFF_DELAY_ENABLED = "power_off_delay_enabled"
|
||||||
|
|
||||||
|
epdiy_ns = cg.esphome_ns.namespace("epdiy")
|
||||||
|
EPDiyDisplay = epdiy_ns.class_("EPDiyDisplay", display.Display)
|
||||||
|
|
||||||
|
|
||||||
|
class EpdBoardDefinition(MockObj):
|
||||||
|
def __str__(self):
|
||||||
|
return f"&{self.base}"
|
||||||
|
|
||||||
|
|
||||||
|
class EpdDisplay_t(MockObj):
|
||||||
|
def __str__(self):
|
||||||
|
return f"&{self.base}"
|
||||||
|
|
||||||
|
|
||||||
|
EpdInitOptions = cg.global_ns.enum("EpdInitOptions")
|
||||||
|
|
||||||
|
|
||||||
|
class Model:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
board_definition: MockObj,
|
||||||
|
display_t: MockObj,
|
||||||
|
init_options: MockObj,
|
||||||
|
width: int,
|
||||||
|
height: int,
|
||||||
|
vcom_mv: int = 0,
|
||||||
|
):
|
||||||
|
self.board_definition = board_definition
|
||||||
|
self.display_t = display_t
|
||||||
|
self.init_options = init_options
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.vcom_mv = vcom_mv
|
||||||
|
|
||||||
|
|
||||||
|
MODELS: dict[str, Model] = {
|
||||||
|
"lilygo_t5_4.7": Model(
|
||||||
|
board_definition=EpdBoardDefinition("epd_board_lilygo_t5_47"),
|
||||||
|
display_t=EpdDisplay_t("ED047TC2"),
|
||||||
|
init_options=(EpdInitOptions.EPD_LUT_64K, EpdInitOptions.EPD_FEED_QUEUE_8),
|
||||||
|
width=960,
|
||||||
|
height=540,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
display.FULL_DISPLAY_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(EPDiyDisplay),
|
||||||
|
cv.Required(CONF_MODEL): cv.one_of(*MODELS.keys()),
|
||||||
|
cv.Optional(CONF_FULL_UPDATE_EVERY, default=10): cv.uint32_t,
|
||||||
|
cv.Optional(CONF_POWER_OFF_DELAY_ENABLED, default=False): cv.boolean,
|
||||||
|
}
|
||||||
|
).extend(cv.polling_component_schema("60s")),
|
||||||
|
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
|
||||||
|
await display.register_display(var, config)
|
||||||
|
|
||||||
|
model = MODELS[config[CONF_MODEL]]
|
||||||
|
cg.add(
|
||||||
|
var.set_model_details(
|
||||||
|
model.board_definition,
|
||||||
|
model.display_t,
|
||||||
|
cg.RawExpression(
|
||||||
|
f"static_cast<EpdInitOptions>({'|'.join(str(o) for o in model.init_options)})"
|
||||||
|
),
|
||||||
|
model.vcom_mv,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if CONF_LAMBDA in config:
|
||||||
|
lambda_ = await cg.process_lambda(
|
||||||
|
config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void
|
||||||
|
)
|
||||||
|
cg.add(var.set_writer(lambda_))
|
||||||
|
|
||||||
|
cg.add(var.set_power_off_delay_enabled(config[CONF_POWER_OFF_DELAY_ENABLED]))
|
||||||
|
|
||||||
|
esp32.add_idf_component(
|
||||||
|
name="vroland/epdiy",
|
||||||
|
repo="https://github.com/vroland/epdiy",
|
||||||
|
ref="c61e9e923ce2418150d54f88cea5d196cdc40c54",
|
||||||
|
)
|
||||||
76
esphome/components/epdiy/epdiy_display.cpp
Normal file
76
esphome/components/epdiy/epdiy_display.cpp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#include "epdiy_display.h"
|
||||||
|
|
||||||
|
#include "esphome/core/application.h"
|
||||||
|
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome::epdiy {
|
||||||
|
|
||||||
|
static const char *const TAG = "epdiy";
|
||||||
|
|
||||||
|
static constexpr uint8_t TEMPERATURE = 23; // default temperature for e-paper displays
|
||||||
|
|
||||||
|
float EPDiyDisplay::get_setup_priority() const { return esphome::setup_priority::LATE; }
|
||||||
|
|
||||||
|
void EPDiyDisplay::setup() {
|
||||||
|
epd_init(this->board_definition_, this->display_t_, this->init_options_);
|
||||||
|
if (this->vcom_mv_ != 0) {
|
||||||
|
epd_set_vcom(this->vcom_mv_);
|
||||||
|
}
|
||||||
|
this->state_ = epd_hl_init(nullptr);
|
||||||
|
this->framebuffer_ = epd_hl_get_framebuffer(&this->state_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EPDiyDisplay::update() {
|
||||||
|
this->do_update_();
|
||||||
|
this->defer([this]() { this->flush_screen_changes_(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void EPDiyDisplay::fill(Color color) {
|
||||||
|
if (color == display::COLOR_OFF) {
|
||||||
|
memset(this->framebuffer_, 0xFF, this->get_buffer_length());
|
||||||
|
|
||||||
|
epd_poweron();
|
||||||
|
epd_hl_update_screen(&this->state_, MODE_GC16, TEMPERATURE);
|
||||||
|
epd_clear();
|
||||||
|
|
||||||
|
epd_poweroff();
|
||||||
|
App.feed_wdt();
|
||||||
|
} else {
|
||||||
|
Display::fill(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EPDiyDisplay::flush_screen_changes_() {
|
||||||
|
epd_poweron();
|
||||||
|
|
||||||
|
epd_hl_update_screen(&this->state_, MODE_GC16, TEMPERATURE);
|
||||||
|
memset(this->state_.back_fb, 0xFF, this->get_buffer_length());
|
||||||
|
|
||||||
|
uint16_t delay = 0;
|
||||||
|
if (this->power_off_delay_enabled_) {
|
||||||
|
delay = 700;
|
||||||
|
}
|
||||||
|
this->set_timeout("poweroff", delay, []() { epd_poweroff(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void EPDiyDisplay::on_shutdown() {
|
||||||
|
epd_poweroff();
|
||||||
|
epd_deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HOT EPDiyDisplay::draw_pixel_at(int x, int y, Color color) {
|
||||||
|
if (color.red == 255 && color.green == 255 && color.blue == 255) {
|
||||||
|
epd_draw_pixel(x, y, 0, this->framebuffer_);
|
||||||
|
} else {
|
||||||
|
int col = (0.2126 * color.red) + (0.7152 * color.green) + (0.0722 * color.blue);
|
||||||
|
int cl = 255 - col;
|
||||||
|
epd_draw_pixel(x, y, cl, this->framebuffer_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace esphome::epdiy
|
||||||
|
|
||||||
|
#endif // USE_ESP32
|
||||||
63
esphome/components/epdiy/epdiy_display.h
Normal file
63
esphome/components/epdiy/epdiy_display.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
|
||||||
|
#include "esphome/components/display/display_buffer.h"
|
||||||
|
#include "esphome/components/display/display_color_utils.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/version.h"
|
||||||
|
|
||||||
|
#include "epd_display.h"
|
||||||
|
#include "epd_highlevel.h"
|
||||||
|
|
||||||
|
namespace esphome::epdiy {
|
||||||
|
|
||||||
|
class EPDiyDisplay : public display::Display {
|
||||||
|
public:
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
void setup() override;
|
||||||
|
void update() override;
|
||||||
|
void on_shutdown() override;
|
||||||
|
|
||||||
|
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_GRAYSCALE; }
|
||||||
|
|
||||||
|
int get_width_internal() override { return this->display_t_->width; };
|
||||||
|
int get_height_internal() override { return this->display_t_->height; };
|
||||||
|
|
||||||
|
size_t get_buffer_length() const { return this->display_t_->width / 2 * this->display_t_->height; }
|
||||||
|
|
||||||
|
void set_power_off_delay_enabled(bool power_off_delay_enabled) {
|
||||||
|
this->power_off_delay_enabled_ = power_off_delay_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_model_details(const EpdBoardDefinition *board_definition, const EpdDisplay_t *display_t,
|
||||||
|
enum EpdInitOptions init_options, uint16_t vcom) {
|
||||||
|
this->board_definition_ = board_definition;
|
||||||
|
this->display_t_ = display_t;
|
||||||
|
this->init_options_ = init_options;
|
||||||
|
this->vcom_mv_ = vcom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill(Color color) override;
|
||||||
|
|
||||||
|
void draw_pixel_at(int x, int y, Color color) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void flush_screen_changes_();
|
||||||
|
EpdiyHighlevelState state_;
|
||||||
|
|
||||||
|
uint8_t *framebuffer_;
|
||||||
|
|
||||||
|
const EpdBoardDefinition *board_definition_;
|
||||||
|
const EpdDisplay_t *display_t_;
|
||||||
|
enum EpdInitOptions init_options_;
|
||||||
|
uint16_t vcom_mv_;
|
||||||
|
|
||||||
|
bool power_off_delay_enabled_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace esphome::epdiy
|
||||||
|
|
||||||
|
#endif // USE_ESP32
|
||||||
@@ -19,3 +19,6 @@ dependencies:
|
|||||||
- if: "target in [esp32h2, esp32p4]"
|
- if: "target in [esp32h2, esp32p4]"
|
||||||
zorxx/multipart-parser:
|
zorxx/multipart-parser:
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
|
vroland/epdiy:
|
||||||
|
git: https://github.com/vroland/epdiy.git
|
||||||
|
version: c61e9e923ce2418150d54f88cea5d196cdc40c54
|
||||||
|
|||||||
Reference in New Issue
Block a user