489 lines
14 KiB
C++
489 lines
14 KiB
C++
#include <ESP8266WiFi.h>
|
|
#include <WiFiUdp.h>
|
|
#include <NTPClient.h>
|
|
#include <TimeLib.h>
|
|
|
|
#include "config.h"
|
|
|
|
//***********************************//
|
|
|
|
// 6 byte
|
|
#define TIMER_DATA_HH 0
|
|
#define TIMER_DATA_MM 1
|
|
#define TIMER_DATA_CH1 2 // the brightness of the channel
|
|
#define TIMER_DATA_CH2 3 // the brightness of the channel
|
|
#define TIMER_DATA_CH3 4 // the brightness of the channel
|
|
#define TIMER_DATA_CH4 5 // the brightness of the channel
|
|
|
|
#define LENGTH_OF_TIMER_DATA_BLOCK (TIMER_DATA_CH4 + 1)
|
|
#define NUMBER_OF_TIMER_DATA_BLOCKS 10
|
|
|
|
//***********************************//
|
|
/* Globals */
|
|
|
|
bool tc_testOngoing = false;
|
|
|
|
uint32_t tc_last_check = 60000;
|
|
|
|
WiFiUDP ntpUDP;
|
|
NTPClient timeClient(ntpUDP, MY_NTP_SERVER);
|
|
|
|
struct tc_data_st {
|
|
uint8_t hh;
|
|
uint8_t mm;
|
|
uint8_t ch1;
|
|
uint8_t ch2;
|
|
uint8_t ch3;
|
|
uint8_t ch4;
|
|
};
|
|
|
|
struct tc_data_st tc_data[10];
|
|
|
|
uint8_t example_timer_data_block[] = {
|
|
// hour min ch1 ch2 ch3 ch3
|
|
8, 0, 0, 0, 0, 0, // 0: off
|
|
8, 30, 25, 0, 0, 0, // 1: 10% ch1 blues
|
|
11, 0, 25, 0, 25, 0, // 2: 10% all blues
|
|
13, 0, 205, 205, 205, 205, // 3: 80% all
|
|
18, 0, 205, 205, 205, 205, // 4: 80% all for 5 hours
|
|
19, 0, 50, 50, 50, 50, // 5: 20% all
|
|
19, 30, 50, 0, 50, 0, // 6: 20% all blues
|
|
20, 0, 25, 0, 25, 0, // 9: disabled
|
|
20, 30, 25, 0, 0, 0, // 7: 10% ch1 blues
|
|
21, 0, 0, 0, 0, 0, // 8: 0% all
|
|
};
|
|
|
|
uint8_t test_timer_data_block[] = {
|
|
// hour min ch1 ch2 ch3 ch3
|
|
9, 20, 0, 0, 0, 0, // 0: off
|
|
9, 30, 25, 0, 0, 0, // 1: 10% ch1 blues
|
|
9, 40, 25, 0, 25, 0, // 2: 10% all blues
|
|
9, 50, 205, 205, 205, 205, // 3: 80% all
|
|
10, 0, 100, 100, 100, 100, // 4: 80% all for 5 hours
|
|
10, 10, 50, 50, 50, 50, // 5: 20% all
|
|
10, 20, 50, 0, 50, 0, // 6: 20% all blues
|
|
10, 30, 25, 0, 0, 0, // 7: 10% ch1 blues
|
|
10, 40, 0, 0, 0, 0, // 8: all off
|
|
11, 0, 0, 0, 0, 0, // 9: all off
|
|
};
|
|
|
|
//***********************************//
|
|
|
|
void tc_init()
|
|
{
|
|
|
|
if (tc_check_no_data_block() == true)
|
|
{
|
|
//Serial.println("TC: No data block found, writing example block to EEPROM.");
|
|
tc_write_default();
|
|
}
|
|
|
|
while ( WiFi.status() != WL_CONNECTED )
|
|
{
|
|
delay (500);
|
|
Serial.print ( "." );
|
|
}
|
|
|
|
tc_last_check = millis();
|
|
|
|
// Set the timezone to Europe/Berlin
|
|
setenv("TZ", LOCAL_TIMEZONE_STRING, 1);
|
|
tzset();
|
|
|
|
timeClient.begin();
|
|
|
|
Serial.println("TC: Read data block from eeprom");
|
|
tc_readConfig();
|
|
|
|
if (tc_testOngoing == true)
|
|
{
|
|
Serial.println("TC: Test ongoing, reading test data");
|
|
for (uint8_t i = 0; i < NUMBER_OF_TIMER_DATA_BLOCKS * LENGTH_OF_TIMER_DATA_BLOCK; i += LENGTH_OF_TIMER_DATA_BLOCK)
|
|
{
|
|
tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].hh = test_timer_data_block[i];
|
|
tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].mm = test_timer_data_block[i+1];
|
|
tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].ch1 = test_timer_data_block[i+2];
|
|
tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].ch2 = test_timer_data_block[i+3];
|
|
tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].ch3 = test_timer_data_block[i+4];
|
|
tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].ch4 = test_timer_data_block[i+5];
|
|
|
|
Serial.print("data block: "); Serial.println(i / LENGTH_OF_TIMER_DATA_BLOCK);
|
|
Serial.print(" hh: "); Serial.println(tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].hh);
|
|
Serial.print(" mm: "); Serial.println(tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].mm);
|
|
Serial.print(" ch1: "); Serial.println(tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].ch1);
|
|
Serial.print(" ch2: "); Serial.println(tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].ch2);
|
|
Serial.print(" ch3: "); Serial.println(tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].ch3);
|
|
Serial.print(" ch4: "); Serial.println(tc_data[i / LENGTH_OF_TIMER_DATA_BLOCK].ch4);
|
|
}
|
|
}
|
|
|
|
if (tc_enabled == TIMING_CONTROL_ENABLED)
|
|
{
|
|
Serial.println("tc_enabled = " + (String)tc_enabled);
|
|
tc_update_main();
|
|
}
|
|
}
|
|
|
|
//********************************//
|
|
|
|
void tc_update_loop()
|
|
{
|
|
static uint8_t last_min_check = 255;
|
|
|
|
if ((timeClient.getMinutes() % 10) != 0 || last_min_check == timeClient.getMinutes()) // && tc_testOngoing == false
|
|
{
|
|
last_min_check = timeClient.getMinutes();
|
|
return; // only run every 10 minutes
|
|
}
|
|
|
|
tc_update_main();
|
|
}
|
|
|
|
void tc_update_main()
|
|
{
|
|
static uint8_t current_target_data_block = 255;
|
|
uint8_t target_data_block = 255;
|
|
|
|
tc_updateTime();
|
|
|
|
// search for the current active time slot
|
|
for (int i = NUMBER_OF_TIMER_DATA_BLOCKS-1; i >= 0 && target_data_block == 255; --i)
|
|
{
|
|
//Serial.println((String)tc_data[i].hh + ":" + (String)tc_data[i].mm);
|
|
|
|
/*if (tc_data[i].hh <= timeClient.getHours() &&
|
|
tc_data[i].mm <= timeClient.getMinutes())*/
|
|
if (tc_data[i].hh <= hour() &&
|
|
tc_data[i].mm <= minute())
|
|
{
|
|
target_data_block = i+1; // found the next block to load
|
|
}
|
|
//Serial.println((String)i + " => " + target_data_block);
|
|
}
|
|
|
|
if (target_data_block == 255)
|
|
{
|
|
// no new predecessor or successor found, start over
|
|
current_target_data_block = 255;
|
|
return;
|
|
}
|
|
|
|
if (current_target_data_block != target_data_block)
|
|
{
|
|
// new target block should be reached
|
|
current_target_data_block = target_data_block;
|
|
|
|
} else {
|
|
// drop the found target block, we are already going on to reach it
|
|
return;
|
|
}
|
|
|
|
if (target_data_block >= NUMBER_OF_TIMER_DATA_BLOCKS)
|
|
{
|
|
// we are not between two valid data points, do nothing
|
|
// TODO check if setting all lights to false is correct here
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
|
{
|
|
light_state[i] = false;
|
|
}
|
|
target_data_block = 255;
|
|
current_target_data_block = 255;
|
|
return;
|
|
}
|
|
|
|
// print out the current light state
|
|
Serial.println("-----\nCurrent values");
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
|
{
|
|
Serial.println("current_bri[" + (String)i + "] = " + (String)current_bri[i]);
|
|
}
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
|
{
|
|
Serial.println("bri[" + (String)i + "] = " + (String)bri[i]);
|
|
}
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
|
{
|
|
Serial.println("step_level[" + (String)i + "] = " + (String)step_level[i]);
|
|
}
|
|
|
|
Serial.println("-----\ntdb = " + (String)target_data_block);
|
|
Serial.print("target time: ");
|
|
Serial.print(tc_data[target_data_block].hh);
|
|
Serial.print(":");
|
|
Serial.print(tc_data[target_data_block].mm);
|
|
Serial.println();
|
|
|
|
// set the channels current and target brightness
|
|
bri[0] = tc_data[target_data_block].ch1;
|
|
bri[1] = tc_data[target_data_block].ch2;
|
|
bri[2] = tc_data[target_data_block].ch3;
|
|
bri[3] = tc_data[target_data_block].ch4;
|
|
if (tc_data[target_data_block-1].ch1 != current_bri[0])
|
|
{
|
|
current_bri[0] = tc_data[target_data_block-1].ch1 + ((tc_data[target_data_block].ch1 == 0) ? 1 : -1);
|
|
}
|
|
if (tc_data[target_data_block-1].ch2 != current_bri[1])
|
|
{
|
|
current_bri[1] = tc_data[target_data_block-1].ch2 + ((tc_data[target_data_block].ch2 == 0) ? 1 : -1);
|
|
}
|
|
if (tc_data[target_data_block-1].ch3 != current_bri[2])
|
|
{
|
|
current_bri[2] = tc_data[target_data_block-1].ch3 + ((tc_data[target_data_block].ch3 == 0) ? 1 : -1);
|
|
}
|
|
if (tc_data[target_data_block-1].ch4 != current_bri[3])
|
|
{
|
|
current_bri[3] = tc_data[target_data_block-1].ch4 + ((tc_data[target_data_block].ch4 == 0) ? 1 : -1);
|
|
}
|
|
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
|
{
|
|
Serial.println("current_bri[" + (String)i + "] = " + (String)current_bri[i]);
|
|
}
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
|
{
|
|
Serial.println("bri[" + (String)i + "] = " + (String)bri[i]);
|
|
}
|
|
|
|
// enable the lights
|
|
light_state[0] = true;
|
|
light_state[1] = true;
|
|
light_state[2] = true;
|
|
light_state[3] = true;
|
|
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
|
{
|
|
Serial.println("light_state[" + (String)i + "] = " + (String)light_state[i]);
|
|
}
|
|
|
|
// set the transition time
|
|
int t_time = 0;
|
|
if (target_data_block > 0)
|
|
{
|
|
// hours as seconds from now on to the next enabled block
|
|
t_time = ((uint16_t)tc_data[target_data_block].hh * 60 * 60) - ((uint16_t)hour() * 60 * 60);
|
|
// add the left over seconds to the next enabled block
|
|
t_time += ((uint16_t)tc_data[target_data_block].mm * 60) - ((uint16_t)minute() * 60);
|
|
|
|
}
|
|
transitiontime[0] = t_time;
|
|
transitiontime[1] = t_time;
|
|
transitiontime[2] = t_time;
|
|
transitiontime[3] = t_time;
|
|
|
|
// calculate the step level
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
|
{
|
|
process_lightdata(i, transitiontime[i]);
|
|
Serial.println("transitiontime[" + (String)i + "] = " + (String)transitiontime[i]);
|
|
}
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
|
{
|
|
Serial.println("step_level[" + (String)i + "] = " + (String)step_level[i]);
|
|
}
|
|
|
|
}
|
|
|
|
//********************************//
|
|
|
|
void tc_updateTime()
|
|
{
|
|
/**/
|
|
if (timeClient.update() || millis() > (tc_last_check + TIME_CHECK_INTERVAL_MS))
|
|
{
|
|
tc_last_check = millis();
|
|
|
|
adjustTimeForDST();
|
|
|
|
Serial.print("=====\nLocal time: ");
|
|
Serial.print(hour());
|
|
Serial.print(":");
|
|
Serial.println(minute());
|
|
}
|
|
/**/
|
|
}
|
|
|
|
//********************************//
|
|
|
|
void adjustTimeForDST()
|
|
{
|
|
|
|
// Get the time and date information
|
|
time_t now = timeClient.getEpochTime();
|
|
struct tm timeinfo;
|
|
localtime_r(&now, &timeinfo);
|
|
|
|
// set the local time
|
|
setTime(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900);
|
|
|
|
}
|
|
|
|
//********************************//
|
|
|
|
void tc_readConfig()
|
|
{
|
|
for (uint8_t i = 0; i < NUMBER_OF_TIMER_DATA_BLOCKS; i++)
|
|
{
|
|
/*Serial.print("Reading from address: "); Serial.print(EEPROM_TIMING_DATA_ADDRESS);
|
|
Serial.print(" + (");
|
|
Serial.print(i);
|
|
Serial.print(" * ");
|
|
Serial.print(LENGTH_OF_TIMER_DATA_BLOCK);
|
|
Serial.print(") + ");
|
|
Serial.println(TIMER_DATA_ENSTATE);*/
|
|
|
|
tc_data[i].hh = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS + i * LENGTH_OF_TIMER_DATA_BLOCK + TIMER_DATA_HH);
|
|
tc_data[i].mm = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS + i * LENGTH_OF_TIMER_DATA_BLOCK + TIMER_DATA_MM);
|
|
tc_data[i].ch1 = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS + i * LENGTH_OF_TIMER_DATA_BLOCK + TIMER_DATA_CH1);
|
|
tc_data[i].ch2 = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS + i * LENGTH_OF_TIMER_DATA_BLOCK + TIMER_DATA_CH2);
|
|
tc_data[i].ch3 = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS + i * LENGTH_OF_TIMER_DATA_BLOCK + TIMER_DATA_CH3);
|
|
tc_data[i].ch4 = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS + i * LENGTH_OF_TIMER_DATA_BLOCK + TIMER_DATA_CH4);
|
|
|
|
/*Serial.print("data block: "); Serial.print(i);
|
|
Serial.print(" @ ");
|
|
Serial.println((EEPROM_TIMING_DATA_ADDRESS + (i * LENGTH_OF_TIMER_DATA_BLOCK) + TIMER_DATA_ENSTATE));
|
|
|
|
Serial.print(" es: "); Serial.println(tc_data[i].enstate);
|
|
Serial.print(" hh: "); Serial.println(tc_data[i].hh);
|
|
Serial.print(" mm: "); Serial.println(tc_data[i].mm);
|
|
Serial.print(" ch1: "); Serial.println(tc_data[i].ch1);
|
|
Serial.print(" ch2: "); Serial.println(tc_data[i].ch2);
|
|
Serial.print(" ch3: "); Serial.println(tc_data[i].ch3);
|
|
Serial.print(" ch4: "); Serial.println(tc_data[i].ch4);*/
|
|
}
|
|
}
|
|
|
|
//********************************//
|
|
|
|
void tc_write_default()
|
|
{
|
|
//Serial.print("-----\nWrite data block starting from address EEPROM_TIMING_DATA_ADDRESS = "); Serial.println(EEPROM_TIMING_DATA_ADDRESS);
|
|
for (int i = 0; i < NUMBER_OF_TIMER_DATA_BLOCKS * LENGTH_OF_TIMER_DATA_BLOCK; i++)
|
|
{
|
|
//Serial.print(EEPROM_TIMING_DATA_ADDRESS + i); Serial.print(" <= "); Serial.print(example_timer_data_block[i]); Serial.print(" <= ");
|
|
|
|
EEPROM.write(EEPROM_TIMING_DATA_ADDRESS + i, example_timer_data_block[i]);
|
|
EEPROM.commit();
|
|
|
|
//Serial.println(EEPROM.read(EEPROM_TIMING_DATA_ADDRESS + i));
|
|
}
|
|
//Serial.println("-----");
|
|
}
|
|
|
|
//********************************//
|
|
|
|
bool tc_check_no_data_block()
|
|
{
|
|
//Serial.print("Check data block address EEPROM_TIMING_DATA_ADDRESS = "); Serial.println(EEPROM_TIMING_DATA_ADDRESS);
|
|
uint8_t e = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS);
|
|
//Serial.println(e);
|
|
|
|
if (e > 23) // the maximum value for tis memory section is 23
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//********************************//
|
|
|
|
String tc_getJsonData()
|
|
{
|
|
String output = "{\"tcdata\":[";
|
|
for (uint8_t i = 0; i < NUMBER_OF_TIMER_DATA_BLOCKS; i++)
|
|
{
|
|
output += "{\"hour\":" + (String)(int)tc_data[i].hh + ",";
|
|
output += "\"min\":" + (String)(int)tc_data[i].mm + ",";
|
|
output += "\"ch1\":" + (String)(int)tc_data[i].ch1 + ",";
|
|
output += "\"ch2\":" + (String)(int)tc_data[i].ch2 + ",";
|
|
output += "\"ch3\":" + (String)(int)tc_data[i].ch3 + ",";
|
|
output += "\"ch4\":" + (String)(int)tc_data[i].ch4 + "}";
|
|
if (i < NUMBER_OF_TIMER_DATA_BLOCKS-1)
|
|
{
|
|
output += ",";
|
|
}
|
|
}
|
|
if (tc_testOngoing == false)
|
|
{
|
|
output += "], \"currenttime\":{\"hour\":" + (String)hour() + ",\"min\":" + (String)minute() + "}}";
|
|
} else {
|
|
output += "], \"currenttime\":{\"hour\":16,\"min\":0}}";
|
|
}
|
|
return output;
|
|
}
|
|
|
|
//********************************//
|
|
|
|
void tc_jsonDataBlocksToEEPROM(String json_data_string)
|
|
{
|
|
StaticJsonDocument<512> doc;
|
|
deserializeJson(doc, json_data_string);
|
|
|
|
// Loop through each data block in the JSON data and store it in the tc_data array
|
|
for (uint8_t i = 0; i < NUMBER_OF_TIMER_DATA_BLOCKS; i++)
|
|
{
|
|
JsonObject obj = doc[i];
|
|
|
|
// Check and set the limits of the hour value
|
|
int hour = obj["hour"];
|
|
if (hour < 0) {
|
|
hour = 0;
|
|
} else if (hour > 23) {
|
|
hour = 23;
|
|
}
|
|
tc_data[i].hh = hour;
|
|
|
|
// Check and set the limits of the minute value
|
|
int minute = obj["min"];
|
|
if (minute < 0) {
|
|
minute = 0;
|
|
} else if (minute > 59) {
|
|
minute = 59;
|
|
}
|
|
tc_data[i].mm = minute;
|
|
|
|
// Check and set the limits of the ch1 value
|
|
int ch1 = obj["ch1"];
|
|
if (ch1 < 0) {
|
|
ch1 = 0;
|
|
} else if (ch1 > 255) {
|
|
ch1 = 255;
|
|
}
|
|
tc_data[i].ch1 = ch1;
|
|
|
|
// Check and set the limits of the ch2 value
|
|
int ch2 = obj["ch2"];
|
|
if (ch2 < 0) {
|
|
ch2 = 0;
|
|
} else if (ch2 > 255) {
|
|
ch2 = 255;
|
|
}
|
|
tc_data[i].ch2 = ch2;
|
|
|
|
// Check and set the limits of the ch3 value
|
|
int ch3 = obj["ch3"];
|
|
if (ch3 < 0) {
|
|
ch3 = 0;
|
|
} else if (ch3 > 255) {
|
|
ch3 = 255;
|
|
}
|
|
tc_data[i].ch3 = ch3;
|
|
|
|
// Check and set the limits of the ch4 value
|
|
int ch4 = obj["ch4"];
|
|
if (ch4 < 0) {
|
|
ch4 = 0;
|
|
} else if (ch4 > 255) {
|
|
ch4 = 255;
|
|
}
|
|
tc_data[i].ch4 = ch4;
|
|
}
|
|
|
|
// Write the tc_data array to the EEPROM
|
|
for (uint16_t i = 0; i < (NUMBER_OF_TIMER_DATA_BLOCKS * LENGTH_OF_TIMER_DATA_BLOCK); i++)
|
|
{
|
|
EEPROM.write(EEPROM_TIMING_DATA_ADDRESS + i, *((uint8_t*)&tc_data + i));
|
|
}
|
|
EEPROM.commit();
|
|
}
|
|
|
|
//********************************//
|