esphome-wordclock/components/wordclock/wordclock.cpp

178 lines
6.1 KiB
C++

#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<uint16_t> *a_vec, std::vector<uint16_t> *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 &current_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 &current_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<Hour> *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<Minute> *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<Minute>();
this->hours = new std::vector<Hour>();
this->segments = new std::vector<SegmentCoords>();
this->static_segments = new std::vector<uint16_t>();
this->previous_segments = new std::vector<uint16_t>();
this->current_segments = new std::vector<uint16_t>();
this->added_segments = new std::vector<uint16_t>();
this->removed_segments = new std::vector<uint16_t>();
this->staying_segments = new std::vector<uint16_t>();
this->on_transformer = new BrightnessTransitionTransformer();
this->off_transformer = new BrightnessTransitionTransformer();
}
} // namespace wordclock
} // namespace esphome