-
-
Save mariusmotea/21e5c1dcc6ec3915638e3dd442d86d98 to your computer and use it in GitHub Desktop.
SK6812_WWA_HueStrip
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ESP8266WiFi.h> | |
#include <ESP8266mDNS.h> | |
#include <WiFiUdp.h> | |
#include <ArduinoOTA.h> | |
#include <ESP8266WebServer.h> | |
#include <NeoPixelBus.h> | |
#include <WiFiManager.h> | |
#include <EEPROM.h> | |
#define lightsCount 2 | |
#define pixelCount 60 | |
// if you want to setup static ip uncomment these 3 lines and line 72 | |
//IPAddress strip_ip ( 192, 168, 10, 95); | |
//IPAddress gateway_ip ( 192, 168, 10, 1); | |
//IPAddress subnet_mask(255, 255, 255, 0); | |
uint8_t wwa[lightsCount][3], bri[lightsCount], scene; | |
bool light_state[lightsCount], in_transition; | |
int ct[lightsCount]; | |
float step_level[lightsCount][3], current_wwa[lightsCount][3]; | |
byte mac[6]; | |
ESP8266WebServer server(80); | |
RgbwColor red = RgbwColor(255, 0, 0, 0); | |
RgbwColor green = RgbwColor(0, 255, 0, 0); | |
RgbwColor white = RgbwColor(255); | |
RgbwColor black = RgbwColor(0); | |
NeoPixelBus<NeoGrbwFeature, Neo800KbpsMethod> strip(pixelCount); | |
void convert_ct(uint8_t light) { | |
uint8 percent_warm; | |
uint8 percent_cold; | |
uint8 percent_amber; | |
if (ct[light] < 400) { | |
percent_warm = ((ct[light] - 150) * 100) / 250; | |
percent_cold = 100 - percent_warm; | |
percent_amber = 0; | |
} else { | |
percent_cold = 0; | |
percent_warm = 500 - ct[light]; | |
percent_amber = 100 - percent_warm; | |
} | |
wwa[light][0] = (bri[light] * percent_cold) / 100; | |
wwa[light][1] = (bri[light] * percent_warm) / 100; | |
wwa[light][2] = (bri[light] * percent_amber) / 100; | |
} | |
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 infoLight(RgbwColor color) { | |
// Flash the strip in the selected color. White = booted, green = WLAN connected, red = WLAN could not connect | |
for (int i = 0; i < pixelCount; i++) | |
{ | |
strip.SetPixelColor(i, color); | |
strip.Show(); | |
delay(10); | |
strip.SetPixelColor(i, black); | |
strip.Show(); | |
} | |
} | |
void apply_scene(uint8_t new_scene, uint8_t light) { | |
if ( new_scene == 0) { | |
bri[light] = 144; ct[light] = 447; convert_ct(light); | |
} else if ( new_scene == 1) { | |
bri[light] = 254; ct[light] = 346; convert_ct(light); | |
} else if ( new_scene == 2) { | |
bri[light] = 254; ct[light] = 233; convert_ct(light); | |
} else if ( new_scene == 3) { | |
bri[light] = 254; ct[light] = 156; convert_ct(light); | |
} else if ( new_scene == 4) { | |
bri[light] = 77; ct[light] = 367; convert_ct(light); | |
} else if ( new_scene == 5) { | |
bri[light] = 254; ct[light] = 447; convert_ct(light); | |
} | |
} | |
void process_lightdata(uint8_t light, float transitiontime) { | |
transitiontime *= 17 - (pixelCount / 40); //every extra led add a small delay that need to be counted | |
if (light_state[light] == true) { | |
convert_ct(light); | |
} | |
for (uint8_t i = 0; i < 3; i++) { | |
if (light_state[light]) { | |
step_level[light][i] = ((float)wwa[light][i] - current_wwa[light][i]) / transitiontime; | |
} else { | |
step_level[light][i] = current_wwa[light][i] / transitiontime; | |
} | |
} | |
} | |
void lightEngine() { | |
for (int i = 0; i < lightsCount; i++) { | |
if (light_state[i]) { | |
if (wwa[i][0] != current_wwa[i][0] || wwa[i][1] != current_wwa[i][1] || wwa[i][2] != current_wwa[i][2]) { | |
in_transition = true; | |
for (uint8_t k = 0; k < 3; k++) { | |
if (wwa[i][k] != current_wwa[i][k]) current_wwa[i][k] += step_level[i][k]; | |
if ((step_level[i][k] > 0.0 && current_wwa[i][k] > wwa[i][k]) || (step_level[i][k] < 0.0 && current_wwa[i][k] < wwa[i][k])) current_wwa[i][k] = wwa[i][k]; | |
} | |
for (int j = 0; j < pixelCount / lightsCount ; j++) | |
{ | |
strip.SetPixelColor(j + i * pixelCount / lightsCount, RgbwColor((int)current_wwa[i][0], (int)current_wwa[i][1], (int)current_wwa[i][2])); | |
} | |
strip.Show(); | |
} | |
} else { | |
if (current_wwa[i][0] != 0 || current_wwa[i][1] != 0 || current_wwa[i][2] != 0) { | |
in_transition = true; | |
for (uint8_t k = 0; k < 3; k++) { | |
if (current_wwa[i][k] != 0) current_wwa[i][k] -= step_level[i][k]; | |
if (current_wwa[i][k] < 0) current_wwa[i][k] = 0; | |
} | |
for (int j = 0; j < pixelCount / lightsCount ; j++) | |
{ | |
strip.SetPixelColor(j + i * pixelCount / lightsCount, RgbwColor((int)current_wwa[i][0], (int)current_wwa[i][1], (int)current_wwa[i][2])); | |
} | |
strip.Show(); | |
} | |
} | |
} | |
if (in_transition) { | |
delay(6); | |
in_transition = false; | |
} | |
} | |
void setup() { | |
strip.Begin(); | |
strip.Show(); | |
EEPROM.begin(512); | |
//WiFi.config(strip_ip, gateway_ip, subnet_mask); | |
for (uint8_t light = 0; light < lightsCount; light++) { | |
float transitiontime = (17 - (pixelCount / 40)) * 4; | |
apply_scene(EEPROM.read(2), light); | |
for (uint8_t j = 0; j < 3; j++) { | |
step_level[light][j] = ((float)wwa[light][j] - current_wwa[light][j]) / transitiontime; | |
} | |
} | |
if (EEPROM.read(1) == 1 || (EEPROM.read(1) == 0 && EEPROM.read(0) == 1)) { | |
for (int i = 0; i < lightsCount; i++) { | |
light_state[i] = true; | |
} | |
for (int j = 0; j < 200; j++) { | |
lightEngine(); | |
} | |
} | |
WiFiManager wifiManager; | |
wifiManager.autoConnect("New Hue Light"); | |
if (! light_state[0]) { | |
infoLight(white); | |
while (WiFi.status() != WL_CONNECTED) { | |
infoLight(red); | |
delay(500); | |
} | |
// Show that we are connected | |
infoLight(green); | |
} | |
WiFi.macAddress(mac); | |
// Port defaults to 8266 | |
// ArduinoOTA.setPort(8266); | |
// Hostname defaults to esp8266-[ChipID] | |
// ArduinoOTA.setHostname("myesp8266"); | |
// No authentication by default | |
// ArduinoOTA.setPassword((const char *)"123"); | |
ArduinoOTA.begin(); | |
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 | |
server.on("/set", []() { | |
uint8_t light; | |
float transitiontime = 4; | |
for (uint8_t i = 0; i < server.args(); i++) { | |
if (server.argName(i) == "light") { | |
light = server.arg(i).toInt() - 1; | |
} | |
else if (server.argName(i) == "on") { | |
if (server.arg(i) == "True" || server.arg(i) == "true") { | |
light_state[light] = true; | |
if (EEPROM.read(1) == 0 && EEPROM.read(0) == 0) { | |
EEPROM.write(0, 1); | |
} | |
} | |
else { | |
light_state[light] = false; | |
if (EEPROM.read(1) == 0 && EEPROM.read(0) == 1) { | |
EEPROM.write(0, 0); | |
} | |
} | |
EEPROM.commit(); | |
} | |
else if (server.argName(i) == "bri") { | |
light_state[light] = true; | |
if (server.arg(i).toInt() != 0) | |
bri[light] = server.arg(i).toInt(); | |
} | |
else if (server.argName(i) == "bri_inc") { | |
bri[light] += server.arg(i).toInt(); | |
if (bri[light] > 255) bri[light] = 255; | |
else if (bri[light] < 0) bri[light] = 0; | |
} | |
else if (server.argName(i) == "ct") { | |
ct[light] = server.arg(i).toInt(); | |
} | |
else if (server.argName(i) == "alert" && server.arg(i) == "select") { | |
if (light_state[light]) { | |
current_wwa[light][0] = 0; current_wwa[light][1] = 0; current_wwa[light][2] = 0; | |
} else { | |
current_wwa[light][0] = 255; current_wwa[light][1] = 255; current_wwa[light][2] = 255; | |
} | |
} | |
else if (server.argName(i) == "transitiontime") { | |
transitiontime = server.arg(i).toInt(); | |
} | |
} | |
server.send(200, "text/plain", "OK, bri:" + (String)bri[light] + ", ct:" + ct[light] + ", state:" + light_state[light]); | |
process_lightdata(light, transitiontime); | |
}); | |
server.on("/get", []() { | |
uint8_t light; | |
if (server.hasArg("light")) | |
light = server.arg("light").toInt() - 1; | |
String power_status; | |
power_status = light_state[light] ? "true" : "false"; | |
server.send(200, "text/plain", "{\"on\": " + power_status + ", \"bri\": " + (String)bri[light] + ", \"ct\":" + (String)ct[light] + ", \"colormode\": \"ct\"}"); | |
}); | |
server.on("/detect", []() { | |
server.send(200, "text/plain", "{\"hue\": \"strip\",\"lights\": " + (String)lightsCount + ",\"modelid\": \"LTW001\",\"mac\": \"" + String(mac[5], HEX) + ":" + String(mac[4], HEX) + ":" + String(mac[3], HEX) + ":" + String(mac[2], HEX) + ":" + String(mac[1], HEX) + ":" + String(mac[0], HEX) + "\"}"); | |
}); | |
server.on("/", []() { | |
float transitiontime = (17 - (pixelCount / 40)) * 4; | |
if (server.hasArg("startup")) { | |
if ( EEPROM.read(1) != server.arg("startup").toInt()) { | |
EEPROM.write(1, server.arg("startup").toInt()); | |
EEPROM.commit(); | |
} | |
} | |
for (int light = 0; light < lightsCount; light++) { | |
if (server.hasArg("scene")) { | |
if (server.arg("bri") == "" && server.arg("ct") == "") { | |
if ( EEPROM.read(2) != server.arg("scene").toInt()) { | |
EEPROM.write(2, server.arg("scene").toInt()); | |
EEPROM.commit(); | |
} | |
apply_scene(server.arg("scene").toInt(), light); | |
} else { | |
if (server.arg("bri") != "") { | |
bri[light] = server.arg("bri").toInt(); | |
} | |
if (server.arg("ct") != "") { | |
ct[light] = server.arg("ct").toInt(); | |
} | |
convert_ct(light); | |
} | |
} else if (server.hasArg("on")) { | |
if (server.arg("on") == "true") { | |
light_state[light] = true; { | |
if (EEPROM.read(1) == 0 && EEPROM.read(0) == 0) { | |
EEPROM.write(0, 1); | |
} | |
} | |
} else { | |
light_state[light] = false; | |
if (EEPROM.read(1) == 0 && EEPROM.read(0) == 1) { | |
EEPROM.write(0, 0); | |
} | |
} | |
EEPROM.commit(); | |
} else if (server.hasArg("alert")) { | |
if (light_state[light]) { | |
current_wwa[light][0] = 0; current_wwa[light][1] = 0; current_wwa[light][2] = 0; | |
} else { | |
current_wwa[light][0] = 255; current_wwa[light][1] = 255; current_wwa[light][2] = 255; | |
} | |
} | |
for (uint8_t j = 0; j < 3; j++) { | |
if (light_state[light]) { | |
step_level[light][j] = ((float)wwa[light][j] - current_wwa[light][j]) / transitiontime; | |
} else { | |
step_level[light][j] = current_wwa[light][j] / transitiontime; | |
} | |
} | |
} | |
if (server.hasArg("reset")) { | |
ESP.reset(); | |
} | |
String http_content = "<!doctype html>"; | |
http_content += "<html>"; | |
http_content += "<head>"; | |
http_content += "<meta charset=\"utf-8\">"; | |
http_content += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"; | |
http_content += "<title>Light Setup</title>"; | |
http_content += "<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/build/pure-min.css\">"; | |
http_content += "</head>"; | |
http_content += "<body>"; | |
http_content += "<fieldset>"; | |
http_content += "<h3>Light Setup</h3>"; | |
http_content += "<form class=\"pure-form pure-form-aligned\" action=\"/\" method=\"post\">"; | |
http_content += "<div class=\"pure-control-group\">"; | |
http_content += "<label for=\"power\"><strong>Power</strong></label>"; | |
http_content += "<a class=\"pure-button"; if (light_state[0]) http_content += " pure-button-primary"; http_content += "\" href=\"/?on=true\">ON</a>"; | |
http_content += "<a class=\"pure-button"; if (!light_state[0]) http_content += " pure-button-primary"; http_content += "\" href=\"/?on=false\">OFF</a>"; | |
http_content += "</div>"; | |
http_content += "<div class=\"pure-control-group\">"; | |
http_content += "<label for=\"startup\">Startup</label>"; | |
http_content += "<select onchange=\"this.form.submit()\" id=\"startup\" name=\"startup\">"; | |
http_content += "<option "; if (EEPROM.read(1) == 0) http_content += "selected=\"selected\""; http_content += " value=\"0\">Last state</option>"; | |
http_content += "<option "; if (EEPROM.read(1) == 1) http_content += "selected=\"selected\""; http_content += " value=\"1\">On</option>"; | |
http_content += "<option "; if (EEPROM.read(1) == 2) http_content += "selected=\"selected\""; http_content += " value=\"2\">Off</option>"; | |
http_content += "</select>"; | |
http_content += "</div>"; | |
http_content += "<div class=\"pure-control-group\">"; | |
http_content += "<label for=\"scene\">Scene</label>"; | |
http_content += "<select onchange = \"this.form.submit()\" id=\"scene\" name=\"scene\">"; | |
http_content += "<option "; if (EEPROM.read(2) == 0) http_content += "selected=\"selected\""; http_content += " value=\"0\">Relax</option>"; | |
http_content += "<option "; if (EEPROM.read(2) == 1) http_content += "selected=\"selected\""; http_content += " value=\"1\">Read</option>"; | |
http_content += "<option "; if (EEPROM.read(2) == 2) http_content += "selected=\"selected\""; http_content += " value=\"2\">Concentrate</option>"; | |
http_content += "<option "; if (EEPROM.read(2) == 3) http_content += "selected=\"selected\""; http_content += " value=\"3\">Energize</option>"; | |
http_content += "<option "; if (EEPROM.read(2) == 4) http_content += "selected=\"selected\""; http_content += " value=\"4\">Bright</option>"; | |
http_content += "<option "; if (EEPROM.read(2) == 5) http_content += "selected=\"selected\""; http_content += " value=\"5\">Dimmed</option>"; | |
http_content += "</select>"; | |
http_content += "</div>"; | |
http_content += "<br>"; | |
http_content += "<div class=\"pure-control-group\">"; | |
http_content += "<label for=\"state\"><strong>State</strong></label>"; | |
http_content += "</div>"; | |
http_content += "<div class=\"pure-control-group\">"; | |
http_content += "<label for=\"bri\">Bri</label>"; | |
http_content += "<input id=\"bri\" name=\"bri\" type=\"text\" placeholder=\"" + (String)bri[0] + "\">"; | |
http_content += "</div>"; | |
http_content += "<div class=\"pure-control-group\">"; | |
http_content += "<label for=\"ct\">CT</label>"; | |
http_content += "<input id=\"ct\" name=\"ct\" type=\"text\" placeholder=\"" + (String)ct[0] + "\">"; | |
http_content += "</div>"; | |
http_content += "<div class=\"pure-controls\">"; | |
http_content += "<span class=\"pure-form-message\"><a href=\"/?alert=1\">alert</a> or <a href=\"/?reset=1\">reset</a></span>"; | |
http_content += "<label for=\"cb\" class=\"pure-checkbox\">"; | |
http_content += "</label>"; | |
http_content += "<button type=\"submit\" class=\"pure-button pure-button-primary\">Save</button>"; | |
http_content += "</div>"; | |
http_content += "</fieldset>"; | |
http_content += "</form>"; | |
http_content += "</body>"; | |
http_content += "</html>"; | |
server.send(200, "text/html", http_content); | |
}); | |
server.onNotFound(handleNotFound); | |
server.begin(); | |
} | |
void loop() { | |
ArduinoOTA.handle(); | |
server.handleClient(); | |
lightEngine(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment