Major refactoring of EEPROM r/w. Add dynamic brightness functionality.
This commit is contained in:
@@ -34,81 +34,68 @@
|
||||
|
||||
// own libraries
|
||||
#include "animation_functions.h"
|
||||
#include "pong.h"
|
||||
#include "snake.h"
|
||||
#include "tetris.h"
|
||||
#include "base64_wrapper.h" // copied from https://github.com/Xander-Electronics/Base64
|
||||
#include "led_matrix.h"
|
||||
#include "littlefs_wrapper.h"
|
||||
#include "base64_wrapper.h" // copied from https://github.com/Xander-Electronics/Base64
|
||||
#include "ntp_client_plus.h"
|
||||
#include "ota_functions.h"
|
||||
#include "pong.h"
|
||||
#include "render_functions.h"
|
||||
#include "snake.h"
|
||||
#include "tetris.h"
|
||||
#include "udp_logger.h"
|
||||
#include "wordclock_constants.h"
|
||||
#include "render_functions.h"
|
||||
|
||||
const String state_names[] = {"Clock", "DiClock", "Spiral", "Tetris", "Snake", "PingPong", "Hearts"};
|
||||
// PERIODS for each state (different for stateAutoChange or Manual mode)
|
||||
const uint32_t PERIODS[2][NUM_STATES] = {{PERIOD_TIME_VISU_UPDATE_US, // stateAutoChange = 0
|
||||
PERIOD_TIME_VISU_UPDATE_US,
|
||||
PERIOD_ANIMATION_US,
|
||||
PERIOD_TETRIS_US,
|
||||
PERIOD_SNAKE_US,
|
||||
PERIOD_PONG_US,
|
||||
PERIOD_ANIMATION_US},
|
||||
{PERIOD_TIME_VISU_UPDATE_US, // stateAutoChange = 1
|
||||
PERIOD_TIME_VISU_UPDATE_US,
|
||||
PERIOD_ANIMATION_US,
|
||||
PERIOD_ANIMATION_US,
|
||||
PERIOD_ANIMATION_US,
|
||||
PERIOD_PONG_US,
|
||||
PERIOD_ANIMATION_US}};
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// GLOBAL VARIABLES
|
||||
// GLOBAL VARIABLES
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
// Webserver
|
||||
ESP8266WebServer webserver(HTTP_PORT);
|
||||
|
||||
// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
|
||||
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
|
||||
// example for more information on possible values.
|
||||
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(MATRIX_WIDTH, MATRIX_HEIGHT + 1, NEOPIXEL_PIN,
|
||||
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG,
|
||||
NEO_GRB + NEO_KHZ800);
|
||||
NEO_GRB + NEO_KHZ800); // NeoMatrix
|
||||
UDPLogger logger; // Logger
|
||||
ESP8266WebServer webserver(HTTP_PORT); // Webserver
|
||||
LEDMatrix led_matrix = LEDMatrix(&matrix, DEFAULT_BRIGHTNESS, &logger); // NeoMatrix wrapper
|
||||
WiFiUDP wifi_udp;
|
||||
NTPClientPlus ntp_client = NTPClientPlus(wifi_udp, NTP_SERVER_URL, 1, true);
|
||||
|
||||
// Globals
|
||||
uint8_t brightness = 40; // current brightness of LEDs
|
||||
LEDMatrix led_matrix = LEDMatrix(&matrix, brightness, &logger);
|
||||
UDPLogger logger;
|
||||
// ----------------------------------------------------------------------------------
|
||||
// STATIC VARIABLES
|
||||
// ----------------------------------------------------------------------------------
|
||||
static EepromLayout_st eeprom_buffer = {{0, 0, 0, 0}, {0U, 0U, 0U, false}, {0U, 0U, 0U, 0U}};
|
||||
static Brightness_st *brightness_ps = &eeprom_buffer.brightness_values;
|
||||
static Color_st *colors_ps = &eeprom_buffer.color_values;
|
||||
static NightModeTimes_st *night_mode_times_ps = &eeprom_buffer.night_mode_times;
|
||||
|
||||
// Statics
|
||||
static bool spiral_direction = false;
|
||||
static uint32 last_led_direct_us = 0; // time of last direct LED command (=> fall back to normal mode after timeout)
|
||||
|
||||
static WiFiUDP wifi_udp;
|
||||
static NTPClientPlus ntp_client = NTPClientPlus(wifi_udp, NTP_SERVER_URL, 1, true);
|
||||
static Pong pong = Pong(&led_matrix, &logger);
|
||||
static Snake snake = Snake(&led_matrix, &logger);
|
||||
static Tetris tetris = Tetris(&led_matrix, &logger);
|
||||
|
||||
static bool night_mode = false; // stores state of nightmode
|
||||
static bool state_auto_change = false; // stores state of automatic state change
|
||||
static bool reset_wifi_creds = false; // used to reset stored wifi credentials
|
||||
static float filter_factor = DEFAULT_SMOOTHING_FACTOR; // stores smoothing factor for led transition
|
||||
static uint32_t main_color_clock = colors_24bit[2]; // color of the clock and digital clock
|
||||
static uint32_t main_color_snake = colors_24bit[1]; // color of the random snake animation
|
||||
static uint8_t current_state = (uint8_t)ST_CLOCK; // stores current state
|
||||
static int watchdog_counter = 30; // Watchdog counter to trigger restart if NTP update was not possible 30 times in a row (5min)
|
||||
static bool flg_night_mode = false; // state of nightmode
|
||||
static bool flg_reset_wifi_creds = false; // used to reset stored wifi credentials
|
||||
static bool spiral_direction = false;
|
||||
static float filter_factor = DEFAULT_SMOOTHING_FACTOR; // stores smoothing factor for led transition
|
||||
static int watchdog_counter = 30; // Watchdog counter to trigger restart if NTP update was not possible 30 times in a row (5min)
|
||||
static uint32 last_led_direct_us = 0; // time of last direct LED command (=> fall back to normal mode after timeout)
|
||||
static uint32_t heartbeat_counter = 0; // for heartbeat on-time in seconds
|
||||
static uint32_t main_color_clock = colors_24bit[2]; // color of the clock and digital clock
|
||||
static uint32_t main_color_snake = colors_24bit[1]; // color of the random snake animation
|
||||
static uint8_t current_brightness = DEFAULT_BRIGHTNESS; // current brightness of LEDs
|
||||
static uint8_t current_state = (uint8_t)ST_CLOCK; // stores current state
|
||||
|
||||
// Nightmode time settings
|
||||
NightModeTimes_st night_mode_times = {
|
||||
NIGHTMODE_START_HR,
|
||||
NIGHTMODE_START_MIN,
|
||||
NIGHTMODE_END_HR,
|
||||
NIGHTMODE_END_MIN};
|
||||
static const String state_names[NUM_STATES] = {"Clock", "DiClock", "Spiral", "Tetris", "Snake", "PingPong", "Hearts"};
|
||||
static const uint32_t period_timings[NUM_STATES] = {PERIOD_CLOCK_UPDATE_US, PERIOD_CLOCK_UPDATE_US,
|
||||
PERIOD_ANIMATION_US, PERIOD_TETRIS_US, PERIOD_SNAKE_US,
|
||||
PERIOD_PONG_US, PERIOD_ANIMATION_US};
|
||||
|
||||
uint32_t heartbeat_counter = 0; // for heartbeat on-time in seconds
|
||||
// Quarterly brightness factor for dynamic brightness
|
||||
static const float qtly_brightness_factor[96] = {
|
||||
0.0f, 0.0f, 0.0f, 0.001f, 0.003f, 0.007f, 0.014f, 0.026f, 0.044f, 0.069f, 0.101f, 0.143f, 0.194f, 0.253f, 0.32f,
|
||||
0.392f, 0.468f, 0.545f, 0.62f, 0.691f, 0.755f, 0.811f, 0.858f, 0.896f, 0.927f, 0.949f, 0.966f, 0.978f, 0.986f,
|
||||
0.991f, 0.995f, 0.997f, 0.998f, 0.999f, 0.999f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.999f, 0.999f,
|
||||
0.998f, 0.997f, 0.995f, 0.991f, 0.986f, 0.978f, 0.966f, 0.949f, 0.927f, 0.896f, 0.858f, 0.811f, 0.755f, 0.691f,
|
||||
0.62f, 0.545f, 0.468f, 0.392f, 0.32f, 0.253f, 0.194f, 0.143f, 0.101f, 0.069f, 0.044f, 0.026f, 0.014f, 0.007f,
|
||||
0.003f, 0.001f, 0.0f, 0.0f};
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// SETUP
|
||||
@@ -132,8 +119,11 @@ void setup()
|
||||
// Init EEPROM
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
|
||||
// Load color for clock from EEPROM
|
||||
load_main_color();
|
||||
// Read global settings from EEPROM
|
||||
read_settings_from_EEPROM();
|
||||
|
||||
// draw color on clock
|
||||
draw_main_color();
|
||||
|
||||
// configure button pin as input
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP);
|
||||
@@ -147,7 +137,7 @@ void setup()
|
||||
led_matrix.draw_on_matrix_instant();
|
||||
|
||||
/* Use WiFiMaanger for handling initial Wifi setup */
|
||||
WiFiManager wifi_manager; // Local intialization. Once its business is done, there is no need to keep it around
|
||||
WiFiManager wifi_manager; // Local initialization. Once its business is done, there is no need to keep it around
|
||||
|
||||
/* fetches ssid and pass from eeprom and tries to connect. if it does not connect it starts an access point with
|
||||
* the specified name and goes into a blocking loop awaiting configuration. */
|
||||
@@ -189,7 +179,7 @@ void setup()
|
||||
|
||||
if (resetInfo->reason != REASON_SOFT_RESTART)
|
||||
{
|
||||
// test quickly each LED
|
||||
// quickly test each LED
|
||||
for (int16_t row = 0; row < MATRIX_HEIGHT; row++)
|
||||
{
|
||||
for (int16_t col = 0; col < MATRIX_WIDTH; col++)
|
||||
@@ -243,40 +233,15 @@ void setup()
|
||||
// init random tetris
|
||||
random_tetris(true);
|
||||
|
||||
// Read nightmode setting from EEPROM
|
||||
night_mode_times.start_hour = EEPROM_read_address(ADR_NM_START_H);
|
||||
night_mode_times.start_min = EEPROM_read_address(ADR_NM_START_M);
|
||||
night_mode_times.end_hour = EEPROM_read_address(ADR_NM_END_H);
|
||||
night_mode_times.end_min = EEPROM_read_address(ADR_NM_END_M);
|
||||
// Range limits
|
||||
limit_value_ranges();
|
||||
|
||||
if (night_mode_times.start_hour < 0 || night_mode_times.start_hour > 23)
|
||||
{
|
||||
night_mode_times.start_hour = NIGHTMODE_START_HR;
|
||||
}
|
||||
if (night_mode_times.start_min < 0 || night_mode_times.start_min > 59)
|
||||
{
|
||||
night_mode_times.start_min = NIGHTMODE_START_MIN;
|
||||
}
|
||||
if (night_mode_times.end_hour < 0 || night_mode_times.end_hour > 23)
|
||||
{
|
||||
night_mode_times.end_hour = NIGHTMODE_END_HR;
|
||||
}
|
||||
if (night_mode_times.end_min < 0 || night_mode_times.end_min > 59)
|
||||
{
|
||||
night_mode_times.end_min = NIGHTMODE_END_MIN;
|
||||
}
|
||||
logger.log_string("Nightmode starts at: " + String(night_mode_times_ps->start_hour) + ":" + String(night_mode_times_ps->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 starts at: " + String(night_mode_times.start_hour) + ":" + String(night_mode_times.start_min));
|
||||
logger.log_string("Nightmode ends at: " + String(night_mode_times.end_hour) + ":" + String(night_mode_times.end_min));
|
||||
|
||||
// Read brightness setting from EEPROM, lower limit is 10 so that the LEDs are not completely off
|
||||
brightness = EEPROM_read_address(ADR_BRIGHTNESS);
|
||||
if (brightness < 10)
|
||||
{
|
||||
brightness = 10;
|
||||
}
|
||||
logger.log_string("Brightness: " + String(brightness));
|
||||
led_matrix.set_brightness(brightness);
|
||||
// Update brightness
|
||||
current_brightness = update_brightness();
|
||||
logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
@@ -292,7 +257,6 @@ void loop()
|
||||
static uint32 last_heartbeat_us = 0; // time of last heartbeat sending
|
||||
static uint32 last_nightmode_check_us = 0; // time of last nightmode check
|
||||
static uint32 last_ntp_update_us = 0; // time of last NTP update
|
||||
static uint32 last_state_change_us = 0; // time of last state change
|
||||
|
||||
handleOTA(); // handle OTA
|
||||
|
||||
@@ -306,7 +270,8 @@ void loop()
|
||||
delay(10);
|
||||
}
|
||||
|
||||
if (!night_mode && ((current_time_us - last_animation_step_us) > PERIODS[state_auto_change][current_state]) && ((current_time_us - last_led_direct_us) > TIMEOUT_LEDDIRECT_US))
|
||||
if (!flg_night_mode && ((current_time_us - last_animation_step_us) > period_timings[current_state]) &&
|
||||
((current_time_us - last_led_direct_us) > TIMEOUT_LEDDIRECT_US))
|
||||
{
|
||||
handle_current_state(); // handle current state
|
||||
last_animation_step_us = system_get_time();
|
||||
@@ -322,18 +287,18 @@ void loop()
|
||||
|
||||
handle_button(); // handle button press
|
||||
|
||||
if (state_auto_change && !night_mode && ((current_time_us - last_state_change_us) > PERIOD_STATE_CHANGE_US)) // this feature could be removed...
|
||||
{
|
||||
update_state_machine(); // handle state changes
|
||||
last_state_change_us = system_get_time();
|
||||
}
|
||||
|
||||
if ((current_time_us - last_ntp_update_us) > PERIOD_NTP_UPDATE_US)
|
||||
{
|
||||
check_wifi_status(); // check WiFi status before NTP update
|
||||
delay(10);
|
||||
|
||||
ntp_time_update(&last_ntp_update_us); // ntp time update
|
||||
ntp_time_update(&last_ntp_update_us); // NTP time update
|
||||
delay(10);
|
||||
|
||||
current_brightness = update_brightness(); // update brightness every PERIOD_NTP_UPDATE_US
|
||||
delay(10);
|
||||
|
||||
logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%");
|
||||
delay(10);
|
||||
}
|
||||
|
||||
@@ -345,15 +310,9 @@ void loop()
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// OTHER FUNCTIONS
|
||||
// OTHER FUNCTIONS
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
void update_state_machine()
|
||||
{
|
||||
// increment state variable and trigger state change
|
||||
state_change((current_state + 1) % (uint8_t)NUM_STATES);
|
||||
}
|
||||
|
||||
void handle_current_state()
|
||||
{
|
||||
switch (current_state)
|
||||
@@ -376,50 +335,31 @@ void handle_current_state()
|
||||
}
|
||||
case ST_SPIRAL: // state spiral
|
||||
{
|
||||
int res = draw_spiral(false, spiral_direction, MATRIX_WIDTH - 6);
|
||||
int res = draw_spiral(false, spiral_direction, MATRIX_WIDTH - 1);
|
||||
if (res && spiral_direction == 0)
|
||||
{
|
||||
// change spiral direction to closing (draw empty leds)
|
||||
spiral_direction = 1;
|
||||
// init spiral with new spiral direction
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 6);
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
|
||||
}
|
||||
else if (res && spiral_direction == 1)
|
||||
{
|
||||
// reset spiral direction to normal drawing leds
|
||||
spiral_direction = 0;
|
||||
// init spiral with new spiral direction
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 6);
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ST_TETRIS: // state tetris
|
||||
{
|
||||
if (state_auto_change)
|
||||
{
|
||||
random_tetris(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
tetris.loopCycle();
|
||||
}
|
||||
tetris.loopCycle();
|
||||
break;
|
||||
}
|
||||
case ST_SNAKE: // state snake
|
||||
{
|
||||
if (state_auto_change)
|
||||
{
|
||||
led_matrix.flush();
|
||||
if (random_snake(false, 8, main_color_snake, -1))
|
||||
{
|
||||
// init snake for next run
|
||||
random_snake(true, 8, main_color_snake, -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
snake.loopCycle();
|
||||
}
|
||||
snake.loopCycle();
|
||||
break;
|
||||
}
|
||||
case ST_PINGPONG: // state ping pong
|
||||
@@ -487,11 +427,11 @@ void check_night_mode()
|
||||
int hours = ntp_client.get_hours_24();
|
||||
int minutes = ntp_client.get_minutes();
|
||||
|
||||
if (hours == night_mode_times.start_hour && minutes == night_mode_times.start_min)
|
||||
if ((hours == night_mode_times_ps->start_hour) && (minutes == night_mode_times_ps->start_min))
|
||||
{
|
||||
set_night_mode(true);
|
||||
}
|
||||
else if (hours == night_mode_times.end_hour && minutes == night_mode_times.end_min)
|
||||
else if ((hours == night_mode_times_ps->end_hour) && (minutes == night_mode_times_ps->end_min))
|
||||
{
|
||||
set_night_mode(false);
|
||||
}
|
||||
@@ -530,7 +470,7 @@ void ntp_time_update(uint32 *last_ntp_update_us)
|
||||
logger.log_string("Time: " + ntp_client.get_formatted_time());
|
||||
logger.log_string("Date: " + ntp_client.get_formatted_date());
|
||||
logger.log_string("TimeOffset (seconds): " + String(ntp_client.get_time_offset()));
|
||||
logger.log_string("Summertime: " + String(ntp_client.update_sw_change()));
|
||||
logger.log_string("Summertime: " + String(ntp_client.check_daylight_saving_time()));
|
||||
*last_ntp_update_us += 10000000;
|
||||
watchdog_counter--;
|
||||
break;
|
||||
@@ -561,52 +501,31 @@ void ntp_time_update(uint32 *last_ntp_update_us)
|
||||
*/
|
||||
void on_state_entry(uint8_t state)
|
||||
{
|
||||
filter_factor = 0.5;
|
||||
filter_factor = 0.5f;
|
||||
switch (state)
|
||||
{
|
||||
case ST_SPIRAL:
|
||||
{ // Init spiral with normal drawing mode
|
||||
spiral_direction = 0;
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 6);
|
||||
{
|
||||
spiral_direction = 0; // Init spiral with normal drawing mode
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
|
||||
break;
|
||||
}
|
||||
case ST_TETRIS:
|
||||
{
|
||||
filter_factor = 1.0; // no smoothing
|
||||
if (state_auto_change)
|
||||
{
|
||||
random_tetris(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
tetris.ctrlStart();
|
||||
}
|
||||
filter_factor = 1.0f; // no smoothing
|
||||
tetris.ctrlStart();
|
||||
break;
|
||||
}
|
||||
case ST_SNAKE:
|
||||
{
|
||||
if (state_auto_change)
|
||||
{
|
||||
random_snake(true, 8, colors_24bit[1], -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
filter_factor = 1.0; // no smoothing
|
||||
snake.initGame();
|
||||
}
|
||||
filter_factor = 1.0f; // no smoothing
|
||||
snake.initGame();
|
||||
break;
|
||||
}
|
||||
case ST_PINGPONG:
|
||||
{
|
||||
if (state_auto_change)
|
||||
{
|
||||
pong.initGame(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
filter_factor = 1.0; // no smoothing
|
||||
pong.initGame(1);
|
||||
}
|
||||
filter_factor = 1.0f; // no smoothing
|
||||
pong.initGame(1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -623,7 +542,7 @@ void on_state_entry(uint8_t state)
|
||||
*/
|
||||
void state_change(uint8_t newState)
|
||||
{
|
||||
if (night_mode)
|
||||
if (flg_night_mode)
|
||||
{
|
||||
set_night_mode(false); // deactivate Nightmode
|
||||
}
|
||||
@@ -632,7 +551,6 @@ void state_change(uint8_t newState)
|
||||
current_state = newState; // set new state
|
||||
on_state_entry(current_state);
|
||||
logger.log_string("State change to: " + state_names[current_state]);
|
||||
delay(5);
|
||||
logger.log_string("FreeMemory=" + String(ESP.getFreeHeap()));
|
||||
}
|
||||
|
||||
@@ -719,7 +637,7 @@ void handle_button()
|
||||
// shortpress -> state change
|
||||
logger.log_string("Button press ended - short press");
|
||||
|
||||
if (night_mode)
|
||||
if (flg_night_mode)
|
||||
{
|
||||
set_night_mode(false);
|
||||
}
|
||||
@@ -740,10 +658,12 @@ void handle_button()
|
||||
void set_main_color(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
main_color_clock = LEDMatrix::color_24bit(red, green, blue);
|
||||
EEPROM.put(ADR_MC_RED, red);
|
||||
EEPROM.put(ADR_MC_GREEN, green);
|
||||
EEPROM.put(ADR_MC_BLUE, blue);
|
||||
EEPROM.commit();
|
||||
colors_ps->blue = blue;
|
||||
colors_ps->red = red;
|
||||
colors_ps->green = green;
|
||||
|
||||
// save color settings to EEPROM
|
||||
write_settings_to_EEPROM();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -751,11 +671,11 @@ void set_main_color(uint8_t red, uint8_t green, uint8_t blue)
|
||||
*
|
||||
*/
|
||||
|
||||
void load_main_color()
|
||||
void draw_main_color()
|
||||
{
|
||||
uint8_t red = EEPROM.read(ADR_MC_RED);
|
||||
uint8_t green = EEPROM.read(ADR_MC_GREEN);
|
||||
uint8_t blue = EEPROM.read(ADR_MC_BLUE);
|
||||
uint8_t red = colors_ps->red;
|
||||
uint8_t green = colors_ps->green;
|
||||
uint8_t blue = colors_ps->blue;
|
||||
|
||||
if ((int(red) + int(green) + int(blue)) < 50)
|
||||
{
|
||||
@@ -828,69 +748,58 @@ void handle_command()
|
||||
state_change(ST_HEARTS);
|
||||
}
|
||||
}
|
||||
else if (webserver.argName(0).equals("nightmode"))
|
||||
else if (webserver.argName(0).equals("night_mode"))
|
||||
{
|
||||
String mode_str = webserver.arg(0);
|
||||
logger.log_string("Nightmode change via Webserver to: " + mode_str);
|
||||
mode_str.equals("1") ? set_night_mode(true) : set_night_mode(false);
|
||||
}
|
||||
else if (webserver.argName(0).equals("dyn_brightness"))
|
||||
{
|
||||
String mode_str = webserver.arg(0);
|
||||
logger.log_string("Dynamic brightness change via Webserver to: " + mode_str);
|
||||
mode_str.equals("1") ? set_dynamic_brightness(true) : set_dynamic_brightness(false);
|
||||
|
||||
// Update brightness
|
||||
current_brightness = update_brightness();
|
||||
logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%");
|
||||
}
|
||||
else if (webserver.argName(0).equals("setting"))
|
||||
{
|
||||
String cmd_str = webserver.arg(0) + "-";
|
||||
logger.log_string("Nightmode setting change via Webserver to: " + cmd_str);
|
||||
night_mode_times.start_hour = split(cmd_str, '-', 0).toInt();
|
||||
night_mode_times.start_min = split(cmd_str, '-', 1).toInt();
|
||||
night_mode_times.end_hour = split(cmd_str, '-', 2).toInt();
|
||||
night_mode_times.end_min = split(cmd_str, '-', 3).toInt();
|
||||
brightness = split(cmd_str, '-', 4).toInt();
|
||||
reset_wifi_creds = split(cmd_str, '-', 5).toInt() > 0 ? true : false;
|
||||
night_mode_times_ps->start_hour = (int)split(cmd_str, '-', 0).toInt();
|
||||
night_mode_times_ps->start_min = (int)split(cmd_str, '-', 1).toInt();
|
||||
night_mode_times_ps->end_hour = (int)split(cmd_str, '-', 2).toInt();
|
||||
night_mode_times_ps->end_min = (int)split(cmd_str, '-', 3).toInt();
|
||||
brightness_ps->static_brightness = (uint8_t)split(cmd_str, '-', 4).toInt();
|
||||
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_ps->dyn_brightness_max = (uint8_t)split(cmd_str, '-', 7).toInt();
|
||||
|
||||
if (brightness < 10)
|
||||
{
|
||||
brightness = 10; // minimum brightness
|
||||
}
|
||||
if (night_mode_times.start_hour < 0 || night_mode_times.start_hour > 23)
|
||||
{
|
||||
night_mode_times.start_hour = NIGHTMODE_START_HR;
|
||||
}
|
||||
if (night_mode_times.start_min < 0 || night_mode_times.start_min > 59)
|
||||
{
|
||||
night_mode_times.start_min = NIGHTMODE_START_MIN;
|
||||
}
|
||||
if (night_mode_times.end_hour < 0 || night_mode_times.end_hour > 23)
|
||||
{
|
||||
night_mode_times.end_hour = NIGHTMODE_END_HR;
|
||||
}
|
||||
if (night_mode_times.end_min < 0 || night_mode_times.end_min > 59)
|
||||
{
|
||||
night_mode_times.end_min = NIGHTMODE_END_MIN;
|
||||
}
|
||||
if (reset_wifi_creds == true)
|
||||
if (flg_reset_wifi_creds == true)
|
||||
{
|
||||
reset_wifi_credentials(); // this function will not return
|
||||
}
|
||||
|
||||
EEPROM_write_to_address(ADR_NM_START_H, night_mode_times.start_hour);
|
||||
EEPROM_write_to_address(ADR_NM_START_M, night_mode_times.start_min);
|
||||
EEPROM_write_to_address(ADR_NM_END_H, night_mode_times.end_hour);
|
||||
EEPROM_write_to_address(ADR_NM_END_M, night_mode_times.end_min);
|
||||
EEPROM_write_to_address(ADR_BRIGHTNESS, brightness);
|
||||
limit_value_ranges();
|
||||
|
||||
logger.log_string("Nightmode starts at: " + String(night_mode_times.start_hour) + ":" + String(night_mode_times.start_min));
|
||||
logger.log_string("Nightmode ends at: " + String(night_mode_times.end_hour) + ":" + String(night_mode_times.end_min));
|
||||
logger.log_string("Brightness: " + String(brightness));
|
||||
led_matrix.set_brightness(brightness);
|
||||
}
|
||||
else if (webserver.argName(0).equals("stateautochange"))
|
||||
{
|
||||
String mode_str = webserver.arg(0);
|
||||
logger.log_string("stateAutoChange change via Webserver to: " + mode_str);
|
||||
mode_str.equals("1") ? state_auto_change = true : state_auto_change = false;
|
||||
// Update EEPROM with new settings
|
||||
write_settings_to_EEPROM();
|
||||
|
||||
logger.log_string("Nightmode starts at: " + String(night_mode_times_ps->start_hour) + ":" + String(night_mode_times_ps->start_min));
|
||||
delay(10);
|
||||
logger.log_string("Nightmode ends at: " + String(night_mode_times_ps->end_hour) + ":" + String(night_mode_times_ps->end_min));
|
||||
delay(10);
|
||||
|
||||
// Update brightness
|
||||
current_brightness = update_brightness();
|
||||
logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%");
|
||||
}
|
||||
else if (webserver.argName(0).equals("tetris"))
|
||||
{
|
||||
String cmd_str = webserver.arg(0);
|
||||
logger.log_string("Tetris cmd via Webserver to: " + cmd_str);
|
||||
// logger.log_string("Tetris cmd via Webserver to: " + cmd_str);
|
||||
if (cmd_str.equals("up"))
|
||||
{
|
||||
tetris.ctrlUp();
|
||||
@@ -919,7 +828,7 @@ void handle_command()
|
||||
else if (webserver.argName(0).equals("snake"))
|
||||
{
|
||||
String cmd_str = webserver.arg(0);
|
||||
logger.log_string("Snake cmd via Webserver to: " + cmd_str);
|
||||
// logger.log_string("Snake cmd via Webserver to: " + cmd_str);
|
||||
if (cmd_str.equals("up"))
|
||||
{
|
||||
snake.ctrlUp();
|
||||
@@ -944,7 +853,7 @@ void handle_command()
|
||||
else if (webserver.argName(0).equals("pong"))
|
||||
{
|
||||
String cmd_str = webserver.arg(0);
|
||||
logger.log_string("Pong cmd via Webserver to: " + cmd_str);
|
||||
// logger.log_string("Pong cmd via Webserver to: " + cmd_str);
|
||||
if (cmd_str.equals("up"))
|
||||
{
|
||||
pong.ctrlUp(1);
|
||||
@@ -976,7 +885,7 @@ void handle_data_request()
|
||||
Serial.println(webserver.arg(i));
|
||||
}
|
||||
|
||||
if (webserver.argName(0).equals("key")) // the parameter which was sent to this server is led color
|
||||
if (webserver.argName(0).equals("key"))
|
||||
{
|
||||
String message = "{";
|
||||
String keystr = webserver.arg(0);
|
||||
@@ -986,15 +895,19 @@ void handle_data_request()
|
||||
message += ",";
|
||||
message += "\"modeid\":\"" + String(current_state) + "\"";
|
||||
message += ",";
|
||||
message += "\"stateAutoChange\":\"" + String(state_auto_change) + "\"";
|
||||
message += "\"night_mode\":\"" + String(flg_night_mode) + "\"";
|
||||
message += ",";
|
||||
message += "\"night_mode\":\"" + String(night_mode) + "\"";
|
||||
message += "\"nightModeStart\":\"" + leading_zero2digit(night_mode_times_ps->start_hour) + "-" + leading_zero2digit(night_mode_times_ps->start_min) + "\"";
|
||||
message += ",";
|
||||
message += "\"nightModeStart\":\"" + leading_zero2digit(night_mode_times.start_hour) + "-" + leading_zero2digit(night_mode_times.start_min) + "\"";
|
||||
message += "\"nightModeEnd\":\"" + leading_zero2digit(night_mode_times_ps->end_hour) + "-" + leading_zero2digit(night_mode_times_ps->end_min) + "\"";
|
||||
message += ",";
|
||||
message += "\"nightModeEnd\":\"" + leading_zero2digit(night_mode_times.end_hour) + "-" + leading_zero2digit(night_mode_times.end_min) + "\"";
|
||||
message += "\"static_brightness\":\"" + String(brightness_ps->static_brightness) + "\"";
|
||||
message += ",";
|
||||
message += "\"brightness\":\"" + String(brightness) + "\"";
|
||||
message += "\"dyn_brightness\":\"" + String(brightness_ps->flg_dynamic_brightness) + "\"";
|
||||
message += ",";
|
||||
message += "\"min_brightness\":\"" + String(brightness_ps->dyn_brightness_min) + "\"";
|
||||
message += ",";
|
||||
message += "\"max_brightness\":\"" + String(brightness_ps->dyn_brightness_max) + "\"";
|
||||
}
|
||||
message += "}";
|
||||
webserver.send(200, "application/json", message);
|
||||
@@ -1010,32 +923,17 @@ void set_night_mode(bool state)
|
||||
{
|
||||
led_matrix.flush();
|
||||
led_matrix.draw_on_matrix_smooth(0.2);
|
||||
night_mode = state;
|
||||
flg_night_mode = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write value to EEPROM
|
||||
* @brief Set the dynamic brightness state
|
||||
*
|
||||
* @param address address to write the value
|
||||
* @param value value to write
|
||||
* @param state true -> nightmode on
|
||||
*/
|
||||
void EEPROM_write_to_address(int address, int value)
|
||||
void set_dynamic_brightness(bool state)
|
||||
{
|
||||
EEPROM.put(address, value);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read value from EEPROM
|
||||
*
|
||||
* @param address address
|
||||
* @return int value
|
||||
*/
|
||||
int EEPROM_read_address(int address)
|
||||
{
|
||||
int value;
|
||||
EEPROM.get(address, value);
|
||||
return value;
|
||||
brightness_ps->flg_dynamic_brightness = state;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1066,3 +964,120 @@ void reset_wifi_credentials()
|
||||
delay(200);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate dynamic brightness value based on daytime.
|
||||
*
|
||||
* @param min_brightness max brightness value set by the user
|
||||
* @param max_brightness min brightness value set by the user
|
||||
* @param hours current hour value
|
||||
* @param minutes current minute value
|
||||
* @param summertime indicates if summertime
|
||||
* @return dynamic brightness
|
||||
*/
|
||||
uint8_t calculate_dynamic_brightness(uint8_t min_brightness, uint8_t max_brightness,
|
||||
int hours, int minutes, bool summertime)
|
||||
{
|
||||
uint8_t calc_brightness = 0;
|
||||
uint8_t factor_index = 0;
|
||||
|
||||
// Calculate index based on current time, respecting array length (and wrap)
|
||||
factor_index = (uint8_t)(((hours + (int)summertime) * MINUTES_IN_HOUR + minutes) /
|
||||
(MINUTES_IN_HOUR / ((sizeof(qtly_brightness_factor) / sizeof(float)) / HOURS_IN_DAY))) %
|
||||
(sizeof(qtly_brightness_factor) / sizeof(float));
|
||||
|
||||
// function for calc_brightness: f(x) = min + (max - min)(1 - cos((t * 2 * Pi) / (96))) / 2
|
||||
calc_brightness = min_brightness +
|
||||
(uint8_t)(((float)(max_brightness - min_brightness)) * qtly_brightness_factor[factor_index]);
|
||||
|
||||
// ouput limits
|
||||
calc_brightness = RANGE_LIMIT(calc_brightness, MIN_BRIGHTNESS, UINT8_MAX);
|
||||
|
||||
return calc_brightness;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Init function. Reads (global) user settings from EEPROM. Call this after EEPROM init!
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void read_settings_from_EEPROM()
|
||||
{
|
||||
EEPROM.get(0, eeprom_buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes (global) user settings to EEPROM
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void write_settings_to_EEPROM()
|
||||
{
|
||||
// Copy EEPROM buffer
|
||||
EEPROM.put(0, eeprom_buffer);
|
||||
// Commit changes
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates brightness based on chosen mode.
|
||||
*
|
||||
* @return newly calculated and set brightness
|
||||
*/
|
||||
uint8_t update_brightness()
|
||||
{
|
||||
uint8_t new_brightness = 0;
|
||||
|
||||
if (brightness_ps->flg_dynamic_brightness == true)
|
||||
{
|
||||
new_brightness = calculate_dynamic_brightness(brightness_ps->dyn_brightness_min,
|
||||
brightness_ps->dyn_brightness_max,
|
||||
ntp_client.get_hours_24(),
|
||||
ntp_client.get_minutes(),
|
||||
ntp_client.check_daylight_saving_time());
|
||||
}
|
||||
else // use static brightness
|
||||
{
|
||||
new_brightness = brightness_ps->static_brightness;
|
||||
}
|
||||
// now set new brightness
|
||||
led_matrix.set_brightness(new_brightness);
|
||||
|
||||
return new_brightness;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Limits values ranges of user settings
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void limit_value_ranges()
|
||||
{
|
||||
// Range limits
|
||||
brightness_ps->dyn_brightness_min = RANGE_LIMIT(brightness_ps->dyn_brightness_min,
|
||||
MIN_BRIGHTNESS,
|
||||
brightness_ps->dyn_brightness_max - 1); // minimum brightness
|
||||
brightness_ps->dyn_brightness_max = RANGE_LIMIT(brightness_ps->dyn_brightness_max,
|
||||
brightness_ps->dyn_brightness_min + 1,
|
||||
MAX_BRIGHTNESS); // maximum brightness
|
||||
brightness_ps->static_brightness = RANGE_LIMIT(brightness_ps->static_brightness,
|
||||
MIN_BRIGHTNESS,
|
||||
MAX_BRIGHTNESS); // static brightness
|
||||
|
||||
night_mode_times_ps->start_hour = RANGE_LIMIT_SUB(night_mode_times_ps->start_hour,
|
||||
0,
|
||||
HOUR_MAX,
|
||||
NIGHTMODE_START_HR);
|
||||
night_mode_times_ps->start_min = RANGE_LIMIT_SUB(night_mode_times_ps->start_min,
|
||||
0,
|
||||
MINUTE_MAX,
|
||||
NIGHTMODE_START_MIN);
|
||||
night_mode_times_ps->end_hour = RANGE_LIMIT_SUB(night_mode_times_ps->end_hour,
|
||||
0,
|
||||
HOUR_MAX,
|
||||
NIGHTMODE_END_HR);
|
||||
night_mode_times_ps->end_min = RANGE_LIMIT_SUB(night_mode_times_ps->end_min,
|
||||
0,
|
||||
MINUTE_MAX,
|
||||
NIGHTMODE_END_MIN);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user