v0.42
- 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:
@@ -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).
|
||||
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.
|
||||
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.
|
||||
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
|
||||
@@ -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).
|
||||
|
||||
## 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 |
|
||||
| `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 |
|
||||
| `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.
|
||||
|
||||
@@ -29,7 +29,7 @@ Built-in app names are:
|
||||
- `hum`
|
||||
- `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 various settings related to the app display.
|
||||
|
||||
@@ -48,9 +48,9 @@ void MatrixDisplayUi::setTargetFPS(uint8_t fps)
|
||||
float oldInterval = this->updateInterval;
|
||||
this->updateInterval = ((float)1.0 / (float)fps) * 1000;
|
||||
|
||||
// Calculate new ticksPerFrame
|
||||
// Calculate new ticksPerApp
|
||||
float changeRatio = oldInterval / (float)this->updateInterval;
|
||||
this->ticksPerFrame *= changeRatio;
|
||||
this->ticksPerApp *= changeRatio;
|
||||
this->ticksPerTransition *= changeRatio;
|
||||
}
|
||||
|
||||
@@ -66,33 +66,34 @@ void MatrixDisplayUi::disablesetAutoTransition()
|
||||
}
|
||||
void MatrixDisplayUi::setsetAutoTransitionForwards()
|
||||
{
|
||||
this->state.frameTransitionDirection = 1;
|
||||
this->state.appTransitionDirection = 1;
|
||||
this->lastTransitionDirection = 1;
|
||||
}
|
||||
void MatrixDisplayUi::setsetAutoTransitionBackwards()
|
||||
{
|
||||
this->state.frameTransitionDirection = -1;
|
||||
this->state.appTransitionDirection = -1;
|
||||
this->lastTransitionDirection = -1;
|
||||
}
|
||||
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)
|
||||
{
|
||||
this->ticksPerTransition = (int)((float)time / (float)updateInterval);
|
||||
}
|
||||
|
||||
// -/----- Frame settings -----\-
|
||||
// -/----- App settings -----\-
|
||||
void MatrixDisplayUi::setAppAnimation(AnimationDirection dir)
|
||||
{
|
||||
this->frameAnimationDirection = dir;
|
||||
this->appAnimationDirection = dir;
|
||||
}
|
||||
|
||||
void MatrixDisplayUi::setApps(const std::vector<std::pair<String, AppCallback>> &appPairs)
|
||||
{
|
||||
delete[] AppFunctions;
|
||||
AppCount = appPairs.size();
|
||||
Serial.println(AppCount);
|
||||
AppFunctions = new AppCallback[AppCount];
|
||||
|
||||
for (size_t i = 0; i < AppCount; ++i)
|
||||
@@ -113,51 +114,51 @@ void MatrixDisplayUi::setOverlays(OverlayCallback *overlayFunctions, uint8_t ove
|
||||
// -/----- Manuel control -----\-
|
||||
void MatrixDisplayUi::nextApp()
|
||||
{
|
||||
if (this->state.frameState != IN_TRANSITION)
|
||||
if (this->state.appState != IN_TRANSITION)
|
||||
{
|
||||
this->state.manuelControll = true;
|
||||
this->state.frameState = IN_TRANSITION;
|
||||
this->state.appState = IN_TRANSITION;
|
||||
this->state.ticksSinceLastStateSwitch = 0;
|
||||
this->lastTransitionDirection = this->state.frameTransitionDirection;
|
||||
this->state.frameTransitionDirection = 1;
|
||||
this->lastTransitionDirection = this->state.appTransitionDirection;
|
||||
this->state.appTransitionDirection = 1;
|
||||
}
|
||||
}
|
||||
void MatrixDisplayUi::previousApp()
|
||||
{
|
||||
if (this->state.frameState != IN_TRANSITION)
|
||||
if (this->state.appState != IN_TRANSITION)
|
||||
{
|
||||
this->state.manuelControll = true;
|
||||
this->state.frameState = IN_TRANSITION;
|
||||
this->state.appState = IN_TRANSITION;
|
||||
this->state.ticksSinceLastStateSwitch = 0;
|
||||
this->lastTransitionDirection = this->state.frameTransitionDirection;
|
||||
this->state.frameTransitionDirection = -1;
|
||||
this->lastTransitionDirection = this->state.appTransitionDirection;
|
||||
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;
|
||||
this->state.ticksSinceLastStateSwitch = 0;
|
||||
if (frame == this->state.currentFrame)
|
||||
if (app == this->state.currentApp)
|
||||
return;
|
||||
this->state.frameState = FIXED;
|
||||
this->state.currentFrame = frame;
|
||||
this->state.appState = FIXED;
|
||||
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;
|
||||
this->state.ticksSinceLastStateSwitch = 0;
|
||||
if (frame == this->state.currentFrame)
|
||||
if (app == this->state.currentApp)
|
||||
return;
|
||||
this->nextAppNumber = frame;
|
||||
this->lastTransitionDirection = this->state.frameTransitionDirection;
|
||||
this->nextAppNumber = app;
|
||||
this->lastTransitionDirection = this->state.appTransitionDirection;
|
||||
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 -----\-
|
||||
@@ -168,18 +169,18 @@ MatrixDisplayUiState *MatrixDisplayUi::getUiState()
|
||||
|
||||
int8_t MatrixDisplayUi::update()
|
||||
{
|
||||
long frameStart = millis();
|
||||
int8_t timeBudget = this->updateInterval - (frameStart - this->state.lastUpdate);
|
||||
long appStart = millis();
|
||||
int8_t timeBudget = this->updateInterval - (appStart - this->state.lastUpdate);
|
||||
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)
|
||||
this->state.ticksSinceLastStateSwitch += ceil(-timeBudget / this->updateInterval);
|
||||
|
||||
this->state.lastUpdate = frameStart;
|
||||
this->state.lastUpdate = appStart;
|
||||
this->tick();
|
||||
}
|
||||
return this->updateInterval - (millis() - frameStart);
|
||||
return this->updateInterval - (millis() - appStart);
|
||||
}
|
||||
|
||||
void MatrixDisplayUi::tick()
|
||||
@@ -188,13 +189,13 @@ void MatrixDisplayUi::tick()
|
||||
|
||||
if (this->AppCount > 0)
|
||||
{
|
||||
switch (this->state.frameState)
|
||||
switch (this->state.appState)
|
||||
{
|
||||
case IN_TRANSITION:
|
||||
if (this->state.ticksSinceLastStateSwitch >= this->ticksPerTransition)
|
||||
{
|
||||
this->state.frameState = FIXED;
|
||||
this->state.currentFrame = getnextAppNumber();
|
||||
this->state.appState = FIXED;
|
||||
this->state.currentApp = getnextAppNumber();
|
||||
this->state.ticksSinceLastStateSwitch = 0;
|
||||
this->nextAppNumber = -1;
|
||||
}
|
||||
@@ -203,14 +204,14 @@ void MatrixDisplayUi::tick()
|
||||
// Revert manuelControll
|
||||
if (this->state.manuelControll)
|
||||
{
|
||||
this->state.frameTransitionDirection = this->lastTransitionDirection;
|
||||
this->state.appTransitionDirection = this->lastTransitionDirection;
|
||||
this->state.manuelControll = false;
|
||||
}
|
||||
if (this->state.ticksSinceLastStateSwitch >= this->ticksPerFrame)
|
||||
if (this->state.ticksSinceLastStateSwitch >= this->ticksPerApp)
|
||||
{
|
||||
if (this->setAutoTransition)
|
||||
{
|
||||
this->state.frameState = IN_TRANSITION;
|
||||
this->state.appState = IN_TRANSITION;
|
||||
}
|
||||
this->state.ticksSinceLastStateSwitch = 0;
|
||||
}
|
||||
@@ -227,13 +228,13 @@ void MatrixDisplayUi::tick()
|
||||
|
||||
void MatrixDisplayUi::drawApp()
|
||||
{
|
||||
switch (this->state.frameState)
|
||||
switch (this->state.appState)
|
||||
{
|
||||
case IN_TRANSITION:
|
||||
{
|
||||
float progress = (float)this->state.ticksSinceLastStateSwitch / (float)this->ticksPerTransition;
|
||||
int16_t x, y, x1, y1;
|
||||
switch (this->frameAnimationDirection)
|
||||
switch (this->appAnimationDirection)
|
||||
{
|
||||
case SLIDE_LEFT:
|
||||
x = -32 * progress;
|
||||
@@ -261,20 +262,20 @@ void MatrixDisplayUi::drawApp()
|
||||
break;
|
||||
}
|
||||
// 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;
|
||||
y *= dir;
|
||||
x1 *= dir;
|
||||
y1 *= dir;
|
||||
bool FirstFrame = progress < 0.2;
|
||||
bool LastFrame = progress > 0.8;
|
||||
bool FirstApp = progress < 0.2;
|
||||
bool LastApp = 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);
|
||||
(this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, x, y, FirstApp, LastApp);
|
||||
(this->AppFunctions[this->getnextAppNumber()])(this->matrix, &this->state, x1, y1, FirstApp, LastApp);
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -283,8 +284,8 @@ void MatrixDisplayUi::resetState()
|
||||
{
|
||||
this->state.lastUpdate = 0;
|
||||
this->state.ticksSinceLastStateSwitch = 0;
|
||||
this->state.frameState = FIXED;
|
||||
this->state.currentFrame = 0;
|
||||
this->state.appState = FIXED;
|
||||
this->state.currentApp = 0;
|
||||
}
|
||||
|
||||
void MatrixDisplayUi::drawOverlays()
|
||||
@@ -299,5 +300,5 @@ uint8_t MatrixDisplayUi::getnextAppNumber()
|
||||
{
|
||||
if (this->nextAppNumber != -1)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ enum AnimationDirection
|
||||
SLIDE_RIGHT
|
||||
};
|
||||
|
||||
enum FrameState
|
||||
enum AppState
|
||||
{
|
||||
IN_TRANSITION,
|
||||
FIXED
|
||||
@@ -58,11 +58,11 @@ struct MatrixDisplayUiState
|
||||
u_int64_t lastUpdate = 0;
|
||||
uint16_t ticksSinceLastStateSwitch = 0;
|
||||
|
||||
FrameState frameState = FIXED;
|
||||
uint8_t currentFrame = 0;
|
||||
AppState appState = FIXED;
|
||||
uint8_t currentApp = 0;
|
||||
|
||||
// Normal = 1, Inverse = -1;
|
||||
int8_t frameTransitionDirection = 1;
|
||||
int8_t appTransitionDirection = 1;
|
||||
|
||||
bool manuelControll = false;
|
||||
|
||||
@@ -70,7 +70,7 @@ struct MatrixDisplayUiState
|
||||
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);
|
||||
|
||||
class MatrixDisplayUi
|
||||
@@ -78,21 +78,19 @@ class MatrixDisplayUi
|
||||
private:
|
||||
FastLED_NeoMatrix *matrix;
|
||||
|
||||
// Values for the Frames
|
||||
AnimationDirection frameAnimationDirection = SLIDE_RIGHT;
|
||||
// Values for the Apps
|
||||
AnimationDirection appAnimationDirection = SLIDE_RIGHT;
|
||||
|
||||
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
|
||||
|
||||
bool setAutoTransition = true;
|
||||
|
||||
AppCallback *AppFunctions;
|
||||
|
||||
uint8_t AppCount = 0;
|
||||
|
||||
// Internally used to transition to a specific frame
|
||||
// Internally used to transition to a specific app
|
||||
int8_t nextAppNumber = -1;
|
||||
|
||||
// Values for Overlays
|
||||
@@ -115,6 +113,7 @@ private:
|
||||
public:
|
||||
MatrixDisplayUi(FastLED_NeoMatrix *matrix);
|
||||
|
||||
uint8_t AppCount = 0;
|
||||
/**
|
||||
* Initialise the display
|
||||
*/
|
||||
@@ -127,12 +126,12 @@ public:
|
||||
|
||||
// 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();
|
||||
|
||||
/**
|
||||
* Disable automatic transition to next frame.
|
||||
* Disable automatic transition to next app.
|
||||
*/
|
||||
void disablesetAutoTransition();
|
||||
|
||||
@@ -143,7 +142,7 @@ public:
|
||||
void setsetAutoTransitionBackwards();
|
||||
|
||||
/**
|
||||
* Set the approx. time a frame is displayed
|
||||
* Set the approx. time a app is displayed
|
||||
*/
|
||||
void setTimePerApp(uint16_t time);
|
||||
|
||||
@@ -154,22 +153,22 @@ public:
|
||||
|
||||
// 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);
|
||||
|
||||
/**
|
||||
* Add frame drawing functions
|
||||
* Add app drawing functions
|
||||
*/
|
||||
void setApps(const std::vector<std::pair<String, AppCallback>> &appPairs);
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -178,15 +177,15 @@ public:
|
||||
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
|
||||
* frame the forward animation will be used, otherwise the backwards animation is used.
|
||||
* Transition to app `app`, when the `app` number is bigger than the current
|
||||
* 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
|
||||
MatrixDisplayUiState *getUiState();
|
||||
|
||||
@@ -8,12 +8,28 @@
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp32dev]
|
||||
[env:ulanzi]
|
||||
platform = https://github.com/platformio/platform-espressif32.git
|
||||
board = esp32dev
|
||||
board_build.partitions = awtrix_partition.csv
|
||||
upload_speed = 921600
|
||||
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 =
|
||||
adafruit/Adafruit SHT31 Library@^2.2.0
|
||||
bblanchon/ArduinoJson@^6.20.0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,12 +12,17 @@
|
||||
#include "Functions.h"
|
||||
#include "ServerManager.h"
|
||||
#include "MenuManager.h"
|
||||
#include "Frames.h"
|
||||
#include "Apps.h"
|
||||
|
||||
Ticker AlarmTicker;
|
||||
Ticker TimerTicker;
|
||||
|
||||
#ifdef ULANZI
|
||||
#define MATRIX_PIN 32
|
||||
#else
|
||||
#define MATRIX_PIN D2
|
||||
#endif
|
||||
|
||||
#define MATRIX_WIDTH 32
|
||||
#define MATRIX_HEIGHT 8
|
||||
|
||||
@@ -68,6 +73,11 @@ void DisplayManager_::MatrixState(bool on)
|
||||
|
||||
bool DisplayManager_::setAutoTransition(bool active)
|
||||
{
|
||||
if (ui.AppCount < 2)
|
||||
{
|
||||
ui.disablesetAutoTransition();
|
||||
return false;
|
||||
}
|
||||
if (active && AUTO_TRANSITION)
|
||||
{
|
||||
ui.enablesetAutoTransition();
|
||||
@@ -198,31 +208,31 @@ void DisplayManager_::HSVtext(int16_t x, int16_t y, const char *text, bool clear
|
||||
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;
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{ return appPair.first == name; });
|
||||
@@ -236,10 +246,10 @@ void removeCustomFrame(const String &name)
|
||||
|
||||
void DisplayManager_::generateCustomPage(String name, String payload)
|
||||
{
|
||||
if (payload == "" && customFrames.count(name))
|
||||
if (payload == "" && customApps.count(name))
|
||||
{
|
||||
customFrames.erase(customFrames.find(name));
|
||||
removeCustomFrame(name);
|
||||
customApps.erase(customApps.find(name));
|
||||
removeCustomApp(name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -248,31 +258,52 @@ void DisplayManager_::generateCustomPage(String name, String payload)
|
||||
if (error)
|
||||
return;
|
||||
|
||||
CustomFrame customFrame;
|
||||
CustomApp customApp;
|
||||
|
||||
if (doc.containsKey("sound"))
|
||||
{
|
||||
customFrame.sound = ("/" + doc["sound"].as<String>() + ".txt");
|
||||
customApp.sound = ("/" + doc["sound"].as<String>() + ".txt");
|
||||
}
|
||||
else
|
||||
{
|
||||
customFrame.sound = "";
|
||||
customApp.sound = "";
|
||||
}
|
||||
|
||||
customFrame.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false;
|
||||
customFrame.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0;
|
||||
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 != name)
|
||||
if (doc.containsKey("bar"))
|
||||
{
|
||||
customFrame.scrollposition = 9;
|
||||
JsonArray barData = doc["bar"];
|
||||
int i = 0;
|
||||
for (JsonVariant v : barData)
|
||||
{
|
||||
if (i >= 16)
|
||||
{
|
||||
break;
|
||||
}
|
||||
customApp.barData[i] = v.as<int>();
|
||||
i++;
|
||||
}
|
||||
customApp.barSize = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
customApp.barSize = 0;
|
||||
}
|
||||
|
||||
customFrame.repeat = doc.containsKey("repeat") ? doc["repeat"].as<uint8_t>() : -1;
|
||||
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;
|
||||
|
||||
if (currentCustomApp != name)
|
||||
{
|
||||
customApp.scrollposition = 9;
|
||||
}
|
||||
|
||||
customApp.repeat = doc.containsKey("repeat") ? doc["repeat"].as<uint8_t>() : -1;
|
||||
|
||||
if (doc.containsKey("icon"))
|
||||
{
|
||||
@@ -280,20 +311,28 @@ void DisplayManager_::generateCustomPage(String name, String payload)
|
||||
|
||||
if (LittleFS.exists("/ICONS/" + iconFileName + ".jpg"))
|
||||
{
|
||||
customFrame.isGif = false;
|
||||
customFrame.icon = LittleFS.open("/ICONS/" + iconFileName + ".jpg");
|
||||
customApp.isGif = false;
|
||||
customApp.icon = LittleFS.open("/ICONS/" + iconFileName + ".jpg");
|
||||
}
|
||||
else if (LittleFS.exists("/ICONS/" + iconFileName + ".gif"))
|
||||
{
|
||||
customFrame.isGif = true;
|
||||
customFrame.icon = LittleFS.open("/ICONS/" + iconFileName + ".gif");
|
||||
customApp.isGif = true;
|
||||
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;
|
||||
|
||||
pushCustomFrame(name, pos - 1);
|
||||
customFrames[name] = customFrame;
|
||||
pushCustomApp(name, pos - 1);
|
||||
customApps[name] = customApp;
|
||||
}
|
||||
|
||||
void DisplayManager_::generateNotification(String payload)
|
||||
@@ -318,6 +357,26 @@ void DisplayManager_::generateNotification(String payload)
|
||||
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>())
|
||||
: TEXTCOLOR_565
|
||||
: TEXTCOLOR_565;
|
||||
@@ -329,17 +388,24 @@ void DisplayManager_::generateNotification(String payload)
|
||||
{
|
||||
notify.isGif = false;
|
||||
notify.icon = LittleFS.open("/ICONS/" + iconFileName + ".jpg");
|
||||
return;
|
||||
}
|
||||
else if (LittleFS.exists("/ICONS/" + iconFileName + ".gif"))
|
||||
{
|
||||
notify.isGif = true;
|
||||
notify.icon = LittleFS.open("/ICONS/" + iconFileName + ".gif");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
fs::File nullPointer;
|
||||
notify.icon = nullPointer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
File f;
|
||||
notify.icon = f;
|
||||
fs::File nullPointer;
|
||||
notify.icon = nullPointer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,25 +440,23 @@ void DisplayManager_::loadNativeApps()
|
||||
};
|
||||
|
||||
// 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
|
||||
updateApp("date", DateFrame, SHOW_DATE, 1);
|
||||
updateApp("date", DateApp, SHOW_DATE, 1);
|
||||
|
||||
// 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
|
||||
updateApp("hum", HumFrame, SHOW_HUM, 3);
|
||||
updateApp("hum", HumApp, SHOW_HUM, 3);
|
||||
|
||||
// Update the "bat" app at position 4
|
||||
updateApp("bat", BatFrame, SHOW_BAT, 4);
|
||||
updateApp("bat", BatApp, SHOW_BAT, 4);
|
||||
|
||||
ui.setApps(Apps);
|
||||
if (AUTO_TRANSITION && Apps.size() == 1)
|
||||
{
|
||||
setAutoTransition(false);
|
||||
}
|
||||
|
||||
setAutoTransition(true);
|
||||
}
|
||||
|
||||
void DisplayManager_::setup()
|
||||
@@ -415,12 +479,12 @@ void DisplayManager_::tick()
|
||||
else
|
||||
{
|
||||
ui.update();
|
||||
if (ui.getUiState()->frameState == IN_TRANSITION && !appIsSwitching)
|
||||
if (ui.getUiState()->appState == IN_TRANSITION && !appIsSwitching)
|
||||
{
|
||||
appIsSwitching = true;
|
||||
MQTTManager.setCurrentApp(CURRENT_APP);
|
||||
}
|
||||
else if (ui.getUiState()->frameState == FIXED && appIsSwitching)
|
||||
else if (ui.getUiState()->appState == FIXED && appIsSwitching)
|
||||
{
|
||||
appIsSwitching = false;
|
||||
MQTTManager.setCurrentApp(CURRENT_APP);
|
||||
@@ -593,4 +657,50 @@ void DisplayManager_::drawMenuIndicator(int cur, int total, uint16_t color)
|
||||
matrix.drawLine(x, 7, x + menuItemWidth - 1, 7, matrix.Color(100, 100, 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
void drawProgressBar(int cur, int total);
|
||||
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 drawBarChart(int16_t x, int16_t y,const int data[], byte dataSize, bool withIcon, uint16_t color);
|
||||
};
|
||||
|
||||
extern DisplayManager_ &DisplayManager;
|
||||
|
||||
@@ -528,7 +528,7 @@ public:
|
||||
}
|
||||
}
|
||||
needNewFrame = false;
|
||||
lastFrameTime = millis();
|
||||
lastFrameTime = millis();
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -612,7 +612,6 @@ public:
|
||||
byte b = readByte();
|
||||
if (b == 0x2c)
|
||||
{
|
||||
Serial.println("Parse");
|
||||
parseTableBasedImage();
|
||||
return 0;
|
||||
}
|
||||
@@ -641,11 +640,10 @@ public:
|
||||
{
|
||||
done = true;
|
||||
file.seek(0);
|
||||
Serial.println("Finished");
|
||||
parseGifHeader();
|
||||
parseLogicalScreenDescriptor();
|
||||
parseGlobalColorTable();
|
||||
drawFrame(offsetX,offsetY);
|
||||
drawFrame(offsetX, offsetY);
|
||||
return ERROR_FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
#include "Globals.h"
|
||||
#include "Preferences.h"
|
||||
#include <WiFi.h>
|
||||
|
||||
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()
|
||||
{
|
||||
Settings.begin("awtrix", false);
|
||||
@@ -23,6 +33,8 @@ void loadSettings()
|
||||
SHOW_HUM = Settings.getBool("HUM", true);
|
||||
SHOW_BAT = Settings.getBool("BAT", true);
|
||||
Settings.end();
|
||||
uniqueID = getID();
|
||||
MQTT_PREFIX = String(uniqueID);
|
||||
}
|
||||
|
||||
void saveSettings()
|
||||
@@ -39,7 +51,6 @@ void saveSettings()
|
||||
Settings.putString("DFORMAT", DATE_FORMAT);
|
||||
Settings.putBool("SOM", START_ON_MONDAY);
|
||||
Settings.putBool("CEL", IS_CELSIUS);
|
||||
|
||||
Settings.putBool("TIM", SHOW_TIME);
|
||||
Settings.putBool("DAT", SHOW_DATE);
|
||||
Settings.putBool("TEMP", SHOW_TEMP);
|
||||
@@ -48,17 +59,18 @@ void saveSettings()
|
||||
Settings.end();
|
||||
}
|
||||
|
||||
const char *uniqueID;
|
||||
IPAddress local_IP;
|
||||
IPAddress gateway;
|
||||
IPAddress subnet;
|
||||
IPAddress primaryDNS;
|
||||
IPAddress secondaryDNS;
|
||||
const char *VERSION = "0.41";
|
||||
const char *VERSION = "0.42";
|
||||
String MQTT_HOST = "";
|
||||
uint16_t MQTT_PORT = 1883;
|
||||
String MQTT_USER;
|
||||
String MQTT_PASS;
|
||||
String MQTT_PREFIX = "AwtrixLight";
|
||||
String MQTT_PREFIX;
|
||||
String CITY = "Berlin,de";
|
||||
bool IO_BROKER = false;
|
||||
bool NET_STATIC = false;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define GLOBALS_H
|
||||
#include <Arduino.h>
|
||||
|
||||
extern const char *uniqueID;
|
||||
extern const char *VERSION;
|
||||
extern IPAddress local_IP;
|
||||
extern IPAddress gateway;
|
||||
|
||||
@@ -6,24 +6,32 @@
|
||||
#include <WiFi.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
unsigned long startTime;
|
||||
|
||||
WiFiClient espClient;
|
||||
uint8_t lastBrightness;
|
||||
HADevice device;
|
||||
HAMqtt mqtt(espClient, device, 15);
|
||||
HAMqtt mqtt(espClient, device, 18);
|
||||
|
||||
unsigned long reconnectTimer = 0;
|
||||
const unsigned long reconnectInterval = 30000; // 30 Sekunden
|
||||
|
||||
HALight Matrix("bri", HALight::BrightnessFeature | HALight::RGBFeature);
|
||||
HASelect BriMode("BriMode");
|
||||
HAButton dismiss("myButtonA");
|
||||
HAButton nextApp("myButtonB");
|
||||
HAButton prevApp("myButtonC");
|
||||
HASensor curApp("curApp");
|
||||
HASensor battery("battery");
|
||||
HASensor temperature("temperature");
|
||||
HASensor humidity("huminity");
|
||||
HASensor illuminance("illuminance");
|
||||
HALight *Matrix = nullptr;
|
||||
HASelect *BriMode = nullptr;
|
||||
HAButton *dismiss = nullptr;
|
||||
HAButton *nextApp = nullptr;
|
||||
HAButton *prevApp = nullptr;
|
||||
|
||||
HASensor *curApp = nullptr;
|
||||
HASensor *battery = nullptr;
|
||||
HASensor *temperature = nullptr;
|
||||
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
|
||||
MQTTManager_ &MQTTManager_::getInstance()
|
||||
@@ -37,15 +45,15 @@ MQTTManager_ &MQTTManager = MQTTManager.getInstance();
|
||||
|
||||
void onButtonCommand(HAButton *sender)
|
||||
{
|
||||
if (sender == &dismiss)
|
||||
if (sender == dismiss)
|
||||
{
|
||||
DisplayManager.dismissNotify();
|
||||
}
|
||||
else if (sender == &nextApp)
|
||||
else if (sender == nextApp)
|
||||
{
|
||||
DisplayManager.nextApp();
|
||||
}
|
||||
else if (sender == &prevApp)
|
||||
else if (sender == prevApp)
|
||||
{
|
||||
DisplayManager.previousApp();
|
||||
}
|
||||
@@ -66,7 +74,7 @@ void onSelectCommand(int8_t index, HASelect *sender)
|
||||
AUTO_BRIGHTNESS = true;
|
||||
return;
|
||||
}
|
||||
Matrix.setBrightness(BRIGHTNESS);
|
||||
Matrix->setBrightness(BRIGHTNESS);
|
||||
saveSettings();
|
||||
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()
|
||||
{
|
||||
byte mac[6];
|
||||
WiFi.macAddress(mac);
|
||||
|
||||
startTime = millis();
|
||||
if (HA_DISCOVERY)
|
||||
{
|
||||
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.setName(MQTT_PREFIX.c_str());
|
||||
device.setName(uniqueID);
|
||||
device.setSoftwareVersion(VERSION);
|
||||
device.setManufacturer("Blueforcer");
|
||||
device.setModel("AWTRIX Light");
|
||||
device.setAvailability(true);
|
||||
Matrix.setIcon("mdi:lightbulb");
|
||||
Matrix.setName("Matrix");
|
||||
Matrix.onStateCommand(onStateCommand);
|
||||
Matrix.onBrightnessCommand(onBrightnessCommand);
|
||||
Matrix.onRGBColorCommand(onRGBColorCommand);
|
||||
Matrix.setCurrentState(true);
|
||||
Matrix.setBRIGHTNESS(BRIGHTNESS);
|
||||
|
||||
String uniqueIDWithSuffix;
|
||||
|
||||
sprintf(matID, "%s_mat", macStr);
|
||||
Matrix = new HALight(matID, HALight::BrightnessFeature | HALight::RGBFeature);
|
||||
|
||||
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;
|
||||
color.red = (TEXTCOLOR_565 >> 11) << 3;
|
||||
color.green = ((TEXTCOLOR_565 >> 5) & 0x3F) << 2;
|
||||
color.blue = (TEXTCOLOR_565 & 0x1F) << 3;
|
||||
Matrix.setCurrentRGBColor(color);
|
||||
Matrix.setState(true, true);
|
||||
Matrix->setCurrentRGBColor(color);
|
||||
Matrix->setState(true, true);
|
||||
|
||||
BriMode.setOptions("Manual;Auto"); // use semicolons as separator of options
|
||||
BriMode.onCommand(onSelectCommand);
|
||||
BriMode.setIcon("mdi:brightness-auto"); // optional
|
||||
BriMode.setName("Brightness mode"); // optional
|
||||
BriMode.setState(AUTO_BRIGHTNESS, true);
|
||||
sprintf(briID, "%s_bri", macStr);
|
||||
BriMode = new HASelect(briID);
|
||||
BriMode->setOptions("Manual;Auto"); // use semicolons as separator of options
|
||||
BriMode->onCommand(onSelectCommand);
|
||||
BriMode->setIcon("mdi:brightness-auto"); // optional
|
||||
BriMode->setName("Brightness mode"); // optional
|
||||
BriMode->setState(AUTO_BRIGHTNESS, true);
|
||||
|
||||
dismiss.setIcon("mdi:bell-off");
|
||||
dismiss.setName("Dismiss notification");
|
||||
nextApp.setIcon("mdi:arrow-right-bold");
|
||||
nextApp.setName("Next app");
|
||||
prevApp.setIcon("mdi:arrow-left-bold");
|
||||
prevApp.setName("Previous app");
|
||||
sprintf(btnAID, "%s_btna", macStr);
|
||||
dismiss = new HAButton(btnAID);
|
||||
dismiss->setIcon("mdi:bell-off");
|
||||
dismiss->setName("Dismiss notification");
|
||||
|
||||
dismiss.onCommand(onButtonCommand);
|
||||
nextApp.onCommand(onButtonCommand);
|
||||
prevApp.onCommand(onButtonCommand);
|
||||
sprintf(btnBID, "%s_btnb", macStr);
|
||||
nextApp = new HAButton(btnBID);
|
||||
nextApp->setIcon("mdi:arrow-right-bold");
|
||||
nextApp->setName("Next app");
|
||||
|
||||
curApp.setIcon("mdi:apps");
|
||||
curApp.setName("Current app");
|
||||
sprintf(btnCID, "%s_btnc", macStr);
|
||||
prevApp = new HAButton(btnCID);
|
||||
prevApp->setIcon("mdi:arrow-left-bold");
|
||||
prevApp->setName("Previous app");
|
||||
|
||||
temperature.setIcon("mdi:thermometer");
|
||||
temperature.setName("Temperature");
|
||||
temperature.setUnitOfMeasurement("°C");
|
||||
dismiss->onCommand(onButtonCommand);
|
||||
nextApp->onCommand(onButtonCommand);
|
||||
prevApp->onCommand(onButtonCommand);
|
||||
|
||||
humidity.setIcon("mdi:water-percent");
|
||||
humidity.setName("humidity");
|
||||
humidity.setUnitOfMeasurement("%");
|
||||
sprintf(appID, "%s_app", macStr);
|
||||
curApp = new HASensor(appID);
|
||||
curApp->setIcon("mdi:apps");
|
||||
curApp->setName("Current app");
|
||||
|
||||
battery.setIcon("mdi:battery-90");
|
||||
battery.setName("Battery");
|
||||
battery.setUnitOfMeasurement("%");
|
||||
sprintf(tempID, "%s_temp", macStr);
|
||||
temperature = new HASensor(tempID);
|
||||
temperature->setIcon("mdi:thermometer");
|
||||
temperature->setName("Temperature");
|
||||
temperature->setDeviceClass("temperature");
|
||||
temperature->setUnitOfMeasurement("°C");
|
||||
|
||||
illuminance.setIcon("mdi:sun-wireless");
|
||||
illuminance.setName("Illuminance");
|
||||
illuminance.setUnitOfMeasurement("lx");
|
||||
sprintf(humID, "%s_hum", macStr);
|
||||
humidity = new HASensor(humID);
|
||||
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
|
||||
{
|
||||
@@ -299,7 +364,23 @@ void MQTTManager_::publish(const char *topic, const char *payload)
|
||||
void MQTTManager_::setCurrentApp(String value)
|
||||
{
|
||||
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()
|
||||
@@ -308,20 +389,32 @@ void MQTTManager_::sendStats()
|
||||
{
|
||||
char buffer[5];
|
||||
snprintf(buffer, 5, "%d", BATTERY_PERCENT);
|
||||
battery.setValue(buffer);
|
||||
battery->setValue(buffer);
|
||||
|
||||
snprintf(buffer, 5, "%.0f", CURRENT_TEMP);
|
||||
temperature.setValue(buffer);
|
||||
temperature->setValue(buffer);
|
||||
|
||||
snprintf(buffer, 5, "%.0f", CURRENT_HUM);
|
||||
humidity.setValue(buffer);
|
||||
humidity->setValue(buffer);
|
||||
|
||||
snprintf(buffer, 5, "%.0f", CURRENT_LUX);
|
||||
illuminance.setValue(buffer);
|
||||
illuminance->setValue(buffer);
|
||||
|
||||
BriMode.setState(AUTO_BRIGHTNESS, true);
|
||||
Matrix.setBRIGHTNESS(BRIGHTNESS);
|
||||
Matrix.setState(!MATRIX_OFF, false);
|
||||
BriMode->setState(AUTO_BRIGHTNESS, true);
|
||||
Matrix->setBRIGHTNESS(BRIGHTNESS);
|
||||
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;
|
||||
@@ -336,6 +429,8 @@ void MQTTManager_::sendStats()
|
||||
doc["temp"] = buffer;
|
||||
snprintf(buffer, 5, "%.0f", CURRENT_HUM);
|
||||
doc["hum"] = buffer;
|
||||
doc["uptime"] = readUptime();
|
||||
doc["wifi"] = WiFi.RSSI();
|
||||
String jsonString;
|
||||
serializeJson(doc, jsonString);
|
||||
char topic[50];
|
||||
|
||||
@@ -135,26 +135,20 @@ String MenuManager_::menutext()
|
||||
return String(TIME_PER_APP / 1000.0, 0) + "s";
|
||||
case TimeFormatMenu:
|
||||
DisplayManager.drawMenuIndicator(timeFormatIndex, timeFormatCount, 0xFBC0);
|
||||
|
||||
char display[9];
|
||||
if (timeFormat[timeFormatIndex][2] == ' ')
|
||||
{
|
||||
strcpy(display, timeFormat[timeFormatIndex]);
|
||||
if (now % 2)
|
||||
{
|
||||
display[2] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
display[2] = ':';
|
||||
}
|
||||
strftime(t, sizeof(t), display, localtime(&now));
|
||||
return t;
|
||||
snprintf(display, sizeof(display), "%s", timeFormat[timeFormatIndex]);
|
||||
display[2] = now % 2 ? ' ' : ':';
|
||||
}
|
||||
else
|
||||
{
|
||||
strftime(t, sizeof(t), timeFormat[timeFormatIndex], localtime(&now));
|
||||
return t;
|
||||
snprintf(display, sizeof(display), "%s", timeFormat[timeFormatIndex]);
|
||||
}
|
||||
|
||||
strftime(t, sizeof(t), display, localtime(&now));
|
||||
return t;
|
||||
case DateFormatMenu:
|
||||
DisplayManager.drawMenuIndicator(dateFormatIndex, dateFormatCount, 0xFBC0);
|
||||
strftime(t, sizeof(t), dateFormat[dateFormatIndex], localtime(&now));
|
||||
@@ -427,6 +421,8 @@ void MenuManager_::selectButtonLong()
|
||||
saveSettings();
|
||||
break;
|
||||
case DateFormatMenu:
|
||||
DATE_FORMAT = dateFormat[dateFormatIndex];
|
||||
saveSettings();
|
||||
case WeekdayMenu:
|
||||
case TempMenu:
|
||||
saveSettings();
|
||||
|
||||
@@ -10,12 +10,25 @@
|
||||
#include <MenuManager.h>
|
||||
|
||||
#define SOUND_OFF false
|
||||
#define BATTERY_PIN 34
|
||||
#define BUZZER_PIN 15
|
||||
#define LDR_PIN 35
|
||||
#define BUTTON_UP_PIN 26
|
||||
#define BUTTON_DOWN_PIN 14
|
||||
#define BUTTON_SELECT_PIN 27
|
||||
|
||||
#ifdef ULANZI
|
||||
// Pinouts für das ULANZI-Environment
|
||||
#define BATTERY_PIN 34
|
||||
#define BUZZER_PIN 15
|
||||
#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;
|
||||
EasyButton button_left(BUTTON_UP_PIN);
|
||||
@@ -45,7 +58,7 @@ float sampleSum = 0.0;
|
||||
float sampleAverage = 0.0;
|
||||
float brightnessPercent = 0.0;
|
||||
|
||||
unsigned long startTime;
|
||||
|
||||
|
||||
// The getter for the instantiated singleton instance
|
||||
PeripheryManager_ &PeripheryManager_::getInstance()
|
||||
@@ -100,7 +113,6 @@ void PeripheryManager_::playBootSound()
|
||||
const int nNotes = 6;
|
||||
String notes[nNotes] = {"E5", "C5", "G4", "E4", "G4", "C5"};
|
||||
const int timeUnit = 150;
|
||||
// create a melody
|
||||
Melody melody = MelodyFactory.load("Nice Melody", timeUnit, notes, nNotes);
|
||||
player.playAsync(melody);
|
||||
}
|
||||
@@ -128,7 +140,7 @@ void fistStart()
|
||||
|
||||
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);
|
||||
|
||||
uint16_t LDRVALUE = analogRead(LDR_PIN);
|
||||
@@ -167,7 +179,7 @@ void PeripheryManager_::tick()
|
||||
{
|
||||
previousMillis_BatTempHum = currentMillis_BatTempHum;
|
||||
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;
|
||||
sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM);
|
||||
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
|
||||
time_t lastAlarmTime = 0;
|
||||
|
||||
@@ -63,7 +63,7 @@ void ServerManager_::setup()
|
||||
{
|
||||
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));
|
||||
Serial.println(myIP.toString());
|
||||
|
||||
@@ -99,7 +99,7 @@ void ServerManager_::setup()
|
||||
mws.addHandler("/version", HTTP_GET, versionHandler);
|
||||
mws.begin();
|
||||
|
||||
if (!MDNS.begin(MQTT_PREFIX.c_str()))
|
||||
if (!MDNS.begin(uniqueID))
|
||||
{
|
||||
Serial.println("Error starting mDNS");
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user