Commit 3321666f2f0e58d15448a92ea90b3a5007d1f623

Authored by Adam Honse
Committed by Moritz Wirger
1 parent 5212c084

Add initial files for Entertainment Mode support

include/hueplusplus/EntertainmentMode.h 0 → 100644
  1 +/**
  2 + \file EntertainmentMode.h
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Adam Honse - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#ifndef INCLUDE_HUEPLUSPLUS_HUE_ENTERTAINMENT_MODE_H
  23 +#define INCLUDE_HUEPLUSPLUS_HUE_ENTERTAINMENT_MODE_H
  24 +
  25 +#include "Bridge.h"
  26 +#include "Group.h"
  27 +
  28 +#include "mbedtls/ssl.h"
  29 +#include "mbedtls/net_sockets.h"
  30 +#include "mbedtls/entropy.h"
  31 +#include "mbedtls/ctr_drbg.h"
  32 +#include "mbedtls/error.h"
  33 +#include "mbedtls/certs.h"
  34 +#include "mbedtls/debug.h"
  35 +#include "mbedtls/timing.h"
  36 +
  37 +#define HUE_ENTERTAINMENT_HEADER_SIZE 16
  38 +#define HUE_ENTERTAINMENT_LIGHT_SIZE 9
  39 +
  40 +namespace hueplusplus
  41 +{
  42 +//! \brief Class for Hue Entertainment Mode
  43 +//!
  44 +//! Provides methods to initialize and control Entertainment groups.
  45 +class EntertainmentMode
  46 +{
  47 +public:
  48 + EntertainmentMode(Bridge& bridge, Group& group);
  49 +
  50 + bool Connect();
  51 + bool Disconnect();
  52 +
  53 + bool SetColorRGB(unsigned int light_index, unsigned char red, unsigned char green, unsigned char blue);
  54 +
  55 + void Update();
  56 +
  57 +protected:
  58 + Bridge& bridge;
  59 + Group& group;
  60 +
  61 + unsigned char* entertainment_msg; //!< buffer containing the entertainment mode packet data
  62 + unsigned int entertainment_msg_size; //!< size of the entertainment mode buffer
  63 + unsigned int entertainment_num_lights; //!< number of lights in entertainment mode group
  64 +
  65 + mbedtls_ssl_context ssl;
  66 + mbedtls_net_context server_fd;
  67 + mbedtls_entropy_context entropy;
  68 + mbedtls_ctr_drbg_context ctr_drbg;
  69 + mbedtls_ssl_config conf;
  70 + mbedtls_x509_crt cacert;
  71 + mbedtls_timing_delay_context timer;
  72 +};
  73 +} // namespace hueplusplus
  74 +
  75 +#endif
... ...
src/EntertainmentMode.cpp 0 → 100644
  1 +/**
  2 + \file EntertainmentMode.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2020 Adam Honse - developer\n
  5 +
  6 + This file is part of hueplusplus.
  7 +
  8 + hueplusplus is free software: you can redistribute it and/or modify
  9 + it under the terms of the GNU Lesser General Public License as published by
  10 + the Free Software Foundation, either version 3 of the License, or
  11 + (at your option) any later version.
  12 +
  13 + hueplusplus is distributed in the hope that it will be useful,
  14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + GNU Lesser General Public License for more details.
  17 +
  18 + You should have received a copy of the GNU Lesser General Public License
  19 + along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
  20 +**/
  21 +
  22 +#include "hueplusplus/EntertainmentMode.h"
  23 +
  24 +std::vector<char> HexToBytes(const std::string& hex)
  25 +{
  26 + std::vector<char> bytes;
  27 +
  28 + for (unsigned int i = 0; i < hex.length(); i += 2)
  29 + {
  30 + std::string byteString = hex.substr(i, 2);
  31 + char byte = (char) strtol(byteString.c_str(), NULL, 16);
  32 + bytes.push_back(byte);
  33 + }
  34 +
  35 + return bytes;
  36 +}
  37 +
  38 +namespace hueplusplus
  39 +{
  40 +EntertainmentMode::EntertainmentMode(Bridge& bridge, Group& group):bridge(bridge),group(group)
  41 +{
  42 + /*-------------------------------------------------*\
  43 + | Signal the bridge to start streaming |
  44 + \*-------------------------------------------------*/
  45 + bridge.StartStreaming(std::to_string(group.getId()));
  46 +
  47 + /*-------------------------------------------------*\
  48 + | Get the number of lights from the group |
  49 + \*-------------------------------------------------*/
  50 + entertainment_num_lights = group.getLightIds().size();
  51 +
  52 + /*-------------------------------------------------*\
  53 + | Create Entertainment Mode message buffer |
  54 + \*-------------------------------------------------*/
  55 + entertainment_msg_size = HUE_ENTERTAINMENT_HEADER_SIZE + (entertainment_num_lights * HUE_ENTERTAINMENT_LIGHT_SIZE);
  56 + entertainment_msg = new unsigned char[entertainment_msg_size];
  57 +
  58 + /*-------------------------------------------------*\
  59 + | Fill in Entertainment Mode message header |
  60 + \*-------------------------------------------------*/
  61 + memcpy(entertainment_msg, "HueStream", 9);
  62 + entertainment_msg[9] = 0x01; // Version Major (1)
  63 + entertainment_msg[10] = 0x00; // Version Minor (0)
  64 + entertainment_msg[11] = 0x00; // Sequence ID
  65 + entertainment_msg[12] = 0x00; // Reserved
  66 + entertainment_msg[13] = 0x00; // Reserved
  67 + entertainment_msg[14] = 0x00; // Color Space (RGB)
  68 + entertainment_msg[15] = 0x00; // Reserved
  69 +
  70 + /*-------------------------------------------------*\
  71 + | Fill in Entertainment Mode light data |
  72 + \*-------------------------------------------------*/
  73 + for (unsigned int light_idx = 0; light_idx < entertainment_num_lights; light_idx++)
  74 + {
  75 + unsigned int msg_idx = HUE_ENTERTAINMENT_HEADER_SIZE + (light_idx * HUE_ENTERTAINMENT_LIGHT_SIZE);
  76 +
  77 + entertainment_msg[msg_idx + 0] = 0x00; // Type (Light)
  78 + entertainment_msg[msg_idx + 1] = group.getLightIds()[light_idx] >> 8; // ID MSB
  79 + entertainment_msg[msg_idx + 2] = group.getLightIds()[light_idx] & 0xFF; // ID LSB
  80 + entertainment_msg[msg_idx + 3] = 0x00; // Red MSB
  81 + entertainment_msg[msg_idx + 4] = 0x00; // Red LSB;
  82 + entertainment_msg[msg_idx + 5] = 0x00; // Green MSB;
  83 + entertainment_msg[msg_idx + 6] = 0x00; // Green LSB;
  84 + entertainment_msg[msg_idx + 7] = 0x00; // Blue MSB;
  85 + entertainment_msg[msg_idx + 8] = 0x00; // Blue LSB;
  86 + }
  87 +
  88 + /*-------------------------------------------------*\
  89 + | Initialize mbedtls contexts |
  90 + \*-------------------------------------------------*/
  91 + mbedtls_net_init(&server_fd);
  92 + mbedtls_ssl_init(&ssl);
  93 + mbedtls_ssl_config_init(&conf);
  94 + mbedtls_x509_crt_init(&cacert);
  95 + mbedtls_ctr_drbg_init(&ctr_drbg);
  96 + mbedtls_entropy_init(&entropy);
  97 +
  98 + /*-------------------------------------------------*\
  99 + | Seed the Deterministic Random Bit Generator (RNG) |
  100 + \*-------------------------------------------------*/
  101 + int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
  102 +
  103 + /*-------------------------------------------------*\
  104 + | Parse certificate |
  105 + \*-------------------------------------------------*/
  106 + ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char*)mbedtls_test_cas_pem, mbedtls_test_cas_pem_len);
  107 +
  108 + /*-------------------------------------------------*\
  109 + | Connect to the Hue bridge UDP server |
  110 + \*-------------------------------------------------*/
  111 + ret = mbedtls_net_connect(&server_fd, bridge.getBridgeIP().c_str(), "2100", MBEDTLS_NET_PROTO_UDP);
  112 +
  113 + /*-------------------------------------------------*\
  114 + | Configure defaults |
  115 + \*-------------------------------------------------*/
  116 + ret = mbedtls_ssl_config_defaults(
  117 + &conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT);
  118 +
  119 + mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
  120 + mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
  121 + mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
  122 +
  123 + /*-------------------------------------------------*\
  124 + | Convert client key to binary array |
  125 + \*-------------------------------------------------*/
  126 + std::vector<char> psk_binary = HexToBytes(bridge.getClientKey());
  127 +
  128 + /*-------------------------------------------------*\
  129 + | Configure SSL pre-shared key and identity |
  130 + | PSK - binary array from client key |
  131 + | Identity - username (ASCII) |
  132 + \*-------------------------------------------------*/
  133 + ret = mbedtls_ssl_conf_psk(&conf, (const unsigned char*)&psk_binary[0], psk_binary.size(),
  134 + (const unsigned char*)bridge.getUsername().c_str(), bridge.getUsername().length());
  135 +
  136 + /*-------------------------------------------------*\
  137 + | Set up the SSL |
  138 + \*-------------------------------------------------*/
  139 + ret = mbedtls_ssl_setup(&ssl, &conf);
  140 +
  141 + ret = mbedtls_ssl_set_hostname(&ssl, "localhost");
  142 +
  143 + mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
  144 + mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
  145 +
  146 + do
  147 + {
  148 + ret = mbedtls_ssl_handshake(&ssl);
  149 + } while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE);
  150 +}
  151 +
  152 +bool EntertainmentMode::SetColorRGB(unsigned int light_index, unsigned char red, unsigned char green, unsigned char blue)
  153 +{
  154 + unsigned int msg_idx = HUE_ENTERTAINMENT_HEADER_SIZE + (light_index * HUE_ENTERTAINMENT_LIGHT_SIZE);
  155 +
  156 + entertainment_msg[msg_idx + 3] = red; // Red MSB
  157 + entertainment_msg[msg_idx + 4] = red; // Red LSB;
  158 + entertainment_msg[msg_idx + 5] = green; // Green MSB;
  159 + entertainment_msg[msg_idx + 6] = green; // Green LSB;
  160 + entertainment_msg[msg_idx + 7] = blue; // Blue MSB;
  161 + entertainment_msg[msg_idx + 8] = blue; // Blue LSB;
  162 +
  163 + return false;
  164 +}
  165 +
  166 +void EntertainmentMode::Update()
  167 +{
  168 + mbedtls_ssl_write(&ssl, (const unsigned char*)entertainment_msg, entertainment_msg_size);
  169 +}
  170 +} // namespace hueplusplus
... ...