mirror of
https://github.com/esphome/esphome.git
synced 2025-03-15 15:18:16 +00:00
Merge branch 'dev' into vornado-ir
This commit is contained in:
commit
08360487b5
@ -18,8 +18,8 @@ namespace esphome {
|
||||
namespace http_request {
|
||||
|
||||
struct Header {
|
||||
const char *name;
|
||||
const char *value;
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
// Some common HTTP status codes
|
||||
|
@ -96,7 +96,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::start(std::string url, std::s
|
||||
container->client_.setUserAgent(this->useragent_);
|
||||
}
|
||||
for (const auto &header : headers) {
|
||||
container->client_.addHeader(header.name, header.value, false, true);
|
||||
container->client_.addHeader(header.name.c_str(), header.value.c_str(), false, true);
|
||||
}
|
||||
|
||||
// returned needed headers must be collected before the requests
|
||||
|
@ -84,7 +84,7 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::start(std::string url, std::strin
|
||||
container->set_secure(secure);
|
||||
|
||||
for (const auto &header : headers) {
|
||||
esp_http_client_set_header(client, header.name, header.value);
|
||||
esp_http_client_set_header(client, header.name.c_str(), header.value.c_str());
|
||||
}
|
||||
|
||||
const int body_len = body.length();
|
||||
|
@ -25,6 +25,15 @@ void ImageDecoder::draw(int x, int y, int w, int h, const Color &color) {
|
||||
}
|
||||
}
|
||||
|
||||
DownloadBuffer::DownloadBuffer(size_t size) : size_(size) {
|
||||
this->buffer_ = this->allocator_.allocate(size);
|
||||
this->reset();
|
||||
if (!this->buffer_) {
|
||||
ESP_LOGE(TAG, "Initial allocation of download buffer failed!");
|
||||
this->size_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *DownloadBuffer::data(size_t offset) {
|
||||
if (offset > this->size_) {
|
||||
ESP_LOGE(TAG, "Tried to access beyond download buffer bounds!!!");
|
||||
@ -46,12 +55,13 @@ size_t DownloadBuffer::resize(size_t size) {
|
||||
return size;
|
||||
}
|
||||
this->allocator_.deallocate(this->buffer_, this->size_);
|
||||
this->size_ = size;
|
||||
this->buffer_ = this->allocator_.allocate(size);
|
||||
this->reset();
|
||||
if (this->buffer_) {
|
||||
this->size_ = size;
|
||||
return size;
|
||||
} else {
|
||||
this->size_ = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -29,8 +29,12 @@ class ImageDecoder {
|
||||
* @brief Initialize the decoder.
|
||||
*
|
||||
* @param download_size The total number of bytes that need to be downloaded for the image.
|
||||
* @return int Returns 0 on success, a {@see DecodeError} value in case of an error.
|
||||
*/
|
||||
virtual void prepare(size_t download_size) { this->download_size_ = download_size; }
|
||||
virtual int prepare(size_t download_size) {
|
||||
this->download_size_ = download_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode a part of the image. It will try reading from the buffer.
|
||||
@ -83,10 +87,7 @@ class ImageDecoder {
|
||||
|
||||
class DownloadBuffer {
|
||||
public:
|
||||
DownloadBuffer(size_t size) : size_(size) {
|
||||
this->buffer_ = this->allocator_.allocate(size);
|
||||
this->reset();
|
||||
}
|
||||
DownloadBuffer(size_t size);
|
||||
|
||||
virtual ~DownloadBuffer() { this->allocator_.deallocate(this->buffer_, this->size_); }
|
||||
|
||||
|
@ -41,13 +41,14 @@ static int draw_callback(JPEGDRAW *jpeg) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void JpegDecoder::prepare(size_t download_size) {
|
||||
int JpegDecoder::prepare(size_t download_size) {
|
||||
ImageDecoder::prepare(download_size);
|
||||
auto size = this->image_->resize_download_buffer(download_size);
|
||||
if (size < download_size) {
|
||||
ESP_LOGE(TAG, "Resize failed!");
|
||||
// TODO: return an error code;
|
||||
ESP_LOGE(TAG, "Download buffer resize failed!");
|
||||
return DECODE_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HOT JpegDecoder::decode(uint8_t *buffer, size_t size) {
|
||||
|
@ -21,7 +21,7 @@ class JpegDecoder : public ImageDecoder {
|
||||
JpegDecoder(OnlineImage *image) : ImageDecoder(image) {}
|
||||
~JpegDecoder() override {}
|
||||
|
||||
void prepare(size_t download_size) override;
|
||||
int prepare(size_t download_size) override;
|
||||
int HOT decode(uint8_t *buffer, size_t size) override;
|
||||
|
||||
protected:
|
||||
|
@ -124,7 +124,7 @@ void OnlineImage::update() {
|
||||
default:
|
||||
accept_mime_type = "image/*";
|
||||
}
|
||||
accept_header.value = (accept_mime_type + ",*/*;q=0.8").c_str();
|
||||
accept_header.value = accept_mime_type + ",*/*;q=0.8";
|
||||
|
||||
headers.push_back(accept_header);
|
||||
|
||||
@ -178,7 +178,12 @@ void OnlineImage::update() {
|
||||
this->download_error_callback_.call();
|
||||
return;
|
||||
}
|
||||
this->decoder_->prepare(total_size);
|
||||
auto prepare_result = this->decoder_->prepare(total_size);
|
||||
if (prepare_result < 0) {
|
||||
this->end_connection_();
|
||||
this->download_error_callback_.call();
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Downloading image (Size: %d)", total_size);
|
||||
this->start_time_ = ::time(nullptr);
|
||||
}
|
||||
|
@ -40,11 +40,16 @@ static void draw_callback(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, ui
|
||||
decoder->draw(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void PngDecoder::prepare(size_t download_size) {
|
||||
int PngDecoder::prepare(size_t download_size) {
|
||||
ImageDecoder::prepare(download_size);
|
||||
if (!this->pngle_) {
|
||||
ESP_LOGE(TAG, "PNG decoder engine not initialized!");
|
||||
return DECODE_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
pngle_set_user_data(this->pngle_, this);
|
||||
pngle_set_init_callback(this->pngle_, init_callback);
|
||||
pngle_set_draw_callback(this->pngle_, draw_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HOT PngDecoder::decode(uint8_t *buffer, size_t size) {
|
||||
|
@ -21,7 +21,7 @@ class PngDecoder : public ImageDecoder {
|
||||
PngDecoder(OnlineImage *image) : ImageDecoder(image), pngle_(pngle_new()) {}
|
||||
~PngDecoder() override { pngle_destroy(this->pngle_); }
|
||||
|
||||
void prepare(size_t download_size) override;
|
||||
int prepare(size_t download_size) override;
|
||||
int HOT decode(uint8_t *buffer, size_t size) override;
|
||||
|
||||
protected:
|
||||
|
@ -182,13 +182,21 @@ AudioPipelineState AudioPipeline::process_state() {
|
||||
if (event_bits & EventGroupBits::PIPELINE_COMMAND_STOP) {
|
||||
// Stop command is fully processed, so clear the command bit
|
||||
xEventGroupClearBits(this->event_group_, EventGroupBits::PIPELINE_COMMAND_STOP);
|
||||
this->hard_stop_ = true;
|
||||
}
|
||||
|
||||
if (!this->is_playing_) {
|
||||
// The tasks have been stopped for two ``process_state`` calls in a row, so delete the tasks
|
||||
if ((this->read_task_handle_ != nullptr) || (this->decode_task_handle_ != nullptr)) {
|
||||
this->delete_tasks_();
|
||||
this->speaker_->stop();
|
||||
if (this->hard_stop_) {
|
||||
// Stop command was sent, so immediately end of the playback
|
||||
this->speaker_->stop();
|
||||
this->hard_stop_ = false;
|
||||
} else {
|
||||
// Decoded all the audio, so let the speaker finish playing before stopping
|
||||
this->speaker_->finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
this->is_playing_ = false;
|
||||
|
@ -112,6 +112,7 @@ class AudioPipeline {
|
||||
|
||||
uint32_t playback_ms_{0};
|
||||
|
||||
bool hard_stop_{false};
|
||||
bool is_playing_{false};
|
||||
bool pause_state_{false};
|
||||
bool task_stack_in_psram_;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "voice_assistant.h"
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
|
||||
@ -127,7 +128,7 @@ void VoiceAssistant::clear_buffers_() {
|
||||
}
|
||||
|
||||
#ifdef USE_SPEAKER
|
||||
if (this->speaker_buffer_ != nullptr) {
|
||||
if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) {
|
||||
memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE);
|
||||
|
||||
this->speaker_buffer_size_ = 0;
|
||||
@ -159,7 +160,7 @@ void VoiceAssistant::deallocate_buffers_() {
|
||||
this->input_buffer_ = nullptr;
|
||||
|
||||
#ifdef USE_SPEAKER
|
||||
if (this->speaker_buffer_ != nullptr) {
|
||||
if ((this->speaker_ != nullptr) && (this->speaker_buffer_ != nullptr)) {
|
||||
ExternalRAMAllocator<uint8_t> speaker_deallocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
||||
speaker_deallocator.deallocate(this->speaker_buffer_, SPEAKER_BUFFER_SIZE);
|
||||
this->speaker_buffer_ = nullptr;
|
||||
@ -389,14 +390,7 @@ void VoiceAssistant::loop() {
|
||||
}
|
||||
#endif
|
||||
if (playing) {
|
||||
this->set_timeout("playing", 2000, [this]() {
|
||||
this->cancel_timeout("speaker-timeout");
|
||||
this->set_state_(State::IDLE, State::IDLE);
|
||||
|
||||
api::VoiceAssistantAnnounceFinished msg;
|
||||
msg.success = true;
|
||||
this->api_client_->send_voice_assistant_announce_finished(msg);
|
||||
});
|
||||
this->start_playback_timeout_();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -614,6 +608,8 @@ void VoiceAssistant::request_stop() {
|
||||
this->desired_state_ = State::IDLE;
|
||||
break;
|
||||
case State::AWAITING_RESPONSE:
|
||||
this->signal_stop_();
|
||||
break;
|
||||
case State::STREAMING_RESPONSE:
|
||||
case State::RESPONSE_FINISHED:
|
||||
break; // Let the incoming audio stream finish then it will go to idle.
|
||||
@ -631,6 +627,17 @@ void VoiceAssistant::signal_stop_() {
|
||||
this->api_client_->send_voice_assistant_request(msg);
|
||||
}
|
||||
|
||||
void VoiceAssistant::start_playback_timeout_() {
|
||||
this->set_timeout("playing", 100, [this]() {
|
||||
this->cancel_timeout("speaker-timeout");
|
||||
this->set_state_(State::IDLE, State::IDLE);
|
||||
|
||||
api::VoiceAssistantAnnounceFinished msg;
|
||||
msg.success = true;
|
||||
this->api_client_->send_voice_assistant_announce_finished(msg);
|
||||
});
|
||||
}
|
||||
|
||||
void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||
ESP_LOGD(TAG, "Event Type: %" PRId32, msg.event_type);
|
||||
switch (msg.event_type) {
|
||||
@ -715,6 +722,8 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
if (this->media_player_ != nullptr) {
|
||||
this->media_player_->make_call().set_media_url(url).set_announcement(true).perform();
|
||||
// Start the playback timeout, as the media player state isn't immediately updated
|
||||
this->start_playback_timeout_();
|
||||
}
|
||||
#endif
|
||||
this->tts_end_trigger_->trigger(url);
|
||||
@ -725,7 +734,11 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||
}
|
||||
case api::enums::VOICE_ASSISTANT_RUN_END: {
|
||||
ESP_LOGD(TAG, "Assist Pipeline ended");
|
||||
if (this->state_ == State::STREAMING_MICROPHONE) {
|
||||
if ((this->state_ == State::STARTING_PIPELINE) || (this->state_ == State::AWAITING_RESPONSE)) {
|
||||
// Pipeline ended before starting microphone
|
||||
// Or there wasn't a TTS start event ("nevermind")
|
||||
this->set_state_(State::IDLE, State::IDLE);
|
||||
} else if (this->state_ == State::STREAMING_MICROPHONE) {
|
||||
this->ring_buffer_->reset();
|
||||
#ifdef USE_ESP_ADF
|
||||
if (this->use_wake_word_) {
|
||||
@ -736,9 +749,6 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||
{
|
||||
this->set_state_(State::IDLE, State::IDLE);
|
||||
}
|
||||
} else if (this->state_ == State::AWAITING_RESPONSE) {
|
||||
// No TTS start event ("nevermind")
|
||||
this->set_state_(State::IDLE, State::IDLE);
|
||||
}
|
||||
this->defer([this]() { this->end_trigger_->trigger(); });
|
||||
break;
|
||||
|
@ -40,6 +40,7 @@ enum VoiceAssistantFeature : uint32_t {
|
||||
FEATURE_SPEAKER = 1 << 1,
|
||||
FEATURE_API_AUDIO = 1 << 2,
|
||||
FEATURE_TIMERS = 1 << 3,
|
||||
FEATURE_ANNOUNCE = 1 << 4,
|
||||
};
|
||||
|
||||
enum class State {
|
||||
@ -136,6 +137,12 @@ class VoiceAssistant : public Component {
|
||||
flags |= VoiceAssistantFeature::FEATURE_TIMERS;
|
||||
}
|
||||
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
if (this->media_player_ != nullptr) {
|
||||
flags |= VoiceAssistantFeature::FEATURE_ANNOUNCE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
@ -209,6 +216,7 @@ class VoiceAssistant : public Component {
|
||||
void set_state_(State state);
|
||||
void set_state_(State state, State desired_state);
|
||||
void signal_stop_();
|
||||
void start_playback_timeout_();
|
||||
|
||||
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
||||
struct sockaddr_storage dest_addr_;
|
||||
|
@ -55,6 +55,9 @@ GDEW029T5 = waveshare_epaper_ns.class_("GDEW029T5", WaveshareEPaper)
|
||||
WaveshareEPaper2P9InDKE = waveshare_epaper_ns.class_(
|
||||
"WaveshareEPaper2P9InDKE", WaveshareEPaper
|
||||
)
|
||||
WaveshareEPaper2P9InD = waveshare_epaper_ns.class_(
|
||||
"WaveshareEPaper2P9InD", WaveshareEPaper
|
||||
)
|
||||
WaveshareEPaper4P2In = waveshare_epaper_ns.class_(
|
||||
"WaveshareEPaper4P2In", WaveshareEPaper
|
||||
)
|
||||
@ -120,7 +123,7 @@ MODELS = {
|
||||
"2.13in-ttgo-b74": ("a", WaveshareEPaperTypeAModel.TTGO_EPAPER_2_13_IN_B74),
|
||||
"2.90in": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_9_IN),
|
||||
"2.90inv2": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_9_IN_V2),
|
||||
"gdew029t5": ("b", GDEW029T5),
|
||||
"gdew029t5": ("c", GDEW029T5),
|
||||
"2.70in": ("b", WaveshareEPaper2P7In),
|
||||
"2.70in-b": ("b", WaveshareEPaper2P7InB),
|
||||
"2.70in-bv2": ("b", WaveshareEPaper2P7InBV2),
|
||||
@ -128,6 +131,7 @@ MODELS = {
|
||||
"2.90in-b": ("b", WaveshareEPaper2P9InB),
|
||||
"2.90in-bv3": ("b", WaveshareEPaper2P9InBV3),
|
||||
"2.90inv2-r2": ("c", WaveshareEPaper2P9InV2R2),
|
||||
"2.90in-d": ("b", WaveshareEPaper2P9InD),
|
||||
"2.90in-dke": ("c", WaveshareEPaper2P9InDKE),
|
||||
"4.20in": ("b", WaveshareEPaper4P2In),
|
||||
"4.20in-bv2": ("b", WaveshareEPaper4P2InBV2),
|
||||
|
@ -1211,6 +1211,93 @@ void WaveshareEPaper2P9InB::dump_config() {
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
// ========================================================
|
||||
// Waveshare 2.9-inch E-Paper (Type D)
|
||||
// Waveshare WIKI: https://www.waveshare.com/wiki/Pico-ePaper-2.9-D
|
||||
// Datasheet: https://www.waveshare.com/w/upload/b/b5/2.9inch_e-Paper_(D)_Specification.pdf
|
||||
// ========================================================
|
||||
|
||||
void WaveshareEPaper2P9InD::initialize() {
|
||||
// EPD hardware init start
|
||||
this->reset_();
|
||||
|
||||
// Booster Soft Start
|
||||
this->command(0x06); // Command: BTST
|
||||
this->data(0x17); // Soft start configuration Phase A
|
||||
this->data(0x17); // Soft start configuration Phase B
|
||||
this->data(0x17); // Soft start configuration Phase C
|
||||
|
||||
// Power Setting
|
||||
this->command(0x01); // Command: PWR
|
||||
this->data(0x03); // Intern DC/DC for VDH/VDL and VGH/VGL
|
||||
this->data(0x00); // Default configuration VCOM_HV and VGHL_LV
|
||||
this->data(0x2b); // VDH = 10.8 V
|
||||
this->data(0x2b); // VDL = -10.8 V
|
||||
|
||||
// Power ON
|
||||
this->command(0x04); // Command: PON
|
||||
this->wait_until_idle_();
|
||||
|
||||
// Panel settings
|
||||
this->command(0x00); // Command: PSR
|
||||
this->data(0x1F); // LUT from OTP, black and white mode, default scan
|
||||
|
||||
// PLL Control
|
||||
this->command(0x30); // Command: PLL
|
||||
this->data(0x3A); // Default PLL frequency
|
||||
|
||||
// Resolution settings
|
||||
this->command(0x61); // Command: TRES
|
||||
this->data(0x80); // Width: 128
|
||||
this->data(0x01); // Height MSB: 296
|
||||
this->data(0x28); // Height LSB: 296
|
||||
|
||||
// VCOM and data interval settings
|
||||
this->command(0x50); // Command: CDI
|
||||
this->data(0x77);
|
||||
|
||||
// VCOM_DC settings
|
||||
this->command(0x82); // Command: VDCS
|
||||
this->data(0x12); // Dafault VCOM_DC
|
||||
}
|
||||
|
||||
void WaveshareEPaper2P9InD::display() {
|
||||
// Start transmitting old data (clearing buffer)
|
||||
this->command(0x10); // Command: DTM1 (OLD frame data)
|
||||
this->start_data_();
|
||||
this->write_array(this->buffer_, this->get_buffer_length_());
|
||||
this->end_data_();
|
||||
|
||||
// Start transmitting new data (updated content)
|
||||
this->command(0x13); // Command: DTM2 (NEW frame data)
|
||||
this->start_data_();
|
||||
this->write_array(this->buffer_, this->get_buffer_length_());
|
||||
this->end_data_();
|
||||
|
||||
// Refresh Display
|
||||
this->command(0x12); // Command: DRF
|
||||
this->wait_until_idle_();
|
||||
|
||||
// Enter Power Off
|
||||
this->command(0x02); // Command: POF
|
||||
this->wait_until_idle_();
|
||||
|
||||
// Enter Deep Sleep
|
||||
this->command(0x07); // Command: DSLP
|
||||
this->data(0xA5);
|
||||
}
|
||||
|
||||
int WaveshareEPaper2P9InD::get_width_internal() { return 128; }
|
||||
int WaveshareEPaper2P9InD::get_height_internal() { return 296; }
|
||||
void WaveshareEPaper2P9InD::dump_config() {
|
||||
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
||||
ESP_LOGCONFIG(TAG, " Model: 2.9in (D)");
|
||||
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);
|
||||
}
|
||||
|
||||
// DKE 2.9
|
||||
// https://www.badge.team/docs/badges/sha2017/hardware/#e-ink-display-the-dke-group-depg0290b1
|
||||
// https://www.badge.team/docs/badges/sha2017/hardware/DEPG0290B01V3.0.pdf
|
||||
@ -1596,15 +1683,108 @@ void WaveshareEPaper2P9InV2R2::set_full_update_every(uint32_t full_update_every)
|
||||
// Datasheet:
|
||||
// - https://v4.cecdn.yun300.cn/100001_1909185148/SSD1680.pdf
|
||||
// - https://github.com/adafruit/Adafruit_EPD/blob/master/src/panels/ThinkInk_290_Grayscale4_T5.h
|
||||
// - https://github.com/ZinggJM/GxEPD2/blob/master/src/epd/GxEPD2_290_T5.cpp
|
||||
// - http://www.e-paper-display.com/GDEW029T5%20V3.1%20Specification5c22.pdf?
|
||||
// ========================================================
|
||||
|
||||
void GDEW029T5::initialize() {
|
||||
// from https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf, page 37
|
||||
// EPD hardware init start
|
||||
this->reset_();
|
||||
// full screen update LUT
|
||||
static const uint8_t LUT_20_VCOMDC_29_5[] = {
|
||||
0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x60, 0x28, 0x28, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t LUT_21_WW_29_5[] = {
|
||||
0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
|
||||
0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t LUT_22_BW_29_5[] = {
|
||||
0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
|
||||
0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t LUT_23_WB_29_5[] = {
|
||||
0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
|
||||
0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t LUT_24_BB_29_5[] = {
|
||||
0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
|
||||
0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
// partial screen update LUT
|
||||
static const uint8_t LUT_20_VCOMDC_PARTIAL_29_5[] = {
|
||||
0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t LUT_21_WW_PARTIAL_29_5[] = {
|
||||
0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t LUT_22_BW_PARTIAL_29_5[] = {
|
||||
0x80, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t LUT_23_WB_PARTIAL_29_5[] = {
|
||||
0x40, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t LUT_24_BB_PARTIAL_29_5[] = {
|
||||
0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
void GDEW029T5::power_on_() {
|
||||
if (!this->power_is_on_) {
|
||||
this->command(0x04);
|
||||
this->wait_until_idle_();
|
||||
}
|
||||
this->power_is_on_ = true;
|
||||
}
|
||||
|
||||
void GDEW029T5::power_off_() {
|
||||
this->command(0x02);
|
||||
this->wait_until_idle_();
|
||||
this->power_is_on_ = false;
|
||||
}
|
||||
|
||||
void GDEW029T5::deep_sleep() {
|
||||
this->power_off_();
|
||||
if (this->deep_sleep_between_updates_) {
|
||||
this->command(0x07); // deep sleep
|
||||
this->data(0xA5); // check code
|
||||
ESP_LOGD(TAG, "go to deep sleep");
|
||||
this->is_deep_sleep_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GDEW029T5::init_display_() {
|
||||
// from https://github.com/ZinggJM/GxEPD2/blob/master/src/epd/GxEPD2_290_T5.cpp
|
||||
|
||||
// Hardware Initialization
|
||||
if (this->deep_sleep_between_updates_ && this->is_deep_sleep_) {
|
||||
ESP_LOGI(TAG, "wake up from deep sleep");
|
||||
this->reset_();
|
||||
this->is_deep_sleep_ = false;
|
||||
}
|
||||
|
||||
// COMMAND POWER SETTINGS
|
||||
this->command(0x00);
|
||||
this->command(0x01);
|
||||
this->data(0x03);
|
||||
this->data(0x00);
|
||||
this->data(0x2b);
|
||||
@ -1617,40 +1797,122 @@ void GDEW029T5::initialize() {
|
||||
this->data(0x17);
|
||||
this->data(0x17);
|
||||
|
||||
// COMMAND POWER ON
|
||||
this->command(0x04);
|
||||
this->wait_until_idle_();
|
||||
|
||||
// Not sure what this does but it's in the Adafruit EPD library
|
||||
this->command(0xFF);
|
||||
this->wait_until_idle_();
|
||||
this->power_on_();
|
||||
|
||||
// COMMAND PANEL SETTING
|
||||
this->command(0x00);
|
||||
// 128x296 resolution: 10
|
||||
// LUT from OTP: 0
|
||||
// LUT from register: 1
|
||||
// B/W mode (doesn't work): 1
|
||||
// scan-up: 1
|
||||
// shift-right: 1
|
||||
// booster ON: 1
|
||||
// no soft reset: 1
|
||||
this->data(0b10011111);
|
||||
this->data(0b10111111);
|
||||
this->data(0x0d); // VCOM to 0V fast
|
||||
this->command(0x30); // PLL setting
|
||||
this->data(0x3a); // 3a 100HZ 29 150Hz 39 200HZ 31 171HZ
|
||||
this->command(0x61); // resolution setting
|
||||
this->data(this->get_width_internal());
|
||||
this->data(this->get_height_internal() >> 8);
|
||||
this->data(this->get_height_internal() & 0xFF);
|
||||
|
||||
// COMMAND RESOLUTION SETTING
|
||||
// set to 128x296 by COMMAND PANEL SETTING
|
||||
|
||||
// COMMAND VCOM AND DATA INTERVAL SETTING
|
||||
// use defaults for white border and ESPHome image polarity
|
||||
|
||||
// EPD hardware init end
|
||||
ESP_LOGD(TAG, "panel setting done");
|
||||
}
|
||||
|
||||
void GDEW029T5::initialize() {
|
||||
// from https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf, page 37
|
||||
if (this->reset_pin_ != nullptr)
|
||||
this->deep_sleep_between_updates_ = true;
|
||||
|
||||
// old buffer for partial update
|
||||
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
||||
this->old_buffer_ = allocator.allocate(this->get_buffer_length_());
|
||||
if (this->old_buffer_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Could not allocate old buffer for display!");
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
||||
this->old_buffer_[i] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize for full(normal) update
|
||||
void GDEW029T5::init_full_() {
|
||||
this->init_display_();
|
||||
this->command(0x82); // vcom_DC setting
|
||||
this->data(0x08);
|
||||
this->command(0X50); // VCOM AND DATA INTERVAL SETTING
|
||||
this->data(0x97); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
|
||||
this->command(0x20);
|
||||
this->write_lut_(LUT_20_VCOMDC_29_5, sizeof(LUT_20_VCOMDC_29_5));
|
||||
this->command(0x21);
|
||||
this->write_lut_(LUT_21_WW_29_5, sizeof(LUT_21_WW_29_5));
|
||||
this->command(0x22);
|
||||
this->write_lut_(LUT_22_BW_29_5, sizeof(LUT_22_BW_29_5));
|
||||
this->command(0x23);
|
||||
this->write_lut_(LUT_23_WB_29_5, sizeof(LUT_23_WB_29_5));
|
||||
this->command(0x24);
|
||||
this->write_lut_(LUT_24_BB_29_5, sizeof(LUT_24_BB_29_5));
|
||||
ESP_LOGD(TAG, "initialized full update");
|
||||
}
|
||||
|
||||
// initialzie for partial update
|
||||
void GDEW029T5::init_partial_() {
|
||||
this->init_display_();
|
||||
this->command(0x82); // vcom_DC setting
|
||||
this->data(0x08);
|
||||
this->command(0X50); // VCOM AND DATA INTERVAL SETTING
|
||||
this->data(0x17); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
|
||||
this->command(0x20);
|
||||
this->write_lut_(LUT_20_VCOMDC_PARTIAL_29_5, sizeof(LUT_20_VCOMDC_PARTIAL_29_5));
|
||||
this->command(0x21);
|
||||
this->write_lut_(LUT_21_WW_PARTIAL_29_5, sizeof(LUT_21_WW_PARTIAL_29_5));
|
||||
this->command(0x22);
|
||||
this->write_lut_(LUT_22_BW_PARTIAL_29_5, sizeof(LUT_22_BW_PARTIAL_29_5));
|
||||
this->command(0x23);
|
||||
this->write_lut_(LUT_23_WB_PARTIAL_29_5, sizeof(LUT_23_WB_PARTIAL_29_5));
|
||||
this->command(0x24);
|
||||
this->write_lut_(LUT_24_BB_PARTIAL_29_5, sizeof(LUT_24_BB_PARTIAL_29_5));
|
||||
ESP_LOGD(TAG, "initialized partial update");
|
||||
}
|
||||
|
||||
void HOT GDEW029T5::display() {
|
||||
bool full_update = this->at_update_ == 0;
|
||||
if (full_update) {
|
||||
this->init_full_();
|
||||
} else {
|
||||
this->init_partial_();
|
||||
this->command(0x91); // partial in
|
||||
// set partial window
|
||||
this->command(0x90);
|
||||
// this->data(0);
|
||||
this->data(0);
|
||||
// this->data(0);
|
||||
this->data((this->get_width_internal() - 1) % 256);
|
||||
this->data(0);
|
||||
this->data(0);
|
||||
this->data(((this->get_height_internal() - 1)) / 256);
|
||||
this->data(((this->get_height_internal() - 1)) % 256);
|
||||
this->data(0x01);
|
||||
}
|
||||
// input old buffer data
|
||||
this->command(0x10);
|
||||
delay(2);
|
||||
this->start_data_();
|
||||
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
||||
this->write_byte(this->old_buffer_[i]);
|
||||
}
|
||||
this->end_data_();
|
||||
delay(2);
|
||||
|
||||
// COMMAND DATA START TRANSMISSION 2 (B/W only)
|
||||
this->command(0x13);
|
||||
delay(2);
|
||||
this->start_data_();
|
||||
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
||||
this->write_byte(this->buffer_[i]);
|
||||
this->old_buffer_[i] = this->buffer_[i];
|
||||
}
|
||||
this->end_data_();
|
||||
delay(2);
|
||||
@ -1660,10 +1922,28 @@ void HOT GDEW029T5::display() {
|
||||
delay(2);
|
||||
this->wait_until_idle_();
|
||||
|
||||
// COMMAND POWER OFF
|
||||
// NOTE: power off < deep sleep
|
||||
this->command(0x02);
|
||||
if (full_update) {
|
||||
ESP_LOGD(TAG, "full update done");
|
||||
} else {
|
||||
this->command(0x92); // partial out
|
||||
ESP_LOGD(TAG, "partial update done");
|
||||
}
|
||||
|
||||
this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
|
||||
// COMMAND deep sleep
|
||||
this->deep_sleep();
|
||||
}
|
||||
|
||||
void GDEW029T5::write_lut_(const uint8_t *lut, const uint8_t size) {
|
||||
// COMMAND WRITE LUT REGISTER
|
||||
this->start_data_();
|
||||
for (uint8_t i = 0; i < size; i++)
|
||||
this->write_byte(lut[i]);
|
||||
this->end_data_();
|
||||
}
|
||||
|
||||
void GDEW029T5::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
|
||||
|
||||
int GDEW029T5::get_width_internal() { return 128; }
|
||||
int GDEW029T5::get_height_internal() { return 296; }
|
||||
void GDEW029T5::dump_config() {
|
||||
@ -1672,6 +1952,7 @@ void GDEW029T5::dump_config() {
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
||||
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||
ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
|
@ -254,16 +254,27 @@ class GDEW029T5 : public WaveshareEPaper {
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
void deep_sleep() override {
|
||||
// COMMAND DEEP SLEEP
|
||||
this->command(0x07);
|
||||
this->data(0xA5); // check byte
|
||||
}
|
||||
void deep_sleep() override;
|
||||
void set_full_update_every(uint32_t full_update_every);
|
||||
|
||||
protected:
|
||||
void init_display_();
|
||||
void init_full_();
|
||||
void init_partial_();
|
||||
void write_lut_(const uint8_t *lut, uint8_t size);
|
||||
void power_off_();
|
||||
void power_on_();
|
||||
int get_width_internal() override;
|
||||
|
||||
int get_height_internal() override;
|
||||
|
||||
private:
|
||||
uint32_t full_update_every_{30};
|
||||
uint32_t at_update_{0};
|
||||
bool deep_sleep_between_updates_{false};
|
||||
bool power_is_on_{false};
|
||||
bool is_deep_sleep_{false};
|
||||
uint8_t *old_buffer_{nullptr};
|
||||
};
|
||||
|
||||
class WaveshareEPaper2P7InV2 : public WaveshareEPaper {
|
||||
@ -416,6 +427,26 @@ class WaveshareEPaper2P9InDKE : public WaveshareEPaper {
|
||||
int get_height_internal() override;
|
||||
};
|
||||
|
||||
class WaveshareEPaper2P9InD : public WaveshareEPaper {
|
||||
public:
|
||||
void initialize() override;
|
||||
|
||||
void display() override;
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
void deep_sleep() override {
|
||||
// COMMAND DEEP SLEEP
|
||||
this->command(0x07);
|
||||
this->data(0xA5);
|
||||
}
|
||||
|
||||
protected:
|
||||
int get_width_internal() override;
|
||||
|
||||
int get_height_internal() override;
|
||||
};
|
||||
|
||||
class WaveshareEPaper4P2In : public WaveshareEPaper {
|
||||
public:
|
||||
void initialize() override;
|
||||
|
@ -459,6 +459,7 @@ display:
|
||||
reset_pin:
|
||||
allow_other_uses: true
|
||||
number: ${reset_pin}
|
||||
full_update_every: 30
|
||||
lambda: |-
|
||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||
|
||||
@ -713,6 +714,25 @@ display:
|
||||
lambda: |-
|
||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||
|
||||
- platform: waveshare_epaper
|
||||
model: 2.90in-d
|
||||
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}
|
||||
reset_duration: 200ms
|
||||
lambda: |-
|
||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||
|
||||
- platform: waveshare_epaper
|
||||
model: 2.90in
|
||||
spi_id: spi_waveshare_epaper
|
||||
|
Loading…
x
Reference in New Issue
Block a user