Skip to content

Instantly share code, notes, and snippets.

@mariusmotea
Created April 20, 2018 19:31
Show Gist options
  • Save mariusmotea/21e5c1dcc6ec3915638e3dd442d86d98 to your computer and use it in GitHub Desktop.
Save mariusmotea/21e5c1dcc6ec3915638e3dd442d86d98 to your computer and use it in GitHub Desktop.
SK6812_WWA_HueStrip
#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/purecss@0.6.2/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