- Introduces an function that allows users to add, remove, and rearrange multiple apps on the device at once via MQTT. This provides greater flexibility and customization options. Please note that this function is experimental and should be used with caution.

https://blueforcer.github.io/awtrix-light/#/mqtt?id=addremove-and-rearange-apps
This commit is contained in:
Stephan Mühl
2023-03-31 00:18:32 +02:00
parent 783180a7d9
commit 39e1b0b0dd
10 changed files with 295 additions and 49 deletions

View File

@@ -245,9 +245,9 @@ void removeCustomApp(const String &name)
}
}
void DisplayManager_::generateCustomPage(String name, String payload)
void DisplayManager_::generateCustomPage(String name, const char *json)
{
if (payload == "" && customApps.count(name))
if (json == "" && customApps.count(name))
{
customApps.erase(customApps.find(name));
removeCustomApp(name);
@@ -255,7 +255,7 @@ void DisplayManager_::generateCustomPage(String name, String payload)
}
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, payload);
DeserializationError error = deserializeJson(doc, json);
if (error)
return;
@@ -300,9 +300,30 @@ void DisplayManager_::generateCustomPage(String name, String payload)
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 (doc.containsKey("color"))
{
auto color = doc["color"];
if (color.is<String>())
{
customApp.color = hexToRgb565(color.as<String>());
}
else if (color.is<JsonArray>() && color.size() == 3)
{
uint8_t r = color[0];
uint8_t g = color[1];
uint8_t b = color[2];
customApp.color = (r << 11) | (g << 5) | b;
}
else
{
customApp.color = TEXTCOLOR_565;
}
}
else
{
customApp.color = TEXTCOLOR_565;
}
if (currentCustomApp != name)
{
@@ -346,10 +367,10 @@ void DisplayManager_::generateCustomPage(String name, String payload)
customApps[name] = customApp;
}
void DisplayManager_::generateNotification(String payload)
void DisplayManager_::generateNotification(const char *json)
{
StaticJsonDocument<1024> doc;
deserializeJson(doc, payload);
deserializeJson(doc, json);
notify.duration = doc.containsKey("duration") ? doc["duration"].as<int>() * 1000 : TIME_PER_APP;
notify.text = utf8ascii(doc["text"].as<String>());
@@ -388,9 +409,29 @@ void DisplayManager_::generateNotification(String payload)
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;
if (doc.containsKey("color"))
{
auto color = doc["color"];
if (color.is<String>())
{
notify.color = hexToRgb565(color.as<String>());
}
else if (color.is<JsonArray>() && color.size() == 3)
{
uint8_t r = color[0];
uint8_t g = color[1];
uint8_t b = color[2];
notify.color = (r << 11) | (g << 5) | b;
}
else
{
notify.color = TEXTCOLOR_565;
}
}
else
{
notify.color = TEXTCOLOR_565;
}
if (doc.containsKey("icon"))
{
@@ -607,10 +648,10 @@ void DisplayManager_::gererateTimer(String Payload)
TimerTicker.attach_ms(interval, timerCallback);
}
void DisplayManager_::switchToApp(String Payload)
void DisplayManager_::switchToApp(const char *json)
{
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, Payload);
DeserializationError error = deserializeJson(doc, json);
if (error)
return;
String name = doc["name"].as<String>();
@@ -620,10 +661,10 @@ void DisplayManager_::switchToApp(String Payload)
ui.transitionToApp(index);
}
void DisplayManager_::setNewSettings(String Payload)
void DisplayManager_::setNewSettings(const char *json)
{
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, Payload);
DeserializationError error = deserializeJson(doc, json);
if (error)
return;
TIME_PER_APP = doc.containsKey("apptime") ? doc["apptime"] : TIME_PER_APP;
@@ -714,4 +755,124 @@ void DisplayManager_::drawBarChart(int16_t x, int16_t y, const int data[], byte
int y1 = min(8 - barHeight, 7);
matrix.fillRect(x1, y1 + y, barWidth, barHeight, color);
}
}
void DisplayManager_::updateAppVector(const char *json)
{
// Parse the JSON input
DynamicJsonDocument doc(1024);
auto error = deserializeJson(doc, json);
if (error)
{
// If parsing fails, print an error message and return
Serial.print("Failed to parse JSON: ");
Serial.println(error.c_str());
return;
}
// Create new vectors to store updated apps
std::vector<std::pair<String, AppCallback>> newApps;
std::vector<String> activeApps;
// Loop through all apps in the JSON input
for (const auto &app : doc.as<JsonArray>())
{
// Get the app name, active status, and position (if specified)
String name = app["name"].as<String>();
bool show = true;
int position = -1;
if (app.containsKey("show"))
{
show = app["show"].as<bool>();
}
if (app.containsKey("pos"))
{
position = app["pos"].as<int>();
}
// Find the corresponding AppCallback function based on the app name
AppCallback callback;
if (name == "time")
{
callback = TimeApp;
SHOW_TIME = show;
}
else if (name == "date")
{
callback = DateApp;
SHOW_DATE = show;
}
else if (name == "temp")
{
callback = TempApp;
SHOW_TEMP = show;
}
else if (name == "hum")
{
callback = HumApp;
SHOW_HUM = show;
}
else if (name == "bat")
{
callback = BatApp;
SHOW_BAT = show;
}
else
{
// If the app is not one of the built-in apps, check if it's already in the vector
int appIndex = findAppIndexByName(name);
if (appIndex >= 0)
{
// The app is in the vector, so we can move it to a new position or remove it
auto it = Apps.begin() + appIndex;
if (show)
{
if (position >= 0 && static_cast<size_t>(position) < newApps.size())
{
Apps.erase(it);
newApps.insert(newApps.begin() + position, std::make_pair(name, it->second));
}
}
else
{
// If the app is being removed, also remove it from the customApps map
if (customApps.count(name))
{
customApps.erase(customApps.find(name));
removeCustomApp(name);
}
}
}
continue;
}
if (show)
{
// Add the app to the new vector
if (position >= 0 && static_cast<size_t>(position) < newApps.size())
{
newApps.insert(newApps.begin() + position, std::make_pair(name, callback));
}
else
{
newApps.emplace_back(name, callback);
}
}
activeApps.push_back(name);
}
// Loop through all apps currently in the vector
for (const auto &app : Apps)
{
// If the app is not in the updated activeApps vector, add it to the newApps vector
if (std::find(activeApps.begin(), activeApps.end(), app.first) == activeApps.end())
{
newApps.push_back(app);
}
}
// Update the apps vector, set it in the UI, and save settings
Apps = std::move(newApps);
ui.setApps(Apps);
}

