Hi Sparkers! I wanted to share my project I just recently finished up this weekend: An intelligent door buzzer for my apartment, built with Node.js + Express.js, the Spark JavaScript SDK, and Twilio. The idea is relatively simple: Trigger my front door buzzer via text message in a secure way. Check out the demo video:
When a SMS is sent to my Twilio phone number, it checks two things for security purposes:
- The phone number that sent the text is on the list of “allowed people” to whom I’ve given access to my apartment. Be nice to me and maybe I’ll add you to the list!
- The body of the SMS matches the password I’ve set to trigger the opening of the door. Double secure, whammy!
The security logic occurs in a Node.js + Express web app triggered by the Twilio SMS. If those two requirements are met, the Spark JS SDK is used to log the user in and switch pin D0 to HIGH, then LOW after a few seconds. On the hardware side, an NPN transistor + a simple relay completes the circuit of the open door terminals in my in-unit intercom system. The below photos show the setup, thanks to @BDub for the help on the circuit!
The code of my app.js file is below for you to check out:
var twilio = require('twilio'),
express = require('express'),
bodyParser = require('body-parser'),
spark = require('spark')
// Create express app with middleware to parse POST body
var app = express()
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Create a route to respond to a call
app.post('/openDoor', function(req, res) {
// Options
var magicWord = 'Open Sesame'
var allowed_people = ['+1xxxxxxxxxx', '+1xxxxxxxxxx'];
var twilioToken = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
var sparkEmail = 'xxx@xxx.com';
var sparkPassword = 'xxxxxxxxxxxxxxx';
var pin = 'D0';
var buzzerTime = 4000;
//Validate that this request really came from Twilio...
if (twilio.validateExpressRequest(req, twilioToken)) {
var twiml = new twilio.TwimlResponse();
var fromPhone = req.body.From;
var textBody = req.body.Body;
if (allowed_people.indexOf(fromPhone) > -1 ) {
if(textBody.toUpperCase() === magicWord.toUpperCase()) {
twiml.message('Door opening... ');
// LOG IN TO SPARK
var promise = spark.login({username: sparkEmail, password: sparkPassword});
promise.then(
function(token){
var devicesPr = spark.listDevices();
devicesPr.then(
// We get an array with devices back and we list them
function(devices){
var core = devices[0];
core.callFunction('digitalwrite', pin+':HIGH');
setTimeout(function() {core.callFunction('digitalwrite', 'D0:LOW');},buzzerTime);
},
function(err) {
console.log('API call List Devices completed on promise fail: ', err);
}
);
},
function(err) {
console.log('API call completed on promise fail: ', err);
}
);
} else {
twiml.message('Wrong password, try again dude!')
}
} else{
twiml.message('Sorry! Jeff did not give you access to his humble abode.');
}
res.type('text/xml');
res.send(twiml.toString());
}
else {
res.send('you are not twilio. Buzz off.');
}
});
app.listen(process.env.PORT || 3000);
Feedback/Comments welcome!