Skip to content

Instantly share code, notes, and snippets.

@ersatzavian
Created November 23, 2014 21:48
Show Gist options
  • Select an option

  • Save ersatzavian/e402ff3032e578504d87 to your computer and use it in GitHub Desktop.

Select an option

Save ersatzavian/e402ff3032e578504d87 to your computer and use it in GitHub Desktop.
twilio lockbox example
/******************** Constants ********************/
// Your MailGun settings
const API_KEY = "key-a1b2c3...";
const SUBDOMAIN = "sandbox123abc.mailgun.org";
// Define what email to notify
const EMAIL = "[email protected]";
const TWILIO_SID = ""; // Your Twilio Account SID
const TWILIO_AUTH = ""; // Your Twilio Auth Token
const TWILIO_NUM = ""; // Your Twilio Phone Number
// sending a message
numberToSendTo <- "15555555555"
// Define your password for the lockbox
const PASSWORD = "yourpassword"
// Define Lock States
const UNLOCKED = 0;
const LOCKED = 1;
/******************** HTML CODE ********************/
const html = @"
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='shortcut icon' href='http://www.freefavicon.com/freefavicons/objects/love-kills-152-173204.png' />
<title>My Lockbox</title>
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css'>
<link rel='stylesheet' href='https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css'>
<style>
.webpage {
/* Background colour */
background-color: white;
/* Full screen background image */
background-image: url('http://www.wallpaperdisk.com/wallpapers/Space/space2.jpg');
/* tiled background image */
/*
* background-image: url('http://zho.berka.com/tiles/starsandnebula250d.jpg');
* background-repeat: repeat;
*/
}
.title {
color: white;
}
.password-box {
width: 80%;
margin: 25px auto 25px auto;
text-align:center;
border-color: black;
background-color: white;
color: black;
}
.btn {
width: 150px;
border-color: grey;
background-color: white;
color: black;
}
.lock-icon {
margin-top: 20px;
color: white;
}
.footer {
position:fixed;
left:0px;
bottom:0px;
height:30px;
width:100%;
}
</style>
</head>
<body class='webpage'>
<div class='container col-xs-12 col-sm-4 col-sm-offset-4 text-center'>
<h1 class='title'>My Lockbox</h1>
<input class='form-control password-box' type='password' id='pw' placeholder='Password'>
<button class='btn' type='button' onclick='lock();'><i class='fa fa-lock'></i>&nbsp; Lock</button>
<button class='btn' type='button' onclick='unlock();'><i class='fa fa-unlock-alt'></i>&nbsp; Unlock</button>
<div class='lock-icon'>
<i class='fa fa-question fa-5x' id='status'></i>
</div>
<div class='footer'>
Powered by <a href='http://electricimp.com' target='_blank'>Electric Imp</a>
</div>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js'></script>
<script src='https://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js'></script>
<script>
var myUrl = window.location.href;
function lock() {
var pw = $('#pw').val();
var lockUrl = myUrl + '/lock';
$.post(lockUrl, pw, function(state) {
setLockIcon(state);
});
}
function unlock() {
var pw = $('#pw').val();
var unlockUrl = myUrl + '/unlock';
$.post(unlockUrl, pw, function(state) {
setLockIcon(state);
});
}
function getStatus() {
// fetch the current state from the agent
var statusUrl = myUrl + '/status';
// set the lock icon based on the result
$.get(statusUrl, function(d) {
setLockIcon(d);
});
}
function setLockIcon(state) {
// remove all the classes that set the image
$('#status').removeClass('fa-question');
$('#status').removeClass('fa-lock');
$('#status').removeClass('fa-unlock-alt');
// add the proper images based on the state
if (state == 0) {
$('#status').addClass('fa-unlock-alt');
}
if (state == 1) {
$('#status').addClass('fa-lock');
}
}
// when the webpage is loaded
$(function() {
getStatus();
});
</script>
</body>
</html>
"
/******************** LIBRARY CODE ********************/
class Twilio {
_baseUrl = "https://api.twilio.com/2010-04-01/Accounts/";
_accountSid = null;
_authToken = null;
_phoneNumber = null;
constructor(accountSid, authToken, phoneNumber) {
_accountSid = accountSid;
_authToken = authToken;
_phoneNumber = phoneNumber;
}
function send(to, message, callback = null) {
local url = _baseUrl + _accountSid + "/SMS/Messages.json"
local auth = http.base64encode(_accountSid + ":" + _authToken);
local headers = { "Authorization": "Basic " + auth };
local body = http.urlencode({
From = _phoneNumber,
To = to,
Body = message
});
local request = http.post(url, headers, body);
if (callback == null) return request.sendsync();
else request.sendasync(callback);
}
function Respond(resp, message) {
local data = { Response = { Message = message } };
local body = xmlEncode(data);
resp.header("Content-Type", "text/xml");
server.log(body);
resp.send(200, body);
}
function xmlEncode(data, version="1.0", encoding="UTF-8") {
return format("<?xml version=\"%s\" encoding=\"%s\" ?>%s", version, encoding, _recursiveEncode(data))
}
/******************** Private Function (DO NOT CALL) ********************/
function _recursiveEncode(data) {
local s = "";
foreach(k, v in data) {
if (typeof(v) == "table" || typeof(v) == "array") {
s += format("<%s>%s</%s>", k.tostring(), _recursiveEncode(v), k.tostring());
}
else {
s += format("<%s>%s</%s>", k.tostring(), v.tostring(), k.tostring());;
}
}
return s
}
}
function SendEmail(to, subject, text) {
local url = "https://api.mailgun.net/v2/" + SUBDOMAIN + "/messages";
local fromEmail = "alarm@" + SUBDOMAIN;
local headers = { "Authorization": "Basic " + http.base64encode("api:" + API_KEY) };
local data = http.urlencode({
to = to,
from = fromEmail,
subject = subject,
text = text
});
http.post(url, headers, data).sendasync(function(resp) {
if (resp.statuscode != 200 && resp.statuscode != 0) {
server.log(resp.statuscode + " - " + resp.body);
}
});
}
/******************** Electric Imp CODE ********************/
// Create a variable to hold the current lock state
lockStatus <- LOCKED;
twilio <- Twilio(TWILIO_SID, TWILIO_AUTH, TWILIO_NUM);
// agent code:
function httpHandler(request, response) {
try {
// webpage
if (request.path == "/") {
response.send(200, html);
return;
}
// get the current status
if (request.path == "/status") {
response.send(200, lockStatus);
return;
}
// Lock command
if (request.path == "/lock") {
// check the password
if (request.body == PASSWORD) {
// change the lockStatus to LOCKED if password is ok
lockStatus = LOCKED;
}
}
// unlock command
if (request.path == "/unlock") {
// check the password
if (request.body == PASSWORD) {
// change the lockStatus to UNLOCKED if password is ok
lockStatus = UNLOCKED;
}
}
// send back a response with the current lock status
response.send(200, lockStatus);
} catch (ex) {
// if there was an error
response.send(500, "ERROR - " + ex);
return;
}
}
// run httpHandler whenever a request comes into the Agent URL
http.onrequest(httpHandler);
// when the alarm is triggered, run this code
function ALARM() {
server.log("ALARM ALARM ALARM");
twilio.send(numberToSendTo, "Alarm!", function(resp) { server.log(resp.statuscode + " - " + resp.body); });
SendEmail(EMAIL, "ALARM! ALARM!", "Someone just tried to open your lockbox without unlocking it!");
}
// when we get a checkAlarm message from the device
device.on("checkAlarm", function(data) {
// send them our current lockStatus
device.send("checkAlarm", lockStatus);
// if it's locked, trigger the alarm!
if (lockStatus == LOCKED) {
ALARM();
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment