mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Add SSD1351 OLED display support (#1100)
* Add SSD1351 display support * Linting round 2 * Updated/rebased for proper Color support * Fix color image processing
This commit is contained in:
		| @@ -1,4 +1,5 @@ | |||||||
| #include "display_buffer.h" | #include "display_buffer.h" | ||||||
|  | #include "esphome/core/color.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| #include "esphome/core/application.h" | #include "esphome/core/application.h" | ||||||
|  |  | ||||||
| @@ -220,7 +221,7 @@ void DisplayBuffer::image(int x, int y, Color color, Image *image, bool invert) | |||||||
|         this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale_pixel(img_x, img_y)); |         this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale_pixel(img_x, img_y)); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } else if (image->get_type() == RGB565) { |   } else if (image->get_type() == RGB) { | ||||||
|     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_color_pixel(img_x, img_y)); |         this->draw_pixel_at(x + img_x, y + img_y, image->get_color_pixel(img_x, img_y)); | ||||||
| @@ -449,13 +450,14 @@ 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 { | Color Image::get_color_pixel(int x, int y) const { | ||||||
|   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) |   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||||
|     return 0; |     return 0; | ||||||
|  |   const uint32_t pos = (x + y * this->width_) * 3; | ||||||
|   const uint32_t pos = (x + y * this->width_) * 2; |   const uint32_t color32 = (pgm_read_byte(this->data_start_ + pos + 2) << 0) | | ||||||
|   int color = (pgm_read_byte(this->data_start_ + pos) << 8) + (pgm_read_byte(this->data_start_ + pos + 1)); |                            (pgm_read_byte(this->data_start_ + pos + 1) << 8) | | ||||||
|   return color; |                            (pgm_read_byte(this->data_start_ + pos + 0) << 16); | ||||||
|  |   return Color(color32); | ||||||
| } | } | ||||||
| Color Image::get_grayscale_pixel(int x, int y) const { | Color Image::get_grayscale_pixel(int x, int y) const { | ||||||
|   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) |   if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) | ||||||
|   | |||||||
| @@ -68,7 +68,7 @@ extern const Color COLOR_OFF; | |||||||
| /// Turn the pixel ON. | /// Turn the pixel ON. | ||||||
| extern const Color COLOR_ON; | extern const Color COLOR_ON; | ||||||
|  |  | ||||||
| enum ImageType { BINARY = 0, GRAYSCALE = 1, RGB565 = 2 }; | enum ImageType { BINARY = 0, GRAYSCALE = 1, RGB = 2 }; | ||||||
|  |  | ||||||
| enum DisplayRotation { | enum DisplayRotation { | ||||||
|   DISPLAY_ROTATION_0_DEGREES = 0, |   DISPLAY_ROTATION_0_DEGREES = 0, | ||||||
| @@ -384,7 +384,7 @@ class Image { | |||||||
|   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); |   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; |   Color get_color_pixel(int x, int y) const; | ||||||
|   Color get_grayscale_pixel(int x, int y) const; |   Color get_grayscale_pixel(int x, int y) const; | ||||||
|   int get_width() const; |   int get_width() const; | ||||||
|   int get_height() const; |   int get_height() const; | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ _LOGGER = logging.getLogger(__name__) | |||||||
| DEPENDENCIES = ['display'] | DEPENDENCIES = ['display'] | ||||||
| MULTI_CONF = True | MULTI_CONF = True | ||||||
|  |  | ||||||
| ImageType = {'binary': 0, 'grayscale': 1, 'rgb565': 2} | ImageType = {'binary': 0, 'grayscale': 1, 'rgb': 2} | ||||||
|  |  | ||||||
| Image_ = display.display_ns.class_('Image') | Image_ = display.display_ns.class_('Image') | ||||||
|  |  | ||||||
| @@ -53,24 +53,22 @@ def to_code(config): | |||||||
|             rhs = [HexInt(x) for x in data] |             rhs = [HexInt(x) for x in data] | ||||||
|             prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) |             prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) | ||||||
|             cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['grayscale']) |             cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['grayscale']) | ||||||
|         elif config[CONF_TYPE].startswith('RGB565'): |         elif config[CONF_TYPE].startswith('RGB'): | ||||||
|             width, height = image.size |             width, height = image.size | ||||||
|             image = image.convert('RGB') |             image = image.convert('RGB') | ||||||
|             pixels = list(image.getdata()) |             pixels = list(image.getdata()) | ||||||
|             data = [0 for _ in range(height * width * 2)] |             data = [0 for _ in range(height * width * 3)] | ||||||
|             pos = 0 |             pos = 0 | ||||||
|             for pix in pixels: |             for pix in pixels: | ||||||
|                 r = (pix[0] >> 3) & 0x1F |                 data[pos] = pix[0] | ||||||
|                 g = (pix[1] >> 2) & 0x3F |  | ||||||
|                 b = (pix[2] >> 3) & 0x1F |  | ||||||
|                 p = (r << 11) + (g << 5) + b |  | ||||||
|                 data[pos] = (p >> 8) & 0xFF |  | ||||||
|                 pos += 1 |                 pos += 1 | ||||||
|                 data[pos] = p & 0xFF |                 data[pos] = pix[1] | ||||||
|  |                 pos += 1 | ||||||
|  |                 data[pos] = pix[2] | ||||||
|                 pos += 1 |                 pos += 1 | ||||||
|             rhs = [HexInt(x) for x in data] |             rhs = [HexInt(x) for x in data] | ||||||
|             prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) |             prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) | ||||||
|             cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['rgb565']) |             cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['rgb']) | ||||||
|     else: |     else: | ||||||
|         image = image.convert('1', dither=Image.NONE) |         image = image.convert('1', dither=Image.NONE) | ||||||
|         width, height = image.size |         width, height = image.size | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								esphome/components/ssd1351_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								esphome/components/ssd1351_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.components import display | ||||||
|  | from esphome.const import CONF_BRIGHTNESS, CONF_LAMBDA, CONF_MODEL, CONF_RESET_PIN | ||||||
|  | from esphome.core import coroutine | ||||||
|  |  | ||||||
|  | ssd1351_base_ns = cg.esphome_ns.namespace('ssd1351_base') | ||||||
|  | SSD1351 = ssd1351_base_ns.class_('SSD1351', cg.PollingComponent, display.DisplayBuffer) | ||||||
|  | SSD1351Model = ssd1351_base_ns.enum('SSD1351Model') | ||||||
|  |  | ||||||
|  | MODELS = { | ||||||
|  |     'SSD1351_128X96': SSD1351Model.SSD1351_MODEL_128_96, | ||||||
|  |     'SSD1351_128X128': SSD1351Model.SSD1351_MODEL_128_128, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SSD1351_MODEL = cv.enum(MODELS, upper=True, space="_") | ||||||
|  |  | ||||||
|  | SSD1351_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend({ | ||||||
|  |     cv.Required(CONF_MODEL): SSD1351_MODEL, | ||||||
|  |     cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, | ||||||
|  |     cv.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage, | ||||||
|  | }).extend(cv.polling_component_schema('1s')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @coroutine | ||||||
|  | def setup_ssd1351(var, config): | ||||||
|  |     yield cg.register_component(var, config) | ||||||
|  |     yield display.register_display(var, config) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_model(config[CONF_MODEL])) | ||||||
|  |     if CONF_RESET_PIN in config: | ||||||
|  |         reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) | ||||||
|  |         cg.add(var.set_reset_pin(reset)) | ||||||
|  |     if CONF_BRIGHTNESS in config: | ||||||
|  |         cg.add(var.init_brightness(config[CONF_BRIGHTNESS])) | ||||||
|  |     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_)) | ||||||
							
								
								
									
										193
									
								
								esphome/components/ssd1351_base/ssd1351_base.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								esphome/components/ssd1351_base/ssd1351_base.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | |||||||
