- moves transistion time and app time setting into onscreen-menu
- Text starts to scroll on the left side instead from right
- allows to switch to a page by name via mqtt
- custompages doesnt need to have integers as an id anymore, you can also use strings now.

closes #7
closes #4
This commit is contained in:
Stephan Mühl
2023-03-23 14:06:11 +01:00
parent ec613ec43e
commit 7b5a4d3aba
14 changed files with 324 additions and 190 deletions

52
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,52 @@
{
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
}
}

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{
"name": "AWTRIX Light",
"version": "0.33",
"version": "0.35",
"home_assistant_domain": "AwtrixLight",
"funding_url": "https://blueforcer.de",
"new_install_prompt_erase": true,

View File

@@ -89,7 +89,7 @@ void MatrixDisplayUi::setAppAnimation(AnimationDirection dir)
this->frameAnimationDirection = dir;
}
void MatrixDisplayUi::setApps(const std::vector<std::pair<uint16_t, AppCallback>> &appPairs)
void MatrixDisplayUi::setApps(const std::vector<std::pair<String, AppCallback>> &appPairs)
{
delete[] AppFunctions;
AppCount = appPairs.size();
@@ -262,8 +262,9 @@ void MatrixDisplayUi::drawApp()
y *= dir;
x1 *= dir;
y1 *= dir;
bool FirstFrame = progress < 0.1;
bool LastFrame = progress > 0.9;
Serial.println(progress);
bool FirstFrame = progress < 0.2;
bool LastFrame = progress > 0.8;
this->matrix->drawRect(x, y, x1, y1, matrix->Color(0, 0, 0));
(this->AppFunctions[this->state.currentFrame])(this->matrix, &this->state, x, y, FirstFrame, LastFrame);
(this->AppFunctions[this->getnextAppNumber()])(this->matrix, &this->state, x1, y1, FirstFrame, LastFrame);

View File

@@ -164,7 +164,7 @@ public:
/**
* Add frame drawing functions
*/
void setApps(const std::vector<std::pair<uint16_t, AppCallback>> &appPairs);
void setApps(const std::vector<std::pair<String, AppCallback>> &appPairs);
// Overlay

View File

@@ -95,7 +95,7 @@ void DisplayManager_::drawJPG(uint16_t x, uint16_t y, fs::File jpgFile)
void DisplayManager_::setSettings()
{
ui.setTargetFPS(MATRIX_FPS);
ui.setTimePerApp(TIME_PER_FRAME);
ui.setTimePerApp(TIME_PER_APP);
ui.setTimePerTransition(TIME_PER_TRANSITION);
}
@@ -128,11 +128,11 @@ bool jpg_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)
return 0;
}
void DisplayManager_::printText(int16_t x, int16_t y, const char *text, bool centered)
void DisplayManager_::printText(int16_t x, int16_t y, const char *text, bool centered, bool ignoreUppercase)
{
if (centered)
{
uint16_t textWidth = getTextWidth(text);
uint16_t textWidth = getTextWidth(text, ignoreUppercase);
int16_t textX = ((32 - textWidth) / 2);
matrix.setCursor(textX, y);
}
@@ -141,7 +141,7 @@ void DisplayManager_::printText(int16_t x, int16_t y, const char *text, bool cen
matrix.setCursor(x, y);
}
if (UPPERCASE_LETTERS)
if (UPPERCASE_LETTERS && !ignoreUppercase)
{
size_t length = strlen(text);
char upperText[length + 1]; // +1 for the null terminator
@@ -184,64 +184,37 @@ void DisplayManager_::HSVtext(int16_t x, int16_t y, const char *text, bool clear
}
char temp_str[2] = {'\0', '\0'};
temp_str[0] = text[i];
xpos += getTextWidth(temp_str);
xpos += getTextWidth(temp_str, false);
}
hueOffset++;
if (clear)
matrix.show();
}
void pushCustomFrame(uint16_t id)
void pushCustomFrame(String name)
{
if (customFrames.count(id) == 0)
if (customFrames.count(name) == 0)
{
uint16_t newID = nativeAppsCount + id;
switch (id)
++customPagesCount;
void (*customFrames[10])(FastLED_NeoMatrix *, MatrixDisplayUiState *, int16_t, int16_t, bool, bool) = {CFrame1, CFrame2, CFrame3, CFrame4, CFrame5, CFrame6, CFrame7, CFrame8, CFrame9, CFrame10};
if (customFrames[customPagesCount] != NULL)
{
case 1:
Apps.push_back(std::make_pair(newID, CFrame1));
break;
case 2:
Apps.push_back(std::make_pair(newID, CFrame2));
break;
case 3:
Apps.push_back(std::make_pair(newID, CFrame3));
break;
case 4:
Apps.push_back(std::make_pair(newID, CFrame4));
break;
case 5:
Apps.push_back(std::make_pair(newID, CFrame5));
break;
case 6:
Apps.push_back(std::make_pair(newID, CFrame6));
break;
case 7:
Apps.push_back(std::make_pair(newID, CFrame7));
break;
case 8:
Apps.push_back(std::make_pair(newID, CFrame8));
break;
case 9:
Apps.push_back(std::make_pair(newID, CFrame9));
break;
case 10:
Apps.push_back(std::make_pair(newID, CFrame10));
break;
default:
return;
break;
}
Apps.push_back(std::make_pair(name, customFrames[customPagesCount]));
ui.setApps(Apps); // Add frames
}
else
{
++customPagesCount;
}
}
}
void removeCustomFrame(uint16_t id)
void removeCustomFrame(const String &name)
{
id += nativeAppsCount;
// Suchen Sie nach dem Element, das der ID entspricht
auto it = std::find_if(Apps.begin(), Apps.end(), [id](const std::pair<uint16_t, AppCallback> &appPair)
{ return appPair.first == id; });
// Suchen Sie nach dem Element, das dem Namen entspricht
auto it = std::find_if(Apps.begin(), Apps.end(), [&name](const std::pair<String, AppCallback> &appPair)
{ return appPair.first == name; });
// Wenn das Element gefunden wurde, entfernen Sie es aus dem Vektor
if (it != Apps.end())
@@ -251,13 +224,13 @@ void removeCustomFrame(uint16_t id)
}
}
void DisplayManager_::generateCustomPage(uint16_t id, String payload)
void DisplayManager_::generateCustomPage(String name, String payload)
{
if (payload == "" && customFrames.count(id))
if (payload == "" && customFrames.count(name))
{
customFrames.erase(customFrames.find(id));
removeCustomFrame(id);
customFrames.erase(customFrames.find(name));
removeCustomFrame(name);
return;
}
@@ -268,21 +241,6 @@ void DisplayManager_::generateCustomPage(uint16_t id, String payload)
CustomFrame customFrame;
if (id == 0)
{
if (doc.containsKey("id"))
{
customFrame.id = doc["id"].as<uint8_t>();
}
else
{
return;
}
}
if (id > 10)
return;
if (doc.containsKey("sound"))
{
customFrame.sound = ("/" + doc["sound"].as<String>() + ".txt");
@@ -292,27 +250,18 @@ void DisplayManager_::generateCustomPage(uint16_t id, String payload)
customFrame.sound = "";
}
if (doc.containsKey("name"))
{
customFrame.name = doc["name"].as<String>();
}
else
{
customFrame.name = "Custom " + String(id);
}
customFrame.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false;
customFrame.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0;
customFrame.id = id;
customFrame.name = name;
customFrame.text = utf8ascii(doc["text"].as<String>());
customFrame.color = doc.containsKey("color") ? doc["color"].is<String>() ? hexToRgb565(doc["color"]) : doc["color"].is<JsonArray>() ? hexToRgb565(doc["color"].as<String>())
: TEXTCOLOR_565
: TEXTCOLOR_565;
if (currentCustomFrame != id)
if (currentCustomFrame != name)
{
customFrame.scrollposition = 34;
customFrame.scrollposition = 9;
}
customFrame.repeat = doc.containsKey("repeat") ? doc["repeat"].as<uint8_t>() : -1;
@@ -333,8 +282,8 @@ void DisplayManager_::generateCustomPage(uint16_t id, String payload)
}
}
pushCustomFrame(id);
customFrames[id] = customFrame;
pushCustomFrame(name);
customFrames[name] = customFrame;
}
void DisplayManager_::generateNotification(String payload)
@@ -342,7 +291,7 @@ void DisplayManager_::generateNotification(String payload)
StaticJsonDocument<1024> doc;
deserializeJson(doc, payload);
notify.duration = doc.containsKey("duration") ? doc["duration"].as<int>() * 1000 : TIME_PER_FRAME;
notify.duration = doc.containsKey("duration") ? doc["duration"].as<int>() * 1000 : TIME_PER_APP;
notify.text = utf8ascii(doc["text"].as<String>());
notify.repeat = doc.containsKey("repeat") ? doc["repeat"].as<uint16_t>() : -1;
notify.rainbow = doc.containsKey("rainbow") ? doc["rainbow"].as<bool>() : false;
@@ -350,7 +299,7 @@ void DisplayManager_::generateNotification(String payload)
notify.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0;
notify.flag = true;
notify.startime = millis();
notify.scrollposition = 34;
notify.scrollposition = 9;
notify.iconWasPushed = false;
notify.iconPosition = 0;
@@ -387,15 +336,15 @@ void DisplayManager_::generateNotification(String payload)
void DisplayManager_::loadApps()
{
Apps.clear();
Apps.push_back(std::make_pair(0, TimeFrame));
Apps.push_back(std::make_pair("time", TimeFrame));
if (SHOW_DATE)
Apps.push_back(std::make_pair(1, DateFrame));
Apps.push_back(std::make_pair("date", DateFrame));
if (SHOW_TEMP)
Apps.push_back(std::make_pair(2, TempFrame));
Apps.push_back(std::make_pair("temp", TempFrame));
if (SHOW_HUM)
Apps.push_back(std::make_pair(3, HumFrame));
Apps.push_back(std::make_pair("hum", HumFrame));
if (SHOW_BATTERY)
Apps.push_back(std::make_pair(4, BatFrame));
Apps.push_back(std::make_pair("bat", BatFrame));
// if (SHOW_WEATHER)
// Apps.push_back(std::make_pair(5, WeatherFrame));
nativeAppsCount = Apps.size();
@@ -531,3 +480,16 @@ void DisplayManager_::gererateTimer(String Payload)
int interval = difftime(futureTime, now) * 1000;
TimerTicker.attach_ms(interval, timerCallback);
}
void DisplayManager_::switchToApp(String Payload)
{
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, Payload);
if (error)
return;
String name = doc["name"].as<String>();
bool fast = doc["fast"] | false;
int index = findAppIndexByName(name);
if (index > -1)
ui.transitionToApp(index);
}

