mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Merge branch 'dev' into vornado-ir
This commit is contained in:
		| @@ -9,10 +9,10 @@ namespace online_image { | ||||
| static const char *const TAG = "online_image.decoder"; | ||||
|  | ||||
| bool ImageDecoder::set_size(int width, int height) { | ||||
|   bool resized = this->image_->resize_(width, height); | ||||
|   bool success = this->image_->resize_(width, height) > 0; | ||||
|   this->x_scale_ = static_cast<double>(this->image_->buffer_width_) / width; | ||||
|   this->y_scale_ = static_cast<double>(this->image_->buffer_height_) / height; | ||||
|   return resized; | ||||
|   return success; | ||||
| } | ||||
|  | ||||
| void ImageDecoder::draw(int x, int y, int w, int h, const Color &color) { | ||||
| @@ -51,8 +51,9 @@ size_t DownloadBuffer::read(size_t len) { | ||||
| } | ||||
|  | ||||
| size_t DownloadBuffer::resize(size_t size) { | ||||
|   if (this->size_ == size) { | ||||
|     return size; | ||||
|   if (this->size_ >= size) { | ||||
|     // Avoid useless reallocations; if the buffer is big enough, don't reallocate. | ||||
|     return this->size_; | ||||
|   } | ||||
|   this->allocator_.deallocate(this->buffer_, this->size_); | ||||
|   this->buffer_ = this->allocator_.allocate(size); | ||||
| @@ -61,6 +62,8 @@ size_t DownloadBuffer::resize(size_t size) { | ||||
|     this->size_ = size; | ||||
|     return size; | ||||
|   } else { | ||||
|     ESP_LOGE(TAG, "allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", size, | ||||
|              this->allocator_.get_max_free_block_size()); | ||||
|     this->size_ = 0; | ||||
|     return 0; | ||||
|   } | ||||
|   | ||||
| @@ -58,7 +58,7 @@ int HOT JpegDecoder::decode(uint8_t *buffer, size_t size) { | ||||
|   } | ||||
|  | ||||
|   if (!this->jpeg_.openRAM(buffer, size, draw_callback)) { | ||||
|     ESP_LOGE(TAG, "Could not open image for decoding."); | ||||
|     ESP_LOGE(TAG, "Could not open image for decoding: %d", this->jpeg_.getLastError()); | ||||
|     return DECODE_ERROR_INVALID_TYPE; | ||||
|   } | ||||
|   auto jpeg_type = this->jpeg_.getJPEGType(); | ||||
| @@ -73,7 +73,9 @@ int HOT JpegDecoder::decode(uint8_t *buffer, size_t size) { | ||||
|  | ||||
|   this->jpeg_.setUserPointer(this); | ||||
|   this->jpeg_.setPixelType(RGB8888); | ||||
|   this->set_size(this->jpeg_.getWidth(), this->jpeg_.getHeight()); | ||||
|   if (!this->set_size(this->jpeg_.getWidth(), this->jpeg_.getHeight())) { | ||||
|     return DECODE_ERROR_OUT_OF_MEMORY; | ||||
|   } | ||||
|   if (!this->jpeg_.decode(0, 0, 0)) { | ||||
|     ESP_LOGE(TAG, "Error while decoding."); | ||||
|     this->jpeg_.close(); | ||||
|   | ||||
| @@ -64,33 +64,34 @@ void OnlineImage::release() { | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool OnlineImage::resize_(int width_in, int height_in) { | ||||
| size_t OnlineImage::resize_(int width_in, int height_in) { | ||||
|   int width = this->fixed_width_; | ||||
|   int height = this->fixed_height_; | ||||
|   if (this->auto_resize_()) { | ||||
|   if (this->is_auto_resize_()) { | ||||
|     width = width_in; | ||||
|     height = height_in; | ||||
|     if (this->width_ != width && this->height_ != height) { | ||||
|       this->release(); | ||||
|     } | ||||
|   } | ||||
|   if (this->buffer_) { | ||||
|     return false; | ||||
|   } | ||||
|   size_t new_size = this->get_buffer_size_(width, height); | ||||
|   if (this->buffer_) { | ||||
|     // Buffer already allocated => no need to resize | ||||
|     return new_size; | ||||
|   } | ||||
|   ESP_LOGD(TAG, "Allocating new buffer of %zu bytes", new_size); | ||||
|   this->buffer_ = this->allocator_.allocate(new_size); | ||||
|   if (this->buffer_ == nullptr) { | ||||
|     ESP_LOGE(TAG, "allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", new_size, | ||||
|              this->allocator_.get_max_free_block_size()); | ||||
|     this->end_connection_(); | ||||
|     return false; | ||||
|     return 0; | ||||
|   } | ||||
|   this->buffer_width_ = width; | ||||
|   this->buffer_height_ = height; | ||||
|   this->width_ = width; | ||||
|   ESP_LOGV(TAG, "New size: (%d, %d)", width, height); | ||||
|   return true; | ||||
|   return new_size; | ||||
| } | ||||
|  | ||||
| void OnlineImage::update() { | ||||
|   | ||||
| @@ -99,9 +99,22 @@ class OnlineImage : public PollingComponent, | ||||
|  | ||||
|   int get_position_(int x, int y) const { return (x + y * this->buffer_width_) * this->get_bpp() / 8; } | ||||
|  | ||||
|   ESPHOME_ALWAYS_INLINE bool auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; } | ||||
|   ESPHOME_ALWAYS_INLINE bool is_auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; } | ||||
|  | ||||
|   bool resize_(int width, int height); | ||||
|   /** | ||||
|    * @brief Resize the image buffer to the requested dimensions. | ||||
|    * | ||||
|    * The buffer will be allocated if not existing. | ||||
|    * If the dimensions have been fixed in the yaml config, the buffer will be created | ||||
|    * with those dimensions and not resized, even on request. | ||||
|    * Otherwise, the old buffer will be deallocated and a new buffer with the requested | ||||
|    * allocated | ||||
|    * | ||||
|    * @param width | ||||
|    * @param height | ||||
|    * @return 0 if no memory could be allocated, the size of the new buffer otherwise. | ||||
|    */ | ||||
|   size_t resize_(int width, int height); | ||||
|  | ||||
|   /** | ||||
|    * @brief Draw a pixel into the buffer. | ||||
|   | ||||
| @@ -83,6 +83,12 @@ void PrometheusHandler::handleRequest(AsyncWebServerRequest *req) { | ||||
|     this->update_entity_row_(stream, obj, area, node, friendly_name); | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_VALVE | ||||
|   this->valve_type_(stream); | ||||
|   for (auto *obj : App.get_valves()) | ||||
|     this->valve_row_(stream, obj, area, node, friendly_name); | ||||
| #endif | ||||
|  | ||||
|   req->send(stream); | ||||
| } | ||||
|  | ||||
| @@ -770,6 +776,54 @@ void PrometheusHandler::update_entity_row_(AsyncResponseStream *stream, update:: | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_VALVE | ||||
| void PrometheusHandler::valve_type_(AsyncResponseStream *stream) { | ||||
|   stream->print(F("#TYPE esphome_valve_operation gauge\n")); | ||||
|   stream->print(F("#TYPE esphome_valve_failed gauge\n")); | ||||
|   stream->print(F("#TYPE esphome_valve_position gauge\n")); | ||||
| } | ||||
|  | ||||
| void PrometheusHandler::valve_row_(AsyncResponseStream *stream, valve::Valve *obj, std::string &area, std::string &node, | ||||
|                                    std::string &friendly_name) { | ||||
|   if (obj->is_internal() && !this->include_internal_) | ||||
|     return; | ||||
|   stream->print(F("esphome_valve_failed{id=\"")); | ||||
|   stream->print(relabel_id_(obj).c_str()); | ||||
|   add_area_label_(stream, area); | ||||
|   add_node_label_(stream, node); | ||||
|   add_friendly_name_label_(stream, friendly_name); | ||||
|   stream->print(F("\",name=\"")); | ||||
|   stream->print(relabel_name_(obj).c_str()); | ||||
|   stream->print(F("\"} 0\n")); | ||||
|   // Data itself | ||||
|   stream->print(F("esphome_valve_operation{id=\"")); | ||||
|   stream->print(relabel_id_(obj).c_str()); | ||||
|   add_area_label_(stream, area); | ||||
|   add_node_label_(stream, node); | ||||
|   add_friendly_name_label_(stream, friendly_name); | ||||
|   stream->print(F("\",name=\"")); | ||||
|   stream->print(relabel_name_(obj).c_str()); | ||||
|   stream->print(F("\",operation=\"")); | ||||
|   stream->print(valve::valve_operation_to_str(obj->current_operation)); | ||||
|   stream->print(F("\"} ")); | ||||
|   stream->print(F("1.0")); | ||||
|   stream->print(F("\n")); | ||||
|   // Now see if position is supported | ||||
|   if (obj->get_traits().get_supports_position()) { | ||||
|     stream->print(F("esphome_valve_position{id=\"")); | ||||
|     stream->print(relabel_id_(obj).c_str()); | ||||
|     add_area_label_(stream, area); | ||||
|     add_node_label_(stream, node); | ||||
|     add_friendly_name_label_(stream, friendly_name); | ||||
|     stream->print(F("\",name=\"")); | ||||
|     stream->print(relabel_name_(obj).c_str()); | ||||
|     stream->print(F("\"} ")); | ||||
|     stream->print(obj->position); | ||||
|     stream->print(F("\n")); | ||||
|   } | ||||
| } | ||||
| #endif | ||||
|  | ||||
| }  // namespace prometheus | ||||
| }  // namespace esphome | ||||
| #endif | ||||
|   | ||||
| @@ -161,6 +161,14 @@ class PrometheusHandler : public AsyncWebHandler, public Component { | ||||
|   void handle_update_state_(AsyncResponseStream *stream, update::UpdateState state); | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_VALVE | ||||
|   /// Return the type for prometheus | ||||
|   void valve_type_(AsyncResponseStream *stream); | ||||
|   /// Return the valve state as prometheus data point | ||||
|   void valve_row_(AsyncResponseStream *stream, valve::Valve *obj, std::string &area, std::string &node, | ||||
|                   std::string &friendly_name); | ||||
| #endif | ||||
|  | ||||
|   web_server_base::WebServerBase *base_; | ||||
|   bool include_internal_{false}; | ||||
|   std::map<EntityBase *, std::string> relabel_map_id_; | ||||
|   | ||||
| @@ -24,6 +24,7 @@ WaveshareEPaper = waveshare_epaper_ns.class_("WaveshareEPaper", WaveshareEPaperB | ||||
| WaveshareEPaperBWR = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaperBWR", WaveshareEPaperBase | ||||
| ) | ||||
| WaveshareEPaper7C = waveshare_epaper_ns.class_("WaveshareEPaper7C", WaveshareEPaperBase) | ||||
| WaveshareEPaperTypeA = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaperTypeA", WaveshareEPaper | ||||
| ) | ||||
| @@ -52,9 +53,11 @@ WaveshareEPaper2P9InV2R2 = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper2P9InV2R2", WaveshareEPaper | ||||
| ) | ||||
| GDEW029T5 = waveshare_epaper_ns.class_("GDEW029T5", WaveshareEPaper) | ||||
| GDEY029T94 = waveshare_epaper_ns.class_("GDEY029T94", WaveshareEPaper) | ||||
| WaveshareEPaper2P9InDKE = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper2P9InDKE", WaveshareEPaper | ||||
| ) | ||||
| GDEY042T81 = waveshare_epaper_ns.class_("GDEY042T81", WaveshareEPaper) | ||||
| WaveshareEPaper2P9InD = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper2P9InD", WaveshareEPaper | ||||
| ) | ||||
| @@ -64,12 +67,18 @@ WaveshareEPaper4P2In = waveshare_epaper_ns.class_( | ||||
| WaveshareEPaper4P2InBV2 = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper4P2InBV2", WaveshareEPaper | ||||
| ) | ||||
| WaveshareEPaper4P2InBV2BWR = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper4P2InBV2BWR", WaveshareEPaperBWR | ||||
| ) | ||||
| WaveshareEPaper5P8In = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper5P8In", WaveshareEPaper | ||||
| ) | ||||
| WaveshareEPaper5P8InV2 = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper5P8InV2", WaveshareEPaper | ||||
| ) | ||||
| WaveshareEPaper7P3InF = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper7P3InF", WaveshareEPaper7C | ||||
| ) | ||||
| WaveshareEPaper7P5In = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper7P5In", WaveshareEPaper | ||||
| ) | ||||
| @@ -91,6 +100,9 @@ WaveshareEPaper7P5InV2 = waveshare_epaper_ns.class_( | ||||
| WaveshareEPaper7P5InV2alt = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper7P5InV2alt", WaveshareEPaper | ||||
| ) | ||||
| WaveshareEPaper7P5InV2P = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper7P5InV2P", WaveshareEPaper | ||||
| ) | ||||
| WaveshareEPaper7P5InHDB = waveshare_epaper_ns.class_( | ||||
|     "WaveshareEPaper7P5InHDB", WaveshareEPaper | ||||
| ) | ||||
| @@ -130,13 +142,17 @@ MODELS = { | ||||
|     "2.70inv2": ("b", WaveshareEPaper2P7InV2), | ||||
|     "2.90in-b": ("b", WaveshareEPaper2P9InB), | ||||
|     "2.90in-bv3": ("b", WaveshareEPaper2P9InBV3), | ||||
|     "gdey029t94": ("c", GDEY029T94), | ||||
|     "2.90inv2-r2": ("c", WaveshareEPaper2P9InV2R2), | ||||
|     "2.90in-d": ("b", WaveshareEPaper2P9InD), | ||||
|     "2.90in-dke": ("c", WaveshareEPaper2P9InDKE), | ||||
|     "gdey042t81": ("c", GDEY042T81), | ||||
|     "4.20in": ("b", WaveshareEPaper4P2In), | ||||
|     "4.20in-bv2": ("b", WaveshareEPaper4P2InBV2), | ||||
|     "4.20in-bv2-bwr": ("b", WaveshareEPaper4P2InBV2BWR), | ||||
|     "5.83in": ("b", WaveshareEPaper5P8In), | ||||
|     "5.83inv2": ("b", WaveshareEPaper5P8InV2), | ||||
|     "7.30in-f": ("b", WaveshareEPaper7P3InF), | ||||
|     "7.50in": ("b", WaveshareEPaper7P5In), | ||||
|     "7.50in-bv2": ("b", WaveshareEPaper7P5InBV2), | ||||
|     "7.50in-bv3": ("b", WaveshareEPaper7P5InBV3), | ||||
| @@ -144,6 +160,7 @@ MODELS = { | ||||
|     "7.50in-bc": ("b", WaveshareEPaper7P5InBC), | ||||
|     "7.50inv2": ("b", WaveshareEPaper7P5InV2), | ||||
|     "7.50inv2alt": ("b", WaveshareEPaper7P5InV2alt), | ||||
|     "7.50inv2p": ("c", WaveshareEPaper7P5InV2P), | ||||
|     "7.50in-hd-b": ("b", WaveshareEPaper7P5InHDB), | ||||
|     "2.13in-ttgo-dke": ("c", WaveshareEPaper2P13InDKE), | ||||
|     "2.13inv3": ("c", WaveshareEPaper2P13InV3), | ||||
|   | ||||
| @@ -87,7 +87,11 @@ void WaveshareEPaper2P13InV3::send_reset_() { | ||||
| } | ||||
|  | ||||
| void WaveshareEPaper2P13InV3::setup() { | ||||
|   setup_pins_(); | ||||
|   this->init_internal_(this->get_buffer_length_()); | ||||
|   this->setup_pins_(); | ||||
|   this->spi_setup(); | ||||
|   this->reset_(); | ||||
|  | ||||
|   delay(20); | ||||
|   this->send_reset_(); | ||||
|   // as a one-off delay this is not worth working around. | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include "esphome/core/application.h" | ||||
| #include "esphome/core/helpers.h" | ||||
| #include <cinttypes> | ||||
| #include <bitset> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace waveshare_epaper { | ||||
| @@ -110,8 +111,14 @@ static const uint8_t PARTIAL_UPD_2IN9_LUT[PARTIAL_UPD_2IN9_LUT_SIZE] = | ||||
| }; | ||||
| // clang-format on | ||||
|  | ||||
| void WaveshareEPaperBase::setup_pins_() { | ||||
| void WaveshareEPaperBase::setup() { | ||||
|   this->init_internal_(this->get_buffer_length_()); | ||||
|   this->setup_pins_(); | ||||
|   this->spi_setup(); | ||||
|   this->reset_(); | ||||
|   this->initialize(); | ||||
| } | ||||
| void WaveshareEPaperBase::setup_pins_() { | ||||
|   this->dc_pin_->setup();  // OUTPUT | ||||
|   this->dc_pin_->digital_write(false); | ||||
|   if (this->reset_pin_ != nullptr) { | ||||
| @@ -121,9 +128,6 @@ void WaveshareEPaperBase::setup_pins_() { | ||||
|   if (this->busy_pin_ != nullptr) { | ||||
|     this->busy_pin_->setup();  // INPUT | ||||
|   } | ||||
|   this->spi_setup(); | ||||
|  | ||||
|   this->reset_(); | ||||
| } | ||||
| float WaveshareEPaperBase::get_setup_priority() const { return setup_priority::PROCESSOR; } | ||||
| void WaveshareEPaperBase::command(uint8_t value) { | ||||
| @@ -173,6 +177,87 @@ void WaveshareEPaper::fill(Color color) { | ||||
|   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) | ||||
|     this->buffer_[i] = fill; | ||||
| } | ||||
| void WaveshareEPaper7C::setup() { | ||||
|   this->init_internal_7c_(this->get_buffer_length_()); | ||||
|   this->setup_pins_(); | ||||
|   this->spi_setup(); | ||||
|   this->reset_(); | ||||
|   this->initialize(); | ||||
| } | ||||
| void WaveshareEPaper7C::init_internal_7c_(uint32_t buffer_length) { | ||||
|   ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE); | ||||
|   uint32_t small_buffer_length = buffer_length / NUM_BUFFERS; | ||||
|  | ||||
|   for (int i = 0; i < NUM_BUFFERS; i++) { | ||||
|     this->buffers_[i] = allocator.allocate(small_buffer_length); | ||||
|     if (this->buffers_[i] == nullptr) { | ||||
|       ESP_LOGE(TAG, "Could not allocate buffer %d for display!", i); | ||||
|       for (auto &buffer : this->buffers_) { | ||||
|         allocator.deallocate(buffer, small_buffer_length); | ||||
|         buffer = nullptr; | ||||
|       } | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   this->clear(); | ||||
| } | ||||
| uint8_t WaveshareEPaper7C::color_to_hex(Color color) { | ||||
|   uint8_t hex_code; | ||||
|   if (color.red > 127) { | ||||
|     if (color.green > 170) { | ||||
|       if (color.blue > 127) { | ||||
|         hex_code = 0x1;  // White | ||||
|       } else { | ||||
|         hex_code = 0x5;  // Yellow | ||||
|       } | ||||
|     } else if (color.green > 85) { | ||||
|       hex_code = 0x6;  // Orange | ||||
|     } else { | ||||
|       hex_code = 0x4;  // Red (or Magenta) | ||||
|     } | ||||
|   } else { | ||||
|     if (color.green > 127) { | ||||
|       if (color.blue > 127) { | ||||
|         hex_code = 0x3;  // Cyan -> Blue | ||||
|       } else { | ||||
|         hex_code = 0x2;  // Green | ||||
|       } | ||||
|     } else { | ||||
|       if (color.blue > 127) { | ||||
|         hex_code = 0x3;  // Blue | ||||
|       } else { | ||||
|         hex_code = 0x0;  // Black | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return hex_code; | ||||
| } | ||||
| void WaveshareEPaper7C::fill(Color color) { | ||||
|   uint8_t pixel_color; | ||||
|   if (color.is_on()) { | ||||
|     pixel_color = this->color_to_hex(color); | ||||
|   } else { | ||||
|     pixel_color = 0x1; | ||||
|   } | ||||
|  | ||||
|   if (this->buffers_[0] == nullptr) { | ||||
|     ESP_LOGE(TAG, "Buffer unavailable!"); | ||||
|   } else { | ||||
|     uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS; | ||||
|     for (auto &buffer : this->buffers_) { | ||||
|       for (uint32_t buffer_pos = 0; buffer_pos < small_buffer_length; buffer_pos += 3) { | ||||
|         // We store 8 bitset<3> in 3 bytes | ||||
|         // | byte 1 | byte 2 | byte 3 | | ||||
|         // |aaabbbaa|abbbaaab|bbaaabbb| | ||||
|         buffer[buffer_pos + 0] = pixel_color << 5 | pixel_color << 2 | pixel_color >> 1; | ||||
|         buffer[buffer_pos + 1] = pixel_color << 7 | pixel_color << 4 | pixel_color << 1 | pixel_color >> 2; | ||||
|         buffer[buffer_pos + 2] = pixel_color << 6 | pixel_color << 3 | pixel_color << 0; | ||||
|       } | ||||
|       App.feed_wdt(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 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) | ||||
|     return; | ||||
| @@ -193,6 +278,9 @@ uint32_t WaveshareEPaper::get_buffer_length_() { | ||||
| uint32_t WaveshareEPaperBWR::get_buffer_length_() { | ||||
|   return this->get_width_controller() * this->get_height_internal() / 4u; | ||||
| }  // black and red buffer | ||||
| uint32_t WaveshareEPaper7C::get_buffer_length_() { | ||||
|   return this->get_width_controller() * this->get_height_internal() / 8u * 3u; | ||||
| }  // 7 colors buffer, 1 pixel = 3 bits, we will store 8 pixels in 24 bits = 3 bytes | ||||
|  | ||||
| void WaveshareEPaperBWR::fill(Color color) { | ||||
|   this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); | ||||
| @@ -219,7 +307,33 @@ void HOT WaveshareEPaperBWR::draw_absolute_pixel_internal(int x, int y, Color co | ||||
|     this->buffer_[pos + buf_half_len] &= ~(0x80 >> subpos); | ||||
|   } | ||||
| } | ||||
| void HOT WaveshareEPaper7C::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) | ||||
|     return; | ||||
|  | ||||
|   uint8_t pixel_bits = this->color_to_hex(color); | ||||
|   uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS; | ||||
|   uint32_t pixel_position = x + y * this->get_width_controller(); | ||||
|   uint32_t first_bit_position = pixel_position * 3; | ||||
|   uint32_t byte_position = first_bit_position / 8u; | ||||
|   uint32_t byte_subposition = first_bit_position % 8u; | ||||
|   uint32_t buffer_position = byte_position / small_buffer_length; | ||||
|   uint32_t buffer_subposition = byte_position % small_buffer_length; | ||||
|  | ||||
|   if (byte_subposition <= 5) { | ||||
|     this->buffers_[buffer_position][buffer_subposition] = | ||||
|         (this->buffers_[buffer_position][buffer_subposition] & (0xFF ^ (0b111 << (5 - byte_subposition)))) | | ||||
|         (pixel_bits << (5 - byte_subposition)); | ||||
|   } else { | ||||
|     this->buffers_[buffer_position][buffer_subposition + 0] = | ||||
|         (this->buffers_[buffer_position][buffer_subposition + 0] & (0xFF ^ (0b111 >> (byte_subposition - 5)))) | | ||||
|         (pixel_bits >> (byte_subposition - 5)); | ||||
|  | ||||
|     this->buffers_[buffer_position][buffer_subposition + 1] = (this->buffers_[buffer_position][buffer_subposition + 1] & | ||||
|                                                                (0xFF ^ (0xFF & (0b111 << (13 - byte_subposition))))) | | ||||
|                                                               (pixel_bits << (13 - byte_subposition)); | ||||
|   } | ||||
| } | ||||
| void WaveshareEPaperBase::start_command_() { | ||||
|   this->dc_pin_->digital_write(false); | ||||
|   this->enable(); | ||||
| @@ -1677,9 +1791,82 @@ int WaveshareEPaper2P9InV2R2::get_width_controller() { return this->get_width_in | ||||
| void WaveshareEPaper2P9InV2R2::set_full_update_every(uint32_t full_update_every) { | ||||
|   this->full_update_every_ = full_update_every; | ||||
| } | ||||
| // ======================================================== | ||||
| //     Good Display 2.9in black/white | ||||
| // Datasheet: | ||||
| //  - https://files.seeedstudio.com/wiki/Other_Display/29-epaper/GDEY029T94.pdf | ||||
| //  - | ||||
| //  https://github.com/Allen-Kuang/e-ink_Demo/blob/main/2.9%20inch%20E-paper%20-%20monocolor%20128x296/example/Display_EPD_W21.cpp | ||||
| // ======================================================== | ||||
|  | ||||
| void GDEY029T94::initialize() { | ||||
|   // EPD hardware init start | ||||
|   this->reset_(); | ||||
|  | ||||
|   this->wait_until_idle_(); | ||||
|   this->command(0x12);  // SWRESET | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   this->command(0x01);  // Driver output control | ||||
|   this->data((this->get_height_internal() - 1) % 256); | ||||
|   this->data((this->get_height_internal() - 1) / 256); | ||||
|   this->data(0x00); | ||||
|  | ||||
|   this->command(0x11);  // data entry mode | ||||
|   this->data(0x03); | ||||
|  | ||||
|   this->command(0x44);  // set Ram-X address start/end position | ||||
|   this->data(0x00); | ||||
|   this->data(this->get_width_internal() / 8 - 1); | ||||
|  | ||||
|   this->command(0x45);  // set Ram-Y address start/end position | ||||
|   this->data(0x00); | ||||
|   this->data(0x00); | ||||
|   this->data((this->get_height_internal() - 1) % 256); | ||||
|   this->data((this->get_height_internal() - 1) / 256); | ||||
|  | ||||
|   this->command(0x3C);  // BorderWavefrom | ||||
|   this->data(0x05); | ||||
|  | ||||
|   this->command(0x21);  //  Display update control | ||||
|   this->data(0x00); | ||||
|   this->data(0x80); | ||||
|  | ||||
|   this->command(0x18);  // Read built-in temperature sensor | ||||
|   this->data(0x80); | ||||
|  | ||||
|   this->command(0x4E);  // set RAM x address count to 0; | ||||
|   this->data(0x00); | ||||
|   this->command(0x4F);  // set RAM y address count to 0X199; | ||||
|   this->command(0x00); | ||||
|   this->command(0x00); | ||||
|   this->wait_until_idle_(); | ||||
| } | ||||
| void HOT GDEY029T94::display() { | ||||
|   this->command(0x24);  // write RAM for black(0)/white (1) | ||||
|   this->start_data_(); | ||||
|   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) { | ||||
|     this->write_byte(this->buffer_[i]); | ||||
|   } | ||||
|   this->end_data_(); | ||||
|   this->command(0x22);  // Display Update Control | ||||
|   this->data(0xF7); | ||||
|   this->command(0x20);  // Activate Display Update Sequence | ||||
|   this->wait_until_idle_(); | ||||
| } | ||||
| int GDEY029T94::get_width_internal() { return 128; } | ||||
| int GDEY029T94::get_height_internal() { return 296; } | ||||
| void GDEY029T94::dump_config() { | ||||
|   LOG_DISPLAY("", "E-Paper (Good Display)", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Model: 2.9in GDEY029T94"); | ||||
|   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); | ||||
| } | ||||
|  | ||||
| // ======================================================== | ||||
| //     Good Display 2.9in black/white/grey | ||||
| //     Good Display 2.9in black/white | ||||
| // 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 | ||||
| @@ -2096,6 +2283,206 @@ void GDEW0154M09::dump_config() { | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
| } | ||||
|  | ||||
| // ======================================================== | ||||
| //     Good Display 4.2in black/white GDEY042T81 (SSD1683) | ||||
| // Product page: | ||||
| //  - https://www.good-display.com/product/386.html | ||||
| // Datasheet: | ||||
| //  - https://v4.cecdn.yun300.cn/100001_1909185148/GDEY042T81.pdf | ||||
| //  - https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF | ||||
| // Reference code from GoodDisplay: | ||||
| //  - https://www.good-display.com/companyfile/1572.html (2024-08-01 15:40:41) | ||||
| // Other reference code: | ||||
| //  - https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp | ||||
| // ======================================================== | ||||
|  | ||||
| void GDEY042T81::initialize() { | ||||
|   this->init_display_(); | ||||
|   ESP_LOGD(TAG, "Initialization complete, set the display to deep sleep"); | ||||
|   this->deep_sleep(); | ||||
| } | ||||
|  | ||||
| // conflicting documentation / examples regarding reset timings | ||||
| //   https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF -> 10ms | ||||
| //   GD sample code (Display_EPD_W21.cpp, see above) -> 10 ms | ||||
| //   https://v4.cecdn.yun300.cn/100001_1909185148/GDEY042T81.pdf (section 14.2) -> 0.2ms (200us) | ||||
| //   https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L351 | ||||
| //   -> 10ms | ||||
| //  10 ms seems to work, so we use this | ||||
| GDEY042T81::GDEY042T81() { this->reset_duration_ = 10; } | ||||
|  | ||||
| void GDEY042T81::reset_() { | ||||
|   if (this->reset_pin_ != nullptr) { | ||||
|     this->reset_pin_->digital_write(false); | ||||
|     delay(reset_duration_);  // NOLINT | ||||
|     this->reset_pin_->digital_write(true); | ||||
|     delay(reset_duration_);  // NOLINT | ||||
|   } | ||||
| } | ||||
|  | ||||
| void GDEY042T81::init_display_() { | ||||
|   this->reset_(); | ||||
|  | ||||
|   this->wait_until_idle_(); | ||||
|   this->command(0x12);  // SWRESET | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   // Specify number of lines for the driver: 300 (MUX 300) | ||||
|   // https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF (section 8.1) | ||||
|   // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L354 | ||||
|   this->command(0x01);  //  driver output control | ||||
|   this->data(0x2B);     // (height - 1) % 256 | ||||
|   this->data(0x01);     // (height - 1) / 256 | ||||
|   this->data(0x00); | ||||
|  | ||||
|   // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L360 | ||||
|   this->command(0x3C);  // BorderWaveform | ||||
|   this->data(0x01); | ||||
|   this->command(0x18);  // Read built-in temperature sensor | ||||
|   this->data(0x80); | ||||
|  | ||||
|   // GD sample code (Display_EPD_W21.cpp@90ff) | ||||
|   this->command(0x11);  // data entry mode | ||||
|   this->data(0x03); | ||||
|   // set windows (0,0,400,300) | ||||
|   this->command(0x44);  // set Ram-X address start/end position | ||||
|   this->data(0); | ||||
|   this->data(0x31);  // (width / 8 -1) | ||||
|  | ||||
|   this->command(0x45);  //  set Ram-y address start/end position | ||||
|   this->data(0); | ||||
|   this->data(0); | ||||
|   this->data(0x2B);  // (height - 1) % 256 | ||||
|   this->data(0x01);  // (height - 1) / 256 | ||||
|  | ||||
|   // set cursor (0,0) | ||||
|   this->command(0x4E);  // set RAM x address count to 0; | ||||
|   this->data(0); | ||||
|   this->command(0x4F);  // set RAM y address count to 0; | ||||
|   this->data(0); | ||||
|   this->data(0); | ||||
|  | ||||
|   this->wait_until_idle_(); | ||||
| } | ||||
|  | ||||
| // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L366 | ||||
| void GDEY042T81::update_full_() { | ||||
|   this->command(0x21);  // display update control | ||||
|   this->data(0x40);     // bypass RED as 0 | ||||
|   this->data(0x00);     // single chip application | ||||
|  | ||||
|   // only ever do a fast update because slow updates are only relevant | ||||
|   // for lower operating temperatures | ||||
|   // see | ||||
|   // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_290_GDEY029T94.h#L30 | ||||
|   // | ||||
|   // Should slow/fast updates be made configurable similar to how GxEPD2 does it? No idea if anyone would need it... | ||||
|   this->command(0x1A);  // Write to temperature register | ||||
|   this->data(0x6E); | ||||
|   this->command(0x22); | ||||
|   this->data(0xd7); | ||||
|  | ||||
|   this->command(0x20); | ||||
|   this->wait_until_idle_(); | ||||
| } | ||||
|  | ||||
| // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L389 | ||||
| void GDEY042T81::update_part_() { | ||||
|   this->command(0x21);  // display update control | ||||
|   this->data(0x00);     // RED normal | ||||
|   this->data(0x00);     // single chip application | ||||
|  | ||||
|   this->command(0x22); | ||||
|   this->data(0xfc); | ||||
|  | ||||
|   this->command(0x20); | ||||
|   this->wait_until_idle_(); | ||||
| } | ||||
|  | ||||
| void HOT GDEY042T81::display() { | ||||
|   ESP_LOGD(TAG, "Wake up the display"); | ||||
|   this->init_display_(); | ||||
|  | ||||
|   if (!this->wait_until_idle_()) { | ||||
|     this->status_set_warning(); | ||||
|     ESP_LOGE(TAG, "Failed to perform update, display is busy"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // basic code structure copied from WaveshareEPaper2P9InV2R2 | ||||
|   if (this->full_update_every_ == 1) { | ||||
|     ESP_LOGD(TAG, "Full update"); | ||||
|     // do single full update | ||||
|     this->command(0x24); | ||||
|     this->start_data_(); | ||||
|     this->write_array(this->buffer_, this->get_buffer_length_()); | ||||
|     this->end_data_(); | ||||
|  | ||||
|     // TurnOnDisplay | ||||
|     this->update_full_(); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // if (this->full_update_every_ == 1 || | ||||
|   if (this->at_update_ == 0) { | ||||
|     ESP_LOGD(TAG, "Update"); | ||||
|     // do base update | ||||
|     this->command(0x24); | ||||
|     this->start_data_(); | ||||
|     this->write_array(this->buffer_, this->get_buffer_length_()); | ||||
|     this->end_data_(); | ||||
|  | ||||
|     this->command(0x26); | ||||
|     this->start_data_(); | ||||
|     this->write_array(this->buffer_, this->get_buffer_length_()); | ||||
|     this->end_data_(); | ||||
|  | ||||
|     // TurnOnDisplay; | ||||
|     this->update_full_(); | ||||
|   } else { | ||||
|     // do partial update (full screen) | ||||
|     // no need to load a LUT for GoodDisplays as they seem to have the LUT onboard | ||||
|     // GD example code (Display_EPD_W21.cpp@283ff) | ||||
|     // | ||||
|     // not setting the BorderWaveform here again (contrary to the GD example) because according to | ||||
|     // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L358 | ||||
|     // it seems to be enough to set it during display initialization | ||||
|     ESP_LOGD(TAG, "Partial update"); | ||||
|     this->reset_(); | ||||
|     if (!this->wait_until_idle_()) { | ||||
|       this->status_set_warning(); | ||||
|       ESP_LOGE(TAG, "Failed to perform partial update, display is busy"); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     this->command(0x24); | ||||
|     this->start_data_(); | ||||
|     this->write_array(this->buffer_, this->get_buffer_length_()); | ||||
|     this->end_data_(); | ||||
|  | ||||
|     // TurnOnDisplay | ||||
|     this->update_part_(); | ||||
|   } | ||||
|  | ||||
|   this->at_update_ = (this->at_update_ + 1) % this->full_update_every_; | ||||
|   this->wait_until_idle_(); | ||||
|   ESP_LOGD(TAG, "Set the display back to deep sleep"); | ||||
|   this->deep_sleep(); | ||||
| } | ||||
| void GDEY042T81::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; } | ||||
| int GDEY042T81::get_width_internal() { return 400; } | ||||
| int GDEY042T81::get_height_internal() { return 300; } | ||||
| uint32_t GDEY042T81::idle_timeout_() { return 5000; } | ||||
| void GDEY042T81::dump_config() { | ||||
|   LOG_DISPLAY("", "GoodDisplay E-Paper", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Model: 4.2in B/W GDEY042T81"); | ||||
|   ESP_LOGCONFIG(TAG, "  Full Update Every: %" PRIu32, this->full_update_every_); | ||||
|   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); | ||||
| } | ||||
|  | ||||
| static const uint8_t LUT_VCOM_DC_4_2[] = { | ||||
|     0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x17, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x01, | ||||
|     0x00, 0x00, 0x01, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
| @@ -2274,6 +2661,64 @@ void WaveshareEPaper4P2InBV2::dump_config() { | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
| } | ||||
|  | ||||
| // ======================================================== | ||||
| //    4.20in Type B With Red colour support (LUT from OTP) | ||||
| // Datasheet: | ||||
| //  - https://www.waveshare.com/w/upload/2/20/4.2inch-e-paper-module-user-manual-en.pdf | ||||
| //  - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_4in2b_V2.c | ||||
| // The implementation is an adaptation of WaveshareEPaper4P2InBV2 class | ||||
| // ======================================================== | ||||
| void WaveshareEPaper4P2InBV2BWR::initialize() { | ||||
|   // these exact timings are required for a proper reset/init | ||||
|   this->reset_pin_->digital_write(false); | ||||
|   delay(2); | ||||
|   this->reset_pin_->digital_write(true); | ||||
|   delay(200);  // NOLINT | ||||
|  | ||||
|   // COMMAND POWER ON | ||||
|   this->command(0x04); | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   // COMMAND PANEL SETTING | ||||
|   this->command(0x00); | ||||
|   this->data(0x0f);  // LUT from OTP | ||||
| } | ||||
|  | ||||
| void HOT WaveshareEPaper4P2InBV2BWR::display() { | ||||
|   const uint32_t buf_len = this->get_buffer_length_() / 2u; | ||||
|  | ||||
|   this->command(0x10);  // Send BW data Transmission | ||||
|   delay(2);             // Delay to prevent Watchdog error | ||||
|   for (uint32_t i = 0; i < buf_len; ++i) { | ||||
|     this->data(this->buffer_[i]); | ||||
|   } | ||||
|  | ||||
|   this->command(0x13);  // Send red data Transmission | ||||
|   delay(2);             // Delay to prevent Watchdog error | ||||
|   for (uint32_t i = 0; i < buf_len; ++i) { | ||||
|     // Red color need to flip bit from the buffer. Otherwise, red will conqure the screen! | ||||
|     this->data(~this->buffer_[buf_len + i]); | ||||
|   } | ||||
|  | ||||
|   // COMMAND DISPLAY REFRESH | ||||
|   this->command(0x12); | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   // COMMAND POWER OFF | ||||
|   // NOTE: power off < deep sleep | ||||
|   this->command(0x02); | ||||
| } | ||||
| int WaveshareEPaper4P2InBV2BWR::get_width_internal() { return 400; } | ||||
| int WaveshareEPaper4P2InBV2BWR::get_height_internal() { return 300; } | ||||
| void WaveshareEPaper4P2InBV2BWR::dump_config() { | ||||
|   LOG_DISPLAY("", "Waveshare E-Paper", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Model: 4.2in (B V2) BWR-Mode"); | ||||
|   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); | ||||
| } | ||||
|  | ||||
| void WaveshareEPaper5P8In::initialize() { | ||||
|   // COMMAND POWER SETTING | ||||
|   this->command(0x01); | ||||
| @@ -2862,6 +3307,195 @@ void WaveshareEPaper7P5In::dump_config() { | ||||
|   LOG_PIN("  Busy Pin: ", this->busy_pin_); | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
| } | ||||
| void WaveshareEPaper7P3InF::initialize() { | ||||
|   if (this->buffers_[0] == nullptr) { | ||||
|     ESP_LOGE(TAG, "Buffer unavailable!"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   this->reset_(); | ||||
|   delay(20); | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   // COMMAND CMDH | ||||
|   this->command(0xAA); | ||||
|   this->data(0x49); | ||||
|   this->data(0x55); | ||||
|   this->data(0x20); | ||||
|   this->data(0x08); | ||||
|   this->data(0x09); | ||||
|   this->data(0x18); | ||||
|  | ||||
|   this->command(0x01); | ||||
|   this->data(0x3F); | ||||
|   this->data(0x00); | ||||
|   this->data(0x32); | ||||
|   this->data(0x2A); | ||||
|   this->data(0x0E); | ||||
|   this->data(0x2A); | ||||
|  | ||||
|   this->command(0x00); | ||||
|   this->data(0x5F); | ||||
|   this->data(0x69); | ||||
|  | ||||
|   this->command(0x03); | ||||
|   this->data(0x00); | ||||
|   this->data(0x54); | ||||
|   this->data(0x00); | ||||
|   this->data(0x44); | ||||
|  | ||||
|   this->command(0x05); | ||||
|   this->data(0x40); | ||||
|   this->data(0x1F); | ||||
|   this->data(0x1F); | ||||
|   this->data(0x2C); | ||||
|  | ||||
|   this->command(0x06); | ||||
|   this->data(0x6F); | ||||
|   this->data(0x1F); | ||||
|   this->data(0x1F); | ||||
|   this->data(0x22); | ||||
|  | ||||
|   this->command(0x08); | ||||
|   this->data(0x6F); | ||||
|   this->data(0x1F); | ||||
|   this->data(0x1F); | ||||
|   this->data(0x22); | ||||
|  | ||||
|   // COMMAND IPC | ||||
|   this->command(0x13); | ||||
|   this->data(0x00); | ||||
|   this->data(0x04); | ||||
|  | ||||
|   this->command(0x30); | ||||
|   this->data(0x3C); | ||||
|  | ||||
|   // COMMAND TSE | ||||
|   this->command(0x41); | ||||
|   this->data(0x00); | ||||
|  | ||||
|   this->command(0x50); | ||||
|   this->data(0x3F); | ||||
|  | ||||
|   this->command(0x60); | ||||
|   this->data(0x02); | ||||
|   this->data(0x00); | ||||
|  | ||||
|   this->command(0x61); | ||||
|   this->data(0x03); | ||||
|   this->data(0x20); | ||||
|   this->data(0x01); | ||||
|   this->data(0xE0); | ||||
|  | ||||
|   this->command(0x82); | ||||
|   this->data(0x1E); | ||||
|  | ||||
|   this->command(0x84); | ||||
|   this->data(0x00); | ||||
|  | ||||
|   // COMMAND AGID | ||||
|   this->command(0x86); | ||||
|   this->data(0x00); | ||||
|  | ||||
|   this->command(0xE3); | ||||
|   this->data(0x2F); | ||||
|  | ||||
|   // COMMAND CCSET | ||||
|   this->command(0xE0); | ||||
|   this->data(0x00); | ||||
|  | ||||
|   // COMMAND TSSET | ||||
|   this->command(0xE6); | ||||
|   this->data(0x00); | ||||
|  | ||||
|   ESP_LOGI(TAG, "Display initialized successfully"); | ||||
| } | ||||
| void HOT WaveshareEPaper7P3InF::display() { | ||||
|   if (this->buffers_[0] == nullptr) { | ||||
|     ESP_LOGE(TAG, "Buffer unavailable!"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // INITIALIZATION | ||||
|   ESP_LOGI(TAG, "Initialise the display"); | ||||
|   this->initialize(); | ||||
|  | ||||
|   // COMMAND DATA START TRANSMISSION | ||||
|   ESP_LOGI(TAG, "Sending data to the display"); | ||||
|   this->command(0x10); | ||||
|   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(); | ||||
|   } | ||||
|  | ||||
|   // COMMAND POWER ON | ||||
|   ESP_LOGI(TAG, "Power on the display"); | ||||
|   this->command(0x04); | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   // COMMAND REFRESH SCREEN | ||||
|   ESP_LOGI(TAG, "Refresh the display"); | ||||
|   this->command(0x12); | ||||
|   this->data(0x00); | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   // COMMAND POWER OFF | ||||
|   ESP_LOGI(TAG, "Power off the display"); | ||||
|   this->command(0x02); | ||||
|   this->data(0x00); | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   ESP_LOGI(TAG, "Set the display to deep sleep"); | ||||
|   this->command(0x07); | ||||
|   this->data(0xA5); | ||||
| } | ||||
| int WaveshareEPaper7P3InF::get_width_internal() { return 800; } | ||||
| int WaveshareEPaper7P3InF::get_height_internal() { return 480; } | ||||
| uint32_t WaveshareEPaper7P3InF::idle_timeout_() { return 35000; } | ||||
| void WaveshareEPaper7P3InF::dump_config() { | ||||
|   LOG_DISPLAY("", "Waveshare E-Paper", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Model: 7.3in-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 WaveshareEPaper7P3InF::wait_until_idle_() { | ||||
|   if (this->busy_pin_ == nullptr) { | ||||
|     return true; | ||||
|   } | ||||
|   const uint32_t start = millis(); | ||||
|   while (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); | ||||
|   } | ||||
|   delay(200);  // NOLINT | ||||
|   return true; | ||||
| } | ||||
| bool WaveshareEPaper7P5InV2::wait_until_idle_() { | ||||
|   if (this->busy_pin_ == nullptr) { | ||||
|     return true; | ||||
| @@ -3100,6 +3734,209 @@ void WaveshareEPaper7P5InV2alt::dump_config() { | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
| } | ||||
|  | ||||
| /* 7.50inV2 with partial and fast refresh */ | ||||
| bool WaveshareEPaper7P5InV2P::wait_until_idle_() { | ||||
|   if (this->busy_pin_ == nullptr) { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   const uint32_t start = millis(); | ||||
|   while (this->busy_pin_->digital_read()) { | ||||
|     this->command(0x71); | ||||
|     if (millis() - start > this->idle_timeout_()) { | ||||
|       ESP_LOGE(TAG, "Timeout while displaying image!"); | ||||
|       return false; | ||||
|     } | ||||
|     App.feed_wdt(); | ||||
|     delay(10); | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| void WaveshareEPaper7P5InV2P::reset_() { | ||||
|   if (this->reset_pin_ != nullptr) { | ||||
|     this->reset_pin_->digital_write(true); | ||||
|     delay(20); | ||||
|     this->reset_pin_->digital_write(false); | ||||
|     delay(2); | ||||
|     this->reset_pin_->digital_write(true); | ||||
|     delay(20); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void WaveshareEPaper7P5InV2P::turn_on_display_() { | ||||
|   this->command(0x12); | ||||
|   delay(100);  // NOLINT | ||||
|   this->wait_until_idle_(); | ||||
| } | ||||
|  | ||||
| void WaveshareEPaper7P5InV2P::initialize() { | ||||
|   this->reset_(); | ||||
|  | ||||
|   // COMMAND POWER SETTING | ||||
|   this->command(0x01); | ||||
|   this->data(0x07); | ||||
|   this->data(0x07); | ||||
|   this->data(0x3f); | ||||
|   this->data(0x3f); | ||||
|  | ||||
|   // COMMAND BOOSTER SOFT START | ||||
|   this->command(0x06); | ||||
|   this->data(0x17); | ||||
|   this->data(0x17); | ||||
|   this->data(0x28); | ||||
|   this->data(0x17); | ||||
|  | ||||
|   // COMMAND POWER DRIVER HAT UP | ||||
|   this->command(0x04); | ||||
|   delay(100);  // NOLINT | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   // COMMAND PANEL SETTING | ||||
|   this->command(0x00); | ||||
|   this->data(0x1F); | ||||
|  | ||||
|   // COMMAND RESOLUTION SETTING | ||||
|   this->command(0x61); | ||||
|   this->data(0x03); | ||||
|   this->data(0x20); | ||||
|   this->data(0x01); | ||||
|   this->data(0xE0); | ||||
|  | ||||
|   // COMMAND DUAL SPI MM_EN, DUSPI_EN | ||||
|   this->command(0x15); | ||||
|   this->data(0x00); | ||||
|  | ||||
|   // COMMAND VCOM AND DATA INTERVAL SETTING | ||||
|   this->command(0x50); | ||||
|   this->data(0x10); | ||||
|   this->data(0x07); | ||||
|  | ||||
|   // COMMAND TCON SETTING | ||||
|   this->command(0x60); | ||||
|   this->data(0x22); | ||||
|  | ||||
|   // COMMAND ENABLE FAST UPDATE | ||||
|   this->command(0xE0); | ||||
|   this->data(0x02); | ||||
|   this->command(0xE5); | ||||
|   this->data(0x5A); | ||||
|  | ||||
|   // COMMAND POWER DRIVER HAT DOWN | ||||
|   this->command(0x02); | ||||
| } | ||||
|  | ||||
| void HOT WaveshareEPaper7P5InV2P::display() { | ||||
|   uint32_t buf_len = this->get_buffer_length_(); | ||||
|  | ||||
|   // COMMAND POWER ON | ||||
|   ESP_LOGI(TAG, "Power on the display and hat"); | ||||
|  | ||||
|   this->command(0x04); | ||||
|   delay(200);  // NOLINT | ||||
|   this->wait_until_idle_(); | ||||
|  | ||||
|   if (this->full_update_every_ == 1) { | ||||
|     this->command(0x13); | ||||
|     for (uint32_t i = 0; i < buf_len; i++) { | ||||
|       this->data(~(this->buffer_[i])); | ||||
|     } | ||||
|  | ||||
|     this->turn_on_display_(); | ||||
|  | ||||
|     this->command(0x02); | ||||
|     this->wait_until_idle_(); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   this->command(0x50); | ||||
|   this->data(0xA9); | ||||
|   this->data(0x07); | ||||
|  | ||||
|   if (this->at_update_ == 0) { | ||||
|     // Enable fast refresh | ||||
|     this->command(0xE5); | ||||
|     this->data(0x5A); | ||||
|  | ||||
|     this->command(0x92); | ||||
|  | ||||
|     this->command(0x10); | ||||
|     delay(2); | ||||
|     for (uint32_t i = 0; i < buf_len; i++) { | ||||
|       this->data(~(this->buffer_[i])); | ||||
|     } | ||||
|  | ||||
|     delay(100);  // NOLINT | ||||
|     this->wait_until_idle_(); | ||||
|  | ||||
|     this->command(0x13); | ||||
|     delay(2); | ||||
|     for (uint32_t i = 0; i < buf_len; i++) { | ||||
|       this->data(this->buffer_[i]); | ||||
|     } | ||||
|  | ||||
|     delay(100);  // NOLINT | ||||
|     this->wait_until_idle_(); | ||||
|  | ||||
|     this->turn_on_display_(); | ||||
|  | ||||
|   } else { | ||||
|     // Enable partial refresh | ||||
|     this->command(0xE5); | ||||
|     this->data(0x6E); | ||||
|  | ||||
|     // Activate partial refresh and set window bounds | ||||
|     this->command(0x91); | ||||
|     this->command(0x90); | ||||
|  | ||||
|     this->data(0x00); | ||||
|     this->data(0x00); | ||||
|     this->data((get_width_internal() - 1) >> 8 & 0xFF); | ||||
|     this->data((get_width_internal() - 1) & 0xFF); | ||||
|  | ||||
|     this->data(0x00); | ||||
|     this->data(0x00); | ||||
|     this->data((get_height_internal() - 1) >> 8 & 0xFF); | ||||
|     this->data((get_height_internal() - 1) & 0xFF); | ||||
|  | ||||
|     this->data(0x01); | ||||
|  | ||||
|     this->command(0x13); | ||||
|     delay(2); | ||||
|     for (uint32_t i = 0; i < buf_len; i++) { | ||||
|       this->data(this->buffer_[i]); | ||||
|     } | ||||
|  | ||||
|     delay(100);  // NOLINT | ||||
|     this->wait_until_idle_(); | ||||
|  | ||||
|     this->turn_on_display_(); | ||||
|   } | ||||
|  | ||||
|   ESP_LOGV(TAG, "Before command(0x02) (>> power off)"); | ||||
|   this->command(0x02); | ||||
|   this->wait_until_idle_(); | ||||
|   ESP_LOGV(TAG, "After command(0x02) (>> power off)"); | ||||
|  | ||||
|   this->at_update_ = (this->at_update_ + 1) % this->full_update_every_; | ||||
| } | ||||
|  | ||||
| int WaveshareEPaper7P5InV2P::get_width_internal() { return 800; } | ||||
| int WaveshareEPaper7P5InV2P::get_height_internal() { return 480; } | ||||
| uint32_t WaveshareEPaper7P5InV2P::idle_timeout_() { return 10000; } | ||||
| void WaveshareEPaper7P5InV2P::dump_config() { | ||||
|   LOG_DISPLAY("", "Waveshare E-Paper", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Model: 7.50inv2p"); | ||||
|   ESP_LOGCONFIG(TAG, "  Full Update Every: %" PRIu32, this->full_update_every_); | ||||
|   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); | ||||
| } | ||||
| void WaveshareEPaper7P5InV2P::set_full_update_every(uint32_t full_update_every) { | ||||
|   this->full_update_every_ = full_update_every; | ||||
| } | ||||
|  | ||||
| /* 7.50in-bc */ | ||||
| void WaveshareEPaper7P5InBC::initialize() { | ||||
|   /* The command sequence is similar to the 7P5In display but differs in subtle ways | ||||
|   | ||||
| @@ -27,10 +27,7 @@ class WaveshareEPaperBase : public display::DisplayBuffer, | ||||
|  | ||||
|   void update() override; | ||||
|  | ||||
|   void setup() override { | ||||
|     this->setup_pins_(); | ||||
|     this->initialize(); | ||||
|   } | ||||
|   void setup() override; | ||||
|  | ||||
|   void on_safe_shutdown() override; | ||||
|  | ||||
| @@ -86,6 +83,23 @@ class WaveshareEPaperBWR : public WaveshareEPaperBase { | ||||
|   uint32_t get_buffer_length_() override; | ||||
| }; | ||||
|  | ||||
| class WaveshareEPaper7C : public WaveshareEPaperBase { | ||||
|  public: | ||||
|   uint8_t color_to_hex(Color color); | ||||
|   void fill(Color color) override; | ||||
|  | ||||
|   display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } | ||||
|  | ||||
|  protected: | ||||
|   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||
|   uint32_t get_buffer_length_() override; | ||||
|   void setup() override; | ||||
|   void init_internal_7c_(uint32_t buffer_length); | ||||
|  | ||||
|   static const int NUM_BUFFERS = 10; | ||||
|   uint8_t *buffers_[NUM_BUFFERS]; | ||||
| }; | ||||
|  | ||||
| enum WaveshareEPaperTypeAModel { | ||||
|   WAVESHARE_EPAPER_1_54_IN = 0, | ||||
|   WAVESHARE_EPAPER_1_54_IN_V2, | ||||
| @@ -160,6 +174,7 @@ enum WaveshareEPaperTypeBModel { | ||||
|   WAVESHARE_EPAPER_2_7_IN_B_V2, | ||||
|   WAVESHARE_EPAPER_4_2_IN, | ||||
|   WAVESHARE_EPAPER_4_2_IN_B_V2, | ||||
|   WAVESHARE_EPAPER_7_3_IN_F, | ||||
|   WAVESHARE_EPAPER_7_5_IN, | ||||
|   WAVESHARE_EPAPER_7_5_INV2, | ||||
|   WAVESHARE_EPAPER_7_5_IN_B_V2, | ||||
| @@ -277,6 +292,25 @@ class GDEW029T5 : public WaveshareEPaper { | ||||
|   uint8_t *old_buffer_{nullptr}; | ||||
| }; | ||||
|  | ||||
| class GDEY029T94 : public WaveshareEPaper { | ||||
|  public: | ||||
|   void initialize() override; | ||||
|  | ||||
|   void display() override; | ||||
|  | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void deep_sleep() override { | ||||
|     this->command(0x10);  // Enter deep sleep | ||||
|     this->data(0x01); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   int get_width_internal() override; | ||||
|  | ||||
|   int get_height_internal() override; | ||||
| }; | ||||
|  | ||||
| class WaveshareEPaper2P7InV2 : public WaveshareEPaper { | ||||
|  public: | ||||
|   void initialize() override; | ||||
| @@ -447,6 +481,43 @@ class WaveshareEPaper2P9InD : public WaveshareEPaper { | ||||
|   int get_height_internal() override; | ||||
| }; | ||||
|  | ||||
| class GDEY042T81 : public WaveshareEPaper { | ||||
|  public: | ||||
|   GDEY042T81(); | ||||
|  | ||||
|   void initialize() override; | ||||
|  | ||||
|   void display() override; | ||||
|  | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void deep_sleep() override { | ||||
|     // COMMAND POWER OFF | ||||
|     this->command(0x22); | ||||
|     this->data(0x83); | ||||
|     this->command(0x20); | ||||
|     // COMMAND DEEP SLEEP | ||||
|     this->command(0x10); | ||||
|     this->data(0x01); | ||||
|   } | ||||
|  | ||||
|   void set_full_update_every(uint32_t full_update_every); | ||||
|  | ||||
|  protected: | ||||
|   uint32_t full_update_every_{30}; | ||||
|   uint32_t at_update_{0}; | ||||
|  | ||||
|   int get_width_internal() override; | ||||
|   int get_height_internal() override; | ||||
|   uint32_t idle_timeout_() override; | ||||
|  | ||||
|  private: | ||||
|   void reset_(); | ||||
|   void update_full_(); | ||||
|   void update_part_(); | ||||
|   void init_display_(); | ||||
| }; | ||||
|  | ||||
| class WaveshareEPaper4P2In : public WaveshareEPaper { | ||||
|  public: | ||||
|   void initialize() override; | ||||
| @@ -518,6 +589,34 @@ class WaveshareEPaper4P2InBV2 : public WaveshareEPaper { | ||||
|   int get_height_internal() override; | ||||
| }; | ||||
|  | ||||
| class WaveshareEPaper4P2InBV2BWR : public WaveshareEPaperBWR { | ||||
|  public: | ||||
|   void initialize() override; | ||||
|  | ||||
|   void display() override; | ||||
|  | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void deep_sleep() override { | ||||
|     // COMMAND VCOM AND DATA INTERVAL SETTING | ||||
|     this->command(0x50); | ||||
|     this->data(0xF7);  // border floating | ||||
|  | ||||
|     // COMMAND POWER OFF | ||||
|     this->command(0x02); | ||||
|     this->wait_until_idle_(); | ||||
|  | ||||
|     // COMMAND DEEP SLEEP | ||||
|     this->command(0x07); | ||||
|     this->data(0xA5);  // check code | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   int get_width_internal() override; | ||||
|  | ||||
|   int get_height_internal() override; | ||||
| }; | ||||
|  | ||||
| class WaveshareEPaper5P8In : public WaveshareEPaper { | ||||
|  public: | ||||
|   void initialize() override; | ||||
| @@ -584,6 +683,39 @@ class WaveshareEPaper5P8InV2 : public WaveshareEPaper { | ||||
|   int get_height_internal() override; | ||||
| }; | ||||
|  | ||||
| class WaveshareEPaper7P3InF : 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 { ; } | ||||
|  | ||||
|   bool wait_until_idle_(); | ||||
|  | ||||
|   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 { | ||||
|  public: | ||||
|   void initialize() override; | ||||
| @@ -775,6 +907,43 @@ class WaveshareEPaper7P5InV2alt : public WaveshareEPaper7P5InV2 { | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| class WaveshareEPaper7P5InV2P : public WaveshareEPaper { | ||||
|  public: | ||||
|   bool wait_until_idle_(); | ||||
|  | ||||
|   void initialize() override; | ||||
|  | ||||
|   void display() override; | ||||
|  | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void deep_sleep() override { | ||||
|     // COMMAND POWER OFF | ||||
|     this->command(0x02); | ||||
|     this->wait_until_idle_(); | ||||
|     // COMMAND DEEP SLEEP | ||||
|     this->command(0x07); | ||||
|     this->data(0xA5);  // check byte | ||||
|   } | ||||
|  | ||||
|   void set_full_update_every(uint32_t full_update_every); | ||||
|  | ||||
|  protected: | ||||
|   int get_width_internal() override; | ||||
|  | ||||
|   int get_height_internal() override; | ||||
|  | ||||
|   uint32_t idle_timeout_() override; | ||||
|  | ||||
|   uint32_t full_update_every_{30}; | ||||
|   uint32_t at_update_{0}; | ||||
|  | ||||
|  private: | ||||
|   void reset_(); | ||||
|  | ||||
|   void turn_on_display_(); | ||||
| }; | ||||
|  | ||||
| class WaveshareEPaper7P5InHDB : public WaveshareEPaper { | ||||
|  public: | ||||
|   void initialize() override; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| """Constants used by esphome.""" | ||||
|  | ||||
| __version__ = "2025.2.0-dev" | ||||
| __version__ = "2025.3.0-dev" | ||||
|  | ||||
| ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" | ||||
| VALID_SUBSTITUTIONS_CHARACTERS = ( | ||||
|   | ||||
| @@ -12,7 +12,7 @@ pyserial==3.5 | ||||
| platformio==6.1.16  # When updating platformio, also update Dockerfile | ||||
| esptool==4.7.0 | ||||
| click==8.1.7 | ||||
| esphome-dashboard==20241217.1 | ||||
| esphome-dashboard==20250212.0 | ||||
| aioesphomeapi==24.6.2 | ||||
| zeroconf==0.143.0 | ||||
| puremagic==1.27 | ||||
|   | ||||
| @@ -121,6 +121,14 @@ number: | ||||
|     max_value: 100 | ||||
|     step: 1 | ||||
|  | ||||
| valve: | ||||
|   - platform: template | ||||
|     name: "Template Valve" | ||||
|     lambda: |- | ||||
|       return VALVE_OPEN; | ||||
|     optimistic: true | ||||
|     has_position: true | ||||
|  | ||||
| prometheus: | ||||
|   include_internal: true | ||||
|   relabel: | ||||
|   | ||||
| @@ -463,6 +463,26 @@ display: | ||||
|     lambda: |- | ||||
|       it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||
|  | ||||
|   - platform: waveshare_epaper | ||||
|     id: epd_gdew042t81 | ||||
|     model: gdey042t81 | ||||
|     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} | ||||
|     full_update_every: 30 | ||||
|     lambda: |- | ||||
|       it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||
|  | ||||
|   # 4.2 inch displays | ||||
|   - platform: waveshare_epaper | ||||
|     id: epd_4_20 | ||||
| @@ -502,6 +522,25 @@ display: | ||||
|     lambda: |- | ||||
|       it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||
|  | ||||
|   - platform: waveshare_epaper | ||||
|     id: epd_4_20in_bv2_bwr | ||||
|     model: 4.20in-bv2-bwr | ||||
|     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 | ||||
|   - platform: waveshare_epaper | ||||
|     id: epd_5_83 | ||||
| @@ -675,6 +714,26 @@ display: | ||||
|     lambda: |- | ||||
|       it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||
|  | ||||
|   - platform: waveshare_epaper | ||||
|     id: epd_7_50inv2p | ||||
|     model: 7.50inv2p | ||||
|     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} | ||||
|     full_update_every: 30 | ||||
|     lambda: |- | ||||
|       it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||
|  | ||||
|   - platform: waveshare_epaper | ||||
|     id: epd_7_50hdb | ||||
|     model: 7.50in-hd-b | ||||
|   | ||||
		Reference in New Issue
	
	Block a user