- App transistion is now inacitve if there is only 1 app
- Adds bargraph to notify and customapps
- Every awtrix now gets a unique id for AP, MQTT and HA
- Adds firmware as HA sensor
- Adds wifi strength as HA sensor
- Adds ram usage as HA sensor
- Adds version as HA sensor
- Adds uptime as ISO 8601 as HA sensot
- HA discorvery now gets correct device classes
- fixes bug where date formats are not saved

closes #24
closes #23
closes #21
This commit is contained in:
Stephan Mühl
2023-03-29 00:24:38 +02:00
parent 3de324605e
commit c51c769cb5
16 changed files with 1217 additions and 967 deletions

View File

@@ -7,11 +7,11 @@ https://paypal.me/blueforcer
Awtrix Light is a custom firmware for the [Ulanzi Smart Pixel clock](https://www.ulanzi.com/products/ulanzi-pixel-smart-clock-2882). Awtrix Light is a custom firmware for the [Ulanzi Smart Pixel clock](https://www.ulanzi.com/products/ulanzi-pixel-smart-clock-2882).
That offers a simple and user-friendly interface, making it the perfect solution for non-techies who want to enjoy the benefits of the popular awtrix system. That offers a simple and user-friendly interface, making it the perfect solution for non-techies who want to enjoy the benefits of the popular awtrix system.
It is ready to use straight out of the box, with time, date, temperature, and humidity pages pre-installed. You don't need to do anything other than turning it on to start using these features. It is ready to use straight out of the box, with time, date, temperature, and humidity apps pre-installed. You don't need to do anything other than turning it on to start using these features.
During the development of Awtrix Light, usability and simplicity are my top priorities. My aim is to make it easy for non-tech-savvy users to benefit from Awtrix Light without any headaches or hours of scripting. During the development of Awtrix Light, usability and simplicity are my top priorities. My aim is to make it easy for non-tech-savvy users to benefit from Awtrix Light without any headaches or hours of scripting.
Awtrix Light is ready to use straight out of the box, without the need for a single line of code or commands. Awtrix Light is ready to use straight out of the box, without the need for a single line of code or commands.
However, for those with more advanced skills, the customization options available with custom pages allow you to take Awtrix Light to its full potential. However, for those with more advanced skills, the customization options available with custom apps allow you to take Awtrix Light to its full potential.
With Awtrix Light, you can effortlessly bring your ideas to life and enjoy a hassle-free experience. With Awtrix Light, you can effortlessly bring your ideas to life and enjoy a hassle-free experience.
Join the thousands of satisfied awtrix users who have already chosen Awtrix 2 and Awtrix Light and experience the difference today! Join the thousands of satisfied awtrix users who have already chosen Awtrix 2 and Awtrix Light and experience the difference today!
https://discord.gg/cyBCpdx https://discord.gg/cyBCpdx

View File

@@ -1,6 +1,6 @@
# Custom Pages & Notifications # Custom Apps & Notifications
With AWTRIX Light, you can create custom pages or notifications to display your own text and icons. With AWTRIX Light, you can create custom apps or notifications to display your own text and icons.
Simply send a JSON object to the topic "awtrixlight/custom/[page]" where [page] is a the name of your page (without spaces). Simply send a JSON object to the topic "awtrixlight/custom/[page]" where [page] is a the name of your page (without spaces).
## JSON Properties ## JSON Properties
@@ -19,6 +19,7 @@ The JSON object has the following properties:
| `hold` | boolean | Set it to true, to hold your notification on top until you press the middle button or dismiss it via HomeAssistant. This key only belongs to notification. | false | | `hold` | boolean | Set it to true, to hold your notification on top until you press the middle button or dismiss it via HomeAssistant. This key only belongs to notification. | false |
| `sound` | string | The filename of your RTTTL ringtone file (without extension). | | | `sound` | string | The filename of your RTTTL ringtone file (without extension). | |
| `pushIcon` | number | 0 = Icon doesn't move. 1 = Icon moves with text and will not appear again. 2 = Icon moves with text but appears again when the text starts to scroll again. | 0 | | `pushIcon` | number | 0 = Icon doesn't move. 1 = Icon moves with text and will not appear again. 2 = Icon moves with text but appears again when the text starts to scroll again. | 0 |
| `bar` | array of integers | draws a bargraph. Without icon maximum 16 values, with icon 11 values | |
All keys are optional, so you can send just the properties you want to use. All keys are optional, so you can send just the properties you want to use.

View File

@@ -29,7 +29,7 @@ Built-in app names are:
- `hum` - `hum`
- `bat` - `bat`
For custom pages, use the name you set in the topic. For example, if `[PREFIX]/custom/test` is your topic, then `test` is the name. For custom apps, use the name you set in the topic. For example, if `[PREFIX]/custom/test` is your topic, then `test` is the name.
## Change Settings ## Change Settings
Change various settings related to the app display. Change various settings related to the app display.

View File

@@ -48,9 +48,9 @@ void MatrixDisplayUi::setTargetFPS(uint8_t fps)
float oldInterval = this->updateInterval; float oldInterval = this->updateInterval;
this->updateInterval = ((float)1.0 / (float)fps) * 1000; this->updateInterval = ((float)1.0 / (float)fps) * 1000;
// Calculate new ticksPerFrame // Calculate new ticksPerApp
float changeRatio = oldInterval / (float)this->updateInterval; float changeRatio = oldInterval / (float)this->updateInterval;
this->ticksPerFrame *= changeRatio; this->ticksPerApp *= changeRatio;
this->ticksPerTransition *= changeRatio; this->ticksPerTransition *= changeRatio;
} }
@@ -66,33 +66,34 @@ void MatrixDisplayUi::disablesetAutoTransition()
} }
void MatrixDisplayUi::setsetAutoTransitionForwards() void MatrixDisplayUi::setsetAutoTransitionForwards()
{ {
this->state.frameTransitionDirection = 1; this->state.appTransitionDirection = 1;
this->lastTransitionDirection = 1; this->lastTransitionDirection = 1;
} }
void MatrixDisplayUi::setsetAutoTransitionBackwards() void MatrixDisplayUi::setsetAutoTransitionBackwards()
{ {
this->state.frameTransitionDirection = -1; this->state.appTransitionDirection = -1;
this->lastTransitionDirection = -1; this->lastTransitionDirection = -1;
} }
void MatrixDisplayUi::setTimePerApp(uint16_t time) void MatrixDisplayUi::setTimePerApp(uint16_t time)
{ {
this->ticksPerFrame = (int)((float)time / (float)updateInterval); this->ticksPerApp = (int)((float)time / (float)updateInterval);
} }
void MatrixDisplayUi::setTimePerTransition(uint16_t time) void MatrixDisplayUi::setTimePerTransition(uint16_t time)
{ {
this->ticksPerTransition = (int)((float)time / (float)updateInterval); this->ticksPerTransition = (int)((float)time / (float)updateInterval);
} }
// -/----- Frame settings -----\- // -/----- App settings -----\-
void MatrixDisplayUi::setAppAnimation(AnimationDirection dir) void MatrixDisplayUi::setAppAnimation(AnimationDirection dir)
{ {
this->frameAnimationDirection = dir; this->appAnimationDirection = dir;
} }
void MatrixDisplayUi::setApps(const std::vector<std::pair<String, AppCallback>> &appPairs) void MatrixDisplayUi::setApps(const std::vector<std::pair<String, AppCallback>> &appPairs)
{ {
delete[] AppFunctions; delete[] AppFunctions;
AppCount = appPairs.size(); AppCount = appPairs.size();
Serial.println(AppCount);
AppFunctions = new AppCallback[AppCount]; AppFunctions = new AppCallback[AppCount];
for (size_t i = 0; i < AppCount; ++i) for (size_t i = 0; i < AppCount; ++i)
@@ -113,51 +114,51 @@ void MatrixDisplayUi::setOverlays(OverlayCallback *overlayFunctions, uint8_t ove
// -/----- Manuel control -----\- // -/----- Manuel control -----\-
void MatrixDisplayUi::nextApp() void MatrixDisplayUi::nextApp()
{ {
if (this->state.frameState != IN_TRANSITION) if (this->state.appState != IN_TRANSITION)
{ {
this->state.manuelControll = true; this->state.manuelControll = true;
this->state.frameState = IN_TRANSITION; this->state.appState = IN_TRANSITION;
this->state.ticksSinceLastStateSwitch = 0; this->state.ticksSinceLastStateSwitch = 0;
this->lastTransitionDirection = this->state.frameTransitionDirection; this->lastTransitionDirection = this->state.appTransitionDirection;
this->state.frameTransitionDirection = 1; this->state.appTransitionDirection = 1;
} }
} }
void MatrixDisplayUi::previousApp() void MatrixDisplayUi::previousApp()
{ {
if (this->state.frameState != IN_TRANSITION) if (this->state.appState != IN_TRANSITION)
{ {
this->state.manuelControll = true; this->state.manuelControll = true;
this->state.frameState = IN_TRANSITION; this->state.appState = IN_TRANSITION;
this->state.ticksSinceLastStateSwitch = 0; this->state.ticksSinceLastStateSwitch = 0;
this->lastTransitionDirection = this->state.frameTransitionDirection; this->lastTransitionDirection = this->state.appTransitionDirection;
this->state.frameTransitionDirection = -1; this->state.appTransitionDirection = -1;
} }
} }
void MatrixDisplayUi::switchToApp(uint8_t frame) void MatrixDisplayUi::switchToApp(uint8_t app)
{ {
if (frame >= this->AppCount) if (app >= this->AppCount)
return; return;
this->state.ticksSinceLastStateSwitch = 0; this->state.ticksSinceLastStateSwitch = 0;
if (frame == this->state.currentFrame) if (app == this->state.currentApp)
return; return;
this->state.frameState = FIXED; this->state.appState = FIXED;
this->state.currentFrame = frame; this->state.currentApp = app;
} }
void MatrixDisplayUi::transitionToApp(uint8_t frame) void MatrixDisplayUi::transitionToApp(uint8_t app)
{ {
if (frame >= this->AppCount) if (app >= this->AppCount)
return; return;
this->state.ticksSinceLastStateSwitch = 0; this->state.ticksSinceLastStateSwitch = 0;
if (frame == this->state.currentFrame) if (app == this->state.currentApp)
return; return;
this->nextAppNumber = frame; this->nextAppNumber = app;
this->lastTransitionDirection = this->state.frameTransitionDirection; this->lastTransitionDirection = this->state.appTransitionDirection;
this->state.manuelControll = true; this->state.manuelControll = true;
this->state.frameState = IN_TRANSITION; this->state.appState = IN_TRANSITION;
this->state.frameTransitionDirection = frame < this->state.currentFrame ? -1 : 1; this->state.appTransitionDirection = app < this->state.currentApp ? -1 : 1;
} }
// -/----- State information -----\- // -/----- State information -----\-
@@ -168,18 +169,18 @@ MatrixDisplayUiState *MatrixDisplayUi::getUiState()
int8_t MatrixDisplayUi::update() int8_t MatrixDisplayUi::update()
{ {
long frameStart = millis(); long appStart = millis();
int8_t timeBudget = this->updateInterval - (frameStart - this->state.lastUpdate); int8_t timeBudget = this->updateInterval - (appStart - this->state.lastUpdate);
if (timeBudget <= 0) if (timeBudget <= 0)
{ {
// Implement frame skipping to ensure time budget is keept // Implement app skipping to ensure time budget is keept
if (this->setAutoTransition && this->state.lastUpdate != 0) if (this->setAutoTransition && this->state.lastUpdate != 0)
this->state.ticksSinceLastStateSwitch += ceil(-timeBudget / this->updateInterval); this->state.ticksSinceLastStateSwitch += ceil(-timeBudget / this->updateInterval);
this->state.lastUpdate = frameStart; this->state.lastUpdate = appStart;
this->tick(); this->tick();
} }
return this->updateInterval - (millis() - frameStart); return this->updateInterval - (millis() - appStart);
} }
void MatrixDisplayUi::tick() void MatrixDisplayUi::tick()
@@ -188,13 +189,13 @@ void MatrixDisplayUi::tick()
if (this->AppCount > 0) if (this->AppCount > 0)
{ {
switch (this->state.frameState) switch (this->state.appState)
{ {
case IN_TRANSITION: case IN_TRANSITION:
if (this->state.ticksSinceLastStateSwitch >= this->ticksPerTransition) if (this->state.ticksSinceLastStateSwitch >= this->ticksPerTransition)
{ {
this->state.frameState = FIXED; this->state.appState = FIXED;
this->state.currentFrame = getnextAppNumber(); this->state.currentApp = getnextAppNumber();
this->state.ticksSinceLastStateSwitch = 0; this->state.ticksSinceLastStateSwitch = 0;
this->nextAppNumber = -1; this->nextAppNumber = -1;
} }
@@ -203,14 +204,14 @@ void MatrixDisplayUi::tick()
// Revert manuelControll // Revert manuelControll
if (this->state.manuelControll) if (this->state.manuelControll)
{ {
this->state.frameTransitionDirection = this->lastTransitionDirection; this->state.appTransitionDirection = this->lastTransitionDirection;
this->state.manuelControll = false; this->state.manuelControll = false;
} }
if (this->state.ticksSinceLastStateSwitch >= this->ticksPerFrame) if (this->state.ticksSinceLastStateSwitch >= this->ticksPerApp)
{ {
if (this->setAutoTransition) if (this->setAutoTransition)
{ {
this->state.frameState = IN_TRANSITION; this->state.appState = IN_TRANSITION;
} }
this->state.ticksSinceLastStateSwitch = 0; this->state.ticksSinceLastStateSwitch = 0;
} }
@@ -227,13 +228,13 @@ void MatrixDisplayUi::tick()
void MatrixDisplayUi::drawApp() void MatrixDisplayUi::drawApp()
{ {
switch (this->state.frameState) switch (this->state.appState)
{ {
case IN_TRANSITION: case IN_TRANSITION:
{ {
float progress = (float)this->state.ticksSinceLastStateSwitch / (float)this->ticksPerTransition; float progress = (float)this->state.ticksSinceLastStateSwitch / (float)this->ticksPerTransition;
int16_t x, y, x1, y1; int16_t x, y, x1, y1;
switch (this->frameAnimationDirection) switch (this->appAnimationDirection)
{ {
case SLIDE_LEFT: case SLIDE_LEFT:
x = -32 * progress; x = -32 * progress;
@@ -261,20 +262,20 @@ void MatrixDisplayUi::drawApp()
break; break;
} }
// Invert animation if direction is reversed. // Invert animation if direction is reversed.
int8_t dir = this->state.frameTransitionDirection >= 0 ? 1 : -1; int8_t dir = this->state.appTransitionDirection >= 0 ? 1 : -1;
x *= dir; x *= dir;
y *= dir; y *= dir;
x1 *= dir; x1 *= dir;
y1 *= dir; y1 *= dir;
bool FirstFrame = progress < 0.2; bool FirstApp = progress < 0.2;
bool LastFrame = progress > 0.8; bool LastApp = progress > 0.8;
this->matrix->drawRect(x, y, x1, y1, matrix->Color(0, 0, 0)); 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->state.currentApp])(this->matrix, &this->state, x, y, FirstApp, LastApp);
(this->AppFunctions[this->getnextAppNumber()])(this->matrix, &this->state, x1, y1, FirstFrame, LastFrame); (this->AppFunctions[this->getnextAppNumber()])(this->matrix, &this->state, x1, y1, FirstApp, LastApp);
break; break;
} }
case FIXED: case FIXED:
(this->AppFunctions[this->state.currentFrame])(this->matrix, &this->state, 0, 0, false, false); (this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, 0, 0, false, false);
break; break;
} }
} }
@@ -283,8 +284,8 @@ void MatrixDisplayUi::resetState()
{ {
this->state.lastUpdate = 0; this->state.lastUpdate = 0;
this->state.ticksSinceLastStateSwitch = 0; this->state.ticksSinceLastStateSwitch = 0;
this->state.frameState = FIXED; this->state.appState = FIXED;
this->state.currentFrame = 0; this->state.currentApp = 0;
} }
void MatrixDisplayUi::drawOverlays() void MatrixDisplayUi::drawOverlays()
@@ -299,5 +300,5 @@ uint8_t MatrixDisplayUi::getnextAppNumber()
{ {
if (this->nextAppNumber != -1) if (this->nextAppNumber != -1)
return this->nextAppNumber; return this->nextAppNumber;
return (this->state.currentFrame + this->AppCount + this->state.frameTransitionDirection) % this->AppCount; return (this->state.currentApp + this->AppCount + this->state.appTransitionDirection) % this->AppCount;
} }

View File

@@ -46,7 +46,7 @@ enum AnimationDirection
SLIDE_RIGHT SLIDE_RIGHT
}; };
enum FrameState enum AppState
{ {
IN_TRANSITION, IN_TRANSITION,
FIXED FIXED
@@ -58,11 +58,11 @@ struct MatrixDisplayUiState
u_int64_t lastUpdate = 0; u_int64_t lastUpdate = 0;
uint16_t ticksSinceLastStateSwitch = 0; uint16_t ticksSinceLastStateSwitch = 0;
FrameState frameState = FIXED; AppState appState = FIXED;
uint8_t currentFrame = 0; uint8_t currentApp = 0;
// Normal = 1, Inverse = -1; // Normal = 1, Inverse = -1;
int8_t frameTransitionDirection = 1; int8_t appTransitionDirection = 1;
bool manuelControll = false; bool manuelControll = false;
@@ -70,7 +70,7 @@ struct MatrixDisplayUiState
void *userData = NULL; void *userData = NULL;
}; };
typedef void (*AppCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame); typedef void (*AppCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp);
typedef void (*OverlayCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state); typedef void (*OverlayCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state);
class MatrixDisplayUi class MatrixDisplayUi
@@ -78,21 +78,19 @@ class MatrixDisplayUi
private: private:
FastLED_NeoMatrix *matrix; FastLED_NeoMatrix *matrix;
// Values for the Frames // Values for the Apps
AnimationDirection frameAnimationDirection = SLIDE_RIGHT; AnimationDirection appAnimationDirection = SLIDE_RIGHT;
int8_t lastTransitionDirection = 1; int8_t lastTransitionDirection = 1;
uint16_t ticksPerFrame = 151; // ~ 5000ms at 30 FPS uint16_t ticksPerApp = 151; // ~ 5000ms at 30 FPS
uint16_t ticksPerTransition = 15; // ~ 500ms at 30 FPS uint16_t ticksPerTransition = 15; // ~ 500ms at 30 FPS
bool setAutoTransition = true; bool setAutoTransition = true;
AppCallback *AppFunctions; AppCallback *AppFunctions;
uint8_t AppCount = 0; // Internally used to transition to a specific app
// Internally used to transition to a specific frame
int8_t nextAppNumber = -1; int8_t nextAppNumber = -1;
// Values for Overlays // Values for Overlays
@@ -115,6 +113,7 @@ private:
public: public:
MatrixDisplayUi(FastLED_NeoMatrix *matrix); MatrixDisplayUi(FastLED_NeoMatrix *matrix);
uint8_t AppCount = 0;
/** /**
* Initialise the display * Initialise the display
*/ */
@@ -127,12 +126,12 @@ public:
// Automatic Controll // Automatic Controll
/** /**
* Enable automatic transition to next frame after the some time can be configured with `setTimePerApp` and `setTimePerTransition`. * Enable automatic transition to next app after the some time can be configured with `setTimePerApp` and `setTimePerTransition`.
*/ */
void enablesetAutoTransition(); void enablesetAutoTransition();
/** /**
* Disable automatic transition to next frame. * Disable automatic transition to next app.
*/ */
void disablesetAutoTransition(); void disablesetAutoTransition();
@@ -143,7 +142,7 @@ public:
void setsetAutoTransitionBackwards(); void setsetAutoTransitionBackwards();
/** /**
* Set the approx. time a frame is displayed * Set the approx. time a app is displayed
*/ */
void setTimePerApp(uint16_t time); void setTimePerApp(uint16_t time);
@@ -154,22 +153,22 @@ public:
// Customize indicator position and style // Customize indicator position and style
// Frame settings // App settings
/** /**
* Configure what animation is used to transition from one frame to another * Configure what animation is used to transition from one app to another
*/ */
void setAppAnimation(AnimationDirection dir); void setAppAnimation(AnimationDirection dir);
/** /**
* Add frame drawing functions * Add app drawing functions
*/ */
void setApps(const std::vector<std::pair<String, AppCallback>> &appPairs); void setApps(const std::vector<std::pair<String, AppCallback>> &appPairs);
// Overlay // Overlay
/** /**
* Add overlays drawing functions that are draw independent of the Frames * Add overlays drawing functions that are draw independent of the Apps
*/ */
void setOverlays(OverlayCallback *overlayFunctions, uint8_t overlayCount); void setOverlays(OverlayCallback *overlayFunctions, uint8_t overlayCount);
@@ -178,15 +177,15 @@ public:
void previousApp(); void previousApp();
/** /**
* Switch without transition to frame `frame`. * Switch without transition to app `app`.
*/ */
void switchToApp(uint8_t frame); void switchToApp(uint8_t app);
/** /**
* Transition to frame `frame`, when the `frame` number is bigger than the current * Transition to app `app`, when the `app` number is bigger than the current
* frame the forward animation will be used, otherwise the backwards animation is used. * app the forward animation will be used, otherwise the backwards animation is used.
*/ */
void transitionToApp(uint8_t frame); void transitionToApp(uint8_t app);
// State Info // State Info
MatrixDisplayUiState *getUiState(); MatrixDisplayUiState *getUiState();

View File

@@ -8,12 +8,28 @@
; Please visit documentation for the other options and examples ; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[env:esp32dev] [env:ulanzi]
platform = https://github.com/platformio/platform-espressif32.git platform = https://github.com/platformio/platform-espressif32.git
board = esp32dev board = esp32dev
board_build.partitions = awtrix_partition.csv board_build.partitions = awtrix_partition.csv
upload_speed = 921600 upload_speed = 921600
framework = arduino framework = arduino
build_flags = -DULANZI
lib_deps =
adafruit/Adafruit SHT31 Library@^2.2.0
bblanchon/ArduinoJson@^6.20.0
evert-arias/EasyButton@^2.0.1
fastled/FastLED@^3.5.0
marcmerlin/FastLED NeoMatrix@^1.2
knolleary/PubSubClient@^2.8
[env:awtrix_upgrade]
platform = https://github.com/platformio/platform-espressif32.git
board = wemos_d1_mini32
board_build.partitions = awtrix_partition.csv
upload_speed = 921600
framework = arduino
build_flags = -DAWTRIX_UPGRADE
lib_deps = lib_deps =
adafruit/Adafruit SHT31 Library@^2.2.0 adafruit/Adafruit SHT31 Library@^2.2.0
bblanchon/ArduinoJson@^6.20.0 bblanchon/ArduinoJson@^6.20.0

View File

@@ -1,5 +1,5 @@
#ifndef FRAMES_H #ifndef AppS_H
#define FRAMES_H #define AppS_H
#include <vector> #include <vector>
#include <map> #include <map>
@@ -26,7 +26,7 @@ int WEATHER_CODE;
String WEATHER_TEMP; String WEATHER_TEMP;
String WEATHER_HUM; String WEATHER_HUM;
struct CustomFrame struct CustomApp
{ {
int16_t scrollposition = 0; int16_t scrollposition = 0;
int16_t scrollDelay = 0; int16_t scrollDelay = 0;
@@ -43,10 +43,12 @@ struct CustomFrame
byte pushIcon = 0; byte pushIcon = 0;
int16_t iconPosition = 0; int16_t iconPosition = 0;
bool iconWasPushed = false; bool iconWasPushed = false;
int barData[16] = {0};
int barSize;
}; };
String currentCustomFrame; String currentCustomApp;
std::map<String, CustomFrame> customFrames; std::map<String, CustomApp> customApps;
struct Notification struct Notification
{ {
@@ -65,28 +67,30 @@ struct Notification
byte pushIcon = 0; byte pushIcon = 0;
int16_t iconPosition = 0; int16_t iconPosition = 0;
bool iconWasPushed = false; bool iconWasPushed = false;
int barData[16] = {0};
int barSize;
}; };
Notification notify; Notification notify;
std::vector<std::pair<String, AppCallback>> Apps; std::vector<std::pair<String, AppCallback>> Apps;
CustomFrame *getCustomFrameById(String name) CustomApp *getCustomAppById(String name)
{ {
return customFrames.count(name) ? &customFrames[name] : nullptr; return customApps.count(name) ? &customApps[name] : nullptr;
} }
String getFrameNameByFunction(AppCallback frameFunction) String getAppNameByFunction(AppCallback AppFunction)
{ {
for (const auto &appPair : Apps) for (const auto &appPair : Apps)
{ {
if (appPair.second == frameFunction) if (appPair.second == AppFunction)
{ {
return appPair.first; return appPair.first;
} }
} }
return ""; // Gibt einen leeren String zurück, wenn die Frame-Funktion nicht gefunden wurde return ""; // Gibt einen leeren String zurück, wenn die App-Funktion nicht gefunden wurde
} }
int findAppIndexByName(const String &name) int findAppIndexByName(const String &name)
@@ -100,7 +104,7 @@ int findAppIndexByName(const String &name)
return -1; return -1;
} }
void TimeFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void TimeApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
if (notify.flag) if (notify.flag)
return; return;
@@ -148,7 +152,7 @@ void TimeFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x
} }
} }
void DateFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void DateApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
if (notify.flag) if (notify.flag)
return; return;
@@ -176,7 +180,7 @@ void DateFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x
} }
} }
void TempFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void TempApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
if (notify.flag) if (notify.flag)
return; return;
@@ -197,7 +201,7 @@ void TempFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x
} }
} }
void HumFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
if (notify.flag) if (notify.flag)
return; return;
@@ -210,7 +214,7 @@ void HumFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x,
matrix->print("%"); matrix->print("%");
} }
void BatFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
if (notify.flag) if (notify.flag)
return; return;
@@ -222,7 +226,7 @@ void BatFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x,
matrix->print("%"); matrix->print("%");
} }
void MenuFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state) void MenuApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
{ {
if (!MenuManager.inMenu) if (!MenuManager.inMenu)
return; return;
@@ -230,7 +234,7 @@ void MenuFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
DisplayManager.printText(0, 6, utf8ascii(MenuManager.menutext()).c_str(), true, true); DisplayManager.printText(0, 6, utf8ascii(MenuManager.menutext()).c_str(), true, true);
} }
void AlarmFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state) void AlarmApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
{ {
if (ALARM_ACTIVE) if (ALARM_ACTIVE)
{ {
@@ -249,7 +253,7 @@ void AlarmFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
} }
} }
void TimerFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state) void TimerApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
{ {
if (TIMER_ACTIVE) if (TIMER_ACTIVE)
{ {
@@ -269,7 +273,7 @@ void TimerFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
} }
} }
void ShowCustomFrame(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
// Abort if notify.flag is set // Abort if notify.flag is set
if (notify.flag) if (notify.flag)
@@ -277,33 +281,38 @@ void ShowCustomFrame(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiStat
return; return;
} }
// Get custom frame by ID // Get custom App by ID
CustomFrame *cf = getCustomFrameById(name); CustomApp *ca = getCustomAppById(name);
// Abort if custom frame not found // Abort if custom App not found
if (cf == nullptr) if (ca == nullptr)
{ {
return; return;
} }
// reset custom frame properties if last frame // reset custom App properties if last App
if (lastFrame) if (lastApp)
{ {
cf->iconWasPushed = false; ca->iconWasPushed = false;
cf->scrollposition = 9; ca->scrollposition = 9;
cf->iconPosition = 0; ca->iconPosition = 0;
cf->scrollDelay = 0; ca->scrollDelay = 0;
} }
CURRENT_APP = cf->name; CURRENT_APP = ca->name;
currentCustomFrame = name; currentCustomApp = name;
bool hasIcon = cf->icon; bool hasIcon = ca->icon;
uint16_t availableWidth = (hasIcon) ? 24 : 32; uint16_t availableWidth = (hasIcon) ? 24 : 32;
bool noScrolling = getTextWidth(cf->text.c_str(), false) <= availableWidth; bool noScrolling = getTextWidth(ca->text.c_str(), false) <= availableWidth;
if (ca->barSize > 0)
if ((cf->repeat > 0) && (getTextWidth(cf->text.c_str(), false) > availableWidth) && (state->frameState == FIXED)) {
DisplayManager.drawBarChart(x, y, ca->barData, ca->barSize, hasIcon, ca->color);
}
else
{
if ((ca->repeat > 0) && (getTextWidth(ca->text.c_str(), false) > availableWidth) && (state->appState == FIXED))
{ {
DisplayManager.setAutoTransition(false); DisplayManager.setAutoTransition(false);
} }
@@ -312,130 +321,132 @@ void ShowCustomFrame(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiStat
DisplayManager.setAutoTransition(true); DisplayManager.setAutoTransition(true);
} }
if (getTextWidth(cf->text.c_str(), false) > availableWidth && !(state->frameState == IN_TRANSITION)) if (getTextWidth(ca->text.c_str(), false) > availableWidth && !(state->appState == IN_TRANSITION))
{ {
if (cf->scrollposition <= -getTextWidth(cf->text.c_str(), false)) if (ca->scrollposition <= -getTextWidth(ca->text.c_str(), false))
{ {
cf->scrollDelay = 0; ca->scrollDelay = 0;
cf->scrollposition = 9; ca->scrollposition = 9;
if (cf->iconWasPushed && cf->pushIcon == 2) if (ca->iconWasPushed && ca->pushIcon == 2)
{ {
cf->iconWasPushed = false; ca->iconWasPushed = false;
} }
if ((cf->currentRepeat + 1 >= cf->repeat) && (cf->repeat > 0)) if ((ca->currentRepeat + 1 >= ca->repeat) && (ca->repeat > 0))
{ {
DisplayManager.setAutoTransition(true); DisplayManager.setAutoTransition(true);
cf->currentRepeat = 0; ca->currentRepeat = 0;
DisplayManager.nextApp(); DisplayManager.nextApp();
return; return;
} }
else if (cf->repeat > 0) else if (ca->repeat > 0)
{ {
++cf->currentRepeat; ++ca->currentRepeat;
} }
} }
} }
if (!noScrolling) if (!noScrolling)
{ {
if ((cf->scrollDelay > MATRIX_FPS * 1.2)) if ((ca->scrollDelay > MATRIX_FPS * 1.2))
{ {
--cf->scrollposition; --ca->scrollposition;
} }
else else
{ {
++cf->scrollDelay; ++ca->scrollDelay;
if (hasIcon) if (hasIcon)
{ {
if (cf->iconWasPushed && cf->pushIcon == 1) if (ca->iconWasPushed && ca->pushIcon == 1)
{ {
cf->scrollposition = 0; ca->scrollposition = 0;
} }
else else
{ {
cf->scrollposition = 9; ca->scrollposition = 9;
} }
} }
else else
{ {
cf->scrollposition = 0; ca->scrollposition = 0;
} }
} }
} }
int16_t textX = (hasIcon) ? ((24 - getTextWidth(cf->text.c_str(), false)) / 2) + 9 : ((32 - getTextWidth(cf->text.c_str(), false)) / 2); int16_t textX = (hasIcon) ? ((24 - getTextWidth(ca->text.c_str(), false)) / 2) + 9 : ((32 - getTextWidth(ca->text.c_str(), false)) / 2);
matrix->setTextColor(cf->color); matrix->setTextColor(ca->color);
if (noScrolling) if (noScrolling)
{ {
cf->repeat = -1; // Disable repeat if text is too short for scrolling ca->repeat = -1; // Disable repeat if text is too short for scrolling
// Display text with rainbow effect if enabled // Display text with rainbow effect if enabled
if (cf->rainbow) if (ca->rainbow)
{ {
DisplayManager.getInstance().HSVtext(x + textX, 6 + y, cf->text.c_str(), false); DisplayManager.HSVtext(x + textX, 6 + y, ca->text.c_str(), false);
} }
else else
{ {
// Display text // Display text
DisplayManager.printText(x + textX, y + 6, cf->text.c_str(), false, false); DisplayManager.printText(x + textX, y + 6, ca->text.c_str(), false, false);
} }
} }
else else
{ {
// Display scrolling text with rainbow effect if enabled // Display scrolling text with rainbow effect if enabled
if (cf->rainbow) if (ca->rainbow)
{ {
DisplayManager.getInstance().HSVtext(x + cf->scrollposition, 6 + y, cf->text.c_str(), false); DisplayManager.HSVtext(x + ca->scrollposition, 6 + y, ca->text.c_str(), false);
} }
else else
{ {
DisplayManager.printText(x + cf->scrollposition, 6 + y, cf->text.c_str(), false, false); DisplayManager.printText(x + ca->scrollposition, 6 + y, ca->text.c_str(), false, false);
} }
} // Display icon if present and not pushed }
}
if (hasIcon) if (hasIcon)
{ {
// Push icon if enabled and text is scrolling // Push icon if enabled and text is scrolling
if (cf->pushIcon > 0 && !noScrolling) if (ca->pushIcon > 0 && !noScrolling && ca->barSize == 0)
{ {
if (cf->iconPosition < 0 && cf->iconWasPushed == false && cf->scrollposition > 8) if (ca->iconPosition < 0 && ca->iconWasPushed == false && ca->scrollposition > 8)
{ {
++cf->iconPosition; ++ca->iconPosition;
} }
if (cf->scrollposition < 8 && !cf->iconWasPushed) if (ca->scrollposition < 8 && !ca->iconWasPushed)
{ {
cf->iconPosition = cf->scrollposition - 8; ca->iconPosition = ca->scrollposition - 8;
if (cf->iconPosition <= -9) if (ca->iconPosition <= -9)
{ {
cf->iconWasPushed = true; ca->iconWasPushed = true;
} }
} }
} }
// Display animated GIF if enabled and frame is fixed, since we have only one gifplayer instance, it looks weird when 2 apps want to draw a different gif // Display animated GIF if enabled and App is fixed, since we have only one gifplayer instance, it looks weird when 2 apps want to draw a different gif
if (cf->isGif) if (ca->isGif)
{ {
if (state->frameState == FIXED) if (state->appState == FIXED)
{ {
DisplayManager.drawGIF(x + cf->iconPosition, y, cf->icon); DisplayManager.drawGIF(x + ca->iconPosition, y, ca->icon);
} }
} }
else else
{ {
// Display JPEG image // Display JPEG image
DisplayManager.drawJPG(x + cf->iconPosition, y, cf->icon); DisplayManager.drawJPG(x + ca->iconPosition, y, ca->icon);
} }
// Draw vertical line if text is scrolling // Draw vertical line if text is scrolling
if (!noScrolling) if (!noScrolling)
{ {
// matrix->drawLine(8 + x + cf->iconPosition, 0 + y, 8 + x + cf->iconPosition, 7 + y, 0); // matrix->drawLine(8 + x + ca->iconPosition, 0 + y, 8 + x + ca->iconPosition, 7 + y, 0);
} }
} }
// Reset text color // Reset text color
DisplayManager.getInstance().resetTextColor(); DisplayManager.getInstance().resetTextColor();
} }
void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state) void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
{ {
// Check if notification flag is set // Check if notification flag is set
if (!notify.flag) if (!notify.flag)
@@ -474,7 +485,12 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
// Check if text is scrolling // Check if text is scrolling
bool noScrolling = textWidth <= availableWidth; bool noScrolling = textWidth <= availableWidth;
if (notify.barSize > 0)
{
DisplayManager.drawBarChart(0, 0, notify.barData, notify.barSize, hasIcon, notify.color);
}
else
{
// Check if text needs to be scrolled // Check if text needs to be scrolled
if (textWidth > availableWidth && notify.scrollposition <= -textWidth) if (textWidth > availableWidth && notify.scrollposition <= -textWidth)
{ {
@@ -536,7 +552,7 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
if (notify.rainbow) if (notify.rainbow)
{ {
// Display text in rainbow color if enabled // Display text in rainbow color if enabled
DisplayManager.getInstance().HSVtext(textX, 6, notify.text.c_str(), false); DisplayManager.HSVtext(textX, 6, notify.text.c_str(), false);
} }
else else
{ {
@@ -549,7 +565,7 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
if (notify.rainbow) if (notify.rainbow)
{ {
// Display scrolling text in rainbow color if enabled // Display scrolling text in rainbow color if enabled
DisplayManager.getInstance().HSVtext(notify.scrollposition, 6, notify.text.c_str(), false); DisplayManager.HSVtext(notify.scrollposition, 6, notify.text.c_str(), false);
} }
else else
{ {
@@ -557,12 +573,13 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
DisplayManager.printText(notify.scrollposition, 6, notify.text.c_str(), false, false); DisplayManager.printText(notify.scrollposition, 6, notify.text.c_str(), false, false);
} }
} }
}
// Display icon if present and not pushed // Display icon if present and not pushed
if (hasIcon) if (hasIcon)
{ {
// Push icon if enabled and text is scrolling // Push icon if enabled and text is scrolling
if (notify.pushIcon > 0 && !noScrolling) if (notify.pushIcon > 0 && !noScrolling && notify.barSize == 0)
{ {
if (notify.iconPosition < 0 && notify.iconWasPushed == false && notify.scrollposition > 8) if (notify.iconPosition < 0 && notify.iconWasPushed == false && notify.scrollposition > 8)
{ {
@@ -603,64 +620,64 @@ void NotifyFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
DisplayManager.getInstance().resetTextColor(); DisplayManager.getInstance().resetTextColor();
} }
void CFrame1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame1); String name = getAppNameByFunction(CApp1);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
void CFrame2(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp2(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame2); String name = getAppNameByFunction(CApp2);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
void CFrame3(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp3(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame3); String name = getAppNameByFunction(CApp3);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
void CFrame4(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp4(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame4); String name = getAppNameByFunction(CApp4);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
void CFrame5(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp5(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame5); String name = getAppNameByFunction(CApp5);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
void CFrame6(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp6(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame6); String name = getAppNameByFunction(CApp6);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
void CFrame7(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp7(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame7); String name = getAppNameByFunction(CApp7);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
void CFrame8(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp8(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame8); String name = getAppNameByFunction(CApp8);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
void CFrame9(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp9(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame9); String name = getAppNameByFunction(CApp9);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
void CFrame10(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void CApp10(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
String name = getFrameNameByFunction(CFrame10); String name = getAppNameByFunction(CApp10);
ShowCustomFrame(name, matrix, state, x, y, firstFrame, lastFrame); ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp);
} }
const uint16_t *getWeatherIcon(int code) const uint16_t *getWeatherIcon(int code)
@@ -677,7 +694,7 @@ const uint16_t *getWeatherIcon(int code)
} }
} }
void WeatherFrame(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) void WeatherApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp)
{ {
if (notify.flag) if (notify.flag)
return; return;
@@ -733,5 +750,5 @@ void StartAppUpdater()
// getWeatherData(); // getWeatherData();
} }
OverlayCallback overlays[] = {MenuFrame, NotifyFrame, AlarmFrame, TimerFrame}; OverlayCallback overlays[] = {MenuApp, NotifyApp, AlarmApp, TimerApp};
#endif #endif

View File

@@ -12,12 +12,17 @@
#include "Functions.h" #include "Functions.h"
#include "ServerManager.h" #include "ServerManager.h"
#include "MenuManager.h" #include "MenuManager.h"
#include "Frames.h" #include "Apps.h"
Ticker AlarmTicker; Ticker AlarmTicker;
Ticker TimerTicker; Ticker TimerTicker;
#ifdef ULANZI
#define MATRIX_PIN 32 #define MATRIX_PIN 32
#else
#define MATRIX_PIN D2
#endif
#define MATRIX_WIDTH 32 #define MATRIX_WIDTH 32
#define MATRIX_HEIGHT 8 #define MATRIX_HEIGHT 8
@@ -68,6 +73,11 @@ void DisplayManager_::MatrixState(bool on)
bool DisplayManager_::setAutoTransition(bool active) bool DisplayManager_::setAutoTransition(bool active)
{ {
if (ui.AppCount < 2)
{
ui.disablesetAutoTransition();
return false;
}
if (active && AUTO_TRANSITION) if (active && AUTO_TRANSITION)
{ {
ui.enablesetAutoTransition(); ui.enablesetAutoTransition();
@@ -198,31 +208,31 @@ void DisplayManager_::HSVtext(int16_t x, int16_t y, const char *text, bool clear
matrix.show(); matrix.show();
} }
void pushCustomFrame(String name, int position) void pushCustomApp(String name, int position)
{ {
if (customFrames.count(name) == 0) if (customApps.count(name) == 0)
{ {
++customPagesCount; ++customPagesCount;
void (*customFrames[10])(FastLED_NeoMatrix *, MatrixDisplayUiState *, int16_t, int16_t, bool, bool) = {CFrame1, CFrame2, CFrame3, CFrame4, CFrame5, CFrame6, CFrame7, CFrame8, CFrame9, CFrame10}; void (*customApps[10])(FastLED_NeoMatrix *, MatrixDisplayUiState *, int16_t, int16_t, bool, bool) = {CApp1, CApp2, CApp3, CApp4, CApp5, CApp6, CApp7, CApp8, CApp9, CApp10};
if (position < 0) // Insert at the end of the vector if (position < 0) // Insert at the end of the vector
{ {
Apps.push_back(std::make_pair(name, customFrames[customPagesCount])); Apps.push_back(std::make_pair(name, customApps[customPagesCount]));
} }
else if (position < Apps.size()) // Insert at a specific position else if (position < Apps.size()) // Insert at a specific position
{ {
Apps.insert(Apps.begin() + position, std::make_pair(name, customFrames[customPagesCount])); Apps.insert(Apps.begin() + position, std::make_pair(name, customApps[customPagesCount]));
} }
else // Invalid position, Insert at the end of the vector else // Invalid position, Insert at the end of the vector
{ {
Apps.push_back(std::make_pair(name, customFrames[customPagesCount])); Apps.push_back(std::make_pair(name, customApps[customPagesCount]));
} }
ui.setApps(Apps); // Add frames ui.setApps(Apps); // Add Apps
} }
} }
void removeCustomFrame(const String &name) void removeCustomApp(const String &name)
{ {
auto it = std::find_if(Apps.begin(), Apps.end(), [&name](const std::pair<String, AppCallback> &appPair) auto it = std::find_if(Apps.begin(), Apps.end(), [&name](const std::pair<String, AppCallback> &appPair)
{ return appPair.first == name; }); { return appPair.first == name; });
@@ -236,10 +246,10 @@ void removeCustomFrame(const String &name)
void DisplayManager_::generateCustomPage(String name, String payload) void DisplayManager_::generateCustomPage(String name, String payload)
{ {
if (payload == "" && customFrames.count(name)) if (payload == "" && customApps.count(name))
{ {
customFrames.erase(customFrames.find(name)); customApps.erase(customApps.find(name));
removeCustomFrame(name); removeCustomApp(name);
return; return;
} }
@@ -248,31 +258,52 @@ void DisplayManager_::generateCustomPage(String name, String payload)
if (error) if (error)
return; return;
CustomFrame customFrame; CustomApp customApp;
if (doc.containsKey("sound")) if (doc.containsKey("sound"))
{ {
customFrame.sound = ("/" + doc["sound"].as<String>() + ".txt"); customApp.sound = ("/" + doc["sound"].as<String>() + ".txt");
} }
else else
{ {
customFrame.sound = ""; customApp.sound = "";
} }
customFrame.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false; if (doc.containsKey("bar"))
customFrame.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0; {
customFrame.name = name; JsonArray barData = doc["bar"];
customFrame.text = utf8ascii(doc["text"].as<String>()); int i = 0;
customFrame.color = doc.containsKey("color") ? doc["color"].is<String>() ? hexToRgb565(doc["color"]) : doc["color"].is<JsonArray>() ? hexToRgb565(doc["color"].as<String>()) for (JsonVariant v : barData)
{
if (i >= 16)
{
break;
}
customApp.barData[i] = v.as<int>();
i++;
}
customApp.barSize = i;
}
else
{
customApp.barSize = 0;
}
int pos = doc.containsKey("pos") ? doc["pos"].as<uint8_t>() : -1;
customApp.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false;
customApp.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0;
customApp.name = name;
customApp.text = utf8ascii(doc["text"].as<String>());
customApp.color = doc.containsKey("color") ? doc["color"].is<String>() ? hexToRgb565(doc["color"]) : doc["color"].is<JsonArray>() ? hexToRgb565(doc["color"].as<String>())
: TEXTCOLOR_565 : TEXTCOLOR_565
: TEXTCOLOR_565; : TEXTCOLOR_565;
if (currentCustomFrame != name) if (currentCustomApp != name)
{ {
customFrame.scrollposition = 9; customApp.scrollposition = 9;
} }
customFrame.repeat = doc.containsKey("repeat") ? doc["repeat"].as<uint8_t>() : -1; customApp.repeat = doc.containsKey("repeat") ? doc["repeat"].as<uint8_t>() : -1;
if (doc.containsKey("icon")) if (doc.containsKey("icon"))
{ {
@@ -280,20 +311,28 @@ void DisplayManager_::generateCustomPage(String name, String payload)
if (LittleFS.exists("/ICONS/" + iconFileName + ".jpg")) if (LittleFS.exists("/ICONS/" + iconFileName + ".jpg"))
{ {
customFrame.isGif = false; customApp.isGif = false;
customFrame.icon = LittleFS.open("/ICONS/" + iconFileName + ".jpg"); customApp.icon = LittleFS.open("/ICONS/" + iconFileName + ".jpg");
} }
else if (LittleFS.exists("/ICONS/" + iconFileName + ".gif")) else if (LittleFS.exists("/ICONS/" + iconFileName + ".gif"))
{ {
customFrame.isGif = true; customApp.isGif = true;
customFrame.icon = LittleFS.open("/ICONS/" + iconFileName + ".gif"); customApp.icon = LittleFS.open("/ICONS/" + iconFileName + ".gif");
}
else
{
fs::File nullPointer;
customApp.icon = nullPointer;
} }
} }
else
{
fs::File nullPointer;
customApp.icon = nullPointer;
}
int pos = doc.containsKey("pos") ? doc["pos"].as<uint8_t>() : -1; pushCustomApp(name, pos - 1);
customApps[name] = customApp;
pushCustomFrame(name, pos - 1);
customFrames[name] = customFrame;
} }
void DisplayManager_::generateNotification(String payload) void DisplayManager_::generateNotification(String payload)
@@ -318,6 +357,26 @@ void DisplayManager_::generateNotification(String payload)
PeripheryManager.playFromFile("/MELODIES/" + doc["sound"].as<String>() + ".txt"); PeripheryManager.playFromFile("/MELODIES/" + doc["sound"].as<String>() + ".txt");
} }
if (doc.containsKey("bar"))
{
JsonArray barData = doc["bar"];
int i = 0;
for (JsonVariant v : barData)
{
if (i >= 16)
{
break;
}
notify.barData[i] = v.as<int>();
i++;
}
notify.barSize = i;
}
else
{
notify.barSize = 0;
}
notify.color = doc.containsKey("color") ? doc["color"].is<String>() ? hexToRgb565(doc["color"]) : doc["color"].is<JsonArray>() ? hexToRgb565(doc["color"].as<String>()) notify.color = doc.containsKey("color") ? doc["color"].is<String>() ? hexToRgb565(doc["color"]) : doc["color"].is<JsonArray>() ? hexToRgb565(doc["color"].as<String>())
: TEXTCOLOR_565 : TEXTCOLOR_565
: TEXTCOLOR_565; : TEXTCOLOR_565;
@@ -329,17 +388,24 @@ void DisplayManager_::generateNotification(String payload)
{ {
notify.isGif = false; notify.isGif = false;
notify.icon = LittleFS.open("/ICONS/" + iconFileName + ".jpg"); notify.icon = LittleFS.open("/ICONS/" + iconFileName + ".jpg");
return;
} }
else if (LittleFS.exists("/ICONS/" + iconFileName + ".gif")) else if (LittleFS.exists("/ICONS/" + iconFileName + ".gif"))
{ {
notify.isGif = true; notify.isGif = true;
notify.icon = LittleFS.open("/ICONS/" + iconFileName + ".gif"); notify.icon = LittleFS.open("/ICONS/" + iconFileName + ".gif");
return;
}
else
{
fs::File nullPointer;
notify.icon = nullPointer;
} }
} }
else else
{ {
File f; fs::File nullPointer;
notify.icon = f; notify.icon = nullPointer;
} }
} }
@@ -374,25 +440,23 @@ void DisplayManager_::loadNativeApps()
}; };
// Update the "time" app at position 0 // Update the "time" app at position 0
updateApp("time", TimeFrame, SHOW_TIME, 0); updateApp("time", TimeApp, SHOW_TIME, 0);
// Update the "date" app at position 1 // Update the "date" app at position 1
updateApp("date", DateFrame, SHOW_DATE, 1); updateApp("date", DateApp, SHOW_DATE, 1);
// Update the "temp" app at position 2 // Update the "temp" app at position 2
updateApp("temp", TempFrame, SHOW_TEMP, 2); updateApp("temp", TempApp, SHOW_TEMP, 2);
// Update the "hum" app at position 3 // Update the "hum" app at position 3
updateApp("hum", HumFrame, SHOW_HUM, 3); updateApp("hum", HumApp, SHOW_HUM, 3);
// Update the "bat" app at position 4 // Update the "bat" app at position 4
updateApp("bat", BatFrame, SHOW_BAT, 4); updateApp("bat", BatApp, SHOW_BAT, 4);
ui.setApps(Apps); ui.setApps(Apps);
if (AUTO_TRANSITION && Apps.size() == 1)
{ setAutoTransition(true);
setAutoTransition(false);
}
} }
void DisplayManager_::setup() void DisplayManager_::setup()
@@ -415,12 +479,12 @@ void DisplayManager_::tick()
else else
{ {
ui.update(); ui.update();
if (ui.getUiState()->frameState == IN_TRANSITION && !appIsSwitching) if (ui.getUiState()->appState == IN_TRANSITION && !appIsSwitching)
{ {
appIsSwitching = true; appIsSwitching = true;
MQTTManager.setCurrentApp(CURRENT_APP); MQTTManager.setCurrentApp(CURRENT_APP);
} }
else if (ui.getUiState()->frameState == FIXED && appIsSwitching) else if (ui.getUiState()->appState == FIXED && appIsSwitching)
{ {
appIsSwitching = false; appIsSwitching = false;
MQTTManager.setCurrentApp(CURRENT_APP); MQTTManager.setCurrentApp(CURRENT_APP);
@@ -594,3 +658,49 @@ void DisplayManager_::drawMenuIndicator(int cur, int total, uint16_t color)
} }
} }
} }
void DisplayManager_::drawBarChart(int16_t x, int16_t y, const int data[], byte dataSize, bool withIcon, uint16_t color)
{
int maximum = 0;
int newData[dataSize];
// Finde das Maximum in der Datenliste
for (int i = 0; i < dataSize; i++)
{
int d = data[i];
if (d > maximum)
{
maximum = d;
}
}
// Berechne neue Datenwerte zwischen 0 und 8 basierend auf dem Maximum
for (int i = 0; i < dataSize; i++)
{
int d = data[i];
newData[i] = map(d, 0, maximum, 0, 8);
}
// Berechne die Breite der Balken basierend auf der Anzahl der Daten und der Breite der Matrix
int barWidth;
if (withIcon)
{
barWidth = ((32 - 9) / (dataSize)-1);
}
else
{
barWidth = (32 / (dataSize)-1);
}
// Berechne die Startposition des Graphen basierend auf dem Icon-Parameter
int startX = withIcon ? 9 : 0;
// Zeichne die Balken auf die Matrix
for (int i = 0; i < dataSize; i++)
{
int x1 = x + startX + (barWidth + 1) * i;
int barHeight = newData[i];
int y1 = min(8 - barHeight, 7);
matrix.fillRect(x1, y1 + y, barWidth, barHeight, color);
}
}

View File

@@ -56,6 +56,7 @@ public:
void drawProgressBar(int cur, int total); void drawProgressBar(int cur, int total);
void drawMenuIndicator(int cur, int total, uint16_t color); void drawMenuIndicator(int cur, int total, uint16_t color);
void drawBMP(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h); void drawBMP(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h);
void drawBarChart(int16_t x, int16_t y,const int data[], byte dataSize, bool withIcon, uint16_t color);
}; };
extern DisplayManager_ &DisplayManager; extern DisplayManager_ &DisplayManager;

