mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2025-12-24 07:47:49 -05:00
481 lines
16 KiB
C++
481 lines
16 KiB
C++
/*---------------------------------------------------------*\
|
|
| LIFXController.cpp |
|
|
| |
|
|
| Driver for LIFX |
|
|
| |
|
|
| Adam Honse (calcprogrammer1@gmail.com) 05 Feb 2022 |
|
|
| |
|
|
| This file is part of the OpenRGB project |
|
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
|
\*---------------------------------------------------------*/
|
|
|
|
#include "LIFXController.h"
|
|
#include <nlohmann/json.hpp>
|
|
#include "hsv.h"
|
|
|
|
using json = nlohmann::json;
|
|
using namespace std::chrono_literals;
|
|
|
|
LIFXController::LIFXController(std::string ip, std::string name, bool multizone, bool extended_multizone)
|
|
{
|
|
this->name = name;
|
|
zone_count = 1;
|
|
this->multizone = multizone;
|
|
this->extended_multizone = extended_multizone;
|
|
|
|
/*-----------------------------------------------------------------*\
|
|
| Fill in location string with device's IP address |
|
|
\*-----------------------------------------------------------------*/
|
|
location = "IP: " + ip;
|
|
|
|
/*-----------------------------------------------------------------*\
|
|
| Open a UDP client sending to the device's IP, port 56700 |
|
|
\*-----------------------------------------------------------------*/
|
|
port.udp_client(ip.c_str(), LIFX_UDP_PORT);
|
|
}
|
|
|
|
LIFXController::~LIFXController()
|
|
{
|
|
|
|
}
|
|
|
|
std::string LIFXController::GetLocation()
|
|
{
|
|
return(location);
|
|
}
|
|
|
|
std::string LIFXController::GetName()
|
|
{
|
|
return(name);
|
|
}
|
|
|
|
std::string LIFXController::GetVersion()
|
|
{
|
|
return(module_name + " " + firmware_version);
|
|
}
|
|
|
|
std::string LIFXController::GetManufacturer()
|
|
{
|
|
return(LIFX_MANUFACTURER);
|
|
}
|
|
|
|
std::string LIFXController::GetUniqueID()
|
|
{
|
|
return(module_mac);
|
|
}
|
|
|
|
unsigned int LIFXController::GetZoneCount()
|
|
{
|
|
return(zone_count);
|
|
}
|
|
|
|
void LIFXController::SetColors(std::vector<RGBColor> colors)
|
|
{
|
|
/*-------------------------*\
|
|
| Non-multizone lifx device |
|
|
\*-------------------------*/
|
|
if(!multizone)
|
|
{
|
|
SetColor(colors[0]);
|
|
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------*\
|
|
| Multizone lifx device with extended support |
|
|
\*-------------------------------------------*/
|
|
if(extended_multizone)
|
|
{
|
|
SetZoneColors(colors);
|
|
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------*\
|
|
| Multizone lifx device without extended support |
|
|
\*----------------------------------------------*/
|
|
for(size_t i = 0; i < zone_count; i++)
|
|
{
|
|
/*-----------------------------------------------------------------*\
|
|
| Utilize caching to avoid setting all zones when 1 zone is changed |
|
|
\*-----------------------------------------------------------------*/
|
|
if(cached_colors[i] == colors[i])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
SetZoneColor(colors[i], (unsigned int)i);
|
|
cached_colors[i] = colors[i];
|
|
}
|
|
}
|
|
|
|
void LIFXController::FetchZoneCount()
|
|
{
|
|
if(!multizone)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*---------------------------*\
|
|
| Send get color zones packet |
|
|
\*---------------------------*/
|
|
data_buf_size = LIFX_PACKET_HEADER_LENGTH + LIFX_GET_COLOR_ZONES_PACKET_LENGTH;
|
|
data = new unsigned char[data_buf_size];
|
|
memset(data, 0, data_buf_size);
|
|
|
|
HeaderPacketSetDefaults(LIFX_PACKET_TYPE_GET_COLOR_ZONES);
|
|
|
|
GetColorZonesPacketSetStartIndex(0);
|
|
GetColorZonesPacketSetEndIndex(0);
|
|
|
|
port.udp_write((char*)data, (int)data_buf_size);
|
|
delete[] data;
|
|
|
|
/*----------------------------*\
|
|
| Listen for state zone packet |
|
|
\*----------------------------*/
|
|
data_buf_size = LIFX_PACKET_HEADER_LENGTH + LIFX_STATE_ZONE_PACKET_LENGTH;
|
|
data = new unsigned char[data_buf_size];
|
|
memset(data, 0, data_buf_size);
|
|
|
|
port.set_receive_timeout(5, 0);
|
|
port.udp_listen((char*)data, (int)data_buf_size);
|
|
|
|
/*-----------------*\
|
|
| Validate response |
|
|
\*-----------------*/
|
|
if(HeaderPacketGetSize() != data_buf_size || HeaderPacketGetProtocol() != LIFX_PROTOCOL || HeaderPacketGetPacketType() != LIFX_PACKET_TYPE_STATE_ZONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
zone_count = StateZonePacketGetZonesCount();
|
|
delete[] data;
|
|
}
|
|
|
|
void LIFXController::SetColor(RGBColor color)
|
|
{
|
|
/*---------------------*\
|
|
| Send set color packet |
|
|
\*---------------------*/
|
|
data_buf_size = LIFX_PACKET_HEADER_LENGTH + LIFX_SET_COLOR_PACKET_LENGTH;
|
|
data = new unsigned char[data_buf_size];
|
|
memset(data, 0, data_buf_size);
|
|
|
|
HeaderPacketSetDefaults(LIFX_PACKET_TYPE_SET_COLOR);
|
|
|
|
hsbk_t hsbk;
|
|
RGBColorToHSBK(color, &hsbk);
|
|
|
|
SetColorPacketSetHSBK(&hsbk);
|
|
SetColorPacketSetDuration(0);
|
|
|
|
port.udp_write((char*)data, (int)data_buf_size);
|
|
delete[] data;
|
|
}
|
|
|
|
void LIFXController::SetZoneColor(RGBColor color, unsigned int zone)
|
|
{
|
|
/*---------------------------*\
|
|
| Send set color zones packet |
|
|
\*---------------------------*/
|
|
data_buf_size = LIFX_PACKET_HEADER_LENGTH + LIFX_SET_COLOR_ZONES_PACKET_LENGTH;
|
|
data = new unsigned char[data_buf_size];
|
|
memset(data, 0, data_buf_size);
|
|
|
|
HeaderPacketSetDefaults(LIFX_PACKET_TYPE_SET_COLOR_ZONES);
|
|
|
|
SetColorZonesPacketSetStartIndex(zone);
|
|
SetColorZonesPacketSetEndIndex(zone);
|
|
|
|
hsbk_t hsbk;
|
|
RGBColorToHSBK(color, &hsbk);
|
|
|
|
SetColorZonesPacketSetHSBK(&hsbk);
|
|
SetColorZonesPacketSetDuration(0);
|
|
SetColorZonesPacketSetApply(LIFX_MULTIZONE_APPLICATION_REQUEST_APPLY);
|
|
|
|
port.udp_write((char*)data, (int)data_buf_size);
|
|
delete[] data;
|
|
}
|
|
|
|
void LIFXController::SetZoneColors(std::vector<RGBColor> colors)
|
|
{
|
|
/*------------------------------------*\
|
|
| Send set extended color zones packet |
|
|
\*------------------------------------*/
|
|
data_buf_size = LIFX_PACKET_HEADER_LENGTH + LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_LENGTH;
|
|
data = new unsigned char[data_buf_size];
|
|
memset(data, 0, data_buf_size);
|
|
|
|
HeaderPacketSetDefaults(LIFX_PACKET_TYPE_SET_EXTENDED_COLOR_ZONES);
|
|
|
|
SetExtendedColorZonesPacketSetDuration(0);
|
|
SetExtendedColorZonesPacketSetApply(LIFX_MULTIZONE_APPLICATION_REQUEST_APPLY);
|
|
SetExtendedColorZonesPacketSetZoneIndex(0);
|
|
SetExtendedColorZonesPacketSetColors(colors);
|
|
|
|
port.udp_write((char*)data, (int)data_buf_size);
|
|
delete[] data;
|
|
}
|
|
|
|
void LIFXController::RGBColorToHSBK(RGBColor color, hsbk_t* hsbk)
|
|
{
|
|
hsv_t hsv;
|
|
rgb2hsv(color, &hsv);
|
|
|
|
hsbk->hue = hsv.hue * (USHRT_MAX/360);
|
|
hsbk->saturation = hsv.saturation * (USHRT_MAX/256);
|
|
hsbk->brightness = hsv.value * (USHRT_MAX/256);
|
|
hsbk->kelvin = DEFAULT_KELVIN;
|
|
}
|
|
|
|
/*----------------------------*\
|
|
| Header packet helper methods |
|
|
\*----------------------------*/
|
|
void LIFXController::HeaderPacketSetDefaults(unsigned short packet_type)
|
|
{
|
|
/*-----*\
|
|
| Frame |
|
|
\*-----*/
|
|
HeaderPacketSetSize((unsigned short)data_buf_size);
|
|
HeaderPacketSetProtocol();
|
|
HeaderPacketSetAddressable(true);
|
|
HeaderPacketSetTagged(false);
|
|
HeaderPacketSetOrigin(0);
|
|
HeaderPacketSetSource(2);
|
|
|
|
/*-------------*\
|
|
| Frame address |
|
|
\*-------------*/
|
|
unsigned char target[TARGET_LENGTH] = {0};
|
|
HeaderPacketSetTarget(target);
|
|
HeaderPacketSetResponseRequired(false);
|
|
HeaderPacketSetAcknowledgeRequired(false);
|
|
HeaderPacketSetSequence(++sequence);
|
|
|
|
/*---------------*\
|
|
| Protocol header |
|
|
\*---------------*/
|
|
HeaderPacketSetPacketType(packet_type);
|
|
}
|
|
|
|
unsigned short LIFXController::HeaderPacketGetSize()
|
|
{
|
|
return data[LIFX_HEADER_PACKET_OFFSET_SIZE];
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetSize(unsigned short size)
|
|
{
|
|
memcpy(&data[LIFX_HEADER_PACKET_OFFSET_SIZE], &size, sizeof(unsigned short));
|
|
}
|
|
|
|
unsigned short LIFXController::HeaderPacketGetProtocol()
|
|
{
|
|
unsigned short protocol;
|
|
memcpy(&protocol, &data[LIFX_HEADER_PACKET_OFFSET_PROTOCOL], sizeof(unsigned short));
|
|
return protocol & 0x0FFF;
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetProtocol(unsigned short protocol)
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_PROTOCOL] = protocol & 0xFF;
|
|
unsigned char current = data[LIFX_HEADER_PACKET_OFFSET_ADDRESSABLE_TAGGED_ORIGIN];
|
|
data[LIFX_HEADER_PACKET_OFFSET_ADDRESSABLE_TAGGED_ORIGIN] = (current & 0xF0) | ((protocol >> 8) & 0x0F);
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetAddressable(bool addressable)
|
|
{
|
|
if(addressable)
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_ADDRESSABLE_TAGGED_ORIGIN] |= 0x10;
|
|
}
|
|
else
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_ADDRESSABLE_TAGGED_ORIGIN] &= ~0x10;
|
|
}
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetTagged(bool tagged)
|
|
{
|
|
if(tagged)
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_ADDRESSABLE_TAGGED_ORIGIN] |= 0x20;
|
|
}
|
|
else
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_ADDRESSABLE_TAGGED_ORIGIN] &= ~0x20;
|
|
}
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetOrigin(unsigned char origin)
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_ADDRESSABLE_TAGGED_ORIGIN] =
|
|
(data[LIFX_HEADER_PACKET_OFFSET_ADDRESSABLE_TAGGED_ORIGIN] & 0xFC) | (origin & 0x03);
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetSource(unsigned int source)
|
|
{
|
|
memcpy(&data[LIFX_HEADER_PACKET_OFFSET_SOURCE], &source, sizeof(unsigned int));
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetTarget(unsigned char* target)
|
|
{
|
|
memcpy(&data[LIFX_HEADER_PACKET_OFFSET_TARGET], target, TARGET_LENGTH);
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetResponseRequired(bool response_required)
|
|
{
|
|
if(response_required)
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_RESPONSE_REQUIRED_ACKNOWLEDGE_REQUIRED] |= 0x01;
|
|
}
|
|
else
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_RESPONSE_REQUIRED_ACKNOWLEDGE_REQUIRED] &= ~0x01;
|
|
}
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetAcknowledgeRequired(bool acknowledge_required)
|
|
{
|
|
if(acknowledge_required)
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_RESPONSE_REQUIRED_ACKNOWLEDGE_REQUIRED] |= 0x02;
|
|
}
|
|
else
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_RESPONSE_REQUIRED_ACKNOWLEDGE_REQUIRED] &= ~0x02;
|
|
}
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetSequence(unsigned char sequence)
|
|
{
|
|
data[LIFX_HEADER_PACKET_OFFSET_SEQUENCE] = sequence;
|
|
}
|
|
|
|
unsigned short LIFXController::HeaderPacketGetPacketType()
|
|
{
|
|
unsigned short packet_type_value;
|
|
memcpy(&packet_type_value, &data[LIFX_HEADER_PACKET_OFFSET_PACKET_TYPE], sizeof(unsigned short));
|
|
|
|
return packet_type_value;
|
|
}
|
|
|
|
void LIFXController::HeaderPacketSetPacketType(unsigned short packet_type)
|
|
{
|
|
memcpy(&data[LIFX_HEADER_PACKET_OFFSET_PACKET_TYPE], &packet_type, sizeof(unsigned short));
|
|
}
|
|
|
|
/*-------------------------------*\
|
|
| Set color packet helper methods |
|
|
\*-------------------------------*/
|
|
void LIFXController::SetColorPacketSetHSBK(hsbk_t* hsbk)
|
|
{
|
|
memcpy(&data[LIFX_SET_COLOR_PACKET_OFFSET_HUE], &hsbk->hue, sizeof(unsigned short));
|
|
memcpy(&data[LIFX_SET_COLOR_PACKET_OFFSET_SATURATION], &hsbk->saturation, sizeof(unsigned short));
|
|
memcpy(&data[LIFX_SET_COLOR_PACKET_OFFSET_BRIGHTNESS], &hsbk->brightness, sizeof(unsigned short));
|
|
memcpy(&data[LIFX_SET_COLOR_PACKET_OFFSET_KELVIN], &hsbk->kelvin, sizeof(unsigned short));
|
|
}
|
|
|
|
void LIFXController::SetColorPacketSetDuration(unsigned int duration)
|
|
{
|
|
memcpy(&data[LIFX_SET_COLOR_PACKET_OFFSET_DURATION], &duration, sizeof(unsigned int));
|
|
}
|
|
|
|
/*-------------------------------------*\
|
|
| Set color zones packet helper methods |
|
|
\*-------------------------------------*/
|
|
void LIFXController::SetColorZonesPacketSetStartIndex(unsigned char start_index)
|
|
{
|
|
memcpy(&data[LIFX_SET_COLOR_ZONES_PACKET_OFFSET_START_INDEX], &start_index, sizeof(unsigned char));
|
|
}
|
|
|
|
void LIFXController::SetColorZonesPacketSetEndIndex(unsigned char end_index)
|
|
{
|
|
memcpy(&data[LIFX_SET_COLOR_ZONES_PACKET_OFFSET_END_INDEX], &end_index, sizeof(unsigned char));
|
|
}
|
|
|
|
void LIFXController::SetColorZonesPacketSetHSBK(hsbk_t* hsbk)
|
|
{
|
|
memcpy(&data[LIFX_SET_COLOR_ZONES_PACKET_OFFSET_HUE], &hsbk->hue, sizeof(unsigned short));
|
|
memcpy(&data[LIFX_SET_COLOR_ZONES_PACKET_OFFSET_SATURATION], &hsbk->saturation, sizeof(unsigned short));
|
|
memcpy(&data[LIFX_SET_COLOR_ZONES_PACKET_OFFSET_BRIGHTNESS], &hsbk->brightness, sizeof(unsigned short));
|
|
memcpy(&data[LIFX_SET_COLOR_ZONES_PACKET_OFFSET_KELVIN], &hsbk->kelvin, sizeof(unsigned short));
|
|
}
|
|
|
|
void LIFXController::SetColorZonesPacketSetDuration(unsigned int duration)
|
|
{
|
|
memcpy(&data[LIFX_SET_COLOR_ZONES_PACKET_OFFSET_DURATION], &duration, sizeof(unsigned int));
|
|
}
|
|
|
|
void LIFXController::SetColorZonesPacketSetApply(unsigned char apply)
|
|
{
|
|
memcpy(&data[LIFX_SET_COLOR_ZONES_PACKET_OFFSET_APPLY], &apply, sizeof(unsigned char));
|
|
}
|
|
|
|
/*-------------------------------------*\
|
|
| Get color zones packet helper methods |
|
|
\*-------------------------------------*/
|
|
void LIFXController::GetColorZonesPacketSetStartIndex(unsigned char start_index)
|
|
{
|
|
memcpy(&data[LIFX_GET_COLOR_ZONES_PACKET_OFFSET_START_INDEX], &start_index, sizeof(unsigned char));
|
|
}
|
|
|
|
void LIFXController::GetColorZonesPacketSetEndIndex(unsigned char end_index)
|
|
{
|
|
memcpy(&data[LIFX_GET_COLOR_ZONES_PACKET_OFFSET_END_INDEX], &end_index, sizeof(unsigned char));
|
|
}
|
|
|
|
/*--------------------------------*\
|
|
| State zone packet helper methods |
|
|
\*--------------------------------*/
|
|
unsigned char LIFXController::StateZonePacketGetZonesCount()
|
|
{
|
|
unsigned char zones_count;
|
|
memcpy(&zones_count, &data[LIFX_STATE_ZONE_PACKET_OFFSET_ZONES_COUNT], sizeof(unsigned char));
|
|
|
|
return zones_count;
|
|
}
|
|
|
|
/*----------------------------------------------*\
|
|
| Set extended color zones packet helper methods |
|
|
\*----------------------------------------------*/
|
|
void LIFXController::SetExtendedColorZonesPacketSetDuration(unsigned int duration)
|
|
{
|
|
memcpy(&data[LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_DURATION], &duration, sizeof(unsigned int));
|
|
}
|
|
|
|
void LIFXController::SetExtendedColorZonesPacketSetApply(unsigned char apply)
|
|
{
|
|
memcpy(&data[LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_APPLY], &apply, sizeof(unsigned char));
|
|
}
|
|
|
|
void LIFXController::SetExtendedColorZonesPacketSetZoneIndex(unsigned short zone_index)
|
|
{
|
|
memcpy(&data[LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_ZONE_INDEX], &zone_index, sizeof(unsigned short));
|
|
}
|
|
|
|
void LIFXController::SetExtendedColorZonesPacketSetColors(std::vector<RGBColor> colors)
|
|
{
|
|
unsigned char colors_count = (unsigned char)colors.size();
|
|
memcpy(&data[LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_COLORS_COUNT], &colors_count, sizeof(unsigned char));
|
|
|
|
for(size_t i = 0; i < colors.size(); i++)
|
|
{
|
|
hsbk_t hsbk;
|
|
RGBColorToHSBK(colors[i], &hsbk);
|
|
|
|
size_t current_color_offset = LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_COLORS + (i * HSBK_LENGTH);
|
|
|
|
size_t hue_offset = current_color_offset;
|
|
size_t saturation_offset = hue_offset + sizeof(unsigned short);
|
|
size_t brightness_offset = saturation_offset + sizeof(unsigned short);
|
|
size_t kelvin_offset = brightness_offset + sizeof(unsigned short);
|
|
|
|
memcpy(&data[hue_offset], &hsbk.hue, sizeof(unsigned short));
|
|
memcpy(&data[saturation_offset], &hsbk.saturation, sizeof(unsigned short));
|
|
memcpy(&data[brightness_offset], &hsbk.brightness, sizeof(unsigned short));
|
|
memcpy(&data[kelvin_offset], &hsbk.kelvin, sizeof(unsigned short));
|
|
}
|
|
}
|