WLED/wled00/wled15_hue.ino
2018-07-21 23:21:07 +02:00

210 lines
5.3 KiB
C++

/*
* Sync to Philips hue lights
*/
void handleHue()
{
if (huePollingEnabled && WiFi.status() == WL_CONNECTED)
{
if (millis() - hueLastRequestSent > huePollIntervalMsTemp)
{
sendHuePoll(false);
}
}
}
bool setupHue()
{
if (WiFi.status() == WL_CONNECTED) //setup needed
{
if (strlen(hueApiKey)>20) //api key is probably ok
{
if (sendHuePoll(false))
{
huePollingEnabled = true;
return true;
}
if (hueError[0] == 'R' || hueError[0] == 'I') return false; //can't connect
delay(20);
}
sendHuePoll(true); //new API key
if (hueError[0] != 'C') return false; //still some error
delay(20);
if (sendHuePoll(false))
{
huePollingEnabled = true;
return true;
}
return false;
}
else return false;
return true;
}
bool sendHuePoll(bool sAuth)
{
bool st;
hueClient.setReuse(true);
hueClient.setTimeout(450);
String hueURL = "http://";
hueURL += hueIP.toString();
hueURL += "/api/";
if (!sAuth) {
hueURL += hueApiKey;
hueURL += "/lights/" + String(huePollLightId);
}
hueClient.begin(hueURL);
int httpCode = (sAuth)? hueClient.POST("{\"devicetype\":\"wled#esp\"}"):hueClient.GET();
//TODO this request may block operation for ages
if (httpCode>0){
st = handleHueResponse(hueClient.getString(),sAuth);
} else {
strcpy(hueError,"Request timed out");
st = false;
}
if (!st){ //error
if (huePollIntervalMsTemp<300000) huePollIntervalMsTemp*=2; // only poll every ~5min when unable to connect
hueFailCount++;
if (hueFailCount > 150) huePollingEnabled = false; //disable after many hours offline
}
hueLastRequestSent = millis();
return st;
}
bool handleHueResponse(String hueResp, bool isAuth)
{
DEBUG_PRINTLN(hueApiKey);
DEBUG_PRINTLN(hueResp);
if (hueResp.indexOf("error")>0)//hue bridge returned error
{
int hueErrorCode = getJsonValue(&hueResp,"type").toInt();
switch (hueErrorCode)
{
case 1: strcpy(hueError,"Unauthorized"); break;
case 3: strcpy(hueError,"Invalid light ID"); break;
case 101: strcpy(hueError,"Link button not pressed"); break;
default:
char coerr[18];
sprintf(coerr,"Bridge Error %i",hueErrorCode);
strcpy(hueError,coerr);
}
return false;
}
if (isAuth)
{
String tempApi = getJsonValue(&hueResp,"username");
if (tempApi.length()>0)
{
strcpy(hueApiKey,tempApi.c_str());
return true;
}
strcpy(hueError,"Invalid response");
return false;
}
float hueX=0, hueY=0;
uint16_t hueHue=0, hueCt=0;
byte hueBri=0, hueSat=0, hueColormode=0;
if (getJsonValue(&hueResp,"on").charAt(0) == 't')
{
String tempV = getJsonValue(&hueResp,"bri");
if (tempV.length()>0) //Dimmable device
{
hueBri = (tempV.toInt())+1;
tempV = getJsonValue(&hueResp,"colormode");
if (hueApplyColor && tempV.length()>0) //Color device
{
if (tempV.charAt(0) == 'x') //xy mode
{
tempV = getJsonValue(&hueResp,"xy");
if (tempV.length()>0) //valid
{
hueColormode = 1;
hueX = tempV.toFloat();
tempV = tempV.substring(tempV.indexOf(',')+1);
hueY = tempV.toFloat();
}
} else if (tempV.charAt(0) == 'h') //hs mode
{
tempV = getJsonValue(&hueResp,"hue");
if (tempV.length()>0) //valid
{
hueColormode = 2;
hueHue = tempV.toInt();
tempV = getJsonValue(&hueResp,"sat");
if (tempV.length()>0) //valid
{
hueSat = tempV.toInt();
}
}
} else //ct mode
{
tempV = getJsonValue(&hueResp,"\"ct"); //dirty hack to not get effect value instead
if (tempV.length()>0) //valid
{
hueColormode = 3;
hueCt = tempV.toInt();
}
}
}
} else //On/Off device
{
hueBri = briLast;
}
} else
{
hueBri = 0;
}
hueFailCount = 0;
huePollIntervalMsTemp = huePollIntervalMs;
strcpy(hueError,"Connected");
//applying vals
if (hueBri != hueBriLast)
{
if (hueApplyOnOff)
{
if (hueBri==0) {bri = 0;}
else if (bri==0 && hueBri>0) bri = briLast;
}
if (hueApplyBri)
{
if (hueBri>0) bri = hueBri;
}
hueBriLast = hueBri;
}
if (hueApplyColor)
{
switch(hueColormode)
{
case 1: if (hueX != hueXLast || hueY != hueYLast) colorXYtoRGB(hueX,hueY,col); hueXLast = hueX; hueYLast = hueY; break;
case 2: if (hueHue != hueHueLast || hueSat != hueSatLast) colorHStoRGB(hueHue,hueSat,col); hueHueLast = hueHue; hueSatLast = hueSat; break;
case 3: if (hueCt != hueCtLast) colorCTtoRGB(hueCt,col); hueCtLast = hueCt; break;
}
}
colorUpdated(7);
return true;
}
String getJsonValue(String* req, String key)
{
//TODO may replace with ArduinoJSON if too complex
//this is horribly inefficient and designed to work only in this case
uint16_t pos = req->indexOf(key);
String b = req->substring(pos + key.length()+2);
if (b.charAt(0)=='\"') //is string
{
return b.substring(1,b.substring(1).indexOf('\"')+1);
} else if (b.charAt(0)=='[') //is array
{
return b.substring(1,b.indexOf(']'));
} else //is primitive type
{
return b.substring(0,b.indexOf(',')); //this works only if value not last
}
return "";
}