diff --git a/include/hueplusplus/Group.h b/include/hueplusplus/Group.h new file mode 100644 index 0000000..c4e65ae --- /dev/null +++ b/include/hueplusplus/Group.h @@ -0,0 +1,86 @@ +/** + \file Group.h + Copyright Notice\n + Copyright (C) 2020 Jan Rogall - developer\n + Copyright (C) 2020 Moritz Wirger - developer\n + + This file is part of hueplusplus. + + hueplusplus is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hueplusplus 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with hueplusplus. If not, see . +**/ + +#ifndef INCLUDE_HUEPLUSPLUS_GROUP_H +#define INCLUDE_HUEPLUSPLUS_GROUP_H + +#include +#include + +#include "APICache.h" +#include "HueCommandAPI.h" + +#include "json/json.hpp" + +namespace hueplusplus +{ + class Group + { + public: + Group(int id, const HueCommandAPI& commands); + + virtual ~Group() = default; + + int getId() const; + std::string getName() const; + std::string getType() const; + std::vector getLightIds() const; + + void setName(const std::string& name); + void setLights(const std::vector& ids); + + std::string getRoomType() const; + void setRoomType(const std::string& type); + + bool getAllOn() const; + bool getAnyOn() const; + + bool getActionOn() const; + std::pair getActionHueSaturation() const; + unsigned int getActionBrightness() const; + unsigned int getActionColorTemperature() const; + std::pair getActionColorXY() const; + std::string getActionColorMode() const; + + void setOn(bool on, uint8_t transition = 4); + void setBrightness(uint8_t brightness, uint8_t transition = 4); + void setColorHueSaturation(uint16_t hue, uint8_t saturation, uint8_t transition = 4); + void setColorXY(float x, float y, uint8_t transition = 4); + void setColorTemperature(unsigned int mired, uint8_t transition = 4); + void setColorLoop(bool on, uint8_t transition = 4); + void incrementBrightness(int increment, uint8_t transition = 4); + void incrementSaturation(int increment, uint8_t transition = 4); + void incrementHue(int increment, uint8_t transition = 4); + void incrementColorTemperature(int increment, uint8_t transition = 4); + void incrementColorXY(float increment, uint8_t transition = 4); + void setScene(const std::string& scene, uint8_t transition = 4); + protected: + nlohmann::json SendPutRequest(const nlohmann::json& request, const std::string& subPath, FileInfo fileInfo); + + protected: + int id; + APICache state; + HueCommandAPI commands; + }; +} // namespace hueplusplus + +#endif \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 655ce42..c7d1f74 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ set(hueplusplus_SOURCES BaseHttpHandler.cpp ExtendedColorHueStrategy.cpp ExtendedColorTemperatureStrategy.cpp + Group.cpp Hue.cpp HueCommandAPI.cpp HueDeviceTypes.cpp diff --git a/src/Group.cpp b/src/Group.cpp new file mode 100644 index 0000000..ae677b5 --- /dev/null +++ b/src/Group.cpp @@ -0,0 +1,229 @@ +#include "hueplusplus/Group.h" + +#include "hueplusplus/HueExceptionMacro.h" + +hueplusplus::Group::Group(int id, const HueCommandAPI& commands) + : id(id), state("/groups/" + std::to_string(id), commands, std::chrono::seconds(10)), commands(commands) +{} + +int hueplusplus::Group::getId() const +{ + return id; +} + +std::string hueplusplus::Group::getName() const +{ + return state.GetValue().at("name").get(); +} + +std::string hueplusplus::Group::getType() const +{ + return state.GetValue().at("type").get(); +} + +std::vector hueplusplus::Group::getLightIds() const +{ + const nlohmann::json& lights = state.GetValue().at("lights"); + std::vector ids(lights.size()); + for (const nlohmann::json& id : lights) + { + ids.push_back(std::stoi(id.get())); + } + return ids; +} + +void hueplusplus::Group::setName(const std::string& name) +{ + nlohmann::json request = {{"name", name}}; + SendPutRequest(request, "", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::setLights(const std::vector& ids) +{ + nlohmann::json lights = nlohmann::json::array(); + for (int id : ids) + { + lights.push_back(std::to_string(id)); + } + SendPutRequest({{"lights", lights}}, "", CURRENT_FILE_INFO); +} + +bool hueplusplus::Group::getAllOn() const +{ + return state.GetValue().at("state").at("all_on").get(); +} + +bool hueplusplus::Group::getAnyOn() const +{ + return state.GetValue().at("state").at("any_on").get(); +} + +bool hueplusplus::Group::getActionOn() const +{ + return state.GetValue().at("action").at("on").get(); +} + +std::pair hueplusplus::Group::getActionHueSaturation() const +{ + const nlohmann::json& action = state.GetValue().at("action"); + + return std::make_pair(action.at("hue").get(), action.at("sat").get()); +} + +unsigned int hueplusplus::Group::getActionBrightness() const +{ + return state.GetValue().at("action").at("bri").get(); +} + +unsigned int hueplusplus::Group::getActionColorTemperature() const +{ + return state.GetValue().at("action").at("ct").get(); +} + +std::pair hueplusplus::Group::getActionColorXY() const +{ + const nlohmann::json& xy = state.GetValue().at("action").at("xy"); + return std::pair(xy[0].get(), xy[1].get()); +} + +std::string hueplusplus::Group::getActionColorMode() const +{ + return state.GetValue().at("action").at("colormode").get(); +} + +void hueplusplus::Group::setOn(bool on, uint8_t transition) +{ + nlohmann::json request = {{"on", on}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::setBrightness(uint8_t brightness, uint8_t transition) +{ + // TODO: turn on/off + nlohmann::json request = {{"bri", brightness}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::setColorHueSaturation(uint16_t hue, uint8_t saturation, uint8_t transition) +{ + nlohmann::json request = {{"hue", hue}, {"sat", saturation}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::setColorXY(float x, float y, uint8_t transition) +{ + nlohmann::json request = {{"xy", {x, y}}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::setColorTemperature(unsigned int mired, uint8_t transition) +{ + nlohmann::json request = {{"ct", mired}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::setColorLoop(bool on, uint8_t transition) +{ + nlohmann::json request = {{"effect", on ? "colorloop" : "none"}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::incrementBrightness(int increment, uint8_t transition) +{ + nlohmann::json request = {{"bri_inc", increment}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::incrementSaturation(int increment, uint8_t transition) +{ + nlohmann::json request = {{"sat_inc", increment}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::incrementHue(int increment, uint8_t transition) +{ + nlohmann::json request = {{"hue_inc", increment}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::incrementColorTemperature(int increment, uint8_t transition) +{ + nlohmann::json request = {{"ct_inc", increment}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::incrementColorXY(float increment, uint8_t transition) +{ + nlohmann::json request = {{"xy_inc", increment}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +void hueplusplus::Group::setScene(const std::string& scene, uint8_t transition) +{ + nlohmann::json request = {{"scene", scene}}; + if (transition != 4) + { + request["transition"] = transition; + } + SendPutRequest(request, "/action", CURRENT_FILE_INFO); +} + +nlohmann::json hueplusplus::Group::SendPutRequest( + const nlohmann::json& request, const std::string& subPath, FileInfo fileInfo) +{ + return commands.PUTRequest("/groups/" + std::to_string(id) + subPath, request, std::move(fileInfo)); +} + +std::string hueplusplus::Group::getRoomType() const +{ + return state.GetValue().at("class").get(); +} + +void hueplusplus::Group::setRoomType(const std::string& type) +{ + SendPutRequest({{"class", type}}, "", CURRENT_FILE_INFO); +} diff --git a/src/HueCommandAPI.cpp b/src/HueCommandAPI.cpp index 738ff30..7562c1c 100644 --- a/src/HueCommandAPI.cpp +++ b/src/HueCommandAPI.cpp @@ -115,9 +115,15 @@ nlohmann::json HueCommandAPI::HandleError(FileInfo fileInfo, const nlohmann::jso { throw HueAPIResponseException::Create(std::move(fileInfo), response); } - else if (response.is_array() && response.size() > 0 && response[0].count("error")) + else if (response.is_array()) { - throw HueAPIResponseException::Create(std::move(fileInfo), response[0]); + // Check if array contains error response + auto it + = std::find_if(response.begin(), response.end(), [](const nlohmann::json& v) { return v.count("error"); }); + if (it != response.end()) + { + throw HueAPIResponseException::Create(std::move(fileInfo), it.value()); + } } return response; }