From 2c888ebeef83be6156df2a016dc5b565416aa3e5 Mon Sep 17 00:00:00 2001 From: Nick Farina Date: Sun, 30 Nov 2014 20:16:33 -0800 Subject: [PATCH] Add XfinityHome accessory shim --- accessories/XfinityHome.js | 286 +++++++++++++++++++++++++++++++++++++ app.js | 2 - config-sample.json | 9 ++ 3 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 accessories/XfinityHome.js diff --git a/accessories/XfinityHome.js b/accessories/XfinityHome.js new file mode 100644 index 0000000..ae73ca8 --- /dev/null +++ b/accessories/XfinityHome.js @@ -0,0 +1,286 @@ +var types = require("../lib/HAP-NodeJS/accessories/types.js"); +var request = require("request"); +var xmldoc = require("xmldoc"); + +function XfinityHomeAccessory(log, config) { + this.log = log; + this.email = config["email"]; + this.password = config["password"]; + this.dsig = config["dsig"]; + this.pinCode = config["pin"]; +} + +XfinityHomeAccessory.prototype = { + + armWithType: function(armed, type) { + this.log("Arming with type " + type + " = " + armed + "..."); + this.targetArmed = armed; + this.targetArmType = type; + this.getLoginToken(); + }, + + getLoginToken: function() { + this.log("Retrieving login token..."); + + var that = this; + + request.post({ + url: "https://login.comcast.net/api/login", + form: { + appkey:"iControl", + dsig: this.dsig, + u: this.email, + p: this.password + } + }, function(err, response, body) { + + if (!err && response.statusCode == 200) { + + var doc = new xmldoc.XmlDocument(body); + that.loginToken = doc.valueWithPath("LoginToken"); + that.refreshLoginCookie(); + } + else { + that.log("Error '"+err+"' getting login token: " + body); + } + }); + }, + + refreshLoginCookie: function() { + this.log("Refreshing login cookie..."); + + var that = this; + + request.post({ + url: "https://www.xfinityhomesecurity.com/rest/icontrol/login", + form: { + token: this.loginToken + } + }, function(err, response, body) { + + if (!err && response.statusCode == 200) { + + // extract our "site" from the login response + var json = JSON.parse(body); + that.siteHref = json["login"]["site"]["href"]; + + // manual cookie handling + that.loginCookie = response.headers["set-cookie"]; + + that.getInstances(); + } + else { + that.log("Error '"+err+"' refreshing login cookie: " + body); + } + }); + }, + + getInstances: function() { + this.log("Getting instances for site " + this.siteHref + "..."); + + this.panelHref = null; + var that = this; + + request.get({ + url: "https://www.xfinityhomesecurity.com/"+that.siteHref+"/network/instances", + headers: { Cookie: this.loginCookie }, + json: true + }, function(err, response, json) { + + if (!err && response.statusCode == 200) { + + // extract our "instance" from the response. look for the first "panel" + var instances = json["instances"]["instance"]; + for (var i=0; i= 200 && response.statusCode < 300) { + that.log("Arm response: " + response); + } + else { + that.log("Error '"+err+"' performing arm request: " + body); + } + }); + }, + + accessoryData: function() { + var that = this; + return { + displayName: "Xfinity Home", + services: [{ + sType: types.ACCESSORY_INFORMATION_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Xfinity Home", + supportEvents: false, + supportBonjour: false, + manfDescription: "Name of the accessory", + designedMaxLength: 255 + },{ + cType: types.MANUFACTURER_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Comcast", + supportEvents: false, + supportBonjour: false, + manfDescription: "Manufacturer", + designedMaxLength: 255 + },{ + cType: types.MODEL_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Rev-1", + 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.SWITCH_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Away Mode", + supportEvents: false, + supportBonjour: false, + manfDescription: "Away Mode service", + designedMaxLength: 255 + },{ + cType: types.POWER_STATE_CTYPE, + onUpdate: function(value) { that.armWithType(value, "away"); }, + perms: ["pw","pr","ev"], + format: "bool", + initialValue: false, + supportEvents: false, + supportBonjour: false, + manfDescription: "Turn on the Away alarm", + designedMaxLength: 1 + }] + },{ + sType: types.SWITCH_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Night Mode", + supportEvents: false, + supportBonjour: false, + manfDescription: "Night Mode service", + designedMaxLength: 255 + },{ + cType: types.POWER_STATE_CTYPE, + onUpdate: function(value) { that.armWithType(value, "night"); }, + perms: ["pw","pr","ev"], + format: "bool", + initialValue: false, + supportEvents: false, + supportBonjour: false, + manfDescription: "Turn on the Night alarm", + designedMaxLength: 1 + }] + },{ + sType: types.SWITCH_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Stay Mode", + supportEvents: false, + supportBonjour: false, + manfDescription: "Stay Mode service", + designedMaxLength: 255 + },{ + cType: types.POWER_STATE_CTYPE, + onUpdate: function(value) { that.armWithType(value, "stay"); }, + perms: ["pw","pr","ev"], + format: "bool", + initialValue: false, + supportEvents: false, + supportBonjour: false, + manfDescription: "Turn on the Stay alarm", + designedMaxLength: 1 + }] + }] + } + } +}; + +// Enable cookie handling and append our expected headers +request = request.defaults({ + headers: { + "X-appkey": "comcastTokenKey", + "X-ClientInfo": "5.2.51", + "X-format": "json" + } +}); + +module.exports.accessory = XfinityHomeAccessory; diff --git a/app.js b/app.js index 51e58d3..73c6a55 100644 --- a/app.js +++ b/app.js @@ -28,7 +28,6 @@ function loadAccessories() { for (var i=0; i