mirror of
https://github.com/esphome/esphome.git
synced 2024-11-26 17:05:21 +01:00
Remove double scheduling from addressable lights (#1963)
This commit is contained in:
parent
5ec9bb0fb5
commit
2f33cd2db5
12 changed files with 57 additions and 45 deletions
|
@ -44,6 +44,7 @@ void AdalightLightEffect::blank_all_leds_(light::AddressableLight &it) {
|
||||||
for (int led = it.size(); led-- > 0;) {
|
for (int led = it.size(); led-- > 0;) {
|
||||||
it[led].set(Color::BLACK);
|
it[led].set(Color::BLACK);
|
||||||
}
|
}
|
||||||
|
it.schedule_show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdalightLightEffect::apply(light::AddressableLight &it, const Color ¤t_color) {
|
void AdalightLightEffect::apply(light::AddressableLight &it, const Color ¤t_color) {
|
||||||
|
@ -133,6 +134,7 @@ AdalightLightEffect::Frame AdalightLightEffect::parse_frame_(light::AddressableL
|
||||||
it[led].set(Color(led_data[0], led_data[1], led_data[2], white));
|
it[led].set(Color(led_data[0], led_data[1], led_data[2], white));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it.schedule_show();
|
||||||
return CONSUMED;
|
return CONSUMED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it->schedule_show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,13 +20,12 @@ void FastLEDLightOutput::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, " Num LEDs: %u", this->num_leds_);
|
ESP_LOGCONFIG(TAG, " Num LEDs: %u", this->num_leds_);
|
||||||
ESP_LOGCONFIG(TAG, " Max refresh rate: %u", *this->max_refresh_rate_);
|
ESP_LOGCONFIG(TAG, " Max refresh rate: %u", *this->max_refresh_rate_);
|
||||||
}
|
}
|
||||||
void FastLEDLightOutput::loop() {
|
void FastLEDLightOutput::write_state(light::LightState *state) {
|
||||||
if (!this->should_show_())
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint32_t now = micros();
|
|
||||||
// protect from refreshing too often
|
// protect from refreshing too often
|
||||||
|
uint32_t now = micros();
|
||||||
if (*this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < *this->max_refresh_rate_) {
|
if (*this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < *this->max_refresh_rate_) {
|
||||||
|
// try again next loop iteration, so that this change won't get lost
|
||||||
|
this->schedule_show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->last_refresh_ = now;
|
this->last_refresh_ = now;
|
||||||
|
|
|
@ -213,7 +213,7 @@ class FastLEDLightOutput : public light::AddressableLight {
|
||||||
}
|
}
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
void loop() override;
|
void write_state(light::LightState *state) override;
|
||||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
void clear_effect_data() override {
|
void clear_effect_data() override {
|
||||||
|
|
|
@ -12,8 +12,7 @@ void AddressableLight::call_setup() {
|
||||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||||
this->set_interval(5000, [this]() {
|
this->set_interval(5000, [this]() {
|
||||||
const char *name = this->state_parent_ == nullptr ? "" : this->state_parent_->get_name().c_str();
|
const char *name = this->state_parent_ == nullptr ? "" : this->state_parent_->get_name().c_str();
|
||||||
ESP_LOGVV(TAG, "Addressable Light '%s' (effect_active=%s next_show=%s)", name, YESNO(this->effect_active_),
|
ESP_LOGVV(TAG, "Addressable Light '%s' (effect_active=%s)", name, YESNO(this->effect_active_));
|
||||||
YESNO(this->next_show_));
|
|
||||||
for (int i = 0; i < this->size(); i++) {
|
for (int i = 0; i < this->size(); i++) {
|
||||||
auto color = this->get(i);
|
auto color = this->get(i);
|
||||||
ESP_LOGVV(TAG, " [%2d] Color: R=%3u G=%3u B=%3u W=%3u", i, color.get_red_raw(), color.get_green_raw(),
|
ESP_LOGVV(TAG, " [%2d] Color: R=%3u G=%3u B=%3u W=%3u", i, color.get_red_raw(), color.get_green_raw(),
|
||||||
|
@ -36,7 +35,7 @@ Color esp_color_from_light_color_values(LightColorValues val) {
|
||||||
return Color(r, g, b, w);
|
return Color(r, g, b, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressableLight::write_state(LightState *state) {
|
void AddressableLight::update_state(LightState *state) {
|
||||||
auto val = state->current_values;
|
auto val = state->current_values;
|
||||||
auto max_brightness = to_uint8_scale(val.get_brightness() * val.get_state());
|
auto max_brightness = to_uint8_scale(val.get_brightness() * val.get_state());
|
||||||
this->correction_.set_local_brightness(max_brightness);
|
this->correction_.set_local_brightness(max_brightness);
|
||||||
|
|
|
@ -51,9 +51,9 @@ class AddressableLight : public LightOutput, public Component {
|
||||||
amnt = this->size();
|
amnt = this->size();
|
||||||
this->range(amnt, this->size()) = this->range(0, -amnt);
|
this->range(amnt, this->size()) = this->range(0, -amnt);
|
||||||
}
|
}
|
||||||
|
// Indicates whether an effect that directly updates the output buffer is active to prevent overwriting
|
||||||
bool is_effect_active() const { return this->effect_active_; }
|
bool is_effect_active() const { return this->effect_active_; }
|
||||||
void set_effect_active(bool effect_active) { this->effect_active_ = effect_active; }
|
void set_effect_active(bool effect_active) { this->effect_active_ = effect_active; }
|
||||||
void write_state(LightState *state) override;
|
|
||||||
std::unique_ptr<LightTransformer> create_default_transition() override;
|
std::unique_ptr<LightTransformer> create_default_transition() override;
|
||||||
void set_correction(float red, float green, float blue, float white = 1.0f) {
|
void set_correction(float red, float green, float blue, float white = 1.0f) {
|
||||||
this->correction_.set_max_brightness(
|
this->correction_.set_max_brightness(
|
||||||
|
@ -63,7 +63,8 @@ class AddressableLight : public LightOutput, public Component {
|
||||||
this->correction_.calculate_gamma_table(state->get_gamma_correct());
|
this->correction_.calculate_gamma_table(state->get_gamma_correct());
|
||||||
this->state_parent_ = state;
|
this->state_parent_ = state;
|
||||||
}
|
}
|
||||||
void schedule_show() { this->next_show_ = true; }
|
void update_state(LightState *state) override;
|
||||||
|
void schedule_show() { this->state_parent_->next_write_ = true; }
|
||||||
|
|
||||||
#ifdef USE_POWER_SUPPLY
|
#ifdef USE_POWER_SUPPLY
|
||||||
void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_.set_parent(power_supply); }
|
void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_.set_parent(power_supply); }
|
||||||
|
@ -74,9 +75,7 @@ class AddressableLight : public LightOutput, public Component {
|
||||||
protected:
|
protected:
|
||||||
friend class AddressableLightTransformer;
|
friend class AddressableLightTransformer;
|
||||||
|
|
||||||
bool should_show_() const { return this->effect_active_ || this->next_show_; }
|
|
||||||
void mark_shown_() {
|
void mark_shown_() {
|
||||||
this->next_show_ = false;
|
|
||||||
#ifdef USE_POWER_SUPPLY
|
#ifdef USE_POWER_SUPPLY
|
||||||
for (auto c : *this) {
|
for (auto c : *this) {
|
||||||
if (c.get().is_on()) {
|
if (c.get().is_on()) {
|
||||||
|
@ -90,7 +89,6 @@ class AddressableLight : public LightOutput, public Component {
|
||||||
virtual ESPColorView get_view_internal(int32_t index) const = 0;
|
virtual ESPColorView get_view_internal(int32_t index) const = 0;
|
||||||
|
|
||||||
bool effect_active_{false};
|
bool effect_active_{false};
|
||||||
bool next_show_{true};
|
|
||||||
ESPColorCorrection correction_{};
|
ESPColorCorrection correction_{};
|
||||||
#ifdef USE_POWER_SUPPLY
|
#ifdef USE_POWER_SUPPLY
|
||||||
power_supply::PowerSupplyRequester power_;
|
power_supply::PowerSupplyRequester power_;
|
||||||
|
|
|
@ -63,6 +63,7 @@ class AddressableLambdaLightEffect : public AddressableLightEffect {
|
||||||
this->last_run_ = now;
|
this->last_run_ = now;
|
||||||
this->f_(it, current_color, this->initial_run_);
|
this->f_(it, current_color, this->initial_run_);
|
||||||
this->initial_run_ = false;
|
this->initial_run_ = false;
|
||||||
|
it.schedule_show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +88,7 @@ class AddressableRainbowLightEffect : public AddressableLightEffect {
|
||||||
var = hsv;
|
var = hsv;
|
||||||
hue += add;
|
hue += add;
|
||||||
}
|
}
|
||||||
|
it.schedule_show();
|
||||||
}
|
}
|
||||||
void set_speed(uint32_t speed) { this->speed_ = speed; }
|
void set_speed(uint32_t speed) { this->speed_ = speed; }
|
||||||
void set_width(uint16_t width) { this->width_ = width; }
|
void set_width(uint16_t width) { this->width_ = width; }
|
||||||
|
@ -134,6 +136,7 @@ class AddressableColorWipeEffect : public AddressableLightEffect {
|
||||||
new_color.b = c.b;
|
new_color.b = c.b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
it.schedule_show();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -151,14 +154,10 @@ class AddressableScanEffect : public AddressableLightEffect {
|
||||||
void set_move_interval(uint32_t move_interval) { this->move_interval_ = move_interval; }
|
void set_move_interval(uint32_t move_interval) { this->move_interval_ = move_interval; }
|
||||||
void set_scan_width(uint32_t scan_width) { this->scan_width_ = scan_width; }
|
void set_scan_width(uint32_t scan_width) { this->scan_width_ = scan_width; }
|
||||||
void apply(AddressableLight &it, const Color ¤t_color) override {
|
void apply(AddressableLight &it, const Color ¤t_color) override {
|
||||||
it.all() = Color::BLACK;
|
|
||||||
|
|
||||||
for (auto i = 0; i < this->scan_width_; i++) {
|
|
||||||
it[this->at_led_ + i] = current_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32_t now = millis();
|
const uint32_t now = millis();
|
||||||
if (now - this->last_move_ > this->move_interval_) {
|
if (now - this->last_move_ < this->move_interval_)
|
||||||
|
return;
|
||||||
|
|
||||||
if (direction_) {
|
if (direction_) {
|
||||||
this->at_led_++;
|
this->at_led_++;
|
||||||
if (this->at_led_ == it.size() - this->scan_width_)
|
if (this->at_led_ == it.size() - this->scan_width_)
|
||||||
|
@ -169,7 +168,13 @@ class AddressableScanEffect : public AddressableLightEffect {
|
||||||
this->direction_ = true;
|
this->direction_ = true;
|
||||||
}
|
}
|
||||||
this->last_move_ = now;
|
this->last_move_ = now;
|
||||||
|
|
||||||
|
it.all() = Color::BLACK;
|
||||||
|
for (auto i = 0; i < this->scan_width_; i++) {
|
||||||
|
it[this->at_led_ + i] = current_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it.schedule_show();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -210,6 +215,7 @@ class AddressableTwinkleEffect : public AddressableLightEffect {
|
||||||
continue;
|
continue;
|
||||||
addressable[pos].set_effect_data(1);
|
addressable[pos].set_effect_data(1);
|
||||||
}
|
}
|
||||||
|
addressable.schedule_show();
|
||||||
}
|
}
|
||||||
void set_twinkle_probability(float twinkle_probability) { this->twinkle_probability_ = twinkle_probability; }
|
void set_twinkle_probability(float twinkle_probability) { this->twinkle_probability_ = twinkle_probability; }
|
||||||
void set_progress_interval(uint32_t progress_interval) { this->progress_interval_ = progress_interval; }
|
void set_progress_interval(uint32_t progress_interval) { this->progress_interval_ = progress_interval; }
|
||||||
|
@ -257,6 +263,7 @@ class AddressableRandomTwinkleEffect : public AddressableLightEffect {
|
||||||
const uint8_t color = random_uint32() & 0b111;
|
const uint8_t color = random_uint32() & 0b111;
|
||||||
it[pos].set_effect_data(0b1000 | color);
|
it[pos].set_effect_data(0b1000 | color);
|
||||||
}
|
}
|
||||||
|
it.schedule_show();
|
||||||
}
|
}
|
||||||
void set_twinkle_probability(float twinkle_probability) { this->twinkle_probability_ = twinkle_probability; }
|
void set_twinkle_probability(float twinkle_probability) { this->twinkle_probability_ = twinkle_probability; }
|
||||||
void set_progress_interval(uint32_t progress_interval) { this->progress_interval_ = progress_interval; }
|
void set_progress_interval(uint32_t progress_interval) { this->progress_interval_ = progress_interval; }
|
||||||
|
@ -301,6 +308,7 @@ class AddressableFireworksEffect : public AddressableLightEffect {
|
||||||
it[pos] = current_color;
|
it[pos] = current_color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
it.schedule_show();
|
||||||
}
|
}
|
||||||
void set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; }
|
void set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; }
|
||||||
void set_spark_probability(float spark_probability) { this->spark_probability_ = spark_probability; }
|
void set_spark_probability(float spark_probability) { this->spark_probability_ = spark_probability; }
|
||||||
|
@ -335,6 +343,7 @@ class AddressableFlickerEffect : public AddressableLightEffect {
|
||||||
// slowly fade back to "real" value
|
// slowly fade back to "real" value
|
||||||
var = (var.get() * inv_intensity) + (current_color * intensity);
|
var = (var.get() * inv_intensity) + (current_color * intensity);
|
||||||
}
|
}
|
||||||
|
it.schedule_show();
|
||||||
}
|
}
|
||||||
void set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; }
|
void set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; }
|
||||||
void set_intensity(float intensity) { this->intensity_ = to_uint8_scale(intensity); }
|
void set_intensity(float intensity) { this->intensity_ = to_uint8_scale(intensity); }
|
||||||
|
|
|
@ -19,6 +19,13 @@ class LightOutput {
|
||||||
|
|
||||||
virtual void setup_state(LightState *state) {}
|
virtual void setup_state(LightState *state) {}
|
||||||
|
|
||||||
|
/// Called on every update of the current values of the associated LightState,
|
||||||
|
/// can optionally be used to do processing of this change.
|
||||||
|
virtual void update_state(LightState *state) {}
|
||||||
|
|
||||||
|
/// Called from loop() every time the light state has changed, and should
|
||||||
|
/// should write the new state to hardware. Every call to write_state() is
|
||||||
|
/// preceded by (at least) one call to update_state().
|
||||||
virtual void write_state(LightState *state) = 0;
|
virtual void write_state(LightState *state) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -114,9 +114,11 @@ void LightState::loop() {
|
||||||
// Apply transformer (if any)
|
// Apply transformer (if any)
|
||||||
if (this->transformer_ != nullptr) {
|
if (this->transformer_ != nullptr) {
|
||||||
auto values = this->transformer_->apply();
|
auto values = this->transformer_->apply();
|
||||||
this->next_write_ = values.has_value(); // don't write if transformer doesn't want us to
|
if (values.has_value()) {
|
||||||
if (values.has_value())
|
|
||||||
this->current_values = *values;
|
this->current_values = *values;
|
||||||
|
this->output_->update_state(this);
|
||||||
|
this->next_write_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->transformer_->is_finished()) {
|
if (this->transformer_->is_finished()) {
|
||||||
this->transformer_->stop();
|
this->transformer_->stop();
|
||||||
|
@ -127,18 +129,15 @@ void LightState::loop() {
|
||||||
|
|
||||||
// Write state to the light
|
// Write state to the light
|
||||||
if (this->next_write_) {
|
if (this->next_write_) {
|
||||||
this->output_->write_state(this);
|
|
||||||
this->next_write_ = false;
|
this->next_write_ = false;
|
||||||
|
this->output_->write_state(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float LightState::get_setup_priority() const { return setup_priority::HARDWARE - 1.0f; }
|
float LightState::get_setup_priority() const { return setup_priority::HARDWARE - 1.0f; }
|
||||||
uint32_t LightState::hash_base() { return 1114400283; }
|
uint32_t LightState::hash_base() { return 1114400283; }
|
||||||
|
|
||||||
void LightState::publish_state() {
|
void LightState::publish_state() { this->remote_values_callback_.call(); }
|
||||||
this->remote_values_callback_.call();
|
|
||||||
this->next_write_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LightOutput *LightState::get_output() const { return this->output_; }
|
LightOutput *LightState::get_output() const { return this->output_; }
|
||||||
std::string LightState::get_effect_name() {
|
std::string LightState::get_effect_name() {
|
||||||
|
@ -248,6 +247,7 @@ void LightState::set_immediately_(const LightColorValues &target, bool set_remot
|
||||||
if (set_remote_values) {
|
if (set_remote_values) {
|
||||||
this->remote_values = target;
|
this->remote_values = target;
|
||||||
}
|
}
|
||||||
|
this->output_->update_state(this);
|
||||||
this->next_write_ = true;
|
this->next_write_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,10 +83,7 @@ class NeoPixelBusLightOutputBase : public light::AddressableLight {
|
||||||
this->controller_->Begin();
|
this->controller_->Begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() override {
|
void write_state(light::LightState *state) override {
|
||||||
if (!this->should_show_())
|
|
||||||
return;
|
|
||||||
|
|
||||||
this->mark_shown_();
|
this->mark_shown_();
|
||||||
this->controller_->Dirty();
|
this->controller_->Dirty();
|
||||||
|
|
||||||
|
|
|
@ -50,14 +50,12 @@ class PartitionLightOutput : public light::AddressableLight {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
light::LightTraits get_traits() override { return this->segments_[0].get_src()->get_traits(); }
|
light::LightTraits get_traits() override { return this->segments_[0].get_src()->get_traits(); }
|
||||||
void loop() override {
|
void write_state(light::LightState *state) override {
|
||||||
if (this->should_show_()) {
|
|
||||||
for (auto seg : this->segments_) {
|
for (auto seg : this->segments_) {
|
||||||
seg.get_src()->schedule_show();
|
seg.get_src()->schedule_show();
|
||||||
}
|
}
|
||||||
this->mark_shown_();
|
this->mark_shown_();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
light::ESPColorView get_view_internal(int32_t index) const override {
|
light::ESPColorView get_view_internal(int32_t index) const override {
|
||||||
|
|
|
@ -42,6 +42,7 @@ void WLEDLightEffect::blank_all_leds_(light::AddressableLight &it) {
|
||||||
for (int led = it.size(); led-- > 0;) {
|
for (int led = it.size(); led-- > 0;) {
|
||||||
it[led].set(Color::BLACK);
|
it[led].set(Color::BLACK);
|
||||||
}
|
}
|
||||||
|
it.schedule_show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WLEDLightEffect::apply(light::AddressableLight &it, const Color ¤t_color) {
|
void WLEDLightEffect::apply(light::AddressableLight &it, const Color ¤t_color) {
|
||||||
|
@ -134,6 +135,7 @@ bool WLEDLightEffect::parse_frame_(light::AddressableLight &it, const uint8_t *p
|
||||||
blank_at_ = millis() + DEFAULT_BLANK_TIME;
|
blank_at_ = millis() + DEFAULT_BLANK_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it.schedule_show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue