ESPHome 2025.12.0-dev
Loading...
Searching...
No Matches
epaper_spi_spectra_e6.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4
5#include "esphome/core/log.h"
6
7namespace esphome::epaper_spi {
8static constexpr const char *const TAG = "epaper_spi.6c";
9static constexpr size_t MAX_TRANSFER_SIZE = 128;
10static constexpr unsigned char GRAY_THRESHOLD = 50;
11
23
24static uint8_t color_to_hex(Color color) {
25 // --- Step 1: Check for Grayscale (Black or White) ---
26 // We define "grayscale" as a color where the min and max components
27 // are close to each other.
28 unsigned char max_rgb = std::max({color.r, color.g, color.b});
29 unsigned char min_rgb = std::min({color.r, color.g, color.b});
30
31 if ((max_rgb - min_rgb) < GRAY_THRESHOLD) {
32 // It's a shade of gray. Map to BLACK or WHITE.
33 // We split the luminance at the halfway point (382 = (255*3)/2)
34 if ((static_cast<int>(color.r) + color.g + color.b) > 382) {
35 return WHITE;
36 }
37 return BLACK;
38 }
39 // --- Step 2: Check for Primary/Secondary Colors ---
40 // If it's not gray, it's a color. We check which components are
41 // "on" (over 128) vs "off". This divides the RGB cube into 8 corners.
42 bool r_on = (color.r > 128);
43 bool g_on = (color.g > 128);
44 bool b_on = (color.b > 128);
45
46 if (r_on && g_on && !b_on) {
47 return YELLOW;
48 }
49 if (r_on && !g_on && !b_on) {
50 return RED;
51 }
52 if (!r_on && g_on && !b_on) {
53 return GREEN;
54 }
55 if (!r_on && !g_on && b_on) {
56 return BLUE;
57 }
58 // Handle "impure" colors (Cyan, Magenta)
59 if (!r_on && g_on && b_on) {
60 // Cyan (G+B) -> Closest is Green or Blue. Pick Green.
61 return GREEN;
62 }
63 if (r_on && !g_on) {
64 // Magenta (R+B) -> Closest is Red or Blue. Pick Red.
65 return RED;
66 }
67 // Handle the remaining corners (White-ish, Black-ish)
68 if (r_on) {
69 // All high (but not gray) -> White
70 return WHITE;
71 }
72 // !r_on && !g_on && !b_on
73 // All low (but not gray) -> Black
74 return BLACK;
75}
76
78 ESP_LOGD(TAG, "Power on");
79 this->command(0x04);
80}
81
83 ESP_LOGD(TAG, "Power off");
84 this->command(0x02);
85 this->data(0x00);
86}
87
89 ESP_LOGD(TAG, "Refresh");
90 this->command(0x12);
91 this->data(0x00);
92}
93
95 ESP_LOGD(TAG, "Deep sleep");
96 this->command(0x07);
97 this->data(0xA5);
98}
99
101 auto pixel_color = color_to_hex(color);
102
103 // We store 2 pixels per byte
104 this->buffer_.fill(pixel_color + (pixel_color << 4));
105}
106
108 // clear buffer to white, just like real paper.
109 this->fill(COLOR_ON);
110}
111
113 if (x >= this->width_ || y >= this->height_ || x < 0 || y < 0)
114 return;
115
116 auto pixel_bits = color_to_hex(color);
117 uint32_t pixel_position = x + y * this->get_width_controller();
118 uint32_t byte_position = pixel_position / 2;
119 auto original = this->buffer_[byte_position];
120 if ((pixel_position & 1) != 0) {
121 this->buffer_[byte_position] = (original & 0xF0) | pixel_bits;
122 } else {
123 this->buffer_[byte_position] = (original & 0x0F) | (pixel_bits << 4);
124 }
125}
126
128 const uint32_t start_time = App.get_loop_component_start_time();
129 const size_t buffer_length = this->buffer_length_;
130 if (this->current_data_index_ == 0) {
131#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
133#endif
134 ESP_LOGV(TAG, "Start sending data at %ums", (unsigned) millis());
135 this->command(0x10);
136 }
137
138 size_t buf_idx = 0;
139 uint8_t bytes_to_send[MAX_TRANSFER_SIZE];
140 while (this->current_data_index_ != buffer_length) {
141 bytes_to_send[buf_idx++] = this->buffer_[this->current_data_index_++];
142
143 if (buf_idx == sizeof bytes_to_send) {
144 this->start_data_();
145 this->write_array(bytes_to_send, buf_idx);
146 this->end_data_();
147 ESP_LOGV(TAG, "Wrote %d bytes at %ums", buf_idx, (unsigned) millis());
148 buf_idx = 0;
149
150 if (millis() - start_time > MAX_TRANSFER_TIME) {
151 // Let the main loop run and come back next loop
152 return false;
153 }
154 }
155 }
156 // Finished the entire dataset
157 if (buf_idx != 0) {
158 this->start_data_();
159 this->write_array(bytes_to_send, buf_idx);
160 this->end_data_();
161 }
162 this->current_data_index_ = 0;
163 ESP_LOGV(TAG, "Sent data in %" PRIu32 " ms", millis() - this->transfer_start_time_);
164 return true;
165}
166} // namespace esphome::epaper_spi
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void command(uint8_t value)
split_buffer::SplitBuffer buffer_
Definition epaper_spi.h:136
void draw_absolute_pixel_internal(int x, int y, Color color) override
void fill(uint8_t value) const
Fill the entire buffer with a single byte value.
const Color COLOR_ON(255, 255, 255, 255)
Turn the pixel ON.
Definition display.h:303
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:30
Application App
Global storage of Application pointer - only one Application can exist.
uint8_t g
Definition color.h:34
uint8_t b
Definition color.h:38
uint8_t r
Definition color.h:30
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6