diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..3ebc1778 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,6 @@ +FROM mcr.microsoft.com/devcontainers/cpp:1-debian-11 + +ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="none" + +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends python3-venv diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..704e51df --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,23 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "awtrix-light", + "build": { + "dockerfile": "Dockerfile" + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "sudo apt -y update && sudo apt-get -y install python3-venv" + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/AWL_Backup/build/conf/logging.properties b/AWL_Backup/build/conf/logging.properties index 58997e5f..bfac8f2b 100644 --- a/AWL_Backup/build/conf/logging.properties +++ b/AWL_Backup/build/conf/logging.properties @@ -23,7 +23,7 @@ handlers= java.util.logging.ConsoleHandler # Default global logging level. # This specifies which kinds of events are logged across # all loggers. For any given facility this global level -# can be overriden by a facility specific level +# can be overridden by a facility specific level # Note that the ConsoleHandler also has a separate level # setting to limit messages printed to the console. .level= INFO diff --git a/AWL_Backup/build/conf/security/java.policy b/AWL_Backup/build/conf/security/java.policy index 1554541d..3388407d 100644 --- a/AWL_Backup/build/conf/security/java.policy +++ b/AWL_Backup/build/conf/security/java.policy @@ -17,7 +17,7 @@ grant { // allows anyone to listen on dynamic ports permission java.net.SocketPermission "localhost:0", "listen"; - // "standard" properies that can be read by anyone + // "standard" properties that can be read by anyone permission java.util.PropertyPermission "java.version", "read"; permission java.util.PropertyPermission "java.vendor", "read"; permission java.util.PropertyPermission "java.vendor.url", "read"; diff --git a/Helper_Scripts/img2rgb888.py b/Helper_Scripts/img2rgb888.py new file mode 100644 index 00000000..7f7391a1 --- /dev/null +++ b/Helper_Scripts/img2rgb888.py @@ -0,0 +1,38 @@ +# Converts an image to a RGB888 array + +import argparse +from PIL import Image + +def rgb_to_rgb888(r, g, b): + return (r << 16) | (g << 8) | (b) + +def convert_bmp_to_rgb888_array(file_path): + # Open image + image = Image.open(file_path) + + # Retrieve pixel data + pixels = list(image.convert("RGB").getdata()) + + # Initialize RGB888 array + rgb888_array = [] + + # Iterate through each pixel and convert to RGB888 + for r, g, b in pixels: + rgb888_value = rgb_to_rgb888(r, g, b) + rgb888_array.append(str(rgb888_value)) + + # Join the array elements into a string with square brackets + return "[" + ", ".join(rgb888_array) + "]" + +# Create argument parser +parser = argparse.ArgumentParser(description="Convert an image to an RGB888 array string.") +parser.add_argument("file_path", help="Path to the image to be converted.") + +# Parse arguments +args = parser.parse_args() + +# Convert the BMP file to an RGB888 array string +rgb888_array_string = convert_bmp_to_rgb888_array(args.file_path) + +# Print the converted string +print(rgb888_array_string) diff --git a/README.md b/README.md index f50c314b..47e21ba9 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Take your Awtrix experience to the next level with the mobile app, tailored for #### **Features:** - **Liveview:** See your Awtrix in real-time. -- **Settings Customization:** Tweak text colors, set transistion and many more with just your fingertip. +- **Settings Customization:** Tweak text colors, set transition and many more with just your fingertip. - **Icon Management:** View, or delete icons effortlessly. - **Exclusive Icon Database:** Get unique icons only available for app users. - **Icon Creation & Sharing:** Design and share your icons with our community. diff --git a/docs/api.md b/docs/api.md index 8f643e07..e7b4f867 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,5 +1,33 @@ # MQTT / HTTP API +## Table of Contents + * [Overview](#overview) + * [Status Retrieval](#status-retrieval) + * [LiveView](#liveview) + * [Power Control](#power-control) + * [Sound Playback](#sound-playback) + * [Mood Lighting](#mood-lighting) + * [Colored Indicators](#colored-indicators) + * [Custom Apps and Notifications](#custom-apps-and-notifications) + + [Interaction](#interaction) + + [JSON Properties](#json-properties) + - [Example](#example) + + [Drawing Instructions](#drawing-instructions) + + [Example](#example-1) + + [Display Text in Colored Fragments](#display-text-in-colored-fragments) + + [Sending Multiple Custom Pages Simultaneously](#sending-multiple-custom-pages-simultaneously) + + [Delete a Custom App](#delete-a-custom-app) + + [Dismiss Notification](#dismiss-notification) + + [Switch Apps](#switch-apps) + + [Switch to Specific App](#switch-to-specific-app) + * [Change Settings](#change-settings) + + [JSON Properties](#json-properties-1) + * [Update](#update) + - [Reboot Awtrix](#reboot-awtrix) + - [Erase Awtrix](#erase-awtrix) + - [Clear Settings](#clear-settings) + + ## Overview This API documentation covers various functionalities such as retrieving device statistics, screen mirroring, notifications, customapps, sound playing, and mood lighting. You can interact with these features via both MQTT and HTTP protocols. @@ -141,7 +169,7 @@ Below are the properties you can utilize in the JSON object. **All keys are opti | Key | Type | Description | Default | Custom App | Notification | | --- | ---- | ----------- | ------- | ------- | ------- | -| `text` | string | The text to display. | N/A | X | X | +| `text` | string | The text to display. Keep in mind the font does not have a fixed size and `I` uses less space than `W`. This facts affects when text will start scrolling | N/A | X | X | | `textCase` | integer | Changes the Uppercase setting. 0=global setting, 1=forces uppercase; 2=shows as it sent. | 0 | X | X | | `topText` | boolean | Draw the text on top. | false | X | X | | `textOffset` | integer | Sets an offset for the x position of a starting text. | 0 | X | X | @@ -175,7 +203,7 @@ Below are the properties you can utilize in the JSON object. **All keys are opti | `noScroll` | boolean | Disables the text scrolling. | false | X | X | | `clients` | array of strings | Allows forwarding a notification to other awtrix devices. Use the MQTT prefix for MQTT and IP addresses for HTTP. | | | X | | `scrollSpeed` | integer | Modifies the scroll speed. Enter a percentage value of the original scroll speed. | 100 | X | X | -| `effect` | string | Shows an [effect](https://blueforcer.github.io/awtrix-light/#/effects) as background. | | X | X | +| `effect` | string | Shows an [effect](https://blueforcer.github.io/awtrix-light/#/effects) as background.The effect can be removed by sending an empty string for effect| | X | X | | `effectSettings` | json map | Changes color and speed of the [effect](https://blueforcer.github.io/awtrix-light/#/effects). | | X | X | | `save` | boolean | Saves your custom app into flash and reloads it after boot. Avoid this for custom apps with high update frequencies because the ESP's flash memory has limited write cycles. | | X | | @@ -359,7 +387,7 @@ You can adjust each property in the JSON object according to your preferences. I **Color Values**: Can either be an RGB array (e.g., `[255,0,0]`) or a valid 6-digit hexadecimal color value (e.g., "#FF0000" for red). -**Transision effects:** +**Transition effects:** ```bash 0 - Random 1 - Slide diff --git a/docs/apps.md b/docs/apps.md index 097fd83f..1d3317e1 100644 --- a/docs/apps.md +++ b/docs/apps.md @@ -10,7 +10,7 @@ There are numerous benefits to this approach: - **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. +You can use any system you like which is able to build json strings and send them to a mqtt topic. ## AWTRIX FLOWS This is your go-to hub for sharing and discovering AWTRIX Light automations, also known as custom Apps for several services. @@ -25,10 +25,184 @@ https://flows.blueforcer.de/ [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: +Here is a demo, please press the triangle to unfold. + +
+ Example for adding a 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":""}] +[ + { + "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: diff --git a/docs/dev.md b/docs/dev.md index 71aa0857..c0838195 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -20,12 +20,12 @@ The JSON object has the following properties: | `mirror_screen` | boolean | Mirrors the screen | `false` | | `temp_dec_places` | integer | Number of decimal places for temperature measurements | `0` | | `sensor_reading` | boolean | Enables or disables the reading of the Temp&Hum sensor | `true` | -| `temp_offset` | float | Sets the offset for the internal temperature messurement | `-9` | -| `hum_offset` | float | Sets the offset for the internal humidity messurement | `0` | +| `temp_offset` | float | Sets the offset for the internal temperature measurement | `-9` | +| `hum_offset` | float | Sets the offset for the internal humidity measurement | `0` | | `min_brightness` | integer | Sets minimum brightness level for the Autobrightness control | `2` | | `max_brightness` | integer | Sets maximum brightness level for the Autobrightness control. On high levels, this could result in overheating! | `180` | -| `min_battery` | integer | Calibrates the minimum battery messurement by the given raw value. You will get that from the stats api | `475` | -| `max_battery` | integer | Calibrates the maximum battery messurement by the given raw value. You will get that from the stats api | `665` | +| `min_battery` | integer | Calibrates the minimum battery measurement by the given raw value. You will get that from the stats api | `475` | +| `max_battery` | integer | Calibrates the maximum battery measurement by the given raw value. You will get that from the stats api | `665` | | `ha_prefix` | string | Sets the prefix for Homassistant discovery | `homeassistant` | | `background_effect` | string | Sets an [effect](https://blueforcer.github.io/awtrix-light/#/effects) as global background layer | - | | `stats_interval` | integer | Sets the interval in milliseconds when awtrix should send its stats to HA and MQTT | 10000 | diff --git a/docs/effects.md b/docs/effects.md index 5c7ac196..2348db08 100644 --- a/docs/effects.md +++ b/docs/effects.md @@ -1,12 +1,12 @@ # Effects AWTRIX light can show effects wherever you want -- Notification and CustomApps. This will show the effect as the first layer, so you can stil draw text over it. +- Notification and CustomApps. This will show the effect as the first layer, so you can still draw text over it. - Backgroundlayer. This will show the effect behind everything and in each app. You can add it via Hidden features. Just call the name for your favorite effect. AWTRIX sends all effect names once after start via MQTT to stats/effects. So you can create external selectors. -Its also accessable via HTTTP /api/effects +Its also accessible via HTTTP /api/effects @@ -159,7 +159,7 @@ Remember, the colors you define in your palette serve as key points in the color # Artnet (DMX) Awtrix light supports Artnet out of the box. -For [Jinx!](http://www.live-leds.de/) you can download this template. Just change the IP of both universes to your awtrix IP and youre ready to go. +For [Jinx!](http://www.live-leds.de/) you can download this template. Just change the IP of both universes to your awtrix IP and you're ready to go. **For any Other Artnet controller:** Create 2 universes with 384 channels each. Also add a new matrix layout with 8 strings รก 32 Strands and top left starting position. When you start to send data, AWTRIX will stop its normal operation and shows your data. 1s after you stop sending data, AWTRIX will return to normal operation. diff --git a/docs/icons.md b/docs/icons.md index d815fc53..af2fb8f3 100644 --- a/docs/icons.md +++ b/docs/icons.md @@ -14,5 +14,5 @@ You can also create your own icon and place it in the "ICONS" folder via the web The icon needs to be a GIF (.gif) or JPG (.jpg) with a resolution of 8x8. !> The Awtrix GIF renderer only supports 8bit gifs at the moment without transparency. -If you have some graphic glitches on the matrix, try to replace the transparency pixels with solid blak color. +If you have some graphic glitches on the matrix, try to replace the transparency pixels with solid black color. For example with this [online tool](https://onlinegiftools.com/add-gif-background) \ No newline at end of file diff --git a/docs/quickstart.md b/docs/quickstart.md index ea7830d2..0df1ab4f 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -4,6 +4,6 @@ 1. :computer: Connect your device to your PC or Mac and [use the online flasher](flasher.md) 2. :signal_strength: After flashing, Awtrix will open an access point with the name "awtrix_XXXXX". Connect with PW "12345678". 3. :mag: Open a browser and navigate to 192.168.4.1. Enter your WiFi information and connect to your WiFi. -4. :clock1: Your clock is accessible via the IP adress you see at connect. +4. :clock1: Your clock is accessible via the IP address you see at connect. 5. :gear: Set up your MQTT and other options in the web interface. 6. :heavy_check_mark: You're ready to go. diff --git a/src/Apps.cpp b/src/Apps.cpp index 1ec92c96..b5d2dc03 100644 --- a/src/Apps.cpp +++ b/src/Apps.cpp @@ -608,7 +608,7 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState DisplayManager.getInstance().resetTextColor(); } -// Unattractive to have a function for every customapp wich does the same, but currently still no other option found TODO +// Unattractive to have a function for every customapp which does the same, but currently still no other option found TODO void CApp1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, GifPlayer *gifPlayer) { diff --git a/src/Apps.h b/src/Apps.h index 1648cb7d..22011e39 100644 --- a/src/Apps.h +++ b/src/Apps.h @@ -83,7 +83,7 @@ void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, GifPlayer *gifPlayer); -// Unattractive to have a function for every customapp wich does the same, but currently still no other option found TODO +// Unattractive to have a function for every customapp which does the same, but currently still no other option found TODO void CApp1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, GifPlayer *gifPlayer); void CApp2(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, GifPlayer *gifPlayer); void CApp3(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, GifPlayer *gifPlayer); diff --git a/src/ArtnetWifi.h b/src/ArtnetWifi.h index f963f5d9..9b39aa63 100644 --- a/src/ArtnetWifi.h +++ b/src/ArtnetWifi.h @@ -106,7 +106,7 @@ class ArtnetWifi } [[deprecated]] - inline void setPhisical(uint8_t port) + inline void setPhysical(uint8_t port) { setPhysical(port); } diff --git a/src/Dictionary.cpp b/src/Dictionary.cpp index 878bf4b4..48e522a5 100644 --- a/src/Dictionary.cpp +++ b/src/Dictionary.cpp @@ -134,7 +134,15 @@ const char HAramName[] PROGMEM = {"Free ram"}; const char HAramClass[] PROGMEM = {"data_size"}; const char HAramUnit[] PROGMEM = {"B"}; -// JSON properites + +// JSON properties + +const char HAipAddrRID[] PROGMEM = {"%s_ip_address"}; +const char HAipAddrName[] PROGMEM = {"IP Address"}; +const char HAipAddrIcon[] PROGMEM = {"mdi:wifi"}; + + + #ifndef awtrix2_upgrade const char BatKey[] PROGMEM = {"bat"}; const char BatRawKey[] PROGMEM = {"bat_raw"}; @@ -150,3 +158,4 @@ const char UpdateKey[] PROGMEM = {"up_available"}; const char MessagesKey[] PROGMEM = {"messages"}; const char VersionKey[] PROGMEM = {"version"}; const char RamKey[] PROGMEM = {"ram"}; +const char IpAddrKey[] PROGMEM = {"ip_address"}; diff --git a/src/Dictionary.h b/src/Dictionary.h index 5f445d0d..e1b045f3 100644 --- a/src/Dictionary.h +++ b/src/Dictionary.h @@ -131,7 +131,13 @@ extern const char HAramName[]; extern const char HAramClass[]; extern const char HAramUnit[]; -// JSON properites + +// JSON properties + +extern const char HAipAddrRID[]; +extern const char HAipAddrName[]; +extern const char HAipAddrIcon[]; + #ifndef awtrix2_upgrade extern const char BatKey[]; extern const char BatRawKey[]; @@ -147,4 +153,5 @@ extern const char UpdateKey[]; extern const char MessagesKey[]; extern const char VersionKey[]; extern const char RamKey[]; +extern const char IpAddrKey[]; #endif diff --git a/src/DisplayManager.cpp b/src/DisplayManager.cpp index 9cacdc6a..1e893cf0 100644 --- a/src/DisplayManager.cpp +++ b/src/DisplayManager.cpp @@ -1589,6 +1589,7 @@ String DisplayManager_::getStats() doc[F("app")] = CURRENT_APP; doc[F("uid")] = uniqueID; doc[F("matrix")] = !MATRIX_OFF; + doc[IpAddrKey] = WiFi.localIP(); String jsonString; serializeJson(doc, jsonString); return jsonString; @@ -2393,7 +2394,7 @@ String DisplayManager_::getEffectNames() return result; } -String DisplayManager_::getTransistionNames() +String DisplayManager_::getTransitionNames() { char effectOptions[100]; strcpy_P(effectOptions, HAeffectOptions); diff --git a/src/DisplayManager.h b/src/DisplayManager.h index b5d20b8f..1a52c8b9 100644 --- a/src/DisplayManager.h +++ b/src/DisplayManager.h @@ -81,7 +81,7 @@ class DisplayManager_ CRGB *getLeds(); void forceNextApp(); String getEffectNames(); - String getTransistionNames(); + String getTransitionNames(); void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color); void drawFilledRect(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color); void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint32_t color); diff --git a/src/Globals.cpp b/src/Globals.cpp index 631e2a25..17510d2b 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -41,7 +41,7 @@ void startLittleFS() else { if (DEBUG_MODE) - DEBUG_PRINTLN(F("Filesystem currupt. Formating...")); + DEBUG_PRINTLN(F("Filesystem corrupt. Formatting...")); LittleFS.format(); ESP.restart(); } diff --git a/src/MQTTManager.cpp b/src/MQTTManager.cpp index 52dea090..a0700e3c 100644 --- a/src/MQTTManager.cpp +++ b/src/MQTTManager.cpp @@ -12,7 +12,7 @@ WiFiClient espClient; HADevice device; -HAMqtt mqtt(espClient, device, 25); +HAMqtt mqtt(espClient, device, 26); // HANumber *ScrollSpeed = nullptr; HALight *Matrix, *Indikator1, *Indikator2, *Indikator3 = nullptr; HASelect *BriMode, *transEffect = nullptr; @@ -21,10 +21,10 @@ HASwitch *transition = nullptr; #ifndef awtrix2_upgrade HASensor *battery = nullptr; #endif -HASensor *temperature, *humidity, *illuminance, *uptime, *strength, *version, *ram, *curApp, *myOwnID = nullptr; +HASensor *temperature, *humidity, *illuminance, *uptime, *strength, *version, *ram, *curApp, *myOwnID, *ipAddr = nullptr; HABinarySensor *btnleft, *btnmid, *btnright = nullptr; bool connected; -char matID[40], ind1ID[40], ind2ID[40], ind3ID[40], briID[40], 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], doUpdateID[40], batID[40], myID[40], sSpeed[40], effectID[40]; +char matID[40], ind1ID[40], ind2ID[40], ind3ID[40], briID[40], 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], doUpdateID[40], batID[40], myID[40], sSpeed[40], effectID[40], ipAddrID[40]; long previousMillis_Stats; // The getter for the instantiated singleton instance MQTTManager_ &MQTTManager_::getInstance() @@ -407,7 +407,7 @@ void onMqttConnected() version->setValue(VERSION); } MQTTManager.publish("stats/effects", DisplayManager.getEffectNames().c_str()); - MQTTManager.publish("stats/transitions", DisplayManager.getTransistionNames().c_str()); + MQTTManager.publish("stats/transitions", DisplayManager.getTransitionNames().c_str()); connected = true; } @@ -487,6 +487,7 @@ void MQTTManager_::sendStats() sprintf(uptimeStr, "%ld", uptimeValue); uptime->setValue(uptimeStr); transition->setState(AUTO_TRANSITION, false); + ipAddr->setValue(ServerManager.myIP.toString().c_str()); } publish(StatsTopic, DisplayManager.getStats().c_str()); @@ -678,6 +679,11 @@ void MQTTManager_::setup() ram->setIcon(HAramIcon); ram->setName(HAramName); ram->setUnitOfMeasurement(HAramUnit); + + sprintf(ipAddrID, HAipAddrRID, macStr); + ipAddr = new HASensor(ipAddrID); + ipAddr->setName(HAipAddrName); + ipAddr->setIcon(HAipAddrIcon); } else { diff --git a/src/MatrixDisplayUi.cpp b/src/MatrixDisplayUi.cpp index 6bba5d6f..7053b679 100644 --- a/src/MatrixDisplayUi.cpp +++ b/src/MatrixDisplayUi.cpp @@ -4,7 +4,7 @@ * Copyright (c) 2016 by Daniel Eichhorn * Copyright (c) 2016 by Fabrice Weinberg * Copyright (c) 2023 by Stephan Muehl (Blueforcer) - * Note: This old lib for SSD1306 displays has been extremly + * Note: This old lib for SSD1306 displays has been extremely * modified for AWTRIX Light and has nothing to do with the original purposes. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -64,7 +64,7 @@ void MatrixDisplayUi::setBackgroundEffect(int effect) this->BackgroundEffect = effect; } -// -/------ Automatic controll ------\- +// -/------ Automatic control ------\- void MatrixDisplayUi::enablesetAutoTransition() { @@ -125,12 +125,12 @@ void MatrixDisplayUi::setBackground(BackgroundCallback backgroundFunction) this->backgroundFunction = backgroundFunction; } -// -/----- Manuel control -----\- +// -/----- Manual control -----\- void MatrixDisplayUi::nextApp() { if (this->state.appState != IN_TRANSITION) { - this->state.manuelControll = true; + this->state.manualControl = true; this->state.appState = IN_TRANSITION; this->state.ticksSinceLastStateSwitch = 0; this->lastTransitionDirection = this->state.appTransitionDirection; @@ -141,7 +141,7 @@ void MatrixDisplayUi::previousApp() { if (this->state.appState != IN_TRANSITION) { - this->state.manuelControll = true; + this->state.manualControl = true; this->state.appState = IN_TRANSITION; this->state.ticksSinceLastStateSwitch = 0; this->lastTransitionDirection = this->state.appTransitionDirection; @@ -170,7 +170,7 @@ void MatrixDisplayUi::transitionToApp(uint8_t app) return; this->nextAppNumber = app; this->lastTransitionDirection = this->state.appTransitionDirection; - this->state.manuelControll = true; + this->state.manualControl = true; this->state.appState = IN_TRANSITION; this->state.appTransitionDirection = app < this->state.currentApp ? -1 : 1; } @@ -187,7 +187,7 @@ int8_t MatrixDisplayUi::update() int8_t timeBudget = this->updateInterval - (appStart - this->state.lastUpdate); if (timeBudget <= 0) { - // Implement frame skipping to ensure time budget is keept + // Implement frame skipping to ensure time budget is kept if (this->setAutoTransition && this->state.lastUpdate != 0) this->state.ticksSinceLastStateSwitch += ceil(-timeBudget / this->updateInterval); @@ -216,11 +216,11 @@ void MatrixDisplayUi::tick() } break; case FIXED: - // Revert manuelControll - if (this->state.manuelControll) + // Revert manualControl + if (this->state.manualControl) { this->state.appTransitionDirection = 1; - this->state.manuelControll = false; + this->state.manualControl = false; } if (this->state.ticksSinceLastStateSwitch >= this->ticksPerApp) { @@ -351,7 +351,7 @@ TransitionType getRandomTransition() return static_cast((rand() % (CROSSFADE)) + 1); } -bool swaped = false; +bool swapped = false; void MatrixDisplayUi::drawApp() { @@ -359,7 +359,7 @@ void MatrixDisplayUi::drawApp() { case IN_TRANSITION: { - swaped = false; + swapped = false; gotNewTransition = false; if (currentTransition == SLIDE) { @@ -418,7 +418,7 @@ void MatrixDisplayUi::drawApp() } (this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, 0, 0, &gif1); - swaped = true; + swapped = true; break; } } diff --git a/src/MatrixDisplayUi.h b/src/MatrixDisplayUi.h index c30ba5b0..404e3e97 100644 --- a/src/MatrixDisplayUi.h +++ b/src/MatrixDisplayUi.h @@ -76,7 +76,7 @@ struct MatrixDisplayUiState // Normal = 1, Inverse = -1; int8_t appTransitionDirection = 1; bool lastFrameShown = false; - bool manuelControll = false; + bool manualControl = false; // Custom data that can be used by the user void *userData = NULL; @@ -113,7 +113,7 @@ class MatrixDisplayUi // UI State MatrixDisplayUiState state; - // Bookeeping for update + // Bookkeeping for update long updateInterval = 33; void drawApp(); @@ -149,7 +149,7 @@ class MatrixDisplayUi void setTargetFPS(uint8_t fps); void setBackgroundEffect(int effect); - // Automatic Controll + // Automatic Control /** * Enable automatic transition to next app after the some time can be configured with `setTimePerApp` and `setTimePerTransition`. */ diff --git a/src/PeripheryManager.cpp b/src/PeripheryManager.cpp index 7d85cf0f..da89987a 100644 --- a/src/PeripheryManager.cpp +++ b/src/PeripheryManager.cpp @@ -492,6 +492,7 @@ void PeripheryManager_::tick() if (AUTO_BRIGHTNESS && !MATRIX_OFF) { brightnessPercent = sampleAverage / 1023.0 * 100.0; + brightnessPercent = (brightnessPercent * brightnessPercent * brightnessPercent) / (100.0 * 100.0); // apply gamma correction (gamma = 3) BRIGHTNESS = map(brightnessPercent, 0, 100, MIN_BRIGHTNESS, MAX_BRIGHTNESS); DisplayManager.setBrightness(BRIGHTNESS); } diff --git a/src/ServerManager.cpp b/src/ServerManager.cpp index 6eeaa30a..f6022d86 100644 --- a/src/ServerManager.cpp +++ b/src/ServerManager.cpp @@ -59,7 +59,7 @@ void addHandler() mws.addHandler("/api/effects", HTTP_GET, []() { mws.webserver->send_P(200, "application/json", DisplayManager.getEffectNames().c_str()); }); mws.addHandler("/api/transitions", HTTP_GET, []() - { mws.webserver->send_P(200, "application/json", DisplayManager.getTransistionNames().c_str()); }); + { mws.webserver->send_P(200, "application/json", DisplayManager.getTransitionNames().c_str()); }); mws.addHandler("/api/reboot", HTTP_ANY, []() { mws.webserver->send(200,F("text/plain"),F("OK")); delay(200); ESP.restart(); }); mws.addHandler("/api/rtttl", HTTP_POST, []() diff --git a/src/UpdateManager.cpp b/src/UpdateManager.cpp index 94cac316..13bbb232 100644 --- a/src/UpdateManager.cpp +++ b/src/UpdateManager.cpp @@ -69,7 +69,7 @@ void UpdateManager_::updateFirmware() switch (ret) { case HTTP_UPDATE_FAILED: - if (DEBUG_MODE) DEBUG_PRINTF("HTTP_UPDATE_FAILD Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); + if (DEBUG_MODE) DEBUG_PRINTF("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); break; case HTTP_UPDATE_NO_UPDATES: