Compare commits

..
Author SHA1 Message Date
Adam Honse befb783f2d Add ROG Strix Scope TKL to Aura Keyboard detector 2021-06-05 15:29:55 -05:00
Jeff P fe11115f32 Add support for Corsair Commander Core / Elite Capellix
Amended for code style by Adam Honse <[email protected]>
2021-06-04 22:45:36 -05:00
Adam Honse 9a00f1d6d8 Fix CI for Philips Hue changes
* Debian builder has been upgraded to buster due to incompatible mbedtls package on stretch
  * Mint 19, Ubuntu 18.04 have been disabled for testing as they use incompatible mbedtls packages
2021-06-05 03:18:12 +00:00
Adam Honse b7e2103f41 Disable parsing certificate, it doesn't appear to be necessary to control Hue and prevents build on older mbedtls releases 2021-06-05 03:18:12 +00:00
Adam Honse 87043cde65 Fix issue with Windows in hueplusplus library 2021-06-05 03:18:12 +00:00
Adam Honse 2aaf7017ee Philips Hue (Standard and Entertainment Mode) Support using hueplusplus library
* Dependency hueplusplus-1.0.0 added from https://github.com/enwi/hueplusplus/releases/tag/v1.0.0
* Dependency mbedtls-2.24.0 added (Windows-only) from https://github.com/ARMmbed/mbedtls/releases/tag/mbedtls-2.24.0
2021-06-05 03:18:12 +00:00
mike 22acdd1fed Check return code from hid_get_serial_number_string() in GetSerialString()
Amended for code style by Adam Honse <[email protected]>
2021-06-04 22:14:05 -05:00
Thomas greenwood 4e4eade335 Pad commands for 0x62 with 4 zero bytes 2021-06-05 02:52:37 +00:00
Joe Smith 9f7812bc7b No more qt5-default package in debian
[Looks](https://askubuntu.com/questions/1335184/qt5-default-not-in-ubuntu-21-04) like this [was removed](https://bugs.launchpad.net/ubuntu/+source/qtbase-opensource-src/+bug/1926802) in Debian `bullseye` + Ubuntu `21.04`.
2021-06-05 02:18:02 +00:00
TheRogueZeta 6029a5b0c5 Add Non OC 2060S PCIe ID, correct RAM 2021-06-04 15:51:15 -07:00
TheRogueZeta 74a49ec3e6 Add ASUS ROG Strix RTX 2060S A8G Evo to detector 2021-06-04 15:50:17 -07:00
Short_String_Dev 21dd2ee66a Add ASUS ROG STRIX 2070 A8G Gaming 2021-06-04 08:57:23 -04:00
Short_String_Dev f76d78775c Add ASUS ROG STRIX 2070 O8G Gaming 2021-06-04 08:25:15 -04:00
TheRogueZeta af01ff5de3 Add ASUS ROG Strix 1080 O8G to detector 2021-06-03 17:53:40 +00:00
Tom Greenwood f2f84fc7e3 Add support for Gigabyte RTX3060 Gaming OC 12GB 2021-06-03 17:07:48 +00:00
TheRogueZeta 939f46c025 G Pro Wired are only 1 zone devices 2021-06-03 08:31:37 -07:00
TheRogueZeta a1469041e5 Add ASUS ROG Strix 1070 Gaming to detector 2021-06-03 02:27:14 +00:00
TheRogueZeta f39b57fadc Add Gigabyte RTX 2060 Gaming OC Pro to the detector 2021-06-03 02:26:00 +00:00
Dennis Piecha 08a985a216 Add ASUS ROG STRIX RTX 2070S O8G Gaming 8G 2021-06-02 22:01:52 +02:00
Harry Kane 7054badf4f Update URL to HTTPS 2021-06-02 03:30:01 +00:00
SR_team 332a04f94c Add missing key for ANSI layout of Logitech G815 into LED View 2021-06-01 20:41:57 +00:00
TheRogueZeta ae88771e79 Correct G502 Wireless (wired) PID in linux builds 2021-06-01 00:19:50 -07:00
TheRogueZeta 09e524314f Correct G502 PS and G502 Hero detector changes. 2021-05-31 23:47:37 -07:00
Adam Honse 8e8573e7d0 Increment version number post-release 2021-06-01 01:35:51 -05:00
1398 changed files with 378168 additions and 113 deletions
+54 -54
View File
@@ -32,7 +32,7 @@ before_script:
#-----------------------------------------------------------------------#
"Linux 32 AppImage":
<<: *ccache_init
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:stretch-32
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:buster-32
stage: build
script:
- export $(dpkg-architecture)
@@ -51,7 +51,7 @@ before_script:
#-----------------------------------------------------------------------#
"Linux 64 AppImage":
<<: *ccache_init
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:stretch-64
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:buster-64
stage: build
script:
- export $(dpkg-architecture)
@@ -70,7 +70,7 @@ before_script:
#-----------------------------------------------------------------------#
"Linux 32 deb":
<<: *ccache_init
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:stretch-32
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:buster-32
stage: build
script:
- dpkg-architecture -l
@@ -91,7 +91,7 @@ before_script:
#-----------------------------------------------------------------------#
"Linux 64 deb":
<<: *ccache_init
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:stretch-64
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:buster-64
stage: build
script:
- dpkg-architecture -l
@@ -143,7 +143,7 @@ before_script:
stage: build
script:
- apt update
- apt install -y build-essential qtcreator qtbase5-dev libusb-1.0-0-dev libhidapi-dev pkgconf wget git file debhelper
- apt install -y build-essential qtcreator qtbase5-dev libusb-1.0-0-dev libhidapi-dev libmbedtls-dev pkgconf wget git file debhelper
- dpkg-architecture -l
- dpkg-buildpackage --target-arch i386 -us -B
- rm -v ../openrgb-dbgsym*.deb
@@ -166,7 +166,7 @@ before_script:
stage: build
script:
- apt update
- apt install -y build-essential qtcreator qtbase5-dev libusb-1.0-0-dev libhidapi-dev pkgconf wget git file debhelper
- apt install -y build-essential qtcreator qtbase5-dev libusb-1.0-0-dev libhidapi-dev libmbedtls-dev pkgconf wget git file debhelper
- dpkg-architecture -l
- dpkg-buildpackage -us -B
- rm -v ../openrgb-dbgsym*.deb
@@ -214,39 +214,39 @@ before_script:
needs:
- "Linux 32 deb"
#-----------------------------------------------------------------------#
# Ubuntu 32 18.04LTS test #
#-----------------------------------------------------------------------#
"Ubuntu 32 18.04LTS":
image: i386/ubuntu:bionic
stage: test
script:
- apt update
- DEBIAN_FRONTEND=noninteractive apt install -yq --no-install-recommends ./openrgb*i386.deb
- openrgb --version
- openrgb -l
- apt remove -y openrgb
dependencies:
- "Linux 32 deb"
needs:
- "Linux 32 deb"
# #-----------------------------------------------------------------------#
# # Ubuntu 32 18.04LTS test #
# #-----------------------------------------------------------------------#
# "Ubuntu 32 18.04LTS":
# image: i386/ubuntu:bionic
# stage: test
# script:
# - apt update
# - DEBIAN_FRONTEND=noninteractive apt install -yq --no-install-recommends ./openrgb*i386.deb
# - openrgb --version
# - openrgb -l
# - apt remove -y openrgb
# dependencies:
# - "Linux 32 deb"
# needs:
# - "Linux 32 deb"
#-----------------------------------------------------------------------#
# Mint 32 19.3 test #
#-----------------------------------------------------------------------#
"Mint 32 20.1":
image: linuxmintd/mint19.3-i386
stage: test
script:
- apt update
- DEBIAN_FRONTEND=noninteractive apt install -yq --no-install-recommends ./openrgb*i386.deb
- openrgb --version
- openrgb -l
- apt remove -y openrgb
dependencies:
- "Linux 32 deb"
needs:
- "Linux 32 deb"
# #-----------------------------------------------------------------------#
# # Mint 32 19.3 test #
# #-----------------------------------------------------------------------#
# "Mint 32 20.1":
# image: linuxmintd/mint19.3-i386
# stage: test
# script:
# - apt update
# - DEBIAN_FRONTEND=noninteractive apt install -yq --no-install-recommends ./openrgb*i386.deb
# - openrgb --version
# - openrgb -l
# - apt remove -y openrgb
# dependencies:
# - "Linux 32 deb"
# needs:
# - "Linux 32 deb"
#-----------------------------------------------------------------------#
# Debian 64 Buster test #
@@ -298,22 +298,22 @@ before_script:
needs:
- "Linux 64 rpm"
#-----------------------------------------------------------------------#
# Ubuntu 64 18.04LTS test #
#-----------------------------------------------------------------------#
"Ubuntu 64 18.04LTS":
image: ubuntu:bionic
stage: test
script:
- apt update
- DEBIAN_FRONTEND=noninteractive apt install -yq --no-install-recommends ./openrgb*amd64.deb
- openrgb --version
- openrgb -l
- apt remove -y openrgb
dependencies:
- "Linux 64 deb"
needs:
- "Linux 64 deb"
# #-----------------------------------------------------------------------#
# # Ubuntu 64 18.04LTS test #
# #-----------------------------------------------------------------------#
# "Ubuntu 64 18.04LTS":
# image: ubuntu:bionic
# stage: test
# script:
# - apt update
# - DEBIAN_FRONTEND=noninteractive apt install -yq --no-install-recommends ./openrgb*amd64.deb
# - openrgb --version
# - openrgb -l
# - apt remove -y openrgb
# dependencies:
# - "Linux 64 deb"
# needs:
# - "Linux 64 deb"
#-----------------------------------------------------------------------#
# Ubuntu 64 20.04LTS test #
@@ -52,7 +52,12 @@ char* AMDWraithPrismController::GetDeviceName()
std::string AMDWraithPrismController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -54,8 +54,13 @@ std::string PolychromeUSBController::GetDeviceName()
std::string PolychromeUSBController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -40,7 +40,12 @@ std::string AuraCoreController::GetDeviceLocation()
std::string AuraCoreController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -33,13 +33,19 @@ typedef struct
static const gpu_pci_device device_list[] =
{
{ NVIDIA_VEN, NVIDIA_GTX1060_DEV, ASUS_SUB_VEN, ASUS_GTX1060_STRIX, 0x29, "ASUS GTX 1060 Strix" },
{ NVIDIA_VEN, NVIDIA_GTX1070_DEV, ASUS_SUB_VEN, ASUS_GTX1070_STRIX, 0x29, "ASUS GTX 1070 Strix OC" },
{ NVIDIA_VEN, NVIDIA_GTX1070_DEV, ASUS_SUB_VEN, ASUS_GTX1070_STRIX_GAMING, 0x29, "ASUS GTX 1070 Strix Gaming" },
{ NVIDIA_VEN, NVIDIA_GTX1070_DEV, ASUS_SUB_VEN, ASUS_GTX1070_STRIX_OC, 0x29, "ASUS GTX 1070 Strix OC" },
{ NVIDIA_VEN, NVIDIA_GTX1080_DEV, ASUS_SUB_VEN, ASUS_GTX1080_STRIX, 0x29, "ASUS GTX 1080 Strix OC" },
{ NVIDIA_VEN, NVIDIA_GTX1080_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_GTX1080_A8G_GAMING, 0x29, "ASUS ROG Strix GTX1080 A8G Gaming" },
{ NVIDIA_VEN, NVIDIA_GTX1080_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_GTX1080_O8G_GAMING, 0x29, "ASUS ROG Strix GTX1080 O8G Gaming" },
{ NVIDIA_VEN, NVIDIA_GTX1080TI_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_GTX1080TI_GAMING, 0x29, "ASUS ROG Strix GTX1080 Ti Gaming" },
{ NVIDIA_VEN, NVIDIA_GTX1660TI_DEV, ASUS_SUB_VEN, ASUS_ROG_GTX1660TI_OC, 0x2A, "ASUS ROG GTX 1660 Ti OC 6G" },
{ NVIDIA_VEN, NVIDIA_RTX2060_TU106_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_RTX2060_EVO_GAMING, 0x2A, "ASUS ROG STRIX RTX 2060 EVO Gaming 6G" },
{ NVIDIA_VEN, NVIDIA_RTX2060S_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_RTX2060S_A8G_EVO_GAMING, 0x2A, "ASUS ROG STRIX RTX 2060S A8G EVO Gaming 6G"},
{ NVIDIA_VEN, NVIDIA_RTX2070_OC_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_RTX2070_A8G_GAMING, 0x2A, "ASUS ROG STRIX RTX 2070 A8G Gaming 8G" },
{ NVIDIA_VEN, NVIDIA_RTX2070_OC_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_RTX2070_O8G_GAMING, 0x2A, "ASUS ROG STRIX RTX 2070 O8G Gaming 8G" },
{ NVIDIA_VEN, NVIDIA_RTX2070S_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_RTX2070S_A8G_GAMING, 0x2A, "ASUS ROG STRIX RTX 2070S A8G Gaming 8G" },
{ NVIDIA_VEN, NVIDIA_RTX2070S_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_RTX2070S_O8G_GAMING, 0x2A, "ASUS ROG STRIX RTX 2070S O8G Gaming 8G" },
{ NVIDIA_VEN, NVIDIA_RTX2080_A_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_RTX2080_O8G_GAMING, 0x2A, "ASUS ROG STRIX RTX 2080 O8G Gaming" },
{ NVIDIA_VEN, NVIDIA_RTX2080TI_DEV, ASUS_SUB_VEN, ASUS_ROG_STRIX_RTX2080TI_O11G_GAMING, 0x2A, "ASUS ROG STRIX RTX 2080 Ti O11G Gaming" },
{ AMD_GPU_VEN, AMD_VEGA10_DEV, ASUS_SUB_VEN, ASUS_VEGA64_STRIX, 0x29, "ASUS Vega 64 Strix" },
@@ -30,7 +30,12 @@ std::string AuraKeyboardController::GetDeviceLocation()
std::string AuraKeyboardController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -30,7 +30,12 @@ std::string AuraMouseController::GetDeviceLocation()
std::string AuraMouseController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -42,7 +42,12 @@ std::string AuraUSBController::GetDeviceName()
std::string AuraUSBController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -28,6 +28,7 @@
#define AURA_ROG_STRIX_FLARE_PNK_LTD_PID 0x18CF
#define AURA_ROG_CHAKRAM_WIRELESS_PID 0x18E5
#define AURA_ROG_CHAKRAM_WIRED_1_PID 0x18E3
#define AURA_ROG_STRIX_SCOPE_TKL_PID 0x190C
#define AURA_ROG_CHAKRAM_WIRED_2_PID 0x1958
void DetectAsusAuraUSBTerminal(hid_device_info* info, const std::string& name)
@@ -117,4 +118,5 @@ REGISTER_HID_DETECTOR_IP("ASUS ROG Chakram (Wireless)", DetectAsusAuraUS
REGISTER_HID_DETECTOR_IP("Asus ROG Chakram (Wired)", DetectAsusAuraUSBMice, AURA_USB_VID, AURA_ROG_CHAKRAM_WIRED_1_PID, 0, 0xFF01);
REGISTER_HID_DETECTOR_IP("Asus ROG Chakram (Wired)", DetectAsusAuraUSBMice, AURA_USB_VID, AURA_ROG_CHAKRAM_WIRED_2_PID, 0, 0xFF01);
REGISTER_HID_DETECTOR_IP("ASUS ROG Strix Flare", DetectAsusAuraUSBKeyboards, AURA_USB_VID, AURA_ROG_STRIX_FLARE_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP("ASUS ROG Strix Flare PNK LTD", DetectAsusAuraUSBKeyboards, AURA_USB_VID, AURA_ROG_STRIX_FLARE_PNK_LTD_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP("ASUS ROG Strix Flare PNK LTD", DetectAsusAuraUSBKeyboards, AURA_USB_VID, AURA_ROG_STRIX_FLARE_PNK_LTD_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP("ASUS ROG Strix Scope TKL", DetectAsusAuraUSBKeyboards, AURA_USB_VID, AURA_ROG_STRIX_SCOPE_TKL_PID, 1, 0xFF00);
@@ -0,0 +1,276 @@
/*---------------------------------------------------------*\
| CorsairCommanderCoreController.cpp |
| |
| Processing Code for Corsair Commander Core |
| |
| Jeff P. |
\*---------------------------------------------------------*/
#include "CorsairCommanderCoreController.h"
#include <cstring>
#include <iomanip>
#include <iostream>
using namespace std::chrono_literals;
CorsairCommanderCoreController::CorsairCommanderCoreController(hid_device* dev_handle, const char* path)
{
dev = dev_handle;
location = path;
keepalive_thread_run = 1;
controller_ready = 0;
/*-----------------------------------------------------*\
| Initialize controller |
\*-----------------------------------------------------*/
InitController();
/*-----------------------------------------------------*\
| Start keepalive thread |
\*-----------------------------------------------------*/
keepalive_thread = new std::thread(&CorsairCommanderCoreController::KeepaliveThread, this);
}
CorsairCommanderCoreController::~CorsairCommanderCoreController()
{
/*-----------------------------------------------------*\
| Close keepalive thread |
\*-----------------------------------------------------*/
keepalive_thread_run = 0;
keepalive_thread->join();
delete keepalive_thread;
/*-----------------------------------------------------*\
| Close HID device |
\*-----------------------------------------------------*/
hid_close(dev);
}
void CorsairCommanderCoreController::InitController()
{
/*-----------------------------------------------------*\
| Packet sequence to put controller into direct mode |
\*-----------------------------------------------------*/
unsigned char buffarray[][5] =
{
{0x08, 0x01, 0x03, 0x00, 0x02},
{0x08, 0x0D, 0x00, 0x22, 0x00},
};
SendMultiPkt(buffarray, sizeof(buffarray) / sizeof(buffarray[0]), sizeof(buffarray)[0] / sizeof(buffarray[0][0]));
SetFanMode();
}
std::string CorsairCommanderCoreController::GetLocationString()
{
return("HID: " + location);
}
void CorsairCommanderCoreController::KeepaliveThread()
{
while(keepalive_thread_run.load())
{
if (controller_ready)
{
if((std::chrono::steady_clock::now() - last_commit_time) > std::chrono::seconds(10))
{
SendCommit();
}
}
std::this_thread::sleep_for(1s);
}
}
void CorsairCommanderCoreController::SendCommit()
{
if(!lastcolors.empty())
{
/*-----------------------------------------------------*\
| If colors remain to be sent, send them |
\*-----------------------------------------------------*/
SetDirectColor(lastcolors, lastzones);
}
else
{
unsigned char usb_buf[1025];
/*-----------------------------------------------------*\
| Zero out buffer |
\*-----------------------------------------------------*/
memset(usb_buf, 0x00, sizeof(usb_buf));
/*-----------------------------------------------------*\
| Update last commit time |
\*-----------------------------------------------------*/
last_commit_time = std::chrono::steady_clock::now();
/*-----------------------------------------------------*\
| Set up Commit packet |
\*-----------------------------------------------------*/
memset(usb_buf, 0, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
usb_buf[0] = 0x00;
usb_buf[1] = 0x08;
usb_buf[2] = 0x06;
usb_buf[4] = 0xBD;
usb_buf[5] = 0x02;
usb_buf[8] = 0x12;
hid_write(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
}
}
void CorsairCommanderCoreController::SendMultiPkt(unsigned char buffarray[][5], int r, int c)
{
/*---------------------------------------------------------*\
| Private function to send multiple packets |
\*---------------------------------------------------------*/
unsigned char* hidtemp = new unsigned char[CORSAIR_COMMANDER_CORE_PACKET_SIZE];
for(unsigned int i = 0; i < r; i++)
{
memset(hidtemp, 0, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
for(unsigned int j = 0; j < c; j++)
{
hidtemp[j+1] = buffarray[i][j];
}
hid_write(dev, hidtemp, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
hid_read(dev, hidtemp, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
}
}
void CorsairCommanderCoreController::SetDirectColor
(
std::vector<RGBColor> colors,
std::vector<zone> zones
)
{
if(controller_ready == 1 && ((std::chrono::steady_clock::now() - last_commit_time) > std::chrono::milliseconds(33)))
{
lastcolors = colors;
lastzones = zones;
int packet_offset = CORSAIR_COMMANDER_CORE_PREAMBLE_OFFSET;
int led_idx = 0;
int channel_idx = 0;
unsigned char* usb_buf = new unsigned char[CORSAIR_COMMANDER_CORE_PACKET_SIZE];
memset(usb_buf, 0, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
/*-----------------------------------------------------*\
| Prepare color information packet |
\*-----------------------------------------------------*/
usb_buf[0] = 0x00;
usb_buf[1] = 0x08;
usb_buf[2] = 0x06;
usb_buf[4] = 0xBD;
usb_buf[5] = 0x02;
usb_buf[8] = 0x12;
for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
/*-------------------------------------------------*\
| Add led colors |
\*-------------------------------------------------*/
for(unsigned int i = led_idx; i < led_idx + zones[zone_idx].leds_count; i++)
{
usb_buf[packet_offset] = RGBGetRValue(colors[i]);
usb_buf[packet_offset+1] = RGBGetGValue(colors[i]);
usb_buf[packet_offset+2] = RGBGetBValue(colors[i]);
packet_offset = packet_offset + 3;
}
led_idx = led_idx + zones[zone_idx].leds_count;
/*-------------------------------------------------*\
| Move offset for pump zone with less than 29 LEDs |
\*-------------------------------------------------*/
if(zone_idx == 0)
{
packet_offset = packet_offset + 3 * (29 - zones[zone_idx].leds_count);
}
/*-------------------------------------------------*\
| Move offset for fans with less than 34 LEDs |
\*-------------------------------------------------*/
if(zone_idx != 0)
{
packet_offset = packet_offset + 3 * (34 - zones[zone_idx].leds_count);
}
channel_idx++;
}
/*-----------------------------------------------------*\
| Sending a direct mode color packet resets the timeout |
\*-----------------------------------------------------*/
last_commit_time = std::chrono::steady_clock::now();
hid_write(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
}
}
void CorsairCommanderCoreController::SetFanMode()
{
/*--------------------------------------------------------------------------------------------------*\
| Force controller to 6 QL fan mode to expose maximum number of LEDs per rgb port (34 LEDs per port) |
\*--------------------------------------------------------------------------------------------------*/
unsigned char usb_buf[1025];
unsigned char buffarray4[][5] =
{
{0x08, 0x05, 0x01, 0x01, 0x00},
{0x08, 0x0D, 0x01, 0x1E, 0x00},
{0x08, 0x09, 0x01, 0x00, 0x00}
};
SendMultiPkt(buffarray4, sizeof(buffarray4) / sizeof(buffarray4[0]), sizeof(buffarray4)[0] / sizeof(buffarray4[0][0]));
memset(usb_buf, 0, sizeof(usb_buf));
usb_buf[0] = 0x00;
usb_buf[1] = 0x08;
usb_buf[2] = 0x06;
usb_buf[3] = 0x01;
usb_buf[4] = 0x11;
usb_buf[8] = 0x0D;
usb_buf[10] = 0x07;
usb_buf[11] = 0x01;
usb_buf[12] = 0x08;
for(unsigned int i = 13; i < 25; i = i + 2)
{
usb_buf[i] = 0x01;
usb_buf[i + 1] = 0x06;
}
hid_write(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
hid_read(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
unsigned char buffarray2[][5] =
{
{0x08, 0x05, 0x01, 0x01, 0x00},
{0x08, 0x15, 0x01, 0x00, 0x00}
};
SendMultiPkt(buffarray2, sizeof(buffarray2) / sizeof(buffarray2[0]), sizeof(buffarray2)[0] / sizeof(buffarray2[0][0]));
memset(usb_buf, 0, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
usb_buf[0] = 0x00;
usb_buf[1] = 0x08;
usb_buf[2] = 0x06;
usb_buf[4] = 0xBD;
usb_buf[5] = 0x02;
usb_buf[8] = 0x12;
hid_write(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
hid_read(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE);
controller_ready = 1;
}
@@ -0,0 +1,65 @@
/*---------------------------------------------------------*\
| CorsairCommanderCoreController.h |
| |
| Definitions for Corsair Commander Core |
| Based on code by: |
| Adam Honse ([email protected]), 8/17/2020 |
| |
| Jeff P. |
\*---------------------------------------------------------*/
#include "RGBController.h"
#include <vector>
#include <chrono>
#include <hidapi/hidapi.h>
#pragma once
#define CORSAIR_COMMANDER_CORE_PACKET_SIZE 1025
#define CORSAIR_COMMANDER_CORE_PREAMBLE_OFFSET 10
#define CORSAIR_ELITE_CAPELLIX_PUMP_LED_OFFSET 87
#define CORSAIR_QL_FAN_ZONE_OFFSET 102
#define CORSAIR_COMMANDER_CORE_NUM_CHANNELS 6
enum
{
CORSAIR_COMMANDER_CORE_MODE_DIRECT = 0x00,
};
class CorsairCommanderCoreController
{
public:
CorsairCommanderCoreController(hid_device* dev_handle, const char* path);
~CorsairCommanderCoreController();
std::string GetLocationString();
void SetDirectColor
(
std::vector<RGBColor>,
std::vector<zone>
);
void KeepaliveThread();
void SetFanMode();
private:
hid_device* dev;
std::thread* keepalive_thread;
std::atomic<bool> keepalive_thread_run;
std::atomic<bool> controller_ready;
std::string location;
std::vector<RGBColor> lastcolors;
std::vector<zone> lastzones;
std::chrono::time_point<std::chrono::steady_clock> last_commit_time;
void SendMultiPkt
(
unsigned char buffarray[][5],
int r,
int c
);
void SendCommit();
void InitController();
};
@@ -0,0 +1,41 @@
#include "Detector.h"
#include "CorsairCommanderCoreController.h"
#include "RGBController.h"
#include "RGBController_CorsairCommanderCore.h"
#include <vector>
#include <hidapi/hidapi.h>
/*-----------------------------------------------------*\
| Corsair vendor ID |
\*-----------------------------------------------------*/
#define CORSAIR_VID 0x1B1C
/*-----------------------------------------------------*\
| Commander Core product IDs |
\*-----------------------------------------------------*/
#define CORSAIR_H150I_COMMANDER_CORE_PID 0x0C1C
/******************************************************************************************\
* *
* DetectCorsairCapellixControllers *
* *
* Tests the USB address to see if a Corsair RGB Cooler controller exists there. *
* *
\******************************************************************************************/
void DetectCorsairCapellixHIDControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CorsairCommanderCoreController* controller = new CorsairCommanderCoreController(dev, info->path);
RGBController_CorsairCommanderCore* rgb_controller = new RGBController_CorsairCommanderCore(controller);
rgb_controller->name = name;
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
REGISTER_HID_DETECTOR_PU("Corsair Commander Core", DetectCorsairCapellixHIDControllers, CORSAIR_VID, CORSAIR_H150I_COMMANDER_CORE_PID, 0xFF42, 0x01);
@@ -0,0 +1,125 @@
/*-----------------------------------------*\
| RGBController_CorsairCapellix.cpp |
| |
| Generic RGB Interface for Corsair |
| Commander Core |
| |
| Jeff P. |
\*-----------------------------------------*/
#include "RGBController_CorsairCommanderCore.h"
RGBController_CorsairCommanderCore::RGBController_CorsairCommanderCore(CorsairCommanderCoreController* corsair_ptr)
{
corsair = corsair_ptr;
vendor = "Corsair";
description = "Corsair Commander Core";
type = DEVICE_TYPE_COOLER;
location = corsair->GetLocationString();
SetupZones();
mode Direct;
Direct.name = "Direct";
Direct.value = 0;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
}
RGBController_CorsairCommanderCore::~RGBController_CorsairCommanderCore()
{
delete corsair;
}
void RGBController_CorsairCommanderCore::SetupZones()
{
std::atomic<bool> first_run;
first_run = 0;
if(zones.size() == 0)
{
first_run = 1;
}
zones.resize(7);
zones[0].name = "Pump";
zones[0].type = ZONE_TYPE_LINEAR;
zones[0].leds_min = 0;
zones[0].leds_max = 29;
for(unsigned int i = 1; i < (CORSAIR_COMMANDER_CORE_NUM_CHANNELS + 1); i++)
{
zones[i].name = "RGB Port " + std::to_string(i);
zones[i].type = ZONE_TYPE_LINEAR;
zones[i].leds_min = 0;
zones[i].leds_max = 34;
if(first_run)
{
zones[i].leds_count = 0;
}
}
leds.clear();
colors.clear();
for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
for (unsigned int led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++)
{
led new_led;
new_led.name = zones[zone_idx].name + " LED " + std::to_string(led_idx+1);
leds.push_back(new_led);
}
}
SetupColors();
}
void RGBController_CorsairCommanderCore::ResizeZone(int zone, int new_size)
{
if((size_t) zone >= zones.size())
{
return;
}
if(((unsigned int)new_size >= zones[zone].leds_min) && ((unsigned int)new_size <= zones[zone].leds_max))
{
zones[zone].leds_count = new_size;
SetupZones();
}
}
void RGBController_CorsairCommanderCore::DeviceUpdateLEDs()
{
DeviceUpdateMode();
}
void RGBController_CorsairCommanderCore::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_CorsairCommanderCore::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_CorsairCommanderCore::SetCustomMode()
{
active_mode = 0;
}
void RGBController_CorsairCommanderCore::DeviceUpdateMode()
{
switch(modes[active_mode].value)
{
case CORSAIR_COMMANDER_CORE_MODE_DIRECT:
corsair->SetDirectColor(colors, zones);
break;
}
}
@@ -0,0 +1,33 @@
/*-----------------------------------------*\
| RGBController_CorsairCapellix.h |
| |
| Generic RGB Interface for Corsair |
| Commander Core |
| |
| Jeff P. |
\*-----------------------------------------*/
#pragma once
#include "RGBController.h"
#include "CorsairCommanderCoreController.h"
class RGBController_CorsairCommanderCore : public RGBController
{
public:
RGBController_CorsairCommanderCore(CorsairCommanderCoreController* corsair_ptr);
~RGBController_CorsairCommanderCore();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void SetCustomMode();
void DeviceUpdateMode();
private:
CorsairCommanderCoreController* corsair;
std::vector<int> fanleds{0};
};
@@ -64,7 +64,12 @@ std::string CorsairLightingNodeController::GetLocationString()
std::string CorsairLightingNodeController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -112,7 +112,12 @@ std::string CorsairPeripheralController::GetName()
std::string CorsairPeripheralController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -51,7 +51,12 @@ std::string CorsairWirelessController::GetName()
std::string CorsairWirelessController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -38,7 +38,7 @@ std::string DasKeyboardController::GetSerialString()
int err = hid_get_serial_number_string(dev, serial_string, 128);
std::string return_string;
if(!err)
if(err == 0)
{
std::wstring return_wstring = serial_string;
return_string = std::string(return_wstring.begin(), return_wstring.end());
@@ -31,7 +31,12 @@ std::string DuckyKeyboardController::GetDeviceLocation()
std::string DuckyKeyboardController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -33,7 +33,12 @@ std::string EVisionKeyboardController::GetDeviceLocation()
std::string EVisionKeyboardController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -30,7 +30,12 @@ std::string ATC800Controller::GetDeviceLocation()
std::string ATC800Controller::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -36,6 +36,15 @@ void RGBFusionGPUController::SetColor(unsigned char red, unsigned char green, un
bus->i2c_smbus_write_byte(dev, red);
bus->i2c_smbus_write_byte(dev, green);
bus->i2c_smbus_write_byte(dev, blue);
// Pad commands with 4 zero-bytes for NVIDIA_RTX3060_DEV
if (dev == 0x62)
{
bus->i2c_smbus_write_byte(dev, 0x00);
bus->i2c_smbus_write_byte(dev, 0x00);
bus->i2c_smbus_write_byte(dev, 0x00);
bus->i2c_smbus_write_byte(dev, 0x00);
}
}
void RGBFusionGPUController::SetMode(unsigned char mode, unsigned char speed)
@@ -44,4 +53,13 @@ void RGBFusionGPUController::SetMode(unsigned char mode, unsigned char speed)
bus->i2c_smbus_write_byte(dev, mode);
bus->i2c_smbus_write_byte(dev, speed);
bus->i2c_smbus_write_byte(dev, 0x63);
// Pad commands with 4 zero-bytes for NVIDIA_RTX3060_DEV
if (dev == 0x62)
{
bus->i2c_smbus_write_byte(dev, 0x00);
bus->i2c_smbus_write_byte(dev, 0x00);
bus->i2c_smbus_write_byte(dev, 0x00);
bus->i2c_smbus_write_byte(dev, 0x00);
}
}
@@ -34,14 +34,16 @@ static const gpu_pci_device device_list[] =
{ NVIDIA_VEN, NVIDIA_GTX1650_DEV, GIGABYTE_SUB_VEN, GIGABYTE_GTX1650_GAMING_OC_SUB_DEV, 0x55, "Gigabyte GTX1650 Gaming OC" },
{ NVIDIA_VEN, NVIDIA_GTX1660S_DEV, GIGABYTE_SUB_VEN, GIGABYTE_GTX1660S_GAMING_OC_SUB_DEV, 0x47, "Gigabyte GTX1660 SUPER Gaming OC" },
{ NVIDIA_VEN, NVIDIA_RTX2060_TU106_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2060_GAMING_OC_SUB_DEV, 0x47, "Gigabyte RTX2060 Gaming OC" },
{ NVIDIA_VEN, NVIDIA_RTX2060S_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2060S_GAMING_SUB_DEV, 0x47, "Gigabyte RTX2060 SUPER Gaming" },
{ NVIDIA_VEN, NVIDIA_RTX2060_TU106_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2060_GAMING_OC_PRO_SUB_DEV, 0x47, "Gigabyte RTX2060 Gaming OC PRO" },
{ NVIDIA_VEN, NVIDIA_RTX2060S_OC_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2060S_GAMING_SUB_DEV, 0x47, "Gigabyte RTX2060 SUPER Gaming" },
{ NVIDIA_VEN, NVIDIA_RTX2070_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2070_GAMING_OC_SUB_DEV, 0x47, "Gigabyte RTX2070 Gaming OC 8G" },
{ NVIDIA_VEN, NVIDIA_RTX2070_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2070_WINDFORCE_SUB_DEV, 0x47, "Gigabyte RTX2070 Windforce 8G" },
{ NVIDIA_VEN, NVIDIA_RTX2070S_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2070S_GAMING_OC_SUB_DEV, 0x47, "Gigabyte RTX2070S Gaming OC" },
{ NVIDIA_VEN, NVIDIA_RTX2070S_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2070S_GAMING_OC_3X_SUB_DEV, 0x55, "Gigabyte RTX2070S Gaming OC 3X" },
{ NVIDIA_VEN, NVIDIA_RTX2080_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2080_GAMING_OC_SUB_DEV, 0x47, "Gigabyte RTX2080 Gaming OC 8G" },
{ NVIDIA_VEN, NVIDIA_RTX2080_A_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX2080_A_GAMING_OC_SUB_DEV, 0x47, "Gigabyte RTX2080 Gaming OC 8G" },
{ NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX3060TI_EAGLE_OC_SUB_DEV, 0x63, "Gigabyte RTX3060 EAGLE OC 8G" },
{ NVIDIA_VEN, NVIDIA_RTX3060_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX3060_GAMING_OC_12GB_SUB_DEV, 0x62, "Gigabyte RTX3060 Gaming OC 12G" },
{ NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX3060TI_EAGLE_OC_SUB_DEV, 0x63, "Gigabyte RTX3060 Ti EAGLE OC 8G" },
{ NVIDIA_VEN, NVIDIA_RTX3070_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX3070_VISION_OC_SUB_DEV, 0x63, "Gigabyte RTX3070 Vision 8G" },
};
@@ -67,6 +69,15 @@ bool TestForGigabyteRGBFusionGPUController(i2c_smbus_interface* bus, unsigned ch
bus->i2c_smbus_write_byte(address, 0x00);
bus->i2c_smbus_write_byte(address, 0x00);
bus->i2c_smbus_write_byte(address, 0x00);
// NVIDIA_RTX3060_DEV requires additional bytes to initialise
if (address == 0x62)
{
bus->i2c_smbus_write_byte(address, 0x00);
bus->i2c_smbus_write_byte(address, 0x00);
bus->i2c_smbus_write_byte(address, 0x00);
bus->i2c_smbus_write_byte(address, 0x00);
}
pass = true;
@@ -29,7 +29,12 @@ std::string HoltekA070Controller::GetDeviceLocation()
std::string HoltekA070Controller::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -30,7 +30,12 @@ std::string HoltekA1FAController::GetDeviceLocation()
std::string HoltekA1FAController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -35,7 +35,12 @@ std::string HyperXAlloyElite2Controller::GetDeviceLocation()
std::string HyperXAlloyElite2Controller::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -33,7 +33,12 @@ std::string HyperXAlloyOriginsController::GetDeviceLocation()
std::string HyperXAlloyOriginsController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -46,7 +46,12 @@ std::string HyperXKeyboardController::GetDeviceLocation()
std::string HyperXKeyboardController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -30,7 +30,12 @@ std::string HyperXPulsefireDartController::GetDeviceLocation()
std::string HyperXPulsefireDartController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -30,7 +30,12 @@ std::string HyperXPulsefireFPSProController::GetDeviceLocation()
std::string HyperXPulsefireFPSProController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -30,7 +30,12 @@ std::string HyperXPulsefireSurgeController::GetDeviceLocation()
std::string HyperXPulsefireSurgeController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -30,7 +30,12 @@ std::string HyperXMousematController::GetDeviceLocation()
std::string HyperXMousematController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -441,9 +441,14 @@ void DetectLogitechMouseG403(hid_device_info* info, const std::string& name)
addLogitechLightsyncMouse2zone(info, name, 0xFF, 0x0E, 0x3A);
}
void DetectLogitechMouseG502PS(hid_device_info* info, const std::string& name)
{
addLogitechLightsyncMouse2zone(info, name, 0xFF, 0x02, 0x3A);
}
void DetectLogitechMouseGPRO(hid_device_info* info, const std::string& name)
{
addLogitechLightsyncMouse2zone(info, name, 0x01, 0x07, 0x3C);
addLogitechLightsyncMouse1zone(info, name, 0xFF, 0x0E, 0x3C);
}
/*-----------------------------------------------------*\
@@ -486,6 +491,8 @@ REGISTER_HID_DETECTOR_IP ("Logitech G203 Prodigy", Dete
REGISTER_HID_DETECTOR_IPU("Logitech G203 Lightsync", DetectLogitechMouseG203L, LOGITECH_VID, LOGITECH_G203_LIGHTSYNC_PID, 1, 0xFF00, 2);
REGISTER_HID_DETECTOR_IP ("Logitech G303 Daedalus Apex", DetectLogitechMouseG303, LOGITECH_VID, LOGITECH_G303_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP ("Logitech G403 Hero", DetectLogitechMouseG403, LOGITECH_VID, LOGITECH_G403_HERO_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP ("Logitech G502 Proteus Spectrum Gaming Mouse", DetectLogitechMouseG502PS, LOGITECH_VID, LOGITECH_G502_PROTEUS_SPECTRUM_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP ("Logitech G502 Hero Gaming Mouse", DetectLogitechMouseG502PS, LOGITECH_VID, LOGITECH_G502_HERO_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP ("Logitech G Pro Gaming Mouse", DetectLogitechMouseGPRO, LOGITECH_VID, LOGITECH_G_PRO_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP ("Logitech G Pro (HERO) Gaming Mouse", DetectLogitechMouseGPRO, LOGITECH_VID, LOGITECH_G_PRO_HERO_PID, 1, 0xFF00);
/*-------------------------------------------------------------------------------------------------------------------------------------------------*\
@@ -596,8 +603,6 @@ REGISTER_HID_DETECTOR_IP("Logitech G Powerplay Mousepad",
| Lightspeed Wireless Devices (Windows Wired) |
\*-------------------------------------------------------------------------------------------------------------------------------------------------*/
REGISTER_HID_DETECTOR_IP("Logitech G403 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G403_LIGHTSPEED_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP("Logitech G502 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G502_PROTEUS_SPECTRUM_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP("Logitech G502 Hero Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G502_HERO_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP("Logitech G502 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G502_LIGHTSPEED_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP("Logitech G703 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G703_LIGHTSPEED_PID, 1, 0xFF00);
REGISTER_HID_DETECTOR_IP("Logitech G900 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G900_LIGHTSPEED_PID, 1, 0xFF00);
@@ -657,9 +662,7 @@ REGISTER_HID_DETECTOR_IPU("Logitech G Pro Wireless Gaming Mouse",
| Lightspeed Wireless Devices (Linux Wired) |
\*-------------------------------------------------------------------------------------------------------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Logitech G403 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G403_LIGHTSPEED_PID, 1, 0xFF00, 2);
REGISTER_HID_DETECTOR_IPU("Logitech G502 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G502_PROTEUS_SPECTRUM_PID, 1, 0xFF00, 2);
REGISTER_HID_DETECTOR_IPU("Logitech G502 Hero Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G502_LIGHTSPEED_PID, 1, 0xFF00, 2);
REGISTER_HID_DETECTOR_IPU("Logitech G502 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G502_HERO_PID, 1, 0xFF00, 2);
REGISTER_HID_DETECTOR_IPU("Logitech G502 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G502_LIGHTSPEED_PID, 1, 0xFF00, 2);
REGISTER_HID_DETECTOR_IPU("Logitech G703 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G703_LIGHTSPEED_PID, 1, 0xFF00, 2);
REGISTER_HID_DETECTOR_IPU("Logitech G900 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G900_LIGHTSPEED_PID, 1, 0xFF00, 2);
REGISTER_HID_DETECTOR_IPU("Logitech G903 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G903_LIGHTSPEED_PID, 1, 0xFF00, 2);
@@ -21,7 +21,12 @@ std::string LogitechG203LController::GetDeviceLocation()
std::string LogitechG203LController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -28,7 +28,12 @@ std::string LogitechG213Controller::GetDeviceLocation()
std::string LogitechG213Controller::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -25,7 +25,12 @@ LogitechG810Controller::~LogitechG810Controller()
std::string LogitechG810Controller::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev_pkt_0x11, serial_string, 128);
int ret = hid_get_serial_number_string(dev_pkt_0x11, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -24,7 +24,12 @@ LogitechG815Controller::~LogitechG815Controller()
std::string LogitechG815Controller::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev_pkt_0x11, serial_string, 128);
int ret = hid_get_serial_number_string(dev_pkt_0x11, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -25,7 +25,12 @@ LogitechG910Controller::~LogitechG910Controller()
std::string LogitechG910Controller::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev_pkt_0x11, serial_string, 128);
int ret = hid_get_serial_number_string(dev_pkt_0x11, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -46,7 +46,12 @@ std::string LogitechGLightsyncController::GetDeviceLocation()
std::string LogitechGLightsyncController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -30,7 +30,12 @@ std::string LogitechLightspeedController::GetDeviceLocation()
std::string LogitechLightspeedController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -21,7 +21,7 @@ static unsigned int matrix_map[7][27] =
{ NA, NA, 37, NA, 54, 55, 56, 57, NA, 58, 59, 60, 61, NA, 62, 63, 64, 65, NA, 66, 67, 68, NA, 106, 107, 108, 109 },
{ 112, NA, 49, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, NA, 41, 42, 38, NA, NA, 69, 70, 71, NA, 79, 80, 81, 82 },
{ 113, NA, 39, NA, 16, 22, 4, 17, NA, 19, 24, 20, 8, 14, 15, 43, 44, 45, NA, 72, 73, 74, NA, 91, 92, 93, 83 },
{ 114, NA, 53, NA, 0, 18, 3, 5, NA, 6, 7, 9, 10, 11, 47, 48, 36, NA, NA, NA, NA, NA, NA, 88, 89, 90, NA },
{ 114, NA, 53, NA, 0, 18, 3, 5, NA, 6, 7, 9, 10, 11, 47, 48, 46, 36, NA, NA, NA, NA, NA, 88, 89, 90, NA },
{ 115, NA, 99, NA, 25, 23, 2, 21, NA, 1, NA, 13, 12, 50, 51, 52, 103, NA, NA, NA, 78, NA, NA, 85, 86, 87, 84 },
{ 116, NA, 98, 101, 100, NA, NA, NA, NA, 40, NA, NA, NA, NA, 104, 105, 97, 102, NA, 76, 77, 75, NA, 94, NA, 95, NA } };
@@ -35,7 +35,12 @@ std::string MSI3ZoneController::GetDeviceLocation()
std::string MSI3ZoneController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -36,8 +36,8 @@ static const msi_gpu_pci_device device_list[] =
{ NVIDIA_VEN, NVIDIA_RTX2060_TU104_DEV, MSI_SUB_VEN, MSI_RTX2060_GAMING_Z_6G_SUB_DEV, "MSI GeForce RTX 2060 Gaming Z 6G" },
{ NVIDIA_VEN, NVIDIA_RTX2060_TU106_DEV, MSI_SUB_VEN, MSI_RTX2060_GAMING_Z_6G_SUB_DEV, "MSI GeForce RTX 2060 Gaming Z 6G" },
{ NVIDIA_VEN, NVIDIA_RTX2060_TU106_DEV, MSI_SUB_VEN, MSI_RTX2060_GAMING_Z_6G_SUB_DEV_2, "MSI GeForce RTX 2060 Gaming Z 6G" },
{ NVIDIA_VEN, NVIDIA_RTX2060S_DEV, MSI_SUB_VEN, MSI_RTX2060S_GAMING_X_SUB_DEV, "MSI GeForce RTX 2060 Super Gaming X" },
{ NVIDIA_VEN, NVIDIA_RTX2060S_DEV, MSI_SUB_VEN, MSI_RTX2060S_ARMOR_OC_SUB_DEV, "MSI GeForce RTX 2060 Super ARMOR OC" },
{ NVIDIA_VEN, NVIDIA_RTX2060S_OC_DEV, MSI_SUB_VEN, MSI_RTX2060S_GAMING_X_SUB_DEV, "MSI GeForce RTX 2060 Super Gaming X" },
{ NVIDIA_VEN, NVIDIA_RTX2060S_OC_DEV, MSI_SUB_VEN, MSI_RTX2060S_ARMOR_OC_SUB_DEV, "MSI GeForce RTX 2060 Super ARMOR OC" },
{ NVIDIA_VEN, NVIDIA_RTX2070_OC_DEV, MSI_SUB_VEN, MSI_RTX2070_GAMING_Z_SUB_DEV, "MSI GeForce RTX 2070 Gaming Z" },
{ NVIDIA_VEN, NVIDIA_RTX2070_DEV, MSI_SUB_VEN, MSI_RTX2070_GAMING_SUB_DEV, "MSI GeForce RTX 2070 Gaming" },
{ NVIDIA_VEN, NVIDIA_RTX2070_DEV, MSI_SUB_VEN, MSI_RTX2070_ARMOR_SUB_DEV, "MSI GeForce RTX 2070 ARMOR" },
@@ -71,7 +71,12 @@ std::string NZXTHue2Controller::GetFirmwareVersion()
std::string NZXTHue2Controller::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -56,7 +56,12 @@ std::string NZXTKrakenController::GetLocation()
std::string NZXTKrakenController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -0,0 +1,81 @@
/*---------------------------------------------------------*\
| Driver for Philips Hue |
| |
| Adam Honse ([email protected]), 9/15/2020 |
\*---------------------------------------------------------*/
#include "PhilipsHueController.h"
PhilipsHueController::PhilipsHueController(hueplusplus::Light& light_ptr, std::string bridge_ip):light(light_ptr)
{
dark = false;
location = "IP: " + bridge_ip;
}
PhilipsHueController::~PhilipsHueController()
{
}
std::string PhilipsHueController::GetLocation()
{
return(location);
}
std::string PhilipsHueController::GetName()
{
return(light.getModelId());
}
std::string PhilipsHueController::GetVersion()
{
return(light.getSwVersion());
}
std::string PhilipsHueController::GetManufacturer()
{
return(light.getManufacturername());
}
std::string PhilipsHueController::GetUniqueID()
{
return(light.getUId());
}
void PhilipsHueController::SetColor(unsigned char red, unsigned char green, unsigned char blue)
{
hueplusplus::RGB rgb;
rgb.r = red;
rgb.g = green;
rgb.b = blue;
if((red == 0) && (green == 0) && (blue == 0))
{
if(!dark)
{
try
{
light.setColorRGB(rgb, 0);
}
catch(std::exception& e)
{
}
}
dark = true;
}
else
{
dark = false;
try
{
light.setColorRGB(rgb, 0);
}
catch(std::exception& e)
{
}
}
}
@@ -0,0 +1,33 @@
/*---------------------------------------------------------*\
| Definitions for Philips Hue |
| |
| Adam Honse ([email protected]), 9/15/2020 |
\*---------------------------------------------------------*/
#include "RGBController.h"
#include "HueDeviceTypes.h"
#include <string>
#include <vector>
#pragma once
class PhilipsHueController
{
public:
PhilipsHueController(hueplusplus::Light& light_ptr, std::string bridge_ip);
~PhilipsHueController();
std::string GetLocation();
std::string GetName();
std::string GetVersion();
std::string GetManufacturer();
std::string GetUniqueID();
void SetColor(unsigned char red, unsigned char green, unsigned char blue);
private:
hueplusplus::Light& light;
std::string location;
bool dark;
};
@@ -0,0 +1,232 @@
#include "Bridge.h"
#include "HueDeviceTypes.h"
#ifdef _WIN32
#include "WinHttpHandler.h"
#else
#include "LinHttpHandler.h"
#endif
#include "Detector.h"
#include "LogManager.h"
#include "PhilipsHueController.h"
#include "PhilipsHueEntertainmentController.h"
#include "RGBController_PhilipsHue.h"
#include "RGBController_PhilipsHueEntertainment.h"
#include "SettingsManager.h"
/******************************************************************************************\
* *
* DetectPhilipsHueControllers *
* *
* Detect Philips Hue lighting devices with RGB control *
* *
\******************************************************************************************/
void DetectPhilipsHueControllers(std::vector<RGBController*>& rgb_controllers)
{
json hue_settings;
/*-------------------------------------------------*\
| Create an HTTP handler |
\*-------------------------------------------------*/
#ifdef _WIN32
using SystemHttpHandler = hueplusplus::WinHttpHandler;
#else
using SystemHttpHandler = hueplusplus::LinHttpHandler;
#endif
/*-------------------------------------------------*\
| Get Philips Hue settings from settings manager |
\*-------------------------------------------------*/
hue_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("PhilipsHueDevices");
/*-------------------------------------------------*\
| Create a finder and find bridges |
\*-------------------------------------------------*/
static hueplusplus::BridgeFinder finder(std::make_shared<SystemHttpHandler>());
std::vector<hueplusplus::BridgeFinder::BridgeIdentification> bridges;// = finder.findBridges();
/*-------------------------------------------------*\
| If no bridges were detected, manually add bridge |
| IP and MAC (need to get these from file) |
\*-------------------------------------------------*/
if(bridges.empty())
{
if(hue_settings.contains("bridges"))
{
hueplusplus::BridgeFinder::BridgeIdentification ident;
if(hue_settings["bridges"][0].contains("ip"))
{
ident.ip = hue_settings["bridges"][0]["ip"];
}
if(hue_settings["bridges"][0].contains("mac"))
{
ident.mac = hue_settings["bridges"][0]["mac"];
}
bridges.push_back(ident);
}
}
/*-------------------------------------------------*\
| If no bridges were found, return, otherwise |
| connect to the first bridge |
\*-------------------------------------------------*/
if(bridges.empty())
{
return;
}
else
{
/*-------------------------------------------------*\
| Check if a saved username exists |
\*-------------------------------------------------*/
if(hue_settings.contains("bridges"))
{
/*-------------------------------------------------*\
| Add the username if it exists |
\*-------------------------------------------------*/
if(hue_settings["bridges"][0].contains("username"))
{
finder.addUsername(bridges[0].mac, hue_settings["bridges"][0]["username"]);
}
/*-------------------------------------------------*\
| Add the client key if it exists |
\*-------------------------------------------------*/
if(hue_settings["bridges"][0].contains("clientkey"))
{
finder.addClientKey(bridges[0].mac, hue_settings["bridges"][0]["clientkey"]);
}
}
/*-------------------------------------------------*\
| If username was added, this should connect right |
| away. If not, the user will have to push the |
| connect button on the bridge. |
\*-------------------------------------------------*/
try
{
static hueplusplus::Bridge bridge = finder.getBridge(bridges[0]);
bridge.refresh();
/*-------------------------------------------------*\
| Check to see if we need to save the settings |
| Settings need to be saved if either username or |
| client key either do not exist or have changed |
\*-------------------------------------------------*/
bool save_settings = false;
bool use_entertainment = false;
if(hue_settings.contains("bridges"))
{
if(hue_settings["bridges"][0].contains("username"))
{
if(hue_settings["bridges"][0]["username"] != bridge.getUsername())
{
save_settings = true;
}
}
else
{
save_settings = true;
}
if(hue_settings["bridges"][0].contains("clientkey"))
{
if(hue_settings["bridges"][0]["clientkey"] != bridge.getClientKey())
{
use_entertainment = true;
save_settings = true;
}
}
else
{
save_settings = true;
}
}
/*-------------------------------------------------*\
| Save the settings if needed |
\*-------------------------------------------------*/
if(save_settings)
{
hue_settings["bridges"][0]["username"] = bridge.getUsername();
hue_settings["bridges"][0]["clientkey"] = bridge.getClientKey();
hue_settings["bridges"][0]["entertainment"] = use_entertainment;
ResourceManager::get()->GetSettingsManager()->SetSettings("PhilipsHueDevices", hue_settings);
ResourceManager::get()->GetSettingsManager()->SaveSettings();
}
/*-------------------------------------------------*\
| Get all groups from the bridge |
\*-------------------------------------------------*/
if(hue_settings["bridges"][0].contains("entertainment"))
{
use_entertainment = hue_settings["bridges"][0]["entertainment"];
}
/*-------------------------------------------------*\
| Get all groups from the bridge |
\*-------------------------------------------------*/
if(use_entertainment)
{
std::vector<hueplusplus::Group> groups = bridge.groups().getAll();
if(groups.size() > 0)
{
/*-------------------------------------------------*\
| Loop through all available groups and check to |
| see if any are Entertainment groups |
\*-------------------------------------------------*/
for(unsigned int group_idx = 0; group_idx < groups.size(); group_idx++)
{
if(groups[group_idx].getType() == "Entertainment")
{
PhilipsHueEntertainmentController* new_controller = new PhilipsHueEntertainmentController(bridge, groups[group_idx]);
RGBController_PhilipsHueEntertainment* new_rgbcontroller = new RGBController_PhilipsHueEntertainment(new_controller);
rgb_controllers.push_back(new_rgbcontroller);
}
}
}
}
/*-------------------------------------------------*\
| Get all lights from the bridge |
\*-------------------------------------------------*/
else
{
std::vector<hueplusplus::Light> lights = bridge.lights().getAll();
if(lights.size() > 0)
{
/*-------------------------------------------------*\
| Loop through all available lights and add those |
| that have color (RGB) control capability |
\*-------------------------------------------------*/
for(unsigned int light_idx = 0; light_idx < lights.size(); light_idx++)
{
if(lights[light_idx].hasColorControl())
{
PhilipsHueController* new_controller = new PhilipsHueController(lights[light_idx], bridge.getBridgeIP());
RGBController_PhilipsHue* new_rgbcontroller = new RGBController_PhilipsHue(new_controller);
rgb_controllers.push_back(new_rgbcontroller);
}
}
}
}
}
catch(std::exception &e)
{
LOG_NOTICE("Exception occurred in Philips Hue detection");
}
}
} /* DetectPhilipsHueControllers() */
REGISTER_DETECTOR("Philips Hue", DetectPhilipsHueControllers);
@@ -0,0 +1,82 @@
/*---------------------------------------------------------*\
| Driver for Philips Hue Entertainment Mode |
| |
| Adam Honse ([email protected]), 11/6/2020 |
\*---------------------------------------------------------*/
#include "PhilipsHueEntertainmentController.h"
PhilipsHueEntertainmentController::PhilipsHueEntertainmentController(hueplusplus::Bridge& bridge_ptr, hueplusplus::Group& group_ptr):bridge(bridge_ptr),group(group_ptr)
{
/*-------------------------------------------------*\
| Fill in location string with bridge IP |
\*-------------------------------------------------*/
location = "IP: " + bridge.getBridgeIP();
num_leds = group.getLightIds().size();
/*-------------------------------------------------*\
| Create Entertainment Mode from bridge and group |
\*-------------------------------------------------*/
entertainment = new hueplusplus::EntertainmentMode(bridge, group);
/*-------------------------------------------------*\
| Connect Hue Entertainment Mode |
\*-------------------------------------------------*/
entertainment->connect();
}
PhilipsHueEntertainmentController::~PhilipsHueEntertainmentController()
{
/*-------------------------------------------------*\
| Disconnect Hue Entertainment Mode |
\*-------------------------------------------------*/
entertainment->disconnect();
}
std::string PhilipsHueEntertainmentController::GetLocation()
{
return(location);
}
std::string PhilipsHueEntertainmentController::GetName()
{
return(group.getName());
}
std::string PhilipsHueEntertainmentController::GetVersion()
{
return("");
}
std::string PhilipsHueEntertainmentController::GetManufacturer()
{
return("");
}
std::string PhilipsHueEntertainmentController::GetUniqueID()
{
return("");
}
unsigned int PhilipsHueEntertainmentController::GetNumLEDs()
{
return(num_leds);
}
void PhilipsHueEntertainmentController::SetColor(RGBColor* colors)
{
/*-------------------------------------------------*\
| Fill in Entertainment Mode light data |
\*-------------------------------------------------*/
for(unsigned int light_idx = 0; light_idx < num_leds; light_idx++)
{
RGBColor color = colors[light_idx];
unsigned char red = RGBGetRValue(color);
unsigned char green = RGBGetGValue(color);
unsigned char blue = RGBGetBValue(color);
entertainment->setColorRGB(light_idx, red, green, blue);
}
entertainment->update();
}
@@ -0,0 +1,42 @@
/*---------------------------------------------------------*\
| Definitions for Philips Hue Entertainment Mode |
| |
| Adam Honse ([email protected]), 11/6/2020 |
\*---------------------------------------------------------*/
#include "RGBController.h"
#include "Bridge.h"
#include "EntertainmentMode.h"
#include "Group.h"
#include <string>
#include <vector>
#pragma once
#define HUE_ENTERTAINMENT_HEADER_SIZE 16
#define HUE_ENTERTAINMENT_LIGHT_SIZE 9
class PhilipsHueEntertainmentController
{
public:
PhilipsHueEntertainmentController(hueplusplus::Bridge& bridge_ptr, hueplusplus::Group& group_ptr);
~PhilipsHueEntertainmentController();
std::string GetLocation();
std::string GetName();
std::string GetVersion();
std::string GetManufacturer();
std::string GetUniqueID();
unsigned int GetNumLEDs();
void SetColor(RGBColor* colors);
private:
hueplusplus::Bridge& bridge;
hueplusplus::Group& group;
hueplusplus::EntertainmentMode* entertainment;
std::string location;
unsigned int num_leds;
};
@@ -0,0 +1,85 @@
/*-----------------------------------------*\
| RGBController_PhilipsHue.cpp |
| |
| Generic RGB Interface for Philips Hue |
| |
| Adam Honse (CalcProgrammer1) 9/15/2020 |
\*-----------------------------------------*/
#include "RGBController_PhilipsHue.h"
RGBController_PhilipsHue::RGBController_PhilipsHue(PhilipsHueController* light_ptr)
{
light = light_ptr;
name = light->GetManufacturer() + " " + light->GetName();
type = DEVICE_TYPE_LIGHT;
version = light->GetVersion();
description = "Philips Hue Device";
serial = light->GetUniqueID();
location = light->GetLocation();
mode Direct;
Direct.name = "Direct";
Direct.value = 0;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
SetupZones();
}
void RGBController_PhilipsHue::SetupZones()
{
zone led_zone;
led_zone.name = "RGB Light";
led_zone.type = ZONE_TYPE_SINGLE;
led_zone.leds_min = 1;
led_zone.leds_max = 1;
led_zone.leds_count = 1;
led_zone.matrix_map = NULL;
zones.push_back(led_zone);
led new_led;
new_led.name = "RGB Light";
leds.push_back(new_led);
SetupColors();
}
void RGBController_PhilipsHue::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_PhilipsHue::DeviceUpdateLEDs()
{
unsigned char red = RGBGetRValue(colors[0]);
unsigned char grn = RGBGetGValue(colors[0]);
unsigned char blu = RGBGetBValue(colors[0]);
light->SetColor(red, grn, blu);
}
void RGBController_PhilipsHue::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_PhilipsHue::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_PhilipsHue::SetCustomMode()
{
}
void RGBController_PhilipsHue::DeviceUpdateMode()
{
}
@@ -0,0 +1,31 @@
/*-----------------------------------------*\
| RGBController_PhilipsHue.h |
| |
| Generic RGB Interface for Philips Hue |
| |
| Adam Honse (CalcProgrammer1) 9/15/2020 |
\*-----------------------------------------*/
#pragma once
#include "RGBController.h"
#include "PhilipsHueController.h"
class RGBController_PhilipsHue : public RGBController
{
public:
RGBController_PhilipsHue(PhilipsHueController* light_ptr);
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void SetCustomMode();
void DeviceUpdateMode();
private:
PhilipsHueController* light;
};
@@ -0,0 +1,113 @@
/*-----------------------------------------*\
| RGBController_PhilipsHueEntertainment.cpp|
| |
| Generic RGB Interface for Philips Hue |
| Entertainment Mode |
| |
| Adam Honse (CalcProgrammer1) 11/7/2020 |
\*-----------------------------------------*/
#include "RGBController_PhilipsHueEntertainment.h"
using namespace std::chrono_literals;
RGBController_PhilipsHueEntertainment::RGBController_PhilipsHueEntertainment(PhilipsHueEntertainmentController* light_ptr)
{
light = light_ptr;
name = light->GetManufacturer() + " " + light->GetName();
type = DEVICE_TYPE_LIGHT;
version = light->GetVersion();
description = "Philips Hue Entertainment Mode Device";
serial = light->GetUniqueID();
location = light->GetLocation();
mode Direct;
Direct.name = "Direct";
Direct.value = 0;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
SetupZones();
/*-----------------------------------------------------*\
| The Philips Hue Entertainment Mode requires a packet |
| within 10 seconds of sending the lighting change in |
| order to not exit entertainment mode. Start a thread |
| to continuously send a packet every 5s |
\*-----------------------------------------------------*/
KeepaliveThreadRunning = true;
KeepaliveThread = new std::thread(&RGBController_PhilipsHueEntertainment::KeepaliveThreadFunction, this);
}
void RGBController_PhilipsHueEntertainment::SetupZones()
{
zone led_zone;
led_zone.name = "RGB Light";
led_zone.type = ZONE_TYPE_SINGLE;
led_zone.leds_min = light->GetNumLEDs();
led_zone.leds_max = light->GetNumLEDs();
led_zone.leds_count = light->GetNumLEDs();
led_zone.matrix_map = NULL;
zones.push_back(led_zone);
for(unsigned int led_idx = 0; led_idx < light->GetNumLEDs(); led_idx++)
{
led new_led;
new_led.name = "RGB Light";
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_PhilipsHueEntertainment::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_PhilipsHueEntertainment::DeviceUpdateLEDs()
{
last_update_time = std::chrono::steady_clock::now();
light->SetColor(&colors[0]);
}
void RGBController_PhilipsHueEntertainment::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_PhilipsHueEntertainment::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_PhilipsHueEntertainment::SetCustomMode()
{
active_mode = 0;
}
void RGBController_PhilipsHueEntertainment::DeviceUpdateMode()
{
}
void RGBController_PhilipsHueEntertainment::KeepaliveThreadFunction()
{
while(KeepaliveThreadRunning)
{
if(active_mode == 0)
{
if((std::chrono::steady_clock::now() - last_update_time) > std::chrono::seconds(5))
{
UpdateLEDs();
}
}
std::this_thread::sleep_for(1s);
}
}
@@ -0,0 +1,42 @@
/*-----------------------------------------*\
| RGBController_PhilipsHueEntertainment.h |
| |
| Generic RGB Interface for Philips Hue |
| Entertainment Mode |
| |
| Adam Honse (CalcProgrammer1) 11/7/2020 |
\*-----------------------------------------*/
#pragma once
#include "RGBController.h"
#include "PhilipsHueEntertainmentController.h"
#include <atomic>
#include <thread>
class RGBController_PhilipsHueEntertainment : public RGBController
{
public:
RGBController_PhilipsHueEntertainment(PhilipsHueEntertainmentController* light_ptr);
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void SetCustomMode();
void DeviceUpdateMode();
void KeepaliveThreadFunction();
private:
PhilipsHueEntertainmentController* light;
std::atomic<bool> KeepaliveThreadRunning;
std::thread* KeepaliveThread;
std::chrono::time_point<std::chrono::steady_clock> last_update_time;
};
@@ -26,7 +26,12 @@ std::string RedragonM711Controller::GetDeviceLocation()
std::string RedragonM711Controller::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -43,7 +43,12 @@ unsigned int SinowealthController::GetLEDCount()
std::string SinowealthController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev_report_id_4, serial_string, 128);
int ret = hid_get_serial_number_string(dev_report_id_4, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -41,7 +41,12 @@ std::string PoseidonZRGBController::GetDeviceLocation()
std::string PoseidonZRGBController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -32,7 +32,12 @@ std::string ThermaltakeRiingController::GetDeviceLocation()
std::string ThermaltakeRiingController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
@@ -74,7 +74,12 @@ std::string ZalmanZSyncController::GetLocationString()
std::string ZalmanZSyncController::GetSerialString()
{
wchar_t serial_string[128];
hid_get_serial_number_string(dev, serial_string, 128);
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());
+142 -1
View File
@@ -23,7 +23,7 @@ greaterThan(QT_MAJOR_VERSION, 5): DEFINES += _QT6
#-----------------------------------------------------------------------------------------------#
# Application Configuration #
#-----------------------------------------------------------------------------------------------#
VERSION = 0.6
VERSION = 0.61
TARGET = OpenRGB
TEMPLATE = app
@@ -49,6 +49,8 @@ DEFINES +=
INCLUDEPATH += \
dependencies/ColorWheel \
dependencies/CRCpp/ \
dependencies/hueplusplus-1.0.0/include \
dependencies/hueplusplus-1.0.0/include/hueplusplus \
dependencies/json/ \
dependencies/libe131/src/ \
dependencies/libcmmk/include/ \
@@ -66,6 +68,7 @@ INCLUDEPATH +=
Controllers/AsusAuraSMBusController/ \
Controllers/AsusAuraUSBController/ \
Controllers/CoolerMasterController/ \
Controllers/CorsairCommanderCoreController/ \
Controllers/CorsairDominatorPlatinumController/ \
Controllers/CorsairHydroController/ \
Controllers/CorsairHydroPlatinumController/ \
@@ -110,6 +113,7 @@ INCLUDEPATH +=
Controllers/NZXTKrakenController/ \
Controllers/OpenRazerController/ \
Controllers/PatriotViperController/ \
Controllers/PhilipsHueController/ \
Controllers/PhilipsWizController/ \
Controllers/QMKOpenRGBController/ \
Controllers/RazerController/ \
@@ -197,6 +201,8 @@ HEADERS +=
Controllers/CoolerMasterController/RGBController_CMSmallARGBController.h \
Controllers/CoolerMasterController/RGBController_CMR6000Controller.h \
Controllers/CoolerMasterController/RGBController_CMMKController.h \
Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.h \
Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.h \
Controllers/CorsairDominatorPlatinumController/CorsairDominatorPlatinumController.h \
Controllers/CorsairDominatorPlatinumController/RGBController_CorsairDominatorPlatinum.h \
Controllers/CorsairHydroController/CorsairHydroController.h \
@@ -316,6 +322,8 @@ HEADERS +=
Controllers/OpenRazerController/OpenRazerDevices.h \
Controllers/PatriotViperController/PatriotViperController.h \
Controllers/PatriotViperController/RGBController_PatriotViper.h \
Controllers/PhilipsHueController/PhilipsHueController.h \
Controllers/PhilipsHueController/RGBController_PhilipsHue.h \
Controllers/PhilipsWizController/PhilipsWizController.h \
Controllers/PhilipsWizController/RGBController_PhilipsWiz.h \
Controllers/QMKOpenRGBController/QMKOpenRGBController.h \
@@ -376,6 +384,35 @@ SOURCES +=
Controllers/LogitechController/LogitechProtocolCommon.cpp \
dependencies/dmiinfo.cpp \
dependencies/ColorWheel/ColorWheel.cpp \
dependencies/hueplusplus-1.0.0/src/Action.cpp \
dependencies/hueplusplus-1.0.0/src/APICache.cpp \
dependencies/hueplusplus-1.0.0/src/BaseDevice.cpp \
dependencies/hueplusplus-1.0.0/src/BaseHttpHandler.cpp \
dependencies/hueplusplus-1.0.0/src/Bridge.cpp \
dependencies/hueplusplus-1.0.0/src/BridgeConfig.cpp \
dependencies/hueplusplus-1.0.0/src/CLIPSensors.cpp \
dependencies/hueplusplus-1.0.0/src/ColorUnits.cpp \
dependencies/hueplusplus-1.0.0/src/EntertainmentMode.cpp \
dependencies/hueplusplus-1.0.0/src/ExtendedColorHueStrategy.cpp \
dependencies/hueplusplus-1.0.0/src/ExtendedColorTemperatureStrategy.cpp \
dependencies/hueplusplus-1.0.0/src/Group.cpp \
dependencies/hueplusplus-1.0.0/src/HueCommandAPI.cpp \
dependencies/hueplusplus-1.0.0/src/HueDeviceTypes.cpp \
dependencies/hueplusplus-1.0.0/src/HueException.cpp \
dependencies/hueplusplus-1.0.0/src/Light.cpp \
dependencies/hueplusplus-1.0.0/src/ModelPictures.cpp \
dependencies/hueplusplus-1.0.0/src/NewDeviceList.cpp \
dependencies/hueplusplus-1.0.0/src/Scene.cpp \
dependencies/hueplusplus-1.0.0/src/Schedule.cpp \
dependencies/hueplusplus-1.0.0/src/Sensor.cpp \
dependencies/hueplusplus-1.0.0/src/SimpleBrightnessStrategy.cpp \
dependencies/hueplusplus-1.0.0/src/SimpleColorHueStrategy.cpp \
dependencies/hueplusplus-1.0.0/src/SimpleColorTemperatureStrategy.cpp \
dependencies/hueplusplus-1.0.0/src/StateTransaction.cpp \
dependencies/hueplusplus-1.0.0/src/TimePattern.cpp \
dependencies/hueplusplus-1.0.0/src/UPnP.cpp \
dependencies/hueplusplus-1.0.0/src/Utils.cpp \
dependencies/hueplusplus-1.0.0/src/ZLLSensors.cpp \
dependencies/libe131/src/e131.c \
dependencies/libcmmk/src/libcmmk.c \
main.cpp \
@@ -446,6 +483,9 @@ SOURCES +=
Controllers/CoolerMasterController/RGBController_CMSmallARGBController.cpp \
Controllers/CoolerMasterController/RGBController_CMR6000Controller.cpp \
Controllers/CoolerMasterController/RGBController_CMMKController.cpp \
Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.cpp \
Controllers/CorsairCommanderCoreController/CorsairCommanderCoreControllerDetect.cpp \
Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.cpp \
Controllers/CorsairDominatorPlatinumController/CorsairDominatorPlatinumController.cpp \
Controllers/CorsairDominatorPlatinumController/CorsairDominatorPlatinumControllerDetect.cpp \
Controllers/CorsairDominatorPlatinumController/RGBController_CorsairDominatorPlatinum.cpp \
@@ -606,6 +646,11 @@ SOURCES +=
Controllers/PatriotViperController/PatriotViperController.cpp \
Controllers/PatriotViperController/PatriotViperControllerDetect.cpp \
Controllers/PatriotViperController/RGBController_PatriotViper.cpp \
Controllers/PhilipsHueController/PhilipsHueController.cpp \
Controllers/PhilipsHueController/PhilipsHueControllerDetect.cpp \
Controllers/PhilipsHueController/PhilipsHueEntertainmentController.cpp \
Controllers/PhilipsHueController/RGBController_PhilipsHue.cpp \
Controllers/PhilipsHueController/RGBController_PhilipsHueEntertainment.cpp \
Controllers/PhilipsWizController/PhilipsWizController.cpp \
Controllers/PhilipsWizController/PhilipsWizControllerDetect.cpp \
Controllers/PhilipsWizController/RGBController_PhilipsWiz.cpp \
@@ -699,6 +744,7 @@ win32:INCLUDEPATH +=
dependencies/hidapi \
dependencies/inpout32_1501/Win32/ \
dependencies/libusb-1.0.22/include \
dependencies/mbedtls-2.24.0/include \
dependencies/NVFC \
dependencies/openrazer-win32 \
wmi/ \
@@ -706,6 +752,91 @@ win32:INCLUDEPATH +=
win32:SOURCES += \
# dependencies/hidapi/hidapi.c \
dependencies/hueplusplus-1.0.0/src/WinHttpHandler.cpp \
dependencies/mbedtls-2.24.0/library/aes.c \
dependencies/mbedtls-2.24.0/library/aesni.c \
dependencies/mbedtls-2.24.0/library/arc4.c \
dependencies/mbedtls-2.24.0/library/aria.c \
dependencies/mbedtls-2.24.0/library/asn1parse.c \
dependencies/mbedtls-2.24.0/library/asn1write.c \
dependencies/mbedtls-2.24.0/library/base64.c \
dependencies/mbedtls-2.24.0/library/bignum.c \
dependencies/mbedtls-2.24.0/library/blowfish.c \
dependencies/mbedtls-2.24.0/library/camellia.c \
dependencies/mbedtls-2.24.0/library/ccm.c \
dependencies/mbedtls-2.24.0/library/certs.c \
dependencies/mbedtls-2.24.0/library/chacha20.c \
dependencies/mbedtls-2.24.0/library/chachapoly.c \
dependencies/mbedtls-2.24.0/library/cipher.c \
dependencies/mbedtls-2.24.0/library/cipher_wrap.c \
dependencies/mbedtls-2.24.0/library/cmac.c \
dependencies/mbedtls-2.24.0/library/ctr_drbg.c \
dependencies/mbedtls-2.24.0/library/debug.c \
dependencies/mbedtls-2.24.0/library/des.c \
dependencies/mbedtls-2.24.0/library/dhm.c \
dependencies/mbedtls-2.24.0/library/ecdh.c \
dependencies/mbedtls-2.24.0/library/ecdsa.c \
dependencies/mbedtls-2.24.0/library/ecjpake.c \
dependencies/mbedtls-2.24.0/library/ecp.c \
dependencies/mbedtls-2.24.0/library/ecp_curves.c \
dependencies/mbedtls-2.24.0/library/entropy.c \
dependencies/mbedtls-2.24.0/library/entropy_poll.c \
dependencies/mbedtls-2.24.0/library/error.c \
dependencies/mbedtls-2.24.0/library/gcm.c \
dependencies/mbedtls-2.24.0/library/havege.c \
dependencies/mbedtls-2.24.0/library/hkdf.c \
dependencies/mbedtls-2.24.0/library/hmac_drbg.c \
dependencies/mbedtls-2.24.0/library/md.c \
dependencies/mbedtls-2.24.0/library/md2.c \
dependencies/mbedtls-2.24.0/library/md4.c \
dependencies/mbedtls-2.24.0/library/md5.c \
dependencies/mbedtls-2.24.0/library/memory_buffer_alloc.c \
dependencies/mbedtls-2.24.0/library/net_sockets.c \
dependencies/mbedtls-2.24.0/library/nist_kw.c \
dependencies/mbedtls-2.24.0/library/oid.c \
dependencies/mbedtls-2.24.0/library/padlock.c \
dependencies/mbedtls-2.24.0/library/pem.c \
dependencies/mbedtls-2.24.0/library/pk.c \
dependencies/mbedtls-2.24.0/library/pk_wrap.c \
dependencies/mbedtls-2.24.0/library/pkcs5.c \
dependencies/mbedtls-2.24.0/library/pkcs11.c \
dependencies/mbedtls-2.24.0/library/pkcs12.c \
dependencies/mbedtls-2.24.0/library/pkparse.c \
dependencies/mbedtls-2.24.0/library/pkwrite.c \
dependencies/mbedtls-2.24.0/library/platform.c \
dependencies/mbedtls-2.24.0/library/platform_util.c \
dependencies/mbedtls-2.24.0/library/poly1305.c \
dependencies/mbedtls-2.24.0/library/psa_crypto.c \
dependencies/mbedtls-2.24.0/library/psa_crypto_se.c \
dependencies/mbedtls-2.24.0/library/psa_crypto_slot_management.c \
dependencies/mbedtls-2.24.0/library/psa_crypto_storage.c \
dependencies/mbedtls-2.24.0/library/psa_its_file.c \
dependencies/mbedtls-2.24.0/library/ripemd160.c \
dependencies/mbedtls-2.24.0/library/rsa.c \
dependencies/mbedtls-2.24.0/library/rsa_internal.c \
dependencies/mbedtls-2.24.0/library/sha1.c \
dependencies/mbedtls-2.24.0/library/sha256.c \
dependencies/mbedtls-2.24.0/library/sha512.c \
dependencies/mbedtls-2.24.0/library/ssl_cache.c \
dependencies/mbedtls-2.24.0/library/ssl_ciphersuites.c \
dependencies/mbedtls-2.24.0/library/ssl_cli.c \
dependencies/mbedtls-2.24.0/library/ssl_cookie.c \
dependencies/mbedtls-2.24.0/library/ssl_msg.c \
dependencies/mbedtls-2.24.0/library/ssl_srv.c \
dependencies/mbedtls-2.24.0/library/ssl_ticket.c \
dependencies/mbedtls-2.24.0/library/ssl_tls.c \
dependencies/mbedtls-2.24.0/library/threading.c \
dependencies/mbedtls-2.24.0/library/timing.c \
dependencies/mbedtls-2.24.0/library/version.c \
dependencies/mbedtls-2.24.0/library/version_features.c \
dependencies/mbedtls-2.24.0/library/x509.c \
dependencies/mbedtls-2.24.0/library/x509_create.c \
dependencies/mbedtls-2.24.0/library/x509_crl.c \
dependencies/mbedtls-2.24.0/library/x509_crt.c \
dependencies/mbedtls-2.24.0/library/x509_csr.c \
dependencies/mbedtls-2.24.0/library/x509write_crt.c \
dependencies/mbedtls-2.24.0/library/x509write_csr.c \
dependencies/mbedtls-2.24.0/library/xtea.c \
dependencies/NVFC/nvapi.cpp \
i2c_smbus/i2c_smbus_amdadl.cpp \
i2c_smbus/i2c_smbus_i801.cpp \
@@ -828,6 +959,9 @@ unix:!macx {
LIBS += \
-lusb-1.0 \
-lstdc++fs \
-lmbedx509 \
-lmbedcrypto \
-lmbedtls \
#-------------------------------------------------------------------------------------------#
# Determine which hidapi to use based on availability #
@@ -853,6 +987,7 @@ unix:!macx {
}
SOURCES += \
dependencies/hueplusplus-1.0.0/src/LinHttpHandler.cpp \
i2c_smbus/i2c_smbus_linux.cpp \
serial_port/find_usb_serial_port_linux.cpp \
Controllers/FaustusController/RGBController_Faustus.cpp \
@@ -902,11 +1037,15 @@ macx {
USE_HID_USAGE \
SOURCES += \
dependencies/hueplusplus-1.0.0/src/LinHttpHandler.cpp \
serial_port/find_usb_serial_port_linux.cpp \
LIBS += \
-lusb-1.0 \
-lhidapi \
-lmbedx509 \
-lmbedcrypto \
-lmbedtls \
}
#-------------------------------------------------------------------------------------------#
@@ -926,9 +1065,11 @@ macx:contains(QMAKE_HOST.arch, arm64) {
macx:contains(QMAKE_HOST.arch, x86_64) {
INCLUDEPATH += \
/usr/local/include \
/usr/local/homebrew/include \
LIBS += \
-L/usr/local/lib \
-L/usr/local/homebrew/lib \
}
DISTFILES += \
+5 -3
View File
@@ -58,8 +58,9 @@ There have been two instances of hardware damage in OpenRGB's development and we
* Pre-built binaries in AppImage format are available under the Releases section on GitLab.
* You can build the project using Qt Creator or on the command line.
1. Install build dependencies
- Debian: sudo apt install git build-essential qtcreator qt5-default libusb-1.0-0-dev libhidapi-dev pkgconf
- Fedora: sudo dnf install git make automake gcc gcc-c++ qt-creator qt5-devel hidapi-devel libusb-devel
- Debian/Ubuntu: `sudo apt install git build-essential qtcreator qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libusb-1.0-0-dev libhidapi-dev pkgconf`
- Debian (before `bullseye`) or Ubuntu (before 21.04): `sudo apt install git build-essential qtcreator qt5-default libusb-1.0-0-dev libhidapi-dev pkgconf`
- Fedora: `sudo dnf install git make automake gcc gcc-c++ qt-creator qt5-devel hidapi-devel libusb-devel`
2. git clone https://gitlab.com/CalcProgrammer1/OpenRGB
3. cd OpenRGB
4. qmake OpenRGB.pro
@@ -186,7 +187,7 @@ There have been two instances of hardware damage in OpenRGB's development and we
## Projects Used
* InpOutx64: http://www.highrez.co.uk/downloads/inpout32/
* InpOutx64: https://www.highrez.co.uk/downloads/inpout32/
* libusb: https://github.com/libusb/libusb
* hidapi: https://github.com/libusb/hidapi
* libe131: https://github.com/hhromic/libe131
@@ -196,6 +197,7 @@ There have been two instances of hardware damage in OpenRGB's development and we
* Qt-Plus (ColorWheel): https://github.com/liuyanghejerry/Qt-Plus
* AMD ADL Libraries: https://github.com/GPUOpen-LibrariesAndSDKs/display-library
* libcmmk: https://github.com/chmod222/libcmmk
* hueplusplus: https://github.com/enwi/hueplusplus
## Projects Researched
+1 -1
View File
@@ -1,4 +1,4 @@
openrgb (0.6.0) UNRELEASED; urgency=medium
openrgb (0.61.1) UNRELEASED; urgency=medium
* Builds from git master. See git history for more information.
+1
View File
@@ -11,6 +11,7 @@ Build-Depends:
qt5-qmake,
libusb-1.0-0-dev,
libhidapi-dev,
libmbedtls-dev,
Homepage: https://gitlab.com/CalcProgrammer1/OpenRGB
Package: openrgb
+61
View File
@@ -0,0 +1,61 @@
---
# Based on Webkit style
BasedOnStyle: Webkit
IndentWidth: 4
ColumnLimit: 120
---
Language: Cpp
Standard: Cpp11
# Pointers aligned to the left
DerivePointerAlignment: false
PointerAlignment: Left
AccessModifierOffset: -4
AllowShortFunctionsOnASingleLine: Inline
AlwaysBreakTemplateDeclarations: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakConstructorInitializers: BeforeColon
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
Cpp11BracedListStyle: true
FixNamespaceComments: true
IncludeBlocks: Regroup
IncludeCategories:
# C++ standard headers (no .h)
- Regex: '<[[:alnum:]_-]+>'
Priority: 1
# Hueplusplus library
- Regex: '<hueplusplus/[[:alnum:]_./-]+>'
Priority: 2
# Extenal libraries (with .h)
- Regex: '<[[:alnum:]_./-]+>'
Priority: 3
# Headers from same folder
- Regex: '"[[:alnum:]_.-]+"'
Priority: 4
# Headers from other folders
- Regex: '"[[:alnum:]_/.-]+"'
Priority: 5
IndentCaseLabels: false
NamespaceIndentation: None
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterTemplateKeyword: true
SpacesInAngles: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
UseTab: Never
+58
View File
@@ -0,0 +1,58 @@
# Contribution Guide
Help is always welcome. If you want to contribute to hueplusplus, please read these guidelines
## Request feature / Report bug
To request a feature or report a bug, create an issue using the templates.
## Making changes
If you want to add a new feature or fix a bug, first check out the development branch and open and closed issues.
Maybe the feature already exists and you would just do duplicate work.
Also use the development branch as the base for your feature branch, because all pull requests are first rebased into development.
## Pull requests
When creating a pull request, be sure to choose development as the target.
You might need to rebase on development again and merge in new changes.
### Keeping up with changes
While you are working on your pull request or your forked branch it might occur that
someone has force pushed the development branch, from which you started your feature branch.
In that case you will need to rebase onto the force pushed branch. For that you need to follow these steps:
1. Switch to the development branch
```
git checkout development
```
2. Add this repository as your remote upstream
```
git remote add upstream [email protected]:enwi/hueplusplus.git
```
3. Fetch all changes
```
git fetch upstream
```
4. Reset your development branch and replace it with our (force pushed) version
```
git reset --hard upstream/development
```
> If you have for some reason made changes to your development branch do a rebase pull to preserve them
> ```
> git pull --rebase upstream/development
> ```
5. Switch back to your feature branch
```
git checkout name-of-your-feature-branch
```
6. Rebase your changes on to the new development branch
```
git rebase development
```
7. Force push your changes (because you are diverged now)
```
git push --force
```
## Code style
The code is formatted using clang-format. If you do not want to use it yourself, try to keep your style consistent with the other code
so not too many reformats are necessary.
@@ -0,0 +1,31 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: 'Status: Available, Type: Bug'
assignees: ''
---
**Describe the bug**:
A clear and concise description of what the bug is.
**To Reproduce**:
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**:
A clear and concise description of what you expected to happen.
**Console log/Error message**:
If applicable, add a console log or error message to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. MacOS, Windows, Linux, ESP32 SDK, Arduino]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'Status: Available, Type: Enhancement'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+65
View File
@@ -0,0 +1,65 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# build directory
/build*
/out
/bin
# Generated documentation
/doc/html
# General
.DS_Store
.AppleDouble
.LSOverride
.vs
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
@@ -0,0 +1,3 @@
[submodule "lib/mbedtls"]
path = lib/mbedtls
url = https://github.com/ARMmbed/mbedtls.git
+76
View File
@@ -0,0 +1,76 @@
language: generic
env:
global:
# Ubuntu version
- LINUX_DIST=bionic
- DEPS_DIR=${TRAVIS_BUILD_DIR}/deps
# compiler settings
- COMPILER_NAME=gcc
- CXX=g++
- CC=gcc
# Misc
- RUN_TESTS=true
- COVERAGE=false
- PATH=${DEPS_DIR}/cmake/bin:${PATH}
matrix:
include:
- os: linux
dist: bionic
sudo: true
compiler: gcc
addons:
apt:
packages:
# Misc
- python-yaml
- doxygen
- graphviz
before_install:
# Combine global build options with OS/compiler-dependent options
- export CMAKE_OPTIONS=${CMAKE_OPTIONS}" "${ENV_CMAKE_OPTIONS}
- export CXX_FLAGS=${CXX_FLAGS}" "${ENV_CXX_FLAGS}
# c++14
- sudo apt-get update -qq
install:
# CodeCov
- sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-7 90
# we have to build lcov on our own, because it is not possible to install lcov-1.13 with apt
- wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.13.orig.tar.gz && tar xf lcov_1.13.orig.tar.gz && make -C lcov-1.13 "PREFIX=${HOME}/.local" install && export PATH="${PATH}:${HOME}/.local/bin";
# show info
- echo ${PATH}
- echo ${CXX}
- ${CXX} --version
- ${CXX} -v
- cmake --version
- lcov --version
script:
############################################################################
# Build main, tests and examples
############################################################################
- mkdir -p build
- cd build
- cmake .. -Dhueplusplus_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -Dhueplusplus_EXAMPLES=ON
- make hueplusplus_examples hueplusplus_snippets
- make coveragetest
- cd ..
- doxygen Doxyfile
# .nojekyll file prevents hiding of files starting with _
- touch doc/html/.nojekyll
after_success:
# upload result to codecov
- bash <(curl -s https://codecov.io/bash)
deploy:
provider: pages
skip_cleanup: true
local_dir: doc/html
github_token: $GH_REPO_TOKEN
on:
branch: master
+105
View File
@@ -0,0 +1,105 @@
cmake_minimum_required(VERSION 3.8)
if(${CMAKE_VERSION} VERSION_LESS 3.11)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.11)
endif()
# Add cmake dir to module path, so Find*.cmake can be found
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
project(hueplusplus VERSION 1.0.0 LANGUAGES CXX)
# check whether hueplusplus is compiled directly or included as a subdirectory
if(NOT DEFINED hueplusplus_master_project)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(hueplusplus_master_project ON)
else()
set(hueplusplus_master_project OFF)
endif()
endif()
# options to set
option(hueplusplus_TESTS "Build tests" OFF)
option(hueplusplus_EXAMPLES "Build examples" OFF)
option(CLANG_TIDY_FIX "Perform fixes for Clang-Tidy" OFF)
find_program(CLANG_TIDY_EXE NAMES "clang-tidy" DOC "Path to clang-tidy executable")
if(CLANG_TIDY_EXE)
if(CLANG_TIDY_FIX)
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" "-fix")
else()
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}")
endif()
endif()
# update submodules
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
option(GIT_SUBMODULE "Check submodules during build" ON)
if(GIT_SUBMODULE)
message(STATUS "Submodule update")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
endif()
endif()
endif()
# Set default build type if none was specified
set(default_build_type "Release")
if(hueplusplus_master_project AND (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES))
message(STATUS "Setting build type to '${default_build_type}' as none was specified")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
# Set possible values for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
# get the correct installation directory for add_library() to work
if(WIN32 AND NOT CYGWIN)
set(DEF_INSTALL_CMAKE_DIR cmake)
else()
set(DEF_INSTALL_CMAKE_DIR lib/cmake/hueplusplus)
endif()
set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
# target for uninstall
if(NOT TARGET uninstall)
configure_file(
"${PROJECT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
"${PROJECT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
# if we are on a apple machine this is needed
if (1 AND APPLE)
set(CMAKE_MACOSX_RPATH 1)
endif()
set(USE_STATIC_MBEDTLS_LIBRARY ON)
set(USE_SHARED_MBEDTLS_LIBRARY OFF)
add_subdirectory("lib/mbedtls" EXCLUDE_FROM_ALL)
# Compile the mbedtls library as a static with position independent code,
# because we need it for both a shared and static library
set_property(TARGET mbedtls PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET mbedcrypto PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET mbedx509 PROPERTY POSITION_INDEPENDENT_CODE ON)
add_subdirectory(src)
# if the user decided to use tests add the subdirectory
if(hueplusplus_TESTS)
add_subdirectory("test")
endif()
if(hueplusplus_EXAMPLES)
add_subdirectory("examples")
endif()
File diff suppressed because it is too large Load Diff
+55
View File
@@ -0,0 +1,55 @@
timestamps {
node('master')
{
stage('SCM')
{
checkout scm
}
stage('Build')
{
sh returnStatus: true, script: 'rm -r build'
sh '''#!/bin/bash
mkdir build
cd build
cmake .. -Dhueplusplus_TESTS=ON
make -j8 2>&1 | tee buildlog.txt
test ${PIPESTATUS[0]} -eq 0'''
}
stage('Test')
{
sh '''cd build
hueplusplus/test/test_HuePlusPlus --gtest_output=xml:test.xml
make -j8 coveragetest'''
step([$class: 'XUnitBuilder', testTimeMargin: '3000', thresholdMode: 1,
thresholds: [
[$class: 'FailedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: ''],
[$class: 'SkippedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '']
],
tools: [
[$class: 'GoogleTestType', deleteOutputFiles: true, failIfNotNew: true, pattern: 'build/test.xml', skipNoTestFiles: false, stopProcessingIfError: true]
]
])
publishHTML(
[allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: 'build/coveragetest', reportFiles: 'index.html', reportName: 'Coveragetest', reportTitles: '']
)
}
stage('CppCheck')
{
sh 'cppcheck -j 8 --force -ihueplusplus/test -ihueplusplus/jsoncpp.cpp hueplusplus/ 2>build/CppCheckResult'
rtp nullAction: '1', parserName: 'HTML', stableText: '${FILE:build/CppCheckResult}'
}
stage('Documentation')
{
sh 'doxygen Doxyfile'
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: 'doc/html/', reportFiles: 'index.html', reportName: 'Doxygen'])
}
stage('Parse warnings')
{
warnings canComputeNew: false, canResolveRelativePaths: false, categoriesPattern: '', defaultEncoding: '', excludePattern: '', healthy: '', includePattern: '', messagesPattern: '', parserConfigurations: [[parserName: 'Doxygen', pattern: 'doxylog.txt']], unHealthy: ''
sh returnStatus: true, script: 'rm doxylog.txt'
warnings canComputeNew: false, canResolveRelativePaths: false, categoriesPattern: '', defaultEncoding: '', excludePattern: '', healthy: '', includePattern: '', messagesPattern: '', parserConfigurations: [[parserName: 'GNU C Compiler 4 (gcc)', pattern: 'build/buildlog.txt']], unHealthy: ''
sh returnStatus: true, script: 'rm build/buildlog.txt'
}
}
}
+165
View File
@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+165
View File
@@ -0,0 +1,165 @@
# hueplusplus
A simple and easy to use library for Philips Hue Lights
| Branch | Travis CI | Codecov | LGTM
|:-|:-|:-|:-|
| [Master](https://github.com/enwi/hueplusplus/tree/master) | [![Build Status](https://travis-ci.com/enwi/hueplusplus.svg?branch=master)](https://travis-ci.com/enwi/hueplusplus) | [![codecov](https://codecov.io/gh/enwi/hueplusplus/branch/master/graph/badge.svg)](https://codecov.io/gh/enwi/hueplusplus) | [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/enwi/hueplusplus.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/enwi/hueplusplus/context:cpp) |
| [Development](https://github.com/enwi/hueplusplus/tree/development) | [![Build Status](https://travis-ci.com/enwi/hueplusplus.svg?branch=development)](https://travis-ci.com/enwi/hueplusplus) | [![codecov](https://codecov.io/gh/enwi/hueplusplus/branch/development/graph/badge.svg)](https://codecov.io/gh/enwi/hueplusplus) | |
## Features
* find bridges with SSDP or set an ip manually
* all common light functions (brightness, color, temperature)
* extended alert() functions, which alert in a specific color (good for notifications)
* supports sensors, rules, groups, scenes and schedules
* streaming with entertainment mode
* [documented with doxygen](https://enwi.github.io/hueplusplus/)
* tested with google test, google mock and gcov/lcov
## Compatibility
* Linux
* Windows
* MacOS
* Espressif ESP32 SDK & Arduino
## How to use
### <a name="searchingBridges"></a>Searching for Bridges
To start searching for a Hue Bridge you will need to choose an IHttpHandler and create one. The options are a "WinHttpHandler" (for windows) or a "LinHttpHandler" (for linux).
Then create a BridgeFinder object with the handler.
The handler is needed, because it tells the finder which functions to use to communicate with a bridge or your local network.
After that you can call findBridges(), which will return a vector containing the ip and mac address of all found Bridges.
```C++
// For windows use std::make_shared<hueplusplus::WinHttpHandler>();
handler = std::make_shared<hueplusplus::LinHttpHandler>();
hueplusplus::BridgeFinder finder(handler);
std::vector<hueplusplus::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
if (bridges.empty())
{
std::cerr << "No bridges found\n";
return;
}
```
### Authenticate Bridges
If you have found the Bridge you were looking for, you can then move on with the authentication process.
To get a new username from the Bridge (for now) you simply call getBridge(bridges[\<index\>]),
where index is your preferred Bridge from the part [Searching for Bridges](#searchingBridges).
```C++
hueplusplus::Bridge bridge = finder.getBridge(bridges[0]);
```
If you on the other hand already have a username you can add your bridge like so
```C++
finder.addUsername(bridges[0].mac, "<username>");
hueplusplus::Bridge bridge = finder.getBridge(bridges[0]);
```
If you do not want to use the BridgeFinder or you already know the ip and username of your bridge you have the option to create your own Bridge object.
Here you will need to provide the ip address, the port number, a username and an HttpHandler
```C++
// For windows use std::make_shared<hueplusplus::WinHttpHandler>();
handler = std::make_shared<hueplusplus::LinHttpHandler>();
hueplusplus::Bridge bridge("192.168.2.102", 80, "<username>", handler);
```
### Controlling lights
If you have your Bridge all set up, you can now control its lights.
For that create a new Light object and call lights().get(\<id\>) on your bridge object to get a reference to a specific light, where id
is the id of the light set internally by the Hue Bridge.
```C++
hueplusplus::Light light1 = bridge.lights().get(1);
```
If you don't know the id of a specific light or want to get an overview over all lights that are controlled by your bridge,
you can get a vector containing them by calling getAll(). If no lights are found the vector will be empty.
```C++
std::vector<hueplusplus::Light> lights = bridge.lights().getAll();
```
If you now want to control a light, call a specific function of it.
```C++
light1.on();
light1.setBrightness(120);
light1.alertHueSaturation(25500, 255);
light1.setColorLoop(true);
light1.setColorRGB(255, 128, 0);
lights[1].off();
lights.at(1).setColorHue(4562);
```
But keep in mind that some light types do not have all functions available. So you might call a
specific function, but nothing will happen. For that you might want to check what type
of a light you are controlling. For that you can call the function getColorType(), which will return
a ColorType.
```C++
hueplusplus::ColorType type1 = light1.getColorType();
```
There's also a new way to check whether specific functions of a light are available:
```C++
light1.hasBrightnessControl();
light1.hasTemperatureControl();
light1.hasColorControl();
```
These will either return true(light has specified function) or false(light lacks specified function).
### Further reading
If you want to know more about all functions just look inside the doxygen documentation. It can be found [here](https://enwi.github.io/hueplusplus/)
## Build and install
### Basic installation
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.
```bash
mkdir build
cd build
cmake ..
```
Then compile the code with make. If you are inpatient use the option -j\<number\>, where number specifies how many files are compiled at the same time. Note this number should not exceed the number of cores*2 of your machine.
```bash
make
```
```bash
make -j4
```
If you want to install the library use
```bash
make install
```
To remove it
```bash
make uninstall
```
### Advanced usage
If you have a project that already uses CMake you probably want to add the hueplusplus library directly in your cmake file.
For that the best way is to use find_package().
When cmake finds the hueplusplus library you can then link against either the shared or static version of the library.
```cmake
find_package(hueplusplus REQUIRED)
target_link_libraries(<executable> PUBLIC hueplusplusstatic)
```
But this will only work if the hueplusplus library is already installed.
To get around this problem there is a pretty awesome way.
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:
```cmake
find_package(hueplusplus QUIET)
if(NOT hueplusplus_FOUND)
message(STATUS "-- hueplusplus not found, building it")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/<path to directory>/hueplusplus" "${CMAKE_CURRENT_BINARY_DIR}/hueplusplus")
endif()
target_link_libraries(<executable> PUBLIC hueplusplusstatic)
```
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.
### Running tests
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. Since I added a custom target you will only need to call "make unittest" and the tests are compiled and executed.
```bash
mkdir build
cd build
cmake .. -Dhueplusplus_TESTS=ON
make unittest
```
If you also want to execute coverage tests you will need to install gcov and lcov yourself. To run the coverage test use
```bash
make coveragetest
```
## Copyright
Copyright (c) 2017 Jan Rogall & Moritz Wirger. See LICENSE for further details.
@@ -0,0 +1,21 @@
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif(NOT "${rm_retval}" STREQUAL 0)
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)
@@ -0,0 +1,7 @@
# -config file of the hueplusplus package
# It defines the following
# hueplusplus_FOUND - which indicates that the module was found
# hueplusplus_INCLUDE_DIR
set(hueplusplus_FOUND TRUE)
set(hueplusplus_INCLUDE_DIR "@INSTALL_INCLUDE_DIR@")
+8
View File
@@ -0,0 +1,8 @@
ignore:
- "/usr/**/*" # ingnore all unix system ressources
- "**/json*.*" # ignore all json files
- "**/hueplusplus/include/json/*" # ignore all files in json folder
- "**/hueplusplus/test/*" # ignore all files in test folder
- "**/hueplusplus/build/**/*" # ignore all files in build folder
- "**/test/**/*" # ignore all files in test folders
- "**/v1/**/*" # ignore all macros files
+86
View File
@@ -0,0 +1,86 @@
# Build and install {#build}
[TOC]
# Basic installation {#basic-install}
## Clone from github {#clone}
To get the newest version of the hueplusplus library, clone it directly from [github](https://github.com/enwi/hueplusplus).
The master branch contains the latest tested and stable version, while the development branch is more unstable.
```{.sh}
~ $ git clone https://github.com/enwi/hueplusplus.git
```
This creates a folder hueplusplus with the library sources.
When you want to update the library for a new version, use pull with rebase.
```{.sh}
~/hueplusplus $ git pull --rebase
```
## Build with CMake {#build-cmake}
To build the library, you need to use [CMake](https://cmake.org) version 3.8 or higher.
It is easiest to create a separate build directory where the build files are stored.
```{.sh}
~/hueplusplus $ mkdir build
~/hueplusplus $ cd build
~/hueplusplus/build $ cmake ..
~/hueplusplus/build $ make
```
To install or uninstall the library use the make targets.
```{.sh}
~/hueplusplus/build $ make install
~/hueplusplus/build $ make uninstall
```
## Use in a CMake project {#import-cmake}
If you have a project that already uses CMake you probably want to add the hueplusplus library directly in your cmake file.
For that the best way is to use find_package().
```{.cmake}
find_package(hueplusplus REQUIRED)
```
But this will only work if the hueplusplus library is already installed.
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:
```{.cmake}
find_package(hueplusplus QUIET)
if(NOT hueplusplus_FOUND)
message(STATUS "-- hueplusplus not found, building it")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/<path to directory>/hueplusplus" "${CMAKE_CURRENT_BINARY_DIR}/hueplusplus")
endif()
```
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.
The cmake project defines two library targets: `hueplusplusstatic` to link as a static library and `hueplusplusshared` to link as a shared library.
```{.cmake}
target_link_libraries(<executable> PUBLIC hueplusplusstatic)
```
## Use in another project {#import-other}
When you are not using CMake, you have to install hueplusplus and change your build configuration to link to the compiled library.
The header files in the include directory need to be added to the include path.
How you do this depends on the build system.
## Building tests {#build-tests}
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.
The custom target `unittest` compiles and executes all tests.
```bash
mkdir build
cd build
cmake .. -Dhueplusplus_TESTS=ON
make unittest
```
If you also want to execute coverage tests you will need to install gcov and lcov yourself. To run the coverage test use
```bash
make coveragetest
```
## Building examples {#build-examples}
There are some small [example programs](@ref examples) using this library in the examples folder. To build them,
set `hueplusplus_EXAMPLES=ON`. The target `hueplusplus_examples` builds all examples into build/examples.
```{.sh}
mkdir build
cd build
cmake .. -Dhueplusplus_EXAMPLES=ON
make hueplusplus_examples
```
@@ -0,0 +1,39 @@
# Getting started {#getting-started}
## Creating the Hue bridge
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).
Then create a [BridgeFinder](@ref hueplusplus::BridgeFinder) object with the handler.
The handler is needed, because it tells the finder which functions to use to communicate with a bridge or your local network.
After that you can call [findBridges()](@ref hueplusplus::BridgeFinder::findBridges), which will return a vector containing the ip and mac address of all found Bridges.
\snippet Snippets.cpp search-bridge
## Authenticate Bridges
If you have found the Bridge you were looking for, you can then move on with the authentication process.
To get a new username from the Bridge (for now) you simply call [getBridge(bridges[\<index\>])](@ref hueplusplus::BridgeFinder::getBridge),
where index is your preferred Bridge from the part [Searching for Bridges](#searchingBridges). This requires the user to press the link button.
\snippet Snippets.cpp get-bridge-1
If you on the other hand already have a username you can add your bridge like so
\snippet Snippets.cpp get-bridge-2
If you do not want to use the BridgeFinder or you already know the ip and username of your bridge you have the option to create your own Hue object.
Here you will need to provide the ip address, the port number, a username and an HttpHandler
\snippet Snippets.cpp get-bridge-3
At this point you may want to decide whether to use a [shared state](@ref shared-state) cache model or keep the default settings.
### Controlling lights
\snippet Snippets.cpp control-lights
Use [transactions](@ref transactions) to change multiple properties at once.
### Controlling groups
\snippet Snippets.cpp control-groups
## More information
- [Transactions](@ref transactions)
- [Shared state cache](@ref shared-state)
+139
View File
@@ -0,0 +1,139 @@
# Documentation for the hueplusplus library
A simple and easy to use library for Philips Hue Lights.
[TOC]
## Features
* find bridges with SSDP or set an ip manually
* all common light functions (brightness, color, temperature)
* extended alert() functions, which alert in a specific color (good for notifications)
* supports sensors, rules, groups, scenes and schedules
* streaming with entertainment mode
* documented with doxygen
* tested with google test, google mock and gcov/lcov
## Compatibility
* Linux
* Windows
* MacOS
* Espressif ESP32 SDK & Arduino
## How to use
[Getting started](@ref getting-started)
### Searching for Bridges
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).
Then create a [BridgeFinder](@ref hueplusplus::BridgeFinder) object with the handler.
The handler is needed, because it tells the finder which functions to use to communicate with a bridge or your local network.
After that you can call [findBridges()](@ref hueplusplus::BridgeFinder::findBridges), which will return a vector containing the ip and mac address of all found Bridges.
\snippet Snippets.cpp search-bridge
At this point you may want to decide whether to use a [shared state](@ref shared-state) cache model or keep the default settings.
### Authenticate Bridges
If you have found the Bridge you were looking for, you can then move on with the authentication process.
To get a new username from the Bridge (for now) you simply call [getBridge(bridges[\<index\>])](@ref hueplusplus::BridgeFinder::getBridge),
where index is your preferred Bridge from the part [Searching for Bridges](#searchingBridges). This requires the user to press the link button.
\snippet Snippets.cpp get-bridge-1
If you on the other hand already have a username you can add your bridge like so
\snippet Snippets.cpp get-bridge-2
If you do not want to use the BridgeFinder or you already know the ip and username of your bridge you have the option to create your own Bridge object.
Here you will need to provide the ip address, the port number, a username and an HttpHandler
\snippet Snippets.cpp get-bridge-3
### Controlling lights
If you have your Bridge all set up, you can now control its lights.
For that create a new Light object and call [lights().get(\<id\>)](@ref hueplusplus::ResourceList::get) on your bridge object to get a reference to a specific light, where id
is the id of the light set internally by the Hue Bridge.
\snippet Snippets.cpp light-1
If you don't know the id of a specific light or want to get an overview over all lights that are controlled by your bridge,
you can get a vector containing them by calling [getAll()](@ref hueplusplus::ResourceList::getAll) on your bridge object. If no lights are found the vector will be empty.
\snippet Snippets.cpp light-2
If you now want to control a light, call a specific function of it.
\snippet Snippets.cpp light-3
But keep in mind that some light types do not have all functions available. So you might call a
specific function, but nothing will happen. For that you might want to check what type
of a light you are controlling. For that you can call the function [getColorType()](@ref hueplusplus::Light::getColorType()), which will return
a ColorType.
\snippet Snippets.cpp light-4
There's also a new way to check whether specific functions of a light are available:
\snippet Snippets.cpp light-5
These will either return true(light has specified function) or false(light lacks specified function).
## Build and install
[Build and install guide](@ref build)
### Basic installation
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.
```bash
mkdir build
cd build
cmake ..
```
Then compile the code with make. If you are inpatient use the option -j\<number\>, where number specifies how many files are compiled at the same time. Note this number should not exceed the number of cores*2 of your machine.
```bash
make
```
```bash
make -j4
```
If you want to install the library use
```bash
make install
```
To remove it
```bash
make uninstall
```
### Advanced usage
If you have a project that already uses CMake you probably want to add the hueplusplus library directly in your cmake file.
For that the best way is to use find_package().
When cmake finds the hueplusplus library you can then link against either the shared or static version of the library.
```cmake
find_package(hueplusplus REQUIRED)
target_link_libraries(<executable> PUBLIC hueplusplusstatic)
```
But this will only work if the hueplusplus library is already installed.
To get around this problem there is a pretty awesome way.
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:
```cmake
find_package(hueplusplus QUIET)
if(NOT hueplusplus_FOUND)
message(STATUS "-- hueplusplus not found, building it")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/<path to directory>/hueplusplus" "${CMAKE_CURRENT_BINARY_DIR}/hueplusplus")
endif()
target_link_libraries(<executable> PUBLIC hueplusplusstatic)
```
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.
### Running tests
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. Since I added a custom target you will only need to call "make unittest" and the tests are compiled and executed.
```bash
mkdir build
cd build
cmake .. -Dhueplusplus_TESTS=ON
make unittest
```
If you also want to execute coverage tests you will need to install gcov and lcov yourself. To run the coverage test use
```bash
make coveragetest
```
## Other pages
- [Getting started](@ref getting-started)
- [Build and install](@ref build)
- [Shared state cache](@ref shared-state)
- [Transactions](@ref transactions)
- [Sensors](@ref sensors)
+47
View File
@@ -0,0 +1,47 @@
# Sensors {#sensors}
[TOC]
## Sensor support
The library supports the sensor types listed on the Hue developer documentation.
Include `hueplusplus/ZLLSensors.h` for ZigBee sensors and `hueplusplus/CLIPSensors.h` for CLIP sensors.
Other sensors can be used with the generic [Sensor](@ref hueplusplus::Sensor) class.
### Working with a known sensor
In most cases, the type of the sensors is known in advance, such as a switch.
The classes in the [sensors](@ref hueplusplus::sensors) namespace provide the documented
functionality. The type can be specified when accessing the sensor. When it does not match,
an exception is thrown.
\snippet Snippets.cpp known-sensor-1
You can also get all sensors of a specified type by using [getAllByType<T>()](@ref hueplusplus::SensorList::getAllByType).
\snippet Snippets.cpp known-sensor-2
### Working with an unknown sensor
When the sensor type is not known, use the generic sensor class. In this case, some attributes might not
exist, so they have to be checked first. This applies to all attributes that have a `hasXXX` method.
\snippet Snippets.cpp generic-sensor-1
It is easiest to compare the sensor type to the existing ones (`typeStr` on the specific sensor classes)
and then convert the sensor to that type.
\snippet Snippets.cpp generic-sensor-2
## ZLL sensors vs. CLIP sensors
ZLL sensors (defined in `ZLLSensors.h`) are physical device sensors which send their data
to the bridge using ZigBee. They are added in the same way as lights are, using [search()](@ref hueplusplus::SearchableResourceList::search).
CLIP sensors (in `CLIPSensors.h`) are added using [create()](@ref hueplusplus::CreateableResourceList::create) with [CreateSensor](@ref hueplusplus::CreateSensor)
for parameters. In general, which config and state attributes exist is specified when the sensor is created.
The values of CLIP sensors can be changed using requests, unlike ZLL sensors. They can also have a URL to query from.
## Creating conditions
The most important use for sensors is in [Rules](@ref hueplusplus::Rule), to trigger changes.
Conditions can be created from the specific sensor types using `makeCondition()`.
These functions return a helper class with methods for the [possible operators](@ref hueplusplus::Condition::Operator) valid for the state.
For some sensors, which have multiple possible states, there exist multiple variations of makeCondition.
\snippet Snippets.cpp sensor-conditions
For generic sensors, the conditions must be created manually using the [Condition](@ref hueplusplus::Condition::Condition)
constructor with a proper address to the sensor state.
@@ -0,0 +1,46 @@
# Shared state cache {#shared-state}
[TOC]
## What shared state means
There are two ways in which the API state (internally JSON) can be handled:
1. Every resource instance holds its own cache of the state (default).
2. All instances share the cache of the entire bridge.
### Advantages of shared state
* Different resources are always consistent on the library level.
If one part of the code uses the light with id 1 and turns it off,
light 1 is also off when using a different variable to access it.
* The number of requests can be reduced, because they can be bundled together on a higher cache level.
### Disadvantages of shared state
* Different objects are no longer thread safe, you cannot use **any** parts of the library
from multiple threads (without locking).
* Changes are not transparent. For example, a `const Light` can suddenly change its name, because the
name was changed somewhere else in the code.
Because of these considerations, shared state is disabled by default.
## Enabling shared state
Shared state can be configured when the bridge is first constructed, either in [getBridge()](@ref hueplusplus::BridgeFinder::getBridge)
or in the [constructor](@ref hueplusplus::Bridge::Bridge). Set `sharedState` to `true` to keep all resources
connected to the bridge cache.
\snippet Snippets.cpp shared-bridge-1
\snippet Snippets.cpp shared-bridge-2
## Shared state and refreshing
When shared cache is used, refreshes use a hierarchichal structure to determine how much should be requested from the bridge.
Every level has its own last update time and refresh duration.
First, it is checked whether the higher level is up to date and refresh everything if not.
Otherwise, only the lowest necessary level is requested from the bridge to be more efficient.
### Example:
\snippet Snippets.cpp refresh-example
[isOn()](@ref hueplusplus::Light::isOn) is a non-const method (in this case). That means it will refresh the
state if it is outdated. The default refresh time is inherited from `bridge.lights()`, so it is 30 seconds.
After 30 seconds, the state of `light` *and* `bridge.lights()` is outdated. Therefore, the entire list of lights is
updated at this point.
After more than one minute, the bridge state is considered outdated. This means that `isOn()` causes an update of
the entire bridge.
@@ -0,0 +1,38 @@
# Transactions {#transactions}
[TOC]
## Using a transaction for lights
Often, you want to change more than one property on a light at the same time,
for example brightness and color. This is done using transactions ([StateTransaction](@ref hueplusplus::StateTransaction)).
\snippet Snippets.cpp transaction-lights
The request is reduced to only the variables that need to be changed based on the current state.
For example, if the light is already on, that part of the transaction is ignored.
__Important:__ The transaction has an internal reference to the light state.
You must not cause a refresh of the state between creating and committing the transaction (e.g. non-const getters/setters),
because that invalidates the reference.
### Advanced usage
Another way to use the transaction is by storing it and building up the calls separately.
\snippet Snippets.cpp transaction-advanced
In this case, it is especially important that the light and the state of the light __MUST NOT__ invalidate. That means
* the light variable has to live longer than the transaction
* especially no non-const method calls on the light while the transaction is open, or committing other transactions
In general, this method is easier to screw up and should only be used when really necessary.
## Using a transaction for groups
The same principles of transactions for lights also apply for groups. The main difference is that
for groups, there are no checks of the current state. Even if all lights in the group are already on,
the request to turn on all lights on the group is still sent.
\snippet Snippets.cpp transaction-groups
## Creating Actions
In a [Schedule](@ref hueplusplus::Schedule) or [Rule](@ref hueplusplus::Rule),
the bridge can set the state of lights and groups. To configure this, a transaction
can be saved for later instead of committing it directly.
\snippet Snippets.cpp transaction-action
+101
View File
@@ -0,0 +1,101 @@
/**
\file BridgeSetup.cpp
Copyright Notice\n
Copyright (C) 2021 Jan Rogall - 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 <http://www.gnu.org/licenses/>.
\example{lineno} BridgeSetup.cpp
This example connects to a bridge with hardcoded mac and username.
**/
#include <algorithm>
#include <iostream>
#include <hueplusplus/Bridge.h>
#ifdef _MSC_VER
#include <hueplusplus/WinHttpHandler.h>
using SystemHttpHandler = hueplusplus::WinHttpHandler;
#else
#include <hueplusplus/LinHttpHandler.h>
using SystemHttpHandler = hueplusplus::LinHttpHandler;
#endif
namespace hue = hueplusplus;
// Configure existing connections here, or leave empty for new connection
const std::string macAddress = "";
const std::string username = "";
// Connects to a bridge and returns it.
hue::Bridge connectToBridge()
{
hue::BridgeFinder finder(std::make_shared<SystemHttpHandler>());
std::vector<hue::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
for (const auto& bridge : bridges)
{
std::cout << "Bridge: " << bridge.mac << " at " << bridge.ip << '\n';
}
if (bridges.empty())
{
std::cout << "Found no bridges\n";
throw std::runtime_error("no bridges found");
}
if (macAddress.empty())
{
std::cout << "No bridge given, connecting to first one.\n";
return finder.getBridge(bridges.front());
}
if (!username.empty())
{
finder.addUsername(macAddress, username);
}
auto it = std::find_if(
bridges.begin(), bridges.end(), [&](const auto& identification) { return identification.mac == macAddress; });
if (it == bridges.end())
{
std::cout << "Given bridge not found\n";
throw std::runtime_error("bridge not found");
}
return finder.getBridge(*it);
}
int main(int argc, char** argv)
{
try
{
hue::Bridge hue = connectToBridge();
std::cout << "Connected to bridge. IP: " << hue.getBridgeIP() << ", username: " << hue.getUsername() << '\n';
}
catch (...)
{ }
std::cout << "Press enter to exit\n";
std::cin.get();
return 0;
}
+24
View File
@@ -0,0 +1,24 @@
add_executable(bridge_setup BridgeSetup.cpp)
set_property(TARGET bridge_setup PROPERTY CXX_STANDARD 14)
set_property(TARGET bridge_setup PROPERTY CXX_EXTENSIONS OFF)
target_link_libraries(bridge_setup hueplusplusstatic)
add_executable(lights_off LightsOff.cpp)
set_property(TARGET lights_off PROPERTY CXX_STANDARD 14)
set_property(TARGET lights_off PROPERTY CXX_EXTENSIONS OFF)
target_link_libraries(lights_off hueplusplusstatic)
add_executable(username_config UsernameConfig.cpp)
set_property(TARGET lights_off PROPERTY CXX_STANDARD 14)
set_property(TARGET lights_off PROPERTY CXX_EXTENSIONS OFF)
target_link_libraries(username_config hueplusplusstatic)
add_custom_target(hueplusplus_examples)
add_dependencies(hueplusplus_examples bridge_setup lights_off username_config)
# Snippets for documentation, not included with the examples target
add_executable(hueplusplus_snippets Snippets.cpp)
set_property(TARGET hueplusplus_snippets PROPERTY CXX_STANDARD 14)
set_property(TARGET hueplusplus_snippets PROPERTY CXX_EXTENSIONS OFF)
target_link_libraries(hueplusplus_snippets hueplusplusstatic)
+136
View File
@@ -0,0 +1,136 @@
/**
\file LightsOff.cpp
Copyright Notice\n
Copyright (C) 2021 Jan Rogall - 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 <http://www.gnu.org/licenses/>.
\example{lineno} LightsOff.cpp
This example turns off all lights for 20 seconds, then turns them on again.
**/
#include <thread>
#include <hueplusplus/Bridge.h>
#ifdef _MSC_VER
#include <hueplusplus/WinHttpHandler.h>
using SystemHttpHandler = hueplusplus::WinHttpHandler;
#else
#include <hueplusplus/LinHttpHandler.h>
using SystemHttpHandler = hueplusplus::LinHttpHandler;
#endif
namespace hue = hueplusplus;
// Configure existing connections here, or leave empty for new connection
const std::string macAddress = "";
const std::string username = "";
// Connects to a bridge and returns it.
hue::Bridge connectToBridge()
{
hue::BridgeFinder finder(std::make_shared<SystemHttpHandler>());
std::vector<hue::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
for (const auto& bridge : bridges)
{
std::cout << "Bridge: " << bridge.mac << " at " << bridge.ip << '\n';
}
if (bridges.empty())
{
std::cout << "Found no bridges\n";
throw std::runtime_error("no bridges found");
}
if (macAddress.empty())
{
std::cout << "No bridge given, connecting to first one.\n";
return finder.getBridge(bridges.front());
}
if (!username.empty())
{
finder.addUsername(macAddress, username);
}
auto it = std::find_if(
bridges.begin(), bridges.end(), [&](const auto& identification) { return identification.mac == macAddress; });
if (it == bridges.end())
{
std::cout << "Given bridge not found\n";
throw std::runtime_error("bridge not found");
}
return finder.getBridge(*it);
}
// Turns off the lights on the bridge for 20 seconds.
// Only turns the lights back on that were on before.
void lightsOff(hue::Bridge& hue)
{
std::vector<hue::Light> lights = hue.lights().getAll();
// Save current on state of the lights
std::map<int, bool> onMap;
for (hue::Light& l : lights)
{
onMap.emplace(l.getId(), l.isOn());
l.off();
}
// This would be preferrable, but does not work because it also resets the brightness of all lights
// Group 0 contains all lights, turn all off with a transition of 1 second
// hue.groups().get(0).setOn(false, 10);
// -------------------------------------
std::cout << "Turned off all lights\n";
std::this_thread::sleep_for(std::chrono::seconds(20));
// Restore the original state of the lights
for (hue::Light& l : lights)
{
if (onMap[l.getId()])
{
l.on();
}
}
std::cout << "Turned lights back on\n";
}
int main(int argc, char** argv)
{
try
{
hue::Bridge hue = connectToBridge();
std::cout << "Connected to bridge. IP: " << hue.getBridgeIP() << ", username: " << hue.getUsername() << '\n';
lightsOff(hue);
}
catch (...)
{ }
std::cout << "Press enter to exit\n";
std::cin.get();
return 0;
}
+199
View File
@@ -0,0 +1,199 @@
/**
\file Snippets.cpp
Copyright Notice\n
Copyright (C) 2021 Jan Rogall - 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 <http://www.gnu.org/licenses/>.
\brief Contains code snippets used in the documentation, performs no useful functions.
**/
#include <hueplusplus/Bridge.h>
#include <hueplusplus/CLIPSensors.h>
#include <hueplusplus/ZLLSensors.h>
#ifdef _MSC_VER
#include <hueplusplus/WinHttpHandler.h>
namespace hueplusplus
{
// Dirty hack to make the snippets compile under windows. Dont do this,
// instead use your own alias which is set to either type like in BridgeSetup.cpp!
using LinHttpHandler = WinHttpHandler;
} // namespace hueplusplus
#else
#include <hueplusplus/LinHttpHandler.h>
#endif
void snippet1()
{
// Main page
//! [search-bridge]
// For windows use std::make_shared<hueplusplus::WinHttpHandler>();
auto handler = std::make_shared<hueplusplus::LinHttpHandler>();
hueplusplus::BridgeFinder finder(handler);
std::vector<hueplusplus::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
if (bridges.empty())
{
std::cerr << "No bridges found\n";
return;
}
//! [search-bridge]
//! [get-bridge-2]
finder.addUsername(bridges[0].mac, "<username>");
//! [get-bridge-1]
hueplusplus::Bridge bridge = finder.getBridge(bridges[0]);
//! [get-bridge-1]
//! [get-bridge-2]
//! [light-1]
hueplusplus::Light light1 = bridge.lights().get(1);
//! [light-1]
//! [light-2]
std::vector<hueplusplus::Light> lights = bridge.lights().getAll();
//! [light-2]
//! [light-3]
light1.on();
light1.setBrightness(120);
light1.alertHueSaturation({25500, 254});
light1.setColorLoop(true);
light1.setColorRGB({255, 128, 0});
lights[1].off();
lights.at(1).setColorHue(4562);
//! [light-3]
//! [light-4]
hueplusplus::ColorType type1 = light1.getColorType();
//! [light-4]
//! [light-5]
light1.hasBrightnessControl();
light1.hasTemperatureControl();
light1.hasColorControl();
//! [light-5]
// Getting started
//! [control-lights]
hueplusplus::Light light = bridge.lights().get(1);
light.on();
light.off();
//! [control-lights]
//! [control-groups]
hueplusplus::Group group = bridge.groups().get(1);
group.setOn(true);
//! [control-groups]
// Sensors
//! [sensor-conditions]
//! [known-sensor-1]
hueplusplus::sensors::ZLLSwitch switchSensor = bridge.sensors().getAsType<hueplusplus::sensors::ZLLSwitch>(2);
//! [known-sensor-1]
// ZLLSwitch conditions operate on `buttonEvent`, use makeConditionLastUpdate()
// to trigger on the last update time.
// Some examples:
hueplusplus::Condition upPressed
= makeCondition(switchSensor).eq(hueplusplus::sensors::ZLLSwitch::c_UP_INITIAL_PRESS);
hueplusplus::Condition buttonChanged = makeCondition(switchSensor).dx();
hueplusplus::time::TimeInterval interval(std::chrono::hours(12), std::chrono::hours(13));
hueplusplus::Condition updatedAtNoon = makeConditionLastUpdate(switchSensor).in(interval);
//! [sensor-conditions]
//! [known-sensor-2]
std::vector<hueplusplus::sensors::ZLLSwitch> allSwitches
= bridge.sensors().getAllByType<hueplusplus::sensors::ZLLSwitch>();
//! [known-sensor-2]
//! [generic-sensor-1]
hueplusplus::Sensor genericSensor = bridge.sensors().get(1);
if (genericSensor.hasOn())
{
// Now can check whether it is on
if (genericSensor.isOn())
{
// ...
}
}
//! [generic-sensor-1]
// Transactions
//! [transaction-lights]
light.transaction().setOn(true).setBrightness(29).setColorHue(3000).setColorSaturation(128).commit();
//! [transaction-lights]
bool shouldTurnOn = true;
//! [transaction-advanced]
hueplusplus::StateTransaction t = light.transaction();
if (shouldTurnOn)
t.setOn(true);
t.commit();
//! [transaction-advanced]
//! [transaction-groups]
group.transaction().setOn(true).setBrightness(64).commit();
//! [transaction-groups]
hueplusplus::Schedule schedule = bridge.schedules().get(1);
//! [transaction-action]
hueplusplus::Action action = light.transaction().setOn(true).setBrightness(254).toAction();
schedule.setCommand(action);
//! [transaction-action]
}
void snippet2()
{
// Main page
//! [get-bridge-3]
// For windows use std::make_shared<hueplusplus::WinHttpHandler>();
auto handler = std::make_shared<hueplusplus::LinHttpHandler>();
hueplusplus::Bridge bridge("192.168.2.102", 80, "<username>", handler);
//! [get-bridge-3]
// Sensors
//! [generic-sensor-2]
hueplusplus::Sensor genericSensor = bridge.sensors().get(1);
if (genericSensor.getType() == hueplusplus::sensors::ZLLSwitch::typeStr)
{
hueplusplus::sensors::ZLLSwitch switchSensor = genericSensor.asSensorType<hueplusplus::sensors::ZLLSwitch>();
// ...
}
//! [generic-sensor-2]
}
void snippet3()
{
// Shared state
auto handler = std::make_shared<hueplusplus::LinHttpHandler>();
hueplusplus::BridgeFinder finder(handler);
std::vector<hueplusplus::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
//! [shared-bridge-1]
hueplusplus::Bridge bridge = finder.getBridge(bridges[0], true);
//! [shared-bridge-1]
//! [refresh-example]
bridge.setRefreshDuration(std::chrono::minutes(1));
bridge.lights().setRefreshDuration(std::chrono::seconds(30));
hueplusplus::Light light = bridge.lights().get(1);
// ... wait some time
bool on = light.isOn();
//! [refresh-example]
}
void snippet4()
{
// Shared state
auto handler = std::make_shared<hueplusplus::LinHttpHandler>();
//! [shared-bridge-2]
hueplusplus::Bridge bridge("192.168.2.102", 80, "<username>", handler, "", std::chrono::seconds(10), true);
//! [shared-bridge-2]
}
int main(int argc, char** argv)
{
return 0;
}
@@ -0,0 +1,149 @@
/**
\file UsernameConfig.cpp
Copyright Notice\n
Copyright (C) 2021 Jan Rogall - 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 <http://www.gnu.org/licenses/>.
\example{lineno} UsernameConfig.cpp
This example reads the username and mac address from a config file.
**/
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <hueplusplus/Bridge.h>
#ifdef _MSC_VER
#include <hueplusplus/WinHttpHandler.h>
using SystemHttpHandler = hueplusplus::WinHttpHandler;
#else
#include <hueplusplus/LinHttpHandler.h>
using SystemHttpHandler = hueplusplus::LinHttpHandler;
#endif
namespace hue = hueplusplus;
// Reads a json config file.
// filename: Path to the config file
// returns parsed json or an empty object if not successful.
nlohmann::json readConfigFile(const std::string& filename)
{
std::ifstream stream(filename);
try
{
nlohmann::json result = nlohmann::json::object();
if (stream)
{
stream >> result;
}
return result;
}
catch (const nlohmann::json::exception&)
{
// Ignore parse errors
return nlohmann::json::object();
}
}
// Saves a json file.
// filename: Path to the config file
// config: Json value to save
void saveConfigFile(const std::string& filename, const nlohmann::json& config)
{
std::ofstream stream(filename);
stream << std::setw(4) << config;
}
// Connects to a bridge and returns it
// username: Already existing username, can be left empty.
// macAddress: MAC address of the bridge, can be left empty.
// throws std::runtime_error when the bridge was not found.
// returns a connected bridge.
hue::Bridge connectToBridge(const std::string& username, const std::string& macAddress)
{
hue::BridgeFinder finder(std::make_shared<SystemHttpHandler>());
std::vector<hue::BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
for (const auto& bridge : bridges)
{
std::cout << "Bridge: " << bridge.mac << " at " << bridge.ip << '\n';
}
if (bridges.empty())
{
std::cout << "Found no bridges\n";
throw std::runtime_error("no bridges found");
}
if (macAddress.empty())
{
std::cout << "No bridge given, connecting to first one.\n";
return finder.getBridge(bridges.front());
}
if (!username.empty())
{
finder.addUsername(macAddress, username);
}
auto it = std::find_if(
bridges.begin(), bridges.end(), [&](const auto& identification) { return identification.mac == macAddress; });
if (it == bridges.end())
{
std::cout << "Given bridge not found\n";
throw std::runtime_error("bridge not found");
}
return finder.getBridge(*it);
}
// Connects to a bridge. The steps are:
// - read "config.json" for an existing config
// - connect to the bridge
// - save the username to the config file for the next run
//
// Also prints out the IP and username.
int main(int argc, char** argv)
{
const std::string filename = "config.json";
try
{
nlohmann::json config = readConfigFile(filename);
const std::string username = config.value("username", "");
const std::string macAddress = config.value("mac", "");
hue::Bridge hue = connectToBridge(username, macAddress);
// Store updated information into file
config["username"] = hue.getUsername();
config["mac"] = hue.config().getMACAddress();
saveConfigFile(filename, config);
std::cout << "Connected to bridge. IP: " << hue.getBridgeIP() << ", username: " << hue.getUsername() << '\n';
}
catch (...)
{ }
std::cout << "Press enter to exit\n";
std::cin.get();
return 0;
}
@@ -0,0 +1,111 @@
/**
\file APICache.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 <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_API_CACHE_H
#define INCLUDE_API_CACHE_H
#include <chrono>
#include <string>
#include "HueCommandAPI.h"
namespace hueplusplus
{
//! \brief Maximum duration, used to indicate that the cache should never be refreshed automatically.
constexpr std::chrono::steady_clock::duration c_refreshNever = std::chrono::steady_clock::duration::max();
//! \brief Caches API GET requests and refreshes regularly.
class APICache
{
public:
//! \brief Constructs APICache which forwards to a base cache
//! \param baseCache Base cache providing a parent state, must not be nullptr
//! \param subEntry Key of the child to use in the base cache
//! \param refresh Interval between cache refreshing. May be 0 to always refresh.
//! This is independent from the base cache refresh rate.
//!
//! Refreshes only part of the base cache.
APICache(
std::shared_ptr<APICache> baseCache, const std::string& subEntry, std::chrono::steady_clock::duration refresh);
//! \brief Constructs APICache with an own internal json cache
//! \param path URL appended after username, may be empty.
//! \param commands HueCommandAPI for making API requests.
//! \param refresh Interval between cache refreshing. May be 0 to always refresh.
//! \param initial Initial value, may be null. If present, assumes the value is up to date.
APICache(const std::string& path, const HueCommandAPI& commands, std::chrono::steady_clock::duration refresh,
const nlohmann::json& initial);
//! \brief Refresh cache now.
//! \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
//!
//! If there is a base cache, refreshes only the used part of that cache.
void refresh();
//! \brief Get cached value, refresh if necessary.
//! \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
nlohmann::json& getValue();
//! \brief Get cached value, does not refresh.
//! \throws HueException when no previous request was cached
const nlohmann::json& getValue() const;
//! \brief Set duration after which the cache is refreshed.
//! \param refreshDuration Interval between cache refreshing.
//! May be 0 to always refresh, or \ref c_refreshNever to never refresh.
//!
//! If the new refresh duration is exceeded, does not refresh immediately.
//! Instead, the next non-const getValue() call will refresh the value.
//! This is to reduce the number of unneccessary requests.
void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
//! \brief Get duration between refreshes.
std::chrono::steady_clock::duration getRefreshDuration() const;
//! \brief Get HueCommandAPI used for requests
HueCommandAPI& getCommandAPI();
//! \brief Get HueCommandAPI used for requests
const HueCommandAPI& getCommandAPI() const;
//! \brief Get path the cache is refreshed from
//! \returns Request path as passed to HueCommandAPI::GETRequest
std::string getRequestPath() const;
private:
bool needsRefresh();
private:
std::shared_ptr<APICache> base;
std::string path;
HueCommandAPI commands;
std::chrono::steady_clock::duration refreshDuration;
std::chrono::steady_clock::time_point lastRefresh;
nlohmann::json value;
};
} // namespace hueplusplus
#endif
@@ -0,0 +1,73 @@
/**
\file Action.h
Copyright Notice\n
Copyright (C) 2020 Jan Rogall - 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 <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_HUEPLUSPLUS_ACTION_H
#define INCLUDE_HUEPLUSPLUS_ACTION_H
#include "json/json.hpp"
namespace hueplusplus
{
//! \brief Action executed by the bridge, e.g. as a Schedule command
//!
//! The action makes either a POST, PUT or DELETE request with a given body
//! to an address on the bridge.
//!
//! The Action can also be created by StateTransaction::toAction().
class Action
{
public:
//! \brief Create Action from json
//! \param json JSON object with address, method and body
explicit Action(const nlohmann::json& json);
//! \brief Method used for the command
enum class Method
{
post, //!< POST request
put, //!< PUT request
deleteMethod //!< DELETE request
};
//! \brief Get address the request is made to
std::string getAddress() const;
//! \brief Get request method
Method getMethod() const;
//! \brief Get request body
const nlohmann::json& getBody() const;
//! \brief Get json object of command
const nlohmann::json& toJson() const;
public:
//! \brief Parse Method from string
//! \param s \c POST, \c PUT or \c DELETE
static Method parseMethod(const std::string& s);
//! \brief Get string from Method
//! \returns \c POST, \c PUT or \c DELETE
static std::string methodToString(Method m);
private:
nlohmann::json json;
};
} // namespace hueplusplus
#endif
@@ -0,0 +1,159 @@
/**
\file BaseDevice.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 <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_HUEPLUSPLUS_HUE_THING_H
#define INCLUDE_HUEPLUSPLUS_HUE_THING_H
#include <memory>
#include "APICache.h"
#include "json/json.hpp"
namespace hueplusplus
{
//! \brief Base class for physical devices connected to the bridge (sensor or light).
class BaseDevice
{
public:
//! \brief Virtual destructor
virtual ~BaseDevice() = default;
//! \brief Const function that returns the id of this device
//!
//! \return integer representing the device id
virtual int getId() const;
//! \brief Const function that returns the device type
//!
//! \return String containing the type
virtual std::string getType() const;
//! \brief Function that returns the name of the device.
//!
//! \return String containig the name of the device
//! \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 device.
//!
//! \note This will not refresh the device state
//! \return String containig the name of the thing
virtual std::string getName() const;
//! \brief Const function that returns the modelid of the device
//!
//! \return String containing the modelid
virtual std::string getModelId() const;
//! \brief Const function that returns the uniqueid of the device
//!
//! \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 device
//!
//! \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 device
//!
//! \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 device
//!
//! \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 device
//!
//! \note This will not refresh the device state
//! \return String containing the software version
virtual std::string getSwVersion() const;
//! \brief Function that sets the name of the device
//!
//! \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 Refreshes internal cached state.
//! \param force \c true forces a refresh, regardless of how long the last refresh was ago.
//! \c false to only refresh when enough time has passed (needed e.g. when calling only const methods).
//! \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 refresh(bool force = false);
//! \brief Sets custom refresh interval for this device.
//! \param refreshDuration The new minimum duration between refreshes. May be 0 or \ref c_refreshNever.
virtual void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
protected:
//! \brief Protected ctor that is used by subclasses, construct with shared cache.
//! \param id Integer that specifies the id of this device
//! \param baseCache Cache of the ResourceList containing this device (must not be null).
BaseDevice(int id, const std::shared_ptr<APICache>& baseCache);
//! \brief Protected ctor that is used by subclasses.
//!
//! \param id Integer that specifies the id of this device
//! \param commands HueCommandAPI for communication with the bridge
//! \param path Base path for the resource type, ending with a '/'. Example: \c "/lights/"
//! \param refreshDuration Time between refreshing the cached state.
//! \param currentState Current state of the device, may be null.
BaseDevice(int id, const HueCommandAPI& commands, const std::string& path,
std::chrono::steady_clock::duration refreshDuration, const nlohmann::json& currentState);
//! \brief Utility function to send a put request to the device.
//!
//! \param subPath A path that is appended to the uri, note it should always start with a slash ("/")
//! \param request A nlohmann::json aka the request to send
//! \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 std::string& subPath, const nlohmann::json& request, FileInfo fileInfo);
protected:
int id; //!< holds the id of the device
APICache state; //!< holds the current state of the device
};
} // namespace hueplusplus
#endif
@@ -0,0 +1,178 @@
/**
\file BaseHttpHandler.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 <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_HUEPLUSPLUS_BASE_HTTP_HANDLER_H
#define INCLUDE_HUEPLUSPLUS_BASE_HTTP_HANDLER_H
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include "IHttpHandler.h"
#include "json/json.hpp"
namespace hueplusplus
{
//! Base class for classes that handle http requests and multicast requests
class BaseHttpHandler : public IHttpHandler
{
public:
//! \brief Virtual dtor
virtual ~BaseHttpHandler() = default;
//! \brief Send a message to a specified host and return the body of the response.
//!
//! \param msg The message that should sent to the specified address
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! \return The body of the response of the host as a string
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
std::string sendGetHTTPBody(const std::string& msg, const std::string& adr, int port = 80) const override;
//! \brief Send a HTTP request with the given method to the specified host and return the body of the response.
//!
//! \param method HTTP method type e.g. GET, HEAD, POST, PUT, DELETE, ...
//! \param uri Uniform Resource Identifier in the request
//! \param contentType MIME type of the body data e.g. "text/html", "application/json", ...
//! \param body Request body, may be empty
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! \return Body of the response of the host
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
std::string sendHTTPRequest(const std::string& method, const std::string& uri, const std::string& contentType,
const std::string& body, const std::string& adr, int port = 80) const override;
//! \brief Send a HTTP GET request to the specified host and return the body of the response.
//!
//! \param uri Uniform Resource Identifier in the request
//! \param contentType MIME type of the body data e.g. "text/html", "application/json", ...
//! \param body Request body, may be empty
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! that specifies the port to which the request is sent to. Default is 80
//! \return Body of the response of the host
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
std::string GETString(const std::string& uri, const std::string& contentType, const std::string& body,
const std::string& adr, int port = 80) const override;
//! \brief Send a HTTP POST request to the specified host and return the body of the response.
//!
//! \param uri Uniform Resource Identifier in the request
//! \param contentType MIME type of the body data e.g. "text/html", "application/json", ...
//! \param body Request body, may be empty
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! that specifies the port to which the request is sent to. Default is 80
//! \return Body of the response of the host
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
std::string POSTString(const std::string& uri, const std::string& contentType, const std::string& body,
const std::string& adr, int port = 80) const override;
//! \brief Send a HTTP PUT request to the specified host and return the body of the response.
//!
//! \param uri Uniform Resource Identifier in the request
//! \param contentType MIME type of the body data e.g. "text/html", "application/json", ...
//! \param body Request body, may be empty
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! that specifies the port to which the request is sent to. Default is 80
//! \return Body of the response of the host
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
std::string PUTString(const std::string& uri, const std::string& contentType, const std::string& body,
const std::string& adr, int port = 80) const override;
//! \brief Send a HTTP DELETE request to the specified host and return the body of the response.
//!
//! \param uri Uniform Resource Identifier in the request
//! \param contentType MIME type of the body data e.g. "text/html", "application/json", ...
//! \param body Request body, may be empty
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! that specifies the port to which the request is sent to. Default is 80
//! \return Body of the response of the host
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
std::string DELETEString(const std::string& uri, const std::string& contentType, const std::string& body,
const std::string& adr, int port = 80) const override;
//! \brief Send a HTTP GET request to the specified host and return the body of the response parsed as JSON.
//!
//! \param uri Uniform Resource Identifier in the request
//! \param body Request body, may be empty
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! \return Parsed body of the response of the host
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
//! \throws nlohmann::json::parse_error when the body could not be parsed
nlohmann::json GETJson(
const std::string& uri, const nlohmann::json& body, const std::string& adr, int port = 80) const override;
//! \brief Send a HTTP POST request to the specified host and return the body of the response parsed as JSON.
//!
//! \param uri Uniform Resource Identifier in the request
//! \param body Request body, may be empty
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! \return Parsed body of the response of the host
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
//! \throws nlohmann::json::parse_error when the body could not be parsed
nlohmann::json POSTJson(
const std::string& uri, const nlohmann::json& body, const std::string& adr, int port = 80) const override;
//! \brief Send a HTTP PUT request to the specified host and return the body of the response parsed as JSON.
//!
//! \param uri Uniform Resource Identifier in the request
//! \param body Request body, may be empty
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! \return Parsed body of the response of the host
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
//! \throws nlohmann::json::parse_error when the body could not be parsed
nlohmann::json PUTJson(
const std::string& uri, const nlohmann::json& body, const std::string& adr, int port = 80) const override;
//! \brief Send a HTTP DELETE request to the specified host and return the body of the response parsed as JSON.
//!
//! \param uri Uniform Resource Identifier in the request
//! \param body Request body, may be empty
//! \param adr Ip or hostname in dotted decimal notation like "192.168.2.1"
//! \param port Optional port the request is sent to, default is 80
//! \return Parsed body of the response of the host
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
//! \throws nlohmann::json::parse_error when the body could not be parsed
nlohmann::json DELETEJson(
const std::string& uri, const nlohmann::json& body, const std::string& adr, int port = 80) const override;
};
} // namespace hueplusplus
#endif
@@ -0,0 +1,308 @@
/**
\file Bridge.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 <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_HUEPLUSPLUS_HUE_H
#define INCLUDE_HUEPLUSPLUS_HUE_H
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "APICache.h"
#include "BridgeConfig.h"
#include "BrightnessStrategy.h"
#include "ColorHueStrategy.h"
#include "ColorTemperatureStrategy.h"
#include "Group.h"
#include "HueCommandAPI.h"
#include "HueDeviceTypes.h"
#include "IHttpHandler.h"
#include "Light.h"
#include "ResourceList.h"
#include "Rule.h"
#include "Scene.h"
#include "Schedule.h"
#include "Sensor.h"
#include "SensorList.h"
#include "Utils.h"
#include "json/json.hpp"
//! \brief Namespace for the hueplusplus library
namespace hueplusplus
{
// forward declarations
class Bridge;
//!
//! Class to find all Hue bridges on the network and create usernames for them.
//!
class BridgeFinder
{
public:
struct BridgeIdentification
{
std::string ip;
int port = 80;
std::string mac;
};
public:
//! \brief Constructor of BridgeFinder class
//!
//! \param handler HttpHandler of type \ref IHttpHandler for communication with the bridge
BridgeFinder(std::shared_ptr<const IHttpHandler> handler);
//! \brief 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
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body
std::vector<BridgeIdentification> findBridges() const;
//! \brief Gets a Hue bridge based on its identification
//!
//! \param identification \ref BridgeIdentification that specifies a bridge
//! \param sharedState Uses a single, shared cache for all objects on the bridge.
//! \return \ref Bridge class object
//! \throws std::system_error when system or socket operations fail
//! \throws HueException when response contained no body or username could not be requested
//! \throws HueAPIResponseException when response contains an error
//! \throws nlohmann::json::parse_error when response could not be parsed
Bridge getBridge(const BridgeIdentification& identification, bool sharedState = false);
//! \brief Function that adds a username to the 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 adds a client key to the clientkeys map
//!
//! The client key is only needed for entertainment mode, otherwise it is optional.
//! \param mac MAC address of Hue bridge
//! \param clientkey Client key that is used to control the Hue bridge in entertainment mode
void addClientKey(const std::string& mac, const std::string& clientkey);
//! \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<std::string, std::string>& getAllUsernames() const;
//! \brief Normalizes mac address to plain hex number.
//! \returns \p input without separators and whitespace, in lower case.
static std::string normalizeMac(std::string input);
private:
//! \brief Parses mac address from description.xml
//!
//! \param description Content of description.xml file as returned by GET request.
//! \returns Content of xml element \c serialNumber if description matches a Hue bridge, otherwise an empty
//! string.
static std::string parseDescription(const std::string& description);
std::map<std::string, std::string> usernames; //!< Maps all macs to usernames added by \ref
//!< BridgeFinder::addUsername
std::map<std::string, std::string> clientkeys; //!< Maps all macs to clientkeys added by \ref
//!< BridgeFinder::addClientKey
std::shared_ptr<const IHttpHandler> http_handler;
};
//! \brief Bridge class for a bridge.
//!
//! This is the main class used to interact with the Hue bridge.
class Bridge
{
friend class BridgeFinder;
public:
using LightList = SearchableResourceList<Light>;
using GroupList = GroupResourceList<Group, CreateGroup>;
using ScheduleList = CreateableResourceList<ResourceList<Schedule, int>, CreateSchedule>;
using SceneList = CreateableResourceList<ResourceList<Scene, std::string>, CreateScene>;
using RuleList = CreateableResourceList<ResourceList<Rule, int>, CreateRule>;
public:
//! \brief Constructor of Bridge class
//!
//! \param ip IP address in dotted decimal notation like "192.168.2.1"
//! \param port Port of the hue bridge
//! \param username String that specifies the username that is used to control
//! the bridge. Can be left empty and acquired in \ref requestUsername.
//! \param handler HttpHandler for communication with the bridge
//! \param clientkey Optional client key for streaming
//! \param refreshDuration Time between refreshing the cached state.
//! \param sharedState Uses a single, shared cache for all objects on the bridge.
Bridge(const std::string& ip, const int port, const std::string& username,
std::shared_ptr<const IHttpHandler> handler, const std::string& clientkey = "",
std::chrono::steady_clock::duration refreshDuration = std::chrono::seconds(10), bool sharedState = false);
//! \brief Refreshes the bridge state.
//!
//! Should only be called rarely, as a full refresh is costly and usually not necessary.
//! Instead refresh only the parts you are interested in or rely on periodic refreshes
//! that happen automatically when calling non-const methods.
//! \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
void refresh();
//! \brief Sets refresh interval for the whole bridge state.
//! \param refreshDuration The new minimum duration between refreshes. May be 0 or \ref c_refreshNever.
//!
//! Also sets refresh duration on all resource lists on the bridge, but not on already existing lights.
//! The resource lists (such as lights()) can have their own durations, but those must be set after calling this function.
void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
//! \brief Function to get the ip address of the hue bridge
//!
//! \return string containing ip
std::string getBridgeIP() const;
//! \brief Function to set stream mode to active for entertainment mode
//!
//! \return bool - whether stream request was successful
bool startStreaming(std::string group_identifier);
//! \brief Function to set stream mode to active for entertainment mode
//!
//! \return bool - whether stream request was successful
bool stopStreaming(std::string group_identifier);
//! \brief Function to get the port of the hue bridge
//!
//! \return integer containing port
int getBridgePort() const;
//! \brief Send a username request to the Hue bridge.
//!
//! Blocks for about 30 seconds and 5 seconds to prepare.
//! It automatically sets the 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. \return username for API usage \throws std::system_error when
//! system or socket operations fail \throws HueException when response contained no body \throws
//! HueAPIResponseException when response contains an error except link button not pressed. \throws
//! nlohmann::json::parse_error when response could not be parsed
std::string requestUsername();
//! \brief Function that returns the username
//!
//! \return The username used for API access
std::string getUsername() const;
//! \brief Function that returns the client key
//!
//! \return The client key used for Entertainment Mode API access
std::string getClientKey() const;
//! \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 to set the port of this class representing a bridge
//!
//! \param port Integer that specifies the port of an address like
//! "192.168.2.1:8080"
void setPort(const int port);
//! \brief Provides access to the configuration of the bridge.
BridgeConfig& config();
//! \brief Provides access to the configuration of the bridge.
//! \note Does not refresh state.
const BridgeConfig& config() const;
//! \brief Provides access to the Light%s on the bridge.
LightList& lights();
//! \brief Provides access to the Light%s on the bridge.
//! \note Does not refresh state.
const LightList& lights() const;
//! \brief Provides access to the Group%s on the bridge.
GroupList& groups();
//! \brief Provides access to the Group%s on the bridge.
//! \note Does not refresh state.
const GroupList& groups() const;
//! \brief Provides access to the Schedule%s on the bridge.
ScheduleList& schedules();
//! \brief Provides access to the Schedule%s on the bridge.
//! \note Does not refresh state.
const ScheduleList& schedules() const;
//! \brief Provides access to the Scene%s on the bridge.
SceneList& scenes();
//! \brief Provides access to the Scene%s on the bridge.
//! \note Does not refresh state.
const SceneList& scenes() const;
//! \brief Provides access to the Sensor%s on the bridge.
SensorList& sensors();
//! \brief Provides access to the Sensor%s on the bridge.
//! \note Does not refresh state.
const SensorList& sensors() const;
//! \brief Provides access to the Rule%s on the bridge.
RuleList& rules();
//! \brief Provides access to the Rule%s on the bridge
//! \note Does not refresh state.
const RuleList& rules() const;
private:
//! \brief Function that sets the HttpHandler and updates the HueCommandAPI.
//! \param handler a HttpHandler of type \ref IHttpHandler
//!
//! The HttpHandler and HueCommandAPI are used for bridge communication.
//! Resetting the HttpHandler should only be done when the username is first set,
//! before Bridge is used.
//! Resets all caches and resource lists.
void setHttpHandler(std::shared_ptr<const IHttpHandler> handler);
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
std::string clientkey; //!< Client key that is used for entertainment mode
int port;
std::shared_ptr<const IHttpHandler> http_handler; //!< A IHttpHandler that is used to communicate with the
//!< bridge
std::chrono::steady_clock::duration refreshDuration;
std::shared_ptr<APICache> stateCache;
detail::MakeCopyable<LightList> lightList;
detail::MakeCopyable<GroupList> groupList;
detail::MakeCopyable<ScheduleList> scheduleList;
detail::MakeCopyable<SceneList> sceneList;
detail::MakeCopyable<SensorList> sensorList;
detail::MakeCopyable<RuleList> ruleList;
detail::MakeCopyable<BridgeConfig> bridgeConfig;
bool sharedState;
};
} // namespace hueplusplus
#endif
@@ -0,0 +1,115 @@
/**
\file BridgeConfig.h
Copyright Notice\n
Copyright (C) 2020 Jan Rogall - 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 <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_HUEPLUSPLUS_BRIDGE_CONFIG_H
#define INCLUDE_HUEPLUSPLUS_BRIDGE_CONFIG_H
#include <string>
#include <vector>
#include "APICache.h"
#include "TimePattern.h"
namespace hueplusplus
{
//! \brief API version consisting of major, minor and patch version
struct Version
{
int major;
int minor;
int patch;
};
//! \brief User that is whitelisted for Hue API usage
struct WhitelistedUser
{
//! \brief API username of the user
std::string key;
//! \brief Name provided on user creation
std::string name;
//! \brief Last time the user was used
time::AbsoluteTime lastUsed;
//! \brief Time the user was created
time::AbsoluteTime created;
};
//! \brief General bridge configuration properties.
class BridgeConfig
{
public:
//! \brief Construct BridgeConfig
BridgeConfig(std::shared_ptr<APICache> baseCache, std::chrono::steady_clock::duration refreshDuration);
//! \brief Refreshes internal cached state.
//! \param force \c true forces a refresh, regardless of how long the last refresh was ago.
//! \c false to only refresh when enough time has passed (needed e.g. when calling only const methods).
//! \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
void refresh(bool force = false);
//! \brief Sets custom refresh interval for the config.
//! \param refreshDuration The new minimum duration between refreshes. May be 0 or \ref c_refreshNever.
void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
//! \brief Get the list of whitelisted users
//! \returns All users authorized for API access
std::vector<WhitelistedUser> getWhitelistedUsers() const;
//! \brief Remove user from the whitelist
//! \param userKey The API username of the user to remove
//! \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
void removeUser(const std::string& userKey);
//! \brief Get link button state
//! \returns true when link button was pressed in the last 30 seconds.
//!
//! Indicates whether new users can be added currently.
bool getLinkButton() const;
//! \brief Set the link button state to pressed
void pressLinkButton();
//! \brief Add the closest lamp to the network
void touchLink();
//! \brief Get bridge MAC address
std::string getMACAddress() const;
//! \brief Get current (of last refresh) UTC time of the bridge
time::AbsoluteTime getUTCTime() const;
//! \brief Get configured timezone for the bridge
//! \note For times not in UTC, the timezone of the program and the bridge are assumed to be identical.
std::string getTimezone() const;
protected:
BridgeConfig(const BridgeConfig&) = default;
BridgeConfig(BridgeConfig&&) = default;
BridgeConfig& operator=(const BridgeConfig&) = default;
BridgeConfig& operator=(BridgeConfig&&) = default;
private:
APICache cache;
};
} // namespace hueplusplus
#endif
@@ -0,0 +1,61 @@
/**
\file BrightnessStrategy.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 <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_HUEPLUSPLUS_BRIGHTNESS_STRATEGY_H
#define INCLUDE_HUEPLUSPLUS_BRIGHTNESS_STRATEGY_H
#include <cstdint>
namespace hueplusplus
{
class Light;
//! Virtual base class for all BrightnessStrategies
class BrightnessStrategy
{
public:
//! \brief Virtual function for changing a lights brightness with a specified
//! transition.
//!
//! \param bri The brightness raning from 0 = off to 255 = fully lit
//! \param transition The time it takes to fade to the new brightness in
//! multiples of 100ms, 4 = 400ms and should be seen as the default \param
//! light A reference of the light
virtual bool setBrightness(unsigned int bri, uint8_t transition, Light& light) const = 0;
//! \brief Virtual function that returns the current brightnessof the light
//!
//! Should update the lights state by calling refreshState()
//! \param light A reference of the light
//! \return Unsigned int representing the brightness
virtual unsigned int getBrightness(Light& light) const = 0;
//! \brief Virtual function that returns the current brightness of the light
//!
//! \note This should not update the lights state
//! \param light A const reference of the light
//! \return Unsigned int representing the brightness
virtual unsigned int getBrightness(const Light& light) const = 0;
//! \brief Virtual dtor
virtual ~BrightnessStrategy() = default;
};
} // namespace hueplusplus
#endif
@@ -0,0 +1,293 @@
/**
\file CLIPSensors.h
Copyright Notice\n
Copyright (C) 2020 Jan Rogall - 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 <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDE_HUEPLUSPLUS_CLIP_SENSORS_H
#define INCLUDE_HUEPLUSPLUS_CLIP_SENSORS_H
#include "Sensor.h"
namespace hueplusplus
{
namespace sensors
{
//! \brief Common methods for CLIP sensors
class BaseCLIP : public BaseDevice
{
public:
//! \brief Check if sensor is on
//!
//! Sensors which are off do not change their status
bool isOn() const;
//! \brief Enable or disable sensor
//! \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
void setOn(bool on);
//! \brief Check whether the sensor has a battery state
bool hasBatteryState() const;
//! \brief Get battery state
//! \returns Battery state in percent
//! \throws nlohmann::json::out_of_range when sensor has no battery state.
int getBatteryState() const;
//! \brief Set battery state
//! \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
void setBatteryState(int percent);
//! \brief Check whether the sensor is reachable
//! \note Reachable verification is not implemented for CLIP sensors yet
bool isReachable() const;
//! \brief Check whether the sensor has a URL
bool hasURL() const;
//! \brief Get sensor URL
std::string getURL() const;
//! \brief Set sensor URL
//! \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
void setURL(const std::string& url);
//! \brief Get time of last status update
//! \returns The last update time, or a time with a zero duration from epoch
//! if the last update time is not set.
time::AbsoluteTime getLastUpdated() const;
protected:
//! \brief Protected constructor to be used by subclasses
explicit BaseCLIP(Sensor sensor) : BaseDevice(std::move(sensor)) { }
};
//! \brief CLIP sensor for button presses
class CLIPSwitch : public BaseCLIP
{
public:
//! \brief Construct from generic sensor
explicit CLIPSwitch(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
//! \brief Get the code of the last switch event.
int getButtonEvent() const;
//! \brief Set the button event code
//! \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
void setButtonEvent(int code);
//! \brief CLIPSwitch sensor type name
static constexpr const char* typeStr = "CLIPSwitch";
};
//! \brief CLIP sensor detecting whether a contact is open or closed
class CLIPOpenClose : public BaseCLIP
{
public:
//! \brief Construct from generic sensor
explicit CLIPOpenClose(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
//! \brief Check whether the switch is open
bool isOpen() const;
//! \brief Set switch state
//!
//! The sensor needs to stay in a state for at least 1s.
//! \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
void setOpen(bool open);
//! \brief CLIPOpenClose sensor type name
static constexpr const char* typeStr = "CLIPOpenClose";
};
detail::ConditionHelper<bool> makeCondition(const CLIPOpenClose& sensor);
//! \brief CLIP sensor to detect presence
class CLIPPresence : public BaseCLIP
{
public:
//! \brief Construct from generic sensor
explicit CLIPPresence(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
//! \brief Check whether presence was detected
bool getPresence() const;
//! \brief Set presence state
//! \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
void setPresence(bool presence);
//! \brief CLIPPresence sensor type name
static constexpr const char* typeStr = "CLIPPresence";
};
//! \brief CLIP sensor for temperature
class CLIPTemperature : public BaseCLIP
{
public:
//! \brief Construct from generic sensor
explicit CLIPTemperature(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
//! \brief Get measured temperature
//! \returns Temperature in 0.01 degrees Celsius.
int getTemperature() const;
//! \brief Set temperature
//! \param temperature Temperature in 0.01 degreese Celsius.
//! \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
void setTemperature(int temperature);
//! \brief CLIPTemperature sensor type name
static constexpr const char* typeStr = "CLIPTemperature";
};
//! \brief CLIP sensor for humidity
class CLIPHumidity : public BaseCLIP
{
public:
//! \brief Construct from generic sensor
explicit CLIPHumidity(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
//! \brief Get measured humidity
//! \returns Humidity in 0.01% steps
int getHumidity() const;
//! \brief Set humidity
//! \param humidity Humidity in 0.01% steps
//! \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
void setHumidity(int humidity);
//! \brief CLIPHumidity sensor type name
static constexpr const char* typeStr = "CLIPHumidity";
};
detail::ConditionHelper<int> makeCondition(const CLIPHumidity& sensor);
//! \brief CLIP sensor for light level
class CLIPLightLevel : public BaseCLIP
{
public:
//! \brief Construct from generic sensor
explicit CLIPLightLevel(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
//! \brief Get threshold to detect darkness
int getDarkThreshold() const;
//! \brief Set threshold to detect darkness
//! \param threshold Light level as reported by \ref getLightLevel
//! \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
void setDarkThreshold(int threshold);
//! \brief Get offset over dark threshold to detect daylight
int getThresholdOffset() const;
//! \brief Set offset to detect daylight
//! \param offset Offset to dark threshold to detect daylight. Must be greater than 1.
//! \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
void setThresholdOffset(int offset);
//! \brief Get measured light level
//! \returns Light level in <code>10000*log10(lux)+1</code> (logarithmic scale)
int getLightLevel() const;
//! \brief Set measured light level
//! \param level Light level in <code>10000*log10(lux)+1</code>
//! \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
void setLightLevel(int level);
//! \brief Check whether light level is below dark threshold
bool isDark() const;
//! \brief Check whether light level is above light threshold
//!
//! Light threshold is dark threshold + offset
bool isDaylight() const;
//! \brief CLIPLightLevel sensor type name
static constexpr const char* typeStr = "CLIPLightLevel";
};
//! \brief CLIP sensor for a generic 3rd party sensor.
//!
//! Can be created by POST.
class CLIPGenericFlag : public BaseCLIP
{
public:
//! \brief Construct from generic sensor
explicit CLIPGenericFlag(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
//! \brief Get boolean flag
bool getFlag() const;
//! \brief Set flag
//! \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
void setFlag(bool flag);
//! \brief CLIPGenericFlag sensor type name
static constexpr const char* typeStr = "CLIPGenericFlag";
};
detail::ConditionHelper<bool> makeCondition(const CLIPGenericFlag& sensor);
//! \brief CLIP sensor for a generic 3rd party status
//!
//! Can be created by POST.
class CLIPGenericStatus : public BaseCLIP
{
public:
//! \brief Construct from generic sensor
explicit CLIPGenericStatus(Sensor sensor) : BaseCLIP(std::move(sensor)) { }
//! \brief Get sensor status
int getStatus() const;
//! \brief Set sensor 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
void setStatus(int status);
//! \brief CLIPGenericStatus sensor type name
static constexpr const char* typeStr = "CLIPGenericStatus";
};
detail::ConditionHelper<int> makeCondition(const CLIPGenericStatus& sensor);
} // namespace sensors
} // namespace hueplusplus
#endif
@@ -0,0 +1,128 @@
/**
\file ColorHueStrategy.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 <http://www.gnu.org/licenses/>.
**/
#ifndef _COLOR_HUE_STRATEGY_H
#define _COLOR_HUE_STRATEGY_H
#include <cstdint>
#include <memory>
#include "ColorUnits.h"
namespace hueplusplus
{
class Light;
//! Virtual base class for all ColorHueStrategies
class ColorHueStrategy
{
public:
//! \brief Virtual function for changing a lights color in hue with a
//! specified transition.
//!
//! The hue ranges from 0 to 65535, whereas 65535 and 0 are red, 25500 is
//! green and 46920 is blue. \param hue The hue of the color \param transition
//! The time it takes to fade to the new color in multiples of 100ms, 4 =
//! 400ms and should be seen as the default \param light A reference of the
//! light
virtual bool setColorHue(uint16_t hue, uint8_t transition, Light& light) const = 0;
//! \brief Virtual function for changing a lights color in saturation with a
//! specified transition.
//!
//! The saturation ranges from 0 to 254, whereas 0 is least saturated (white)
//! and 254 is most saturated (vibrant). \param sat The saturation of the
//! color \param transition The time it takes to fade to the new color in
//! multiples of 100ms, 4 = 400ms and should be seen as the default \param
//! light A reference of the light
virtual bool setColorSaturation(uint8_t sat, uint8_t transition, Light& light) const = 0;
//! \brief Virtual function for changing a lights color in hue and saturation
//! format with a specified transition.
//!
//! \param hueSat Color in hue and satuation.
//! \param transition The time it takes to fade to the new color in multiples of
//! 100ms, 4 = 400ms and should be seen as the default
//! \param light A reference of the light
virtual bool setColorHueSaturation(const HueSaturation& hueSat, uint8_t transition, Light& light) const = 0;
//! \brief Virtual function for changing a lights color in CIE format with a
//! specified transition.
//!
//! \param xy The color in XY and brightness
//! \param transition The time it takes to fade to the new color in multiples
//! of 100ms, 4 = 400ms and should be seen as the default \param light A
//! reference of the light
virtual bool setColorXY(const XYBrightness& xy, uint8_t transition, Light& light) const = 0;
//! \brief Virtual function for turning on/off the color loop feature of a
//! light.
//!
//! Can be theoretically set for any light, but it only works for lights that
//! support this feature. When this feature is activated the light will fade
//! through every color on the current hue and saturation settings. Notice
//! that none of the setter functions check whether this feature is enabled
//! and the colorloop can only be disabled with this function or by simply
//! calling off() and then on(), so you could
//! alternatively call off() and then use any of the setter functions. \param
//! on Boolean to turn this feature on or off, true/1 for on and false/0 for
//! off \param light A reference of the light
virtual bool setColorLoop(bool on, Light& light) const = 0;
//! \brief Virtual function that lets the light perform one breath cycle in
//! the specified color.
//!
//! \param hueSat The color in hue and saturation
//! \param light A reference of the light
virtual bool alertHueSaturation(const HueSaturation& hueSat, Light& light) const = 0;
//! \brief Virtual function that lets the light perform one breath cycle in
//! the specified color.
//!
//! \param xy The color in XY and brightness
//! \param light A reference of the light
virtual bool alertXY(const XYBrightness& xy, Light& light) const = 0;
//! \brief Virtual function that returns the current color of the light as hue
//! and saturation
//!
//! Should update the lights state by calling refreshState()
//! \param light A reference of the light
virtual HueSaturation getColorHueSaturation(Light& light) const = 0;
//! \brief Virtual function that returns the current color of the light as hue
//! and saturation
//!
//! \note This should not update the lights state
//! \param light A const reference of the light
virtual HueSaturation getColorHueSaturation(const Light& light) const = 0;
//! \brief Virtual function that returns the current color of the light as xy
//!
//! Should update the lights state by calling refreshState()
//! \param light A reference of the light
//! \return XY and brightness of current color
virtual XYBrightness getColorXY(Light& light) const = 0;
//! \brief Virtual function that returns the current color of the light as xy
//!
//! \note This should not update the lights state
//! \param light A const reference of the light
//! \return XY and brightness of current color
virtual XYBrightness getColorXY(const Light& light) const = 0;
//! \brief Virtual dtor
virtual ~ColorHueStrategy() = default;
};
} // namespace hueplusplus
#endif
@@ -0,0 +1,73 @@
/**
\file ColorTemperatureStrategy.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 <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_HUEPLUSPLUS_COLOR_TEMPERATURE_STRATEGY_H
#define INCLUDE_HUEPLUSPLUS_COLOR_TEMPERATURE_STRATEGY_H
#include <stdint.h>
namespace hueplusplus
{
class Light;
//! Virtual base class for all ColorTemperatureStrategies
class ColorTemperatureStrategy
{
public:
//! \brief Virtual function for changing a lights color temperature in mired
//! with a specified transition.
//!
//! The color temperature in mired ranges from 153 to 500 whereas 153 is cold
//! and 500 is warm. \param mired The color temperature in mired \param
//! transition The time it takes to fade to the new color in multiples of
//! 100ms, 4 = 400ms and should be seen as the default \param light A
//! reference of the light
virtual bool setColorTemperature(unsigned int mired, uint8_t transition, Light& light) const = 0;
//! \brief Virtual function that lets the light perform one breath cycle in
//! the specified color.
//!
//! The color temperature in mired ranges from 153 to 500 whereas 153 is cold
//! and 500 is warm. \param mired The color temperature in mired \param light
//! A reference of the light
virtual bool alertTemperature(unsigned int mired, Light& light) const = 0;
//! \brief Virtual function that returns the current color temperature of the
//! light
//!
//! Should update the lights state by calling refreshState()
//! The color temperature in mired ranges from 153 to 500 whereas 153 is cold
//! and 500 is warm. \param light A reference of the light \return Unsigned
//! int representing the color temperature in mired
virtual unsigned int getColorTemperature(Light& light) const = 0;
//! \brief Virtual function that returns the current color temperature of the
//! light
//!
//! The color temperature in mired ranges from 153 to 500 whereas 153 is cold
//! and 500 is warm. \note This should not update the lights state \param
//! light A const reference of the light \return Unsigned int representing the
//! color temperature in mired
virtual unsigned int getColorTemperature(const Light& light) const = 0;
//! \brief Virtual dtor
virtual ~ColorTemperatureStrategy() = default;
};
} // namespace hueplusplus
#endif
@@ -0,0 +1,164 @@
/**
\file ColorUnits.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 <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_HUEPLUSPLUS_UNITS_H
#define INCLUDE_HUEPLUSPLUS_UNITS_H
#include <cstdint>
namespace hueplusplus
{
//! \brief Color in hue and saturation
struct HueSaturation
{
//! \brief Color hue
//!
//! Ranges from 0 to 65535 (16 bit), where 65535 and 0 are red, 25500 is green and 46920 is blue.
int hue;
//! \brief Color saturation
//!
//! Ranges from 0 to 254 (8 bit), where 0 is least saturated (white) and 254 is most saturated (vibrant).
int saturation;
bool operator==(const HueSaturation& other) const { return hue == other.hue && saturation == other.saturation; }
bool operator!=(const HueSaturation& other) const { return !(*this == other); }
};
//! \brief Color in CIE x and y coordinates
struct XY
{
//! \brief x coordinate in CIE, 0 to 1
float x;
//! \brief y coordinate in CIE, 0 to 1
float y;
bool operator==(const XY& other) const { return x == other.x && y == other.y; }
bool operator!=(const XY& other) const { return !(*this == other); }
};
//! \brief Color and brightness in CIE
//!
//! The brightness is needed to convert back to RGB colors if necessary.
//! \note brightness is not the actual luminance of the color, but instead the brightness the light is set to.
struct XYBrightness
{
//! \brief XY color
XY xy;
//! \brief Brightness from 0 to 1
float brightness;
bool operator==(const XYBrightness& other) const { return xy == other.xy && brightness == other.brightness; }
bool operator!=(const XYBrightness& other) const { return !(*this == other); }
};
//! \brief Triangle of representable colors in CIE
//!
//! \note Red, green and blue corner are oriented counter clockwise.
//! \see https://en.wikipedia.org/wiki/Chromaticity
struct ColorGamut
{
//! \brief Red corner in the color triangle
XY redCorner;
//! \brief Green corner in the color triangle
XY greenCorner;
//! \brief Blue corner in the color triangle
XY blueCorner;
//! \brief Check whether \c xy is representable.
bool contains(const XY& xy) const;
//! \brief Correct \c xy to closest representable color.
//! \returns \c xy if it is in the triangle, otherwise the closest point on the border.
XY corrected(const XY& xy) const;
};
//! \brief Predefined ColorGamut%s for Hue API
namespace gamut
{
//! \brief Gamut A, used by most Color Lights
constexpr ColorGamut gamutA {{0.704f, 0.296f}, {0.2151f, 0.7106f}, {0.138f, 0.08f}};
//! \brief Gamut B, used by older Extended Color Lights
constexpr ColorGamut gamutB {{0.675f, 0.322f}, {0.409f, 0.518f}, {0.167f, 0.04f}};
//! \brief Gamut C, used by newer Extended Color Lights
constexpr ColorGamut gamutC {{0.692f, 0.308f}, {0.17f, 0.7f}, {0.153f, 0.048f}};
//! \brief Maximal gamut to be used when unknown
//!
//! \note Most of this triangle is outside of visible colors.
constexpr ColorGamut maxGamut {{1.f, 0.f}, {0.f, 1.f}, {0.f, 0.f}};
} // namespace gamut
//! \brief Color in RGB
struct RGB
{
//! \brief Red amount from 0 to 255
uint8_t r;
//! \brief Green amount from 0 to 255
uint8_t g;
//! \brief Blue amount from 0 to 255
uint8_t b;
bool operator==(const RGB& other) const { return r == other.r && g == other.g && b == other.b; }
bool operator!=(const RGB& other) const { return !(*this == other); }
//! \brief Convert to XYBrightness without clamping
//!
//! Performs gamma correction so the light color matches the screen color better.
XYBrightness toXY() const;
//! \brief Convert to XYBrightness and clip to \c gamut
//!
//! Performs gamma correction so the light color matches the screen color better.
XYBrightness toXY(const ColorGamut& gamut) const;
//! \brief Convert to HueSaturation
//!
//! To get the correct color, set brightness to max(r,g,b).
HueSaturation toHueSaturation() const;
//! \brief Create from XYBrightness
//!
//! Performs gamma correction so the light color matches the screen color better.
//! \note The conversion formula is not exact, it can be off by up to 9 for each channel.
//! This is because the color luminosity is not saved.
static RGB fromXY(const XYBrightness& xy);
//! \brief Create from XYBrightness and clip to \c gamut
//!
//! A light may have XY set out of its range. Then this function returns the actual color
//! the light shows rather than what it is set to.
//! Performs gamma correction so the light color matches the screen color better.
//! \note The conversion formula is not exact, it can be off by up to 9 for each channel.
//! This is because the color luminosity is not saved.
static RGB fromXY(const XYBrightness& xy, const ColorGamut& gamut);
};
//! \brief Const function that converts Kelvin to Mired.
//!
//! \param kelvin Unsigned integer value in Kelvin
//! \return Unsigned integer value in Mired
unsigned int kelvinToMired(unsigned int kelvin);
//! \brief Const function that converts Mired to Kelvin.
//!
//! \param mired Unsigned integer value in Mired
//! \return Unsigned integer value in Kelvin
unsigned int miredToKelvin(unsigned int mired);
} // namespace hueplusplus
#endif

Some files were not shown because too many files have changed in this diff Show More