-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added motion class with PIR controller
- Loading branch information
1 parent
79b1207
commit 829a5a3
Showing
9 changed files
with
358 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<!--remove-start--> | ||
|
||
# Motion | ||
|
||
|
||
Basic infrared Motion example | ||
|
||
|
||
Run with: | ||
```bash | ||
node eg/motion.js | ||
``` | ||
|
||
<!--remove-end--> | ||
|
||
```javascript | ||
var five = require("johnny-five"); | ||
var board = new five.Board(); | ||
|
||
board.on("ready", function() { | ||
|
||
// Create a new `motion` hardware instance. | ||
var motion = new five.Motion(7); | ||
|
||
// "calibrated" occurs once, at the beginning of a session, | ||
motion.on("calibrated", function() { | ||
console.log("calibrated"); | ||
}); | ||
|
||
// "motionstart" events are fired when the "calibrated" | ||
// proximal area is disrupted, generally by some form of movement | ||
motion.on("motionstart", function() { | ||
console.log("motionstart"); | ||
}); | ||
|
||
// "motionend" events are fired following a "motionstart" event | ||
// when no movement has occurred in X ms | ||
motion.on("motionend", function() { | ||
console.log("motionend"); | ||
}); | ||
|
||
// "data" events are fired at the interval set in opts.freq | ||
// or every 25ms | ||
motion.on("data", function(data) { | ||
console.log(data); | ||
}); | ||
}); | ||
|
||
``` | ||
|
||
|
||
## Illustrations / Photos | ||
|
||
|
||
### Breadboard for "Motion" | ||
|
||
|
||
|
||
![docs/breadboard/motion.png](breadboard/motion.png)<br> | ||
|
||
Fritzing diagram: [docs/breadboard/motion.fzz](breadboard/motion.fzz) | ||
|
||
| ||
|
||
|
||
|
||
|
||
|
||
| ||
|
||
<!--remove-start--> | ||
|
||
## License | ||
Copyright (c) 2012, 2013, 2014 Rick Waldron <waldron.rick@gmail.com> | ||
Licensed under the MIT license. | ||
Copyright (c) 2014, 2015 The Johnny-Five Contributors | ||
Licensed under the MIT license. | ||
|
||
<!--remove-end--> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
var five = require("../lib/johnny-five.js"); | ||
var board = new five.Board(); | ||
|
||
board.on("ready", function() { | ||
|
||
// Create a new `motion` hardware instance. | ||
var motion = new five.Motion(7); | ||
|
||
// "calibrated" occurs once, at the beginning of a session, | ||
motion.on("calibrated", function() { | ||
console.log("calibrated"); | ||
}); | ||
|
||
// "motionstart" events are fired when the "calibrated" | ||
// proximal area is disrupted, generally by some form of movement | ||
motion.on("motionstart", function() { | ||
console.log("motionstart"); | ||
}); | ||
|
||
// "motionend" events are fired following a "motionstart" event | ||
// when no movement has occurred in X ms | ||
motion.on("motionend", function() { | ||
console.log("motionend"); | ||
}); | ||
|
||
// "data" events are fired at the interval set in opts.freq | ||
// or every 25ms | ||
motion.on("data", function(data) { | ||
console.log(data); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
var Board = require("../lib/board.js"), | ||
events = require("events"), | ||
util = require("util"), | ||
temporal = require("temporal"), | ||
priv = new Map(); | ||
|
||
var Controllers = { | ||
PIR: { | ||
initialize: { | ||
value: function (opts, dataHandler) { | ||
|
||
var state = priv.get(this); | ||
var calibrationDelay = "calibrationDelay" in opts ? opts.calibrationDelay : 30000; | ||
|
||
this.io.pinMode(opts.pin, this.io.MODES.INPUT); | ||
|
||
temporal.delay(calibrationDelay, function() { | ||
state.isCalibrated = true; | ||
this.emit("calibrated", null); | ||
}.bind(this)); | ||
|
||
this.io.digitalRead(opts.pin, function(data) { | ||
dataHandler.call(this, !!data); | ||
}.bind(this)); | ||
|
||
} | ||
} | ||
}, | ||
}; | ||
|
||
/** | ||
* Motion | ||
* @constructor | ||
* | ||
* five.Motion(7); | ||
* | ||
* five.Motion({ | ||
* controller: "PIR", | ||
* pin: 7, | ||
* freq: 100, | ||
* calibrationDelay: 1000 | ||
* }); | ||
* | ||
* | ||
* @param {Object} opts [description] | ||
* | ||
*/ | ||
|
||
function Motion(opts) { | ||
|
||
if (!(this instanceof Motion)) { | ||
return new Motion(opts); | ||
} | ||
|
||
var controller; | ||
var freq = opts.freq || 25; | ||
|
||
// new | ||
var state; | ||
var last = false; | ||
|
||
Board.Device.call( | ||
this, opts = Board.Options(opts) | ||
); | ||
|
||
if (typeof opts.controller === "string") { | ||
controller = Controllers[opts.controller]; | ||
} else { | ||
controller = opts.controller || Controllers["PIR"]; | ||
} | ||
|
||
Object.defineProperties(this, controller); | ||
|
||
state = { | ||
detectedMotion: false, | ||
isCalibrated: false | ||
}; | ||
|
||
priv.set(this, state); | ||
|
||
Object.defineProperties(this, { | ||
/** | ||
* [read-only] Current sensor state | ||
* @property detectedMotion | ||
* @type Boolean | ||
*/ | ||
detectedMotion: { | ||
get: function() { | ||
return state.detectedMotion; | ||
} | ||
}, | ||
/** | ||
* [read-only] Sensor calibration status | ||
* @property isCalibrated | ||
* @type Boolean | ||
*/ | ||
isCalibrated: { | ||
get: function() { | ||
return state.isCalibrated; | ||
} | ||
}, | ||
}); | ||
|
||
if (typeof this.initialize === "function") { | ||
this.initialize(opts, function(data) { | ||
state.detectedMotion = data; | ||
}); | ||
} | ||
|
||
setInterval(function() { | ||
|
||
var eventData = { | ||
timestamp : Date.now(), | ||
detectedMotion : state.detectedMotion, | ||
isCalibrated : state.isCalibrated | ||
}; | ||
|
||
if (state.isCalibrated && state.detectedMotion && !last) { | ||
this.emit("motionstart", eventData); | ||
} | ||
|
||
if (state.isCalibrated && !state.detectedMotion && last) { | ||
this.emit("motionend", eventData); | ||
} | ||
|
||
this.emit("data", eventData); | ||
|
||
last = state.detectedMotion; | ||
|
||
}.bind(this), freq); | ||
} | ||
|
||
util.inherits(Motion, events.EventEmitter); | ||
|
||
module.exports = Motion; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
var MockFirmata = require("./util/mock-firmata"), | ||
five = require("../lib/johnny-five.js"), | ||
events = require("events"), | ||
sinon = require("sinon"), | ||
Board = five.Board, | ||
Motion = five.Motion, | ||
board = new Board({ | ||
io: new MockFirmata(), | ||
debug: false, | ||
repl: false | ||
}); | ||
|
||
exports["Motion"] = { | ||
setUp: function(done) { | ||
this.clock = sinon.useFakeTimers(); | ||
this.digitalRead = sinon.spy(board.io, "digitalRead"); | ||
this.motion = new Motion({ | ||
pin: 7, | ||
calibrationDelay: 10, | ||
board: board | ||
}); | ||
|
||
this.instance = [{ | ||
name: "detectedMotion" | ||
}, { | ||
name: "isCalibrated" | ||
}]; | ||
|
||
done(); | ||
}, | ||
|
||
tearDown: function(done) { | ||
this.motion.removeAllListeners(); | ||
this.clock.restore(); | ||
this.digitalRead.restore(); | ||
done(); | ||
}, | ||
|
||
shape: function(test) { | ||
test.expect(this.instance.length); | ||
|
||
this.instance.forEach(function(property) { | ||
test.notEqual(typeof this.motion[property.name], "undefined"); | ||
}, this); | ||
|
||
test.done(); | ||
}, | ||
|
||
emitter: function(test) { | ||
test.expect(1); | ||
|
||
test.ok(this.motion instanceof events.EventEmitter); | ||
|
||
test.done(); | ||
}, | ||
|
||
data: function(test) { | ||
var spy = sinon.spy(); | ||
test.expect(1); | ||
this.motion.on("data", spy); | ||
this.clock.tick(25); | ||
test.ok(spy.calledOnce); | ||
test.done(); | ||
}, | ||
|
||
motionstart: function(test) { | ||
var callback = this.digitalRead.args[0][1], | ||
spy = sinon.spy(); | ||
|
||
test.expect(1); | ||
this.motion.on("motionstart", spy); | ||
|
||
// 0 then changes to 1 | ||
callback(0); | ||
callback(1); | ||
this.clock.tick(25); | ||
|
||
test.ok(spy.calledOnce); | ||
test.done(); | ||
}, | ||
|
||
motionend: function(test) { | ||
var callback = this.digitalRead.args[0][1], | ||
spy = sinon.spy(); | ||
|
||
test.expect(1); | ||
this.motion.on("motionend", spy); | ||
|
||
// 1 then changes to 0 | ||
callback(1); | ||
this.clock.tick(25); | ||
callback(0); | ||
this.clock.tick(25); | ||
|
||
test.ok(spy.calledOnce); | ||
test.done(); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters