diff --git a/firmware/config.h b/firmware/config.h index 1a81adb..4b4ddd5 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -5,14 +5,17 @@ #define light_name "Dimmable Hue Light" //default light name -#define LIGHTS_COUNT 4 // do not modify because luminie p30 only ha 4 channel +#define LIGHTS_COUNT 4 // do not modify because luminie p30 only has 4 channel, never set above 80 -#define EEPROM_LAST_STATE_STARTUP_ADDRESS 0 // startup behavior is used for all lights -#define EEPROM_SCENE_ADDRESS 1 // scene is used for all of the lights -#define EEPROM_LAST_STATE_ADDRESS 2 // the first "last state" information for the first light -#define EEPROM_TIMING_CONTROL_ENABLED_ADDRESS 3 // the first "last state" information for the first light -#define EEPROM_DYNAMIC_IP_ADDRESS 4 -#define EEPROM_LAST_DEFAULT_BLOCK_ADDRESS 20 -#define EEPROM_TIMING_DATA_ADDRESS (EEPROM_TIMING_CONTROL_ENABLED_ADDRESS + LIGHTS_COUNT) // Stored data date per light ELE_USED; HH; MM; CH1; CH2; CH3; CH4; +#define EEPROM_LAST_STATE_STARTUP_ADDRESS 0 // startup behavior is used for all lights +#define EEPROM_SCENE_ADDRESS 1 // scene is used for all of the lights +#define EEPROM_TIMING_CONTROL_ENABLED_ADDRESS 2 +#define EEPROM_DYNAMIC_IP_ADDRESS 3 +#define EEPROM_LAST_STATE_ADDRESS 4 // the first "last state" information for the first light +#define EEPROM_TIMING_DATA_ADDRESS (EEPROM_LAST_STATE_ADDRESS + LIGHTS_COUNT) // Stored data date per light ELE_USED; HH; MM; CH1; CH2; CH3; CH4; -#define TC_TIME_CHECK_INTERVAL_MS 600000 +#define TIME_CHECK_INTERVAL_MS (10000UL) // 600000 + +#define MY_NTP_SERVER "de.pool.ntp.org" + +#define DISABLE_WEB_CONTROL diff --git a/firmware/firmware.ino b/firmware/firmware.ino index 937cc3a..b07c7d9 100644 --- a/firmware/firmware.ino +++ b/firmware/firmware.ino @@ -35,10 +35,11 @@ IPAddress subnet_mask( 255, 255, 255, 0); #define SCENE_NIGHTLY 2 // 10 bit PWM -#define PWM_OFF 0 // 0V -#define PWM_MIN 640 // 15V - minimum light amount (~1%) -#define PWM_MAX 1023 // 24V - maximum light amount (100%) -#define PWM_INC 4 // 24V-15V = 9V range; 9V ≙ 1024/640 = 383 counts; 383/100% = 3,83 counts (1%) / % => round up 4 counts / % (~1%) +#define PWM_OFF 0 // 0V +#define PWM_MIN 640 // 15V - minimum light amount (~1%) +#define PWM_MAX 1023 // 24V - maximum light amount (100%) +#define PWM_INC 4 // 24V-15V = 9V range; 9V ≙ 1024/640 = 383 counts; 383/100% = 3,83 counts (1%) / % => round up 4 counts / % (~1%) +#define BRI_TO_PWM_FACTOR 4 // 0-255 uint8_t brightness data x4 is 0 to 1024 //********************************// @@ -127,7 +128,6 @@ void lightEngine() { delay(6); in_transition = false; - } } @@ -232,13 +232,13 @@ void setup() init_webserver(); - - tc_init(); server.begin(); } // end of setup +//********************************// + void loop() { server.handleClient(); @@ -250,6 +250,8 @@ void loop() } } +//********************************// + void handleNotFound() { String message = "File Not Found\n\n"; @@ -268,9 +270,13 @@ void handleNotFound() server.send(404, "text/plain", message); } +//********************************// + void init_webserver() { - server.on("/state", HTTP_PUT, []() + +#ifndef DISABLE_WEB_CONTROL + server.on("/state", HTTP_PUT, []() { // HTTP PUT request used to set a new light state DynamicJsonDocument root(1024); DeserializationError error = deserializeJson(root, server.arg("plain")); @@ -360,8 +366,12 @@ void init_webserver() server.send(200, "text/plain", output); }); +#endif // DISABLE_WEB_CONTROL + server.on("/", []() { + +#ifndef DISABLE_WEB_CONTROL static float transitiontime = 4.0; if (server.hasArg("transition")) @@ -376,10 +386,21 @@ void init_webserver() if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) != startup) { EEPROM.write(EEPROM_LAST_STATE_STARTUP_ADDRESS, startup); + + for (uint8_t i = 0; i < LIGHTS_COUNT; i++) + { + uint8_t tmp = (light_state[i] == true ? LIGHT_STATE_ON : LIGHT_STATE_OFF); + if (EEPROM.read(EEPROM_LAST_STATE_ADDRESS + i) != tmp) + { + EEPROM.write(EEPROM_LAST_STATE_ADDRESS + i, tmp); + } + } + EEPROM.commit(); Serial.print("Startup behavior set to "); Serial.println(EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS)); } } +#endif // DISABLE_WEB_CONTROL // timing controller switch handling if (server.hasArg("tc")) @@ -412,6 +433,8 @@ void init_webserver() } } +#ifndef DISABLE_WEB_CONTROL + // scene switch handling if (server.hasArg("scene")) { @@ -425,6 +448,18 @@ void init_webserver() } + if (server.hasArg("dip")) + { + uint8_t tmp = EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS); + uint8_t tmp2 = (server.arg("dip") == "true" ? 1 : 0); + if (tmp != tmp2) + { + EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, tmp2); + EEPROM.commit(); + Serial.print("Set dynamic IP to "); Serial.println(EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS)); + } + } + // process the received data for every light for (int light = 0; light < LIGHTS_COUNT; light++) { @@ -439,24 +474,25 @@ void init_webserver() if (server.hasArg("on" + (String)light)) { uint8_t tmp = EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS); - if (server.arg("on" + (String)light) == "true") + if (server.arg("on" + (String)light) == "true" && light_state[light] == false) { light_state[light] = true; if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 0) { EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_ON); } + Serial.print("Light "); Serial.print(light); Serial.print(" state set to "); Serial.println(light_state[light]); - } else { + } else if (server.arg("on" + (String)light) == "false" && light_state[light] == true) + { light_state[light] = false; if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 1) { EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_OFF); } + Serial.print("Light "); Serial.print(light); Serial.print(" state set to "); Serial.println(light_state[light]); } - Serial.print("Light "); Serial.print(light); Serial.print(" state set to "); Serial.println(light_state[light]); - EEPROM.commit(); } @@ -464,7 +500,6 @@ void init_webserver() // start alerting for every light if (server.hasArg("alert")) { - if (light_state[light]) { current_bri[light] = 0; @@ -474,7 +509,7 @@ void init_webserver() } - // switch the light + // set the light step level if (light_state[light]) { step_level[light] = ((float)bri[light] - current_bri[light]) / transitiontime; @@ -484,6 +519,8 @@ void init_webserver() } } +#endif // DISABLE_WEB_CONTROL + if (server.hasArg("resettc")) { // reqrite the tc config and reboot tc_write_default(); @@ -507,57 +544,28 @@ void init_webserver() http_content += ""; http_content += ""; http_content += "
"; - http_content += "

