commit 143c037dd33ba367d600352c419f3286c0e55dff Author: Kai Lauterbach Date: Mon Apr 24 20:26:49 2023 +0200 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..bcdfad4 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# Custom light instruction + +This build is for: https://github.com/mariusmotea/diyHue/tree/master/Lights/Arduino/Generic_Dimmable_Light + +1. try out your parts and plan pathways + +2. solder gnd/- pathway and the 1k OHM resistors in place + +3. fasten wemos headers, and connect G pin to ground pathway + +4. Bring a wires from GPIO pins to the paths with resistors + +5. Fasten the blue cables (these go to the - of your strip(s)) (the board in the picture will have 2 individual controlable lights, you can have multiple strips on each) + +7. Fasten 3 pin headers for mosfets + +8. Connect the various paths to 3 pin headers + +9. Done + + +This build is very simular to the Generic RGBW light build. (didnt take picture with the mosfets and wemos inserted, but i guess this can be imagined) make sure the G pin on the wemos hits the grounded path. + +![Top](https://github.com/mariusmotea/diyHue/blob/master/Lights/Arduino/Generic_Dimmable_Light/images/Over.jpg?raw=true) +![Back](https://github.com/mariusmotea/diyHue/blob/master/Lights/Arduino/Generic_Dimmable_Light/images/Under.jpg?raw=true) + +## Components +[IRLB8721-TO220 MOSFETS (2x)](https://www.aliexpress.com/item/10PCS-IRLB8721-TO220-IRLB8721PBF-TO-220-free-shipping/32714364118.html) + +[Wemos D1 mini (1x)](https://www.aliexpress.com/item/ESP8266-ESP12-ESP-12-WeMos-D1-Mini-WIFI-Dev-Kit-Development-Board-NodeMCU-Lua/32653918483.html) + +[1k OHM resistor (2x)](https://www.aliexpress.com/item/100pcs-1-4W-Metal-Film-Resistor-1K-ohm-1KR-1-Tolerance-Precision-RoHS-Lead-Free-In/1851964338.html) + +[Female Headers (2x)](https://www.aliexpress.com/item/10-10-pcs-Single-Row-Pin-Female-Header-Socket-2-54mm-Pitch-1-10p-12p-20p/32783590196.html) + +[Prototyping board (1x)](https://www.aliexpress.com/item/20pcs-5x7-4x6-3x7-2x8-cm-double-Side-Copper-prototype-pcb-Universal-Board-for-Arduino/1847727667.html) diff --git a/firmware/config.h b/firmware/config.h new file mode 100644 index 0000000..e333e59 --- /dev/null +++ b/firmware/config.h @@ -0,0 +1,19 @@ + +#define USE_STATIC_IP //! uncomment to enable Static IP Adress + +#define SERIAL_BAUD_RATE 115200 + +#define light_name "Dimmable Hue Light" //default light name + +#define LIGHTS_COUNT 4 // do not modify because luminie p30 only ha 4 channel + +#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 TC_TIME_CHECK_INTERVAL_MS 600000 diff --git a/firmware/firmware.ino b/firmware/firmware.ino new file mode 100644 index 0000000..8531b87 --- /dev/null +++ b/firmware/firmware.ino @@ -0,0 +1,649 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +//********* Config block *********// + +uint8_t pins[LIGHTS_COUNT] = {12, 15, 13, 14}; + +#define use_hardware_switch false // To control on/off state and brightness using GPIO/Pushbutton, set this value to true. +//For GPIO based on/off and brightness control, it is mandatory to connect the following GPIO pins to ground using 10k resistor +#define button1_pin 4 // on and brightness up +#define button2_pin 5 // off and brightness down + +#ifdef USE_STATIC_IP +IPAddress strip_ip ( 192, 168, 0, 26); // choose an unique IP Adress +IPAddress gateway_ip ( 192, 168, 0, 1); // Router IP +IPAddress subnet_mask( 255, 255, 255, 0); +#endif + +//********************************// + +#define LIGHT_VERSION 2.1 + +#define LAST_STATE_STARTUP_LIGHT_LAST_STATE 0 +#define LAST_STATE_STARTUP_LIGHT_ON_STATE 1 +#define LAST_STATE_STARTUP_LIGHT_OFF_STATE 2 + +#define LIGHT_STATE_ON 1 +#define LIGHT_STATE_OFF 0 + +#define TIMING_CONTROL_ENABLED 1 +#define TIMING_CONTROL_DISABLED 0 + +#define SCENE_RELEAX 0 +#define SCENE_BRIGHT 1 +#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%) + +uint8_t scene; +uint8_t tc_enabled; + +bool light_state[LIGHTS_COUNT]; +bool in_transition; + +int transitiontime[LIGHTS_COUNT]; +int bri[LIGHTS_COUNT]; + +float step_level[LIGHTS_COUNT]; +float current_bri[LIGHTS_COUNT]; +byte mac[6]; + +ESP8266WebServer server(80); +ESP8266HTTPUpdateServer httpUpdateServer; + +void handleNotFound() +{ + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + + for (uint8_t i = 0; i < server.args(); i++) + { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(404, "text/plain", message); +} + +void apply_scene(uint8_t new_scene, uint8_t light) +{ + if (new_scene == SCENE_RELEAX) + { + bri[light] = 144; + } else if (new_scene == SCENE_BRIGHT) + { + bri[light] = 254; + } else if (new_scene == SCENE_NIGHTLY) + { + bri[0] = 25; + bri[1] = 0; + bri[2] = 0; + bri[3] = 0; + } +} + +void process_lightdata(uint8_t light, float transitiontime) +{ + transitiontime *= 16; + if (light_state[light]) + { + step_level[light] = (bri[light] - current_bri[light]) / transitiontime; + } else { + step_level[light] = current_bri[light] / transitiontime; + } +} + +void lightEngine() +{ + for (int i = 0; i < LIGHTS_COUNT; i++) + { + if (light_state[i]) + { + if (bri[i] != current_bri[i]) + { + in_transition = true; + current_bri[i] += step_level[i]; + if ((step_level[i] > 0.0 && current_bri[i] > bri[i]) || (step_level[i] < 0.0 && current_bri[i] < bri[i])) + { + current_bri[i] = bri[i]; + } + analogWrite(pins[i], (int)(current_bri[i] * 4)); + } + } else { + + if (current_bri[i] != 0 ) + { + in_transition = true; + current_bri[i] -= step_level[i]; + if (current_bri[i] < 0) + { + current_bri[i] = 0; + } + analogWrite(pins[i], (int)(current_bri[i] * 4)); + } + } + } + + if (in_transition) + { + delay(6); + in_transition = false; + + } else if (use_hardware_switch == true) + { + if (digitalRead(button1_pin) == HIGH) + { + int i = 0; + while (digitalRead(button1_pin) == HIGH && i < 30) + { + delay(20); + i++; + } + + for (int light = 0; light < LIGHTS_COUNT; light++) + { + if (i < 30) + { + // there was a short press + light_state[light] = true; + } + else { + // there was a long press + bri[light] += 56; + if (bri[light] > 254) + { + // don't increase the brightness more then maximum value + bri[light] = 254; + } + } + process_lightdata(light, 4); + } + + } else if (digitalRead(button2_pin) == HIGH) + { + int i = 0; + while (digitalRead(button2_pin) == HIGH && i < 30) + { + delay(20); + i++; + } + + for (int light = 0; light < LIGHTS_COUNT; light++) + { + if (i < 30) + { + // there was a short press + light_state[light] = false; + + } else { + // there was a long press + bri[light] -= 56; + if (bri[light] < 1) + { + // don't decrease the brightness less than minimum value. + bri[light] = 1; + } + } + process_lightdata(light, 4); + } + } + } +} + +void setup() +{ + EEPROM.begin(512); + + Serial.begin(SERIAL_BAUD_RATE); + +#ifdef USE_STATIC_IP + WiFi.config(strip_ip, gateway_ip, subnet_mask); +#endif + + for (uint8_t light = 0; light < LIGHTS_COUNT; light++) + { + apply_scene(EEPROM.read(EEPROM_SCENE_ADDRESS), light); + step_level[light] = bri[light] / 150.0; + + if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == LAST_STATE_STARTUP_LIGHT_LAST_STATE || + (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == LAST_STATE_STARTUP_LIGHT_ON_STATE && + EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == LIGHT_STATE_ON)) + { + light_state[light] = true; // set the light state to on + } + } + + if (EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS) == TIMING_CONTROL_DISABLED) + { + tc_enabled = TIMING_CONTROL_DISABLED; + + } else if (EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS) == TIMING_CONTROL_ENABLED) + { + tc_enabled = TIMING_CONTROL_ENABLED; + + } else { + + EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_DISABLED); + EEPROM.commit(); + tc_enabled = TIMING_CONTROL_DISABLED; + } + + if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == 255) + { + // set the default value on uninitialized EEPROM + EEPROM.write(EEPROM_LAST_STATE_STARTUP_ADDRESS, 0); + EEPROM.commit(); + } + +#ifdef USE_STATIC_IP + if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 255) + { + EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, 0); + EEPROM.commit(); + } +#else + if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 255) + { + EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, 1); + EEPROM.commit(); + } +#endif + + for (int j = 0; j < 200; j++) + { + lightEngine(); + } + + WiFi.mode(WIFI_STA); + WiFiManager wifiManager; + wifiManager.setConfigPortalTimeout(120); + wifiManager.autoConnect(light_name); + + IPAddress myIP = WiFi.localIP(); + Serial.print("IP: "); + Serial.println(myIP); + + if (!light_state[0]) + { + // Show that we are connected + analogWrite(pins[0], 100); + delay(500); + analogWrite(pins[0], 0); + } + + WiFi.macAddress(mac); + + pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output + digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH + + httpUpdateServer.setup(&server); // start http server + + if (use_hardware_switch == true) + { + pinMode(button1_pin, INPUT); + pinMode(button2_pin, INPUT); + } + + 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")); + + if (error) + { + server.send(404, "text/plain", "FAIL. " + server.arg("plain")); + } else { + + for (JsonPair state : root.as()) + { + const char* key = state.key().c_str(); + int light = atoi(key) - 1; + JsonObject values = state.value(); + int transitiontime = 4; + + if (values.containsKey("on")) + { + if (values["on"]) + { + light_state[light] = true; + if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == LAST_STATE_STARTUP_LIGHT_LAST_STATE && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == LIGHT_STATE_OFF) + { + EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_ON); + } + } else { + light_state[light] = false; + if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == LAST_STATE_STARTUP_LIGHT_LAST_STATE && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == LIGHT_STATE_ON) + { + EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_OFF); + } + } + } + + if (values.containsKey("bri")) + { + bri[light] = values["bri"]; + } + + if (values.containsKey("bri_inc")) + { + bri[light] += (int) values["bri_inc"]; + if (bri[light] > 255) bri[light] = 255; + else if (bri[light] < 1) bri[light] = 1; + } + + if (values.containsKey("transitiontime")) + { + transitiontime = values["transitiontime"]; + } + process_lightdata(light, transitiontime); + } + String output; + serializeJson(root, output); + server.send(200, "text/plain", output); + } + }); + + server.on("/state", HTTP_GET, []() + { // HTTP GET request used to fetch current light state + uint8_t light = server.arg("light").toInt() - 1; + DynamicJsonDocument root(1024); + root["on"] = light_state[light]; + root["bri"] = bri[light]; + String output; + serializeJson(root, output); + server.send(200, "text/plain", output); + }); + + server.on("/detect", []() + { // HTTP GET request used to discover the light type + char macString[32] = {0}; + sprintf(macString, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + DynamicJsonDocument root(1024); + root["name"] = light_name; + root["lights"] = LIGHTS_COUNT; + root["protocol"] = "native_multi"; + root["modelid"] = "LWB010"; + root["type"] = "dimmable_light"; + root["mac"] = String(macString); + root["version"] = LIGHT_VERSION; + String output; + serializeJson(root, output); + server.send(200, "text/plain", output); + }); + + server.on("/", []() + { + float transitiontime = 4; + + if (server.hasArg("startup")) + { + int startup = server.arg("startup").toInt(); + EEPROM.write(EEPROM_LAST_STATE_STARTUP_ADDRESS, startup); + EEPROM.commit(); + Serial.print("Startup behavior set to "); Serial.println(EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS)); + } + + if (server.hasArg("tc")) + { + if (server.arg("tc") == "true") + { + if (tc_enabled == TIMING_CONTROL_DISABLED) + { + tc_enabled = TIMING_CONTROL_ENABLED; + EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_ENABLED); + EEPROM.commit(); + Serial.print("Timing control = "); Serial.println(EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS)); + } + + } else { // tc is set to false or something else + + if (tc_enabled == TIMING_CONTROL_ENABLED) + { + tc_enabled = TIMING_CONTROL_DISABLED; + EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_DISABLED); + EEPROM.commit(); + Serial.print("Timing control = "); Serial.println(EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS)); + } + } + } + + if (server.hasArg("scene")) + { + scene = server.arg("scene").toInt(); + EEPROM.write(EEPROM_SCENE_ADDRESS, scene); + EEPROM.commit(); + Serial.print("Scene set to "); Serial.println(EEPROM.read(EEPROM_SCENE_ADDRESS)); + + } + + for (int light = 0; light < LIGHTS_COUNT; light++) + { + + if (server.hasArg("bri" + (String)light)) + { + bri[light] = server.arg("bri" + (String)light).toInt(); + Serial.print("Brightness set to "); Serial.println(bri[light]); + + } + + if (server.hasArg("on" + (String)light)) + { + if (server.arg("on" + (String)light) == "true") + { + light_state[light] = true; + if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 0) + { + EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_ON); + } + + } else { + light_state[light] = false; + if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == 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]); + + EEPROM.commit(); + + } + + if (server.hasArg("alert")) { + + if (light_state[light]) + { + current_bri[light] = 0; + } else { + current_bri[light] = 255; + } + + } + + if (light_state[light]) + { + step_level[light] = ((float)bri[light] - current_bri[light]) / transitiontime; + + } else { + step_level[light] = current_bri[light] / transitiontime; + } + } + + if (server.hasArg("resettc")) + { + tc_write_default(); + ESP.reset(); + } + + if (server.hasArg("reset")) + { + ESP.reset(); + } + + String http_content = ""; + http_content += ""; + http_content += ""; + http_content += ""; + http_content += ""; + http_content += ""; // Reload the page every 15 seconds automatically + http_content += "Light Setup"; + http_content += ""; + 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 += "
"; + + // 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 += "
"; + http_content += "
"; + + // Light control + + for (uint8 light_num = 0; light_num < LIGHTS_COUNT; light_num++) + { + 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 += ""; + http_content += ""; + http_content += ""; + http_content += "
"; + } + + // Wifi settings + http_content += "
"; + http_content += "

