A framework for creating LIFX Tile effects. 👨🔬💡
- Overview
- Requirements
- Installation
- Usage
- Configuration
- Example Effects
- Example Repositories
- Device Cache
- Troubleshooting
- Credits
- License
The lifx-tile-effects-framework
package:
- Discovers and caches your LIFX devices
- Displays a menu for selecting a Tile device
- Auto-selects your Tile device if only one is discovered
- Discovers your custom Tile effect files
- Displays a menu for selecting a Tile effect
- Auto-selects your Tile effect if only one is discovered
- Creates your Tile effect
- Injects
device
,tiles
andbounds
objects
- Injects
- Exposes CLI options to:
- Run an effect directly (
--effect
,-e
) - Clear your cached devices (
--clear-cache
,-c
) - Display a help screen (
--help
,-h
)
- Run an effect directly (
node -v
>=v12.10.*
npm -v
>=6.10.*
- One or more LIFX Tiles accessible via LAN
$ npm install furey/lifx-tile-effects-framework#semver:^v1
Add the following code block to your script:
// example.js
require('lifx-tile-effects-framework')
.run()
.catch(console.error)
Assuming your configured EFFECTS_PATH
contained the effect files…
effect-1.js
effect-2.js
etc.js
…running the example.js
script above would log the following output:
$ node example.js
? Choose an effect …
effect-1
❯ effect-2
etc
✔ Choose an effect · effect-2
Starting effect-2 effect… (press [ctrl+c] to exit)
Add the following .env
file to your repository root:
EFFECTS_PATH=path/to/my/effects/directory
Set EFFECTS_PATH
to the directory containing your effect files.
Add one or more effect files into your EFFECTS_PATH
directory:
path/to/my/effects/directory
├── effect-1.js
├── effect-2.js
└── etc.js
Effect files must conform to the following interface:
module.exports = class {
// Color to flush tiles with before effect runs…
static getFlushColor()
// Effect instantiation method…
static async create({ device, tiles, bounds })
}
For example implementations, see the Example Effects section below.
The getFlushColor
method must return a LifxLanColor
object to flush your tiles with before your effect is instantiated.
The create
method receives an object containing the following properties to instantiate your effect with:
Property | Description | Documentation |
---|---|---|
device |
A LIFX device object | See: LifxLanDevice |
tiles |
An array of tile objects | See: tileGetTiles() |
bounds |
A spacial bounds object | See: tileGetTilesAndBounds() |
The following example effect files are outlined below:
Sets all tiles to the same random color every second:
module.exports = class {
static getFlushColor() {
return { saturation: 1, brightness: 0, kelvin: 9000 }
}
static async create({ device, tiles }) {
return await (new this({ device, tiles })).boot()
}
constructor({ device, tiles }) {
this.device = device
this.tiles = tiles
}
async boot() {
await this.step()
setInterval(async () => await this.step(), 1000)
}
async step() {
await this.device.tileSetTileState64({
tile_index: this.tiles[0].tile_index,
length: this.tiles.length,
colors: [...Array(64)].fill({
hue: Math.floor(Math.random() * 360)/360,
brightness: 1,
})
}).catch(console.error)
}
}
Sets each tile to a different random color every second:
module.exports = class {
static getFlushColor() {
return { saturation: 1, brightness: 0, kelvin: 9000 }
}
static async create({ device, tiles }) {
return await (new this({ device, tiles })).boot()
}
constructor({ device, tiles }) {
this.device = device
this.tiles = tiles
}
async boot() {
await this.step()
setInterval(async () => await this.step(), 1000)
}
async step() {
for (let i = 0; i < this.tiles.length; i++) {
const tile = this.tiles[i]
await this.device.tileSetTileState64({
tile_index: tile.tile_index,
colors: [...Array(64)].fill({
hue: Math.floor(Math.random() * 360)/360,
brightness: 1
})
}).catch(console.error)
}
}
}
Fades each tile's 64 pixels to different random colors every second:
module.exports = class {
static getFlushColor() {
return { saturation: 0, brightness: 0, kelvin: 9000 }
}
static async create({ device, tiles }) {
return await (new this({ device, tiles })).boot()
}
constructor({ device, tiles }) {
this.device = device
this.tiles = tiles
}
async boot() {
await this.step()
setInterval(async () => await this.step(), 1000)
}
async step() {
for (let i = 0; i < this.tiles.length; i++) {
const tile = this.tiles[i]
await this.device.tileSetTileState64({
tile_index: tile.tile_index,
duration: 500,
colors: [...Array(64)].map(() => ({
hue: Math.floor(Math.random() * 360)/360,
saturation: 1,
brightness: 1,
}))
}).catch(console.error)
}
}
}
See the following repositories for advanced usage examples:
To increase the speed of script re-execution, your LIFX devices are cached on first run.
If a new LIFX device is added to your network but not discovered by the framework, refresh your device cache by passing --clear-cache
the next time you run your script:
$ node example.js --clear-cache
Clearing device cache…
Discovering LIFX devices…
EFFECTS_PATH
value not set (see: Effects Path).
EFFECTS_PATH
value can't be found on disk (check .env
value).
EFFECTS_PATH
value is a file and not a directory (check .env
value).
EFFECTS_PATH
does not contain any valid effect files (see: Effect Files).
No Tile devices were discovered on your LAN (check your device is plugged in and powered on, then clear your Device Cache the next time you run your script).
For unknown reasons your Tile is not responding (exit your script and try again).
You're attempting to update your Tiles too quickly (increase the time between updates and try again).
This repo builds upon the excellent node-lifx-lan library by @futomi.
ISC License
Copyright (c) 2019, James Furey
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.