From 69254c49db051dca7f1ac71c08c9f2966346cd27 Mon Sep 17 00:00:00 2001 From: Stefan Herbrechtsmeier Date: Fri, 17 Apr 2020 11:15:25 +0200 Subject: [PATCH] Add sensor support --- include/hueplusplus/Hue.h | 1 + include/hueplusplus/HueLight.h | 59 +++++++++++++++++++++++++++-------------------------------- include/hueplusplus/HueSensor.h | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/hueplusplus/HueThing.h | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 2 ++ src/Hue.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++++- src/HueLight.cpp | 58 +++------------------------------------------------------- src/HueSensor.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/HueThing.cpp | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 554 insertions(+), 88 deletions(-) create mode 100644 include/hueplusplus/HueSensor.h create mode 100644 include/hueplusplus/HueThing.h create mode 100644 src/HueSensor.cpp create mode 100644 src/HueThing.cpp diff --git a/include/hueplusplus/Hue.h b/include/hueplusplus/Hue.h index 4b69abd..50361b1 100644 --- a/include/hueplusplus/Hue.h +++ b/include/hueplusplus/Hue.h @@ -38,6 +38,7 @@ #include "HueCommandAPI.h" #include "HueDeviceTypes.h" #include "HueLight.h" +#include "HueSensor.h" #include "IHttpHandler.h" #include "ResourceList.h" #include "Scene.h" diff --git a/include/hueplusplus/HueLight.h b/include/hueplusplus/HueLight.h index 00907ab..0fe38e3 100644 --- a/include/hueplusplus/HueLight.h +++ b/include/hueplusplus/HueLight.h @@ -30,6 +30,7 @@ #include "ColorHueStrategy.h" #include "ColorTemperatureStrategy.h" #include "HueCommandAPI.h" +#include "HueThing.h" #include "StateTransaction.h" #include "json/json.hpp" @@ -95,7 +96,7 @@ enum class ColorType //! \brief Class for Hue Light fixtures //! //! Provides methods to query and control lights. -class HueLight +class HueLight : public HueThing { friend class HueLightFactory; friend class SimpleBrightnessStrategy; @@ -111,6 +112,31 @@ public: //! \name General information ///@{ + //! \brief Function that turns the light off. + //! + //! \param transition Optional parameter to set the transition from current state to new, standard is 4 = 400ms + //! \return Bool that is true on success + //! \throws std::system_error when system or socket operations fail + //! \throws HueException when response contained no body + //! \throws HueAPIResponseException when response contains an error + //! \throws nlohmann::json::parse_error when response could not be parsed + virtual bool Off(uint8_t transition = 4); + + //! \brief Function to check whether a light is on or off + //! + //! \return Bool that is true, when the light is on and false, when off + //! \throws std::system_error when system or socket operations fail + //! \throws HueException when response contained no body + //! \throws HueAPIResponseException when response contains an error + //! \throws nlohmann::json::parse_error when response could not be parsed + virtual bool isOn(); + + //! \brief Const function to check whether a light is on or off + //! + //! \note This will not refresh the light state + //! \return Bool that is true, when the light is on and false, when off + virtual bool isOn() const; + //! \brief Const function that returns the id of this light //! //! \return integer representing the light id @@ -118,13 +144,7 @@ public: //! \brief Const function that returns the light type //! - //! The type determines which functions the light has. //! \return String containing the type - //! - "On/Off light": on/off - //! - "Dimmable light": on/off, brightness - //! - "Color light": on/off, brightness, color hue/sat/xy - //! - "Color temperature light": on/off, brightness, color temperature - //! - "Extended color light": on/off, brightness, color temperature, color hue/sat/xy virtual std::string getType() const; //! \brief Function that returns the name of the light. @@ -142,15 +162,6 @@ public: //! \return String containig the name of the light virtual std::string getName() const; - //! \brief Function that sets the name of the light - //! - //! \return Bool that is true on success - //! \throws std::system_error when system or socket operations fail - //! \throws HueException when response contained no body - //! \throws HueAPIResponseException when response contains an error - //! \throws nlohmann::json::parse_error when response could not be parsed - virtual bool setName(const std::string& name); - //! \brief Const function that returns the modelid of the light //! //! \return String conatining the modelid @@ -180,22 +191,6 @@ public: //! \return String containing the luminaireuniqueid or an empty string when the function is not supported virtual std::string getLuminaireUId() const; - //! \brief Function that returns the software version of the light - //! - //! \return String containing the software version - //! \throws std::system_error when system or socket operations fail - //! \throws HueException when response contained no body - //! \throws HueAPIResponseException when response contains an error - //! \throws nlohmann::json::parse_error when response could not be parsed - virtual std::string getSwVersion(); - - //! \brief Const function that returns the software version of the light - //! - //! \note This will not refresh the light state - //! \return String containing the software version - virtual std::string getSwVersion() const; - - //! \brief Const function that returns the color type of the light. //! //! \return ColorType containig the color type of the light diff --git a/include/hueplusplus/HueSensor.h b/include/hueplusplus/HueSensor.h new file mode 100644 index 0000000..5199b6e --- /dev/null +++ b/include/hueplusplus/HueSensor.h @@ -0,0 +1,98 @@ +/** + \file HueSensor.h + Copyright Notice\n + Copyright (C) 2020 Stefan Herbrechtsmeier - 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_HUE_SENSOR_H +#define INCLUDE_HUEPLUSPLUS_HUE_SENSOR_H + +#include + +#include "HueCommandAPI.h" +#include "HueThing.h" + +#include "json/json.hpp" + +namespace hueplusplus +{ +//! +//! Class for Hue Sensor fixtures +//! +class HueSensor : public HueThing +{ + friend class Hue; + +public: + //! \brief std dtor + ~HueSensor() = default; + + //! \brief Function to get button event + //! + //! \return integer representing the button event + //! \throws std::system_error when system or socket operations fail + //! \throws HueException when response contained no body + //! \throws HueAPIResponseException when response contains an error + //! \throws nlohmann::json::parse_error when response could not be parsed + virtual int getButtonEvent(); + + //! \brief Const function to get button event + //! + //! \note This will not refresh the sensor state + //! \return integer representing the button event + virtual int getButtonEvent() const; + + //! \brief Function to get sensor status + //! + //! \return integer representing the status + //! \throws std::system_error when system or socket operations fail + //! \throws HueException when response contained no body + //! \throws HueAPIResponseException when response contains an error + //! \throws nlohmann::json::parse_error when response could not be parsed + virtual int getStatus(); + + //! \brief Const function to get sensor status + //! + //! \note This will not refresh the sensor state + //! \return integer representing the button event + virtual int getStatus() const; + + //! \brief Const function to check whether this sensor has a button event + //! + //! \return Bool that is true when the sensor has specified abilities and false + //! when not + virtual bool hasButtonEvent() const; + + //! \brief Const function to check whether this sensor has a status + //! + //! \return Bool that is true when the sensor has specified abilities and false + //! when not + virtual bool hasStatus() const; + +protected: + //! \brief Protected ctor that is used by \ref Hue class. + //! + //! \param id Integer that specifies the id of this sensor + //! \param commands HueCommandAPI for communication with the bridge + //! + //! leaves strategies unset + HueSensor(int id, const HueCommandAPI& commands); +}; +} // namespace hueplusplus + +#endif diff --git a/include/hueplusplus/HueThing.h b/include/hueplusplus/HueThing.h new file mode 100644 index 0000000..833333b --- /dev/null +++ b/include/hueplusplus/HueThing.h @@ -0,0 +1,159 @@ +/** + \file HueThing.h + Copyright Notice\n + Copyright (C) 2017 Jan Rogall - developer\n + Copyright (C) 2017 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_HUE_THING_H +#define INCLUDE_HUEPLUSPLUS_HUE_THING_H + +#include + +#include "HueCommandAPI.h" + +#include "json/json.hpp" + +namespace hueplusplus +{ +//! +//! Class for Hue Thing fixtures +//! +class HueThing +{ +public: + //! \brief std dtor + ~HueThing() = default; + + //! \brief Const function that returns the id of this thing + //! + //! \return integer representing the thing id + virtual int getId() const; + + //! \brief Const function that returns the thing type + //! + //! \return String containing the type + virtual std::string getType() const; + + //! \brief Function that returns the name of the thing. + //! + //! \return String containig the name of the thing + //! \throws std::system_error when system or socket operations fail + //! \throws HueException when response contained no body + //! \throws HueAPIResponseException when response contains an error + //! \throws nlohmann::json::parse_error when response could not be parsed + virtual std::string getName(); + + //! \brief Const function that returns the name of the thing. + //! + //! \note This will not refresh the thing state + //! \return String containig the name of the thing + virtual std::string getName() const; + + //! \brief Const function that returns the modelid of the thing + //! + //! \return String conatining the modelid + virtual std::string getModelId() const; + + //! \brief Const function that returns the uniqueid of the thing + //! + //! \note Only working on bridges with versions starting at 1.4 + //! \return String containing the uniqueid or an empty string when the function is not supported + virtual std::string getUId() const; + + //! \brief Const function that returns the manufacturername of the thing + //! + //! \note Only working on bridges with versions starting at 1.7 + //! \return String containing the manufacturername or an empty string when the function is not supported + virtual std::string getManufacturername() const; + + //! \brief Const function that returns the productname of the thing + //! + //! \note Only working on bridges with versions starting at 1.24 + //! \return String containing the productname or an empty string when the function is not supported + virtual std::string getProductname() const; + + //! \brief Function that returns the software version of the thing + //! + //! \return String containing the software version + //! \throws std::system_error when system or socket operations fail + //! \throws HueException when response contained no body + //! \throws HueAPIResponseException when response contains an error + //! \throws nlohmann::json::parse_error when response could not be parsed + virtual std::string getSwVersion(); + + //! \brief Const function that returns the software version of the thing + //! + //! \note This will not refresh the thing state + //! \return String containing the software version + virtual std::string getSwVersion() const; + + //! \brief Function that sets the name of the thing + //! + //! \return Bool that is true on success + //! \throws std::system_error when system or socket operations fail + //! \throws HueException when response contained no body + //! \throws HueAPIResponseException when response contains an error + //! \throws nlohmann::json::parse_error when response could not be parsed + virtual bool setName(const std::string& name); + +protected: + //! \brief Protected ctor that is used by \ref Hue class. + //! + //! \param id Integer that specifies the id of this thing + //! \param commands HueCommandAPI for communication with the bridge + //! + //! leaves strategies unset + HueThing(int id, const HueCommandAPI& commands, const std::string& path); + + //! \brief Protected function that sets the HueCommandAPI. + //! + //! The HueCommandAPI is used for bridge communication + //! \param commandAPI the new HueCommandAPI + virtual void setCommandAPI(const HueCommandAPI& commandAPI) { commands = commandAPI; }; + + //! \brief Utility function to send a put request to the thing. + //! + //! \throws nlohmann::json::parse_error if the reply could not be parsed + //! \param request A nlohmann::json aka the request to send + //! \param subPath A path that is appended to the uri, note it should always start with a slash ("/") + //! \param fileInfo FileInfo from calling function for exception details. + //! \return The parsed reply + //! \throws std::system_error when system or socket operations fail + //! \throws HueException when response contained no body + //! \throws HueAPIResponseException when response contains an error + //! \throws nlohmann::json::parse_error when response could not be parsed + virtual nlohmann::json SendPutRequest(const nlohmann::json& request, const std::string& subPath, FileInfo fileInfo); + + //! \brief Virtual function that refreshes the \ref state of the thing. + //! \throws std::system_error when system or socket operations fail + //! \throws HueException when response contained no body + //! \throws HueAPIResponseException when response contains an error + //! \throws nlohmann::json::parse_error when response could not be parsed + virtual void refreshState(); + +protected: + int id; //!< holds the id of the thing + std::string path; //!< holds the path of the thing + nlohmann::json state; //!< holds the current state of the thing updated by \ref refreshState + + HueCommandAPI commands; //!< A IHttpHandler that is used to communicate with the bridge +}; +} // namespace hueplusplus + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9754d5c..9749dcb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,8 @@ set(hueplusplus_SOURCES ModelPictures.cpp Scene.cpp Schedule.cpp + HueSensor.cpp + HueThing.cpp SimpleBrightnessStrategy.cpp SimpleColorHueStrategy.cpp SimpleColorTemperatureStrategy.cpp diff --git a/src/Hue.cpp b/src/Hue.cpp index f06400f..93834df 100644 --- a/src/Hue.cpp +++ b/src/Hue.cpp @@ -231,6 +231,35 @@ const BridgeConfig& Hue::config() const return bridgeConfig; } +HueSensor& Hue::getSensor(int id) +{ + auto pos = sensors.find(id); + if (pos != sensors.end()) + { + pos->second.refreshState(); + return pos->second; + } + refreshState(); + if (!state["sensors"].count(std::to_string(id))) + { + std::cerr << "Error in Hue getSensor(): sensor with id " << id << " is not valid\n"; + throw HueException(CURRENT_FILE_INFO, "Sensor id is not valid"); + } + // std::cout << state["sensors"][std::to_string(id)] << std::endl; + std::string type = state["sensors"][std::to_string(id)]["modelid"]; + // std::cout << type << std::endl; + if (type == "RWL021" || type == "PHDL00" || type == "PHWA01") + { + // Hue dimmer switch + HueSensor sensor = HueSensor(id, commands); + sensors.emplace(id, sensor); + return sensors.find(id)->second; + } + std::cerr << "Could not determine HueSensor type:" << type << "!\n"; + throw HueException(CURRENT_FILE_INFO, "Could not determine HueSensor type!"); +} + + Hue::LightList& Hue::lights() { return lightList; @@ -246,7 +275,23 @@ Hue::GroupList& Hue::groups() return groupList; } -const Hue::GroupList& Hue::groups() const +std::vector> Hue::getAllSensors() +{ + refreshState(); + nlohmann::json sensorsState = state["sensors"]; + for (nlohmann::json::iterator it = sensorsState.begin(); it != sensorsState.end(); ++it) + { + getSensor(std::stoi(it.key())); + } + std::vector> result; + for (auto& entry : sensors) + { + result.emplace_back(entry.second); + } + return result; +} + +bool Hue::lightExists(int id) { return groupList; } diff --git a/src/HueLight.cpp b/src/HueLight.cpp index da17a2f..0f0f1dd 100644 --- a/src/HueLight.cpp +++ b/src/HueLight.cpp @@ -27,6 +27,7 @@ #include #include "hueplusplus/HueExceptionMacro.h" +#include "hueplusplus/HueThing.h" #include "hueplusplus/Utils.h" #include "json/json.hpp" @@ -52,46 +53,6 @@ bool HueLight::isOn() const return state.getValue().at("state").at("on").get(); } -int HueLight::getId() const -{ - return id; -} - -std::string HueLight::getType() const -{ - return state.getValue()["type"].get(); -} - -std::string HueLight::getName() -{ - return state.getValue()["name"].get(); -} - -std::string HueLight::getName() const -{ - return state.getValue()["name"].get(); -} - -std::string HueLight::getModelId() const -{ - return state.getValue()["modelid"].get(); -} - -std::string HueLight::getUId() const -{ - return state.getValue().value("uniqueid", std::string()); -} - -std::string HueLight::getManufacturername() const -{ - return state.getValue().value("manufacturername", std::string()); -} - -std::string HueLight::getProductname() const -{ - return state.getValue().value("productname", std::string()); -} - std::string HueLight::getLuminaireUId() const { return state.getValue().value("luminaireuniqueid", std::string()); @@ -107,18 +68,6 @@ std::string HueLight::getSwVersion() const return state.getValue()["swversion"].get(); } -bool HueLight::setName(const std::string& name) -{ - nlohmann::json request = nlohmann::json::object(); - request["name"] = name; - nlohmann::json reply = sendPutRequest(request, "/name", CURRENT_FILE_INFO); - state.refresh(); - - // Check whether request was successful (returned name is not necessarily the actually set name) - // If it already exists, a number is added, if it is too long to be returned, "Updated" is returned - return utils::safeGetMember(reply, 0, "success", "/lights/" + std::to_string(id) + "/name").is_string(); -} - ColorType HueLight::getColorType() const { return colorType; @@ -183,9 +132,8 @@ HueLight::HueLight(int id, const HueCommandAPI& commands) : HueLight(id, command HueLight::HueLight(int id, const HueCommandAPI& commands, std::shared_ptr brightnessStrategy, std::shared_ptr colorTempStrategy, - std::shared_ptr colorHueStrategy, std::chrono::steady_clock::duration refreshDuration) - : id(id), - state("/lights/" + std::to_string(id), commands, refreshDuration), + std::shared_ptr colorHueStrategy, chrono::steady_clock::duration refreshDuration) + : HueThing(id, commands, "/lights/"), colorType(ColorType::NONE), brightnessStrategy(std::move(brightnessStrategy)), colorTemperatureStrategy(std::move(colorTempStrategy)), diff --git a/src/HueSensor.cpp b/src/HueSensor.cpp new file mode 100644 index 0000000..c5cafc2 --- /dev/null +++ b/src/HueSensor.cpp @@ -0,0 +1,82 @@ +/** + \file HueSensor.cpp + Copyright Notice\n + Copyright (C) 2020 Stefan Herbrechtsmeier - 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 . +**/ + +#include "hueplusplus/HueSensor.h" + +#include "hueplusplus/HueThing.h" +#include "json/json.hpp" + +namespace hueplusplus +{ +int HueSensor::getButtonEvent() +{ + refreshState(); + if (hasButtonEvent()) + { + return state["state"]["buttonevent"]; + } + return 0; +} + +int HueSensor::getButtonEvent() const +{ + if (hasButtonEvent()) + { + return state["state"]["buttonevent"]; + } + return 0; +} + +int HueSensor::getStatus() +{ + refreshState(); + if (hasStatus()) + { + return state["state"]["status"]; + } + return 0; +} + +int HueSensor::getStatus() const +{ + if (hasStatus()) + { + return state["state"]["status"]; + } + return 0; +} + +bool HueSensor::hasButtonEvent() const +{ + return state["state"].count("buttonevent") > 0; +} + +bool HueSensor::hasStatus() const +{ + return state["state"].count("status") > 0; +} + +HueSensor::HueSensor(int id, const HueCommandAPI& commands) + : HueThing(id, commands, "/sensors/") +{ + refreshState(); +} +} // namespace hueplusplus diff --git a/src/HueThing.cpp b/src/HueThing.cpp new file mode 100644 index 0000000..2fc7af4 --- /dev/null +++ b/src/HueThing.cpp @@ -0,0 +1,136 @@ +/** + \file HueThing.cpp + Copyright Notice\n + Copyright (C) 2020 Stefan Herbrechtsmeier - 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 . +**/ + +#include "hueplusplus/HueThing.h" + +#include +#include +#include + +#include "hueplusplus/HueExceptionMacro.h" +#include "hueplusplus/Utils.h" +#include "json/json.hpp" + +namespace hueplusplus +{ +int HueThing::getId() const +{ + return id; +} + +std::string HueThing::getType() const +{ + return state["type"]; +} + +std::string HueThing::getName() +{ + refreshState(); + return state["name"]; +} + +std::string HueThing::getName() const +{ + return state["name"]; +} + +std::string HueThing::getModelId() const +{ + return state["modelid"]; +} + +std::string HueThing::getUId() const +{ + if (state.count("uniqueid")) + { + return state["uniqueid"]; + } + return std::string(); +} + +std::string HueThing::getManufacturername() const +{ + if (state.count("manufacturername")) + { + return state["manufacturername"]; + } + return std::string(); +} + +std::string HueThing::getProductname() const +{ + if (state.count("productname")) + { + return state["productname"]; + } + return std::string(); +} + +std::string HueThing::getSwVersion() +{ + refreshState(); + return state["swversion"]; +} + +std::string HueThing::getSwVersion() const +{ + return state["swversion"]; +} + +bool HueThing::setName(const std::string& name) +{ + nlohmann::json request = nlohmann::json::object(); + request["name"] = name; + nlohmann::json reply = SendPutRequest(request, "/name", CURRENT_FILE_INFO); + + // Check whether request was successful + return utils::safeGetMember(reply, 0, "success", path + std::to_string(id) + "/name") == name; +} + +HueThing::HueThing(int id, const HueCommandAPI& commands, const std::string& path) + : id(id), + commands(commands), + path(path) +{ + refreshState(); +} + +nlohmann::json HueThing::SendPutRequest(const nlohmann::json& request, const std::string& subPath, FileInfo fileInfo) +{ + return commands.PUTRequest(path + std::to_string(id) + subPath, request, std::move(fileInfo)); +} + +void HueThing::refreshState() +{ + nlohmann::json answer + = commands.GETRequest(path + std::to_string(id), nlohmann::json::object(), CURRENT_FILE_INFO); + if (answer.count("state")) + { + state = answer; + } + else + { + std::cout << "Answer in HueThing::refreshState of " + "http_handler->GETJson(...) is not expected!\nAnswer:\n\t" + << answer.dump() << std::endl; + } +} +} // namespace hueplusplus -- libgit2 0.21.4