#include "wordclock.h" namespace esphome { namespace wordclock { void Wordclock::setup() { this->valid_time = this->time->now().is_valid(); if (!this->valid_time) { this->start_idle_animation(); } } void Wordclock::update() { esphome::time::ESPTime time = this->time->now(); if (!time.is_valid()) { if (this->valid_time) { ESP_LOGD("wordclock.cpp", "time is not valid [%02i:%02i:%02i]", time.hour, time.minute, time.second); this->start_idle_animation(); this->valid_time = false; return; } } else { if (!this->valid_time) { ESP_LOGD("wordclock.cpp", "time is valid [%02i:%02i:%02i]", time.hour, time.minute, time.second); this->end_idle_animation(); this->valid_time = true; return; } bool dirty = false; int8_t minute = this->find_minute(time.minute); int8_t hour = this->find_hour((time.hour + this->minutes->at(minute).hour_offset) % 24); if (hour != this->current_hour) { this->current_hour = hour; dirty = true; } if (minute != this->current_minute) { this->current_minute = minute; dirty = true; } if (dirty) { this->previous_segments->clear(); for (uint16_t segment_idx : *this->current_segments) { this->previous_segments->push_back(segment_idx); } this->current_segments->clear(); for (uint16_t segment_idx : *this->static_segments) { this->current_segments->push_back(segment_idx); } for (uint16_t segment_idx : *(this->minutes->at(minute).segments)) { this->current_segments->push_back(segment_idx); } for (uint16_t segment_idx : *(this->hours->at(hour).segments)) { this->current_segments->push_back(segment_idx); } std::sort(this->current_segments->begin(), this->current_segments->end()); this->find_difference(this->previous_segments, this->current_segments); this->on_transformer->reset(); this->off_transformer->reset(); } this->current_position = 0; uint8_t transition_progress = this->on_transformer->apply().value_or(255); Color removed_color = this->on_color.gradient(this->off_color, transition_progress); for (uint16_t segment_idx : *this->removed_segments) { this->disable_segment_effect(segment_idx, this->off_color, transition_progress); } for (uint16_t segment_idx : *this->added_segments) { this->enable_segment_effect(segment_idx, this->off_color, transition_progress); } for (uint16_t segment_idx : *this->staying_segments) { this->apply_segment_effect(segment_idx); } } } void Wordclock::find_difference(std::vector *a_vec, std::vector *b_vec) { this->added_segments->clear(); this->removed_segments->clear(); this->staying_segments->clear(); auto a = a_vec->begin(); auto b = b_vec->begin(); while (!(a == a_vec->end() && b == b_vec->end())) { if (a == a_vec->end()) { this->added_segments-> push_back(*b); b++; } else if (b == b_vec->end()) { this->removed_segments->push_back(*a); a++; } else if (*a > *b) { this->added_segments-> push_back(*b); b++; } else if (*a < *b) { this->removed_segments->push_back(*a); a++; } else if (*a == *b) { this->staying_segments->push_back(*a); a++; b++; } } } Color Wordclock::get_next_color_base_(uint32_t position, uint32_t speed, uint16_t width, const Color ¤t_color) { esphome::light::ESPHSVColor hsv; hsv.value = 255; hsv.saturation = 240; 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++) { if (elements->at(i).hour == target_value) { return i; } else if (elements->at(i).hour > target_value) { return i - 1; } } return elements->size() - 1; } int8_t Wordclock::find_minute(uint8_t target_value) { std::vector *elements = this->minutes; for (int i = 0; i < elements->size(); i++) { if (elements->at(i).minute == target_value) { return i; } else if (elements->at(i).minute > target_value) { return i - 1; } } return elements->size() - 1; } void Wordclock::setup_transitions(uint32_t milliseconds) { this->on_transformer->setup(0, this->brightness, milliseconds); this->off_transformer->setup(this->brightness, 0, milliseconds); } Wordclock::Wordclock( esphome::time::RealTimeClock *time, esphome::addressable_light::AddressableLightDisplay *display, esphome::light::AddressableLightState *light_state) { this->time = time; this->display = display; this->light_state = light_state; this->light_state->set_default_transition_length(1); this->minutes = new std::vector(); this->hours = new std::vector(); this->segments = new std::vector(); this->static_segments = new std::vector(); this->previous_segments = new std::vector(); this->current_segments = new std::vector(); this->added_segments = new std::vector(); this->removed_segments = new std::vector(); this->staying_segments = new std::vector(); this->on_transformer = new BrightnessTransitionTransformer(); this->off_transformer = new BrightnessTransitionTransformer(); } } // namespace wordclock } // namespace esphome