From ac25b138f55c56bdba9a7dd0937e8858cdef18b3 Mon Sep 17 00:00:00 2001 From: SenexCrenshaw <35600301+SenexCrenshaw@users.noreply.github.com> Date: Tue, 2 Mar 2021 09:08:57 -0500 Subject: [PATCH] Migrate ESPColor to Color (#1551) * Migrate ESPColor to Color * color.h constructor fix * Updated componets to use Color Added a using for ESPColor * Lint fixes * Fixed value error * Update display components to use colorutil * Updated to latest PR comments * Fixed COLOR_WHITE * Moved esp_scale to color_utils * Rename color_utils to display_color_utils --- .../adalight/adalight_light_effect.cpp | 6 +- .../adalight/adalight_light_effect.h | 2 +- esphome/components/color/__init__.py | 60 ++++-- esphome/components/display/display_buffer.h | 2 +- .../components/display/display_color_utils.h | 110 +++++++++++ .../e131/e131_addressable_light_effect.cpp | 10 +- .../e131/e131_addressable_light_effect.h | 2 +- .../components/ili9341/ili9341_display.cpp | 6 +- .../components/light/addressable_light.cpp | 17 +- esphome/components/light/addressable_light.h | 183 ++---------------- .../light/addressable_light_effect.h | 46 ++--- esphome/components/light/effects.py | 5 +- esphome/components/light/types.py | 2 +- .../neopixelbus/neopixelbus_light.h | 3 +- .../components/ssd1322_base/ssd1322_base.cpp | 4 +- .../components/ssd1325_base/ssd1325_base.cpp | 4 +- .../components/ssd1327_base/ssd1327_base.cpp | 4 +- .../components/ssd1331_base/ssd1331_base.cpp | 4 +- .../components/ssd1351_base/ssd1351_base.cpp | 4 +- esphome/components/st7735/st7735.cpp | 12 +- esphome/components/st7789v/st7789v.cpp | 2 +- esphome/components/wled/wled_light_effect.cpp | 12 +- esphome/components/wled/wled_light_effect.h | 2 +- esphome/core/color.h | 137 ++----------- tests/test1.yaml | 2 +- 25 files changed, 272 insertions(+), 369 deletions(-) create mode 100644 esphome/components/display/display_color_utils.h diff --git a/esphome/components/adalight/adalight_light_effect.cpp b/esphome/components/adalight/adalight_light_effect.cpp index 1bf357e308..d162c90721 100644 --- a/esphome/components/adalight/adalight_light_effect.cpp +++ b/esphome/components/adalight/adalight_light_effect.cpp @@ -42,11 +42,11 @@ void AdalightLightEffect::reset_frame_(light::AddressableLight &it) { void AdalightLightEffect::blank_all_leds_(light::AddressableLight &it) { for (int led = it.size(); led-- > 0;) { - it[led].set(light::ESPColor::BLACK); + it[led].set(COLOR_BLACK); } } -void AdalightLightEffect::apply(light::AddressableLight &it, const light::ESPColor ¤t_color) { +void AdalightLightEffect::apply(light::AddressableLight &it, const Color ¤t_color) { const uint32_t now = millis(); if (now - this->last_ack_ >= ADALIGHT_ACK_INTERVAL) { @@ -130,7 +130,7 @@ AdalightLightEffect::Frame AdalightLightEffect::parse_frame_(light::AddressableL for (int led = 0; led < accepted_led_count; led++, led_data += 3) { auto white = std::min(std::min(led_data[0], led_data[1]), led_data[2]); - it[led].set(light::ESPColor(led_data[0], led_data[1], led_data[2], white)); + it[led].set(Color(led_data[0], led_data[1], led_data[2], white)); } return CONSUMED; diff --git a/esphome/components/adalight/adalight_light_effect.h b/esphome/components/adalight/adalight_light_effect.h index 4f77394ebc..c1df55659b 100644 --- a/esphome/components/adalight/adalight_light_effect.h +++ b/esphome/components/adalight/adalight_light_effect.h @@ -16,7 +16,7 @@ class AdalightLightEffect : public light::AddressableLightEffect, public uart::U public: void start() override; void stop() override; - void apply(light::AddressableLight &it, const light::ESPColor ¤t_color) override; + void apply(light::AddressableLight &it, const Color ¤t_color) override; protected: enum Frame { diff --git a/esphome/components/color/__init__.py b/esphome/components/color/__init__.py index 3e2e7b2c07..db2fc6c093 100644 --- a/esphome/components/color/__init__.py +++ b/esphome/components/color/__init__.py @@ -2,22 +2,58 @@ 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') +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) + +CONF_RED_INT = "red_int" +CONF_GREEN_INT = "green_int" +CONF_BLUE_INT = "blue_int" +CONF_WHITE_INT = "white_int" + +CONFIG_SCHEMA = cv.Schema( + { + cv.Required(CONF_ID): cv.declare_id(ColorStruct), + cv.Exclusive(CONF_RED, 'red'): cv.percentage, + cv.Exclusive(CONF_RED_INT, 'red'): cv.uint8_t, + cv.Exclusive(CONF_GREEN, 'green'): cv.percentage, + cv.Exclusive(CONF_GREEN_INT, 'green'): cv.uint8_t, + cv.Exclusive(CONF_BLUE, 'blue'): cv.percentage, + cv.Exclusive(CONF_BLUE_INT, 'blue'): cv.uint8_t, + cv.Exclusive(CONF_WHITE, 'white'): cv.percentage, + cv.Exclusive(CONF_WHITE_INT, 'white'): cv.uint8_t, + } +).extend(cv.COMPONENT_SCHEMA) def to_code(config): + r = 0 + if CONF_RED in config: + r = int(config[CONF_RED]*255) + elif CONF_RED_INT in config: + r = config[CONF_RED_INT] + + g = 0 + if CONF_GREEN in config: + g = int(config[CONF_GREEN]*255) + elif CONF_GREEN_INT in config: + g = config[CONF_GREEN_INT] + + b = 0 + if CONF_BLUE in config: + b = int(config[CONF_BLUE]*255) + elif CONF_BLUE_INT in config: + b = config[CONF_BLUE_INT] + + w = 0 + if CONF_WHITE in config: + w = int(config[CONF_WHITE]*255) + elif CONF_WHITE_INT in config: + w = config[CONF_WHITE_INT] + cg.variable(config[CONF_ID], cg.StructInitializer( ColorStruct, - ('r', config[CONF_RED]), - ('g', config[CONF_GREEN]), - ('b', config[CONF_BLUE]), - ('w', config[CONF_WHITE]))) + ('r', r), + ('g', g), + ('b', b), + ('w', w))) diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 235224d42e..5a63441e2d 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -3,7 +3,7 @@ #include "esphome/core/component.h" #include "esphome/core/defines.h" #include "esphome/core/automation.h" -#include "esphome/core/color.h" +#include "display_color_utils.h" #ifdef USE_TIME #include "esphome/components/time/real_time_clock.h" diff --git a/esphome/components/display/display_color_utils.h b/esphome/components/display/display_color_utils.h new file mode 100644 index 0000000000..8fc3b0adb9 --- /dev/null +++ b/esphome/components/display/display_color_utils.h @@ -0,0 +1,110 @@ +#pragma once +#include "esphome/core/color.h" + +namespace esphome { +namespace display { +enum ColorOrder : uint8_t { COLOR_ORDER_RGB = 0, COLOR_ORDER_BGR = 1, COLOR_ORDER_GRB = 2 }; +enum ColorBitness : uint8_t { COLOR_BITNESS_888 = 0, COLOR_BITNESS_565 = 1, COLOR_BITNESS_332 = 2 }; +inline static uint8_t esp_scale(uint8_t i, uint8_t scale, uint8_t max_value = 255) { return (max_value * i / scale); } + +class ColorUtil { + public: + static Color to_color(uint32_t colorcode, ColorOrder color_order, + ColorBitness color_bitness = ColorBitness::COLOR_BITNESS_888, bool right_bit_aligned = true) { + uint8_t first_color, second_color, third_color; + uint8_t first_bits = 0; + uint8_t second_bits = 0; + uint8_t third_bits = 0; + + switch (color_bitness) { + case COLOR_BITNESS_888: + first_bits = 8; + second_bits = 8; + third_bits = 8; + break; + case COLOR_BITNESS_565: + first_bits = 5; + second_bits = 6; + third_bits = 5; + break; + case COLOR_BITNESS_332: + first_bits = 3; + second_bits = 3; + third_bits = 2; + break; + } + + first_color = right_bit_aligned ? esp_scale(((colorcode >> (second_bits + third_bits)) & ((1 << first_bits) - 1)), + ((1 << first_bits) - 1)) + : esp_scale(((colorcode >> 16) & 0xFF), (1 << first_bits) - 1); + + second_color = right_bit_aligned + ? esp_scale(((colorcode >> third_bits) & ((1 << second_bits) - 1)), ((1 << second_bits) - 1)) + : esp_scale(((colorcode >> 8) & 0xFF), ((1 << second_bits) - 1)); + + third_color = (right_bit_aligned ? esp_scale(((colorcode >> 0) & 0xFF), ((1 << third_bits) - 1)) + : esp_scale(((colorcode >> 0) & 0xFF), (1 << third_bits) - 1)); + + Color color_return; + + switch (color_order) { + case COLOR_ORDER_RGB: + color_return.r = first_color; + color_return.g = second_color; + color_return.b = third_color; + break; + case COLOR_ORDER_BGR: + color_return.b = first_color; + color_return.g = second_color; + color_return.r = third_color; + break; + case COLOR_ORDER_GRB: + color_return.g = first_color; + color_return.r = second_color; + color_return.b = third_color; + break; + } + return color_return; + } + static uint8_t color_to_332(Color color, ColorOrder color_order = ColorOrder::COLOR_ORDER_RGB) { + uint16_t red_color, green_color, blue_color; + + red_color = esp_scale8(color.red, ((1 << 3) - 1)); + green_color = esp_scale8(color.green, ((1 << 3) - 1)); + blue_color = esp_scale8(color.blue, (1 << 2) - 1); + + switch (color_order) { + case COLOR_ORDER_RGB: + return red_color << 5 | green_color << 2 | blue_color; + case COLOR_ORDER_BGR: + return blue_color << 6 | green_color << 3 | red_color; + case COLOR_ORDER_GRB: + return green_color << 5 | red_color << 2 | blue_color; + } + return 0; + } + static uint16_t color_to_565(Color color, ColorOrder color_order = ColorOrder::COLOR_ORDER_RGB) { + uint16_t red_color, green_color, blue_color; + + red_color = esp_scale8(color.red, ((1 << 5) - 1)); + green_color = esp_scale8(color.green, ((1 << 6) - 1)); + blue_color = esp_scale8(color.blue, (1 << 5) - 1); + + switch (color_order) { + case COLOR_ORDER_RGB: + return red_color << 11 | green_color << 5 | blue_color; + case COLOR_ORDER_BGR: + return blue_color << 11 | green_color << 5 | red_color; + case COLOR_ORDER_GRB: + return green_color << 10 | red_color << 5 | blue_color; + } + return 0; + } + + static uint32_t color_to_grayscale4(Color color) { + uint32_t gs4 = esp_scale8(color.white, 15); + return gs4; + } +}; +} // namespace display +} // namespace esphome diff --git a/esphome/components/e131/e131_addressable_light_effect.cpp b/esphome/components/e131/e131_addressable_light_effect.cpp index 8657d828c5..3283f71931 100644 --- a/esphome/components/e131/e131_addressable_light_effect.cpp +++ b/esphome/components/e131/e131_addressable_light_effect.cpp @@ -40,7 +40,7 @@ void E131AddressableLightEffect::stop() { AddressableLightEffect::stop(); } -void E131AddressableLightEffect::apply(light::AddressableLight &it, const light::ESPColor ¤t_color) { +void E131AddressableLightEffect::apply(light::AddressableLight &it, const Color ¤t_color) { // ignore, it is run by `E131Component::update()` } @@ -63,22 +63,22 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet case E131_MONO: for (; output_offset < output_end; output_offset++, input_data++) { auto output = (*it)[output_offset]; - output.set(light::ESPColor(input_data[0], input_data[0], input_data[0], input_data[0])); + output.set(Color(input_data[0], input_data[0], input_data[0], input_data[0])); } break; case E131_RGB: for (; output_offset < output_end; output_offset++, input_data += 3) { auto output = (*it)[output_offset]; - output.set(light::ESPColor(input_data[0], input_data[1], input_data[2], - (input_data[0] + input_data[1] + input_data[2]) / 3)); + output.set( + Color(input_data[0], input_data[1], input_data[2], (input_data[0] + input_data[1] + input_data[2]) / 3)); } break; case E131_RGBW: for (; output_offset < output_end; output_offset++, input_data += 4) { auto output = (*it)[output_offset]; - output.set(light::ESPColor(input_data[0], input_data[1], input_data[2], input_data[3])); + output.set(Color(input_data[0], input_data[1], input_data[2], input_data[3])); } break; } diff --git a/esphome/components/e131/e131_addressable_light_effect.h b/esphome/components/e131/e131_addressable_light_effect.h index 85af4fe7a9..1ab5d43164 100644 --- a/esphome/components/e131/e131_addressable_light_effect.h +++ b/esphome/components/e131/e131_addressable_light_effect.h @@ -18,7 +18,7 @@ class E131AddressableLightEffect : public light::AddressableLightEffect { public: void start() override; void stop() override; - void apply(light::AddressableLight &it, const light::ESPColor ¤t_color) override; + void apply(light::AddressableLight &it, const Color ¤t_color) override; public: int get_data_per_universe() const; diff --git a/esphome/components/ili9341/ili9341_display.cpp b/esphome/components/ili9341/ili9341_display.cpp index c0e7873284..48a95f4df0 100644 --- a/esphome/components/ili9341/ili9341_display.cpp +++ b/esphome/components/ili9341/ili9341_display.cpp @@ -130,7 +130,7 @@ uint8_t ILI9341Display::convert_to_8bit_color_(uint16_t color_16bit) { } void ILI9341Display::fill(Color color) { - auto color565 = color.to_rgb_565(); + auto color565 = display::ColorUtil::color_to_565(color); memset(this->buffer_, convert_to_8bit_color_(color565), this->get_buffer_length_()); this->x_low_ = 0; this->y_low_ = 0; @@ -142,7 +142,7 @@ void ILI9341Display::fill_internal_(Color color) { this->set_addr_window_(0, 0, this->get_width_internal(), this->get_height_internal()); this->start_data_(); - auto color565 = color.to_rgb_565(); + auto color565 = display::ColorUtil::color_to_565(color); for (uint32_t i = 0; i < (this->get_width_internal()) * (this->get_height_internal()); i++) { this->write_byte(color565 >> 8); this->write_byte(color565); @@ -162,7 +162,7 @@ void HOT ILI9341Display::draw_absolute_pixel_internal(int x, int y, Color color) this->y_high_ = (y > this->y_high_) ? y : this->y_high_; uint32_t pos = (y * width_) + x; - auto color565 = color.to_rgb_565(); + auto color565 = display::ColorUtil::color_to_565(color); buffer_[pos] = convert_to_8bit_color_(color565); } diff --git a/esphome/components/light/addressable_light.cpp b/esphome/components/light/addressable_light.cpp index b5dc70a083..236e5cede6 100644 --- a/esphome/components/light/addressable_light.cpp +++ b/esphome/components/light/addressable_light.cpp @@ -6,10 +6,7 @@ namespace light { static const char *TAG = "light.addressable"; -const ESPColor ESPColor::BLACK = ESPColor(0, 0, 0, 0); -const ESPColor ESPColor::WHITE = ESPColor(255, 255, 255, 255); - -ESPColor ESPHSVColor::to_rgb() const { +Color ESPHSVColor::to_rgb() const { // based on FastLED's hsv rainbow to rgb const uint8_t hue = this->hue; const uint8_t sat = this->saturation; @@ -19,7 +16,7 @@ ESPColor ESPHSVColor::to_rgb() const { // third of the offset, 255/3 = 85 (actually only up to 82; 164) const uint8_t third = esp_scale8(offset8, 85); const uint8_t two_thirds = esp_scale8(offset8, 170); - ESPColor rgb(255, 255, 255, 0); + Color rgb(255, 255, 255, 0); switch (hue >> 5) { case 0b000: rgb.r = 255 - third; @@ -76,7 +73,7 @@ ESPColor ESPHSVColor::to_rgb() const { return rgb; } -void ESPRangeView::set(const ESPColor &color) { +void ESPRangeView::set(const Color &color) { for (int32_t i = this->begin_; i < this->end_; i++) { (*this->parent_)[i] = color; } @@ -179,12 +176,12 @@ void AddressableLight::call_setup() { #endif } -ESPColor esp_color_from_light_color_values(LightColorValues val) { +Color esp_color_from_light_color_values(LightColorValues val) { auto r = static_cast(roundf(val.get_red() * 255.0f)); auto g = static_cast(roundf(val.get_green() * 255.0f)); auto b = static_cast(roundf(val.get_blue() * 255.0f)); auto w = static_cast(roundf(val.get_white() * val.get_state() * 255.0f)); - return ESPColor(r, g, b, w); + return Color(r, g, b, w); } void AddressableLight::write_state(LightState *state) { @@ -219,7 +216,7 @@ void AddressableLight::write_state(LightState *state) { this->last_transition_progress_ = new_progress; auto end_values = state->transformer_->get_end_values(); - ESPColor target_color = esp_color_from_light_color_values(end_values); + Color target_color = esp_color_from_light_color_values(end_values); // our transition will handle brightness, disable brightness in correction. this->correction_.set_local_brightness(255); @@ -247,7 +244,7 @@ void AddressableLight::write_state(LightState *state) { if (alpha8 != 0) { uint8_t inv_alpha8 = 255 - alpha8; - ESPColor add = target_color * alpha8; + Color add = target_color * alpha8; for (auto led : *this) led = add + led.get() * inv_alpha8; diff --git a/esphome/components/light/addressable_light.h b/esphome/components/light/addressable_light.h index 4e7ec4b931..39bd905c65 100644 --- a/esphome/components/light/addressable_light.h +++ b/esphome/components/light/addressable_light.h @@ -2,6 +2,7 @@ #include "esphome/core/component.h" #include "esphome/core/defines.h" +#include "esphome/core/color.h" #include "light_output.h" #include "light_state.h" @@ -12,151 +13,7 @@ namespace esphome { namespace light { -inline static uint8_t esp_scale8(uint8_t i, uint8_t scale) { return (uint16_t(i) * (1 + uint16_t(scale))) / 256; } - -struct ESPColor { - 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 ESPColor() ALWAYS_INLINE : r(0), g(0), b(0), w(0) {} // NOLINT - inline ESPColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) ALWAYS_INLINE : r(red), - g(green), - b(blue), - w(white) {} - inline ESPColor(uint8_t red, uint8_t green, uint8_t blue) ALWAYS_INLINE : r(red), g(green), b(blue), w(0) {} - inline ESPColor(uint32_t colorcode) ALWAYS_INLINE : r((colorcode >> 16) & 0xFF), - g((colorcode >> 8) & 0xFF), - b((colorcode >> 0) & 0xFF), - w((colorcode >> 24) & 0xFF) {} - inline ESPColor(const ESPColor &rhs) ALWAYS_INLINE { - this->r = rhs.r; - this->g = rhs.g; - this->b = rhs.b; - this->w = rhs.w; - } - inline bool is_on() ALWAYS_INLINE { return this->raw_32 != 0; } - inline ESPColor &operator=(const ESPColor &rhs) ALWAYS_INLINE { - this->r = rhs.r; - this->g = rhs.g; - this->b = rhs.b; - this->w = rhs.w; - return *this; - } - inline ESPColor &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 ESPColor operator*(uint8_t scale) const ALWAYS_INLINE { - return ESPColor(esp_scale8(this->red, scale), esp_scale8(this->green, scale), esp_scale8(this->blue, scale), - esp_scale8(this->white, scale)); - } - inline ESPColor &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 ESPColor operator*(const ESPColor &scale) const ALWAYS_INLINE { - return ESPColor(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 ESPColor &operator*=(const ESPColor &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 ESPColor operator+(const ESPColor &add) const ALWAYS_INLINE { - ESPColor 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 ESPColor &operator+=(const ESPColor &add) ALWAYS_INLINE { return *this = (*this) + add; } - inline ESPColor operator+(uint8_t add) const ALWAYS_INLINE { return (*this) + ESPColor(add, add, add, add); } - inline ESPColor &operator+=(uint8_t add) ALWAYS_INLINE { return *this = (*this) + add; } - inline ESPColor operator-(const ESPColor &subtract) const ALWAYS_INLINE { - ESPColor 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 ESPColor &operator-=(const ESPColor &subtract) ALWAYS_INLINE { return *this = (*this) - subtract; } - inline ESPColor operator-(uint8_t subtract) const ALWAYS_INLINE { - return (*this) - ESPColor(subtract, subtract, subtract, subtract); - } - inline ESPColor &operator-=(uint8_t subtract) ALWAYS_INLINE { return *this = (*this) - subtract; } - static ESPColor random_color() { - uint32_t rand = random_uint32(); - uint8_t w = rand >> 24; - uint8_t r = rand >> 16; - uint8_t g = rand >> 8; - uint8_t b = rand >> 0; - const uint16_t max_rgb = std::max(r, std::max(g, b)); - return ESPColor(uint8_t((uint16_t(r) * 255U / max_rgb)), uint8_t((uint16_t(g) * 255U / max_rgb)), - uint8_t((uint16_t(b) * 255U / max_rgb)), w); - } - ESPColor fade_to_white(uint8_t amnt) const { return ESPColor(255, 255, 255, 255) - (*this * amnt); } - ESPColor fade_to_black(uint8_t amnt) const { return *this * amnt; } - ESPColor lighten(uint8_t delta) const { return *this + delta; } - ESPColor darken(uint8_t delta) const { return *this - delta; } - - static const ESPColor BLACK; - static const ESPColor WHITE; -}; +using ESPColor = Color; struct ESPHSVColor { union { @@ -181,19 +38,19 @@ struct ESPHSVColor { inline ESPHSVColor(uint8_t hue, uint8_t saturation, uint8_t value) ALWAYS_INLINE : hue(hue), saturation(saturation), value(value) {} - ESPColor to_rgb() const; + Color to_rgb() const; }; class ESPColorCorrection { public: ESPColorCorrection() : max_brightness_(255, 255, 255, 255) {} - void set_max_brightness(const ESPColor &max_brightness) { this->max_brightness_ = max_brightness; } + void set_max_brightness(const Color &max_brightness) { this->max_brightness_ = max_brightness; } void set_local_brightness(uint8_t local_brightness) { this->local_brightness_ = local_brightness; } void calculate_gamma_table(float gamma); - inline ESPColor color_correct(ESPColor color) const ALWAYS_INLINE { + inline Color color_correct(Color color) const ALWAYS_INLINE { // corrected = (uncorrected * max_brightness * local_brightness) ^ gamma - return ESPColor(this->color_correct_red(color.red), this->color_correct_green(color.green), - this->color_correct_blue(color.blue), this->color_correct_white(color.white)); + return Color(this->color_correct_red(color.red), this->color_correct_green(color.green), + this->color_correct_blue(color.blue), this->color_correct_white(color.white)); } inline uint8_t color_correct_red(uint8_t red) const ALWAYS_INLINE { uint8_t res = esp_scale8(esp_scale8(red, this->max_brightness_.red), this->local_brightness_); @@ -212,10 +69,10 @@ class ESPColorCorrection { uint8_t res = esp_scale8(white, this->max_brightness_.white); return this->gamma_table_[res]; } - inline ESPColor color_uncorrect(ESPColor color) const ALWAYS_INLINE { + inline Color color_uncorrect(Color color) const ALWAYS_INLINE { // uncorrected = corrected^(1/gamma) / (max_brightness * local_brightness) - return ESPColor(this->color_uncorrect_red(color.red), this->color_uncorrect_green(color.green), - this->color_uncorrect_blue(color.blue), this->color_uncorrect_white(color.white)); + return Color(this->color_uncorrect_red(color.red), this->color_uncorrect_green(color.green), + this->color_uncorrect_blue(color.blue), this->color_uncorrect_white(color.white)); } inline uint8_t color_uncorrect_red(uint8_t red) const ALWAYS_INLINE { if (this->max_brightness_.red == 0 || this->local_brightness_ == 0) @@ -249,13 +106,13 @@ class ESPColorCorrection { protected: uint8_t gamma_table_[256]; uint8_t gamma_reverse_table_[256]; - ESPColor max_brightness_; + Color max_brightness_; uint8_t local_brightness_{255}; }; class ESPColorSettable { public: - virtual void set(const ESPColor &color) = 0; + virtual void set(const Color &color) = 0; virtual void set_red(uint8_t red) = 0; virtual void set_green(uint8_t green) = 0; virtual void set_blue(uint8_t blue) = 0; @@ -267,7 +124,7 @@ class ESPColorSettable { virtual void darken(uint8_t delta) = 0; void set(const ESPHSVColor &color) { this->set_hsv(color); } void set_hsv(const ESPHSVColor &color) { - ESPColor rgb = color.to_rgb(); + Color rgb = color.to_rgb(); this->set_rgb(rgb.r, rgb.g, rgb.b); } void set_rgb(uint8_t red, uint8_t green, uint8_t blue) { @@ -291,7 +148,7 @@ class ESPColorView : public ESPColorSettable { white_(white), effect_data_(effect_data), color_correction_(color_correction) {} - ESPColorView &operator=(const ESPColor &rhs) { + ESPColorView &operator=(const Color &rhs) { this->set(rhs); return *this; } @@ -299,7 +156,7 @@ class ESPColorView : public ESPColorSettable { this->set_hsv(rhs); return *this; } - void set(const ESPColor &color) override { this->set_rgbw(color.r, color.g, color.b, color.w); } + void set(const Color &color) override { this->set_rgbw(color.r, color.g, color.b, color.w); } void set_red(uint8_t red) override { *this->red_ = this->color_correction_->color_correct_red(red); } void set_green(uint8_t green) override { *this->green_ = this->color_correction_->color_correct_green(green); } void set_blue(uint8_t blue) override { *this->blue_ = this->color_correction_->color_correct_blue(blue); } @@ -317,7 +174,7 @@ class ESPColorView : public ESPColorSettable { void fade_to_black(uint8_t amnt) override { this->set(this->get().fade_to_black(amnt)); } void lighten(uint8_t delta) override { this->set(this->get().lighten(delta)); } void darken(uint8_t delta) override { this->set(this->get().darken(delta)); } - ESPColor get() const { return ESPColor(this->get_red(), this->get_green(), this->get_blue(), this->get_white()); } + Color get() const { return Color(this->get_red(), this->get_green(), this->get_blue(), this->get_white()); } uint8_t get_red() const { return this->color_correction_->color_uncorrect_red(*this->red_); } uint8_t get_red_raw() const { return *this->red_; } uint8_t get_green() const { return this->color_correction_->color_uncorrect_green(*this->green_); } @@ -370,8 +227,8 @@ class ESPRangeView : public ESPColorSettable { ESPRangeIterator begin(); ESPRangeIterator end(); - void set(const ESPColor &color) override; - ESPRangeView &operator=(const ESPColor &rhs) { + void set(const Color &color) override; + ESPRangeView &operator=(const Color &rhs) { this->set(rhs); return *this; } @@ -454,8 +311,8 @@ class AddressableLight : public LightOutput, public Component { void set_effect_active(bool effect_active) { this->effect_active_ = effect_active; } void write_state(LightState *state) override; void set_correction(float red, float green, float blue, float white = 1.0f) { - this->correction_.set_max_brightness(ESPColor(uint8_t(roundf(red * 255.0f)), uint8_t(roundf(green * 255.0f)), - uint8_t(roundf(blue * 255.0f)), uint8_t(roundf(white * 255.0f)))); + this->correction_.set_max_brightness(Color(uint8_t(roundf(red * 255.0f)), uint8_t(roundf(green * 255.0f)), + uint8_t(roundf(blue * 255.0f)), uint8_t(roundf(white * 255.0f)))); } void setup_state(LightState *state) override { this->correction_.calculate_gamma_table(state->get_gamma_correct()); diff --git a/esphome/components/light/addressable_light_effect.h b/esphome/components/light/addressable_light_effect.h index e6528fcd8a..8d4d37ec34 100644 --- a/esphome/components/light/addressable_light_effect.h +++ b/esphome/components/light/addressable_light_effect.h @@ -34,13 +34,13 @@ class AddressableLightEffect : public LightEffect { this->start(); } void stop() override { this->get_addressable_()->set_effect_active(false); } - virtual void apply(AddressableLight &it, const ESPColor ¤t_color) = 0; + virtual void apply(AddressableLight &it, const Color ¤t_color) = 0; void apply() override { LightColorValues color = this->state_->remote_values; // not using any color correction etc. that will be handled by the addressable layer - ESPColor current_color = - ESPColor(static_cast(color.get_red() * 255), static_cast(color.get_green() * 255), - static_cast(color.get_blue() * 255), static_cast(color.get_white() * 255)); + Color current_color = + Color(static_cast(color.get_red() * 255), static_cast(color.get_green() * 255), + static_cast(color.get_blue() * 255), static_cast(color.get_white() * 255)); this->apply(*this->get_addressable_(), current_color); } @@ -51,11 +51,11 @@ class AddressableLightEffect : public LightEffect { class AddressableLambdaLightEffect : public AddressableLightEffect { public: AddressableLambdaLightEffect(const std::string &name, - const std::function &f, + const std::function &f, uint32_t update_interval) : AddressableLightEffect(name), f_(f), update_interval_(update_interval) {} void start() override { this->initial_run_ = true; } - void apply(AddressableLight &it, const ESPColor ¤t_color) override { + void apply(AddressableLight &it, const Color ¤t_color) override { const uint32_t now = millis(); if (now - this->last_run_ >= this->update_interval_) { this->last_run_ = now; @@ -65,7 +65,7 @@ class AddressableLambdaLightEffect : public AddressableLightEffect { } protected: - std::function f_; + std::function f_; uint32_t update_interval_; uint32_t last_run_{0}; bool initial_run_; @@ -74,7 +74,7 @@ class AddressableLambdaLightEffect : public AddressableLightEffect { class AddressableRainbowLightEffect : public AddressableLightEffect { public: explicit AddressableRainbowLightEffect(const std::string &name) : AddressableLightEffect(name) {} - void apply(AddressableLight &it, const ESPColor ¤t_color) override { + void apply(AddressableLight &it, const Color ¤t_color) override { ESPHSVColor hsv; hsv.value = 255; hsv.saturation = 240; @@ -106,7 +106,7 @@ class AddressableColorWipeEffect : public AddressableLightEffect { void set_colors(const std::vector &colors) { this->colors_ = colors; } void set_add_led_interval(uint32_t add_led_interval) { this->add_led_interval_ = add_led_interval; } void set_reverse(bool reverse) { this->reverse_ = reverse; } - void apply(AddressableLight &it, const ESPColor ¤t_color) override { + void apply(AddressableLight &it, const Color ¤t_color) override { const uint32_t now = millis(); if (now - this->last_add_ < this->add_led_interval_) return; @@ -116,7 +116,7 @@ class AddressableColorWipeEffect : public AddressableLightEffect { else it.shift_right(1); const AddressableColorWipeEffectColor color = this->colors_[this->at_color_]; - const ESPColor esp_color = ESPColor(color.r, color.g, color.b, color.w); + const Color esp_color = Color(color.r, color.g, color.b, color.w); if (this->reverse_) it[-1] = esp_color; else @@ -126,7 +126,7 @@ class AddressableColorWipeEffect : public AddressableLightEffect { this->at_color_ = (this->at_color_ + 1) % this->colors_.size(); AddressableColorWipeEffectColor &new_color = this->colors_[this->at_color_]; if (new_color.random) { - ESPColor c = ESPColor::random_color(); + Color c = Color::random_color(); new_color.r = c.r; new_color.g = c.g; new_color.b = c.b; @@ -148,8 +148,8 @@ class AddressableScanEffect : public AddressableLightEffect { explicit AddressableScanEffect(const std::string &name) : AddressableLightEffect(name) {} void set_move_interval(uint32_t move_interval) { this->move_interval_ = move_interval; } void set_scan_width(uint32_t scan_width) { this->scan_width_ = scan_width; } - void apply(AddressableLight &it, const ESPColor ¤t_color) override { - it.all() = ESPColor::BLACK; + void apply(AddressableLight &it, const Color ¤t_color) override { + it.all() = COLOR_BLACK; for (auto i = 0; i < this->scan_width_; i++) { it[this->at_led_ + i] = current_color; @@ -181,7 +181,7 @@ class AddressableScanEffect : public AddressableLightEffect { class AddressableTwinkleEffect : public AddressableLightEffect { public: explicit AddressableTwinkleEffect(const std::string &name) : AddressableLightEffect(name) {} - void apply(AddressableLight &addressable, const ESPColor ¤t_color) override { + void apply(AddressableLight &addressable, const Color ¤t_color) override { const uint32_t now = millis(); uint8_t pos_add = 0; if (now - this->last_progress_ > this->progress_interval_) { @@ -199,7 +199,7 @@ class AddressableTwinkleEffect : public AddressableLightEffect { else view.set_effect_data(new_pos); } else { - view = ESPColor::BLACK; + view = COLOR_BLACK; } } while (random_float() < this->twinkle_probability_) { @@ -221,7 +221,7 @@ class AddressableTwinkleEffect : public AddressableLightEffect { class AddressableRandomTwinkleEffect : public AddressableLightEffect { public: explicit AddressableRandomTwinkleEffect(const std::string &name) : AddressableLightEffect(name) {} - void apply(AddressableLight &it, const ESPColor ¤t_color) override { + void apply(AddressableLight &it, const Color ¤t_color) override { const uint32_t now = millis(); uint8_t pos_add = 0; if (now - this->last_progress_ > this->progress_interval_) { @@ -237,7 +237,7 @@ class AddressableRandomTwinkleEffect : public AddressableLightEffect { if (color == 0) { view = current_color * sine; } else { - view = ESPColor(((color >> 2) & 1) * sine, ((color >> 1) & 1) * sine, ((color >> 0) & 1) * sine); + view = Color(((color >> 2) & 1) * sine, ((color >> 1) & 1) * sine, ((color >> 0) & 1) * sine); } const uint8_t new_x = x + pos_add; if (new_x > 0b11111) @@ -245,7 +245,7 @@ class AddressableRandomTwinkleEffect : public AddressableLightEffect { else view.set_effect_data((new_x << 3) | color); } else { - view = ESPColor(0, 0, 0, 0); + view = Color(0, 0, 0, 0); } } while (random_float() < this->twinkle_probability_) { @@ -270,9 +270,9 @@ class AddressableFireworksEffect : public AddressableLightEffect { explicit AddressableFireworksEffect(const std::string &name) : AddressableLightEffect(name) {} void start() override { auto &it = *this->get_addressable_(); - it.all() = ESPColor::BLACK; + it.all() = COLOR_BLACK; } - void apply(AddressableLight &it, const ESPColor ¤t_color) override { + void apply(AddressableLight &it, const Color ¤t_color) override { const uint32_t now = millis(); if (now - this->last_update_ < this->update_interval_) return; @@ -280,7 +280,7 @@ class AddressableFireworksEffect : public AddressableLightEffect { // "invert" the fade out parameter so that higher values make fade out faster const uint8_t fade_out_mult = 255u - this->fade_out_rate_; for (auto view : it) { - ESPColor target = view.get() * fade_out_mult; + Color target = view.get() * fade_out_mult; if (target.r < 64) target *= 170; view = target; @@ -294,7 +294,7 @@ class AddressableFireworksEffect : public AddressableLightEffect { if (random_float() < this->spark_probability_) { const size_t pos = random_uint32() % it.size(); if (this->use_random_color_) { - it[pos] = ESPColor::random_color(); + it[pos] = Color::random_color(); } else { it[pos] = current_color; } @@ -316,7 +316,7 @@ class AddressableFireworksEffect : public AddressableLightEffect { class AddressableFlickerEffect : public AddressableLightEffect { public: explicit AddressableFlickerEffect(const std::string &name) : AddressableLightEffect(name) {} - void apply(AddressableLight &it, const ESPColor ¤t_color) override { + void apply(AddressableLight &it, const Color ¤t_color) override { const uint32_t now = millis(); const uint8_t intensity = this->intensity_; const uint8_t inv_intensity = 255 - intensity; diff --git a/esphome/components/light/effects.py b/esphome/components/light/effects.py index d8c709b8ad..edb7a39ed9 100644 --- a/esphome/components/light/effects.py +++ b/esphome/components/light/effects.py @@ -1,6 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation + from esphome.const import CONF_NAME, CONF_LAMBDA, CONF_UPDATE_INTERVAL, CONF_TRANSITION_LENGTH, \ CONF_COLORS, CONF_STATE, CONF_DURATION, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE, \ CONF_WHITE, CONF_ALPHA, CONF_INTENSITY, CONF_SPEED, CONF_WIDTH, CONF_NUM_LEDS, CONF_RANDOM, \ @@ -11,7 +12,7 @@ from .types import LambdaLightEffect, RandomLightEffect, StrobeLightEffect, \ FlickerLightEffect, AddressableRainbowLightEffect, AddressableColorWipeEffect, \ AddressableColorWipeEffectColor, AddressableScanEffect, AddressableTwinkleEffect, \ AddressableRandomTwinkleEffect, AddressableFireworksEffect, AddressableFlickerEffect, \ - AutomationLightEffect, ESPColor + AutomationLightEffect, Color CONF_ADD_LED_INTERVAL = 'add_led_interval' CONF_REVERSE = 'reverse' @@ -162,7 +163,7 @@ def flicker_effect_to_code(config, effect_id): } ) def addressable_lambda_effect_to_code(config, effect_id): - args = [(AddressableLightRef, 'it'), (ESPColor, 'current_color'), (bool, 'initial_run')] + args = [(AddressableLightRef, 'it'), (Color, 'current_color'), (bool, 'initial_run')] lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], args, return_type=cg.void) var = cg.new_Pvariable(effect_id, config[CONF_NAME], lambda_, config[CONF_UPDATE_INTERVAL]) diff --git a/esphome/components/light/types.py b/esphome/components/light/types.py index d32ef0214c..6bcfd5fdb4 100644 --- a/esphome/components/light/types.py +++ b/esphome/components/light/types.py @@ -10,7 +10,7 @@ LightOutput = light_ns.class_('LightOutput') AddressableLight = light_ns.class_('AddressableLight', cg.Component) AddressableLightRef = AddressableLight.operator('ref') -ESPColor = light_ns.class_('ESPColor') +Color = cg.esphome_ns.class_('Color') LightColorValues = light_ns.class_('LightColorValues') # Actions diff --git a/esphome/components/neopixelbus/neopixelbus_light.h b/esphome/components/neopixelbus/neopixelbus_light.h index 5e8097187e..46601d8345 100644 --- a/esphome/components/neopixelbus/neopixelbus_light.h +++ b/esphome/components/neopixelbus/neopixelbus_light.h @@ -2,6 +2,7 @@ #include "esphome/core/component.h" #include "esphome/core/helpers.h" +#include "esphome/core/color.h" #include "esphome/components/light/light_output.h" #include "esphome/components/light/addressable_light.h" @@ -73,7 +74,7 @@ class NeoPixelBusLightOutputBase : public light::AddressableLight { // ========== INTERNAL METHODS ========== void setup() override { for (int i = 0; i < this->size(); i++) { - (*this)[i] = light::ESPColor(0, 0, 0, 0); + (*this)[i] = Color(0, 0, 0, 0); } this->effect_data_ = new uint8_t[this->size()]; diff --git a/esphome/components/ssd1322_base/ssd1322_base.cpp b/esphome/components/ssd1322_base/ssd1322_base.cpp index 9f382190a6..703f53fa93 100644 --- a/esphome/components/ssd1322_base/ssd1322_base.cpp +++ b/esphome/components/ssd1322_base/ssd1322_base.cpp @@ -162,7 +162,7 @@ size_t SSD1322::get_buffer_length_() { void HOT SSD1322::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; - uint32_t color4 = color.to_grayscale4(); + uint32_t color4 = display::ColorUtil::color_to_grayscale4(color); // where should the bits go in the big buffer array? math... uint16_t pos = (x / SSD1322_PIXELSPERBYTE) + (y * this->get_width_internal() / SSD1322_PIXELSPERBYTE); uint8_t shift = (1u - (x % SSD1322_PIXELSPERBYTE)) * SSD1322_COLORSHIFT; @@ -174,7 +174,7 @@ void HOT SSD1322::draw_absolute_pixel_internal(int x, int y, Color color) { this->buffer_[pos] |= color4; } void SSD1322::fill(Color color) { - const uint32_t color4 = color.to_grayscale4(); + const uint32_t color4 = display::ColorUtil::color_to_grayscale4(color); uint8_t fill = (color4 & SSD1322_COLORMASK) | ((color4 & SSD1322_COLORMASK) << SSD1322_COLORSHIFT); for (uint32_t i = 0; i < this->get_buffer_length_(); i++) this->buffer_[i] = fill; diff --git a/esphome/components/ssd1325_base/ssd1325_base.cpp b/esphome/components/ssd1325_base/ssd1325_base.cpp index dfb1ef00ee..9818880505 100644 --- a/esphome/components/ssd1325_base/ssd1325_base.cpp +++ b/esphome/components/ssd1325_base/ssd1325_base.cpp @@ -192,7 +192,7 @@ size_t SSD1325::get_buffer_length_() { 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) return; - uint32_t color4 = color.to_grayscale4(); + uint32_t color4 = display::ColorUtil::color_to_grayscale4(color); // where should the bits go in the big buffer array? math... uint16_t pos = (x / SSD1325_PIXELSPERBYTE) + (y * this->get_width_internal() / SSD1325_PIXELSPERBYTE); uint8_t shift = (x % SSD1325_PIXELSPERBYTE) * SSD1325_COLORSHIFT; @@ -204,7 +204,7 @@ void HOT SSD1325::draw_absolute_pixel_internal(int x, int y, Color color) { this->buffer_[pos] |= color4; } void SSD1325::fill(Color color) { - const uint32_t color4 = color.to_grayscale4(); + const uint32_t color4 = display::ColorUtil::color_to_grayscale4(color); uint8_t fill = (color4 & SSD1325_COLORMASK) | ((color4 & SSD1325_COLORMASK) << SSD1325_COLORSHIFT); for (uint32_t i = 0; i < this->get_buffer_length_(); i++) this->buffer_[i] = fill; diff --git a/esphome/components/ssd1327_base/ssd1327_base.cpp b/esphome/components/ssd1327_base/ssd1327_base.cpp index debe2455ff..398712c083 100644 --- a/esphome/components/ssd1327_base/ssd1327_base.cpp +++ b/esphome/components/ssd1327_base/ssd1327_base.cpp @@ -136,7 +136,7 @@ size_t SSD1327::get_buffer_length_() { void HOT SSD1327::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; - uint32_t color4 = color.to_grayscale4(); + uint32_t color4 = display::ColorUtil::color_to_grayscale4(color); // where should the bits go in the big buffer array? math... uint16_t pos = (x / SSD1327_PIXELSPERBYTE) + (y * this->get_width_internal() / SSD1327_PIXELSPERBYTE); uint8_t shift = (x % SSD1327_PIXELSPERBYTE) * SSD1327_COLORSHIFT; @@ -148,7 +148,7 @@ void HOT SSD1327::draw_absolute_pixel_internal(int x, int y, Color color) { this->buffer_[pos] |= color4; } void SSD1327::fill(Color color) { - const uint32_t color4 = color.to_grayscale4(); + const uint32_t color4 = display::ColorUtil::color_to_grayscale4(color); uint8_t fill = (color4 & SSD1327_COLORMASK) | ((color4 & SSD1327_COLORMASK) << SSD1327_COLORSHIFT); for (uint32_t i = 0; i < this->get_buffer_length_(); i++) this->buffer_[i] = fill; diff --git a/esphome/components/ssd1331_base/ssd1331_base.cpp b/esphome/components/ssd1331_base/ssd1331_base.cpp index 1405184177..9db5581044 100644 --- a/esphome/components/ssd1331_base/ssd1331_base.cpp +++ b/esphome/components/ssd1331_base/ssd1331_base.cpp @@ -123,14 +123,14 @@ size_t SSD1331::get_buffer_length_() { void HOT SSD1331::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(); + const uint32_t color565 = display::ColorUtil::color_to_565(color); // where should the bits go in the big buffer array? math... uint16_t pos = (x + y * this->get_width_internal()) * SSD1331_BYTESPERPIXEL; this->buffer_[pos++] = (color565 >> 8) & 0xff; this->buffer_[pos] = color565 & 0xff; } void SSD1331::fill(Color color) { - const uint32_t color565 = color.to_rgb_565(); + const uint32_t color565 = display::ColorUtil::color_to_565(color); for (uint32_t i = 0; i < this->get_buffer_length_(); i++) if (i & 1) { this->buffer_[i] = color565 & 0xff; diff --git a/esphome/components/ssd1351_base/ssd1351_base.cpp b/esphome/components/ssd1351_base/ssd1351_base.cpp index fded8e3482..42407a13de 100644 --- a/esphome/components/ssd1351_base/ssd1351_base.cpp +++ b/esphome/components/ssd1351_base/ssd1351_base.cpp @@ -151,14 +151,14 @@ size_t SSD1351::get_buffer_length_() { 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(); + const uint32_t color565 = display::ColorUtil::color_to_565(color); // 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(); + const uint32_t color565 = display::ColorUtil::color_to_565(color); for (uint32_t i = 0; i < this->get_buffer_length_(); i++) if (i & 1) { this->buffer_[i] = color565 & 0xff; diff --git a/esphome/components/st7735/st7735.cpp b/esphome/components/st7735/st7735.cpp index 5cd79da2cb..201098f3cf 100644 --- a/esphome/components/st7735/st7735.cpp +++ b/esphome/components/st7735/st7735.cpp @@ -308,11 +308,11 @@ void HOT ST7735::draw_absolute_pixel_internal(int x, int y, Color color) { return; if (this->eightbitcolor_) { - const uint32_t color332 = color.to_332(); + const uint32_t color332 = display::ColorUtil::color_to_332(color); uint16_t pos = (x + y * this->get_width_internal()); this->buffer_[pos] = color332; } else { - const uint32_t color565 = color.to_565(); + const uint32_t color565 = display::ColorUtil::color_to_565(color); uint16_t pos = (x + y * this->get_width_internal()) * 2; this->buffer_[pos++] = (color565 >> 8) & 0xff; this->buffer_[pos] = color565 & 0xff; @@ -444,9 +444,11 @@ void HOT ST7735::write_display_data_() { if (this->eightbitcolor_) { for (int line = 0; line < this->get_buffer_length(); line = line + this->get_width_internal()) { for (int index = 0; index < this->get_width_internal(); ++index) { - auto color = Color(this->buffer_[index + line], Color::ColorOrder::COLOR_ORDER_RGB, - Color::ColorBitness::COLOR_BITNESS_332, true) - .to_565(); + auto color332 = display::ColorUtil::to_color(this->buffer_[index + line], display::ColorOrder::COLOR_ORDER_RGB, + display::ColorBitness::COLOR_BITNESS_332, true); + + auto color = display::ColorUtil::color_to_565(color332); + this->write_byte((color >> 8) & 0xff); this->write_byte(color & 0xff); } diff --git a/esphome/components/st7789v/st7789v.cpp b/esphome/components/st7789v/st7789v.cpp index 284f2342fc..3a6374263a 100644 --- a/esphome/components/st7789v/st7789v.cpp +++ b/esphome/components/st7789v/st7789v.cpp @@ -263,7 +263,7 @@ 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(); + auto color565 = display::ColorUtil::color_to_565(color); uint16_t pos = (x + y * this->get_width_internal()) * 2; this->buffer_[pos++] = (color565 >> 8) & 0xff; diff --git a/esphome/components/wled/wled_light_effect.cpp b/esphome/components/wled/wled_light_effect.cpp index e06a23aacf..3c26beeed4 100644 --- a/esphome/components/wled/wled_light_effect.cpp +++ b/esphome/components/wled/wled_light_effect.cpp @@ -40,11 +40,11 @@ void WLEDLightEffect::stop() { void WLEDLightEffect::blank_all_leds_(light::AddressableLight &it) { for (int led = it.size(); led-- > 0;) { - it[led].set(light::ESPColor::BLACK); + it[led].set(COLOR_BLACK); } } -void WLEDLightEffect::apply(light::AddressableLight &it, const light::ESPColor ¤t_color) { +void WLEDLightEffect::apply(light::AddressableLight &it, const Color ¤t_color) { // Init UDP lazily if (!udp_) { udp_.reset(new WiFiUDP()); @@ -152,7 +152,7 @@ bool WLEDLightEffect::parse_warls_frame_(light::AddressableLight &it, const uint uint8_t b = payload[3]; if (led < max_leds) { - it[led].set(light::ESPColor(r, g, b)); + it[led].set(Color(r, g, b)); } } @@ -174,7 +174,7 @@ bool WLEDLightEffect::parse_drgb_frame_(light::AddressableLight &it, const uint8 uint8_t b = payload[2]; if (led < max_leds) { - it[led].set(light::ESPColor(r, g, b)); + it[led].set(Color(r, g, b)); } } @@ -197,7 +197,7 @@ bool WLEDLightEffect::parse_drgbw_frame_(light::AddressableLight &it, const uint uint8_t w = payload[3]; if (led < max_leds) { - it[led].set(light::ESPColor(r, g, b, w)); + it[led].set(Color(r, g, b, w)); } } @@ -228,7 +228,7 @@ bool WLEDLightEffect::parse_dnrgb_frame_(light::AddressableLight &it, const uint uint8_t b = payload[2]; if (led < max_leds) { - it[led].set(light::ESPColor(r, g, b)); + it[led].set(Color(r, g, b)); } } diff --git a/esphome/components/wled/wled_light_effect.h b/esphome/components/wled/wled_light_effect.h index f1d27b06c7..2a7654ec27 100644 --- a/esphome/components/wled/wled_light_effect.h +++ b/esphome/components/wled/wled_light_effect.h @@ -18,7 +18,7 @@ class WLEDLightEffect : public light::AddressableLightEffect { public: void start() override; void stop() override; - void apply(light::AddressableLight &it, const light::ESPColor ¤t_color) override; + void apply(light::AddressableLight &it, const Color ¤t_color) override; void set_port(uint16_t port) { this->port_ = port; } protected: diff --git a/esphome/core/color.h b/esphome/core/color.h index 3120e48064..d2f225dc3a 100644 --- a/esphome/core/color.h +++ b/esphome/core/color.h @@ -6,7 +6,6 @@ namespace esphome { inline static uint8_t esp_scale8(uint8_t i, uint8_t scale) { return (uint16_t(i) * (1 + uint16_t(scale))) / 256; } -inline static uint8_t esp_scale(uint8_t i, uint8_t scale, uint8_t max_value = 255) { return (max_value * i / scale); } struct Color { union { @@ -31,75 +30,19 @@ struct Color { uint8_t raw[4]; uint32_t raw_32; }; - enum ColorOrder : uint8_t { COLOR_ORDER_RGB = 0, COLOR_ORDER_BGR = 1, COLOR_ORDER_GRB = 2 }; - enum ColorBitness : uint8_t { COLOR_BITNESS_888 = 0, COLOR_BITNESS_565 = 1, COLOR_BITNESS_332 = 2 }; + 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(uint8_t red, uint8_t green, uint8_t blue) ALWAYS_INLINE : r(red), g(green), b(blue), w(0) {} + + inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) ALWAYS_INLINE : r(red), + g(green), + b(blue), + w(white) {} inline Color(uint32_t colorcode) ALWAYS_INLINE : r((colorcode >> 16) & 0xFF), g((colorcode >> 8) & 0xFF), b((colorcode >> 0) & 0xFF), w((colorcode >> 24) & 0xFF) {} - inline Color(uint32_t colorcode, ColorOrder color_order, ColorBitness color_bitness = ColorBitness::COLOR_BITNESS_888, - bool right_bit_aligned = true) { - uint8_t first_color, second_color, third_color; - uint8_t first_bits = 0; - uint8_t second_bits = 0; - uint8_t third_bits = 0; - switch (color_bitness) { - case COLOR_BITNESS_888: - first_bits = 8; - second_bits = 8; - third_bits = 8; - break; - case COLOR_BITNESS_565: - first_bits = 5; - second_bits = 6; - third_bits = 5; - break; - case COLOR_BITNESS_332: - first_bits = 3; - second_bits = 3; - third_bits = 2; - break; - } - - first_color = right_bit_aligned ? esp_scale(((colorcode >> (second_bits + third_bits)) & ((1 << first_bits) - 1)), - ((1 << first_bits) - 1)) - : esp_scale(((colorcode >> 16) & 0xFF), (1 << first_bits) - 1); - - second_color = right_bit_aligned - ? esp_scale(((colorcode >> third_bits) & ((1 << second_bits) - 1)), ((1 << second_bits) - 1)) - : esp_scale(((colorcode >> 8) & 0xFF), ((1 << second_bits) - 1)); - - third_color = (right_bit_aligned ? esp_scale(((colorcode >> 0) & 0xFF), ((1 << third_bits) - 1)) - : esp_scale(((colorcode >> 0) & 0xFF), (1 << third_bits) - 1)); - - switch (color_order) { - case COLOR_ORDER_RGB: - this->r = first_color; - this->g = second_color; - this->b = third_color; - break; - case COLOR_ORDER_BGR: - this->b = first_color; - this->g = second_color; - this->r = third_color; - break; - case COLOR_ORDER_GRB: - this->g = first_color; - this->r = second_color; - this->b = third_color; - break; - } - } inline bool is_on() ALWAYS_INLINE { return this->raw_32 != 0; } inline Color &operator=(const Color &rhs) ALWAYS_INLINE { this->r = rhs.r; @@ -187,65 +130,21 @@ struct Color { } 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); + uint32_t rand = random_uint32(); + uint8_t w = rand >> 24; + uint8_t r = rand >> 16; + uint8_t g = rand >> 8; + uint8_t b = rand >> 0; + const uint16_t max_rgb = std::max(r, std::max(g, b)); + return Color(uint8_t((uint16_t(r) * 255U / max_rgb)), uint8_t((uint16_t(g) * 255U / max_rgb)), + uint8_t((uint16_t(b) * 255U / max_rgb)), w); } - Color fade_to_white(uint8_t amnt) { return Color(1, 1, 1, 1) - (*this * amnt); } + Color fade_to_white(uint8_t amnt) { return Color(255, 255, 255, 255) - (*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; } - uint8_t to_332(ColorOrder color_order = ColorOrder::COLOR_ORDER_RGB) const { - uint16_t red_color, green_color, blue_color; - - red_color = esp_scale8(this->red, ((1 << 3) - 1)); - green_color = esp_scale8(this->green, ((1 << 3) - 1)); - blue_color = esp_scale8(this->blue, (1 << 2) - 1); - - switch (color_order) { - case COLOR_ORDER_RGB: - return red_color << 5 | green_color << 2 | blue_color; - case COLOR_ORDER_BGR: - return blue_color << 6 | green_color << 3 | red_color; - case COLOR_ORDER_GRB: - return green_color << 5 | red_color << 2 | blue_color; - } - return 0; - } - uint16_t to_565(ColorOrder color_order = ColorOrder::COLOR_ORDER_RGB) const { - uint16_t red_color, green_color, blue_color; - - red_color = esp_scale8(this->red, ((1 << 5) - 1)); - green_color = esp_scale8(this->green, ((1 << 6) - 1)); - blue_color = esp_scale8(this->blue, (1 << 5) - 1); - - switch (color_order) { - case COLOR_ORDER_RGB: - return red_color << 11 | green_color << 5 | blue_color; - case COLOR_ORDER_BGR: - return blue_color << 11 | green_color << 5 | red_color; - case COLOR_ORDER_GRB: - return green_color << 10 | red_color << 5 | blue_color; - } - return 0; - } - 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); +static const Color COLOR_WHITE(255, 255, 255, 255); }; // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index 59c2bf96c4..1b1d3799a0 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1693,7 +1693,7 @@ interval: color: - id: kbx_red red: 100% - green: 1% + green_int: 123 blue: 2% - id: kbx_blue red: 0%