diff --git a/components/wordclock/__init__.py b/components/wordclock/__init__.py index 242f2b6..449526b 100644 --- a/components/wordclock/__init__.py +++ b/components/wordclock/__init__.py @@ -97,17 +97,12 @@ WORDCLOCK_SCHEMA = cv.Schema( cv.Required(CONF_SEGMENTS): cv.ensure_list(WORDCLOCK_SEGMENT_SCHEMA), cv.Required(CONF_MINUTES): cv.ensure_list(WORDCLOCK_MINUTE_SCHEMA), cv.Required(CONF_HOURS): cv.ensure_list(WORDCLOCK_HOUR_SCHEMA), - # cv.Optional( - # CONF_FADE_LENGTH, default="700ms" - # ): cv., cv.Optional( CONF_FADE_LENGTH, default="700ms" ): cv.positive_time_period_milliseconds, cv.Optional( CONF_UPDATE_INTERVAL, default="16ms" ): cv.positive_time_period_milliseconds, - # cv.GenerateID(DATA_VECTOR_SEGMENTS_HOUR): cv.declare_id(cg.std_vector.template(cg.std_vector.template(cg.uint16))), - # cv.GenerateID(DATA_VECTOR_SEGMENTS_MINUTE): cv.declare_id(cg.std_vector.template(cg.std_vector.template(cg.uint16))), cv.GenerateID(DATA_VECTOR_SEGMENTS): cv.declare_id(cg.std_vector.template(cg.uint16)), } ) @@ -127,16 +122,8 @@ async def to_code(config): wrapped_color_off = await cg.get_variable(config[CONF_COLOR_OFF]) cg.add(var.set_off_color(wrapped_color_off)) - # segments_vector_ptr = cg.new_Pvariable(config[DATA_VECTOR_SEGMENTS]) -# void Wordclock::setup_transitions(uint32_t milliseconds) { -# this->on_transformer->setup(0, this->brightness, milliseconds); -# this->off_transformer->setup(this->brightness, 0, milliseconds); -# } cg.add(var.setup_transitions(config[CONF_FADE_LENGTH])) cg.add(var.set_brightness(int(config[CONF_BRIGHTNESS] * 255))) - - - SEGMENT_MAP = dict() for idx, segment in enumerate(config[CONF_SEGMENTS]): @@ -151,7 +138,6 @@ async def to_code(config): exp = cg.StructInitializer(SegmentCoords, ("x1", x1), ("y1", y1), ("x2", x2), ("y2", y2),) cg.add(var.add_segment(exp)) - if CONF_WORDCLOCK_STATIC_SEGMENTS in config: for segment_name in config[CONF_WORDCLOCK_STATIC_SEGMENTS]: cg.add(var.add_static(SEGMENT_MAP[segment_name])) @@ -159,45 +145,9 @@ async def to_code(config): for idx, hour in enumerate(config[CONF_HOURS]): segment_ids = [SEGMENT_MAP[a] for a in hour[CONF_SEGMENTS]] cg.add(var.add_hour(hour[CONF_HOUR], cg.std_vector.template(cg.uint16).new(segment_ids))) - # segments_vector_ptr = segments_vector_ptr.new(segment_ids) - # foo = await cg.get_variable(config[DATA_VECTOR_SEGMENTS]) - # foo = cg.std_vector.template(cg.uint16).new(segment_ids) - - # del foo for idx, minute in enumerate(config[CONF_MINUTES]): segment_ids = [SEGMENT_MAP[a] for a in minute[CONF_SEGMENTS]] cg.add(var.add_minute(minute[CONF_MINUTE], minute[CONF_HOUR_OFFSET], cg.std_vector.template(cg.uint16).new(segment_ids))) - # segments_vector_ptr = segments_vector_ptr.new(segment_ids) - # segments_vector_ptr = cg.new_Pvariable(config[DATA_VECTOR_SEGMENTS], segment_ids) - # foo = await cg.get_variable(config[DATA_VECTOR_SEGMENTS]) - # foo = cg.std_vector.template(cg.uint16).new(segment_ids) - # segments_vector = cg.new_Pvariable(core.ID(None, type=cg.std_vector.template(cg.uint16)), segment_ids) - # del foo + await cg.register_component(var, config) - - # hours = [] - # for idx, hour in enumerate(config[CONF_HOURS]): - # segment_ids = [SEGMENT_MAP[a] for a in hour[CONF_SEGMENTS]] - # exp = cg.std_vector.template(cg.uint16)(segment_ids) - # hours.append(exp) - # hours_array = cg.new_variable(config[DATA_VECTOR_SEGMENTS_HOUR], cg.std_vector.template(cg.std_vector.template(cg.uint16))(hours)) - - # minutes = [] - # for idx, hour in enumerate(config[CONF_MINUTES]): - # segment_ids = [SEGMENT_MAP[a] for a in hour[CONF_SEGMENTS]] - # exp = cg.std_vector.template(cg.uint16)(segment_ids) - # minutes.append(exp) - # minutes_array = cg.new_variable(config[DATA_VECTOR_SEGMENTS_MINUTE], cg.std_vector.template(cg.std_vector.template(cg.uint16))(minutes)) - - # for idx, hour in enumerate(config[CONF_HOURS]): - # exp = cg.std_vector.template(cg.uint16)(segment_ids) - # cg.add(var.add_hour(hour[CONF_HOUR], cpp.UnaryOpExpression("&", hours_array[idx]))) - - # for idx, minute in enumerate(config[CONF_MINUTES]): - # exp = cg.std_vector.template(cg.uint16)(segment_ids) - # cg.add(var.add_minute(minute[CONF_MINUTE], cpp.UnaryOpExpression("&", minutes_array[idx]))) - - # for idx, minute in enumerate(config[CONF_MINUTES]): - # cg.add(var.add_hour_offset(minute[CONF_MINUTE], minute[CONF_HOUR_OFFSET])) - diff --git a/components/wordclock/wordclock.cpp b/components/wordclock/wordclock.cpp index ee41e18..8ec0262 100644 --- a/components/wordclock/wordclock.cpp +++ b/components/wordclock/wordclock.cpp @@ -8,7 +8,6 @@ void Wordclock::setup() { if (!this->valid_time) { this->start_idle_animation(); } - // this->valid_time = true; } void Wordclock::update() { @@ -45,62 +44,42 @@ void Wordclock::update() { if (dirty) { this->previous_segments->clear(); + for (uint16_t segment_idx : *this->current_segments) { this->previous_segments->push_back(segment_idx); } - // std::sort(this->previous_segments->begin(), this->previous_segments->end()); - - // std::sort(s.begin(), s.end(), [](int a, int b) - // { - // return a > b; - // }); this->current_segments->clear(); + for (uint16_t segment_idx : *this->static_segments) { this->current_segments->push_back(segment_idx); - // this->draw_segment(segment_idx); } for (uint16_t segment_idx : *(this->minutes->at(minute).segments)) { this->current_segments->push_back(segment_idx); - // this->draw_segment(segment_idx); } for (uint16_t segment_idx : *(this->hours->at(hour).segments)) { this->current_segments->push_back(segment_idx); - // this->draw_segment(segment_idx); } + std::sort(this->current_segments->begin(), this->current_segments->end()); this->find_difference(this->previous_segments, this->current_segments); - // ESP_LOGD("wordclock.cpp", "reset"); + this->on_transformer->reset(); this->off_transformer->reset(); } - // Color on = this->on_color * this->on_transformer->apply().value_or(255); - // Color off = this->off_color * this->off_transformer->apply().value_or(255); this->current_position = 0; uint8_t transition_progress = this->on_transformer->apply().value_or(255); - // uint8_t on_progress = this->on_transformer->apply().value_or(255); - // uint8_t off_progress = this->off_transformer->apply().value_or(255); - // ESP_LOGD("wordclock.cpp", "off progress [%d]", off_progress); - // Color added_color = this->off_color.gradient(this->on_color, transition_progress); Color removed_color = this->on_color.gradient(this->off_color, transition_progress); - // ESP_LOGD("wordclock.cpp", "transition progress [%d], added [0x%06x], removed [0x%06x]", transition_progress, added_color.raw_32, removed_color.raw_32); for (uint16_t segment_idx : *this->removed_segments) { - // ESP_LOGD("wordclock.cpp", "off [%d]", segment_idx); - // this->disable_segment(segment_idx, this->off_color, transition_progress); this->disable_segment_effect(segment_idx, this->off_color, transition_progress); - // this->disable_segment(segment_idx, removed_color); - // this->draw_segment(segment_idx, off_progress); } for (uint16_t segment_idx : *this->added_segments) { - // ESP_LOGD("wordclock.cpp", "on [%d]", segment_idx); - // this->segment_effect_base(segment_idx, this->off_color, transition_progress); this->enable_segment_effect(segment_idx, this->off_color, transition_progress); - // this->draw_segment(segment_idx, on_progress); } for (uint16_t segment_idx : *this->staying_segments) { this->apply_segment_effect(segment_idx); @@ -109,14 +88,10 @@ void Wordclock::update() { } void Wordclock::find_difference(std::vector *a_vec, std::vector *b_vec) { - // for (uint16_t segment_idx : a) { - // this->current_segments->push_back(segment_idx); - // } this->added_segments->clear(); this->removed_segments->clear(); this->staying_segments->clear(); - auto a = a_vec->begin(); auto b = b_vec->begin(); @@ -129,18 +104,20 @@ void Wordclock::find_difference(std::vector *a_vec, std::vector> 8; - // hsv.hue = hue >> 8; + hsv.hue = ((millis() * speed + (position * (0xFFFF / width))) % 0xFFFF) >> 8; return hsv.to_rgb(); } +Color Wordclock::get_next_color(uint32_t position, const Color ¤t_color) { + uint32_t speed_ = 3; + uint16_t width_ = 100; // Original width_ = 50 + return get_next_color_base_(position, speed_, width_, current_color); +} + int8_t Wordclock::find_hour(uint8_t target_value) { std::vector *elements = this->hours; for (int i = 0; i < elements->size(); i++) { @@ -151,15 +128,6 @@ int8_t Wordclock::find_hour(uint8_t target_value) { } } return elements->size() - 1; - // uint16_t last_defined_index = -1; - // for (int i = 0; i < elements->size(); i++) { - // if (elements->at(i).size()) { - // last_defined_index = i; - // } - // if (i >= target_value) break; - // } - // return last_defined_index; - } int8_t Wordclock::find_minute(uint8_t target_value) { @@ -179,11 +147,6 @@ void Wordclock::setup_transitions(uint32_t milliseconds) { this->off_transformer->setup(this->brightness, 0, milliseconds); } - - -// Wordclock::Wordclock() : PollingComponent(1000) { -// } - Wordclock::Wordclock( esphome::time::RealTimeClock *time, esphome::addressable_light::AddressableLightDisplay *display, @@ -209,20 +172,7 @@ Wordclock::Wordclock( this->staying_segments = new std::vector(); this->on_transformer = new BrightnessTransitionTransformer(); - // this->on_transformer->setup(0, this->brightness, 700); this->off_transformer = new BrightnessTransitionTransformer(); - // this->off_transformer->setup(this->brightness, 0, 700); - -// wordclock_wordclock->add_segment(wordclock::SegmentCoords{ -// .x1 = 0, -// .x2 = 4, -// .y1 = 8, -// .y2 = 8, -// }); - - // this->hour_offsets = new std::vector(60, 0); - // this->minutes = new std::vector>(60, std::vector()); - // this->hours = new std::vector>(24, std::vector()); } } // namespace wordclock } // namespace esphome diff --git a/components/wordclock/wordclock.h b/components/wordclock/wordclock.h index 6104dfb..f4d1e19 100644 --- a/components/wordclock/wordclock.h +++ b/components/wordclock/wordclock.h @@ -22,9 +22,9 @@ struct SegmentCoords { uint16_t y2; }; -class BrightnessTransformer { +class BrightnessTransitionTransformer { public: - virtual ~BrightnessTransformer() = default; + virtual ~BrightnessTransitionTransformer() = default; void setup(const uint8_t start_values, const uint8_t target_values, uint32_t length) { this->start_time_ = millis(); @@ -33,29 +33,22 @@ public: this->target_values_ = target_values; this->start(); } - - /// Indicates whether this transformation is finished. virtual bool is_finished() { return this->get_progress_() >= 1.0f; } - - /// This will be called before the transition is started. virtual void start() {} - - /// This will be called while the transformer is active to apply the transition to the light. Can either write to the - /// light directly, or return LightColorValues that will be applied. - virtual optional apply() = 0; - - /// This will be called after transition is finished. + // virtual optional apply() = 0; + virtual optional apply() { + float v = BrightnessTransitionTransformer::smoothed_progress(this->get_progress_()); + return esphome::lerp(v, this->start_values_, this->target_values_); + } virtual void stop() {} - void reset() { this->start_time_ = millis(); } - const uint8_t &get_start_values() const { return this->start_values_; } const uint8_t &get_target_values() const { return this->target_values_; } protected: - /// The progress of this transition, on a scale of 0 to 1. + // The progress of this transition, on a scale of 0 to 1. float get_progress_() { uint32_t now = esphome::millis(); if (now < this->start_time_) @@ -65,29 +58,16 @@ protected: return clamp((now - this->start_time_) / float(this->length_), 0.0f, 1.0f); } + static float smoothed_progress(float x) { return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f); } + uint32_t start_time_; uint32_t length_; uint8_t start_values_; uint8_t target_values_; }; -class BrightnessTransitionTransformer : public BrightnessTransformer { -public: - optional apply() override { - float v = BrightnessTransitionTransformer::smoothed_progress(this->get_progress_()); - return esphome::lerp(v, this->start_values_, this->target_values_); - } -protected: - // This looks crazy, but it reduces to 6x^5 - 15x^4 + 10x^3 which is just a smooth sigmoid-like - // transition from 0 to 1 on x = [0, 1] - static float smoothed_progress(float x) { return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f); } -}; - - class Wordclock : public esphome::PollingComponent { - public: - // Wordclock(); Wordclock( esphome::time::RealTimeClock *time, esphome::addressable_light::AddressableLightDisplay *display, @@ -96,9 +76,8 @@ public: void setup(); void update(); - // void setup_color(uint8_t brightness, Color on_color, Color off_color); void set_brightness(uint8_t brightness) { -this->brightness = brightness; + this->brightness = brightness; } void set_on_color(Color on_color) { this->on_color = on_color; @@ -131,17 +110,6 @@ this->brightness = brightness; }); } - // void add_hour_segment(uint8_t index, uint16_t segment_id) { - // this->hours->at(index).segments->push_back(segment_id); - // } - // void add_minute_segment(uint8_t index, uint16_t segment_id) { - // this->minutes->at(index).segments->push_back(segment_id); - // } - // void add_hour(uint8_t index, std::vector *segments); - // void add_minute(uint8_t index, std::vector *segments); - // void add_hour_offset(uint8_t index, int8_t offset) { - // this->minutes->at(index).hour_offset = offset; - // } protected: // ESPHome Components esphome::time::RealTimeClock *time; @@ -170,14 +138,9 @@ protected: std::vector *previous_segments; uint32_t current_position{0}; + Color get_next_color_base_(uint32_t position, uint32_t speed, uint16_t width, const Color ¤t_color); Color get_next_color(uint32_t position, const Color ¤t_color); - // Color - // Color get_on_color() { - // return this->on_color * this->brightness; - // } - // Color get_off_color() { - // return this->off_color * this->brightness; - // } + Color on_color {Color(0xFFFFFF)}; Color off_color {Color(0x000000)}; uint8_t brightness{255}; @@ -186,21 +149,8 @@ protected: int8_t find_hour(uint8_t target_value); int8_t find_minute(uint8_t target_value); void find_difference(std::vector *a_vec, std::vector *b_vec); - // void draw_segment(uint16_t segment_id) { - // this->draw_segment(segment_id, this->brightness); - // } - // void draw_segment(uint16_t segment_id, uint8_t brightness) { - // this->draw_segment(segment_id, this->on_color * brightness); - // } - - // void draw_segment(uint16_t segment_id, Color color) { - // SegmentCoords s = this->segments->at(segment_id); - // // ESP_LOGD("wordclock.cpp", "brightness[%d] * color[%06x] = %06x", brightness, color.raw_32, (color * brightness).raw_32); - // this->display->line(s.x1, s.y1, s.x2, s.y2, color); - // } void segment_effect_base(uint16_t segment_id, bool to_effect, Color base_color, uint8_t transition_progress) { - // ESP_LOGD("wordclock.cpp", "brightness[%d] * color[%06x] = %06x", brightness, color.raw_32, (color * brightness).raw_32); SegmentCoords s = this->segments->at(segment_id); int x1 = s.x1; int y1 = s.y1; int x2 = s.x2; int y2 = s.y2; Color color_to_draw; @@ -215,11 +165,8 @@ protected: color_to_draw = base_color.gradient(effect_color, transition_progress); } else { color_to_draw = effect_color.gradient(base_color, transition_progress); - // c = base_color.gradient(this->get_next_color(x1 + y1, Color(0)), transition_progress); } - this->display->draw_pixel_at(x1, y1, color_to_draw); - // this->display->draw_pixel_at(x1, y1, this->get_next_color(this->current_position++, Color(0))); if (x1 == x2 && y1 == y2) break; int32_t e2 = 2 * err; if (e2 >= dy) { @@ -242,10 +189,6 @@ protected: void apply_segment_effect(uint16_t segment_id) { segment_effect_base(segment_id, true, Color(0), 255); } - // void disable_segment(uint16_t segment_id, Color off_color, uint8_t transition_progress) { - // SegmentCoords s = this->segments->at(segment_id); - // this->display->line(s.x1, s.y1, s.x2, s.y2, color); - // } void start_idle_animation() { this->display->fill(this->off_color); this->display->set_enabled(false); @@ -259,13 +202,7 @@ protected: this->previous_segments->clear(); this->current_segments->clear(); } - - - // std::vector> *minutes; - // std::vector> *hours; - // std::vector *hour_offsets; }; - } // namespace wordclock } // namespace esphome