Merge pull request #238 from hybridgroup/change/specifying-multiple-connections-or-devices

Support providing connections/devices as an object
This commit is contained in:
Edgar O Silva 2014-11-10 15:46:03 -06:00
commit aac7bd0de8
13 changed files with 186 additions and 141 deletions

View File

@ -84,16 +84,16 @@ Cylon.robot({
var Cylon = require('cylon'); var Cylon = require('cylon');
Cylon.robot({ Cylon.robot({
connections: [ connections: {
{ name: 'digispark', adaptor: 'digispark'}, digispark: { adaptor: 'digispark' },
{ name: 'leapmotion', adaptor: 'leapmotion' } leapmotion: { adaptor: 'leapmotion' }
], },
devices: [ devices: {
{ name: 'servo1', driver: 'servo', pin: 0, connection: 'digispark' }, servo1: { driver: 'servo', pin: 0, connection: 'digispark' },
{ name: 'servo2', driver: 'servo', pin: 1, connection: 'digispark' }, servo2: { driver: 'servo', pin: 1, connection: 'digispark' },
{ name: 'leapmotion', driver: 'leapmotion', connection: 'leapmotion' } leapmotion: { driver: 'leapmotion', connection: 'leapmotion' }
], },
work: function(my) { work: function(my) {
my.x = 90; my.x = 90;

View File

@ -15,11 +15,12 @@ Arduino = (function(){
})(); })();
skynet = { skynet = {
connections: [ connection: {
{ name: 'skynet', name: 'skynet',
adaptor: 'skynet', adaptor: 'skynet',
uuid: "96630051-a3dc-11e3-8442-5bf31d98c912", token: "2s67o7ek98pycik98f43reqr90t6s9k9" } uuid: "96630051-a3dc-11e3-8442-5bf31d98c912",
], token: "2s67o7ek98pycik98f43reqr90t6s9k9"
},
work: function(my) { work: function(my) {
console.log("Skynet is listening..."); console.log("Skynet is listening...");

View File

@ -1,16 +1,16 @@
var Cylon = require('../..'); var Cylon = require('../..');
Cylon.robot({ Cylon.robot({
connections: [ connections: {
{ name: 'digispark', adaptor: 'digispark'}, digispark: { adaptor: 'digispark' },
{ name: 'leapmotion', adaptor: 'leapmotion' } leapmotion: { adaptor: 'leapmotion' }
], },
devices: [ devices: {
{name: 'servo1', driver: 'servo', pin: 0, connection: 'digispark'}, servo1: { driver: 'servo', pin: 0, connection: 'digispark' },
{name: 'servo2', driver: 'servo', pin: 1, connection: 'digispark'}, servo2: { driver: 'servo', pin: 1, connection: 'digispark' },
{name: 'leapmotion', driver: 'leapmotion', connection: 'leapmotion'} leapmotion: { driver: 'leapmotion', connection: 'leapmotion' }
], },
work: function(my) { work: function(my) {
my['x'] = 90; my['x'] = 90;

View File

@ -10,16 +10,16 @@ Now that we have Cylon imported, we can start defining our robot
Let's define the connections and devices: Let's define the connections and devices:
connections: [ connections: {
{ name: 'digispark', adaptor: 'digispark'}, digispark: { adaptor: 'digispark' },
{ name: 'leapmotion', adaptor: 'leapmotion' } leapmotion: { adaptor: 'leapmotion' }
], },
devices: [ devices: {
{name: 'servo1', driver: 'servo', pin: 0, connection: 'digispark'}, servo1: { driver: 'servo', pin: 0, connection: 'digispark' },
{name: 'servo2', driver: 'servo', pin: 1, connection: 'digispark'}, servo2: { driver: 'servo', pin: 1, connection: 'digispark' },
{name: 'leapmotion', driver: 'leapmotion', connection: 'leapmotion'} leapmotion: { driver: 'leapmotion', connection: 'leapmotion' }
], },
Now that Cylon knows about the necessary hardware we're going to be using, we'll Now that Cylon knows about the necessary hardware we're going to be using, we'll
tell it what work we want to do: tell it what work we want to do:

View File

@ -25,17 +25,17 @@ var handStartPosition = [],
var handWasClosedInLastFrame = false; var handWasClosedInLastFrame = false;
Cylon.robot({ Cylon.robot({
connections: [ connections: {
{ name: 'leapmotion', adaptor: 'leapmotion' }, leapmotion: { adaptor: 'leapmotion' },
{ name: 'ardrone', adaptor: 'ardrone', port: '192.168.1.1' }, ardrone: { adaptor: 'ardrone', port: '192.168.1.1' },
{ name: 'keyboard', adaptor: 'keyboard' } keyboard: { adaptor: 'keyboard' }
], },
devices: [ devices: {
{ name: 'drone', driver: 'ardrone', connection: 'ardrone' }, drone: { driver: 'ardrone', connection:'ardrone' },
{ name: 'leapmotion', driver: 'leapmotion', connection: 'leapmotion' }, leapmotion: { driver: 'leapmotion', connection:'leapmotion' },
{ name: 'keyboard', driver: 'keyboard', connection: 'keyboard'} keyboard: { driver: 'keyboard', connection:'keyboard' }
], },
work: function(my) { work: function(my) {
my.keyboard.on('right', my.drone.rightFlip); my.keyboard.on('right', my.drone.rightFlip);

View File

@ -12,16 +12,17 @@ Now that we have Cylon imported, we can start defining our robot
Let's define the connections and devices: Let's define the connections and devices:
connections: [ connections: {
{ name: 'leapmotion', adaptor: 'leapmotion' }, leapmotion: { adaptor: 'leapmotion' },
{ name: 'ardrone', adaptor: 'ardrone', port: '192.168.1.1' }, ardrone: { adaptor: 'ardrone', port: '192.168.1.1' },
{ name: 'keyboard', adaptor: 'keyboard' } keyboard: { adaptor: 'keyboard' }
], },
devices: [
{ name: 'drone', driver: 'ardrone', connection:'ardrone' }, devices: {
{ name: 'leapmotion', driver: 'leapmotion', connection:'leapmotion' }, drone: { driver: 'ardrone', connection:'ardrone' },
{ name: 'keyboard', driver: 'keyboard', connection:'keyboard'} leapmotion: { driver: 'leapmotion', connection:'leapmotion' },
], keyboard: { driver: 'keyboard', connection:'keyboard' }
},
Now that Cylon knows about the necessary hardware we're going to be using, we'll Now that Cylon knows about the necessary hardware we're going to be using, we'll
tell it what work we want to do: tell it what work we want to do:

View File

@ -1,11 +1,15 @@
var Cylon = require('../..'); var Cylon = require('../..');
Cylon.robot({ Cylon.robot({
connections: [{ name: 'leapmotion', adaptor: 'leapmotion' }, connections: {
{ name: 'arduino', adaptor: 'firmata', port: '/dev/ttyACM0' }], arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
leapmotion: { adaptor: 'leapmotion' },
},
devices: [{ name: 'leapmotion', driver: 'leapmotion', connection: 'leapmotion' }, devices: {
{ name: 'led', driver: 'led', pin: 13, connection: 'arduino' }], led: { driver: 'led', pin: 13, connection: 'arduino' }
leapmotion: { driver: 'leapmotion', connection: 'leapmotion' },
},
work: function(my) { work: function(my) {
my.leapmotion.on('frame', function(frame) { my.leapmotion.on('frame', function(frame) {

View File

@ -10,15 +10,15 @@ Now that we have Cylon imported, we can start defining our robot
Let's define the connections and devices: Let's define the connections and devices:
connections: [ connections: {
{ name: 'leapmotion', adaptor: 'leapmotion' }, leapmotion: { adaptor: 'leapmotion' },
{ name: 'arduino', adaptor: 'firmata', port: '/dev/ttyACM0' } arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
], },
devices: [ devices: {
{ name: 'leapmotion', driver: 'leapmotion', connection: 'leapmotion' }, leapmotion: { driver: 'leapmotion', connection: 'leapmotion' },
{ name: 'led', driver: 'led', pin: 13, connection: 'arduino' } led: { driver: 'led', pin: 13, connection: 'arduino' }
], },
Now that Cylon knows about the necessary hardware we're going to be using, we'll Now that Cylon knows about the necessary hardware we're going to be using, we'll
tell it what work we want to do: tell it what work we want to do:

View File

@ -2,8 +2,10 @@ var Cylon = require('../..');
Cylon.robot({ Cylon.robot({
connection: { name: 'arduino', adaptor: 'firmata', port: '/dev/ttyUSB0' }, connection: { name: 'arduino', adaptor: 'firmata', port: '/dev/ttyUSB0' },
devices: [{name: 'led', driver: 'led', pin: 17}, devices: {
{ name: 'servo', driver: 'servo', pin: 2, range: { min: 30, max: 150 } }], led: { driver: 'led', pin: 17 },
servo: { driver: 'servo', pin: 2, range: { min: 30, max: 150 } }
},
work: function(my) { work: function(my) {
my.led.turnOn(); my.led.turnOn();

View File

@ -1,11 +1,14 @@
var Cylon = require('../..'); var Cylon = require('../..');
Cylon.robot({ Cylon.robot({
connections: [ connections: {
{ name: 'arduino', adaptor: 'firmata', port: '/dev/ttyACM0' }, arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' },
{ name: 'skynet', adaptor: 'skynet', skynet: {
uuid: "96630051-a3dc-11e3-8442-5bf31d98c912", token: "2s67o7ek98pycik98f43reqr90t6s9k9" } adaptor: 'skynet',
], uuid: "96630051-a3dc-11e3-8442-5bf31d98c912",
token: "2s67o7ek98pycik98f43reqr90t6s9k9"
}
},
device: { name: 'led13', driver: 'led', pin: 13, connection: 'arduino' }, device: { name: 'led13', driver: 'led', pin: 13, connection: 'arduino' },

View File

@ -10,19 +10,14 @@ Now that we have Cylon imported, we can start defining our robot
Let's define the connections and devices: Let's define the connections and devices:
connections: [ connections: {
{ arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' },
name: 'arduino', skynet: {
adaptor: 'firmata',
port: '/dev/ttyACM0'
},
{
name: 'skynet',
adaptor: 'skynet', adaptor: 'skynet',
uuid: "96630051-a3dc-11e3-8442-5bf31d98c912", uuid: "96630051-a3dc-11e3-8442-5bf31d98c912",
token: "2s67o7ek98pycik98f43reqr90t6s9k9" token: "2s67o7ek98pycik98f43reqr90t6s9k9"
} }
], },
device: { name: 'led13', driver: 'led', pin: 13, connection: 'arduino' }, device: { name: 'led13', driver: 'led', pin: 13, connection: 'arduino' },

View File

@ -78,8 +78,8 @@ var Robot = module.exports = function Robot(opts) {
this.work = function() { Logger.debug("No work yet."); }; this.work = function() { Logger.debug("No work yet."); };
} }
this.initConnections(opts.connection || opts.connections); this.initConnections(opts);
this.initDevices(opts.device || opts.devices); this.initDevices(opts);
for (var n in opts) { for (var n in opts) {
var opt = opts[n]; var opt = opts[n];
@ -156,19 +156,15 @@ Robot.prototype.toJSON = function() {
// Public: Initializes all connections for the robot // Public: Initializes all connections for the robot
// //
// connections - connections to initialize // opts - options array passed to constructor
// //
// Returns initialized connections // Returns initialized connections
Robot.prototype.initConnections = function(connections) { Robot.prototype.initConnections = function(opts) {
Logger.info("Initializing connections."); Logger.info("Initializing connections.");
if (connections == null) { var isArray = Array.isArray;
return;
}
connections = [].concat(connections); var addConnection = function(conn) {
connections.forEach(function(conn) {
conn.robot = this; conn.robot = this;
if (this.connections[conn.name]) { if (this.connections[conn.name]) {
@ -177,34 +173,47 @@ Robot.prototype.initConnections = function(connections) {
Logger.warn("Connection names must be unique. Renaming '" + original + "' to '" + conn.name + "'"); Logger.warn("Connection names must be unique. Renaming '" + original + "' to '" + conn.name + "'");
} }
Logger.info("Initializing connection '" + conn.name + "'.");
this.connections[conn.name] = new Connection(conn); this.connections[conn.name] = new Connection(conn);
}.bind(this)); }.bind(this);
if (opts.connection == null && opts.connections == null) {
return this.connections;
}
if (opts.connection) {
addConnection(opts.connection);
return this.connections;
}
if (typeof opts.connections == 'object' && !isArray(opts.connections)) {
for (var name in opts.connections) {
var conn = opts.connections[name];
conn.name = name;
addConnection(conn);
}
}
if (isArray(opts.connections)) {
Logger.warn("Specifying connections as an array is deprecated, and will be removed in 1.0.0.");
opts.connections.forEach(function(conn) {
addConnection(conn);
});
}
return this.connections; return this.connections;
}; };
// Public: Initializes all devices for the robot // Public: Initializes all devices for the robot
// //
// devices - devices to initialize // opts - options array passed to constructor
// //
// Returns initialized devices // Returns initialized devices
Robot.prototype.initDevices = function(devices) { Robot.prototype.initDevices = function(opts) {
Logger.info("Initializing devices."); Logger.info("Initializing devices.");
if (devices == null) { var isArray = Array.isArray;
return;
}
// check that there are connections to use var addDevice = function(device) {
if (!Object.keys(this.connections).length) {
throw new Error("No connections specified")
}
devices = [].concat(devices);
devices.forEach(function(device) {
device.robot = this; device.robot = this;
if (this.devices[device.name]) { if (this.devices[device.name]) {
@ -228,11 +237,37 @@ Robot.prototype.initDevices = function(devices) {
} }
} }
device.adaptor = device.connection.adaptor;
Logger.info("Initializing device '" + device.name + "'.");
this.devices[device.name] = new Device(device); this.devices[device.name] = new Device(device);
}.bind(this)); }.bind(this);
if (opts.device == null && opts.devices == null) {
return this.devices;
}
// check that there are connections to use
if (!Object.keys(this.connections).length) {
throw new Error("No connections specified")
}
if (opts.device) {
addDevice(opts.device);
return this.devices;
}
if (typeof opts.devices == 'object' && !isArray(opts.devices)) {
for (var name in opts.devices) {
var device = opts.devices[name];
device.name = name;
addDevice(device);
}
}
if (isArray(opts.devices)) {
Logger.warn("Specifying devices as an array is deprecated, and will be removed in 1.0.0.");
opts.devices.forEach(function(device) {
addDevice(device);
});
}
return this.devices; return this.devices;
}; };

View File

@ -233,15 +233,16 @@ describe("Robot", function() {
}); });
context("when not passed anything", function() { context("when not passed anything", function() {
it("returns immediately", function() { it("does not modify the bot's connections", function() {
expect(bot.initConnections()).to.be.eql(undefined); bot.initConnections({});
expect(bot.connections).to.be.eql({});
}); });
}); });
context("when passed a connection object", function() { context("when passed a connection object", function() {
it("instantiates a new connection with the provided object", function() { it("instantiates a new connection with the provided object", function() {
var connection = { name: 'loopback', adaptor: 'loopback' }; var connection = { name: 'loopback', adaptor: 'loopback' };
bot.initConnections(connection); bot.initConnections({ connection: connection });
expect(bot.connections['loopback']).to.be.instanceOf(Connection); expect(bot.connections['loopback']).to.be.instanceOf(Connection);
}); });
}); });
@ -249,15 +250,19 @@ describe("Robot", function() {
context("when passed an array of connection objects", function() { context("when passed an array of connection objects", function() {
it("instantiates a new connection with each of the provided objects", function() { it("instantiates a new connection with each of the provided objects", function() {
var connections = [{ name: 'loopback', adaptor: 'loopback' }] var connections = [{ name: 'loopback', adaptor: 'loopback' }]
bot.initConnections(connections); bot.initConnections({ connections: connections });
expect(bot.connections['loopback']).to.be.instanceOf(Connection); expect(bot.connections['loopback']).to.be.instanceOf(Connection);
}); });
it("avoids name collisions collisions", function() { it("avoids name collisions", function() {
bot.initConnections([ var opts = {
{ name: 'loopback', adaptor: 'loopback' }, connections: [
{ name: 'loopback', adaptor: 'loopback' } { name: 'loopback', adaptor: 'loopback' },
]); { name: 'loopback', adaptor: 'loopback' }
]
};
bot.initConnections(opts);
var keys = Object.keys(bot.connections); var keys = Object.keys(bot.connections);
expect(keys).to.be.eql(["loopback", "loopback-1"]); expect(keys).to.be.eql(["loopback", "loopback-1"]);
@ -275,36 +280,35 @@ describe("Robot", function() {
}); });
context("when not passed anything", function() { context("when not passed anything", function() {
it("returns immediately", function() { it("does not modify the bot's devices", function() {
expect(bot.initDevices()).to.be.eql(undefined); bot.initDevices({});
expect(bot.devices).to.be.eql({});
}); });
}); });
context("when passed a connection object", function() { context("when passed a devicw object", function() {
afterEach(function() { bot.devices = {}; });
it("instantiates a new device with the provided object", function() { it("instantiates a new device with the provided object", function() {
var device = { name: 'ping', driver: 'ping' }; var device = { name: 'ping', driver: 'ping' };
bot.initDevices(device); bot.initDevices({ device: device });
expect(bot.devices['ping']).to.be.instanceOf(Device); expect(bot.devices['ping']).to.be.instanceOf(Device);
}); });
}); });
context("when passed an array of device objects", function() { context("when passed an array of device objects", function() {
afterEach(function() { bot.devices = {}; });
it("instantiates a new device with each of the provided objects", function() { it("instantiates a new device with each of the provided objects", function() {
var devices = [{ name: 'ping', driver: 'ping' }] var devices = [{ name: 'ping', driver: 'ping' }]
bot.initDevices(devices); bot.initDevices({ devices: devices});
expect(bot.devices['ping']).to.be.instanceOf(Device); expect(bot.devices['ping']).to.be.instanceOf(Device);
}); });
it("avoids name collisions collisions", function() { it("avoids name collisions collisions", function() {
bot.initDevices([ bot.initDevices({
{ name: 'ping', driver: 'ping' }, devices: [
{ name: 'ping', driver: 'ping' } { name: 'ping', driver: 'ping' },
]); { name: 'ping', driver: 'ping' }
]
});
var keys = Object.keys(bot.devices); var keys = Object.keys(bot.devices);
expect(keys).to.be.eql(["ping", "ping-1"]); expect(keys).to.be.eql(["ping", "ping-1"]);
@ -353,10 +357,10 @@ describe("Robot", function() {
beforeEach(function() { beforeEach(function() {
bot = new Robot({ bot = new Robot({
connections: [ connections: {
{ name: 'alpha', adaptor: 'loopback' }, alpha: { adaptor: 'loopback' },
{ name: 'bravo', adaptor: 'loopback' } bravo: { adaptor: 'loopback' }
] }
}); });
stub(bot.connections.alpha, 'connect').returns(true); stub(bot.connections.alpha, 'connect').returns(true);
@ -376,11 +380,11 @@ describe("Robot", function() {
beforeEach(function() { beforeEach(function() {
bot = new Robot({ bot = new Robot({
connection: [{ name: 'loopback', adaptor: 'loopback' }], connection: { name: 'loopback', adaptor: 'loopback' },
devices: [ devices: {
{ name: 'alpha', driver: 'ping' }, alpha: { driver: 'ping' },
{ name: 'bravo', driver: 'ping' } bravo: { driver: 'ping' }
] }
}); });
stub(bot.devices.alpha, 'start').returns(true); stub(bot.devices.alpha, 'start').returns(true);