184 lines
6.2 KiB
C++
184 lines
6.2 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 ¤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) {
|
|
if (this->effect_active) {
|
|
uint32_t speed_ = 3;
|
|
uint16_t width_ = 100; // Original width_ = 50
|
|
return get_next_color_base_(position, speed_, width_, current_color);
|
|
}
|
|
else {
|
|
return Color(this->on_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, 255, milliseconds);
|
|
this->off_transformer->setup(255, 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
|