diff --git a/include/hueplusplus/EntertainmentMode.h b/include/hueplusplus/EntertainmentMode.h
new file mode 100644
index 0000000..3e4fe05
--- /dev/null
+++ b/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/src/EntertainmentMode.cpp b/src/EntertainmentMode.cpp
new file mode 100644
index 0000000..228c2ac
--- /dev/null
+++ b/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