Skip to content

Commit

Permalink
fix Philips Hue integration
Browse files Browse the repository at this point in the history
Works for multiple Philips Hue lights (tested with 5 lights)
  • Loading branch information
Massimo53 authored May 14, 2024
1 parent 7a4212b commit 7ab029d
Showing 1 changed file with 114 additions and 27 deletions.
141 changes: 114 additions & 27 deletions src/hardware/devices/philipsHueDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,12 @@ bool PhilipsHueDevice::configure(std::unordered_map<string, string> settings)

if (username != "")
{
LOG(INFO) << ip_address;
LOG(INFO) << port;
sp::io::http::Request http(ip_address,port);
auto response = http.get(string{ "/api/" } + username + "/lights");
string lightsListAPI = "/api/" + username + "/lights";
auto response = http.get(lightsListAPI);

if (response.status != 200) // !OK
{
LOG(WARNING) << "Failed to validate username on philips hue bridge: " << response.status;
Expand All @@ -146,7 +150,7 @@ bool PhilipsHueDevice::configure(std::unordered_map<string, string> settings)
for (const auto& entry : hue_json.items())
{
auto currentInt = string(entry.key()).toInt();
LOG(DEBUG) << "Got key from Hue API " << currentInt;
LOG(INFO) << "Got key from Hue API " << currentInt;
if (currentInt >= light_count) light_count = currentInt;
}

Expand Down Expand Up @@ -180,6 +184,7 @@ bool PhilipsHueDevice::configure(std::unordered_map<string, string> settings)

void PhilipsHueDevice::setChannelData(int channel, float value)
{
//LOG(INFO) << "Setting Channel Info";
int light_idx = channel / 4;
if (light_idx < 0 || light_idx >= light_count)
return;
Expand All @@ -192,6 +197,7 @@ void PhilipsHueDevice::setChannelData(int channel, float value)
case 2: if (lights[light_idx].hue != value * 65535) lights[light_idx].dirty = true; lights[light_idx].hue = value * 65535; break;
case 3: if (lights[light_idx].transitiontime != value) lights[light_idx].dirty = true; lights[light_idx].transitiontime = value; break;
}
//LOG(INFO) << "Light:" + string(light_idx) + " Channel:" + string(channel) + " Value:" + string(value);
}

int PhilipsHueDevice::getChannelCount()
Expand All @@ -201,37 +207,118 @@ int PhilipsHueDevice::getChannelCount()

void PhilipsHueDevice::updateLoop()
{
sp::io::http::Request http(ip_address,port);
//LOG(INFO) << "lights vector contents at start of main loop:";
//for(int n=0; n<light_count;n++)
//{
//LOG(INFO) << "Light#: " + (n+1);
//LOG(INFO) << "---Dirty: " + lights[n].dirty;
//LOG(INFO) << "--Bright: " + lights[n].brightness;
//LOG(INFO) << "-----Sat: " + lights[n].saturation;
//LOG(INFO) << "-----Hue: " + lights[n].hue;
//LOG(INFO) << "----Time: " + lights[n].transitiontime;
//LOG(INFO) << "----last: " + lights[n].laststate;
//}
//sp::io::http::Request http(ip_address,port);


while(run_thread)
{
for(int n=0; n<light_count; n++)
{
if (lights[n].dirty)
LightInfo info = lights[n];
//LOG(INFO) << "Running through lights (Light[" + string(n+1) + "]), short sleep now to slow it down.";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
//LOG(INFO) << "Check Light[" << n+1 << "] laststate to see if it is dirty.";
if (info.laststate != "sat-" + string(info.saturation) + "-bri-" + string(info.brightness) + "-hue-" + string(info.hue) + "-transition-" + string(info.transitiontime))
{
LightInfo info;
{
std::lock_guard<std::mutex> lock(mutex);
lights[n].dirty = false;
info = lights[n];
}
string post_data;
if (info.laststate != "sat-" + string(info.saturation) + "-bri-" + string(info.brightness) + "-hue-" + string(info.hue) + "-transition-" + string(info.transitiontime))
{
//LOG(INFO) << "Last State does not match current state - update it to become current state, and mark it dirty.";
lights[n].laststate = "sat-" + string(info.saturation) + "-bri-" + string(info.brightness) + "-hue-" + string(info.hue) + "-transition-" + string(info.transitiontime);
if (info.brightness > 0)
post_data = "{\"on\":true, \"sat\":"+string(info.saturation)+", \"bri\":"+string(info.brightness)+",\"hue\":"+string(info.hue)+", \"transitiontime\": "+string(info.transitiontime)+"}";
else
post_data = "{\"on\":false, \"transitiontime\": "+string(info.transitiontime)+"}";
auto response = http.request("put", string{ "/api/" } + username + "/lights/" + string(n + 1) + "/state", post_data);
if (response.status != 200) // !OK
{
LOG(WARNING) << "Failed to set light [" << (n + 1) << "] philips hue bridge: " << response.status;
LOG(WARNING) << response.body;
}
}
}
lights[n].dirty = true;
}

if (lights[n].dirty)
{
//LOG(INFO) << "Light[" << n+1 << "] dirty, make call to following:";
sp::io::http::Request setLights(ip_address, port);
string APIEndpoint = "/api/" + username + "/lights/" + string(n+1) + "/state";
//LOG(INFO) << "http:////" + string(ip_address) + APIEndpoint;

// build the request body
LightInfo currentLight = lights[n];
string postData;
if (currentLight.brightness > 0) //light is on
{
postData = "{\"on\":true, \"sat\":" + string(currentLight.saturation) + ", \"bri\":" + string(currentLight.brightness) + ", \"hue\":" + string(currentLight.hue) + ", \"transitiontime\":" + string(currentLight.transitiontime) + "}";
//LOG(INFO) << "Request Body: " << postData;
}
else
{
postData = "{\"on\":false}";
//LOG(INFO) << "Request Body: " << postData << " (turn it off)";
}

// call the API
auto resp = setLights.request("PUT", APIEndpoint, postData);
if (resp.status == 200) // OK
{
//LOG(INFO) << "Light[" << n+1 << "] updated. Mark clean.";
//LOG(INFO) << "Light[" << n+1 << "] Response:" << resp.status << " Body:" << resp.body;
lights[n].dirty = false;
}
else
{
//LOG(INFO) << "Light[" << n+1 << "] update failed. Keep dirty. StatusCode:" << resp.status << " RespBody:" << resp.body;
}
}
else // light does not need changed so its fine, do nothing
{
//LOG(INFO) << "Light[" << n+1 << "] is clean - no update.";
}
}



//if (lights[n].dirty)
//{
//LOG(INFO) << "Light [" << n+1 << "] is dirty.";
//LightInfo info;
//{
////std::lock_guard<std::mutex> lock(mutex);
//lights[n].dirty = false;
//info = lights[n];
//}
//LOG(INFO) << "Light[" << n+1 << "] info: Bri:" << info.brightness << " Sat:" << info.saturation << " Hue:" << info.hue << " TT:" << info.transitiontime << " Dirty:" << info.dirty;
//string post_data;
//string thisLightAPI = APIEndpoint + string(n+1) + "/state";

//LOG(INFO) << "Light[" << n+1 << "] LastState:" << info.laststate;
////if (info.laststate != "sat-" + string(info.saturation) + "-bri-" + string(info.brightness) + "-hue-" + string(info.hue) + "-transition-" + string(info.transitiontime))
////{
////LOG(INFO) << "Last State does not match current state - update it to become current state, and (maybe) mark it dirty???";
////lights[n].laststate = "sat-" + string(info.saturation) + "-bri-" + string(info.brightness) + "-hue-" + string(info.hue) + "-transition-" + string(info.transitiontime);
////if (info.brightness > 0)
////post_data = "{\"on\":true, \"sat\":"+string(info.saturation)+", \"bri\":"+string(info.brightness)+",\"hue\":"+string(info.hue)+", \"transitiontime\": "+string(info.transitiontime)+"}";
////else
////post_data = "{\"on\":false, \"transitiontime\": "+string(info.transitiontime)+"}";
////LOG(INFO) << "Attempting API call to " + thisLightAPI;
////LOG(INFO) << "With Body: " + post_data;
////http.setHeader("connection", "keep-alive");
////auto response = http.request("PUT", thisLightAPI, post_data);
////LOG(INFO) << "response status: " + string(response.status);
////LOG(INFO) << "response body: " + string(response.body);
////if (response.status != 200) // !OK
////{
////LOG(WARNING) << "Failed to set light [" << (n + 1) << "] philips hue bridge: " << response.status;
////LOG(WARNING) << response.body;
////lights[n].dirty = true;
////}
////else
////{
////LOG(INFO) << "Hue response 200, the light[" << n+1 << "] should now be changed.";
////lights[n].dirty = false;
////}
////}
//}
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
//std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
}

0 comments on commit 7ab029d

Please sign in to comment.