Remove double scheduling from addressable lights (#1963)

This commit is contained in:
Oxan van Leeuwen 2021-08-23 10:00:38 +02:00 committed by GitHub
parent 5ec9bb0fb5
commit 2f33cd2db5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 57 additions and 45 deletions

View file

@ -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 &current_color) { void AdalightLightEffect::apply(light::AddressableLight &it, const Color &current_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;
} }

View file

@ -84,6 +84,7 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet
break; break;
} }
it->schedule_show();
return true; return true;
} }

View file

@ -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;

View file

@ -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 {

View file

@ -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);

View file

@ -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_;

View file

@ -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 &current_color) override { void apply(AddressableLight &it, const Color &current_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); }

View file

@ -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;
}; };

View file

@ -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;
} }

View file

@ -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();

View file

@ -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 {

View file

@ -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 &current_color) { void WLEDLightEffect::apply(light::AddressableLight &it, const Color &current_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;
} }