Commit fd5fa01a416b8e5489fbc68fdd17212c14393072

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent 3323e501

Add more documentation pages with more detailed instructions, add second example program.

doc/markdown/Build.md 0 → 100644
  1 +# Build and install {#build}
  2 +
  3 +# Basic installation {#basic-install}
  4 +
  5 +## Clone from github {#clone}
  6 +To get the newest version of the hueplusplus library, clone it directly from [github](https://github.com/enwi/hueplusplus).
  7 +The master branch contains the latest tested and stable version, while the development branch is more unstable.
  8 +```{.sh}
  9 +~ $ git clone https://github.com/enwi/hueplusplus.git
  10 +```
  11 +This creates a folder hueplusplus with the library sources.
  12 +
  13 +When you want to update the library for a new version, use pull with rebase.
  14 +```{.sh}
  15 +~/hueplusplus $ git pull --rebase
  16 +```
  17 +
  18 +## Build with CMake {#build-cmake}
  19 +To build the library, you need to use [CMake](https://cmake.org) version 3.8 or higher.
  20 +It is easiest to create a separate build directory where the build files are stored.
  21 +```{.sh}
  22 +~/hueplusplus $ mkdir build
  23 +~/hueplusplus $ cd build
  24 +~/hueplusplus/build $ cmake ..
  25 +~/hueplusplus/build $ make
  26 +```
  27 +
  28 +To install or uninstall the library use the make targets.
  29 +```{.sh}
  30 +~/hueplusplus/build $ make install
  31 +~/hueplusplus/build $ make uninstall
  32 +```
  33 +
  34 +## Use in a CMake project {#import-cmake}
  35 +If you have a project that already uses CMake you probably want to add the hueplusplus library directly in your cmake file.
  36 +For that the best way is to use find_package().
  37 +```{.cmake}
  38 +find_package(hueplusplus REQUIRED)
  39 +```
  40 +But this will only work if the hueplusplus library is already installed.
  41 +Instead, if you have the hueplusplus repository included in your project repository (as a submodule) or know where the folder lives you can do the following:
  42 +```{.cmake}
  43 +find_package(hueplusplus QUIET)
  44 +if(NOT hueplusplus_FOUND)
  45 + message(STATUS "-- hueplusplus not found, building it")
  46 + add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/<path to directory>/hueplusplus" "${CMAKE_CURRENT_BINARY_DIR}/hueplusplus")
  47 +endif()
  48 +```
  49 +This will check if the hueplusplus library was found by find_package() and if not it will use the specified path to the library source and compile it during the build process.
  50 +
  51 +The cmake project defines two library targets: `hueplusplusstatic` to link as a static library and `hueplusplusshared` to link as a shared library.
  52 +```{.cmake}
  53 +target_link_libraries(<executable> PUBLIC hueplusplusstatic)
  54 +```
  55 +
  56 +## Use in another project {#import-other}
  57 +When you are not using CMake, you have to install hueplusplus and change your build configuration to link to the compiled library.
  58 +The header files in the include directory need to be added to the include path.
  59 +How you do this depends on the build system.
  60 +
  61 +## Building tests {#build-tests}
  62 +If you additionally want to run the tests use cmake with the option -Dhueplusplus_TESTS=ON. Testing is done with Google gtest and gmock. Note that you wont need to install gtest/gmock yourself, because cmake will automatically download them and include them during the build.
  63 +The custom target `unittest` compiles and executes all tests.
  64 +```bash
  65 +mkdir build
  66 +cd build
  67 +cmake .. -Dhueplusplus_TESTS=ON
  68 +make unittest
  69 +```
  70 +
  71 +If you also want to execute coverage tests you will need to install gcov and lcov yourself. To run the coverage test use
  72 +```bash
  73 +make coveragetest
  74 +```
  75 +
  76 +## Building examples {#build-examples}
  77 +There are some small example programs using this library in the examples folder. To build them,
  78 +set `hueplusplus_SAMPLES=ON`. The target `hueplusplus_examples` builds all examples into build/examples.
  79 +```{.sh}
  80 +mkdir build
  81 +cd build
  82 +cmake .. -Dhueplusplus_SAMPLES=ON
  83 +make hueplusplus_examples
  84 +```
... ...
doc/markdown/Getting_Started.md 0 → 100644
  1 +# Getting started {#getting-started}
  2 +
  3 +## Creating the Hue bridge
  4 +To start searching for a Hue Bridge you will need to choose an IHttpHandler and create one.
  5 +The options are a [WinHttpHandler](@ref hueplusplus::WinHttpHandler) (for windows) or a [LinHttpHandler](@ref hueplusplus::LinHttpHandler) (for linux or linux-like).
  6 +
  7 +Then create a [BridgeFinder](@ref hueplusplus::BridgeFinder) object with the handler.
  8 +The handler is needed, because it tells the finder which functions to use to communicate with a bridge or your local network.
  9 +After that you can call [findBridges()](@ref hueplusplus::HueFinder::findBridges), which will return a vector containing the ip and mac address of all found Bridges.
  10 +```{.cpp}
  11 +// For windows use std::make_shared<hueplusplus::WinHttpHandler>();
  12 +auto handler = std::make_shared<hueplusplus::LinHttpHandler>();
  13 +hueplusplus::BridgeFinder finder(handler);
  14 +std::vector<hueplusplus::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
  15 +if (bridges.empty())
  16 +{
  17 + std::cerr << "No bridges found\n";
  18 + return;
  19 +}
  20 +```
  21 +
  22 +## Authenticate Bridges
  23 +If you have found the Bridge you were looking for, you can then move on with the authentication process.
  24 +To get a new username from the Bridge (for now) you simply call [getBridge(bridges[\<index\>])](@ref hueplusplus::BridgeFinder::getBridge),
  25 +where index is your preferred Bridge from the part [Searching for Bridges](#searchingBridges). This requires the user to press the link button.
  26 +```{.cpp}
  27 +hueplusplus::Bridge bridge = finder.getBridge(bridges[0]);
  28 +```
  29 +If you on the other hand already have a username you can add your bridge like so
  30 +```{.cpp}
  31 +finder.addUsername(bridges[0].mac, "<username>");
  32 +hueplusplus::Bridge bridge = finder.getBridge(bridges[0]);
  33 +```
  34 +If you do not want to use the HueFinder or you already know the ip and username of your bridge you have the option to create your own Hue object.
  35 +Here you will need to provide the ip address, the port number, a username and an HttpHandler
  36 +```{.cpp}
  37 +// For windows use std::make_shared<hueplusplus::WinHttpHandler>();
  38 +auto handler = std::make_shared<hueplusplus::LinHttpHandler>();
  39 +hueplusplus::Bridge bridge("192.168.2.102", 80, "<username>", handler);
  40 +```
  41 +
  42 +### Controlling lights
  43 +
  44 +```{.cpp}
  45 +hueplusplus::Light light = bridge.getLight(1);
  46 +light1.On();
  47 +light1.Off();
  48 +```
  49 +
  50 +### Controlling groups
  51 +
  52 +```{.cpp}
  53 +hueplusplus::Group group = bridge.getGroup(1);
  54 +group.setOn(true);
  55 +```
  56 +
  57 +## More information
  58 +- [Transactions](@ref transactions)
0 59 \ No newline at end of file
... ...
doc/markdown/Mainpage.md
... ... @@ -17,7 +17,8 @@ A simple and easy to use library for Philips Hue Lights.
17 17 * Espressif ESP32 SDK & Arduino
18 18  
19 19 ## How to use
20   -### <a name="searchingBridges"></a>Searching for Bridges
  20 +- [Getting Started](@ref getting-started)
  21 +### Searching for Bridges
21 22 To start searching for a Hue Bridge you will need to choose an IHttpHandler and create one. The options are a [WinHttpHandler](@ref hueplusplus::WinHttpHandler) (for windows) or a [LinHttpHandler](@ref hueplusplus::LinHttpHandler) (for linux or linux-like).
22 23  
23 24 Then create a [BridgeFinder](@ref hueplusplus::BridgeFinder) object with the handler.
... ... @@ -94,6 +95,8 @@ light1.hasColorControl();
94 95 These will either return true(light has specified function) or false(light lacks specified function).
95 96  
96 97 ## Build and install
  98 +- [Build and install guide](@ref build)
  99 +
97 100 ### Basic installation
98 101 If you want to build the library you can use cmake (at least version 3.8). First create a build folder and then execute cmake.
99 102 ```bash
... ...
doc/markdown/Sensors.md 0 → 100644
  1 +# Sensors {#sensors}
  2 +
  3 +## Sensor support
  4 +The library supports the sensor types listed on the Hue developer documentation.
  5 +Other sensors can be used with the generic [Sensor](@ref hueplusplus::Sensor) class.
  6 +
  7 +### Working with a known sensor
  8 +In most cases, the type of the sensors is known in advance, such as a switch.
  9 +The classes in the [sensors](@ref hueplusplus::sensors) namespace provide the documented
  10 +functionality. The type can be specified when accessing the sensor. When it does not match,
  11 +an exception is thrown.
  12 +```{.cpp}
  13 +hueplusplus::sensors::ZLLSwitch switchSensor = bridge.sensors().getAsType<hueplusplus::sensors::ZLLSwitch>(2);
  14 +```
  15 +
  16 +You can also get all sensors of a specified type by using [getAllByType<T>()](@ref hueplusplus::SensorList::getAllByType).
  17 +```{.cpp}
  18 +std::vector<hueplusplus::sensors::ZLLSwitch> allSwitches = bridge.sensors().getAllByType<hueplusplus::sensors::ZLLSwitch>();
  19 +```
  20 +
  21 +### Working with an unknown sensor
  22 +When the sensor type is not known, use the generic sensor class. In this case, some attributes might not
  23 +exist, so they have to be checked first. This applies to all attributes that have a `hasXXX` method.
  24 +
  25 +```{.cpp}
  26 +hueplusplus::Sensor genericSensor = bridge.sensors().get(1);
  27 +if(genericSensor.hasOn())
  28 +{
  29 + // Now can check whether it is on
  30 + if(genericSensor.isOn())
  31 + {
  32 + // ...
  33 + }
  34 +}
  35 +```
  36 +
  37 +It is easiest to compare the sensor type to the existing ones (`typeStr` on the specific sensor classes)
  38 +and then convert the sensor to that type.
  39 +```{.cpp}
  40 +hueplusplus::Sensor genericSensor = bridge.sensors().get(1);
  41 +if(genericSensor.getType() == hueplusplus::sensors::ZLLSwitch::typeStr)
  42 +{
  43 + hueplusplus::sensors::ZLLSwitch switchSensor = genericSensor.asSensorType<hueplusplus::sensors::ZLLSwitch>();
  44 + // ...
  45 +}
  46 +```
  47 +
  48 +## ZLL sensors vs. CLIP sensors
  49 +ZLL sensors (defined in `ZLLSensors.h`) are physical device sensors which send their data
  50 +to the bridge using ZigBee. They are added in the same way as lights are, using [search()](@ref hueplusplus::SearchableResourceList::search).
  51 +
  52 +CLIP sensors (in `CLIPSensors.h`) are added using [create()](@ref hueplusplus::CreateableResourceList::create) with [CreateSensor](@ref hueplusplus::CreateSensor)
  53 +for parameters. In general, which config and state attributes exist is specified when the sensor is created.
  54 +The values of CLIP sensors can be changed using requests, unlike ZLL sensors. They can also have a URL to query from.
  55 +
  56 +## Creating conditions
  57 +The most important use for sensors is in [Rules](@ref hueplusplus::Rule), to trigger changes.
  58 +Conditions can be created from the specific sensor types using `makeCondition()`.
  59 +
  60 +These functions return a helper class with methods for the [possible operators](@ref hueplusplus::Condition::Operator) valid for the state.
  61 +
  62 +For some sensors, which have multiple possible states, there exist multiple variations of makeCondition.
  63 +
  64 +```{.cpp}
  65 +hueplusplus::sensors::ZLLSwitch switchSensor = ...;
  66 +// ZLLSwitch conditions operate on `buttonEvent`, use makeConditionLastUpdate()
  67 +// to trigger on the last update time.
  68 +
  69 +// Some examples:
  70 +hueplusplus::Condition upPressed = makeCondition(switchSensor).eq(hueplusplus::sensors::ZLLSwitch::c_UP_INITIAL_PRESS);
  71 +hueplusplus::Condition buttonChanged = makeCondition(switchSensor).dx();
  72 +
  73 +hueplusplus::time::TimeInterval interval(std::chrono::hours(12), std::chrono::hours(13));
  74 +hueplusplus::Condition updatedAtNoon = makeConditionLastUpdate(switchSensor).in(interval);
  75 +```
  76 +
  77 +For generic sensors, the conditions must be created manually using the [Condition](@ref hueplusplus::Condition::Condition)
  78 +constructor with a proper address to the sensor state.
0 79 \ No newline at end of file
... ...
doc/markdown/Transactions.md 0 → 100644
  1 +# Transactions {#transactions}
  2 +
  3 +## Using a transaction for lights
  4 +Often, you want to change more than one variable on a light at the same time,
  5 +for example brightness and color. This is done using transactions ([StateTransaction](@ref hueplusplus::StateTransaction)).
  6 +
  7 +```{.cpp}
  8 +light.transaction().setOn(true).setBrightness(29).setColorHue(3000).setColorSaturation(128).commit();
  9 +```
  10 +The request is reduced to only the variables that need to be changed based on the current state.
  11 +For example, if the light is already on, that part of the transaction is ignored.
  12 +
  13 +__Important:__ The transaction has an internal reference to the light state.
  14 +You must not cause a refresh of the state between creating and committing the transaction (e.g. non-const getters/setters),
  15 +because that invalidates the reference.
  16 +
  17 +### Advanced usage
  18 +Another way to use the transaction is by storing it and building up the calls separately.
  19 +
  20 +```{.cpp}
  21 +hueplusplus::StateTransaction t = light.transaction();
  22 +if(shouldTurnOn)
  23 + t.setOn(true);
  24 +t.commit();
  25 +```
  26 +
  27 +In this case, it is especially important that the light and the state of the light __MUST NOT__ invalidate. That means
  28 +* the light variable has to live longer than the transaction
  29 +* especially no non-const method calls on the light while the transaction is open, or committing other transactions
  30 +
  31 +In general, this method is easier to screw up and should only be used when really necessary.
  32 +
  33 +## Using a transaction for groups
  34 +The same principles of transactions for lights also apply for groups. The main difference is that
  35 +for groups, there are no checks of the current state. Even if all lights in the group are already on,
  36 +the request to turn on all lights on the group is still sent.
  37 +
  38 +```{.cpp}
  39 +group.transaction().setOn(true).setBrightness(64).commit();
  40 +```
  41 +
  42 +
  43 +## Creating Actions
  44 +In a [Schedule](@ref hueplusplus::Schedule) or [Rule](@ref hueplusplus::Rule),
  45 +the bridge can set the state of lights and groups. To configure this, a transaction
  46 +can be saved for later instead of committing it directly.
  47 +```{.cpp}
  48 +hueplusplus::Action action = light.transaction().setOn(true).setBrightness(255).toAction();
  49 +schedule.setCommand(action);
  50 +```
... ...
examples/BridgeSetup.cpp
... ... @@ -15,15 +15,17 @@ using SystemHttpHandler = hueplusplus::LinHttpHandler;
15 15  
16 16 #endif
17 17  
  18 +namespace hue = hueplusplus;
  19 +
18 20 // Configure existing connections here, or leave empty for new connection
19 21 const std::string macAddress = "";
20 22 const std::string username = "";
21 23  
22   -hueplusplus::Bridge connectToBridge()
  24 +hue::Bridge connectToBridge()
23 25 {
24   - hueplusplus::BridgeFinder finder(std::make_shared<SystemHttpHandler>());
  26 + hue::BridgeFinder finder(std::make_shared<SystemHttpHandler>());
25 27  
26   - std::vector<hueplusplus::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
  28 + std::vector<hue::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
27 29  
28 30 for (const auto& bridge : bridges)
29 31 {
... ... @@ -59,7 +61,7 @@ int main(int argc, char** argv)
59 61  
60 62 try
61 63 {
62   - hueplusplus::Bridge hue = connectToBridge();
  64 + hue::Bridge hue = connectToBridge();
63 65  
64 66 std::cout << "Connected to bridge. IP: " << hue.getBridgeIP() << ", username: " << hue.getUsername() << '\n';
65 67 }
... ...
examples/CMakeLists.txt
1   -add_executable(bridge_setup BridgeSetup.cpp)
  1 +add_executable(bridge_setup BridgeSetup.cpp )
2 2 set_property(TARGET bridge_setup PROPERTY CXX_STANDARD 14)
3 3 set_property(TARGET bridge_setup PROPERTY CXX_EXTENSIONS OFF)
4 4 target_link_libraries(bridge_setup hueplusplusstatic)
  5 +
  6 +add_executable(lights_off LightsOff.cpp )
  7 +set_property(TARGET lights_off PROPERTY CXX_STANDARD 14)
  8 +set_property(TARGET lights_off PROPERTY CXX_EXTENSIONS OFF)
  9 +target_link_libraries(lights_off hueplusplusstatic)
  10 +
  11 +
  12 +add_custom_target(hueplusplus_examples)
  13 +add_dependencies(hueplusplus_examples bridge_setup)
5 14 \ No newline at end of file
... ...
examples/LightsOff.cpp 0 → 100644
  1 +
  2 +#include <hueplusplus/Bridge.h>
  3 +
  4 +#ifdef _MSC_VER
  5 +#include <hueplusplus/WinHttpHandler.h>
  6 +
  7 +using SystemHttpHandler = hueplusplus::WinHttpHandler;
  8 +
  9 +#else
  10 +#include <hueplusplus/LinHttpHandler.h>
  11 +
  12 +using SystemHttpHandler = hueplusplus::LinHttpHandler;
  13 +
  14 +#endif
  15 +
  16 +namespace hue = hueplusplus;
  17 +
  18 +// Configure existing connections here, or leave empty for new connection
  19 +const std::string macAddress = "";
  20 +const std::string username = "";
  21 +
  22 +hue::Bridge connectToBridge()
  23 +{
  24 + hue::BridgeFinder finder(std::make_shared<SystemHttpHandler>());
  25 +
  26 + std::vector<hue::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
  27 +
  28 + for (const auto& bridge : bridges)
  29 + {
  30 + std::cout << "Bridge: " << bridge.mac << " at " << bridge.ip << '\n';
  31 + }
  32 + if (bridges.empty())
  33 + {
  34 + std::cout << "Found no bridges\n";
  35 + throw std::runtime_error("no bridges found");
  36 + }
  37 +
  38 + if (macAddress.empty())
  39 + {
  40 + std::cout << "No bridge given, connecting to first one.\n";
  41 + return finder.getBridge(bridges.front());
  42 + }
  43 + if (!username.empty())
  44 + {
  45 + finder.addUsername(macAddress, username);
  46 + }
  47 + auto it = std::find_if(
  48 + bridges.begin(), bridges.end(), [&](const auto& identification) { return identification.mac == macAddress; });
  49 + if (it == bridges.end())
  50 + {
  51 + std::cout << "Given bridge not found\n";
  52 + throw std::runtime_error("bridge not found");
  53 + }
  54 + return finder.getBridge(*it);
  55 +}
  56 +
  57 +void lightsOff(hue::Bridge& hue)
  58 +{
  59 + std::vector<hue::Light> lights = hue.lights().getAll();
  60 +
  61 + // Save current on state of the lights
  62 + std::map<int, bool> onMap;
  63 + for (const hue::Light& l : lights)
  64 + {
  65 + onMap.emplace(l.getId(), l.isOn());
  66 + }
  67 +
  68 + // Group 0 contains all lights, turn all off with a transition of 1 second
  69 + hue.groups().get(0).setOn(false, 10);
  70 + std::cout << "Turned off all lights\n";
  71 +
  72 + std::this_thread::sleep_for(std::chrono::seconds(20));
  73 +
  74 + // Restore the original state of the lights
  75 + for (hue::Light& l : lights)
  76 + {
  77 + if (onMap[l.getId()])
  78 + {
  79 + // Refresh, because the state change from the group is not updated in the light.
  80 + // This is not strictly necessary in this case, because the state is updated
  81 + // automatically every 10 seconds.
  82 + // However, when the sleep above is shorter, no refresh can cause the on request
  83 + // to be removed, because the light thinks it is still on.
  84 + l.refresh(true);
  85 + l.on();
  86 + }
  87 + }
  88 +
  89 + std::cout << "Turned lights back on\n";
  90 +}
  91 +
  92 +int main(int argc, char** argv)
  93 +{
  94 +
  95 + try
  96 + {
  97 + hue::Bridge hue = connectToBridge();
  98 +
  99 + std::cout << "Connected to bridge. IP: " << hue.getBridgeIP() << ", username: " << hue.getUsername() << '\n';
  100 +
  101 + lightsOff(hue);
  102 + }
  103 + catch (...)
  104 + {
  105 + }
  106 +
  107 + std::cout << "Press enter to exit\n";
  108 + std::cin.get();
  109 +
  110 + return 0;
  111 +}
0 112 \ No newline at end of file
... ...
test/CMakeLists.txt
... ... @@ -63,9 +63,9 @@ set(HuePlusPlus_INCLUDE_DIR &quot;${PROJECT_SOURCE_DIR}/include&quot;)
63 63  
64 64 # test executable
65 65 add_executable(test_HuePlusPlus ${TEST_SOURCES})
66   -if(DO_CLANG_TIDY)
67   - set_target_properties(test_HuePlusPlus PROPERTIES CXX_CLANG_TIDY ${DO_CLANG_TIDY})
68   -endif()
  66 +#if(DO_CLANG_TIDY)
  67 +# set_target_properties(test_HuePlusPlus PROPERTIES CXX_CLANG_TIDY ${DO_CLANG_TIDY})
  68 +#endif()
69 69 target_compile_features(test_HuePlusPlus PUBLIC cxx_std_14)
70 70 set_property(TARGET test_HuePlusPlus PROPERTY CXX_EXTENSIONS OFF)
71 71  
... ...