ESPHome  2024.9.0
automation.h
Go to the documentation of this file.
1 #pragma once
2 
4 #include "light_state.h"
5 #include "addressable_light.h"
6 
7 namespace esphome {
8 namespace light {
9 
10 enum class LimitMode { CLAMP, DO_NOTHING };
11 
12 template<typename... Ts> class ToggleAction : public Action<Ts...> {
13  public:
14  explicit ToggleAction(LightState *state) : state_(state) {}
15 
16  TEMPLATABLE_VALUE(uint32_t, transition_length)
17 
18  void play(Ts... x) override {
19  auto call = this->state_->toggle();
20  call.set_transition_length(this->transition_length_.optional_value(x...));
21  call.perform();
22  }
23 
24  protected:
26 };
27 
28 template<typename... Ts> class LightControlAction : public Action<Ts...> {
29  public:
30  explicit LightControlAction(LightState *parent) : parent_(parent) {}
31 
32  TEMPLATABLE_VALUE(ColorMode, color_mode)
33  TEMPLATABLE_VALUE(bool, state)
34  TEMPLATABLE_VALUE(uint32_t, transition_length)
35  TEMPLATABLE_VALUE(uint32_t, flash_length)
36  TEMPLATABLE_VALUE(float, brightness)
37  TEMPLATABLE_VALUE(float, color_brightness)
38  TEMPLATABLE_VALUE(float, red)
39  TEMPLATABLE_VALUE(float, green)
40  TEMPLATABLE_VALUE(float, blue)
41  TEMPLATABLE_VALUE(float, white)
42  TEMPLATABLE_VALUE(float, color_temperature)
43  TEMPLATABLE_VALUE(float, cold_white)
44  TEMPLATABLE_VALUE(float, warm_white)
45  TEMPLATABLE_VALUE(std::string, effect)
46 
47  void play(Ts... x) override {
48  auto call = this->parent_->make_call();
49  call.set_color_mode(this->color_mode_.optional_value(x...));
50  call.set_state(this->state_.optional_value(x...));
51  call.set_brightness(this->brightness_.optional_value(x...));
52  call.set_color_brightness(this->color_brightness_.optional_value(x...));
53  call.set_red(this->red_.optional_value(x...));
54  call.set_green(this->green_.optional_value(x...));
55  call.set_blue(this->blue_.optional_value(x...));
56  call.set_white(this->white_.optional_value(x...));
57  call.set_color_temperature(this->color_temperature_.optional_value(x...));
58  call.set_cold_white(this->cold_white_.optional_value(x...));
59  call.set_warm_white(this->warm_white_.optional_value(x...));
60  call.set_effect(this->effect_.optional_value(x...));
61  call.set_flash_length(this->flash_length_.optional_value(x...));
62  call.set_transition_length(this->transition_length_.optional_value(x...));
63  call.perform();
64  }
65 
66  protected:
67  LightState *parent_;
68 };
69 
70 template<typename... Ts> class DimRelativeAction : public Action<Ts...> {
71  public:
72  explicit DimRelativeAction(LightState *parent) : parent_(parent) {}
73 
74  TEMPLATABLE_VALUE(float, relative_brightness)
75  TEMPLATABLE_VALUE(uint32_t, transition_length)
76 
77  void play(Ts... x) override {
78  auto call = this->parent_->make_call();
79  float rel = this->relative_brightness_.value(x...);
80  float cur;
81  this->parent_->remote_values.as_brightness(&cur);
82  if ((limit_mode_ == LimitMode::DO_NOTHING) && ((cur < min_brightness_) || (cur > max_brightness_))) {
83  return;
84  }
85  float new_brightness = clamp(cur + rel, min_brightness_, max_brightness_);
86  call.set_state(new_brightness != 0.0f);
87  call.set_brightness(new_brightness);
88 
89  call.set_transition_length(this->transition_length_.optional_value(x...));
90  call.perform();
91  }
92 
93  void set_min_max_brightness(float min, float max) {
94  this->min_brightness_ = min;
95  this->max_brightness_ = max;
96  }
97 
98  void set_limit_mode(LimitMode limit_mode) { this->limit_mode_ = limit_mode; }
99 
100  protected:
102  float min_brightness_{0.0};
103  float max_brightness_{1.0};
105 };
106 
107 template<typename... Ts> class LightIsOnCondition : public Condition<Ts...> {
108  public:
109  explicit LightIsOnCondition(LightState *state) : state_(state) {}
110  bool check(Ts... x) override { return this->state_->current_values.is_on(); }
111 
112  protected:
114 };
115 template<typename... Ts> class LightIsOffCondition : public Condition<Ts...> {
116  public:
117  explicit LightIsOffCondition(LightState *state) : state_(state) {}
118  bool check(Ts... x) override { return !this->state_->current_values.is_on(); }
119 
120  protected:
122 };
123 
124 class LightTurnOnTrigger : public Trigger<> {
125  public:
127  a_light->add_new_remote_values_callback([this, a_light]() {
128  // using the remote value because of transitions we need to trigger as early as possible
129  auto is_on = a_light->remote_values.is_on();
130  // only trigger when going from off to on
131  auto should_trigger = is_on && !this->last_on_;
132  // Set new state immediately so that trigger() doesn't devolve
133  // into infinite loop
134  this->last_on_ = is_on;
135  if (should_trigger) {
136  this->trigger();
137  }
138  });
139  this->last_on_ = a_light->current_values.is_on();
140  }
141 
142  protected:
143  bool last_on_;
144 };
145 
146 class LightTurnOffTrigger : public Trigger<> {
147  public:
149  a_light->add_new_target_state_reached_callback([this, a_light]() {
150  auto is_on = a_light->current_values.is_on();
151  // only trigger when going from on to off
152  if (!is_on) {
153  this->trigger();
154  }
155  });
156  }
157 };
158 
159 class LightStateTrigger : public Trigger<> {
160  public:
162  a_light->add_new_remote_values_callback([this]() { this->trigger(); });
163  }
164 };
165 
166 // This is slightly ugly, but we can't log in headers, and can't make this a static method on AddressableSet
167 // due to the template. It's just a temporary warning anyway.
168 void addressableset_warn_about_scale(const char *field);
169 
170 template<typename... Ts> class AddressableSet : public Action<Ts...> {
171  public:
172  explicit AddressableSet(LightState *parent) : parent_(parent) {}
173 
174  TEMPLATABLE_VALUE(int32_t, range_from)
175  TEMPLATABLE_VALUE(int32_t, range_to)
176  TEMPLATABLE_VALUE(float, color_brightness)
177  TEMPLATABLE_VALUE(float, red)
178  TEMPLATABLE_VALUE(float, green)
179  TEMPLATABLE_VALUE(float, blue)
180  TEMPLATABLE_VALUE(float, white)
181 
182  void play(Ts... x) override {
183  auto *out = (AddressableLight *) this->parent_->get_output();
184  int32_t range_from = interpret_index(this->range_from_.value_or(x..., 0), out->size());
185  if (range_from < 0 || range_from >= out->size())
186  range_from = 0;
187 
188  int32_t range_to = interpret_index(this->range_to_.value_or(x..., out->size() - 1) + 1, out->size());
189  if (range_to < 0 || range_to >= out->size())
190  range_to = out->size();
191 
192  uint8_t color_brightness =
193  to_uint8_scale(this->color_brightness_.value_or(x..., this->parent_->remote_values.get_color_brightness()));
194  auto range = out->range(range_from, range_to);
195  if (this->red_.has_value())
196  range.set_red(esp_scale8(to_uint8_compat(this->red_.value(x...), "red"), color_brightness));
197  if (this->green_.has_value())
198  range.set_green(esp_scale8(to_uint8_compat(this->green_.value(x...), "green"), color_brightness));
199  if (this->blue_.has_value())
200  range.set_blue(esp_scale8(to_uint8_compat(this->blue_.value(x...), "blue"), color_brightness));
201  if (this->white_.has_value())
202  range.set_white(to_uint8_compat(this->white_.value(x...), "white"));
203  out->schedule_show();
204  }
205 
206  protected:
208 
209  // Historically, this action required uint8_t (0-255) for RGBW values from lambdas. Keep compatibility.
210  static inline uint8_t to_uint8_compat(float value, const char *field) {
211  if (value > 1.0f) {
213  return static_cast<uint8_t>(value);
214  }
215  return to_uint8_scale(value);
216  }
217 };
218 
219 } // namespace light
220 } // namespace esphome
ToggleAction(LightState *state)
Definition: automation.h:14
ColorMode
Color modes are a combination of color capabilities that can be used at the same time.
Definition: color_mode.h:49
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition: light_state.h:34
bool is_on() const
Get the binary true/false state of these light color values.
void set_min_max_brightness(float min, float max)
Definition: automation.h:93
LightColorValues current_values
The current values of the light as outputted to the light.
Definition: light_state.h:65
void addressableset_warn_about_scale(const char *field)
Definition: automation.cpp:9
uint16_t x
Definition: tt21100.cpp:17
void add_new_target_state_reached_callback(std::function< void()> &&send_callback)
The callback is called once the state of current_values and remote_values are equal (when the transit...
int32_t HOT interpret_index(int32_t index, int32_t size)
LightTurnOffTrigger(LightState *a_light)
Definition: automation.h:148
constexpr const T & clamp(const T &v, const T &lo, const T &hi, Compare comp)
Definition: helpers.h:92
LightIsOffCondition(LightState *state)
Definition: automation.h:117
AddressableSet(LightState *parent)
Definition: automation.h:172
void set_limit_mode(LimitMode limit_mode)
Definition: automation.h:98
DimRelativeAction(LightState *parent)
Definition: automation.h:72
Base class for all automation conditions.
Definition: automation.h:74
TEMPLATABLE_VALUE(uint32_t, transition_length) void play(Ts... x) override
Definition: automation.h:16
bool check(Ts... x) override
Definition: automation.h:118
LightStateTrigger(LightState *a_light)
Definition: automation.h:161
void add_new_remote_values_callback(std::function< void()> &&send_callback)
This lets front-end components subscribe to light change events.
bool check(Ts... x) override
Definition: automation.h:110
LightControlAction(LightState *parent)
Definition: automation.h:30
static uint8_t to_uint8_compat(float value, const char *field)
Definition: automation.h:210
LightTurnOnTrigger(LightState *a_light)
Definition: automation.h:126
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
LightColorValues remote_values
The remote color values reported to the frontend.
Definition: light_state.h:77
LightIsOnCondition(LightState *state)
Definition: automation.h:109
bool state
Definition: fan.h:34