### LIFX LAN Client Setup in Deno Source: https://github.com/jmmoser/lifxlan/blob/main/README.md Provides an example of setting up a `lifxlan` client within the Deno runtime. It demonstrates using Deno's native `listenDatagram` for UDP communication, configuring the `Router` for message handling, and `Devices` for tracking discovered devices. The client broadcasts a `GetServiceCommand` to initiate device discovery. ```JavaScript import { Client, Router, Devices, GetServiceCommand } from 'lifxlan/index.js'; const socket = Deno.listenDatagram({ hostname: '0.0.0.0', port: 0, transport: 'udp', }); const router = Router({ onSend(message, port, hostname) { socket.send(message, { port, hostname }); } }); const devices = Devices({ onAdded(device) { console.log(device); }, }); const client = Client({ router }); client.broadcast(GetServiceCommand()); setTimeout(() => { socket.close(); }, 1000); for await (const [message, remote] of socket) { const { header, serialNumber } = router.receive(message); devices.register(serialNumber, remote.port, remote.hostname, header.target); } ``` -------------------------------- ### LIFX LAN Client Setup in Node.js/Bun Source: https://github.com/jmmoser/lifxlan/blob/main/README.md Illustrates how to set up a `lifxlan` client in a Node.js or Bun environment. This includes initializing a UDP socket, configuring the `Router` to handle message sending and receiving, and setting up `Devices` to track discovered LIFX devices. The example demonstrates broadcasting a `GetServiceCommand` to discover devices on the network. ```JavaScript import dgram from 'node:dgram'; import { Client, Router, Devices, GetServiceCommand } from 'lifxlan/index.js'; const socket = dgram.createSocket('udp4'); // Router handles outgoing messages and forwards responses to clients const router = Router({ onSend(message, port, address) { // A message is ready to be sent socket.send(message, port, address); }, }); // Devices keeps track of devices discovered on the network const devices = Devices({ onAdded(device) { // A device has been discovered console.log(device); }, }); socket.on('message', (message, remote) => { // Forward received messages to the router const { header, serialNumber } = router.receive(message); // Forward the message to devices so it can keep track devices.register(serialNumber, remote.port, remote.address, header.target); }); // Client handles communication with devices const client = Client({ router }); socket.once('listening', () => { socket.setBroadcast(true); // Discover devices on the network client.broadcast(GetServiceCommand()); }); socket.bind(); setTimeout(() => { socket.close(); }, 1000); ``` -------------------------------- ### Turn on a specific LIFX light using lifxlan Source: https://github.com/jmmoser/lifxlan/blob/main/README.md This example demonstrates the full setup for controlling a LIFX light: initializing a UDP socket, setting up the 'lifxlan' router and device registry, discovering devices, and sending a 'SetPowerCommand' to turn on a specific light identified by its serial number. It showcases the core components of the library in action. ```javascript import dgram from 'node:dgram'; import { Client, Devices, Router, GetServiceCommand, SetPowerCommand } from 'lifxlan/index.js'; const socket = dgram.createSocket('udp4'); // Set up the router to send messages const router = Router({ onSend(message, port, address) { socket.send(message, port, address); }, }); // Track discovered devices const devices = Devices(); // Handle incoming messages socket.on('message', (message, remote) => { const { header, serialNumber } = router.receive(message); devices.register(serialNumber, remote.port, remote.address, header.target); }); // Start the socket await new Promise((resolve, reject) => { socket.once('error', reject); socket.once('listening', resolve); socket.bind(); }); socket.setBroadcast(true); const client = Client({ router }); // Discover devices client.broadcast(GetServiceCommand()); const scanInterval = setInterval(() => { client.broadcast(GetServiceCommand()); }, 1000); // Wait for a specific device (replace with your device's serial number) const device = await devices.get('d07123456789'); // Stop scanning clearInterval(scanInterval); // Turn the light on! await client.send(SetPowerCommand(true), device); socket.close(); ``` -------------------------------- ### Install lifxlan via npm Source: https://github.com/jmmoser/lifxlan/blob/main/README.md Instructions to install the 'lifxlan' library using the npm package manager. This command adds the library to your project's dependencies, making it available for use in Node.js, Bun, or Deno environments. ```bash npm install lifxlan ``` -------------------------------- ### GetHostFirmware - Packet 14 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This message is used to determine the version of the host firmware installed on a LIFX device. The retrieved information can be used to ascertain the device's capabilities as specified in the LIFX Product Registry. ```APIDOC Message Type: GetHostFirmware (Packet 14) Payload: Empty Purpose: Determine host firmware version Expected Response: StateHostFirmware (Packet 15) - 1 message ``` -------------------------------- ### GetColor - Packet 101 (Light) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet is used to get the current visual state of the device. It will return one LightState (107) message. ```APIDOC GetColor: Packet ID: 101 Purpose: Get the current visual state of the device. Returns: LightState (107) ``` -------------------------------- ### Discover and control all LIFX devices Source: https://github.com/jmmoser/lifxlan/blob/main/README.md Building upon the initial setup, this snippet demonstrates how to discover all LIFX devices on the network and then iterate through the discovered devices to send a 'SetPowerCommand' to each, effectively turning on all lights. It illustrates batch operations using the 'lifxlan' library. ```javascript import { GetServiceCommand, SetPowerCommand } from 'lifxlan/index.js'; // ... setup code from above ... // Discover all devices client.broadcast(GetServiceCommand()); const scanInterval = setInterval(() => { client.broadcast(GetServiceCommand()); }, 1000); // Wait a few seconds for discovery await new Promise(resolve => setTimeout(resolve, 3000)); // Stop scanning clearInterval(scanInterval); // Turn on all discovered lights for (const device of devices) { await client.send(SetPowerCommand(true), device); } ``` -------------------------------- ### Managing LIFX Device Groups (JavaScript) Source: https://github.com/jmmoser/lifxlan/blob/main/README.md This example demonstrates how to use the `Groups` and `Devices` APIs to discover and manage LIFX device groups. It shows how to register devices to groups and then send commands to all devices within a specific group, enabling synchronized control. ```javascript import { Groups, GetGroupCommand } from 'lifxlan/index.js'; const groups = Groups({ onAdded(group) { console.log('Group added', group); }, onChanged(group) { console.log('Group changed', group); }, }); const devices = Devices({ async onAdded(device) { const group = await client.send(GetGroupCommand(), device); groups.register(device, group); }, }); // Send command to all devices in a group for (const group of groups) { await Promise.all( group.devices.map(device => client.send(GetLabelCommand(), device) ) ); } ``` -------------------------------- ### Get Device Chain Information (GetDeviceChain - Packet 701) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md Obtains information about all connected devices in a chain, such as LIFX Tiles (up to 5 devices) or LIFX Candle (1 device). This packet requires the device to have the 'Matrix Zones' capability. The device will respond with a 'StateDeviceChain (702)' message containing the requested information. ```APIDOC GetDeviceChain (Packet 701): Description: Get information about all devices in the chain. Requires Capability: Matrix Zones Returns: StateDeviceChain (702) Parameters: None ``` -------------------------------- ### Managing Client Resources for Many LIFX Devices (JavaScript) Source: https://github.com/jmmoser/lifxlan/blob/main/README.md This example demonstrates proper resource management when creating multiple client instances in a loop. It shows how to use `client.dispose()` to release resources and prevent exhaustion of source values, ensuring efficient and stable operation. ```javascript while (true) { const client = Client({ router }); console.log(await client.send(GetPowerCommand(), device)); // When creating a lot of clients, call dispose to avoid running out of source values client.dispose(); } ``` -------------------------------- ### Defining and Using Custom LIFX Commands (JavaScript) Source: https://github.com/jmmoser/lifxlan/blob/main/README.md This example demonstrates how to define a custom command with a specific type and a decode function for parsing its payload. It shows how to create a `CustomCommand` and then send it using the client, allowing for interaction with non-standard or experimental LIFX features. ```javascript /** * @param {Uint8Array} bytes * @param {{ current: number; }} */ function decodeCustom(bytes, offsetRef) { const val1 = bytes[offsetRef.current++]; const val2 = bytes[offsetRef.current++]; return { val1, val2 }; } function CustomCommand() { return { type: 1234, decode: decodeCustom, }; } const res = await client.send(CustomCommand(), device); console.log(res.val1, res.val2); ``` -------------------------------- ### Get Ambient Light Level (SensorGetAmbientLight - Packet 401) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md Retrieves the current ambient light level detected by a device's sensor. The device will respond to this query with a 'SensorStateAmbientLight (402)' message, providing the measured light intensity. ```APIDOC SensorGetAmbientLight (Packet 401): Description: Get the current ambient light level from a device. Returns: SensorStateAmbientLight (402) Parameters: None ``` -------------------------------- ### Handling Router and Client Message Callbacks (JavaScript) Source: https://github.com/jmmoser/lifxlan/blob/main/README.md This example demonstrates how to implement `onMessage` callbacks at both the `Router` and `Client` levels. The router-level callback intercepts all incoming messages, while the client-level callback processes messages specifically relevant to that client, providing flexible message handling. ```javascript // Router-level message callback (all messages) const router = Router({ onMessage(header, payload, serialNumber) { console.log('Router received:', header.type); }, }); // Client-level message callback (messages for this client) const client = Client({ router, onMessage(header, payload, serialNumber) { console.log('Client received:', header.type); }, }); ``` -------------------------------- ### GetPower - Packet 20 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet allows for querying the current power level or state of the LIFX device. ```APIDOC Message Type: GetPower (Packet 20) Payload: Empty Purpose: Determine device power level Expected Response: StatePower (Packet 22) - 1 message ``` -------------------------------- ### GetHevCycleConfiguration - Packet 145 (Light) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet is used to determine the default configuration for using the HEV LEDs on the device. It requires the device to have the `hev` capability. It will return one StateHevCycleConfiguration (147) message. ```APIDOC GetHevCycleConfiguration: Packet ID: 145 Purpose: Determine the default configuration for using the HEV LEDs on the device. Requirements: Device must have `hev` capability (check with GetVersion (32), GetHostFirmware (14), Product Registry). Returns: StateHevCycleConfiguration (147) ``` -------------------------------- ### GetWifiFirmware - Packet 18 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md For first and second-generation LIFX devices, which feature separate Wi-Fi firmware from the host firmware, this message is used to retrieve the version of the Wi-Fi firmware. ```APIDOC Message Type: GetWifiFirmware (Packet 18) Payload: Empty Purpose: Determine Wi-Fi firmware version (for specific device generations) Expected Response: StateWifiFirmware (Packet 19) - 1 message ``` -------------------------------- ### Change LIFX light color and transition Source: https://github.com/jmmoser/lifxlan/blob/main/README.md This example shows how to use the 'SetColorCommand' to modify the color (hue, saturation, brightness, kelvin) of a LIFX light. It also demonstrates how to specify a transition duration for smooth color changes, providing fine-grained control over the light's appearance. ```javascript import { SetColorCommand } from 'lifxlan/index.js'; // Set to bright red await client.send( SetColorCommand(0, 65535, 65535, 3500, 0), // hue, saturation, brightness, kelvin, duration device ); // Set to blue with 2-second transition await client.send( SetColorCommand(43690, 65535, 65535, 3500, 2000), device ); ``` -------------------------------- ### Implementing Party Mode with Animated Colors (JavaScript) Source: https://github.com/jmmoser/lifxlan/blob/main/README.md This snippet provides an example of an animated color loop, simulating a 'party mode' for LIFX devices. It cycles through a predefined array of colors, randomly selecting one and applying it to each discovered device with a short delay, creating a dynamic light show. ```javascript const PARTY_COLORS = [ [48241, 65535, 65535, 3500], // Red [43690, 49151, 65535, 3500], // Blue [54612, 65535, 65535, 3500], // Green [43690, 65535, 65535, 3500], // Cyan [38956, 55704, 65535, 3500], // Purple ]; while (true) { for (const device of devices) { const [hue, saturation, brightness, kelvin] = PARTY_COLORS[Math.floor(Math.random() * PARTY_COLORS.length)]; client.unicast( SetColorCommand(hue, saturation, brightness, kelvin, 1000), device ); await new Promise(resolve => setTimeout(resolve, 100)); } } ``` -------------------------------- ### Get Tile Effect Status (GetTileEffect - Packet 718) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md Determines if a device is currently running a Firmware Effect. Upon sending this packet, the device will respond with a 'StateTileEffect (720)' message, indicating the status of any active firmware effects. ```APIDOC GetTileEffect (Packet 718): Description: Determine if the device is running a Firmware Effect. Returns: StateTileEffect (720) Parameters: reserved6: 1 Reserved bytes reserved7: 1 Reserved bytes ``` -------------------------------- ### Configuring Separate Sockets for Broadcast/Unicast (JavaScript) Source: https://github.com/jmmoser/lifxlan/blob/main/README.md This snippet illustrates how to configure the `Router` to use separate UDP sockets for broadcast and unicast messages. This advanced setup allows for more granular control over network communication, potentially optimizing performance or handling specific network topologies. ```javascript const broadcastSocket = dgram.createSocket('udp4'); const unicastSocket = dgram.createSocket('udp4'); const router = Router({ onSend(message, port, address, serialNumber) { if (!serialNumber) { broadcastSocket.send(message, port, address); } else { unicastSocket.send(message, port, address); } }, }); // ... handle messages from both sockets ... ``` -------------------------------- ### GetLightPower - Packet 116 (Light) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet will return the current power level of the device, similar to GetPower (20). It will return one StateLightPower (118) message. ```APIDOC GetLightPower: Packet ID: 116 Purpose: Return the current power level of the device. Returns: StateLightPower (118) ``` -------------------------------- ### LIFX LAN API: SetTileEffect - Packet 719 Structure Source: https://github.com/jmmoser/lifxlan/blob/main/docs/changing-a-device.md Defines the structure and parameters for the SetTileEffect packet (719) used to start a Firmware Effect on a LIFX device. Each field includes its type, size, and a description of its purpose and any specific usage notes. ```APIDOC SetTileEffect - Packet 719: reserved0: 1 Reserved bytes reserved1: 1 Reserved bytes 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: 4 Reserved bytes reserved3: 4 Reserved bytes skyType: TileEffectSkyType (only used on SKY effect) reserved4: 3 Reserved bytes cloudSaturationMin: 1 Bytes (only used on SKY effect when using CLOUDS, recommended default is 50) reserved5: 3 Reserved bytes reserved6: 24 Reserved bytes (This field is currently ignored by all firmware effects.) palette_count: Uint8 (The number of values in palette that you want to use.) palette: 16 Color structures (The HSBK values to be used by the effect. On the MORPH effect this is used as the palette for generating the effect. With the SKY effect, the indices specified in TileEffectSkyPalette dictate how each color will be used.) ``` -------------------------------- ### Calculate Expected MultiZone Messages (Pseudo-code) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This pseudo-code demonstrates how to calculate the expected number of StateMultiZone messages to receive when querying color zones. It considers both the request's range and the first response's zone count to determine the minimum expected messages. ```Pseudo-code 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) ``` -------------------------------- ### GetHevCycle - Packet 142 (Light) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet is used to determine the state of the HEV LEDs on the device. It requires the device to have the `hev` capability. It will return one StateHevCycle (144) message. ```APIDOC GetHevCycle: Packet ID: 142 Purpose: Determine the state of the HEV LEDs on the device. Requirements: Device must have `hev` capability (check with GetVersion (32), GetHostFirmware (14), Product Registry). Returns: StateHevCycle (144) ``` -------------------------------- ### Controlling Response Modes with `client.send()` Source: https://github.com/jmmoser/lifxlan/blob/main/README.md Demonstrates the `client.send()` method's flexible response modes (`auto`, `ack-only`, `response`, `both`) with full type safety, where the return type adapts based on the chosen mode. It also shows how to incorporate an `AbortSignal` for command cancellation. Get commands default to 'response', while Set commands default to 'ack-only'. For fire-and-forget, `client.unicast()` can be used. ```JavaScript // Use command defaults (recommended) const color = await client.send(GetColorCommand(), device); // Promise await client.send(SetPowerCommand(true), device); // Promise (ack-only default) // Override response behavior with type-safe returns await client.send(command, device, { responseMode: 'ack-only' }); // Promise const data = await client.send(command, device, { responseMode: 'response' }); // Promise const result = await client.send(command, device, { responseMode: 'both' }); // Promise // With abort signal const response = await client.send(GetColorCommand(), device, { responseMode: 'both', // TypeScript knows this returns Promise signal: abortController.signal }); console.log(response.hue); // ✅ TypeScript knows response is LightState ``` -------------------------------- ### LIFX LAN API: GetMultiZoneEffect (Packet 507) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md Documents the GetMultiZoneEffect packet, used to check if a device is running a multizone Firmware Effect. It returns a StateMultiZoneEffect (509) message and requires the 'Linear Zones' capability. ```APIDOC Packet: GetMultiZoneEffect (507) Purpose: Determine if the device is running a multizone Firmware Effect. Returns: StateMultiZoneEffect (509) message. Requirements: Device must have 'Linear Zones' capability. Related: GetVersion (32), GetHostFirmware (14), Product Registry. ``` -------------------------------- ### Get HSBK Values for Zones (Get64 - Packet 707) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md Used to retrieve the HSBK color values for all zones within devices connected in a chain. This operation necessitates the 'Matrix Zones' capability. The device will return one or more 'State64 (711)' messages, with the maximum number of messages limited by the 'length' parameter in the request. ```APIDOC Get64 (Packet 707): Description: Get HSBK values of all zones in chained devices. Requires Capability: Matrix Zones Returns: State64 (711) (one or more) Parameters: tile_index: Uint8 - The first item in the chain you want zones. length: Uint8 - The number of tiles after tile_index you want HSBK values from. reserved6: 1 Reserved bytes x: Uint8 - The x value to start from. You likely always want this to be 0. y: Uint8 - The y value to start from. You likely always want this to be 0. width: Uint8 - The width of each item in the chain. For the LIFX Tile you want this to be 8 and for the LIFX Candle you want this to be 5. ``` -------------------------------- ### EchoRequest - Packet 58 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet can be used to check that a device is online and responding. It includes a payload that will be echoed back in the response. It will return one EchoResponse (59) message. ```APIDOC EchoRequest: Packet ID: 58 Purpose: Check if a device is online and responding. Parameters: echoing: 64 Bytes - The bytes you want to receive in the EchoResponse (59) message. Returns: EchoResponse (59) ``` -------------------------------- ### GetWifiInfo - Packet 16 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet is utilized to query and determine the current Wi-Fi signal strength of the LIFX device. ```APIDOC Message Type: GetWifiInfo (Packet 16) Payload: Empty Purpose: Determine device Wi-Fi signal strength Expected Response: StateWifiInfo (Packet 17) - 1 message ``` -------------------------------- ### GetVersion - Packet 32 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet is used to determine the product type of the LIFX device. This information is typically used to understand the device's specific capabilities as defined by the LIFX Product Registry. ```APIDOC Message Type: GetVersion (Packet 32) Payload: Empty Purpose: Determine device product type and capabilities Expected Response: StateVersion (Packet 33) - 1 message ``` -------------------------------- ### GetLabel - Packet 23 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet is used to retrieve the user-defined label or name that has been set on the LIFX device. ```APIDOC Message Type: GetLabel (Packet 23) Payload: Empty Purpose: Determine device label Expected Response: StateLabel (Packet 25) - 1 message ``` -------------------------------- ### StateDeviceChain - Packet 702 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/information-messages.md This packet provides information about each device in a chain, requiring the `Matrix Zones` capability. It serves as a reply to the `GetDeviceChain (701)` message. Fields include the starting index, an array of tile device structures, and the count of relevant devices. ```APIDOC StateDeviceChain (Packet 702): start_index: Uint8 - The index of the first device in the chain this packet refers to tile_devices: 16 Tile structures - The information for each device in the chain tile_devices_count: Uint8 - The number of device in `tile_devices` that map to devices in the chain. ``` -------------------------------- ### GetLocation - Packet 48 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet can be used to determine the UUID and label of the location assigned to this device. It will return one StateLocation (50) message. ```APIDOC GetLocation: Packet ID: 48 Purpose: Determine the UUID and label of the location assigned to the device. Returns: StateLocation (50) ``` -------------------------------- ### GetGroup - Packet 51 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet can be used to determine the UUID and label of the group assigned to this device. It will return one StateGroup (53) message. ```APIDOC GetGroup: Packet ID: 51 Purpose: Determine the UUID and label of the group assigned to the device. Returns: StateGroup (53) ``` -------------------------------- ### GetInfrared - Packet 120 (Light) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet is used to determine the current infrared level of the device. It requires the device to have the `infrared` capability. It will return one StateInfrared (121) message. ```APIDOC GetInfrared: Packet ID: 120 Purpose: Determine the current infrared level of the device. Requirements: Device must have `infrared` capability (check with GetVersion (32), GetHostFirmware (14), Product Registry). Returns: StateInfrared (121) ``` -------------------------------- ### GetService - Packet 2 (Discovery) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet is used for discovering LIFX devices on the network. It should typically be broadcast with the `tagged` field in the header set to `0` and the `target` field set to all zeros. Each device receiving this packet will respond with multiple `StateService (3)` messages, primarily indicating `UDP` service availability on port `56700`. ```APIDOC Message Type: GetService (Packet 2) Payload: Empty Purpose: Device discovery Expected Response: StateService (Packet 3) - Multiple messages ``` -------------------------------- ### GetInfo - Packet 34 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md This packet can be used to retrieve various operational details about the device, including its uptime, downtime, and the current time according to the device's internal clock. ```APIDOC Message Type: GetInfo (Packet 34) Payload: Empty Purpose: Determine device uptime, downtime, and current time Expected Response: StateInfo (Packet 35) - 1 message ``` -------------------------------- ### Get Relay Power State (GetRPower - Packet 816) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md Retrieves the power state of a specific relay on a LIFX switch device. This operation requires the device to possess the 'Relays' capability. Upon successful execution, the device will return a 'StateRPower (818)' message, indicating the current power status of the specified relay. ```APIDOC GetRPower (Packet 816): Description: Get the power state of a relay on a switch device. Requires Capability: Relays Returns: StateRPower (818) Parameters: relay_index: Uint8 - The relay on the switch starting from 0. ``` -------------------------------- ### LIFX LAN API: GetColorZones (Packet 502) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md Documents the GetColorZones packet, used to retrieve color zone information. It can return StateZone (503) for single zones or StateMultiZone (506) for multiple zones. Requires 'Linear Zones' capability. ```APIDOC Packet: GetColorZones (502) Purpose: Get color zone information from the device. Returns: - StateZone (503) if only one zone. - StateMultiZone (506) for multiple zones (one or more replies). Parameters: - start_index: Uint8 (The first zone to get information from) - end_index: Uint8 (The last zone to get information from) Note: Set start_index to 0 and end_index to 255 to get all zones. Requirements: Device must have 'Linear Zones' capability. Related: GetVersion (32), GetHostFirmware (14), Product Registry. ``` -------------------------------- ### SetHevCycle - Packet 143 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/changing-a-device.md This packet enables starting or stopping a HEV (High Energy Visible) cycle on a LIFX device. The device must possess the `hev` capability, verifiable through GetVersion (32), GetHostFirmware (14), and the Product Registry. A StateHevCycle (144) message is returned after the operation. ```APIDOC Packet: SetHevCycle (143) Description: Start or stop a HEV cycle on the device. Returns: StateHevCycle (144) Requires Capability: hev Fields: enable: BoolInt Description: Set this to false to turn off the cycle and true to start the cycle. duration_s: Uint32 Description: The duration, in seconds, that the cycle should last for. A value of 0 will use the default duration set by SetHevCycleConfiguration (146). ``` -------------------------------- ### LIFX LAN API: GetExtendedColorZones (Packet 511) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md Documents the GetExtendedColorZones packet, used to retrieve HSBK values for all zones. It returns StateExtendedColorZones (512) messages, potentially multiple if the device has more than 82 zones. Requires 'Extended Linear Zones' capability. ```APIDOC Packet: GetExtendedColorZones (511) Purpose: Get HSBK values for every zone on the strip. Returns: StateExtendedColorZones (512) messages. - Multiple responses if > 82 zones, with different 'zone_index' values. - 'zone_count' property indicates total zones. Requirements: Device must have 'Extended Linear Zones' capability. Related: GetVersion (32), GetHostFirmware (14), Product Registry. ``` -------------------------------- ### LIFX LAN API: GetLastHevCycleResult (Packet 148) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/querying-the-device-for-data.md Documents the GetLastHevCycleResult packet, used to query the result of the last HEV cycle. It returns a StateLastHevCycleResult (149) message and requires the device to have the 'hev' capability. ```APIDOC Packet: GetLastHevCycleResult (148) Purpose: Determine the result of the last HEV cycle. Returns: StateLastHevCycleResult (149) message. Requirements: Device must have 'hev' capability. Related: GetVersion (32), GetHostFirmware (14), Product Registry. ``` -------------------------------- ### Common Development Commands for LIFX LAN Library Source: https://github.com/jmmoser/lifxlan/blob/main/CLAUDE.md Provides a list of essential commands for developing and maintaining the LIFX LAN protocol library, including testing, building, type checking, and linting. These commands are executed using Bun or npx. ```Shell bun run test ``` ```Shell bun run build ``` ```Shell npx tsc ``` ```Shell bun run lint ``` -------------------------------- ### Using Multiple `lifxlan` Clients Source: https://github.com/jmmoser/lifxlan/blob/main/README.md Demonstrates how to instantiate and use multiple `Client` instances within the same application. Both clients share the same `Router`, allowing them to operate independently while efficiently managing network communication. This pattern is useful for organizing different sets of interactions or concurrent operations. ```JavaScript const client1 = Client({ router }); const client2 = Client({ router }); // Both clients share the same router and can operate independently await client1.broadcast(GetServiceCommand()); await client2.send(SetPowerCommand(true), device); ``` -------------------------------- ### Sending Commands Without Device Discovery Source: https://github.com/jmmoser/lifxlan/blob/main/README.md Explains how to interact with a LIFX device directly without relying on the discovery process. This is achieved by manually creating a `Device` instance with its known serial number and IP address, then using this instance with `client.send()` to control the device. ```JavaScript import { Client, Device, Router, SetPowerCommand } from 'lifxlan/index.js'; // ... socket setup ... const client = Client({ router }); // Create the device directly const device = Device({ serialNumber: 'd07123456789', address: '192.168.1.50', }); await client.send(SetPowerCommand(true), device); ``` -------------------------------- ### Execute Full Code Quality Checks Source: https://github.com/jmmoser/lifxlan/blob/main/CLAUDE.md A combined command to perform linting, TypeScript type checking, and run all tests sequentially. This ensures comprehensive code quality and correctness before commits or releases, following the project's quality standards. ```Shell bun run lint && npx tsc && bun run test ``` -------------------------------- ### Implementing Error Handling with Retries Source: https://github.com/jmmoser/lifxlan/blob/main/README.md Demonstrates a common pattern for robust error handling using a retry loop with exponential backoff. This snippet attempts to send a `GetColorCommand` multiple times, introducing a random delay between retries to mitigate transient network issues and improve reliability. ```JavaScript for (let i = 0; i < 3; i++) { try { console.log(await client.send(GetColorCommand(), device)); break; } catch (err) { const delay = Math.random() * Math.min(Math.pow(2, i) * 1000, 30 * 1000); await new Promise((resolve) => setTimeout(resolve, delay)); } } ``` -------------------------------- ### Controlling Response Modes for LIFX Commands (JavaScript) Source: https://github.com/jmmoser/lifxlan/blob/main/README.md This snippet illustrates different response modes when sending commands to LIFX devices. It covers 'both' for high reliability with typed returns, 'fire-and-forget' for fast animations, 'ack-only' for confirmation without data, and 'response' for receiving typed data. ```javascript // High-reliability mode: wait for both ack and response (typed return) const state = await client.send(SetColorCommand(120, 100, 100, 3500, 1000), device, { responseMode: 'both' // TypeScript knows this returns Promise }); console.log('Confirmed color:', state.hue); // ✅ Fully typed // Fast mode: fire-and-forget for animations (no promise) for (let i = 0; i < 360; i += 10) { client.unicast(SetColorCommand(i * 182, 65535, 65535, 3500, 100), device); await new Promise(resolve => setTimeout(resolve, 50)); } // Confirmation only (void return) await client.send(SetColorCommand(120, 100, 100, 3500, 0), device, { responseMode: 'ack-only' // TypeScript knows this returns Promise }); // Get response data (typed return) const currentState = await client.send(SetColorCommand(120, 100, 100, 3500, 0), device, { responseMode: 'response' // TypeScript knows this returns Promise }); console.log('Light is now:', currentState.hue); // ✅ Fully typed, no assertions needed ``` -------------------------------- ### Setting Custom Timeouts for Commands Source: https://github.com/jmmoser/lifxlan/blob/main/README.md Illustrates how to implement custom timeouts for `client.send()` operations using an `AbortController`. This pattern ensures that commands do not hang indefinitely, automatically aborting the operation after a specified duration and allowing for proper cleanup. ```JavaScript const controller = new AbortController(); const timeout = setTimeout(() => { controller.abort(); }, 100); try { console.log(await client.send(GetColorCommand(), device, { signal: controller.signal })); } finally { clearTimeout(timeout) } ``` -------------------------------- ### LIFX LAN Protocol: StateHostFirmware Packet (15) Definition Source: https://github.com/jmmoser/lifxlan/blob/main/docs/information-messages.md Defines the structure of the StateHostFirmware packet, providing details about the device's host firmware version. This information, combined with StateVersion (33), helps determine device capabilities. This packet is a reply to the GetHostFirmware (14) message. ```APIDOC StateHostFirmware - Packet 15: build: Uint64 (The timestamp of the firmware that is on the device as an epoch) reserved6: 8 Reserved bytes version_minor: Uint16 (The minor component of the firmware version) version_major: Uint16 (The Major component of the firmware version) ``` -------------------------------- ### SetLightPower - Packet 117 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/changing-a-device.md This is the same as SetPower (21) but allows you to specify how long it will take to transition to the new power state. Will return one StateLightPower (118) message. ```APIDOC Packet: SetLightPower (117) Returns: StateLightPower (118) Parameters: level: Uint16 - If you specify `0` the light will turn off and if you specify `65535` the device will turn on. duration: Uint32 - The time it will take to transition to the new state in milliseconds. ``` -------------------------------- ### State64 - Packet 711 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/information-messages.md This packet conveys the current HSBK color values for zones within a single device, also requiring the `Matrix Zones` capability. It is a response to both `Get64 (707)` and `Set64 (715)` messages. Key fields include the tile index, coordinates, width, and an array of 64 color structures. ```APIDOC State64 (Packet 711): tile_index: Uint8 - The index of the device in the chain this packet refers to. This is `0` based starting from the device closest to the controller. reserved6: 1 Reserved bytes x: Uint8 - The x coordinate the colors start from y: Uint8 - The y coordinate the colors start from width: Uint8 - The width of each row colors: 64 Color structures ``` -------------------------------- ### SetWaveformOptional - Packet 119 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/changing-a-device.md This behaves like SetWaveform (103) but allows you to keep certain parts of the original HSBK values during the transition. Will return one LightState (107) message. ```APIDOC Packet: SetWaveformOptional (119) Returns: LightState (107) Parameters: reserved6: 1 Reserved bytes transient: BoolInt - See Waveforms hue: Uint16 saturation: Uint16 brightness: Uint16 kelvin: Uint16 period: Uint32 - See Waveforms cycles: Float - See Waveforms skew_ratio: Int16 - See Waveforms waveform: Uint8 using Waveform Enum - See Waveforms set_hue: BoolInt - Use the hue value in this message set_saturation: BoolInt - Use the saturation value in this message set_brightness: BoolInt - Use the brightness value in this message set_kelvin: BoolInt - Use the kelvin value in this message ``` -------------------------------- ### LIFX LAN Protocol: StateWifiFirmware Packet (19) Definition Source: https://github.com/jmmoser/lifxlan/blob/main/docs/information-messages.md Defines the structure of the StateWifiFirmware packet, providing details about the device's Wi-Fi firmware version. This packet is a reply to the GetWifiFirmware (18) message. ```APIDOC StateWifiFirmware - Packet 19: build: Uint64 (The timestamp when the wifi firmware was created as an epoch, This is only relevant for the first two generations of our products.) reserved6: 8 Reserved bytes version_minor: Uint16 (The minor component of the version.) version_major: Uint16 (The major component of the version.) ``` -------------------------------- ### SetColor - Packet 102 (LIFX Light API) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/changing-a-device.md This packet allows setting the HSBK (Hue, Saturation, Brightness, Kelvin) color value for a LIFX light. For devices that have multiple zones, this will set all zones to the specified color. It includes a 'duration' parameter for the transition time. Upon successful execution, it returns a LightState (107) message. ```APIDOC Packet Name: SetColor Packet ID: 102 Description: Sets the HSBK value for the light. For devices with multiple zones, this sets all Zones. Returns: LightState (107) Parameters: - reserved6: 1 Reserved bytes - hue: Uint16 - saturation: Uint16 - brightness: Uint16 - kelvin: Uint16 - duration: Uint32 Description: The time in milliseconds to transition to the new HSBK color. ``` -------------------------------- ### LIFX LAN Protocol: SetMultiZoneEffect (Packet 508) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/changing-a-device.md Initiates a multizone firmware effect on a LIFX device. This message requires the device to possess the 'Linear Zones' capability and will result in a StateMultiZoneEffect (509) message being returned. ```APIDOC SetMultiZoneEffect (Packet 508): Description: Start a multizone Firmware Effect on the device. Returns: StateMultiZoneEffect (509) Requirements: Linear Zones capability Parameters: instanceid: Uint32 - A unique number identifying this effect. type: Uint8 (MultiZoneEffectType Enum) reserved6: 2 Reserved bytes 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. reserved7: 4 Reserved bytes reserved8: 4 Reserved bytes parameters: 32 Bytes - This field is 8 4-byte fields which change meaning based on the effect that is running. When the effect is MOVE only the second field is used and is a Uint32 representing the DIRECTION enum. This field is currently ignored for all other multizone effects. ``` -------------------------------- ### SetWaveform - Packet 103 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/changing-a-device.md This packet lets you set the HSBK and Waveforms value for the light. For devices that have multiple zones, this will treat all the zones on the device as one. Will return one LightState (107) message. ```APIDOC Packet: SetWaveform (103) Returns: LightState (107) Parameters: reserved6: 1 Reserved bytes transient: BoolInt - See Waveforms hue: Uint16 saturation: Uint16 brightness: Uint16 kelvin: Uint16 period: Uint32 - See Waveforms cycles: Float - See Waveforms skew_ratio: Int16 - See Waveforms waveform: Uint8 using Waveform Enum - See Waveforms ``` -------------------------------- ### StateVersion - Packet 33: Device Firmware Version Source: https://github.com/jmmoser/lifxlan/blob/main/docs/information-messages.md This packet provides the firmware version details of the device, including vendor and product IDs. This information can be used with the Product Registry to determine device capabilities. It is a reply to the GetVersion (32) message. ```APIDOC StateVersion (Packet 33) Fields: vendor: Uint32 (For LIFX products this value is 1. There may be devices in the future with a different vendor value.) product: Uint32 (The product id of the device. The available products can be found in our Product Registry.) reserved6: 4 Reserved bytes ``` -------------------------------- ### StateMultiZone - Packet 506 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/information-messages.md This packet represents a segment of 8 HSBK values on your strip. It requires the device to have the `Linear Zones` capability. This packet is the reply to the GetColorZones (502) and SetColorZones (501) messages. ```APIDOC StateMultiZone (Packet 506): zones_count: Uint8 - The total number of zones on your strip zone_index: Uint8 - The first zone represented by this packet colors: 8 Color structures - The HSBK values of the zones this packet refers to. ``` -------------------------------- ### StateTileEffect - Packet 720 Source: https://github.com/jmmoser/lifxlan/blob/main/docs/information-messages.md This packet describes the current Firmware Effect running on a device, requiring the `Matrix Zones` capability. It replies to `GetTileEffect (718)` and `SetTileEffect (719)` messages. It includes details such as effect type, speed, duration, specific sky effect parameters, and a color palette. ```APIDOC StateTileEffect (Packet 720): reserved0: 1 Reserved bytes instanceid: Uint32 - The unique value identifying the request type: Uint8 (using TileEffectType Enum) speed: Uint32 - The time it takes for one cycle in milliseconds. duration: Uint64 - The amount of time left in the current effect in nanoseconds reserved1: 4 Reserved bytes reserved2: 4 Reserved bytes skyType: TileEffectSkyType (only used on SKY effect) reserved3: 3 Reserved bytes cloudSaturationMin: 1 Bytes (only used on SKY effect when using CLOUDS) reserved4: 3 Reserved bytes cloudSaturationMax: 1 Bytes (only used on SKY effect when using CLOUDS (recommended default is 180)) reserved5: 23 Reserved bytes - This field is currently ignored by all firmware effects. palette_count: Uint8 - The number of colors in the `palette` that are relevant palette: 16 Color structures - The colors specified for the effect. ``` -------------------------------- ### SetReboot - Packet 38 (LIFX Device API) Source: https://github.com/jmmoser/lifxlan/blob/main/docs/changing-a-device.md This packet instructs a LIFX device to perform a reboot, similar to a power cycle. The documentation does not specify any parameters or return messages for this packet. ```APIDOC Packet Name: SetReboot Packet ID: 38 Description: Instructs the device to perform a reboot similar to if it had been power cycled. ```