periodic push

This commit is contained in:
2023-06-29 16:14:36 +02:00
parent c948b95622
commit 831f676068
267 changed files with 17705 additions and 10864 deletions

View File

@@ -1,500 +0,0 @@
#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);
}
}

View File

@@ -1,422 +0,0 @@
#ifndef EHMTX_H
#define EHMTX_H
#include "esphome.h"
const uint8_t MAXQUEUE = 24;
const uint8_t MAXICONS = 64;
const uint8_t TEXTSCROLLSTART = 8;
const uint8_t TEXTSTARTOFFSET = (32 - 8);
const uint16_t TICKINTERVAL = 1000; // each 1000ms
static const char *const EHMTX_VERSION = "Version: 2022.7.0";
static const char *const TAG = "EHMTX";
namespace esphome
{
class EHMTX_screen;
class EHMTX_store;
class EhmtxSelect;
class EHMTX_Icon;
class EHMTXNextScreenTrigger;
class EHMTX : public PollingComponent
{
protected:
float get_setup_priority() const override { return esphome::setup_priority::AFTER_CONNECTION; }
uint8_t brightness_;
bool week_starts_monday;
bool show_day_of_week;
std::string time_fmt;
std::string date_fmt;
Color indicator_color;
Color clock_color;
Color today_color;
Color weekday_color;
EHMTX_store *store;
std::vector<EHMTXNextScreenTrigger *> on_next_screen_triggers_;
void internal_add_screen(uint8_t icon, std::string text, uint16_t duration, bool alarm);
public:
EHMTX();
Color text_color, alarm_color, gauge_color;
void dump_config();
bool show_screen;
bool show_indicator;
bool show_gauge;
bool show_date;
uint8_t gauge_value;
bool show_icons;
void force_screen(std::string name);
EHMTX_Icon *icons[MAXICONS];
EHMTX_screen *icon_screen;
void add_icon(EHMTX_Icon *icon);
#ifdef USE_EHMTX_SELECT
std::vector<std::string> select_options;
esphome::EhmtxSelect *select;
void set_select(esphome::EhmtxSelect *es);
#endif
addressable_light::AddressableLightDisplay *display;
time::RealTimeClock *clock;
display::Font *font;
int8_t yoffset, xoffset;
uint8_t find_icon(std::string name);
uint16_t duration; // in minutes how long is a screen valid
uint16_t scroll_intervall; // ms to between scrollsteps
uint16_t anim_intervall; // ms to next_frame()
uint16_t clock_time; // seconds display of screen_time - clock_time = date_time
uint16_t screen_time; // seconds display of screen
uint8_t icon_count; // max iconnumber -1
unsigned long last_scroll_time;
unsigned long last_anim_time;
time_t last_clock_time = 0; // starttime clock display
time_t next_action_time = 0; // when is the next screen change
void draw_day_of_week();
void show_all_icons();
void tick();
void draw();
void get_status();
void skip_screen();
std::string get_current();
void set_display(addressable_light::AddressableLightDisplay *disp);
void set_screen_time(uint16_t t);
void set_clock_time(uint16_t t);
void set_show_day_of_week(bool b);
void set_show_date(bool b);
void set_font_offset(int8_t x, int8_t y);
void set_week_start(bool b);
void set_default_brightness(uint8_t b);
void set_brightness(uint8_t b);
uint8_t get_brightness();
void add_screen(std::string icon, std::string text, uint16_t duration, bool alarm);
void del_screen(std::string iname);
void set_clock(time::RealTimeClock *clock);
void set_font(display::Font *font);
void set_anim_intervall(uint16_t intervall);
void set_scroll_intervall(uint16_t intervall);
void set_duration(uint8_t d);
void set_indicator_off();
void set_time_format(std::string s);
void set_date_format(std::string s);
void set_indicator_on();
void set_indicator_color(int r, int g, int b);
void set_gauge_off();
void set_gauge_value(uint8_t v);
void set_gauge_color(int r, int g, int b);
void set_text_color(int r, int g, int b);
void set_clock_color(int r, int g, int b);
void set_today_color(int r, int g, int b);
void set_weekday_color(int r, int g, int b);
void set_alarm_color(int r, int g, int b);
void set_icon_count(uint8_t ic);
void draw_clock();
void add_on_next_screen_trigger(EHMTXNextScreenTrigger *t) { this->on_next_screen_triggers_.push_back(t); }
void setup();
void update();
};
class EHMTX_store
{
protected:
EHMTX_screen *slots[MAXQUEUE];
uint8_t active_slot;
uint8_t force_screen;
uint8_t count_active_screens();
public:
EHMTX_store(EHMTX *config);
void force_next_screen(uint8_t icon_id);
time::RealTimeClock *clock;
EHMTX_screen *find_free_screen(uint8_t icon);
void delete_screen(uint8_t icon);
bool move_next();
EHMTX_screen *current();
void log_status();
};
class EHMTX_screen
{
protected:
uint8_t shiftx_;
uint8_t pixels_;
EHMTX *config_;
public:
uint16_t display_duration;
bool alarm;
time_t endtime;
uint8_t icon;
std::string text;
EHMTX_screen(EHMTX *config);
bool active();
bool is_alarm();
void draw();
void draw_();
bool isfree();
bool update_slot(uint8_t _icon);
void update_screen();
bool del_slot(uint8_t _icon);
void set_text(std::string text, uint8_t icon, uint8_t pixel, uint16_t et);
};
class EHMTXNextScreenTrigger : public Trigger<std::string, std::string>
{
public:
explicit EHMTXNextScreenTrigger(EHMTX *parent) { parent->add_on_next_screen_trigger(this); }
void process(std::string, std::string);
};
template <typename... Ts>
class SetBrightnessAction : public Action<Ts...>
{
public:
SetBrightnessAction(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(uint8_t, brightness)
void play(Ts... x) override
{
auto brightness = this->brightness_.value(x...);
this->parent_->set_brightness(brightness);
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class AddScreenAction : public Action<Ts...>
{
public:
AddScreenAction(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(std::string, icon)
TEMPLATABLE_VALUE(std::string, text)
TEMPLATABLE_VALUE(uint8_t, duration)
TEMPLATABLE_VALUE(bool, alarm)
void play(Ts... x) override
{
auto icon = this->icon_.value(x...);
auto text = this->text_.value(x...);
auto duration = this->duration_.value(x...);
auto alarm = this->alarm_.value(x...);
if (duration)
{
this->parent_->add_screen(icon, text, duration, alarm);
}
else
{
this->parent_->add_screen(icon, text, this->parent_->duration, alarm);
}
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class SetIndicatorOn : public Action<Ts...>
{
public:
SetIndicatorOn(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(uint8_t, red)
TEMPLATABLE_VALUE(uint8_t, green)
TEMPLATABLE_VALUE(uint8_t, blue)
void play(Ts... x) override
{
this->parent_->set_indicator_on();
this->parent_->set_indicator_color(this->red_.value(x...), this->green_.value(x...), this->blue_.value(x...));
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class SetClockColor : public Action<Ts...>
{
public:
SetClockColor(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(uint8_t, red)
TEMPLATABLE_VALUE(uint8_t, green)
TEMPLATABLE_VALUE(uint8_t, blue)
void play(Ts... x) override
{
this->parent_->set_clock_color(this->red_.value(x...), this->green_.value(x...), this->blue_.value(x...));
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class SetAlarmColor : public Action<Ts...>
{
public:
SetAlarmColor(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(uint8_t, red)
TEMPLATABLE_VALUE(uint8_t, green)
TEMPLATABLE_VALUE(uint8_t, blue)
void play(Ts... x) override
{
this->parent_->set_alarm_color(this->red_.value(x...), this->green_.value(x...), this->blue_.value(x...));
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class SetTodayColor : public Action<Ts...>
{
public:
SetTodayColor(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(uint8_t, red)
TEMPLATABLE_VALUE(uint8_t, green)
TEMPLATABLE_VALUE(uint8_t, blue)
void play(Ts... x) override
{
this->parent_->set_today_color(this->red_.value(x...), this->green_.value(x...), this->blue_.value(x...));
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class SetShowDate : public Action<Ts...>
{
public:
SetShowDate(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(uint8_t, flag)
void play(Ts... x) override
{
this->parent_->set_show_date(this->flag_.value(x...));
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class SetShowDayOfWeek : public Action<Ts...>
{
public:
SetShowDayOfWeek(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(uint8_t, flag)
void play(Ts... x) override
{
this->parent_->set_show_day_of_week(this->flag_.value(x...));
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class SetTextColor : public Action<Ts...>
{
public:
SetTextColor(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(uint8_t, red)
TEMPLATABLE_VALUE(uint8_t, green)
TEMPLATABLE_VALUE(uint8_t, blue)
void play(Ts... x) override
{
this->parent_->set_text_color(this->red_.value(x...), this->green_.value(x...), this->blue_.value(x...));
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class SetWeekdayColor : public Action<Ts...>
{
public:
SetWeekdayColor(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(uint8_t, red)
TEMPLATABLE_VALUE(uint8_t, green)
TEMPLATABLE_VALUE(uint8_t, blue)
void play(Ts... x) override
{
this->parent_->set_weekday_color(this->red_.value(x...), this->green_.value(x...), this->blue_.value(x...));
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class SetIndicatorOff : public Action<Ts...>
{
public:
SetIndicatorOff(EHMTX *parent) : parent_(parent) {}
void play(Ts... x) override
{
this->parent_->set_indicator_off();
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class DeleteScreen : public Action<Ts...>
{
public:
DeleteScreen(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(std::string, icon)
void play(Ts... x) override
{
this->parent_->del_screen(this->icon_.value(x...));
}
protected:
EHMTX *parent_;
};
template <typename... Ts>
class ForceScreen : public Action<Ts...>
{
public:
ForceScreen(EHMTX *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(std::string, icon)
void play(Ts... x) override
{
this->parent_->force_screen(this->icon_.value(x...));
}
protected:
EHMTX *parent_;
};
class EHMTX_Icon : public display::Animation
{
protected:
bool counting_up;
public:
EHMTX_Icon(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, display::ImageType type, std::string icon_name, bool revers, uint16_t frame_duration);
std::string name;
uint16_t frame_duration;
void next_frame();
bool reverse;
};
}
#endif

View File

@@ -1,37 +0,0 @@
#include "esphome.h"
namespace esphome
{
EHMTX_Icon::EHMTX_Icon(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, display::ImageType type, std::string icon_name, bool revers, uint16_t frame_duration)
: Animation(data_start, width, height, animation_frame_count, type)
{
this->name = icon_name;
this->reverse = revers;
this->frame_duration = frame_duration;
this->counting_up = true;
}
void EHMTX_Icon::next_frame()
{
if (this->get_animation_frame_count() > 1)
{
if (this->counting_up)
{
if (this->reverse && (this->get_current_frame() == this->get_animation_frame_count() - 2))
{
this->counting_up = false;
}
Animation::next_frame();
}
else
{
if (this->get_current_frame() == 1) // this->get_animation_frame_count())
{
this->counting_up = true;
}
Animation::prev_frame();
}
}
}
}

View File

@@ -1,121 +0,0 @@
#include "esphome.h"
namespace esphome
{
EHMTX_screen::EHMTX_screen(EHMTX *config)
{
this->config_ = config;
this->endtime = 0;
this->alarm = false;
}
bool EHMTX_screen::is_alarm() { return this->alarm; }
bool EHMTX_screen::del_slot(uint8_t _icon)
{
if (this->icon == _icon)
{
this->endtime = 0;
this->icon = 0;
ESP_LOGD(TAG, "delete screen icon: %d", _icon);
return true;
}
return false;
}
void EHMTX_screen::update_screen()
{
if (millis() - this->config_->last_scroll_time >= this->config_->scroll_intervall && this->pixels_ > TEXTSTARTOFFSET)
{
this->shiftx_++;
if (this->shiftx_ > this->pixels_ + TEXTSTARTOFFSET)
{
this->shiftx_ = 0;
}
this->config_->last_scroll_time = millis();
}
if (millis() - this->config_->last_anim_time >= this->config_->icons[this->icon]->frame_duration)
{
this->config_->icons[this->icon]->next_frame();
this->config_->last_anim_time = millis();
}
}
bool EHMTX_screen::active()
{
if (this->endtime > 0)
{
time_t ts = this->config_->clock->now().timestamp;
if (ts < this->endtime)
{
return true;
}
}
return false;
}
void EHMTX_screen::draw_()
{
int8_t extraoffset = 0;
if (this->pixels_ > TEXTSTARTOFFSET)
{
extraoffset = TEXTSTARTOFFSET;
}
if (this->config_->show_gauge)
{
extraoffset += 2;
}
if (this->alarm)
{
this->config_->display->print(TEXTSCROLLSTART - this->shiftx_ + extraoffset + this->config_->xoffset, this->config_->yoffset, this->config_->font, this->config_->alarm_color, esphome::display::TextAlign::BASELINE_LEFT,
this->text.c_str());
}
else
{
this->config_->display->print(TEXTSCROLLSTART - this->shiftx_ + extraoffset + this->config_->xoffset, this->config_->yoffset, this->config_->font, this->config_->text_color, esphome::display::TextAlign::BASELINE_LEFT,
this->text.c_str());
}
if (this->alarm)
{
this->config_->display->draw_pixel_at(30, 0, this->config_->alarm_color);
this->config_->display->draw_pixel_at(31, 1, this->config_->alarm_color);
this->config_->display->draw_pixel_at(31, 0, this->config_->alarm_color);
}
if (this->config_->show_gauge)
{
this->config_->display->line(0, 7, 0, 0, esphome::display::COLOR_OFF);
this->config_->display->line(0, 7, 0, this->config_->gauge_value, this->config_->gauge_color);
this->config_->display->line(1, 7, 1, 0, esphome::display::COLOR_OFF);
this->config_->display->image(2, 0, this->config_->icons[this->icon]);
this->config_->display->line(10, 0, 10, 7, esphome::display::COLOR_OFF);
}
else
{
this->config_->display->line(8, 0, 8, 7, esphome::display::COLOR_OFF);
this->config_->display->image(0, 0, this->config_->icons[this->icon]);
}
}
void EHMTX_screen::draw()
{
this->draw_();
this->update_screen();
}
void EHMTX_screen::set_text(std::string text, uint8_t icon, uint8_t pixel, uint16_t et)
{
this->text = text;
this->pixels_ = pixel;
this->shiftx_ = 0;
float dd = ceil((2 * (TEXTSTARTOFFSET + pixel) * this->config_->scroll_intervall) / 1000);
this->display_duration = (dd > this->config_->screen_time) ? dd : this->config_->screen_time;
ESP_LOGD(TAG, "display length text: %s pixels %d calculated: %d default: %d", text.c_str(),pixel, this->display_duration, this->config_->screen_time);
this->endtime = this->config_->clock->now().timestamp + et * 60;
this->icon = icon;
}
}

View File

@@ -1,144 +0,0 @@
#include "esphome.h"
namespace esphome
{
EHMTX_store::EHMTX_store(EHMTX *config)
{
for (uint8_t i = 0; i < MAXQUEUE; i++)
{
this->slots[i] = new EHMTX_screen(config);
}
this->active_slot = 0;
}
EHMTX_screen *EHMTX_store::find_free_screen(uint8_t icon)
{
ESP_LOGD(TAG, "findfreeslot for icon: %d", icon);
for (uint8_t i = 0; i < MAXQUEUE; i++)
{
EHMTX_screen *screen = this->slots[i];
if (screen->icon == icon)
{
return screen;
}
}
time_t ts = this->clock->now().timestamp;
for (uint8_t i = 0; i < MAXQUEUE; i++)
{
EHMTX_screen *screen = this->slots[i];
if (screen->endtime <= ts)
{
return screen;
}
}
return this->slots[0];
}
void EHMTX_store::delete_screen(uint8_t icon)
{
for (uint8_t i = 0; i < MAXQUEUE; i++)
{
this->slots[i]->del_slot(icon);
}
}
void EHMTX_store::force_next_screen(uint8_t icon_id)
{
if (icon_id < MAXICONS)
{
this->force_screen = icon_id;
}
}
bool EHMTX_store::move_next()
{
if (this->force_screen < MAXICONS)
{
for (uint8_t slot = 0; slot < MAXQUEUE; slot++)
{
EHMTX_screen *screen = this->slots[slot];
if (screen->active() && screen->icon == this->force_screen)
{
this->force_screen = MAXICONS;
this->active_slot = slot;
return true;
}
}
}
if (this->count_active_screens() == 1)
{
// Find first and only active screen
for (uint8_t slot = 0; slot < MAXQUEUE; slot++)
{
EHMTX_screen *screen = this->slots[slot];
if (screen->active())
{
this->active_slot = slot;
return true;
}
}
}
// Find active screen between active slot and end of array
for (uint8_t slot = (this->active_slot + 1); slot < MAXQUEUE; slot++)
{
EHMTX_screen *screen = this->slots[slot];
if (screen->active())
{
this->active_slot = slot;
return true;
}
}
// Find active screen between 0 and active slot
for (uint8_t slot = 0; slot < this->active_slot; slot++)
{
EHMTX_screen *screen = this->slots[slot];
if (screen->active())
{
this->active_slot = slot;
return true;
}
}
// No active screen found
this->active_slot = 0;
return false;
}
EHMTX_screen *EHMTX_store::current()
{
return this->slots[this->active_slot];
}
uint8_t EHMTX_store::count_active_screens()
{
uint8_t count = 0;
for (uint8_t screen = 0; screen < MAXQUEUE; screen++)
{
if (this->slots[screen]->active())
{
count++;
}
}
return count;
}
void EHMTX_store::log_status()
{
uint8_t status = 0;
time_t ts = this->clock->now().timestamp;
ESP_LOGI(TAG, "status active slot: %d", this->active_slot);
ESP_LOGI(TAG, "status screen count: %d of %d", this->count_active_screens(), MAXQUEUE);
for (uint8_t i = 0; i < MAXQUEUE; i++)
{
if (this->slots[i]->active())
{
EHMTX_screen *screen = this->slots[i];
int td = screen->endtime - ts;
ESP_LOGI(TAG, "status slot %d icon %d text: %s alarm: %d dd: %d sec end: %d sec", i, screen->icon, screen->text.c_str(), screen->alarm, screen->display_duration, td);
}
}
}
}

View File

@@ -1,609 +0,0 @@
from argparse import Namespace
import logging
import io
import requests
from esphome import core, automation
from esphome.components import display, font, time
import esphome.components.image as espImage
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_BLUE, CONF_GREEN, CONF_RED, CONF_FILE, CONF_ID, CONF_BRIGHTNESS, CONF_RAW_DATA_ID, CONF_TIME, CONF_DURATION, CONF_TRIGGER_ID
from esphome.core import CORE, HexInt
from esphome.cpp_generator import RawExpression
from .select import EHMTXSelect
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ["display", "light", "api"]
AUTO_LOAD = ["ehmtx"]
IMAGE_TYPE_RGB565 = 4
MAXFRAMES = 20
MAXICONS = 72
ICONWIDTH = 8
ICONHEIGHT = 8
ICONBUFFERSIZE = ICONWIDTH * ICONHEIGHT
ICONSIZE = [ICONWIDTH,ICONHEIGHT]
SVG_START = '<svg width="80px" height="80px" viewBox="0 0 80 80">'
SVG_END = "</svg>"
def rgb888_svg(x,y,r,g,b):
return f"<rect style=\"fill:rgb({r},{g},{b});\" x=\"{x*10}\" y=\"{y*10}\" width=\"10\" height=\"10\"/>"
def rgb565_svg(x,y,r,g,b):
return f"<rect style=\"fill:rgb({(r << 3) | (r >> 2)},{(g << 2) | (g >> 4)},{(b << 3) | (b >> 2)});\" x=\"{x*10}\" y=\"{y*10}\" width=\"10\" height=\"10\"/>"
ehmtx_ns = cg.esphome_ns.namespace("esphome")
EHMTX_ = ehmtx_ns.class_("EHMTX", cg.Component)
Icons_ = ehmtx_ns.class_("EHMTX_Icon")
NextScreenTrigger = ehmtx_ns.class_(
"EHMTXNextScreenTrigger", automation.Trigger.template(cg.std_string)
)
CONF_SHOWCLOCK = "show_clock"
CONF_SHOWSCREEN = "show_screen"
CONF_EHMTX = "ehmtx"
CONF_URL = "url"
CONF_FLAG = "flag"
CONF_LAMEID = "lameid"
CONF_AWTRIXID = "awtrixid"
CONF_ICONS = "icons"
CONF_SHOWDOW = "dayofweek"
CONF_SHOWDATE = "show_date"
CONF_DISPLAY = "display8x32"
CONF_HTML = "html"
CONF_SCROLLINTERVALL = "scroll_intervall"
CONF_ANIMINTERVALL = "anim_intervall"
CONF_FONT_ID = "font_id"
CONF_YOFFSET = "yoffset"
CONF_XOFFSET = "xoffset"
CONF_PINGPONG = "pingpong"
CONF_TIME_FORMAT = "time_format"
CONF_DATE_FORMAT = "date_format"
CONF_SELECT = "ehmtxselect"
CONF_ON_NEXT_SCREEN = "on_next_screen"
CONF_WEEK_ON_MONDAY = "week_start_monday"
CONF_ICON = "icon_name"
CONF_TEXT = "text"
CONF_ALARM = "alarm"
EHMTX_SCHEMA = cv.Schema({
cv.Required(CONF_ID): cv.declare_id(EHMTX_),
cv.Required(CONF_TIME): cv.use_id(time),
cv.Required(CONF_DISPLAY): cv.use_id(display),
cv.Required(CONF_FONT_ID): cv.use_id(font),
cv.Optional(
CONF_SHOWCLOCK, default="5"
): cv.templatable(cv.positive_int),
cv.Optional(
CONF_SELECT,
): cv.use_id(EHMTXSelect),
cv.Optional(
CONF_YOFFSET, default="6"
): cv.templatable(cv.int_range(min=-32, max=32)),
cv.Optional(
CONF_HTML, default=False
): cv.boolean,
cv.Optional(
CONF_SHOWDATE, default=True
): cv.boolean,
cv.Optional(
CONF_WEEK_ON_MONDAY, default=True
): cv.boolean,
cv.Optional(
CONF_SHOWDOW, default=True
): cv.boolean,
cv.Optional(
CONF_TIME_FORMAT, default="%H:%M"
): cv.string,
cv.Optional(
CONF_DATE_FORMAT, default="%d.%m."
): cv.string,
cv.Optional(
CONF_XOFFSET, default="1"
): cv.templatable(cv.int_range(min=-32, max=32)),
cv.Optional(CONF_SCROLLINTERVALL, default="80"
): cv.templatable(cv.positive_int),
cv.Optional(
CONF_ANIMINTERVALL, default="192"
): cv.templatable(cv.positive_int),
cv.Optional(
CONF_SHOWSCREEN, default="8"
): cv.templatable(cv.positive_int),
cv.Optional(CONF_BRIGHTNESS, default=80): cv.templatable(cv.int_range(min=0, max=255)),
cv.Optional(
CONF_DURATION, default="5"
): cv.templatable(cv.positive_int),
cv.Optional(CONF_ON_NEXT_SCREEN): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(NextScreenTrigger),
}
),
cv.Required(CONF_ICONS): cv.All(
cv.ensure_list(
{
cv.Required(CONF_ID): cv.declare_id(Icons_),
cv.Exclusive(CONF_FILE,"uri"): cv.file_,
cv.Exclusive(CONF_URL,"uri"): cv.url,
cv.Exclusive(CONF_LAMEID,"uri"): cv.string,
cv.Exclusive(CONF_AWTRIXID,"uri"): cv.string,
cv.Optional(
CONF_DURATION, default="0"
): cv.templatable(cv.positive_int),
cv.Optional(
CONF_PINGPONG, default=False
): cv.boolean,
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
}
),
cv.Length(max=MAXICONS),
)})
CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, EHMTX_SCHEMA)
ADD_SCREEN_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(EHMTX_),
cv.Required(CONF_ICON): cv.templatable(cv.string),
cv.Required(CONF_TEXT): cv.templatable(cv.string),
cv.Optional(CONF_DURATION): cv.templatable(cv.positive_int),
cv.Optional(CONF_ALARM, default=False): cv.templatable(cv.boolean),
}
)
NextScreenTrigger = ehmtx_ns.class_(
"EHMTXNextScreenTrigger", automation.Trigger.template(cg.std_string)
)
AddScreenAction = ehmtx_ns.class_("AddScreenAction", automation.Action)
@automation.register_action(
"ehmtx.add.screen", AddScreenAction, ADD_SCREEN_ACTION_SCHEMA
)
async def ehmtx_add_screen_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_ICON], args, cg.std_string)
cg.add(var.set_icon(template_))
template_ = await cg.templatable(config[CONF_TEXT], args, cg.std_string)
cg.add(var.set_text(template_))
if CONF_DURATION in config:
template_ = await cg.templatable(config[CONF_DURATION], args, cg.uint8)
cg.add(var.set_duration(template_))
template_ = await cg.templatable(config[CONF_ALARM], args, bool)
cg.add(var.set_alarm(template_))
return var
SET_BRIGHTNESS_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(EHMTX_),
cv.Optional(CONF_BRIGHTNESS, default=80): cv.templatable(cv.int_range(min=0, max=255)),
}
)
SetBrightnessAction = ehmtx_ns.class_("SetBrightnessAction", automation.Action)
@automation.register_action(
"ehmtx.set.brightness", SetBrightnessAction, SET_BRIGHTNESS_ACTION_SCHEMA
)
async def ehmtx_set_brightness_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_BRIGHTNESS], args, cg.int_)
cg.add(var.set_brightness(template_))
return var
SET_COLOR_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(EHMTX_),
cv.Optional(CONF_RED,default=80): cv.templatable(cv.uint8_t,),
cv.Optional(CONF_BLUE,default=80): cv.templatable(cv.uint8_t,),
cv.Optional(CONF_GREEN,default=80): cv.templatable(cv.uint8_t,),
}
)
SetClockColorAction = ehmtx_ns.class_("SetClockColor", automation.Action)
@automation.register_action(
"ehmtx.clock.color", SetClockColorAction, SET_COLOR_ACTION_SCHEMA
)
async def ehmtx_set_clock_color_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_RED], args, cg.int_)
cg.add(var.set_red(template_))
template_ = await cg.templatable(config[CONF_GREEN], args, cg.int_)
cg.add(var.set_green(template_))
template_ = await cg.templatable(config[CONF_BLUE], args, cg.int_)
cg.add(var.set_blue(template_))
return var
SetTextColorAction = ehmtx_ns.class_("SetTextColor", automation.Action)
@automation.register_action(
"ehmtx.text.color", SetTextColorAction, SET_COLOR_ACTION_SCHEMA
)
async def ehmtx_set_text_color_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_RED], args, cg.int_)
cg.add(var.set_red(template_))
template_ = await cg.templatable(config[CONF_GREEN], args, cg.int_)
cg.add(var.set_green(template_))
template_ = await cg.templatable(config[CONF_BLUE], args, cg.int_)
cg.add(var.set_blue(template_))
return var
SetAlarmColorAction = ehmtx_ns.class_("SetAlarmColor", automation.Action)
@automation.register_action(
"ehmtx.alarm.color", SetAlarmColorAction, SET_COLOR_ACTION_SCHEMA
)
async def ehmtx_set_alarm_color_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_RED], args, cg.int_)
cg.add(var.set_red(template_))
template_ = await cg.templatable(config[CONF_GREEN], args, cg.int_)
cg.add(var.set_green(template_))
template_ = await cg.templatable(config[CONF_BLUE], args, cg.int_)
cg.add(var.set_blue(template_))
return var
SET_FLAG_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(EHMTX_),
cv.Optional(CONF_FLAG,default=True): cv.templatable(cv.boolean),
}
)
SetShowDateAction = ehmtx_ns.class_("SetShowDate", automation.Action)
@automation.register_action(
"ehmtx.show.date", SetShowDateAction, SET_FLAG_ACTION_SCHEMA
)
async def ehmtx_show_date_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_FLAG], args, cg.bool_)
cg.add(var.set_flag(template_))
return var
SetShowDayOfWeekAction = ehmtx_ns.class_("SetShowDayOfWeek", automation.Action)
@automation.register_action(
"ehmtx.show.dayofweek", SetShowDayOfWeekAction, SET_FLAG_ACTION_SCHEMA
)
async def ehmtx_show_dayofweek_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_FLAG], args, cg.bool_)
cg.add(var.set_flag(template_))
return var
SetTodayColorAction = ehmtx_ns.class_("SetTodayColor", automation.Action)
@automation.register_action(
"ehmtx.today.color", SetTodayColorAction, SET_COLOR_ACTION_SCHEMA
)
async def ehmtx_set_today_color_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_RED], args, cg.int_)
cg.add(var.set_red(template_))
template_ = await cg.templatable(config[CONF_GREEN], args, cg.int_)
cg.add(var.set_green(template_))
template_ = await cg.templatable(config[CONF_BLUE], args, cg.int_)
cg.add(var.set_blue(template_))
return var
SetWeekdayColorAction = ehmtx_ns.class_("SetWeekdayColor", automation.Action)
@automation.register_action(
"ehmtx.weekday.color", SetWeekdayColorAction, SET_COLOR_ACTION_SCHEMA
)
async def ehmtx_set_week_color_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_RED], args, cg.int_)
cg.add(var.set_red(template_))
template_ = await cg.templatable(config[CONF_GREEN], args, cg.int_)
cg.add(var.set_green(template_))
template_ = await cg.templatable(config[CONF_BLUE], args, cg.int_)
cg.add(var.set_blue(template_))
return var
SetIndicatorOnAction = ehmtx_ns.class_("SetIndicatorOn", automation.Action)
@automation.register_action(
"ehmtx.indicator.on", SetIndicatorOnAction, SET_COLOR_ACTION_SCHEMA
)
async def ehmtx_set_indicator_on_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_RED], args, cg.int_)
cg.add(var.set_red(template_))
template_ = await cg.templatable(config[CONF_GREEN], args, cg.int_)
cg.add(var.set_green(template_))
template_ = await cg.templatable(config[CONF_BLUE], args, cg.int_)
cg.add(var.set_blue(template_))
return var
DELETE_SCREEN_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(EHMTX_),
cv.Required(CONF_ICON): cv.templatable(cv.string),
}
)
DeleteScreenAction = ehmtx_ns.class_("DeleteScreen", automation.Action)
@automation.register_action(
"ehmtx.delete.screen", DeleteScreenAction, DELETE_SCREEN_ACTION_SCHEMA
)
async def ehmtx_delete_screen_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_ICON], args, cg.std_string)
cg.add(var.set_icon(template_))
return var
ForceScreenAction = ehmtx_ns.class_("ForceScreen", automation.Action)
@automation.register_action(
"ehmtx.force.screen", ForceScreenAction, DELETE_SCREEN_ACTION_SCHEMA
)
async def ehmtx_force_screen_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_ICON], args, cg.std_string)
cg.add(var.set_icon(template_))
return var
SetIndicatorOffAction = ehmtx_ns.class_("SetIndicatorOff", automation.Action)
INDICATOR_OFF_ACTION_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(EHMTX_),
}
)
@automation.register_action(
"ehmtx.indicator.off", SetIndicatorOffAction, INDICATOR_OFF_ACTION_SCHEMA
)
async def ehmtx_set_indicator_off_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
return var
CODEOWNERS = ["@lubeda"]
async def to_code(config):
from PIL import Image
var = cg.new_Pvariable(config[CONF_ID])
html_string = F"<HTML><HEAD><TITLE>{CORE.config_path}</TITLE></HEAD>"
html_string += '''\
<STYLE>
</STYLE><BODY>\
'''
for conf in config[CONF_ICONS]:
if CONF_FILE in conf:
path = CORE.relative_config_path(conf[CONF_FILE])
try:
image = Image.open(path)
except Exception as e:
raise core.EsphomeError(f" ICONS: Could not load image file {path}: {e}")
elif CONF_LAMEID in conf:
r = requests.get("https://developer.lametric.com/content/apps/icon_thumbs/" + conf[CONF_LAMEID], timeout=4.0)
if r.status_code != requests.codes.ok:
raise core.EsphomeError(f" ICONS: Could not download image file {conf[CONF_LAMEID]}: {conf[CONF_ID]}")
image = Image.open(io.BytesIO(r.content))
elif CONF_AWTRIXID in conf:
r = requests.post("https://awtrix.blueforcer.de/icon",json={"reqType":"getIcon","ID":"" + conf[CONF_AWTRIXID] + ""} , timeout=4.0)
if r.status_code != requests.codes.ok:
raise core.EsphomeError(f" ICONS: Could not download awtrix data {conf[CONF_AWTRIXID]}: {conf[CONF_ID]}")
awtrixdata = r.json()
r = requests.get("https://awtrix.blueforcer.de/icons/"+conf[CONF_AWTRIXID], timeout=4.0)
if r.status_code != requests.codes.ok:
raise core.EsphomeError(f" ICONS: Could not download awtrix icon {conf[CONF_URL]}: {conf[CONF_ID]}")
image = Image.open(io.BytesIO(r.content))
elif CONF_URL in conf:
r = requests.get(conf[CONF_URL], timeout=4.0)
if r.status_code != requests.codes.ok:
raise core.EsphomeError(f" ICONS: Could not download image file {conf[CONF_URL]}: {conf[CONF_ID]}")
image = Image.open(io.BytesIO(r.content))
width, height = image.size
if (width != ICONWIDTH) or (height != ICONHEIGHT):
image = image.resize(ICONSIZE)
width, height = image.size
if hasattr(image, 'n_frames'):
frames = min(image.n_frames, MAXFRAMES)
else:
frames = 1
if (conf[CONF_DURATION] == 0):
try:
duration = image.info['duration']
except:
duration = config[CONF_ANIMINTERVALL]
else:
duration = conf[CONF_DURATION]
html_string += F"<BR><B>{conf[CONF_ID]}</B>&nbsp;-&nbsp;({duration} ms):<BR>"
pos = 0
frameIndex = 0
html_string += f"<DIV ID={conf[CONF_ID]}>"
if CONF_AWTRIXID in conf:
if "data" in awtrixdata:
frames = len(awtrixdata["data"])
frameIndex = 0
data = [0 for _ in range(ICONBUFFERSIZE * 2 * frames)]
duration = awtrixdata["tick"]
for frame in awtrixdata["data"]:
if len(frame) != ICONBUFFERSIZE:
raise core.EsphomeError(
f"Unexpected number of pixels in awtrix"
)
i = 0
html_string += SVG_START
for pix in frame:
G = (pix & 0x07e0) >> 5
B = pix & 0x1f
R = (pix & 0xF800) >> 11
x = (i % ICONWIDTH)
y = i//ICONHEIGHT
i += 1
rgb = pix # (R << 11) | (G << 5) | B
html_string += rgb565_svg(x,y,R,G,B)
data[pos] = rgb >> 8
pos += 1
data[pos] = rgb & 255
pos += 1
frameIndex += 1
html_string += SVG_END
else:
frames = 1
i = 0
data = [0 for _ in range(ICONBUFFERSIZE * 2)]
html_string += SVG_START
for pix in awtrixdata:
x = (i % ICONWIDTH)
y = i//ICONHEIGHT
i +=1
rgb = pix
G = (pix & 0x07e0) >> 5
B = pix & 0x1f
R = (pix & 0xF800) >> 11
html_string += rgb565_svg(x,y,R,G,B)
data[pos] = rgb >> 8
pos += 1
data[pos] = rgb & 255
pos += 1
html_string += SVG_END
else:
data = [0 for _ in range(ICONBUFFERSIZE * 2 * frames)]
for frameIndex in range(frames):
html_string += SVG_START
image.seek(frameIndex)
frame = image.convert("RGB")
pixels = list(frame.getdata())
if len(pixels) != ICONBUFFERSIZE:
raise core.EsphomeError(
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
)
i = 0
for pix in pixels:
R = pix[0] >> 3
G = pix[1] >> 2
B = pix[2] >> 3
x = (i % ICONWIDTH)
y = i//ICONHEIGHT
i +=1
rgb = (R << 11) | (G << 5) | B
html_string += rgb565_svg(x,y,R,G,B)
data[pos] = rgb >> 8
pos += 1
data[pos] = rgb & 255
pos += 1
html_string += SVG_END
html_string += f"</DIV>"
rhs = [HexInt(x) for x in data]
prog_arr = cg.progmem_array(conf[CONF_RAW_DATA_ID], rhs)
cg.new_Pvariable(
conf[CONF_ID],
prog_arr,
width,
height,
frames,
espImage.IMAGE_TYPE["RGB565"],
str(conf[CONF_ID]),
conf[CONF_PINGPONG],
duration,
)
cg.add(var.add_icon(RawExpression(str(conf[CONF_ID]))))
html_string += "</BODY></HTML>"
if config[CONF_HTML]:
try:
with open(CORE.config_path.replace(".yaml","") + ".html", 'w') as f:
f.truncate()
f.write(html_string)
f.close()
except:
print("Error writing HTML file")
cg.add(var.set_clock_time(config[CONF_SHOWCLOCK]))
cg.add(var.set_default_brightness(config[CONF_BRIGHTNESS]))
cg.add(var.set_screen_time(config[CONF_SHOWSCREEN]))
cg.add(var.set_duration(config[CONF_DURATION]))
cg.add(var.set_scroll_intervall(config[CONF_SCROLLINTERVALL]))
cg.add(var.set_anim_intervall(config[CONF_ANIMINTERVALL]))
cg.add(var.set_week_start(config[CONF_WEEK_ON_MONDAY]))
cg.add(var.set_time_format(config[CONF_TIME_FORMAT]))
cg.add(var.set_date_format(config[CONF_DATE_FORMAT]))
cg.add(var.set_show_day_of_week(config[CONF_SHOWDOW]))
cg.add(var.set_show_date(config[CONF_SHOWDATE]))
cg.add(var.set_font_offset(config[CONF_XOFFSET], config[CONF_YOFFSET]))
disp = await cg.get_variable(config[CONF_DISPLAY])
cg.add(var.set_display(disp))
f = await cg.get_variable(config[CONF_FONT_ID])
cg.add(var.set_font(f))
ehmtxtime = await cg.get_variable(config[CONF_TIME])
cg.add(var.set_clock(ehmtxtime))
if (config.get(CONF_SELECT)):
ehmtxselect = await cg.get_variable(config[CONF_SELECT])
cg.add(var.set_select(ehmtxselect))
for conf in config.get(CONF_ON_NEXT_SCREEN, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [(cg.std_string, "x"), (cg.std_string, "y")], conf)
await cg.register_component(var, config)

View File

@@ -1,27 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import select
from esphome.const import (
CONF_ID,
)
CONF_EHMTX = "ehmtx"
select_ns = cg.esphome_ns.namespace("esphome")
EHMTXSelect = select_ns.class_(
"EhmtxSelect", select.Select, cg.PollingComponent
)
CONFIG_SCHEMA = cv.All(
select.SELECT_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(EHMTXSelect),
}
).extend(cv.polling_component_schema("30s")),
)
async def to_code(config):
cg.add_define("USE_EHMTX_SELECT")
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await select.register_select(var, config, options=[])

View File

@@ -1,33 +0,0 @@
#include "ehmtx_select.h"
#include "esphome/core/log.h"
namespace esphome {
static const char *const TAG = "ehmtx.select";
void EhmtxSelect::setup() {
this->publish_state("initializing...");
}
void EhmtxSelect::update() {
if (this->parent != NULL) {
std::string value;
value = this->parent->get_current();
this->publish_state(value);
}
}
void EhmtxSelect::dump_config() {
LOG_SELECT(TAG," ", this);
LOG_UPDATE_INTERVAL(this);
}
void EhmtxSelect::control(const std::string &value) {
// value from HA => check if displayable
if (this->parent != NULL) {
ESP_LOGD(TAG, "select control to: %s",value.c_str());
this->parent->force_screen(value.c_str());
}
}
} // namespace esphome

View File

@@ -1,22 +0,0 @@
#pragma once
#include "esphome.h"
namespace esphome {
class EHMTX;
class EhmtxSelect : public select::Select, public PollingComponent {
public:
void setup() override;
void update() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::LATE; }
EHMTX *parent;
protected:
void control(const std::string &value) override;
};
}