ESPHome 2025.12.0-dev
Loading...
Searching...
No Matches
addressable_light.cpp
Go to the documentation of this file.
1#include "addressable_light.h"
2#include "esphome/core/log.h"
3
4namespace esphome {
5namespace light {
6
7static const char *const TAG = "light.addressable";
8
10 this->setup();
11
12#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
13 this->set_interval(5000, [this]() {
14 const char *name = this->state_parent_ == nullptr ? "" : this->state_parent_->get_name().c_str();
15 ESP_LOGVV(TAG, "Addressable Light '%s' (effect_active=%s)", name, YESNO(this->effect_active_));
16 for (int i = 0; i < this->size(); i++) {
17 auto color = this->get(i);
18 ESP_LOGVV(TAG, " [%2d] Color: R=%3u G=%3u B=%3u W=%3u", i, color.get_red_raw(), color.get_green_raw(),
19 color.get_blue_raw(), color.get_white_raw());
20 }
21 ESP_LOGVV(TAG, " ");
22 });
23#endif
24}
25
26std::unique_ptr<LightTransformer> AddressableLight::create_default_transition() {
27 return make_unique<AddressableLightTransformer>(*this);
28}
29
31 auto r = to_uint8_scale(val.get_color_brightness() * val.get_red());
32 auto g = to_uint8_scale(val.get_color_brightness() * val.get_green());
33 auto b = to_uint8_scale(val.get_color_brightness() * val.get_blue());
34 auto w = to_uint8_scale(val.get_white());
35 return Color(r, g, b, w);
36}
37
39 auto val = state->current_values;
40 auto max_brightness = to_uint8_scale(val.get_brightness() * val.get_state());
41 this->correction_.set_local_brightness(max_brightness);
42
43 if (this->is_effect_active())
44 return;
45
46 // don't use LightState helper, gamma correction+brightness is handled by ESPColorView
48 this->schedule_show();
49}
50
52 // don't try to transition over running effects.
53 if (this->light_.is_effect_active())
54 return;
55
56 auto end_values = this->target_values_;
58
59 // our transition will handle brightness, disable brightness in correction.
61 this->target_color_ *= to_uint8_scale(end_values.get_brightness() * end_values.get_state());
62}
63
64inline constexpr uint8_t subtract_scaled_difference(uint8_t a, uint8_t b, int32_t scale) {
65 return uint8_t(int32_t(a) - (((int32_t(a) - int32_t(b)) * scale) / 256));
66}
67
70
71 // When running an output-buffer modifying effect, don't try to transition individual LEDs, but instead just fade the
72 // LightColorValues. write_state() then picks up the change in brightness, and the color change is picked up by the
73 // effects which respect it.
74 if (this->light_.is_effect_active())
75 return LightColorValues::lerp(this->get_start_values(), this->get_target_values(), smoothed_progress);
76
77 // Use a specialized transition for addressable lights: instead of using a unified transition for
78 // all LEDs, we use the current state of each LED as the start.
79
80 // We can't use a direct lerp smoothing here though - that would require creating a copy of the original
81 // state of each LED at the start of the transition. Instead, we "fake" the look of lerp by calculating
82 // the delta between the current state and the target state, assuming that the delta represents the rest
83 // of the transition that was to be applied as of the previous transition step, and scaling the delta for
84 // what should be left after the current transition step. In this manner, the delta decays to zero as the
85 // transition progresses.
86 //
87 // Here's an example of how the algorithm progresses in discrete steps:
88 //
89 // At time = 0.00, 0% complete, 100% remaining, 100% will remain after this step, so the scale is 100% / 100% = 100%.
90 // At time = 0.10, 0% complete, 100% remaining, 90% will remain after this step, so the scale is 90% / 100% = 90%.
91 // At time = 0.20, 10% complete, 90% remaining, 80% will remain after this step, so the scale is 80% / 90% = 88.9%.
92 // At time = 0.50, 20% complete, 80% remaining, 50% will remain after this step, so the scale is 50% / 80% = 62.5%.
93 // At time = 0.90, 50% complete, 50% remaining, 10% will remain after this step, so the scale is 10% / 50% = 20%.
94 // At time = 0.91, 90% complete, 10% remaining, 9% will remain after this step, so the scale is 9% / 10% = 90%.
95 // At time = 1.00, 91% complete, 9% remaining, 0% will remain after this step, so the scale is 0% / 9% = 0%.
96 //
97 // Because the color values are quantized to 8 bit resolution after each step, the transition may appear
98 // non-linear when applying small deltas.
99
101 int32_t scale = int32_t(256.f * std::max((1.f - smoothed_progress) / (1.f - this->last_transition_progress_), 0.f));
102 for (auto led : this->light_) {
103 led.set_rgbw(subtract_scaled_difference(this->target_color_.red, led.get_red(), scale),
104 subtract_scaled_difference(this->target_color_.green, led.get_green(), scale),
105 subtract_scaled_difference(this->target_color_.blue, led.get_blue(), scale),
106 subtract_scaled_difference(this->target_color_.white, led.get_white(), scale));
107 }
109 this->light_.schedule_show();
110 }
111
112 return {};
113}
114
115} // namespace light
116} // namespace esphome
virtual void setup()
Where the component's initialization should happen.
Definition component.cpp:94
void set_interval(const std::string &name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
Definition component.cpp:98
const StringRef & get_name() const
constexpr const char * c_str() const
Definition string_ref.h:69
ESPColorView get(int32_t index)
virtual int32_t size() const =0
void update_state(LightState *state) override
std::unique_ptr< LightTransformer > create_default_transition() override
optional< LightColorValues > apply() override
void set_local_brightness(uint8_t local_brightness)
This class represents the color state for a light object.
static LightColorValues lerp(const LightColorValues &start, const LightColorValues &end, float completion)
Linearly interpolate between the values in start to the values in end.
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition light_state.h:69
const LightColorValues & get_target_values() const
float get_progress_()
The progress of this transition, on a scale of 0 to 1.
static float smoothed_progress(float x)
const LightColorValues & get_start_values() const
bool state
Definition fan.h:0
mopeka_std_values val[4]
Color color_from_light_color_values(LightColorValues val)
Convert the color information from a LightColorValues object to a Color object (does not apply bright...
constexpr uint8_t subtract_scaled_difference(uint8_t a, uint8_t b, int32_t scale)
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint8_t red
Definition color.h:31
uint8_t white
Definition color.h:43
uint8_t green
Definition color.h:35
uint8_t blue
Definition color.h:39