/*---------------------------------------------------------*\ | LIFXController.h | | | | 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 | \*---------------------------------------------------------*/ #pragma once #include #include #include #include "RGBController.h" #include "net_port.h" #define LIFX_MANUFACTURER "LIFX" #define LIFX_UDP_PORT "56700" #define LIFX_PROTOCOL 1024 #define TARGET_LENGTH 8 #define DEFAULT_KELVIN 3500 #define HSBK_LENGTH 8 /*---------------------*\ | Packet size constants | \*---------------------*/ #define LIFX_PACKET_HEADER_LENGTH 36 #define LIFX_SET_COLOR_PACKET_LENGTH 13 #define LIFX_SET_COLOR_ZONES_PACKET_LENGTH 15 #define LIFX_GET_COLOR_ZONES_PACKET_LENGTH 2 #define LIFX_STATE_ZONE_PACKET_LENGTH 10 #define LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_LENGTH 664 /*---------------------------------------------------------------------------*\ | https://lan.developer.lifx.com/docs/field-types#multizoneapplicationrequest | \*---------------------------------------------------------------------------*/ enum { LIFX_MULTIZONE_APPLICATION_REQUEST_NO_APPLY = 0, LIFX_MULTIZONE_APPLICATION_REQUEST_APPLY = 1, LIFX_MULTIZONE_APPLICATION_REQUEST_APPLY_ONLY = 2 }; /*----------------------------------------------------------------*\ | https://lan.developer.lifx.com/docs/representing-color-with-hsbk | \*----------------------------------------------------------------*/ typedef struct { unsigned short hue; /* 0-360 value normalized to 0-65535 */ unsigned short saturation; /* 0-1 value normalized to 0-65535 */ unsigned short brightness; /* 0-1 value normalized to 0-65535 */ unsigned short kelvin; /* 0-65535 value */ /* Note: Devices may only support a subset of the full range. */ } hsbk_t; /*-----------------*\ | LIFX packet types | \*-----------------*/ enum { LIFX_PACKET_TYPE_SET_COLOR = 102, LIFX_PACKET_TYPE_SET_COLOR_ZONES = 501, LIFX_PACKET_TYPE_GET_COLOR_ZONES = 502, LIFX_PACKET_TYPE_STATE_ZONE = 503, LIFX_PACKET_TYPE_SET_EXTENDED_COLOR_ZONES = 510 }; /*-----------------------------------------------------*\ | LIFX header packet offsets | | https://lan.developer.lifx.com/docs/encoding-a-packet | \*-----------------------------------------------------*/ enum { LIFX_HEADER_PACKET_OFFSET_SIZE = 0, /* 2 bytes, size of the entire message in bytes */ LIFX_HEADER_PACKET_OFFSET_PROTOCOL = 2, /* Protocol number, must be 1024 */ LIFX_HEADER_PACKET_OFFSET_ADDRESSABLE_TAGGED_ORIGIN = 3, /* Bits 0-3 are part of Protocol */ /* Bit 4, addressable flag */ /* Bit 5, tagged flag */ /* Bit 6/7, origin value */ LIFX_HEADER_PACKET_OFFSET_SOURCE = 4, /* Source identifier, unique value set by client */ LIFX_HEADER_PACKET_OFFSET_TARGET = 8, /* 6 byte device address (MAC) or zero */ /* Last two bytes should be 0 */ LIFX_HEADER_PACKET_OFFSET_RESPONSE_REQUIRED_ACKNOWLEDGE_REQUIRED = 22, /* Bit 0, res_required flag */ /* Bit 1, ack_required flag */ LIFX_HEADER_PACKET_OFFSET_SEQUENCE = 23, /* Wrap around message sequence number */ LIFX_HEADER_PACKET_OFFSET_PACKET_TYPE = 32 /* Message type determines the payload used */ }; /*---------------------------------------------------------------------------*\ | LIFX set color packet offsets | | https://lan.developer.lifx.com/docs/changing-a-device#setcolor---packet-102 | \*---------------------------------------------------------------------------*/ enum { /* 1 byte, reserved */ LIFX_SET_COLOR_PACKET_OFFSET_HUE = LIFX_PACKET_HEADER_LENGTH + 1, /* 2 bytes, hue as a 0-65535 value */ LIFX_SET_COLOR_PACKET_OFFSET_SATURATION = LIFX_PACKET_HEADER_LENGTH + 3, /* 2 bytes, saturation as a 0-65535 value */ LIFX_SET_COLOR_PACKET_OFFSET_BRIGHTNESS = LIFX_PACKET_HEADER_LENGTH + 5, /* 2 bytes, brightness as a 0-65535 value */ LIFX_SET_COLOR_PACKET_OFFSET_KELVIN = LIFX_PACKET_HEADER_LENGTH + 7, /* 2 bytes, kelvin as a 0-65535 value. */ /* Note: The actual max for this is device specific */ LIFX_SET_COLOR_PACKET_OFFSET_DURATION = LIFX_PACKET_HEADER_LENGTH + 9, /* 4 bytes, transition time in ms */ }; /*--------------------------------------------------------------------------------*\ | LIFX set color zones packet offsets | | https://lan.developer.lifx.com/docs/changing-a-device#setcolorzones---packet-501 | \*--------------------------------------------------------------------------------*/ enum { LIFX_SET_COLOR_ZONES_PACKET_OFFSET_START_INDEX = LIFX_PACKET_HEADER_LENGTH + 0, /* 1 byte, the first zone in the segment we are changing */ LIFX_SET_COLOR_ZONES_PACKET_OFFSET_END_INDEX = LIFX_PACKET_HEADER_LENGTH + 1, /* 1 byte, the last zone in the segment we are changing */ LIFX_SET_COLOR_ZONES_PACKET_OFFSET_HUE = LIFX_PACKET_HEADER_LENGTH + 2, /* 2 bytes, hue as a 0-65535 value */ LIFX_SET_COLOR_ZONES_PACKET_OFFSET_SATURATION = LIFX_PACKET_HEADER_LENGTH + 4, /* 2 bytes, saturation as a 0-65535 value */ LIFX_SET_COLOR_ZONES_PACKET_OFFSET_BRIGHTNESS = LIFX_PACKET_HEADER_LENGTH + 6, /* 2 bytes, brightness as a 0-65535 value */ LIFX_SET_COLOR_ZONES_PACKET_OFFSET_KELVIN = LIFX_PACKET_HEADER_LENGTH + 8, /* 2 bytes, kelvin as a 0-65535 value. */ /* Note: The actual max for this is device specific */ LIFX_SET_COLOR_ZONES_PACKET_OFFSET_DURATION = LIFX_PACKET_HEADER_LENGTH + 10, /* 4 bytes, transition time in ms */ LIFX_SET_COLOR_ZONES_PACKET_OFFSET_APPLY = LIFX_PACKET_HEADER_LENGTH + 14 /* 1 byte, multizone application request */ }; /*-------------------------------------------------------------------------------------------*\ | LIFX get color zones packet offsets | | https://lan.developer.lifx.com/docs/querying-the-device-for-data#getcolorzones---packet-502 | \*-------------------------------------------------------------------------------------------*/ enum { LIFX_GET_COLOR_ZONES_PACKET_OFFSET_START_INDEX = LIFX_PACKET_HEADER_LENGTH + 0, /* 1 byte, The first zone you want to get information from */ LIFX_GET_COLOR_ZONES_PACKET_OFFSET_END_INDEX = LIFX_PACKET_HEADER_LENGTH + 1, /* 1 byte, The second zone you want to get information from */ }; /*-------------------------------------------------------------------------------*\ | LIFX state zone packet offsets | | https://lan.developer.lifx.com/docs/information-messages#statezone---packet-503 | \*-------------------------------------------------------------------------------*/ enum { LIFX_STATE_ZONE_PACKET_OFFSET_ZONES_COUNT = LIFX_PACKET_HEADER_LENGTH + 0, /* 1 byte, the total number of zones on the strip. */ LIFX_STATE_ZONE_PACKET_OFFSET_ZONE_INDEX = LIFX_PACKET_HEADER_LENGTH + 1, /* 1 byte, the zone this packet refers to. */ LIFX_STATE_ZONE_PACKET_OFFSET_HUE = LIFX_PACKET_HEADER_LENGTH + 2, /* 2 bytes, hue as a 0-65535 value */ LIFX_STATE_ZONE_PACKET_OFFSET_SATURATION = LIFX_PACKET_HEADER_LENGTH + 4, /* 2 bytes, saturation as a 0-65535 value */ LIFX_STATE_ZONE_PACKET_OFFSET_BRIGHTNESS = LIFX_PACKET_HEADER_LENGTH + 6, /* 2 bytes, brightness as a 0-65535 value */ LIFX_STATE_ZONE_PACKET_OFFSET_KELVIN = LIFX_PACKET_HEADER_LENGTH + 8, /* 2 bytes, kelvin as a 0-65535 value. */ /* Note: The actual max for this is device specific */ }; /*----------------------------------------------------------------------------------------*\ | LIFX set extended color zones packet offsets | | https://lan.developer.lifx.com/docs/changing-a-device#setextendedcolorzones---packet-510 | \*----------------------------------------------------------------------------------------*/ enum { LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_DURATION = LIFX_PACKET_HEADER_LENGTH + 0, /* 4 bytes, transition time in ms */ LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_APPLY = LIFX_PACKET_HEADER_LENGTH + 4, /* 1 byte, multizone application request */ LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_ZONE_INDEX = LIFX_PACKET_HEADER_LENGTH + 5, /* 2 bytes, The first zone to apply colors from. */ /* If the light has more than 82 zones, then */ /* send multiple messages with different indices */ /* to update the whole device. */ LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_COLORS_COUNT = LIFX_PACKET_HEADER_LENGTH + 7, /* 1 byte, The number of colors in the colors field */ LIFX_SET_EXTENDED_COLOR_ZONES_PACKET_OFFSET_COLORS = LIFX_PACKET_HEADER_LENGTH + 8, /* 656 bytes (82 * 4 * 2), 82 HSBK values to change */ /* the device with */ }; class LIFXController { public: LIFXController(std::string ip, std::string name, bool multizone, bool extended_multizone); ~LIFXController(); std::string GetLocation(); std::string GetName(); std::string GetVersion(); std::string GetManufacturer(); std::string GetUniqueID(); unsigned int GetZoneCount(); void FetchZoneCount(); void SetColors(std::vector colors); private: RGBColor cached_colors[UCHAR_MAX]; unsigned int zone_count; size_t data_buf_size; unsigned char* data; unsigned char sequence; std::string name; std::string firmware_version; std::string module_name; std::string module_mac; std::string location; net_port port; bool multizone; bool extended_multizone; void SetColor(RGBColor color); void SetZoneColor(RGBColor color, unsigned int zone); void SetZoneColors(std::vector colors); void RGBColorToHSBK(RGBColor color, hsbk_t* hsbk); /*---------------------*\ | Packet helper methods | \*---------------------*/ void HeaderPacketSetDefaults(unsigned short packet_type); unsigned short HeaderPacketGetSize(); void HeaderPacketSetSize(unsigned short size); unsigned short HeaderPacketGetProtocol(); void HeaderPacketSetProtocol(unsigned short protocol=LIFX_PROTOCOL); void HeaderPacketSetAddressable(bool addressable=true); void HeaderPacketSetTagged(bool tagged=false); void HeaderPacketSetOrigin(unsigned char origin=0); void HeaderPacketSetSource(unsigned int source=2); void HeaderPacketSetTarget(unsigned char* target); void HeaderPacketSetResponseRequired(bool response_required=false); void HeaderPacketSetAcknowledgeRequired(bool acknowledge_required=false); void HeaderPacketSetSequence(unsigned char sequence); unsigned short HeaderPacketGetPacketType(); void HeaderPacketSetPacketType(unsigned short packet_type); void SetColorPacketSetDuration(unsigned int duration=0); void SetColorPacketSetHSBK(hsbk_t* hsbk); void SetColorZonesPacketSetStartIndex(unsigned char start_index); void SetColorZonesPacketSetEndIndex(unsigned char end_index); void SetColorZonesPacketSetHSBK(hsbk_t* hsbk); void SetColorZonesPacketSetDuration(unsigned int duration=0); void SetColorZonesPacketSetApply(unsigned char apply=LIFX_MULTIZONE_APPLICATION_REQUEST_APPLY); void GetColorZonesPacketSetStartIndex(unsigned char start_index=0); void GetColorZonesPacketSetEndIndex(unsigned char end_index=0); unsigned char StateZonePacketGetZonesCount(); void SetExtendedColorZonesPacketSetDuration(unsigned int duration=0); void SetExtendedColorZonesPacketSetApply(unsigned char apply=LIFX_MULTIZONE_APPLICATION_REQUEST_APPLY); void SetExtendedColorZonesPacketSetZoneIndex(unsigned short zone_index=0); void SetExtendedColorZonesPacketSetColors(std::vector colors); };