ESPHome 2025.5.0
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() {
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
66
67 // When running an output-buffer modifying effect, don't try to transition individual LEDs, but instead just fade the
68 // LightColorValues. write_state() then picks up the change in brightness, and the color change is picked up by the
69 // effects which respect it.
70 if (this->light_.is_effect_active())
71 return LightColorValues::lerp(this->get_start_values(), this->get_target_values(), smoothed_progress);
72
73 // Use a specialized transition for addressable lights: instead of using a unified transition for
74 // all LEDs, we use the current state of each LED as the start.
75
76 // We can't use a direct lerp smoothing here though - that would require creating a copy of the original
77 // state of each LED at the start of the transition.
78 // Instead, we "fake" the look of the LERP by using an exponential average over time and using
79 // dynamically-calculated alpha values to match the look.
80
81 float denom = (1.0f - smoothed_progress);
82 float alpha = denom == 0.0f ? 1.0f : (smoothed_progress - this->last_transition_progress_) / denom;
83
84 // We need to use a low-resolution alpha here which makes the transition set in only after ~half of the length
85 // We solve this by accumulating the fractional part of the alpha over time.
86 float alpha255 = alpha * 255.0f;
87 float alpha255int = floorf(alpha255);
88 float alpha255remainder = alpha255 - alpha255int;
89
90 this->accumulated_alpha_ += alpha255remainder;
91 float alpha_add = floorf(this->accumulated_alpha_);
92 this->accumulated_alpha_ -= alpha_add;
93
94 alpha255 += alpha_add;
95 alpha255 = clamp(alpha255, 0.0f, 255.0f);
96 auto alpha8 = static_cast<uint8_t>(alpha255);
97
98 if (alpha8 != 0) {
99 uint8_t inv_alpha8 = 255 - alpha8;
100 Color add = this->target_color_ * alpha8;
101
102 for (auto led : this->light_)
103 led.set(add + led.get() * inv_alpha8);
104 }
105
107 this->light_.schedule_show();
108
109 return {};
110}
111
112} // namespace light
113} // namespace esphome
virtual void setup()
Where the component's initialization should happen.
Definition component.cpp:51
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:55
const StringRef & get_name() const
constexpr const char * c_str() const
Definition string_ref.h:68
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:63
const LightColorValues & get_target_values() const
float get_progress_()
The progress of this transition, on a scale of 0 to 1.
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...
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::unique_ptr< T > make_unique(Args &&...args)
Definition helpers.h:85
constexpr const T & clamp(const T &v, const T &lo, const T &hi, Compare comp)
Definition helpers.h:101