From 4b6bb332ef0b44620a1c2bdf4c4d4f11a73ec4bf Mon Sep 17 00:00:00 2001 From: Jon Maddox Date: Mon, 18 May 2015 22:07:17 -0400 Subject: [PATCH 1/9] Wink platform library --- platforms/Wink.js | 204 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 platforms/Wink.js diff --git a/platforms/Wink.js b/platforms/Wink.js new file mode 100644 index 0000000..f7a36f1 --- /dev/null +++ b/platforms/Wink.js @@ -0,0 +1,204 @@ +var types = require("../lib/HAP-NodeJS/accessories/types.js"); +var wink = require('wink-js'); + +var model = { + light_bulbs: require('wink-js/lib/model/light') +}; + + +function WinkPlatform(log, config){ + + // auth info + this.client_id = config["client_id"]; + this.client_secret = config["client_secret"]; + this.username = config["username"]; + this.password = config["password"]; + + this.log = log; +} + +WinkPlatform.prototype = { + accessories: function(callback) { + this.log("Fetching Wink devices."); + + var that = this; + var foundAccessories = []; + + wink.init({ + "client_id": this.client_id, + "client_secret": this.client_secret, + "username": this.username, + "password": this.password + }, function(auth_return) { + if ( auth_return === undefined ) { + that.log("There was a problem authenticating with Wink."); + } else { + // success + wink.user().devices('light_bulbs', function(devices) { + for (var i=0; i Date: Mon, 18 May 2015 22:07:41 -0400 Subject: [PATCH 2/9] whitespace --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index fb881c4..60ddeff 100644 --- a/app.js +++ b/app.js @@ -140,4 +140,4 @@ function createUsername(str) { hash[10] + hash[11]; } -loadAccessories(); \ No newline at end of file +loadAccessories(); From bfd5d6d360379f343d7ede73ac2c609362136139 Mon Sep 17 00:00:00 2001 From: Jon Maddox Date: Mon, 18 May 2015 22:07:49 -0400 Subject: [PATCH 3/9] move this --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 60ddeff..ea12358 100644 --- a/app.js +++ b/app.js @@ -21,11 +21,11 @@ storage.initSync(); var config = JSON.parse(fs.readFileSync(configPath)); function loadAccessories() { - console.log("Loading " + config.accessories.length + " accessories..."); var accessories = []; // Instantiate all accessories in the config + console.log("Loading " + config.accessories.length + " accessories..."); for (var i=0; i Date: Mon, 18 May 2015 22:09:08 -0400 Subject: [PATCH 4/9] loop through platforms in config to fetch all supported devices to register them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds an additional loop to fetch devices by platform. This saves time and effort in that it returns all the devices a platform can ‘see’ on for your Home Automation, rather than making you define each one individually. --- app.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/app.js b/app.js index ea12358..533619c 100644 --- a/app.js +++ b/app.js @@ -24,6 +24,41 @@ function loadAccessories() { var accessories = []; + console.log("Loading " + config.platforms.length + " platforms..."); + for (var i=0; i Date: Mon, 18 May 2015 22:09:31 -0400 Subject: [PATCH 5/9] add platforms section of config with an example for Wink --- config-sample.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/config-sample.json b/config-sample.json index 0b9ca0f..0406aa8 100644 --- a/config-sample.json +++ b/config-sample.json @@ -1,6 +1,17 @@ { "description": "This is an example configuration file with all supported devices. You can use this as a template for creating your own configuration file containing devices you actually own.", + "platforms": [ + { + "platform": "Wink", + "name": "Wink", + "client_id": "YOUR_WINK_API_CLIENT_ID", + "client_secret": "YOUR_WINK_API_CLIENT_SECRET", + "username": "your@email.com", + "password": "WINK_PASSWORD" + } + ], + "accessories": [ { "accessory": "WeMo", From 3c5cfaa2b86164fa53e31ecb7460c6c905b0c2cb Mon Sep 17 00:00:00 2001 From: Jon Maddox Date: Mon, 18 May 2015 22:09:58 -0400 Subject: [PATCH 6/9] drop the Wink example since Wink devices will be powered by the platform, not by individual device configs --- config-sample.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/config-sample.json b/config-sample.json index 0406aa8..1afbd81 100644 --- a/config-sample.json +++ b/config-sample.json @@ -69,15 +69,6 @@ "device_id": "E1", "protocol": "pl", "can_dim": true - }, - { - "accessory": "Wink", - "client_id": "YOUR_WINK_API_CLIENT_ID", - "client_secret": "YOUR_WINK_API_CLIENT_SECRET", - "username": "your@email.com", - "password": "WINK_PASSWORD", - "name": "Family Room Lamp", - "description": "Lamp on the left side of the room" } ] } From c4026e997af9ac13c6937fb3026f964b4b204453 Mon Sep 17 00:00:00 2001 From: Jon Maddox Date: Mon, 18 May 2015 22:10:28 -0400 Subject: [PATCH 7/9] :fire: Wink accessory lib --- accessories/Wink.js | 187 -------------------------------------------- 1 file changed, 187 deletions(-) delete mode 100644 accessories/Wink.js diff --git a/accessories/Wink.js b/accessories/Wink.js deleted file mode 100644 index 0c60dda..0000000 --- a/accessories/Wink.js +++ /dev/null @@ -1,187 +0,0 @@ -var types = require("../lib/HAP-NodeJS/accessories/types.js"); -var wink = require('wink-js'); - -function WinkAccessory(log, config) { - this.log = log; - - // auth info - this.client_id = config["client_id"]; - this.client_secret = config["client_secret"]; - this.username = config["username"]; - this.password = config["password"]; - - // device info - this.name = config["name"]; - this.device = null; - - this.log("Searching for Wink device with exact name '" + this.name + "'..."); - this.search(); -} - -WinkAccessory.prototype = { - - search: function() { - var that = this; - - wink.init({ - "client_id": this.client_id, - "client_secret": this.client_secret, - "username": this.username, - "password": this.password - }, function(auth_return) { - if ( auth_return === undefined ) { - that.log("There was a problem authenticating with Wink."); - } else { - // success - wink.user().device(that.name, function(device) { - that.device = device - }); - } - }); - - }, - - setPowerState: function(powerOn) { - if (!this.device) { - this.log("No '"+this.name+"' device found (yet?)"); - return; - } - - var that = this; - - if (powerOn) { - this.log("Setting power state on the '"+this.name+"' to on"); - this.device.power.on(function(response) { - if (response === undefined) { - that.log("Error setting power state on the '"+that.name+"'") - } else { - that.log("Successfully set power state on the '"+that.name+"' to on"); - } - }); - }else{ - this.log("Setting power state on the '"+this.name+"' to off"); - this.device.power.off(function(response) { - if (response === undefined) { - that.log("Error setting power state on the '"+that.name+"'") - } else { - that.log("Successfully set power state on the '"+that.name+"' to off"); - } - }); - } - - }, - - setBrightness: function(level) { - if (!this.device) { - this.log("No '"+this.name+"' device found (yet?)"); - return; - } - - var that = this; - - this.log("Setting brightness on the '"+this.name+"' to on"); - this.device.brightness(level, function(response) { - if (response === undefined) { - that.log("Error setting brightness on the '"+that.name+"'") - } else { - that.log("Successfully set brightness on the '"+that.name+"' to " + level); - } - }); - }, - - getServices: function() { - var that = this; - return [{ - sType: types.ACCESSORY_INFORMATION_STYPE, - characteristics: [{ - 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: "Wink", - 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.LIGHTBULB_STYPE, - characteristics: [{ - cType: types.NAME_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: this.name, - supportEvents: true, - supportBonjour: false, - manfDescription: "Name of service", - designedMaxLength: 255 - },{ - cType: types.POWER_STATE_CTYPE, - onUpdate: function(value) { that.setPowerState(value); }, - perms: ["pw","pr","ev"], - format: "bool", - initialValue: 0, - supportEvents: true, - supportBonjour: false, - manfDescription: "Change the power state of the Bulb", - designedMaxLength: 1 - },{ - cType: types.BRIGHTNESS_CTYPE, - onUpdate: function(value) { that.setBrightness(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: "%" - }] - }]; - } -}; - -module.exports.accessory = WinkAccessory; From 9d11a624cc6c23a9d1405ef49065fd3cc9c8a8ff Mon Sep 17 00:00:00 2001 From: Jon Maddox Date: Mon, 18 May 2015 22:16:41 -0400 Subject: [PATCH 8/9] device -> platform --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 533619c..c39de45 100644 --- a/app.js +++ b/app.js @@ -34,7 +34,7 @@ function loadAccessories() { var platformModule = require('./platforms/' + platformName + ".js"); // like "./platforms/Wink.js" var platformConstructor = platformModule.platform; // like "WinkPlatform", a JavaScript constructor - // Create a custom logging function that prepends the device display name for debugging + // Create a custom logging function that prepends the platform display name for debugging var name = platformConfig["name"]; var log = function(name) { return function(s) { console.log("[" + name + "] " + s); }; }(name); From ffa49cf462aeba899a9bd6c54218cb17b6599fda Mon Sep 17 00:00:00 2001 From: Jon Maddox Date: Tue, 19 May 2015 15:04:32 -0400 Subject: [PATCH 9/9] update README to reference platforms --- README.md | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b48fc08..e972e3e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # HomeBridge -HomeBridge is a lightweight NodeJS server you can run on your home network that emulates the iOS HomeKit API. It includes a set of "shims" (found in the [accessories](accessories/) folder) that provide a basic bridge from HomeKit to various 3rd-party APIs provided by manufacturers of "smart home" devices. +HomeBridge is a lightweight NodeJS server you can run on your home network that emulates the iOS HomeKit API. It includes a set of "shims" (found in the [accessories](accessories/) and [platforms](platforms/) folders) that provide a basic bridge from HomeKit to various 3rd-party APIs provided by manufacturers of "smart home" devices. Since Siri supports devices added through HomeKit, this means that with HomeBridge you can ask Siri to control devices that don't have any support for HomeKit at all. For instance, using the included shims, you can say things like: @@ -15,6 +15,24 @@ Since Siri supports devices added through HomeKit, this means that with HomeBrid If you would like to support any other devices, please write a shim and create a pull request and I'd be happy to add it to this official list. +# Shim types +There are 2 types of shims supported in HomeBridge. + +* Accessory - Individual device +* Platform - A full bridge to another system + +## Accessories + +Accessories are individual devices you would like to bridge to HomeKit. You set them up by declaring them individually in your `config.json` file. Generally, you specify them by `name` or `id` and which system they use. + +## Platforms + +Platforms bridge entire systems to HomeKit. Platforms can be things like Wink or SmartThings or Vera. By adding a platform to your `config.json`, HomeBridge will automatically detect all of your devices for you. + + Wink is currently the only supported platform at the moment. + +All you have to do is add the right config options so HomeBridge can authenticate and communicate with your other system, and voila, your devices will be available to HomeKit via HomeBridge. + # Why? Technically, the device manufacturers should be the ones implementing the HomeKit API. And I'm sure they will - eventually. When they do, these shims will be obsolete, and I hope that happens soon. In the meantime, this server is a fun way to get a taste of the future, for those who just can't bear to wait until "real" HomeKit devices are on the market. @@ -58,15 +76,20 @@ Now you should be able to run the homebridge server: Starting HomeBridge server... Couldn't find a config.json file [snip] -The server won't do anything until you've created a `config.json` file containing your home devices (or _accessories_ in HomeKit parlance) you wish to make available to iOS. +The server won't do anything until you've created a `config.json` file containing your home devices (or _accessories_ in HomeKit parlance) or platforms you wish to make available to iOS. -One you've added your devices, you should be able to run the server again and see them initialize: +Once you've added your devices or platforms, you should be able to run the server again and see them initialize: $ npm run start Starting HomeBridge server... Loading 6 accessories... [Speakers] Initializing 'Sonos' accessory... [Coffee Maker] Initializing 'WeMo' accessory... + [Speakers] Initializing 'Sonos' accessory... + [Coffee Maker] Initializing 'WeMo' accessory... + [Wink] Initializing Wink platform... + [Wink] Fetching Wink devices. + [Wink] Initializing device with name Living Room Lamp... Your server is now ready to receive commands from iOS.