UNPKG

hugo

Version:

Yet another node.js interface for philips hue

177 lines (149 loc) 4.59 kB
/*jshint expr:true */ 'use strict'; var color = require('./color') , async = require('async') , _ = require('lodash') , debug = require('debug')('hugo.lightstate') ; module.exports = LightState; function LightState(bridge, nr, state) { this.bridge = bridge; this.nr = nr; this.setState(state); } LightState.read = function (bridge, light, cb) { var instance = new LightState(bridge, light, {}); instance.reload(cb); }; LightState.prototype.reload = function (cb) { var lightstate = this; this.bridge.get('lights/' + this.nr, function (err, resp, body) { if (err) { cb && cb(err); return; } lightstate.setState(body.state); cb && cb(null, body.state); }); }; LightState.prototype.setState = function (state, val) { if ('object' === typeof(state)) { this.state = state; return; } this.state[state] = val; }; LightState.prototype.mergeValues = function (newValues) { var state = _.clone(newValues), lightstate = this; delete state.transitiontime; if (state.xy && this.state.colormode !== 'xy') { state.colormode = 'xy'; } if (state.hasOwnProperty('ct') && this.colormode !== 'ct') { state.colormode = 'ct'; } if ( (this.colormode !== 'hs') && ( state.hasOwnProperty('hue') || state.hasOwnProperty('sat') ) ) { // firmware bug! Actually, setting sat without hue while coming // from colormode ct sets hs mode, but does not set the bulb to the // old hue. state.colormode = 'hs'; } Object.keys(state).forEach(function (k) { lightstate.setState(k, state[k]); }); }; LightState.prototype.set = function (keyVal, cb) { var newValues = this.getChanges(keyVal); if (! newValues) { debug('ignoring redundant values for bulb %d:', this.nr, keyVal); if (cb) { cb(null, this.state); } return; } debug('sending to bridge', newValues); this.bridge.put( 'lights/' + this.nr + '/state', newValues, this.getResponseParser(cb) ); }; LightState.prototype.getChanges = function (newValues) { var keyVal = _.clone(newValues) , transitiontime = keyVal.transitiontime ; // transitiontime isn't recorded in state. Delete before weeding. delete keyVal.transitiontime; // if not specified, assume to switch on: if (! keyVal.hasOwnProperty('on') && (this.state.on === false)) { keyVal.on = true; } // weed unused parameters based on old and new color mode: keyVal = color.removeUnusedParams(keyVal, this.state); if (_.isEmpty(keyVal)) { return null; } // add any transition back in: if ('undefined' !== typeof(transitiontime)) { keyVal.transitiontime = transitiontime; } return keyVal; }; LightState.prototype.getResponseParser = function (cb) { var lightstate = this; return function (err, resp, body) { var newValues = {}; if (err) { if (cb) { return cb(err); } throw new Error(err); } if (200 !== resp.statusCode) { return cb(body); } body.forEach(function (row) { var errMsg; if (row.error) { errMsg = row.error.address + ': ' + row.error.description; console.error(errMsg); return; } Object.keys(row.success).forEach(function (r) { var matches; matches = r.match(/\/lights\/(\d+)\/state\/(\S+)/); newValues[matches[2]] = row.success[r]; }); }); lightstate.mergeValues(newValues); cb && cb(null, lightstate.state); }; }; LightState.prototype.setColor = function (col, transition, cb) { var colorState = color.ToState(col); _.extend(colorState, { transitiontime : ('undefined' !== typeof(transition)) ? transition : 1, on: true }); this.set(colorState, cb); }; LightState.prototype.flash = function (col, cb) { var oldVals = this.getColorValues(); oldVals.transitiontime = 1; async.series([ async.apply(this.setColor.bind(this), col, 0), async.apply(this.set.bind(this), oldVals) ], cb); }; LightState.prototype.getColorValues = function () { return color.fromState(this.state); }; LightState.prototype.isOn = function () { return (this.state.on === true); };