node-rc6
Version:
Small home automation project. Controls Fire TV + Kodi (via adb) and hue lights (via API) using a Harmony One + RC6 USB IR receiver (on a Raspberry Pi).
163 lines (143 loc) • 5.14 kB
JavaScript
exports = module.exports = (function(){
var request = require('request-json');
var hue_user = 'node-rc6-user';
var ALL_GROUP = 'all';
function hue(ev, hue_ip) {
var client = request.createClient('http://' + hue_ip + '/');
function api(path, options, cb) {
options = options || {};
options.url = path ? 'api/' + hue_user + path : 'api';
ev.debug('call ' + path||'/api', options);
var method = 'get', params = [options.url];
if ('post' in options) {
method = 'post';
params.push(options.post);
} else if ('put' in options) {
method = 'put';
params.push(options.put);
}
params.push(function(error, response, body){
if (error !== null) {
ev.error(error, options);
} else {
if (body[0] && body[0].error) {
if (body[0].error.type === 1 || body[0].error.type === 101) {
ev.debug('unauthorized', { options: options, body: body });
if (body[0].error.type === 101)
ev.info(body[0].error.description);
api(null, { post: { devicetype: hue_user+'#nodejs', username: hue_user } }, path === null ? cb : (function(p,o,c){
return function(){api(p,o,c)};
})(path, options, cb));
} else {
ev.error('[' + body[0].error.type + '] ' + body[0].error.description, { options: options, body: body });
}
} else {
ev.debug(path||'/api', body);
if (cb) cb(body);
}
}
});
client[method].apply(client, params);
}
var lightIds = [], groupId = null;
api('/lights', {}, function(lights){
for (var lightId in lights)
lightIds.push(lightId);
ev.debug('found lights', lightIds);
api('/groups', function(groups){
for (var group in groups) {
if (groups[group].name === ALL_GROUP) {
groupId = group;
ev.debug('found group', group);
break;
}
}
if (groupId === null) {
ev.debug('create group', ALL_GROUP);
api('/groups', { post: { lights: lightIds, name: ALL_GROUP } }, function(){
api('/groups', function(groups){
for (var group in groups) {
if (groups[group].name === ALL_GROUP) {
groupId = group;
ev.debug('found group', group);
break;
}
}
});
});
}
});
});
var randomMode = false;
function setLightState(id, state, cb) {
return api('/lights/' + id + '/state', { put: state }, cb);
}
function setGroupState(state, cb) {
return api('/groups/' + groupId + '/action', { put: state }, cb);
}
this.stop = function() {
randomMode = false;
};
this.on = function(on) {
randomMode = false;
setGroupState({ on:on===true });
};
this.scene = function(no) {
randomMode = false;
api('/scenes', {}, function(scenes){
var i=0;
if (scenes)
for (var scene in scenes)
if (++i === no)
setGroupState({ scene: scene });
});
};
function calcBri(op, val, cur) {
var bri = op==='=' ? val : (op==='-' ? cur - val : (op==='+' ? cur + val : cur));
return Math.min(Math.max(bri, 1), 254);
}
this.bri = function(op, val) {
api('/lights', {}, function(lights){
if (lights)
for (light in lights)
setLightState(light, { bri: calcBri(op, val, lights[light].state.bri) });
});
};
function rand(min, max, prec) {
var pow = Math.pow(10, prec||0);
return Math.round(Math.floor(Math.random() * (max * pow - min * pow + 1)) + min * pow) / pow;
}
function moodLight(lightId, duration, transition) {
if (randomMode) {
_duration = typeof(duration) === 'object' ? rand(duration[0], duration[1]) : duration;
_transition = transition ? transition : _duration;
setLightState(lightId, { transitiontime: Math.round(_transition/100), xy: [rand(0,1,4),rand(0,1,4)] } );
setTimeout(moodLight, _duration, lightId, duration, transition);
}
}
function moodLights(duration, transition) {
if (randomMode) {
_duration = typeof(duration) === 'object' ? rand(duration[0], duration[1]) : duration;
_transition = transition ? transition : _duration;
setGroupState( { transitiontime: Math.round(_transition/100), xy: [rand(0,1,4),rand(0,1,4)] } );
setTimeout(moodLights, _duration, duration, transition);
}
}
this.random = function(sync, duration, transition) {
randomMode = true;
setGroupState({ on: true, bri: 254 });
if (sync) {
moodLights(duration, transition);
} else {
lightIds.forEach(function(lightId){
moodLight(lightId, duration, transition);
});
}
};
}
return {
getInstance: function(ev, hue_ip) {
return new hue(ev, hue_ip);
}
};
})();