-
1Step 1
The hardware
The circuit schematic for the solenoid driver looks like this:-
(You can also find it on Upverter)
And this is how we assembled the solenoid driver on the protoboard:-
The software
the Raspberry Pi runs a node.js server which implements a multi-step authentication mechanism, in order to achieve this we designed a state-machine using machina.js served up over HTTP via express.js. Most of the interaction operates over socket.io, to provide real time feedback to the user.
We use the "authy" npm package to easily interact with the Authy API, borrowing some code from their tutorial.
State machines consist of states and events which generate transitions from one state to another - the model we use in our application, 'Safebox', has 'open' and 'closed' states with transitions going from one to the other in both directions, passing through intermediate states which handle the auth process.
Whenever a user interacts with the UI, input events are fired via socket.io which are passed on to the state machine.
The code below is an example of how these states and transitions are defined:
var safebox = new machina.Fsm({ /* ... other properties here */ states: { /* ... other states here and below */ closed: { _onEnter: function(){ this.lock.enabled(false); this.lock.close(); this.persistedState.currentState = 'closed'; this.persistedState.save(); this.emitStatus(); }, input: function(data){ this.currentUser.comparePassword(data.code, function(err, match){ if(match){ safebox.transition('authenticating'); } else { io.emit('notice', 'That\'s not your code!'); safebox.transition('closed'); } }); } }, /* ... */ } });
When the machine transitions to the 'closed' state its _onEnter function is called disabling the lock and saving this new state. When the user subsequently inputs a code we compare it against their password only transitioning to the next state if there's a match.
We used MongoDB to persist the box's current state and user data - storing user data allows us to store user's passcodes and phone numbers so they don't need to reconfigure their device each time the device is restarted.
The code integrating the user model also interacts with the Authy API which provides methods for sending an SMS to the user and verifying the code that they provide.
On the client side, we have a simple single-page jQuery app that shows different HTML content for each of the state-machine's states, listens to events on the dialpad and inputs, sends socket.io messages and provides the user with the appropiate feedback. We used Bootstrap and toastr to rapidly design an interface that is reasonably pleasing to the eye :)
We use resin.io to tie everything together with a Dockerfile that sets up the environment and runs our start script:-
FROM resin/rpi-raspbian:jessie RUN apt-get update && apt-get install -y curl RUN curl -sL https://deb.nodesource.com/setup | bash - RUN apt-get install -y build-essential nodejs mongodb COPY . . RUN mkdir -p /datadb RUN npm install EXPOSE 8080 CMD bash start.sh
Our start.sh script then starts MongoDB (repairing it in case of an unclean shutdown) and our web server:-
rm /datadb/mongod.lock /usr/bin/mongod --dbpath /datadb --repair /usr/bin/mongod --dbpath /datadb --fork --logpath mongod.log && node index.js
Using resin.io makes our deployment as simple as typing 'git push' and the fact that it allows us to use docker ensures that all our dependencies are met in the precisely the same way for every device. It couldn't be simpler :)
You can find all the source code for the project in our GitHub repository!
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.