From 1ff9f9e235f97773d53ac74b125ed4a4af88303b Mon Sep 17 00:00:00 2001 From: Nick Farina Date: Sun, 30 Nov 2014 22:18:52 -0800 Subject: [PATCH] Add Lockitron accessory shim --- accessories/Lockitron.js | 173 +++++++++++++++++++++++++++++++++++++++ config-sample.json | 7 ++ 2 files changed, 180 insertions(+) create mode 100644 accessories/Lockitron.js diff --git a/accessories/Lockitron.js b/accessories/Lockitron.js new file mode 100644 index 0000000..313f252 --- /dev/null +++ b/accessories/Lockitron.js @@ -0,0 +1,173 @@ +var types = require("../lib/HAP-NodeJS/accessories/types.js"); +var request = require("request"); + +// +// Lockitron Accessory +// + +function LockitronAccessory(log, config) { + this.log = log; + this.lockID = config["lock_id"]; + this.accessToken = config["api_token"]; +} + +LockitronAccessory.prototype = { + setState: function(state) { + this.log("Set state to " + state); + + var lockitronState = (state == 1) ? "lock" : "unlock"; + var that = this; + + var query = { + access_token: this.accessToken, + state: lockitronState + }; + + request.put({ + url: "https://api.lockitron.com/v2/locks/"+this.lockID, + qs: query + }, function(err, response, body) { + + if (!err && response.statusCode == 200) { + that.log("State change complete."); + } + else { + that.log("Error '"+err+"' setting lock state: " + body); + } + }); + }, + + accessoryData: function() { + var that = this; + return { + services: [{ + sType: types.ACCESSORY_INFORMATION_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Lockitron", + supportEvents: false, + supportBonjour: false, + manfDescription: "Name of the accessory", + designedMaxLength: 255 + },{ + cType: types.MANUFACTURER_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Apigee", + supportEvents: false, + supportBonjour: false, + manfDescription: "Manufacturer", + designedMaxLength: 255 + },{ + cType: types.MODEL_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Rev-2", + supportEvents: false, + supportBonjour: false, + manfDescription: "Model", + designedMaxLength: 255 + },{ + cType: types.SERIAL_NUMBER_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "A1S2NASF88EW", + supportEvents: false, + supportBonjour: false, + manfDescription: "SN", + designedMaxLength: 255 + },{ + cType: types.IDENTIFY_CTYPE, + onUpdate: null, + perms: ["pw"], + format: "bool", + initialValue: false, + supportEvents: false, + supportBonjour: false, + manfDescription: "Identify Accessory", + designedMaxLength: 1 + }] + },{ + sType: types.LOCK_MECHANISM_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Lock Mechanism", + supportEvents: false, + supportBonjour: false, + manfDescription: "Name of service", + designedMaxLength: 255 + },{ + cType: types.CURRENT_LOCK_MECHANISM_STATE_CTYPE, + onUpdate: function(value) { that.log("Update current state to " + value); }, + perms: ["pr","ev"], + format: "int", + initialValue: 0, + supportEvents: false, + supportBonjour: false, + manfDescription: "BlaBla", + designedMinValue: 0, + designedMaxValue: 3, + designedMinStep: 1, + designedMaxLength: 1 + },{ + cType: types.TARGET_LOCK_MECHANISM_STATE_CTYPE, + onUpdate: function(value) { that.setState(value); }, + perms: ["pr","pw","ev"], + format: "int", + initialValue: 0, + supportEvents: false, + supportBonjour: false, + manfDescription: "BlaBla", + designedMinValue: 0, + designedMaxValue: 1, + designedMinStep: 1, + designedMaxLength: 1 + }] + },{ + sType: types.LOCK_MANAGEMENT_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Lock Management", + supportEvents: false, + supportBonjour: false, + manfDescription: "Name of service", + designedMaxLength: 255 + },{ + cType: types.LOCK_MANAGEMENT_CONTROL_POINT_CTYPE, + onUpdate: function(value) { that.log("Update control point to " + value); }, + perms: ["pw"], + format: "data", + initialValue: 0, + supportEvents: false, + supportBonjour: false, + manfDescription: "BlaBla", + designedMaxLength: 255 + },{ + cType: types.VERSION_CTYPE, + onUpdate: function(value) { that.log("Update version to " + value); }, + perms: ["pr"], + format: "string", + initialValue: "1.0", + supportEvents: false, + supportBonjour: false, + manfDescription: "BlaBla", + designedMaxLength: 255 + }] + }] + }; + } +}; + +module.exports.accessory = LockitronAccessory; \ No newline at end of file diff --git a/config-sample.json b/config-sample.json index 835b8c3..1575cb3 100644 --- a/config-sample.json +++ b/config-sample.json @@ -14,6 +14,13 @@ "siri_name": "Speakers", "play_volume": 25 }, + { + "accessory": "Lockitron", + "description": "This shim supports Lockitron locks. It uses the Lockitron cloud API, so the Lockitron must be 'awake' for locking and unlocking to actually happen. You can wake up Lockitron after issuing an lock/unlock command by knocking on the door.", + "siri_name": "Front Door", + "lock_id": "your-lock-id", + "api_token" : "your-lockitron-api-access-token" + }, { "accessory": "XfinityHome", "description": "This shim supports the 'Xfinity Home' security system. Unfortunately I don't know how to generate the 'dsig' property, so you'll need to figure yours out by running the Xfinity Home app on your iOS device while connected to a proxy server like Charles. If you didn't understand any of that, sorry! I welcome any suggestions for how to figure out dsig automatically.",