diff --git a/device/LIFX/controller.js b/device/LIFX/controller.js new file mode 100644 index 0000000..f7d7a34 --- /dev/null +++ b/device/LIFX/controller.js @@ -0,0 +1,99 @@ +'use strict'; + +/* + * Example code for an LIFX light integration wrote by Geert Wille + */ +const BluePromise = require('bluebird'); +const Lifx = require('lifx-http-api'); +const client = new Lifx({ + bearerToken: '' // https://cloud.lifx.com/settings +}); + +const LIFX_ALL_LIGHTS_SELECTOR = 'all'; +const LIFX_LIGHT_OFF = 'off'; +const LIFX_LIGHT_ON = 'on'; + +let sliderValue = 50; +let switchValue = true; + +// Helper function +function getLifxDeviceSelector(deviceId) { + return 'id:' + deviceId; +} + +/* + * Device Controller + * Events on that device from the Brain will be forwarded here for handling. + */ +module.exports.onPulse = function (name, deviceId) { + // Just randomly pulse the light + client.pulse(getLifxDeviceSelector(deviceId), { + color: '#' + Math.floor(Math.random() * 16777215).toString(16), // Generate random color + from_color: '#' + Math.floor(Math.random() * 16777215).toString(16), // Generate random color + period: 1, + cycles: 5, + persist: false, + power_on: true, + peak: 0.8 + }); +}; + +module.exports.allOff = function (name, deviceId) { + // Just randomly pulse the light + client.setState(LIFX_ALL_LIGHTS_SELECTOR, { + power: LIFX_LIGHT_OFF + }).then(console.log, console.error); +}; + +/** + * Getters and setters: + * - The getters are used to send the current Values through the SDK (read) + * - The setter allow changing values on the Brain and handling the changes here (write) + */ +module.exports.switchSet = function (deviceId, value) { + console.log('[CONTROLLER] switch set to', deviceId, value); + switchValue = value; + + // Update LIFX light + client.setState(getLifxDeviceSelector(deviceId), { + power: switchValue == 'true' ? LIFX_LIGHT_ON : LIFX_LIGHT_OFF + }).then(console.log, console.error); +}; + +module.exports.switchGet = function (deviceId) { + console.log('[CONTROLLER] return switch value', deviceId, switchValue); + return BluePromise.resolve(switchValue); +}; + +module.exports.sliderSet = function (deviceId, value) { + console.log('[CONTROLLER] dimmer set to', deviceId, value); + sliderValue = value; + + // Update LIFX light + client.setState(LIFX_ALL_LIGHTS_SELECTOR, { + brightness: sliderValue / 100 + }).then(console.log, console.error); +}; + +module.exports.sliderGet = function (deviceId) { + console.log('[CONTROLLER] return current dimmer value', deviceId, sliderValue); + return BluePromise.resolve(sliderValue); +}; + +/* + * Discover all LIFX lights and return them in the proper format + */ +module.exports.discoverLifx = function () { + return client.listLights(LIFX_ALL_LIGHTS_SELECTOR) + .then((LifxLights) => { + console.info(LifxLights); + return LifxLights.map((lifx) => ({ + id: lifx.id, + name: lifx.label, + reachable: lifx.reachable + })); + }) + .catch((err) => { + console.error('ERROR!', err); + }); +} diff --git a/device/LIFX/index.js b/device/LIFX/index.js new file mode 100644 index 0000000..7c35e64 --- /dev/null +++ b/device/LIFX/index.js @@ -0,0 +1,52 @@ +'use strict'; + +/* + * Example code for an LIFX light integration wrote by Geert Wille + */ +const neeoapi = require('neeo-sdk'); +const controller = require('./controller'); + +console.log('NEEO SDK Example "LIFX" adapter'); +console.log('---------------------------------------------'); + +/* + * Adapter - simple LIFX integration. + */ + +// first we set the device info, used to identify it on the Brain +const lifxLight = neeoapi.buildDevice('Smart Light') // LIFX LIFX looked weird in the app so I just named it Smart Light + .setManufacturer('LIFX') + .addAdditionalSearchToken('light') + .setType('LIGHT') + .enableDiscovery({ + headerText: 'Ready to discover LIFX lights', + description: 'Make sure that you\'re logged in in the LIFX app and that you\'ve create a new accessToken on https://cloud.lifx.com/settings so we can retrieve your lights' + }, controller.discoverLifx) + // Then we add the capabilities of the LIFX bulb + .addSlider({ name: 'power-slider', label: 'Dimmer', range: [0, 100], unit: '%' }, { setter: controller.sliderSet, getter: controller.sliderGet }) + .addSwitch({ name: 'toggle', label: 'Toggle On/Off' }, { setter: controller.switchSet, getter: controller.switchGet }) + .addButton({ name: 'pulse', label: 'Pulse' }) + .addButtonHander(controller.onPulse) + .addButton({ name: 'all-off', label: 'All Off' }) + .addButtonHander(controller.allOff); + +console.log('- discover one NEEO Brain...'); +neeoapi.discoverOneBrain() + .then((brain) => { + console.log('- Brain discovered:', brain.name); + + console.log('- Start server'); + return neeoapi.startServer({ + brain, + port: 6336, + name: 'lifx', + devices: [lifxLight] + }); + }) + .then(() => { + console.log('# READY! use the NEEO app to search for "LIFX".'); + }) + .catch((err) => { + console.error('ERROR!', err); + process.exit(1); + }); diff --git a/package.json b/package.json index 57bccc8..e1fb12c 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "private": false, "dependencies": { "bluebird": "^3.5.0", - "neeo-sdk": "*" + "neeo-sdk": "*", + "lifx-http-api": "^1.0.3" }, "engines": { "node": ">=6.0.0" @@ -17,6 +18,7 @@ "recipe": "node recipe/listAllRecipes.js", "server:simple": "node device/simpleDevice/index.js", "server:complex": "node device/discoverableLightDevice/index.js", + "server:lifx": "node device/LIFX/index.js", "clean": "rm -rf ./dist && mkdir -p ./dist", "release": "npm run jshint && npm run clean && npm run release:copy", "release:copy": "cp -r ./{device,recipe} ./dist && cp .jshintrc .gitignore .editorconfig *.md package.json License ./dist" @@ -24,4 +26,4 @@ "devDependencies": { "jshint": "^2.9.4" } -} +} \ No newline at end of file