Setup of " + (String)LIGHTS_COUNT + " light"; if (LIGHTS_COUNT > 1) http_content += "'s"; http_content += "

"; + http_content += "

" + (String)light_name + "

"; + + http_content += "
"; + http_content += "alert   reset   reset timing control data   update"; + http_content += ""; + http_content += "
"; http_content += "
"; - // timer data processing, startup state and scene for all of the lights - http_content += "
"; - http_content += ""; - http_content += ""; - http_content += "
"; - - http_content += "
"; - http_content += ""; - http_content += ""; - http_content += "
"; - - http_content += "
"; - http_content += ""; - int tc_val = EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS); - http_content += "ON"; - http_content += "OFF"; - http_content += "
"; +#ifndef DISABLE_WEB_CONTROL http_content += "
"; - - http_content += "
"; - http_content += ""; - http_content += ""; - http_content += "
"; - // Light control for (uint8 light_num = 0; light_num < LIGHTS_COUNT; light_num++) { - http_content += "

Light " + (String)(light_num+1) + "

"; + http_content += "

Light " + (String)(light_num+1) + "

"; http_content += "
"; http_content += ""; http_content += "ON"; http_content += "OFF"; http_content += "
"; - http_content += "
"; - http_content += ""; - http_content += "
"; http_content += "
"; http_content += ""; http_content += ""; @@ -573,6 +581,42 @@ void init_webserver() http_content += "
"; } + // timer data processing, startup state and scene for all of the lights + http_content += "
"; + http_content += "

Config

