Merge branch 'nfarina/master'

This commit is contained in:
S'pht'Kr
2015-10-07 05:38:46 +02:00
8 changed files with 455 additions and 325 deletions

View File

@@ -11,6 +11,17 @@ function LockitronAccessory(log, config) {
this.name = config["name"];
this.accessToken = config["api_token"];
this.lockID = config["lock_id"];
this.service = new Service.LockMechanism(this.name);
this.service
.getCharacteristic(Characteristic.LockCurrentState)
.on('get', this.getState.bind(this));
this.service
.getCharacteristic(Characteristic.LockTargetState)
.on('get', this.getState.bind(this))
.on('set', this.setState.bind(this));
}
LockitronAccessory.prototype.getState = function(callback) {
@@ -36,7 +47,7 @@ LockitronAccessory.prototype.getState = function(callback) {
}
LockitronAccessory.prototype.setState = function(state, callback) {
var lockitronState = (state == 1) ? "lock" : "unlock";
var lockitronState = (state == Characteristic.LockTargetState.SECURED) ? "lock" : "unlock";
this.log("Set state to %s", lockitronState);
@@ -47,6 +58,14 @@ LockitronAccessory.prototype.setState = function(state, callback) {
if (!err && response.statusCode == 200) {
this.log("State change complete.");
// we succeeded, so update the "current" state as well
var currentState = (state == Characteristic.LockTargetState.SECURED) ?
Characteristic.LockCurrentState.SECURED : Characteristic.LockCurrentState.UNSECURED;
this.service
.setCharacteristic(Characteristic.LockCurrentState, currentState);
callback(null); // success
}
else {
@@ -57,17 +76,5 @@ LockitronAccessory.prototype.setState = function(state, callback) {
},
LockitronAccessory.prototype.getServices = function() {
var service = new Service.LockMechanism(this.name);
service
.getCharacteristic(Characteristic.LockCurrentState)
.on('get', this.getState.bind(this));
service
.getCharacteristic(Characteristic.LockTargetState)
.on('get', this.getState.bind(this))
.on('set', this.setState.bind(this));
return [service];
return [this.service];
}

View File

@@ -144,6 +144,16 @@ WeMoAccessory.prototype.getServices = function() {
return [garageDoorService];
}
else if (this.service == "Light") {
var lightbulbService = new Service.Lightbulb(this.name);
lightbulbService
.getCharacteristic(Characteristic.On)
.on('get', this.getPowerOn.bind(this))
.on('set', this.setPowerOn.bind(this));
return [lightbulbService];
}
else if (this.service == "MotionSensor") {
var motionSensorService = new Service.MotionSensor(this.name);

View File

@@ -14,6 +14,9 @@ New 2015-09-18:
New 2015-09-19:
- GarageDoorOpener Service
- MotionSensor Service
New 2015-10-02:
- Check for valid group addresses
- new "R" flag allowed for Boolean addresses: 1/2/3R is the boolean not(1/2/3), i.e. 0 and 1 switched on read and write
*
*/
var Service = require("HAP-NodeJS").Service;
@@ -24,6 +27,8 @@ var knxd_startMonitor = require('../platforms/KNX.js').startMonitor;
var milliTimeout = 300; // used to block responses while swiping
var colorOn = "\x1b[30;47m";
var colorOff = "\x1b[0m";
function KNXDevice(log, config) {
this.log = log;
@@ -115,6 +120,7 @@ KNXDevice.prototype = {
if (!groupAddress) {
return null;
}
this.log("[knxdevice:knxread] preparing knx request for "+groupAddress);
var knxdConnection = new knxd.Connection();
// this.log("DEBUG in knxread: created empty connection, trying to connect socket to "+this.knxd_ip+":"+this.knxd_port);
knxdConnection.socketRemote({ host: this.knxd_ip, port: this.knxd_port }, function() {
@@ -130,7 +136,7 @@ KNXDevice.prototype = {
if (err) {
this.log("[ERROR] knxread:sendAPDU: " + err);
} else {
this.log("knx request sent for "+groupAddress);
this.log("[knxdevice:knxread] knx request sent for "+groupAddress);
}
}.bind(this));
}
@@ -143,12 +149,12 @@ KNXDevice.prototype = {
// handle multiple addresses
for (var i = 0; i < groupAddresses.length; i++) {
if (groupAddresses[i]) { // do not bind empty addresses
this.knxread (groupAddresses[i]);
this.knxread (groupAddresses[i].match(/(\d*\/\d*\/\d*)/)[0]); // clean address
}
}
} else {
// it's only one
this.knxread (groupAddresses);
this.knxread (groupAddresses.match(/(\d*\/\d*\/\d*)/)[0]); // regex for cleaning address
}
},
@@ -158,70 +164,80 @@ KNXDevice.prototype = {
// boolean: get 0 or 1 from the bus, write boolean
knxregister_bool: function(addresses, characteristic) {
this.log("knx registering BOOLEAN " + addresses);
knxd_registerGA(addresses, function(val, src, dest, type){
this.log("Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type + " for " + characteristic.displayName);
knxd_registerGA(addresses, function(val, src, dest, type, reverse){
this.log("[" +this.name + "]: Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type + " for " + characteristic.displayName);
// iterate(characteristic);
characteristic.setValue(val ? 1 : 0, undefined, 'fromKNXBus');
}.bind(this));
},
knxregister_boolReverse: function(addresses, characteristic) {
this.log("knx registering BOOLEAN " + addresses);
knxd_registerGA(addresses, function(val, src, dest, type){
this.log("Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type + " for " + characteristic.displayName);
// iterate(characteristic);
characteristic.setValue(val ? 0 : 1, undefined, 'fromKNXBus');
characteristic.setValue(val ? (reverse ? 0:1) : (reverse ? 1:0), undefined, 'fromKNXBus');
}.bind(this));
},
// knxregister_boolReverse: function(addresses, characteristic) {
// this.log("knx registering BOOLEAN REVERSE " + addresses);
// knxd_registerGA(addresses, function(val, src, dest, type, reverse){
// this.log("[" +this.name + "]: Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type + " for " + characteristic.displayName);
//// iterate(characteristic);
// characteristic.setValue(val ? 0 : 1, undefined, 'fromKNXBus');
// }.bind(this));
// },
// percentage: get 0..255 from the bus, write 0..100 to characteristic
knxregister_percent: function(addresses, characteristic) {
this.log("knx registering PERCENT " + addresses);
knxd_registerGA(addresses, function(val, src, dest, type){
this.log("Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
knxd_registerGA(addresses, function(val, src, dest, type, reverse){
this.log("[" +this.name + "]: Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
if (type !== "DPT5") {
this.log("[ERROR] Received value cannot be a percentage value");
} else {
if (!characteristic.timeout) {
if (characteristic.timeout < Date.now()) {
characteristic.setValue(Math.round(val/255*100), undefined, 'fromKNXBus');
} else {
this.log("Blackout time");
}
} else {
characteristic.setValue(Math.round(val/255*100), undefined, 'fromKNXBus');
} // todo get the boolean logic right into one OR expresssion
characteristic.setValue(Math.round(( reverse ? (255-val):val)/255*100), undefined, 'fromKNXBus');
}
}.bind(this));
},
// float
knxregister_float: function(addresses, characteristic) {
this.log("knx registering FLOAT " + addresses);
knxd_registerGA(addresses, function(val, src, dest, type){
this.log("Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
var hk_value = Math.round(val*10)/10;
if (hk_value>=characteristic.minimumValue && hk_value<=characteristic.maximumValue) {
// update for props refactor https://github.com/KhaosT/HAP-NodeJS/commit/1d84d128d1513beedcafc24d2c07d98185563243#diff-cb84de3a1478a38b2cf8388d709f1c1cR50
var validValue = true;
var hk_value = 0.0;
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]:knx registering FLOAT " + addresses);
knxd_registerGA(addresses, function(val, src, dest, type, reverse){
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]: Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
// make hk_value compliant to properties
if (characteristic.props.minStep) {
// quantize
hk_value = Math.round(val/characteristic.props.minStep)/(1/characteristic.props.minStep);
} else {
hk_value = val;
}
// range check
validValue = true; // assume validity at beginning
if (characteristic.props.minValue) {
validValue = validValue && (hk_value>=characteristic.props.minValue);
}
if (characteristic.props.maxValue) {
validValue = validValue && (hk_value<=characteristic.props.maxValue);
}
if (validValue) {
characteristic.setValue(hk_value, undefined, 'fromKNXBus'); // 1 decimal for HomeKit
} else {
this.log("Value %s out of bounds %s...%s ",hk_value, characteristic.minimumValue, characteristic.maximumValue);
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]: Value %s out of bounds %s...%s ",hk_value, characteristic.props.minValue, characteristic.props.maxValue);
}
}.bind(this));
},
//integer
knxregister_int: function(addresses, characteristic) {
this.log("knx registering FLOAT " + addresses);
knxd_registerGA(addresses, function(val, src, dest, type){
this.log("Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
if (val>=(characteristic.minimumValue || 0) && val<=(characteristic.maximumValue || 255)) {
characteristic.setValue(val, undefined, 'fromKNXBus');
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]:knx registering INT " + addresses);
knxd_registerGA(addresses, function(val, src, dest, type, reverse){
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]: Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
if (val>=(characteristic.props.minValue || 0) && val<=(characteristic.props.maxValue || 255)) {
characteristic.setValue(reverse ? (255-val):val, undefined, 'fromKNXBus');
} else {
this.log("Value %s out of bounds %s...%s ",hk_value, (characteristic.minimumValue || 0), (characteristic.maximumValue || 255));
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]: Value %s out of bounds %s...%s ",hk_value, (characteristic.props.minValue || 0), (characteristic.props.maxValue || 255));
}
}.bind(this));
},
knxregister_HVAC: function(addresses, characteristic) {
this.log("knx registering HVAC " + addresses);
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]:knx registering HVAC " + addresses);
knxd_registerGA(addresses, function(val, src, dest, type){
this.log("Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]:Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
var HAPvalue = 0;
switch (val){
case 0:
@@ -261,9 +277,9 @@ KNXDevice.prototype = {
*/
// undefined, has to match!
knxregister: function(addresses, characteristic) {
this.log("knx registering " + addresses);
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]:knx registering " + addresses);
knxd_registerGA(addresses, function(val, src, dest, type){
this.log("Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
this.log("["+ this.name +"]:[" + characteristic.displayName+ "]:Received value from bus:"+val+ " for " +dest+ " from "+src+" of type "+type+ " for " + characteristic.displayName);
characteristic.setValue(val, undefined, 'fromKNXBus');
}.bind(this));
},
@@ -276,71 +292,74 @@ KNXDevice.prototype = {
* }.bind(this));
*
*/
setBooleanState: function(value, callback, context, gaddress) {
setBooleanState: function(value, callback, context, gaddress, reverseflag) {
if (context === 'fromKNXBus') {
this.log(gaddress + " event ping pong, exit!");
// this.log(gaddress + " event ping pong, exit!");
if (callback) {
callback();
}
} else {
var numericValue = 0;
var numericValue = reverseflag ? 1:0;
if (value) {
numericValue = 1; // need 0 or 1, not true or something
numericValue = reverseflag ? 0:1; // need 0 or 1, not true or something
}
this.log("Setting "+gaddress+" Boolean to %s", numericValue);
this.log("["+ this.name +"]:Setting "+gaddress+" " + reverseflag ? " (reverse)":""+ " Boolean to %s", numericValue);
this.knxwrite(callback, gaddress,'DPT1',numericValue);
}
},
setBooleanReverseState: function(value, callback, context, gaddress) {
// setBooleanReverseState: function(value, callback, context, gaddress) {
// if (context === 'fromKNXBus') {
//// this.log(gaddress + " event ping pong, exit!");
// if (callback) {
// callback();
// }
// } else {
// var numericValue = 0;
// if (!value) {
// numericValue = 1; // need 0 or 1, not true or something
// }
// this.log("["+ this.name +"]:Setting "+gaddress+" Boolean to %s", numericValue);
// this.knxwrite(callback, gaddress,'DPT1',numericValue);
// }
//
// },
setPercentage: function(value, callback, context, gaddress, reverseflag) {
if (context === 'fromKNXBus') {
this.log(gaddress + " event ping pong, exit!");
if (callback) {
callback();
}
} else {
var numericValue = 0;
if (!value) {
numericValue = 1; // need 0 or 1, not true or something
}
this.log("Setting "+gaddress+" Boolean to %s", numericValue);
this.knxwrite(callback, gaddress,'DPT1',numericValue);
}
},
setPercentage: function(value, callback, context, gaddress) {
if (context === 'fromKNXBus') {
this.log("event ping pong, exit!");
// this.log(gaddress + "event ping pong, exit!");
if (callback) {
callback();
}
} else {
var numericValue = 0;
if (value) {
numericValue = Math.round(255*value/100); // convert 1..100 to 1..255 for KNX bus
value = ( value>=0 ? (value<=100 ? value:100):0 ); //ensure range 0..100
if (reverseflag) {
numericValue = 255 - Math.round(255*value/100); // convert 0..100 to 255..0 for KNX bus
} else {
numericValue = Math.round(255*value/100); // convert 0..100 to 0..255 for KNX bus
}
this.log("Setting "+gaddress+" percentage to %s (%s)", value, numericValue);
this.log("["+ this.name +"]:Setting "+gaddress+" percentage to %s (%s)", value, numericValue);
this.knxwrite(callback, gaddress,'DPT5',numericValue);
}
},
setInt: function(value, callback, context, gaddress) {
if (context === 'fromKNXBus') {
this.log("event ping pong, exit!");
// this.log(gaddress + "event ping pong, exit!");
if (callback) {
callback();
}
} else {
var numericValue = 0;
if (value && value>=0 && value<=255) {
numericValue = value; // assure 1..255 for KNX bus
numericValue = value; // assure 0..255 for KNX bus
}
this.log("Setting "+gaddress+" int to %s (%s)", value, numericValue);
this.log("["+ this.name +"]:Setting "+gaddress+" int to %s (%s)", value, numericValue);
this.knxwrite(callback, gaddress,'DPT5',numericValue);
}
},
setFloat: function(value, callback, context, gaddress) {
if (context === 'fromKNXBus') {
this.log(gaddress + " event ping pong, exit!");
// this.log(gaddress + " event ping pong, exit!");
if (callback) {
callback();
}
@@ -349,13 +368,13 @@ KNXDevice.prototype = {
if (value) {
numericValue = value; // homekit expects precision of 1 decimal
}
this.log("Setting "+gaddress+" Float to %s", numericValue);
this.log("["+ this.name +"]:Setting "+gaddress+" Float to %s", numericValue);
this.knxwrite(callback, gaddress,'DPT9',numericValue);
}
},
setHVACState: function(value, callback, context, gaddress) {
if (context === 'fromKNXBus') {
this.log(gaddress + " event ping pong, exit!");
// this.log(gaddress + " event ping pong, exit!");
if (callback) {
callback();
}
@@ -378,7 +397,7 @@ KNXDevice.prototype = {
KNXvalue = 1;
}
this.log("Setting "+gaddress+" HVAC to %s", KNXvalue);
this.log("["+ this.name +"]:Setting "+gaddress+" HVAC to %s", KNXvalue);
this.knxwrite(callback, gaddress,'DPT5',KNXvalue);
}
@@ -387,33 +406,50 @@ KNXDevice.prototype = {
*
*/
identify: function(callback) {
this.log("Identify requested!");
this.log("["+ this.name +"]:Identify requested!");
callback(); // success
},
/** bindCharacteristic
* initializes callbacks for 'set' events (from HK) and for KNX bus reads (to HK)
*/
bindCharacteristic: function(myService, characteristicType, valueType, config) {
bindCharacteristic: function(myService, characteristicType, valueType, config, defaultValue) {
var myCharacteristic = myService.getCharacteristic(characteristicType);
var setGA = "";
var setReverse = false;
if (myCharacteristic === undefined) {
throw new Error("unknown characteristics cannot be bound");
}
if (defaultValue) {
myCharacteristic.setValue(defaultValue);
}
if (config.Set) {
// can write
// extract address and Reverse flag
setGA = config.Set.match(/\d*\/\d*\/\d*/);
if (setGA===null) {
this.log(colorOn + "["+ this.name +"]:["+myCharacteristic.displayName+"] Error in group adress: ["+ config.Set +"] "+colorOff);
throw new Error("EINVGROUPADRESS - Invalid group address given");
} else {
setGA=setGA[0]; // first element of returned array is the group address
}
setReverse = config.Set.match(/\d*\/\d*\/\d*(R)/) ? true:false;
switch (valueType) {
case "Bool":
myCharacteristic.on('set', function(value, callback, context) {
this.setBooleanState(value, callback, context, config.Set);
}.bind(this));
break;
case "BoolReverse":
myCharacteristic.on('set', function(value, callback, context) {
this.setBooleanReverseState(value, callback, context, config.Set);
this.setBooleanState(value, callback, context, setGA, setReverse); //NEW
}.bind(this));
break;
// case "BoolReverse":
// this.log("["+ this.name +"]:["+myCharacteristic.displayName+"] \x1b[30;47m%s\x1b[0mWARNING in group adress: "+ config.Set +": Legacy BoolReverse used. Use " + config.Set +"R instead");
// myCharacteristic.on('set', function(value, callback, context) {
// this.setBooleanReverseState(value, callback, context, config.Set);
// }.bind(this));
// break;
case "Percent":
myCharacteristic.on('set', function(value, callback, context) {
this.setPercentage(value, callback, context, config.Set);
this.setPercentage(value, callback, context, setGA, setReverse);
myCharacteristic.timeout = Date.now()+milliTimeout;
}.bind(this));
break;
@@ -433,7 +469,7 @@ KNXDevice.prototype = {
}.bind(this));
break;
default: {
this.log("[ERROR] unknown type passed");
this.log(colorOn + "[ERROR] unknown type passed: [" + valueType+"]"+ colorOff);
throw new Error("[ERROR] unknown type passed");
}
}
@@ -445,9 +481,9 @@ KNXDevice.prototype = {
case "Bool":
this.knxregister_bool([config.Set].concat(config.Listen || []), myCharacteristic);
break;
case "BoolReverse":
this.knxregister_boolReverse([config.Set].concat(config.Listen || []), myCharacteristic);
break;
// case "BoolReverse":
// this.knxregister_boolReverse([config.Set].concat(config.Listen || []), myCharacteristic);
// break;
case "Percent":
this.knxregister_percent([config.Set].concat(config.Listen || []), myCharacteristic);
break;
@@ -461,10 +497,10 @@ KNXDevice.prototype = {
this.knxregister_HVAC([config.Set].concat(config.Listen || []), myCharacteristic);
break;
default:
this.log("[ERROR] unknown type passed");
throw new Error("[ERROR] unknown type passed");
this.log(colorOn+ "[ERROR] unknown type passed: ["+valueType+"]"+colorOff);
throw new Error("[ERROR] unknown type passed");
}
this.log("Issuing read requests on the KNX bus...");
this.log("["+ this.name +"]:["+myCharacteristic.displayName+"]: Issuing read requests on the KNX bus...");
this.knxreadarray([config.Set].concat(config.Listen || []));
}
return myCharacteristic; // for chaining or whatsoever
@@ -494,30 +530,30 @@ KNXDevice.prototype = {
var myService = new Service.ContactSensor(config.name,config.name);
if (config.ContactSensorState) {
this.log("ContactSensor ContactSensorState characteristic enabled");
this.log("["+ this.name +"]:ContactSensor ContactSensorState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.ContactSensorState, "Bool", config.ContactSensorState);
} else if (config.ContactSensorStateContact1) {
this.log("ContactSensor ContactSensorStateContact1 characteristic enabled");
this.bindCharacteristic(myService, Characteristic.ContactSensorState, "BoolReverse", config.ContactSensorStateContact1);
this.log(colorOn+ "[ERROR] outdated type passed: [ContactSensorStateContact1]"+colorOff);
throw new Error("[ERROR] outdated type passed");
}
//optionals
if (config.StatusActive) {
this.log("ContactSensor StatusActive characteristic enabled");
this.log("["+ this.name +"]:ContactSensor StatusActive characteristic enabled");
myService.addCharacteristic(Characteristic.StatusActive);
this.bindCharacteristic(myService, Characteristic.StatusActive, "Bool", config.StatusActive);
}
if (config.StatusFault) {
this.log("ContactSensor StatusFault characteristic enabled");
this.log("["+ this.name +"]:ContactSensor StatusFault characteristic enabled");
myService.addCharacteristic(Characteristic.StatusFault);
this.bindCharacteristic(myService, Characteristic.StatusFault, "Bool", config.StatusFault);
}
if (config.StatusTampered) {
this.log("ContactSensor StatusTampered characteristic enabled");
this.log("["+ this.name +"]:ContactSensor StatusTampered characteristic enabled");
myService.addCharacteristic(Characteristic.StatusTampered);
this.bindCharacteristic(myService, Characteristic.StatusTampered, "Bool", config.StatusTampered);
}
if (config.StatusLowBattery) {
this.log("ContactSensor StatusLowBattery characteristic enabled");
this.log("["+ this.name +"]:ContactSensor StatusLowBattery characteristic enabled");
myService.addCharacteristic(Characteristic.StatusLowBattery);
this.bindCharacteristic(myService, Characteristic.StatusLowBattery, "Bool", config.StatusLowBattery);
}
@@ -555,27 +591,27 @@ KNXDevice.prototype = {
var myService = new Service.GarageDoorOpener(config.name,config.name);
if (config.CurrentDoorState) {
this.log("GarageDoorOpener CurrentDoorState characteristic enabled");
this.log("["+ this.name +"]:GarageDoorOpener CurrentDoorState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.CurrentDoorState, "Int", config.CurrentDoorState);
}
if (config.TargetDoorState) {
this.log("GarageDoorOpener TargetDoorState characteristic enabled");
this.log("["+ this.name +"]:GarageDoorOpener TargetDoorState characteristic enabled");
//myService.getCharacteristic(Characteristic.TargetDoorState).minimumValue=0; //
//myService.getCharacteristic(Characteristic.TargetDoorState).maximumValue=4; //
this.bindCharacteristic(myService, Characteristic.TargetDoorState, "Int", config.TargetDoorState);
}
if (config.ObstructionDetected) {
this.log("GarageDoorOpener ObstructionDetected characteristic enabled");
this.log("["+ this.name +"]:GarageDoorOpener ObstructionDetected characteristic enabled");
this.bindCharacteristic(myService, Characteristic.ObstructionDetected, "Bool", config.ObstructionDetected);
}
//optionals
if (config.LockCurrentState) {
this.log("GarageDoorOpener LockCurrentState characteristic enabled");
this.log("["+ this.name +"]:GarageDoorOpener LockCurrentState characteristic enabled");
myService.addCharacteristic(Characteristic.LockCurrentState);
this.bindCharacteristic(myService, Characteristic.LockCurrentState, "Int", config.LockCurrentState);
}
if (config.LockTargetState) {
this.log("GarageDoorOpener LockTargetState characteristic enabled");
this.log("["+ this.name +"]:GarageDoorOpener LockTargetState characteristic enabled");
myService.addCharacteristic(Characteristic.LockTargetState);
this.bindCharacteristic(myService, Characteristic.LockTargetState, "Bool", config.LockTargetState);
}
@@ -596,12 +632,12 @@ KNXDevice.prototype = {
var myService = new Service.Lightbulb(config.name,config.name);
// On (and Off)
if (config.On) {
this.log("Lightbulb on/off characteristic enabled");
this.log("["+ this.name +"]:Lightbulb on/off characteristic enabled");
this.bindCharacteristic(myService, Characteristic.On, "Bool", config.On);
} // On characteristic
// Brightness if available
if (config.Brightness) {
this.log("Lightbulb Brightness characteristic enabled");
this.log("["+ this.name +"]:Lightbulb Brightness characteristic enabled");
myService.addCharacteristic(Characteristic.Brightness); // it's an optional
this.bindCharacteristic(myService, Characteristic.Brightness, "Percent", config.Brightness);
}
@@ -623,7 +659,7 @@ KNXDevice.prototype = {
var myService = new Service.LightSensor(config.name,config.name);
// CurrentTemperature)
if (config.CurrentAmbientLightLevel) {
this.log("LightSensor CurrentAmbientLightLevel characteristic enabled");
this.log("["+ this.name +"]:LightSensor CurrentAmbientLightLevel characteristic enabled");
this.bindCharacteristic(myService, Characteristic.CurrentAmbientLightLevel, "Float", config.CurrentAmbientLightLevel);
}
return myService;
@@ -648,20 +684,20 @@ KNXDevice.prototype = {
// LockCurrentState
if (config.LockCurrentState) {
// for normal contacts: Secured = 1
this.log("LockMechanism LockCurrentState characteristic enabled");
this.log("["+ this.name +"]:LockMechanism LockCurrentState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.LockCurrentState, "Bool", config.LockCurrentState);
} else if (config.LockCurrentStateSecured0) {
// for reverse contacts Secured = 0
this.log("LockMechanism LockCurrentState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.LockCurrentState, "BoolReverse", config.LockCurrentStateSecured0);
this.log(colorOn+ "[ERROR] outdated type passed: [LockCurrentStateSecured0]"+colorOff);
throw new Error("[ERROR] outdated type passed");
}
// LockTargetState
if (config.LockTargetState) {
this.log("LockMechanism LockTargetState characteristic enabled");
this.log("["+ this.name +"]:LockMechanism LockTargetState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.LockTargetState, "Bool", config.LockTargetState);
} else if (config.LockTargetStateSecured0) {
this.log("LockMechanism LockTargetState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.LockTargetState, "BoolReverse", config.LockTargetStateSecured0);
this.log(colorOn+ "[ERROR] outdated type passed: [LockTargetStateSecured0]"+colorOff);
throw new Error("[ERROR] outdated type passed");
}
//iterate(myService);
@@ -683,27 +719,27 @@ KNXDevice.prototype = {
var myService = new Service.MotionSensor(config.name,config.name);
if (config.MotionDetected) {
this.log("MotionSensor MotionDetected characteristic enabled");
this.log("["+ this.name +"]:MotionSensor MotionDetected characteristic enabled");
this.bindCharacteristic(myService, Characteristic.MotionDetected, "Bool", config.MotionDetected);
}
//optionals
if (config.StatusActive) {
this.log("MotionSensor StatusActive characteristic enabled");
this.log("["+ this.name +"]:MotionSensor StatusActive characteristic enabled");
myService.addCharacteristic(Characteristic.StatusActive);
this.bindCharacteristic(myService, Characteristic.StatusActive, "Bool", config.StatusActive);
}
if (config.StatusFault) {
this.log("MotionSensor StatusFault characteristic enabled");
this.log("["+ this.name +"]:MotionSensor StatusFault characteristic enabled");
myService.addCharacteristic(Characteristic.StatusFault);
this.bindCharacteristic(myService, Characteristic.StatusFault, "Bool", config.StatusFault);
}
if (config.StatusTampered) {
this.log("MotionSensor StatusTampered characteristic enabled");
this.log("["+ this.name +"]:MotionSensor StatusTampered characteristic enabled");
myService.addCharacteristic(Characteristic.StatusTampered);
this.bindCharacteristic(myService, Characteristic.StatusTampered, "Bool", config.StatusTampered);
}
if (config.StatusLowBattery) {
this.log("MotionSensor StatusLowBattery characteristic enabled");
this.log("["+ this.name +"]:MotionSensor StatusLowBattery characteristic enabled");
myService.addCharacteristic(Characteristic.StatusLowBattery);
this.bindCharacteristic(myService, Characteristic.StatusLowBattery, "Bool", config.StatusLowBattery);
}
@@ -726,11 +762,11 @@ KNXDevice.prototype = {
var myService = new Service.Outlet(config.name,config.name);
// On (and Off)
if (config.On) {
this.log("Outlet on/off characteristic enabled");
this.log("["+ this.name +"]:Outlet on/off characteristic enabled");
this.bindCharacteristic(myService, Characteristic.On, "Bool", config.On);
} // OutletInUse characteristic
if (config.OutletInUse) {
this.log("Outlet on/off characteristic enabled");
this.log("["+ this.name +"]:Outlet on/off characteristic enabled");
this.bindCharacteristic(myService, Characteristic.OutletInUse, "Bool", config.OutletInUse);
}
return myService;
@@ -748,7 +784,7 @@ KNXDevice.prototype = {
var myService = new Service.Switch(config.name,config.name);
// On (and Off)
if (config.On) {
this.log("Switch on/off characteristic enabled");
this.log("["+ this.name +"]:Switch on/off characteristic enabled");
this.bindCharacteristic(myService, Characteristic.On, "Bool", config.On);
} // On characteristic
@@ -775,26 +811,35 @@ KNXDevice.prototype = {
var myService = new Service.Thermostat(config.name,config.name);
// CurrentTemperature)
// props update for https://github.com/KhaosT/HAP-NodeJS/commit/1d84d128d1513beedcafc24d2c07d98185563243#diff-cb84de3a1478a38b2cf8388d709f1c1cR108
if (config.CurrentTemperature) {
this.log("Thermostat CurrentTemperature characteristic enabled");
this.log("["+ this.name +"]:Thermostat CurrentTemperature characteristic enabled");
myService.getCharacteristic(Characteristic.CurrentTemperature).setProps({
minValue: config.CurrentTemperature.minValue || -40,
maxValue: config.CurrentTemperature.maxValue || 60
}); // °C by default
this.bindCharacteristic(myService, Characteristic.CurrentTemperature, "Float", config.CurrentTemperature);
}
// TargetTemperature if available
if (config.TargetTemperature) {
this.log("Thermostat TargetTemperature characteristic enabled");
this.log("["+ this.name +"]:Thermostat TargetTemperature characteristic enabled");
// default boundary too narrow for thermostats
myService.getCharacteristic(Characteristic.TargetTemperature).minimumValue=0; // °C
myService.getCharacteristic(Characteristic.TargetTemperature).maximumValue=40; // °C
// props update for https://github.com/KhaosT/HAP-NodeJS/commit/1d84d128d1513beedcafc24d2c07d98185563243#diff-cb84de3a1478a38b2cf8388d709f1c1cR108
myService.getCharacteristic(Characteristic.TargetTemperature).setProps({
minValue: config.TargetTemperature.minValue || 0,
maxValue: config.TargetTemperature.maxValue || 40
});
this.bindCharacteristic(myService, Characteristic.TargetTemperature, "Float", config.TargetTemperature);
}
// HVAC
if (config.CurrentHeatingCoolingState) {
this.log("Thermostat CurrentHeatingCoolingState characteristic enabled");
this.log("["+ this.name +"]:Thermostat CurrentHeatingCoolingState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.CurrentHeatingCoolingState, "HVAC", config.CurrentHeatingCoolingState);
}
// HVAC
if (config.TargetHeatingCoolingState) {
this.log("Thermostat TargetHeatingCoolingState characteristic enabled");
this.log("["+ this.name +"]:Thermostat TargetHeatingCoolingState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.TargetHeatingCoolingState, "HVAC", config.TargetHeatingCoolingState);
}
return myService;
@@ -812,10 +857,16 @@ KNXDevice.prototype = {
}
var myService = new Service.TemperatureSensor(config.name,config.name);
// CurrentTemperature)
// props update for https://github.com/KhaosT/HAP-NodeJS/commit/1d84d128d1513beedcafc24d2c07d98185563243#diff-cb84de3a1478a38b2cf8388d709f1c1cR108
if (config.CurrentTemperature) {
this.log("TemperatureSensor CurrentTemperature characteristic enabled");
this.log("["+ this.name +"]:TemperatureSensor CurrentTemperature characteristic enabled");
myService.getCharacteristic(Characteristic.CurrentTemperature).setProps({
minValue: config.CurrentTemperature.minValue || -40,
maxValue: config.CurrentTemperature.maxValue || 60
}); // °C by default
this.bindCharacteristic(myService, Characteristic.CurrentTemperature, "Float", config.CurrentTemperature);
}
return myService;
},
getWindowService: function(config) {
@@ -845,16 +896,16 @@ KNXDevice.prototype = {
var myService = new Service.Window(config.name,config.name);
if (config.CurrentPosition) {
this.log("Window CurrentPosition characteristic enabled");
this.log("["+ this.name +"]:Window CurrentPosition characteristic enabled");
this.bindCharacteristic(myService, Characteristic.CurrentPosition, "Percent", config.CurrentPosition);
}
if (config.TargetPosition) {
this.log("Window TargetPosition characteristic enabled");
this.log("["+ this.name +"]:Window TargetPosition characteristic enabled");
this.bindCharacteristic(myService, Characteristic.TargetPosition, "Percent", config.TargetPosition);
}
if (config.PositionState) {
this.log("Window PositionState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.PositionState, "Float", config.PositionState);
this.log("["+ this.name +"]:Window PositionState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.PositionState, "Int", config.PositionState);
}
return myService;
},
@@ -880,15 +931,15 @@ KNXDevice.prototype = {
var myService = new Service.WindowCovering(config.name,config.name);
if (config.CurrentPosition) {
this.log("WindowCovering CurrentPosition characteristic enabled");
this.log("["+ this.name +"]:WindowCovering CurrentPosition characteristic enabled");
this.bindCharacteristic(myService, Characteristic.CurrentPosition, "Percent", config.CurrentPosition);
}
if (config.TargetPosition) {
this.log("WindowCovering TargetPosition characteristic enabled");
this.log("["+ this.name +"]:WindowCovering TargetPosition characteristic enabled");
this.bindCharacteristic(myService, Characteristic.TargetPosition, "Percent", config.TargetPosition);
}
if (config.PositionState) {
this.log("WindowCovering PositionState characteristic enabled");
this.log("["+ this.name +"]:WindowCovering PositionState characteristic enabled");
this.bindCharacteristic(myService, Characteristic.PositionState, "Float", config.PositionState);
}
return myService;
@@ -910,7 +961,7 @@ KNXDevice.prototype = {
informationService
.setCharacteristic(Characteristic.Manufacturer, "Opensource Community")
.setCharacteristic(Characteristic.Model, "KNX Universal Device")
.setCharacteristic(Characteristic.SerialNumber, "Version 1.1.2");
.setCharacteristic(Characteristic.SerialNumber, "Version 1.1.4");
accessoryServices.push(informationService);
@@ -965,8 +1016,8 @@ KNXDevice.prototype = {
accessoryServices.push(this.getWindowCoveringService(configService));
break;
default:
this.log("[ERROR] unknown 'type' property of '"+configService.type+"' for service "+ configService.name + " in config.json. KNX platform section fault ");
//throw new Error("[ERROR] unknown 'type' property for service "+ configService.name + " in config.json. KNX platform section fault ");
this.log("[ERROR] unknown 'type' property of ["+configService.type+"] for service ["+ configService.name + "] in config.json. KNX platform section fault ");
throw new Error("[ERROR] unknown 'type' property of ["+configService.type+"] for service '"+ configService.name + "' in config.json. KNX platform section fault ");
}
}
// start listening for events on the bus (if not started yet - will prevent itself)

View File

@@ -89,14 +89,19 @@
"delay": 30,
"repeat": 3,
"zones":["Kitchen Lamp","Bedroom Lamp","Living Room Lamp","Hallway Lamp"]
},
{
},
{
"platform": "HomeAssistant",
"name": "HomeAssistant",
"host": "http://192.168.1.10:8123",
"password": "XXXXX",
"supported_types": ["light", "switch", "media_player", "scene"]
}
},
{
"platform": "LIFx",
"name": "LIFx",
"access_token": "XXXXXXXX generate at https://cloud.lifx.com/settings"
}
],
"accessories": [

View File

@@ -152,15 +152,24 @@ HomeAssistantPlatform.prototype = {
entity = data[i]
entity_type = entity.entity_id.split('.')[0]
// ignore devices that are not in the list of supported types
if (that.supportedTypes.indexOf(entity_type) == -1) {
continue;
}
// ignore hidden devices
if (entity.attributes && entity.attributes.hidden) {
continue;
}
var accessory = null
if (entity_type == 'light') {
accessory = new HomeAssistantLight(that.log, entity, that)
}else if (entity_type == 'switch'){
console.log(JSON.stringify(entity))
console.log("");
console.log("");
accessory = new HomeAssistantSwitch(that.log, entity, that)
}else if (entity_type == 'scene'){
accessory = new HomeAssistantSwitch(that.log, entity, that, 'scene')

View File

@@ -1,154 +1,156 @@
{
"bridge": {
"name": "Homebridge",
"username": "CC:22:3D:E3:CE:30",
"port": 51826,
"pin": "031-45-154"
},
"description": "This is an example configuration file for KNX platform shim",
"hint": "Always paste into jsonlint.com validation page before starting your homebridge, saves a lot of frustration",
"hint2": "Replace all group addresses by current addresses of your installation, these are arbitrary examples!",
"hint3": "For valid services and their characteristics have a look at the knxdevice.md file in folder accessories!",
"platforms": [
{
"platform": "KNX",
"name": "KNX",
"knxd_ip": "192.168.178.205",
"knxd_port": 6720,
"accessories": [
{
"accessory_type": "knxdevice",
"description": "Only generic type knxdevice is supported, all previous knx types have been merged into that.",
"name": "Living Room North Lamp",
"services": [
{
"type": "Lightbulb",
"description": "iOS8 Lightbulb type, supports On (Switch) and Brightness",
"name": "Living Room North Lamp",
"On": {
"Set": "1/1/6",
"Listen": [
"1/1/63"
]
},
"Brightness": {
"Set": "1/1/62",
"Listen": [
"1/1/64"
]
}
}
],
"services-description": "Services is an array, you CAN have multiple service types in one accessory, though it is not fully supported in many iOS HK apps, such as EVE and myTouchHome"
},
{
"accessory_type": "knxdevice",
"name": "Office Temperature",
"description": "iOS8.4.1 TemperatureSensor type, supports CurrentTemperature",
"services": [
{
"type": "TemperatureSensor",
"name": "Raumtemperatur",
"CurrentTemperature": {
"Listen": "3/3/44"
}
}
]
},
{
"accessory_type": "knxdevice",
"name": "Office Window Lock",
"services": [
{
"type": "LockMechanism",
"description": "iOS8 Lock mechanism, Supports LockCurrentStateSecured0 OR LockCurrentState, LockTargetStateSecured0 OR LockTargetState, use depending if LOCKED is 0 or 1",
"name": "Office Window Lock",
"LockCurrentStateSecured0": {
"Listen": "5/3/15"
},
"LockTargetStateSecured0": {
"Listen": "5/3/15"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample device with multiple services. Multiple services of different types are widely supported",
"name": "Office",
"services": [
{
"type": "Lightbulb",
"name": "Office Lamp",
"On": {
"Set": "1/3/5"
}
},
{
"type": "Thermostat",
"description": "iOS8 Thermostat type, supports CurrentTemperature, TargetTemperature, CurrentHeatingCoolingState ",
"name": "Raumtemperatur",
"CurrentTemperature": {
"Listen": "3/3/44"
},
"TargetTemperature": {
"Set": "3/3/94"
},
"CurrentHeatingCoolingState": {
"Listen": "3/3/64"
}
},
{
"type": "WindowCovering",
"description": "iOS9 Window covering (blinds etc) type, still WIP",
"name": "Blinds",
"TargetPosition": {
"Set": "1/2/3",
"Listen": "1/2/4"
},
"CurrentPosition": {
"Set": "1/3/1",
"Listen": "1/3/2"
},
"PositionState": {
"Listen": "2/7/1"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample contact sensor device",
"name": "Office Contact",
"services": [
{
"type": "ContactSensor",
"name": "Office Door",
"ContactSensorState": {
"Listen": "5/3/5"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample garage door opener",
"name": "Office Garage",
"services": [
{
"type": "GarageDoorOpener",
"name": "Office Garage Opener",
"CurrentDoorState": {
"Listen": "5/4/5"
},
"TargetDoorState": {
"Listen": "5/4/6"
}
}
]
}
]
}
],
"accessories": []
"bridge": {
"name": "Homebridge",
"username": "CC:22:3D:E3:CE:30",
"port": 51826,
"pin": "031-45-154"
},
"description": "This is an example configuration file for KNX platform shim",
"hint": "Always paste into jsonlint.com validation page before starting your homebridge, saves a lot of frustration",
"hint2": "Replace all group addresses by current addresses of your installation, these are arbitrary examples!",
"hint3": "For valid services and their characteristics have a look at the KNX.md file in folder platforms!",
"platforms": [
{
"platform": "KNX",
"name": "KNX",
"knxd_ip": "192.168.178.205",
"knxd_port": 6720,
"accessories": [
{
"accessory_type": "knxdevice",
"description": "Only generic type knxdevice is supported, all previous knx types have been merged into that.",
"name": "Living Room North Lamp",
"services": [
{
"type": "Lightbulb",
"description": "iOS8 Lightbulb type, supports On (Switch) and Brightness",
"name": "Living Room North Lamp",
"On": {
"Set": "1/1/6",
"Listen": [
"1/1/63"
]
},
"Brightness": {
"Set": "1/1/62",
"Listen": [
"1/1/64"
]
}
}
],
"services-description": "Services is an array, you CAN have multiple service types in one accessory, though it is not fully supported in many iOS HK apps, such as EVE and myTouchHome"
},
{
"accessory_type": "knxdevice",
"name": "Office Temperature",
"description": "iOS8.4.1 TemperatureSensor type, supports CurrentTemperature",
"services": [
{
"type": "TemperatureSensor",
"name": "Raumtemperatur",
"CurrentTemperature": {
"Listen": "3/3/44"
}
}
]
},
{
"accessory_type": "knxdevice",
"name": "Office Window Lock",
"services": [
{
"type": "LockMechanism",
"description": "iOS8 Lock mechanism, Supports LockCurrentState, LockTargetState, append R to the addresses if LOCKED is 1",
"name": "Office Window Lock",
"LockCurrentState": {
"Listen": "5/3/15R"
},
"LockTargetState": {
"Listen": "5/3/16R"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample device with multiple services. Multiple services of different types are widely supported",
"name": "Office",
"services": [
{
"type": "Lightbulb",
"name": "Office Lamp",
"On": {
"Set": "1/3/5"
}
},
{
"type": "Thermostat",
"description": "iOS8 Thermostat type, supports CurrentTemperature, TargetTemperature, CurrentHeatingCoolingState ",
"name": "Raumtemperatur",
"CurrentTemperature": {
"Listen": "3/3/44"
},
"TargetTemperature": {
"Set": "3/3/94"
},
"CurrentHeatingCoolingState": {
"Listen": "3/3/64"
}
},
{
"type": "WindowCovering",
"description": "iOS9 Window covering (blinds etc) type, still WIP",
"name": "Blinds",
"TargetPosition": {
"Set": "1/2/3",
"Listen": "1/2/4"
},
"CurrentPosition": {
"Set": "1/3/1",
"Listen": "1/3/2"
},
"PositionState": {
"Listen": "2/7/1"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample contact sensor device",
"name": "Office Contact",
"services": [
{
"type": "ContactSensor",
"name": "Office Door",
"ContactSensorState": {
"Listen": "5/3/5"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample garage door opener",
"name": "Office Garage",
"services": [
{
"type": "GarageDoorOpener",
"name": "Office Garage Opener",
"CurrentDoorState": {
"Listen": "5/4/5"
},
"TargetDoorState": {
"Listen": "5/4/6"
}
}
]
}
]
}
],
"accessories": [
]
}

View File

@@ -116,8 +116,8 @@ function groupsocketlisten(opts, callback) {
}
var registerSingleGA = function registerSingleGA (groupAddress, callback) {
subscriptions.push({address: groupAddress, callback: callback });
var registerSingleGA = function registerSingleGA (groupAddress, callback, reverse) {
subscriptions.push({address: groupAddress, callback: callback, reverse:reverse });
}
/*
@@ -143,7 +143,7 @@ var startMonitor = function startMonitor(opts) { // using { host: name-ip, port
if (subscriptions[i].address === dest) {
// found one, notify
console.log('HIT: Write from '+src+' to '+dest+': '+val+' ['+type+']');
subscriptions[i].callback(val, src, dest, type);
subscriptions[i].callback(val, src, dest, type, subscriptions[i].reverse);
}
}
});
@@ -156,7 +156,7 @@ var startMonitor = function startMonitor(opts) { // using { host: name-ip, port
if (subscriptions[i].address === dest) {
// found one, notify
// console.log('HIT: Response from '+src+' to '+dest+': '+val+' ['+type+']');
subscriptions[i].callback(val, src, dest, type);
subscriptions[i].callback(val, src, dest, type, subscriptions[i].reverse);
}
}
@@ -185,13 +185,16 @@ var registerGA = function (groupAddresses, callback) {
if (groupAddresses.constructor.toString().indexOf("Array") > -1) {
// handle multiple addresses
for (var i = 0; i < groupAddresses.length; i++) {
if (groupAddresses[i]) { // do not bind empty addresses
registerSingleGA (groupAddresses[i], callback);
if (groupAddresses[i] && groupAddresses[i].match(/(\d*\/\d*\/\d*)/)) { // do not bind empty addresses or invalid addresses
// clean the addresses
registerSingleGA (groupAddresses[i].match(/(\d*\/\d*\/\d*)/)[0], callback,groupAddresses[i].match(/\d*\/\d*\/\d*(R)/) ? true:false );
}
}
} else {
// it's only one
registerSingleGA (groupAddresses, callback);
if (groupAddresses.match(/(\d*\/\d*\/\d*)/)) {
registerSingleGA (groupAddresses.match(/(\d*\/\d*\/\d*)/)[0], callback, groupAddresses[i].match(/\d*\/\d*\/\d*(R)/) ? true:false);
}
}
// console.log("listeners now: " + subscriptions.length);
};

View File

@@ -47,7 +47,7 @@ You have to add services in the following syntax:
{
"type": "SERVICENAME",
"description": "This is just for you to remember things",
"name": "We need a name for each service, though it usually shows only if multiple services are present in one accessory",
"name": "beer tap thermostat",
"CHARACTERISTIC1": {
"Set": "1/1/6",
"Listen": [
@@ -68,11 +68,54 @@ Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group addres
`"Listen":["1/2/3","1/2/4","1/2/5"]` is an array of addresses that are listened to additionally. To these addresses never values get written, but the on startup the service will issue *KNX read requests* to ALL addresses listed in `Set:` and in `Listen:`
# Supported Services and their characteristics
For two characteristics there are additional minValue and maxValue attributes. These are CurrentTemperature and TargetTemperature, and are used in TemperatureSensor and Thermostat.
So the charcteristic section may look like:
````json
{
"type": "Thermostat",
"description": "Sample thermostat",
"name": "We need a name for each service, though it usually shows only if multiple services are present in one accessory",
"CurrentTemperature": {
"Set": "1/1/6",
"Listen": [
"1/1/63"
],
"minValue": -18,
"maxValue": 30
},
"TargetTemperature": {
"Set": "1/1/62",
"Listen": [
"1/1/64"
],
"minValue": -4,
"maxValue": 12
}
}
````
## reversal of values for characteristics
In general, all DPT1 types can be reversed. If you need a 1 for "contact" of a contact senser, you can append an "R" to the group address.
Likewise, all percentages of DPT5 can be reversed, if you need a 100% (=255) for window closed, append an "R" to the group address. Do not forget the listening addresses!
````json
{
"type": "ContactSensor",
"description": "Sample ContactSensor with 1 as contact (0 is Apple's default)",
"name": "WindowContact1",
"ContactSensorState": {
"Listen": [
"1/1/100R"
]
}
}
````
# Supported Services and their characteristics
## ContactSensor
- ContactSensorState: DPT 1.002, 0 as contact **OR**
- ContactSensorStateContact1: DPT 1.002, 1 as contact
- ContactSensorState: DPT 1.002, 0 as contact
- ~~ContactSensorStateContact1: DPT 1.002, 1 as contact~~
- StatusActive: DPT 1.011, 1 as true
- StatusFault: DPT 1.011, 1 as true
@@ -113,10 +156,10 @@ Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group addres
- CurrentAmbientLightLevel: DPT 9.004, 0 to 100000 Lux
## LockMechanism (This is poorly mapped!)
- LockCurrentState: DPT 1, 1 as secured **OR (but not both:)**
- LockCurrentStateSecured0: DPT 1, 0 as secured
- LockTargetState: DPT 1, 1 as secured **OR**
- LockTargetStateSecured0: DPT 1, 0 as secured
- LockCurrentState: DPT 1, 1 as secured
- ~~LockCurrentStateSecured0: DPT 1, 0 as secured~~
- LockTargetState: DPT 1, 1 as secured
- ~~LockTargetStateSecured0: DPT 1, 0 as secured~~
*ToDo here: correction of mappings, HomeKit reqires lock states UNSECURED=0, SECURED=1, JAMMED = 2, UNKNOWN=3*
@@ -136,11 +179,11 @@ Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group addres
- On: DPT 1.001, 1 as on, 0 as off
## TemperatureSensor
- CurrentTemperature: DPT9.001 in °C [listen only]
- CurrentTemperature: DPT9.001 in °C [listen only]
## Thermostat
- CurrentTemperature: DPT9.001 in °C [listen only]
- TargetTemperature: DPT9.001, values 0..40°C only, all others are ignored
- CurrentTemperature: DPT9.001 in °C [listen only], -40 to 80°C if not overriden as shown above
- TargetTemperature: DPT9.001, values 0..40°C only, all others are ignored
- CurrentHeatingCoolingState: DPT20.102 HVAC, because of the incompatible mapping only off and heating (=auto) are shown, [listen only]
- TargetHeatingCoolingState: DPT20.102 HVAC, as above
@@ -152,7 +195,7 @@ Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group addres
## WindowCovering
- CurrentPosition: DPT5 percentage
- TargetPosition: DPT5 percentage
- PositionState: DPT5 value [listen only]
- PositionState: DPT5 value [listen only: 0 Closing, 1 Opening, 2 Stopped]
### not yet supported
- HoldPosition