|  | #include "ssd1351_base.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/helpers.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ssd1351_base { | ||||||
|  |  | ||||||
|  | static const char *TAG = "ssd1351"; | ||||||
|  |  | ||||||
|  | static const uint16_t BLACK = 0; | ||||||
|  | static const uint16_t WHITE = 0xffff; | ||||||
|  | static const uint16_t SSD1351_COLORMASK = 0xffff; | ||||||
|  | static const uint8_t SSD1351_MAX_CONTRAST = 15; | ||||||
|  | static const uint8_t SSD1351_BYTESPERPIXEL = 2; | ||||||
|  | // SSD1351 commands | ||||||
|  | static const uint8_t SSD1351_SETCOLUMN = 0x15; | ||||||
|  | static const uint8_t SSD1351_SETROW = 0x75; | ||||||
|  | static const uint8_t SSD1351_SETREMAP = 0xA0; | ||||||
|  | static const uint8_t SSD1351_STARTLINE = 0xA1; | ||||||
|  | static const uint8_t SSD1351_DISPLAYOFFSET = 0xA2; | ||||||
|  | static const uint8_t SSD1351_DISPLAYOFF = 0xAE; | ||||||
|  | static const uint8_t SSD1351_DISPLAYON = 0xAF; | ||||||
|  | static const uint8_t SSD1351_PRECHARGE = 0xB1; | ||||||
|  | static const uint8_t SSD1351_CLOCKDIV = 0xB3; | ||||||
|  | static const uint8_t SSD1351_PRECHARGELEVEL = 0xBB; | ||||||
|  | static const uint8_t SSD1351_VCOMH = 0xBE; | ||||||
|  | // display controls | ||||||
|  | static const uint8_t SSD1351_DISPLAYALLOFF = 0xA4; | ||||||
|  | static const uint8_t SSD1351_DISPLAYALLON = 0xA5; | ||||||
|  | static const uint8_t SSD1351_NORMALDISPLAY = 0xA6; | ||||||
|  | static const uint8_t SSD1351_INVERTDISPLAY = 0xA7; | ||||||
|  | // contrast controls | ||||||
|  | static const uint8_t SSD1351_CONTRASTABC = 0xC1; | ||||||
|  | static const uint8_t SSD1351_CONTRASTMASTER = 0xC7; | ||||||
|  | // memory functions | ||||||
|  | static const uint8_t SSD1351_WRITERAM = 0x5C; | ||||||
|  | static const uint8_t SSD1351_READRAM = 0x5D; | ||||||
|  | // other functions | ||||||
|  | static const uint8_t SSD1351_FUNCTIONSELECT = 0xAB; | ||||||
|  | static const uint8_t SSD1351_DISPLAYENHANCE = 0xB2; | ||||||
|  | static const uint8_t SSD1351_SETVSL = 0xB4; | ||||||
|  | static const uint8_t SSD1351_SETGPIO = 0xB5; | ||||||
|  | static const uint8_t SSD1351_PRECHARGE2 = 0xB6; | ||||||
|  | static const uint8_t SSD1351_SETGRAY = 0xB8; | ||||||
|  | static const uint8_t SSD1351_USELUT = 0xB9; | ||||||
|  | static const uint8_t SSD1351_MUXRATIO = 0xCA; | ||||||
|  | static const uint8_t SSD1351_COMMANDLOCK = 0xFD; | ||||||
|  | static const uint8_t SSD1351_HORIZSCROLL = 0x96; | ||||||
|  | static const uint8_t SSD1351_STOPSCROLL = 0x9E; | ||||||
|  | static const uint8_t SSD1351_STARTSCROLL = 0x9F; | ||||||
|  |  | ||||||
|  | void SSD1351::setup() { | ||||||
|  |   this->init_internal_(this->get_buffer_length_()); | ||||||
|  |  | ||||||
|  |   this->command(SSD1351_COMMANDLOCK); | ||||||
|  |   this->data(0x12); | ||||||
|  |   this->command(SSD1351_COMMANDLOCK); | ||||||
|  |   this->data(0xB1); | ||||||
|  |   this->command(SSD1351_DISPLAYOFF); | ||||||
|  |   this->command(SSD1351_CLOCKDIV); | ||||||
|  |   this->data(0xF1);  // 7:4 = Oscillator Freq, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16) | ||||||
|  |   this->command(SSD1351_MUXRATIO); | ||||||
|  |   this->data(127); | ||||||
|  |   this->command(SSD1351_DISPLAYOFFSET); | ||||||
|  |   this->data(0x00); | ||||||
|  |   this->command(SSD1351_SETGPIO); | ||||||
|  |   this->data(0x00); | ||||||
|  |   this->command(SSD1351_FUNCTIONSELECT); | ||||||
|  |   this->data(0x01);  // internal (diode drop) | ||||||
|  |   this->command(SSD1351_PRECHARGE); | ||||||
|  |   this->data(0x32); | ||||||
|  |   this->command(SSD1351_VCOMH); | ||||||
|  |   this->data(0x05); | ||||||
|  |   this->command(SSD1351_NORMALDISPLAY); | ||||||
|  |   this->command(SSD1351_SETVSL); | ||||||
|  |   this->data(0xA0); | ||||||
|  |   this->data(0xB5); | ||||||
|  |   this->data(0x55); | ||||||
|  |   this->command(SSD1351_PRECHARGE2); | ||||||
|  |   this->data(0x01); | ||||||
|  |   this->command(SSD1351_SETREMAP); | ||||||
|  |   this->data(0x34); | ||||||
|  |   this->command(SSD1351_STARTLINE); | ||||||
|  |   this->data(0x00); | ||||||
|  |   this->command(SSD1351_CONTRASTABC); | ||||||
|  |   this->data(0xC8); | ||||||
|  |   this->data(0x80); | ||||||
|  |   this->data(0xC8); | ||||||
|  |   set_brightness(this->brightness_); | ||||||
|  |   this->fill(BLACK);  // clear display - ensures we do not see garbage at power-on | ||||||
|  |   this->display();    // ...write buffer, which actually clears the display's memory | ||||||
|  |   this->turn_on();    // display ON | ||||||
|  | } | ||||||
|  | void SSD1351::display() { | ||||||
|  |   this->command(SSD1351_SETCOLUMN);  // set column address | ||||||
|  |   this->data(0x00);                  // set column start address | ||||||
|  |   this->data(0x7F);                  // set column end address | ||||||
|  |   this->command(SSD1351_SETROW);     // set row address | ||||||
|  |   this->data(0x00);                  // set row start address | ||||||
|  |   this->data(0x7F);                  // set last row | ||||||
|  |   this->command(SSD1351_WRITERAM); | ||||||
|  |   this->write_display_data(); | ||||||
|  | } | ||||||
|  | void SSD1351::update() { | ||||||
|  |   this->do_update_(); | ||||||
|  |   this->display(); | ||||||
|  | } | ||||||
|  | void SSD1351::set_brightness(float brightness) { | ||||||
|  |   // validation | ||||||
|  |   if (brightness > 1) | ||||||
|  |     this->brightness_ = 1.0; | ||||||
|  |   else if (brightness < 0) | ||||||
|  |     this->brightness_ = 0; | ||||||
|  |   else | ||||||
|  |     this->brightness_ = brightness; | ||||||
|  |   // now write the new brightness level to the display | ||||||
|  |   this->command(SSD1351_CONTRASTMASTER); | ||||||
|  |   this->data(int(SSD1351_MAX_CONTRAST * (this->brightness_))); | ||||||
|  | } | ||||||
|  | bool SSD1351::is_on() { return this->is_on_; } | ||||||
|  | void SSD1351::turn_on() { | ||||||
|  |   this->command(SSD1351_DISPLAYON); | ||||||
|  |   this->is_on_ = true; | ||||||
|  | } | ||||||
|  | void SSD1351::turn_off() { | ||||||
|  |   this->command(SSD1351_DISPLAYOFF); | ||||||
|  |   this->is_on_ = false; | ||||||
|  | } | ||||||
|  | int SSD1351::get_height_internal() { | ||||||
|  |   switch (this->model_) { | ||||||
|  |     case SSD1351_MODEL_128_96: | ||||||
|  |       return 96; | ||||||
|  |     case SSD1351_MODEL_128_128: | ||||||
|  |       return 128; | ||||||
|  |     default: | ||||||
|  |       return 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | int SSD1351::get_width_internal() { | ||||||
|  |   switch (this->model_) { | ||||||
|  |     case SSD1351_MODEL_128_96: | ||||||
|  |     case SSD1351_MODEL_128_128: | ||||||
|  |       return 128; | ||||||
|  |     default: | ||||||
|  |       return 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | size_t SSD1351::get_buffer_length_() { | ||||||
|  |   return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) * size_t(SSD1351_BYTESPERPIXEL); | ||||||
|  | } | ||||||
|  | void HOT SSD1351::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; | ||||||
|  |   const uint32_t color565 = color.to_rgb_565(); | ||||||
|  |   // where should the bits go in the big buffer array? math... | ||||||
|  |   uint16_t pos = (x + y * this->get_width_internal()) * SSD1351_BYTESPERPIXEL; | ||||||
|  |   this->buffer_[pos++] = (color565 >> 8) & 0xff; | ||||||
|  |   this->buffer_[pos] = color565 & 0xff; | ||||||
|  | } | ||||||
|  | void SSD1351::fill(Color color) { | ||||||
|  |   const uint32_t color565 = color.to_rgb_565(); | ||||||
|  |   for (uint32_t i = 0; i < this->get_buffer_length_(); i++) | ||||||
|  |     if (i & 1) { | ||||||
|  |       this->buffer_[i] = color565 & 0xff; | ||||||
|  |     } else { | ||||||
|  |       this->buffer_[i] = (color565 >> 8) & 0xff; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | void SSD1351::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); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | const char *SSD1351::model_str_() { | ||||||
|  |   switch (this->model_) { | ||||||
|  |     case SSD1351_MODEL_128_96: | ||||||
|  |       return "SSD1351 128x96"; | ||||||
|  |     case SSD1351_MODEL_128_128: | ||||||
|  |       return "SSD1351 128x128"; | ||||||
|  |     default: | ||||||
|  |       return "Unknown"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace ssd1351_base | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										54
									
								
								esphome/components/ssd1351_base/ssd1351_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								esphome/components/ssd1351_base/ssd1351_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/esphal.h" | ||||||
|  | #include "esphome/components/display/display_buffer.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ssd1351_base { | ||||||
|  |  | ||||||
|  | enum SSD1351Model { | ||||||
|  |   SSD1351_MODEL_128_96 = 0, | ||||||
|  |   SSD1351_MODEL_128_128, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class SSD1351 : public PollingComponent, public display::DisplayBuffer { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |  | ||||||
|  |   void display(); | ||||||
|  |  | ||||||
|  |   void update() override; | ||||||
|  |  | ||||||
|  |   void set_model(SSD1351Model model) { this->model_ = model; } | ||||||
|  |   void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } | ||||||
|  |   void init_brightness(float brightness) { this->brightness_ = brightness; } | ||||||
|  |   void set_brightness(float brightness); | ||||||
|  |   bool is_on(); | ||||||
|  |   void turn_on(); | ||||||
|  |   void turn_off(); | ||||||
|  |  | ||||||
|  |   float get_setup_priority() const override { return setup_priority::PROCESSOR; } | ||||||
|  |   void fill(Color color) override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   virtual void command(uint8_t value) = 0; | ||||||
|  |   virtual void data(uint8_t value) = 0; | ||||||
|  |   virtual void write_display_data() = 0; | ||||||
|  |   void init_reset_(); | ||||||
|  |  | ||||||
|  |   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||||
|  |  | ||||||
|  |   int get_height_internal() override; | ||||||
|  |   int get_width_internal() override; | ||||||
|  |   size_t get_buffer_length_(); | ||||||
|  |   const char *model_str_(); | ||||||
|  |  | ||||||
|  |   SSD1351Model model_{SSD1351_MODEL_128_96}; | ||||||
|  |   GPIOPin *reset_pin_{nullptr}; | ||||||
|  |   bool is_on_{false}; | ||||||
|  |   float brightness_{1.0}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace ssd1351_base | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										0
									
								
								esphome/components/ssd1351_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/ssd1351_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										26
									
								
								esphome/components/ssd1351_spi/display.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								esphome/components/ssd1351_spi/display.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.components import spi, ssd1351_base | ||||||
|  | from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES | ||||||
|  |  | ||||||
|  | AUTO_LOAD = ['ssd1351_base'] | ||||||
|  | DEPENDENCIES = ['spi'] | ||||||
|  |  | ||||||
|  | ssd1351_spi = cg.esphome_ns.namespace('ssd1351_spi') | ||||||
|  | SPISSD1351 = ssd1351_spi.class_('SPISSD1351', ssd1351_base.SSD1351, spi.SPIDevice) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All(ssd1351_base.SSD1351_SCHEMA.extend({ | ||||||
|  |     cv.GenerateID(): cv.declare_id(SPISSD1351), | ||||||
|  |     cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, | ||||||
|  | }).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema()), | ||||||
|  |                        cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     yield ssd1351_base.setup_ssd1351(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)) | ||||||
							
								
								
									
										72
									
								
								esphome/components/ssd1351_spi/ssd1351_spi.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								esphome/components/ssd1351_spi/ssd1351_spi.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | #include "ssd1351_spi.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/application.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ssd1351_spi { | ||||||
|  |  | ||||||
|  | static const char *TAG = "ssd1351_spi"; | ||||||
|  |  | ||||||
|  | void SPISSD1351::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up SPI SSD1351..."); | ||||||
|  |   this->spi_setup(); | ||||||
|  |   this->dc_pin_->setup();  // OUTPUT | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->setup();  // OUTPUT | ||||||
|  |  | ||||||
|  |   this->init_reset_(); | ||||||
|  |   delay(500);  // NOLINT | ||||||
|  |   SSD1351::setup(); | ||||||
|  | } | ||||||
|  | void SPISSD1351::dump_config() { | ||||||
|  |   LOG_DISPLAY("", "SPI SSD1351", this); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Model: %s", this->model_str_()); | ||||||
|  |   if (this->cs_) | ||||||
|  |     LOG_PIN("  CS Pin: ", this->cs_); | ||||||
|  |   LOG_PIN("  DC Pin: ", this->dc_pin_); | ||||||
|  |   LOG_PIN("  Reset Pin: ", this->reset_pin_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Initial Brightness: %.2f", this->brightness_); | ||||||
|  |   LOG_UPDATE_INTERVAL(this); | ||||||
|  | } | ||||||
|  | void SPISSD1351::command(uint8_t value) { | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->digital_write(true); | ||||||
|  |   this->dc_pin_->digital_write(false); | ||||||
|  |   delay(1); | ||||||
|  |   this->enable(); | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->digital_write(false); | ||||||
|  |   this->write_byte(value); | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->digital_write(true); | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  | void SPISSD1351::data(uint8_t value) { | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->digital_write(true); | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   delay(1); | ||||||
|  |   this->enable(); | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->digital_write(false); | ||||||
|  |   this->write_byte(value); | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->digital_write(true); | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  | void HOT SPISSD1351::write_display_data() { | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->digital_write(true); | ||||||
|  |   this->dc_pin_->digital_write(true); | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->digital_write(false); | ||||||
|  |   delay(1); | ||||||
|  |   this->enable(); | ||||||
|  |   this->write_array(this->buffer_, this->get_buffer_length_()); | ||||||
|  |   if (this->cs_) | ||||||
|  |     this->cs_->digital_write(true); | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace ssd1351_spi | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										30
									
								
								esphome/components/ssd1351_spi/ssd1351_spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								esphome/components/ssd1351_spi/ssd1351_spi.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/ssd1351_base/ssd1351_base.h" | ||||||
|  | #include "esphome/components/spi/spi.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ssd1351_spi { | ||||||
|  |  | ||||||
|  | class SPISSD1351 : public ssd1351_base::SSD1351, | ||||||
|  |                    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) { dc_pin_ = dc_pin; } | ||||||
|  |  | ||||||
|  |   void setup() override; | ||||||
|  |  | ||||||
|  |   void dump_config() override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void command(uint8_t value) override; | ||||||
|  |   void data(uint8_t value) override; | ||||||
|  |  | ||||||
|  |   void write_display_data() override; | ||||||
|  |  | ||||||
|  |   GPIOPin *dc_pin_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace ssd1351_spi | ||||||
|  | }  // namespace esphome | ||||||
| @@ -1594,6 +1594,13 @@ display: | |||||||
|   reset_pin: GPIO23 |   reset_pin: GPIO23 | ||||||
|   lambda: |- |   lambda: |- | ||||||
|     it.rectangle(0, 0, it.get_width(), it.get_height()); |     it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||||
|  | - platform: ssd1351_spi | ||||||
|  |   model: "SSD1351 128x128" | ||||||
|  |   cs_pin: GPIO23 | ||||||
|  |   dc_pin: GPIO23 | ||||||
|  |   reset_pin: GPIO23 | ||||||
|  |   lambda: |- | ||||||
|  |     it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||||
| - platform: waveshare_epaper | - platform: waveshare_epaper | ||||||
|   cs_pin: GPIO23 |   cs_pin: GPIO23 | ||||||
|   dc_pin: GPIO23 |   dc_pin: GPIO23 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user