This project brings together all of the fundamental concepts of the previous examples to illustrate how easy it is to create a fully functional Internet-connected security system. It uses the EVB’s on-board accelerometer to detect movement, the EVB’s buttons to arm and disarm the system, and the board’s multi-color LED to signal the system’s state. The example uses agent-device communications to signal a change of state and, if necessary, the agent sends the user a warning by way of an SMS message transmitted by Twilio, an SMS web service.
If you are having problems getting the EVB online, please consult the BlinkUp Troubleshooting Guide.
A successful BlinkUp operation is indicated by a slowly flashing green LED on the EVB. The EVB will be listed in impCentral’s ‘My Development Devices’ list (accessed via the devices menu in the black bar at the top). The number presented in impCentral is the EVB’s unique Device ID. You can, if you wish, give it a more friendly name as follows:
This example provides a rudimentary but complete Internet-connected security system. When armed, the system will send an alert SMS to the cellphone number of your choice if a door in your office or workroom is opened. The EVB, with suitable AA batteries in place, is attached to the door you want to monitor.
By default, the system is unarmed but always actively detecting motion. Buttons BTN1 and BTN2 respectively arm and disarm the device. When you arm the system, the multi-color LED glows orange. If motion is detected, the LED will turn red, and the agent is signalled to activate the transmission of a warning SMS. The LED stays red for a programmable period of time elapses. This timeout prevents additional alarms — and therefore SMS messages — from triggering during that time. You can configure the timeout, specified in seconds, in the device code here:
// Change Timeouts as desired
ARMED_TIMEOUT <- 10.0;
DISARMED_TIMEOUT <- 1.0;
The device has a few more things to do than set the timeout. It is responsible for handling button events, accelerometer events, and alerting the user through its LED and, via the agent, SMS.
The LIS3DH accelerometer is an I²C device. We need to configure the pins already connected to the accelerometer to use I²C signalling. You’ll note that we have implemented the LIS3DH code not merely as its own Squirrel class — which we instantiate as the object accel
— but that this is a sub-class of an existing class, sensor
. The sensor class defines general parameters and functionality for connected data-generating devices. The class lis3dh
uses the Squirrel keyword extends
to incorporate all that generic functionality with its own accelerometer-specific functionality.
class sensor {...}
class lis3dh extends sensor {...}
This is a powerful facility: not only can classes easily be used in multiple projects, but sub-classing them allows broad categories of classes to be adapted for specific circumstances. You can read more about how Squirrel provides classes and objects in the Squirrel Programming Guide.
The example’s classes contain a special initialization function marked with the keyword constructor
. The lis3dh
class takes an imp i2c object as a parameter, along with a pin to be used to wake the imp003/LBWA1ZV1CD from the deep sleep mode it will be programmed to enter to conserve battery power. Only one imp003/LBWA1ZV1CD pin can be used this way: pin W.
i2c <- hardware.i2cAB;
accel <- lis3dh(i2c, hardware.pinW);
In addition, we have a third class, Security
, which manages all of the higher level application behavior: it takes as parameters an lis3dh
instance, and references to the arming and disarming buttons, and the multi-color LED’s green and red components. The Security
class is essential a simple state machine. When an event is triggered, it responds by checking state variables and then decides whether an alert needs to be send:
function event() {
if (MOVEMENT == null) {
MOVEMENT = true;
GREEN_LED.write(1);
switch(STATE) {
case ARMED:
server.log("ALARM CONDITION");
agent.send("alarm", null);
imp.wakeup(ARMED_TIMEOUT, function(){ clearMovement(); }.bindenv(this));
break;
case DISARMED:
imp.wakeup(DISARMED_TIMEOUT, function(){ clearMovement(); }.bindenv(this));
server.log("FAULT CONDITION");
break;
}
server.log("I moved!");
}
}
It is the agent.send() seen above in the ARMED
condition that tells the agent to send the SMS. We have no data to pass, so we simply add null
as the data payload.
The agent is responsible for sending the SMS via the Twillio web service. We have implemented a Twillio library — you can find out about it here — for your use in any application and we’ve used it here too. It makes use of the http object to interact with the restful interface that Twillio provides.
The class is instantiated with your Twilio credentials as parameters.
#require "Twilio.class.nut:1.0.0"
twilio <- Twilio(TWILIO_SID, TWILIO_AUTH, TWILIO_NUM);
To send an SMS message, call the class’ send() method, providing a phone number, the text of the message and, optionally, a function to handle the response. If a callback function isn’t provided, the class sends the request to Twilio synchronously; providing a callback ensures that the request is send asynchronously.
twilio.send(numberToSendTo, "MESSAGE", function(resp) { server.log(resp.statuscode + " - " + resp.body); });
Aside from this, the agent needs a way to register its interest in messages from the device. This is established with a callback assigned with device.on():
device.on("alarm", function(val) {
server.log("ALARM CONDITION");
twilio.send(numberToSendTo, "ALARM CONDTION!", function(resp) { server.log(resp.statuscode + " - " + resp.body); });
});
The first parameter, "alarm"
, sets the message name to match the identifier the device will send. The second parameter is the callback function to execute. The callback takes a single parameter for data sent by the device; in this case there is none, but we need to include a dummy parameter in any case. When an "alarm"
message is received by the agent, the callback function logs the event and calls on the twilio
object to send an SMS message to the specified cellphone number.