ESPHome  2024.11.1
addressable_light.cpp
Go to the documentation of this file.
1 #include "addressable_light.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace light {
6 
7 static 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 
26 std::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_;
57  this->target_color_ = color_from_light_color_values(end_values);
58 
59  // our transition will handle brightness, disable brightness in correction.
60  this->light_.correction_.set_local_brightness(255);
61  this->target_color_ *= to_uint8_scale(end_values.get_brightness() * end_values.get_state());
62 }
63 
65  float smoothed_progress = LightTransitionTransformer::smoothed_progress(this->get_progress_());
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 
106  this->last_transition_progress_ = smoothed_progress;
107  this->light_.schedule_show();
108 
109  return {};
110 }
111 
112 } // namespace light
113 } // namespace esphome
const char * name
Definition: stm32flash.h:78
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition: light_state.h:63
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:52
std::unique_ptr< LightTransformer > create_default_transition() override
LightColorValues current_values
The current values of the light as outputted to the light.
Definition: light_state.h:94
float get_red() const
Get the red property of these light color values. In range 0.0 to 1.0.
mopeka_std_values val[4]
optional< LightColorValues > apply() override
constexpr const T & clamp(const T &v, const T &lo, const T &hi, Compare comp)
Definition: helpers.h:93
float get_blue() const
Get the blue property of these light color values. In range 0.0 to 1.0.
This class represents the color state for a light object.
float get_white() const
Get the white property of these light color values. In range 0.0 to 1.0.
void update_state(LightState *state) override
virtual void setup()
Where the component&#39;s initialization should happen.
Definition: component.cpp:48
void set_local_brightness(uint8_t local_brightness)
virtual int32_t size() const =0
constexpr const char * c_str() const
Definition: string_ref.h:68
Color color_from_light_color_values(LightColorValues val)
Convert the color information from a LightColorValues object to a Color object (does not apply bright...
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
float get_color_brightness() const
Get the color brightness property of these light color values. In range 0.0 to 1.0.
static LightColorValues lerp(const LightColorValues &start, const LightColorValues &end, float completion)
Linearly interpolate between the values in start to the values in end.
float get_green() const
Get the green property of these light color values. In range 0.0 to 1.0.
const StringRef & get_name() const
Definition: entity_base.cpp:10
bool state
Definition: fan.h:34