v0.43
- Expose buttons to HA - HA Switch to control the transition - Icons are not reloaded if its the same as before
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
- [Onscreen](onscreen.md)
|
||||
|
||||
- Features
|
||||
- [Apps](apps.md)
|
||||
- [Custom Pages & Notifications](custom.md)
|
||||
- [Alarm clock](alarm.md)
|
||||
- [Timer](timer.md)
|
||||
|
||||
38
docs/apps.md
Normal file
38
docs/apps.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Apps
|
||||
|
||||
The AWTRIX Light system comes equipped with several built-in applications, including Time, Date, Temperature, Humidity, and Battery status.
|
||||
As it is designed to integrate seamlessly with your smart home ecosystem, additional applications can be created using MQTT.
|
||||
|
||||
There are numerous benefits to this approach:
|
||||
|
||||
- **Personalization:** Customize each application to suit your preferences and needs.
|
||||
- **Flexibility:** Develop your own applications without the need to modify the firmware.
|
||||
- **Efficient resource management:** Save valuable flash memory space on the ESP module.
|
||||
- **Adaptability:** No need to rewrite the firmware if an API undergoes changes.
|
||||
|
||||
|
||||
You can use any system you like wich is able to build json strings and send them to a mqtt topic.
|
||||
|
||||
[Node-RED](https://nodered.org/) serves as an ideal software solution for creating these applications.
|
||||
It is available as a standalone program or as a plugin for Home Assistant and ioBroker, allowing you to further enhance the capabilities of your AWTRIX Light system.
|
||||
|
||||
|
||||
Here is a demo of an Youtube App as NodeRED Flow:
|
||||
```json
|
||||
[{"id":"2a59d30d07abe14f","type":"group","z":"54b42d8d.cda474","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["f0f17299.3736c","dc7878f9.4756c8","f234aae371d72680","555bb8624b88c9c3","69c388146e28049d","a349ade5a57f7537"],"x":34,"y":39,"w":892,"h":122},{"id":"f0f17299.3736c","type":"inject","z":"54b42d8d.cda474","g":"2a59d30d07abe14f","name":"","props":[],"repeat":"3600","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":130,"y":120,"wires":[["a349ade5a57f7537"]]},{"id":"dc7878f9.4756c8","type":"http request","z":"54b42d8d.cda474","g":"2a59d30d07abe14f","name":"","method":"GET","ret":"obj","paytoqs":"query","url":"https://youtube.googleapis.com/youtube/v3/channels","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":430,"y":120,"wires":[["f234aae371d72680"]]},{"id":"f234aae371d72680","type":"function","z":"54b42d8d.cda474","g":"2a59d30d07abe14f","name":"parser","func":"var json = msg.payload;\nvar subscriberCount = json.items[0].statistics.subscriberCount;\n\nmsg.payload = { \"text\": subscriberCount, \"icon\": 5029};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":120,"wires":[["555bb8624b88c9c3"]]},{"id":"555bb8624b88c9c3","type":"mqtt out","z":"54b42d8d.cda474","g":"2a59d30d07abe14f","name":"","topic":"ulanzi/custom/youtube","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"346df2a95aac5785","x":800,"y":120,"wires":[]},{"id":"69c388146e28049d","type":"comment","z":"54b42d8d.cda474","g":"2a59d30d07abe14f","name":"Youtube Follower","info":"Just enter your channelID and Youtube API key in the \"Data\" node and set your AWTRIX MQTT prefix.\nUses Icon 5029 (LM)","x":140,"y":80,"wires":[]},{"id":"a349ade5a57f7537","type":"function","z":"54b42d8d.cda474","g":"2a59d30d07abe14f","name":"Data","func":"msg.payload = { \"id\": \"UCpGLALzRO0uaasWTsm9M99w\", \"key\": \"XXX\", \"part\":\"statistics\"}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":120,"wires":[["dc7878f9.4756c8"]]},{"id":"346df2a95aac5785","type":"mqtt-broker","name":"","broker":"localhost","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""}]
|
||||
```
|
||||
|
||||
This Node-RED flow retrieves and displays the subscriber count of a specified YouTube channel on an AWTRIX light device. The flow consists of the following nodes:
|
||||
|
||||
1. **Inject**: This node triggers the flow periodically (every hour) or manually.
|
||||
2. **Data (Function)**: This node contains the YouTube channel ID and the YouTube API key. Replace "XXX" with your YouTube API key and Youtube ID. The node constructs a payload containing the channel ID, API key, and required statistics and sends it to the "HTTP request" node.
|
||||
3. **HTTP request**: This node sends a GET request to the YouTube API to retrieve the channel's statistics. The response is returned as a JavaScript object and passed to the "parser" node.
|
||||
4. **parser (Function)**: This node extracts the subscriber count from the received channel statistics and constructs a payload containing the count and an icon (Icon 5029). The payload is sent to the "MQTT out" node.
|
||||
5. **MQTT out**: This node publishes the payload to the MQTT topic "ulanzi/custom/youtube" on a local MQTT broker. You also have to change the topic in this node to fit your mqtt prefix.
|
||||
6. **Comment (Youtube Follower)**: This node contains additional information about the flow. It does not affect the flow's functionality.
|
||||
|
||||
To use this flow, replace the "XXX" in the "Data" node with your YouTube API key and ensure that the MQTT broker settings in the "MQTT out" node are correct.
|
||||
The flow will then retrieve the subscriber count of the specified YouTube channel and display it on your AWTRIX device along with the icon.
|
||||
This Flow uses icon 5029 from LM (Just download it from the awtrix webinterface). You can change the icon in the flow to your favorite one.
|
||||
|
||||
|
||||
@@ -11,4 +11,4 @@ To download an icon, simply enter the ID of a LaMetric or AWTRIX 2.0 icon in the
|
||||
AWTRIX 2.0 icons can be found in the respective software. In a future update, non-AWTRIX 2.0 users will also get access to the database.
|
||||
|
||||
You can also create your own icon and place it in the "ICONS" folder via the web interface file browser.
|
||||
The icon needs to be a GIF or JPEG with a resolution of 8x8.
|
||||
The icon needs to be a GIF (.gif) or JPG (.jpg) with a resolution of 8x8.
|
||||
@@ -20,11 +20,22 @@
|
||||
coverpage: true,
|
||||
loadNavbar: true,
|
||||
mergeNavbar: true,
|
||||
repo: 'https://github.com/Blueforcer/awtrix-light'
|
||||
repo: 'https://github.com/Blueforcer/awtrix-light',
|
||||
share: {
|
||||
reddit: true,
|
||||
linkedin: true,
|
||||
facebook: true,
|
||||
twitter: true,
|
||||
whatsapp: true,
|
||||
telegram: true,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Docsify v4 -->
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
||||
<script src="https://unpkg.com/docsify-copy-code@2"></script>
|
||||
<script src="//unpkg.com/docsify-share/build/index.min.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -236,18 +236,6 @@ void MatrixDisplayUi::drawApp()
|
||||
int16_t x, y, x1, y1;
|
||||
switch (this->appAnimationDirection)
|
||||
{
|
||||
case SLIDE_LEFT:
|
||||
x = -32 * progress;
|
||||
y = 0;
|
||||
x1 = x + 32;
|
||||
y1 = 0;
|
||||
break;
|
||||
case SLIDE_RIGHT:
|
||||
x = 32 * progress;
|
||||
y = 0;
|
||||
x1 = x - 32;
|
||||
y1 = 0;
|
||||
break;
|
||||
case SLIDE_UP:
|
||||
x = 0;
|
||||
y = -8 * progress;
|
||||
|
||||
@@ -41,9 +41,7 @@
|
||||
enum AnimationDirection
|
||||
{
|
||||
SLIDE_UP,
|
||||
SLIDE_DOWN,
|
||||
SLIDE_LEFT,
|
||||
SLIDE_RIGHT
|
||||
SLIDE_DOWN
|
||||
};
|
||||
|
||||
enum AppState
|
||||
@@ -79,7 +77,7 @@ private:
|
||||
FastLED_NeoMatrix *matrix;
|
||||
|
||||
// Values for the Apps
|
||||
AnimationDirection appAnimationDirection = SLIDE_RIGHT;
|
||||
AnimationDirection appAnimationDirection = SLIDE_DOWN;
|
||||
|
||||
int8_t lastTransitionDirection = 1;
|
||||
|
||||
|
||||
@@ -65,6 +65,10 @@ const char HAluxUnit[] PROGMEM = {"lx"};
|
||||
const char HAverID[] PROGMEM = {"%s_ver"};
|
||||
const char HAverName[] PROGMEM = {"Version"};
|
||||
|
||||
const char HAtransID[] PROGMEM = {"%s_tra"};
|
||||
const char HAtransName[] PROGMEM = {"Transition"};
|
||||
const char HAtransIcon[] PROGMEM = {"mdi:swap-vertical"};
|
||||
|
||||
const char HAsigID[] PROGMEM = {"%s_sig"};
|
||||
const char HAsigIcon[] PROGMEM = {"mdi:sun-wireless"};
|
||||
const char HAsigName[] PROGMEM = {"WiFi strength"};
|
||||
@@ -84,7 +88,7 @@ const char HAbtnMName[] PROGMEM = {"Button select"};
|
||||
const char HAbtnRID[] PROGMEM = {"%s_btnR"};
|
||||
const char HAbtnRName[] PROGMEM = {"Button right"};
|
||||
|
||||
const char HAramRID[] PROGMEM = {"%s_btnR"};
|
||||
const char HAramRID[] PROGMEM = {"%s_ram"};
|
||||
const char HAramIcon[] PROGMEM = {"mdi:application-cog"};
|
||||
const char HAramName[] PROGMEM = {"Free ram"};
|
||||
const char HAramClass[] PROGMEM = {"data_size"};
|
||||
|
||||
@@ -75,6 +75,10 @@ extern const char HAupID[];
|
||||
extern const char HAupName[];
|
||||
extern const char HAupClass[];
|
||||
|
||||
extern const char HAtransID[];
|
||||
extern const char HAtransName[];
|
||||
extern const char HAtransIcon[];
|
||||
|
||||
extern const char HAbtnLID[];
|
||||
extern const char HAbtnLName[];
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ void DisplayManager_::MatrixState(bool on)
|
||||
|
||||
bool DisplayManager_::setAutoTransition(bool active)
|
||||
{
|
||||
|
||||
if (ui.AppCount < 2)
|
||||
{
|
||||
ui.disablesetAutoTransition();
|
||||
@@ -315,7 +316,6 @@ void DisplayManager_::generateCustomPage(String name, String payload)
|
||||
String iconFileName = String(doc["icon"].as<String>());
|
||||
if (customApp.icon && String(customApp.icon.name()).startsWith(iconFileName))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -65,7 +65,7 @@ IPAddress gateway;
|
||||
IPAddress subnet;
|
||||
IPAddress primaryDNS;
|
||||
IPAddress secondaryDNS;
|
||||
const char *VERSION = "0.42";
|
||||
const char *VERSION = "0.43";
|
||||
String MQTT_HOST = "";
|
||||
uint16_t MQTT_PORT = 1883;
|
||||
String MQTT_USER;
|
||||
|
||||
@@ -12,7 +12,7 @@ unsigned long startTime;
|
||||
WiFiClient espClient;
|
||||
uint8_t lastBrightness;
|
||||
HADevice device;
|
||||
HAMqtt mqtt(espClient, device, 18);
|
||||
HAMqtt mqtt(espClient, device, 19);
|
||||
|
||||
unsigned long reconnectTimer = 0;
|
||||
const unsigned long reconnectInterval = 30000; // 30 Sekunden
|
||||
@@ -22,7 +22,7 @@ HASelect *BriMode = nullptr;
|
||||
HAButton *dismiss = nullptr;
|
||||
HAButton *nextApp = nullptr;
|
||||
HAButton *prevApp = nullptr;
|
||||
|
||||
HASwitch *transition = nullptr;
|
||||
HASensor *curApp = nullptr;
|
||||
HASensor *battery = nullptr;
|
||||
HASensor *temperature = nullptr;
|
||||
@@ -62,6 +62,14 @@ void onButtonCommand(HAButton *sender)
|
||||
}
|
||||
}
|
||||
|
||||
void onSwitchCommand(bool state, HASwitch *sender)
|
||||
{
|
||||
AUTO_TRANSITION = state;
|
||||
DisplayManager.setAutoTransition(state);
|
||||
saveSettings();
|
||||
sender->setState(state);
|
||||
}
|
||||
|
||||
void onSelectCommand(int8_t index, HASelect *sender)
|
||||
{
|
||||
switch (index)
|
||||
@@ -215,7 +223,7 @@ 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], btnLID[40], btnMID[40], btnRID[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], btnLID[40], btnMID[40], btnRID[40], transID[40];
|
||||
|
||||
void MQTTManager_::setup()
|
||||
{
|
||||
@@ -268,6 +276,17 @@ void MQTTManager_::setup()
|
||||
dismiss->setIcon(HAbtnaIcon);
|
||||
dismiss->setName(HAbtnaName);
|
||||
|
||||
sprintf(transID, HAtransID, macStr);
|
||||
transition = new HASwitch(transID);
|
||||
transition->setIcon(HAtransIcon);
|
||||
transition->setName(HAtransName);
|
||||
transition->onCommand(onSwitchCommand);
|
||||
|
||||
sprintf(appID, HAappID, macStr);
|
||||
curApp = new HASensor(appID);
|
||||
curApp->setIcon(HAappIcon);
|
||||
curApp->setName(HAappName);
|
||||
|
||||
sprintf(btnBID, HAbtnbID, macStr);
|
||||
nextApp = new HAButton(btnBID);
|
||||
nextApp->setIcon(HAbtnbIcon);
|
||||
@@ -282,11 +301,6 @@ void MQTTManager_::setup()
|
||||
nextApp->onCommand(onButtonCommand);
|
||||
prevApp->onCommand(onButtonCommand);
|
||||
|
||||
sprintf(appID, HAappID, macStr);
|
||||
curApp = new HASensor(appID);
|
||||
curApp->setIcon(HAappIcon);
|
||||
curApp->setName(HAappName);
|
||||
|
||||
sprintf(tempID, HAtempID, macStr);
|
||||
temperature = new HASensor(tempID);
|
||||
temperature->setIcon(HAtempIcon);
|
||||
@@ -430,6 +444,10 @@ void MQTTManager_::sendStats()
|
||||
ram->setValue(rambuffer);
|
||||
uptime->setValue(readUptime());
|
||||
version->setValue(VERSION);
|
||||
transition->setState(AUTO_TRANSITION, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
StaticJsonDocument<200> doc;
|
||||
|
||||
@@ -225,7 +225,7 @@ void PeripheryManager_::checkAlarms()
|
||||
DeserializationError error = deserializeJson(doc, file);
|
||||
if (error)
|
||||
{
|
||||
Serial.println("Failed to read Alarm file");
|
||||
Serial.println(F("Failed to read Alarm file"));
|
||||
return;
|
||||
}
|
||||
JsonArray alarms = doc["alarms"];
|
||||
|
||||
Reference in New Issue
Block a user