View File

@@ -44,9 +44,10 @@ public:
void setFPS(uint8_t);
void MatrixState(bool);
void generateNotification(String);
void generateCustomPage(uint16_t, String);
void printText(int16_t x, int16_t y, const char *text, bool centered);
void generateCustomPage(String, String);
void printText(int16_t x, int16_t y, const char *text, bool centered, bool ignoreUppercase);
bool setAutoTransition(bool active);
void switchToApp(String Payload);
void drawGIF(uint16_t x, uint16_t y, fs::File gifFile);
void drawJPG(uint16_t x, uint16_t y, fs::File jpgFile);
};

View File

@@ -20,6 +20,7 @@ Ticker downloader;
tm timeInfo;
uint16_t nativeAppsCount;
uint16_t customPagesCount;
int WEATHER_CODE;
String WEATHER_TEMP;
@@ -27,8 +28,8 @@ String WEATHER_HUM;
struct CustomFrame
{
uint8_t id;
int16_t scrollposition = 34;
int16_t scrollposition = 0;
int16_t scrollDelay = 0;
String text;
uint16_t color;
File icon;
@@ -44,13 +45,13 @@ struct CustomFrame
bool iconWasPushed = false;
};
uint8_t currentCustomFrame;
std::map<uint8_t, CustomFrame> customFrames;
String currentCustomFrame;
std::map<String, CustomFrame> customFrames;
struct Notification
{
uint8_t id;
int16_t scrollposition = 34;
int16_t scrollDelay = 0;
String text;
uint16_t color;
File icon;
@@ -68,9 +69,35 @@ struct Notification
Notification notify;
CustomFrame *getCustomFrameById(uint8_t id)
std::vector<std::pair<String, AppCallback>> Apps;
CustomFrame *getCustomFrameById(String name)
{
return customFrames.count(id) ? &customFrames[id] : nullptr;
return customFrames.count(name) ? &customFrames[name] : nullptr;
}
String getFrameNameByFunction(AppCallback frameFunction)
{
for (const auto &appPair : Apps)
{
if (appPair.second == frameFunction)
{
return appPair.first;
}
}
return ""; // Gibt einen leeren String zurück, wenn die Frame-Funktion nicht gefunden wurde
}
int findAppIndexByName(const String &name)
{
auto it = std::find_if(Apps.begin(), Apps.end(), [&name](const std::pair<String, AppCallback> &appPair)
{ return appPair.first == name; });
if (it != Apps.end())
{
return std::distance(Apps.begin(), it);
}
return -1;
}
void TimeFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
@@ -181,7 +208,7 @@ void MenuFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
if (!MenuManager.inMenu)
return;
matrix->fillScreen(0);
DisplayManager.printText(0, 6, MenuManager.menutext().c_str(), true);
DisplayManager.printText(0, 6, MenuManager.menutext().c_str(), true, true);
}
void AlarmFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
@@ -191,7 +218,7 @@ void AlarmFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
{
matrix->fillScreen(matrix->Color(255, 0, 0));
CURRENT_APP = "Alarm";
uint16_t textWidth = getTextWidth("ALARM");
uint16_t textWidth = getTextWidth("ALARM",false);
int16_t textX = ((32 - textWidth) / 2);
matrix->setTextColor(0);
matrix->setCursor(textX, 6);
@@ -211,7 +238,7 @@ void TimerFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
matrix->fillScreen(matrix->Color(0, 255, 0));
CURRENT_APP = "Timer";
String menuText = "TIMER";
uint16_t textWidth = getTextWidth(menuText.c_str());
uint16_t textWidth = getTextWidth(menuText.c_str(),false);
int16_t textX = ((32 - textWidth) / 2);
matrix->setTextColor(0);
matrix->setCursor(textX, 6);
@@ -224,7 +251,7 @@ void TimerFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
}
}
void ShowCustomFrame(uint8_t id, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void ShowCustomFrame(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
// Abort if notify.flag is set
if (notify.flag)
@@ -233,7 +260,7 @@ void ShowCustomFrame(uint8_t id, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
}
// Get custom frame by ID
CustomFrame *cf = getCustomFrameById(id);
CustomFrame *cf = getCustomFrameById(name);
// Abort if custom frame not found
if (cf == nullptr)
@@ -241,26 +268,24 @@ void ShowCustomFrame(uint8_t id, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
return;
}
// Initialize custom frame properties if first frame
// reset custom frame properties if last frame
if (lastFrame)
{
cf->iconWasPushed = false;
cf->scrollposition = 34;
cf->scrollposition = 9;
cf->iconPosition = 0;
cf->scrollDelay = 0;
}
// Update current app and custom frame IDs
CURRENT_APP = cf->name;
currentCustomFrame = id;
currentCustomFrame = name;
// Check if there is an icon
bool hasIcon = cf->icon;
// Calculate available display width based on icon
uint16_t availableWidth = (hasIcon) ? 24 : 32;
// Disable auto transition if text is repeating and too wide
if ((cf->repeat > 0) && (getTextWidth(cf->text.c_str()) > availableWidth) && (state->frameState == FIXED))
bool noScrolling = getTextWidth(cf->text.c_str(),false) <= availableWidth;
if ((cf->repeat > 0) && (getTextWidth(cf->text.c_str(),false) > availableWidth) && (state->frameState == FIXED))
{
DisplayManager.setAutoTransition(false);
}
@@ -269,21 +294,16 @@ void ShowCustomFrame(uint8_t id, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
DisplayManager.setAutoTransition(true);
}
// Check if text is wider than available display width and frame is not in transition
if (getTextWidth(cf->text.c_str()) > availableWidth && !(state->frameState == IN_TRANSITION))
if (getTextWidth(cf->text.c_str(),false) > availableWidth && !(state->frameState == IN_TRANSITION))
{
// Reset scroll position when text has finished scrolling all the way to the left
if (cf->scrollposition <= -getTextWidth(cf->text.c_str()))
if (cf->scrollposition <= -getTextWidth(cf->text.c_str(),false))
{
cf->scrollposition = 38;
// Set iconWasPushed to false if icon has been pushed
cf->scrollDelay = 0;
cf->scrollposition = 9;
if (cf->iconWasPushed && cf->pushIcon == 2)
{
cf->iconWasPushed = false;
}
// Transition to next app if frame is repeating and repeat limit has been reached
if ((cf->currentRepeat + 1 >= cf->repeat) && (cf->repeat > 0))
{
DisplayManager.setAutoTransition(true);
@@ -296,24 +316,39 @@ void ShowCustomFrame(uint8_t id, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
++cf->currentRepeat;
}
}
// Update scroll position
--cf->scrollposition;
}
// Calculate horizontal text alignment
int16_t textX = (hasIcon) ? ((24 - getTextWidth(cf->text.c_str())) / 2) + 9 : ((32 - getTextWidth(cf->text.c_str())) / 2);
// Set text color
if (!noScrolling)
{
if ((cf->scrollDelay > MATRIX_FPS * 1.2))
{
--cf->scrollposition;
}
else
{
++cf->scrollDelay;
if (hasIcon)
{
if (cf->iconWasPushed && cf->pushIcon == 1)
{
cf->scrollposition = 0;
}
else
{
cf->scrollposition = 9;
}
}
else
{
cf->scrollposition = 0;
}
}
}
int16_t textX = (hasIcon) ? ((24 - getTextWidth(cf->text.c_str(),false)) / 2) + 9 : ((32 - getTextWidth(cf->text.c_str(),false)) / 2);
matrix->setTextColor(cf->color);
// Check if text is scrolling or not
bool noScrolling = getTextWidth(cf->text.c_str()) <= availableWidth;
if (noScrolling)
{
cf->repeat = -1; // Disable repeat if text is too short for scrolling
// Display text with rainbow effect if enabled
if (cf->rainbow)
{
@@ -322,8 +357,7 @@ void ShowCustomFrame(uint8_t id, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
else
{
// Display text
DisplayManager.printText(x + textX, y + 6, cf->text.c_str(), false);
DisplayManager.printText(x + textX, y + 6, cf->text.c_str(), false, false);
}
}
else
@@ -335,7 +369,7 @@ void ShowCustomFrame(uint8_t id, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
}
else
{
DisplayManager.printText(x + cf->scrollposition, 6 + y, cf->text.c_str(), false);
DisplayManager.printText(x + cf->scrollposition, 6 + y, cf->text.c_str(), false, false);
}
} // Display icon if present and not pushed
if (hasIcon)
@@ -343,14 +377,14 @@ void ShowCustomFrame(uint8_t id, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
// Push icon if enabled and text is scrolling
if (cf->pushIcon > 0 && !noScrolling)
{
if (cf->iconPosition < 0 && cf->iconWasPushed == false && cf->scrollposition > 9)
if (cf->iconPosition < 0 && cf->iconWasPushed == false && cf->scrollposition > 8)
{
++cf->iconPosition;
}
if (cf->scrollposition < 9 && !cf->iconWasPushed)
if (cf->scrollposition < 8 && !cf->iconWasPushed)
{
cf->iconPosition = cf->scrollposition - 9;
cf->iconPosition = cf->scrollposition - 8;
if (cf->iconPosition <= -9)
{
@@ -376,10 +410,9 @@ void ShowCustomFrame(uint8_t id, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
// Draw vertical line if text is scrolling
if (!noScrolling)
{
matrix->drawLine(8 + x + notify.iconPosition, 0 + y, 8 + x + notify.iconPosition, 7 + y, 0);
// matrix->drawLine(8 + x + cf->iconPosition, 0 + y, 8 + x + cf->iconPosition, 7 + y, 0);
}
}
// Reset text color
DisplayManager.getInstance().resetTextColor();
}
@@ -407,6 +440,7 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
notify.scrollposition = 34;
notify.iconWasPushed = false;
notify.iconPosition = 0;
notify.scrollDelay = 0;
return;
}
@@ -417,31 +451,58 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
matrix->fillRect(0, 0, 32, 8, 0);
// Calculate text and available width
uint16_t textWidth = getTextWidth(notify.text.c_str());
uint16_t textWidth = getTextWidth(notify.text.c_str(),false);
uint16_t availableWidth = hasIcon ? 24 : 32;
// Check if text is scrolling
bool noScrolling = textWidth <= availableWidth;
// Check if text needs to be scrolled
if (textWidth > availableWidth && notify.scrollposition <= -textWidth)
{
// Reset scroll position and icon position if needed
notify.scrollposition = 38;
notify.scrollDelay = 0;
notify.scrollposition = 9;
if (notify.pushIcon == 2)
{
notify.iconWasPushed = false;
// notify.iconPosition = 0;
}
if (notify.repeat > 0)
{
--notify.repeat;
if (notify.repeat == 0)
return;
}
}
else if (textWidth > availableWidth)
if (!noScrolling)
{
if ((notify.scrollDelay > MATRIX_FPS * 1.2))
{
// Update scroll position
--notify.scrollposition;
}
else
{
++notify.scrollDelay;
if (hasIcon)
{
if (notify.iconWasPushed && notify.pushIcon == 1)
{
notify.scrollposition = 0;
}
else
{
notify.scrollposition = 9;
}
}
else
{
notify.scrollposition = 0;
}
}
}
// Calculate text X position based on icon presence
int16_t textX = hasIcon ? ((24 - textWidth) / 2) + 9 : ((32 - textWidth) / 2);
@@ -449,9 +510,6 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
// Set text color
matrix->setTextColor(notify.color);
// Check if text is scrolling
bool noScrolling = textWidth <= availableWidth;
if (noScrolling)
{
// Disable repeat if text is not scrolling
@@ -465,7 +523,7 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
else
{
// Display text in solid color
DisplayManager.printText(textX, 6, notify.text.c_str(), false);
DisplayManager.printText(textX, 6, notify.text.c_str(), false, false);
}
}
else
@@ -478,7 +536,7 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
else
{
// Display scrolling text in solid color
DisplayManager.printText(notify.scrollposition, 6, notify.text.c_str(), false);
DisplayManager.printText(notify.scrollposition, 6, notify.text.c_str(), false, false);
}
}
@@ -488,12 +546,12 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
// Push icon if enabled and text is scrolling
if (notify.pushIcon > 0 && !noScrolling)
{
if (notify.iconPosition < 0 && notify.iconWasPushed == false && notify.scrollposition > 9)
if (notify.iconPosition < 0 && notify.iconWasPushed == false && notify.scrollposition > 8)
{
++notify.iconPosition;
}
if (notify.scrollposition < 9 && !notify.iconWasPushed)
if (notify.scrollposition < 8 && !notify.iconWasPushed)
{
notify.iconPosition = notify.scrollposition - 9;
@@ -519,7 +577,7 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
// Display icon divider line if text is scrolling
if (!noScrolling)
{
matrix->drawLine(8 + notify.iconPosition, 0, 8 + notify.iconPosition, 7, 0);
// matrix->drawLine(8 + notify.iconPosition, 0, 8 + notify.iconPosition, 7, 0);
}
}
@@ -529,52 +587,62 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
void CFrame1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(1, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame1);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
void CFrame2(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(2, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame2);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
void CFrame3(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(3, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame3);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
void CFrame4(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(4, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame4);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
void CFrame5(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(5, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame5);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
void CFrame6(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(6, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame6);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
void CFrame7(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(7, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame7);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
void CFrame8(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(8, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame8);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
void CFrame9(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(9, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame9);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
void CFrame10(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
{
ShowCustomFrame(10, matrix, state, x, y, firstFrame, lastFrame);
String name = getFrameNameByFunction(CFrame10);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame);
}
const uint16_t *getWeatherIcon(int code)
@@ -599,7 +667,7 @@ void WeatherFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_
DisplayManager.getInstance().resetTextColor();
matrix->drawRGBBitmap(x, y, getWeatherIcon(WEATHER_CODE), 8, 8);
String text = WEATHER_TEMP + "°" + WEATHER_HUM + "%";
uint16_t textWidth = getTextWidth(text.c_str());
uint16_t textWidth = getTextWidth(text.c_str(), false);
int16_t textX = ((23 - textWidth) / 2);
matrix->setCursor(textX + 11, 6 + y);
matrix->print(utf8ascii(text));
@@ -647,6 +715,5 @@ void StartAppUpdater()
// getWeatherData();
}
std::vector<std::pair<uint16_t, AppCallback>> Apps;
OverlayCallback overlays[] = {MenuFrame, NotifyFrame, AlarmFrame, TimerFrame};
#endif

View File

@@ -28,13 +28,13 @@ uint16_t hexToRgb565(String hexValue)
return color;
}
uint16_t getTextWidth(const char *text)
uint16_t getTextWidth(const char *text, bool ignoreUpperCase)
{
uint16_t width = 0;
for (const char *c = text; *c != '\0'; ++c)
{
char current_char = *c;
if (UPPERCASE_LETTERS)
if (UPPERCASE_LETTERS && !ignoreUpperCase)
{
current_char = toupper(current_char);
}

View File

@@ -11,6 +11,8 @@ void loadSettings()
AUTO_BRIGHTNESS = Settings.getBool("ABRI", true);
TEXTCOLOR_565 = Settings.getUInt("COL", 0xFFFF);
AUTO_TRANSITION = Settings.getBool("TRANS", true);
TIME_PER_TRANSITION = Settings.getUInt("TSPEED", 500);
TIME_PER_APP = Settings.getUInt("ADUR", 5000);
Settings.end();
}
@@ -22,6 +24,8 @@ void saveSettings()
Settings.putBool("ABRI", AUTO_BRIGHTNESS);
Settings.putBool("TRANS", AUTO_TRANSITION);
Settings.putUInt("COL", TEXTCOLOR_565);
Settings.putUInt("TSPEED", TIME_PER_TRANSITION);
Settings.putUInt("ADUR", TIME_PER_APP);
Settings.end();
}
@@ -30,7 +34,7 @@ IPAddress gateway;
IPAddress subnet;
IPAddress primaryDNS;
IPAddress secondaryDNS;
const char *VERSION = "0.33";
const char *VERSION = "0.35";
String MQTT_HOST = "";
uint16_t MQTT_PORT = 1883;
String MQTT_USER;
@@ -51,7 +55,7 @@ String NET_GW = "192.168.178.1";
String NET_SN = "255.255.255.0";
String NET_PDNS = "8.8.8.8";
String NET_SDNS = "1.1.1.1";
int TIME_PER_FRAME = 7000;
int TIME_PER_APP = 7000;
uint8_t MATRIX_FPS = 23;
int TIME_PER_TRANSITION = 500;
String NTP_SERVER = "de.pool.ntp.org";

View File

@@ -28,7 +28,7 @@ extern String NET_GW;
extern String NET_SN;
extern String NET_PDNS;
extern String NET_SDNS;
extern int TIME_PER_FRAME;
extern int TIME_PER_APP;
extern uint8_t MATRIX_FPS;
extern int TIME_PER_TRANSITION;
extern String NTP_SERVER;

View File

@@ -132,6 +132,12 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length)
return;
}
if (strTopic == MQTT_PREFIX + "/switch")
{
DisplayManager.switchToApp(strPayload);
return;
}
else if (strTopic.startsWith(MQTT_PREFIX + "/custom"))
{
String topic_str = topic;
@@ -140,8 +146,8 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length)
{
topic_str = topic_str.substring(prefix.length());
}
uint16_t id = topic_str.toInt();
DisplayManager.generateCustomPage(id, strPayload);
DisplayManager.generateCustomPage(topic_str, strPayload);
return;
}
}
@@ -154,6 +160,7 @@ void onMqttConnected()
mqtt.subscribe((prefix + String("/notify")).c_str());
mqtt.subscribe((prefix + String("/timer")).c_str());
mqtt.subscribe((prefix + String("/custom/#")).c_str());
mqtt.subscribe((prefix + String("/switch")).c_str());
Serial.println("MQTT Connected");
}

View File

@@ -18,12 +18,13 @@ enum MenuState
RadioMenu,
StationSelection,
PlayingStation,
Reset,
VolumeMenu,
BrightnessMenu,
FPSMenu,
ColorMenu,
SwitchMenu
SwitchMenu,
TspeedMenu,
AppTimeMenu
};
const char *menuItems[] = {
@@ -31,9 +32,10 @@ const char *menuItems[] = {
"FPS",
"COLOR",
"SWITCH",
"RESET"};
"T-SPEED",
"APPTIME"};
byte menuItemCount = 5;
byte menuItemCount = 6;
MenuState currentState = MainMenu;
@@ -98,6 +100,18 @@ String MenuManager_::menutext()
{
return AUTO_TRANSITION ? "ON" : "OFF";
}
else if (currentState == TspeedMenu)
{
float seconds = (float)TIME_PER_TRANSITION / 1000.0;
return String(seconds, 1) + "s";
;
}
else if (currentState == AppTimeMenu)
{
float seconds = (float)TIME_PER_APP / 1000.0;
return String(seconds, 0) + "s";
;
}
return "";
}
@@ -142,6 +156,14 @@ void MenuManager_::rightButton()
{
AUTO_TRANSITION = !AUTO_TRANSITION;
}
else if (currentState == TspeedMenu)
{
TIME_PER_TRANSITION = min(1200, TIME_PER_TRANSITION + 100);
}
else if (currentState == AppTimeMenu)
{
TIME_PER_APP = min(30000, TIME_PER_APP + 1000);
}
}
void MenuManager_::leftButton()
@@ -185,6 +207,14 @@ void MenuManager_::leftButton()
{
AUTO_TRANSITION = !AUTO_TRANSITION;
}
else if (currentState == TspeedMenu)
{
TIME_PER_TRANSITION = max(200, TIME_PER_TRANSITION - 100);
}
else if (currentState == AppTimeMenu)
{
TIME_PER_APP = max(1000, TIME_PER_APP - 1000);
}
}
void MenuManager_::selectButton()
@@ -210,9 +240,13 @@ void MenuManager_::selectButton()
{
currentState = SwitchMenu;
}
else if (menuIndex == 4) // FPS
else if (menuIndex == 4) // TSPEED
{
ESP.restart();
currentState = TspeedMenu;
}
else if (menuIndex == 5) // AppTIme
{
currentState = AppTimeMenu;
}
}
else if (currentState == StationSelection)
@@ -253,6 +287,16 @@ void MenuManager_::selectButtonLong()
DisplayManager.setAutoTransition(AUTO_TRANSITION);
saveSettings();
}
else if (currentState == TspeedMenu)
{
DisplayManager.setSettings();
saveSettings();
}
else if (currentState == AppTimeMenu)
{
DisplayManager.setSettings();
saveSettings();
}
currentState = MainMenu;
}
else

View File

@@ -94,8 +94,6 @@ void ServerManager_::setup()
mws.addCSS(custom_css);
mws.addJavascript(custom_script);
mws.addOptionBox("General");
mws.addOption("Duration per Page", TIME_PER_FRAME);
mws.addOption("Transistion duration", TIME_PER_TRANSITION);
mws.addOption("Uppercase letters", UPPERCASE_LETTERS);
mws.addOption("Show date", SHOW_DATE);
mws.addOption("Show temperature", SHOW_TEMP);
@@ -193,8 +191,6 @@ void ServerManager_::loadSettings()
MQTT_USER = doc["Username"].as<String>();
MQTT_PASS = doc["Password"].as<String>();
MQTT_PREFIX = doc["Prefix"].as<String>();
TIME_PER_FRAME = doc["Duration per Page"].as<int>();
TIME_PER_TRANSITION = doc["Transistion duration"].as<int>();
NET_STATIC = doc["Static IP"];
HA_DISCOVERY = doc["Homeassistant Discovery"];
NET_IP = doc["Local IP"].as<String>();