Files
hassos_config/esphome/components/ehmtx/EHMTX.cpp
2022-12-20 21:26:47 +01:00

501 lines
13 KiB
C++

#include "esphome.h"
namespace esphome
{
EHMTX::EHMTX() : PollingComponent(TICKINTERVAL)
{
this->store = new EHMTX_store(this);
this->icon_screen = new EHMTX_screen(this);
this->show_screen = false;
this->show_gauge = false;
this->text_color = Color(240, 240, 240);
this->today_color = Color(240, 240, 240);
this->weekday_color = Color(100, 100, 100);
this->clock_color = Color(240, 240, 240);
this->alarm_color = Color(200, 50, 50);
this->gauge_color = Color(100, 100, 200);
this->gauge_value = 0;
this->icon_count = 0;
this->last_clock_time = 0;
#ifdef USE_EHMTX_SELECT
this->select = NULL;
#endif
}
void EHMTX::force_screen(std::string name)
{
uint8_t icon_id = this->find_icon(name);
if (icon_id < MAXICONS)
{
this->store->force_next_screen(icon_id);
ESP_LOGD(TAG, "force next screen: %s", name.c_str());
}
}
void EHMTX::set_time_format(std::string s)
{
this->time_fmt = s;
}
void EHMTX::set_date_format(std::string s)
{
this->date_fmt = s;
}
void EHMTX::set_indicator_color(int r, int g, int b)
{
this->indicator_color = Color((uint8_t)r & 248, (uint8_t)g & 252, (uint8_t)b & 248);
ESP_LOGD(TAG, "indicator r: %d g: %d b: %d", r, g, b);
}
void EHMTX::set_today_color(int r, int g, int b)
{
this->today_color = Color((uint8_t)r & 248, (uint8_t)g & 252, (uint8_t)b & 248);
ESP_LOGD("EHMTX", "today color r: %d g: %d b: %d", r, g, b);
}
void EHMTX::set_weekday_color(int r, int g, int b)
{
this->weekday_color = Color((uint8_t)r & 248, (uint8_t)g & 252, (uint8_t)b & 248);
ESP_LOGD("EHMTX", "weekday color: %d g: %d b: %d", r, g, b);
}
void EHMTX::set_clock_color(int r, int g, int b)
{
this->clock_color = Color((uint8_t)r & 248, (uint8_t)g & 252, (uint8_t)b & 248);
ESP_LOGD("EHMTX", "clock color r: %d g: %d b: %d", r, g, b);
}
void EHMTX::set_gauge_color(int r, int g, int b)
{
this->gauge_color = Color((uint8_t)r & 248, (uint8_t)g & 252, (uint8_t)b & 248);
ESP_LOGD(TAG, "gauge color r: %d g: %d b: %d", r, g, b);
}
void EHMTX::set_alarm_color(int r, int g, int b)
{
this->alarm_color = Color((uint8_t)r & 248, (uint8_t)g & 252, (uint8_t)b & 248);
ESP_LOGD(TAG, "alarm color r: %d g: %d b: %d", r, g, b);
}
void EHMTX::set_text_color(int r, int g, int b)
{
this->text_color = Color((uint8_t)r & 248, (uint8_t)g & 252, (uint8_t)b & 248);
ESP_LOGD(TAG, "text color r: %d g: %d b: %d", r, g, b);
}
uint8_t EHMTX::find_icon(std::string name)
{
for (uint8_t i = 0; i < this->icon_count; i++)
{
if (strcmp(this->icons[i]->name.c_str(), name.c_str()) == 0)
{
ESP_LOGD(TAG, "icon: %s found id: %d", name.c_str(), i);
return i;
}
}
ESP_LOGD(TAG, "icon: %s not found", name.c_str());
return MAXICONS;
}
void EHMTX::set_indicator_off()
{
this->show_indicator = false;
ESP_LOGD(TAG, "indicator off");
}
void EHMTX::set_indicator_on()
{
this->show_indicator = true;
ESP_LOGD(TAG, "indicator on");
}
void EHMTX::set_gauge_off()
{
this->show_gauge = false;
ESP_LOGD(TAG, "gauge off");
}
void EHMTX::set_gauge_value(uint8_t val)
{
this->show_gauge = false;
if ((val > 0) && (val <= 100))
{
this->show_gauge = true;
this->gauge_value = (uint8_t)(100 - val) * 7 / 100;
ESP_LOGD(TAG, "gauge value: %d => %d",val, this->gauge_value);
}
}
void EHMTX::draw_clock()
{
if (this->clock->now().timestamp > 6000) // valid time
{
time_t ts = this->clock->now().timestamp;
if (!this->show_date or ((this->next_action_time - ts) < this->clock_time))
{
this->display->strftime(this->xoffset + 15, this->yoffset, this->font, this->clock_color, display::TextAlign::BASELINE_CENTER, this->time_fmt.c_str(),
this->clock->now());
}
else
{
this->display->strftime(this->xoffset + 15, this->yoffset, this->font, this->clock_color, display::TextAlign::BASELINE_CENTER, this->date_fmt.c_str(),
this->clock->now());
}
this->draw_day_of_week();
}
else
{
this->display->print(this->xoffset + 15, this->yoffset, this->font, this->alarm_color, display::TextAlign::BASELINE_CENTER, "!t!");
}
}
void EHMTX::setup()
{
#ifdef USE_EHMTX_SELECT
if (this->select != NULL)
{
ESP_LOGD(TAG, "select_component activated");
this->select->traits.set_options(this->select_options);
this->select->parent = this;
}
#endif
}
void EHMTX::update() // called from polling component
{
}
void EHMTX::tick()
{
time_t ts = this->clock->now().timestamp;
if (ts > this->next_action_time)
{
if (this->show_icons)
{
this->next_action_time = ts + this->screen_time;
uint8_t i = this->icon_screen->icon;
++i;
if (i < this->icon_count)
{
int x, y, w, h;
this->display->get_text_bounds(0, 0, this->icons[i]->name.c_str(), this->font, display::TextAlign::LEFT, &x, &y, &w, &h);
this->icon_screen->set_text(this->icons[i]->name, i, w, 1);
ESP_LOGD(TAG, "show all icons icon: %d name: %s", i, this->icons[i]->name.c_str());
}
else
{
this->show_icons = false;
ESP_LOGD(TAG, "show all icons done");
}
}
else
{
this->show_screen = false;
if (!(ts - this->last_clock_time > 60)) // force clock if last time more the 60s old
{
bool has_next_screen = this->store->move_next();
if (has_next_screen)
{
this->show_screen = true;
}
}
if (this->show_screen == false)
{
ESP_LOGD(TAG, "next action: show clock/date for %d/%d sec",this->clock_time, this->screen_time-this->clock_time);
this->last_clock_time = ts;
this->next_action_time = ts + this->screen_time;
}
else
{
ESP_LOGD(TAG, "next action: show screen \"%s\" for %d sec", this->icons[this->store->current()->icon]->name.c_str() ,this->store->current()->display_duration);
this->next_action_time = ts + this->store->current()->display_duration;
for (auto *t : on_next_screen_triggers_)
{
t->process(this->icons[this->store->current()->icon]->name, this->store->current()->text);
}
}
}
}
}
void EHMTX::set_screen_time(uint16_t t)
{
this->screen_time = t;
}
void EHMTX::set_duration(uint8_t t)
{
this->duration = t;
}
void EHMTX::get_status()
{
time_t ts = this->clock->now().timestamp;
ESP_LOGI(TAG, "status time: %d.%d.%d %02d:%02d", this->clock->now().day_of_month,
this->clock->now().month, this->clock->now().year,
this->clock->now().hour, this->clock->now().minute);
ESP_LOGI(TAG, "status brightness: %d (0..255)", this->brightness_);
ESP_LOGI(TAG, "status default duration: %d", this->duration);
ESP_LOGI(TAG, "status date format: %s", this->date_fmt.c_str());
ESP_LOGI(TAG, "status time format: %s", this->time_fmt.c_str());
ESP_LOGI(TAG, "status text_color: RGB(%d,%d,%d)", this->text_color.r, this->text_color.g, this->text_color.b);
ESP_LOGI(TAG, "status alarm_color: RGB(%d,%d,%d)", this->alarm_color.r, this->alarm_color.g, this->alarm_color.b);
if (this->show_indicator)
{
ESP_LOGI(TAG, "status indicator on");
}
else
{
ESP_LOGI(TAG, "status indicator off");
}
this->store->log_status();
for (uint8_t i = 0; i < this->icon_count; i++)
{
ESP_LOGI(TAG, "status icon: %d name: %s", i, this->icons[i]->name.c_str());
}
#ifdef USE_EHMTX_SELECT
ESP_LOGI(TAG, "select enabled");
#endif
}
void EHMTX::set_font(display::Font *font)
{
this->font = font;
}
void EHMTX::set_anim_intervall(uint16_t ai)
{
this->anim_intervall = ai;
}
void EHMTX::set_scroll_intervall(uint16_t si)
{
this->scroll_intervall = si;
}
void EHMTX::del_screen(std::string iname)
{
uint8_t icon = this->find_icon(iname.c_str());
this->store->delete_screen(icon);
}
void EHMTX::add_screen(std::string iconname, std::string text, uint16_t duration, bool alarm)
{
uint8_t icon = this->find_icon(iconname.c_str());
this->internal_add_screen(icon, text, duration, alarm);
ESP_LOGD(TAG, "add_screen icon: %d iconname: %s text: %s duration: %d alarm: %d", icon, iconname.c_str(), text.c_str(), duration, alarm);
}
void EHMTX::internal_add_screen(uint8_t icon, std::string text, uint16_t duration, bool alarm = false)
{
if (icon >= this->icon_count)
{
ESP_LOGD(TAG, "icon %d not found => default: 0", icon);
icon = 0;
}
EHMTX_screen *screen = this->store->find_free_screen(icon);
int x, y, w, h;
this->display->get_text_bounds(0, 0, text.c_str(), this->font, display::TextAlign::LEFT, &x, &y, &w, &h);
screen->alarm = alarm;
screen->set_text(text, icon, w, duration);
}
void EHMTX::set_default_brightness(uint8_t b)
{
this->brightness_ = b;
}
void EHMTX::set_show_date(bool b)
{
this->show_date = b;
if (b)
{
ESP_LOGI(TAG, "show date");
}
else
{
ESP_LOGI(TAG, "don't show date");
}
}
void EHMTX::set_show_day_of_week(bool b)
{
this->show_day_of_week = b;
if (b)
{
ESP_LOGI(TAG, "show day of week");
}
else
{
ESP_LOGI(TAG, "don't show day of week");
}
}
void EHMTX::set_week_start(bool b)
{
this->week_starts_monday = b;
if (b)
{
ESP_LOGI(TAG, "weekstart: monday");
}
else
{
ESP_LOGI(TAG, "weekstart: sunday");
}
}
void EHMTX::set_brightness(uint8_t b)
{
this->brightness_ = b;
float br = (float)b / (float)255;
ESP_LOGI(TAG, "set_brightness %d => %.2f %%", b, 100 * br);
this->display->get_light()->set_correction(br, br, br, br);
}
uint8_t EHMTX::get_brightness()
{
return this->brightness_;
}
std::string EHMTX::get_current()
{
return this->icons[this->store->current()->icon]->name;
}
void EHMTX::set_clock_time(uint16_t t)
{
this->clock_time = t;
}
void EHMTX::set_display(addressable_light::AddressableLightDisplay *disp)
{
this->display = disp;
}
void EHMTX::set_clock(time::RealTimeClock *clock)
{
this->clock = clock;
this->store->clock = clock;
}
void EHMTX::draw_day_of_week()
{
if (this->show_day_of_week)
{
auto dow = this->clock->now().day_of_week - 1; // SUN = 0
for (uint8_t i = 0; i <= 6; i++)
{
if (((!this->week_starts_monday) && (dow == i)) ||
((this->week_starts_monday) && ((dow == (i + 1)) || ((dow == 0 && i == 6)))))
{
this->display->line(2 + i * 4, 7, i * 4 + 4, 7, this->today_color);
}
else
{
this->display->line(2 + i * 4, 7, i * 4 + 4, 7, this->weekday_color);
}
}
}
};
void EHMTX::set_font_offset(int8_t x, int8_t y)
{
this->xoffset = x;
this->yoffset = y;
}
void EHMTX::dump_config()
{
ESP_LOGCONFIG(TAG, "EspHoMatriX %s", EHMTX_VERSION);
ESP_LOGCONFIG(TAG, "Icons: %d of %d", this->icon_count, MAXICONS);
ESP_LOGCONFIG(TAG, "Font offset: x=%d y=%d", this->xoffset, this->yoffset);
ESP_LOGCONFIG(TAG, "Max screens: %d", MAXQUEUE);
ESP_LOGCONFIG(TAG, "Date format: %s", this->date_fmt.c_str());
ESP_LOGCONFIG(TAG, "Time format: %s", this->time_fmt.c_str());
ESP_LOGCONFIG(TAG, "Intervall (ms) scroll: %d anim: %d", this->scroll_intervall, this->anim_intervall);
ESP_LOGCONFIG(TAG, "Displaytime (s) clock: %d screen: %d", this->clock_time, this->screen_time);
if (this->show_day_of_week)
{
ESP_LOGCONFIG(TAG, "show day of week");
}
if (this->show_date)
{
ESP_LOGCONFIG(TAG, "show date");
}
if (this->week_starts_monday)
{
ESP_LOGCONFIG(TAG, "weekstart: monday");
}
else
{
ESP_LOGCONFIG(TAG, "weekstart: sunday");
}
}
#ifdef USE_EHMTX_SELECT
void EHMTX::set_select(esphome::EhmtxSelect *es)
{
this->select = es;
}
#endif
void EHMTX::add_icon(EHMTX_Icon *icon)
{
this->icons[this->icon_count] = icon;
ESP_LOGD(TAG, "add_icon no.: %d name: %s frame_duration: %d ms", this->icon_count, icon->name.c_str(), icon->frame_duration);
this->icon_count++;
#ifdef USE_EHMTX_SELECT
this->select_options.push_back(icon->name);
#endif
}
void EHMTX::show_all_icons()
{
int x, y, w, h;
ESP_LOGD(TAG, "show all icons icon: %s", this->icons[0]->name.c_str());
this->display->get_text_bounds(0, 0, this->icons[0]->name.c_str(), this->font, display::TextAlign::LEFT, &x, &y, &w, &h);
this->icon_screen->set_text(this->icons[0]->name, 0, w, 1);
this->show_icons = true;
}
void EHMTX::draw()
{
if (this->show_icons)
{
this->icon_screen->draw();
}
else
{
if (this->show_screen)
{
this->store->current()->draw();
}
else
{
this->draw_clock();
}
}
if (this->show_indicator)
{
this->display->line(31, 5, 29, 7, this->indicator_color);
this->display->draw_pixel_at(30, 7, this->indicator_color);
this->display->draw_pixel_at(31, 6, this->indicator_color);
this->display->draw_pixel_at(31, 7, this->indicator_color);
}
}
void EHMTXNextScreenTrigger::process(std::string iconname, std::string text)
{
this->trigger(iconname, text);
}
}