From c7bc50e9e2909a35e616c9fed50047364f2cfbdf Mon Sep 17 00:00:00 2001 From: Jesse Newland Date: Tue, 19 May 2015 21:27:34 -0700 Subject: [PATCH 1/6] sample config --- config-sample.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config-sample.json b/config-sample.json index 1afbd81..2e07d4f 100644 --- a/config-sample.json +++ b/config-sample.json @@ -9,7 +9,14 @@ "client_secret": "YOUR_WINK_API_CLIENT_SECRET", "username": "your@email.com", "password": "WINK_PASSWORD" + }, + { + "platform": "SmartThings", + "name": "SmartThings", + "app_id": "Homebridge SmartApp Id", + "access_token": "Homebridge SmartApp AccessToken", } + ], "accessories": [ From 4feffe9bc6b243075c142403ded9d0f7aaa73ea9 Mon Sep 17 00:00:00 2001 From: Jesse Newland Date: Tue, 19 May 2015 21:34:15 -0700 Subject: [PATCH 2/6] paired, but commands fail --- platforms/SmartThings.js | 241 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 platforms/SmartThings.js diff --git a/platforms/SmartThings.js b/platforms/SmartThings.js new file mode 100644 index 0000000..bd8fccf --- /dev/null +++ b/platforms/SmartThings.js @@ -0,0 +1,241 @@ +var types = require("../lib/HAP-NodeJS/accessories/types.js"); +var request = require("request"); + +function SmartThingsPlatform(log, config){ + this.log = log; + this.app_id = config["app_id"]; + this.access_token = config["access_token"]; +} + +SmartThingsPlatform.prototype = { + accessories: function(callback) { + this.log("Fetching SmartThings devices..."); + + var that = this; + var foundAccessories = []; + + request.get({ + url: "https://graph.api.smartthings.com/api/smartapps/installations/"+this.app_id+"/devices?access_token="+this.access_token, + json: true + }, function(err, response, json) { + if (!err && response.statusCode == 200) { + if (json['switches'] != undefined) { + json['switches'].map(function(s) { + accessory = new SmartThingsAccessory(that.log, s.name, s.commands); + foundAccessories.push(accessory); + }) + } + if (json['hues'] != undefined) { + json['hues'].map(function(s) { + accessory = new SmartThingsAccessory(that.log, s.name, s.commands); + foundAccessories.push(accessory); + }) + } + callback(foundAccessories); + } else { + that.log("There was a problem authenticating with SmartThings."); + } + }); + + } +} + +function SmartThingsAccessory(log, name, commands) { + // device info + this.name = name; + this.commands = commands; + this.log = log; +} + +SmartThingsAccessory.prototype = { + + command: function(c,value) { + this.log("Received command " + c); + var url; + if (value == undefined) { + url = this.commands[c]; + } else { + url = this.commands[c] + "&value="+value + } + + var that = this; + request.put({ + url: url + }, function(err, response) { + if (err) { + that.log("There was a problem sending command " + c + " to SmartThings"); + that.log(url); + } else { + that.log("Sent command " + c); + } + }) + }, + + informationCharacteristics: function() { + return [ + { + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: this.name, + supportEvents: false, + supportBonjour: false, + manfDescription: "Name of the accessory", + designedMaxLength: 255 + },{ + cType: types.MANUFACTURER_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "SmartThings", + 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 + } + ] + }, + + controlCharacteristics: function(that) { + cTypes = [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: this.name, + supportEvents: true, + supportBonjour: false, + manfDescription: "Name of service", + designedMaxLength: 255 + }] + + if (this.commands['on'] != undefined) { + cTypes.push({ + cType: types.POWER_STATE_CTYPE, + onUpdate: function(value) { + if (value == 0) { + that.command("off") + } else { + that.command("on") + } + }, + perms: ["pw","pr","ev"], + format: "bool", + initialValue: 0, + supportEvents: true, + supportBonjour: false, + manfDescription: "Change the power state", + designedMaxLength: 1 + }) + } + + if (this.commands['on'] != undefined) { + cTypes.push({ + cType: types.BRIGHTNESS_CTYPE, + onUpdate: function(value) { that.command("setLevel", value); }, + perms: ["pw","pr","ev"], + format: "int", + initialValue: 0, + supportEvents: true, + supportBonjour: false, + manfDescription: "Adjust Brightness of Light", + designedMinValue: 0, + designedMaxValue: 100, + designedMinStep: 1, + unit: "%" + }) + } + + if (this.commands['setHue'] != undefined) { + cTypes.push({ + cType: types.HUE_CTYPE, + onUpdate: function(value) { that.command("setHue", value); }, + perms: ["pw","pr","ev"], + format: "int", + initialValue: 0, + supportEvents: true, + supportBonjour: false, + manfDescription: "Adjust Hue of Light", + designedMinValue: 0, + designedMaxValue: 360, + designedMinStep: 1, + unit: "arcdegrees" + }) + } + + if (this.commands['setSaturation'] != undefined) { + cTypes.push({ + cType: types.SATURATION_CTYPE, + onUpdate: function(value) { that.command("setSaturation", value); }, + perms: ["pw","pr","ev"], + format: "int", + initialValue: 0, + supportEvents: true, + supportBonjour: false, + manfDescription: "Adjust Brightness of Light", + designedMinValue: 0, + designedMaxValue: 100, + designedMinStep: 1, + unit: "%" + }) + } + + return cTypes + }, + + sType: function() { + if (this.commands['setLevel'] != undefined) { + return types.LIGHTBULB_STYPE + } else { + return types.SWITCH_STYPE + } + }, + + getServices: function() { + var that = this; + var services = [{ + sType: types.ACCESSORY_INFORMATION_STYPE, + characteristics: this.informationCharacteristics(), + }, + { + sType: this.sType(), + characteristics: this.controlCharacteristics(that) + }]; + this.log("Loaded services for " + this.name) + return services; + } +}; + +module.exports.accessory = SmartThingsAccessory; +module.exports.platform = SmartThingsPlatform; From 46d99a46156c8e22ccb274ce43d8b7d388a6f26c Mon Sep 17 00:00:00 2001 From: Jesse Newland Date: Tue, 19 May 2015 21:40:53 -0700 Subject: [PATCH 3/6] log adjustments --- platforms/SmartThings.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/platforms/SmartThings.js b/platforms/SmartThings.js index bd8fccf..cfaa550 100644 --- a/platforms/SmartThings.js +++ b/platforms/SmartThings.js @@ -50,11 +50,9 @@ function SmartThingsAccessory(log, name, commands) { SmartThingsAccessory.prototype = { command: function(c,value) { - this.log("Received command " + c); - var url; - if (value == undefined) { - url = this.commands[c]; - } else { + this.log(this.name + " sending command " + c); + var url = this.commands[c]; + if (value != undefined) { url = this.commands[c] + "&value="+value } @@ -63,10 +61,10 @@ SmartThingsAccessory.prototype = { url: url }, function(err, response) { if (err) { - that.log("There was a problem sending command " + c + " to SmartThings"); + that.log("There was a problem sending command " + c + " to" + that.name); that.log(url); } else { - that.log("Sent command " + c); + that.log(that.name + " sent command " + c); } }) }, From bcde0d6a68ac63d464025ab4428fbdf983b0a85e Mon Sep 17 00:00:00 2001 From: Jesse Newland Date: Tue, 19 May 2015 22:16:43 -0700 Subject: [PATCH 4/6] whitespace --- config-sample.json | 1 - 1 file changed, 1 deletion(-) diff --git a/config-sample.json b/config-sample.json index 2e07d4f..ec0c5a9 100644 --- a/config-sample.json +++ b/config-sample.json @@ -16,7 +16,6 @@ "app_id": "Homebridge SmartApp Id", "access_token": "Homebridge SmartApp AccessToken", } - ], "accessories": [ From 89e128e01fea92cfa86e083c311af11335758730 Mon Sep 17 00:00:00 2001 From: Jesse Newland Date: Tue, 19 May 2015 22:17:55 -0700 Subject: [PATCH 5/6] document where the api is --- platforms/SmartThings.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platforms/SmartThings.js b/platforms/SmartThings.js index cfaa550..693b587 100644 --- a/platforms/SmartThings.js +++ b/platforms/SmartThings.js @@ -1,3 +1,6 @@ +// SmartThings JSON API SmartApp required +// https://github.com/jnewland/SmartThings/blob/master/JSON.groovy +// var types = require("../lib/HAP-NodeJS/accessories/types.js"); var request = require("request"); From 8369efb4a222417621337fa45978d7a8e52ae970 Mon Sep 17 00:00:00 2001 From: Jesse Newland Date: Tue, 19 May 2015 22:21:31 -0700 Subject: [PATCH 6/6] fix name --- config-sample.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config-sample.json b/config-sample.json index ec0c5a9..48af54e 100644 --- a/config-sample.json +++ b/config-sample.json @@ -13,8 +13,8 @@ { "platform": "SmartThings", "name": "SmartThings", - "app_id": "Homebridge SmartApp Id", - "access_token": "Homebridge SmartApp AccessToken", + "app_id": "JSON SmartApp Id", + "access_token": "JSON SmartApp AccessToken", } ],