diff --git a/README.md b/README.md index 0c6d64a..c4a3d72 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Currently supported: - [MilightRF24] (https://github.com/henryk/openmili) - [Blinkstick] (https://www.blinkstick.com) - [Hyperion] (https://github.com/tvdzwan/hyperion/wiki) + - [Hue] (http://wwww.meethue.com) ## Installation @@ -103,6 +104,25 @@ Get the sketch from here https://github.com/henryk/openmili and change the CE an } ``` +### For Hue + +``` + { + "id": "some_id", + "name": "some_name", + "class": "Hue", + "addr": "xxx.xxx.xxx.xxx", + "username": "your username", + "hueId": 1, + "isGroup": false + } +``` + +You need to create an `username` on your bridge to use this plugin. See the +[hue Developer Program Documentation](http://www.developers.meethue.com/documentation/getting-started) +for details. If you're planning to use the [Hue Emulator](http://steveyo.github.io/Hue-Emulator/) +you can use the username "newdeveloper". + ## Features - switch on/off (UI and rules) diff --git a/device-config-schema.coffee b/device-config-schema.coffee index 910de93..a597738 100644 --- a/device-config-schema.coffee +++ b/device-config-schema.coffee @@ -84,5 +84,31 @@ module.exports = { description: "Port of hyperion device" type: "string", default: "19444" + }, + Hue: { + title: "Hue Light", + type: "object" + properties: + addr: + description: "IP-Address of hue bridge" + type: "string" + username: + description: "Username registered (white-listed) on the bridge for PUT access" + type: "string" + hueId: + description: "The light or group id to be controlled" + type: "number" + isGroup: + description: "If set to true the id property is group id. It is a light id, otherwise." + type: "boolean" + default: false + port: + description: "Port of hue bridge (provided for testing purposes)" + type: "number", + default: 80 + timeout: + description: "Timeout in ms for a pending bridge request to complete" + type: "number" + default: 10000 } } diff --git a/devices/hue.coffee b/devices/hue.coffee new file mode 100644 index 0000000..9b04662 --- /dev/null +++ b/devices/hue.coffee @@ -0,0 +1,89 @@ +module.exports = (env) -> + Promise = env.require 'bluebird' + _ = require 'lodash' + Color = require 'color' + # 'es6-promise' needs to be required at this point to initialize promises for the underlying base library + es6Promise = require 'es6-promise' + hue = require 'node-hue-api' + BaseLedLight = require('./base')(env) + + + class HueLight extends BaseLedLight + + constructor: (@config, lastState) -> + @device = new hue.HueApi( + @config.addr, + @config.username, + @config.timeout, + @config.port, + ) + + @hueId = @config.hueId + @hueStateCommand = if @config.isGroup then "setGroupLightState" else "setLightState" + + initState = _.clone lastState + for key, value of lastState + initState[key] = value.value + super(initState) + if @power then @turnOn() else @turnOff() + + _updateState: (attr) => + state = _.assign @getState(), attr + super null, state + + turnOn: -> + hueState = hue.lightState.create().on() + @device[@hueStateCommand](@hueId, hueState).then( => + @_updateState power: true + ).catch( (error) => + env.logger.error error + ).done() + + turnOff: -> + hueState = hue.lightState.create().off() + @device[@hueStateCommand](@hueId, hueState).then( => + @_updateState power: false + ).catch( (error) => + env.logger.error error + ).done() + + setColor: (newColor) -> + color = Color(newColor).rgb() + hslColor = Color(newColor).hsl() + if color.r == 255 && color.g == 255 && color.b == 255 + return @setWhite() + else + hueState = hue.lightState.create().on().hsl(hslColor.h, hslColor.s, hslColor.l) + @device[@hueStateCommand](@hueId, hueState).then( + @_updateState + mode: @COLOR_MODE + color: color + power: true + ).catch( (error) => + env.logger.error error + ).done() + + setWhite: () -> + hslColor = Color("#FFFFFF").hsl() + hueState = hue.lightState.create().on().hsl(hslColor.h, hslColor.s, hslColor.l) + @device[@hueStateCommand](@hueId, hueState).then( + @_updateState + mode: @WHITE_MODE + power: true + ).catch( (error) => + env.logger.error error + ).done() + + setBrightness: (newBrightness) -> + # Maximum brightness for hue is 254 rather than 255 + # See also http://www.developers.meethue.com/content/maximum-brightness-254-or-255 + hueState = hue.lightState.create().on().bri(Math.round(newBrightness * 254 / 100)) + @device[@hueStateCommand](@hueId, hueState).then( + @_updateState + brightness: newBrightness + power: true + ).catch( (error) => + env.logger.error error + ).done() + + return HueLight diff --git a/package.json b/package.json index 06a725d..b3dce9c 100644 --- a/package.json +++ b/package.json @@ -17,16 +17,18 @@ "test": "node_modules/.bin/mocha test" }, "dependencies": { + "blinkstick": "1.1.1", "bluebird": "^3.1.1", "cassert": "^0.1.2", - "color": "^0.8.0", + "color": "^0.11.1", + "es6-promise": "^3.0.2", + "event-to-promise": "0.6.0", + "hyperion-client": "1.0.0", "iwy_master": "0.2.3", - "node-milight-promise": ">=0.0.3", - "node-milight-rf24": ">=0.1.1", "lodash": "^3.10.1", - "blinkstick": "1.1.1", - "hyperion-client": "1.0.0", - "event-to-promise": "0.6.0" + "node-hue-api": "^2.0.0", + "node-milight-promise": ">=0.0.3", + "node-milight-rf24": ">=0.1.1" }, "peerDependencies": { "pimatic": "0.8.*" diff --git a/pimatic-led-light.coffee b/pimatic-led-light.coffee index 670916c..f561188 100644 --- a/pimatic-led-light.coffee +++ b/pimatic-led-light.coffee @@ -9,6 +9,7 @@ module.exports = (env) -> Blinkstick = require('./devices/blinkstick')(env) DummyLedLight = require('./devices/dummy')(env) HyperionLedLight = require('./devices/hyperion')(env) + HueLight = require('./devices/hue')(env) # import preadicares and actions ColorActionProvider = require('./predicates_and_actions/color_action')(env) @@ -48,6 +49,10 @@ module.exports = (env) -> configDef: deviceConfigDef.HyperionLedLight createCallback: (config) -> return new HyperionLedLight(config) + @framework.deviceManager.registerDeviceClass 'Hue', + configDef: deviceConfigDef.Hue + createCallback: (config) -> return new HueLight(config) + @framework.ruleManager.addActionProvider(new ColorActionProvider(@framework)) # wait till all plugins are loaded