From 47a624a2cb0cf48f9c504a9f2aa400d14ab80d2b Mon Sep 17 00:00:00 2001 From: Jojo-1000 <33495614+Jojo-1000@users.noreply.github.com> Date: Sat, 21 Apr 2018 22:28:43 +0200 Subject: [PATCH] Add HueCommandAPI as a layer over HttpHandler. - Used to enforce a timeout between api requests, closes #15 --- hueplusplus/CMakeLists.txt | 1 + hueplusplus/Hue.cpp | 437 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- hueplusplus/HueCommandAPI.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hueplusplus/HueLight.cpp | 320 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------------------------------------------------------------------------------- hueplusplus/include/Hue.h | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------------------ hueplusplus/include/HueCommandAPI.h | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hueplusplus/include/HueLight.h | 24 ++++++++++-------------- hueplusplus/test/CMakeLists.txt | 2 -- hueplusplus/test/mocks/mock_HueLight.h | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------------- hueplusplus/test/test_ExtendedColorHueStrategy.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------- hueplusplus/test/test_SimpleColorHueStrategy.cpp | 22 +++++++++++----------- 11 files changed, 809 insertions(+), 652 deletions(-) create mode 100644 hueplusplus/HueCommandAPI.cpp create mode 100644 hueplusplus/include/HueCommandAPI.h diff --git a/hueplusplus/CMakeLists.txt b/hueplusplus/CMakeLists.txt index 44fa08d..99182ba 100755 --- a/hueplusplus/CMakeLists.txt +++ b/hueplusplus/CMakeLists.txt @@ -3,6 +3,7 @@ set(hueplusplus_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ExtendedColorHueStrategy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ExtendedColorTemperatureStrategy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Hue.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/HueCommandAPI.cpp ${CMAKE_CURRENT_SOURCE_DIR}/HueLight.cpp ${CMAKE_CURRENT_SOURCE_DIR}/jsoncpp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SimpleBrightnessStrategy.cpp diff --git a/hueplusplus/Hue.cpp b/hueplusplus/Hue.cpp index 7684eb9..147eac4 100755 --- a/hueplusplus/Hue.cpp +++ b/hueplusplus/Hue.cpp @@ -1,20 +1,20 @@ /** - \file Hue.cpp - Copyright Notice\n - Copyright (C) 2017 Jan Rogall - developer\n - Copyright (C) 2017 Moritz Wirger - developer\n + \file Hue.cpp + Copyright Notice\n + Copyright (C) 2017 Jan Rogall - developer\n + Copyright (C) 2017 Moritz Wirger - developer\n - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **/ #include "include/Hue.h" @@ -38,270 +38,267 @@ HueFinder::HueFinder(std::shared_ptr handler) : http_handler std::vector HueFinder::FindBridges() const { - UPnP uplug; - std::vector> foundDevices = uplug.getDevices(http_handler); + UPnP uplug; + std::vector> foundDevices = uplug.getDevices(http_handler); - //Does not work - std::regex manufRegex("Royal Philips Electronics"); - std::regex manURLRegex("http://www\\.philips\\.com"); - std::regex modelRegex("Philips hue bridge[^<]*"); - std::regex serialRegex("(\\w+)"); - std::vector foundBridges; - for (const std::pair &p : foundDevices) - { - size_t found = p.second.find("IpBridge"); - if (found != std::string::npos) - { - HueIdentification bridge; - size_t start = p.first.find("//") + 2; - size_t length = p.first.find(":", start) - start; - bridge.ip = p.first.substr(start, length); - std::string desc = http_handler->GETString("/description.xml", "application/xml", "", bridge.ip); - std::smatch matchResult; - if (std::regex_search(desc, manufRegex) && std::regex_search(desc, manURLRegex) && std::regex_search(desc, modelRegex) && std::regex_search(desc, matchResult, serialRegex)) - { - //The string matches - //Get 1st submatch (0 is whole match) - bridge.mac = matchResult[1].str(); - foundBridges.push_back(std::move(bridge)); - } - //break; - } - } - return foundBridges; + //Does not work + std::regex manufRegex("Royal Philips Electronics"); + std::regex manURLRegex("http://www\\.philips\\.com"); + std::regex modelRegex("Philips hue bridge[^<]*"); + std::regex serialRegex("(\\w+)"); + std::vector foundBridges; + for (const std::pair &p : foundDevices) + { + size_t found = p.second.find("IpBridge"); + if (found != std::string::npos) + { + HueIdentification bridge; + size_t start = p.first.find("//") + 2; + size_t length = p.first.find(":", start) - start; + bridge.ip = p.first.substr(start, length); + std::string desc = http_handler->GETString("/description.xml", "application/xml", "", bridge.ip); + std::smatch matchResult; + if (std::regex_search(desc, manufRegex) && std::regex_search(desc, manURLRegex) && std::regex_search(desc, modelRegex) && std::regex_search(desc, matchResult, serialRegex)) + { + //The string matches + //Get 1st submatch (0 is whole match) + bridge.mac = matchResult[1].str(); + foundBridges.push_back(std::move(bridge)); + } + //break; + } + } + return foundBridges; } Hue HueFinder::GetBridge(const HueIdentification& identification) { - Hue bridge(identification.ip, "", http_handler); - auto pos = usernames.find(identification.mac); - if (pos != usernames.end()) - { - bridge.username = pos->second; - } - else - { - bridge.requestUsername(identification.ip); - if (bridge.getUsername().empty() || bridge.getUsername() == "") - { - std::cerr << "Failed to request username for ip " << identification.ip << std::endl; - throw std::runtime_error("Failed to request username!"); - } - else - { - AddUsername(identification.mac, bridge.getUsername()); - } - } - return bridge; + Hue bridge(identification.ip, "", http_handler); + auto pos = usernames.find(identification.mac); + if (pos != usernames.end()) + { + bridge.username = pos->second; + } + else + { + bridge.requestUsername(identification.ip); + if (bridge.getUsername().empty() || bridge.getUsername() == "") + { + std::cerr << "Failed to request username for ip " << identification.ip << std::endl; + throw std::runtime_error("Failed to request username!"); + } + else + { + AddUsername(identification.mac, bridge.getUsername()); + } + } + return bridge; } void HueFinder::AddUsername(const std::string& mac, const std::string& username) { - usernames[mac] = username; + usernames[mac] = username; } const std::map& HueFinder::GetAllUsernames() const { - return usernames; + return usernames; } -Hue::Hue(const std::string& ip, const std::string& username, std::shared_ptr handler) : -ip(ip), -username(username), -http_handler(std::move(handler)) +Hue::Hue(const std::string& ip, const std::string& username, std::shared_ptr handler) + : ip(ip), + username(username), + http_handler(std::move(handler)), + commands(ip, username, http_handler) { - simpleBrightnessStrategy = std::make_shared(); - simpleColorHueStrategy = std::make_shared(); - extendedColorHueStrategy = std::make_shared(); - simpleColorTemperatureStrategy = std::make_shared(); - extendedColorTemperatureStrategy = std::make_shared(); + simpleBrightnessStrategy = std::make_shared(); + simpleColorHueStrategy = std::make_shared(); + extendedColorHueStrategy = std::make_shared(); + simpleColorTemperatureStrategy = std::make_shared(); + extendedColorTemperatureStrategy = std::make_shared(); } std::string Hue::getBridgeIP() { - return ip; + return ip; } std::string Hue::requestUsername(const std::string& ip) { - std::cout << "Please press the link Button! You've got 35 secs!\n"; // when the link button was presed we got 30 seconds to get our username for control + std::cout << "Please press the link Button! You've got 35 secs!\n"; // when the link button was presed we got 30 seconds to get our username for control - Json::Value request; - request["devicetype"] = "HuePlusPlus#User"; + Json::Value request; + request["devicetype"] = "HuePlusPlus#User"; - Json::Value answer; - std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); - std::chrono::steady_clock::time_point lastCheck; - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(35)) - { - if (std::chrono::steady_clock::now() - lastCheck > std::chrono::seconds(1)) - { - lastCheck = std::chrono::steady_clock::now(); - answer = http_handler->POSTJson("/api", request, ip); + Json::Value answer; + std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); + std::chrono::steady_clock::time_point lastCheck; + while (std::chrono::steady_clock::now() - start < std::chrono::seconds(35)) + { + if (std::chrono::steady_clock::now() - lastCheck > std::chrono::seconds(1)) + { + lastCheck = std::chrono::steady_clock::now(); + answer = http_handler->POSTJson("/api", request, ip); - if (answer[0]["success"] != Json::nullValue) - { - // [{"success":{"username": ""}}] - username = answer[0]["success"]["username"].asString(); - this->ip = ip; - std::cout << "Success! Link button was pressed!\n"; - std::cout << "Username is \"" << username << "\"\n"; - break; - } - if (answer[0]["error"] != Json::nullValue) - { - std::cout << "Link button not pressed!\n"; - } - } - } - return username; + if (answer[0]["success"] != Json::nullValue) + { + // [{"success":{"username": ""}}] + username = answer[0]["success"]["username"].asString(); + this->ip = ip; + std::cout << "Success! Link button was pressed!\n"; + std::cout << "Username is \"" << username << "\"\n"; + break; + } + if (answer[0]["error"] != Json::nullValue) + { + std::cout << "Link button not pressed!\n"; + } + } + } + return username; } std::string Hue::getUsername() { - return username; + return username; } void Hue::setIP(const std::string ip) { - this->ip = ip; + this->ip = ip; } HueLight& Hue::getLight(int id) { - auto pos = lights.find(id); - if(pos != lights.end()) - { - pos->second.refreshState(); - return pos->second; - } - refreshState(); - if (!state["lights"].isMember(std::to_string(id))) - { - std::cerr << "Error in Hue getLight(): light with id " << id << " is not valid\n"; - throw(std::runtime_error("Error in Hue getLight(): light id is not valid")); - } - //std::cout << state["lights"][std::to_string(id)] << std::endl; - std::string type = state["lights"][std::to_string(id)]["modelid"].asString(); - //std::cout << type << std::endl; - if (type == "LCT001" || type == "LCT002" || type == "LCT003" || type == "LCT007" || type == "LLM001") - { - // HueExtendedColorLight Gamut B - HueLight light = HueLight(ip, username, id, simpleBrightnessStrategy, extendedColorTemperatureStrategy, extendedColorHueStrategy, http_handler); - light.colorType = ColorType::GAMUT_B; - lights.emplace(id, light); - return lights.find(id)->second; - } - else if (type == "LCT010" || type == "LCT011" || type == "LCT014" || type == "LLC020" || type == "LST002") - { - // HueExtendedColorLight Gamut C - HueLight light = HueLight(ip, username, id, simpleBrightnessStrategy, extendedColorTemperatureStrategy, extendedColorHueStrategy, http_handler); - light.colorType = ColorType::GAMUT_C; - lights.emplace(id, light); - return lights.find(id)->second; - } - else if (type == "LST001" || type == "LLC006" || type == "LLC007" || type == "LLC010" || type == "LLC011" || type == "LLC012" || type == "LLC013") - { - // HueColorLight Gamut A - HueLight light = HueLight(ip, username, id, simpleBrightnessStrategy, nullptr, simpleColorHueStrategy, http_handler); - light.colorType = ColorType::GAMUT_A; - lights.emplace(id, light); - return lights.find(id)->second; - } - else if (type == "LWB004" || type == "LWB006" || type == "LWB007" || type == "LWB010" || type == "LWB014") - { - // HueDimmableLight No Color Type - HueLight light = HueLight(ip, username, id, simpleBrightnessStrategy, nullptr, nullptr, http_handler); - light.colorType = ColorType::NONE; - lights.emplace(id, light); - return lights.find(id)->second; - } - else if (type == "LLM010" || type == "LLM011" || type == "LLM012" || type == "LTW001" || type == "LTW004" || type == "LTW013" || type == "LTW014") - { - // HueTemperatureLight - HueLight light = HueLight(ip, username, id, simpleBrightnessStrategy, simpleColorTemperatureStrategy, nullptr, http_handler); - light.colorType = ColorType::TEMPERATURE; - lights.emplace(id, light); - return lights.find(id)->second; - } - std::cerr << "Could not determine HueLight type!\n"; - throw(std::runtime_error("Could not determine HueLight type!")); + auto pos = lights.find(id); + if (pos != lights.end()) + { + pos->second.refreshState(); + return pos->second; + } + refreshState(); + if (!state["lights"].isMember(std::to_string(id))) + { + std::cerr << "Error in Hue getLight(): light with id " << id << " is not valid\n"; + throw(std::runtime_error("Error in Hue getLight(): light id is not valid")); + } + //std::cout << state["lights"][std::to_string(id)] << std::endl; + std::string type = state["lights"][std::to_string(id)]["modelid"].asString(); + //std::cout << type << std::endl; + if (type == "LCT001" || type == "LCT002" || type == "LCT003" || type == "LCT007" || type == "LLM001") + { + // HueExtendedColorLight Gamut B + HueLight light = HueLight(id, commands, simpleBrightnessStrategy, extendedColorTemperatureStrategy, extendedColorHueStrategy); + light.colorType = ColorType::GAMUT_B; + lights.emplace(id, light); + return lights.find(id)->second; + } + else if (type == "LCT010" || type == "LCT011" || type == "LCT014" || type == "LLC020" || type == "LST002") + { + // HueExtendedColorLight Gamut C + HueLight light = HueLight(id, commands, simpleBrightnessStrategy, extendedColorTemperatureStrategy, extendedColorHueStrategy); + light.colorType = ColorType::GAMUT_C; + lights.emplace(id, light); + return lights.find(id)->second; + } + else if (type == "LST001" || type == "LLC006" || type == "LLC007" || type == "LLC010" || type == "LLC011" || type == "LLC012" || type == "LLC013") + { + // HueColorLight Gamut A + HueLight light = HueLight(id, commands, simpleBrightnessStrategy, nullptr, simpleColorHueStrategy); + light.colorType = ColorType::GAMUT_A; + lights.emplace(id, light); + return lights.find(id)->second; + } + else if (type == "LWB004" || type == "LWB006" || type == "LWB007" || type == "LWB010" || type == "LWB014") + { + // HueDimmableLight No Color Type + HueLight light = HueLight(id, commands, simpleBrightnessStrategy, nullptr, nullptr); + light.colorType = ColorType::NONE; + lights.emplace(id, light); + return lights.find(id)->second; + } + else if (type == "LLM010" || type == "LLM011" || type == "LLM012" || type == "LTW001" || type == "LTW004" || type == "LTW013" || type == "LTW014") + { + // HueTemperatureLight + HueLight light = HueLight(id, commands, simpleBrightnessStrategy, simpleColorTemperatureStrategy, nullptr); + light.colorType = ColorType::TEMPERATURE; + lights.emplace(id, light); + return lights.find(id)->second; + } + std::cerr << "Could not determine HueLight type!\n"; + throw(std::runtime_error("Could not determine HueLight type!")); } bool Hue::removeLight(int id) { - Json::Value result = http_handler->DELETEJson("/api/"+username+"/lights/"+std::to_string(id), Json::objectValue, ip); - bool success = result.isArray() && !result[0].isNull() && result[0].isMember("success") && result[0]["success"] == "/lights/" + std::to_string(id) + " deleted"; - if (success && lights.count(id) != 0) - { - lights.erase(id); - } - return success; + Json::Value result = commands.DELETERequest("/lights/" + std::to_string(id), Json::objectValue); + bool success = result.isArray() && !result[0].isNull() && result[0].isMember("success") && result[0]["success"] == "/lights/" + std::to_string(id) + " deleted"; + if (success && lights.count(id) != 0) + { + lights.erase(id); + } + return success; } std::vector> Hue::getAllLights() { - refreshState(); - for (const auto& name : state["lights"].getMemberNames()) - { - uint8_t id = std::stoi(name); - if(lights.count(id)<=0) - { - getLight(id); - } - } - std::vector> result; - for (auto& entry : lights) - { - result.emplace_back(entry.second); - } - return result; + refreshState(); + for (const auto& id : state["lights"].getMemberNames()) + { + getLight(std::stoi(id)); + } + std::vector> result; + for (auto& entry : lights) + { + result.emplace_back(entry.second); + } + return result; } bool Hue::lightExists(int id) { - refreshState(); - auto pos = lights.find(id); - if (pos != lights.end()) - { - return true; - } - if (state["lights"].isMember(std::to_string(id))) - { - return true; - } - return false; + refreshState(); + auto pos = lights.find(id); + if (pos != lights.end()) + { + return true; + } + if (state["lights"].isMember(std::to_string(id))) + { + return true; + } + return false; } bool Hue::lightExists(int id) const { - auto pos = lights.find(id); - if (pos != lights.end()) - { - return true; - } - if (state["lights"].isMember(std::to_string(id))) - { - return true; - } - return false; + auto pos = lights.find(id); + if (pos != lights.end()) + { + return true; + } + if (state["lights"].isMember(std::to_string(id))) + { + return true; + } + return false; } void Hue::refreshState() { - if (username.empty()) - { - return; - } - Json::Value answer = http_handler->GETJson("/api/"+username, Json::objectValue, ip); - if (answer.isObject() && answer.isMember("lights")) - { - state = answer; - } - else - { - std::cout << "Answer in Hue::refreshState of http_handler->GETJson(...) is not expected!\nAnswer:\n\t" << answer.toStyledString() << std::endl; - } + if (username.empty()) + { + return; + } + Json::Value answer = commands.GETRequest("", Json::objectValue); + if (answer.isObject() && answer.isMember("lights")) + { + state = answer; + } + else + { + std::cout << "Answer in Hue::refreshState of http_handler->GETJson(...) is not expected!\nAnswer:\n\t" << answer.toStyledString() << std::endl; + } } diff --git a/hueplusplus/HueCommandAPI.cpp b/hueplusplus/HueCommandAPI.cpp new file mode 100644 index 0000000..7312d2d --- /dev/null +++ b/hueplusplus/HueCommandAPI.cpp @@ -0,0 +1,71 @@ +/** + \file HueCommandAPI.h + Copyright Notice\n + Copyright (C) 2018 Jan Rogall - developer\n + Copyright (C) 2018 Moritz Wirger - developer\n + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +**/ + +#include "include\HueCommandAPI.h" + +#include + +HueCommandAPI::HueCommandAPI(const std::string& ip, const std::string& username, std::shared_ptr httpHandler) + : ip(ip), + username(username), + httpHandler(std::move(httpHandler)), + timeout(new TimeoutData{std::chrono::steady_clock::now()}) +{} + +Json::Value HueCommandAPI::PUTRequest(const std::string& path, const Json::Value& request) const +{ + auto now = std::chrono::steady_clock::now(); + std::lock_guard lock(timeout->mutex); + if (timeout->timeout > now) + { + std::this_thread::sleep_until(timeout->timeout); + } + Json::Value v = httpHandler->PUTJson("/api/" + username + path, request, ip); + timeout->timeout = now + minDelay; + + return v; +} + +Json::Value HueCommandAPI::GETRequest(const std::string& path, const Json::Value& request) const +{ + auto now = std::chrono::steady_clock::now(); + std::lock_guard lock(timeout->mutex); + if (timeout->timeout > now) + { + std::this_thread::sleep_until(timeout->timeout); + } + Json::Value v = httpHandler->GETJson("/api/" + username + path, request, ip); + timeout->timeout = now + minDelay; + + return v; +} + +Json::Value HueCommandAPI::DELETERequest(const std::string& path, const Json::Value& request) const +{ + auto now = std::chrono::steady_clock::now(); + std::lock_guard lock(timeout->mutex); + if (timeout->timeout > now) + { + std::this_thread::sleep_until(timeout->timeout); + } + Json::Value v = httpHandler->DELETEJson("/api/" + username + path, request, ip); + timeout->timeout = now + minDelay; + + return v; +} diff --git a/hueplusplus/HueLight.cpp b/hueplusplus/HueLight.cpp index f155d83..bfc8d30 100755 --- a/hueplusplus/HueLight.cpp +++ b/hueplusplus/HueLight.cpp @@ -1,20 +1,20 @@ /** - \file HueLight.cpp - Copyright Notice\n - Copyright (C) 2017 Jan Rogall - developer\n - Copyright (C) 2017 Moritz Wirger - developer\n - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + \file HueLight.cpp + Copyright Notice\n + Copyright (C) 2017 Jan Rogall - developer\n + Copyright (C) 2017 Moritz Wirger - developer\n + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **/ #include "include/HueLight.h" @@ -27,250 +27,250 @@ bool HueLight::On(uint8_t transition) { - refreshState(); - return OnNoRefresh(transition); + refreshState(); + return OnNoRefresh(transition); } bool HueLight::Off(uint8_t transition) { - refreshState(); - return OffNoRefresh(transition); + refreshState(); + return OffNoRefresh(transition); } bool HueLight::isOn() { - refreshState(); - return state["state"]["on"].asBool(); + refreshState(); + return state["state"]["on"].asBool(); } bool HueLight::isOn() const { - return state["state"]["on"].asBool(); + return state["state"]["on"].asBool(); } int HueLight::getId() const { - return id; + return id; } std::string HueLight::getType() const { - return state["type"].asString(); + return state["type"].asString(); } std::string HueLight::getName() { - refreshState(); - return state["name"].asString(); + refreshState(); + return state["name"].asString(); } std::string HueLight::getName() const { - return state["name"].asString(); + return state["name"].asString(); } std::string HueLight::getModelId() const { - return state["modelid"].asString(); + return state["modelid"].asString(); } std::string HueLight::getUId() const { - if (state.isMember("uniqueid")) - { - return state["uniqueid"].asString(); - } - return std::string(); + if (state.isMember("uniqueid")) + { + return state["uniqueid"].asString(); + } + return std::string(); } std::string HueLight::getManufacturername() const { - if (state.isMember("manufacturername")) - { - return state["manufacturername"].asString(); - } - return std::string(); + if (state.isMember("manufacturername")) + { + return state["manufacturername"].asString(); + } + return std::string(); } std::string HueLight::getProductname() const { - if (state.isMember("productname")) - { - return state["productname"].asString(); - } - return std::string(); + if (state.isMember("productname")) + { + return state["productname"].asString(); + } + return std::string(); } std::string HueLight::getLuminaireUId() const { - if (state.isMember("luminaireuniqueid")) - { - return state["luminaireuniqueid"].asString(); - } - return std::string(); + if (state.isMember("luminaireuniqueid")) + { + return state["luminaireuniqueid"].asString(); + } + return std::string(); } std::string HueLight::getSwVersion() { - refreshState(); - return state["swversion"].asString(); + refreshState(); + return state["swversion"].asString(); } std::string HueLight::getSwVersion() const { - return state["swversion"].asString(); + return state["swversion"].asString(); } bool HueLight::setName(const std::string& name) { - Json::Value request(Json::objectValue); - request["name"] = name; - Json::Value reply = SendPutRequest(request, "/name"); + Json::Value request(Json::objectValue); + request["name"] = name; + Json::Value reply = SendPutRequest(request, "/name"); - //Check whether request was successful - return !reply[0].isNull() && reply[0].isMember("success") && reply[0]["success"]["/lights/" + std::to_string(id) + "/name"] == name; + //Check whether request was successful + return !reply[0].isNull() && reply[0].isMember("success") && reply[0]["success"]["/lights/" + std::to_string(id) + "/name"] == name; } ColorType HueLight::getColorType() const { - return colorType; + return colorType; } unsigned int HueLight::KelvinToMired(unsigned int kelvin) const { - return int(0.5f + (1000000 / kelvin)); + return int(0.5f + (1000000 / kelvin)); } unsigned int HueLight::MiredToKelvin(unsigned int mired) const { - return int(0.5f + (1000000 / mired)); + return int(0.5f + (1000000 / mired)); } bool HueLight::alert() { - Json::Value request; - request["alert"] = "select"; + Json::Value request; + request["alert"] = "select"; - Json::Value reply = SendPutRequest(request, "/state"); + Json::Value reply = SendPutRequest(request, "/state"); - if (reply[0]["success"]["/lights/" + std::to_string(id) + "/state/alert"].asString() == "select") - { - return true; - } + if (reply[0]["success"]["/lights/" + std::to_string(id) + "/state/alert"].asString() == "select") + { + return true; + } - return false; + return false; } -HueLight::HueLight(const std::string& ip, const std::string& username, int id, std::shared_ptr handler) - : HueLight(ip, username, id, nullptr, nullptr, nullptr, handler) +HueLight::HueLight(int id, const HueCommandAPI& commands) + : HueLight(id, commands, nullptr, nullptr, nullptr) {} -HueLight::HueLight(const std::string& ip, const std::string& username, int id, std::shared_ptr brightnessStrategy, std::shared_ptr colorTempStrategy, std::shared_ptr colorHueStrategy, std::shared_ptr handler) - : ip(ip), - username(username), - id(id), - brightnessStrategy(std::move(brightnessStrategy)), - colorTemperatureStrategy(std::move(colorTempStrategy)), - colorHueStrategy(std::move(colorHueStrategy)), - http_handler(std::move(handler)) +HueLight::HueLight(int id, const HueCommandAPI& commands, std::shared_ptr brightnessStrategy, std::shared_ptr colorTempStrategy, std::shared_ptr colorHueStrategy) + : ip(ip), + username(username), + id(id), + brightnessStrategy(std::move(brightnessStrategy)), + colorTemperatureStrategy(std::move(colorTempStrategy)), + colorHueStrategy(std::move(colorHueStrategy)), + commands(commands) { - refreshState(); + refreshState(); } bool HueLight::OnNoRefresh(uint8_t transition) { - Json::Value request(Json::objectValue); - if (transition != 4) - { - request["transitiontime"] = transition; - } - if (state["state"]["on"].asBool() != true) - { - request["on"] = true; - } - - if (!request.isMember("on")) - { - //Nothing needs to be changed - return true; - } - - Json::Value reply = SendPutRequest(request, "/state"); - - //Check whether request was successful - std::string path = "/lights/" + std::to_string(id) + "/state/"; - bool success = true; - int i = 0; - if (success && request.isMember("transitiontime")) - { - //Check if success was sent and the value was changed - success = !reply[i].isNull() && reply[i].isMember("success") && reply[i]["success"][path + "transitiontime"].asUInt() == request["transitiontime"].asUInt(); - ++i; - } - if (success && request.isMember("on")) - { - //Check if success was sent and the value was changed - success = !reply[i].isNull() && reply[i].isMember("success") && reply[i]["success"][path + "on"].asBool() == request["on"].asBool(); - } - return success; + Json::Value request(Json::objectValue); + if (transition != 4) + { + request["transitiontime"] = transition; + } + if (state["state"]["on"].asBool() != true) + { + request["on"] = true; + } + + if (!request.isMember("on")) + { + //Nothing needs to be changed + return true; + } + + Json::Value reply = SendPutRequest(request, "/state"); + + //Check whether request was successful + std::string path = "/lights/" + std::to_string(id) + "/state/"; + bool success = true; + int i = 0; + if (success && request.isMember("transitiontime")) + { + //Check if success was sent and the value was changed + success = !reply[i].isNull() && reply[i].isMember("success") && reply[i]["success"][path + "transitiontime"].asUInt() == request["transitiontime"].asUInt(); + ++i; + } + if (success && request.isMember("on")) + { + //Check if success was sent and the value was changed + success = !reply[i].isNull() && reply[i].isMember("success") && reply[i]["success"][path + "on"].asBool() == request["on"].asBool(); + } + return success; } bool HueLight::OffNoRefresh(uint8_t transition) { - Json::Value request(Json::objectValue); - if (transition != 4) - { - request["transitiontime"] = transition; - } - if (state["state"]["on"].asBool() != false) - { - request["on"] = false; - } - - if (!request.isMember("on")) - { - //Nothing needs to be changed - return true; - } - - Json::Value reply = SendPutRequest(request, "/state"); - - //Check whether request was successful - std::string path = "/lights/" + std::to_string(id) + "/state/"; - bool success = true; - int i = 0; - if (success && request.isMember("transitiontime")) - { - //Check if success was sent and the value was changed - success = !reply[i].isNull() && reply[i].isMember("success") && reply[i]["success"][path + "transitiontime"].asUInt() == request["transitiontime"].asUInt(); - ++i; - } - if (success && request.isMember("on")) - { - //Check if success was sent and the value was changed - success = !reply[i].isNull() && reply[i].isMember("success") && reply[i]["success"][path + "on"].asBool() == request["on"].asBool(); - } - return success; + Json::Value request(Json::objectValue); + if (transition != 4) + { + request["transitiontime"] = transition; + } + if (state["state"]["on"].asBool() != false) + { + request["on"] = false; + } + + if (!request.isMember("on")) + { + //Nothing needs to be changed + return true; + } + + Json::Value reply = SendPutRequest(request, "/state"); + + //Check whether request was successful + std::string path = "/lights/" + std::to_string(id) + "/state/"; + bool success = true; + int i = 0; + if (success && request.isMember("transitiontime")) + { + //Check if success was sent and the value was changed + success = !reply[i].isNull() && reply[i].isMember("success") && reply[i]["success"][path + "transitiontime"].asUInt() == request["transitiontime"].asUInt(); + ++i; + } + if (success && request.isMember("on")) + { + //Check if success was sent and the value was changed + success = !reply[i].isNull() && reply[i].isMember("success") && reply[i]["success"][path + "on"].asBool() == request["on"].asBool(); + } + return success; } Json::Value HueLight::SendPutRequest(const Json::Value& request, const std::string& subPath) { - return http_handler->PUTJson("/api/"+username+"/lights/"+std::to_string(id)+subPath, request, ip); + return commands.PUTRequest("/lights/" + std::to_string(id) + subPath, request); } void HueLight::refreshState() { - //std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); - //std::cout << "\tRefreshing lampstate of lamp with id: " << id << ", ip: " << ip << "\n"; - Json::Value answer = http_handler->GETJson("/api/"+username+"/lights/"+std::to_string(id), Json::objectValue, ip); - if (answer.isObject() && answer.isMember("state")) - { - state = answer; - } - else - { - std::cout << "Answer in HueLight::refreshState of http_handler->GETJson(...) is not expected!\nAnswer:\n\t" << answer.toStyledString() << std::endl; - } - //std::cout << "\tRefresh state took: " << std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count() << "ms" << std::endl; + //std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); + //std::cout << "\tRefreshing lampstate of lamp with id: " << id << ", ip: " << ip << "\n"; + Json::Value answer = commands.GETRequest("/lights/" + std::to_string(id), Json::objectValue); + if (answer.isObject() && answer.isMember("state")) + { + state = answer; + } + else + { + std::cout << "Answer in HueLight::refreshState of http_handler->GETJson(...) is not expected!\nAnswer:\n\t" << answer.toStyledString() << std::endl; + } + //std::cout << "\tRefresh state took: " << std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count() << "ms" << std::endl; } diff --git a/hueplusplus/include/Hue.h b/hueplusplus/include/Hue.h index f0d8530..93b69e2 100755 --- a/hueplusplus/include/Hue.h +++ b/hueplusplus/include/Hue.h @@ -1,20 +1,20 @@ /** - \file Hue.h - Copyright Notice\n - Copyright (C) 2017 Jan Rogall - developer\n - Copyright (C) 2017 Moritz Wirger - developer\n - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + \file Hue.h + Copyright Notice\n + Copyright (C) 2017 Jan Rogall - developer\n + Copyright (C) 2017 Moritz Wirger - developer\n + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **/ #ifndef _HUE_H @@ -29,6 +29,7 @@ #include "BrightnessStrategy.h" #include "ColorHueStrategy.h" #include "ColorTemperatureStrategy.h" +#include "HueCommandAPI.h" #include "HueLight.h" #include "IHttpHandler.h" @@ -43,144 +44,145 @@ class Hue; class HueFinder { public: - struct HueIdentification - { - std::string ip; - std::string mac; - }; + struct HueIdentification + { + std::string ip; + std::string mac; + }; public: - //! \brief Constructor of HueFinder class - //! - //! \param handler HttpHandler of type \ref IHttpHandler for communication with the bridge - HueFinder(std::shared_ptr handler); - - //! \brief Function that finds all bridges in the network and returns them. - //! - //! The user should be given the opportunity to select the correct one based on the mac address. - //! \return vector containing ip and mac of all found bridges - std::vector FindBridges() const; - - //! \brief Function that gets a \ref Hue bridge based on its identification - //! - //! \param identification \ref HueIdentification that specifies a bridge - //! \return \ref Hue class object - Hue GetBridge(const HueIdentification& identification); - - //! \brief Function that adds a username to the \ref usernames map - //! - //! \param mac MAC address of Hue bridge - //! \param username Username that is used to control the Hue bridge - void AddUsername(const std::string& mac, const std::string& username); - - //! \brief Function that returns a map of mac addresses and usernames. - //! - //! Note these should be saved at the end and re-loaded with \ref AddUsername next time, so only one username is generated per bridge. - //! \returns A map mapping mac address to username for every bridge - const std::map& GetAllUsernames() const; + //! \brief Constructor of HueFinder class + //! + //! \param handler HttpHandler of type \ref IHttpHandler for communication with the bridge + HueFinder(std::shared_ptr handler); + + //! \brief Function that finds all bridges in the network and returns them. + //! + //! The user should be given the opportunity to select the correct one based on the mac address. + //! \return vector containing ip and mac of all found bridges + std::vector FindBridges() const; + + //! \brief Function that gets a \ref Hue bridge based on its identification + //! + //! \param identification \ref HueIdentification that specifies a bridge + //! \return \ref Hue class object + Hue GetBridge(const HueIdentification& identification); + + //! \brief Function that adds a username to the \ref usernames map + //! + //! \param mac MAC address of Hue bridge + //! \param username Username that is used to control the Hue bridge + void AddUsername(const std::string& mac, const std::string& username); + + //! \brief Function that returns a map of mac addresses and usernames. + //! + //! Note these should be saved at the end and re-loaded with \ref AddUsername next time, so only one username is generated per bridge. + //! \returns A map mapping mac address to username for every bridge + const std::map& GetAllUsernames() const; private: - std::map usernames; //!< Maps all macs to usernames added by \ref HueFinder::AddUsername - std::shared_ptr http_handler; + std::map usernames; //!< Maps all macs to usernames added by \ref HueFinder::AddUsername + std::shared_ptr http_handler; }; //! Hue class class Hue { - friend class HueFinder; + friend class HueFinder; public: - //! \brief Constructor of Hue class - //! - //! \param ip String that specifies the ip address of the Hue bridge in dotted decimal notation like "192.168.2.1" - //! \param username String that specifies the username that is used to control the bridge. This needs to be acquired in \ref requestUsername - //! \param handler HttpHandler of type \ref IHttpHandler for communication with the bridge - Hue(const std::string& ip, const std::string& username, std::shared_ptr handler); - - //! \brief Function to get the ip address of the hue bridge - //! - //! \return string containing ip - std::string getBridgeIP(); - - //! \brief Function that sends a username request to the Hue bridge. - //! - //! It does that for about 30 seconds and you have 5 seconds to prepare - //! It automatically sets the \ref username variable according to the username received and returns the username received - //! This function should only be called once to acquire a username to control the bridge and the username should be saved for future use - //! \param ip String that specifies the ip (in dotted decimal notation like "192.168.2.1") the request is send to - //! \return String containing username - std::string requestUsername(const std::string& ip); - - //! \brief Function that returns the \ref username - //! - //! \return String containing \ref username - std::string getUsername(); - - //! \brief Function to set the ip address of this class representing a bridge - //! - //! \param ip String that specifies the ip in dotted decimal notation like "192.168.2.1" - void setIP(const std::string ip); - - //! \brief Function that returns a \ref Hue::HueLight of specified id - //! - //! \param id Integer that specifies the ID of a Hue light - //! \return \ref HueLight that can be controlled - HueLight& getLight(int id); - - //! \brief Function to remove a light from the bridge - //! - //! \attention Any use of the light after it was successfully removed results in undefined behavior - //! \param id Id of the light to remove - //! \return Bool that is true on success - bool removeLight(int id); - - //! \brief Function that returns all light types that are associated with this bridge - //! - //! \return A map mapping light id's to light types for every light - //const std::map& getAllLightTypes(); - - //! \brief Function that returns all lights that are associated with this bridge - //! - //! \return A vector containing references to every HueLight - std::vector> getAllLights(); - - //! \brief Function that tells whether a given light id represents an existing light - //! - //! Calls refreshState to update the local bridge state - //! \param id Id of a light to check for existance - //! \return Bool that is true when a light with the given id exists and false when not - bool lightExists(int id); - - //! \brief Const function that tells whether a given light id represents an existing light - //! - //! \note This will not update the local state of the bridge - //! \param id Id of a light to check for existance - //! \return Bool that is true when a light with the given id exists and false when not - bool lightExists(int id) const; - - //! \brief Function that sets the HttpHandler. - //! - //! The HttpHandler defines how specific commands that deal with bridge communication are executed - //! \param handler a HttpHandler of type \ref IHttpHandler - void setHttpHandler(std::shared_ptr handler) { http_handler = std::move(handler); }; + //! \brief Constructor of Hue class + //! + //! \param ip String that specifies the ip address of the Hue bridge in dotted decimal notation like "192.168.2.1" + //! \param username String that specifies the username that is used to control the bridge. This needs to be acquired in \ref requestUsername + //! \param handler HttpHandler of type \ref IHttpHandler for communication with the bridge + Hue(const std::string& ip, const std::string& username, std::shared_ptr handler); + + //! \brief Function to get the ip address of the hue bridge + //! + //! \return string containing ip + std::string getBridgeIP(); + + //! \brief Function that sends a username request to the Hue bridge. + //! + //! It does that for about 30 seconds and you have 5 seconds to prepare + //! It automatically sets the \ref username variable according to the username received and returns the username received + //! This function should only be called once to acquire a username to control the bridge and the username should be saved for future use + //! \param ip String that specifies the ip (in dotted decimal notation like "192.168.2.1") the request is send to + //! \return String containing username + std::string requestUsername(const std::string& ip); + + //! \brief Function that returns the \ref username + //! + //! \return String containing \ref username + std::string getUsername(); + + //! \brief Function to set the ip address of this class representing a bridge + //! + //! \param ip String that specifies the ip in dotted decimal notation like "192.168.2.1" + void setIP(const std::string ip); + + //! \brief Function that returns a \ref Hue::HueLight of specified id + //! + //! \param id Integer that specifies the ID of a Hue light + //! \return \ref HueLight that can be controlled + HueLight& getLight(int id); + + //! \brief Function to remove a light from the bridge + //! + //! \attention Any use of the light after it was successfully removed results in undefined behavior + //! \param id Id of the light to remove + //! \return Bool that is true on success + bool removeLight(int id); + + //! \brief Function that returns all light types that are associated with this bridge + //! + //! \return A map mapping light id's to light types for every light + //const std::map& getAllLightTypes(); + + //! \brief Function that returns all lights that are associated with this bridge + //! + //! \return A vector containing references to every HueLight + std::vector> getAllLights(); + + //! \brief Function that tells whether a given light id represents an existing light + //! + //! Calls refreshState to update the local bridge state + //! \param id Id of a light to check for existance + //! \return Bool that is true when a light with the given id exists and false when not + bool lightExists(int id); + + //! \brief Const function that tells whether a given light id represents an existing light + //! + //! \note This will not update the local state of the bridge + //! \param id Id of a light to check for existance + //! \return Bool that is true when a light with the given id exists and false when not + bool lightExists(int id) const; + + //! \brief Function that sets the HttpHandler and updates the HueCommandAPI. + //! + //! The HttpHandler and HueCommandAPI are used for bridge communication + //! \param handler a HttpHandler of type \ref IHttpHandler + void setHttpHandler(std::shared_ptr handler) { http_handler = std::move(handler); commands = HueCommandAPI(ip, username, http_handler); }; private: - //! \brief Function that refreshes the local \ref state of the Hue bridge - void refreshState(); + //! \brief Function that refreshes the local \ref state of the Hue bridge + void refreshState(); private: - std::string ip; //!< IP-Address of the hue bridge in dotted decimal notation like "192.168.2.1" - std::string username; //!< Username that is ussed to access the hue bridge - Json::Value state; //!< The state of the hue bridge as it is returned from it - std::map< uint8_t, HueLight > lights; //!< Maps ids to HueLights that are controlled by this bridge - - std::shared_ptr simpleBrightnessStrategy; //!< Strategy that is used for controlling the brightness of lights - std::shared_ptr simpleColorHueStrategy; //!< Strategy that is used for controlling the color of lights - std::shared_ptr extendedColorHueStrategy; //!< Strategy that is used for controlling the color of lights - std::shared_ptr simpleColorTemperatureStrategy; //!< Strategy that is used for controlling the color temperature of lights - std::shared_ptr extendedColorTemperatureStrategy; //!< Strategy that is used for controlling the color temperature of lights - std::shared_ptr http_handler; //!< A IHttpHandler that is used to communicate with the bridge + std::string ip; //!< IP-Address of the hue bridge in dotted decimal notation like "192.168.2.1" + std::string username; //!< Username that is ussed to access the hue bridge + Json::Value state; //!< The state of the hue bridge as it is returned from it + std::map< uint8_t, HueLight > lights; //!< Maps ids to HueLights that are controlled by this bridge + + std::shared_ptr simpleBrightnessStrategy; //!< Strategy that is used for controlling the brightness of lights + std::shared_ptr simpleColorHueStrategy; //!< Strategy that is used for controlling the color of lights + std::shared_ptr extendedColorHueStrategy; //!< Strategy that is used for controlling the color of lights + std::shared_ptr simpleColorTemperatureStrategy; //!< Strategy that is used for controlling the color temperature of lights + std::shared_ptr extendedColorTemperatureStrategy; //!< Strategy that is used for controlling the color temperature of lights + std::shared_ptr http_handler; //!< A IHttpHandler that is used to communicate with the bridge + HueCommandAPI commands; //!< A HueCommandAPI that is used to communicate with the bridge }; #endif diff --git a/hueplusplus/include/HueCommandAPI.h b/hueplusplus/include/HueCommandAPI.h new file mode 100644 index 0000000..db803fd --- /dev/null +++ b/hueplusplus/include/HueCommandAPI.h @@ -0,0 +1,92 @@ +/** + \file HueCommandAPI.h + Copyright Notice\n + Copyright (C) 2018 Jan Rogall - developer\n + Copyright (C) 2018 Moritz Wirger - developer\n + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +**/ + +#ifndef _HUECOMMANDAPI_H +#define _HUECOMMANDAPI_H + +#include +#include +#include + +#include "IHttpHandler.h" + + +//! Handles communication to the bridge via IHttpHandler and enforces a timeout between each request +class HueCommandAPI +{ +public: + //! \brief Construct from ip, username and HttpHandler + //! + //! \param ip String that specifies the ip address of the Hue bridge in dotted decimal notation like "192.168.2.1" + //! \param username String that specifies the username that is used to control the bridge + //! \param handler HttpHandler of type \ref IHttpHandler for communication with the bridge + HueCommandAPI(const std::string& ip, const std::string& username, std::shared_ptr httpHandler); + + //! \brief Copy construct from other HueCommandAPI + //! \note All copies refer to the same timeout data, so even calls from different objects will be delayed + HueCommandAPI(const HueCommandAPI&) = default; + //! \brief Move construct from other HueCommandAPI + //! \note All copies refer to the same timeout data, so even calls from different objects will be delayed + HueCommandAPI(HueCommandAPI&&) = default; + + //! \brief Copy assign from other HueCommandAPI + //! \note All copies refer to the same timeout data, so even calls from different objects will be delayed + HueCommandAPI& operator=(const HueCommandAPI&) = default; + //! \brief Move assign from other HueCommandAPI + //! \note All copies refer to the same timeout data, so even calls from different objects will be delayed + HueCommandAPI& operator=(HueCommandAPI&&) = default; + + //! \brief Sends a HTTP PUT request via the \ref httpHandler to the bridge and returns the response + //! + //! This function will block until at least \ref minDelay has passed to any previous request + //! \param path String that contains the request path (appended after /api/) + //! \param request Json value containing the request. May be empty + //! \returns The return value of the underlying \ref IHttpHandler::PUTJson call + Json::Value PUTRequest(const std::string& path, const Json::Value& request) const; + + //! \brief Sends a HTTP GET request via the \ref httpHandler to the bridge and returns the response + //! + //! This function will block until at least \ref minDelay has passed to any previous request + //! \param path String that contains the request path (appended after /api/) + //! \param request Json value containing the request. May be empty + //! \returns The return value of the underlying \ref IHttpHandler::GETJson call + Json::Value GETRequest(const std::string& path, const Json::Value& request) const; + + //! \brief Sends a HTTP DELETE request via the \ref httpHandler to the bridge and returns the response + //! + //! This function will block until at least \ref minDelay has passed to any previous request + //! \param path String that contains the request path (appended after /api/) + //! \param request Json value containing the request. May be empty + //! \returns The return value of the underlying \ref IHttpHandler::DELETEJson call + Json::Value DELETERequest(const std::string& path, const Json::Value& request) const; +private: + struct TimeoutData + { + std::chrono::steady_clock::time_point timeout; + std::mutex mutex; + }; +private: + static constexpr std::chrono::steady_clock::duration minDelay = std::chrono::milliseconds(100); + std::string ip; + std::string username; + std::shared_ptr httpHandler; + std::shared_ptr timeout; +}; + +#endif \ No newline at end of file diff --git a/hueplusplus/include/HueLight.h b/hueplusplus/include/HueLight.h index 440f319..232d0e2 100755 --- a/hueplusplus/include/HueLight.h +++ b/hueplusplus/include/HueLight.h @@ -25,7 +25,7 @@ #include "BrightnessStrategy.h" #include "ColorHueStrategy.h" #include "ColorTemperatureStrategy.h" -#include "IHttpHandler.h" +#include "HueCommandAPI.h" #include "json/json.h" @@ -557,24 +557,20 @@ public: protected: //! \brief Protected ctor that is used by \ref Hue class. //! - //! \param ip String that specifies the ip of the Hue bridge - //! \param username String that specifies the username used to control the bridge //! \param id Integer that specifies the id of this light - //! \param handler HttpHandler of type \ref IHttpHandler for communication with the bridge + //! \param commands HueCommandAPI for communication with the bridge //! //! leaves strategies unset - HueLight(const std::string& ip, const std::string& username, int id, std::shared_ptr handler); + HueLight(int id, const HueCommandAPI& commands); //! \brief Protected ctor that is used by \ref Hue class, also sets strategies. //! - //! \param ip String that specifies the ip of the Hue bridge - //! \param username String that specifies the username used to control the bridge //! \param id Integer that specifies the id of this light + //! \param commands HueCommandAPI for communication with the bridge //! \param brightnessStrategy Strategy for brightness. May be nullptr. //! \param colorTempStrategy Strategy for color temperature. May be nullptr. //! \param colorHueStrategy Strategy for color hue/saturation. May be nullptr. - //! \param handler HttpHandler of type \ref IHttpHandler for communication with the bridge - HueLight(const std::string& ip, const std::string& username, int id, std::shared_ptr brightnessStrategy, std::shared_ptr colorTempStrategy, std::shared_ptr colorHueStrategy, std::shared_ptr handler); + HueLight(int id, const HueCommandAPI& commands, std::shared_ptr brightnessStrategy, std::shared_ptr colorTempStrategy, std::shared_ptr colorHueStrategy); //! \brief Protected function that sets the brightness strategy. //! @@ -594,11 +590,11 @@ protected: //! \param strat a strategy of type \ref ColorHueStrategy virtual void setColorHueStrategy(std::shared_ptr strat) { colorHueStrategy = std::move(strat); }; - //! \brief Protected function that sets the HttpHandler. + //! \brief Protected function that sets the HueCommandAPI. //! - //! The HttpHandler defines how specific commands that deal with bridge communication are executed - //! \param handler a HttpHandler of type \ref IHttpHandler - virtual void setHttpHandler(std::shared_ptr handler) { http_handler = std::move(handler); }; + //! The HueCommandAPI is used for bridge communication + //! \param commandAPI the new HueCommandAPI + virtual void setCommandAPI(const HueCommandAPI& commandAPI) { commands = commandAPI; }; //! \brief Function that turns the light on without refreshing its state. //! @@ -633,7 +629,7 @@ protected: std::shared_ptr brightnessStrategy; //!< holds a reference to the strategy that handles brightness commands std::shared_ptr colorTemperatureStrategy; //!< holds a reference to the strategy that handles colortemperature commands std::shared_ptr colorHueStrategy; //!< holds a reference to the strategy that handles all color commands - std::shared_ptr http_handler; //!< A IHttpHandler that is used to communicate with the bridge + HueCommandAPI commands; //!< A IHttpHandler that is used to communicate with the bridge }; #endif diff --git a/hueplusplus/test/CMakeLists.txt b/hueplusplus/test/CMakeLists.txt index 89cab3b..8f4b41f 100755 --- a/hueplusplus/test/CMakeLists.txt +++ b/hueplusplus/test/CMakeLists.txt @@ -49,8 +49,6 @@ set(TEST_SOURCES # test executable add_executable(test_HuePlusPlus ${TEST_SOURCES} ${hueplusplus_SOURCES}) target_link_libraries(test_HuePlusPlus gtest gmock) -# prevent Main.cpp from defining main() -target_compile_definitions(test_HuePlusPlus PUBLIC MAIN_CPP_NO_MAIN_FUNCTION) target_include_directories(test_HuePlusPlus PUBLIC ${GTest_INCLUDE_DIRS}) target_include_directories(test_HuePlusPlus PUBLIC ${HuePlusPlus_INCLUDE_DIR}) set_property(TARGET test_HuePlusPlus PROPERTY CXX_STANDARD 14) diff --git a/hueplusplus/test/mocks/mock_HueLight.h b/hueplusplus/test/mocks/mock_HueLight.h index 193a858..2a44005 100755 --- a/hueplusplus/test/mocks/mock_HueLight.h +++ b/hueplusplus/test/mocks/mock_HueLight.h @@ -1,20 +1,20 @@ /** - \file mock_HueLight.h - Copyright Notice\n - Copyright (C) 2017 Jan Rogall - developer\n - Copyright (C) 2017 Moritz Wirger - developer\n - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + \file mock_HueLight.h + Copyright Notice\n + Copyright (C) 2017 Jan Rogall - developer\n + Copyright (C) 2017 Moritz Wirger - developer\n + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **/ #ifndef _MOCK_HUE_LIGHT_H @@ -33,97 +33,97 @@ class MockHueLight : public HueLight { public: - MockHueLight(std::shared_ptr handler) : HueLight(bridge_ip, bridge_username, 1, handler){}; + MockHueLight(std::shared_ptr handler) : HueLight(1, HueCommandAPI(bridge_ip, bridge_username, handler)) {}; - Json::Value& getState() {return state;}; + Json::Value& getState() { return state; }; - MOCK_METHOD1( On, bool(uint8_t transition) ); + MOCK_METHOD1(On, bool(uint8_t transition)); - MOCK_METHOD1( Off, bool(uint8_t transition) ); + MOCK_METHOD1(Off, bool(uint8_t transition)); - MOCK_METHOD0( isOn, bool() ); + MOCK_METHOD0(isOn, bool()); - MOCK_CONST_METHOD0( isOn, bool() ); + MOCK_CONST_METHOD0(isOn, bool()); - MOCK_CONST_METHOD0( getId, int() ); + MOCK_CONST_METHOD0(getId, int()); - MOCK_CONST_METHOD0( getType, std::string() ); + MOCK_CONST_METHOD0(getType, std::string()); - MOCK_METHOD0( getName, std::string() ); + MOCK_METHOD0(getName, std::string()); - MOCK_CONST_METHOD0( getName, std::string() ); + MOCK_CONST_METHOD0(getName, std::string()); - MOCK_CONST_METHOD0( getModelId, std::string() ); + MOCK_CONST_METHOD0(getModelId, std::string()); - MOCK_CONST_METHOD0( getUId, std::string() ); + MOCK_CONST_METHOD0(getUId, std::string()); - MOCK_CONST_METHOD0( getManufacturername, std::string() ); + MOCK_CONST_METHOD0(getManufacturername, std::string()); - MOCK_CONST_METHOD0( getLuminaireUId, std::string() ); + MOCK_CONST_METHOD0(getLuminaireUId, std::string()); - MOCK_METHOD0( getSwVersion, std::string() ); + MOCK_METHOD0(getSwVersion, std::string()); - MOCK_CONST_METHOD0( getSwVersion, std::string() ); + MOCK_CONST_METHOD0(getSwVersion, std::string()); - MOCK_METHOD1( setName, bool(std::string& name)); + MOCK_METHOD1(setName, bool(std::string& name)); - MOCK_CONST_METHOD0( getColorType, ColorType() ); + MOCK_CONST_METHOD0(getColorType, ColorType()); - MOCK_CONST_METHOD0( hasBrightnessControl, bool() ); + MOCK_CONST_METHOD0(hasBrightnessControl, bool()); - MOCK_CONST_METHOD0( hasTemperatureControl, bool() ); + MOCK_CONST_METHOD0(hasTemperatureControl, bool()); - MOCK_CONST_METHOD0( hasColorControl, bool() ); + MOCK_CONST_METHOD0(hasColorControl, bool()); - MOCK_METHOD2( setBrightness, bool(unsigned int bri, uint8_t transition) ); + MOCK_METHOD2(setBrightness, bool(unsigned int bri, uint8_t transition)); - MOCK_CONST_METHOD0( getBrightness, unsigned int() ); + MOCK_CONST_METHOD0(getBrightness, unsigned int()); - MOCK_METHOD0( getBrightness, unsigned int() ); + MOCK_METHOD0(getBrightness, unsigned int()); - MOCK_METHOD2( setColorTemperature, bool(unsigned int mired, uint8_t transition) ); + MOCK_METHOD2(setColorTemperature, bool(unsigned int mired, uint8_t transition)); - MOCK_CONST_METHOD0( getColorTemperature, unsigned int() ); + MOCK_CONST_METHOD0(getColorTemperature, unsigned int()); - MOCK_METHOD0( getColorTemperature, unsigned int() ); + MOCK_METHOD0(getColorTemperature, unsigned int()); - MOCK_METHOD2( setColorHue, bool(uint16_t hue, uint8_t transition) ); + MOCK_METHOD2(setColorHue, bool(uint16_t hue, uint8_t transition)); - MOCK_METHOD2( setColorSaturation, bool(uint8_t sat, uint8_t transition) ); + MOCK_METHOD2(setColorSaturation, bool(uint8_t sat, uint8_t transition)); - MOCK_METHOD3( setColorHueSaturation, bool(uint16_t hue, uint8_t sat, uint8_t transition) ); + MOCK_METHOD3(setColorHueSaturation, bool(uint16_t hue, uint8_t sat, uint8_t transition)); - MOCK_CONST_METHOD0( getColorHueSaturation, std::pair() ); + MOCK_CONST_METHOD0(getColorHueSaturation, std::pair()); - MOCK_METHOD0( getColorHueSaturation, std::pair() ); + MOCK_METHOD0(getColorHueSaturation, std::pair()); - MOCK_METHOD3( setColorXY, bool(float x, float y, uint8_t transition) ); + MOCK_METHOD3(setColorXY, bool(float x, float y, uint8_t transition)); - MOCK_CONST_METHOD0( getColorXY, std::pair() ); + MOCK_CONST_METHOD0(getColorXY, std::pair()); - MOCK_METHOD0( getColorXY, std::pair() ); + MOCK_METHOD0(getColorXY, std::pair()); - MOCK_METHOD4( setColorRGB, bool(uint8_t r, uint8_t g, uint8_t b, uint8_t transition) ); + MOCK_METHOD4(setColorRGB, bool(uint8_t r, uint8_t g, uint8_t b, uint8_t transition)); - MOCK_METHOD0( alert, bool() ); + MOCK_METHOD0(alert, bool()); - MOCK_METHOD1( alertTemperature, bool(unsigned int mired) ); + MOCK_METHOD1(alertTemperature, bool(unsigned int mired)); - MOCK_METHOD2( alertHueSaturation, bool(uint16_t hue, uint8_t sat) ); + MOCK_METHOD2(alertHueSaturation, bool(uint16_t hue, uint8_t sat)); - MOCK_METHOD2( alertXY, bool(float x, float y) ); + MOCK_METHOD2(alertXY, bool(float x, float y)); - MOCK_METHOD3( alertRGB, bool(uint8_t r, uint8_t g, uint8_t b) ); + MOCK_METHOD3(alertRGB, bool(uint8_t r, uint8_t g, uint8_t b)); - MOCK_METHOD1( setColorLoop, bool(bool on) ); + MOCK_METHOD1(setColorLoop, bool(bool on)); - MOCK_METHOD1( OnNoRefresh, bool(uint8_t transition) ); + MOCK_METHOD1(OnNoRefresh, bool(uint8_t transition)); - MOCK_METHOD1( OffNoRefresh, bool(uint8_t transition) ); + MOCK_METHOD1(OffNoRefresh, bool(uint8_t transition)); - MOCK_METHOD2( SendPutRequest, Json::Value(const Json::Value& request, const std::string& subPath) ); + MOCK_METHOD2(SendPutRequest, Json::Value(const Json::Value& request, const std::string& subPath)); - MOCK_METHOD0( refreshState, void() ); + MOCK_METHOD0(refreshState, void()); }; #endif diff --git a/hueplusplus/test/test_ExtendedColorHueStrategy.cpp b/hueplusplus/test/test_ExtendedColorHueStrategy.cpp index 188bdc0..a26e704 100755 --- a/hueplusplus/test/test_ExtendedColorHueStrategy.cpp +++ b/hueplusplus/test/test_ExtendedColorHueStrategy.cpp @@ -15,15 +15,15 @@ TEST(ExtendedColorHueStrategy, alertHueSaturation) using namespace ::testing; std::shared_ptr handler(std::make_shared()); EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", Json::Value(Json::objectValue), bridge_ip, 80)) - .Times(AtLeast(1)) - .WillRepeatedly(Return(Json::Value(Json::objectValue))); + .Times(AtLeast(1)) + .WillRepeatedly(Return(Json::Value(Json::objectValue))); MockHueLight test_light(handler); EXPECT_CALL(test_light, refreshState()) .Times(AtLeast(1)) .WillRepeatedly(Return()); test_light.getState()["state"]["colormode"] = "invalid"; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertHueSaturation(30000, 128, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertHueSaturation(30000, 128, test_light)); EXPECT_CALL(test_light, setColorHueSaturation(_, _, 1)) .Times(AtLeast(2)) @@ -33,21 +33,21 @@ TEST(ExtendedColorHueStrategy, alertHueSaturation) test_light.getState()["state"]["on"] = true; test_light.getState()["state"]["sat"] = 100; test_light.getState()["state"]["hue"] = 200; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); - EXPECT_EQ( true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, setColorHueSaturation(_, _, 1)) .Times(AtLeast(2)) @@ -57,24 +57,24 @@ TEST(ExtendedColorHueStrategy, alertHueSaturation) test_light.getState()["state"]["on"] = true; test_light.getState()["state"]["xy"][0] = 0.1; test_light.getState()["state"]["xy"][1] = 0.1; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, setColorXY(_, _, 1)) .Times(AtLeast(2)) .WillRepeatedly(Return(true)); - EXPECT_EQ( true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, setColorHueSaturation(_, _, 1)) .Times(AtLeast(2)) @@ -83,24 +83,24 @@ TEST(ExtendedColorHueStrategy, alertHueSaturation) test_light.getState()["state"]["colormode"] = "ct"; test_light.getState()["state"]["on"] = true; test_light.getState()["state"]["ct"] = 200; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, setColorTemperature(_, 1)) .Times(AtLeast(2)) .WillRepeatedly(Return(true)); - EXPECT_EQ( true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertHueSaturation(200, 100, test_light)); } TEST(ExtendedColorHueStrategy, alertXY) @@ -108,15 +108,15 @@ TEST(ExtendedColorHueStrategy, alertXY) using namespace ::testing; std::shared_ptr handler(std::make_shared()); EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", Json::Value(Json::objectValue), bridge_ip, 80)) - .Times(AtLeast(1)) - .WillRepeatedly(Return(Json::Value(Json::objectValue))); + .Times(AtLeast(1)) + .WillRepeatedly(Return(Json::Value(Json::objectValue))); MockHueLight test_light(handler); EXPECT_CALL(test_light, refreshState()) .Times(AtLeast(1)) .WillRepeatedly(Return()); test_light.getState()["state"]["colormode"] = "invalid"; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, setColorXY(_, _, 1)) .Times(AtLeast(2)) @@ -128,24 +128,24 @@ TEST(ExtendedColorHueStrategy, alertXY) test_light.getState()["state"]["xy"][1] = 0.1; test_light.getState()["state"]["sat"] = 100; test_light.getState()["state"]["hue"] = 200; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, setColorHueSaturation(_, _, 1)) .Times(AtLeast(2)) .WillRepeatedly(Return(true)); - EXPECT_EQ( true, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, setColorXY(_, _, 1)) .Times(AtLeast(2)) @@ -153,21 +153,21 @@ TEST(ExtendedColorHueStrategy, alertXY) .WillRepeatedly(Return(true)); test_light.getState()["state"]["colormode"] = "xy"; test_light.getState()["state"]["on"] = true; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); - EXPECT_EQ( true, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, setColorXY(_, _, 1)) .Times(AtLeast(2)) @@ -176,24 +176,24 @@ TEST(ExtendedColorHueStrategy, alertXY) test_light.getState()["state"]["colormode"] = "ct"; test_light.getState()["state"]["on"] = true; test_light.getState()["state"]["ct"] = 200; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, setColorTemperature(_, 1)) .Times(AtLeast(2)) .WillRepeatedly(Return(true)); - EXPECT_EQ( true, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, ExtendedColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertXY(0.1f, 0.1f, test_light)); } TEST(ExtendedColorHueStrategy, alertRGB) @@ -201,15 +201,15 @@ TEST(ExtendedColorHueStrategy, alertRGB) using namespace ::testing; std::shared_ptr handler(std::make_shared()); EXPECT_CALL(*handler, GETJson("/api/" + bridge_username + "/lights/1", Json::Value(Json::objectValue), bridge_ip, 80)) - .Times(AtLeast(1)) - .WillRepeatedly(Return(Json::Value(Json::objectValue))); + .Times(AtLeast(1)) + .WillRepeatedly(Return(Json::Value(Json::objectValue))); MockHueLight test_light(handler); EXPECT_CALL(test_light, refreshState()) .Times(AtLeast(1)) .WillRepeatedly(Return()); test_light.getState()["state"]["colormode"] = "invalid"; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, setColorRGB(_, _, _, 1)) .Times(AtLeast(2)) @@ -219,24 +219,24 @@ TEST(ExtendedColorHueStrategy, alertRGB) test_light.getState()["state"]["on"] = true; test_light.getState()["state"]["sat"] = 100; test_light.getState()["state"]["hue"] = 200; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, setColorHueSaturation(_, _, 1)) .Times(AtLeast(2)) .WillRepeatedly(Return(true)); - EXPECT_EQ( true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, setColorRGB(_, _, _, 1)) .Times(AtLeast(2)) @@ -246,24 +246,24 @@ TEST(ExtendedColorHueStrategy, alertRGB) test_light.getState()["state"]["on"] = true; test_light.getState()["state"]["xy"][0] = 0.1; test_light.getState()["state"]["xy"][1] = 0.1; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, setColorXY(_, _, 1)) .Times(AtLeast(2)) .WillRepeatedly(Return(true)); - EXPECT_EQ( true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, setColorRGB(_, _, _, 1)) .Times(AtLeast(2)) @@ -272,22 +272,22 @@ TEST(ExtendedColorHueStrategy, alertRGB) test_light.getState()["state"]["colormode"] = "ct"; test_light.getState()["state"]["on"] = true; test_light.getState()["state"]["ct"] = 200; - EXPECT_EQ( false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(false, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, setColorTemperature(_, 1)) .Times(AtLeast(2)) .WillRepeatedly(Return(true)); - EXPECT_EQ( true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light) ); + EXPECT_EQ(true, ExtendedColorHueStrategy().alertRGB(128, 128, 128, test_light)); } diff --git a/hueplusplus/test/test_SimpleColorHueStrategy.cpp b/hueplusplus/test/test_SimpleColorHueStrategy.cpp index 41acd38..49245d8 100755 --- a/hueplusplus/test/test_SimpleColorHueStrategy.cpp +++ b/hueplusplus/test/test_SimpleColorHueStrategy.cpp @@ -150,10 +150,10 @@ TEST(SimpleColorHueStrategy, setColorXY) test_light.getState()["state"]["xy"][0] = 0.1; test_light.getState()["state"]["xy"][1] = 0.1; test_light.getState()["state"]["colormode"] = "xy"; - EXPECT_EQ( true, SimpleColorHueStrategy().setColorXY(0.1, 0.1, 4, test_light) ); + EXPECT_EQ( true, SimpleColorHueStrategy().setColorXY(0.1f, 0.1f, 4, test_light) ); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, SimpleColorHueStrategy().setColorXY(0.2355, 0.1234, 6, test_light) ); + EXPECT_EQ( true, SimpleColorHueStrategy().setColorXY(0.2355f, 0.1234f, 6, test_light) ); } TEST(SimpleColorHueStrategy, setColorRGB) @@ -290,7 +290,7 @@ TEST(SimpleColorHueStrategy, alertXY) .WillRepeatedly(Return()); test_light.getState()["state"]["colormode"] = "invalid"; - EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1f, 0.1f, test_light) ); EXPECT_CALL(test_light, setColorXY(_, _, 1)) .Times(AtLeast(2)) @@ -302,24 +302,24 @@ TEST(SimpleColorHueStrategy, alertXY) test_light.getState()["state"]["xy"][1] = 0.1; test_light.getState()["state"]["sat"] = 100; test_light.getState()["state"]["hue"] = 200; - EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1f, 0.1f, test_light) ); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1f, 0.1f, test_light) ); EXPECT_CALL(test_light, setColorHueSaturation(_, _, 1)) .Times(AtLeast(2)) .WillRepeatedly(Return(true)); - EXPECT_EQ( true, SimpleColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ( true, SimpleColorHueStrategy().alertXY(0.1f, 0.1f, test_light) ); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, SimpleColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ( true, SimpleColorHueStrategy().alertXY(0.1f, 0.1f, test_light) ); EXPECT_CALL(test_light, setColorXY(_, _, 1)) .Times(AtLeast(2)) @@ -327,21 +327,21 @@ TEST(SimpleColorHueStrategy, alertXY) .WillRepeatedly(Return(true)); test_light.getState()["state"]["colormode"] = "xy"; test_light.getState()["state"]["on"] = true; - EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1f, 0.1f, test_light) ); EXPECT_CALL(test_light, alert()) .Times(AtLeast(2)) .WillOnce(Return(false)) .WillRepeatedly(Return(true)); - EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ( false, SimpleColorHueStrategy().alertXY(0.1f, 0.1f, test_light) ); - EXPECT_EQ( true, SimpleColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ( true, SimpleColorHueStrategy().alertXY(0.1f, 0.1f, test_light) ); EXPECT_CALL(test_light, OffNoRefresh(_)) .Times(AtLeast(1)) .WillRepeatedly(Return(true)); test_light.getState()["state"]["on"] = false; - EXPECT_EQ( true, SimpleColorHueStrategy().alertXY(0.1, 0.1, test_light) ); + EXPECT_EQ( true, SimpleColorHueStrategy().alertXY(0.1f, 0.1f, test_light) ); } TEST(SimpleColorHueStrategy, alertRGB) -- libgit2 0.21.4