Wifi

"; + http_content += "
"; + http_content += ""; + http_content += ""; + http_content += "
"; + http_content += "
"; + http_content += ""; + http_content += ""; + http_content += "
"; + + // Network settings + uint8_t dip = EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS); + http_content += "
"; + http_content += "

Network

"; + http_content += "
"; + http_content += ""; + http_content += "ON"; + http_content += "OFF"; + http_content += "
"; + + if (dip == 0) + { + http_content += "
"; + http_content += ""; + http_content += ""; + http_content += "
"; + http_content += "
"; + http_content += ""; + http_content += ""; + http_content += "
"; + http_content += "
"; + http_content += ""; + http_content += ""; + http_content += "
"; + } + + http_content += "
"; + http_content += "alert   reset   reset timing control data   update"; + http_content += ""; + http_content += ""; + http_content += "
"; + + http_content += "
"; + http_content += ""; + http_content += ""; + http_content += ""; + + server.send(200, "text/html", http_content); + + }); + + server.on("/reset", []() + { // trigger manual reset + server.send(200, "text/html", "reset"); + delay(1000); + ESP.restart(); + }); + + server.onNotFound(handleNotFound); + + tc_init(); + + server.begin(); +} // end of setup + +void loop() +{ + server.handleClient(); + lightEngine(); + + if (tc_enabled == TIMING_CONTROL_ENABLED) + { + tc_update(); + } +} diff --git a/firmware/images/Over.jpg b/firmware/images/Over.jpg new file mode 100755 index 0000000..8f6ddab Binary files /dev/null and b/firmware/images/Over.jpg differ diff --git a/firmware/images/Under.jpg b/firmware/images/Under.jpg new file mode 100755 index 0000000..87c4456 Binary files /dev/null and b/firmware/images/Under.jpg differ diff --git a/firmware/timing_control.ino b/firmware/timing_control.ino new file mode 100644 index 0000000..85febe6 --- /dev/null +++ b/firmware/timing_control.ino @@ -0,0 +1,219 @@ + +#include +#include + +#include "config.h" + +//***********************************// + +// 7 byte +#define TIMER_DATA_ENSTATE 0 +#define TIMER_DATA_HH 1 +#define TIMER_DATA_MM 2 +#define TIMER_DATA_CH1 3 // the brightness of the channel +#define TIMER_DATA_CH2 4 // the brightness of the channel +#define TIMER_DATA_CH3 5 // the brightness of the channel +#define TIMER_DATA_CH4 6 // the brightness of the channel + +#define LENGTH_OF_TIMER_DATA_BLOCK (TIMER_DATA_CH4 + 1) +#define NUMBER_OF_TIMER_DATA_BLOCKS 10 + +#define ENSTATE_ENABLED 1 +#define ENSTATE_DISABLED 0 + +//***********************************// + +const long utcOffsetInSeconds = 3600; // Europe/Berlin (not summer time) + +// Define NTP Client to get time +WiFiUDP ntpUDP; +NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds); + +static uint32_t tc_last_time_check; + +struct tc_data_st { + uint8_t enstate; + uint8_t hh; + uint8_t mm; + uint8_t ch1; + uint8_t ch2; + uint8_t ch3; + uint8_t ch4; +}; + +struct tc_data_st tc_data[LIGHTS_COUNT]; + +uint8_t example_timer_data_block[] = { + // state hour min ch1 ch2 ch3 ch3 + ENSTATE_ENABLED, 8, 0, 0, 0, 0, 0, // off + ENSTATE_ENABLED, 8, 30, 25, 0, 0, 0, // 10% ch1 blues + ENSTATE_ENABLED, 9, 0, 25, 0, 25, 0, // 10% all blues + ENSTATE_ENABLED, 13, 0, 205, 205, 205, 205, // 80% all + ENSTATE_ENABLED, 18, 0, 50, 50, 50, 50, // 20% blue + ENSTATE_ENABLED, 20, 0, 50, 0, 50, 0, // 20% all blues + ENSTATE_ENABLED, 20, 0, 25, 0, 0, 0, // 10% ch1 blues + ENSTATE_ENABLED, 21, 0, 0, 0, 0, 0, // 0% all + ENSTATE_DISABLED, 20, 0, 0, 0, 0, 0, // disabled + ENSTATE_DISABLED, 20, 0, 0, 0, 0, 0, // disabled +}; + +//***********************************// + +void tc_init() +{ + while ( WiFi.status() != WL_CONNECTED ) + { + delay ( 500 ); + Serial.print ( "." ); + } + + timeClient.begin(); + + if (tc_check_no_data_block() == true) + { + //Serial.println("TC: No data block found, writing example block to EEPROM."); + tc_write_default(); + } + + //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(); + } + + 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 + 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) + { + target_data_block = j; // get the next block to activate + } + } + } + } + + if (target_data_block == 255) + { + // no new successor found + return; + } + + // 3. set the channels 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; + + // 4. enable/disable the lights + light_state[0] = tc_data[target_data_block].ch1 > 0 ? true : false; + light_state[0] = tc_data[target_data_block].ch2 > 0 ? true : false; + light_state[0] = tc_data[target_data_block].ch3 > 0 ? true : false; + light_state[0] = tc_data[target_data_block].ch4 > 0 ? true : false; + + // 5. set the transition time + int t_time = 0; + if (target_data_block > 0) + { + t_time = (tc_data[target_data_block].hh * 60 * 30) - (tc_data[target_data_block-1].hh * 60 * 30); // hours as seconds from now on to the next enabled block + t_time += (tc_data[target_data_block].mm * 60) - (tc_data[target_data_block-1].mm * 60); // add the left over seconds to the next enabled block + } + transitiontime[0] = t_time; + transitiontime[1] = t_time; + transitiontime[2] = t_time; + transitiontime[3] = t_time; + +} + +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 == 255) + { + return true; + } + return false; +} diff --git a/lp3ctrl.sh b/lp3ctrl.sh new file mode 100755 index 0000000..472bc81 --- /dev/null +++ b/lp3ctrl.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +LIGHT=$1 +STATE=$2 +BRI=$3 + +echo --- +curl http://192.168.0.26/state\?light=1 +echo +curl http://192.168.0.26/state\?light=2 +echo +curl http://192.168.0.26/state\?light=3 +echo +curl http://192.168.0.26/state\?light=4 +echo +echo --- + +if [ "$1" ]; then + curl -i -X PUT -d '{ "'$LIGHT'": { "on": '$STATE', "bri": '$BRI' } }' http://192.168.0.26/state + + echo + echo --- + + curl http://192.168.0.26/state\?light=1 + echo + curl http://192.168.0.26/state\?light=2 + echo + curl http://192.168.0.26/state\?light=3 + echo + curl http://192.168.0.26/state\?light=4 + + echo + echo --- +fi +