feat: add transitions and clean up code.

This commit is contained in:
Philip Stark 2023-05-12 05:07:21 +02:00
parent 7f091409cf
commit dd1408c5cb
8 changed files with 533 additions and 1099 deletions

View file

@ -4,302 +4,202 @@ namespace esphome {
namespace wordclock {
void Wordclock::setup() {
// this->time->update();
// this->light_state->add_effects({this->randomTwinkle});
// this->start_idle_animation();
}
void Wordclock::start_idle_animation() {
this->display->set_enabled(false);
// auto call =
this->light_state->turn_on().set_effect("random_twinkle").perform();
// call.set_effect("random_twinkle");
// call.perform();
}
void Wordclock::end_idle_animation() {
this->light_state->turn_off().perform();
this->display->set_enabled(true);
// this->light->clear_effect_data();
// this->display->get_light()->set_effect_active(false);
// auto call1 = this->light_state->turn_on();
// call1.set_effect("None");
// call1.perform();
// this->light->all().set(Color(0xF0FF00));
// this->display->fill(Color(0));
// this->light_state->turn_off().perform();
// call2.perform();
this->valid_time = this->time->now().is_valid();
if (!this->valid_time) {
this->start_idle_animation();
}
// this->valid_time = true;
}
void Wordclock::update() {
// esphome::addressable_light::AddressableLightDisplay it = *(this->display);
// ESP_LOGD("loop", "beep");
// ESP_LOGD("loop", "time is now [%02i:%02i:%02i]", this->time->now().hour, this->time->now().minute, this->time->now().second);
// ESP_LOGE("wordclock.cpp", "display_ptr: 0x%x", it);
// ESP_LOGE("wordclock.cpp", "this: 0x%x", (this));
// ESP_LOGE("wordclock.cpp", "this->display: 0x%x", (this->display));
// ESP_LOGE("wordclock.cpp", "&this->display: 0x%x", &(this->display));
// ESP_LOGE("loop", "time_ptr: %i", this->time);
// it.line(0,0,0,0, Color(0x00FF00));
esphome::time::ESPTime time = this->time->now();
this->find_hour(9);
this->find_minute(31);
if (time.is_valid() == false) {
if (!time.is_valid()) {
if (this->valid_time) {
ESP_LOGD("loop", "time is not valid [%02i:%02i:%02i]", time.hour, time.minute, time.second);
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;
ESP_LOGD("wordclock.cpp", "time is now valid [%02i:%02i:%02i]", time.hour, time.minute, time.second);
return;
}
// for (uint8_t idx = 0;idx < ; idx++) {
// }
// std::vector<uint16_t> *minute = this->find_minute(time.minute);
// std::vector<uint16_t> *hour = this->find_hour(time.hour);
this->display->fill(Color(0x000000));
bool dirty = false;
int8_t minute = this->find_minute(time.minute);
int8_t hour = this->find_hour((time.hour + this->hour_offsets->at(minute)) % 24);
int8_t hour = this->find_hour((time.hour + this->minutes->at(minute).hour_offset) % 24);
for (uint16_t segment_idx : *this->static_segments){
this->draw_segment(segment_idx);
if (hour != this->current_hour) {
this->current_hour = hour;
dirty = true;
}
if (minute != this->current_minute) {
this->current_minute = minute;
dirty = true;
}
for (uint16_t segment_idx : this->minutes->at(minute)){
this->draw_segment(segment_idx);
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();
}
for (uint16_t segment_idx : this->hours->at(hour)){
this->draw_segment(segment_idx);
// Color on = this->on_color * this->on_transformer->apply().value_or(255);
// Color off = this->off_color * this->off_transformer->apply().value_or(255);
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->added_segments) {
// ESP_LOGD("wordclock.cpp", "on [%d]", segment_idx);
this->draw_segment(segment_idx, added_color);
// this->draw_segment(segment_idx, on_progress);
}
for (uint16_t segment_idx : *this->removed_segments) {
// ESP_LOGD("wordclock.cpp", "off [%d]", segment_idx);
this->draw_segment(segment_idx, removed_color);
// this->draw_segment(segment_idx, off_progress);
}
// this->draw_segment(0);
// this->draw_segment(1);
// this->draw_segment(4);
// this->draw_segment(10);
// this->draw_segment(19);
// this->light->range(0, 10).fade_to_white(100);
// this->display->get_light()->range(18, 35).set(Color(0xf0ff0f));
// SegmentCoords s = this->segments->at(time);
// ESP_LOGD("wordclock.cpp", "time is now [%02i:%02i:%02i]", time.hour, time.minute, time.second);
// ESP_LOGD("wordclock.cpp", "x1: %i, y1: %i, x2: %i, y2: %i", s.x1, s.y1, s.x2, s.y2);
// this->display->draw_pixel_at(0, 0, Color(0xFF0000));
// this->display->draw_pixel_at(1, 0, Color(0x00FF00));
// this->display->draw_pixel_at(2, 0, Color(0x0000FF));
// if (time.second != second) {
// second = time.second;
// ESP_LOGD("loop", "time is now [%02i:%02i:%02i]", time.hour, time.minute, time.second);
// }
// if(time.hour != hour || time.minute != minute) {
// hour = time.hour;
// minute = time.minute;
// if (hour >= 0 && time.is_valid() == true){
// display_time(time.hour, time.minute, CRGB(red, green, blue));
// ESP_LOGE("loop", "Update Time: %i:%i Brightness: %i RGB: %i-%i-%i", time.hour, time.minute, brightness, red, green, blue);
// }
// }
// }
// if (!this->reading_ && !mode_funcs_.empty()) {
// this->reading_ = true;
// this->read_mode_(0);
}
}
void Wordclock::draw_segment(uint16_t segment_id) {
SegmentCoords s = this->segments->at(segment_id);
// ESP_LOGD("wordclock.cpp", "x1: %i, y1: %i, x2: %i, y2: %i", s.x1, s.y1, s.x2, s.y2);
this->display->line(s.x1, s.y1, s.x2, s.y2, esphome::Color(0xFFFFFF));
void Wordclock::find_difference(std::vector<uint16_t> *a_vec, std::vector<uint16_t> *b_vec) {
// for (uint16_t segment_idx : a) {
// this->current_segments->push_back(segment_idx);
// }
this->added_segments->clear();
this->removed_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) { a++; b++; }
}
}
// void Wordclock::set_writer(display_writer_t &&writer) {
// this->writer_ = writer;
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;
// 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) {
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() : PollingComponent(1000) {
// }
void Wordclock::add_segment(SegmentCoords segment) {
// if (!this->segments) {
// }
Wordclock::Wordclock(
esphome::time::RealTimeClock *time,
esphome::addressable_light::AddressableLightDisplay *display,
esphome::light::AddressableLightState *light_state) {
this->segments->push_back(segment);
// this->writer_ = writer;
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->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<int8_t>(60, 0);
// this->minutes = new std::vector<std::vector<uint16_t>>(60, std::vector<uint16_t>());
// this->hours = new std::vector<std::vector<uint16_t>>(24, std::vector<uint16_t>());
}
// std::vector<uint16_t> * Wordclock::find_hour(uint8_t hour) {
// std::vector<uint16_t> *empty_vector; // = new std::vector<uint16_t>();
// uint16_t last_defined_hour = -1;
// for (int i = 0; i < this->hours->size(); i++) {
// if (this->hours->at(i).size()) {
// if (hour == i) {
// return &(this->hours->at(i));
// }
// else {
// last_defined_hour = i;
// }
// }
// else {
// empty_vector = &(this->hours->at(i));
// if (hour == i) {
// if (last_defined_hour == -1) return empty_vector;
// return &(this->hours->at(last_defined_hour));
// }
// }
// }
// return empty_vector;
// }
int8_t Wordclock::find_hour(uint8_t hour) {
uint16_t last_defined_hour = -1;
for (int i = 0; i < this->hours->size(); i++) {
if (this->hours->at(i).size()) {
last_defined_hour = i;
if (hour == i) {
return last_defined_hour;
}
}
if (hour == i) break;
}
return last_defined_hour;
}
int8_t Wordclock::find_minute(uint8_t minute) {
uint16_t last_defined_minute = -1;
for (int i = 0; i < this->minutes->size(); i++) {
if (this->minutes->at(i).size()) {
last_defined_minute = i;
if (minute == i) {
return last_defined_minute;
}
}
if (minute == i) break;
}
return last_defined_minute;
}
// std::vector<uint16_t> * Wordclock::find_minute(uint8_t minute) {
// std::vector<uint16_t> *empty_vector;// = new std::vector<uint16_t>();
// uint16_t last_defined_minute = -1;
// for (int i = 0; i < this->minutes->size(); i++) {
// if (this->minutes->at(i).size()) {
// if (minute == i) {
// return &(this->minutes->at(i));
// }
// else {
// last_defined_minute = i;
// }
// }
// else {
// empty_vector = &(this->minutes->at(i));
// if (minute == i) {
// if (last_defined_minute == -1) return empty_vector;
// return &(this->minutes->at(last_defined_minute));
// }
// }
// }
// return empty_vector;
// }
void Wordclock::add_hour_offset(uint8_t index, int8_t offset) {
(*this->hour_offsets)[index] = offset;
}
void Wordclock::add_hour(uint8_t hour, std::vector<uint16_t> *segments) {
for (uint16_t i : *segments){
this->hours->at(hour).push_back(i);
}
}
void Wordclock::add_minute(uint8_t minute, std::vector<uint16_t> *segments) {
for (uint16_t i : *segments){
this->minutes->at(minute).push_back(i);
}
}
void Wordclock::add_static(uint16_t segment_id) {
this->static_segments->push_back(segment_id);
}
// uint16_t **
// Wordclock::Wordclock(std::vector<uint16_t> *minutes, std::vector<uint16_t> *hours, SegmentCoords *segments)
// Wordclock::Wordclock(uint16_t **minutes, uint16_t **hours, SegmentCoords *segments)
// : PollingComponent(1000) {
// // this->minutes = minutes;
// // this->hours = hours;
// // this->segments = segments;
// // std::vector<uint16_t> minutes[60];
// // std::vector<uint16_t> hours[24];
// }
Wordclock::Wordclock()
: PollingComponent(1000) {
// this->minutes = std::vector<std::vector<uint16_t>>();
// // for (int i=0; i<60; i++) this->minutes.push_back(std::vector<uint16_t>());
// this->hours = std::vector<std::vector<uint16_t>>();
// // for (int i=0; i<24; i++) this->minutes.push_back(std::vector<uint16_t>());
// this->segments = std::vector<SegmentCoords>();
}
Wordclock::Wordclock(esphome::time::RealTimeClock *time, esphome::addressable_light::AddressableLightDisplay *display, esphome::light::AddressableLightState *light_state)
: PollingComponent(16) {
// ESP_LOGE("wordclock.cpp", "this: 0x%x", (this));
// ESP_LOGE("wordclock.cpp", "display: 0x%x", (display));
// ESP_LOGE("wordclock.cpp", "&display: 0x%x", (&display));
this->time = time;
this->display = display;
this->light = this->display->get_light();
this->light_state = light_state;
// light::AddressableLight *light = this->display->get_light();
// light::AddressableRainbowLightEffect *light_addressablerainbowlighteffect;
// light::AddressableTwinkleEffect *light_addressabletwinkleeffect;
// light::AddressableRandomTwinkleEffect *light_addressablerandomtwinkleeffect;
// this->rainbow = new light::AddressableRainbowLightEffect("rainbow");
// this->rainbow->set_speed(10);
// this->rainbow->set_width(50);
// this->twinkle = new light::AddressableTwinkleEffect("twinkle");
// this->twinkle->set_twinkle_probability(0.05f);
// this->twinkle->set_progress_interval(4);
// this->randomTwinkle = new light::AddressableRandomTwinkleEffect("random_twinkle");
// this->randomTwinkle->set_twinkle_probability(0.05f);
// this->randomTwinkle->set_progress_interval(32);
this->hour_offsets = new std::vector<int8_t>(60, 0);
this->minutes = new std::vector<std::vector<uint16_t>>(60, std::vector<uint16_t>());
// for (int i=0; i<60; i++) this->minutes->push_back(std::vector<uint16_t>());
this->hours = new std::vector<std::vector<uint16_t>>(24, std::vector<uint16_t>());
// for (int i=0; i<24; i++) this->hours->push_back(std::vector<uint16_t>());
this->segments = new std::vector<SegmentCoords>();
this->static_segments = new std::vector<uint16_t>();
}
} // namespace wordclock
} // namespace esphome