Skip to content

Commit

Permalink
V0.59
Browse files Browse the repository at this point in the history
- Adds drawing function to notify and customapp. closes #93
- Swap buttons in MQTT and HA with upside down mode
- Sets a free pixel between icon and text while scrolling. closes #92
  • Loading branch information
Blueforcer committed Apr 28, 2023
1 parent 9ae147e commit ca178cc
Show file tree
Hide file tree
Showing 11 changed files with 783 additions and 614 deletions.
52 changes: 52 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ All keys are optional, so you can send just the properties you want to use.
| `progressC` | string or array of integers | The color of the progressbar | -1 |
| `progressBC` | string or array of integers | The color of the progressbar background | -1 |
| `pos` | number | defines the position of your custompage in the loop, starting at 0 for the first position. This will only apply with your first push. This function is experimental | N/A |
| `draw` | array of objects | Array of drawing instructions. Each object represents a drawing command. | See the drawing instructions below |

Color values can have a hex string or an array of R,G,B values:
`"#FFFFFF" or [255,255,0]`
Expand All @@ -91,6 +92,57 @@ Here's an example JSON object to display the text "Hello, AWTRIX Light!" with th
"duration": 10
}
```

### Drawing Instructions
?> Pease note: Depending on the amount of objects, the RAM usage can be very high. This could cause freezes or reboots.
It's important to be mindful of the number of objects and the complexity of the drawing instructions to avoid performance issues.

Each drawing instruction is an object with a required command key `c` and additional keys depending on the command:

| Command | Additional Keys | Description |
| ------- | --------------- | ----------- |
| `dp` | `x`, `y`, `cl` | Draw a pixel at position (`x`, `y`) with color `cl` |

This comment has been minimized.

Copy link
@dalv666

dalv666 Apr 29, 2023

Restrictions for x and y are not clear. What is the maximum and minimum value, and whether there will be scrolling when drawing, if you go beyond the screen boundaries?

| `dl` | `x0`, `y0`, `x1`, `y1`, `cl` | Draw a line from (`x0`, `y0`) to (`x1`, `y1`) with color `cl` |
| `dr` | `x`, `y`, `w`, `h`, `cl` | Draw a rectangle with top-left corner at (`x`, `y`), width `w`, height `h`, and color `cl` |
| `df` | `x`, `y`, `w`, `h`, `cl` | Draw a filled rectangle with top-left corner at (`x`, `y`), width `w`, height `h`, and color `cl` |
| `dc` | `x`, `y`, `r`, `cl` | Draw a circle with center at (`x`, `y`), radius `r`, and color `cl` |
| `dfc` | `x`, `y`, `r`, `cl` | Draw a filled circle with center at (`x`, `y`), radius `r`, and color `cl` |
| `dt` | `x`, `y`, `t`, `cl` | Draw text `t` with top-left corner at (`x`, `y`) and color `cl` |

Color values can be a hex string or an array of R, G, B values:
`"#FFFFFF" or [255, 255, 0]`

### Example

Here's an example JSON object to draw a red circle, a blue rectangle, and the text "Hello" in green:

```json
{ "draw": [
{
"c": "dc",
"x": 28,
"y": 4,
"r": 3,
"cl": "#FF0000"
},
{
"c": "dr",
"x": 20,
"y": 4,
"w": 4,
"h": 4,
"cl": "#0000FF"
},
{
"c": "dt",
"x": 0,
"y": 0,
"t": "Hello",
"cl": "#00FF00"
}
]
}
```

### Display a text in colored fragments
You can display a text where you allowed to colorize fragments of the text.
Expand Down
32 changes: 23 additions & 9 deletions src/Apps.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <WiFi.h>
#include <HTTPClient.h>
#include <Ticker.h>
#include <ArduinoJson.h>

Ticker downloader;

Expand All @@ -27,6 +28,7 @@ String WEATHER_HUM;

struct CustomApp
{
std::vector<String> drawInstructions;
int16_t scrollposition = 0;
int16_t scrollDelay = 0;
String text;
Expand Down Expand Up @@ -64,6 +66,7 @@ std::map<String, CustomApp> customApps;

struct Notification
{
std::vector<String> drawInstructions;
int16_t scrollposition = 34;
int16_t scrollDelay = 0;
String text;
Expand Down Expand Up @@ -266,7 +269,7 @@ void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i
}
matrix->drawRGBBitmap(x, y + 1, icon_2075, 8, 8);
matrix->setCursor(14 + x, 6 + y);
int humidity = CURRENT_HUM;
int humidity = CURRENT_HUM;
matrix->print(humidity);
matrix->print("%");
}
Expand Down Expand Up @@ -368,8 +371,9 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
return;
}


// reset custom App properties if last frame
if (lastFrame)
if (firstFrame)
{
ca->iconWasPushed = false;
ca->scrollposition = 9 + ca->textOffset;
Expand All @@ -390,6 +394,7 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState

bool hasIcon = ca->icon;
matrix->fillRect(x, y, 32, 8, ca->background);

// Calculate text and available width
uint16_t textWidth = 0;
if (!ca->fragments.empty())
Expand Down Expand Up @@ -495,7 +500,6 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
}
else
{

if (ca->rainbow)
{
DisplayManager.HSVtext(x + textX, 6 + y, ca->text.c_str(), false, ca->textCase);
Expand Down Expand Up @@ -545,9 +549,9 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
++ca->iconPosition;
}

if (ca->scrollposition < 8 && !ca->iconWasPushed)
if (ca->scrollposition < 9 && !ca->iconWasPushed)
{
ca->iconPosition = ca->scrollposition - 8;
ca->iconPosition = ca->scrollposition - 9;

if (ca->iconPosition <= -9)
{
Expand All @@ -559,7 +563,6 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
// 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 (ca->isGif)
{

gifPlayer->playGif(x + ca->iconPosition, y, &ca->icon);
}
else
Expand All @@ -571,10 +574,15 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
// Draw vertical line if text is scrolling
if (!noScrolling)
{
// matrix->drawLine(8 + x + ca->iconPosition, 0 + y, 8 + x + ca->iconPosition, 7 + y, 0);
matrix->drawLine(8 + x + ca->iconPosition, 0 + y, 8 + x + ca->iconPosition, 7 + y, 0);
}
}

if (ca->drawInstructions.size() > 0)
{
DisplayManager.processDrawInstructions(x, y, ca->drawInstructions);
}

if (ca->progress > -1)
{
DisplayManager.drawProgressBar((hasIcon ? 9 : 0), 7 + y, ca->progress, ca->pColor, ca->pbColor);
Expand Down Expand Up @@ -617,6 +625,7 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer
notify.lineSize = 0;
notify.textOffset = 0;
notify.progress = -1;
notify.drawInstructions.clear();
return;
}

Expand Down Expand Up @@ -773,7 +782,7 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer
++notify.iconPosition;
}

if (notify.scrollposition < 8 && !notify.iconWasPushed)
if (notify.scrollposition < 9 && !notify.iconWasPushed)
{
notify.iconPosition = notify.scrollposition - 9;

Expand All @@ -800,7 +809,7 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer
// Display icon divider line if text is scrolling
if (!noScrolling)
{
// matrix->drawLine(8 + notify.iconPosition, 0, 8 + notify.iconPosition, 7, 0);
matrix->drawLine(8 + notify.iconPosition, 0, 8 + notify.iconPosition, 7, 0);
}
}

Expand All @@ -809,6 +818,11 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer
DisplayManager.drawProgressBar((hasIcon ? 9 : 0), 7, notify.progress, notify.pColor, notify.pbColor);
}

if (notify.drawInstructions.size() > 0)
{
DisplayManager.processDrawInstructions(0, 0, notify.drawInstructions);
}

// Reset text color after displaying notification
DisplayManager.getInstance().resetTextColor();
}
Expand Down
101 changes: 95 additions & 6 deletions src/DisplayManager.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#include <DisplayManager.h>
#include <FastLED_NeoMatrix.h>

#include "MatrixDisplayUi.h"
#include <TJpg_Decoder.h>
#include "icons.h"
#include "Globals.h"
#include <ArduinoJson.h>
#include "PeripheryManager.h"
#include "MQTTManager.h"
#include "GifPlayer.h"
Expand Down Expand Up @@ -301,15 +301,13 @@ void DisplayManager_::generateCustomPage(const String &name, const char *json)
if (strcmp(json, "") == 0 && customApps.count(name))
{
removeCustomAppFromApps(name, true);
showGif = false;
return;
}

StaticJsonDocument<2048> doc;
DeserializationError error = deserializeJson(doc, json);
if (error)
{
showGif = false;
doc.clear();
return;
}
Expand Down Expand Up @@ -437,6 +435,18 @@ void DisplayManager_::generateCustomPage(const String &name, const char *json)
customApp.lineSize = 0;
}

customApp.drawInstructions.clear();
if (doc.containsKey("draw"))
{
JsonArray instructions = doc["draw"];
for (JsonObject instruction : instructions)
{
String instructionStr;
serializeJson(instruction, instructionStr);
customApp.drawInstructions.push_back(instructionStr);
}
}

customApp.duration = doc.containsKey("duration") ? doc["duration"].as<int>() * 1000 : 0;
int pos = doc.containsKey("pos") ? doc["pos"].as<uint8_t>() : -1;
customApp.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false;
Expand Down Expand Up @@ -548,6 +558,18 @@ void DisplayManager_::generateNotification(const char *json)
auto background = doc["background"];
notify.background = getColorFromJsonVariant(background, 0);
}
notify.flag = true;
notify.drawInstructions.clear();
if (doc.containsKey("draw"))
{
JsonArray instructions = doc["draw"];
for (JsonObject instruction : instructions)
{
String instructionStr;
serializeJson(instruction, instructionStr);
notify.drawInstructions.push_back(instructionStr);
}
}

notify.duration = doc.containsKey("duration") ? doc["duration"].as<int>() * 1000 : TIME_PER_APP;
notify.repeat = doc.containsKey("repeat") ? doc["repeat"].as<uint16_t>() : -1;
Expand Down Expand Up @@ -666,8 +688,6 @@ void DisplayManager_::generateNotification(const char *json)
notify.text = "";
}

notify.flag = true;

if (doc.containsKey("icon"))
{
String iconFileName = doc["icon"].as<String>();
Expand Down Expand Up @@ -929,6 +949,7 @@ void DisplayManager_::gererateTimer(String Payload)
time_t futureTime = mktime(&futureTimeinfo);
int interval = difftime(futureTime, now) * 1000;
TimerTicker.once_ms(interval, timerCallback);

}

void DisplayManager_::switchToApp(const char *json)
Expand Down Expand Up @@ -1557,4 +1578,72 @@ void DisplayManager_::reorderApps(const String &jsonString)
Apps = reorderedApps;
ui->setApps(Apps);
ui->forceResetState();
}
}

void DisplayManager_::processDrawInstructions(int16_t xOffset, int16_t yOffset, const std::vector<String> &drawInstructions)
{
for (const String &instructionStr : drawInstructions)
{
StaticJsonDocument<128> instructionDoc;
deserializeJson(instructionDoc, instructionStr);
JsonObject instruction = instructionDoc.as<JsonObject>();

String command = instruction["c"].as<String>();
Serial.println(command);
auto cl = instruction["cl"];
uint16_t color = getColorFromJsonVariant(cl, TEXTCOLOR_565);
if (command == "dp")
{
int x = instruction["x"].as<int>();
int y = instruction["y"].as<int>();
matrix->drawPixel(x + xOffset, y + yOffset, color);
}
else if (command == "dl")
{
int x0 = instruction["x0"].as<int>();
int y0 = instruction["y0"].as<int>();
int x1 = instruction["x1"].as<int>();
int y1 = instruction["y1"].as<int>();
matrix->drawLine(x0 + xOffset, y0 + yOffset, x1 + xOffset, y1 + yOffset, color);
}
else if (command == "dr")
{
int x = instruction["x"].as<int>();
int y = instruction["y"].as<int>();
int w = instruction["w"].as<int>();
int h = instruction["h"].as<int>();
matrix->drawRect(x + xOffset, y + yOffset, w, h, color);
}
else if (command == "df")
{
int x = instruction["x"].as<int>();
int y = instruction["y"].as<int>();
int w = instruction["w"].as<int>();
int h = instruction["h"].as<int>();
matrix->fillRect(x + xOffset, y + yOffset, w, h, color);
}
else if (command == "dc")
{
int x = instruction["x"].as<int>();
int y = instruction["y"].as<int>();
int r = instruction["r"].as<int>();
matrix->drawCircle(x + xOffset, y + yOffset, r, color);
}
else if (command == "dfc")
{
int x = instruction["x"].as<int>();
int y = instruction["y"].as<int>();
int r = instruction["r"].as<int>();
matrix->fillCircle(x + xOffset, y + yOffset, r, color);
}
else if (command == "dt")
{
int x = instruction["x"].as<int>();
int y = instruction["y"].as<int>();
String text = instruction["t"].as<String>();
matrix->setCursor(x + xOffset, y + yOffset + 5);
matrix->setTextColor(color);
matrix->print(text);
}
}
}
5 changes: 5 additions & 0 deletions src/DisplayManager.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#ifndef DisplayManager_h
#define DisplayManager_h


#include <Arduino.h>
#include <ArduinoJson.h>
#include <LittleFS.h>
#include <vector>


class DisplayManager_
{
Expand Down Expand Up @@ -78,6 +82,7 @@ class DisplayManager_
void showSleepAnimation();
void showCurtainEffect();
void sendAppLoop();
void processDrawInstructions(int16_t x, int16_t y, const std::vector<String> &drawInstructions);
String ledsAsJson();
String getAppsWithIcon();
};
Expand Down
2 changes: 1 addition & 1 deletion src/Globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ IPAddress gateway;
IPAddress subnet;
IPAddress primaryDNS;
IPAddress secondaryDNS;
const char *VERSION = "0.58";
const char *VERSION = "0.59";
String MQTT_HOST = "";
uint16_t MQTT_PORT = 1883;
String MQTT_USER;
Expand Down
1 change: 0 additions & 1 deletion src/Globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#define DEBUG_PRINTF(format, ...)
#endif

#define configASSERT(x) if((x) == 0) {printf("ASSERTION FAILED at line %d in file %s.\n", __LINE__, __FILE__); taskDISABLE_INTERRUPTS(); for(;;);}

extern const char *uniqueID;
extern const char *VERSION;
Expand Down
Loading

0 comments on commit ca178cc

Please sign in to comment.