### LIFX Header Parsing and Accessors Source: https://lan.developer.lifx.com/docs/decoding-a-packet Demonstrates how to parse a LIFX header from a byte slice and access its fields using methods. Includes an example of decoding a hex string and printing header information. Requires standard Go libraries for binary operations, hex decoding, and I/O. ```go // AckRequired returns whether the ack required bit is set in the header. func (h *Header) AckRequired() bool { v := h[22] v >>= 1 v &= 0b1 return v != 0 } // Sequence returns the sequence ID from the header. func (h *Header) Sequence() uint8 { return h[23] } // Type returns the Payload ID for the accompanying payload in the message. func (h *Header) Type() uint16 { return binary.LittleEndian.Uint16(h[32:34]) } // Example of using the Header class func main() { bts, err := hex.DecodeString("2400001400034746d073d500133700000000000000000701000000000000000014000000") if err != nil { log.Fatal(fmt.Errorf("Failed to decode bytes, %w", err)) } header, err := ReadHeader(bts) if err != nil { log.Fatal(fmt.Errorf("Failed to read header, %w", err)) } fmt.Printf("size: %d\n", header.Size()) fmt.Printf("protocol: %d\n", header.Protocol()) fmt.Printf("addressable: %t\n", header.Addressable()) fmt.Printf("tagged: %t\n", header.Tagged()) fmt.Printf("source: %d\n", header.Source()) fmt.Printf("target: %s\n", header.Target()) fmt.Printf("res_required: %t\n", header.ResponseRequired()) fmt.Printf("ack_required: %t\n", header.AckRequired()) fmt.Printf("sequence: %d\n", header.Sequence()) fmt.Printf("pkt_type: %d\n", header.Type()) // size: 36 // protocol: 1024 // addressable: true // tagged: false // source: 1179058944 // target: d073d5001337 // res_required: true // ack_required: true // sequence: 1 // pkt_type: 20 } ``` -------------------------------- ### Uint8 Encoding Example (Sequence) Source: https://lan.developer.lifx.com/docs/encoding-a-packet Shows the encoding of the value 1 as a Uint8 for the 'sequence' field. The sequence number should be incremented for each message sent. ```APIDOC Sequence Field Encoding: Value: 1 Type: Uint8 Binary Representation: 00000001 ``` -------------------------------- ### Uint32 Encoding Example (Source) Source: https://lan.developer.lifx.com/docs/encoding-a-packet Demonstrates the encoding of the value 2 as a Uint32 for the 'source' field. The source field is an arbitrary number used to identify the sender. ```APIDOC Source Field Encoding: Value: 2 Type: Uint32 Binary Representation: 00000010 00000000 00000000 00000000 ``` -------------------------------- ### SetMultiZoneEffect (Packet 508) - Start MultiZone Effect Source: https://lan.developer.lifx.com/docs/changing-a-device Starts a multizone Firmware Effect on the device. This packet requires the 'Linear Zones' capability. It returns a StateMultiZoneEffect (509) message. ```APIDOC SetMultiZoneEffect (Packet 508): Description: Starts a multizone Firmware Effect on the device. Requires Capability: Linear Zones Returns: StateMultiZoneEffect (509) Parameters: instanceid: Uint32 - A unique number identifying this effect. type: Uint8 - Using MultiZoneEffectType Enum. reserved6: 2 - Reserved bytes. speed: Uint32 - The time in milliseconds for one cycle of the effect. duration: Uint64 - The time in nanoseconds the effect will run for. reserved7: 4 - Reserved bytes. reserved8: 4 - Reserved bytes. parameters: 32 Bytes - Field meaning depends on the effect. For MOVE, the second 4-byte field is a Uint32 representing DIRECTION enum. Ignored for other effects. ``` -------------------------------- ### LIFX Packet Header Fields Source: https://lan.developer.lifx.com/docs/encoding-a-packet Defines the fields, their types, and example values for a LIFX packet header. This includes size, protocol, addressable, tagged, origin, source, target, sequence, and packet type. ```APIDOC Field | Type | Value --- | --- | --- size | Uint16 | 49 protocol | Uint16 (12 bits) | 1024 addressable | Bool (1 bit) | true tagGED | Bool (1 bit) | false origin | Uint8 (2 bits) | 0 source | Uint32 | 2 target | 8 Uint8 integers | d073d5001337 reserved | 6 Reserved bytes | 0 res_required | Bool (1 bit) | false ack_required | Bool (1 bit) | true reserved | 6 Reserved bits | 0 sequence | Uint8 | 1 reserved | 8 Reserved bytes | 0 pkt_type | Uint16 | 102 reserved | 2 Reserved bytes | 0 ``` -------------------------------- ### Uint16 Encoding Example (Packet Type) Source: https://lan.developer.lifx.com/docs/encoding-a-packet Illustrates the encoding of the packet type value 102 (for SetColor) as a Uint16. The description mentions that this field indicates the payload type. ```APIDOC Packet Type Field Encoding: Value: 102 (SetColor) Type: Uint16 Binary Representation: 01100110 00000000 ``` -------------------------------- ### Target Field Encoding (MAC Address) Source: https://lan.developer.lifx.com/docs/encoding-a-packet Explains how a target MAC address, like 'd073d5001337', is represented as an array of 8 Uint8 values for the 'target' field. The example shows the hexadecimal and binary representations. ```APIDOC Target Field Encoding: MAC Address: d073d5001337 Uint8 Array (Hex): [0xd0, 0x73, 0xd5, 0x00, 0x13, 0x37, 0x00, 0x00] Uint8 Array (Binary): ['11010000', '01110011', '11010101', '00000000', '00010011', '00110111', '00000000', '00000000'] Concatenated Binary: 11010000 01110011 11010101 00000000 00010011 00110111 00000000 00000000 ``` -------------------------------- ### Uint16 Encoding Example (Size) Source: https://lan.developer.lifx.com/docs/encoding-a-packet Illustrates how the value 49 is encoded as a Uint16 for the 'size' field in a LIFX packet header. The description notes that the full packet size is 36 bytes plus a 13-byte payload. ```APIDOC Size Field Encoding: Value: 49 Type: Uint16 Binary Representation: 00110001 00000000 ``` -------------------------------- ### LIFX SetTileEffect Packet Specification Source: https://lan.developer.lifx.com/docs/changing-a-device Defines the structure and parameters for the SetTileEffect packet (719) used to start firmware effects on LIFX devices. Includes details on reserved fields, instance ID, effect type, speed, duration, and effect-specific parameters like skyType and palette. ```APIDOC SetTileEffect Packet (719) Description: Starts a Firmware Effect on the device. Requires 'Matrix Zones' capability. Returns StateTileEffect (720). Dependencies: Device must have 'Matrix Zones' capability. Sky effect requires specific firmware (e.g., 4.4+ for LIFX Ceiling). Parameters: reserved0: Uint8 - 1 Reserved byte. reserved1: Uint8 - 1 Reserved byte. instanceid: Uint32 - A unique number identifying this effect. type: Uint8 - Using TileEffectType Enum. speed: Uint32 - The time it takes for one cycle of the effect in milliseconds. duration: Uint64 - The time the effect will run for in nanoseconds. reserved2: Uint32 - 4 Reserved bytes. reserved3: Uint32 - 4 Reserved bytes. skyType: TileEffectSkyType - Only used on `SKY` effect. reserved4: Uint8[3] - 3 Reserved bytes. cloudSaturationMin: Uint8 - Only used on `SKY` effect when using `CLOUDS` (recommended default is 50). reserved5: Uint8[3] - 3 Reserved bytes. reserved6: Uint8[24] - 24 Reserved bytes. Ignored by all firmware effects. palette_count: Uint8 - The number of values in `palette` to use. palette: Color[16] - HSBK values for the effect. Used as palette for MORPH effect. For SKY effect, indices in TileEffectSkyPalette dictate color usage. ``` -------------------------------- ### LIFX Tile Control and Addressing Source: https://lan.developer.lifx.com/docs/tile-control Details on controlling LIFX Tiles, including backwards compatibility, addressing zones with color arrays, and individual tile control using tile_index and length parameters. ```APIDOC LIFX Tile Control: Backwards Compatibility: When not using Tile-specific messages (messages without a `tile_index` attribute), the entire chain of tiles is controlled as a single unit. For example, a SetColor (102) message sent to a tile will affect all tiles in the chain. Addressing Zones: Colors are specified as an array of 64 colors for the 8x8 LED matrix. The order of colors in the array corresponds to the visual layout of the LEDs on a right-side-up tile. Individual Tile Control: Tiles can be controlled individually using `tile_index` and `length` properties in Tile messages. - `tile_index`: Represents the first tile to process the command (master tile is 0). - `length`: Specifies how many tiles, starting from `tile_index`, should process the command. Example Scenarios: - `tile_index: 0`, `length: 1`: Affects only the master tile. - `tile_index: 1`, `length: 2`: Affects the tile after the master tile and the tile following that one. ``` -------------------------------- ### SetHevCycle (Packet 143) - Start or Stop HEV Cycle Source: https://lan.developer.lifx.com/docs/changing-a-device Starts or stops a HEV (High Energy Visible) cycle on the device. This packet requires the 'hev' capability. It returns a StateHevCycle (144) message. ```APIDOC SetHevCycle (Packet 143): Description: Starts or stops a HEV cycle on the device. Requires Capability: hev Returns: StateHevCycle (144) Parameters: enable: BoolInt - Set to false to turn off the cycle, true to start. duration_s: Uint32 - The duration, in seconds, for the cycle. A value of 0 uses the default duration from SetHevCycleConfiguration (146). ``` -------------------------------- ### LIFX Echo Request Source: https://lan.developer.lifx.com/docs/querying-the-device-for-data Sends an echo request to a device to verify it is online and responsive. The device will echo back the provided data. ```APIDOC EchoRequest - Packet 58 Description: Checks that a device is online and responding. Payload: - echoing: 64 Bytes - The bytes to be echoed back in the EchoResponse message. Response: One EchoResponse (59) message containing the 'echoing' data. ``` -------------------------------- ### LIFX Tile Positioning and User Coordinates Source: https://lan.developer.lifx.com/docs/tile-control Explains how LIFX Tiles can be positioned in a 2D space using `user_x` and `user_y` fields, and how these values can be updated. ```APIDOC LIFX Tile Positioning: User Position Fields: - `user_x`: The X-coordinate of the tile's center in a 2D plane. - `user_y`: The Y-coordinate of the tile's center in a 2D plane. Units: The unit of measurement for coordinates is one tile width. Purpose: These fields allow client applications to locate tiles on a 2D plane, enabling features like applying images across tile sets or matching tile borders for patterns. Updating Position: Tile position values can be changed using the `SetUserPosition` (703) message. ``` -------------------------------- ### LIFX Protocol Discovery Source: https://lan.developer.lifx.com/docs/querying-the-device-for-data Used for discovering LIFX devices on the network. Broadcasting this message prompts devices to respond with their available services and ports. ```APIDOC GetService - Packet 2 Description: Used for Discovery of devices. Usage: Broadcast this message to the network (with 'tagged' field in header set to 0 and 'target' field set to all zeros). Response: Multiple StateService (3) messages indicating available services and their ports. Note: The primary StateService (3) message indicates UDP availability on port 56700, from which the device IP can be determined. ``` -------------------------------- ### LIFX Device Info Query Source: https://lan.developer.lifx.com/docs/querying-the-device-for-data Fetches device uptime, downtime, and its current time. Useful for monitoring device health and operational status. ```APIDOC GetInfo - Packet 34 Description: Determines the uptime and downtime of the device, as well as the current time according to the device. Usage: Send this packet to the device. Response: One StateInfo (35) message. ``` -------------------------------- ### LIFX Multizone Control Messages Source: https://lan.developer.lifx.com/docs/multizone-light-control Details on controlling LIFX devices with multiple light zones arranged linearly. Covers both Legacy Multizone messages for older LIFX Z products and Extended Multizone messages for more efficient control and querying of zone colors. ```APIDOC LIFX Multizone Control: Devices like Lightstrips, Strings, Neons, and Beams have multiple light zones in a linear layout. Each zone is controlled individually. **Legacy Multizone Messages:** - Required for older LIFX Z products. - All products still support these messages. - When not using MultiZone messages, the whole device is controlled (e.g., a SetColor message affects all zones). **Extended Multizone Messages:** - Preferable if your device supports them. - Allow control/querying of all zones with significantly fewer messages. - Have a fixed size of 82 zones. If a device has fewer than 82 zones, some zones will have all 0 values. If a device has more than 82 zones, it will return multiple messages with different starting `zone_index`. - It is important to check the `zone_count` property to know the total number of zones. **Example Message (Legacy):** SetColor (102) - Controls the color of a specific zone or the entire device. - Parameters: - `zone_index`: The index of the zone to control (0 for the first zone). - `color`: HSBK color value. - `duration`: Transition duration. - `apply_transition`: Whether to apply a transition. - Returns: Acknowledgment message. **Zone Indexing:** - Zones are represented by an index starting at 0. - Index 0 is the zone closest to the controller. ``` -------------------------------- ### Light Configuration - LIFX LAN Protocol Source: https://lan.developer.lifx.com/docs/changing-a-device This section details LIFX LAN protocol messages for controlling the visual appearance of lights, including setting color (HSBK) and applying waveform effects. These 'Set' messages typically result in a LightState message. ```APIDOC SetColor - Packet 102 Sets the HSBK (Hue, Saturation, Brightness, Kelvin) color value for the light. For multi-zone devices, this applies to all zones. Returns: LightState (Packet 107) Parameters: reserved6: 1 Reserved byte hue: Uint16 saturation: Uint16 brightness: Uint16 kelvin: Uint16 duration: Uint32 - Transition time in milliseconds. ``` ```APIDOC SetWaveform - Packet 103 Sets HSBK color values and applies waveform effects to the light. For multi-zone devices, all zones are treated as one. Returns: LightState (Packet 107) Parameters: reserved6: 1 Reserved byte transient: BoolInt - See Waveforms documentation. hue: Uint16 saturation: Uint16 brightness: Uint16 kelvin: Uint16 period: Uint32 - See Waveforms documentation. cycles: Float - See Waveforms documentation. skew_ratio: Int16 - See Waveforms documentation. waveform: Uint8 - Using Waveform Enum, see Waveforms documentation. ``` -------------------------------- ### Split Byte Encoding (res_required, ack_required, reserved) Source: https://lan.developer.lifx.com/docs/encoding-a-packet Details the encoding of a single byte containing 'res_required' (1 bit), 'ack_required' (1 bit), and 6 reserved bits. The example sets 'res_required' to false (0) and 'ack_required' to true (1). ```APIDOC Split Byte Encoding: res_required | ack_required | reserved (6 bits) --- | --- | --- 0 | 1 | 000000 Binary Representation: 00000010 ``` -------------------------------- ### LIFX Candle Firmware Effects Source: https://lan.developer.lifx.com/docs/candle Information on firmware effects supported by the LIFX Candle product, specifically 'Flame' and 'Morph'. ```APIDOC Firmware Effects: Supported Effects for LIFX Candle: - Flame: A dynamic lighting effect simulating a flame. - Morph: A transition effect between different states or colors. ``` -------------------------------- ### LIFX Header Parsing and Structure (C) Source: https://lan.developer.lifx.com/docs/decoding-a-packet Defines the LIFX frame structure using a C struct with bitfields and provides functions to read a header from a hex string and extract the target MAC address. Includes a main function demonstrating usage. Requires standard C libraries for I/O, string manipulation, and memory allocation. ```c #include #include #include #include #pragma pack(push, 1) typedef struct lx_frame_t { uint16_t size; uint16_t protocol : 12; uint8_t addressable : 1; uint8_t tagged : 1; uint8_t reserved_1 : 2; uint32_t source; uint64_t target; uint8_t reserved_2[6]; uint8_t res_required : 1; uint8_t ack_required : 1; uint8_t reserved_3 : 6; uint8_t sequence; uint64_t reserved_4; uint16_t pkt_type; uint16_t reserved_5; } lx_frame_t; #pragma pack(pop) void extract_frame_serial(lx_frame_t *frame, char *serial) { char ss[16]; sprintf(ss, "%#06llx", frame->target); for (int i = 12; i > 0; i = i - 2) { serial[12 - i] = ss[i]; serial[13 - i] = ss[i + 1]; } } lx_frame_t *read_frame(char *hex) { int str_len = strlen(hex); if (str_len < 72) { return NULL; } uint8_t buffer[36] = {}; for (int i = 0; i < (str_len / 2) && i < 72; i++) { unsigned int nxt; sscanf(hex + 2 * i, "%02x", &nxt); buffer[i] = (uint8_t)nxt; } struct lx_frame_t *f; f = (lx_frame_t *)malloc(sizeof(struct lx_frame_t)); memcpy(f, buffer, 36); return f; } int main() { char *hex = "2400001400034746d073d5001337000000000000000007010000000" "00000000014000000"; lx_frame_t *frame = read_frame(hex); if (frame == NULL) { fprintf(stdout, "Failed to convert hex into a header"); return 1; } char serial[12] = {}; extract_frame_serial(frame, serial); char *t = "true"; char *f = "false"; char *bools[2] = {f, t}; fprintf(stdout, "size: %d\n", frame->size); fprintf(stdout, "protocol: %hu\n", frame->protocol); fprintf(stdout, "addressable: %s\n", bools[frame->addressable]); fprintf(stdout, "lagged: %s\n", bools[frame->tagged]); fprintf(stdout, "source: %d\n", frame->source); fprintf(stdout, "target: %s\n", serial); fprintf(stdout, "res_required: %s\n", bools[frame->res_required]); fprintf(stdout, "ack_required: %s\n", bools[frame->ack_required]); fprintf(stdout, "sequence: %d\n", frame->sequence); fprintf(stdout, "pkt_type: %d\n", frame->pkt_type); /* # size: 36 # protocol: 1024 # addressable: True # tagged: False # source: 1179058944 # target: d073d5001337 # res_required: True # ack_required: True # sequence: 1 # pkt_type: 20 */ free(frame); } ``` -------------------------------- ### LIFX Relay and Device Chain Information Source: https://lan.developer.lifx.com/docs/querying-the-device-for-data These packets are used to get the power state of a specific relay on a switch device and to retrieve information about devices connected in a chain. They require 'Relays' and 'Matrix Zones' capabilities respectively. ```APIDOC GetRPower - Packet 816 Description: Gets the power state of a relay on a switch device. Requires Capability: Relays Returns: StateRPower (818) Parameters: relay_index: Uint8 - The index of the relay on the switch, starting from 0. GetDeviceChain - Packet 701 Description: Retrieves information about all devices in the chain. Requires Capability: Matrix Zones Returns: StateDeviceChain (702) Notes: For LIFX Tiles, this will be up to 5 devices; for LIFX Candle, it will be 1 device. ``` -------------------------------- ### LIFX Protocol Information Messages Overview Source: https://lan.developer.lifx.com/docs/information-messages Provides context for LIFX information messages, which are replies to Get messages or sent when a Set message has the 'res_required' flag set. Typically, acknowledgement is only required from Set messages. ```APIDOC Information messages are State messages returned in response to Get messages or when a Set message has the 'res_required' flag set to 1. Acknowledgement is usually only required from Set messages. ``` -------------------------------- ### LIFX Device Wi-Fi Firmware Query Source: https://lan.developer.lifx.com/docs/querying-the-device-for-data Retrieves the version of the Wi-Fi firmware for first and second generation devices. This is separate from the host firmware. ```APIDOC GetWifiFirmware - Packet 18 Description: Returns the version of the Wi-Fi firmware on first and second generation devices. Usage: Send this packet to the device. Response: One StateWifiFirmware (19) message. ``` -------------------------------- ### LIFX Multi-Zone Color and Effect Retrieval Source: https://lan.developer.lifx.com/docs/querying-the-device-for-data These packets are used to get color information for specific zones or all zones on a LIFX device, and to check for active multi-zone effects. They require 'Linear Zones' or 'Extended Linear Zones' capabilities. ```APIDOC GetColorZones - Packet 502 Description: Retrieves color information for a range of zones. Returns: StateZone (503) for a single zone, or StateMultiZone (506) for multiple zones. Requires Capability: Linear Zones Parameters: start_index: Uint8 - The first zone to get information from. end_index: Uint8 - The last zone to get information from. Notes: To retrieve all zones, set start_index to 0 and end_index to 255. Pseudo-code for message count: number_segments_of_8 = (request.end_index - request.start_index) / 8 count_from_request = maximum(1, floor(number_segements_of_8) + 1) count_from_response = ceil(first_response.zone_count / 8) expected_number_of_messages = minimum(count_from_request, count_from_response) GetMultiZoneEffect - Packet 507 Description: Determines if the device is currently running a multizone Firmware Effect. Requires Capability: Linear Zones Returns: StateMultiZoneEffect (509) GetExtendedColorZones - Packet 511 Description: Retrieves HSBK values for every zone on the strip. Returns: StateExtendedColorZones (512). Multiple responses may be returned if the light has more than 82 zones. Requires Capability: Extended Linear Zones ``` -------------------------------- ### LIFX Device Host Firmware Query Source: https://lan.developer.lifx.com/docs/querying-the-device-for-data Retrieves the firmware version of the device's host. This information is useful for determining device capabilities based on the Product Registry. ```APIDOC GetHostFirmware - Packet 14 Description: Determines the version of the firmware on the device. Usage: Send this packet to the device. Response: One StateHostFirmware (15) message. ``` -------------------------------- ### LIFX Header Class and Usage Source: https://lan.developer.lifx.com/docs/decoding-a-packet Defines a JavaScript class `Header` to parse and access fields within a LIFX packet header. It includes getter methods for properties like sequence, type, and flags. An example demonstrates creating a header instance from a hex string and logging its extracted values. ```javascript class Header { constructor(hexString) { // Convert hex string to ArrayBuffer const bytes = new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); this.data = new DataView(bytes.buffer); } // Size (uint16, offset 0) get size() { return this.data.getUint16(0, true); } // Protocol (uint16, offset 2) get protocol() { return this.data.getUint16(2, true); } // Addressable (uint8, offset 4, bit 0) get addressable() { return (this.data.getUint8(4) & 0b1) === 1; } // Tagged (uint8, offset 4, bit 1) get tagged() { return ((this.data.getUint8(4) >> 1) & 0b1) === 1; } // Source (uint32, offset 8) get source() { return this.data.getUint32(8, true); } // Target (uint64, offset 12) get target() { // LIFX target is a 6-byte MAC address, represented as a string let mac = ''; for (let i = 0; i < 6; i++) { const byte = this.data.getUint8(12 + i).toString(16).padStart(2, '0'); mac += byte; } return mac; } get resRequired() { let v = this.data.getUint8(22); v &= 0b1; return !!v; } get ackRequired() { let v = this.data.getUint8(22); v >>= 1; v &= 0b1; return !!v; } get sequence() { let v = this.data.getUint8(23); return v; } get type() { let v = this.data.getUint16(32, true); return v; } } // Example Usage: const header = new Header( "2400001400034746d073d500133700000000000000000701000000000000000014000000" ); console.log("size:", header.size); console.log("protocol:", header.protocol); console.log("addressable:", header.addressable); console.log("tagged:", header.tagged); console.log("source:", header.source); console.log("target:", header.target); console.log("res_required:", header.resRequired); console.log("ack_required:", header.ackRequired); console.log("sequence:", header.sequence); console.log("pkt_type:", header.type); // Expected Output: // size: 36 // protocol: 1024 // addressable: true // tagged: false // source: 1179058944 // target: d073d5001337 // res_required: true // ack_required: true // sequence: 1 // pkt_type: 20 ``` ``` -------------------------------- ### LIFX Device Version Query Source: https://lan.developer.lifx.com/docs/querying-the-device-for-data Obtains the product type of the LIFX device. This information is crucial for understanding device capabilities via the Product Registry. ```APIDOC GetVersion - Packet 32 Description: Determines the product type of the device. Usage: Send this packet to the device. Response: One StateVersion (33) message. ``` -------------------------------- ### Convert HSBK to Uint16 for LIFX Source: https://lan.developer.lifx.com/docs/encoding-a-packet Provides a Python code snippet demonstrating the conversion of HSBK (Hue, Saturation, Brightness, Kelvin) color values into the Uint16 format required by the LIFX protocol. It shows how to scale hue (0-360) and saturation/brightness (0-100) to the 0-65535 range. ```python hue = 120 saturation = 1 brightness = 1 kelvin = 3500 # Convert hue from 0-360 to 0-65535 uint16_hue = int(round(0x10000 * hue) / 360)) % 0x10000 # Convert saturation from 0-1 to 0-65535 uint16_saturation = int(round(0xFFFF * saturation)) # Convert brightness from 0-1 to 0-65535 uint16_brightness = int(round(0xFFFF * saturation)) uint16_kelvin = kelvin ``` -------------------------------- ### LIFX Header Parsing and Accessors (JavaScript) Source: https://lan.developer.lifx.com/docs/decoding-a-packet Provides a JavaScript implementation for parsing LIFX headers from hex strings using DataView and Uint8Array. Includes a `Header` class with getter methods to access individual fields like size, protocol, source, and target MAC address. Handles hex validation and buffer manipulation. ```javascript function read_header(s) { if (s.length < 72) { throw new Error("Need atleast 72 characters in hex for frame header"); } if (!/^[a-fA-F0-9]*$/.test(s)) { throw new Error(`Invalid HEX input: "${s}"`); } const buffer = new Uint8Array(36).buffer; const data = new DataView(buffer, 0, 36); const bytes = new Uint8Array(data.buffer); bytes.forEach((_, i, b) => (b[i] = parseInt(s.substr(2 * i, 2), 16))); return data; } class Header { constructor(s) { this.data = read_header(s); } get size() { let v = this.data.getUint16(0, true); return v; } get protocol() { let v = this.data.getUint16(2, true); v &= 0b111111111111; return v; } get addressable() { let v = this.data.getUint8(3); v >>= 4; v &= 0b1; return !!v; } get tagged() { let v = this.data.getUint8(3); v >>= 5; v &= 0b1; return !!v; } get source() { return this.data.getUint32(4, true); } get target() { const bytes = new Uint8Array(this.data.buffer, 8, 6); const serial = []; bytes.map(b => serial.push(b.toString(16).padStart(2, "0"))); return serial.join(""); } ``` -------------------------------- ### Device Configuration - LIFX LAN Protocol Source: https://lan.developer.lifx.com/docs/changing-a-device This section covers LIFX LAN protocol messages for configuring device-level settings such as power, label, reboot, location, and group. These 'Set' messages often trigger corresponding 'State' messages in response. ```APIDOC SetPower - Packet 21 Sets the current power level of the device. Returns: StatePower (Packet 22) Parameters: level: Uint16 - 0 for off, 65535 for on. ``` ```APIDOC SetLabel - Packet 24 Sets the user-assigned label (name) for the device. Returns: StateLabel (Packet 25) Parameters: label: 32 bytes String - The desired name for the device. ``` ```APIDOC SetReboot - Packet 38 Instructs the device to perform a reboot. No explicit state message is returned for this action. ``` ```APIDOC SetLocation - Packet 49 Sets the location information for the device. Returns: StateLocation (Packet 50) Parameters: location: 16 Bytes - UUID representing the location. label: 32 bytes String - The name of the location. updated_at: Uint64 - Epoch time in nanoseconds of the update. ``` ```APIDOC SetGroup - Packet 52 Sets the group information for the device. Returns: StateGroup (Packet 53) Parameters: group: 16 Bytes - UUID representing the group. label: 32 bytes String - The name of the group. updated_at: Uint64 - Epoch time in nanoseconds of the update. ``` -------------------------------- ### Convert HSBK Color Values to/from Uint16 (Python) Source: https://lan.developer.lifx.com/docs/representing-color-with-hsbk Demonstrates how to convert standard color values (0-360 for Hue, 0-1 for Saturation/Brightness) to the 0-65535 Uint16 format used by LIFX devices, and vice-versa. It includes specific logic for Hue conversion with rounding and for Saturation/Brightness conversion. ```Python # From a 0-360 value to a 0-65535 value hue = 120 uint16_hue = int(round(0x10000 * hue) / 360)) % 0x10000 # from a 0-65535 value to a 0-360 value hue = round(float(uint16_hue) * 360 / 0x10000, 2) ``` ```Python # From a 0-1 value to a 0-65535 value saturation = 0.5 uint16_saturation = int(round(0xFFFF * saturation)) # from a 0-65535 value to a 0-1 value saturation = round(float(uint16_saturation) / 0xFFFF, 4) ``` -------------------------------- ### LIFX Candle Set64 Message Configuration Source: https://lan.developer.lifx.com/docs/candle Details on configuring the Set64 message for the LIFX Candle product. This includes specifying the message type, width, and height to correctly address the device's 26 zones. ```APIDOC Set64 (715): Description: Sets 64 individual zones on a device. Parameters: - width: Integer, required. For the Candle, this must be set to 5. - height: Integer, required. For the Candle, this must be set to 6. - colors: Array of color objects, up to 64 elements. The first 5 colors in the array correspond to the top zone, and the subsequent colors map to the 5 columns of 5 zones each. Notes: - The LIFX Candle has 26 zones. When sending a Set64 message, only the first 26 color entries are relevant. - The first color entry affects the zone at the top of the candle. - The remaining 25 color entries map to the 5 columns of 5 zones each. ``` -------------------------------- ### LIFX LAN Protocol Communication Scenarios Source: https://lan.developer.lifx.com/docs/communicating-with-device Describes the different ways to send packets to LIFX devices, including discovery, requests requiring acknowledgments, responses, or both. It outlines the packet fields like source, sequence, ack_required, and res_required. ```APIDOC LIFX LAN Protocol Communication: All LIFX packets are sent over UDP to each device on port 56700. Scenarios: 1. Broadcasting a message to everything on the network (discovery). 2. Sending a message and getting back just an Acknowledgment. 3. Sending a message and getting back just a State message. 4. Sending a message and getting both an Acknowledgement and a State message. 5. Sending a message and getting no reply. Discovery: 1. Send GetService (type 2) as a UDP broadcast to port 56700 with Frame Header `tagged` field set to `1`. 2. Devices respond with StateService (type 3) messages. 3. Clients can then send messages directly or broadcast. Request with Acknowledgement: 1. Discover devices. 2. Set `source` field with a unique 32-bit number. 3. Use wrap-around `sequence` as message ID. 4. Set `ack_required` field to `1`. 5. Send message; acknowledged by Acknowledgement (type 45) with same source and sequence. Note: Get messages also send back a State response even if `res_required` is `0`. Request with Response: 1. Discover devices. 2. Set `source` field with a unique 32-bit number. 3. Use wrap-around `sequence` as message ID. 4. Send a Get message and/or set `res_required` field to `1`. 5. Send message; a corresponding semantic reply (State message) is sent back with same source and sequence. Recommendation: Do not rely on `State` messages when sending a `Set` message, as the `State` is likely the state before the change. Request with Acknowledgement and Response: - When a request receives a State message and also requests an acknowledgment, the ack is sent just before the device processes the message. Request without Acknowledgement or Response: - If a packet is sent with `ack_required` and `res_required` set to `false`, and the message is not a `Get` message, the device may or may not receive the packet, and no response will be sent. In this case, query the device later to determine if the packet had an impact. ``` -------------------------------- ### LIFX Waveform Behavior Explanations Source: https://lan.developer.lifx.com/docs/waveforms Details the behavior of different LIFX waveform types, including how they transition between colors, the role of parameters like 'period' and 'transient', and specific logic for pulse effects. ```APIDOC Waveform Behavior: General: - If transient is true or waveform is SINE or TRIANGLE, the device returns to the original color after the effect. - Otherwise, the device retains the final color of the effect. SINE: - Color cycles smoothly from current color to 'color' and back to current color. - Duration of one cycle is 'period' milliseconds. HALF_SINE: - Light interpolates smoothly from current color to 'color'. - Duration of each cycle is 'period' milliseconds. TRIANGLE: - Light interpolates linearly from current color to 'color', then back to current color. - Duration of each cycle is 'period' milliseconds. SAW: - Light interpolates linearly from current color to 'color'. - Duration of each cycle is 'period' milliseconds. PULSE: - Color is set immediately to 'color'. - After the duty cycle fraction expires, it reverts to the current color until the end of the cycle. - Duty cycle percentage is calculated by applying (1 - skew_ratio) to the 'cycle' duration. - skew_ratio is a signed Int16 scaled from 0 to 1: - -32768 maps to 0 - -16383 maps to 0.25 - 0 maps to 0.5 - 16383 maps to 0.75 - 32767 maps to 1 ``` -------------------------------- ### LIFX StateWifiFirmware Packet Source: https://lan.developer.lifx.com/docs/information-messages This packet reports the version of the Wi-Fi firmware. The 'build' timestamp is primarily relevant for older product generations. ```APIDOC StateWifiFirmware - Packet 19 Purpose: Reports the Wi-Fi firmware version. Reply to: GetWifiFirmware (18) Fields: build: Uint64 - Timestamp of Wi-Fi firmware creation as an epoch (relevant for first two generations). reserved6: 8 bytes - Reserved. version_minor: Uint16 - The minor component of the Wi-Fi firmware version. version_major: Uint16 - The major component of the Wi-Fi firmware version. ``` -------------------------------- ### LIFX SetColor Packet (Binary and Hex) Source: https://lan.developer.lifx.com/docs/encoding-a-packet Presents the complete LIFX packet constructed for setting a device to green. It shows the final concatenated binary data and its equivalent hexadecimal representation, combining header and payload fields. ```binary 00110001 00000000 00000000 00010100 00000010 00000000 00000000 00000000 11010000 01110011 11010101 00000000 00010011 00110111 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000010 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 01100110 00000000 00000000 00000000 00000000 01010101 01010101 11111111 11111111 11111111 11111111 10101100 00001101 00000000 00000000 00000000 00000000 ``` ```hex 3100001402000000 d073d50013370000 0000000000000201 0000000000000000 66000000005555ff ffffffac0d000000 00 ``` -------------------------------- ### LIFX Get64 Packet Source: https://lan.developer.lifx.com/docs/querying-the-device-for-data Retrieves HSBK values for zones across multiple devices in a chain. Requires the 'Matrix Zones' capability. Returns one or more State64 messages based on the requested length. ```APIDOC Get64 - Packet 707 Purpose: Get HSBK values of all zones in devices connected in the chain. Returns: One or more State64 (711) messages. Requires Capability: Matrix Zones Parameters: tile_index: Uint8 - The first item in the chain to query. length: Uint8 - The number of tiles after tile_index to retrieve HSBK values from. reserved6: 1 byte - Reserved bytes. x: Uint8 - The starting x-coordinate (typically 0). y: Uint8 - The starting y-coordinate (typically 0). width: Uint8 - The width of each item in the chain (e.g., 8 for LIFX Tile, 5 for LIFX Candle). ``` -------------------------------- ### Set64 (Packet 715) Source: https://lan.developer.lifx.com/docs/changing-a-device Sets up to 64 HSBK values on a device, typically for tiles. This message has no response packet. Requires the 'Matrix Zones' capability. ```APIDOC Set64 - Packet 715 Purpose: Set HSBK values for up to 64 zones. Response: None Capability Required: Matrix Zones Parameters: tile_index: Uint8 - The device index to change (0-indexed). length: Uint8 - Number of devices to change starting from tile_index. fb_index: Uint8 - Frame buffer index (usually 0 for visible). x: Uint8 - Starting X-coordinate. y: Uint8 - Starting Y-coordinate. width: Uint8 - Width of the square to apply colors (e.g., 8 for Tile, 5 for Candle). duration: Uint32 - Transition time in milliseconds. colors: 64 Color structures - HSBK values for each zone. ```