Skip to content

Instantly share code, notes, and snippets.

@AdamMagaluk
Last active August 29, 2015 14:01
Show Gist options
  • Save AdamMagaluk/3f3d921270adfc557365 to your computer and use it in GitHub Desktop.
Save AdamMagaluk/3f3d921270adfc557365 to your computer and use it in GitHub Desktop.
Zetta Devices
/*
Hue Hub represents the hub interface to the hue bulbs
it also implents a group control of all hue bulbs.
Weeknesses
- A single state doesn't make sense.
- passing in a callback function for a new light is hacky.
- Could of just added a sub-device to the hub for each bulb.
- Error handling breaks stops zetta runtime. Ignoring all http errors
from hue http api.
- Hue hub and bulb api look identical except where finding new bulbs. Could of did it much DRYer.
- Inherit from a HueControl module.
Strengths
- config.map, config.when and all methods.
*/
var HueApi = require("node-hue-api").HueApi;
var async = require('async');
var HueBulbDriver = require('./hue_bulb');
var Scientist = require("zetta-runtime").scientist;
var lightState = require("node-hue-api").lightState;
var HueHubDriver = module.exports = function(data, _newLightFunc) {
this.type = 'huehub';
this.name = 'Hue Hub '+data.id;
this.data = data;
this._newLight = _newLightFunc;
this.lights = [];
if(!data.registered)
this.state = 'unregistered';
else{
this.state = 'registered';
this.hue = new HueApi(this.data.ipaddress, this.data.user);
}
};
HueHubDriver.prototype.init = function(config) {
config
.when('unregistered', { allow: ['register'] })
.when('registered', { allow: ['blink','find-lights','all-on','all-off','brightness', 'color','color-loop'] })
.when('colorloop', { allow: ['blink','find-lights','all-on','all-off','brightness', 'color'] })
.map('register', this.register)
.map('blink', this.blink)
.map('all-on',this.allOn)
.map('all-off',this.allOff)
.map('find-lights',this.findLights)
.map('color-loop',this.colorLoop)
.map('color',this.color,[{type:'color',name : 'color'}])
.map('brightness',this.brightness,[{type: 'number', name: 'brightness'}]);
};
HueHubDriver.prototype.register = function(cb) {
var self = this;
var hue = new HueApi();
hue.createUser(this.data.ipaddress, null, null, function(err, user) {
if (err)
return cb(null);
self.data.user = user;
self.data.registered = true;
self.state = 'registered';
self.hue = new HueApi(self.data.ipaddress, self.data.user);
self.findLights(function(){
cb(null);
});
});
};
HueHubDriver.prototype.color = function(color,cb){
if(!this.hue)
return cb();
color = color.match(/[0-9a-f]{1,2}/g).map(function(c){ return parseInt(c,16); });
console.log('setting color:',color);
var self = this;
var state = lightState.create().on().rgb(color[0],color[1],color[2]);
this.hue.setGroupLightState(0,state,function(err){
cb();
});
};
HueHubDriver.prototype.blink = function(cb) {
if(!this.hue)
return cb();
var self = this;
self.hue.setGroupLightState(0, {alert : "select"},function(){
cb();
});
};
HueHubDriver.prototype.allOn = function(cb) {
if(!this.hue)
return cb();
var self = this;
this.data.lightval = 'on';
var state = lightState.create().on().brightness(100).transition(0).effect('none');
this.hue.setGroupLightState(0,state,function(err){
if(!err)
self.state = 'registered';
cb();
});
};
HueHubDriver.prototype.allOff = function(cb) {
if(!this.hue)
return cb();
this.data.lightval = 'off';
var state = lightState.create().off().transition(0);
this.hue.setGroupLightState(0,state,function(){
return cb();
});
};
HueHubDriver.prototype.colorLoop = function(cb) {
if(!this.hue)
return cb();
var self = this;
this.data.lightval = 'on';
var state = lightState.create().on().brightness(100).transition(0).effect('colorloop');
this.hue.setGroupLightState(0,state,function(err){
if(!err)
self.state = 'colorloop';
cb();
});
};
HueHubDriver.prototype.brightness = function(brightness,cb) {
if(!this.hue)
return cb();
var state = lightState.create().brightness(brightness);
this.hue.setGroupLightState(0,state,function(err){
cb();
});
};
HueHubDriver.prototype._lightExists = function(light) {
return (this.lights.filter(function(l){
return (l.id === light.id);
}).length > 0);
};
HueHubDriver.prototype.findLights = function(cb) {
if(!this.hue)
return cb();
var self = this;
this.hue.lights(function(err, res) {
if (err)
return cb();
res.lights.forEach(function(light){
if(self._lightExists(light))
return;
self.lights.push(light);
self._newLight(light,self.hue);
});
cb();
});
};
var LEDDriver = module.exports = function() {
this.type = 'led';
this.name = "joes-office-led";
this.data = {};
this.state = 'off';
};
LEDDriver.prototype.init = function(config) {
config
.when('on', { allow: ['turn-off', 'toggle'] })
.when('off', { allow: ['turn-on', 'toggle'] })
.map('turn-on', this.turnOn)
.map('turn-off', this.turnOff)
.map('toggle', this.toggle)
};
LEDDriver.prototype.turnOn = function(cb) {
this.state = 'on';
cb();
};
LEDDriver.prototype.turnOff = function(cb) {
this.state = 'off';
cb();
};
LEDDriver.prototype.toggle = function(cb) {
if (this.state === 'off') {
this.call('turn-on');
cb();
} else if (this.state === 'on') {
this.call('turn-off');
cb();
} else {
cb(new Error('Invalid state - Valid states are "on" and "off".'));
}
};
var PhotosensorDriver = module.exports = function() {
this.type = 'photosensor';
this.name = 'joes-office-photosensor';
this.data = {};
this.state = 'on';
this.value = 0;
};
PhotosensorDriver.prototype.init = function(config) {
config
.stream('value', this.onValue);
};
PhotosensorDriver.prototype.onValue = function(emitter) {
setInterval(function() {
emitter.emit('data', Math.floor(Math.random() * 100));
}, 32);
/*this.board.on('digitalChange', function(e) {
emitter.emit('data', e.value);
});*/
};
var Robot = require('../lib/robot_lib');
var iphash = require('../lib/iphash');
var RobotArmDriver = module.exports = function(id, socket, port, ip) {
this.type = 'arm';
this.name = 'arm-'+iphash(ip);
this.data = {};
this.id = id;
this._socket = socket;
this._port = port;
this._robot = new Robot(socket, port, ip);
this.ip = ip;
this.state = 'standby';
this.x = 0;
this.y = 0;
this.z = 0;
this.led = false;
};
RobotArmDriver.prototype.init = function(config) {
config
.when('standby', { allow: ['open-claw', 'close-claw', 'elbow-up', 'elbow-down', 'shoulder-up', 'shoulder-down', 'pivot-left', 'pivot-right']})
.when('open-claw', { allow: [] })
.when('close-claw', { allow: []})
.when('elbow-up', { allow: []})
.when('elbow-down', { allow: [] })
.when('pivot-left', { allow: [] })
.when('pivot-right', { allow: [] })
.when('shoulder-up', { allow: [] })
.when('shoulder-down', { allow: []})
.map('standby', this.standby)
.map('open-claw', this.openClaw)
.map('close-claw', this.closeClaw)
.map('elbow-up', this.elbowUp)
.map('elbow-down', this.elbowDown)
.map('shoulder-up', this.shoulderUp)
.map('shoulder-down', this.shoulderDown)
.map('pivot-left', this.pivotLeft)
.map('pivot-right', this.pivotRight);
};
RobotArmDriver.prototype.standby = function(cb) {
this.state = 'standby';
if(cb) {
cb();
}
};
RobotArmDriver.prototype.openClaw = function(cb) {
this.state = 'open-claw';
var self = this;
this._robot.openGripper(function() {
self.call('standby');
cb();
});
};
RobotArmDriver.prototype.closeClaw = function(cb) {
this.state = 'close-claw';
var self = this;
this._robot.closeGripper(function() {
self.call('standby');
cb();
});
};
RobotArmDriver.prototype.elbowUp = function(cb) {
this.state = 'elbow-up';
var self = this;
this._robot.elbowUp(function() {
self.call('standby');
cb();
});
};
RobotArmDriver.prototype.elbowDown = function(cb) {
this.state = 'elbow-down';
var self = this;
this._robot.elbowDown(function() {
self.call('standby');
cb();
});
};
RobotArmDriver.prototype.shoulderUp = function(cb) {
this.state = 'shoulder-up';
var self = this;
this._robot.shoulderUp(function() {
self.call('standby');
cb();
});
};
RobotArmDriver.prototype.shoulderDown = function(cb) {
this.state = 'shoulder-down';
var self = this;
this._robot.shoulderDown(function() {
self.call('standby');
cb();
});
};
RobotArmDriver.prototype.pivotLeft = function(cb) {
this.state = 'pivot-left';
var self = this;
this._robot.pivotLeft(function() {
self.call('standby');
cb();
});
};
RobotArmDriver.prototype.pivotRight = function(cb) {
this.state = 'pivot-right';
var self = this;
this._robot.pivotRight(function() {
self.call('standby');
cb();
});
};
var PhotosensorDriver = module.exports = function(info,xbeeAPI) {
this.type = 'photosensor';
this.name = 'xbee-photosensor-'+info.remote16;
this.data = {
remote16 : info.remote16,
remote64 : info.remote64
};
this.value = NaN;
this.xbeeAPI = xbeeAPI;
this.state = 'ready';
};
PhotosensorDriver.prototype.init = function(config) {
config
.stream(this.name+'/value', this.onValue);
};
PhotosensorDriver.prototype.onValue = function(emitter) {
var self = this;
this.xbeeAPI.on('frame_object',function(frame){
if(frame.remote64 !== self.data.remote64)
return;
if(frame.type !== 146)
return;
self.value = frame.analogSamples.AD0;
self.emit('update',self.value);
// emitter.emit('data', {value : self.value,units : 'mV'} );
emitter.emit('data', self.value );
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment