initial commit
26
esphome/.gitignore
vendored
Executable file
@@ -0,0 +1,26 @@
|
||||
# Gitignore settings for ESPHome
|
||||
# This is an example and may include too much for your use-case.
|
||||
# You can modify this file to suit your needs.
|
||||
/.esphome/
|
||||
/secrets.yaml
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
|
||||
# Example .gitignore file for your config dir.
|
||||
# An * ensures that everything will be ignored.
|
||||
#*
|
||||
# You can whitelist files/folders with !, these will not be ignored.
|
||||
!*.yaml
|
||||
!.gitignore
|
||||
!*.md
|
||||
|
||||
# Ignore folders.
|
||||
.storage
|
||||
.cloud
|
||||
.google.token
|
||||
|
||||
# Ensure these YAML files are ignored, otherwise your secret data/credentials will leak.
|
||||
ip_bans.yaml
|
||||
secrets.yaml
|
||||
known_devices.yaml
|
||||
145
esphome/common.h
Executable file
@@ -0,0 +1,145 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#define ICON_stop "\U000F04DB"
|
||||
#define ICON_play "\U000F040A"
|
||||
#define ICON_pause "\U000F03E4"
|
||||
|
||||
std::string playbackStatusToIcon(bool playing, bool paused) {
|
||||
if (playing) return ICON_play;
|
||||
else if (paused) return ICON_pause;
|
||||
else return ICON_stop;
|
||||
}
|
||||
|
||||
#define ICON_moon_first_quarter "\U000F0F61"
|
||||
#define ICON_moon_full "\U000F0F62"
|
||||
#define ICON_moon_last_quarter "\U000F0F63"
|
||||
#define ICON_moon_new "\U000F0F64"
|
||||
#define ICON_moon_waning_crescent "\U000F0F65"
|
||||
#define ICON_moon_waning_gibbous "\U000F0F66"
|
||||
#define ICON_moon_waxing_crescent "\U000F0F67"
|
||||
#define ICON_moon_waxing_gibbous "\U000F0F68"
|
||||
|
||||
std::string moonToIcon(std::string moonPhase)
|
||||
{
|
||||
if (moonPhase == "new_moon") return ICON_moon_new;
|
||||
if (moonPhase == "waxing_crescent") return ICON_moon_waxing_crescent;
|
||||
if (moonPhase == "first_quarter") return ICON_moon_first_quarter;
|
||||
if (moonPhase == "waxing_gibbous") return ICON_moon_waxing_gibbous;
|
||||
if (moonPhase == "full_moon") return ICON_moon_full;
|
||||
if (moonPhase == "waning_gibbous") return ICON_moon_waning_gibbous;
|
||||
if (moonPhase == "last_quarter") return ICON_moon_last_quarter;
|
||||
if (moonPhase == "waning_crescent") return ICON_moon_waning_crescent;
|
||||
return "";
|
||||
}
|
||||
|
||||
// Map weather states to MDI characters.
|
||||
std::map<std::string, std::string> weather_icon_map
|
||||
{
|
||||
{"cloudy", "\U000F0590"},
|
||||
{"cloudy-alert", "\U000F0F2F"},
|
||||
{"cloudy-arrow-right", "\U000F0E6E"},
|
||||
{"fog", "\U000F0591"},
|
||||
{"hail", "\U000F0592"},
|
||||
{"hazy", "\U000F0F30"},
|
||||
{"hurricane", "\U000F0898"},
|
||||
{"lightning", "\U000F0593"},
|
||||
{"lightning-rainy", "\U000F067E"},
|
||||
{"night", "\U000F0594"},
|
||||
{"night-partly-cloudy", "\U000F0F31"},
|
||||
{"partlycloudy", "\U000F0595"},
|
||||
{"partly-lightning", "\U000F0F32"},
|
||||
{"partly-rainy", "\U000F0F33"},
|
||||
{"partly-snowy", "\U000F0F34"},
|
||||
{"partly-snowy-rainy", "\U000F0F35"},
|
||||
{"pouring", "\U000F0596"},
|
||||
{"rainy", "\U000F0597"},
|
||||
{"snowy", "\U000F0598"},
|
||||
{"snowy-heavy", "\U000F0F36"},
|
||||
{"snowy-rainy", "\U000F067F"},
|
||||
{"sunny", "\U000F0599"},
|
||||
{"sunny-alert", "\U000F0F37"},
|
||||
{"sunny-off", "\U000F14E4"},
|
||||
{"sunset", "\U000F059A"},
|
||||
{"sunset-down", "\U000F059B"},
|
||||
{"sunset-up", "\U000F059C"},
|
||||
{"tornado", "\U000F0F38"},
|
||||
{"windy", "\U000F059D"},
|
||||
{"windy-variant", "\U000F059E"},
|
||||
{"car", "\U000f010b"},
|
||||
{"trash", "\U000F0819"},
|
||||
};
|
||||
std::map<std::string, std::string> moon_icon_map
|
||||
{
|
||||
{ "mdi:moon-waxing-crescent", "\U000f0f67" },
|
||||
{ "mdi:moon-first-quarter", "\U000F0F61" },
|
||||
{ "mdi:moon-waxing-gibbous", "\U000F0F68" },
|
||||
{ "mdi:moon-full", "\U000F0F62" },
|
||||
{ "mdi:moon-waning-gibbous", "\U000F0F66" },
|
||||
{ "mdi:moon-last-quarter", "\U000F0F63" },
|
||||
{ "mdi:moon-waning-crescent", "\U000F0F65" },
|
||||
};
|
||||
|
||||
|
||||
#define ICON_w_clear_night "\U000F0594"
|
||||
#define ICON_w_cloudy "\U000F0590"
|
||||
#define ICON_w_fog "\U000F0591"
|
||||
#define ICON_w_hail "\U000F0592"
|
||||
#define ICON_w_lightning "\U000F0593"
|
||||
#define ICON_w_lightning_rainy "\U000F067E"
|
||||
#define ICON_w_night_partly_cloudy "\U000F0F31"
|
||||
#define ICON_w_partly_cloudy "\U000F0595"
|
||||
#define ICON_w_pouring "\U000F0596"
|
||||
#define ICON_w_rainy "\U000F0597"
|
||||
#define ICON_w_snowy "\U000F0F36"
|
||||
#define ICON_w_snowy_rainy "\U000F067F"
|
||||
#define ICON_w_sunny "\U000F0599"
|
||||
#define ICON_w_windy "\U000F059D"
|
||||
#define ICON_w_windy_variant "\U000F059E"
|
||||
#define ICON_w_exceptional "\U000F0F38"
|
||||
|
||||
std::string conditionToIcon(std::string condition, bool daytime)
|
||||
{
|
||||
if (condition == "clear") return ICON_w_clear_night;
|
||||
if (condition == "clear-night") return ICON_w_clear_night;
|
||||
if (condition == "cloudy") return ICON_w_cloudy;
|
||||
if (condition == "dust") return ICON_w_fog;
|
||||
if (condition == "dusty") return ICON_w_fog;
|
||||
if (condition == "fog") return ICON_w_fog;
|
||||
if (condition == "frost") return ICON_w_snowy;
|
||||
if (condition == "hail") return ICON_w_hail;
|
||||
if (condition == "haze") return ICON_w_fog;
|
||||
if (condition == "hazy") return ICON_w_fog;
|
||||
if (condition == "heavy_shower") return ICON_w_rainy;
|
||||
if (condition == "heavy_showers") return ICON_w_rainy;
|
||||
if (condition == "light_rain") return ICON_w_rainy;
|
||||
if (condition == "light_showers") return ICON_w_rainy;
|
||||
if (condition == "light_shower") return ICON_w_rainy;
|
||||
if (condition == "lightning") return ICON_w_lightning;
|
||||
if (condition == "lightning-rainy") return ICON_w_lightning_rainy;
|
||||
if (condition == "mostly_sunny") return ICON_w_sunny;
|
||||
if (condition == "night") return ICON_w_clear_night;
|
||||
if (condition == "partlycloudy" && !daytime) return ICON_w_night_partly_cloudy;
|
||||
if (condition == "partlycloudy" && daytime) return ICON_w_partly_cloudy;
|
||||
if (condition == "partly_cloudy" && !daytime) return ICON_w_night_partly_cloudy;
|
||||
if (condition == "partly_cloudy" && daytime) return ICON_w_partly_cloudy;
|
||||
if (condition == "pouring") return ICON_w_pouring;
|
||||
if (condition == "rain") return ICON_w_rainy;
|
||||
if (condition == "rainy") return ICON_w_rainy;
|
||||
if (condition == "shower") return ICON_w_rainy;
|
||||
if (condition == "showers") return ICON_w_rainy;
|
||||
if (condition == "snow") return ICON_w_snowy;
|
||||
if (condition == "snowy") return ICON_w_snowy;
|
||||
if (condition == "snowy-rainy") return ICON_w_snowy_rainy;
|
||||
if (condition == "storm") return ICON_w_lightning_rainy;
|
||||
if (condition == "storms") return ICON_w_lightning_rainy;
|
||||
if (condition == "sunny") return ICON_w_sunny;
|
||||
if (condition == "wind") return ICON_w_windy;
|
||||
if (condition == "windy") return ICON_w_windy;
|
||||
if (condition == "windy-variant") return ICON_w_windy_variant;
|
||||
if (condition == "exceptional") return ICON_w_exceptional;
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
500
esphome/components/ehmtx/EHMTX.cpp
Normal file
@@ -0,0 +1,500 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
422
esphome/components/ehmtx/EHMTX.h
Normal file
@@ -0,0 +1,422 @@
|
||||
#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
|
||||
37
esphome/components/ehmtx/EHMTX_icons.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
121
esphome/components/ehmtx/EHMTX_screen.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#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;
|
||||
}
|
||||
}
|
||||
144
esphome/components/ehmtx/EHMTX_store.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
609
esphome/components/ehmtx/__init__.py
Normal file
@@ -0,0 +1,609 @@
|
||||
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> - ({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)
|
||||
BIN
esphome/components/ehmtx/__pycache__/__init__.cpython-39.pyc
Normal file
27
esphome/components/ehmtx/select/__init__.py
Normal file
@@ -0,0 +1,27 @@
|
||||
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=[])
|
||||
33
esphome/components/ehmtx/select/ehmtx_select.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#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
|
||||
22
esphome/components/ehmtx/select/ehmtx_select.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#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;
|
||||
};
|
||||
|
||||
}
|
||||
643
esphome/esp32-75epaper-keuken.yaml
Normal file
@@ -0,0 +1,643 @@
|
||||
substitutions:
|
||||
esp_name: "esp32-75epaper-keuken"
|
||||
|
||||
esphome:
|
||||
name: ${esp_name}
|
||||
comment: ${esp_name}
|
||||
includes:
|
||||
- common.h
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: arduino
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: git
|
||||
url: https://github.com/atomicmike/esphome.git
|
||||
ref: waveshare-color-2022.6
|
||||
components: [waveshare_epaper]
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: !secrets eink_display_api
|
||||
|
||||
ota:
|
||||
password: !secret ota_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: ${esp_name} fallback
|
||||
password: !secret fallback_password
|
||||
|
||||
|
||||
#Include sun
|
||||
sun:
|
||||
latitude: !secret home_latitude
|
||||
longitude: !secret home_longitude
|
||||
|
||||
globals:
|
||||
- id: data_updated
|
||||
type: bool
|
||||
restore_value: no
|
||||
initial_value: 'false'
|
||||
- id: initial_data_received
|
||||
type: bool
|
||||
restore_value: no
|
||||
initial_value: 'false'
|
||||
- id: recorded_display_refresh
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: '0'
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
id: esptime
|
||||
on_time_sync:
|
||||
- then:
|
||||
- component.update: sunrise
|
||||
- component.update: sunset
|
||||
- logger.log: Time has been set and is valid!
|
||||
on_time:
|
||||
- minutes: 5
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
lambda: 'return id(data_updated) == true;'
|
||||
then:
|
||||
- lambda: 'id(initial_data_received) = true;'
|
||||
- logger.log: "Sensor data updated: Refreshing display..."
|
||||
- component.update: eink_display
|
||||
- lambda: 'id(data_updated) = false;'
|
||||
- lambda: 'id(recorded_display_refresh) += 1;'
|
||||
- lambda: 'id(display_last_update).publish_state(id(esptime).now().timestamp);'
|
||||
else:
|
||||
- logger.log: "No sensors updated - skipping display refresh."
|
||||
|
||||
button:
|
||||
- platform: template
|
||||
name: "Refresh screen"
|
||||
id: refresh
|
||||
icon: "mdi:emoticon-outline"
|
||||
on_press:
|
||||
- logger.log: "Button pressed"
|
||||
- component.update: eink_display
|
||||
|
||||
# deep_sleep:
|
||||
# run_duration: 15s
|
||||
# sleep_duration: 1min
|
||||
|
||||
# Include custom fonts
|
||||
font:
|
||||
- file: 'fonts/GothamRnd-Book.ttf'
|
||||
id: font_small_book
|
||||
size: 18
|
||||
- file: 'fonts/GothamRnd-Bold.ttf'
|
||||
id: font_large_bold
|
||||
size: 108
|
||||
glyphs: ['-',' ', '°', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', 'a', 'n']
|
||||
- file: 'fonts/GothamRnd-Bold.ttf'
|
||||
id: font_medium_bold
|
||||
size: 30
|
||||
# glyphs: [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'M', 'I', 'N']
|
||||
- file: 'fonts/GothamRnd-Bold.ttf'
|
||||
id: font_small_bold
|
||||
size: 18
|
||||
# glyphs: ['°', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', 'M', 'I', 'N']
|
||||
|
||||
- file: 'fonts/GothamRnd-Bold.ttf'
|
||||
id: font_time
|
||||
size: 90
|
||||
glyphs: [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':']
|
||||
- file: 'fonts/GothamRnd-Book.ttf'
|
||||
id: font_weekday
|
||||
size: 30
|
||||
- file: 'fonts/GothamRnd-Book.ttf'
|
||||
id: font_day
|
||||
size: 65
|
||||
glyphs: [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
|
||||
- file: 'fonts/GothamRnd-Bold.ttf'
|
||||
id: font_month
|
||||
size: 40
|
||||
|
||||
- file: fonts/materialdesignicons-webfont.ttf
|
||||
id: font_wifi
|
||||
size: 20
|
||||
glyphs:
|
||||
- "\U000F091F"
|
||||
- "\U000F0922"
|
||||
- "\U000F0925"
|
||||
- "\U000F0928"
|
||||
- "\U000F092B"
|
||||
|
||||
# Include Material Design Icons font
|
||||
# Thanks to https://community.home-assistant.io/t/display-materialdesign-icons-on-esphome-attached-to-screen/199790/16
|
||||
- file: 'fonts/materialdesignicons-webfont.ttf'
|
||||
id: font_mdi_large
|
||||
size: 96
|
||||
glyphs: &mdi-weather-glyphs
|
||||
- "\U000F0590" # mdi-weather-cloudy
|
||||
- "\U000F0F2F" # mdi-weather-cloudy-alert
|
||||
- "\U000F0E6E" # mdi-weather-cloudy-arrow-right
|
||||
- "\U000F0591" # mdi-weather-fog
|
||||
- "\U000F0592" # mdi-weather-hail
|
||||
- "\U000F0F30" # mdi-weather-hazy
|
||||
- "\U000F0898" # mdi-weather-hurricane
|
||||
- "\U000F0593" # mdi-weather-lightning
|
||||
- "\U000F067E" # mdi-weather-lightning-rainy
|
||||
- "\U000F0594" # mdi-weather-night
|
||||
- "\U000F0F31" # mdi-weather-night-partly-cloudy
|
||||
- "\U000F0595" # mdi-weather-partly-cloudy
|
||||
- "\U000F0F32" # mdi-weather-partly-lightning
|
||||
- "\U000F0F33" # mdi-weather-partly-rainy
|
||||
- "\U000F0F34" # mdi-weather-partly-snowy
|
||||
- "\U000F0F35" # mdi-weather-partly-snowy-rainy
|
||||
- "\U000F0596" # mdi-weather-pouring
|
||||
- "\U000F0597" # mdi-weather-rainy
|
||||
- "\U000F0598" # mdi-weather-snowy
|
||||
- "\U000F0F36" # mdi-weather-snowy-heavy
|
||||
- "\U000F067F" # mdi-weather-snowy-rainy
|
||||
- "\U000F0599" # mdi-weather-sunny
|
||||
- "\U000F0F37" # mdi-weather-sunny-alert
|
||||
- "\U000F14E4" # mdi-weather-sunny-off
|
||||
- "\U000F059A" # mdi-weather-sunset
|
||||
- "\U000F059B" # mdi-weather-sunset-down
|
||||
- "\U000F059C" # mdi-weather-sunset-up
|
||||
- "\U000F0F38" # mdi-weather-tornado
|
||||
- "\U000F059D" # mdi-weather-windy
|
||||
- "\U000F059E" # mdi-weather-windy-variant
|
||||
- "\U000f010b" # mdi-car
|
||||
- "\U000f0819" # trash
|
||||
|
||||
- file: 'fonts/materialdesignicons-webfont.ttf'
|
||||
id: font_mdi_medlarge
|
||||
size: 60
|
||||
glyphs:
|
||||
- "\U000f0f64" # new moon
|
||||
- "\U000f0f67" # mdi-moon-waxing-crescent
|
||||
- "\U000F0F61" # mdi-moon-first-quarter
|
||||
- "\U000F0F68" # mdi-moon-waxing-gibbous
|
||||
- "\U000F0F62" # mdi-moon-full
|
||||
- "\U000F0F66" # mdi-moon-waning-gibbous
|
||||
- "\U000F0F63" # mdi-moon-last-quarter
|
||||
- "\U000F0F65" # mdi-moon-waning-crescent
|
||||
- file: 'fonts/materialdesignicons-webfont.ttf'
|
||||
id: font_mdi_medium
|
||||
size: 36
|
||||
glyphs: *mdi-weather-glyphs
|
||||
|
||||
|
||||
sensor:
|
||||
- platform: template
|
||||
name: "${esp_name} Last Update"
|
||||
device_class: timestamp
|
||||
id: display_last_update
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: weather.forecast_home
|
||||
attribute: temperature
|
||||
id: weather_temperature
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_temperature_0
|
||||
id: weather_temperature_0
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_temperature_1
|
||||
id: weather_temperature_1
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_temperature_2
|
||||
id: weather_temperature_2
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_temperature_3
|
||||
id: weather_temperature_3
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: travel_Best_time
|
||||
id: travel_Best_time
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: travel_ASML_time
|
||||
id: travel_ASML_time
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: travel_GGD_time
|
||||
id: travel_GGD_time
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: wifi_signal
|
||||
id: sensor_wifi_signal
|
||||
name: "${esp_name} WiFi"
|
||||
update_interval: 60s
|
||||
on_value:
|
||||
- component.update: sensor_wifi_signal_percentage
|
||||
|
||||
- platform: template
|
||||
id: sensor_wifi_signal_percentage
|
||||
name: "${esp_name} Wi-Fi Signal Percentage"
|
||||
icon: "mdi:wifi"
|
||||
unit_of_measurement: "%"
|
||||
update_interval: never
|
||||
lambda: |-
|
||||
if (id(sensor_wifi_signal).state) {
|
||||
if (id(sensor_wifi_signal).state <= -100 ) {
|
||||
return 0;
|
||||
} else if (id(sensor_wifi_signal).state >= -50) {
|
||||
return 100;
|
||||
} else {
|
||||
return 2 * (id(sensor_wifi_signal).state + 100);
|
||||
}
|
||||
} else {
|
||||
return NAN;
|
||||
}
|
||||
|
||||
- platform: template
|
||||
name: "${esp_name} Recorded Display Refresh"
|
||||
lambda: 'return id(recorded_display_refresh);'
|
||||
unit_of_measurement: "refreshes"
|
||||
|
||||
text_sensor:
|
||||
- platform: homeassistant
|
||||
entity_id: weather.forecast_home
|
||||
id: weather_state
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_condition_now
|
||||
id: weather_condition_now
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_condition_0
|
||||
id: weather_condition_0
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_timestamp_0
|
||||
id: weather_timestamp_0
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_condition_1
|
||||
id: weather_condition_1
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_timestamp_1
|
||||
id: weather_timestamp_1
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_condition_2
|
||||
id: weather_condition_2
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_timestamp_2
|
||||
id: weather_timestamp_2
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_condition_3
|
||||
id: weather_condition_3
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: weather_timestamp_3
|
||||
id: weather_timestamp_3
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: afval_today
|
||||
id: afval_today
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: afval_tomorrow
|
||||
id: afval_tomorrow
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: travel_Best_name
|
||||
id: travel_Best_name
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: travel_ASML_name
|
||||
id: travel_ASML_name
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.e_ink_display_data
|
||||
attribute: travel_GGD_name
|
||||
id: travel_GGD_name
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.moon_phase
|
||||
#attribute: icon
|
||||
id: moon_phase
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: homeassistant
|
||||
entity_id: sensor.moon
|
||||
id: moon
|
||||
internal: true
|
||||
|
||||
# Sunrise
|
||||
- platform: sun
|
||||
type: sunrise
|
||||
id: sun_sunrise
|
||||
format: "%H:%M"
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
# Sunset
|
||||
- platform: sun
|
||||
type: sunset
|
||||
id: sun_sunset
|
||||
format: "%H:%M"
|
||||
on_value:
|
||||
then:
|
||||
- lambda: 'id(data_updated) = true;'
|
||||
|
||||
- platform: wifi_info
|
||||
ssid:
|
||||
name: "${esp_name} Connected SSID"
|
||||
id: ssid
|
||||
icon: mdi:wifi-strength-2
|
||||
entity_category: diagnostic
|
||||
|
||||
bssid:
|
||||
name: "${esp_name} Connected BSSID"
|
||||
id: bssid
|
||||
icon: mdi:wifi-strength-2
|
||||
entity_category: diagnostic
|
||||
|
||||
mac_address:
|
||||
name: "${esp_name} WiFi Mac Address"
|
||||
id: macaddress
|
||||
icon: mdi:wifi-strength-2
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: sun
|
||||
id: sunrise
|
||||
name: Sun Next Sunrise
|
||||
type: sunrise
|
||||
format: "%H:%M"
|
||||
internal: true
|
||||
update_interval: never
|
||||
|
||||
- platform: sun
|
||||
id: sunset
|
||||
name: Sun Next Sunset
|
||||
type: sunset
|
||||
format: "%H:%M"
|
||||
internal: true
|
||||
update_interval: never
|
||||
|
||||
# Define colors
|
||||
# This design is white on black so this is necessary.
|
||||
color:
|
||||
- id: color_black
|
||||
red: 0%
|
||||
green: 0%
|
||||
blue: 0%
|
||||
white: 50%
|
||||
- id: color_white
|
||||
red: 0%
|
||||
green: 0%
|
||||
blue: 0%
|
||||
white: 0%
|
||||
- id: COLOR_RED
|
||||
red: 100%
|
||||
green: 0%
|
||||
blue: 0%
|
||||
white: 0%
|
||||
|
||||
|
||||
# Pins for Waveshare ePaper ESP Board
|
||||
spi:
|
||||
clk_pin: GPIO13
|
||||
mosi_pin: GPIO14
|
||||
|
||||
|
||||
# Now render everything on the ePaper screen.
|
||||
display:
|
||||
- platform: waveshare_epaper
|
||||
cs_pin: GPIO27
|
||||
dc_pin: GPIO16
|
||||
busy_pin: GPIO25
|
||||
reset_pin: GPIO26
|
||||
#model: 7.50in-bV2
|
||||
model: 7.50inv2b
|
||||
#model: 7.50inv2
|
||||
#model: 7.50inV2alt
|
||||
update_interval: 1h
|
||||
id: eink_display
|
||||
rotation: 90°
|
||||
lambda: |-
|
||||
int xres = it.get_width();
|
||||
int yres = it.get_height();
|
||||
|
||||
#define x_pad 10 // border padding
|
||||
#define y_pad 10 // border padding
|
||||
|
||||
int wifi_x_a = xres-x_pad;
|
||||
int wifi_y_a = yres-y_pad+2;
|
||||
|
||||
|
||||
|
||||
// Fill background in black.
|
||||
it.fill(COLOR_OFF);
|
||||
|
||||
// wifi strength
|
||||
// if (id(sensor_wifi_signal).has_state())
|
||||
// {
|
||||
if (id(sensor_wifi_signal).state >= -50) {
|
||||
//Excellent
|
||||
it.print(wifi_x_a, wifi_y_a, id(font_wifi), TextAlign::BASELINE_RIGHT, "");
|
||||
ESP_LOGI("WiFi", "Excellent");
|
||||
} else if (id(sensor_wifi_signal).state >= -60) {
|
||||
//Good
|
||||
it.print(wifi_x_a, wifi_y_a, id(font_wifi), TextAlign::BASELINE_RIGHT, "");
|
||||
ESP_LOGI("WiFi", "Good");
|
||||
} else if (id(sensor_wifi_signal).state >= -67) {
|
||||
//Fair
|
||||
it.print(wifi_x_a, wifi_y_a, id(font_wifi), TextAlign::BASELINE_RIGHT, "");
|
||||
ESP_LOGI("WiFi", "Fair");
|
||||
} else if (id(sensor_wifi_signal).state >= -70) {
|
||||
//Weak
|
||||
it.print(wifi_x_a, wifi_y_a, id(font_wifi), TextAlign::BASELINE_RIGHT, "");
|
||||
ESP_LOGI("WiFi", "Weak");
|
||||
} else {
|
||||
//Unlikely working signal
|
||||
it.print(wifi_x_a, wifi_y_a, id(font_wifi), TextAlign::BASELINE_RIGHT, "");
|
||||
ESP_LOGI("WiFi", "Unlikely");
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
// clock section
|
||||
int clk_yoffset = 50;
|
||||
int clk_xoffset = 310;
|
||||
// Print full weekday name
|
||||
it.strftime(clk_xoffset, clk_yoffset, id(font_weekday), TextAlign::TOP_RIGHT, "%A", id(esptime).now());
|
||||
|
||||
// Print time in HH:MM format 335
|
||||
it.strftime(clk_xoffset, clk_yoffset+105, id(font_time), TextAlign::BASELINE_RIGHT, "%H:%M", id(esptime).now());
|
||||
|
||||
// Print day of the month
|
||||
it.strftime(clk_xoffset+100, clk_yoffset, id(font_day), TextAlign::TOP_RIGHT, "%d", id(esptime).now());
|
||||
// Print abbreviated month name
|
||||
it.strftime(clk_xoffset+100, clk_yoffset+105, id(font_month), TextAlign::BASELINE_RIGHT, "%b", id(esptime).now());
|
||||
|
||||
int sry_offset = 200; //sunrise/set y-offset
|
||||
// Print sunrise
|
||||
it.printf(60, sry_offset, id(font_mdi_medium), COLOR_RED, TextAlign::CENTER_RIGHT, "\U000F059C");
|
||||
if(id(sun_sunrise).has_state ()) {
|
||||
it.printf(65, sry_offset, id(font_small_bold), TextAlign::CENTER_LEFT, "%s", id(sun_sunrise).state.c_str());
|
||||
}
|
||||
// Print sunset
|
||||
it.printf(425, sry_offset, id(font_mdi_medium), COLOR_RED, TextAlign::CENTER_RIGHT, "\U000F059B");
|
||||
if(id(sun_sunset).has_state ()) {
|
||||
it.printf(385, sry_offset, id(font_small_bold), TextAlign::CENTER_RIGHT, "%s", id(sun_sunset).state.c_str());
|
||||
}
|
||||
// Moonphae
|
||||
//it.printf(265, sry_offset, id(font_mdi_medlarge), TextAlign::CENTER, "%s", moon_icon_map[id(moon_phase).state.c_str()].c_str());
|
||||
|
||||
it.line(30, sry_offset+30, 420, sry_offset+30);
|
||||
|
||||
|
||||
// Weather Section
|
||||
int wy_offset = sry_offset + 60; //weather y offset
|
||||
// WEATHER STATE ICON
|
||||
it.printf(80, wy_offset, id(font_mdi_large), COLOR_RED, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_now).state.c_str()].c_str());
|
||||
// TEMPERATURE
|
||||
it.printf(410, wy_offset, id(font_large_bold), TextAlign::TOP_RIGHT, "%2.0f°C", id(weather_temperature).state);
|
||||
|
||||
int forecast_yoffset = wy_offset+30+108;
|
||||
int fcst_xstart = 90;
|
||||
int fcst_offset = 90;
|
||||
it.printf(fcst_xstart, forecast_yoffset, id(font_small_bold), TextAlign::TOP_CENTER, "%s", id(weather_timestamp_0).state.c_str());
|
||||
it.printf(fcst_xstart, forecast_yoffset+20, id(font_mdi_medium), COLOR_RED, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_0).state.c_str()].c_str());
|
||||
it.printf(fcst_xstart, forecast_yoffset+72, id(font_small_bold), TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_0).state);
|
||||
|
||||
fcst_xstart += fcst_offset;
|
||||
it.printf(fcst_xstart, forecast_yoffset, id(font_small_bold), TextAlign::TOP_CENTER, "%s", id(weather_timestamp_1).state.c_str());
|
||||
it.printf(fcst_xstart, forecast_yoffset+20, id(font_mdi_medium), COLOR_RED, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_1).state.c_str()].c_str());
|
||||
it.printf(fcst_xstart, forecast_yoffset+72, id(font_small_bold), TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_1).state);
|
||||
|
||||
fcst_xstart += fcst_offset;
|
||||
it.printf(fcst_xstart, forecast_yoffset, id(font_small_bold), TextAlign::TOP_CENTER, "%s", id(weather_timestamp_2).state.c_str());
|
||||
it.printf(fcst_xstart, forecast_yoffset+20, id(font_mdi_medium), COLOR_RED, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_2).state.c_str()].c_str());
|
||||
it.printf(fcst_xstart, forecast_yoffset+72, id(font_small_bold), TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_2).state);
|
||||
|
||||
fcst_xstart += fcst_offset;
|
||||
it.printf(fcst_xstart, forecast_yoffset, id(font_small_bold), TextAlign::TOP_CENTER, "%s", id(weather_timestamp_3).state.c_str());
|
||||
it.printf(fcst_xstart, forecast_yoffset+20, id(font_mdi_medium), COLOR_RED, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_3).state.c_str()].c_str());
|
||||
it.printf(fcst_xstart, forecast_yoffset+72, id(font_small_bold), TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_3).state);
|
||||
|
||||
it.line(30, forecast_yoffset+102, 420, forecast_yoffset+102);
|
||||
|
||||
int drvtime_yoffset = forecast_yoffset+132;
|
||||
int drvtime_xoffset = 40;
|
||||
it.printf(drvtime_xoffset, drvtime_yoffset, id(font_mdi_medium), COLOR_RED, TextAlign::TOP_CENTER, "%s", weather_icon_map["car"].c_str());
|
||||
|
||||
it.printf(drvtime_xoffset+90, drvtime_yoffset, id(font_small_bold), TextAlign::TOP_CENTER, "%s", id(travel_Best_name).state.c_str());
|
||||
it.printf(drvtime_xoffset+90, drvtime_yoffset+30, id(font_small_bold), TextAlign::TOP_CENTER, "%2.0f min", id(travel_Best_time).state);
|
||||
|
||||
it.printf(drvtime_xoffset+210, drvtime_yoffset, id(font_small_bold), TextAlign::TOP_CENTER, "%s", id(travel_ASML_name).state.c_str());
|
||||
it.printf(drvtime_xoffset+210, drvtime_yoffset+30, id(font_small_bold), TextAlign::TOP_CENTER, "%2.0f min", id(travel_ASML_time).state);
|
||||
|
||||
it.printf(drvtime_xoffset+330, drvtime_yoffset, id(font_small_bold), TextAlign::TOP_CENTER, "%s", id(travel_GGD_name).state.c_str());
|
||||
it.printf(drvtime_xoffset+330, drvtime_yoffset+30, id(font_small_bold), TextAlign::TOP_CENTER, "%2.0f min", id(travel_GGD_time).state);
|
||||
|
||||
it.line(30, drvtime_yoffset+60, 420, drvtime_yoffset+60);
|
||||
|
||||
int waste_yoffset = drvtime_yoffset+90;
|
||||
int waste_xoffset = 60;
|
||||
it.printf(waste_xoffset, waste_yoffset, id(font_mdi_medium), COLOR_RED, TextAlign::TOP_CENTER, "%s", weather_icon_map["trash"].c_str());
|
||||
|
||||
it.printf(waste_xoffset+100, waste_yoffset, id(font_small_bold), TextAlign::TOP_CENTER, "Vandaag:");
|
||||
it.printf(waste_xoffset+260, waste_yoffset, id(font_small_bold), TextAlign::TOP_CENTER, "Morgen:");
|
||||
it.printf(waste_xoffset+95, waste_yoffset+30, id(font_small_bold), TextAlign::TOP_CENTER, "%s", id(afval_today).state.c_str());
|
||||
it.printf(waste_xoffset+255, waste_yoffset+30, id(font_small_bold), TextAlign::TOP_CENTER, "%s", id(afval_tomorrow).state.c_str());
|
||||
|
||||
// it.line(30, 400, 440, 400);
|
||||
|
||||
// it.printf(30, 520, id(font_mdi_medium), color_white, TextAlign::TOP_CENTER, "%s", moon_icon_map[id(moon_phace_icon).state.c_str()].c_str());
|
||||
|
||||
|
||||
|
||||
captive_portal:
|
||||
|
||||
90
esphome/esp32-aqs1.yaml
Normal file
@@ -0,0 +1,90 @@
|
||||
substitutions:
|
||||
esp_name: "esp32-aqs1"
|
||||
|
||||
esphome:
|
||||
name: ${esp_name}
|
||||
comment: ${esp_name}
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: arduino
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: !secret air_quality_woonkamer_api
|
||||
|
||||
ota:
|
||||
password: !secret aqs1_ota_passwoord
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: ${esp_name} fallback
|
||||
password: !secret fallback_password
|
||||
|
||||
captive_portal:
|
||||
|
||||
esp32_ble_tracker:
|
||||
|
||||
bluetooth_proxy:
|
||||
|
||||
# Example configuration entry
|
||||
uart:
|
||||
rx_pin: GPIO19
|
||||
tx_pin: GPIO26
|
||||
baud_rate: 9600
|
||||
|
||||
i2c:
|
||||
sda: 21
|
||||
scl: 22
|
||||
scan: true
|
||||
id: bus_a
|
||||
|
||||
# spi:
|
||||
# clk_pin: GPIO18
|
||||
# mosi_pin: GPIO23
|
||||
# miso_pin: GPIO12
|
||||
|
||||
sensor:
|
||||
- platform: pmsx003
|
||||
type: PMSX003
|
||||
pm_1_0:
|
||||
name: "Particulate Matter <1.0µm Concentration"
|
||||
pm_2_5:
|
||||
name: "Particulate Matter <2.5µm Concentration"
|
||||
pm_10_0:
|
||||
name: "Particulate Matter <10.0µm Concentration"
|
||||
update_interval: 60000ms
|
||||
|
||||
- platform: scd30
|
||||
co2:
|
||||
name: "Woonkamer CO2"
|
||||
accuracy_decimals: 1
|
||||
temperature:
|
||||
name: "Woonkamer Temperature"
|
||||
accuracy_decimals: 2
|
||||
humidity:
|
||||
name: "Woonkamer Humidity"
|
||||
accuracy_decimals: 1
|
||||
temperature_offset: 1.5 °C
|
||||
address: 0x61
|
||||
update_interval: 5s
|
||||
|
||||
- platform: sgp30
|
||||
eco2:
|
||||
name: "Woonkamer eCO2"
|
||||
accuracy_decimals: 1
|
||||
tvoc:
|
||||
name: "Woonkamer TVOC"
|
||||
accuracy_decimals: 1
|
||||
store_baseline: yes
|
||||
address: 0x58
|
||||
update_interval: 1s
|
||||
67
esphome/esp32-m5-bt-proxy.yaml
Normal file
@@ -0,0 +1,67 @@
|
||||
substitutions:
|
||||
esp_name: "esp32-m5-bt-proxy"
|
||||
|
||||
esphome:
|
||||
name: ${esp_name}
|
||||
comment: ${esp_name}
|
||||
|
||||
esp32:
|
||||
board: m5stack-atom
|
||||
framework:
|
||||
type: arduino
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: !secret moon_light_api
|
||||
|
||||
ota:
|
||||
password: !secret moon_ota_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: ${esp_name} fallback
|
||||
password: !secret fallback_password
|
||||
|
||||
# captive_portal:
|
||||
|
||||
media_player:
|
||||
- platform: i2s_audio
|
||||
id: media_out
|
||||
name: moon_sound
|
||||
dac_type: external
|
||||
i2s_lrclk_pin: GPIO33
|
||||
i2s_dout_pin: GPIO22
|
||||
i2s_bclk_pin: GPIO19
|
||||
mode: mono
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
pin:
|
||||
number: GPIO39
|
||||
inverted: true
|
||||
name: Moon_Button
|
||||
|
||||
light:
|
||||
- platform: fastled_clockless
|
||||
chipset: ws2812b
|
||||
pin: GPIO25
|
||||
num_leds: 1
|
||||
rgb_order: GRB
|
||||
name: "Moon_Light"
|
||||
effects:
|
||||
- random:
|
||||
name: "Random"
|
||||
transition_length: 4s
|
||||
update_interval: 5s
|
||||
- addressable_rainbow:
|
||||
name: Rainbow Effect
|
||||
speed: 10
|
||||
width: 50
|
||||
178
esphome/esp32-matrix.yaml
Normal file
@@ -0,0 +1,178 @@
|
||||
substitutions:
|
||||
devicename: esp32-matrix
|
||||
mypin: GPIO14
|
||||
board: esp32dev
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: git
|
||||
url: https://github.com/lubeda/EsphoMaTrix
|
||||
|
||||
esphome:
|
||||
name: $devicename
|
||||
|
||||
esp32:
|
||||
board: $board
|
||||
|
||||
binary_sensor:
|
||||
- platform: status
|
||||
name: "$devicename Status"
|
||||
|
||||
font:
|
||||
- file: fonts/monobit.ttf
|
||||
id: ehmtx_font
|
||||
size: 16
|
||||
glyphs: |
|
||||
!?"%()+*=,-_.:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz€@<>/
|
||||
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
api:
|
||||
encryption:
|
||||
key: !secret matrix_led_api
|
||||
|
||||
services:
|
||||
- service: alarm
|
||||
variables:
|
||||
icon_name: string
|
||||
text: string
|
||||
then:
|
||||
lambda: |-
|
||||
id(rgb8x32)->add_screen(icon_name, text, 7, true);
|
||||
id(rgb8x32)->force_screen(icon_name);
|
||||
- service: screen
|
||||
variables:
|
||||
icon_name: string
|
||||
text: string
|
||||
then:
|
||||
lambda: |-
|
||||
id(rgb8x32)->add_screen(icon_name, text, 5, false);
|
||||
- service: brightness
|
||||
variables:
|
||||
brightness: int
|
||||
then:
|
||||
lambda: |-
|
||||
id(rgb8x32)->set_brightness(brightness);
|
||||
- service: status
|
||||
then:
|
||||
lambda: |-
|
||||
id(rgb8x32)->get_status();
|
||||
- service: del_screen
|
||||
variables:
|
||||
icon_name: string
|
||||
then:
|
||||
lambda: |-
|
||||
id(rgb8x32)->del_screen(icon_name);
|
||||
- service: indicator_on
|
||||
variables:
|
||||
r: int
|
||||
g: int
|
||||
b: int
|
||||
then:
|
||||
lambda: |-
|
||||
id(rgb8x32)->set_indicator_color(r,g,b);
|
||||
id(rgb8x32)->set_indicator_on();
|
||||
- service: text_color
|
||||
variables:
|
||||
r: int
|
||||
g: int
|
||||
b: int
|
||||
then:
|
||||
lambda: |-
|
||||
id(rgb8x32)->set_text_color(r,g,b);
|
||||
- service: alarm_color
|
||||
variables:
|
||||
r: int
|
||||
g: int
|
||||
b: int
|
||||
then:
|
||||
lambda: |-
|
||||
id(rgb8x32)->set_alarm_color(r,g,b);
|
||||
- service: indicator_off
|
||||
then:
|
||||
lambda: |-
|
||||
id(rgb8x32)->set_indicator_off();
|
||||
|
||||
ota:
|
||||
password: !secret ota_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: $devicename
|
||||
password: "InM2TlqVfJe4"
|
||||
|
||||
|
||||
light:
|
||||
- platform: neopixelbus
|
||||
id: ehmtx_light
|
||||
type: GRB
|
||||
variant: WS2812
|
||||
pin: $mypin
|
||||
num_leds: 256
|
||||
color_correct: [30%, 30%, 30%]
|
||||
name: "$devicename Light"
|
||||
restore_mode: ALWAYS_OFF
|
||||
on_turn_on:
|
||||
lambda: |-
|
||||
id(ehmtx_display)->set_enabled(false);
|
||||
on_turn_off:
|
||||
lambda: |-
|
||||
id(ehmtx_display)->set_enabled(true);
|
||||
|
||||
number:
|
||||
- platform: template
|
||||
name: "LED brightness"
|
||||
min_value: 0
|
||||
max_value: 255
|
||||
step: 1
|
||||
lambda: |-
|
||||
return id(rgb8x32)->get_brightness();
|
||||
set_action:
|
||||
lambda: |-
|
||||
id(rgb8x32)->set_brightness(x);
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
id: ehmtx_time
|
||||
|
||||
display:
|
||||
- platform: addressable_light
|
||||
id: ehmtx_display
|
||||
addressable_light_id: ehmtx_light
|
||||
width: 32
|
||||
height: 8
|
||||
pixel_mapper: |-
|
||||
if (x % 2 == 0) {
|
||||
return (x * 8) + y;
|
||||
}
|
||||
return (x * 8) + (7 - y);
|
||||
rotation: 0°
|
||||
update_interval: 16ms
|
||||
auto_clear_enabled: true
|
||||
lambda: |-
|
||||
id(rgb8x32)->tick();
|
||||
id(rgb8x32)->draw();
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
|
||||
ehmtx:
|
||||
id: rgb8x32
|
||||
show_clock: 4
|
||||
show_screen: 6
|
||||
display8x32: ehmtx_display
|
||||
time: ehmtx_time
|
||||
duration: 7
|
||||
font_id: ehmtx_font
|
||||
on_next_screen:
|
||||
lambda: |-
|
||||
ESP_LOGD("Trigger","Ole it works");
|
||||
icons:
|
||||
- file: icons/1350.gif
|
||||
id: boot
|
||||
41
esphome/esp32-s2-aqs-ikea.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
substitutions:
|
||||
esp_name: "esp32-s2-aqs-ikea"
|
||||
|
||||
esphome:
|
||||
name: ${esp_name}
|
||||
comment: ${esp_name}
|
||||
|
||||
esp32:
|
||||
board: esp32-s2-saola-1
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: !secret air_quality_zolder_api
|
||||
|
||||
ota:
|
||||
password: !secret aqs2_ota_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot in case wifi connection fails
|
||||
ap:
|
||||
ssid: ${esp_name} fallback
|
||||
password: !secret fallback_password
|
||||
|
||||
|
||||
uart:
|
||||
rx_pin: GPIO18
|
||||
baud_rate: 9600
|
||||
|
||||
sensor:
|
||||
- platform: pm1006
|
||||
pm_2_5:
|
||||
name: "Zolder Particulate Matter 2.5µm Concentration"
|
||||
69
esphome/esp8266-p1-meter.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
esphome:
|
||||
name: esp8266-p1-meter
|
||||
|
||||
esp8266:
|
||||
board: esp01_1m
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
baud_rate: 0
|
||||
level: DEBUG
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: "rl7h1lxgaeutnmINJ2mJ3WOWtzUX1AfebHnidDJJdXA="
|
||||
|
||||
ota:
|
||||
password: "122afb0ac402638f10972a8d97256f6f"
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: "Esp8266-P1-Meter"
|
||||
password: "pKpA1k7rR6K9"
|
||||
|
||||
captive_portal:
|
||||
|
||||
font:
|
||||
# gfonts://family[@weight]
|
||||
- file: "gfonts://Roboto"
|
||||
id: roboto
|
||||
size: 20
|
||||
|
||||
uart:
|
||||
rx_pin: GPIO13
|
||||
baud_rate: 115200
|
||||
rx_buffer_size: 1700
|
||||
|
||||
status_led:
|
||||
pin: GPIO2
|
||||
|
||||
dsmr:
|
||||
|
||||
sensor:
|
||||
- platform: dsmr
|
||||
energy_delivered_tariff1:
|
||||
name: Energy Consumed Tariff 1
|
||||
|
||||
text_sensor:
|
||||
- platform: dsmr
|
||||
identification:
|
||||
name: "DSMR Identification"
|
||||
p1_version:
|
||||
name: "DSMR Version"
|
||||
|
||||
# Example configuration entry
|
||||
i2c:
|
||||
sda: 4
|
||||
scl: 5
|
||||
|
||||
display:
|
||||
- platform: ssd1306_i2c
|
||||
model: "SSD1306 128x64"
|
||||
address: 0x3C
|
||||
lambda: |-
|
||||
it.print(0, 0, id(roboto), "Hello World!");
|
||||
BIN
esphome/fonts/Arial-Black.ttf
Executable file
BIN
esphome/fonts/BebasNeue-Regular.ttf
Executable file
BIN
esphome/fonts/DejaVuSans-Bold.ttf
Normal file
BIN
esphome/fonts/DejaVuSans.ttf
Normal file
BIN
esphome/fonts/GothamRnd-Bold.ttf
Executable file
BIN
esphome/fonts/GothamRnd-Book.ttf
Executable file
BIN
esphome/fonts/Roboto-Black.ttf
Executable file
BIN
esphome/fonts/Roboto-BlackItalic.ttf
Executable file
BIN
esphome/fonts/Roboto-Bold.ttf
Executable file
BIN
esphome/fonts/Roboto-BoldItalic.ttf
Executable file
BIN
esphome/fonts/Roboto-Italic.ttf
Executable file
BIN
esphome/fonts/Roboto-Light.ttf
Executable file
BIN
esphome/fonts/Roboto-LightItalic.ttf
Executable file
BIN
esphome/fonts/Roboto-Medium.ttf
Executable file
BIN
esphome/fonts/Roboto-MediumItalic.ttf
Executable file
BIN
esphome/fonts/Roboto-Regular.ttf
Executable file
BIN
esphome/fonts/Roboto-Thin.ttf
Executable file
BIN
esphome/fonts/Roboto-ThinItalic.ttf
Executable file
BIN
esphome/fonts/materialdesignicons-webfont.ttf
Executable file
BIN
esphome/fonts/monobit.ttf
Normal file
BIN
esphome/fonts/slkscr.ttf
Executable file
92
esphome/hvac-ir-sensor-display.yaml
Normal file
@@ -0,0 +1,92 @@
|
||||
substitutions:
|
||||
esp_name: "hvac-ir-sensor-display"
|
||||
|
||||
esphome:
|
||||
name: ${esp_name}
|
||||
comment: ${esp_name}
|
||||
|
||||
esp8266:
|
||||
board: nodemcuv2
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
baud_rate: 0
|
||||
|
||||
uart:
|
||||
rx_pin: GPIO3
|
||||
tx_pin: GPIO1
|
||||
baud_rate: 9600
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: !secret hvac_woonkamer_api
|
||||
|
||||
ota:
|
||||
password: !secret hvac_woonkamer_ota
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: ${esp_name} fallback
|
||||
password: !secret fallback_password
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
id: homeassistant_time
|
||||
|
||||
remote_transmitter:
|
||||
pin: GPIO14
|
||||
carrier_duty_percent: 50%
|
||||
|
||||
status_led:
|
||||
pin: GPIO4
|
||||
|
||||
remote_receiver:
|
||||
id: rcvr
|
||||
pin:
|
||||
number: GPIO5
|
||||
inverted: true
|
||||
# mode:
|
||||
# input: true
|
||||
# pullup: true
|
||||
tolerance: 55%
|
||||
dump: all
|
||||
|
||||
climate:
|
||||
- platform: fujitsu_general
|
||||
name: "Airco Woonkamer"
|
||||
receiver_id: rcvr
|
||||
# visual:
|
||||
# min_temperature: 18
|
||||
# max_temperature: 25
|
||||
# temperature_Step: 1
|
||||
|
||||
tuya:
|
||||
status_pin: GPIO16
|
||||
time_id: homeassistant_time
|
||||
|
||||
sensor:
|
||||
- platform: "tuya"
|
||||
name: "Temperature"
|
||||
sensor_datapoint: 101
|
||||
unit_of_measurement: "°C"
|
||||
device_class: "temperature"
|
||||
state_class: "measurement"
|
||||
filters:
|
||||
- multiply: 0.1
|
||||
accuracy_decimals: 1
|
||||
|
||||
- platform: "tuya"
|
||||
name: "humidity"
|
||||
sensor_datapoint: 102
|
||||
unit_of_measurement: "%rh"
|
||||
device_class: "humidity"
|
||||
state_class: "measurement"
|
||||
accuracy_decimals: 1
|
||||
|
||||
|
||||
|
||||
75
esphome/hvac-ir-slaapkamer.yaml
Normal file
@@ -0,0 +1,75 @@
|
||||
substitutions:
|
||||
esp_name: "hvac-ir-slaapkamer"
|
||||
|
||||
esphome:
|
||||
name: ${esp_name}
|
||||
|
||||
esp8266:
|
||||
board: nodemcuv2
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: !secret hvac_slaapkamer_api
|
||||
|
||||
ota:
|
||||
password: !secret hvac_slaapkamer_ota
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: ${esp_name} fallback
|
||||
password: !secret fallback_password
|
||||
|
||||
i2c:
|
||||
- id: bus_a
|
||||
sda: GPIO4
|
||||
scl: GPIO0
|
||||
scan: false
|
||||
|
||||
remote_transmitter:
|
||||
pin: GPIO14
|
||||
carrier_duty_percent: 50%
|
||||
|
||||
#status_led:
|
||||
# pin: GPIO2
|
||||
|
||||
remote_receiver:
|
||||
id: rcvr
|
||||
pin:
|
||||
number: GPIO5
|
||||
inverted: true
|
||||
# mode:
|
||||
# input: true
|
||||
# pullup: true
|
||||
tolerance: 55%
|
||||
dump: all
|
||||
|
||||
sensor:
|
||||
- platform: sht3xd
|
||||
temperature:
|
||||
name: "Temperatuur slaapkamer (airco)"
|
||||
id: sht_temp
|
||||
humidity:
|
||||
name: "Humidity slaapkamer (airco)"
|
||||
address: 0x44
|
||||
update_interval: 60s
|
||||
|
||||
climate:
|
||||
- platform: fujitsu_general
|
||||
name: "Airco Slaapkamer"
|
||||
receiver_id: rcvr
|
||||
sensor: sht_temp
|
||||
# visual:
|
||||
# min_temperature: 18
|
||||
# max_temperature: 25
|
||||
# temperature_Step: 1
|
||||
|
||||
|
||||
|
||||
BIN
esphome/icons/1350.gif
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
esphome/images/0-default.png
Executable file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
esphome/images/1-clear-night.png
Executable file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
esphome/images/10-snowy.png
Executable file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
esphome/images/11-snowy-rainy.png
Executable file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
esphome/images/12-sunny.png
Executable file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
esphome/images/13-windy.png
Executable file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
esphome/images/14-windy-variant.png
Executable file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
esphome/images/15-exceptional.png
Executable file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
esphome/images/2-cloudy.png
Executable file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
esphome/images/3-fog.png
Executable file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
esphome/images/3Dview.png
Executable file
|
After Width: | Height: | Size: 156 KiB |
BIN
esphome/images/4-hail.png
Executable file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
esphome/images/5-lightning.png
Executable file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
esphome/images/6-lightning-rainy.png
Executable file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
esphome/images/7-partlycloudy.png
Executable file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
esphome/images/8-pouring.png
Executable file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
esphome/images/9-rainy.png
Executable file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
esphome/images/IMG_3539.jpg
Executable file
|
After Width: | Height: | Size: 470 KiB |
BIN
esphome/images/IMG_3540.jpg
Executable file
|
After Width: | Height: | Size: 393 KiB |
BIN
esphome/images/IMG_3542.jpg
Executable file
|
After Width: | Height: | Size: 374 KiB |
BIN
esphome/images/IMG_3543.jpg
Executable file
|
After Width: | Height: | Size: 377 KiB |
BIN
esphome/images/IMG_3547.jpg
Executable file
|
After Width: | Height: | Size: 317 KiB |
BIN
esphome/images/IMG_5573.jpg
Executable file
|
After Width: | Height: | Size: 443 KiB |
BIN
esphome/images/IMG_5575.jpg
Executable file
|
After Width: | Height: | Size: 328 KiB |
BIN
esphome/images/weatherman-title-train.png
Executable file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
esphome/images/weatherman-title-weather.png
Executable file
|
After Width: | Height: | Size: 1.8 KiB |
95
esphome/vw-bus.yaml
Normal file
@@ -0,0 +1,95 @@
|
||||
substitutions:
|
||||
esp_name: "vw-bus"
|
||||
|
||||
esphome:
|
||||
name: ${esp_name}
|
||||
comment: ${esp_name}
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: arduino
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: !secret vw_bus_api
|
||||
|
||||
ota:
|
||||
password: !secret vw_bus_ota
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: ${esp_name} fallback
|
||||
password: !secret fallback_password
|
||||
|
||||
captive_portal:
|
||||
|
||||
output:
|
||||
- platform: ledc
|
||||
pin: GPIO5
|
||||
id: INTERIOUR
|
||||
- platform: ledc
|
||||
pin: GPIO18
|
||||
id: DIM_FL
|
||||
- platform: ledc
|
||||
pin: GPIO27
|
||||
id: DIM_FR
|
||||
- platform: ledc
|
||||
pin: GPIO4
|
||||
id: BLINK_FL
|
||||
- platform: ledc
|
||||
pin: GPIO17
|
||||
id: BLINK_FR
|
||||
- platform: ledc
|
||||
pin: GPIO14
|
||||
id: DIM_RL
|
||||
- platform: ledc
|
||||
pin: GPIO26
|
||||
id: DIM_RR
|
||||
|
||||
light:
|
||||
- platform: monochromatic
|
||||
output: INTERIOUR
|
||||
name: "Interiour lights"
|
||||
- platform: monochromatic
|
||||
output: DIM_FL
|
||||
name: "Dim FL"
|
||||
- platform: monochromatic
|
||||
output: DIM_FR
|
||||
name: "Dim FR"
|
||||
- platform: monochromatic
|
||||
output: DIM_RL
|
||||
name: "Dim RL"
|
||||
effects:
|
||||
- pulse:
|
||||
transition_length: 0.3s
|
||||
update_interval: 0.5s
|
||||
- platform: monochromatic
|
||||
output: DIM_RR
|
||||
name: "Dim RR"
|
||||
effects:
|
||||
- pulse:
|
||||
transition_length: 0.3s
|
||||
update_interval: 0.5s
|
||||
- platform: monochromatic
|
||||
output: BLINK_FL
|
||||
name: "Blink FL"
|
||||
effects:
|
||||
- pulse:
|
||||
transition_length: 0.3s
|
||||
update_interval: 0.5s
|
||||
- platform: monochromatic
|
||||
output: BLINK_FR
|
||||
name: "Blink FR"
|
||||
effects:
|
||||
- pulse:
|
||||
transition_length: 0.3s
|
||||
update_interval: 0.5s
|
||||