mirror of
https://github.com/mtan93/homebridge.git
synced 2026-03-08 05:31:55 +00:00
Add LiftMaster accessory shim
Refactoring
This commit is contained in:
@@ -82,7 +82,7 @@ At this point, you should be able to tell Siri to control your devices. However,
|
||||
|
||||
Also, remember that HomeKit is not very robust yet, and it is common for it to fail intermittently ("Sorry, I wasn't able to control your devices" kind of thing) then start working again for no reason. Also I've noticed that it will get cranky and stop working altogether sometimes. The usual voodoo applies here: reboot your device, or run the BetterHomeKit app and poke around, etc.
|
||||
|
||||
One final thing to remember is that Siri will almost always prefer its default phrase handling over HomeKit devices. For instance, if you name your Sonos device "Radio" and try saying "Siri, turn on the Radio" then Siri will probably start playing an iTunes Radio station on your phone. Even if you name it "Sonos" and say "Siri, turn on the Sonos", Siri will probably just launch the Sonos app instead. This is why, for instance, the suggested `siri_name` for the Sonos shim in `config-samples.json` is "Speakers".
|
||||
One final thing to remember is that Siri will almost always prefer its default phrase handling over HomeKit devices. For instance, if you name your Sonos device "Radio" and try saying "Siri, turn on the Radio" then Siri will probably start playing an iTunes Radio station on your phone. Even if you name it "Sonos" and say "Siri, turn on the Sonos", Siri will probably just launch the Sonos app instead. This is why, for instance, the suggested `name` for the Sonos shim in `config-samples.json` is "Speakers".
|
||||
|
||||
# Final Notes
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ var carwings = require("carwingsjs");
|
||||
|
||||
function CarwingsAccessory(log, config) {
|
||||
this.log = log;
|
||||
this.siriName = config["siri_name"];
|
||||
this.name = config["name"];
|
||||
this.username = config["username"];
|
||||
this.password = config["password"];
|
||||
}
|
||||
@@ -41,87 +41,85 @@ CarwingsAccessory.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
accessoryData: function() {
|
||||
getServices: function() {
|
||||
var that = this;
|
||||
return {
|
||||
services: [{
|
||||
sType: types.ACCESSORY_INFORMATION_STYPE,
|
||||
characteristics: [{
|
||||
cType: types.NAME_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: this.siriName,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Name of the accessory",
|
||||
designedMaxLength: 255
|
||||
},{
|
||||
cType: types.MANUFACTURER_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "Nissan",
|
||||
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
|
||||
}]
|
||||
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
|
||||
},{
|
||||
sType: types.SWITCH_STYPE,
|
||||
characteristics: [{
|
||||
cType: types.NAME_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: this.siriName,
|
||||
supportEvents: false,
|
||||
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: false,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Change the power state of the car",
|
||||
designedMaxLength: 1
|
||||
}]
|
||||
cType: types.MANUFACTURER_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "Nissan",
|
||||
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: this.name,
|
||||
supportEvents: false,
|
||||
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: false,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Change the power state of the car",
|
||||
designedMaxLength: 1
|
||||
}]
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
262
accessories/LiftMaster.js
Normal file
262
accessories/LiftMaster.js
Normal file
@@ -0,0 +1,262 @@
|
||||
var types = require("../lib/HAP-NodeJS/accessories/types.js");
|
||||
var request = require("request");
|
||||
|
||||
// This seems to be the "id" of the official LiftMaster iOS app
|
||||
var APP_ID = "JVM/G9Nwih5BwKgNCjLxiFUQxQijAebyyg8QUHr7JOrP+tuPb8iHfRHKwTmDzHOu"
|
||||
|
||||
function LiftMasterAccessory(log, config) {
|
||||
this.log = log;
|
||||
this.name = config["name"];
|
||||
this.username = config["username"];
|
||||
this.password = config["password"];
|
||||
}
|
||||
|
||||
LiftMasterAccessory.prototype = {
|
||||
|
||||
setState: function(state) {
|
||||
this.targetState = state;
|
||||
this.login();
|
||||
},
|
||||
|
||||
login: function() {
|
||||
var that = this;
|
||||
|
||||
// reset our logged-in state hint until we're logged in
|
||||
this.deviceId = null;
|
||||
|
||||
// querystring params
|
||||
var query = {
|
||||
appId: APP_ID,
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
culture: "en"
|
||||
};
|
||||
|
||||
// login to liftmaster
|
||||
request.get({
|
||||
url: "https://myqexternal.myqdevice.com/api/user/validatewithculture",
|
||||
qs: query
|
||||
}, function(err, response, body) {
|
||||
|
||||
if (!err && response.statusCode == 200) {
|
||||
|
||||
// parse and interpret the response
|
||||
var json = JSON.parse(body);
|
||||
that.userId = json["UserId"];
|
||||
that.securityToken = json["SecurityToken"];
|
||||
that.log("Logged in with user ID " + that.userId);
|
||||
that.getDevice();
|
||||
}
|
||||
else {
|
||||
that.log("Error '"+err+"' logging in: " + body);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// find your garage door ID
|
||||
getDevice: function() {
|
||||
var that = this;
|
||||
|
||||
// querystring params
|
||||
var query = {
|
||||
appId: APP_ID,
|
||||
SecurityToken: this.securityToken,
|
||||
filterOn: "true"
|
||||
};
|
||||
|
||||
// some necessary duplicated info in the headers
|
||||
var headers = {
|
||||
MyQApplicationId: APP_ID,
|
||||
SecurityToken: this.securityToken
|
||||
};
|
||||
|
||||
// request details of all your devices
|
||||
request.get({
|
||||
url: "https://myqexternal.myqdevice.com/api/v4/userdevicedetails/get",
|
||||
qs: query,
|
||||
headers: headers
|
||||
}, function(err, response, body) {
|
||||
|
||||
if (!err && response.statusCode == 200) {
|
||||
|
||||
// parse and interpret the response
|
||||
var json = JSON.parse(body);
|
||||
var devices = json["Devices"];
|
||||
|
||||
// look through the array of devices for an opener
|
||||
for (var i=0; i<devices.length; i++) {
|
||||
var device = devices[i];
|
||||
if (device["MyQDeviceTypeName"] == "GarageDoorOpener") {
|
||||
that.deviceId = device.MyQDeviceId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (that.deviceId) {
|
||||
that.log("Found an opener with ID " + that.deviceId +". Ready to open.");
|
||||
that.setTargetState();
|
||||
}
|
||||
}
|
||||
else {
|
||||
that.log("Error '"+err+"' getting devices: " + body);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setTargetState: function() {
|
||||
|
||||
var that = this;
|
||||
var liftmasterState = (this.targetState + "") == "1" ? "0" : "1";
|
||||
|
||||
// querystring params
|
||||
var query = {
|
||||
appId: APP_ID,
|
||||
SecurityToken: this.securityToken,
|
||||
filterOn: "true"
|
||||
};
|
||||
|
||||
// some necessary duplicated info in the headers
|
||||
var headers = {
|
||||
MyQApplicationId: APP_ID,
|
||||
SecurityToken: this.securityToken
|
||||
};
|
||||
|
||||
// PUT request body
|
||||
var body = {
|
||||
AttributeName: "desireddoorstate",
|
||||
AttributeValue: liftmasterState,
|
||||
ApplicationId: APP_ID,
|
||||
SecurityToken: this.securityToken,
|
||||
MyQDeviceId: this.deviceId
|
||||
};
|
||||
|
||||
// send the state request to liftmaster
|
||||
request.put({
|
||||
url: "https://myqexternal.myqdevice.com/api/v4/DeviceAttribute/PutDeviceAttribute",
|
||||
qs: query,
|
||||
headers: headers,
|
||||
body: body,
|
||||
json: true
|
||||
}, function(err, response, json) {
|
||||
|
||||
if (!err && response.statusCode == 200) {
|
||||
|
||||
if (json["ReturnCode"] == "0")
|
||||
that.log("State was successfully set.");
|
||||
else
|
||||
that.log("Bad return code: " + json["ReturnCode"]);
|
||||
}
|
||||
else {
|
||||
that.log("Error '"+err+"' setting door state: " + JSON.stringify(json));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
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: "LiftMaster",
|
||||
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.GARAGE_DOOR_OPENER_STYPE,
|
||||
characteristics: [{
|
||||
cType: types.NAME_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "Garage Door Opener Control",
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Name of service",
|
||||
designedMaxLength: 255
|
||||
},{
|
||||
cType: types.CURRENT_DOOR_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: 4,
|
||||
designedMinStep: 1,
|
||||
designedMaxLength: 1
|
||||
},{
|
||||
cType: types.TARGET_DOORSTATE_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
|
||||
},{
|
||||
cType: types.OBSTRUCTION_DETECTED_CTYPE,
|
||||
onUpdate: function(value) { that.log("Obstruction detected: " + value); },
|
||||
perms: ["pr","ev"],
|
||||
format: "bool",
|
||||
initialValue: false,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "BlaBla"
|
||||
}]
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.accessory = LiftMasterAccessory;
|
||||
@@ -3,7 +3,7 @@ var request = require("request");
|
||||
|
||||
function LockitronAccessory(log, config) {
|
||||
this.log = log;
|
||||
this.siriName = config["siri_name"];
|
||||
this.name = config["name"];
|
||||
this.lockID = config["lock_id"];
|
||||
this.accessToken = config["api_token"];
|
||||
}
|
||||
@@ -34,136 +34,134 @@ LockitronAccessory.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
accessoryData: function() {
|
||||
getServices: function() {
|
||||
var that = this;
|
||||
return {
|
||||
services: [{
|
||||
sType: types.ACCESSORY_INFORMATION_STYPE,
|
||||
characteristics: [{
|
||||
cType: types.NAME_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: this.siriName,
|
||||
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
|
||||
}]
|
||||
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
|
||||
},{
|
||||
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
|
||||
}]
|
||||
cType: types.MANUFACTURER_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "Apigee",
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Manufacturer",
|
||||
designedMaxLength: 255
|
||||
},{
|
||||
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
|
||||
}]
|
||||
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
|
||||
}]
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ var sonos = require('sonos');
|
||||
|
||||
function SonosAccessory(log, config) {
|
||||
this.log = log;
|
||||
this.siriName = config["siri_name"];
|
||||
this.name = config["name"];
|
||||
this.playVolume = config["play_volume"];
|
||||
this.device = null;
|
||||
this.search();
|
||||
@@ -61,87 +61,85 @@ SonosAccessory.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
accessoryData: function() {
|
||||
getServices: function() {
|
||||
var that = this;
|
||||
return {
|
||||
services: [{
|
||||
sType: types.ACCESSORY_INFORMATION_STYPE,
|
||||
characteristics: [{
|
||||
cType: types.NAME_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: this.siriName,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Name of the accessory",
|
||||
designedMaxLength: 255
|
||||
},{
|
||||
cType: types.MANUFACTURER_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "Sonos",
|
||||
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
|
||||
}]
|
||||
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
|
||||
},{
|
||||
sType: types.SWITCH_STYPE,
|
||||
characteristics: [{
|
||||
cType: types.NAME_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "Speakers",
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Name of service",
|
||||
designedMaxLength: 255
|
||||
},{
|
||||
cType: types.POWER_STATE_CTYPE,
|
||||
onUpdate: function(value) { that.setPlaying(value); },
|
||||
perms: ["pw","pr","ev"],
|
||||
format: "bool",
|
||||
initialValue: false,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Change the playback state of the sonos",
|
||||
designedMaxLength: 1
|
||||
}]
|
||||
cType: types.MANUFACTURER_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "Sonos",
|
||||
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: "Speakers",
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Name of service",
|
||||
designedMaxLength: 255
|
||||
},{
|
||||
cType: types.POWER_STATE_CTYPE,
|
||||
onUpdate: function(value) { that.setPlaying(value); },
|
||||
perms: ["pw","pr","ev"],
|
||||
format: "bool",
|
||||
initialValue: false,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Change the playback state of the sonos",
|
||||
designedMaxLength: 1
|
||||
}]
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ var wemo = require('wemo');
|
||||
|
||||
function WeMoAccessory(log, config) {
|
||||
this.log = log;
|
||||
this.siriName = config["siri_name"];
|
||||
this.name = config["name"];
|
||||
this.wemoName = config["wemo_name"];
|
||||
this.device = null;
|
||||
this.log("Searching for WeMo device with exact name '" + this.wemoName + "'...");
|
||||
@@ -16,8 +16,13 @@ WeMoAccessory.prototype = {
|
||||
var that = this;
|
||||
|
||||
wemo.Search(this.wemoName, function(err, device) {
|
||||
that.log("Found '"+that.wemoName+"' device at " + device.ip);
|
||||
that.device = new wemo(device.ip, device.port);
|
||||
if (!err && device) {
|
||||
that.log("Found '"+that.wemoName+"' device at " + device.ip);
|
||||
that.device = new wemo(device.ip, device.port);
|
||||
}
|
||||
else {
|
||||
that.log("Error finding device '" + that.wemoName + "': " + err);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -43,87 +48,85 @@ WeMoAccessory.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
accessoryData: function() {
|
||||
getServices: function() {
|
||||
var that = this;
|
||||
return {
|
||||
services: [{
|
||||
sType: types.ACCESSORY_INFORMATION_STYPE,
|
||||
characteristics: [{
|
||||
cType: types.NAME_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: this.siriName,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Name of the accessory",
|
||||
designedMaxLength: 255
|
||||
},{
|
||||
cType: types.MANUFACTURER_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "WeMo",
|
||||
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
|
||||
}]
|
||||
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
|
||||
},{
|
||||
sType: types.SWITCH_STYPE,
|
||||
characteristics: [{
|
||||
cType: types.NAME_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: this.siriName,
|
||||
supportEvents: false,
|
||||
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: false,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Change the power state of the WeMo",
|
||||
designedMaxLength: 1
|
||||
}]
|
||||
cType: types.MANUFACTURER_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "WeMo",
|
||||
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: this.name,
|
||||
supportEvents: false,
|
||||
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: false,
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Change the power state of the WeMo",
|
||||
designedMaxLength: 1
|
||||
}]
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ var xmldoc = require("xmldoc");
|
||||
|
||||
function XfinityHomeAccessory(log, config) {
|
||||
this.log = log;
|
||||
this.siriName = config["siri_name"];
|
||||
this.name = config["name"];
|
||||
this.email = config["email"];
|
||||
this.password = config["password"];
|
||||
this.dsig = config["dsig"];
|
||||
@@ -144,133 +144,131 @@ XfinityHomeAccessory.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
accessoryData: function() {
|
||||
getServices: function() {
|
||||
var that = this;
|
||||
return {
|
||||
services: [{
|
||||
sType: types.ACCESSORY_INFORMATION_STYPE,
|
||||
characteristics: [{
|
||||
cType: types.NAME_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: this.siriName,
|
||||
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
|
||||
}]
|
||||
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
|
||||
},{
|
||||
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
|
||||
}]
|
||||
cType: types.MANUFACTURER_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "Comcast",
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Manufacturer",
|
||||
designedMaxLength: 255
|
||||
},{
|
||||
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
|
||||
}]
|
||||
cType: types.MODEL_CTYPE,
|
||||
onUpdate: null,
|
||||
perms: ["pr"],
|
||||
format: "string",
|
||||
initialValue: "Rev-1",
|
||||
supportEvents: false,
|
||||
supportBonjour: false,
|
||||
manfDescription: "Model",
|
||||
designedMaxLength: 255
|
||||
},{
|
||||
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
|
||||
}]
|
||||
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
|
||||
}]
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
64
app.js
64
app.js
@@ -35,21 +35,20 @@ function loadAccessories() {
|
||||
var accessoryModule = require('./accessories/' + accessoryName + ".js"); // like "./accessories/WeMo.js"
|
||||
var accessoryConstructor = accessoryModule.accessory; // like "WeMoAccessory", a JavaScript constructor
|
||||
|
||||
// Create a custom logging function that prepends the Siri name for debugging
|
||||
var siriName = accessoryConfig["siri_name"];
|
||||
var log = function(siriName) { return function(s) { console.log("[" + siriName + "] " + s); }; }(siriName);
|
||||
// Create a custom logging function that prepends the device display name for debugging
|
||||
var name = accessoryConfig["name"];
|
||||
var log = function(name) { return function(s) { console.log("[" + name + "] " + s); }; }(name);
|
||||
|
||||
log("Initializing " + accessoryName + " accessory...");
|
||||
var accessory = new accessoryConstructor(log, accessoryConfig);
|
||||
accessories.push(accessory);
|
||||
|
||||
// Extract the raw "accessoryData" for this accessory which is a big object-blob describing the various
|
||||
// Extract the raw "services" for this accessory which is a big array of objects describing the various
|
||||
// hooks in and out of HomeKit for the HAP-NodeJS server.
|
||||
var accessoryData = accessory.accessoryData();
|
||||
accessoryData["displayName"] = siriName;
|
||||
var services = accessory.getServices();
|
||||
|
||||
// Create the HAP server for this accessory
|
||||
createHAPServer(accessoryData);
|
||||
createHAPServer(name, services);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,52 +69,47 @@ var accessoryServers = [];
|
||||
var accessoryControllers = [];
|
||||
var usernames = {};
|
||||
|
||||
function createHAPServer(data) {
|
||||
function createHAPServer(name, services) {
|
||||
var accessoryController = new accessoryController_Factor.AccessoryController();
|
||||
|
||||
//loop through services
|
||||
for (var j = 0; j < data.services.length; j++) {
|
||||
var service = new service_Factor.Service(data.services[j].sType);
|
||||
for (var j = 0; j < services.length; j++) {
|
||||
var service = new service_Factor.Service(services[j].sType);
|
||||
|
||||
//loop through characteristics
|
||||
for (var k = 0; k < data.services[j].characteristics.length; k++) {
|
||||
for (var k = 0; k < services[j].characteristics.length; k++) {
|
||||
var options = {
|
||||
type: data.services[j].characteristics[k].cType,
|
||||
perms: data.services[j].characteristics[k].perms,
|
||||
format: data.services[j].characteristics[k].format,
|
||||
initialValue: data.services[j].characteristics[k].initialValue,
|
||||
supportEvents: data.services[j].characteristics[k].supportEvents,
|
||||
supportBonjour: data.services[j].characteristics[k].supportBonjour,
|
||||
manfDescription: data.services[j].characteristics[k].manfDescription,
|
||||
designedMaxLength: data.services[j].characteristics[k].designedMaxLength,
|
||||
designedMinValue: data.services[j].characteristics[k].designedMinValue,
|
||||
designedMaxValue: data.services[j].characteristics[k].designedMaxValue,
|
||||
designedMinStep: data.services[j].characteristics[k].designedMinStep,
|
||||
unit: data.services[j].characteristics[k].unit
|
||||
type: services[j].characteristics[k].cType,
|
||||
perms: services[j].characteristics[k].perms,
|
||||
format: services[j].characteristics[k].format,
|
||||
initialValue: services[j].characteristics[k].initialValue,
|
||||
supportEvents: services[j].characteristics[k].supportEvents,
|
||||
supportBonjour: services[j].characteristics[k].supportBonjour,
|
||||
manfDescription: services[j].characteristics[k].manfDescription,
|
||||
designedMaxLength: services[j].characteristics[k].designedMaxLength,
|
||||
designedMinValue: services[j].characteristics[k].designedMinValue,
|
||||
designedMaxValue: services[j].characteristics[k].designedMaxValue,
|
||||
designedMinStep: services[j].characteristics[k].designedMinStep,
|
||||
unit: services[j].characteristics[k].unit
|
||||
};
|
||||
|
||||
var characteristic = new characteristic_Factor.Characteristic(options, data.services[j].characteristics[k].onUpdate);
|
||||
var characteristic = new characteristic_Factor.Characteristic(options, services[j].characteristics[k].onUpdate);
|
||||
|
||||
service.addCharacteristic(characteristic);
|
||||
}
|
||||
accessoryController.addService(service);
|
||||
}
|
||||
|
||||
// grab the intended name for Siri
|
||||
var displayName = data["displayName"];
|
||||
|
||||
console.log(displayName);
|
||||
|
||||
// create a unique "username" for this accessory based on the default Siri name
|
||||
var username = createUsername(displayName);
|
||||
// create a unique "username" for this accessory based on the default display name
|
||||
var username = createUsername(name);
|
||||
|
||||
if (usernames[username]) {
|
||||
console.log("Cannot create another accessory with the same name '" + displayName + "'. The 'siri_name' property must be unique for each accessory.");
|
||||
console.log("Cannot create another accessory with the same name '" + name + "'. The 'name' property must be unique for each accessory.");
|
||||
return;
|
||||
}
|
||||
|
||||
// remember that we used this name already
|
||||
usernames[username] = displayName;
|
||||
usernames[username] = name;
|
||||
|
||||
// increment ports for each accessory
|
||||
nextPort = nextPort + (nextServer*2);
|
||||
@@ -123,7 +117,7 @@ function createHAPServer(data) {
|
||||
// hardcode the PIN to something random (same PIN as HAP-NodeJS sample accessories)
|
||||
var pincode = "031-45-154";
|
||||
|
||||
var accessory = new accessory_Factor.Accessory(displayName, username, storage, parseInt(nextPort), pincode, accessoryController);
|
||||
var accessory = new accessory_Factor.Accessory(name, username, storage, parseInt(nextPort), pincode, accessoryController);
|
||||
accessoryServers[nextServer] = accessory;
|
||||
accessoryControllers[nextServer] = accessoryController;
|
||||
accessory.publishAccessory();
|
||||
@@ -134,7 +128,7 @@ function createHAPServer(data) {
|
||||
// Creates a unique "username" for HomeKit from a hash of the given string
|
||||
function createUsername(str) {
|
||||
|
||||
// Hash siri_name into something like "098F6BCD4621D373CADE4E832627B4F6"
|
||||
// Hash str into something like "098F6BCD4621D373CADE4E832627B4F6"
|
||||
var hash = crypto.createHash('md5').update(str).digest("hex").toUpperCase();
|
||||
|
||||
// Turn it into a MAC-address-looking "username" for HomeKit
|
||||
|
||||
@@ -4,34 +4,41 @@
|
||||
"accessories": [
|
||||
{
|
||||
"accessory": "WeMo",
|
||||
"description": "This shim supports Belkin WeMo devices on the same network as this server. You can create duplicate entries for this device and change the 'siri_name' attribute to reflect what device is plugged into the WeMo, for instance 'Air Conditioner' or 'Coffee Maker'. This name will be used by Siri. Make sure to update the 'wemo_name' attribute with the EXACT name of the device in the WeMo app itself. This can be the same value as 'siri_name' but it doesn't have to be.",
|
||||
"siri_name": "Coffee Maker",
|
||||
"name": "Coffee Maker",
|
||||
"description": "This shim supports Belkin WeMo devices on the same network as this server. You can create duplicate entries for this device and change the 'name' attribute to reflect what device is plugged into the WeMo, for instance 'Air Conditioner' or 'Coffee Maker'. This name will be used by Siri. Make sure to update the 'wemo_name' attribute with the EXACT name of the device in the WeMo app itself. This can be the same value as 'name' but it doesn't have to be.",
|
||||
"wemo_name": "CoffeeMaker"
|
||||
},
|
||||
{
|
||||
"accessory": "LiftMaster",
|
||||
"name": "Garage Door",
|
||||
"description": "This shim supports LiftMaster garage door openers that are already internet-connected to the 'MyQ' service.",
|
||||
"username": "your-liftmaster-username",
|
||||
"password" : "your-liftmaster-password"
|
||||
},
|
||||
{
|
||||
"accessory": "Sonos",
|
||||
"name": "Speakers",
|
||||
"description": "This shim supports Sonos devices on the same network as this server. It acts as a simple switch that calls play() or pause() on the Sonos, so it's only useful for pausing and resuming tracks or radio stations that are already in the queue. When 'play_volume' is nonzero, the volume will be reset to that value when it turns the Sonos on.",
|
||||
"siri_name": "Speakers",
|
||||
"play_volume": 25
|
||||
},
|
||||
{
|
||||
"accessory": "Lockitron",
|
||||
"name": "Front Door",
|
||||
"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": "Carwings",
|
||||
"name": "Leaf",
|
||||
"description": "This shim supports controlling climate control on Nissan cars with Carwings. Note that Carwings is super slow and it may take up to 5 minutes for your command to be processed by the Carwings system.",
|
||||
"siri_name": "Leaf",
|
||||
"username": "your-carwings-username",
|
||||
"password" : "your-carwings-password"
|
||||
},
|
||||
{
|
||||
"accessory": "XfinityHome",
|
||||
"name": "Xfinity Home",
|
||||
"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.",
|
||||
"siri_name": "Xfinity Home",
|
||||
"email": "your-comcast-email@example.com",
|
||||
"password": "your-comcast-password",
|
||||
"dsig": "your-digital-signature",
|
||||
|
||||
Reference in New Issue
Block a user