@bobfrankston/lxlan
Core LIFX LAN protocol library. Transport-agnostic implementation of the LIFX LAN protocol for controlling LIFX devices over local networks.
Purpose
This package provides the protocol-level implementation for LIFX device control. It knows:
- ✅ LIFX protocol messages (SetPower, SetColor, GetState, etc.)
- ✅ Message encoding/decoding (binary packet format)
- ✅ Device state management (power, color, label, etc.)
- ✅ Event emission patterns (device discovery, state updates)
It does NOT know:
- ❌ How to send UDP packets (no Node.js dgram)
- ❌ How to open WebSockets (no browser APIs)
- ❌ Any specific transport implementation
Architecture Factoring
┌─────────────────────────────────────────────────┐
│ Application (your code) │
├─────────────────────────────────────────────────┤
│ @bobfrankston/lxlan (this package) │
│ • LxClient - device discovery & management │
│ • LxDevice - individual device control │
│ • LxProtocol - message encode/decode │
│ • LxTransport - alias for UdpTransport │
├─────────────────────────────────────────────────┤
│ Shared Transport (pick one): │
│ • @bobfrankston/node-transport → Node dgram │
│ • @bobfrankston/browser-transport → httpudp WS │
├─────────────────────────────────────────────────┤
│ @bobfrankston/udp-transport (interface only) │
└─────────────────────────────────────────────────┘
Legacy wrappers (lxlan-node, lxlan-browser) pre-wire transport + event emitter and re-export everything. These are deprecated — use @bobfrankston/lxlan directly with a shared transport package instead (see Direct Usage below).
Transport Abstraction
LxTransport is an alias for UdpTransport from @bobfrankston/udp-transport:
export interface UdpTransport {
bind(): Promise<void>;
close(): void;
send(ip: string, port: number, data: Uint8Array): void;
broadcast(data: Uint8Array, port: number): void;
onMessage(handler: (data: Uint8Array, rinfo: RemoteInfo) => void): void;
onError(handler: (err: Error) => void): void;
onClose(handler: () => void): void;
}
Shared transport implementations:
- Node.js:
NodeUdpTransport from @bobfrankston/node-transport (dgram)
- Browser:
BrowserUdpTransport from @bobfrankston/browser-transport (httpudp WebSocket)
See transport-architecture.md for the full transport stack reference.
Installation
npm install @bobfrankston/lxlan
Then pick a transport for your platform:
npm install @bobfrankston/node-transport
npm install @bobfrankston/browser-transport
Note: The legacy convenience wrappers @bobfrankston/lxlan-node and @bobfrankston/lxlan-browser are deprecated. Use @bobfrankston/lxlan directly with a shared transport package instead.
Direct Usage (No Wrapper)
Pass a transport factory — LxClient creates the transport and emitter internally:
import { LxClient } from '@bobfrankston/lxlan';
import { NodeUdpTransport } from '@bobfrankston/node-transport';
const client = new LxClient({
Transport: NodeUdpTransport,
});
await client.start();
client.on('device', (device) => {
console.log('Found:', device.label);
device.setPower(true);
device.setColor({ h: 120, s: 100, b: 50 });
});
For custom transport config (e.g., browser with specific httpudp URL):
import { LxClient } from '@bobfrankston/lxlan';
import { BrowserUdpTransport } from '@bobfrankston/browser-transport';
const client = new LxClient({
Transport: { create: (port) => new BrowserUdpTransport({ httpudpUrl: 'ws://myserver:8080' }) },
});
Features
- 🎯 Full LIFX LAN protocol support
- 🔍 Automatic device discovery
- 🎨 Color control (HSB, RGB, Kelvin)
- 💡 Power control
- 📊 Device state caching
- 📡 Event-driven architecture
- 🔄 Automatic retry with configurable timeouts
- 📝 Comprehensive device info (firmware, WiFi, uptime)
LxDevice
Extends DeviceBase from @bobfrankston/devdefs — shared state (mac, ip, port, power, label, online, lastSeen, markSeen()) and transport plumbing. See devdefs README for base class details and MAC utilities (mac12, macmac).
Device Control
device.setPower(true);
device.setPower(false);
device.setColor({ h: 180, s: 100, b: 75 });
device.setColor({ r: 255, g: 0, b: 0 });
device.setColor({ kelvin: 3500 });
device.getDeviceInfo();
console.log(device.label, device.power, device.color);
Events
client.on('device', (device) => {
});
client.on('state', (device, info) => {
if (info.primary) {
console.log('Direct update from device');
}
});
client.on('deviceInfo', (device) => {
console.log(device.firmwareVersion, device.signal, device.uptime);
});
Dependencies
@bobfrankston/devdefs - Shared device base class (DeviceBase, mac12, macmac)
@bobfrankston/colorlib - Color space conversions (HSB ↔ RGB ↔ Kelvin)
Legacy Wrappers (Deprecated)
lxlan-node and lxlan-browser are legacy convenience wrappers that pre-wire transport + event emitter. They still work but are deprecated — prefer direct usage with shared transport packages. No new features will be added to the wrappers.
Importing Types
Types should be imported from this package using import type:
import type { StateEventInfo, DeviceState } from '@bobfrankston/lxlan';
Related Packages
TypeScript Configuration
This package uses strictNullChecks: false - undefined is treated as a first-class value throughout the codebase.
License
MIT