diff --git a/Controllers/PhilipsHueController/PhilipsHueEntertainmentController.cpp b/Controllers/PhilipsHueController/PhilipsHueEntertainmentController.cpp index 02597d626..a88108d12 100644 --- a/Controllers/PhilipsHueController/PhilipsHueEntertainmentController.cpp +++ b/Controllers/PhilipsHueController/PhilipsHueEntertainmentController.cpp @@ -6,7 +6,7 @@ #include "PhilipsHueEntertainmentController.h" -std::vector HexToBytes(const std::string& hex) +static std::vector HexToBytes(const std::string& hex) { std::vector bytes; @@ -22,127 +22,20 @@ std::vector HexToBytes(const std::string& hex) PhilipsHueEntertainmentController::PhilipsHueEntertainmentController(hueplusplus::Bridge& bridge_ptr, hueplusplus::Group& group_ptr):bridge(bridge_ptr),group(group_ptr) { - /*-------------------------------------------------*\ - | Signal the bridge to start streaming | - \*-------------------------------------------------*/ - bridge.StartStreaming(std::to_string(group.getId())); - /*-------------------------------------------------*\ | Fill in location string with bridge IP | \*-------------------------------------------------*/ location = "IP: " + bridge.getBridgeIP(); - - /*-------------------------------------------------*\ - | Get the number of lights from the group | - \*-------------------------------------------------*/ num_leds = group.getLightIds().size(); /*-------------------------------------------------*\ - | Create Entertainment Mode message buffer | + | Create Entertainment Mode from bridge and group | \*-------------------------------------------------*/ - entertainment_msg_size = HUE_ENTERTAINMENT_HEADER_SIZE + (num_leds * HUE_ENTERTAINMENT_LIGHT_SIZE); - entertainment_msg = new unsigned char[entertainment_msg_size]; - - /*-------------------------------------------------*\ - | Fill in Entertainment Mode message header | - \*-------------------------------------------------*/ - memcpy(entertainment_msg, "HueStream", 9); - entertainment_msg[9] = 0x01; // Version Major (1) - entertainment_msg[10] = 0x00; // Version Minor (0) - entertainment_msg[11] = 0x00; // Sequence ID - entertainment_msg[12] = 0x00; // Reserved - entertainment_msg[13] = 0x00; // Reserved - entertainment_msg[14] = 0x00; // Color Space (RGB) - entertainment_msg[15] = 0x00; // Reserved - - /*-------------------------------------------------*\ - | Fill in Entertainment Mode light data | - \*-------------------------------------------------*/ - for(unsigned int light_idx = 0; light_idx < num_leds; light_idx++) - { - unsigned int msg_idx = HUE_ENTERTAINMENT_HEADER_SIZE + (light_idx * HUE_ENTERTAINMENT_LIGHT_SIZE); - - entertainment_msg[msg_idx + 0] = 0x00; // Type (Light) - entertainment_msg[msg_idx + 1] = group.getLightIds()[light_idx] >> 8; // ID MSB - entertainment_msg[msg_idx + 2] = group.getLightIds()[light_idx] & 0xFF; // ID LSB - entertainment_msg[msg_idx + 3] = 0x00; // Red MSB - entertainment_msg[msg_idx + 4] = 0x00; // Red LSB; - entertainment_msg[msg_idx + 5] = 0x00; // Green MSB; - entertainment_msg[msg_idx + 6] = 0x00; // Green LSB; - entertainment_msg[msg_idx + 7] = 0x00; // Blue MSB; - entertainment_msg[msg_idx + 8] = 0x00; // Blue LSB; - } - - /*-------------------------------------------------*\ - | Initialize mbedtls contexts | - \*-------------------------------------------------*/ - mbedtls_net_init(&server_fd); - mbedtls_ssl_init(&ssl); - mbedtls_ssl_config_init(&conf); - mbedtls_x509_crt_init(&cacert); - mbedtls_ctr_drbg_init(&ctr_drbg); - mbedtls_entropy_init( &entropy ); - - /*-------------------------------------------------*\ - | Seed the Deterministic Random Bit Generator (RNG) | - \*-------------------------------------------------*/ - int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); - - /*-------------------------------------------------*\ - | Parse certificate | - \*-------------------------------------------------*/ - ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_cas_pem, mbedtls_test_cas_pem_len ); - - /*-------------------------------------------------*\ - | Connect to the Hue bridge UDP server | - \*-------------------------------------------------*/ - ret = mbedtls_net_connect( &server_fd, bridge.getBridgeIP().c_str(), "2100", MBEDTLS_NET_PROTO_UDP ); - - /*-------------------------------------------------*\ - | Configure defaults | - \*-------------------------------------------------*/ - ret = mbedtls_ssl_config_defaults( &conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT ); - - mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); - mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL ); - mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); - - /*-------------------------------------------------*\ - | Convert client key to binary array | - \*-------------------------------------------------*/ - std::vector psk_binary = HexToBytes(bridge.getClientKey()); - - /*-------------------------------------------------*\ - | Configure SSL pre-shared key and identity | - | PSK - binary array from client key | - | Identity - username (ASCII) | - \*-------------------------------------------------*/ - ret = mbedtls_ssl_conf_psk(&conf, (const unsigned char *)&psk_binary[0], psk_binary.size(), (const unsigned char *)bridge.getUsername().c_str(), bridge.getUsername().length()); - - /*-------------------------------------------------*\ - | Set up the SSL | - \*-------------------------------------------------*/ - ret = mbedtls_ssl_setup( &ssl, &conf ); - - ret = mbedtls_ssl_set_hostname( &ssl, "localhost" ); - - mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout ); - mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay ); - - do - { - ret = mbedtls_ssl_handshake( &ssl ); - } while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ); + entertainment = new hueplusplus::EntertainmentMode(bridge, group); } PhilipsHueEntertainmentController::~PhilipsHueEntertainmentController() { - mbedtls_ssl_close_notify(&ssl); - - /*-------------------------------------------------*\ - | Signal the bridge to stop streaming | - \*-------------------------------------------------*/ - bridge.StopStreaming(std::to_string(group.getId())); } std::string PhilipsHueEntertainmentController::GetLocation() @@ -182,20 +75,13 @@ void PhilipsHueEntertainmentController::SetColor(RGBColor* colors) \*-------------------------------------------------*/ for(unsigned int light_idx = 0; light_idx < num_leds; light_idx++) { - unsigned int msg_idx = HUE_ENTERTAINMENT_HEADER_SIZE + (light_idx * HUE_ENTERTAINMENT_LIGHT_SIZE); - RGBColor color = colors[light_idx]; unsigned char red = RGBGetRValue(color); unsigned char green = RGBGetGValue(color); unsigned char blue = RGBGetBValue(color); - entertainment_msg[msg_idx + 3] = red; // Red MSB - entertainment_msg[msg_idx + 4] = red; // Red LSB; - entertainment_msg[msg_idx + 5] = green; // Green MSB; - entertainment_msg[msg_idx + 6] = green; // Green LSB; - entertainment_msg[msg_idx + 7] = blue; // Blue MSB; - entertainment_msg[msg_idx + 8] = blue; // Blue LSB; + entertainment->SetColorRGB(light_idx, red, green, blue); } - mbedtls_ssl_write(&ssl, (const unsigned char *)entertainment_msg, entertainment_msg_size); + entertainment->Update(); } diff --git a/Controllers/PhilipsHueController/PhilipsHueEntertainmentController.h b/Controllers/PhilipsHueController/PhilipsHueEntertainmentController.h index ee7e12c9f..6289c02db 100644 --- a/Controllers/PhilipsHueController/PhilipsHueEntertainmentController.h +++ b/Controllers/PhilipsHueController/PhilipsHueEntertainmentController.h @@ -6,17 +6,9 @@ #include "RGBController.h" #include "Bridge.h" +#include "EntertainmentMode.h" #include "Group.h" -#include "mbedtls/ssl.h" -#include "mbedtls/net_sockets.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/error.h" -#include "mbedtls/certs.h" -#include "mbedtls/debug.h" -#include "mbedtls/timing.h" - #include #include @@ -43,16 +35,8 @@ public: private: hueplusplus::Bridge& bridge; hueplusplus::Group& group; - std::string location; - unsigned char* entertainment_msg; - unsigned int entertainment_msg_size; - unsigned int num_leds; + hueplusplus::EntertainmentMode* entertainment; - mbedtls_ssl_context ssl; - mbedtls_net_context server_fd; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_ssl_config conf; - mbedtls_x509_crt cacert; - mbedtls_timing_delay_context timer; + std::string location; + unsigned int num_leds; }; diff --git a/OpenRGB.pro b/OpenRGB.pro index e99af278e..b21c8bc2a 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -280,6 +280,7 @@ SOURCES += dependencies/hueplusplus/src/BridgeConfig.cpp \ dependencies/hueplusplus/src/CLIPSensors.cpp \ dependencies/hueplusplus/src/ColorUnits.cpp \ + dependencies/hueplusplus/src/EntertainmentMode.cpp \ dependencies/hueplusplus/src/ExtendedColorHueStrategy.cpp \ dependencies/hueplusplus/src/ExtendedColorTemperatureStrategy.cpp \ dependencies/hueplusplus/src/Group.cpp \ diff --git a/dependencies/hueplusplus/include/hueplusplus/EntertainmentMode.h b/dependencies/hueplusplus/include/hueplusplus/EntertainmentMode.h new file mode 100644 index 000000000..3e4fe052a --- /dev/null +++ b/dependencies/hueplusplus/include/hueplusplus/EntertainmentMode.h @@ -0,0 +1,75 @@ +/** + \file EntertainmentMode.h + Copyright Notice\n + Copyright (C) 2020 Adam Honse - developer\n + + This file is part of hueplusplus. + + hueplusplus is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hueplusplus is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with hueplusplus. If not, see . +**/ + +#ifndef INCLUDE_HUEPLUSPLUS_HUE_ENTERTAINMENT_MODE_H +#define INCLUDE_HUEPLUSPLUS_HUE_ENTERTAINMENT_MODE_H + +#include "Bridge.h" +#include "Group.h" + +#include "mbedtls/ssl.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/error.h" +#include "mbedtls/certs.h" +#include "mbedtls/debug.h" +#include "mbedtls/timing.h" + +#define HUE_ENTERTAINMENT_HEADER_SIZE 16 +#define HUE_ENTERTAINMENT_LIGHT_SIZE 9 + +namespace hueplusplus +{ +//! \brief Class for Hue Entertainment Mode +//! +//! Provides methods to initialize and control Entertainment groups. +class EntertainmentMode +{ +public: + EntertainmentMode(Bridge& bridge, Group& group); + + bool Connect(); + bool Disconnect(); + + bool SetColorRGB(unsigned int light_index, unsigned char red, unsigned char green, unsigned char blue); + + void Update(); + +protected: + Bridge& bridge; + Group& group; + + unsigned char* entertainment_msg; //!< buffer containing the entertainment mode packet data + unsigned int entertainment_msg_size; //!< size of the entertainment mode buffer + unsigned int entertainment_num_lights; //!< number of lights in entertainment mode group + + mbedtls_ssl_context ssl; + mbedtls_net_context server_fd; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_config conf; + mbedtls_x509_crt cacert; + mbedtls_timing_delay_context timer; +}; +} // namespace hueplusplus + +#endif diff --git a/dependencies/hueplusplus/src/EntertainmentMode.cpp b/dependencies/hueplusplus/src/EntertainmentMode.cpp new file mode 100644 index 000000000..228c2ac7f --- /dev/null +++ b/dependencies/hueplusplus/src/EntertainmentMode.cpp @@ -0,0 +1,170 @@ +/** + \file EntertainmentMode.cpp + Copyright Notice\n + Copyright (C) 2020 Adam Honse - developer\n + + This file is part of hueplusplus. + + hueplusplus is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hueplusplus is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with hueplusplus. If not, see . +**/ + +#include "hueplusplus/EntertainmentMode.h" + +std::vector HexToBytes(const std::string& hex) +{ + std::vector bytes; + + for (unsigned int i = 0; i < hex.length(); i += 2) + { + std::string byteString = hex.substr(i, 2); + char byte = (char) strtol(byteString.c_str(), NULL, 16); + bytes.push_back(byte); + } + + return bytes; +} + +namespace hueplusplus +{ +EntertainmentMode::EntertainmentMode(Bridge& bridge, Group& group):bridge(bridge),group(group) +{ + /*-------------------------------------------------*\ + | Signal the bridge to start streaming | + \*-------------------------------------------------*/ + bridge.StartStreaming(std::to_string(group.getId())); + + /*-------------------------------------------------*\ + | Get the number of lights from the group | + \*-------------------------------------------------*/ + entertainment_num_lights = group.getLightIds().size(); + + /*-------------------------------------------------*\ + | Create Entertainment Mode message buffer | + \*-------------------------------------------------*/ + entertainment_msg_size = HUE_ENTERTAINMENT_HEADER_SIZE + (entertainment_num_lights * HUE_ENTERTAINMENT_LIGHT_SIZE); + entertainment_msg = new unsigned char[entertainment_msg_size]; + + /*-------------------------------------------------*\ + | Fill in Entertainment Mode message header | + \*-------------------------------------------------*/ + memcpy(entertainment_msg, "HueStream", 9); + entertainment_msg[9] = 0x01; // Version Major (1) + entertainment_msg[10] = 0x00; // Version Minor (0) + entertainment_msg[11] = 0x00; // Sequence ID + entertainment_msg[12] = 0x00; // Reserved + entertainment_msg[13] = 0x00; // Reserved + entertainment_msg[14] = 0x00; // Color Space (RGB) + entertainment_msg[15] = 0x00; // Reserved + + /*-------------------------------------------------*\ + | Fill in Entertainment Mode light data | + \*-------------------------------------------------*/ + for (unsigned int light_idx = 0; light_idx < entertainment_num_lights; light_idx++) + { + unsigned int msg_idx = HUE_ENTERTAINMENT_HEADER_SIZE + (light_idx * HUE_ENTERTAINMENT_LIGHT_SIZE); + + entertainment_msg[msg_idx + 0] = 0x00; // Type (Light) + entertainment_msg[msg_idx + 1] = group.getLightIds()[light_idx] >> 8; // ID MSB + entertainment_msg[msg_idx + 2] = group.getLightIds()[light_idx] & 0xFF; // ID LSB + entertainment_msg[msg_idx + 3] = 0x00; // Red MSB + entertainment_msg[msg_idx + 4] = 0x00; // Red LSB; + entertainment_msg[msg_idx + 5] = 0x00; // Green MSB; + entertainment_msg[msg_idx + 6] = 0x00; // Green LSB; + entertainment_msg[msg_idx + 7] = 0x00; // Blue MSB; + entertainment_msg[msg_idx + 8] = 0x00; // Blue LSB; + } + + /*-------------------------------------------------*\ + | Initialize mbedtls contexts | + \*-------------------------------------------------*/ + mbedtls_net_init(&server_fd); + mbedtls_ssl_init(&ssl); + mbedtls_ssl_config_init(&conf); + mbedtls_x509_crt_init(&cacert); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + + /*-------------------------------------------------*\ + | Seed the Deterministic Random Bit Generator (RNG) | + \*-------------------------------------------------*/ + int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); + + /*-------------------------------------------------*\ + | Parse certificate | + \*-------------------------------------------------*/ + ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char*)mbedtls_test_cas_pem, mbedtls_test_cas_pem_len); + + /*-------------------------------------------------*\ + | Connect to the Hue bridge UDP server | + \*-------------------------------------------------*/ + ret = mbedtls_net_connect(&server_fd, bridge.getBridgeIP().c_str(), "2100", MBEDTLS_NET_PROTO_UDP); + + /*-------------------------------------------------*\ + | Configure defaults | + \*-------------------------------------------------*/ + ret = mbedtls_ssl_config_defaults( + &conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); + + mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); + mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); + + /*-------------------------------------------------*\ + | Convert client key to binary array | + \*-------------------------------------------------*/ + std::vector psk_binary = HexToBytes(bridge.getClientKey()); + + /*-------------------------------------------------*\ + | Configure SSL pre-shared key and identity | + | PSK - binary array from client key | + | Identity - username (ASCII) | + \*-------------------------------------------------*/ + ret = mbedtls_ssl_conf_psk(&conf, (const unsigned char*)&psk_binary[0], psk_binary.size(), + (const unsigned char*)bridge.getUsername().c_str(), bridge.getUsername().length()); + + /*-------------------------------------------------*\ + | Set up the SSL | + \*-------------------------------------------------*/ + ret = mbedtls_ssl_setup(&ssl, &conf); + + ret = mbedtls_ssl_set_hostname(&ssl, "localhost"); + + mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout); + mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay); + + do + { + ret = mbedtls_ssl_handshake(&ssl); + } while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE); +} + +bool EntertainmentMode::SetColorRGB(unsigned int light_index, unsigned char red, unsigned char green, unsigned char blue) +{ + unsigned int msg_idx = HUE_ENTERTAINMENT_HEADER_SIZE + (light_index * HUE_ENTERTAINMENT_LIGHT_SIZE); + + entertainment_msg[msg_idx + 3] = red; // Red MSB + entertainment_msg[msg_idx + 4] = red; // Red LSB; + entertainment_msg[msg_idx + 5] = green; // Green MSB; + entertainment_msg[msg_idx + 6] = green; // Green LSB; + entertainment_msg[msg_idx + 7] = blue; // Blue MSB; + entertainment_msg[msg_idx + 8] = blue; // Blue LSB; + + return false; +} + +void EntertainmentMode::Update() +{ + mbedtls_ssl_write(&ssl, (const unsigned char*)entertainment_msg, entertainment_msg_size); +} +} // namespace hueplusplus