"; + http_content += "
"; + http_content += ""; + http_content += ""; + http_content += "
"; + + http_content += "
"; + http_content += ""; + http_content += ""; + http_content += "
"; + + http_content += "
"; + http_content += ""; + int tc_val = EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS); + http_content += "ON"; + http_content += "OFF"; + http_content += "
"; + http_content += "
"; + + http_content += "
"; + http_content += ""; + http_content += ""; + http_content += "
"; + // Wifi settings http_content += "
"; http_content += "

Wifi

"; @@ -612,12 +656,11 @@ void init_webserver() } http_content += "
"; - http_content += "alert   reset   reset timing control data   update"; - http_content += ""; http_content += ""; http_content += "
"; +#endif // DISABLE_WEB_CONTROL + http_content += "
"; http_content += ""; http_content += ""; diff --git a/firmware/timing_control.ino b/firmware/timing_control.ino index 85febe6..4667a8b 100644 --- a/firmware/timing_control.ino +++ b/firmware/timing_control.ino @@ -1,6 +1,6 @@ - -#include +#include #include +#include #include "config.h" @@ -22,14 +22,15 @@ #define ENSTATE_DISABLED 0 //***********************************// +/* Globals */ -const long utcOffsetInSeconds = 3600; // Europe/Berlin (not summer time) +uint32_t tc_last_check = 0; + +const long updateInterval = 60000; +const long utcOffsetInSeconds = 3600; -// Define NTP Client to get time WiFiUDP ntpUDP; -NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds); - -static uint32_t tc_last_time_check; +NTPClient timeClient(ntpUDP, MY_NTP_SERVER, utcOffsetInSeconds, updateInterval); struct tc_data_st { uint8_t enstate; @@ -61,13 +62,6 @@ uint8_t example_timer_data_block[] = { void tc_init() { - while ( WiFi.status() != WL_CONNECTED ) - { - delay ( 500 ); - Serial.print ( "." ); - } - - timeClient.begin(); if (tc_check_no_data_block() == true) { @@ -75,79 +69,42 @@ void tc_init() tc_write_default(); } - //Serial.println("TC: Read data block from eeprom"); + while ( WiFi.status() != WL_CONNECTED ) + { + delay (500); + Serial.print ( "." ); + } + + tc_last_check = millis(); + + timeClient.begin(); + + Serial.println("TC: Read data block from eeprom"); tc_readConfig(); - tc_last_time_check = millis(); } -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].enstate = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS + i * LENGTH_OF_TIMER_DATA_BLOCK + 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_updateTime() -{ - timeClient.update(); - - Serial.print("Local time: "); - Serial.print(timeClient.getHours()); - Serial.print(":"); - Serial.println(timeClient.getMinutes()); - -} +//********************************// void tc_update() { uint8_t target_data_block = 255; - if (millis() > tc_last_time_check + TC_TIME_CHECK_INTERVAL_MS) - { - tc_last_time_check = millis(); - tc_updateTime(); - } + tc_updateTime(); if ((timeClient.getMinutes() % 10) != 0) { return; // only run every 10 minutes } - //tc_updateTime(); - // 2. find current active time slot for (uint8_t i = 0; i < NUMBER_OF_TIMER_DATA_BLOCKS-1; i++) { - if (tc_data[i].hh == timeClient.getHours() && tc_data[i].mm == timeClient.getMinutes() && tc_data[i].enstate == ENSTATE_ENABLED) - { // we have a new time data slot reached + if (tc_data[i].hh == timeClient.getHours() && + tc_data[i].mm == timeClient.getMinutes() && + tc_data[i].enstate == ENSTATE_ENABLED) + { + // we have a new time data slot reached for (uint8_t j = i+1; j < NUMBER_OF_TIMER_DATA_BLOCKS; j++) { // search for the next enabled successor if (tc_data[j].enstate == ENSTATE_ENABLED) @@ -190,6 +147,60 @@ void tc_update() } +//********************************// + +void tc_updateTime() +{ + if (timeClient.update()) + { + Serial.println("TC: Reading time from server..."); + Serial.println(timeClient.getFormattedTime()); + + Serial.print("Local time: "); + Serial.print(timeClient.getHours()); + Serial.print(":"); + Serial.println(timeClient.getMinutes()); + } +} + +//********************************// + +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].enstate = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS + i * LENGTH_OF_TIMER_DATA_BLOCK + 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); @@ -205,6 +216,8 @@ void tc_write_default() //Serial.println("-----"); } +//********************************// + bool tc_check_no_data_block() { //Serial.print("Check data block address EEPROM_TIMING_DATA_ADDRESS = "); Serial.println(EEPROM_TIMING_DATA_ADDRESS); @@ -217,3 +230,5 @@ bool tc_check_no_data_block() } return false; } + +//********************************//