Skip to content

Commit

Permalink
added GpioPlugin with basic functionality (execute/listenEvents)
Browse files Browse the repository at this point in the history
 + tests
  • Loading branch information
caducas committed Nov 12, 2013
1 parent aab030f commit 434227a
Show file tree
Hide file tree
Showing 2 changed files with 221 additions and 0 deletions.
97 changes: 97 additions & 0 deletions src/plugins/GpioPlugin/GpioPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* This module is used to handle tasks and events directly with GPIO Ports on Raspberry Pi.
* It is used within pi@home.
*
* @class GpioPlugin
*/

var onOff;

/**
* The constructor can be used to change settings of GpioPlugin by using options.
*
* @method GpioPlugin
* @param {opts} opts The options:
* - 'gpioPlugin' = Plugin for using onOff functionality (can be set for testing i.e.)
*/
function GpioPlugin(opts) {
if(opts==='undefined') {
onOff = require('onoff').Gpio;
}

if(opts.gpioPlugin) {
onOff = opts.gpioPlugin;
} else {
onOff = require('onoff').Gpio;
}
return this;
}

/**
* This method is used to execute a pi@home command concerning GPIO Ports.
*
* @method execute
* @param {opts} opts The options:
* - 'direction' = 'in' or 'out'
* - 'pin' = the pin number on RPi GPIOs
* - 'value' = the value for direction 'out'
*/
function execute(opts) {
if(opts==='undefined') {
throw new Error("arguments for execute missing");
}
if(!opts.direction) {
throw new Error("option 'direction' is missing");
}
if(!opts.pin) {
throw new Error("option 'pin' is missing");
}

if(opts.direction === 'out') {
if(!opts.value) {
throw new Error("option 'value' is missing for pin output");
}
this.sendOutput(opts.pin, opts.value);
}
}

/**
* This method is used to send a output to a GPIO pin.
*
* @method sendOutput
* @param {int} pin The pin on which the signal/value should be send.
* @param {int} value The value which should be send (1 = HIGH, 0 = LOW).
*/
function sendOutput(pin, value) {
var gpioPin = onOff.Gpio(pin, 'out');
gpioPin.writeSync(value);
gpioPin.unexport();
}

/**
* This method listens on a GPIO pin and throws events with eventId when value of pin changes.
*
* @method listenEvents
* @param {int} eventId The eventId like configured in event config.
* @param {opts} opts The opts must contain 'pin' on which should be listened.
*/
function listenEvents(eventId, opts) {
if(!opts.pin) {
throw new Error("option 'pin' is missing");
}
//TODO check eventId = valid int
var listenPort = new onOff.Gpio(opts.pin, 'in', 'both', {persistentWatch: true});
var eventIdString = eventId + '';

listenPort.watch(function(err, value) {
process.emit(eventId+'', value);
});
}

// If we're running under Node,
if(typeof exports !== 'undefined') {
exports.execute = execute;
exports.GpioPlugin = GpioPlugin;
exports.sendOutput = sendOutput;
exports.listenEvents = listenEvents;
}
124 changes: 124 additions & 0 deletions test/plugins/Gpio/GpioPlugin-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
var gpioPlugin = require('./../../../src/plugins/GpioPlugin/GpioPlugin');
var assert = require('chai').assert;
var sinon = require('sinon');

describe('GPIO-tests', function(){

it("should throw error because one or more options are missing", function() {
var gpio = gpioPlugin.GpioPlugin({'GpioPlugin':null});
var error;
//without arguments
try {
gpio.execute();
} catch (err) {
error = err;
}
assert.include(error.message, "Cannot read property 'direction' of undefined");

//empty arguments
error = null;
try {
gpio.execute({});
} catch (err) {
error = err;
}
assert.include(error.message, "option 'direction' is missing");

//missing pin
error = null;
try {
gpio.execute({'direction':'in'});
} catch (err) {
error = err;
}
assert.include(error.message, "option 'pin' is missing");

//value missing
error = null;
try {
gpio.execute({'direction':'out','pin':17});
} catch (err) {
error = err;
}
assert.include(error.message, "option 'value' is missing");
});

it("should execute function 'sendOutput' with correct values", function() {
//Preparation
var onOff = require('onoff').Gpio;

var gpioMock = {
writeSync:function(value) {
assert.equal(value,1);
},
unexport:function() {
}
};

var onOffMock = {
Gpio:function(pin,direction) {
assert.equal(pin,18);
assert.equal(direction,'out');
return gpioMock;
}
};

gpio = gpioPlugin.GpioPlugin({'gpioPlugin':onOffMock});

var spy1 = sinon.spy(onOffMock, "Gpio");
var spy2 = sinon.spy(gpioMock, "writeSync");
var spy3 = sinon.spy(gpioMock, "unexport");

//execution
gpio.execute({'direction':'out','pin':18,'value':1});

//assertion
assert(spy1.calledOnce, "method Gpio should be called");
assert(spy2.calledOnce, "method writeSync should be called");
assert(spy3.calledOnce, "method unexport should be called");
});

it("should check functionality of method 'listenEvents'", function() {
//Preparation
var eventId = 1234;
var onOff = require('onoff').Gpio;
var success = false;

process.on("1234", function(value) {
if(value===1) {
success = true;
}
});

var gpioMock = {
watch:function(callback) {
callback(false, 1);
}
};

var onOffMock = {
Gpio:function(pin,direction,edge,options) {
assert.equal(pin,18);
assert.equal(direction,'in');
assert.equal(edge,'both');
assert.equal(options.persistentWatch,true);
return gpioMock;
}
};

gpio = gpioPlugin.GpioPlugin({'gpioPlugin':onOffMock});

var spy1 = sinon.spy(onOffMock, "Gpio");
var spy2 = sinon.spy(gpioMock, "watch");


//execution
gpio.listenEvents(eventId, {'pin':18});

//assertion
assert.equal(success, true, "should return correct event with correct value");

//after test
process.removeAllListeners("1234");
});
});

0 comments on commit 434227a

Please sign in to comment.