Merge branch 'development' of https://github.com/Blueforcer/awtrix-light into development

This commit is contained in:
Stephan Mühl
2023-04-03 12:13:35 +02:00
26 changed files with 320 additions and 89 deletions

39
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,39 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ''
---
<!-- Make sure to read the README before opening an issue. [https://xaviml.github.io/controllerx/faq](https://blueforcer.github.io/awtrix-light/#/README) -->
# Bug report
## Describe the bug
Add a description of the bug. Detail the expected behaviour in contrast with the behaviour you're observing.
## Additional information
- Devices involved:
- Model: Ulanzi Awtrix Smart Pixel Clock 2882 (TC001)
- AWTRIX-LIGHT version: [ eg. v0.45 ]
## To Reproduce
Steps to reproduce the behavior:
## Expected behavior
A clear and concise description of what you expected to happen.
## Screenshots
If applicable, add screenshots to help explain your problem.
## Logs
```text
(optional) Add relevant logs which could help tackle the problem.
```
## Additional context
Add any other context about the problem here.

View File

@@ -0,0 +1,28 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE REQUEST]"
labels: feature request
assignees: ''
---
<!-- Make sure to read the README before opening an issue. [https://xaviml.github.io/controllerx/faq](https://blueforcer.github.io/awtrix-light/#/README) -->
# Feature Request
### Is your feature request related to a problem?
If so, then add a clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
### Describe the solution / feature you'd like
A clear and concise description of what you want to happen.
### Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots about the feature request here.

30
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@@ -0,0 +1,30 @@
---
name: Question
about: Open an issue to ask something
title: "[QUESTION]"
labels: question
assignees: ''
---
<!-- Make sure to read the README before opening an issue. [https://xaviml.github.io/controllerx/faq](https://blueforcer.github.io/awtrix-light/#/README) -->
# Question
Add here your question.
## Additional information
- Devices involved:
- Model: Ulanzi Awtrix Smart Pixel Clock 2882 (TC001)
- AWTRIX-LIGHT version: [ eg. v0.45 ]
## Logs
```text
(optional) Add relevant logs which could help tackle the problem.
```
## Additional context
Add any other context about the problem here.

View File

@@ -89,14 +89,6 @@ jobs:
asset_name: firmware.bin asset_name: firmware.bin
asset_content_type: application/octet-stream asset_content_type: application/octet-stream
- name: Discord notification
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
uses: Ilshidur/action-discord@master
with:
args: 'https://github.com/Blueforcer/awtrix-light/releases/tag/${{ steps.version_number.outputs.firmware_version }}'
- name: Commit - name: Commit
id: commit id: commit
uses: stefanzweifel/git-auto-commit-action@v4 uses: stefanzweifel/git-auto-commit-action@v4

View File

@@ -14,12 +14,17 @@
![GitHub all releases](https://img.shields.io/github/downloads/blueforcer/awtrix-light/total?style=flat-square) ![GitHub all releases](https://img.shields.io/github/downloads/blueforcer/awtrix-light/total?style=flat-square)
![GitHub Sponsors](https://img.shields.io/github/sponsors/blueforcer?style=flat-square) ![GitHub Sponsors](https://img.shields.io/github/sponsors/blueforcer?style=flat-square)
![Discord](https://img.shields.io/discord/546407049148366859?label=Discord&style=flat-square) ![Discord](https://img.shields.io/discord/546407049148366859?label=Discord&style=flat-square)
[![Compile](https://github.com/Blueforcer/awtrix-light/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/Blueforcer/awtrix-light/actions/workflows/main.yml)
![GIF-230324_161917](https://user-images.githubusercontent.com/31169771/227567565-3780ee83-1158-4371-9390-fd03a7873496.gif) ![GIF-230324_161917](https://user-images.githubusercontent.com/31169771/227567565-3780ee83-1158-4371-9390-fd03a7873496.gif)
</div> </div>
AWTRIX Light is an opensource custom firmware for the [Ulanzi Smart Pixel clock TC001](https://www.ulanzi.com/products/ulanzi-pixel-smart-clock-2882) which lives on your smarthome. AWTRIX Light is an opensource custom firmware for the [Ulanzi Smart Pixel clock TC001](https://www.ulanzi.com/products/ulanzi-pixel-smart-clock-2882)
AWL meant to be a companion for your smarthome like HomeAssistant, IOBroker, NodeRed and so on.
Even if you don't have a Smarthome system, but would like to experiment with NodeRed or N8N, you are still welcome to join us.
There are many users who are willing to help you!
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 pages pre-installed. You don't need to do anything other than turning it on to start using these features.
@@ -35,8 +40,10 @@ Join the thousands of satisfied awtrix users who have already chosen Awtrix 2 an
- Onscreen menu where you can change your settings directly on the device - Onscreen menu where you can change your settings directly on the device
- Pre-installed Apps like time, date, temperature, humidity and battery - Pre-installed Apps like time, date, temperature, humidity and battery
- Add customapps without recompiling straight from your Smarthome. - Add customapps without recompiling straight from your Smarthome.
- Noitification support
- Easy to use icon system - Easy to use icon system
- Powerful MQTT commands - Powerful MQTT commands
- HTTP API
- RTTTL melody player - RTTTL melody player
- Integrated filebrowser - Integrated filebrowser
- No cloud - No cloud
@@ -47,7 +54,15 @@ Join the thousands of satisfied awtrix users who have already chosen Awtrix 2 an
Starting is easy as 1-2-3 Starting is easy as 1-2-3
[with the documentation](https://blueforcer.github.io/awtrix-light/) [with the documentation](https://blueforcer.github.io/awtrix-light/)
# Contributors
<a href="https://github.com/Blueforcer/awtrix-light/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Blueforcer/awtrix-light" />
</a>
# Community # Community
Join the discord channel with over 1500 Users Join the discord channel with over 1500 Users
https://discord.gg/cyBCpdx https://discord.gg/cyBCpdx
# Support
If you like my work, please consider supporting the project.
https://github.com/sponsors/Blueforcer

View File

@@ -1,17 +1,21 @@
# AWTRIX-LIGHT # AWTRIX-LIGHT
If you like my work, please consider supporting the project.
https://github.com/sponsors/Blueforcer
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. It meant to be a companion for your smarthome like HomeAssistant, IOBroker, NodeRed and so on.
Even if you don't have a Smarthome system, but would like to experiment, you are still welcome to join us. There are many users who are willing to help you!
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. 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.
However, for those with more advanced skills, the customization options available with custom apps 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
## Support
If you like my work, please consider supporting the project.
https://github.com/sponsors/Blueforcer
https://paypal.me/blueforcer

View File

@@ -11,7 +11,6 @@
- Features - Features
- [Apps](apps.md) - [Apps](apps.md)
- [Alarm clock](alarm.md) - [Alarm clock](alarm.md)
- [Timer](timer.md)
- [Icons](icons.md) - [Icons](icons.md)
- [Sounds](sounds.md) - [Sounds](sounds.md)
- [Hidden features](dev.md) - [Hidden features](dev.md)

View File

@@ -6,6 +6,13 @@ In MQTT awtrix send its stats every 10s to `[PREFIX]/stats`
With HTTP, make GET request to `http://[IP]/api/stats` With HTTP, make GET request to `http://[IP]/api/stats`
## Update
Awtrix searches for an update every 1 Hour. If a new one is found it will be published to HA and in the stats.
You can start the update with update button in HA or:
| Topic | URL | Payload/Body | HTTP Header | HTTP method |
| --- | --- | --- |--- |--- |
| `[PREFIX]/doupdate` |`http://[IP]/api/doupdate` | JSON | empty payload/body | POST |
## Add custom app ## Add custom app
create custom apps or notifications to display your own text and icons. create custom apps or notifications to display your own text and icons.
Have a look at [this section](custom?id=custom-apps-and-notifications) Have a look at [this section](custom?id=custom-apps-and-notifications)
@@ -27,7 +34,7 @@ Switch to next or previous app.
| Topic | URL | Payload/Body | HTTP method | | Topic | URL | Payload/Body | HTTP method |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `[PREFIX]/nextapp` | `http://[IP]/api/nextapp` | empty payload/body | POST | | `[PREFIX]/nextapp` | `http://[IP]/api/nextapp` | empty payload/body | POST |
| `[PREFIX]/previousapp` | `http://[IP]/api/previousapp` | payload/body | POST | | `[PREFIX]/previousapp` | `http://[IP]/api/previousapp` | empty payload/body | POST |
## Switch to Specific App ## Switch to Specific App
Switch to a specific app by name. Switch to a specific app by name.
@@ -43,7 +50,8 @@ Built-in app names are:
- `hum` - `hum`
- `bat` - `bat`
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. For custom apps, use the name you set in the topic or http request header.
In MQTT for example, if `[PREFIX]/custom/test` is your topic, then `test` is the name.
## Add/remove and rearange apps ## Add/remove and rearange apps
@@ -63,10 +71,14 @@ This provides flexibility in organizing apps according to personal preference.
The JSON payload is an array of objects, where each object represents an app to be displayed on awtrix. Each app object contains the following fields: The JSON payload is an array of objects, where each object represents an app to be displayed on awtrix. Each app object contains the following fields:
`"name"`: The name of the app ("time", "date", "temp", "hum", "bat") are the native apps. ### JSON Properties
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.
`"show"`: A boolean indicating whether the app should be shown on the screen or not. If not present, the app is considered active by default. | Property | Description |Default |
`"pos"`: An integer indicating the position of the app in the list. If not present, the app will be added to the end of the list. |----------|-------------|-------------|
| name | The name of the app. If it's a native app, it can be one of "time", "date", "temp", "hum", or "bat". 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. | |
| show | A boolean indicating whether the app should be shown on the screen or not. If not present, the app is considered active by default. | true |
| pos | An integer indicating the position of the app in the list. If not present, the app will be added to the end of the list. | Last Item |
> You can also just send the information for one app. > You can also just send the information for one app.
@@ -128,6 +140,8 @@ Change various settings related to the app display.
| --- | --- | --- |--- | | --- | --- | --- |--- |
| `[PREFIX]/settings` |`http://[IP]/api/settings`| JSON | POST | | `[PREFIX]/settings` |`http://[IP]/api/settings`| JSON | POST |
#### JSON Properties
Each property is optional; you do not need to send all. Each property is optional; you do not need to send all.
| Key | Type | Description | Value Range | Default | | Key | Type | Description | Value Range | Default |
@@ -139,3 +153,37 @@ Each property is optional; you do not need to send all.
| `brightness` | number | Determines the brightness of the matrix. | An integer between 0 and 255. | N/A | | `brightness` | number | Determines the brightness of the matrix. | An integer between 0 and 255. | N/A |
| `autobrightness` | boolean | Determines if automatic brightness control is active. | `true` or `false`. | N/A | | `autobrightness` | boolean | Determines if automatic brightness control is active. | `true` or `false`. | N/A |
| `autotransition` | boolean | Determines if automatic switching to the next app is active. | `true` or `false`. | N/A | | `autotransition` | boolean | Determines if automatic switching to the next app is active. | `true` or `false`. | N/A |
## Timer
With AWTRIX Light, you can set a timer using MQTT. Simply send a JSON object to the topic **[PREFIX]/timer** to start a timer.
When the timer goes off, the display will show a notification, and you can dismiss the timer by pressing the middle button.
#### JSON Properties
The JSON object has the following properties:
| Key | Type | Description |
| --- | ---- | ----------- |
| `hours` | number | The number of hours after midnight when the timer should be triggered. |
| `minutes` | number | The number of minutes after the hour when the timer should be triggered. |
| `seconds` | number | The number of seconds after the minute when the timer should be triggered. |
| `sound` | string | The name of the sound file (without extension) to play when the timer is triggered. |
Each value is optional, so you can set a timer for just minutes, or any combination of hours, minutes, and seconds. If you only want to start a timer in some minutes, just send the minutes.
## Example
Here's an example JSON object to start a timer for 1 hour, 30 minutes, and 10 seconds, with the sound "friends":
```json
{
"hours": 1,
"minutes": 30,
"seconds": 10,
"sound": "friends"
}
```

View File

@@ -16,7 +16,7 @@ The JSON object has the following properties:
| `icon` | string | The icon ID or filename (without extension) to display on the page. | | | `icon` | string | The icon ID or filename (without extension) to display on the page. | |
| `repeat` | number | Sets how many times the text should be scrolled through the matrix before the display ends. | 1 | | `repeat` | number | Sets how many times the text should be scrolled through the matrix before the display ends. | 1 |
| `rainbow` | boolean | Fades each letter in the text differently through the entire RGB spectrum. | false | | `rainbow` | boolean | Fades each letter in the text differently through the entire RGB spectrum. | false |
| `duration` | number | Sets how long the page should be displayed. | 5 | | `duration` | number | Sets how long the notification should be displayed. | 5 |
| `color` | string | A color hex string for the text color, or an array of R,G,B values | "#FFFFFF" or [255,255,0] | | `color` | string | A color hex string for the text color, or an array of R,G,B values | "#FFFFFF" or [255,255,0] |
| `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). | |

View File

@@ -11,5 +11,5 @@ The JSON object has the following properties:
| Key | Type | Description | Default | | Key | Type | Description | Default |
| --- | ---- | ----------- | ------- | | --- | ---- | ----------- | ------- |
| `bootsound` | string | Uses a custom melodie from the MELODIES folder | standart | | `bootsound` | string | Uses a custom melodie from the MELODIES folder | |
| `uppercase` | boolean | Print every character in uppercase | true | | `uppercase` | boolean | Print every character in uppercase | true |

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{ {
"name": "AWTRIX Light", "name": "AWTRIX Light",
"version": "0.43", "version": "0.47",
"home_assistant_domain": "AwtrixLight", "home_assistant_domain": "AwtrixLight",
"funding_url": "https://blueforcer.de", "funding_url": "https://blueforcer.de",
"new_install_prompt_erase": true, "new_install_prompt_erase": true,

View File

@@ -1,31 +0,0 @@
# Timer
With AWTRIX Light, you can set a timer using MQTT. Simply send a JSON object to the topic **[PREFIX]/timer** to start a timer.
When the timer goes off, the display will show a notification, and you can dismiss the timer by pressing the middle button.
## JSON Properties
The JSON object has the following properties:
| Key | Type | Description |
| --- | ---- | ----------- |
| `hours` | number | The number of hours after midnight when the timer should be triggered. |
| `minutes` | number | The number of minutes after the hour when the timer should be triggered. |
| `seconds` | number | The number of seconds after the minute when the timer should be triggered. |
| `sound` | string | The name of the sound file (without extension) to play when the timer is triggered. |
Each value is optional, so you can set a timer for just minutes, or any combination of hours, minutes, and seconds. If you only want to start a timer in some minutes, just send the minutes.
## Example
Here's an example JSON object to start a timer for 1 hour, 30 minutes, and 10 seconds, with the sound "friends":
```json
{
"hours": 1,
"minutes": 30,
"seconds": 10,
"sound": "friends"
}
```

View File

@@ -69,6 +69,17 @@ const char HAtransID[] PROGMEM = {"%s_tra"};
const char HAtransName[] PROGMEM = {"Transition"}; const char HAtransName[] PROGMEM = {"Transition"};
const char HAtransIcon[] PROGMEM = {"mdi:swap-vertical"}; const char HAtransIcon[] PROGMEM = {"mdi:swap-vertical"};
const char HAupdateID[] PROGMEM = {"%s_upd"};
const char HAupdateName[] PROGMEM = {"Update"};
const char HAupdateClass[] PROGMEM = {"update"};
const char HAupdateIcon[] PROGMEM = {"mdi:update"};
const char HAdoUpID[] PROGMEM = {"%s_doupd"};
const char HAdoUpName[] PROGMEM = {"Start Update"};
const char HAdoUpIcon[] PROGMEM = {"mdi:update"};
const char HAsigID[] PROGMEM = {"%s_sig"}; const char HAsigID[] PROGMEM = {"%s_sig"};
const char HAsigIcon[] PROGMEM = {"mdi:sun-wireless"}; const char HAsigIcon[] PROGMEM = {"mdi:sun-wireless"};
const char HAsigName[] PROGMEM = {"WiFi strength"}; const char HAsigName[] PROGMEM = {"WiFi strength"};
@@ -104,3 +115,4 @@ const char TempKey[] PROGMEM = {"temp"};
const char HumKey[] PROGMEM = {"hum"}; const char HumKey[] PROGMEM = {"hum"};
const char UpTimeKey[] PROGMEM = {"uptime"}; const char UpTimeKey[] PROGMEM = {"uptime"};
const char SignalStrengthKey[] PROGMEM = {"wifi_signal"}; const char SignalStrengthKey[] PROGMEM = {"wifi_signal"};
const char UpdateKey[] PROGMEM = {"up_available"};

View File

@@ -77,10 +77,19 @@ extern const char HAupID[];
extern const char HAupName[]; extern const char HAupName[];
extern const char HAupClass[]; extern const char HAupClass[];
extern const char HAdoUpID[];
extern const char HAdoUpName[];
extern const char HAdoUpIcon[];
extern const char HAtransID[]; extern const char HAtransID[];
extern const char HAtransName[]; extern const char HAtransName[];
extern const char HAtransIcon[]; extern const char HAtransIcon[];
extern const char HAupdateID[];
extern const char HAupdateName[];
extern const char HAupdateClass[];
extern const char HAupdateIcon[];
extern const char HAbtnLID[]; extern const char HAbtnLID[];
extern const char HAbtnLName[]; extern const char HAbtnLName[];
@@ -106,5 +115,5 @@ extern const char TempKey[];
extern const char HumKey[]; extern const char HumKey[];
extern const char UpTimeKey[]; extern const char UpTimeKey[];
extern const char SignalStrengthKey[]; extern const char SignalStrengthKey[];
extern const char UpdateKey[];
#endif #endif

View File

@@ -298,7 +298,7 @@ void DisplayManager_::generateCustomPage(String name, const char *json)
customApp.barSize = 0; customApp.barSize = 0;
} }
customApp.duration = doc.containsKey("duration") ? doc["duration"].as<int>() * 1000 : -1; customApp.duration = doc.containsKey("duration") ? doc["duration"].as<int>() * 1000 : 0;
int pos = doc.containsKey("pos") ? doc["pos"].as<uint8_t>() : -1; int pos = doc.containsKey("pos") ? doc["pos"].as<uint8_t>() : -1;
customApp.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false; customApp.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false;
customApp.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0; customApp.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0;
@@ -907,8 +907,10 @@ String DisplayManager_::getStat()
{ {
StaticJsonDocument<200> doc; StaticJsonDocument<200> doc;
char buffer[5]; char buffer[5];
#ifdef ULANZI
doc[BatKey] = BATTERY_PERCENT; doc[BatKey] = BATTERY_PERCENT;
doc[BatRawKey] = BATTERY_RAW; doc[BatRawKey] = BATTERY_RAW;
#endif
snprintf(buffer, 5, "%.0f", CURRENT_LUX); snprintf(buffer, 5, "%.0f", CURRENT_LUX);
doc[LuxKey] = buffer; doc[LuxKey] = buffer;
doc[LDRRawKey] = LDR_RAW; doc[LDRRawKey] = LDR_RAW;
@@ -920,6 +922,7 @@ String DisplayManager_::getStat()
doc[HumKey] = buffer; doc[HumKey] = buffer;
doc[UpTimeKey] = PeripheryManager.readUptime(); doc[UpTimeKey] = PeripheryManager.readUptime();
doc[SignalStrengthKey] = WiFi.RSSI(); doc[SignalStrengthKey] = WiFi.RSSI();
doc[UpdateKey] = UPDATE_AVAILABLE;
String jsonString; String jsonString;
serializeJson(doc, jsonString); serializeJson(doc, jsonString);
return jsonString; return jsonString;

View File

@@ -121,7 +121,7 @@ IPAddress gateway;
IPAddress subnet; IPAddress subnet;
IPAddress primaryDNS; IPAddress primaryDNS;
IPAddress secondaryDNS; IPAddress secondaryDNS;
const char *VERSION = "0.46"; const char *VERSION = "0.47";
String MQTT_HOST = ""; String MQTT_HOST = "";
uint16_t MQTT_PORT = 1883; uint16_t MQTT_PORT = 1883;
String MQTT_USER; String MQTT_USER;
@@ -188,3 +188,4 @@ String BOOT_SOUND = "";
uint8_t VOLUME; uint8_t VOLUME;
uint8_t VOLUME_PERCENT; uint8_t VOLUME_PERCENT;
int MATRIX_LAYOUT; int MATRIX_LAYOUT;
bool UPDATE_AVAILABLE = false;

View File

@@ -71,6 +71,7 @@ extern String BOOT_SOUND;
extern uint8_t VOLUME; extern uint8_t VOLUME;
extern uint8_t VOLUME_PERCENT; extern uint8_t VOLUME_PERCENT;
extern int MATRIX_LAYOUT; extern int MATRIX_LAYOUT;
extern bool UPDATE_AVAILABLE;
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();
#endif // Globals_H #endif // Globals_H

View File

@@ -7,6 +7,7 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include "Dictionary.h" #include "Dictionary.h"
#include "PeripheryManager.h" #include "PeripheryManager.h"
#include "UpdateManager.h"
WiFiClient espClient; WiFiClient espClient;
uint8_t lastBrightness; uint8_t lastBrightness;
@@ -36,6 +37,8 @@ HASensor *ram = nullptr;
HABinarySensor *btnleft = nullptr; HABinarySensor *btnleft = nullptr;
HABinarySensor *btnmid = nullptr; HABinarySensor *btnmid = nullptr;
HABinarySensor *btnright = nullptr; HABinarySensor *btnright = nullptr;
HABinarySensor *update = nullptr;
HAButton *doUpdate = nullptr;
// The getter for the instantiated singleton instance // The getter for the instantiated singleton instance
MQTTManager_ &MQTTManager_::getInstance() MQTTManager_ &MQTTManager_::getInstance()
@@ -61,6 +64,11 @@ void onButtonCommand(HAButton *sender)
{ {
DisplayManager.previousApp(); DisplayManager.previousApp();
} }
else if (sender == doUpdate)
{
if (UPDATE_AVAILABLE)
UpdateManager.updateFirmware();
}
} }
void onSwitchCommand(bool state, HASwitch *sender) void onSwitchCommand(bool state, HASwitch *sender)
@@ -183,6 +191,12 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length)
DisplayManager.previousApp(); DisplayManager.previousApp();
return; return;
} }
if (strTopic == MQTT_PREFIX + "/doupdate")
{
if (UPDATE_AVAILABLE)
UpdateManager.updateFirmware();
return;
}
else if (strTopic.startsWith(MQTT_PREFIX + "/custom")) else if (strTopic.startsWith(MQTT_PREFIX + "/custom"))
{ {
@@ -212,6 +226,7 @@ void onMqttConnected()
"/settings", "/settings",
"/previousapp", "/previousapp",
"/nextapp", "/nextapp",
"/doupdate",
"/nextapp", "/nextapp",
"/apps"}; "/apps"};
for (const char *topic : topics) for (const char *topic : topics)
@@ -222,7 +237,6 @@ void onMqttConnected()
Serial.println(F("MQTT Connected")); Serial.println(F("MQTT Connected"));
} }
void connect() void connect()
{ {
mqtt.onMessage(onMqttMessage); mqtt.onMessage(onMqttMessage);
@@ -241,7 +255,7 @@ void connect()
} }
char matID[40], briID[40]; char matID[40], briID[40];
char btnAID[40], btnBID[40], btnCID[40], appID[40], tempID[40], humID[40], luxID[40], verID[40], ramID[40], upID[40], sigID[40], btnLID[40], btnMID[40], btnRID[40], transID[40]; char btnAID[40], btnBID[40], btnCID[40], appID[40], tempID[40], humID[40], luxID[40], verID[40], ramID[40], upID[40], sigID[40], btnLID[40], btnMID[40], btnRID[40], transID[40], updateID[40], doUpdateID[40];
#ifdef ULANZI #ifdef ULANZI
char batID[40]; char batID[40];
#endif #endif
@@ -302,6 +316,12 @@ void MQTTManager_::setup()
dismiss->setIcon(HAbtnaIcon); dismiss->setIcon(HAbtnaIcon);
dismiss->setName(HAbtnaName); dismiss->setName(HAbtnaName);
sprintf(doUpdateID, HAdoUpID, macStr);
doUpdate = new HAButton(doUpdateID);
doUpdate->setIcon(HAdoUpIcon);
doUpdate->setName(HAdoUpName);
doUpdate->onCommand(onButtonCommand);
sprintf(transID, HAtransID, macStr); sprintf(transID, HAtransID, macStr);
transition = new HASwitch(transID); transition = new HASwitch(transID);
transition->setIcon(HAtransIcon); transition->setIcon(HAtransIcon);
@@ -376,6 +396,12 @@ void MQTTManager_::setup()
btnleft = new HABinarySensor(btnLID); btnleft = new HABinarySensor(btnLID);
btnleft->setName(HAbtnLName); btnleft->setName(HAbtnLName);
sprintf(updateID, HAupdateID, macStr);
update = new HABinarySensor(updateID);
update->setIcon(HAupdateIcon);
update->setName(HAupdateName);
update->setDeviceClass(HAupdateClass);
sprintf(btnMID, HAbtnMID, macStr); sprintf(btnMID, HAbtnMID, macStr);
btnmid = new HABinarySensor(btnMID); btnmid = new HABinarySensor(btnMID);
btnmid->setName(HAbtnMName); btnmid->setName(HAbtnMName);
@@ -459,6 +485,8 @@ void MQTTManager_::sendStats()
uptime->setValue(PeripheryManager.readUptime()); uptime->setValue(PeripheryManager.readUptime());
version->setValue(VERSION); version->setValue(VERSION);
transition->setState(AUTO_TRANSITION, false); transition->setState(AUTO_TRANSITION, false);
update->setState(UPDATE_AVAILABLE, false);
} }
else else
{ {

View File

@@ -4,8 +4,9 @@
#include <ServerManager.h> #include <ServerManager.h>
#include <DisplayManager.h> #include <DisplayManager.h>
#include <PeripheryManager.h> #include <PeripheryManager.h>
#include <updater.h> //#include <update.h>
#include <icons.h> #include <icons.h>
#include <UpdateManager.h>
String menuText; String menuText;
int menuSelection; int menuSelection;
@@ -377,9 +378,9 @@ void MenuManager_::selectButton()
#endif #endif
case 13: case 13:
if (FirmwareVersionCheck()) if (UpdateManager.checkUpdate(true))
{ {
updateFirmware(); UpdateManager.updateFirmware();
} }
break; break;
default: default:

View File

@@ -9,6 +9,7 @@
#include <LittleFS.h> #include <LittleFS.h>
#include <WiFi.h> #include <WiFi.h>
#include "DisplayManager.h" #include "DisplayManager.h"
#include "UpdateManager.h"
WebServer server(80); WebServer server(80);
FSWebServer mws(LittleFS, server); FSWebServer mws(LittleFS, server);
@@ -37,7 +38,6 @@ void saveHandler()
webRequest->send(200); webRequest->send(200);
} }
void ServerManager_::setup() void ServerManager_::setup()
{ {
if (!local_IP.fromString(NET_IP) || !gateway.fromString(NET_GW) || !subnet.fromString(NET_SN) || !primaryDNS.fromString(NET_PDNS) || !secondaryDNS.fromString(NET_SDNS)) if (!local_IP.fromString(NET_IP) || !gateway.fromString(NET_GW) || !subnet.fromString(NET_SN) || !primaryDNS.fromString(NET_PDNS) || !secondaryDNS.fromString(NET_SDNS))
@@ -97,6 +97,9 @@ void ServerManager_::setup()
{ DisplayManager.generateCustomPage(mws.webserver->arg("name"),mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); }); { DisplayManager.generateCustomPage(mws.webserver->arg("name"),mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/stats", HTTP_GET, []() mws.addHandler("/api/stats", HTTP_GET, []()
{ mws.webserver->sendContent(DisplayManager.getStat()); }); { mws.webserver->sendContent(DisplayManager.getStat()); });
mws.addHandler("/api/doupdate", HTTP_POST, []()
{ if (UPDATE_AVAILABLE)
UpdateManager.updateFirmware(); mws.webserver->send(200,"OK"); });
Serial.println("Webserver loaded"); Serial.println("Webserver loaded");
} }
mws.addHandler("/version", HTTP_GET, versionHandler); mws.addHandler("/version", HTTP_GET, versionHandler);

View File

@@ -1,20 +1,34 @@
#include <UpdateManager.h>
#include <WiFi.h> #include <WiFi.h>
#include <HTTPClient.h> #include <HTTPClient.h>
#include <HTTPUpdate.h> #include <HTTPUpdate.h>
#include <WiFiClientSecure.h> #include <WiFiClientSecure.h>
#include "cert.h" #include "cert.h"
#include "DisplayManager.h" #include "DisplayManager.h"
#include <Ticker.h>
#include "Globals.h"
#define URL_fw_Version "https://raw.githubusercontent.com/Blueforcer/awtrix-light/main/version" #define URL_fw_Version "https://raw.githubusercontent.com/Blueforcer/awtrix-light/main/version"
#define URL_fw_Bin "https://raw.githubusercontent.com/Blueforcer/awtrix-light/main/docs/flasher/firmware/firmware.bin" #define URL_fw_Bin "https://raw.githubusercontent.com/Blueforcer/awtrix-light/main/docs/flasher/firmware/firmware.bin"
Ticker UpdateTicker;
// The getter for the instantiated singleton instance
UpdateManager_ &UpdateManager_::getInstance()
{
static UpdateManager_ instance;
return instance;
}
// Initialize the global shared instance
UpdateManager_ &UpdateManager = UpdateManager.getInstance();
void update_started() void update_started()
{ {
} }
void update_finished() void update_finished()
{ {
} }
void update_progress(int cur, int total) void update_progress(int cur, int total)
@@ -29,7 +43,7 @@ void update_error(int err)
DisplayManager.show(); DisplayManager.show();
} }
void updateFirmware() void UpdateManager_::updateFirmware()
{ {
WiFiClientSecure client; WiFiClientSecure client;
client.setCACert(rootCACertificate); client.setCACert(rootCACertificate);
@@ -56,13 +70,15 @@ void updateFirmware()
} }
} }
bool UpdateManager_::checkUpdate(bool withScreen)
bool FirmwareVersionCheck() {
if (withScreen)
{ {
DisplayManager.clear(); DisplayManager.clear();
DisplayManager.printText(0, 6, "CHECK", true, true); DisplayManager.printText(0, 6, "CHECK", true, true);
DisplayManager.show(); DisplayManager.show();
}
String payload; String payload;
int httpCode; int httpCode;
String fwurl = ""; String fwurl = "";
@@ -103,20 +119,34 @@ bool FirmwareVersionCheck()
payload.trim(); payload.trim();
if (payload.equals(VERSION)) if (payload.equals(VERSION))
{ {
UPDATE_AVAILABLE = false;
Serial.printf("\nDevice already on latest firmware version: %s\n", VERSION); Serial.printf("\nDevice already on latest firmware version: %s\n", VERSION);
if (withScreen)
{
DisplayManager.clear(); DisplayManager.clear();
DisplayManager.printText(0, 6, "NO UP :(", true, true); DisplayManager.printText(0, 6, "NO UP :(", true, true);
DisplayManager.show(); DisplayManager.show();
delay(1000); delay(1000);
}
return 0; return 0;
} }
else else
{ {
Serial.println(payload); UPDATE_AVAILABLE = true;
Serial.println("New firmware detected");
DisplayManager.printText(0, 6, payload.c_str(), true, true);
return 1; return 1;
} }
} }
UPDATE_AVAILABLE = false;
return 0; return 0;
} }
void checkUpdateNoReturn()
{
Serial.println("Check Update");
UpdateManager.getInstance().checkUpdate(false);
}
void UpdateManager_::setup()
{
UpdateTicker.attach(3600, checkUpdateNoReturn);
}

18
src/UpdateManager.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef UpdateManager_h
#define UpdateManager_h
#include <Arduino.h>
class UpdateManager_
{
private:
UpdateManager_() = default;
public:
static UpdateManager_ &getInstance();
void setup();
bool checkUpdate(bool);
void updateFirmware();
};
extern UpdateManager_ &UpdateManager;
#endif

View File

@@ -75,6 +75,8 @@ void setup()
{ {
MQTTManager.setup(); MQTTManager.setup();
DisplayManager.loadNativeApps(); DisplayManager.loadNativeApps();
UpdateManager.setup();
UpdateManager.checkUpdate(false);
StopTask = true; StopTask = true;
float x = 4; float x = 4;
while (x >= -85) while (x >= -85)
@@ -101,7 +103,6 @@ void loop()
PeripheryManager.tick(); PeripheryManager.tick();
if (ServerManager.isConnected) if (ServerManager.isConnected)
{ {
MQTTManager.tick(); MQTTManager.tick();
} }
} }

View File

@@ -1 +1 @@
0.43 0.47