mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Merge branch 'dev' of https://github.com/esphome/esphome into dev
This commit is contained in:
		
							
								
								
									
										23
									
								
								esphome/components/color/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								esphome/components/color/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | from esphome import config_validation as cv | ||||||
|  | from esphome import codegen as cg | ||||||
|  | from esphome.const import CONF_BLUE, CONF_GREEN, CONF_ID, CONF_RED, CONF_WHITE | ||||||
|  |  | ||||||
|  | ColorStruct = cg.esphome_ns.struct('Color') | ||||||
|  |  | ||||||
|  | MULTI_CONF = True | ||||||
|  | CONFIG_SCHEMA = cv.Schema({ | ||||||
|  |     cv.Required(CONF_ID): cv.declare_id(ColorStruct), | ||||||
|  |     cv.Optional(CONF_RED, default=0.0): cv.percentage, | ||||||
|  |     cv.Optional(CONF_GREEN, default=0.0): cv.percentage, | ||||||
|  |     cv.Optional(CONF_BLUE, default=0.0): cv.percentage, | ||||||
|  |     cv.Optional(CONF_WHITE, default=0.0): cv.percentage, | ||||||
|  | }).extend(cv.COMPONENT_SCHEMA) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def to_code(config): | ||||||
|  |     cg.variable(config[CONF_ID], cg.StructInitializer( | ||||||
|  |         ColorStruct, | ||||||
|  |         ('r', config[CONF_RED]), | ||||||
|  |         ('g', config[CONF_GREEN]), | ||||||
|  |         ('b', config[CONF_BLUE]), | ||||||
|  |         ('w', config[CONF_WHITE]))) | ||||||
| @@ -7,8 +7,8 @@ namespace display { | |||||||
|  |  | ||||||
| static const char *TAG = "display"; | static const char *TAG = "display"; | ||||||
|  |  | ||||||
| const uint8_t COLOR_OFF = 0; | const Color COLOR_OFF = 0; | ||||||
| const uint8_t COLOR_ON = 1; | const Color COLOR_ON = 1; | ||||||
|  |  | ||||||
| void DisplayBuffer::init_internal_(uint32_t buffer_length) { | void DisplayBuffer::init_internal_(uint32_t buffer_length) { | ||||||
|   this->buffer_ = new uint8_t[buffer_length]; |   this->buffer_ = new uint8_t[buffer_length]; | ||||||
| @@ -18,7 +18,7 @@ void DisplayBuffer::init_internal_(uint32_t buffer_length) { | |||||||
|   } |   } | ||||||
|   this->clear(); |   this->clear(); | ||||||
| } | } | ||||||
| void DisplayBuffer::fill(int color) { this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); } | void DisplayBuffer::fill(Color color) { this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); } | ||||||
| void DisplayBuffer::clear() { this->fill(COLOR_OFF); } | void DisplayBuffer::clear() { this->fill(COLOR_OFF); } | ||||||
| int DisplayBuffer::get_width() { | int DisplayBuffer::get_width() { | ||||||
|   switch (this->rotation_) { |   switch (this->rotation_) { | ||||||
| @@ -43,7 +43,7 @@ int DisplayBuffer::get_height() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| void DisplayBuffer::set_rotation(DisplayRotation rotation) { this->rotation_ = rotation; } | void DisplayBuffer::set_rotation(DisplayRotation rotation) { this->rotation_ = rotation; } | ||||||
| void HOT DisplayBuffer::draw_pixel_at(int x, int y, int color) { | void HOT DisplayBuffer::draw_pixel_at(int x, int y, Color color) { | ||||||
|   switch (this->rotation_) { |   switch (this->rotation_) { | ||||||
|     case DISPLAY_ROTATION_0_DEGREES: |     case DISPLAY_ROTATION_0_DEGREES: | ||||||
|       break; |       break; | ||||||
| @@ -63,7 +63,7 @@ void HOT DisplayBuffer::draw_pixel_at(int x, int y, int color) { | |||||||
|   this->draw_absolute_pixel_internal(x, y, color); |   this->draw_absolute_pixel_internal(x, y, color); | ||||||
|   App.feed_wdt(); |   App.feed_wdt(); | ||||||
| } | } | ||||||
| void HOT DisplayBuffer::line(int x1, int y1, int x2, int y2, int color) { | void HOT DisplayBuffer::line(int x1, int y1, int x2, int y2, Color color) { | ||||||
|   const int32_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1; |   const int32_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1; | ||||||
|   const int32_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1; |   const int32_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1; | ||||||
|   int32_t err = dx + dy; |   int32_t err = dx + dy; | ||||||
| @@ -83,29 +83,29 @@ void HOT DisplayBuffer::line(int x1, int y1, int x2, int y2, int color) { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void HOT DisplayBuffer::horizontal_line(int x, int y, int width, int color) { | void HOT DisplayBuffer::horizontal_line(int x, int y, int width, Color color) { | ||||||
|   // Future: Could be made more efficient by manipulating buffer directly in certain rotations. |   // Future: Could be made more efficient by manipulating buffer directly in certain rotations. | ||||||
|   for (int i = x; i < x + width; i++) |   for (int i = x; i < x + width; i++) | ||||||
|     this->draw_pixel_at(i, y, color); |     this->draw_pixel_at(i, y, color); | ||||||
| } | } | ||||||
| void HOT DisplayBuffer::vertical_line(int x, int y, int height, int color) { | void HOT DisplayBuffer::vertical_line(int x, int y, int height, Color color) { | ||||||
|   // Future: Could be made more efficient by manipulating buffer directly in certain rotations. |   // Future: Could be made more efficient by manipulating buffer directly in certain rotations. | ||||||
|   for (int i = y; i < y + height; i++) |   for (int i = y; i < y + height; i++) | ||||||
|     this->draw_pixel_at(x, i, color); |     this->draw_pixel_at(x, i, color); | ||||||
| } | } | ||||||
| void DisplayBuffer::rectangle(int x1, int y1, int width, int height, int color) { | void DisplayBuffer::rectangle(int x1, int y1, int width, int height, Color color) { | ||||||
|   this->horizontal_line(x1, y1, width, color); |   this->horizontal_line(x1, y1, width, color); | ||||||
|   this->horizontal_line(x1, y1 + height - 1, width, color); |   this->horizontal_line(x1, y1 + height - 1, width, color); | ||||||
|   this->vertical_line(x1, y1, height, color); |   this->vertical_line(x1, y1, height, color); | ||||||
|   this->vertical_line(x1 + width - 1, y1, height, color); |   this->vertical_line(x1 + width - 1, y1, height, color); | ||||||
| } | } | ||||||
| void DisplayBuffer::filled_rectangle(int x1, int y1, int width, int height, int color) { | void DisplayBuffer::filled_rectangle(int x1, int y1, int width, int height, Color color) { | ||||||
|   // Future: Use vertical_line and horizontal_line methods depending on rotation to reduce memory accesses. |   // Future: Use vertical_line and horizontal_line methods depending on rotation to reduce memory accesses. | ||||||
|   for (int i = y1; i < y1 + height; i++) { |   for (int i = y1; i < y1 + height; i++) { | ||||||
|     this->horizontal_line(x1, i, width, color); |     this->horizontal_line(x1, i, width, color); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void HOT DisplayBuffer::circle(int center_x, int center_xy, int radius, int color) { | void HOT DisplayBuffer::circle(int center_x, int center_xy, int radius, Color color) { | ||||||
|   int dx = -radius; |   int dx = -radius; | ||||||
|   int dy = 0; |   int dy = 0; | ||||||
|   int err = 2 - 2 * radius; |   int err = 2 - 2 * radius; | ||||||
| @@ -128,7 +128,7 @@ void HOT DisplayBuffer::circle(int center_x, int center_xy, int radius, int colo | |||||||
|     } |     } | ||||||
|   } while (dx <= 0); |   } while (dx <= 0); | ||||||
| } | } | ||||||
| void DisplayBuffer::filled_circle(int center_x, int center_y, int radius, int color) { | void DisplayBuffer::filled_circle(int center_x, int center_y, int radius, Color color) { | ||||||
|   int dx = -int32_t(radius); |   int dx = -int32_t(radius); | ||||||
|   int dy = 0; |   int dy = 0; | ||||||
|   int err = 2 - 2 * radius; |   int err = 2 - 2 * radius; | ||||||
| @@ -155,7 +155,7 @@ void DisplayBuffer::filled_circle(int center_x, int center_y, int radius, int co | |||||||
|   } while (dx <= 0); |   } while (dx <= 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| void DisplayBuffer::print(int x, int y, Font *font, int color, TextAlign align, const char *text) { | void DisplayBuffer::print(int x, int y, Font *font, Color color, TextAlign align, const char *text) { | ||||||
|   int x_start, y_start; |   int x_start, y_start; | ||||||
|   int width, height; |   int width, height; | ||||||
|   this->get_text_bounds(x, y, text, font, align, &x_start, &y_start, &width, &height); |   this->get_text_bounds(x, y, text, font, align, &x_start, &y_start, &width, &height); | ||||||
| @@ -197,16 +197,34 @@ void DisplayBuffer::print(int x, int y, Font *font, int color, TextAlign align, | |||||||
|     i += match_length; |     i += match_length; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void DisplayBuffer::vprintf_(int x, int y, Font *font, int color, TextAlign align, const char *format, va_list arg) { | void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign align, const char *format, va_list arg) { | ||||||
|   char buffer[256]; |   char buffer[256]; | ||||||
|   int ret = vsnprintf(buffer, sizeof(buffer), format, arg); |   int ret = vsnprintf(buffer, sizeof(buffer), format, arg); | ||||||
|   if (ret > 0) |   if (ret > 0) | ||||||
|     this->print(x, y, font, color, align, buffer); |     this->print(x, y, font, color, align, buffer); | ||||||
| } | } | ||||||
| void DisplayBuffer::image(int x, int y, Image *image) { | void DisplayBuffer::image(int x, int y, Image *image) { this->image(x, y, COLOR_ON, image); } | ||||||
|  | void DisplayBuffer::image(int x, int y, Color color, Image *image, bool invert) { | ||||||
|  |   if (image->get_type() == BINARY) { | ||||||
|     for (int img_x = 0; img_x < image->get_width(); img_x++) { |     for (int img_x = 0; img_x < image->get_width(); img_x++) { | ||||||
|       for (int img_y = 0; img_y < image->get_height(); img_y++) { |       for (int img_y = 0; img_y < image->get_height(); img_y++) { | ||||||
|       this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? COLOR_ON : COLOR_OFF); |         if (invert) | ||||||
|  |           this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? COLOR_OFF : color); | ||||||
|  |         else | ||||||
|  |           this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? color : COLOR_OFF); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } else if (image->get_type() == GRAYSCALE4) { | ||||||
|  |     for (int img_x = 0; img_x < image->get_width(); img_x++) { | ||||||
|  |       for (int img_y = 0; img_y < image->get_height(); img_y++) { | ||||||
|  |         this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale4_pixel(img_x, img_y)); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } else if (image->get_type() == RGB565) { | ||||||
|  |     for (int img_x = 0; img_x < image->get_width(); img_x++) { | ||||||
|  |       for (int img_y = 0; img_y < image->get_height(); img_y++) { | ||||||
|  |         this->draw_pixel_at(x + img_x, y + img_y, image->get_color_pixel(img_x, img_y)); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -248,7 +266,7 @@ void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, | |||||||
|       break; |       break; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void DisplayBuffer::print(int x, int y, Font *font, int color, const char *text) { | void DisplayBuffer::print(int x, int y, Font *font, Color color, const char *text) { | ||||||
|   this->print(x, y, font, color, TextAlign::TOP_LEFT, text); |   this->print(x, y, font, color, TextAlign::TOP_LEFT, text); | ||||||
| } | } | ||||||
| void DisplayBuffer::print(int x, int y, Font *font, TextAlign align, const char *text) { | void DisplayBuffer::print(int x, int y, Font *font, TextAlign align, const char *text) { | ||||||
| @@ -257,13 +275,13 @@ void DisplayBuffer::print(int x, int y, Font *font, TextAlign align, const char | |||||||
| void DisplayBuffer::print(int x, int y, Font *font, const char *text) { | void DisplayBuffer::print(int x, int y, Font *font, const char *text) { | ||||||
|   this->print(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, text); |   this->print(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, text); | ||||||
| } | } | ||||||
| void DisplayBuffer::printf(int x, int y, Font *font, int color, TextAlign align, const char *format, ...) { | void DisplayBuffer::printf(int x, int y, Font *font, Color color, TextAlign align, const char *format, ...) { | ||||||
|   va_list arg; |   va_list arg; | ||||||
|   va_start(arg, format); |   va_start(arg, format); | ||||||
|   this->vprintf_(x, y, font, color, align, format, arg); |   this->vprintf_(x, y, font, color, align, format, arg); | ||||||
|   va_end(arg); |   va_end(arg); | ||||||
| } | } | ||||||
| void DisplayBuffer::printf(int x, int y, Font *font, int color, const char *format, ...) { | void DisplayBuffer::printf(int x, int y, Font *font, Color color, const char *format, ...) { | ||||||
|   va_list arg; |   va_list arg; | ||||||
|   va_start(arg, format); |   va_start(arg, format); | ||||||
|   this->vprintf_(x, y, font, color, TextAlign::TOP_LEFT, format, arg); |   this->vprintf_(x, y, font, color, TextAlign::TOP_LEFT, format, arg); | ||||||
| @@ -306,14 +324,14 @@ void DisplayBuffer::do_update_() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| #ifdef USE_TIME | #ifdef USE_TIME | ||||||
| void DisplayBuffer::strftime(int x, int y, Font *font, int color, TextAlign align, const char *format, | void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, | ||||||
|                              time::ESPTime time) { |                              time::ESPTime time) { | ||||||
|   char buffer[64]; |   char buffer[64]; | ||||||
|   size_t ret = time.strftime(buffer, sizeof(buffer), format); |   size_t ret = time.strftime(buffer, sizeof(buffer), format); | ||||||
|   if (ret > 0) |   if (ret > 0) | ||||||
|     this->print(x, y, font, color, align, buffer); |     this->print(x, y, font, color, align, buffer); | ||||||
| } | } | ||||||
| void DisplayBuffer::strftime(int x, int y, Font *font, int color, const char *format, time::ESPTime time) { | void DisplayBuffer::strftime(int x, int y, Font *font, Color color, const char *format, time::ESPTime time) { | ||||||
|   this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time); |   this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time); | ||||||
| } | } | ||||||
| void DisplayBuffer::strftime(int x, int y, Font *font, TextAlign align, const char *format, time::ESPTime time) { | void DisplayBuffer::strftime(int x, int y, Font *font, TextAlign align, const char *format, time::ESPTime time) { | ||||||
| @@ -431,10 +449,30 @@ bool Image::get_pixel(int x, int y) const { | |||||||
|   const uint32_t pos = x + y * width_8; |   const uint32_t pos = x + y * width_8; | ||||||
|   return pgm_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); |   return pgm_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); | ||||||
| } | } | ||||||
|  | int Image::get_color_pixel(int x, int y) const { | ||||||
|  |   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||||
|  |     return 0; | ||||||
|  |  | ||||||
|  |   const uint32_t pos = (x + y * this->width_) * 2; | ||||||
|  |   int color = (pgm_read_byte(this->data_start_ + pos) << 8) + (pgm_read_byte(this->data_start_ + pos + 1)); | ||||||
|  |   return color; | ||||||
|  | } | ||||||
|  | int Image::get_grayscale4_pixel(int x, int y) const { | ||||||
|  |   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||||
|  |     return 0; | ||||||
|  |   const uint32_t pos = (x + y * this->width_) / 2; | ||||||
|  |   // 2 = number of pixels per byte, 4 = pixel shift | ||||||
|  |   uint8_t shift = (x % 2) * 4; | ||||||
|  |   int color = (pgm_read_byte(this->data_start_ + pos) >> shift) & 0x0f; | ||||||
|  |   return color; | ||||||
|  | } | ||||||
| int Image::get_width() const { return this->width_; } | int Image::get_width() const { return this->width_; } | ||||||
| int Image::get_height() const { return this->height_; } | int Image::get_height() const { return this->height_; } | ||||||
|  | ImageType Image::get_type() const { return this->type_; } | ||||||
| Image::Image(const uint8_t *data_start, int width, int height) | Image::Image(const uint8_t *data_start, int width, int height) | ||||||
|     : width_(width), height_(height), data_start_(data_start) {} |     : width_(width), height_(height), data_start_(data_start) {} | ||||||
|  | Image::Image(const uint8_t *data_start, int width, int height, int type) | ||||||
|  |     : width_(width), height_(height), type_((ImageType) type), data_start_(data_start) {} | ||||||
|  |  | ||||||
| DisplayPage::DisplayPage(const display_writer_t &writer) : writer_(writer) {} | DisplayPage::DisplayPage(const display_writer_t &writer) : writer_(writer) {} | ||||||
| void DisplayPage::show() { this->parent_->show_page(this); } | void DisplayPage::show() { this->parent_->show_page(this); } | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/defines.h" | #include "esphome/core/defines.h" | ||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
|  | #include "esphome/core/color.h" | ||||||
|  |  | ||||||
| #ifdef USE_TIME | #ifdef USE_TIME | ||||||
| #include "esphome/components/time/real_time_clock.h" | #include "esphome/components/time/real_time_clock.h" | ||||||
| @@ -63,9 +64,11 @@ enum class TextAlign { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| /// Turn the pixel OFF. | /// Turn the pixel OFF. | ||||||
| extern const uint8_t COLOR_OFF; | extern const Color COLOR_OFF; | ||||||
| /// Turn the pixel ON. | /// Turn the pixel ON. | ||||||
| extern const uint8_t COLOR_ON; | extern const Color COLOR_ON; | ||||||
|  |  | ||||||
|  | enum ImageType { BINARY = 0, GRAYSCALE4 = 1, RGB565 = 2 }; | ||||||
|  |  | ||||||
| enum DisplayRotation { | enum DisplayRotation { | ||||||
|   DISPLAY_ROTATION_0_DEGREES = 0, |   DISPLAY_ROTATION_0_DEGREES = 0, | ||||||
| @@ -91,7 +94,7 @@ using display_writer_t = std::function<void(DisplayBuffer &)>; | |||||||
| class DisplayBuffer { | class DisplayBuffer { | ||||||
|  public: |  public: | ||||||
|   /// Fill the entire screen with the given color. |   /// Fill the entire screen with the given color. | ||||||
|   virtual void fill(int color); |   virtual void fill(Color color); | ||||||
|   /// Clear the entire screen by filling it with OFF pixels. |   /// Clear the entire screen by filling it with OFF pixels. | ||||||
|   void clear(); |   void clear(); | ||||||
|  |  | ||||||
| @@ -100,29 +103,29 @@ class DisplayBuffer { | |||||||
|   /// Get the height of the image in pixels with rotation applied. |   /// Get the height of the image in pixels with rotation applied. | ||||||
|   int get_height(); |   int get_height(); | ||||||
|   /// Set a single pixel at the specified coordinates to the given color. |   /// Set a single pixel at the specified coordinates to the given color. | ||||||
|   void draw_pixel_at(int x, int y, int color = COLOR_ON); |   void draw_pixel_at(int x, int y, Color color = COLOR_ON); | ||||||
|  |  | ||||||
|   /// Draw a straight line from the point [x1,y1] to [x2,y2] with the given color. |   /// Draw a straight line from the point [x1,y1] to [x2,y2] with the given color. | ||||||
|   void line(int x1, int y1, int x2, int y2, int color = COLOR_ON); |   void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON); | ||||||
|  |  | ||||||
|   /// Draw a horizontal line from the point [x,y] to [x+width,y] with the given color. |   /// Draw a horizontal line from the point [x,y] to [x+width,y] with the given color. | ||||||
|   void horizontal_line(int x, int y, int width, int color = COLOR_ON); |   void horizontal_line(int x, int y, int width, Color color = COLOR_ON); | ||||||
|  |  | ||||||
|   /// Draw a vertical line from the point [x,y] to [x,y+width] with the given color. |   /// Draw a vertical line from the point [x,y] to [x,y+width] with the given color. | ||||||
|   void vertical_line(int x, int y, int height, int color = COLOR_ON); |   void vertical_line(int x, int y, int height, Color color = COLOR_ON); | ||||||
|  |  | ||||||
|   /// Draw the outline of a rectangle with the top left point at [x1,y1] and the bottom right point at |   /// Draw the outline of a rectangle with the top left point at [x1,y1] and the bottom right point at | ||||||
|   /// [x1+width,y1+height]. |   /// [x1+width,y1+height]. | ||||||
|   void rectangle(int x1, int y1, int width, int height, int color = COLOR_ON); |   void rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON); | ||||||
|  |  | ||||||
|   /// Fill a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+width,y1+height]. |   /// Fill a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+width,y1+height]. | ||||||
|   void filled_rectangle(int x1, int y1, int width, int height, int color = COLOR_ON); |   void filled_rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON); | ||||||
|  |  | ||||||
|   /// Draw the outline of a circle centered around [center_x,center_y] with the radius radius with the given color. |   /// Draw the outline of a circle centered around [center_x,center_y] with the radius radius with the given color. | ||||||
|   void circle(int center_x, int center_xy, int radius, int color = COLOR_ON); |   void circle(int center_x, int center_xy, int radius, Color color = COLOR_ON); | ||||||
|  |  | ||||||
|   /// Fill a circle centered around [center_x,center_y] with the radius radius with the given color. |   /// Fill a circle centered around [center_x,center_y] with the radius radius with the given color. | ||||||
|   void filled_circle(int center_x, int center_y, int radius, int color = COLOR_ON); |   void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON); | ||||||
|  |  | ||||||
|   /** Print `text` with the anchor point at [x,y] with `font`. |   /** Print `text` with the anchor point at [x,y] with `font`. | ||||||
|    * |    * | ||||||
| @@ -133,7 +136,7 @@ class DisplayBuffer { | |||||||
|    * @param align The alignment of the text. |    * @param align The alignment of the text. | ||||||
|    * @param text The text to draw. |    * @param text The text to draw. | ||||||
|    */ |    */ | ||||||
|   void print(int x, int y, Font *font, int color, TextAlign align, const char *text); |   void print(int x, int y, Font *font, Color color, TextAlign align, const char *text); | ||||||
|  |  | ||||||
|   /** Print `text` with the top left at [x,y] with `font`. |   /** Print `text` with the top left at [x,y] with `font`. | ||||||
|    * |    * | ||||||
| @@ -143,7 +146,7 @@ class DisplayBuffer { | |||||||
|    * @param color The color to draw the text with. |    * @param color The color to draw the text with. | ||||||
|    * @param text The text to draw. |    * @param text The text to draw. | ||||||
|    */ |    */ | ||||||
|   void print(int x, int y, Font *font, int color, const char *text); |   void print(int x, int y, Font *font, Color color, const char *text); | ||||||
|  |  | ||||||
|   /** Print `text` with the anchor point at [x,y] with `font`. |   /** Print `text` with the anchor point at [x,y] with `font`. | ||||||
|    * |    * | ||||||
| @@ -174,7 +177,7 @@ class DisplayBuffer { | |||||||
|    * @param format The format to use. |    * @param format The format to use. | ||||||
|    * @param ... The arguments to use for the text formatting. |    * @param ... The arguments to use for the text formatting. | ||||||
|    */ |    */ | ||||||
|   void printf(int x, int y, Font *font, int color, TextAlign align, const char *format, ...) |   void printf(int x, int y, Font *font, Color color, TextAlign align, const char *format, ...) | ||||||
|       __attribute__((format(printf, 7, 8))); |       __attribute__((format(printf, 7, 8))); | ||||||
|  |  | ||||||
|   /** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`. |   /** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`. | ||||||
| @@ -186,7 +189,7 @@ class DisplayBuffer { | |||||||
|    * @param format The format to use. |    * @param format The format to use. | ||||||
|    * @param ... The arguments to use for the text formatting. |    * @param ... The arguments to use for the text formatting. | ||||||
|    */ |    */ | ||||||
|   void printf(int x, int y, Font *font, int color, const char *format, ...) __attribute__((format(printf, 6, 7))); |   void printf(int x, int y, Font *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7))); | ||||||
|  |  | ||||||
|   /** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`. |   /** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`. | ||||||
|    * |    * | ||||||
| @@ -220,7 +223,7 @@ class DisplayBuffer { | |||||||
|    * @param format The strftime format to use. |    * @param format The strftime format to use. | ||||||
|    * @param time The time to format. |    * @param time The time to format. | ||||||
|    */ |    */ | ||||||
|   void strftime(int x, int y, Font *font, int color, TextAlign align, const char *format, time::ESPTime time) |   void strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, time::ESPTime time) | ||||||
|       __attribute__((format(strftime, 7, 0))); |       __attribute__((format(strftime, 7, 0))); | ||||||
|  |  | ||||||
|   /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. |   /** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`. | ||||||
| @@ -232,7 +235,7 @@ class DisplayBuffer { | |||||||
|    * @param format The strftime format to use. |    * @param format The strftime format to use. | ||||||
|    * @param time The time to format. |    * @param time The time to format. | ||||||
|    */ |    */ | ||||||
|   void strftime(int x, int y, Font *font, int color, const char *format, time::ESPTime time) |   void strftime(int x, int y, Font *font, Color color, const char *format, time::ESPTime time) | ||||||
|       __attribute__((format(strftime, 6, 0))); |       __attribute__((format(strftime, 6, 0))); | ||||||
|  |  | ||||||
|   /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. |   /** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`. | ||||||
| @@ -261,6 +264,7 @@ class DisplayBuffer { | |||||||
|  |  | ||||||
|   /// Draw the `image` with the top-left corner at [x,y] to the screen. |   /// Draw the `image` with the top-left corner at [x,y] to the screen. | ||||||
|   void image(int x, int y, Image *image); |   void image(int x, int y, Image *image); | ||||||
|  |   void image(int x, int y, Color color, Image *image, bool invert = false); | ||||||
|  |  | ||||||
|   /** Get the text bounds of the given string. |   /** Get the text bounds of the given string. | ||||||
|    * |    * | ||||||
| @@ -290,9 +294,9 @@ class DisplayBuffer { | |||||||
|   void set_rotation(DisplayRotation rotation); |   void set_rotation(DisplayRotation rotation); | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void vprintf_(int x, int y, Font *font, int color, TextAlign align, const char *format, va_list arg); |   void vprintf_(int x, int y, Font *font, Color color, TextAlign align, const char *format, va_list arg); | ||||||
|  |  | ||||||
|   virtual void draw_absolute_pixel_internal(int x, int y, int color) = 0; |   virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0; | ||||||
|  |  | ||||||
|   virtual int get_height_internal() = 0; |   virtual int get_height_internal() = 0; | ||||||
|  |  | ||||||
| @@ -378,13 +382,18 @@ class Font { | |||||||
| class Image { | class Image { | ||||||
|  public: |  public: | ||||||
|   Image(const uint8_t *data_start, int width, int height); |   Image(const uint8_t *data_start, int width, int height); | ||||||
|  |   Image(const uint8_t *data_start, int width, int height, int type); | ||||||
|   bool get_pixel(int x, int y) const; |   bool get_pixel(int x, int y) const; | ||||||
|  |   int get_color_pixel(int x, int y) const; | ||||||
|  |   int get_grayscale4_pixel(int x, int y) const; | ||||||
|   int get_width() const; |   int get_width() const; | ||||||
|   int get_height() const; |   int get_height() const; | ||||||
|  |   ImageType get_type() const; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   int width_; |   int width_; | ||||||
|   int height_; |   int height_; | ||||||
|  |   ImageType type_{BINARY}; | ||||||
|   const uint8_t *data_start_; |   const uint8_t *data_start_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,13 +4,15 @@ from esphome import core | |||||||
| from esphome.components import display, font | from esphome.components import display, font | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| from esphome.const import CONF_FILE, CONF_ID, CONF_RESIZE | from esphome.const import CONF_FILE, CONF_ID, CONF_RESIZE, CONF_TYPE | ||||||
| from esphome.core import CORE, HexInt | from esphome.core import CORE, HexInt | ||||||
| _LOGGER = logging.getLogger(__name__) | _LOGGER = logging.getLogger(__name__) | ||||||
|  |  | ||||||
| DEPENDENCIES = ['display'] | DEPENDENCIES = ['display'] | ||||||
| MULTI_CONF = True | MULTI_CONF = True | ||||||
|  |  | ||||||
|  | ImageType = {'binary': 0, 'grayscale4': 1, 'rgb565': 2} | ||||||
|  |  | ||||||
| Image_ = display.display_ns.class_('Image') | Image_ = display.display_ns.class_('Image') | ||||||
|  |  | ||||||
| CONF_RAW_DATA_ID = 'raw_data_id' | CONF_RAW_DATA_ID = 'raw_data_id' | ||||||
| @@ -19,6 +21,7 @@ IMAGE_SCHEMA = cv.Schema({ | |||||||
|     cv.Required(CONF_ID): cv.declare_id(Image_), |     cv.Required(CONF_ID): cv.declare_id(Image_), | ||||||
|     cv.Required(CONF_FILE): cv.file_, |     cv.Required(CONF_FILE): cv.file_, | ||||||
|     cv.Optional(CONF_RESIZE): cv.dimensions, |     cv.Optional(CONF_RESIZE): cv.dimensions, | ||||||
|  |     cv.Optional(CONF_TYPE): cv.string, | ||||||
|     cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), |     cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), | ||||||
| }) | }) | ||||||
|  |  | ||||||
| @@ -37,11 +40,45 @@ def to_code(config): | |||||||
|     if CONF_RESIZE in config: |     if CONF_RESIZE in config: | ||||||
|         image.thumbnail(config[CONF_RESIZE]) |         image.thumbnail(config[CONF_RESIZE]) | ||||||
|  |  | ||||||
|  |     if CONF_TYPE in config: | ||||||
|  |         if config[CONF_TYPE].startswith('GRAYSCALE4'): | ||||||
|  |             width, height = image.size | ||||||
|  |             image = image.convert('L', dither=Image.NONE) | ||||||
|  |             pixels = list(image.getdata()) | ||||||
|  |             data = [0 for _ in range(height * width // 2)] | ||||||
|  |             pos = 0 | ||||||
|  |             for pixnum, pix in enumerate(pixels): | ||||||
|  |                 pixshift = (pixnum % 2) * 4 | ||||||
|  |                 data[pos] |= (pix >> 4) << pixshift | ||||||
|  |                 if pixshift != 0: | ||||||
|  |                     pos += 1 | ||||||
|  |             rhs = [HexInt(x) for x in data] | ||||||
|  |             prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) | ||||||
|  |             cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['grayscale4']) | ||||||
|  |         elif config[CONF_TYPE].startswith('RGB565'): | ||||||
|  |             width, height = image.size | ||||||
|  |             image = image.convert('RGB') | ||||||
|  |             pixels = list(image.getdata()) | ||||||
|  |             data = [0 for _ in range(height * width * 2)] | ||||||
|  |             pos = 0 | ||||||
|  |             for pix in pixels: | ||||||
|  |                 r = (pix[0] >> 3) & 0x1F | ||||||
|  |                 g = (pix[1] >> 2) & 0x3F | ||||||
|  |                 b = (pix[2] >> 3) & 0x1F | ||||||
|  |                 p = (r << 11) + (g << 5) + b | ||||||
|  |                 data[pos] = (p >> 8) & 0xFF | ||||||
|  |                 pos += 1 | ||||||
|  |                 data[pos] = p & 0xFF | ||||||
|  |                 pos += 1 | ||||||
|  |             rhs = [HexInt(x) for x in data] | ||||||
|  |             prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) | ||||||
|  |             cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['rgb565']) | ||||||
|  |     else: | ||||||
|         image = image.convert('1', dither=Image.NONE) |         image = image.convert('1', dither=Image.NONE) | ||||||
|         width, height = image.size |         width, height = image.size | ||||||
|         if width > 500 or height > 500: |         if width > 500 or height > 500: | ||||||
|         _LOGGER.warning("The image you requested is very big. Please consider using the resize " |             _LOGGER.warning("The image you requested is very big. Please consider using" | ||||||
|                         "parameter") |                             " the resize parameter.") | ||||||
|         width8 = ((width + 7) // 8) * 8 |         width8 = ((width + 7) // 8) * 8 | ||||||
|         data = [0 for _ in range(height * width8 // 8)] |         data = [0 for _ in range(height * width8 // 8)] | ||||||
|         for y in range(height): |         for y in range(height): | ||||||
|   | |||||||
| @@ -120,7 +120,7 @@ void INA219Component::setup() { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   this->calibration_lsb_ = lsb; |   this->calibration_lsb_ = lsb; | ||||||
|   auto calibration = uint32_t(0.04096f / (0.0001 * lsb * this->shunt_resistance_ohm_)); |   auto calibration = uint32_t(0.04096f / (0.000001 * lsb * this->shunt_resistance_ohm_)); | ||||||
|   ESP_LOGV(TAG, "    Using LSB=%u calibration=%u", lsb, calibration); |   ESP_LOGV(TAG, "    Using LSB=%u calibration=%u", lsb, calibration); | ||||||
|   if (!this->write_byte_16(INA219_REGISTER_CALIBRATION, calibration)) { |   if (!this->write_byte_16(INA219_REGISTER_CALIBRATION, calibration)) { | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|   | |||||||
| @@ -100,7 +100,7 @@ void INA3221Component::update() { | |||||||
|         this->status_set_warning(); |         this->status_set_warning(); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       const float shunt_voltage_v = int16_t(raw) * 40.0f / 1000000.0f; |       const float shunt_voltage_v = int16_t(raw) * 40.0f / 8.0f / 1000000.0f; | ||||||
|       if (channel.shunt_voltage_sensor_ != nullptr) |       if (channel.shunt_voltage_sensor_ != nullptr) | ||||||
|         channel.shunt_voltage_sensor_->publish_state(shunt_voltage_v); |         channel.shunt_voltage_sensor_->publish_state(shunt_voltage_v); | ||||||
|       current_a = shunt_voltage_v / channel.shunt_resistance_; |       current_a = shunt_voltage_v / channel.shunt_resistance_; | ||||||
|   | |||||||
| @@ -123,7 +123,7 @@ int MAX7219Component::get_width_internal() { return this->num_chips_ * 8; } | |||||||
|  |  | ||||||
| size_t MAX7219Component::get_buffer_length_() { return this->num_chips_ * 8; } | size_t MAX7219Component::get_buffer_length_() { return this->num_chips_ * 8; } | ||||||
|  |  | ||||||
| void HOT MAX7219Component::draw_absolute_pixel_internal(int x, int y, int color) { | void HOT MAX7219Component::draw_absolute_pixel_internal(int x, int y, Color color) { | ||||||
|   if (x + 1 > this->max_displaybuffer_.size()) {  // Extend the display buffer in case required |   if (x + 1 > this->max_displaybuffer_.size()) {  // Extend the display buffer in case required | ||||||
|     this->max_displaybuffer_.resize(x + 1, this->bckgrnd_); |     this->max_displaybuffer_.resize(x + 1, this->bckgrnd_); | ||||||
|   } |   } | ||||||
| @@ -134,7 +134,7 @@ void HOT MAX7219Component::draw_absolute_pixel_internal(int x, int y, int color) | |||||||
|   uint16_t pos = x;    // X is starting at 0 top left |   uint16_t pos = x;    // X is starting at 0 top left | ||||||
|   uint8_t subpos = y;  // Y is starting at 0 top left |   uint8_t subpos = y;  // Y is starting at 0 top left | ||||||
|  |  | ||||||
|   if (color == 1) { |   if (color.is_on()) { | ||||||
|     this->max_displaybuffer_[pos] |= (1 << subpos); |     this->max_displaybuffer_[pos] |= (1 << subpos); | ||||||
|   } else { |   } else { | ||||||
|     this->max_displaybuffer_[pos] &= ~(1 << subpos); |     this->max_displaybuffer_[pos] &= ~(1 << subpos); | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ class MAX7219Component : public PollingComponent, | |||||||
|  |  | ||||||
|   void turn_on_off(bool on_off); |   void turn_on_off(bool on_off); | ||||||
|  |  | ||||||
|   void draw_absolute_pixel_internal(int x, int y, int color) override; |   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||||
|   int get_height_internal() override; |   int get_height_internal() override; | ||||||
|   int get_width_internal() override; |   int get_width_internal() override; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -85,14 +85,14 @@ void HOT PCD8544::display() { | |||||||
|   this->command(this->PCD8544_SETYADDR); |   this->command(this->PCD8544_SETYADDR); | ||||||
| } | } | ||||||
|  |  | ||||||
| void HOT PCD8544::draw_absolute_pixel_internal(int x, int y, int color) { | void HOT PCD8544::draw_absolute_pixel_internal(int x, int y, Color color) { | ||||||
|   if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0) { |   if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0) { | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   uint16_t pos = x + (y / 8) * this->get_width_internal(); |   uint16_t pos = x + (y / 8) * this->get_width_internal(); | ||||||
|   uint8_t subpos = y % 8; |   uint8_t subpos = y % 8; | ||||||
|   if (color) { |   if (color.is_on()) { | ||||||
|     this->buffer_[pos] |= (1 << subpos); |     this->buffer_[pos] |= (1 << subpos); | ||||||
|   } else { |   } else { | ||||||
|     this->buffer_[pos] &= ~(1 << subpos); |     this->buffer_[pos] &= ~(1 << subpos); | ||||||
| @@ -117,8 +117,8 @@ void PCD8544::update() { | |||||||
|   this->display(); |   this->display(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PCD8544::fill(int color) { | void PCD8544::fill(Color color) { | ||||||
|   uint8_t fill = color ? 0xFF : 0x00; |   uint8_t fill = color.is_on() ? 0xFF : 0x00; | ||||||
|   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) |   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) | ||||||
|     this->buffer_[i] = fill; |     this->buffer_[i] = fill; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -43,7 +43,7 @@ class PCD8544 : public PollingComponent, | |||||||
|  |  | ||||||
|   void update() override; |   void update() override; | ||||||
|  |  | ||||||
|   void fill(int color) override; |   void fill(Color color) override; | ||||||
|  |  | ||||||
|   void setup() override { |   void setup() override { | ||||||
|     this->setup_pins_(); |     this->setup_pins_(); | ||||||
| @@ -51,7 +51,7 @@ class PCD8544 : public PollingComponent, | |||||||
|   } |   } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void draw_absolute_pixel_internal(int x, int y, int color) override; |   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||||
|  |  | ||||||
|   void setup_pins_(); |   void setup_pins_(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -179,20 +179,20 @@ size_t SSD1306::get_buffer_length_() { | |||||||
|   return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u; |   return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u; | ||||||
| } | } | ||||||
|  |  | ||||||
| void HOT SSD1306::draw_absolute_pixel_internal(int x, int y, int color) { | void HOT SSD1306::draw_absolute_pixel_internal(int x, int y, Color color) { | ||||||
|   if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) |   if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   uint16_t pos = x + (y / 8) * this->get_width_internal(); |   uint16_t pos = x + (y / 8) * this->get_width_internal(); | ||||||
|   uint8_t subpos = y & 0x07; |   uint8_t subpos = y & 0x07; | ||||||
|   if (color) { |   if (color.is_on()) { | ||||||
|     this->buffer_[pos] |= (1 << subpos); |     this->buffer_[pos] |= (1 << subpos); | ||||||
|   } else { |   } else { | ||||||
|     this->buffer_[pos] &= ~(1 << subpos); |     this->buffer_[pos] &= ~(1 << subpos); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void SSD1306::fill(int color) { | void SSD1306::fill(Color color) { | ||||||
|   uint8_t fill = color ? 0xFF : 0x00; |   uint8_t fill = color.is_on() ? 0xFF : 0x00; | ||||||
|   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) |   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) | ||||||
|     this->buffer_[i] = fill; |     this->buffer_[i] = fill; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ class SSD1306 : public PollingComponent, public display::DisplayBuffer { | |||||||
|   void set_brightness(float brightness) { this->brightness_ = brightness; } |   void set_brightness(float brightness) { this->brightness_ = brightness; } | ||||||
|  |  | ||||||
|   float get_setup_priority() const override { return setup_priority::PROCESSOR; } |   float get_setup_priority() const override { return setup_priority::PROCESSOR; } | ||||||
|   void fill(int color) override; |   void fill(Color color) override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   virtual void command(uint8_t value) = 0; |   virtual void command(uint8_t value) = 0; | ||||||
| @@ -41,7 +41,7 @@ class SSD1306 : public PollingComponent, public display::DisplayBuffer { | |||||||
|  |  | ||||||
|   bool is_sh1106_() const; |   bool is_sh1106_() const; | ||||||
|  |  | ||||||
|   void draw_absolute_pixel_internal(int x, int y, int color) override; |   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||||
|  |  | ||||||
|   int get_height_internal() override; |   int get_height_internal() override; | ||||||
|   int get_width_internal() override; |   int get_width_internal() override; | ||||||
|   | |||||||
| @@ -144,20 +144,20 @@ size_t SSD1325::get_buffer_length_() { | |||||||
|   return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u; |   return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u; | ||||||
| } | } | ||||||
|  |  | ||||||
| void HOT SSD1325::draw_absolute_pixel_internal(int x, int y, int color) { | void HOT SSD1325::draw_absolute_pixel_internal(int x, int y, Color color) { | ||||||
|   if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) |   if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   uint16_t pos = x + (y / 8) * this->get_width_internal(); |   uint16_t pos = x + (y / 8) * this->get_width_internal(); | ||||||
|   uint8_t subpos = y % 8; |   uint8_t subpos = y % 8; | ||||||
|   if (color) { |   if (color.is_on()) { | ||||||
|     this->buffer_[pos] |= (1 << subpos); |     this->buffer_[pos] |= (1 << subpos); | ||||||
|   } else { |   } else { | ||||||
|     this->buffer_[pos] &= ~(1 << subpos); |     this->buffer_[pos] &= ~(1 << subpos); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void SSD1325::fill(int color) { | void SSD1325::fill(Color color) { | ||||||
|   uint8_t fill = color ? 0xFF : 0x00; |   uint8_t fill = color.is_on() ? 0xFF : 0x00; | ||||||
|   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) |   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) | ||||||
|     this->buffer_[i] = fill; |     this->buffer_[i] = fill; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,14 +28,14 @@ class SSD1325 : public PollingComponent, public display::DisplayBuffer { | |||||||
|   void set_external_vcc(bool external_vcc) { this->external_vcc_ = external_vcc; } |   void set_external_vcc(bool external_vcc) { this->external_vcc_ = external_vcc; } | ||||||
|  |  | ||||||
|   float get_setup_priority() const override { return setup_priority::PROCESSOR; } |   float get_setup_priority() const override { return setup_priority::PROCESSOR; } | ||||||
|   void fill(int color) override; |   void fill(Color color) override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   virtual void command(uint8_t value) = 0; |   virtual void command(uint8_t value) = 0; | ||||||
|   virtual void write_display_data() = 0; |   virtual void write_display_data() = 0; | ||||||
|   void init_reset_(); |   void init_reset_(); | ||||||
|  |  | ||||||
|   void draw_absolute_pixel_internal(int x, int y, int color) override; |   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||||
|  |  | ||||||
|   int get_height_internal() override; |   int get_height_internal() override; | ||||||
|   int get_width_internal() override; |   int get_width_internal() override; | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								esphome/components/st7789v/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								esphome/components/st7789v/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  |  | ||||||
|  | st7789v_ns = cg.esphome_ns.namespace('st7789v') | ||||||
							
								
								
									
										44
									
								
								esphome/components/st7789v/display.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								esphome/components/st7789v/display.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.components import display, spi | ||||||
|  | from esphome.const import CONF_BACKLIGHT_PIN, CONF_BRIGHTNESS, CONF_CS_PIN, CONF_DC_PIN, CONF_ID, \ | ||||||
|  |                           CONF_LAMBDA, CONF_RESET_PIN | ||||||
|  | from . import st7789v_ns | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ['spi'] | ||||||
|  |  | ||||||
|  | ST7789V = st7789v_ns.class_('ST7789V', cg.PollingComponent, spi.SPIDevice, | ||||||
|  |                             display.DisplayBuffer) | ||||||
|  | ST7789VRef = ST7789V.operator('ref') | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend({ | ||||||
|  |     cv.GenerateID(): cv.declare_id(ST7789V), | ||||||
|  |     cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema, | ||||||
|  |     cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, | ||||||
|  |     cv.Required(CONF_CS_PIN): pins.gpio_output_pin_schema, | ||||||
|  |     cv.Required(CONF_BACKLIGHT_PIN): pins.gpio_output_pin_schema, | ||||||
|  |     cv.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage, | ||||||
|  | }).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     yield cg.register_component(var, config) | ||||||
|  |     yield spi.register_spi_device(var, config) | ||||||
|  |  | ||||||
|  |     dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) | ||||||
|  |     cg.add(var.set_dc_pin(dc)) | ||||||
|  |  | ||||||
|  |     reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) | ||||||
|  |     cg.add(var.set_reset_pin(reset)) | ||||||
|  |  | ||||||
|  |     bl = yield cg.gpio_pin_expression(config[CONF_BACKLIGHT_PIN]) | ||||||
|  |     cg.add(var.set_backlight_pin(bl)) | ||||||
|  |  | ||||||
|  |     if CONF_LAMBDA in config: | ||||||
|  |         lambda_ = yield cg.process_lambda( | ||||||
|  |             config[CONF_LAMBDA], [(display.DisplayBufferRef, 'it')], return_type=cg.void) | ||||||
|  |         cg.add(var.set_writer(lambda_)) | ||||||
|  |  | ||||||
|  |     yield display.register_display(var, config) | ||||||
							
								
								
									
										274
									
								
								esphome/components/st7789v/st7789v.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								esphome/components/st7789v/st7789v.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,274 @@ | |||||||
|  | #include "st7789v.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace st7789v { | ||||||
|  |  | ||||||
|  | static const char *TAG = "st7789v"; | ||||||
|  |  | ||||||
|  | void ST7789V::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up SPI ST7789V..."); | ||||||
|  |   this->spi_setup(); | ||||||
|  |   this->dc_pin_->setup();  // OUTPUT | ||||||
|  |  | ||||||
|  |   this->init_reset_(); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_SLPOUT);  // Sleep out | ||||||
|  |   delay(120);                           // NOLINT | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_NORON);  // Normal display mode on | ||||||
|  |  | ||||||
|  |   // *** display and color format setting *** | ||||||
|  |   this->write_command_(ST7789_MADCTL); | ||||||
|  |   this->write_data_(ST7789_MADCTL_COLOR_ORDER); | ||||||
|  |  | ||||||
|  |   // JLX240 display datasheet | ||||||
|  |   this->write_command_(0xB6); | ||||||
|  |   this->write_data_(0x0A); | ||||||
|  |   this->write_data_(0x82); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_COLMOD); | ||||||
|  |   this->write_data_(0x55); | ||||||
|  |   delay(10); | ||||||
|  |  | ||||||
|  |   // *** ST7789V Frame rate setting *** | ||||||
|  |   this->write_command_(ST7789_PORCTRL); | ||||||
|  |   this->write_data_(0x0c); | ||||||
|  |   this->write_data_(0x0c); | ||||||
|  |   this->write_data_(0x00); | ||||||
|  |   this->write_data_(0x33); | ||||||
|  |   this->write_data_(0x33); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_GCTRL);  // Voltages: VGH / VGL | ||||||
|  |   this->write_data_(0x35); | ||||||
|  |  | ||||||
|  |   // *** ST7789V Power setting *** | ||||||
|  |   this->write_command_(ST7789_VCOMS); | ||||||
|  |   this->write_data_(0x28);  // JLX240 display datasheet | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_LCMCTRL); | ||||||
|  |   this->write_data_(0x0C); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_VDVVRHEN); | ||||||
|  |   this->write_data_(0x01); | ||||||
|  |   this->write_data_(0xFF); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_VRHS);  // voltage VRHS | ||||||
|  |   this->write_data_(0x10); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_VDVS); | ||||||
|  |   this->write_data_(0x20); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_FRCTRL2); | ||||||
|  |   this->write_data_(0x0f); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_PWCTRL1); | ||||||
|  |   this->write_data_(0xa4); | ||||||
|  |   this->write_data_(0xa1); | ||||||
|  |  | ||||||
|  |   // *** ST7789V gamma setting *** | ||||||
|  |   this->write_command_(ST7789_PVGAMCTRL); | ||||||
|  |   this->write_data_(0xd0); | ||||||
|  |   this->write_data_(0x00); | ||||||
|  |   this->write_data_(0x02); | ||||||
|  |   this->write_data_(0x07); | ||||||
|  |   this->write_data_(0x0a); | ||||||
|  |   this->write_data_(0x28); | ||||||
|  |   this->write_data_(0x32); | ||||||
|  |   this->write_data_(0x44); | ||||||
|  |   this->write_data_(0x42); | ||||||
|  |   this->write_data_(0x06); | ||||||
|  |   this->write_data_(0x0e); | ||||||
|  |   this->write_data_(0x12); | ||||||
|  |   this->write_data_(0x14); | ||||||
|  |   this->write_data_(0x17); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_NVGAMCTRL); | ||||||
|  |   this->write_data_(0xd0); | ||||||
|  |   this->write_data_(0x00); | ||||||
|  |   this->write_data_(0x02); | ||||||
|  |   this->write_data_(0x07); | ||||||
|  |   this->write_data_(0x0a); | ||||||
|  |   this->write_data_(0x28); | ||||||
|  |   this->write_data_(0x31); | ||||||
|  |   this->write_data_(0x54); | ||||||
|  |   this->write_data_(0x47); | ||||||
|  |   this->write_data_(0x0e); | ||||||
|  |   this->write_data_(0x1c); | ||||||
|  |   this->write_data_(0x17); | ||||||
|  |   this->write_data_(0x1b); | ||||||
|  |   this->write_data_(0x1e); | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_INVON); | ||||||
|  |  | ||||||
|  |   // Clear display - ensures we do not see garbage at power-on | ||||||
|  |   this->draw_filled_rect_(0, 0, 239, 319, 0x0000); | ||||||
|  |  | ||||||
|  |   delay(120);  // NOLINT | ||||||
|  |  | ||||||
|  |   this->write_command_(ST7789_DISPON);  // Display on | ||||||
|  |   delay(120);                           // NOLINT | ||||||
|  |  | ||||||
|  |   backlight_(true); | ||||||
|  |  | ||||||
|  |   this->init_internal_(this->get_buffer_length_()); | ||||||
|  |   memset(this->buffer_, 0x00, this->get_buffer_length_()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ST7789V::dump_config() { | ||||||
|  |   LOG_DISPLAY("", "SPI ST7789V", this); | ||||||
|  |   LOG_PIN("  CS Pin: ", this->cs_); | ||||||
|  |   LOG_PIN("  DC Pin: ", this->dc_pin_); | ||||||
|  |   LOG_PIN("  Reset Pin: ", this->reset_pin_); | ||||||
|  |   LOG_PIN("  B/L Pin: ", this->backlight_pin_); | ||||||
|  |   LOG_UPDATE_INTERVAL(this); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float ST7789V::get_setup_priority() const { return setup_priority::PROCESSOR; } | ||||||
|  |  | ||||||
|  | void ST7789V::update() { | ||||||
|  |   this->do_update_(); | ||||||
|  |   this->write_display_data(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ST7789V::loop() {} | ||||||
|  |  | ||||||
|  | void ST7789V::write_display_data() { | ||||||
|  |   uint16_t x1 = 52;   // _offsetx | ||||||
|  |   uint16_t x2 = 186;  // _offsetx | ||||||
|  |   uint16_t y1 = 40;   // _offsety | ||||||
|  |   uint16_t y2 = 279;  // _offsety | ||||||
|  |  | ||||||
|  |   this->enable(); | ||||||
|  |  | ||||||
|  |   // set column(x) address | ||||||
|  |   this->dc_pin_->digital_write(false); | ||||||
|  |   this->write_byte(ST7789_CASET); | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   this->write_addr_(x1, x2); | ||||||
|  |   // set page(y) address | ||||||
|  |   this->dc_pin_->digital_write(false); | ||||||
|  |   this->write_byte(ST7789_RASET); | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   this->write_addr_(y1, y2); | ||||||
|  |   // write display memory | ||||||
|  |   this->dc_pin_->digital_write(false); | ||||||
|  |   this->write_byte(ST7789_RAMWR); | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |  | ||||||
|  |   this->write_array(this->buffer_, this->get_buffer_length_()); | ||||||
|  |  | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ST7789V::init_reset_() { | ||||||
|  |   if (this->reset_pin_ != nullptr) { | ||||||
|  |     this->reset_pin_->setup(); | ||||||
|  |     this->reset_pin_->digital_write(true); | ||||||
|  |     delay(1); | ||||||
|  |     // Trigger Reset | ||||||
|  |     this->reset_pin_->digital_write(false); | ||||||
|  |     delay(10); | ||||||
|  |     // Wake up | ||||||
|  |     this->reset_pin_->digital_write(true); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ST7789V::backlight_(bool onoff) { | ||||||
|  |   if (this->backlight_pin_ != nullptr) { | ||||||
|  |     this->backlight_pin_->setup(); | ||||||
|  |     this->backlight_pin_->digital_write(onoff); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ST7789V::write_command_(uint8_t value) { | ||||||
|  |   this->enable(); | ||||||
|  |   this->dc_pin_->digital_write(false); | ||||||
|  |   this->write_byte(value); | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ST7789V::write_data_(uint8_t value) { | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   this->enable(); | ||||||
|  |   this->write_byte(value); | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ST7789V::write_addr_(uint16_t addr1, uint16_t addr2) { | ||||||
|  |   static uint8_t BYTE[4]; | ||||||
|  |   BYTE[0] = (addr1 >> 8) & 0xFF; | ||||||
|  |   BYTE[1] = addr1 & 0xFF; | ||||||
|  |   BYTE[2] = (addr2 >> 8) & 0xFF; | ||||||
|  |   BYTE[3] = addr2 & 0xFF; | ||||||
|  |  | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   this->write_array(BYTE, 4); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ST7789V::write_color_(uint16_t color, uint16_t size) { | ||||||
|  |   static uint8_t BYTE[1024]; | ||||||
|  |   int index = 0; | ||||||
|  |   for (int i = 0; i < size; i++) { | ||||||
|  |     BYTE[index++] = (color >> 8) & 0xFF; | ||||||
|  |     BYTE[index++] = color & 0xFF; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   return write_array(BYTE, size * 2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int ST7789V::get_height_internal() { | ||||||
|  |   return 240;  // 320; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int ST7789V::get_width_internal() { | ||||||
|  |   return 135;  // 240; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | size_t ST7789V::get_buffer_length_() { | ||||||
|  |   return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) * 2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Draw a filled rectangle | ||||||
|  | // x1: Start X coordinate | ||||||
|  | // y1: Start Y coordinate | ||||||
|  | // x2: End X coordinate | ||||||
|  | // y2: End Y coordinate | ||||||
|  | // color: color | ||||||
|  | void ST7789V::draw_filled_rect_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) { | ||||||
|  |   // ESP_LOGD(TAG,"offset(x)=%d offset(y)=%d",dev->_offsetx,dev->_offsety); | ||||||
|  |   this->enable(); | ||||||
|  |   this->dc_pin_->digital_write(false); | ||||||
|  |   this->write_byte(ST7789_CASET);  // set column(x) address | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   this->write_addr_(x1, x2); | ||||||
|  |  | ||||||
|  |   this->dc_pin_->digital_write(false); | ||||||
|  |   this->write_byte(ST7789_RASET);  // set Page(y) address | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   this->write_addr_(y1, y2); | ||||||
|  |   this->dc_pin_->digital_write(false); | ||||||
|  |   this->write_byte(ST7789_RAMWR);  // begin a write to memory | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   for (int i = x1; i <= x2; i++) { | ||||||
|  |     uint16_t size = y2 - y1 + 1; | ||||||
|  |     this->write_color_(color, size); | ||||||
|  |   } | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HOT ST7789V::draw_absolute_pixel_internal(int x, int y, Color color) { | ||||||
|  |   if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   auto color565 = color.to_rgb_565(); | ||||||
|  |  | ||||||
|  |   uint16_t pos = (x + y * this->get_width_internal()) * 2; | ||||||
|  |   this->buffer_[pos++] = (color565 >> 8) & 0xff; | ||||||
|  |   this->buffer_[pos] = color565 & 0xff; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace st7789v | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										151
									
								
								esphome/components/st7789v/st7789v.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								esphome/components/st7789v/st7789v.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/spi/spi.h" | ||||||
|  | #include "esphome/components/display/display_buffer.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace st7789v { | ||||||
|  |  | ||||||
|  | static const uint8_t BLACK = 0; | ||||||
|  | static const uint8_t WHITE = 1; | ||||||
|  |  | ||||||
|  | static const uint8_t ST7789_NOP = 0x00;        // No Operation | ||||||
|  | static const uint8_t ST7789_SWRESET = 0x01;    // Software Reset | ||||||
|  | static const uint8_t ST7789_RDDID = 0x04;      // Read Display ID | ||||||
|  | static const uint8_t ST7789_RDDST = 0x09;      // Read Display Status | ||||||
|  | static const uint8_t ST7789_RDDPM = 0x0A;      // Read Display Power Mode | ||||||
|  | static const uint8_t ST7789_RDDMADCTL = 0x0B;  // Read Display MADCTL | ||||||
|  | static const uint8_t ST7789_RDDCOLMOD = 0x0C;  // Read Display Pixel Format | ||||||
|  | static const uint8_t ST7789_RDDIM = 0x0D;      // Read Display Image Mode | ||||||
|  | static const uint8_t ST7789_RDDSM = 0x0E;      // Read Display Signal Mod | ||||||
|  | static const uint8_t ST7789_RDDSDR = 0x0F;     // Read Display Self-Diagnostic Resul | ||||||
|  | static const uint8_t ST7789_SLPIN = 0x10;      // Sleep in | ||||||
|  | static const uint8_t ST7789_SLPOUT = 0x11;     // Sleep Out | ||||||
|  | static const uint8_t ST7789_PTLON = 0x12;      // Partial Display Mode O | ||||||
|  | static const uint8_t ST7789_NORON = 0x13;      // Normal Display Mode O | ||||||
|  | static const uint8_t ST7789_INVOFF = 0x20;     // Display Inversion Off | ||||||
|  | static const uint8_t ST7789_INVON = 0x21;      // Display Inversion O | ||||||
|  | static const uint8_t ST7789_GAMSET = 0x26;     // Gamma Set | ||||||
|  | static const uint8_t ST7789_DISPOFF = 0x28;    // Display Off | ||||||
|  | static const uint8_t ST7789_DISPON = 0x29;     // Display On | ||||||
|  | static const uint8_t ST7789_CASET = 0x2A;      // Column Address Set | ||||||
|  | static const uint8_t ST7789_RASET = 0x2B;      // Row Address Set | ||||||
|  | static const uint8_t ST7789_RAMWR = 0x2C;      // Memory Write | ||||||
|  | static const uint8_t ST7789_RAMRD = 0x2E;      // Memory Read | ||||||
|  | static const uint8_t ST7789_PTLAR = 0x30;      // Partial Area | ||||||
|  | static const uint8_t ST7789_VSCRDEF = 0x33;    // Vertical Scrolling Definitio | ||||||
|  | static const uint8_t ST7789_TEOFF = 0x34;      // Tearing Effect Line OFF | ||||||
|  | static const uint8_t ST7789_TEON = 0x35;       // Tearing Effect Line On | ||||||
|  | static const uint8_t ST7789_MADCTL = 0x36;     // Memory Data Access Control | ||||||
|  | static const uint8_t ST7789_VSCSAD = 0x37;     // Vertical Scroll Start Address of RAM | ||||||
|  | static const uint8_t ST7789_IDMOFF = 0x38;     // Idle Mode Off | ||||||
|  | static const uint8_t ST7789_IDMON = 0x39;      // Idle mode on | ||||||
|  | static const uint8_t ST7789_COLMOD = 0x3A;     // Interface Pixel Format | ||||||
|  | static const uint8_t ST7789_WRMEMC = 0x3C;     // Write Memory Continue | ||||||
|  | static const uint8_t ST7789_RDMEMC = 0x3E;     // Read Memory Continue | ||||||
|  | static const uint8_t ST7789_STE = 0x44;        // Set Tear Scanline | ||||||
|  | static const uint8_t ST7789_GSCAN = 0x45;      // Get Scanlin | ||||||
|  | static const uint8_t ST7789_WRDISBV = 0x51;    // Write Display Brightness | ||||||
|  | static const uint8_t ST7789_RDDISBV = 0x52;    // Read Display Brightness Value | ||||||
|  | static const uint8_t ST7789_WRCTRLD = 0x53;    // Write CTRL Display | ||||||
|  | static const uint8_t ST7789_RDCTRLD = 0x54;    // Read CTRL Value Display | ||||||
|  | static const uint8_t ST7789_WRCACE = 0x55;     // Write Content Adaptive Brightness Control and Color Enhancement | ||||||
|  | static const uint8_t ST7789_RDCABC = 0x56;     // Read Content Adaptive Brightness Control | ||||||
|  | static const uint8_t ST7789_WRCABCMB = 0x5E;   // Write CABC Minimum Brightnes | ||||||
|  | static const uint8_t ST7789_RDCABCMB = 0x5F;   // Read CABC Minimum Brightnes | ||||||
|  | static const uint8_t ST7789_RDABCSDR = 0x68;   // Read Automatic Brightness Control Self-Diagnostic Result | ||||||
|  | static const uint8_t ST7789_RDID1 = 0xDA;      // Read ID1 | ||||||
|  | static const uint8_t ST7789_RDID2 = 0xDB;      // Read ID2 | ||||||
|  | static const uint8_t ST7789_RDID3 = 0xDC;      // Read ID3 | ||||||
|  | static const uint8_t ST7789_RAMCTRL = 0xB0;    // RAM Control | ||||||
|  | static const uint8_t ST7789_RGBCTRL = 0xB1;    // RGB Interface Contro | ||||||
|  | static const uint8_t ST7789_PORCTRL = 0xB2;    // Porch Setting | ||||||
|  | static const uint8_t ST7789_FRCTRL1 = 0xB3;    // Frame Rate Control 1 (In partial mode/ idle colors) | ||||||
|  | static const uint8_t ST7789_PARCTRL = 0xB5;    // Partial mode Contro | ||||||
|  | static const uint8_t ST7789_GCTRL = 0xB7;      // Gate Contro | ||||||
|  | static const uint8_t ST7789_GTADJ = 0xB8;      // Gate On Timing Adjustmen | ||||||
|  | static const uint8_t ST7789_DGMEN = 0xBA;      // Digital Gamma Enable | ||||||
|  | static const uint8_t ST7789_VCOMS = 0xBB;      // VCOMS Setting | ||||||
|  | static const uint8_t ST7789_LCMCTRL = 0xC0;    // LCM Control | ||||||
|  | static const uint8_t ST7789_IDSET = 0xC1;      // ID Code Settin | ||||||
|  | static const uint8_t ST7789_VDVVRHEN = 0xC2;   // VDV and VRH Command Enabl | ||||||
|  | static const uint8_t ST7789_VRHS = 0xC3;       // VRH Set | ||||||
|  | static const uint8_t ST7789_VDVS = 0xC4;       // VDV Set | ||||||
|  | static const uint8_t ST7789_VCMOFSET = 0xC5;   // VCOMS Offset Set | ||||||
|  | static const uint8_t ST7789_FRCTRL2 = 0xC6;    // Frame Rate Control in Normal Mode | ||||||
|  | static const uint8_t ST7789_CABCCTRL = 0xC7;   // CABC Control | ||||||
|  | static const uint8_t ST7789_REGSEL1 = 0xC8;    // Register Value Selection 1 | ||||||
|  | static const uint8_t ST7789_REGSEL2 = 0xCA;    // Register Value Selection | ||||||
|  | static const uint8_t ST7789_PWMFRSEL = 0xCC;   // PWM Frequency Selection | ||||||
|  | static const uint8_t ST7789_PWCTRL1 = 0xD0;    // Power Control 1 | ||||||
|  | static const uint8_t ST7789_VAPVANEN = 0xD2;   // Enable VAP/VAN signal output | ||||||
|  | static const uint8_t ST7789_CMD2EN = 0xDF;     // Command 2 Enable | ||||||
|  | static const uint8_t ST7789_PVGAMCTRL = 0xE0;  // Positive Voltage Gamma Control | ||||||
|  | static const uint8_t ST7789_NVGAMCTRL = 0xE1;  // Negative Voltage Gamma Control | ||||||
|  | static const uint8_t ST7789_DGMLUTR = 0xE2;    // Digital Gamma Look-up Table for Red | ||||||
|  | static const uint8_t ST7789_DGMLUTB = 0xE3;    // Digital Gamma Look-up Table for Blue | ||||||
|  | static const uint8_t ST7789_GATECTRL = 0xE4;   // Gate Control | ||||||
|  | static const uint8_t ST7789_SPI2EN = 0xE7;     // SPI2 Enable | ||||||
|  | static const uint8_t ST7789_PWCTRL2 = 0xE8;    // Power Control 2 | ||||||
|  | static const uint8_t ST7789_EQCTRL = 0xE9;     // Equalize time control | ||||||
|  | static const uint8_t ST7789_PROMCTRL = 0xEC;   // Program Mode Contro | ||||||
|  | static const uint8_t ST7789_PROMEN = 0xFA;     // Program Mode Enabl | ||||||
|  | static const uint8_t ST7789_NVMSET = 0xFC;     // NVM Setting | ||||||
|  | static const uint8_t ST7789_PROMACT = 0xFE;    // Program action | ||||||
|  |  | ||||||
|  | // Flags for ST7789_MADCTL | ||||||
|  | static const uint8_t ST7789_MADCTL_MY = 0x80; | ||||||
|  | static const uint8_t ST7789_MADCTL_MX = 0x40; | ||||||
|  | static const uint8_t ST7789_MADCTL_MV = 0x20; | ||||||
|  | static const uint8_t ST7789_MADCTL_ML = 0x10; | ||||||
|  | static const uint8_t ST7789_MADCTL_RGB = 0x00; | ||||||
|  | static const uint8_t ST7789_MADCTL_BGR = 0x08; | ||||||
|  | static const uint8_t ST7789_MADCTL_MH = 0x04; | ||||||
|  | static const uint8_t ST7789_MADCTL_SS = 0x02; | ||||||
|  | static const uint8_t ST7789_MADCTL_GS = 0x01; | ||||||
|  |  | ||||||
|  | static const uint8_t ST7789_MADCTL_COLOR_ORDER = ST7789_MADCTL_BGR; | ||||||
|  |  | ||||||
|  | class ST7789V : public PollingComponent, | ||||||
|  |                 public display::DisplayBuffer, | ||||||
|  |                 public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_HIGH, spi::CLOCK_PHASE_TRAILING, | ||||||
|  |                                       spi::DATA_RATE_8MHZ> { | ||||||
|  |  public: | ||||||
|  |   void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; } | ||||||
|  |   void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } | ||||||
|  |   void set_backlight_pin(GPIOPin *backlight_pin) { this->backlight_pin_ = backlight_pin; } | ||||||
|  |  | ||||||
|  |   // ========== INTERNAL METHODS ========== | ||||||
|  |   // (In most use cases you won't need these) | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |   void update() override; | ||||||
|  |   void loop() override; | ||||||
|  |  | ||||||
|  |   void write_display_data(); | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   GPIOPin *dc_pin_; | ||||||
|  |   GPIOPin *reset_pin_{nullptr}; | ||||||
|  |   GPIOPin *backlight_pin_{nullptr}; | ||||||
|  |  | ||||||
|  |   void init_reset_(); | ||||||
|  |   void backlight_(bool onoff); | ||||||
|  |   void write_command_(uint8_t value); | ||||||
|  |   void write_data_(uint8_t value); | ||||||
|  |   void write_addr_(uint16_t addr1, uint16_t addr2); | ||||||
|  |   void write_color_(uint16_t color, uint16_t size); | ||||||
|  |  | ||||||
|  |   int get_height_internal() override; | ||||||
|  |   int get_width_internal() override; | ||||||
|  |   size_t get_buffer_length_(); | ||||||
|  |  | ||||||
|  |   void draw_filled_rect_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color); | ||||||
|  |  | ||||||
|  |   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace st7789v | ||||||
|  | }  // namespace esphome | ||||||
| @@ -10,15 +10,20 @@ VL53L0XSensor = vl53l0x_ns.class_('VL53L0XSensor', sensor.Sensor, cg.PollingComp | |||||||
|                                   i2c.I2CDevice) |                                   i2c.I2CDevice) | ||||||
|  |  | ||||||
| CONF_SIGNAL_RATE_LIMIT = 'signal_rate_limit' | CONF_SIGNAL_RATE_LIMIT = 'signal_rate_limit' | ||||||
|  | CONF_LONG_RANGE = 'long_range' | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2).extend({ | CONFIG_SCHEMA = sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2).extend({ | ||||||
|     cv.GenerateID(): cv.declare_id(VL53L0XSensor), |     cv.GenerateID(): cv.declare_id(VL53L0XSensor), | ||||||
|     cv.Optional(CONF_SIGNAL_RATE_LIMIT, default=0.25): cv.float_range( |     cv.Optional(CONF_SIGNAL_RATE_LIMIT, default=0.25): cv.float_range( | ||||||
|         min=0.0, max=512.0, min_included=False, max_included=False) |         min=0.0, max=512.0, min_included=False, max_included=False), | ||||||
|  |     cv.Optional(CONF_LONG_RANGE, default=False): cv.boolean, | ||||||
| }).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x29)) | }).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x29)) | ||||||
|  |  | ||||||
|  |  | ||||||
| def to_code(config): | def to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     yield cg.register_component(var, config) |     yield cg.register_component(var, config) | ||||||
|  |     cg.add(var.set_signal_rate_limit(config[CONF_SIGNAL_RATE_LIMIT])) | ||||||
|  |     cg.add(var.set_long_range(config[CONF_LONG_RANGE])) | ||||||
|     yield sensor.register_sensor(var, config) |     yield sensor.register_sensor(var, config) | ||||||
|     yield i2c.register_i2c_device(var, config) |     yield i2c.register_i2c_device(var, config) | ||||||
|   | |||||||
| @@ -33,7 +33,8 @@ void VL53L0XSensor::setup() { | |||||||
|   reg(0xFF) = 0x00; |   reg(0xFF) = 0x00; | ||||||
|   reg(0x80) = 0x00; |   reg(0x80) = 0x00; | ||||||
|   reg(0x60) |= 0x12; |   reg(0x60) |= 0x12; | ||||||
|  |   if (this->long_range_) | ||||||
|  |     this->signal_rate_limit_ = 0.1; | ||||||
|   auto rate_value = static_cast<uint16_t>(signal_rate_limit_ * 128); |   auto rate_value = static_cast<uint16_t>(signal_rate_limit_ * 128); | ||||||
|   write_byte_16(0x44, rate_value); |   write_byte_16(0x44, rate_value); | ||||||
|  |  | ||||||
| @@ -104,7 +105,11 @@ void VL53L0XSensor::setup() { | |||||||
|   reg(0x48) = 0x00; |   reg(0x48) = 0x00; | ||||||
|   reg(0x30) = 0x20; |   reg(0x30) = 0x20; | ||||||
|   reg(0xFF) = 0x00; |   reg(0xFF) = 0x00; | ||||||
|  |   if (this->long_range_) { | ||||||
|  |     reg(0x30) = 0x07;  // WAS 0x09 | ||||||
|  |   } else { | ||||||
|     reg(0x30) = 0x09; |     reg(0x30) = 0x09; | ||||||
|  |   } | ||||||
|   reg(0x54) = 0x00; |   reg(0x54) = 0x00; | ||||||
|   reg(0x31) = 0x04; |   reg(0x31) = 0x04; | ||||||
|   reg(0x32) = 0x03; |   reg(0x32) = 0x03; | ||||||
| @@ -116,7 +121,11 @@ void VL53L0XSensor::setup() { | |||||||
|   reg(0x51) = 0x00; |   reg(0x51) = 0x00; | ||||||
|   reg(0x52) = 0x96; |   reg(0x52) = 0x96; | ||||||
|   reg(0x56) = 0x08; |   reg(0x56) = 0x08; | ||||||
|  |   if (this->long_range_) { | ||||||
|  |     reg(0x57) = 0x50;  // was 0x30 | ||||||
|  |   } else { | ||||||
|     reg(0x57) = 0x30; |     reg(0x57) = 0x30; | ||||||
|  |   } | ||||||
|   reg(0x61) = 0x00; |   reg(0x61) = 0x00; | ||||||
|   reg(0x62) = 0x00; |   reg(0x62) = 0x00; | ||||||
|   reg(0x64) = 0x00; |   reg(0x64) = 0x00; | ||||||
| @@ -153,7 +162,11 @@ void VL53L0XSensor::setup() { | |||||||
|   reg(0x44) = 0x00; |   reg(0x44) = 0x00; | ||||||
|   reg(0x45) = 0x20; |   reg(0x45) = 0x20; | ||||||
|   reg(0x47) = 0x08; |   reg(0x47) = 0x08; | ||||||
|  |   if (this->long_range_) { | ||||||
|  |     reg(0x48) = 0x48;  // was 0x28 | ||||||
|  |   } else { | ||||||
|     reg(0x48) = 0x28; |     reg(0x48) = 0x28; | ||||||
|  |   } | ||||||
|   reg(0x67) = 0x00; |   reg(0x67) = 0x00; | ||||||
|   reg(0x70) = 0x04; |   reg(0x70) = 0x04; | ||||||
|   reg(0x71) = 0x01; |   reg(0x71) = 0x01; | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ class VL53L0XSensor : public sensor::Sensor, public PollingComponent, public i2c | |||||||
|   void loop() override; |   void loop() override; | ||||||
|  |  | ||||||
|   void set_signal_rate_limit(float signal_rate_limit) { signal_rate_limit_ = signal_rate_limit; } |   void set_signal_rate_limit(float signal_rate_limit) { signal_rate_limit_ = signal_rate_limit; } | ||||||
|  |   void set_long_range(bool long_range) { long_range_ = long_range; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   uint32_t get_measurement_timing_budget_() { |   uint32_t get_measurement_timing_budget_() { | ||||||
| @@ -247,6 +248,7 @@ class VL53L0XSensor : public sensor::Sensor, public PollingComponent, public i2c | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   float signal_rate_limit_; |   float signal_rate_limit_; | ||||||
|  |   bool long_range_; | ||||||
|   uint32_t measurement_timing_budget_us_; |   uint32_t measurement_timing_budget_us_; | ||||||
|   bool initiated_read_{false}; |   bool initiated_read_{false}; | ||||||
|   bool waiting_for_interrupt_{false}; |   bool waiting_for_interrupt_{false}; | ||||||
|   | |||||||
| @@ -115,20 +115,20 @@ void WaveshareEPaper::update() { | |||||||
|   this->do_update_(); |   this->do_update_(); | ||||||
|   this->display(); |   this->display(); | ||||||
| } | } | ||||||
| void WaveshareEPaper::fill(int color) { | void WaveshareEPaper::fill(Color color) { | ||||||
|   // flip logic |   // flip logic | ||||||
|   const uint8_t fill = color ? 0x00 : 0xFF; |   const uint8_t fill = color.is_on() ? 0x00 : 0xFF; | ||||||
|   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) |   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) | ||||||
|     this->buffer_[i] = fill; |     this->buffer_[i] = fill; | ||||||
| } | } | ||||||
| void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, int color) { | void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, Color color) { | ||||||
|   if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0) |   if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   const uint32_t pos = (x + y * this->get_width_internal()) / 8u; |   const uint32_t pos = (x + y * this->get_width_internal()) / 8u; | ||||||
|   const uint8_t subpos = x & 0x07; |   const uint8_t subpos = x & 0x07; | ||||||
|   // flip logic |   // flip logic | ||||||
|   if (!color) |   if (!color.is_on()) | ||||||
|     this->buffer_[pos] |= 0x80 >> subpos; |     this->buffer_[pos] |= 0x80 >> subpos; | ||||||
|   else |   else | ||||||
|     this->buffer_[pos] &= ~(0x80 >> subpos); |     this->buffer_[pos] &= ~(0x80 >> subpos); | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ class WaveshareEPaper : public PollingComponent, | |||||||
|  |  | ||||||
|   void update() override; |   void update() override; | ||||||
|  |  | ||||||
|   void fill(int color) override; |   void fill(Color color) override; | ||||||
|  |  | ||||||
|   void setup() override { |   void setup() override { | ||||||
|     this->setup_pins_(); |     this->setup_pins_(); | ||||||
| @@ -36,7 +36,7 @@ class WaveshareEPaper : public PollingComponent, | |||||||
|   void on_safe_shutdown() override; |   void on_safe_shutdown() override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void draw_absolute_pixel_internal(int x, int y, int color) override; |   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||||
|  |  | ||||||
|   bool wait_until_idle_(); |   bool wait_until_idle_(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -49,6 +49,7 @@ CONF_AUTOMATION_ID = 'automation_id' | |||||||
| CONF_AVAILABILITY = 'availability' | CONF_AVAILABILITY = 'availability' | ||||||
| CONF_AWAY = 'away' | CONF_AWAY = 'away' | ||||||
| CONF_AWAY_CONFIG = 'away_config' | CONF_AWAY_CONFIG = 'away_config' | ||||||
|  | CONF_BACKLIGHT_PIN = 'backlight_pin' | ||||||
| CONF_BATTERY_LEVEL = 'battery_level' | CONF_BATTERY_LEVEL = 'battery_level' | ||||||
| CONF_BATTERY_VOLTAGE = 'battery_voltage' | CONF_BATTERY_VOLTAGE = 'battery_voltage' | ||||||
| CONF_BAUD_RATE = 'baud_rate' | CONF_BAUD_RATE = 'baud_rate' | ||||||
|   | |||||||
							
								
								
									
										161
									
								
								esphome/core/color.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								esphome/core/color.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "component.h" | ||||||
|  | #include "helpers.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  |  | ||||||
|  | inline static uint8_t esp_scale8(uint8_t i, uint8_t scale) { return (uint16_t(i) * (1 + uint16_t(scale))) / 256; } | ||||||
|  |  | ||||||
|  | struct Color { | ||||||
|  |   union { | ||||||
|  |     struct { | ||||||
|  |       union { | ||||||
|  |         uint8_t r; | ||||||
|  |         uint8_t red; | ||||||
|  |       }; | ||||||
|  |       union { | ||||||
|  |         uint8_t g; | ||||||
|  |         uint8_t green; | ||||||
|  |       }; | ||||||
|  |       union { | ||||||
|  |         uint8_t b; | ||||||
|  |         uint8_t blue; | ||||||
|  |       }; | ||||||
|  |       union { | ||||||
|  |         uint8_t w; | ||||||
|  |         uint8_t white; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |     uint8_t raw[4]; | ||||||
|  |     uint32_t raw_32; | ||||||
|  |   }; | ||||||
|  |   inline Color() ALWAYS_INLINE : r(0), g(0), b(0), w(0) {}  // NOLINT | ||||||
|  |   inline Color(float red, float green, float blue) ALWAYS_INLINE : r(uint8_t(red * 255)), | ||||||
|  |                                                                    g(uint8_t(green * 255)), | ||||||
|  |                                                                    b(uint8_t(blue * 255)), | ||||||
|  |                                                                    w(0) {} | ||||||
|  |   inline Color(float red, float green, float blue, float white) ALWAYS_INLINE : r(uint8_t(red * 255)), | ||||||
|  |                                                                                 g(uint8_t(green * 255)), | ||||||
|  |                                                                                 b(uint8_t(blue * 255)), | ||||||
|  |                                                                                 w(uint8_t(white * 255)) {} | ||||||
|  |   inline Color(uint32_t colorcode) ALWAYS_INLINE : r((colorcode >> 16) & 0xFF), | ||||||
|  |                                                    g((colorcode >> 8) & 0xFF), | ||||||
|  |                                                    b((colorcode >> 0) & 0xFF), | ||||||
|  |                                                    w((colorcode >> 24) & 0xFF) {} | ||||||
|  |   inline bool is_on() ALWAYS_INLINE { return this->raw_32 != 0; } | ||||||
|  |   inline Color &operator=(const Color &rhs) ALWAYS_INLINE { | ||||||
|  |     this->r = rhs.r; | ||||||
|  |     this->g = rhs.g; | ||||||
|  |     this->b = rhs.b; | ||||||
|  |     this->w = rhs.w; | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |   inline Color &operator=(uint32_t colorcode) ALWAYS_INLINE { | ||||||
|  |     this->w = (colorcode >> 24) & 0xFF; | ||||||
|  |     this->r = (colorcode >> 16) & 0xFF; | ||||||
|  |     this->g = (colorcode >> 8) & 0xFF; | ||||||
|  |     this->b = (colorcode >> 0) & 0xFF; | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |   inline uint8_t &operator[](uint8_t x) ALWAYS_INLINE { return this->raw[x]; } | ||||||
|  |   inline Color operator*(uint8_t scale) const ALWAYS_INLINE { | ||||||
|  |     return Color(esp_scale8(this->red, scale), esp_scale8(this->green, scale), esp_scale8(this->blue, scale), | ||||||
|  |                  esp_scale8(this->white, scale)); | ||||||
|  |   } | ||||||
|  |   inline Color &operator*=(uint8_t scale) ALWAYS_INLINE { | ||||||
|  |     this->red = esp_scale8(this->red, scale); | ||||||
|  |     this->green = esp_scale8(this->green, scale); | ||||||
|  |     this->blue = esp_scale8(this->blue, scale); | ||||||
|  |     this->white = esp_scale8(this->white, scale); | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |   inline Color operator*(const Color &scale) const ALWAYS_INLINE { | ||||||
|  |     return Color(esp_scale8(this->red, scale.red), esp_scale8(this->green, scale.green), | ||||||
|  |                  esp_scale8(this->blue, scale.blue), esp_scale8(this->white, scale.white)); | ||||||
|  |   } | ||||||
|  |   inline Color &operator*=(const Color &scale) ALWAYS_INLINE { | ||||||
|  |     this->red = esp_scale8(this->red, scale.red); | ||||||
|  |     this->green = esp_scale8(this->green, scale.green); | ||||||
|  |     this->blue = esp_scale8(this->blue, scale.blue); | ||||||
|  |     this->white = esp_scale8(this->white, scale.white); | ||||||
|  |     return *this; | ||||||
|  |   } | ||||||
|  |   inline Color operator+(const Color &add) const ALWAYS_INLINE { | ||||||
|  |     Color ret; | ||||||
|  |     if (uint8_t(add.r + this->r) < this->r) | ||||||
|  |       ret.r = 255; | ||||||
|  |     else | ||||||
|  |       ret.r = this->r + add.r; | ||||||
|  |     if (uint8_t(add.g + this->g) < this->g) | ||||||
|  |       ret.g = 255; | ||||||
|  |     else | ||||||
|  |       ret.g = this->g + add.g; | ||||||
|  |     if (uint8_t(add.b + this->b) < this->b) | ||||||
|  |       ret.b = 255; | ||||||
|  |     else | ||||||
|  |       ret.b = this->b + add.b; | ||||||
|  |     if (uint8_t(add.w + this->w) < this->w) | ||||||
|  |       ret.w = 255; | ||||||
|  |     else | ||||||
|  |       ret.w = this->w + add.w; | ||||||
|  |     return ret; | ||||||
|  |   } | ||||||
|  |   inline Color &operator+=(const Color &add) ALWAYS_INLINE { return *this = (*this) + add; } | ||||||
|  |   inline Color operator+(uint8_t add) const ALWAYS_INLINE { return (*this) + Color(add, add, add, add); } | ||||||
|  |   inline Color &operator+=(uint8_t add) ALWAYS_INLINE { return *this = (*this) + add; } | ||||||
|  |   inline Color operator-(const Color &subtract) const ALWAYS_INLINE { | ||||||
|  |     Color ret; | ||||||
|  |     if (subtract.r > this->r) | ||||||
|  |       ret.r = 0; | ||||||
|  |     else | ||||||
|  |       ret.r = this->r - subtract.r; | ||||||
|  |     if (subtract.g > this->g) | ||||||
|  |       ret.g = 0; | ||||||
|  |     else | ||||||
|  |       ret.g = this->g - subtract.g; | ||||||
|  |     if (subtract.b > this->b) | ||||||
|  |       ret.b = 0; | ||||||
|  |     else | ||||||
|  |       ret.b = this->b - subtract.b; | ||||||
|  |     if (subtract.w > this->w) | ||||||
|  |       ret.w = 0; | ||||||
|  |     else | ||||||
|  |       ret.w = this->w - subtract.w; | ||||||
|  |     return ret; | ||||||
|  |   } | ||||||
|  |   inline Color &operator-=(const Color &subtract) ALWAYS_INLINE { return *this = (*this) - subtract; } | ||||||
|  |   inline Color operator-(uint8_t subtract) const ALWAYS_INLINE { | ||||||
|  |     return (*this) - Color(subtract, subtract, subtract, subtract); | ||||||
|  |   } | ||||||
|  |   inline Color &operator-=(uint8_t subtract) ALWAYS_INLINE { return *this = (*this) - subtract; } | ||||||
|  |   static Color random_color() { | ||||||
|  |     float r = float(random_uint32()) / float(UINT32_MAX); | ||||||
|  |     float g = float(random_uint32()) / float(UINT32_MAX); | ||||||
|  |     float b = float(random_uint32()) / float(UINT32_MAX); | ||||||
|  |     float w = float(random_uint32()) / float(UINT32_MAX); | ||||||
|  |     return Color(r, g, b, w); | ||||||
|  |   } | ||||||
|  |   Color fade_to_white(uint8_t amnt) { return Color(1, 1, 1, 1) - (*this * amnt); } | ||||||
|  |   Color fade_to_black(uint8_t amnt) { return *this * amnt; } | ||||||
|  |   Color lighten(uint8_t delta) { return *this + delta; } | ||||||
|  |   Color darken(uint8_t delta) { return *this - delta; } | ||||||
|  |  | ||||||
|  |   uint32_t to_rgb_565() const { | ||||||
|  |     uint32_t color565 = | ||||||
|  |         (esp_scale8(this->red, 31) << 11) | (esp_scale8(this->green, 63) << 5) | (esp_scale8(this->blue, 31) << 0); | ||||||
|  |     return color565; | ||||||
|  |   } | ||||||
|  |   uint32_t to_bgr_565() const { | ||||||
|  |     uint32_t color565 = | ||||||
|  |         (esp_scale8(this->blue, 31) << 11) | (esp_scale8(this->green, 63) << 5) | (esp_scale8(this->red, 31) << 0); | ||||||
|  |     return color565; | ||||||
|  |   } | ||||||
|  |   uint32_t to_grayscale4() const { | ||||||
|  |     uint32_t gs4 = esp_scale8(this->white, 15); | ||||||
|  |     return gs4; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | static const Color COLOR_BLACK(0, 0, 0); | ||||||
|  | static const Color COLOR_WHITE(1, 1, 1); | ||||||
|  | };  // namespace esphome | ||||||
| @@ -1507,6 +1507,16 @@ interval: | |||||||
|  |  | ||||||
|             id(btn_left)->set_threshold(btn_left_state * 0.9); |             id(btn_left)->set_threshold(btn_left_state * 0.9); | ||||||
|  |  | ||||||
|  | color: | ||||||
|  |   - id: kbx_red | ||||||
|  |     red: 100% | ||||||
|  |     green: 1% | ||||||
|  |     blue: 2% | ||||||
|  |   - id: kbx_blue | ||||||
|  |     red: 0% | ||||||
|  |     green: 1% | ||||||
|  |     blue: 100% | ||||||
|  |  | ||||||
| display: | display: | ||||||
| - platform: lcd_gpio | - platform: lcd_gpio | ||||||
|   dimensions: 18x4 |   dimensions: 18x4 | ||||||
| @@ -1591,6 +1601,13 @@ display: | |||||||
|   full_update_every: 30 |   full_update_every: 30 | ||||||
|   lambda: |- |   lambda: |- | ||||||
|     it.rectangle(0, 0, it.get_width(), it.get_height()); |     it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||||
|  | - platform: st7789v | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |   dc_pin: GPIO16 | ||||||
|  |   reset_pin: GPIO23 | ||||||
|  |   backlight_pin: GPIO4 | ||||||
|  |   lambda: |- | ||||||
|  |     it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||||
|  |  | ||||||
| tm1651: | tm1651: | ||||||
|   id: tm1651_battery |   id: tm1651_battery | ||||||
|   | |||||||
| @@ -217,6 +217,10 @@ sensor: | |||||||
|   - platform: apds9960 |   - platform: apds9960 | ||||||
|     type: proximity |     type: proximity | ||||||
|     name: APDS9960 Proximity |     name: APDS9960 Proximity | ||||||
|  |   - platform: vl53l0x | ||||||
|  |     name: "VL53L0x Distance" | ||||||
|  |     address: 0x29 | ||||||
|  |     update_interval: 60s | ||||||
|   - platform: apds9960 |   - platform: apds9960 | ||||||
|     type: clear |     type: clear | ||||||
|     name: APDS9960 Clear |     name: APDS9960 Clear | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user