ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
addressable_light.h
Go to the documentation of this file.
1#pragma once
2
4#include "esp_color_view.h"
5#include "esp_range_view.h"
9#include "light_output.h"
10#include "light_state.h"
11#include "light_transformer.h"
12
13#include <cmath>
14
15#ifdef USE_POWER_SUPPLY
17#endif
18
19namespace esphome::light {
20
22Color color_from_light_color_values(LightColorValues val);
23
26class AddressableLightState final : public LightState {
28
29 public:
30#ifdef USE_LIGHT_POWER_ESTIMATION
31 float get_estimated_current_ma() const;
32 void loop() override;
33#endif
34};
35
36#ifdef USE_LIGHT_POWER_ESTIMATION
37// Allocated only for a strip with power_estimation configured
39 float ma_per_level[4];
41 float max_current_ma{NAN};
42 // Set by call_setup() once size() is known; the budget is what is left for the pixels, NAN for no limit
43 float idle_ma{0.0f};
44 float budget_ma{NAN};
45 // The draw the last pass left in the buffer; a pass that sees it again has nothing new to limit
46 float last_frame_ma{NAN};
47};
48#endif
49
50class AddressableLight : public LightOutput, public Component {
51 public:
52 virtual int32_t size() const = 0;
53 ESPColorView operator[](int32_t index) const { return this->get_view_internal(interpret_index(index, this->size())); }
54 ESPColorView get(int32_t index) { return this->get_view_internal(interpret_index(index, this->size())); }
55 virtual void clear_effect_data() = 0;
56 ESPRangeView range(int32_t from, int32_t to) {
57 from = interpret_index(from, this->size());
58 to = interpret_index(to, this->size());
59 return ESPRangeView(this, from, to);
60 }
61 ESPRangeView all() { return ESPRangeView(this, 0, this->size()); }
62 ESPRangeIterator begin() { return this->all().begin(); }
63 ESPRangeIterator end() { return this->all().end(); }
64 void shift_left(int32_t amnt) {
65 if (amnt < 0) {
66 this->shift_right(-amnt);
67 return;
68 }
69 if (amnt > this->size())
70 amnt = this->size();
71 this->range(0, -amnt) = this->range(amnt, this->size());
72 }
73 void shift_right(int32_t amnt) {
74 if (amnt < 0) {
75 this->shift_left(-amnt);
76 return;
77 }
78 if (amnt > this->size())
79 amnt = this->size();
80 this->range(amnt, this->size()) = this->range(0, -amnt);
81 }
82 // Indicates whether an effect that directly updates the output buffer is active to prevent overwriting
83 bool is_effect_active() const { return this->effect_active_; }
84 void set_effect_active(bool effect_active) { this->effect_active_ = effect_active; }
85 std::unique_ptr<LightTransformer> create_default_transition() override;
86 void set_correction(float red, float green, float blue, float white = 1.0f) {
88 Color(to_uint8_scale(red), to_uint8_scale(green), to_uint8_scale(blue), to_uint8_scale(white)));
89 }
90#ifdef USE_LIGHT_POWER_ESTIMATION
91 // Per-channel draw at full level and idle draw per LED
92 void set_power_estimation(float ma_red, float ma_green, float ma_blue, float ma_white, float idle_ma_per_led) {
93 if (this->power_estimation_ == nullptr)
94 this->power_estimation_ = new PowerEstimation(); // NOLINT(cppcoreguidelines-owning-memory)
95 auto *power = this->power_estimation_;
96 power->ma_per_level[0] = ma_red / 255.0f;
97 power->ma_per_level[1] = ma_green / 255.0f;
98 power->ma_per_level[2] = ma_blue / 255.0f;
99 power->ma_per_level[3] = ma_white / 255.0f;
100 power->idle_ma_per_led = idle_ma_per_led;
101 }
102 // Called after set_power_estimation()
103 void set_max_current_ma(float max_current_ma) { this->power_estimation_->max_current_ma = max_current_ma; }
104 // The draw of the frame in the buffer, NAN without power_estimation
105 float get_estimated_current_ma() const;
106#endif
107 void setup_state(LightState *state) override {
108#ifdef USE_LIGHT_GAMMA_LUT
110#endif
111 this->state_parent_ = state;
112 }
113 void update_state(LightState *state) override;
115
116#ifdef USE_POWER_SUPPLY
117 void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_.set_parent(power_supply); }
118#endif
119
120 void call_setup() override;
121
122 protected:
124
125 void mark_shown_() {
126#ifdef USE_POWER_SUPPLY
127 for (const auto &c : *this) {
128 if (c.get_red_raw() > 0 || c.get_green_raw() > 0 || c.get_blue_raw() > 0 || c.get_white_raw() > 0) {
129 this->power_.request();
130 return;
131 }
132 }
133 this->power_.unrequest();
134#endif
135 }
136 virtual ESPColorView get_view_internal(int32_t index) const = 0;
137 // Queues the frame for the next loop and returns true until interval_us has passed since last_us
138 bool throttle_show_(uint32_t now_us, uint32_t last_us, uint32_t interval_us) {
139 if (now_us - last_us >= interval_us)
140 return false;
141 this->schedule_show();
142 return true;
143 }
144
145#ifdef USE_LIGHT_POWER_ESTIMATION
147 // Run by the light state before each frame goes out
148 void limit_power_();
149 void setup_power_budget_();
150 // slack_ma, when asked for, is one level's draw for every lit channel: the most the round-up on the way
151 // down can have added to the frame
152 float frame_ma_(float *slack_ma = nullptr) const;
153 float draw_ma_(const uint32_t sums[4]) const;
154#endif
155
158#ifdef USE_LIGHT_POWER_ESTIMATION
160#endif
161#ifdef USE_POWER_SUPPLY
163#endif
164 bool effect_active_{false};
165};
166
168 public:
170
171 void start() override;
172 optional<LightColorValues> apply() override;
173
174 protected:
181};
182
183} // namespace esphome::light
float draw_ma_(const uint32_t sums[4]) const
virtual void clear_effect_data()=0
virtual ESPColorView get_view_internal(int32_t index) const =0
void set_power_estimation(float ma_red, float ma_green, float ma_blue, float ma_white, float idle_ma_per_led)
void set_power_supply(power_supply::PowerSupply *power_supply)
void setup_state(LightState *state) override
bool throttle_show_(uint32_t now_us, uint32_t last_us, uint32_t interval_us)
ESPColorView get(int32_t index)
float frame_ma_(float *slack_ma=nullptr) const
power_supply::PowerSupplyRequester power_
ESPColorView operator[](int32_t index) const
void set_max_current_ma(float max_current_ma)
void set_effect_active(bool effect_active)
virtual int32_t size() const =0
void update_state(LightState *state) override
void set_correction(float red, float green, float blue, float white=1.0f)
ESPRangeView range(int32_t from, int32_t to)
std::unique_ptr< LightTransformer > create_default_transition() override
Use a custom state class for addressable lights, to allow type system to discriminate between address...
optional< LightColorValues > apply() override
void set_max_brightness(const Color &max_brightness)
void set_gamma_table(const uint16_t *table)
A half-open range of LEDs, inclusive of the begin index and exclusive of the end index,...
Interface to write LightStates to hardware.
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition light_state.h:68
LightState(LightOutput *output)
void schedule_write_()
Schedule a write to the light output and enable the loop to process it.
const uint16_t * get_gamma_table() const
Get the forward gamma lookup table, 256 PROGMEM entries.
Base class for all light color transformers, such as transitions or flashes.
bool state
Definition fan.h:2
mopeka_std_values val[3]
Range range
Definition msa3xx.h:0
Color color_from_light_color_values(LightColorValues val)
Convert the color information from a LightColorValues object to a Color object (does not apply bright...
int32_t HOT interpret_index(int32_t index, int32_t size)