Merge pull request #17 from lubeda/develop

Develop
main
LuBeDa 3 years ago committed by GitHub
commit 103650965c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,7 +4,7 @@
## Important information
If you like my work, please donate me a star on GitHub and consider sponsoring me!!
If you like my work, please donate me a star on GitHub and consider [sponsoring](https://www.paypal.com/donate/?hosted_button_id=FZDKSLQ46HJTU) me!!
## Introduction
@ -151,6 +151,22 @@ full_screen => {"icon_name", "lifetime", "screen_time"}
void full_screen(string iconname, int =D_LIFETIME, int screen_time=D_SCREEN_TIME);
```
##### bitmap screen
For 8x32 images as text. You can generate this images with e.g. [Pixel Bitmap Creator (8x32)](https://pixelit.bastelbunker.de/PixelCreator)
###### service via API
```c
bitmap_screen => {"[0,4523,0,2342,0,..... (256 values 16bit values rgb565)]", "lifetime", "screen_time"}
```
###### Lambda
```c
void bitmap_screen(string text, int =D_LIFETIME, int screen_time=D_SCREEN_TIME);
```
#### Display Elements
![elements](./images/elements.png)
@ -470,6 +486,7 @@ ehmtxv2:
brightness: 80 # percent
time_format: "%H:%M"
date_format: "%d.%m."
rtl: false # write vom left to right
week_start_monday: true # false equals sunday
scroll_count: 2 # scroll long text at least two times
scroll_interval: 80 # milliseconds
@ -497,6 +514,8 @@ ehmtxv2:
**special_font_xoffset** (optional, pixel): xoffset the text is aligned BASELINE_LEFT, the left defaults to `1`
**rtl** (optional, boolean): if `true` write from right to left (arabic, hebrew etc.). Default ist `false`
**matrix_component** (required, ID): ID of the addressable display
**show_dow** (optional, bool): draw the day of week indicator on the bottom of the clock screen. Disable, e.g. if you want larger fonts, defaults to true.
@ -1032,7 +1051,9 @@ sensor:
## Breaking changes
### **nothing yet, since it is new**
### 2023.5.0
- removed the rtttl buzzer from the ulanzi easy template, because it often caused reboots!
## EspHoMaTriX in the media
@ -1065,7 +1086,7 @@ THE SOFTWARE IS PROVIDED "AS IS", use at your own risk!
- **[aptonline](https://github.com/aptonline)** for his work on the ulanzi hardware
- **[wsbtak](https://github.com/wsbtak)** for the work on the ulanzi hardware
- **[ofirsnb](https://github.com/ofirsnb)** for his contributions
- **[darkpoet78](https://github.com/darkpoet78/MatrixClockFonts)** for his work on optimized fonts
- **[darkpoet78](https://github.com/darkpoet78/MatrixClockFonts)** for his work on optimized fonts and user support
- **[pplucky](https://user-images.githubusercontent.com/16407309/224850723-634c9b2d-55d9-44f2-9f93-765c0485b090.GIF)** for his 8x32 GIF animation
- **[dennisse](https://github.com/dennisse)** Auto brightness for the Ulanzi
- **[geekofweek](https://github.com/geekofweek)** fixed sample YAML

@ -2,17 +2,20 @@
## function
- [ ] screen_time on ms sec base
- [ ] scroll left to right
- [ ] seconds point moveable
- [ ] dynamic bitmap as JSON (works partially)
- [ ] fix find_free_icon to work for bitmap screen
- [x] alarm on all screens but full screen
- [x] indicator on all screens but full screen and clock
- [x] refreshing an icon screen should extend the display time
- [ ] scroll left to right
- [x] size of indicator and alarm
- [x] center text
- [x] alarm independent of screen
- [x] del_screen with * and filter by type, do delete all clocks etc.
- [x] force_screen with * and filter by type, do delete all clocks etc.
- [x] gauge with color and del_gaugeall clocks etc.
- [ ] seconds point moveable
- [x] seconds point to clock screen only
- [x] rainbow icon and text
- [x] del_slot still active?
@ -22,16 +25,16 @@
## user experience
- [ ] blueprints
- [x] Color in blueprints
- [ ] all modes in one blueprint
- [ ] external HTML with more blueprint helpers (icons and modes)
- [ ] ~~all modes in one blueprint~~
- [x] Color in blueprints
- [x] default values for all functions
- [x] provide sample font from [url](https://www.pentacom.jp/pentacom/bitfontmaker2/)
- [x] start animation
## style
- [ ] in screen rename text_color to color
- [x] ~~in screen rename text_color to color~~
- [x] default_font before alarm parameter
- [x] screen_time instead of showtime
- [x] lifetime instead of durations

@ -9,6 +9,7 @@ namespace esphome
this->display_indicator = 0;
this->display_alarm = 0;
this->clock_time = 10;
this->clock_interval = 90;
this->hold_time = 10;
this->icon_count = 0;
this->hue_ = 0;
@ -20,7 +21,9 @@ namespace esphome
this->alarm_color = Color(CA_RED, CA_GREEN, CA_BLUE);
this->gauge_color = Color(CD_RED, CD_GREEN, CD_BLUE);
this->gauge_value = 0;
this->screen_pointer = 0;
this->next_action_time = 0;
this->last_scroll_time = 0;
this->screen_pointer = MAXQUEUE;
for (uint8_t i = 0; i < MAXQUEUE; i++)
{
@ -100,6 +103,40 @@ namespace esphome
}
}
void EHMTX::bitmap_screen(std::string text, int lifetime, int screen_time)
{
ESP_LOGD(TAG, "bitmap screen: lifetime: %d screen_time: %d", lifetime, screen_time);
const size_t CAPACITY = JSON_ARRAY_SIZE(256);
StaticJsonDocument<CAPACITY> doc;
deserializeJson(doc, text);
JsonArray array = doc.as<JsonArray>();
// extract the values
uint16_t i = 0;
for (JsonVariant v : array)
{
uint16_t buf = v.as<int>();
unsigned char b = (((buf)&0x001F) << 3);
unsigned char g = (((buf)&0x07E0) >> 3); // Fixed: shift >> 5 and << 2
unsigned char r = (((buf)&0xF800) >> 8); // shift >> 11 and << 3
Color c = Color(r, g, b);
this->bitmap[i++] = c;
}
EHMTX_queue *screen = this->find_free_queue_element();
screen->text = "";
screen->endtime = this->clock->now().timestamp + lifetime * 60;
screen->mode = MODE_BITMAP_SCREEN;
screen->screen_time_ = screen_time;
for (auto *t : on_add_screen_triggers_)
{
t->process("bitmap", (uint8_t)screen->mode);
}
screen->status();
}
uint8_t EHMTX::find_icon(std::string name)
{
for (uint8_t i = 0; i < this->icon_count; i++)
@ -185,6 +222,7 @@ namespace esphome
register_service(&EHMTX::rainbow_text_screen, "rainbow_text_screen", {"text", "lifetime", "screen_time", "default_font"});
register_service(&EHMTX::clock_screen, "clock_screen", {"lifetime", "screen_time", "default_font", "r", "g", "b"});
register_service(&EHMTX::bitmap_screen, "bitmap_screen", {"text", "lifetime", "screen_time"});
register_service(&EHMTX::rainbow_clock_screen, "rainbow_clock_screen", {"lifetime", "screen_time", "default_font"});
register_service(&EHMTX::date_screen, "date_screen", {"lifetime", "screen_time", "default_font", "r", "g", "b"});
@ -219,7 +257,7 @@ namespace esphome
void EHMTX::blank_screen(int lifetime, int showtime)
{
auto scr = this->find_free_queue_element();
scr->screen_time = showtime;
scr->screen_time_ = showtime;
scr->mode = MODE_BLANK;
scr->endtime = this->clock->now().timestamp + lifetime * 60;
}
@ -228,22 +266,19 @@ namespace esphome
{
if (!this->is_running)
{
if (this->clock->now().timestamp > 15)
if (this->clock->now().is_valid())
{
ESP_LOGD(TAG, "time sync => starting");
ESP_LOGD(TAG, "time sync => start running");
this->bitmap_screen("[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63519,63519,63519,63519,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63519,0,0,0,0,2016,0,0,0,0,0,0,0,0,0,0,31,0,0,0,0,0,0,0,0,0,63488,0,63488,0,0,0,63519,0,0,0,0,2016,2016,0,0,0,65514,0,65514,0,0,0,31,0,0,0,64512,0,0,64512,0,63488,63488,0,63488,63488,0,0,63519,63519,63519,0,0,2016,0,2016,0,65514,0,65514,0,65514,0,31,31,31,0,0,0,64512,64512,0,0,63488,63488,63488,63488,63488,0,0,63519,0,0,0,0,2016,0,2016,0,65514,0,65514,0,65514,0,0,31,0,0,0,0,64512,64512,0,0,0,63488,63488,63488,0,0,0,63519,63519,63519,63519,0,2016,0,2016,0,65514,0,65514,0,65514,0,0,0,31,31,0,64512,0,0,64512,0,0,0,63488,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]",1,10);
this->clock_screen(14 * 24 * 60, this->clock_time, false, C_RED, C_GREEN, C_BLUE);
this->date_screen(14 * 24 * 60, (int)this->clock_time / 2, false, C_RED, C_GREEN, C_BLUE);
this->is_running = true;
}
}
}
void EHMTX::force_screen(std::string icon_name, int mode)
{
// if (this->string_has_ending(icon_name, "*"))
// {
// // remove the *
// icon_name = icon_name.substr(0, icon_name.length() - 1);
// }
for (uint8_t i = 0; i < MAXQUEUE; i++)
{
if (this->queue[i]->mode == mode)
@ -259,7 +294,7 @@ namespace esphome
{
ESP_LOGD(TAG, "force_screen: found position: %d", i);
this->queue[i]->last_time = 0;
this->queue[i]->endtime += this->queue[i]->screen_time;
this->queue[i]->endtime += this->queue[i]->screen_time_;
this->next_action_time = this->clock->now().timestamp;
ESP_LOGW(TAG, "force_screen: icon %s in mode %d", icon_name.c_str(), mode);
}
@ -294,9 +329,9 @@ namespace esphome
time_t ts = this->clock->now().timestamp;
for (size_t i = 0; i < MAXQUEUE; i++)
{
if ((this->queue[i]->mode == MODE_CLOCK)||(this->queue[i]->mode == MODE_RAINBOW_CLOCK))
if ((this->queue[i]->mode == MODE_CLOCK) || (this->queue[i]->mode == MODE_RAINBOW_CLOCK))
{
if (ts > (this->queue[i]->last_time + this->clock_interval))
if (ts > (this->queue[i]->last_time + this->clock_interval))
{
hit = i;
}
@ -322,7 +357,7 @@ namespace esphome
this->queue[i]->endtime = 0;
if (this->queue[i]->mode != MODE_EMPTY)
{
ESP_LOGD(TAG, "remove expired queue element: removed slot %d: icon_name: %s text: %s", i, this->queue[i]->icon_name.c_str(), this->queue[i]->text.c_str());
ESP_LOGD(TAG, "remove expired queue element: slot %d: mode: %d icon_name: %s text: %s", i, this->queue[i]->mode, this->queue[i]->icon_name.c_str(), this->queue[i]->text.c_str());
for (auto *t : on_expired_screen_triggers_)
{
infotext = "";
@ -359,6 +394,7 @@ namespace esphome
}
}
}
void EHMTX::tick()
{
this->hue_++;
@ -369,22 +405,36 @@ namespace esphome
float red, green, blue;
esphome::hsv_to_rgb(this->hue_, 0.8, 0.8, red, green, blue);
this->rainbow_color = Color(uint8_t(255 * red), uint8_t(255 * green), uint8_t(255 * blue));
time_t ts = this->clock->now().timestamp;
if (this->is_running)
{
if (millis() - this->last_scroll_time >= this->scroll_interval)
{
this->scroll_step++;
this->last_scroll_time = millis();
if (this->scroll_step > this->queue[this->screen_pointer]->scroll_reset)
{
this->scroll_step = 0;
}
}
if (ts > this->next_action_time)
{
this->remove_expired_queue_element();
this->screen_pointer = this->find_last_clock();
this->scroll_step = 0;
if (this->screen_pointer == MAXQUEUE)
{
this->screen_pointer = find_oldest_queue_element();
}
if (this->screen_pointer != MAXQUEUE)
{
this->queue[this->screen_pointer]->shiftx_ = 0;
this->queue[this->screen_pointer]->last_time = ts + this->queue[this->screen_pointer]->screen_time;
this->queue[this->screen_pointer]->last_time = ts + this->queue[this->screen_pointer]->screen_time_;
if (this->queue[this->screen_pointer]->icon < this->icon_count)
{
this->icons[this->queue[this->screen_pointer]->icon]->set_frame(0);
@ -544,35 +594,14 @@ namespace esphome
}
EHMTX_queue *screen = this->find_icon_queue_element(icon);
int x, y, pixel, h;
if (default_font)
{
this->display->get_text_bounds(0, 0, text.c_str(), this->default_font, display::TextAlign::LEFT, &x, &y, &pixel, &h);
}
else
{
this->display->get_text_bounds(0, 0, text.c_str(), this->special_font, display::TextAlign::LEFT, &x, &y, &pixel, &h);
}
if (pixel < 23)
{
screen->centerx_ = ceil((22 - pixel) / 2);
screen->screen_time = screen_time;
}
else
{
screen->centerx_ = 0;
int display_duration = ceil((this->scroll_count * (TEXTSTARTOFFSET + pixel) * this->scroll_interval) / 1000);
screen->screen_time = (display_duration > screen_time) ? display_duration : screen_time;
}
screen->text = text;
screen->pixels_ = pixel;
screen->endtime = this->clock->now().timestamp + lifetime * 60;
screen->shiftx_ = 0;
screen->text_color = Color(r, g, b);
screen->default_font = default_font;
screen->mode = MODE_ICON_SCREEN;
screen->icon_name = iconname;
screen->icon = icon;
screen->calc_scroll_time(text, screen_time);
for (auto *t : on_add_screen_triggers_)
{
t->process(screen->icon_name, (uint8_t)screen->mode);
@ -596,34 +625,14 @@ namespace esphome
}
EHMTX_queue *screen = this->find_icon_queue_element(icon);
int x, y, pixel, h;
if (default_font)
{
this->display->get_text_bounds(0, 0, text.c_str(), this->default_font, display::TextAlign::LEFT, &x, &y, &pixel, &h);
}
else
{
this->display->get_text_bounds(0, 0, text.c_str(), this->special_font, display::TextAlign::LEFT, &x, &y, &pixel, &h);
}
if (pixel < 23)
{
screen->centerx_ = ceil((22 - pixel) / 2);
screen->screen_time = screen_time;
}
else
{
screen->centerx_ = 0;
int display_duration = ceil((this->scroll_count * (TEXTSTARTOFFSET + pixel) * this->scroll_interval) / 1000);
screen->screen_time = (display_duration > screen_time) ? display_duration : screen_time;
}
screen->text = text;
screen->pixels_ = pixel;
screen->endtime = this->clock->now().timestamp + lifetime * 60;
screen->shiftx_ = 0;
screen->default_font = default_font;
screen->mode = MODE_RAINBOW_ICON;
screen->icon_name = iconname;
screen->icon = icon;
screen->calc_scroll_time(text, screen_time);
for (auto *t : on_add_screen_triggers_)
{
t->process(screen->icon_name, (uint8_t)screen->mode);
@ -639,7 +648,14 @@ namespace esphome
ESP_LOGD(TAG, "rainbow_clock_screen lifetime: %d screen_time: %d", lifetime, screen_time);
screen->mode = MODE_RAINBOW_CLOCK;
screen->default_font = default_font;
screen->screen_time = (screen_time > this->clock_interval)?screen_time:this->clock_interval-1;
if (this->clock_interval == 0 || (this->clock_interval > screen_time))
{
screen->screen_time_ = screen_time;
}
else
{
screen->screen_time_ = this->clock_interval - 2;
}
screen->endtime = this->clock->now().timestamp + lifetime * 60;
screen->status();
}
@ -651,7 +667,7 @@ namespace esphome
ESP_LOGD(TAG, "rainbow_date_screen lifetime: %d screen_time: %d", lifetime, screen_time);
screen->mode = MODE_RAINBOW_DATE;
screen->default_font = default_font;
screen->screen_time = screen_time;
screen->screen_time_ = screen_time;
screen->endtime = this->clock->now().timestamp + lifetime * 60;
screen->status();
}
@ -662,24 +678,21 @@ namespace esphome
screen->text = text;
screen->endtime = this->clock->now().timestamp + lifetime * 60;
screen->screen_time = screen_time;
screen->default_font = default_font;
screen->text_color = Color(r, g, b);
screen->mode = MODE_TEXT_SCREEN;
screen->calc_scroll_time();
screen->calc_scroll_time(text, screen_time);
screen->status();
}
void EHMTX::rainbow_text_screen(std::string text, int lifetime, int screen_time, bool default_font)
{
EHMTX_queue *screen = this->find_free_queue_element();
screen->text = text;
screen->endtime = this->clock->now().timestamp + lifetime * 60;
screen->screen_time = screen_time;
screen->default_font = default_font;
screen->mode = MODE_RAINBOW_TEXT;
screen->calc_scroll_time();
screen->calc_scroll_time(text, screen_time);
screen->status();
}
@ -701,7 +714,7 @@ namespace esphome
screen->mode = MODE_FULL_SCREEN;
screen->icon = icon;
screen->icon_name = iconname;
screen->screen_time = screen_time;
screen->screen_time_ = screen_time;
screen->endtime = this->clock->now().timestamp + lifetime * 60;
for (auto *t : on_add_screen_triggers_)
{
@ -719,7 +732,7 @@ namespace esphome
ESP_LOGD(TAG, "clock_screen_color lifetime: %d screen_time: %d red: %d green: %d blue: %d", lifetime, screen_time, r, g, b);
screen->mode = MODE_CLOCK;
screen->default_font = default_font;
screen->screen_time = (screen_time > this->clock_interval)?screen_time:this->clock_interval-1;
screen->screen_time_ = screen_time;
screen->endtime = this->clock->now().timestamp + lifetime * 60;
screen->status();
}
@ -731,7 +744,7 @@ namespace esphome
screen->text_color = Color(r, g, b);
ESP_LOGD(TAG, "date_screen lifetime: %d screen_time: %d red: %d green: %d blue: %d", lifetime, screen_time, r, g, b);
screen->mode = MODE_DATE;
screen->screen_time = screen_time;
screen->screen_time_ = screen_time;
screen->default_font = default_font;
screen->endtime = this->clock->now().timestamp + lifetime * 60;
screen->status();
@ -777,6 +790,15 @@ namespace esphome
}
}
void EHMTX::set_rtl(bool b)
{
this->rtl = b;
if (b)
{
ESP_LOGI(TAG, "show text right to left");
}
}
void EHMTX::set_show_seconds(bool b)
{
this->show_seconds = b;
@ -906,6 +928,10 @@ namespace esphome
{
ESP_LOGCONFIG(TAG, "show date");
}
if (this->rtl)
{
ESP_LOGCONFIG(TAG, "RTL activated");
}
if (this->week_starts_monday)
{
ESP_LOGCONFIG(TAG, "weekstart: monday");
@ -914,6 +940,10 @@ namespace esphome
{
ESP_LOGCONFIG(TAG, "weekstart: sunday");
}
if (this->clock->now().is_valid())
{
this->is_running = true;
}
}
void EHMTX::add_icon(EHMTX_Icon *icon)

@ -20,10 +20,10 @@ const uint8_t MAXICONS = 90;
const uint8_t TEXTSCROLLSTART = 8;
const uint8_t TEXTSTARTOFFSET = (32 - 8);
const uint16_t POLLINGINTERVAL = 800;
const uint16_t POLLINGINTERVAL = 1000;
static const char *const EHMTX_VERSION = "Version: 2023.5.0 beta";
static const char *const TAG = "EHMTXv2";
enum show_mode : uint8_t { MODE_EMPTY = 0,MODE_BLANK = 1, MODE_CLOCK = 2, MODE_DATE = 3, MODE_FULL_SCREEN = 4, MODE_ICON_SCREEN = 5, MODE_TEXT_SCREEN = 6 , MODE_RAINBOW_ICON = 7,MODE_RAINBOW_TEXT = 8, MODE_RAINBOW_CLOCK = 9,MODE_RAINBOW_DATE=10 };
enum show_mode : uint8_t { MODE_EMPTY = 0,MODE_BLANK = 1, MODE_CLOCK = 2, MODE_DATE = 3, MODE_FULL_SCREEN = 4, MODE_ICON_SCREEN = 5, MODE_TEXT_SCREEN = 6 , MODE_RAINBOW_ICON = 7,MODE_RAINBOW_TEXT = 8, MODE_RAINBOW_CLOCK = 9,MODE_RAINBOW_DATE=10,MODE_BITMAP_SCREEN=11 };
namespace esphome
{
@ -37,7 +37,7 @@ namespace esphome
class EHMTX : public PollingComponent, public api::CustomAPIDevice {
protected:
float get_setup_priority() const override { return esphome::setup_priority::PROCESSOR; }
float get_setup_priority() const override { return esphome::setup_priority::BEFORE_CONNECTION; }
uint8_t brightness_;
uint32_t boot_anim=0;
uint8_t screen_pointer;
@ -57,7 +57,7 @@ namespace esphome
EHMTX();
Color text_color, alarm_color, gauge_color,indicator_color,clock_color;
Color today_color,weekday_color,rainbow_color;
int hue_;
uint16_t hue_=0;
void dump_config();
std::string time_fmt;
std::string date_fmt;
@ -67,9 +67,12 @@ namespace esphome
bool display_gauge;
bool is_running=false;
bool show_date;
bool rtl;
uint8_t gauge_value;
uint16_t clock_time;
uint16_t scroll_step;
uint8_t scroll_count;
Color bitmap[256];
void remove_expired_queue_element();
uint8_t find_oldest_queue_element();
uint8_t find_icon_in_queue(std::string);
@ -93,6 +96,7 @@ namespace esphome
uint16_t frame_interval; // ms to next_frame()
uint16_t clock_interval;
uint16_t hold_time; // seconds display of screen_time to extend
uint8_t icon_count; // max iconnumber -1
unsigned long last_scroll_time;
unsigned long last_rainbow_time;
@ -107,12 +111,14 @@ namespace esphome
void skip_screen();
void hold_screen(int t=30);
void set_display(addressable_light::AddressableLightDisplay *disp);
void set_clock_interval(uint16_t t=60);
void set_clock_interval(uint16_t t=90);
void get_string(std::string);
void set_hold_time(uint16_t t=30);
void set_clock_time(uint16_t t=10);
void set_show_day_of_week(bool b);
void set_show_seconds(bool b);
void set_show_date(bool b);
void set_rtl(bool b);
void set_font_offset(int8_t x, int8_t y);
void set_week_start(bool b);
void set_brightness(int b);
@ -138,13 +144,13 @@ namespace esphome
void hide_gauge();
void hide_indicator();
void hide_alarm();
void full_screen(std::string icon, int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME);
void icon_screen(std::string icon, std::string text, int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME,bool default_font=true,int r=C_RED, int g=C_GREEN, int b=C_BLUE);
void text_screen(std::string text, int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME, bool default_font=true, int r=C_RED, int g=C_GREEN, int b=C_BLUE);
void clock_screen(int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME,bool default_font=true,int r=C_RED, int g=C_GREEN, int b=C_BLUE);
void date_screen(int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME,bool default_font=true, int r=C_RED, int g=C_GREEN, int b=C_BLUE);
void blank_screen(int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME);
void bitmap_screen(std::string text,int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME);
void rainbow_icon_screen(std::string icon_name, std::string text, int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME, bool default_font=true);
void rainbow_text_screen(std::string text, int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME, bool default_font=true);
void rainbow_clock_screen(int lifetime=D_LIFETIME, int screen_time=D_SCREEN_TIME, bool default_font=true);
@ -173,13 +179,13 @@ namespace esphome
public:
uint8_t centerx_;
uint16_t shiftx_;
uint16_t pixels_;
uint16_t screen_time;
uint16_t screen_time_;
bool default_font;
time_t endtime;
time_t last_time;
uint8_t icon;
uint16_t scroll_reset;
Color text_color;
show_mode mode;
@ -194,7 +200,8 @@ namespace esphome
bool update_slot(uint8_t _icon);
void update_screen();
void hold_slot(uint8_t _sec);
void calc_scroll_time();
void calc_scroll_time(std::string,uint16_t );
int xpos();
};
class EHMTXNextScreenTrigger : public Trigger<std::string, std::string>

@ -9,8 +9,7 @@ namespace esphome
this->endtime = 0;
this->last_time = 0;
this->centerx_ = 0;
this->shiftx_ = 0;
this->screen_time = 0;
this->screen_time_ = 0;
this->mode = MODE_EMPTY;
this->icon_name = "";
this->icon = 0;
@ -23,37 +22,40 @@ namespace esphome
switch (this->mode)
{
case MODE_EMPTY:
ESP_LOGD(TAG, "queue: empty slot");
ESP_LOGD(TAG, " empty slot");
break;
case MODE_BLANK:
ESP_LOGD(TAG, "queue: blank screen for %d sec", this->screen_time);
ESP_LOGD(TAG, "queue: blank screen for %d sec", this->screen_time_);
break;
case MODE_CLOCK:
ESP_LOGD(TAG, "queue: clock for %d sec", this->screen_time);
ESP_LOGD(TAG, "queue: clock for: %d sec", this->screen_time_);
break;
case MODE_DATE:
ESP_LOGD(TAG, "queue: date for %d sec", this->screen_time);
ESP_LOGD(TAG, "queue: date for: %d sec", this->screen_time_);
break;
case MODE_FULL_SCREEN:
ESP_LOGD(TAG, "queue: full screen: %s for %d sec", this->icon_name.c_str(), this->screen_time);
ESP_LOGD(TAG, "queue: full screen: \"%s\" for: %d sec", this->icon_name.c_str(), this->screen_time_);
break;
case MODE_ICON_SCREEN:
ESP_LOGD(TAG, "queue: icon screen: %s text: %s for %d sec", this->icon_name.c_str(), this->text.c_str(), this->screen_time);
ESP_LOGD(TAG, "queue: icon screen: \"%s\" text: %s for: %d sec", this->icon_name.c_str(), this->text.c_str(), this->screen_time_);
break;
case MODE_TEXT_SCREEN:
ESP_LOGD(TAG, "queue: text text: %s for %d sec", this->text.c_str(), this->screen_time);
ESP_LOGD(TAG, "queue: text text: \"%s\" for: %d sec", this->text.c_str(), this->screen_time_);
break;
case MODE_RAINBOW_ICON:
ESP_LOGD(TAG, "queue: rainbow icon: %s text: %s for %d sec", this->icon_name.c_str(), this->text.c_str(), this->screen_time);
ESP_LOGD(TAG, "queue: rainbow icon: \"%s\" text: %s for: %d sec", this->icon_name.c_str(), this->text.c_str(), this->screen_time_);
break;
case MODE_RAINBOW_TEXT:
ESP_LOGD(TAG, "queue: rainbow text: %s for %d sec", this->text.c_str(), this->screen_time);
ESP_LOGD(TAG, "queue: rainbow text: \"%s\" for: %d sec", this->text.c_str(), this->screen_time_);
break;
case MODE_RAINBOW_CLOCK:
ESP_LOGD(TAG, "queue: clock for %d sec", this->screen_time);
ESP_LOGD(TAG, "queue: clock for: %d sec", this->screen_time_);
break;
case MODE_RAINBOW_DATE:
ESP_LOGD(TAG, "queue: date for %d sec", this->screen_time);
ESP_LOGD(TAG, "queue: date for: %d sec", this->screen_time_);
break;
case MODE_BITMAP_SCREEN:
ESP_LOGD(TAG, "queue: bitmap for: %d sec", this->screen_time_);
break;
default:
ESP_LOGD(TAG, "queue: UPPS");
@ -61,6 +63,57 @@ namespace esphome
}
}
int EHMTX_queue::xpos()
{
uint8_t width = 32;
uint8_t startx = 0;
int result = 0;
switch (this->mode)
{
case MODE_RAINBOW_ICON:
case MODE_ICON_SCREEN:
startx = 8;
break;
case MODE_TEXT_SCREEN:
case MODE_RAINBOW_TEXT:
// no correction
break;
default:
break;
}
if (this->config_->display_gauge)
{
startx += 2;
}
width -= startx;
if (this->config_->rtl)
{
if (this->pixels_ < width)
{
result = 32 - ceil((width - this->pixels_) / 2);
}
else
{
result = startx + this->config_->scroll_step;
}
}
else
{
if (this->pixels_ < width)
{
result = startx + ceil((width - this->pixels_) / 2);
}
else
{
result = startx - this->config_->scroll_step + width;
}
}
return result;
}
void EHMTX_queue::update_screen()
{
if (millis() - this->config_->last_rainbow_time >= this->config_->rainbow_interval)
@ -76,31 +129,6 @@ namespace esphome
this->config_->last_rainbow_time = millis();
}
if ((this->mode == MODE_ICON_SCREEN) || (this->mode == MODE_RAINBOW_ICON))
{
if (millis() - this->config_->last_scroll_time >= this->config_->scroll_interval && this->pixels_ > TEXTSTARTOFFSET)
{
this->shiftx_++;
if (this->shiftx_ > this->pixels_ + TEXTSTARTOFFSET)
{
this->shiftx_ = 0;
}
this->config_->last_scroll_time = millis();
}
}
if ((this->mode == MODE_TEXT_SCREEN) || (this->mode == MODE_RAINBOW_TEXT))
{
if (millis() - this->config_->last_scroll_time >= this->config_->scroll_interval && this->pixels_ >= 32)
{
this->shiftx_++;
if (this->shiftx_ > this->pixels_ + 32)
{
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();
@ -123,9 +151,18 @@ namespace esphome
break;
case MODE_BLANK:
break;
case MODE_BITMAP_SCREEN:
for (uint8_t x = 0; x < 32; x++)
{
for (uint8_t y = 0; y < 8; y++)
{
this->config_->display->draw_pixel_at(x, y, this->config_->bitmap[x + y * 32]);
}
}
break;
case MODE_RAINBOW_CLOCK:
case MODE_CLOCK:
if (this->config_->clock->now().timestamp > 6000) // valid time
if (this->config_->clock->now().is_valid()) // valid time
{
color_ = (this->mode == MODE_RAINBOW_CLOCK) ? this->config_->rainbow_color : this->config_->clock_color;
time_t ts = this->config_->clock->now().timestamp;
@ -135,7 +172,8 @@ namespace esphome
{
this->config_->display->draw_pixel_at(0, 0, color_);
}
if (this->mode != MODE_RAINBOW_CLOCK){
if (this->mode != MODE_RAINBOW_CLOCK)
{
this->config_->draw_day_of_week();
}
}
@ -146,7 +184,7 @@ namespace esphome
break;
case MODE_RAINBOW_DATE:
case MODE_DATE:
if (this->config_->clock->now().timestamp > 6000) // valid time
if (this->config_->clock->now().is_valid())
{
color_ = (this->mode == MODE_RAINBOW_DATE) ? this->config_->rainbow_color : this->config_->clock_color;
time_t ts = this->config_->clock->now().timestamp;
@ -156,7 +194,8 @@ namespace esphome
{
this->config_->display->draw_pixel_at(0, 0, color_);
}
if (this->mode != MODE_RAINBOW_DATE){
if (this->mode != MODE_RAINBOW_DATE)
{
this->config_->draw_day_of_week();
}
}
@ -181,9 +220,16 @@ namespace esphome
}
color_ = (this->mode == MODE_RAINBOW_ICON) ? this->config_->rainbow_color : this->text_color;
this->config_->display->print(this->centerx_ + TEXTSCROLLSTART - this->shiftx_ + extraoffset + xoffset, yoffset, font, color_, esphome::display::TextAlign::BASELINE_LEFT,
this->text.c_str());
if (this->config_->rtl)
{
this->config_->display->print(this->xpos() + xoffset, yoffset, font, color_, esphome::display::TextAlign::BASELINE_RIGHT,
this->text.c_str());
}
else
{
this->config_->display->print(this->xpos() + xoffset, yoffset, font, color_, esphome::display::TextAlign::BASELINE_LEFT,
this->text.c_str());
}
if (this->config_->display_gauge)
{
this->config_->display->image(2, 0, this->config_->icons[this->icon]);
@ -208,14 +254,22 @@ namespace esphome
extraoffset += 2;
}
color_ = (this->mode == MODE_RAINBOW_TEXT) ? this->config_->rainbow_color : this->text_color;
this->config_->display->print(this->centerx_ - this->shiftx_ + xoffset + extraoffset, yoffset, font, color_, esphome::display::TextAlign::BASELINE_LEFT,
this->text.c_str());
if (this->config_->rtl)
{
this->config_->display->print(this->xpos() + xoffset, yoffset, font, color_, esphome::display::TextAlign::BASELINE_RIGHT,
this->text.c_str());
}
else
{
this->config_->display->print(this->xpos() + xoffset, yoffset, font, color_, esphome::display::TextAlign::BASELINE_LEFT,
this->text.c_str());
}
break;
default:
break;
}
this->update_screen();
}
}
}
void EHMTX_queue::hold_slot(uint8_t _sec)
@ -225,11 +279,16 @@ namespace esphome
}
// TODO void EHMTX_queue::set_mode_icon()
void EHMTX_queue::calc_scroll_time()
void EHMTX_queue::calc_scroll_time(std::string text, uint16_t screen_time)
{
int x, y, w, h;
float display_duration;
uint8_t width = 32;
uint8_t startx = 0;
uint16_t max_steps = 0;
if (this->default_font)
{
this->config_->display->get_text_bounds(0, 0, text.c_str(), this->config_->default_font, display::TextAlign::LEFT, &x, &y, &w, &h);
@ -240,33 +299,46 @@ namespace esphome
}
this->pixels_ = w;
this->shiftx_ = 0;
this->centerx_ = 0;
switch (this->mode)
{
case MODE_RAINBOW_TEXT:
case MODE_TEXT_SCREEN:
display_duration = ceil((28+(this->config_->scroll_count * (32 + this->pixels_)) * this->config_->scroll_interval) / 1000);
this->screen_time = (display_duration > this->screen_time) ? display_duration : this->screen_time;
if (this->pixels_ < 32)
{
this->screen_time_ = screen_time;
this->centerx_ = ceil((32 - this->pixels_) / 2);
}
break;
else
{
max_steps = (this->config_->scroll_count + 1) * (width - startx) + this->config_->scroll_count * this->pixels_;
display_duration = ceil((max_steps * this->config_->scroll_interval) / 1000);
this->screen_time_ = (display_duration > screen_time) ? display_duration : screen_time;
}
break;
case MODE_RAINBOW_ICON:
case MODE_ICON_SCREEN:
display_duration = ceil(((28-TEXTSTARTOFFSET)+(this->config_->scroll_count * (TEXTSTARTOFFSET + this->pixels_)) * this->config_->scroll_interval) / 1000);
this->screen_time = (display_duration > this->screen_time) ? display_duration : this->screen_time;
startx = 8;
if (this->pixels_ < 23)
{
this->screen_time_ = screen_time;
this->centerx_ = ceil((23 - this->pixels_) / 2);
}
break;
else
{
max_steps = (this->config_->scroll_count + 1) * (width - startx) + this->config_->scroll_count * this->pixels_;
display_duration = ceil((max_steps * this->config_->scroll_interval) / 1000);
this->screen_time_ = (display_duration > screen_time) ? display_duration : screen_time;
}
break;
default:
break;
}
this->shiftx_ = 0;
ESP_LOGD(TAG, "display text: %s pixels %d calculated: %d", text.c_str(), this->pixels_, this->screen_time);
this->scroll_reset = (width - startx) + this->pixels_;
;
ESP_LOGD(TAG, "calc_scroll_time: mode: %d text: \"%s\" pixels %d calculated: %d defined: %d max_steps: %d", this->mode, text.c_str(), this->pixels_, this->screen_time_, screen_time, this->scroll_reset);
}
}

@ -66,6 +66,7 @@ CONF_LIFETIME = "lifetime"
CONF_ICONS = "icons"
CONF_SHOWDOW = "show_dow"
CONF_SHOWDATE = "show_date"
CONF_RTL = "rtl"
CONF_FRAMEDURATION = "frame_duration"
CONF_SCROLLCOUNT = "scroll_count"
CONF_MATRIXCOMPONENT = "matrix_component"
@ -105,6 +106,9 @@ EHMTX_SCHEMA = cv.Schema({
): cv.templatable(cv.positive_int),
cv.Optional(
CONF_HTML, default=False
): cv.boolean,
cv.Optional(
CONF_RTL, default=False
): cv.boolean,
cv.Optional(
CONF_SHOW_SECONDS, default=False
@ -362,6 +366,7 @@ async def to_code(config):
cg.add(var.set_brightness(config[CONF_BRIGHTNESS]))
cg.add(var.set_scroll_interval(config[CONF_SCROLLINTERVAL]))
cg.add(var.set_rainbow_interval(config[CONF_SCROLLINTERVAL]))
cg.add(var.set_rtl(config[CONF_RTL]))
cg.add(var.set_scroll_count(config[CONF_SCROLLCOUNT]))
cg.add(var.set_frame_interval(config[CONF_FRAMEINTERVAL]))
cg.add(var.set_week_start(config[CONF_WEEK_START_MONDAY]))

@ -1,17 +1,15 @@
substitutions:
devicename: ulanzi
ledpin: GPIO32
buzzerpin: GPIO15
friendly_name: LED Matrix
board: esp32dev
# Pin definition from https://github.com/aptonline/PixelIt_Ulanzi
battery_pin: GPIO34
buzzer_pin: GPIO15
ldr_pin: GPIO35
matrix_pin: GPIO32
left_button_pin: GPIO26
mid_button_pin: GPIO27
right_button_pin: GPIO14
buzzer_pin: GPIO15
scl_pin: GPIO22
sda_pin: GPIO21
@ -64,7 +62,15 @@ esphome:
on_boot:
then:
- ds1307.read_time:
output:
- platform: ledc
pin: $buzzer_pin
id: rtttl_out
rtttl:
output: rtttl_out
esp32:
board: esp32dev
@ -155,6 +161,7 @@ sensor:
if (n > id(aab_max)) n = id(aab_max);
if (n < id(aab_min)) n = id(aab_min);
int c = id(rgb8x32)->get_brightness(); // current value
c = c>0?c:1 ;
int d = (n - c) * 100 / c; // diff in %
if ( abs(d) > 2 ) id(rgb8x32)->set_brightness(n);
}
@ -168,14 +175,6 @@ wifi:
web_server:
output:
- platform: ledc
pin: $buzzerpin
id: rtttl_out
rtttl:
output: rtttl_out
i2c:
sda: $sda_pin
scl: $scl_pin
@ -188,7 +187,7 @@ light:
type: GRB
internal: true
variant: WS2812
pin: $ledpin
pin: $matrix_pin
num_leds: 256
color_correct: [30%, 30%, 30%]
gamma_correct: 2.0

@ -117,6 +117,8 @@ ehmtxv2:
time_format: "%H:%M"
date_format: "%d.%m."
show_seconds: false
clock_interval: 90
rtl: true
default_font_id: default_font
special_font_id: default_font
icons:

@ -1,17 +1,15 @@
substitutions:
devicename: ulanzi
ledpin: GPIO32
buzzerpin: GPIO15
friendly_name: LED Matrix
board: esp32dev
# Pin definition from https://github.com/aptonline/PixelIt_Ulanzi
battery_pin: GPIO34
buzzer_pin: GPIO15
ldr_pin: GPIO35
matrix_pin: GPIO32
left_button_pin: GPIO26
mid_button_pin: GPIO27
right_button_pin: GPIO14
buzzer_pin: GPIO15
scl_pin: GPIO22
sda_pin: GPIO21
@ -64,7 +62,15 @@ esphome:
on_boot:
then:
- ds1307.read_time:
output:
- platform: ledc
pin: $buzzer_pin
id: rtttl_out
rtttl:
output: rtttl_out
esp32:
board: esp32dev
@ -155,6 +161,7 @@ sensor:
if (n > id(aab_max)) n = id(aab_max);
if (n < id(aab_min)) n = id(aab_min);
int c = id(rgb8x32)->get_brightness(); // current value
c = c>0?c:1 ;
int d = (n - c) * 100 / c; // diff in %
if ( abs(d) > 2 ) id(rgb8x32)->set_brightness(n);
}
@ -168,14 +175,6 @@ wifi:
web_server:
output:
- platform: ledc
pin: $buzzerpin
id: rtttl_out
rtttl:
output: rtttl_out
i2c:
sda: $sda_pin
scl: $scl_pin
@ -188,7 +187,7 @@ light:
type: GRB
internal: true
variant: WS2812
pin: $ledpin
pin: $matrix_pin
num_leds: 256
color_correct: [30%, 30%, 30%]
gamma_correct: 2.0

Loading…
Cancel
Save