mirror of
https://github.com/esphome/esphome.git
synced 2026-05-24 01:37:15 +08:00
Split files in light component (#1893)
This commit is contained in:
@@ -6,158 +6,6 @@ namespace light {
|
||||
|
||||
static const char *const TAG = "light.addressable";
|
||||
|
||||
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;
|
||||
const uint8_t val = this->value;
|
||||
// upper 3 hue bits are for branch selection, lower 5 are for values
|
||||
const uint8_t offset8 = (hue & 0x1F) << 3; // 0..248
|
||||
// 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);
|
||||
Color rgb(255, 255, 255, 0);
|
||||
switch (hue >> 5) {
|
||||
case 0b000:
|
||||
rgb.r = 255 - third;
|
||||
rgb.g = third;
|
||||
rgb.b = 0;
|
||||
break;
|
||||
case 0b001:
|
||||
rgb.r = 171;
|
||||
rgb.g = 85 + third;
|
||||
rgb.b = 0;
|
||||
break;
|
||||
case 0b010:
|
||||
rgb.r = 171 - two_thirds;
|
||||
rgb.g = 170 + third;
|
||||
rgb.b = 0;
|
||||
break;
|
||||
case 0b011:
|
||||
rgb.r = 0;
|
||||
rgb.g = 255 - third;
|
||||
rgb.b = third;
|
||||
break;
|
||||
case 0b100:
|
||||
rgb.r = 0;
|
||||
rgb.g = 171 - two_thirds;
|
||||
rgb.b = 85 + two_thirds;
|
||||
break;
|
||||
case 0b101:
|
||||
rgb.r = third;
|
||||
rgb.g = 0;
|
||||
rgb.b = 255 - third;
|
||||
break;
|
||||
case 0b110:
|
||||
rgb.r = 85 + third;
|
||||
rgb.g = 0;
|
||||
rgb.b = 171 - third;
|
||||
break;
|
||||
case 0b111:
|
||||
rgb.r = 170 + third;
|
||||
rgb.g = 0;
|
||||
rgb.b = 85 - third;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// low saturation -> add uniform color to orig. hue
|
||||
// high saturation -> use hue directly
|
||||
// scales with square of saturation
|
||||
// (r,g,b) = (r,g,b) * sat + (1 - sat)^2
|
||||
rgb *= sat;
|
||||
const uint8_t desat = 255 - sat;
|
||||
rgb += esp_scale8(desat, desat);
|
||||
// (r,g,b) = (r,g,b) * val
|
||||
rgb *= val;
|
||||
return rgb;
|
||||
}
|
||||
|
||||
void ESPRangeView::set(const Color &color) {
|
||||
for (int32_t i = this->begin_; i < this->end_; i++) {
|
||||
(*this->parent_)[i] = color;
|
||||
}
|
||||
}
|
||||
ESPColorView ESPRangeView::operator[](int32_t index) const {
|
||||
index = interpret_index(index, this->size()) + this->begin_;
|
||||
return (*this->parent_)[index];
|
||||
}
|
||||
ESPRangeIterator ESPRangeView::begin() { return {*this, this->begin_}; }
|
||||
ESPRangeIterator ESPRangeView::end() { return {*this, this->end_}; }
|
||||
void ESPRangeView::set_red(uint8_t red) {
|
||||
for (auto c : *this)
|
||||
c.set_red(red);
|
||||
}
|
||||
void ESPRangeView::set_green(uint8_t green) {
|
||||
for (auto c : *this)
|
||||
c.set_green(green);
|
||||
}
|
||||
void ESPRangeView::set_blue(uint8_t blue) {
|
||||
for (auto c : *this)
|
||||
c.set_blue(blue);
|
||||
}
|
||||
void ESPRangeView::set_white(uint8_t white) {
|
||||
for (auto c : *this)
|
||||
c.set_white(white);
|
||||
}
|
||||
void ESPRangeView::set_effect_data(uint8_t effect_data) {
|
||||
for (auto c : *this)
|
||||
c.set_effect_data(effect_data);
|
||||
}
|
||||
void ESPRangeView::fade_to_white(uint8_t amnt) {
|
||||
for (auto c : *this)
|
||||
c.fade_to_white(amnt);
|
||||
}
|
||||
void ESPRangeView::fade_to_black(uint8_t amnt) {
|
||||
for (auto c : *this)
|
||||
c.fade_to_black(amnt);
|
||||
}
|
||||
void ESPRangeView::lighten(uint8_t delta) {
|
||||
for (auto c : *this)
|
||||
c.lighten(delta);
|
||||
}
|
||||
void ESPRangeView::darken(uint8_t delta) {
|
||||
for (auto c : *this)
|
||||
c.darken(delta);
|
||||
}
|
||||
ESPRangeView &ESPRangeView::operator=(const ESPRangeView &rhs) { // NOLINT
|
||||
// If size doesn't match, error (todo warning)
|
||||
if (rhs.size() != this->size())
|
||||
return *this;
|
||||
|
||||
if (this->parent_ != rhs.parent_) {
|
||||
for (int32_t i = 0; i < this->size(); i++)
|
||||
(*this)[i].set(rhs[i].get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If both equal, already done
|
||||
if (rhs.begin_ == this->begin_)
|
||||
return *this;
|
||||
|
||||
if (rhs.begin_ > this->begin_) {
|
||||
// Copy from left
|
||||
for (int32_t i = 0; i < this->size(); i++) {
|
||||
(*this)[i].set(rhs[i].get());
|
||||
}
|
||||
} else {
|
||||
// Copy from right
|
||||
for (int32_t i = this->size() - 1; i >= 0; i--) {
|
||||
(*this)[i].set(rhs[i].get());
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ESPColorView ESPRangeIterator::operator*() const { return this->range_.parent_->get(this->i_); }
|
||||
|
||||
int32_t HOT interpret_index(int32_t index, int32_t size) {
|
||||
if (index < 0)
|
||||
return size + index;
|
||||
return index;
|
||||
}
|
||||
|
||||
void AddressableLight::call_setup() {
|
||||
this->setup();
|
||||
|
||||
@@ -254,23 +102,5 @@ void AddressableLight::write_state(LightState *state) {
|
||||
this->schedule_show();
|
||||
}
|
||||
|
||||
void ESPColorCorrection::calculate_gamma_table(float gamma) {
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
// corrected = val ^ gamma
|
||||
auto corrected = static_cast<uint8_t>(roundf(255.0f * gamma_correct(i / 255.0f, gamma)));
|
||||
this->gamma_table_[i] = corrected;
|
||||
}
|
||||
if (gamma == 0.0f) {
|
||||
for (uint16_t i = 0; i < 256; i++)
|
||||
this->gamma_reverse_table_[i] = i;
|
||||
return;
|
||||
}
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
// val = corrected ^ (1/gamma)
|
||||
auto uncorrected = static_cast<uint8_t>(roundf(255.0f * powf(i / 255.0f, 1.0f / gamma)));
|
||||
this->gamma_reverse_table_[i] = uncorrected;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/color.h"
|
||||
#include "esp_color_correction.h"
|
||||
#include "esp_color_view.h"
|
||||
#include "esp_range_view.h"
|
||||
#include "light_output.h"
|
||||
#include "light_state.h"
|
||||
|
||||
@@ -15,266 +18,6 @@ namespace light {
|
||||
|
||||
using ESPColor = Color;
|
||||
|
||||
struct ESPHSVColor {
|
||||
union {
|
||||
struct {
|
||||
union {
|
||||
uint8_t hue;
|
||||
uint8_t h;
|
||||
};
|
||||
union {
|
||||
uint8_t saturation;
|
||||
uint8_t s;
|
||||
};
|
||||
union {
|
||||
uint8_t value;
|
||||
uint8_t v;
|
||||
};
|
||||
};
|
||||
uint8_t raw[3];
|
||||
};
|
||||
inline ESPHSVColor() ALWAYS_INLINE : h(0), s(0), v(0) { // NOLINT
|
||||
}
|
||||
inline ESPHSVColor(uint8_t hue, uint8_t saturation, uint8_t value) ALWAYS_INLINE : hue(hue),
|
||||
saturation(saturation),
|
||||
value(value) {}
|
||||
Color to_rgb() const;
|
||||
};
|
||||
|
||||
class ESPColorCorrection {
|
||||
public:
|
||||
ESPColorCorrection() : max_brightness_(255, 255, 255, 255) {}
|
||||
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 Color color_correct(Color color) const ALWAYS_INLINE {
|
||||
// corrected = (uncorrected * max_brightness * local_brightness) ^ gamma
|
||||
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_);
|
||||
return this->gamma_table_[res];
|
||||
}
|
||||
inline uint8_t color_correct_green(uint8_t green) const ALWAYS_INLINE {
|
||||
uint8_t res = esp_scale8(esp_scale8(green, this->max_brightness_.green), this->local_brightness_);
|
||||
return this->gamma_table_[res];
|
||||
}
|
||||
inline uint8_t color_correct_blue(uint8_t blue) const ALWAYS_INLINE {
|
||||
uint8_t res = esp_scale8(esp_scale8(blue, this->max_brightness_.blue), this->local_brightness_);
|
||||
return this->gamma_table_[res];
|
||||
}
|
||||
inline uint8_t color_correct_white(uint8_t white) const ALWAYS_INLINE {
|
||||
// do not scale white value with brightness
|
||||
uint8_t res = esp_scale8(white, this->max_brightness_.white);
|
||||
return this->gamma_table_[res];
|
||||
}
|
||||
inline Color color_uncorrect(Color color) const ALWAYS_INLINE {
|
||||
// uncorrected = corrected^(1/gamma) / (max_brightness * local_brightness)
|
||||
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)
|
||||
return 0;
|
||||
uint16_t uncorrected = this->gamma_reverse_table_[red] * 255UL;
|
||||
uint8_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_;
|
||||
return res;
|
||||
}
|
||||
inline uint8_t color_uncorrect_green(uint8_t green) const ALWAYS_INLINE {
|
||||
if (this->max_brightness_.green == 0 || this->local_brightness_ == 0)
|
||||
return 0;
|
||||
uint16_t uncorrected = this->gamma_reverse_table_[green] * 255UL;
|
||||
uint8_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_;
|
||||
return res;
|
||||
}
|
||||
inline uint8_t color_uncorrect_blue(uint8_t blue) const ALWAYS_INLINE {
|
||||
if (this->max_brightness_.blue == 0 || this->local_brightness_ == 0)
|
||||
return 0;
|
||||
uint16_t uncorrected = this->gamma_reverse_table_[blue] * 255UL;
|
||||
uint8_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_;
|
||||
return res;
|
||||
}
|
||||
inline uint8_t color_uncorrect_white(uint8_t white) const ALWAYS_INLINE {
|
||||
if (this->max_brightness_.white == 0)
|
||||
return 0;
|
||||
uint16_t uncorrected = this->gamma_reverse_table_[white] * 255UL;
|
||||
uint8_t res = uncorrected / this->max_brightness_.white;
|
||||
return res;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t gamma_table_[256];
|
||||
uint8_t gamma_reverse_table_[256];
|
||||
Color max_brightness_;
|
||||
uint8_t local_brightness_{255};
|
||||
};
|
||||
|
||||
class ESPColorSettable {
|
||||
public:
|
||||
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;
|
||||
virtual void set_white(uint8_t white) = 0;
|
||||
virtual void set_effect_data(uint8_t effect_data) = 0;
|
||||
virtual void fade_to_white(uint8_t amnt) = 0;
|
||||
virtual void fade_to_black(uint8_t amnt) = 0;
|
||||
virtual void lighten(uint8_t delta) = 0;
|
||||
virtual void darken(uint8_t delta) = 0;
|
||||
void set(const ESPHSVColor &color) { this->set_hsv(color); }
|
||||
void set_hsv(const ESPHSVColor &color) {
|
||||
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) {
|
||||
this->set_red(red);
|
||||
this->set_green(green);
|
||||
this->set_blue(blue);
|
||||
}
|
||||
void set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
|
||||
this->set_rgb(red, green, blue);
|
||||
this->set_white(white);
|
||||
}
|
||||
};
|
||||
|
||||
class ESPColorView : public ESPColorSettable {
|
||||
public:
|
||||
ESPColorView(uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *white, uint8_t *effect_data,
|
||||
const ESPColorCorrection *color_correction)
|
||||
: red_(red),
|
||||
green_(green),
|
||||
blue_(blue),
|
||||
white_(white),
|
||||
effect_data_(effect_data),
|
||||
color_correction_(color_correction) {}
|
||||
ESPColorView &operator=(const Color &rhs) {
|
||||
this->set(rhs);
|
||||
return *this;
|
||||
}
|
||||
ESPColorView &operator=(const ESPHSVColor &rhs) {
|
||||
this->set_hsv(rhs);
|
||||
return *this;
|
||||
}
|
||||
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); }
|
||||
void set_white(uint8_t white) override {
|
||||
if (this->white_ == nullptr)
|
||||
return;
|
||||
*this->white_ = this->color_correction_->color_correct_white(white);
|
||||
}
|
||||
void set_effect_data(uint8_t effect_data) override {
|
||||
if (this->effect_data_ == nullptr)
|
||||
return;
|
||||
*this->effect_data_ = effect_data;
|
||||
}
|
||||
void fade_to_white(uint8_t amnt) override { this->set(this->get().fade_to_white(amnt)); }
|
||||
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)); }
|
||||
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_); }
|
||||
uint8_t get_green_raw() const { return *this->green_; }
|
||||
uint8_t get_blue() const { return this->color_correction_->color_uncorrect_blue(*this->blue_); }
|
||||
uint8_t get_blue_raw() const { return *this->blue_; }
|
||||
uint8_t get_white() const {
|
||||
if (this->white_ == nullptr)
|
||||
return 0;
|
||||
return this->color_correction_->color_uncorrect_white(*this->white_);
|
||||
}
|
||||
uint8_t get_white_raw() const {
|
||||
if (this->white_ == nullptr)
|
||||
return 0;
|
||||
return *this->white_;
|
||||
}
|
||||
uint8_t get_effect_data() const {
|
||||
if (this->effect_data_ == nullptr)
|
||||
return 0;
|
||||
return *this->effect_data_;
|
||||
}
|
||||
void raw_set_color_correction(const ESPColorCorrection *color_correction) {
|
||||
this->color_correction_ = color_correction;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t *const red_;
|
||||
uint8_t *const green_;
|
||||
uint8_t *const blue_;
|
||||
uint8_t *const white_;
|
||||
uint8_t *const effect_data_;
|
||||
const ESPColorCorrection *color_correction_;
|
||||
};
|
||||
|
||||
class AddressableLight;
|
||||
|
||||
int32_t interpret_index(int32_t index, int32_t size);
|
||||
|
||||
class ESPRangeIterator;
|
||||
|
||||
class ESPRangeView : public ESPColorSettable {
|
||||
public:
|
||||
ESPRangeView(AddressableLight *parent, int32_t begin, int32_t an_end) : parent_(parent), begin_(begin), end_(an_end) {
|
||||
if (this->end_ < this->begin_) {
|
||||
this->end_ = this->begin_;
|
||||
}
|
||||
}
|
||||
|
||||
ESPColorView operator[](int32_t index) const;
|
||||
ESPRangeIterator begin();
|
||||
ESPRangeIterator end();
|
||||
|
||||
void set(const Color &color) override;
|
||||
ESPRangeView &operator=(const Color &rhs) {
|
||||
this->set(rhs);
|
||||
return *this;
|
||||
}
|
||||
ESPRangeView &operator=(const ESPColorView &rhs) {
|
||||
this->set(rhs.get());
|
||||
return *this;
|
||||
}
|
||||
ESPRangeView &operator=(const ESPHSVColor &rhs) {
|
||||
this->set_hsv(rhs);
|
||||
return *this;
|
||||
}
|
||||
ESPRangeView &operator=(const ESPRangeView &rhs);
|
||||
void set_red(uint8_t red) override;
|
||||
void set_green(uint8_t green) override;
|
||||
void set_blue(uint8_t blue) override;
|
||||
void set_white(uint8_t white) override;
|
||||
void set_effect_data(uint8_t effect_data) override;
|
||||
void fade_to_white(uint8_t amnt) override;
|
||||
void fade_to_black(uint8_t amnt) override;
|
||||
void lighten(uint8_t delta) override;
|
||||
void darken(uint8_t delta) override;
|
||||
int32_t size() const { return this->end_ - this->begin_; }
|
||||
|
||||
protected:
|
||||
friend ESPRangeIterator;
|
||||
|
||||
AddressableLight *parent_;
|
||||
int32_t begin_;
|
||||
int32_t end_;
|
||||
};
|
||||
|
||||
class ESPRangeIterator {
|
||||
public:
|
||||
ESPRangeIterator(const ESPRangeView &range, int32_t i) : range_(range), i_(i) {}
|
||||
ESPRangeIterator operator++() {
|
||||
this->i_++;
|
||||
return *this;
|
||||
}
|
||||
bool operator!=(const ESPRangeIterator &other) const { return this->i_ != other.i_; }
|
||||
ESPColorView operator*() const;
|
||||
|
||||
protected:
|
||||
ESPRangeView range_;
|
||||
int32_t i_;
|
||||
};
|
||||
|
||||
class AddressableLight : public LightOutput, public Component {
|
||||
public:
|
||||
virtual int32_t size() const = 0;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "esp_color_correction.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
void ESPColorCorrection::calculate_gamma_table(float gamma) {
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
// corrected = val ^ gamma
|
||||
auto corrected = static_cast<uint8_t>(roundf(255.0f * gamma_correct(i / 255.0f, gamma)));
|
||||
this->gamma_table_[i] = corrected;
|
||||
}
|
||||
if (gamma == 0.0f) {
|
||||
for (uint16_t i = 0; i < 256; i++)
|
||||
this->gamma_reverse_table_[i] = i;
|
||||
return;
|
||||
}
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
// val = corrected ^ (1/gamma)
|
||||
auto uncorrected = static_cast<uint8_t>(roundf(255.0f * powf(i / 255.0f, 1.0f / gamma)));
|
||||
this->gamma_reverse_table_[i] = uncorrected;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/color.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
class ESPColorCorrection {
|
||||
public:
|
||||
ESPColorCorrection() : max_brightness_(255, 255, 255, 255) {}
|
||||
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 Color color_correct(Color color) const ALWAYS_INLINE {
|
||||
// corrected = (uncorrected * max_brightness * local_brightness) ^ gamma
|
||||
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_);
|
||||
return this->gamma_table_[res];
|
||||
}
|
||||
inline uint8_t color_correct_green(uint8_t green) const ALWAYS_INLINE {
|
||||
uint8_t res = esp_scale8(esp_scale8(green, this->max_brightness_.green), this->local_brightness_);
|
||||
return this->gamma_table_[res];
|
||||
}
|
||||
inline uint8_t color_correct_blue(uint8_t blue) const ALWAYS_INLINE {
|
||||
uint8_t res = esp_scale8(esp_scale8(blue, this->max_brightness_.blue), this->local_brightness_);
|
||||
return this->gamma_table_[res];
|
||||
}
|
||||
inline uint8_t color_correct_white(uint8_t white) const ALWAYS_INLINE {
|
||||
// do not scale white value with brightness
|
||||
uint8_t res = esp_scale8(white, this->max_brightness_.white);
|
||||
return this->gamma_table_[res];
|
||||
}
|
||||
inline Color color_uncorrect(Color color) const ALWAYS_INLINE {
|
||||
// uncorrected = corrected^(1/gamma) / (max_brightness * local_brightness)
|
||||
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)
|
||||
return 0;
|
||||
uint16_t uncorrected = this->gamma_reverse_table_[red] * 255UL;
|
||||
uint8_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_;
|
||||
return res;
|
||||
}
|
||||
inline uint8_t color_uncorrect_green(uint8_t green) const ALWAYS_INLINE {
|
||||
if (this->max_brightness_.green == 0 || this->local_brightness_ == 0)
|
||||
return 0;
|
||||
uint16_t uncorrected = this->gamma_reverse_table_[green] * 255UL;
|
||||
uint8_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_;
|
||||
return res;
|
||||
}
|
||||
inline uint8_t color_uncorrect_blue(uint8_t blue) const ALWAYS_INLINE {
|
||||
if (this->max_brightness_.blue == 0 || this->local_brightness_ == 0)
|
||||
return 0;
|
||||
uint16_t uncorrected = this->gamma_reverse_table_[blue] * 255UL;
|
||||
uint8_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_;
|
||||
return res;
|
||||
}
|
||||
inline uint8_t color_uncorrect_white(uint8_t white) const ALWAYS_INLINE {
|
||||
if (this->max_brightness_.white == 0)
|
||||
return 0;
|
||||
uint16_t uncorrected = this->gamma_reverse_table_[white] * 255UL;
|
||||
uint8_t res = uncorrected / this->max_brightness_.white;
|
||||
return res;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t gamma_table_[256];
|
||||
uint8_t gamma_reverse_table_[256];
|
||||
Color max_brightness_;
|
||||
uint8_t local_brightness_{255};
|
||||
};
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/color.h"
|
||||
#include "esp_hsv_color.h"
|
||||
#include "esp_color_correction.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
class ESPColorSettable {
|
||||
public:
|
||||
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;
|
||||
virtual void set_white(uint8_t white) = 0;
|
||||
virtual void set_effect_data(uint8_t effect_data) = 0;
|
||||
virtual void fade_to_white(uint8_t amnt) = 0;
|
||||
virtual void fade_to_black(uint8_t amnt) = 0;
|
||||
virtual void lighten(uint8_t delta) = 0;
|
||||
virtual void darken(uint8_t delta) = 0;
|
||||
void set(const ESPHSVColor &color) { this->set_hsv(color); }
|
||||
void set_hsv(const ESPHSVColor &color) {
|
||||
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) {
|
||||
this->set_red(red);
|
||||
this->set_green(green);
|
||||
this->set_blue(blue);
|
||||
}
|
||||
void set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
|
||||
this->set_rgb(red, green, blue);
|
||||
this->set_white(white);
|
||||
}
|
||||
};
|
||||
|
||||
class ESPColorView : public ESPColorSettable {
|
||||
public:
|
||||
ESPColorView(uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *white, uint8_t *effect_data,
|
||||
const ESPColorCorrection *color_correction)
|
||||
: red_(red),
|
||||
green_(green),
|
||||
blue_(blue),
|
||||
white_(white),
|
||||
effect_data_(effect_data),
|
||||
color_correction_(color_correction) {}
|
||||
ESPColorView &operator=(const Color &rhs) {
|
||||
this->set(rhs);
|
||||
return *this;
|
||||
}
|
||||
ESPColorView &operator=(const ESPHSVColor &rhs) {
|
||||
this->set_hsv(rhs);
|
||||
return *this;
|
||||
}
|
||||
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); }
|
||||
void set_white(uint8_t white) override {
|
||||
if (this->white_ == nullptr)
|
||||
return;
|
||||
*this->white_ = this->color_correction_->color_correct_white(white);
|
||||
}
|
||||
void set_effect_data(uint8_t effect_data) override {
|
||||
if (this->effect_data_ == nullptr)
|
||||
return;
|
||||
*this->effect_data_ = effect_data;
|
||||
}
|
||||
void fade_to_white(uint8_t amnt) override { this->set(this->get().fade_to_white(amnt)); }
|
||||
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)); }
|
||||
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_); }
|
||||
uint8_t get_green_raw() const { return *this->green_; }
|
||||
uint8_t get_blue() const { return this->color_correction_->color_uncorrect_blue(*this->blue_); }
|
||||
uint8_t get_blue_raw() const { return *this->blue_; }
|
||||
uint8_t get_white() const {
|
||||
if (this->white_ == nullptr)
|
||||
return 0;
|
||||
return this->color_correction_->color_uncorrect_white(*this->white_);
|
||||
}
|
||||
uint8_t get_white_raw() const {
|
||||
if (this->white_ == nullptr)
|
||||
return 0;
|
||||
return *this->white_;
|
||||
}
|
||||
uint8_t get_effect_data() const {
|
||||
if (this->effect_data_ == nullptr)
|
||||
return 0;
|
||||
return *this->effect_data_;
|
||||
}
|
||||
void raw_set_color_correction(const ESPColorCorrection *color_correction) {
|
||||
this->color_correction_ = color_correction;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t *const red_;
|
||||
uint8_t *const green_;
|
||||
uint8_t *const blue_;
|
||||
uint8_t *const white_;
|
||||
uint8_t *const effect_data_;
|
||||
const ESPColorCorrection *color_correction_;
|
||||
};
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "esp_hsv_color.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
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;
|
||||
const uint8_t val = this->value;
|
||||
// upper 3 hue bits are for branch selection, lower 5 are for values
|
||||
const uint8_t offset8 = (hue & 0x1F) << 3; // 0..248
|
||||
// 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);
|
||||
Color rgb(255, 255, 255, 0);
|
||||
switch (hue >> 5) {
|
||||
case 0b000:
|
||||
rgb.r = 255 - third;
|
||||
rgb.g = third;
|
||||
rgb.b = 0;
|
||||
break;
|
||||
case 0b001:
|
||||
rgb.r = 171;
|
||||
rgb.g = 85 + third;
|
||||
rgb.b = 0;
|
||||
break;
|
||||
case 0b010:
|
||||
rgb.r = 171 - two_thirds;
|
||||
rgb.g = 170 + third;
|
||||
rgb.b = 0;
|
||||
break;
|
||||
case 0b011:
|
||||
rgb.r = 0;
|
||||
rgb.g = 255 - third;
|
||||
rgb.b = third;
|
||||
break;
|
||||
case 0b100:
|
||||
rgb.r = 0;
|
||||
rgb.g = 171 - two_thirds;
|
||||
rgb.b = 85 + two_thirds;
|
||||
break;
|
||||
case 0b101:
|
||||
rgb.r = third;
|
||||
rgb.g = 0;
|
||||
rgb.b = 255 - third;
|
||||
break;
|
||||
case 0b110:
|
||||
rgb.r = 85 + third;
|
||||
rgb.g = 0;
|
||||
rgb.b = 171 - third;
|
||||
break;
|
||||
case 0b111:
|
||||
rgb.r = 170 + third;
|
||||
rgb.g = 0;
|
||||
rgb.b = 85 - third;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// low saturation -> add uniform color to orig. hue
|
||||
// high saturation -> use hue directly
|
||||
// scales with square of saturation
|
||||
// (r,g,b) = (r,g,b) * sat + (1 - sat)^2
|
||||
rgb *= sat;
|
||||
const uint8_t desat = 255 - sat;
|
||||
rgb += esp_scale8(desat, desat);
|
||||
// (r,g,b) = (r,g,b) * val
|
||||
rgb *= val;
|
||||
return rgb;
|
||||
}
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/color.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
struct ESPHSVColor {
|
||||
union {
|
||||
struct {
|
||||
union {
|
||||
uint8_t hue;
|
||||
uint8_t h;
|
||||
};
|
||||
union {
|
||||
uint8_t saturation;
|
||||
uint8_t s;
|
||||
};
|
||||
union {
|
||||
uint8_t value;
|
||||
uint8_t v;
|
||||
};
|
||||
};
|
||||
uint8_t raw[3];
|
||||
};
|
||||
inline ESPHSVColor() ALWAYS_INLINE : h(0), s(0), v(0) { // NOLINT
|
||||
}
|
||||
inline ESPHSVColor(uint8_t hue, uint8_t saturation, uint8_t value) ALWAYS_INLINE : hue(hue),
|
||||
saturation(saturation),
|
||||
value(value) {}
|
||||
Color to_rgb() const;
|
||||
};
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "esp_range_view.h"
|
||||
#include "addressable_light.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
int32_t HOT interpret_index(int32_t index, int32_t size) {
|
||||
if (index < 0)
|
||||
return size + index;
|
||||
return index;
|
||||
}
|
||||
|
||||
ESPColorView ESPRangeView::operator[](int32_t index) const {
|
||||
index = interpret_index(index, this->size()) + this->begin_;
|
||||
return (*this->parent_)[index];
|
||||
}
|
||||
ESPRangeIterator ESPRangeView::begin() { return {*this, this->begin_}; }
|
||||
ESPRangeIterator ESPRangeView::end() { return {*this, this->end_}; }
|
||||
|
||||
void ESPRangeView::set(const Color &color) {
|
||||
for (int32_t i = this->begin_; i < this->end_; i++) {
|
||||
(*this->parent_)[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
void ESPRangeView::set_red(uint8_t red) {
|
||||
for (auto c : *this)
|
||||
c.set_red(red);
|
||||
}
|
||||
void ESPRangeView::set_green(uint8_t green) {
|
||||
for (auto c : *this)
|
||||
c.set_green(green);
|
||||
}
|
||||
void ESPRangeView::set_blue(uint8_t blue) {
|
||||
for (auto c : *this)
|
||||
c.set_blue(blue);
|
||||
}
|
||||
void ESPRangeView::set_white(uint8_t white) {
|
||||
for (auto c : *this)
|
||||
c.set_white(white);
|
||||
}
|
||||
void ESPRangeView::set_effect_data(uint8_t effect_data) {
|
||||
for (auto c : *this)
|
||||
c.set_effect_data(effect_data);
|
||||
}
|
||||
|
||||
void ESPRangeView::fade_to_white(uint8_t amnt) {
|
||||
for (auto c : *this)
|
||||
c.fade_to_white(amnt);
|
||||
}
|
||||
void ESPRangeView::fade_to_black(uint8_t amnt) {
|
||||
for (auto c : *this)
|
||||
c.fade_to_black(amnt);
|
||||
}
|
||||
void ESPRangeView::lighten(uint8_t delta) {
|
||||
for (auto c : *this)
|
||||
c.lighten(delta);
|
||||
}
|
||||
void ESPRangeView::darken(uint8_t delta) {
|
||||
for (auto c : *this)
|
||||
c.darken(delta);
|
||||
}
|
||||
ESPRangeView &ESPRangeView::operator=(const ESPRangeView &rhs) { // NOLINT
|
||||
// If size doesn't match, error (todo warning)
|
||||
if (rhs.size() != this->size())
|
||||
return *this;
|
||||
|
||||
if (this->parent_ != rhs.parent_) {
|
||||
for (int32_t i = 0; i < this->size(); i++)
|
||||
(*this)[i].set(rhs[i].get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If both equal, already done
|
||||
if (rhs.begin_ == this->begin_)
|
||||
return *this;
|
||||
|
||||
if (rhs.begin_ > this->begin_) {
|
||||
// Copy from left
|
||||
for (int32_t i = 0; i < this->size(); i++) {
|
||||
(*this)[i].set(rhs[i].get());
|
||||
}
|
||||
} else {
|
||||
// Copy from right
|
||||
for (int32_t i = this->size() - 1; i >= 0; i--) {
|
||||
(*this)[i].set(rhs[i].get());
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ESPColorView ESPRangeIterator::operator*() const { return this->range_.parent_->get(this->i_); }
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_color_view.h"
|
||||
#include "esp_hsv_color.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
int32_t interpret_index(int32_t index, int32_t size);
|
||||
|
||||
class AddressableLight;
|
||||
class ESPRangeIterator;
|
||||
|
||||
class ESPRangeView : public ESPColorSettable {
|
||||
public:
|
||||
ESPRangeView(AddressableLight *parent, int32_t begin, int32_t end)
|
||||
: parent_(parent), begin_(begin), end_(end < begin ? begin : end) {}
|
||||
|
||||
int32_t size() const { return this->end_ - this->begin_; }
|
||||
ESPColorView operator[](int32_t index) const;
|
||||
ESPRangeIterator begin();
|
||||
ESPRangeIterator end();
|
||||
|
||||
void set(const Color &color) override;
|
||||
void set(const ESPHSVColor &color) { this->set(color.to_rgb()); }
|
||||
void set_red(uint8_t red) override;
|
||||
void set_green(uint8_t green) override;
|
||||
void set_blue(uint8_t blue) override;
|
||||
void set_white(uint8_t white) override;
|
||||
void set_effect_data(uint8_t effect_data) override;
|
||||
|
||||
void fade_to_white(uint8_t amnt) override;
|
||||
void fade_to_black(uint8_t amnt) override;
|
||||
void lighten(uint8_t delta) override;
|
||||
void darken(uint8_t delta) override;
|
||||
|
||||
ESPRangeView &operator=(const Color &rhs) {
|
||||
this->set(rhs);
|
||||
return *this;
|
||||
}
|
||||
ESPRangeView &operator=(const ESPColorView &rhs) {
|
||||
this->set(rhs.get());
|
||||
return *this;
|
||||
}
|
||||
ESPRangeView &operator=(const ESPHSVColor &rhs) {
|
||||
this->set_hsv(rhs);
|
||||
return *this;
|
||||
}
|
||||
ESPRangeView &operator=(const ESPRangeView &rhs);
|
||||
|
||||
protected:
|
||||
friend ESPRangeIterator;
|
||||
|
||||
AddressableLight *parent_;
|
||||
int32_t begin_;
|
||||
int32_t end_;
|
||||
};
|
||||
|
||||
class ESPRangeIterator {
|
||||
public:
|
||||
ESPRangeIterator(const ESPRangeView &range, int32_t i) : range_(range), i_(i) {}
|
||||
ESPRangeIterator operator++() {
|
||||
this->i_++;
|
||||
return *this;
|
||||
}
|
||||
bool operator!=(const ESPRangeIterator &other) const { return this->i_ != other.i_; }
|
||||
ESPColorView operator*() const;
|
||||
|
||||
protected:
|
||||
ESPRangeView range_;
|
||||
int32_t i_;
|
||||
};
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,160 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/optional.h"
|
||||
#include "light_color_values.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
class LightState;
|
||||
|
||||
/** This class represents a requested change in a light state.
|
||||
*/
|
||||
class LightCall {
|
||||
public:
|
||||
explicit LightCall(LightState *parent) : parent_(parent) {}
|
||||
|
||||
/// Set the binary ON/OFF state of the light.
|
||||
LightCall &set_state(optional<bool> state);
|
||||
/// Set the binary ON/OFF state of the light.
|
||||
LightCall &set_state(bool state);
|
||||
/** Set the transition length of this call in milliseconds.
|
||||
*
|
||||
* This argument is ignored for starting flashes and effects.
|
||||
*
|
||||
* Defaults to the default transition length defined in the light configuration.
|
||||
*/
|
||||
LightCall &set_transition_length(optional<uint32_t> transition_length);
|
||||
/** Set the transition length of this call in milliseconds.
|
||||
*
|
||||
* This argument is ignored for starting flashes and effects.
|
||||
*
|
||||
* Defaults to the default transition length defined in the light configuration.
|
||||
*/
|
||||
LightCall &set_transition_length(uint32_t transition_length);
|
||||
/// Set the transition length property if the light supports transitions.
|
||||
LightCall &set_transition_length_if_supported(uint32_t transition_length);
|
||||
/// Start and set the flash length of this call in milliseconds.
|
||||
LightCall &set_flash_length(optional<uint32_t> flash_length);
|
||||
/// Start and set the flash length of this call in milliseconds.
|
||||
LightCall &set_flash_length(uint32_t flash_length);
|
||||
/// Set the target brightness of the light from 0.0 (fully off) to 1.0 (fully on)
|
||||
LightCall &set_brightness(optional<float> brightness);
|
||||
/// Set the target brightness of the light from 0.0 (fully off) to 1.0 (fully on)
|
||||
LightCall &set_brightness(float brightness);
|
||||
/// Set the brightness property if the light supports brightness.
|
||||
LightCall &set_brightness_if_supported(float brightness);
|
||||
/** Set the red RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_red(optional<float> red);
|
||||
/** Set the red RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_red(float red);
|
||||
/// Set the red property if the light supports RGB.
|
||||
LightCall &set_red_if_supported(float red);
|
||||
/** Set the green RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_green(optional<float> green);
|
||||
/** Set the green RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_green(float green);
|
||||
/// Set the green property if the light supports RGB.
|
||||
LightCall &set_green_if_supported(float green);
|
||||
/** Set the blue RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_blue(optional<float> blue);
|
||||
/** Set the blue RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_blue(float blue);
|
||||
/// Set the blue property if the light supports RGB.
|
||||
LightCall &set_blue_if_supported(float blue);
|
||||
/// Set the white value value of the light from 0.0 to 1.0 for RGBW[W] lights.
|
||||
LightCall &set_white(optional<float> white);
|
||||
/// Set the white value value of the light from 0.0 to 1.0 for RGBW[W] lights.
|
||||
LightCall &set_white(float white);
|
||||
/// Set the white property if the light supports RGB.
|
||||
LightCall &set_white_if_supported(float white);
|
||||
/// Set the color temperature of the light in mireds for CWWW or RGBWW lights.
|
||||
LightCall &set_color_temperature(optional<float> color_temperature);
|
||||
/// Set the color temperature of the light in mireds for CWWW or RGBWW lights.
|
||||
LightCall &set_color_temperature(float color_temperature);
|
||||
/// Set the color_temperature property if the light supports color temperature.
|
||||
LightCall &set_color_temperature_if_supported(float color_temperature);
|
||||
/// Set the effect of the light by its name.
|
||||
LightCall &set_effect(optional<std::string> effect);
|
||||
/// Set the effect of the light by its name.
|
||||
LightCall &set_effect(const std::string &effect);
|
||||
/// Set the effect of the light by its internal index number (only for internal use).
|
||||
LightCall &set_effect(uint32_t effect_number);
|
||||
LightCall &set_effect(optional<uint32_t> effect_number);
|
||||
/// Set whether this light call should trigger a publish state.
|
||||
LightCall &set_publish(bool publish);
|
||||
/// Set whether this light call should trigger a save state to recover them at startup..
|
||||
LightCall &set_save(bool save);
|
||||
|
||||
/** Set the RGB color of the light by RGB values.
|
||||
*
|
||||
* Please note that this only changes the color of the light, not the brightness.
|
||||
*
|
||||
* @param red The red color value from 0.0 to 1.0.
|
||||
* @param green The green color value from 0.0 to 1.0.
|
||||
* @param blue The blue color value from 0.0 to 1.0.
|
||||
* @return The light call for chaining setters.
|
||||
*/
|
||||
LightCall &set_rgb(float red, float green, float blue);
|
||||
/** Set the RGBW color of the light by RGB values.
|
||||
*
|
||||
* Please note that this only changes the color of the light, not the brightness.
|
||||
*
|
||||
* @param red The red color value from 0.0 to 1.0.
|
||||
* @param green The green color value from 0.0 to 1.0.
|
||||
* @param blue The blue color value from 0.0 to 1.0.
|
||||
* @param white The white color value from 0.0 to 1.0.
|
||||
* @return The light call for chaining setters.
|
||||
*/
|
||||
LightCall &set_rgbw(float red, float green, float blue, float white);
|
||||
#ifdef USE_JSON
|
||||
LightCall &parse_color_json(JsonObject &root);
|
||||
LightCall &parse_json(JsonObject &root);
|
||||
#endif
|
||||
LightCall &from_light_color_values(const LightColorValues &values);
|
||||
|
||||
void perform();
|
||||
|
||||
protected:
|
||||
/// Validate all properties and return the target light color values.
|
||||
LightColorValues validate_();
|
||||
|
||||
bool has_transition_() { return this->transition_length_.has_value(); }
|
||||
bool has_flash_() { return this->flash_length_.has_value(); }
|
||||
bool has_effect_() { return this->effect_.has_value(); }
|
||||
|
||||
LightState *parent_;
|
||||
optional<bool> state_;
|
||||
optional<uint32_t> transition_length_;
|
||||
optional<uint32_t> flash_length_;
|
||||
optional<float> brightness_;
|
||||
optional<float> red_;
|
||||
optional<float> green_;
|
||||
optional<float> blue_;
|
||||
optional<float> white_;
|
||||
optional<float> color_temperature_;
|
||||
optional<uint32_t> effect_;
|
||||
bool publish_{true};
|
||||
bool save_{true};
|
||||
};
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,161 +5,15 @@
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "light_effect.h"
|
||||
#include "light_color_values.h"
|
||||
#include "light_call.h"
|
||||
#include "light_traits.h"
|
||||
#include "light_transformer.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
class LightState;
|
||||
class LightOutput;
|
||||
|
||||
class LightCall {
|
||||
public:
|
||||
explicit LightCall(LightState *parent) : parent_(parent) {}
|
||||
|
||||
/// Set the binary ON/OFF state of the light.
|
||||
LightCall &set_state(optional<bool> state);
|
||||
/// Set the binary ON/OFF state of the light.
|
||||
LightCall &set_state(bool state);
|
||||
/** Set the transition length of this call in milliseconds.
|
||||
*
|
||||
* This argument is ignored for starting flashes and effects.
|
||||
*
|
||||
* Defaults to the default transition length defined in the light configuration.
|
||||
*/
|
||||
LightCall &set_transition_length(optional<uint32_t> transition_length);
|
||||
/** Set the transition length of this call in milliseconds.
|
||||
*
|
||||
* This argument is ignored for starting flashes and effects.
|
||||
*
|
||||
* Defaults to the default transition length defined in the light configuration.
|
||||
*/
|
||||
LightCall &set_transition_length(uint32_t transition_length);
|
||||
/// Set the transition length property if the light supports transitions.
|
||||
LightCall &set_transition_length_if_supported(uint32_t transition_length);
|
||||
/// Start and set the flash length of this call in milliseconds.
|
||||
LightCall &set_flash_length(optional<uint32_t> flash_length);
|
||||
/// Start and set the flash length of this call in milliseconds.
|
||||
LightCall &set_flash_length(uint32_t flash_length);
|
||||
/// Set the target brightness of the light from 0.0 (fully off) to 1.0 (fully on)
|
||||
LightCall &set_brightness(optional<float> brightness);
|
||||
/// Set the target brightness of the light from 0.0 (fully off) to 1.0 (fully on)
|
||||
LightCall &set_brightness(float brightness);
|
||||
/// Set the brightness property if the light supports brightness.
|
||||
LightCall &set_brightness_if_supported(float brightness);
|
||||
/** Set the red RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_red(optional<float> red);
|
||||
/** Set the red RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_red(float red);
|
||||
/// Set the red property if the light supports RGB.
|
||||
LightCall &set_red_if_supported(float red);
|
||||
/** Set the green RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_green(optional<float> green);
|
||||
/** Set the green RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_green(float green);
|
||||
/// Set the green property if the light supports RGB.
|
||||
LightCall &set_green_if_supported(float green);
|
||||
/** Set the blue RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_blue(optional<float> blue);
|
||||
/** Set the blue RGB value of the light from 0.0 to 1.0.
|
||||
*
|
||||
* Note that this only controls the color of the light, not its brightness.
|
||||
*/
|
||||
LightCall &set_blue(float blue);
|
||||
/// Set the blue property if the light supports RGB.
|
||||
LightCall &set_blue_if_supported(float blue);
|
||||
/// Set the white value value of the light from 0.0 to 1.0 for RGBW[W] lights.
|
||||
LightCall &set_white(optional<float> white);
|
||||
/// Set the white value value of the light from 0.0 to 1.0 for RGBW[W] lights.
|
||||
LightCall &set_white(float white);
|
||||
/// Set the white property if the light supports RGB.
|
||||
LightCall &set_white_if_supported(float white);
|
||||
/// Set the color temperature of the light in mireds for CWWW or RGBWW lights.
|
||||
LightCall &set_color_temperature(optional<float> color_temperature);
|
||||
/// Set the color temperature of the light in mireds for CWWW or RGBWW lights.
|
||||
LightCall &set_color_temperature(float color_temperature);
|
||||
/// Set the color_temperature property if the light supports color temperature.
|
||||
LightCall &set_color_temperature_if_supported(float color_temperature);
|
||||
/// Set the effect of the light by its name.
|
||||
LightCall &set_effect(optional<std::string> effect);
|
||||
/// Set the effect of the light by its name.
|
||||
LightCall &set_effect(const std::string &effect);
|
||||
/// Set the effect of the light by its internal index number (only for internal use).
|
||||
LightCall &set_effect(uint32_t effect_number);
|
||||
LightCall &set_effect(optional<uint32_t> effect_number);
|
||||
/// Set whether this light call should trigger a publish state.
|
||||
LightCall &set_publish(bool publish);
|
||||
/// Set whether this light call should trigger a save state to recover them at startup..
|
||||
LightCall &set_save(bool save);
|
||||
|
||||
/** Set the RGB color of the light by RGB values.
|
||||
*
|
||||
* Please note that this only changes the color of the light, not the brightness.
|
||||
*
|
||||
* @param red The red color value from 0.0 to 1.0.
|
||||
* @param green The green color value from 0.0 to 1.0.
|
||||
* @param blue The blue color value from 0.0 to 1.0.
|
||||
* @return The light call for chaining setters.
|
||||
*/
|
||||
LightCall &set_rgb(float red, float green, float blue);
|
||||
/** Set the RGBW color of the light by RGB values.
|
||||
*
|
||||
* Please note that this only changes the color of the light, not the brightness.
|
||||
*
|
||||
* @param red The red color value from 0.0 to 1.0.
|
||||
* @param green The green color value from 0.0 to 1.0.
|
||||
* @param blue The blue color value from 0.0 to 1.0.
|
||||
* @param white The white color value from 0.0 to 1.0.
|
||||
* @return The light call for chaining setters.
|
||||
*/
|
||||
LightCall &set_rgbw(float red, float green, float blue, float white);
|
||||
#ifdef USE_JSON
|
||||
LightCall &parse_color_json(JsonObject &root);
|
||||
LightCall &parse_json(JsonObject &root);
|
||||
#endif
|
||||
LightCall &from_light_color_values(const LightColorValues &values);
|
||||
|
||||
void perform();
|
||||
|
||||
protected:
|
||||
/// Validate all properties and return the target light color values.
|
||||
LightColorValues validate_();
|
||||
|
||||
bool has_transition_() { return this->transition_length_.has_value(); }
|
||||
bool has_flash_() { return this->flash_length_.has_value(); }
|
||||
bool has_effect_() { return this->effect_.has_value(); }
|
||||
|
||||
LightState *parent_;
|
||||
optional<bool> state_;
|
||||
optional<uint32_t> transition_length_;
|
||||
optional<uint32_t> flash_length_;
|
||||
optional<float> brightness_;
|
||||
optional<float> red_;
|
||||
optional<float> green_;
|
||||
optional<float> blue_;
|
||||
optional<float> white_;
|
||||
optional<float> color_temperature_;
|
||||
optional<uint32_t> effect_;
|
||||
bool publish_{true};
|
||||
bool save_{true};
|
||||
};
|
||||
|
||||
enum LightRestoreMode {
|
||||
LIGHT_RESTORE_DEFAULT_OFF,
|
||||
LIGHT_RESTORE_DEFAULT_ON,
|
||||
@@ -204,14 +58,6 @@ class LightState : public Nameable, public Component {
|
||||
*/
|
||||
LightColorValues current_values;
|
||||
|
||||
/// Deprecated method to access current_values.
|
||||
ESPDEPRECATED("get_current_values() is deprecated, please use .current_values instead.")
|
||||
LightColorValues get_current_values();
|
||||
|
||||
/// Deprecated method to access remote_values.
|
||||
ESPDEPRECATED("get_remote_values() is deprecated, please use .remote_values instead.")
|
||||
LightColorValues get_remote_values();
|
||||
|
||||
/** The remote color values reported to the frontend.
|
||||
*
|
||||
* These are different from the "current" values: For example transitions will
|
||||
@@ -222,6 +68,14 @@ class LightState : public Nameable, public Component {
|
||||
*/
|
||||
LightColorValues remote_values;
|
||||
|
||||
/// Deprecated method to access current_values.
|
||||
ESPDEPRECATED("get_current_values() is deprecated, please use .current_values instead.")
|
||||
LightColorValues get_current_values();
|
||||
|
||||
/// Deprecated method to access remote_values.
|
||||
ESPDEPRECATED("get_remote_values() is deprecated, please use .remote_values instead.")
|
||||
LightColorValues get_remote_values();
|
||||
|
||||
/// Publish the currently active state to the frontend.
|
||||
void publish_state();
|
||||
|
||||
@@ -231,29 +85,22 @@ class LightState : public Nameable, public Component {
|
||||
/// Return the name of the current effect, or if no effect is active "None".
|
||||
std::string get_effect_name();
|
||||
|
||||
/** This lets front-end components subscribe to light change events.
|
||||
*
|
||||
* This is different from add_new_current_values_callback in that it only sends events for start
|
||||
* and end values. For example, with transitions it will only send a single callback whereas
|
||||
* the callback passed in add_new_current_values_callback will be called every loop() cycle when
|
||||
* a transition is active
|
||||
*
|
||||
* Note the callback should get the output values through get_remote_values().
|
||||
/**
|
||||
* This lets front-end components subscribe to light change events. This callback is called once
|
||||
* when the remote color values are changed.
|
||||
*
|
||||
* @param send_callback The callback.
|
||||
*/
|
||||
void add_new_remote_values_callback(std::function<void()> &&send_callback);
|
||||
|
||||
/**
|
||||
* The callback is called once the state of current_values and remote_values are equal
|
||||
* The callback is called once the state of current_values and remote_values are equal (when the
|
||||
* transition is finished).
|
||||
*
|
||||
* @param send_callback
|
||||
*/
|
||||
void add_new_target_state_reached_callback(std::function<void()> &&send_callback);
|
||||
|
||||
/// Return whether the light has any effects that meet the trait requirements.
|
||||
bool supports_effects();
|
||||
|
||||
#ifdef USE_JSON
|
||||
/// Dump the state of this light as JSON.
|
||||
void dump_json(JsonObject &root);
|
||||
@@ -265,10 +112,17 @@ class LightState : public Nameable, public Component {
|
||||
/// Set the gamma correction factor
|
||||
void set_gamma_correct(float gamma_correct);
|
||||
float get_gamma_correct() const { return this->gamma_correct_; }
|
||||
void set_restore_mode(LightRestoreMode restore_mode) { restore_mode_ = restore_mode; }
|
||||
|
||||
/// Set the restore mode of this light
|
||||
void set_restore_mode(LightRestoreMode restore_mode);
|
||||
|
||||
/// Return whether the light has any effects that meet the trait requirements.
|
||||
bool supports_effects();
|
||||
|
||||
/// Get all effects for this light state.
|
||||
const std::vector<LightEffect *> &get_effects() const;
|
||||
|
||||
/// Add effects for this light state.
|
||||
void add_effects(const std::vector<LightEffect *> &effects);
|
||||
|
||||
void current_values_as_binary(bool *binary);
|
||||
@@ -293,6 +147,8 @@ class LightState : public Nameable, public Component {
|
||||
|
||||
/// Internal method to start an effect with the given index
|
||||
void start_effect_(uint32_t effect_index);
|
||||
/// Internal method to get the currently active effect
|
||||
LightEffect *get_active_effect_();
|
||||
/// Internal method to stop the current effect (if one is active).
|
||||
void stop_effect_();
|
||||
/// Internal method to start a transition to the target color with the given length.
|
||||
@@ -307,18 +163,21 @@ class LightState : public Nameable, public Component {
|
||||
/// Internal method to start a transformer.
|
||||
void set_transformer_(std::unique_ptr<LightTransformer> transformer);
|
||||
|
||||
LightEffect *get_active_effect_();
|
||||
/// Internal method to save the current remote_values to the preferences
|
||||
void save_remote_values_();
|
||||
|
||||
/// Object used to store the persisted values of the light.
|
||||
ESPPreferenceObject rtc_;
|
||||
/// Restore mode of the light.
|
||||
LightRestoreMode restore_mode_;
|
||||
/// Default transition length for all transitions in ms.
|
||||
uint32_t default_transition_length_{};
|
||||
/// Store the output to allow effects to have more access.
|
||||
LightOutput *output_;
|
||||
/// Value for storing the index of the currently active effect. 0 if no effect is active
|
||||
uint32_t active_effect_index_{};
|
||||
/// The currently active transformer for this light (transition/flash).
|
||||
std::unique_ptr<LightTransformer> transformer_{nullptr};
|
||||
/// Whether the light value should be written in the next cycle.
|
||||
bool next_write_{true};
|
||||
|
||||
/// Object used to store the persisted values of the light.
|
||||
ESPPreferenceObject rtc_;
|
||||
|
||||
/** Callback to call when new values for the frontend are available.
|
||||
*
|
||||
* "Remote values" are light color values that are reported to the frontend and have a lower
|
||||
@@ -333,11 +192,12 @@ class LightState : public Nameable, public Component {
|
||||
*/
|
||||
CallbackManager<void()> target_state_reached_callback_{};
|
||||
|
||||
LightOutput *output_; ///< Store the output to allow effects to have more access.
|
||||
/// Whether the light value should be written in the next cycle.
|
||||
bool next_write_{true};
|
||||
/// Default transition length for all transitions in ms.
|
||||
uint32_t default_transition_length_{};
|
||||
/// Gamma correction factor for the light.
|
||||
float gamma_correct_{};
|
||||
/// Restore mode of the light.
|
||||
LightRestoreMode restore_mode_;
|
||||
/// List of effects for this light.
|
||||
std::vector<LightEffect *> effects_;
|
||||
};
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
//
|
||||
// Modified by Otto Winter on 18.05.18
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
// type for nullopt
|
||||
|
||||
Reference in New Issue
Block a user