View File

@@ -45,18 +45,19 @@ public:
void setTextColor(uint16_t color);
void setFPS(uint8_t);
void MatrixState(bool);
void generateNotification(String);
void generateCustomPage(String, String);
void generateNotification(const char *json);
void generateCustomPage(String, const char *json);
void printText(int16_t x, int16_t y, const char *text, bool centered, bool ignoreUppercase);
bool setAutoTransition(bool active);
void switchToApp(String Payload);
void setNewSettings(String Payload);
void switchToApp(const char *json);
void setNewSettings(const char *json);
void drawGIF(uint16_t x, uint16_t y, fs::File gifFile);
void drawJPG(uint16_t x, uint16_t y, fs::File jpgFile);
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);
void drawBarChart(int16_t x, int16_t y, const int data[], byte dataSize, bool withIcon, uint16_t color);
void updateAppVector(const char *json);
};
extern DisplayManager_ &DisplayManager;

View File

@@ -65,7 +65,7 @@ IPAddress gateway;
IPAddress subnet;
IPAddress primaryDNS;
IPAddress secondaryDNS;
const char *VERSION = "0.44";
const char *VERSION = "0.45";
String MQTT_HOST = "";
uint16_t MQTT_PORT = 1883;
String MQTT_USER;

View File

@@ -128,21 +128,22 @@ void onBrightnessCommand(uint8_t brightness, HALight *sender)
void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length)
{
String strTopic = String(topic);
String strPayload = String((const char *)payload).substring(0, length);
char *payloadCopy = new char[length + 1];
memcpy(payloadCopy, payload, length);
payloadCopy[length] = '\0';
if (strTopic == MQTT_PREFIX + "/notify")
{
if (payload[0] != '{' || payload[length - 1] != '}')
{
return;
}
DisplayManager.generateNotification(strPayload);
DisplayManager.generateNotification(payloadCopy);
return;
}
if (strTopic == MQTT_PREFIX + "/timer")
{
DisplayManager.gererateTimer(strPayload);
DisplayManager.gererateTimer(payloadCopy);
return;
}
@@ -152,15 +153,21 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length)
return;
}
if (strTopic == MQTT_PREFIX + "/apps")
{
DisplayManager.updateAppVector(payloadCopy);
return;
}
if (strTopic == MQTT_PREFIX + "/switch")
{
DisplayManager.switchToApp(strPayload);
DisplayManager.switchToApp(payloadCopy);
return;
}
if (strTopic == MQTT_PREFIX + "/settings")
{
DisplayManager.setNewSettings(strPayload);
DisplayManager.setNewSettings(payloadCopy);
return;
}
@@ -185,26 +192,34 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length)
topic_str = topic_str.substring(prefix.length());
}
DisplayManager.generateCustomPage(topic_str, strPayload);
DisplayManager.generateCustomPage(topic_str, payloadCopy);
return;
}
delete[] payloadCopy;
}
void onMqttConnected()
{
String prefix = MQTT_PREFIX;
mqtt.subscribe((prefix + String("/brightness")).c_str());
mqtt.subscribe((prefix + String("/notify/dismiss")).c_str());
mqtt.subscribe((prefix + String("/notify")).c_str());
mqtt.subscribe((prefix + String("/timer")).c_str());
mqtt.subscribe((prefix + String("/custom/#")).c_str());
mqtt.subscribe((prefix + String("/switch")).c_str());
mqtt.subscribe((prefix + String("/settings")).c_str());
mqtt.subscribe((prefix + String("/previousapp")).c_str());
mqtt.subscribe((prefix + String("/nextapp")).c_str());
Serial.println("MQTT Connected");
const char* topics[] PROGMEM = {
"/brightness",
"/notify/dismiss",
"/notify",
"/timer",
"/custom/#",
"/switch",
"/settings",
"/previousapp",
"/nextapp",
"/nextapp",
"/apps"
};
for (const char* topic : topics) {
String fullTopic = prefix + topic;
mqtt.subscribe(fullTopic.c_str());
}
Serial.println(F("MQTT Connected"));
}
void connect()
{
mqtt.onMessage(onMqttMessage);
@@ -212,12 +227,12 @@ void connect()
if (MQTT_USER == "" || MQTT_PASS == "")
{
Serial.println("Connecting to MQTT w/o login");
Serial.println(F("Connecting to MQTT w/o login"));
mqtt.begin(MQTT_HOST.c_str(), MQTT_PORT, nullptr, nullptr, MQTT_PREFIX.c_str());
}
else
{
Serial.println("Connecting to MQTT with login");
Serial.println(F("Connecting to MQTT with login"));
mqtt.begin(MQTT_HOST.c_str(), MQTT_PORT, MQTT_USER.c_str(), MQTT_PASS.c_str(), MQTT_PREFIX.c_str());
}
}
@@ -365,7 +380,7 @@ void MQTTManager_::setup()
}
else
{
Serial.println("Homeassistant discovery disabled");
Serial.println(F("Homeassistant discovery disabled"));
mqtt.disableHA();
}
connect();