Merge branch 'nfarina/master' into z-way-server-2

This commit is contained in:
S'pht'Kr
2015-08-30 14:27:07 +02:00
7 changed files with 159 additions and 198 deletions

View File

@@ -11,7 +11,7 @@ Since Siri supports devices added through HomeKit, this means that with Homebrid
* _Siri, turn off the Speakers._ ([Sonos](http://www.sonos.com))
* _Siri, turn on the Dehumidifier._ ([WeMo](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/))
* _Siri, turn on Away Mode._ ([Xfinity Home](http://www.comcast.com/home-security.html))
* _Siri, turn on the living room lights._ ([Wink](http://www.wink.com), [SmartThings](http://www.smartthings.com), [X10](http://github.com/edc1591/rest-mochad), [Philips Hue](http://meethue.com))
* _Siri, turn on the living room lights._ ([Wink](http://www.wink.com), [SmartThings](http://www.smartthings.com), [X10](http://github.com/edc1591/rest-mochad), [Philips Hue](http://meethue.com), [LimitlessLED/MiLight/Easybulb](http://www.limitlessled.com/))
* _Siri, set the movie scene._ ([Logitech Harmony](http://myharmony.com/))
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.

0
accessories/HomeMatic.js Executable file → Normal file
View File

View File

@@ -1,181 +1,113 @@
var types = require("HAP-NodeJS/accessories/types.js");
var Service = require("HAP-NodeJS").Service;
var Characteristic = require("HAP-NodeJS").Characteristic;
var Milight = require('node-milight-promise').MilightController;
var commands = require('node-milight-promise').commands;
module.exports = {
accessory: MiLight
}
function MiLight(log, config) {
this.log = log;
this.ip_address = config["ip_address"];
this.port = config["port"];
this.name = config["name"];
this.zone = config["zone"];
this.type = config["type"];
this.delay = config["delay"];
this.repeat = config["repeat"];
this.log = log;
// config info
this.ip_address = config["ip_address"];
this.port = config["port"];
this.name = config["name"];
this.zone = config["zone"];
this.type = config["type"];
this.delay = config["delay"];
this.repeat = config["repeat"];
}
var light = new Milight({
ip: this.ip_address,
port: this.port,
delayBetweenCommands: this.delay,
commandRepeat: this.repeat
ip: this.ip_address,
port: this.port,
delayBetweenCommands: this.delay,
commandRepeat: this.repeat
});
MiLight.prototype = {
setPowerState: function(powerOn) {
setPowerState: function(powerOn, callback) {
if (powerOn) {
light.sendCommands(commands[this.type].on(this.zone));
this.log("Setting power state to on");
}
else {
light.sendCommands(commands[this.type].off(this.zone));
this.log("Setting power state to off");
}
callback();
},
var binaryState = powerOn ? "on" : "off";
var that = this;
setBrightness: function(level, callback) {
this.log("Setting brightness to %s", level);
if (binaryState === "on") {
this.log("Setting power state of zone " + this.zone + " to " + powerOn);
light.sendCommands(commands[this.type].on(this.zone));
} else {
this.log("Setting power state of zone " + this.zone + " to " + powerOn);
light.sendCommands(commands[this.type].off(this.zone));
}
// If this is an rgbw lamp, set the absolute brightness specified
if (this.type == "rgbw") {
light.sendCommands(commands.rgbw.brightness(level));
} else {
// If this is an rgb or a white lamp, they only support brightness up and down.
// Set brightness up when value is >50 and down otherwise. Not sure how well this works real-world.
if (level >= 50) {
light.sendCommands(commands[this.type].brightUp());
} else {
light.sendCommands(commands[this.type].brightDown());
}
}
callback();
},
},
setHue: function(value, callback) {
this.log("Setting hue to %s", value);
setBrightnessLevel: function(value) {
if (this.type == "rgbw") {
if (value == 0) {
light.sendCommands(commands.rgbw.whiteMode(this.zone));
} else {
light.sendCommands(commands.rgbw.hue(commands.rgbw.hsvToMilightColor(Array(value, 0, 0))));
}
} else if (this.type == "rgb") {
light.sendCommands(commands.rgb.hue(commands.rgbw.hsvToMilightColor(Array(value, 0, 0))));
} else if (this.type == "white") {
// Again, white lamps don't support setting an absolue colour temp, so trying to do warmer/cooler step at a time based on colour
if (value >= 180) {
light.sendCommands(commands.white.warmer());
} else {
light.sendCommands(commands.white.cooler());
}
}
var that = this;
},
identify: function(callback) {
this.log("Identify requested!");
callback(); // success
},
getServices: function() {
var informationService = new Service.AccessoryInformation();
informationService
.setCharacteristic(Characteristic.Manufacturer, "MiLight")
.setCharacteristic(Characteristic.Model, this.type)
.setCharacteristic(Characteristic.SerialNumber, "MILIGHT12345");
var lightbulbService = new Service.Lightbulb();
lightbulbService
.getCharacteristic(Characteristic.On)
.on('set', this.setPowerState.bind(this));
lightbulbService
.addCharacteristic(new Characteristic.Brightness())
.on('set', this.setBrightness.bind(this));
this.log("Setting brightness level of zone " + this.zone + " to " + value);
light.sendCommands(commands[this.type].brightness(value));
},
setHue: function(value) {
var that = this;
this.log("Setting hue of zone " + this.zone + " to " + value);
if (value == "0") {
light.sendCommands(commands.rgbw.whiteMode(this.zone));
} else {
light.sendCommands(commands.rgbw.hue(commands.rgbw.hsvToMilightColor(Array(value, 0, 0))));
}
},
getServices: function() {
var that = this;
var services = [{
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: "MiLight",
supportEvents: false,
supportBonjour: false,
manfDescription: "Manufacturer",
designedMaxLength: 255
}, {
cType: types.MODEL_CTYPE,
onUpdate: null,
perms: ["pr"],
format: "string",
initialValue: this.type,
supportEvents: false,
supportBonjour: false,
manfDescription: "Model",
designedMaxLength: 255
}, {
cType: types.SERIAL_NUMBER_CTYPE,
onUpdate: null,
perms: ["pr"],
format: "string",
initialValue: "MILIGHT1234",
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: 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: "Turn on the light",
designedMaxLength: 1
}, {
cType: types.BRIGHTNESS_CTYPE,
onUpdate: function(value) {
that.setBrightnessLevel(value);
},
perms: ["pw", "pr", "ev"],
format: "bool",
initialValue: 100,
supportEvents: false,
supportBonjour: false,
manfDescription: "Adjust brightness of light",
designedMinValue: 0,
designedMaxValue: 100,
designedMinStep: 1,
unit: "%"
}]
}];
if (that.type == "rgbw" || that.type == "rgb") {
services[1].characteristics.push({
cType: types.HUE_CTYPE,
onUpdate: function(value) {
that.setHue(value);
},
perms: ["pw", "pr", "ev"],
format: "int",
initialValue: 0,
supportEvents: false,
supportBonjour: false,
manfDescription: "Adjust Hue of Light",
designedMinValue: 0,
designedMaxValue: 360,
designedMinStep: 1,
unit: "arcdegrees"
});
}
return services;
}
lightbulbService
.addCharacteristic(new Characteristic.Hue())
.on('set', this.setHue.bind(this));
return [informationService, lightbulbService];
}
};
module.exports.accessory = MiLight;

View File

@@ -41,7 +41,9 @@
"platform": "Domoticz",
"name": "Domoticz",
"server": "127.0.0.1",
"port": "8005"
"port": "8080",
"roomid": 0,
"loadscenes": 1
},
{
"platform": "PhilipsHue",
@@ -153,12 +155,12 @@
{
"accessory":"MiLight",
"name": "Lamp",
"ip_address": "255.255.255.255", // IP Address of the WiFi Bridge, or 255.255.255.255 to broadcast to all
"port": 8899, // Default port 8899 (50000 for v1 or v2 bridge)
"zone": 1, // Zone to address commands to (not used for rgb only bulbs)
"type": "rgbw", // Bulb type (rgbw, rgb, white)
"delay": 35, // Delay between commands sent to the WiFi bridge (default 35)
"repeat": 3 // Number of times each command is repeated for reliability (default 3)
"ip_address": "255.255.255.255",
"port": 8899,
"zone": 1,
"type": "rgbw",
"delay": 35,
"repeat": 3
},
{
"accessory": "Tesla",

View File

@@ -15,12 +15,12 @@
"carwingsjs": "0.0.x",
"color": "0.10.x",
"elkington": "kevinohara80/elkington",
"hap-nodejs": "git+https://github.com/KhaosT/HAP-NodeJS#46ba0597eb339983a14d98c53764a58a5516fcd2",
"hap-nodejs": "git+https://github.com/KhaosT/HAP-NodeJS#fff863d7a387636fc612cf27cb859e82d9ee3294",
"harmonyhubjs-client": "^1.1.4",
"harmonyhubjs-discover": "git+https://github.com/swissmanu/harmonyhubjs-discover.git",
"mdns": "^2.2.4",
"node-hue-api": "^1.0.5",
"node-milight-promise": "0.0.2",
"node-milight-promise": "0.0.x",
"node-persist": "0.0.x",
"q": "1.4.x",
"tough-cookie": "^2.0.0",

View File

@@ -8,6 +8,15 @@
// - Added support for Scenes
// - Sorting device names
//
// 26 August 2015 [EddyK69]
// - Added parameter in config.json: 'loadscenes' for enabling/disabling loading scenes
// - Fixed issue with dimmer-range; was 0-100, should be 0-16
//
// 27 August 2015 [EddyK69]
// - Fixed issue that 'on/off'-type lights showed as dimmers in HomeKit. Checking now on SwitchType instead of HaveDimmer
// - Fixed issue that 'on-off'-type lights would not react on Siri 'Switch on/off light'; On/Off types are now handled as Lights instead of Switches
// (Cannot determine if 'on/off'-type device is a Light or a Switch :( )
//
// Domoticz JSON API required
// https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's#Lights_and_switches
//
@@ -18,7 +27,8 @@
// "name": "Domoticz",
// "server": "127.0.0.1",
// "port": "8080",
// "roomid": 123 (0=no roomplan)
// "roomid": 123, (0=no roomplan)
// "loadscenes": 1 (0=disable scenes)
// }
// ],
//
@@ -47,6 +57,10 @@ function DomoticzPlatform(log, config){
if (typeof config["roomid"] != 'undefined') {
this.roomid = config["roomid"];
}
this.loadscenes = 1;
if (typeof config["loadscenes"] != 'undefined') {
this.loadscenes = config["loadscenes"];
}
}
function sortByKey(array, key) {
@@ -85,7 +99,8 @@ DomoticzPlatform.prototype = {
if (json['result'] != undefined) {
var sArray=sortByKey(json['result'],"Name");
sArray.map(function(s) {
accessory = new DomoticzAccessory(that.log, that, false, s.idx, s.Name, s.HaveDimmer, s.MaxDimLevel, (s.SubType=="RGB")||(s.SubType=="RGBW"));
var havedimmer = (s.SwitchType == 'Dimmer')
accessory = new DomoticzAccessory(that.log, that, false, s.idx, s.Name, havedimmer, s.MaxDimLevel, (s.SubType=="RGB")||(s.SubType=="RGBW"));
foundAccessories.push(accessory);
})
}
@@ -108,7 +123,8 @@ DomoticzPlatform.prototype = {
sArray.map(function(s) {
//only accept switches for now
if (typeof s.SwitchType != 'undefined') {
accessory = new DomoticzAccessory(that.log, that, false, s.idx, s.Name, s.HaveDimmer, s.MaxDimLevel, (s.SubType=="RGB")||(s.SubType=="RGBW"));
var havedimmer = (s.SwitchType == 'Dimmer')
accessory = new DomoticzAccessory(that.log, that, false, s.idx, s.Name, havedimmer, s.MaxDimLevel, (s.SubType=="RGB")||(s.SubType=="RGBW"));
foundAccessories.push(accessory);
}
})
@@ -120,24 +136,26 @@ DomoticzPlatform.prototype = {
});
}
//Get Scenes
asyncCalls++;
request.get({
url: this.urlForQuery("type=scenes"),
json: true
}, function(err, response, json) {
if (!err && response.statusCode == 200) {
if (json['result'] != undefined) {
var sArray=sortByKey(json['result'],"Name");
sArray.map(function(s) {
accessory = new DomoticzAccessory(that.log, that, true, s.idx, s.Name, false, 0, false);
foundAccessories.push(accessory);
})
if (this.loadscenes == 1) {
asyncCalls++;
request.get({
url: this.urlForQuery("type=scenes"),
json: true
}, function(err, response, json) {
if (!err && response.statusCode == 200) {
if (json['result'] != undefined) {
var sArray=sortByKey(json['result'],"Name");
sArray.map(function(s) {
accessory = new DomoticzAccessory(that.log, that, true, s.idx, s.Name, false, 0, false);
foundAccessories.push(accessory);
})
}
callbackLater();
} else {
that.log("There was a problem connecting to Domoticz.");
}
callbackLater();
} else {
that.log("There was a problem connecting to Domoticz.");
}
});
});
}
}
}
@@ -165,6 +183,9 @@ DomoticzAccessory.prototype = {
url = this.platform.urlForQuery("type=command&param=setcolbrightnessvalue&idx=" + this.idx + "&hue=" + value + "&brightness=100" + "&iswhite=false");
}
else if (c == "setLevel") {
//Range should be 0-16 instead of 0-100
//See http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Set_a_dimmable_light_to_a_certain_level
value = Math.round((value / 100) * 16)
url = this.platform.urlForQuery("type=command&param=switchlight&idx=" + this.idx + "&switchcmd=Set%20Level&level=" + value);
}
else if (value != undefined) {
@@ -318,11 +339,11 @@ DomoticzAccessory.prototype = {
},
sType: function() {
if (this.HaveDimmer == true) {
//if (this.HaveDimmer == true) {
return types.LIGHTBULB_STYPE
} else {
return types.SWITCH_STYPE
}
//} else {
// return types.SWITCH_STYPE
//}
},
getServices: function() {

View File

@@ -216,7 +216,13 @@ PhilipsHueAccessory.prototype = {
that.log(device.name + ", characteristic: " + characteristic + ", value: " + value + ".");
}
else {
that.log(err);
if (err.code == "ECONNRESET") {
setTimeout(function() {
that.executeChange(api, device, characteristic, value);
}, 300);
} else {
that.log(err);
}
}
});
},