LinuxLock
About
Kaleidus Code LinuxLock service for Raspberry Pi
Installation
Dependencies:
- Stable Node.js for Raspberry Pi (currently 0.10.13). We can not use the Debian repository's copy of Node, as it is unfortunately very old and out of date. Further, it renames the
node
executable, which is terribly inconvenient. Installation instructions:
# Download binary tarball wget http://nodejs.org/dist/v0.10.13/node-v0.10.13-linux-arm-pi.tar.gz # Install for the entire system sudo tar -xzf node-v0.10.13-linux-arm-pi.tar.gz --strip 1 -C /usr/local
To install, download the package with sudo npm install -g linux-lock-pi
, on a Raspberry Pi, equipped with the Raspbian Wheezy operating system.
Setup
linux-lock-service
uses JSON configuration files to learn how to configure the system. BY DEFAULT, linux-lock-service
will try to open ~/.linux-lock-service.json
, if a configuration file is not specified on the command line. If no configuration is found, then the application will quit.
Currently, there are 3 configuration keys, for each of the three different concerns of the application: client
, gpio
, and rfidReader
. Each of these keys are special, in that they can be Objects containing the pertinent keys, or they can be Strings, interpretted as paths to JSON files containing the pertinent definition.
EG:
would attempt to load the JSON file at that path, which should contain a JSON Object literal similar to this:
The object defined in /var/opt/linux-lock-client.json
is then incorporated into the configuration object, as the value for the client
key.
client
key
The tells the application which web server we are communicating with. There is no way to manually configure the URLs to be queried, as Client#checkRFID()
will always request /api/auth/rfid/:rfidNo.json
. This might be adjusted in the future, but it is not difficult to circumvent, for applications which need to do so.
The supported keys include:
key | value |
---|---|
server | The URL for the web service. The path requested by `Client#checkRFID()` should be relative to that domain. Currently, applications served under subdirectories are not supported. There is no default value |
port | The server port to be used. This is a convenience field, as the port can be inserted directly into the URL and nobody would be the wiser. Defaults to the default port of the connection scheme being used |
version | The version of the JSON API we are expecting. This is a feature which enables Restify to select a route based on a strict API version. LinuxLock is no longer using restify on the server side, however it is kept in place on the client side for applications which may wish to use it. It defaults to "~1.0" |
gpio
key
The tells the application which electric signals to send to the Raspberry Pi's GPIO headers, when, and for how long.
warning: No validation is performed, it is entirely up to you to ensure that your values are safe for you and your machinery. Caitlin Potter and Kaleidus Code are not in any way, shape or form liable should something go wrong.
The API allows for the execution of arbitrary GPIO configurations, however the main application uses only two, which are detailed here. An example configuration:
The above configuration demonstrates simple GPIO instructions, split into two sets of comments.
The authorized
command, which is recognized by the linux-lock-service
application, is told to set
(raise voltage on) pins 11 and 15, in parallel, for 1 second (1000 milliseconds
)
The unauthorized
command, which is also recognized by the linux-lock-service
application, is told to set
(raise voltage on) pins 16 and 17, in series.
The reason why authorized
executes the commands for the two pins in parallel, while unauthorized
executes them in series, is because of the algorithm which is used to walk the instruction object, detailed further on.
Further GPIO details:
The Pi configuration uses the Raspberry Pi Header Schema for pin numbers. As a reference, here is a diagram relating the Header pin schema to the WiringPi pin schema:
WiringPi | Name | Header | Name | WiringPi |
---|---|---|---|---|
– | 3.3v | 01 | 02 | 5v | – |
8 | SDA0 | 03 | 04 | 5v | – |
9 | SCL0 | 05 | 06 | 0v | – |
7 | GPIO7 | 07 | 08 | TxD | 15 |
– | 0v | 09 | 10 | RxD | 16 |
0 | GPIO0 | 11 | 12 | GPIO1 | 1 |
2 | GPIO2 | 13 | 14 | 0v | – |
3 | GPIO3 | 15 | 16 | GPIO4 | 4 |
– | 3.3v | 17 | 18 | GPIO5 | 5 |
12 | MOSI | 19 | 20 | 0v | – |
13 | MISO | 21 | 22 | GPIO6 | 6 |
14 | SCLK | 23 | 24 | CE0 | 10 |
– | 0v | 25 | 26 | CE1 | 11 |
The structure of a GPIO instruction set is the following:
"authorized": // The configuration (or command) name. Its value is an Object // or Array of Objects (Sub-configurations) // Sub-configuration #1 "pin": 22 // Sub-configuration default pin (can be overridden by actions) "action": // Object, or Array of Objects, denoting actions to be taken // (Actions) // Action #1 "set": 1000 // Verb, with Time (Milliseconds) value // Action #2 "pin": 17 // This action overrides the Sub-configuration default pin "set": 2000
The algorithm for executing GPIO instructions is the following:
- Execute each Sub-configuration in parallel
- Abort processing Sub-configuration if it's not an Object
- Cache Sub-configuration Default Pin, if specified
- Store Sub-configuration Action, if specified.
- Abort processing Sub-configuration if Action is not an Object or Array
- Execute each Sub-configuration Action in series
- Abort processing Action if it is not an Object, or is an Array
- Cache either the Sub-configuration Default Pin, or the Action Pin, if specified
- Abort action if there is no specified Pin
- For each Supported Verb, execute in parallel:
- If the Action specifies the verb, and the value for the Action Verb is a Number, execute the Verb
The Supported Verbs are currently:
verb | description |
---|---|
set | Raise pin for specified duration of time |
Different verbs may be provided in the future, as well as a mechanism for specifying whether a block is executed in series or in parallel.
rfidReader
key
The Enables the application to specify the means and parameters for communicating with a particular RFID reader.
Currently, only a Serial protocol is supported.
The following options are supported:
key | description |
---|---|
serialPort | The device name to use. Defaults to /dev/ttyUSB0 |
baudRate | Baud Rate, defaults to 2400 . Must be one of: 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1800, 1200, 600, 300, 200, 150, 134, 110, 75, or 50. |
dataBits | Data Bits, defaults to 8 . Must be one of: 8, 7, 6, or 5. |
stopBits | Stop Bits, defaults to 1 . Must be one of: 1 or 2. |
parity | Parity, defaults to none . Must be one of: 'none', 'even', 'mark', 'odd', 'space' |
bufferSize | Size of read buffer, defaults to 255 . Must be an integer value. |
These are passed directly into the node-serialport module, however only supported values are used due to the normalization process. These settings enable the selection of the serial port to be used, as well as the parameters for communicating with it.
In development, we have been using the Parallax RFID Card Reader (USB Serial). Technical specifications for different RFID Readers should be available on a manufacturer's website.
A very simple rfidReader
configuration suitable for the Parallax RFID Card Reader on a Raspberry Pi, would look like the following:
Further configuration
After building a satisfactory configuration, it is desirable to run the service in perpetuum, using tools such as Debian Services, or node-forever/nodemon
This configuration is entirely up to the user, however I've provided an example of configuring the service as a Debian Service (example instructions).
In order for the service to communicate with the LinuxLock webserver, we require a static IP which is known to the server itself. It is the task of the network administrator to configure the networking correctly. Using Raspbian Wheezy, network configuration is largely a task of writing /etc/network/interfaces in an effective manner.
Congratulations, your lock service is now communicating with the LinuxLock server, and can be notified when a user is authorized to enter a door via an RFID swipe, and it takes only milliseconds. Wonderful!
API Documentation
Due to the separation of concerns, it is possible (and not very difficult) to build an application similar to linux-lock-service
, using the APIs provided.
Client
This module is responsible for communication with a remote JSON web service. Access it via the following:
var client = Client
Client#normalizeConfig(config, done)
Parameters |
|
Returns | undefined |
Description | Normalize the client configuration of linux-lock-pi, by removing unknown or invalid keys. |
Client#loadConfig(path, done)
Parameters |
|
Returns | undefined |
Description | Load a client/server configuration from a JSON file, and return an object containing the parsed key/values which are pertinent to the client/server module. |
Client#createClient(options)
Parameters |
|
Returns | Object (node-restify JsonClient). This Restify client is a customized instance featuring LinuxLock-specific routines: JsonClient#checkRFID(rfidNo) |
Description | Create an instance of a JsonClient, which will interact with the LinuxLock JSON web service / API. |
Client#checkRFID(rfidNo)
Parameters |
|
Returns | undefined |
Description | Sends a request to the web service, which shall in turn emit either an 'authorized' event, or an 'unauthorized' event. The event data for these events shall contain the deserialized RFID tag under 'tag', and the type 'rfid', EG "{type: 'rfid', tag: '01AB9607AD'}" |
GPIO
This module is responsible for communication with the Raspberry Pi GPIO Header, and sending electric signals to peripheral devices, such as magnetic locks.
var client = GPIO
GPIO#normalizeConfig(config, done)
Parameters |
|
Returns | undefined |
Description | Normalize the gpio configuration of linux-lock-pi, by removing unknown or invalid keys. |
GPIO#loadConfig(path, done)
Parameters |
|
Returns | undefined |
Description | Load a GPIO configuration from a JSON file, and return an object containing the parsed key/values which are pertinent to the GPIO module. |
GPIO#GPIO()
Returns | Object (instanceof GPIO) |
Description | Construct a GPIO object, which will issue commands to the Raspberry Pi GPIO headers, using instructions parsed from JSON files. |
GPIO#GPIO#execute(config)
Parameters |
|
RFIDReader
This module is responsible for communication with a serial RFID Reader/Scanner.
// Helper methodsvar rfidReader = rfidReader // Constructor RFIDReader = RFIDReader
RFIDReader#normalizeConfig(config, done)
Parameters |
|
Returns | undefined |
Description | Normalize the RFIDReader configuration of linux-lock-pi, by removing unknown or invalid keys. |
RFIDReader#loadConfig(path, done)
Parameters |
|
Returns | undefined |
Description | Load an rfid/serial port configuration from a JSON file, and return an object containing the parsed key/values which are pertinent to the RFIDReader module. |
RFIDReader#RFIDReader(serialPort, config, open)
Parameters |
|
Returns | Object (instanceof RFIDReader) |
Description | Construct an RFIDReader interface, which manages the communication with a serial port, and emits a 'scanned' event when an RFID tag has been read. |