View File

@@ -612,7 +612,6 @@ public:
byte b = readByte(); byte b = readByte();
if (b == 0x2c) if (b == 0x2c)
{ {
Serial.println("Parse");
parseTableBasedImage(); parseTableBasedImage();
return 0; return 0;
} }
@@ -641,11 +640,10 @@ public:
{ {
done = true; done = true;
file.seek(0); file.seek(0);
Serial.println("Finished");
parseGifHeader(); parseGifHeader();
parseLogicalScreenDescriptor(); parseLogicalScreenDescriptor();
parseGlobalColorTable(); parseGlobalColorTable();
drawFrame(offsetX,offsetY); drawFrame(offsetX, offsetY);
return ERROR_FINISHED; return ERROR_FINISHED;
} }
} }

View File

@@ -1,8 +1,18 @@
#include "Globals.h" #include "Globals.h"
#include "Preferences.h" #include "Preferences.h"
#include <WiFi.h>
Preferences Settings; Preferences Settings;
char *getID()
{
uint8_t mac[6];
WiFi.macAddress(mac);
char *macStr = new char[24];
snprintf(macStr, 24, "awtrix_%02x%02x%02x", mac[3], mac[4], mac[5]);
return macStr;
}
void loadSettings() void loadSettings()
{ {
Settings.begin("awtrix", false); Settings.begin("awtrix", false);
@@ -23,6 +33,8 @@ void loadSettings()
SHOW_HUM = Settings.getBool("HUM", true); SHOW_HUM = Settings.getBool("HUM", true);
SHOW_BAT = Settings.getBool("BAT", true); SHOW_BAT = Settings.getBool("BAT", true);
Settings.end(); Settings.end();
uniqueID = getID();
MQTT_PREFIX = String(uniqueID);
} }
void saveSettings() void saveSettings()
@@ -39,7 +51,6 @@ void saveSettings()
Settings.putString("DFORMAT", DATE_FORMAT); Settings.putString("DFORMAT", DATE_FORMAT);
Settings.putBool("SOM", START_ON_MONDAY); Settings.putBool("SOM", START_ON_MONDAY);
Settings.putBool("CEL", IS_CELSIUS); Settings.putBool("CEL", IS_CELSIUS);
Settings.putBool("TIM", SHOW_TIME); Settings.putBool("TIM", SHOW_TIME);
Settings.putBool("DAT", SHOW_DATE); Settings.putBool("DAT", SHOW_DATE);
Settings.putBool("TEMP", SHOW_TEMP); Settings.putBool("TEMP", SHOW_TEMP);
@@ -48,17 +59,18 @@ void saveSettings()
Settings.end(); Settings.end();
} }
const char *uniqueID;
IPAddress local_IP; IPAddress local_IP;
IPAddress gateway; IPAddress gateway;
IPAddress subnet; IPAddress subnet;
IPAddress primaryDNS; IPAddress primaryDNS;
IPAddress secondaryDNS; IPAddress secondaryDNS;
const char *VERSION = "0.41"; const char *VERSION = "0.42";
String MQTT_HOST = ""; String MQTT_HOST = "";
uint16_t MQTT_PORT = 1883; uint16_t MQTT_PORT = 1883;
String MQTT_USER; String MQTT_USER;
String MQTT_PASS; String MQTT_PASS;
String MQTT_PREFIX = "AwtrixLight"; String MQTT_PREFIX;
String CITY = "Berlin,de"; String CITY = "Berlin,de";
bool IO_BROKER = false; bool IO_BROKER = false;
bool NET_STATIC = false; bool NET_STATIC = false;

View File

@@ -2,6 +2,7 @@
#define GLOBALS_H #define GLOBALS_H
#include <Arduino.h> #include <Arduino.h>
extern const char *uniqueID;
extern const char *VERSION; extern const char *VERSION;
extern IPAddress local_IP; extern IPAddress local_IP;
extern IPAddress gateway; extern IPAddress gateway;

View File

@@ -6,24 +6,32 @@
#include <WiFi.h> #include <WiFi.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
unsigned long startTime;
WiFiClient espClient; WiFiClient espClient;
uint8_t lastBrightness; uint8_t lastBrightness;
HADevice device; HADevice device;
HAMqtt mqtt(espClient, device, 15); HAMqtt mqtt(espClient, device, 18);
unsigned long reconnectTimer = 0; unsigned long reconnectTimer = 0;
const unsigned long reconnectInterval = 30000; // 30 Sekunden const unsigned long reconnectInterval = 30000; // 30 Sekunden
HALight Matrix("bri", HALight::BrightnessFeature | HALight::RGBFeature); HALight *Matrix = nullptr;
HASelect BriMode("BriMode"); HASelect *BriMode = nullptr;
HAButton dismiss("myButtonA"); HAButton *dismiss = nullptr;
HAButton nextApp("myButtonB"); HAButton *nextApp = nullptr;
HAButton prevApp("myButtonC"); HAButton *prevApp = nullptr;
HASensor curApp("curApp");
HASensor battery("battery"); HASensor *curApp = nullptr;
HASensor temperature("temperature"); HASensor *battery = nullptr;
HASensor humidity("huminity"); HASensor *temperature = nullptr;
HASensor illuminance("illuminance"); HASensor *humidity = nullptr;
HASensor *illuminance = nullptr;
HASensor *uptime = nullptr;
HASensor *strength = nullptr;
HASensor *version = nullptr;
HASensor *ram = nullptr;
// The getter for the instantiated singleton instance // The getter for the instantiated singleton instance
MQTTManager_ &MQTTManager_::getInstance() MQTTManager_ &MQTTManager_::getInstance()
@@ -37,15 +45,15 @@ MQTTManager_ &MQTTManager = MQTTManager.getInstance();
void onButtonCommand(HAButton *sender) void onButtonCommand(HAButton *sender)
{ {
if (sender == &dismiss) if (sender == dismiss)
{ {
DisplayManager.dismissNotify(); DisplayManager.dismissNotify();
} }
else if (sender == &nextApp) else if (sender == nextApp)
{ {
DisplayManager.nextApp(); DisplayManager.nextApp();
} }
else if (sender == &prevApp) else if (sender == prevApp)
{ {
DisplayManager.previousApp(); DisplayManager.previousApp();
} }
@@ -66,7 +74,7 @@ void onSelectCommand(int8_t index, HASelect *sender)
AUTO_BRIGHTNESS = true; AUTO_BRIGHTNESS = true;
return; return;
} }
Matrix.setBrightness(BRIGHTNESS); Matrix->setBrightness(BRIGHTNESS);
saveSettings(); saveSettings();
sender->setState(index); // report the selected option back to the HA panel sender->setState(index); // report the selected option back to the HA panel
} }
@@ -203,71 +211,128 @@ void connect()
} }
} }
char matID[40], briID[40];
char btnAID[40], btnBID[40], btnCID[40], appID[40], tempID[40], humID[40], luxID[40], verID[40], batID[40], ramID[40], upID[40], sigID[40];
void MQTTManager_::setup() void MQTTManager_::setup()
{ {
byte mac[6]; startTime = millis();
WiFi.macAddress(mac);
if (HA_DISCOVERY) if (HA_DISCOVERY)
{ {
Serial.println("Starting Homeassistant discorvery"); Serial.println("Starting Homeassistant discorvery");
uint8_t mac[6];
WiFi.macAddress(mac);
char *macStr = new char[18 + 1];
snprintf(macStr, 24, "%02x%02x%02x", mac[3], mac[4], mac[5]);
device.setUniqueId(mac, sizeof(mac)); device.setUniqueId(mac, sizeof(mac));
device.setName(MQTT_PREFIX.c_str()); device.setName(uniqueID);
device.setSoftwareVersion(VERSION); device.setSoftwareVersion(VERSION);
device.setManufacturer("Blueforcer"); device.setManufacturer("Blueforcer");
device.setModel("AWTRIX Light"); device.setModel("AWTRIX Light");
device.setAvailability(true); device.setAvailability(true);
Matrix.setIcon("mdi:lightbulb");
Matrix.setName("Matrix"); String uniqueIDWithSuffix;
Matrix.onStateCommand(onStateCommand);
Matrix.onBrightnessCommand(onBrightnessCommand); sprintf(matID, "%s_mat", macStr);
Matrix.onRGBColorCommand(onRGBColorCommand); Matrix = new HALight(matID, HALight::BrightnessFeature | HALight::RGBFeature);
Matrix.setCurrentState(true);
Matrix.setBRIGHTNESS(BRIGHTNESS); Matrix->setIcon("mdi:lightbulb");
Matrix->setName("Matrix");
Matrix->onStateCommand(onStateCommand);
Matrix->onBrightnessCommand(onBrightnessCommand);
Matrix->onRGBColorCommand(onRGBColorCommand);
Matrix->setCurrentState(true);
Matrix->setBRIGHTNESS(BRIGHTNESS);
HALight::RGBColor color; HALight::RGBColor color;
color.red = (TEXTCOLOR_565 >> 11) << 3; color.red = (TEXTCOLOR_565 >> 11) << 3;
color.green = ((TEXTCOLOR_565 >> 5) & 0x3F) << 2; color.green = ((TEXTCOLOR_565 >> 5) & 0x3F) << 2;
color.blue = (TEXTCOLOR_565 & 0x1F) << 3; color.blue = (TEXTCOLOR_565 & 0x1F) << 3;
Matrix.setCurrentRGBColor(color); Matrix->setCurrentRGBColor(color);
Matrix.setState(true, true); Matrix->setState(true, true);
BriMode.setOptions("Manual;Auto"); // use semicolons as separator of options sprintf(briID, "%s_bri", macStr);
BriMode.onCommand(onSelectCommand); BriMode = new HASelect(briID);
BriMode.setIcon("mdi:brightness-auto"); // optional BriMode->setOptions("Manual;Auto"); // use semicolons as separator of options
BriMode.setName("Brightness mode"); // optional BriMode->onCommand(onSelectCommand);
BriMode.setState(AUTO_BRIGHTNESS, true); BriMode->setIcon("mdi:brightness-auto"); // optional
BriMode->setName("Brightness mode"); // optional
BriMode->setState(AUTO_BRIGHTNESS, true);
dismiss.setIcon("mdi:bell-off"); sprintf(btnAID, "%s_btna", macStr);
dismiss.setName("Dismiss notification"); dismiss = new HAButton(btnAID);
nextApp.setIcon("mdi:arrow-right-bold"); dismiss->setIcon("mdi:bell-off");
nextApp.setName("Next app"); dismiss->setName("Dismiss notification");
prevApp.setIcon("mdi:arrow-left-bold");
prevApp.setName("Previous app");
dismiss.onCommand(onButtonCommand); sprintf(btnBID, "%s_btnb", macStr);
nextApp.onCommand(onButtonCommand); nextApp = new HAButton(btnBID);
prevApp.onCommand(onButtonCommand); nextApp->setIcon("mdi:arrow-right-bold");
nextApp->setName("Next app");
curApp.setIcon("mdi:apps"); sprintf(btnCID, "%s_btnc", macStr);
curApp.setName("Current app"); prevApp = new HAButton(btnCID);
prevApp->setIcon("mdi:arrow-left-bold");
prevApp->setName("Previous app");
temperature.setIcon("mdi:thermometer"); dismiss->onCommand(onButtonCommand);
temperature.setName("Temperature"); nextApp->onCommand(onButtonCommand);
temperature.setUnitOfMeasurement("°C"); prevApp->onCommand(onButtonCommand);
humidity.setIcon("mdi:water-percent"); sprintf(appID, "%s_app", macStr);
humidity.setName("humidity"); curApp = new HASensor(appID);
humidity.setUnitOfMeasurement("%"); curApp->setIcon("mdi:apps");
curApp->setName("Current app");
battery.setIcon("mdi:battery-90"); sprintf(tempID, "%s_temp", macStr);
battery.setName("Battery"); temperature = new HASensor(tempID);
battery.setUnitOfMeasurement("%"); temperature->setIcon("mdi:thermometer");
temperature->setName("Temperature");
temperature->setDeviceClass("temperature");
temperature->setUnitOfMeasurement("°C");
illuminance.setIcon("mdi:sun-wireless"); sprintf(humID, "%s_hum", macStr);
illuminance.setName("Illuminance"); humidity = new HASensor(humID);
illuminance.setUnitOfMeasurement("lx"); humidity->setIcon("mdi:water-percent");
humidity->setName("humidity");
humidity->setDeviceClass("humidity");
humidity->setUnitOfMeasurement("%");
sprintf(batID, "%s_bat", macStr);
battery = new HASensor(batID);
battery->setIcon("mdi:battery-90");
battery->setName("Battery");
battery->setDeviceClass("battery");
battery->setUnitOfMeasurement("%");
sprintf(luxID, "%s_lux", macStr);
illuminance = new HASensor(luxID);
illuminance->setIcon("mdi:sun-wireless");
illuminance->setName("Illuminance");
illuminance->setDeviceClass("illuminance");
illuminance->setUnitOfMeasurement("lx");
sprintf(verID, "%s_ver", macStr);
version = new HASensor(verID);
version->setName("Version");
sprintf(sigID, "%s_sig", macStr);
strength = new HASensor(sigID);
strength->setName("WiFi strength");
strength->setDeviceClass("signal_strength");
strength->setUnitOfMeasurement("dB");
sprintf(upID, "%s_up", macStr);
uptime = new HASensor(upID);
uptime->setName("Uptime");
uptime->setDeviceClass("duration");
sprintf(ramID, "%s_ram", macStr);
ram = new HASensor(ramID);
ram->setDeviceClass("data_size");
ram->setIcon("mdi:application-cog");
ram->setName("Free ram");
ram->setUnitOfMeasurement("B");
} }
else else
{ {
@@ -299,7 +364,23 @@ void MQTTManager_::publish(const char *topic, const char *payload)
void MQTTManager_::setCurrentApp(String value) void MQTTManager_::setCurrentApp(String value)
{ {
if (HA_DISCOVERY) if (HA_DISCOVERY)
curApp.setValue(value.c_str()); curApp->setValue(value.c_str());
}
const char *readUptime()
{
static char uptime[25]; // Make the array static to keep it from being destroyed when the function returns
unsigned long currentTime = millis();
unsigned long elapsedTime = currentTime - startTime;
unsigned long uptimeSeconds = elapsedTime / 1000;
unsigned long uptimeMinutes = uptimeSeconds / 60;
unsigned long uptimeHours = uptimeMinutes / 60;
unsigned long uptimeDays = uptimeHours / 24;
unsigned long hours = uptimeHours % 24;
unsigned long minutes = uptimeMinutes % 60;
unsigned long seconds = uptimeSeconds % 60;
sprintf(uptime, "P%dDT%dH%dM%dS", uptimeDays, hours, minutes, seconds);
return uptime;
} }
void MQTTManager_::sendStats() void MQTTManager_::sendStats()
@@ -308,20 +389,32 @@ void MQTTManager_::sendStats()
{ {
char buffer[5]; char buffer[5];
snprintf(buffer, 5, "%d", BATTERY_PERCENT); snprintf(buffer, 5, "%d", BATTERY_PERCENT);
battery.setValue(buffer); battery->setValue(buffer);
snprintf(buffer, 5, "%.0f", CURRENT_TEMP); snprintf(buffer, 5, "%.0f", CURRENT_TEMP);
temperature.setValue(buffer); temperature->setValue(buffer);
snprintf(buffer, 5, "%.0f", CURRENT_HUM); snprintf(buffer, 5, "%.0f", CURRENT_HUM);
humidity.setValue(buffer); humidity->setValue(buffer);
snprintf(buffer, 5, "%.0f", CURRENT_LUX); snprintf(buffer, 5, "%.0f", CURRENT_LUX);
illuminance.setValue(buffer); illuminance->setValue(buffer);
BriMode.setState(AUTO_BRIGHTNESS, true); BriMode->setState(AUTO_BRIGHTNESS, true);
Matrix.setBRIGHTNESS(BRIGHTNESS); Matrix->setBRIGHTNESS(BRIGHTNESS);
Matrix.setState(!MATRIX_OFF, false); Matrix->setState(!MATRIX_OFF, false);
int8_t rssiValue = WiFi.RSSI();
char rssiString[4];
snprintf(rssiString, sizeof(rssiString), "%d", rssiValue);
strength->setValue(rssiString);
char rambuffer[10];
int freeHeapBytes = ESP.getFreeHeap();
itoa(freeHeapBytes, rambuffer, 10);
ram->setValue(rambuffer);
uptime->setValue(readUptime());
version->setValue(VERSION);
} }
StaticJsonDocument<200> doc; StaticJsonDocument<200> doc;
@@ -336,6 +429,8 @@ void MQTTManager_::sendStats()
doc["temp"] = buffer; doc["temp"] = buffer;
snprintf(buffer, 5, "%.0f", CURRENT_HUM); snprintf(buffer, 5, "%.0f", CURRENT_HUM);
doc["hum"] = buffer; doc["hum"] = buffer;
doc["uptime"] = readUptime();
doc["wifi"] = WiFi.RSSI();
String jsonString; String jsonString;
serializeJson(doc, jsonString); serializeJson(doc, jsonString);
char topic[50]; char topic[50];

View File

@@ -135,26 +135,20 @@ String MenuManager_::menutext()
return String(TIME_PER_APP / 1000.0, 0) + "s"; return String(TIME_PER_APP / 1000.0, 0) + "s";
case TimeFormatMenu: case TimeFormatMenu:
DisplayManager.drawMenuIndicator(timeFormatIndex, timeFormatCount, 0xFBC0); DisplayManager.drawMenuIndicator(timeFormatIndex, timeFormatCount, 0xFBC0);
char display[9];
if (timeFormat[timeFormatIndex][2] == ' ') if (timeFormat[timeFormatIndex][2] == ' ')
{ {
strcpy(display, timeFormat[timeFormatIndex]); snprintf(display, sizeof(display), "%s", timeFormat[timeFormatIndex]);
if (now % 2) display[2] = now % 2 ? ' ' : ':';
{
display[2] = ' ';
} }
else else
{ {
display[2] = ':'; snprintf(display, sizeof(display), "%s", timeFormat[timeFormatIndex]);
}
strftime(t, sizeof(t), display, localtime(&now));
return t;
}
else
{
strftime(t, sizeof(t), timeFormat[timeFormatIndex], localtime(&now));
return t;
} }
strftime(t, sizeof(t), display, localtime(&now));
return t;
case DateFormatMenu: case DateFormatMenu:
DisplayManager.drawMenuIndicator(dateFormatIndex, dateFormatCount, 0xFBC0); DisplayManager.drawMenuIndicator(dateFormatIndex, dateFormatCount, 0xFBC0);
strftime(t, sizeof(t), dateFormat[dateFormatIndex], localtime(&now)); strftime(t, sizeof(t), dateFormat[dateFormatIndex], localtime(&now));
@@ -427,6 +421,8 @@ void MenuManager_::selectButtonLong()
saveSettings(); saveSettings();
break; break;
case DateFormatMenu: case DateFormatMenu:
DATE_FORMAT = dateFormat[dateFormatIndex];
saveSettings();
case WeekdayMenu: case WeekdayMenu:
case TempMenu: case TempMenu:
saveSettings(); saveSettings();

View File

@@ -10,12 +10,25 @@
#include <MenuManager.h> #include <MenuManager.h>
#define SOUND_OFF false #define SOUND_OFF false
#define BATTERY_PIN 34
#define BUZZER_PIN 15 #ifdef ULANZI
#define LDR_PIN 35 // Pinouts für das ULANZI-Environment
#define BUTTON_UP_PIN 26 #define BATTERY_PIN 34
#define BUTTON_DOWN_PIN 14 #define BUZZER_PIN 15
#define BUTTON_SELECT_PIN 27 #define LDR_PIN 35
#define BUTTON_UP_PIN 26
#define BUTTON_DOWN_PIN 14
#define BUTTON_SELECT_PIN 27
#else
// Pinouts für das WEMOS_D1_MINI32-Environment
#define BATTERY_PIN -1
#define BUZZER_PIN -1
#define LDR_PIN A0
#define BUTTON_UP_PIN D0
#define BUTTON_DOWN_PIN D4
#define BUTTON_SELECT_PIN D8
#endif
Adafruit_SHT31 sht31; Adafruit_SHT31 sht31;
EasyButton button_left(BUTTON_UP_PIN); EasyButton button_left(BUTTON_UP_PIN);
@@ -45,7 +58,7 @@ float sampleSum = 0.0;
float sampleAverage = 0.0; float sampleAverage = 0.0;
float brightnessPercent = 0.0; float brightnessPercent = 0.0;
unsigned long startTime;
// The getter for the instantiated singleton instance // The getter for the instantiated singleton instance
PeripheryManager_ &PeripheryManager_::getInstance() PeripheryManager_ &PeripheryManager_::getInstance()
@@ -100,7 +113,6 @@ void PeripheryManager_::playBootSound()
const int nNotes = 6; const int nNotes = 6;
String notes[nNotes] = {"E5", "C5", "G4", "E4", "G4", "C5"}; String notes[nNotes] = {"E5", "C5", "G4", "E4", "G4", "C5"};
const int timeUnit = 150; const int timeUnit = 150;
// create a melody
Melody melody = MelodyFactory.load("Nice Melody", timeUnit, notes, nNotes); Melody melody = MelodyFactory.load("Nice Melody", timeUnit, notes, nNotes);
player.playAsync(melody); player.playAsync(melody);
} }
@@ -128,7 +140,7 @@ void fistStart()
uint16_t ADCVALUE = analogRead(BATTERY_PIN); uint16_t ADCVALUE = analogRead(BATTERY_PIN);
BATTERY_PERCENT = min((int)map(ADCVALUE, 510, 660, 0, 100), 100); BATTERY_PERCENT = min((int)map(ADCVALUE, 490, 660, 0, 100), 100);
sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM); sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM);
uint16_t LDRVALUE = analogRead(LDR_PIN); uint16_t LDRVALUE = analogRead(LDR_PIN);
@@ -167,7 +179,7 @@ void PeripheryManager_::tick()
{ {
previousMillis_BatTempHum = currentMillis_BatTempHum; previousMillis_BatTempHum = currentMillis_BatTempHum;
uint16_t ADCVALUE = analogRead(BATTERY_PIN); uint16_t ADCVALUE = analogRead(BATTERY_PIN);
BATTERY_PERCENT = min((int)map(ADCVALUE, 510, 665, 0, 100), 100); BATTERY_PERCENT = min((int)map(ADCVALUE, 475, 665, 0, 100), 100);
BATTERY_RAW = ADCVALUE; BATTERY_RAW = ADCVALUE;
sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM); sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM);
CURRENT_TEMP -= 9.0; CURRENT_TEMP -= 9.0;
@@ -200,16 +212,7 @@ void PeripheryManager_::tick()
} }
} }
void readUptime()
{
unsigned long currentTime = millis();
unsigned long elapsedTime = currentTime - startTime;
int hours = (elapsedTime / 1000) / 3600;
int minutes = ((elapsedTime / 1000) % 3600) / 60;
int seconds = (elapsedTime / 1000) % 60;
char timeString[10];
sprintf(timeString, "%02d:%02d:%02d", hours, minutes, seconds);
}
const int MIN_ALARM_INTERVAL = 60; // 1 Minute const int MIN_ALARM_INTERVAL = 60; // 1 Minute
time_t lastAlarmTime = 0; time_t lastAlarmTime = 0;

View File

@@ -63,7 +63,7 @@ void ServerManager_::setup()
{ {
WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
} }
IPAddress myIP = mws.startWiFi(150000, "AWTRIX LIGHT", "12345678"); IPAddress myIP = mws.startWiFi(150000, uniqueID, "12345678");
isConnected = !(myIP == IPAddress(192, 168, 4, 1)); isConnected = !(myIP == IPAddress(192, 168, 4, 1));
Serial.println(myIP.toString()); Serial.println(myIP.toString());
@@ -99,7 +99,7 @@ void ServerManager_::setup()
mws.addHandler("/version", HTTP_GET, versionHandler); mws.addHandler("/version", HTTP_GET, versionHandler);
mws.begin(); mws.begin();
if (!MDNS.begin(MQTT_PREFIX.c_str())) if (!MDNS.begin(uniqueID))
{ {
Serial.println("Error starting mDNS"); Serial.println("Error starting mDNS");
return; return;