Compare commits

...

16 Commits

Author SHA1 Message Date
975e388da7 Add checksum calc for bin file 2025-12-07 03:01:41 +01:00
4a85b28079 Set CPU frequency to 160 MHz. Add sha256 checksum calc for bin file 2025-12-07 03:01:24 +01:00
4e0983e1fa Minor refactoring 2025-12-07 02:38:45 +01:00
6c8e4ef5c9 MInor refactoring 2025-12-07 02:38:36 +01:00
6cb023d96c Minor refactoring 2025-12-07 02:38:23 +01:00
d03c61b7ef Add CPU frequency to device info 2025-12-07 02:36:56 +01:00
1629f24fcc Merge branch 'main' of ssh://192.168.178.10:2022/ranse/wordclock 2024-10-05 17:14:39 +02:00
adb3677d71 Bump FastLED to latest ESP8266 stable version 3.7.6. Bump WiFiManager to 2.0.17. 2024-10-05 17:13:57 +02:00
d6f06525c9 Update README.md. 2024-07-21 20:04:50 +02:00
4d810783fc Add diagnosis module via HTTP. 2024-07-21 19:30:21 +02:00
feb26d7269 Remove array initialization with single 0 because of compiler compatibility (espressif8266@2.6.3). 2024-07-21 19:30:06 +02:00
3dfd6c82fe Remove serial output in UDP Logger. 2024-07-21 19:28:38 +02:00
244455909d Use FastLED instead of NeoMatrix. Downgrade platform platform "espressif8266" to version 2.6.3 because of FastLED. 2024-07-21 19:27:58 +02:00
f53f557a6a Use FastLED instead of NeoMatrix. 2024-07-21 19:26:56 +02:00
e1df24633a Add diagnosis script and refactor UDP receiver. 2024-07-21 19:24:20 +02:00
4543cf1e09 Add backup and Python files. 2024-07-21 19:22:29 +02:00
17 changed files with 431 additions and 304 deletions

11
.gitignore vendored
View File

@@ -66,3 +66,14 @@ modules.order
Module.symvers Module.symvers
Mkfile.old Mkfile.old
dkms.conf dkms.conf
# Python
venv
.venv
# Logs
*.log
# Local backup
*.*_
*.*bak*

View File

@@ -1,96 +1,49 @@
# Important Note: # Important Note:
This project has been unofficially forked from https://github.com/techniccontroller/wordclock_esp8266 which was initially created by techniccontroller. Copyright and licensing is respected. This project has been unofficially forked from https://github.com/techniccontroller/wordclock_esp8266 which was initially created by techniccontroller. Copyright and licensing is respected. Very many thanks for the initial code!
# Wordclock 2.0 # Wordclock 2.0
Wordclock 2.0 with ESP8266 and NTP time Wordclock 2.0 with ESP8266 and NTP time
More details on my website: https://techniccontroller.com/word-clock-with-wifi-and-neopixel/ More details on techniccontroller's website: https://techniccontroller.com/word-clock-with-wifi-and-neopixel/
**Languages** **Languages**
The Wordclock is available in **German**, **English** and **Italian** language. By default the language is German. The Wordclock is available in **German** language.
To use the English or Italian language please replace the file *wordclockfunctions.ino* with *wordclockfunctions.ino_english* or *wordclockfunctions.ino_italian*.
The code compiles only with one file named *wordclockfunctions.ino*. So please rename the file you want to use to *wordclockfunctions.ino* and replace the existing file.
## Features ## Features
- 6 modes (Clock, Digital Clock, SPIRAL animation, TETRIS, SNAKE, PONG) - Time update via NTP server
- time update via NTP server - Games: Pong, Snake, Tetris, ...
- automatic summer/wintertime change - Automatic summer/wintertime change
- easy WIFI setup with WifiManager - Easy wifi setup with WifiManager
- configurable color - Configurable color
- configurable night mode (start and end time) - Configurable night mode (start and end time)
- configurable brightness - Configurable brightness
- automatic mode change - Automatic mode change
- webserver interface for configuration and control - Webserver interface for configuration and control (web address: wordclock.local)
- physical button to change mode or enable night mode without webserver - Automatic current limiting of LEDs
- automatic current limiting of LEDs
## Pictures of clock ## Pictures of clock
![modes_images2](https://user-images.githubusercontent.com/36072504/156947689-dd90874d-a887-4254-bede-4947152d85c1.png) ![modes_images2](https://user-images.githubusercontent.com/36072504/156947689-dd90874d-a887-4254-bede-4947152d85c1.png)
## Screenshots of webserver UI
![screenshots_UI](https://user-images.githubusercontent.com/36072504/158478447-d828e460-d4eb-489e-981e-216e08d4b129.png)
## Quickstart ## Quickstart
1. Clone the project into the sketch folder of the Arduino IDE, 1. Clone the project into the a directory.
2. Rename the file "example_secrets.h" to "secrets.h". You don't need to change anything in the file if you want uses the normal WiFi setup with WiFiManager (see section "Remark about the WiFi setup"). 2. Open directory in VSCode with PlatformIO extension installed.
3. Install the additional libraries and flash it to the ESP8266 as usual (See section [*Upload program to ESP8266*](https://github.com/techniccontroller/wordclock_esp8266/blob/main/README.md#upload-program-to-esp8266-with-arduino-ide) below). 3. Current dependencies (2024-07-21):
4. The implemented WiFiManager helps you to set up a WiFi connection with your home WiFi -> on the first startup it will create a WiFi access point named "WordclockAP". Connect your phone to this access point and follow the steps which will be shown to you. - Platform espressif8266 @ 2.6.3 (required: espressif8266 @ 2.6.3)
5. After a successful WiFi setup, open the browser and enter the IP address of your ESP8266 to access the interface of the webserver. - Libraries
6. Here you can then upload all files located in the folder "data". Please make sure all icons stay in the folder "icons" also on the webserver. - ├── FastLED @ 3.7.0 (required: fastled/FastLED @ 3.7.0)
- ├── FastLED NeoMatrix @ 1.2.0 (required: marcmerlin/FastLED NeoMatrix @ ^1.2)
- │⠀⠀⠀└── Framebuffer GFX @ 1.1.0 (required: Framebuffer GFX)
<img src="https://techniccontroller.com/wp-content/uploads/filemanager1-1.png" height="300px" /> <img src="https://techniccontroller.com/wp-content/uploads/filemanager2-1.png" height="300px" /> <img src="https://techniccontroller.com/wp-content/uploads/filemanager3-1.png" height="300px" /> - │⠀⠀⠀│⠀⠀⠀├── Adafruit GFX Library @ 1.11.9 (required: Adafruit GFX Library)
- │⠀⠀⠀│⠀⠀⠀│⠀⠀⠀└── Adafruit BusIO @ 1.16.1 (required: Adafruit BusIO)
## Install needed Libraries - ├── WiFiManager @ 0.16.0 (required: tzapu/WiFiManager @ ^0.16.0)
- └── base64 @ 1.4.0 (required: densaugeo/base64 @ ^1.4.0)
Please download all these libraries as ZIP from GitHub, and extract them in the *libraries* folder of your Sketchbook location (see **File -> Preferences**):
- https://github.com/adafruit/Adafruit-GFX-Library
- https://github.com/adafruit/Adafruit_NeoMatrix
- https://github.com/adafruit/Adafruit_NeoPixel
- https://github.com/tzapu/WiFiManager
- https://github.com/adafruit/Adafruit_BusIO
## Remark about the WiFi setup ## Remark about the WiFi setup
Regarding the Wifi setting, I have actually implemented two variants: By default the WifiManager is activated. That is, the word clock makes the first time its own WiFi (should be called "WordclockAP"). There you simply connect to the cell phone and you can perform configuration of the WiFi settings conveniently as with SmartHome devices.
1. By default the WifiManager is activated. That is, the word clock makes the first time its own WiFi (should be called "WordclockAP"). There you simply connect to the cell phone and you can perform configuration of the WiFi settings conveniently as with a SmartHome devices (Very elegant 😊)
2. Another (traditional) variant is to define the wifi credentials in the code (in secrets.h).
- For this you have to comment out lines 230 to 251 in the code of the file *wordclock_esp8266.ino* (/\* before and \*/ after)
- and comment out lines 257 to 305 (/\* and \*/ remove)
## Remark about Logging
The wordclock send continuously log messages to the serial port and via multicast UDP. If you want to see these messages, you have to
- open the serial monitor in the Arduino IDE (Tools -> Serial Monitor). The serial monitor must be set to 115200 baud.
OR
- run the following steps for the multicast UDP logging:
1. starting situation: wordclock is connected to WLAN, a computer with installed Python (https://www.python.org/downloads/) is in the same local area network (WLAN or LAN doesn't matter).
3. open the file **multicastUDP_receiver.py** in a text editor and in line 81 enter the IP address of the computer (not the wordclock!).
```python
# ip address of network interface
MCAST_IF_IP = '192.168.0.7'
```
4. execute the script with following command:
```bash
python multicastUDP_receiver_analyzer.py
```
5. now you should see the log messages of the word clock (every 5 seconds a heartbeat message and the currently displayed time).
If this is not the case, there could be a problem with the network settings of the computer, then recording is unfortunately not possible.
6. If special events (failed NTP update, reboot) occur, a section of the log is saved in a file called *log.txt*.
In principle, the events are not critical and will occur from time to time, but should not be too frequent.

26
include/diagnosis.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef DIAGNOSIS_H
#define DIAGNOSIS_H
#include <Arduino.h>
#include "led_matrix.h"
#include "udp_logger.h"
class Diagnosis
{
public:
Diagnosis(); // constructor
Diagnosis(UDPLogger *logger, LEDMatrix *matrix); // constructor
String handle_command(const String &command);
String print_device_info();
String print_sketch_info();
String print_last_reset_details();
String print_matrix_fps();
private:
UDPLogger *_logger;
LEDMatrix * _matrix;
void print(const String &s);
};
#endif // DIAGNOSIS_H

View File

@@ -1,24 +1,28 @@
#ifndef LEDMATRIX_H #ifndef LEDMATRIX_H
#define LEDMATRIX_H #define LEDMATRIX_H
#ifndef FASTLED_INTERNAL
#define FASTLED_INTERNAL
#endif
#include <Arduino.h> #include <Arduino.h>
#include <Adafruit_GFX.h> #include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h> #include <FastLED_NeoMatrix.h>
#include "wordclock_constants.h" #include "wordclock_constants.h"
#include "udp_logger.h" #include "udp_logger.h"
#define DEFAULT_CURRENT_LIMIT 9999 #define DEFAULT_CURRENT_LIMIT 9999
extern const uint32_t colors_24bit[NUM_COLORS]; extern const uint32_t colors_24bit[NUM_COLORS];
class LEDMatrix class LEDMatrix
{ {
public: public:
LEDMatrix(Adafruit_NeoMatrix * matrix, uint8_t brightness, UDPLogger * logger); LEDMatrix(FastLED_NeoMatrix *matrix, uint8_t brightness, UDPLogger *logger);
static uint16_t color_24_to_16bit(uint32_t color24bit); static uint16_t color_24_to_16bit(uint32_t color24bit);
static uint32_t color_24bit(uint8_t r, uint8_t g, uint8_t b); static uint32_t color_24bit(uint8_t r, uint8_t g, uint8_t b);
static uint32_t interpolate_color_24bit(uint32_t color1, uint32_t color2, float factor); static uint32_t interpolate_color_24bit(uint32_t color1, uint32_t color2, float factor);
static uint32_t wheel(uint8_t WheelPos); static uint32_t wheel(uint8_t WheelPos);
uint16_t get_fps(void);
void draw_on_matrix_instant(); void draw_on_matrix_instant();
void draw_on_matrix_smooth(float factor); void draw_on_matrix_smooth(float factor);
void flush(void); void flush(void);
@@ -31,17 +35,17 @@ public:
void setup_matrix(); void setup_matrix();
private: private:
Adafruit_NeoMatrix * _neomatrix; FastLED_NeoMatrix *_neomatrix;
UDPLogger * _logger; UDPLogger *_logger;
uint8_t _brightness; uint8_t _brightness;
uint16_t _current_limit; uint16_t _current_limit;
// target representation of matrix as 2D array // target representation of matrix as 2D array
uint32_t _target_grid[MATRIX_HEIGHT][MATRIX_WIDTH] = {0}; uint32_t _target_grid[MATRIX_HEIGHT][MATRIX_WIDTH];
// current representation of matrix as 2D array // current representation of matrix as 2D array
uint32_t _current_grid[MATRIX_HEIGHT][MATRIX_WIDTH] = {0}; uint32_t _current_grid[MATRIX_HEIGHT][MATRIX_WIDTH];
// target representation of minutes indicator LEDs // target representation of minutes indicator LEDs
uint32_t _target_minute_indicators[4] = {0, 0, 0, 0}; uint32_t _target_minute_indicators[4] = {0, 0, 0, 0};

View File

@@ -79,8 +79,8 @@ private:
UDPLogger *_logger; UDPLogger *_logger;
uint8_t _gameState = 0; uint8_t _gameState = 0;
uint8_t _numBots = 0; uint8_t _numBots = 0;
uint8_t _playerMovement[PLAYER_AMOUNT] = {0}; uint8_t _playerMovement[PLAYER_AMOUNT];
Coords _paddles[PLAYER_AMOUNT][PADDLE_WIDTH] = {0}; Coords _paddles[PLAYER_AMOUNT][PADDLE_WIDTH];
Coords _ball = {0, 0}; Coords _ball = {0, 0};
Coords _ball_old = {0, 0}; Coords _ball_old = {0, 0};
int _ballMovement[2] = {0, 0}; int _ballMovement[2] = {0, 0};

View File

@@ -76,7 +76,7 @@ private:
uint8_t _userDirection = 0; uint8_t _userDirection = 0;
uint8_t _gameState = 0; uint8_t _gameState = 0;
Coords _head = {0, 0}; Coords _head = {0, 0};
Coords _tail[MAX_TAIL_LENGTH] = {0}; Coords _tail[MAX_TAIL_LENGTH];
Coords _food = {0, 0}; Coords _food = {0, 0};
unsigned long _lastDrawUpdate = 0; unsigned long _lastDrawUpdate = 0;
unsigned long _lastButtonClick = 0; unsigned long _lastButtonClick = 0;

View File

@@ -16,7 +16,7 @@
#define HTTP_PORT (80) // Standard HTTP port #define HTTP_PORT (80) // Standard HTTP port
// ESP8266 Pins // ESP8266 Pins
#define NEOPIXEL_PIN (14) // pin to which the NeoPixels are attached #define FASTLED_PIN (14) // pin to which the LEDs are attached
#define BUTTON_PIN (5) // pin to which the button is attached #define BUTTON_PIN (5) // pin to which the button is attached
// Time limits // Time limits
@@ -36,8 +36,8 @@
#define PERIOD_ANIMATION_US (200 * 1000) // 200ms #define PERIOD_ANIMATION_US (200 * 1000) // 200ms
#define PERIOD_CLOCK_UPDATE_US (1 * 1000 * 1000) // Must be 1s! Do not change! #define PERIOD_CLOCK_UPDATE_US (1 * 1000 * 1000) // Must be 1s! Do not change!
#define PERIOD_HEARTBEAT_US (1 * 1000 * 1000) // 1s #define PERIOD_HEARTBEAT_US (1 * 1000 * 1000) // 1s
#define PERIOD_MATRIX_UPDATE_US (100 * 1000) // 100ms #define PERIOD_MATRIX_UPDATE_US (33 * 1000) // 33ms
#define PERIOD_NIGHTMODE_CHECK_US (20 * 1000 * 1000) // 20s #define PERIOD_NIGHTMODE_CHECK_US (30 * 1000 * 1000) // 30s
#define PERIOD_TIME_UPDATE_US (1 * 1000 * 1000) // 1000ms #define PERIOD_TIME_UPDATE_US (1 * 1000 * 1000) // 1000ms
#define PERIOD_PONG_US (10 * 1000) // 10ms #define PERIOD_PONG_US (10 * 1000) // 10ms
#define PERIOD_SNAKE_US (50 * 1000) // 50ms #define PERIOD_SNAKE_US (50 * 1000) // 50ms
@@ -63,10 +63,13 @@
// Number of colors in colors array // Number of colors in colors array
#define NUM_COLORS (7) #define NUM_COLORS (7)
#define COLOR_ORDER GRB // WS2812B color order
// LED matrix size // LED matrix size
#define MATRIX_WIDTH (11) #define MATRIX_WIDTH (11)
#define MATRIX_HEIGHT (11) #define MATRIX_HEIGHT (11)
#define NUM_MATRIX (MATRIX_WIDTH * (MATRIX_HEIGHT + 1))
#define MIN_LEDS_PATTERN (0x0F)
// NTP macros // NTP macros
#define BUILD_YEAR (__DATE__ + 7) // Will expand to current year at compile time as string. #define BUILD_YEAR (__DATE__ + 7) // Will expand to current year at compile time as string.

View File

@@ -12,15 +12,18 @@
default_envs = nodemcuv2 default_envs = nodemcuv2
[env] [env]
platform = espressif8266 platform = espressif8266@2.6.3
board = nodemcuv2 board = nodemcuv2
framework = arduino framework = arduino
lib_deps = lib_deps =
adafruit/Adafruit BusIO@^1.15.0
adafruit/Adafruit NeoMatrix@^1.3.0
adafruit/Adafruit NeoPixel@^1.11.0
densaugeo/base64@^1.4.0 densaugeo/base64@^1.4.0
tzapu/WiFiManager@^0.16.0 fastled/FastLED@3.7.6
marcmerlin/FastLED NeoMatrix@^1.2
tzapu/WiFiManager@^2.0.17
build_flags =
-DFASTLED_ESP8266_RAW_PIN_ORDER
board_build.f_cpu = 160000000L
extra_scripts = post:post_build.py
[env:nodemcuv2] [env:nodemcuv2]
monitor_speed = 115200 monitor_speed = 115200

25
post_build.py Normal file
View File

@@ -0,0 +1,25 @@
Import("env")
from pathlib import Path
import hashlib
print("Current CLI targets", COMMAND_LINE_TARGETS)
print("Current Build targets", BUILD_TARGETS)
def sha256sum(filename):
with open(filename, 'rb', buffering=0) as f:
return hashlib.file_digest(f, 'sha256').hexdigest()
def post_buildprog_action(source, target, env):
source_path = Path(source[0].get_abspath())
sha256 = sha256sum(source_path)
print(f"Calculated SHA256: {sha256}")
build_dir = source_path.parent
sha_txt_file = build_dir / "firmware.bin.sha256"
with Path.open(sha_txt_file, "w") as f:
f.write(sha256)
env.AddPostAction("buildprog", post_buildprog_action)

13
scripts/http_diagnosis.py Normal file
View File

@@ -0,0 +1,13 @@
import requests
r = requests.get("http://wordclock.local/cmd?diag=reset_info")
print(r.status_code)
print(r.text)
r = requests.get("http://wordclock.local/cmd?diag=sketch_info")
print(r.status_code)
print(r.text)
r = requests.get("http://wordclock.local/cmd?diag=device_info")
print(r.status_code)
print(r.text)

View File

@@ -4,15 +4,17 @@ import queue
import socket import socket
import struct import struct
import sys import sys
from pathlib import Path
LOG_PATH = Path("C:/temp/wordclock_log.txt")
def setup_logging(): def setup_logging():
FORMAT = "%(asctime)s %(message)s" FORMAT = "%(asctime)s %(message)s"
logging.basicConfig(format=FORMAT, level=logging.INFO) logging.basicConfig(format=FORMAT, level=logging.INFO)
logger = logging.getLogger() logger = logging.getLogger()
#handler = logging.StreamHandler(sys.stdout) handler = logging.FileHandler(LOG_PATH)
#handler.setLevel(logging.INFO) handler.setLevel(logging.INFO)
#logger.addHandler(handler) logger.addHandler(handler)
return logger return logger
@@ -42,33 +44,9 @@ mreq = struct.pack("4s4s", group, socket.inet_aton(get_ip_address()))
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
logger.info("Ready") logger.info("Ready")
saveCounter = 0
buffer = queue.Queue(20)
# Receive/respond loop # Receive/respond loop
while True: while True:
data, address = sock.recvfrom(1024) data, address = sock.recvfrom(1024)
data_str = data.decode("utf-8").strip() data_str = data.decode("utf-8").strip()
logger.info(data_str) logger.info(data_str)
data_str = datetime.now().strftime("%b-%d-%Y_%H%M%S") + ": " + data_str
buffer.put(data_str)
if buffer.full():
buffer.get()
if "NTP-Update not successful" in data_str or "Start program" in data_str:
f = open("log.txt", "a")
while not buffer.empty():
f.write(buffer.get())
f.write("\n")
f.close()
saveCounter = 20
if saveCounter > 0:
f = open("log.txt", "a")
f.write(data_str)
f.write("\n")
if saveCounter == 1:
f.write("\n")
f.close()
saveCounter -= 1

BIN
scripts/requirements.txt Normal file

Binary file not shown.

View File

@@ -0,0 +1,94 @@
#include "diagnosis.h"
Diagnosis::Diagnosis()
{
_logger = nullptr;
}
Diagnosis::Diagnosis(UDPLogger *logger, LEDMatrix *matrix) // constructor
{
_logger = logger;
_matrix = matrix;
}
String Diagnosis::handle_command(const String &command)
{
if (command == "device_info")
{
return print_device_info();
}
else if (command == "sketch_info")
{
return print_sketch_info();
}
else if (command == "reset_info")
{
return print_last_reset_details();
}
else if (command == "matrix_fps")
{
return print_matrix_fps();
}
else
{
// Handle unknown command
String unknown_command = "Diagnosis: Unknown command!\n";
print(unknown_command);
return unknown_command;
}
}
String Diagnosis::print_device_info()
{
// Retrieve and print device information
String device_info = "Device Information:\n";
device_info += "Chip ID: " + String(ESP.getChipId()) + "\n";
device_info += "CPU frequency: " + String(ESP.getCpuFreqMHz()) + " MHz\n";
device_info += "Flash Chip ID: " + String(ESP.getFlashChipId()) + "\n";
device_info += "Flash Chip Size: " + String(ESP.getFlashChipSize()) + " bytes\n";
device_info += "Free Heap Size: " + String(ESP.getFreeHeap()) + " bytes\n";
device_info += "Free Sketch Space: " + String(ESP.getFreeSketchSpace()) + " bytes\n";
device_info += "SDK Version: " + String(ESP.getSdkVersion()) + "\n";
print(device_info);
return device_info;
}
String Diagnosis::print_sketch_info()
{
// Retrieve and print sketch information
String sketch_info = "Sketch Information:\n";
sketch_info += "Sketch Size: " + String(ESP.getSketchSize()) + " bytes\n";
sketch_info += "Sketch MD5: " + String(ESP.getSketchMD5()) + "\n";
print(sketch_info);
return sketch_info;
}
String Diagnosis::print_last_reset_details()
{
// Retrieve and print last reset details
String reset_info = "Last Reset Details:\n";
reset_info += "Reset Reason: " + String(ESP.getResetReason()) + "\n";
reset_info += "Reset Info: " + String(ESP.getResetInfo()) + "\n";
print(reset_info);
return reset_info;
}
String Diagnosis::print_matrix_fps()
{
// Retrieve and print matrix FPS
String matrix_fps = "Matrix FPS: " + String(_matrix->get_fps()) + "\n";
print(matrix_fps);
return matrix_fps;
}
void Diagnosis::print(const String &s)
{
if (_logger != nullptr)
{
_logger->log_string(s);
}
else
{
Serial.println(s);
}
}

View File

@@ -44,12 +44,13 @@ bool TimeManager::ntp_sync_successful(void) const
bool TimeManager::ntp_sync_overdue(void) bool TimeManager::ntp_sync_overdue(void)
{ {
bool retval = false;
if (!ntp_sync_successful()) if (!ntp_sync_successful())
{ {
return false; return retval;
} }
bool retval = false;
// after the ntp sync update delay has been reached six times, the sync is considered overdue // after the ntp sync update delay has been reached six times, the sync is considered overdue
if (_now >= (_ntp_sync_timestamp_s + (time_t)(6 * (sntp_update_delay_MS_rfc_not_less_than_15000() / 1000)))) if (_now >= (_ntp_sync_timestamp_s + (time_t)(6 * (sntp_update_delay_MS_rfc_not_less_than_15000() / 1000))))
{ {
@@ -61,12 +62,13 @@ bool TimeManager::ntp_sync_overdue(void)
bool TimeManager::ntp_sync_timeout(void) bool TimeManager::ntp_sync_timeout(void)
{ {
bool retval = false;
if (!ntp_sync_successful()) if (!ntp_sync_successful())
{ {
return false; return retval;
} }
bool retval = false;
// after the maxmimum offline time has been reached, the sync is considered timed out // after the maxmimum offline time has been reached, the sync is considered timed out
if (_now >= (_ntp_sync_timestamp_s + (time_t)_ntp_max_offline_time_s)) if (_now >= (_ntp_sync_timestamp_s + (time_t)_ntp_max_offline_time_s))
{ {

View File

@@ -1,8 +1,6 @@
#include "udp_logger.h" #include "udp_logger.h"
UDPLogger::UDPLogger() UDPLogger::UDPLogger() {}
{
}
UDPLogger::UDPLogger(IPAddress interface_addr, IPAddress multicast_addr, int port, String name) UDPLogger::UDPLogger(IPAddress interface_addr, IPAddress multicast_addr, int port, String name)
{ {
@@ -26,8 +24,10 @@ void UDPLogger::log_string(String message)
delay(10); delay(10);
} }
message = _name + ": " + message; message = _name + ": " + message;
#ifdef SERIAL_DEBUG
Serial.println(message); Serial.println(message);
delay(10); delay(10);
#endif /* SERIAL_DEBUG */
_udp.beginPacketMulticast(_multicastAddr, _port, _interfaceAddr); _udp.beginPacketMulticast(_multicastAddr, _port, _interfaceAddr);
message.toCharArray(_packetBuffer, 100); message.toCharArray(_packetBuffer, 100);
_udp.print(_packetBuffer); _udp.print(_packetBuffer);

View File

@@ -21,7 +21,7 @@ const uint32_t colors_24bit[NUM_COLORS] = {
* @param mybrightness the initial brightness of the leds * @param mybrightness the initial brightness of the leds
* @param mylogger pointer to the UDPLogger object * @param mylogger pointer to the UDPLogger object
*/ */
LEDMatrix::LEDMatrix(Adafruit_NeoMatrix *matrix, uint8_t brightness, UDPLogger *logger) LEDMatrix::LEDMatrix(FastLED_NeoMatrix *matrix, uint8_t brightness, UDPLogger *logger)
{ {
_neomatrix = matrix; _neomatrix = matrix;
_brightness = brightness; _brightness = brightness;
@@ -181,6 +181,11 @@ void LEDMatrix::flush(void)
_target_minute_indicators[3] = 0; _target_minute_indicators[3] = 0;
} }
uint16_t LEDMatrix::get_fps(void)
{
return FastLED.getFPS();
}
/** /**
* @brief Write target pixels directly to leds * @brief Write target pixels directly to leds
* *

View File

@@ -1,7 +1,7 @@
/** /**
* Wordclock 2.0 - Wordclock with ESP8266 and NTP time update * Wordclock 2.0 - Wordclock with ESP8266 and NTP time update
* *
* created by techniccontroller 04.12.2021 * created by techniccontroller 04.12.2021, refactored and additions by ranse 10.12.2024
* *
* components: * components:
* - ESP8266 * - ESP8266
@@ -24,16 +24,16 @@
#include "wordclock_esp8266.h" #include "wordclock_esp8266.h"
#include <Adafruit_GFX.h> // https://github.com/adafruit/Adafruit-GFX-Library #include <Adafruit_GFX.h> // https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_NeoMatrix.h> // https://github.com/adafruit/Adafruit_NeoMatrix
#include <Adafruit_NeoPixel.h> // NeoPixel library used to run the NeoPixel LEDs: https://github.com/adafruit/Adafruit_NeoPixel
#include <base64.hpp> #include <base64.hpp>
#include <EEPROM.h> // from ESP8266 Arduino Core (automatically installed when ESP8266 was installed via Boardmanager) #include <EEPROM.h> // from ESP8266 Arduino Core (automatically installed when ESP8266 was installed via Boardmanager)
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <FastLED.h>
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager WiFi Configuration Magic #include <WiFiManager.h> // https://github.com/tzapu/WiFiManager WiFi Configuration Magic
// own libraries // own libraries
#include "animation_functions.h" #include "animation_functions.h"
#include "diagnosis.h"
#include "led_matrix.h" #include "led_matrix.h"
#include "littlefs_wrapper.h" #include "littlefs_wrapper.h"
#include "ota_functions.h" #include "ota_functions.h"
@@ -49,20 +49,21 @@
// GLOBAL VARIABLES // GLOBAL VARIABLES
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
UDPLogger logger; // Global UDP logger instance UDPLogger logger; // Global UDP logger instance
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(MATRIX_WIDTH, MATRIX_HEIGHT + 1, NEOPIXEL_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG, CRGB leds[NUM_MATRIX]; // LED array for FastLED
NEO_GRB + NEO_KHZ800); // NeoMatrix FastLED_NeoMatrix matrix = FastLED_NeoMatrix(leds, MATRIX_WIDTH, (MATRIX_HEIGHT + 1),
LEDMatrix led_matrix = LEDMatrix(&matrix, DEFAULT_BRIGHTNESS, &logger); // NeoMatrix wrapper NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG);
LEDMatrix led_matrix = LEDMatrix(&matrix, DEFAULT_BRIGHTNESS, &logger); // FastLED_NeoMatrix wrapper
ESP8266WebServer webserver(HTTP_PORT); // Webserver ESP8266WebServer webserver(HTTP_PORT); // Webserver
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// STATIC VARIABLES // STATIC VARIABLES
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// EEPROM values // EEPROM values
static EepromLayout_st eeprom_buffer = {{0, 0, 0, 0}, {0U, 0U, 0U, false}, {0U, 0U, 0U, 0U}}; static EepromLayout_st eeprom_buffer_st = {{0, 0, 0, 0}, {0U, 0U, 0U, false}, {0U, 0U, 0U, 0U}};
static Brightness_st *const brightness_ps = &eeprom_buffer.brightness_values; static Brightness_st *const brightness_cpst = &eeprom_buffer_st.brightness_values;
static Color_st *const colors_ps = &eeprom_buffer.color_values; static Color_st *const colors_cpst = &eeprom_buffer_st.color_values;
static NightModeTimes_st *const night_mode_times_ps = &eeprom_buffer.night_mode_times; static NightModeTimes_st *const night_mode_times_cpst = &eeprom_buffer_st.night_mode_times;
// Games // Games
static Pong pong = Pong(&led_matrix, &logger); static Pong pong = Pong(&led_matrix, &logger);
@@ -98,7 +99,6 @@ static const uint32_t period_timings[NUM_STATES] = {PERIOD_TIME_UPDATE_US, PERIO
PERIOD_ANIMATION_US, PERIOD_TETRIS_US, PERIOD_SNAKE_US, PERIOD_ANIMATION_US, PERIOD_TETRIS_US, PERIOD_SNAKE_US,
PERIOD_PONG_US, PERIOD_ANIMATION_US}; PERIOD_PONG_US, PERIOD_ANIMATION_US};
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// SETUP // SETUP
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
@@ -118,6 +118,9 @@ void setup()
Serial.printf("Reset address: %u\n", reset_info->excvaddr); Serial.printf("Reset address: %u\n", reset_info->excvaddr);
Serial.println(); Serial.println();
// Init FastLED
FastLED.addLeds<WS2812B, FASTLED_PIN, COLOR_ORDER>(leds, NUM_MATRIX);
// Init EEPROM // Init EEPROM
EEPROM.begin(EEPROM_SIZE); EEPROM.begin(EEPROM_SIZE);
@@ -135,7 +138,7 @@ void setup()
led_matrix.set_current_limit(CURRENT_LIMIT_LED); led_matrix.set_current_limit(CURRENT_LIMIT_LED);
// Turn on minutes LEDs (blue) // Turn on minutes LEDs (blue)
led_matrix.set_min_indicator((uint8_t)0b1111, colors_24bit[6]); led_matrix.set_min_indicator(MIN_LEDS_PATTERN, colors_24bit[6]);
led_matrix.draw_on_matrix_instant(); led_matrix.draw_on_matrix_instant();
/* Use WiFiMaanger for handling initial Wifi setup */ /* Use WiFiMaanger for handling initial Wifi setup */
@@ -154,7 +157,7 @@ void setup()
WiFi.persistent(true); WiFi.persistent(true);
// Turn off minutes LEDs // Turn off minutes LEDs
led_matrix.set_min_indicator((uint8_t)0b1111, 0); led_matrix.set_min_indicator(MIN_LEDS_PATTERN, 0);
led_matrix.draw_on_matrix_instant(); led_matrix.draw_on_matrix_instant();
// init ESP8266 File manager (LittleFS) // init ESP8266 File manager (LittleFS)
@@ -234,7 +237,6 @@ void loop()
{ {
send_heartbeat(); // send heartbeat update send_heartbeat(); // send heartbeat update
last_heartbeat_us = system_get_time(); last_heartbeat_us = system_get_time();
delay(10);
} }
if (!flg_night_mode && ((current_time_us - last_animation_step_us) > period_timings[current_state]) && if (!flg_night_mode && ((current_time_us - last_animation_step_us) > period_timings[current_state]) &&
@@ -242,7 +244,6 @@ void loop()
{ {
handle_current_state(); // handle current state handle_current_state(); // handle current state
last_animation_step_us = system_get_time(); last_animation_step_us = system_get_time();
delay(10);
} }
if ((current_time_us - last_brightness_update_us) >= PERIOD_BRIGHTNESS_UPDATE_US) if ((current_time_us - last_brightness_update_us) >= PERIOD_BRIGHTNESS_UPDATE_US)
@@ -250,14 +251,12 @@ void loop()
current_brightness = update_brightness(); // update brightness current_brightness = update_brightness(); // update brightness
logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%"); logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%");
last_brightness_update_us = system_get_time(); last_brightness_update_us = system_get_time();
delay(10);
} }
if ((current_time_us - last_matrix_update_us) >= PERIOD_MATRIX_UPDATE_US) if ((current_time_us - last_matrix_update_us) >= PERIOD_MATRIX_UPDATE_US)
{ {
update_matrix(); // update matrix update_matrix(); // update matrix
last_matrix_update_us = system_get_time(); last_matrix_update_us = system_get_time();
delay(10);
} }
if ((current_time_us - last_time_update_us) >= PERIOD_TIME_UPDATE_US) if ((current_time_us - last_time_update_us) >= PERIOD_TIME_UPDATE_US)
@@ -296,8 +295,8 @@ void log_data()
logger.log_string("IP: " + WiFi.localIP().toString()); logger.log_string("IP: " + WiFi.localIP().toString());
logger.log_string("Reset Reason: " + ESP.getResetReason()); logger.log_string("Reset Reason: " + ESP.getResetReason());
logger.log_string("Nightmode starts at: " + String(night_mode_times_ps->start_hour) + ":" + String(night_mode_times_ps->start_min)); logger.log_string("Nightmode starts at: " + String(night_mode_times_cpst->start_hour) + ":" + String(night_mode_times_cpst->start_min));
logger.log_string("Nightmode ends at: " + String(night_mode_times_ps->end_hour) + ":" + String(night_mode_times_ps->end_min)); logger.log_string("Nightmode ends at: " + String(night_mode_times_cpst->end_hour) + ":" + String(night_mode_times_cpst->end_min));
logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%\n"); logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%\n");
} }
@@ -364,7 +363,7 @@ void handle_current_state()
// clear matrix // clear matrix
led_matrix.flush(); led_matrix.flush();
// Turn on minutes LEDs (blue) // Turn on minutes LEDs (blue)
led_matrix.set_min_indicator((uint8_t)0b1111, colors_24bit[6]); led_matrix.set_min_indicator((uint8_t)MIN_LEDS_PATTERN, colors_24bit[6]);
led_matrix.draw_on_matrix_instant(); led_matrix.draw_on_matrix_instant();
} }
break; break;
@@ -380,7 +379,7 @@ void handle_current_state()
// clear matrix // clear matrix
led_matrix.flush(); led_matrix.flush();
// Turn on minutes LEDs (blue) // Turn on minutes LEDs (blue)
led_matrix.set_min_indicator((uint8_t)0b1111, colors_24bit[6]); led_matrix.set_min_indicator((uint8_t)MIN_LEDS_PATTERN, colors_24bit[6]);
led_matrix.draw_on_matrix_instant(); led_matrix.draw_on_matrix_instant();
} }
break; break;
@@ -483,11 +482,11 @@ void check_night_mode()
int hours = tm_mgr.hour(); int hours = tm_mgr.hour();
int minutes = tm_mgr.minute(); int minutes = tm_mgr.minute();
if ((hours == night_mode_times_ps->start_hour) && (minutes == night_mode_times_ps->start_min)) if ((hours == night_mode_times_cpst->start_hour) && (minutes == night_mode_times_cpst->start_min))
{ {
set_night_mode(true); set_night_mode(true);
} }
else if ((hours == night_mode_times_ps->end_hour) && (minutes == night_mode_times_ps->end_min)) else if ((hours == night_mode_times_cpst->end_hour) && (minutes == night_mode_times_cpst->end_min))
{ {
set_night_mode(false); set_night_mode(false);
} }
@@ -658,9 +657,9 @@ void set_main_color(uint8_t red, uint8_t green, uint8_t blue)
main_color_clock = LEDMatrix::color_24bit(red, green, blue); main_color_clock = LEDMatrix::color_24bit(red, green, blue);
// Update colors and save color settings to EEPROM // Update colors and save color settings to EEPROM
colors_ps->blue = blue; colors_cpst->blue = blue;
colors_ps->red = red; colors_cpst->red = red;
colors_ps->green = green; colors_cpst->green = green;
write_settings_to_EEPROM(); write_settings_to_EEPROM();
} }
@@ -671,9 +670,9 @@ void set_main_color(uint8_t red, uint8_t green, uint8_t blue)
void draw_main_color() void draw_main_color()
{ {
uint8_t red = colors_ps->red; uint8_t red = colors_cpst->red;
uint8_t green = colors_ps->green; uint8_t green = colors_cpst->green;
uint8_t blue = colors_ps->blue; uint8_t blue = colors_cpst->blue;
if ((int(red) + int(green) + int(blue)) < 50) if ((int(red) + int(green) + int(blue)) < 50)
{ {
@@ -691,13 +690,16 @@ void draw_main_color()
*/ */
void handle_command() void handle_command()
{ {
bool send204 = true; // flag to send 204 response
// receive command and handle accordingly // receive command and handle accordingly
#ifdef SERIAL_DEBUG
for (uint8_t i = 0; i < webserver.args(); i++) for (uint8_t i = 0; i < webserver.args(); i++)
{ {
Serial.print(webserver.argName(i)); Serial.print(webserver.argName(i));
Serial.print(F(": ")); Serial.print(F(": "));
Serial.println(webserver.arg(i)); Serial.println(webserver.arg(i));
} }
#endif /* SERIAL_DEBUG */
if (webserver.argName(0).equals("led")) // the parameter which was sent to this server is led color if (webserver.argName(0).equals("led")) // the parameter which was sent to this server is led color
{ {
@@ -767,14 +769,14 @@ void handle_command()
{ {
String cmd_str = webserver.arg(0) + "-"; String cmd_str = webserver.arg(0) + "-";
logger.log_string("Nightmode setting change via Webserver to: " + cmd_str); logger.log_string("Nightmode setting change via Webserver to: " + cmd_str);
night_mode_times_ps->start_hour = (int)split(cmd_str, '-', 0).toInt(); night_mode_times_cpst->start_hour = (int)split(cmd_str, '-', 0).toInt();
night_mode_times_ps->start_min = (int)split(cmd_str, '-', 1).toInt(); night_mode_times_cpst->start_min = (int)split(cmd_str, '-', 1).toInt();
night_mode_times_ps->end_hour = (int)split(cmd_str, '-', 2).toInt(); night_mode_times_cpst->end_hour = (int)split(cmd_str, '-', 2).toInt();
night_mode_times_ps->end_min = (int)split(cmd_str, '-', 3).toInt(); night_mode_times_cpst->end_min = (int)split(cmd_str, '-', 3).toInt();
brightness_ps->static_brightness = (uint8_t)split(cmd_str, '-', 4).toInt(); brightness_cpst->static_brightness = (uint8_t)split(cmd_str, '-', 4).toInt();
flg_reset_wifi_creds = split(cmd_str, '-', 5).toInt() > 0 ? true : false; flg_reset_wifi_creds = split(cmd_str, '-', 5).toInt() > 0 ? true : false;
brightness_ps->dyn_brightness_min = (uint8_t)split(cmd_str, '-', 6).toInt(); brightness_cpst->dyn_brightness_min = (uint8_t)split(cmd_str, '-', 6).toInt();
brightness_ps->dyn_brightness_max = (uint8_t)split(cmd_str, '-', 7).toInt(); brightness_cpst->dyn_brightness_max = (uint8_t)split(cmd_str, '-', 7).toInt();
if (flg_reset_wifi_creds == true) if (flg_reset_wifi_creds == true)
{ {
@@ -786,9 +788,9 @@ void handle_command()
// Update EEPROM with new settings // Update EEPROM with new settings
write_settings_to_EEPROM(); write_settings_to_EEPROM();
logger.log_string("Nightmode starts at: " + String(night_mode_times_ps->start_hour) + ":" + String(night_mode_times_ps->start_min)); logger.log_string("Nightmode starts at: " + String(night_mode_times_cpst->start_hour) + ":" + String(night_mode_times_cpst->start_min));
delay(10); delay(10);
logger.log_string("Nightmode ends at: " + String(night_mode_times_ps->end_hour) + ":" + String(night_mode_times_ps->end_min)); logger.log_string("Nightmode ends at: " + String(night_mode_times_cpst->end_hour) + ":" + String(night_mode_times_cpst->end_min));
delay(10); delay(10);
// Update brightness // Update brightness
@@ -798,7 +800,6 @@ void handle_command()
else if (webserver.argName(0).equals("tetris")) else if (webserver.argName(0).equals("tetris"))
{ {
String cmd_str = webserver.arg(0); String cmd_str = webserver.arg(0);
// logger.log_string("Tetris cmd via Webserver to: " + cmd_str);
if (cmd_str.equals("up")) if (cmd_str.equals("up"))
{ {
tetris.ctrlUp(); tetris.ctrlUp();
@@ -827,7 +828,6 @@ void handle_command()
else if (webserver.argName(0).equals("snake")) else if (webserver.argName(0).equals("snake"))
{ {
String cmd_str = webserver.arg(0); String cmd_str = webserver.arg(0);
// logger.log_string("Snake cmd via Webserver to: " + cmd_str);
if (cmd_str.equals("up")) if (cmd_str.equals("up"))
{ {
snake.ctrlUp(); snake.ctrlUp();
@@ -852,7 +852,6 @@ void handle_command()
else if (webserver.argName(0).equals("pong")) else if (webserver.argName(0).equals("pong"))
{ {
String cmd_str = webserver.arg(0); String cmd_str = webserver.arg(0);
// logger.log_string("Pong cmd via Webserver to: " + cmd_str);
if (cmd_str.equals("up")) if (cmd_str.equals("up"))
{ {
pong.ctrlUp(1); pong.ctrlUp(1);
@@ -866,8 +865,18 @@ void handle_command()
pong.initGame(1); pong.initGame(1);
} }
} }
else if (webserver.argName(0).equals("diag"))
{
String cmd_str = webserver.arg(0);
Diagnosis diag(&logger, &led_matrix);
webserver.send(200, "text/plain", diag.handle_command(cmd_str));
send204 = false;
}
if (send204)
{
webserver.send(204, "text/plain", "No Content"); // this page doesn't send back content --> 204 webserver.send(204, "text/plain", "No Content"); // this page doesn't send back content --> 204
}
} }
/** /**
@@ -876,6 +885,7 @@ void handle_command()
*/ */
void handle_data_request() void handle_data_request()
{ {
#ifdef SERIAL_DEBUG
// receive data request and handle accordingly // receive data request and handle accordingly
for (uint8_t i = 0; i < webserver.args(); i++) for (uint8_t i = 0; i < webserver.args(); i++)
{ {
@@ -883,7 +893,7 @@ void handle_data_request()
Serial.print(F(": ")); Serial.print(F(": "));
Serial.println(webserver.arg(i)); Serial.println(webserver.arg(i));
} }
#endif /* SERIAL_DEBUG */
if (webserver.argName(0).equals("key")) if (webserver.argName(0).equals("key"))
{ {
String message = "{"; String message = "{";
@@ -896,17 +906,17 @@ void handle_data_request()
message += ","; message += ",";
message += "\"night_mode\":\"" + String(flg_night_mode) + "\""; message += "\"night_mode\":\"" + String(flg_night_mode) + "\"";
message += ","; message += ",";
message += "\"nightModeStart\":\"" + leading_zero2digit(night_mode_times_ps->start_hour) + "-" + leading_zero2digit(night_mode_times_ps->start_min) + "\""; message += "\"nightModeStart\":\"" + leading_zero2digit(night_mode_times_cpst->start_hour) + "-" + leading_zero2digit(night_mode_times_cpst->start_min) + "\"";
message += ","; message += ",";
message += "\"nightModeEnd\":\"" + leading_zero2digit(night_mode_times_ps->end_hour) + "-" + leading_zero2digit(night_mode_times_ps->end_min) + "\""; message += "\"nightModeEnd\":\"" + leading_zero2digit(night_mode_times_cpst->end_hour) + "-" + leading_zero2digit(night_mode_times_cpst->end_min) + "\"";
message += ","; message += ",";
message += "\"static_brightness\":\"" + String(brightness_ps->static_brightness) + "\""; message += "\"static_brightness\":\"" + String(brightness_cpst->static_brightness) + "\"";
message += ","; message += ",";
message += "\"dyn_brightness\":\"" + String(brightness_ps->flg_dynamic_brightness) + "\""; message += "\"dyn_brightness\":\"" + String(brightness_cpst->flg_dynamic_brightness) + "\"";
message += ","; message += ",";
message += "\"min_brightness\":\"" + String(brightness_ps->dyn_brightness_min) + "\""; message += "\"min_brightness\":\"" + String(brightness_cpst->dyn_brightness_min) + "\"";
message += ","; message += ",";
message += "\"max_brightness\":\"" + String(brightness_ps->dyn_brightness_max) + "\""; message += "\"max_brightness\":\"" + String(brightness_cpst->dyn_brightness_max) + "\"";
} }
message += "}"; message += "}";
webserver.send(200, "application/json", message); webserver.send(200, "application/json", message);
@@ -932,7 +942,7 @@ void set_night_mode(bool state)
*/ */
void set_dynamic_brightness(bool state) void set_dynamic_brightness(bool state)
{ {
brightness_ps->flg_dynamic_brightness = state; brightness_cpst->flg_dynamic_brightness = state;
} }
/** /**
@@ -1002,7 +1012,7 @@ uint8_t calculate_dynamic_brightness(uint8_t min_brightness, uint8_t max_brightn
*/ */
void read_settings_from_EEPROM() void read_settings_from_EEPROM()
{ {
EEPROM.get(0, eeprom_buffer); EEPROM.get(0, eeprom_buffer_st);
} }
/** /**
@@ -1013,7 +1023,7 @@ void read_settings_from_EEPROM()
void write_settings_to_EEPROM() void write_settings_to_EEPROM()
{ {
// Copy EEPROM buffer // Copy EEPROM buffer
EEPROM.put(0, eeprom_buffer); EEPROM.put(0, eeprom_buffer_st);
// Commit changes // Commit changes
EEPROM.commit(); EEPROM.commit();
} }
@@ -1027,17 +1037,17 @@ uint8_t update_brightness()
{ {
uint8_t new_brightness = 0; uint8_t new_brightness = 0;
if (brightness_ps->flg_dynamic_brightness == true) if (brightness_cpst->flg_dynamic_brightness == true)
{ {
new_brightness = calculate_dynamic_brightness(brightness_ps->dyn_brightness_min, new_brightness = calculate_dynamic_brightness(brightness_cpst->dyn_brightness_min,
brightness_ps->dyn_brightness_max, brightness_cpst->dyn_brightness_max,
tm_mgr.hour(), tm_mgr.hour(),
tm_mgr.minute(), tm_mgr.minute(),
tm_mgr.isdst()); tm_mgr.isdst());
} }
else // use static brightness else // use static brightness
{ {
new_brightness = brightness_ps->static_brightness; new_brightness = brightness_cpst->static_brightness;
} }
// now set new brightness // now set new brightness
led_matrix.set_brightness(new_brightness); led_matrix.set_brightness(new_brightness);
@@ -1053,29 +1063,29 @@ uint8_t update_brightness()
void limit_value_ranges() void limit_value_ranges()
{ {
// Range limits // Range limits
brightness_ps->dyn_brightness_min = RANGE_LIMIT(brightness_ps->dyn_brightness_min, brightness_cpst->dyn_brightness_min = RANGE_LIMIT(brightness_cpst->dyn_brightness_min,
MIN_BRIGHTNESS, MIN_BRIGHTNESS,
brightness_ps->dyn_brightness_max - 1); // minimum brightness brightness_cpst->dyn_brightness_max - 1); // minimum brightness
brightness_ps->dyn_brightness_max = RANGE_LIMIT(brightness_ps->dyn_brightness_max, brightness_cpst->dyn_brightness_max = RANGE_LIMIT(brightness_cpst->dyn_brightness_max,
brightness_ps->dyn_brightness_min + 1, brightness_cpst->dyn_brightness_min + 1,
MAX_BRIGHTNESS); // maximum brightness MAX_BRIGHTNESS); // maximum brightness
brightness_ps->static_brightness = RANGE_LIMIT(brightness_ps->static_brightness, brightness_cpst->static_brightness = RANGE_LIMIT(brightness_cpst->static_brightness,
MIN_BRIGHTNESS, MIN_BRIGHTNESS,
MAX_BRIGHTNESS); // static brightness MAX_BRIGHTNESS); // static brightness
night_mode_times_ps->start_hour = RANGE_LIMIT_SUB(night_mode_times_ps->start_hour, night_mode_times_cpst->start_hour = RANGE_LIMIT_SUB(night_mode_times_cpst->start_hour,
0, 0,
HOUR_MAX, HOUR_MAX,
NIGHTMODE_START_HR); NIGHTMODE_START_HR);
night_mode_times_ps->start_min = RANGE_LIMIT_SUB(night_mode_times_ps->start_min, night_mode_times_cpst->start_min = RANGE_LIMIT_SUB(night_mode_times_cpst->start_min,
0, 0,
MINUTE_MAX, MINUTE_MAX,
NIGHTMODE_START_MIN); NIGHTMODE_START_MIN);
night_mode_times_ps->end_hour = RANGE_LIMIT_SUB(night_mode_times_ps->end_hour, night_mode_times_cpst->end_hour = RANGE_LIMIT_SUB(night_mode_times_cpst->end_hour,
0, 0,
HOUR_MAX, HOUR_MAX,
NIGHTMODE_END_HR); NIGHTMODE_END_HR);
night_mode_times_ps->end_min = RANGE_LIMIT_SUB(night_mode_times_ps->end_min, night_mode_times_cpst->end_min = RANGE_LIMIT_SUB(night_mode_times_cpst->end_min,
0, 0,
MINUTE_MAX, MINUTE_MAX,
NIGHTMODE_END_MIN); NIGHTMODE_END_MIN);