So, this is very much a work in progress, and only vaguely approaching functional at the moment…but…
Using https://github.com/KhaosT/HAP-NodeJS I’ve got my phone capable of opening a virtualized garadget.
If anyone else wants to give it a try, the steps are (from memory)
git clone https://github.com/KhaosT/HAP-NodeJS.git
cd HAP-NodeJS
npm install
-
npm install node-libcurl
(If you are on a Mac:npm install node-libcurl --build-from-source
instead!) - swap out the
LightAccessory.js
file underaccessories
for the one in-line below - don’t forget to edit in your device’s ID and your API key!
node BridgedCore.js
At this point you need something on your iDevice to talk to homekit stuff, and the best option I’ve found is https://itunes.apple.com/us/app/home-smart-home-automation/id995994352?mt=8
It’s spendy, but is really well put together and will let you talk to any kind of device and do some nice organization and scenario setups.
At this point you MUST be on the same network as the computer running HAP-NodeJS.
- Open Home
- Click the Plus to add a “home”, you should see a bunch of options including Demo Light
- Select Demo Light
- On = open, Off = closed
Off also currently equals “Crashed” since my JS knowledge is almost non-existent. This is just copy/paste from the lib-nodejs examples folder with a couple minor modifications. Both on and off leave the session open, and that makes things really unhappy.
Worth mentioning: you cannot talk to HomeKit devices from outside your home network without an AppleTV. Apple loves to sell you more things so any HomeKit system consists of a HomeKit Bridge (HAP-NodeJS in our case), A device to be controlled, and if you want in from the outside world…a HomeKit Extender (AppleTV).
There is an example GarageDoor device in the HAP-NodeJS accessories folder, and I intend to get it running so you can do more than just open and close (also you can talk to Siri about the “garage door” and “open” instead of “turn on the light” being secret code for “open the garage”).
Lastly, here’s the LightAccessory.js file you’ll want to copy in:
var Accessory = require('../').Accessory;
var Service = require('../').Service;
var Characteristic = require('../').Characteristic;
var uuid = require('../').uuid;
// Curl Setup
var Curl = require( 'node-libcurl' ).Curl,
querystring = require( 'querystring' );
//https://api.particle.io/v1/devices/$device_id/setState -d access_token=$api_key -d arg="closed"
var endpoint = 'setState';
var device = 'YOUR_DEVICE_ID_GOES_HERE';
var api_key = 'YOUR_API_KEY_GOES_HERE';
var action = 'open';
var curl = new Curl(),
url = 'https://api.particle.io/v1/devices/' + device + '/' + endpoint,
data = 'access_token=' + api_key + '&arg=' + action ;
// here's a fake hardware device that we'll expose to HomeKit
var FAKE_LIGHT = {
powerOn: false,
brightness: 100, // percentage
setPowerOn: function(on) {
console.log("Turning the light %s!", on ? "on" : "off");
FAKE_LIGHT.powerOn = on;
if (on) {
var action = 'closed'
curl.setOpt( Curl.option.URL, url );
curl.setOpt( Curl.option.FOLLOWLOCATION, true );
curl.setOpt( Curl.option.POSTFIELDS, data );
curl.setOpt( Curl.option.HTTPHEADER, ['User-Agent: node-libcurl/1.0'] );
curl.setOpt( Curl.option.VERBOSE, true );
console.log( querystring.stringify( data ) );
curl.perform();
curl.on( 'end', function( statusCode, body ) {
console.log( body );
this.close();
});
curl.on( 'error', curl.close.bind( curl ) );
} else {
curl.setOpt( Curl.option.URL, url );
curl.setOpt( Curl.option.FOLLOWLOCATION, true );
curl.setOpt( Curl.option.POSTFIELDS, data );
curl.setOpt( Curl.option.HTTPHEADER, ['User-Agent: node-libcurl/1.0'] );
curl.setOpt( Curl.option.VERBOSE, true );
console.log( querystring.stringify( data ) );
curl.perform();
curl.on( 'end', function( statusCode, body ) {
console.log( body );
this.close();
});
curl.on( 'error', curl.close.bind( curl ) );
};
},
setBrightness: function(brightness) {
console.log("Setting light brightness to %s", brightness);
FAKE_LIGHT.brightness = brightness;
},
identify: function() {
console.log("Identify the light!");
}
}