diff --git a/accessories/knxdevice.js b/accessories/knxdevice.js index 5801249..b2967c2 100644 --- a/accessories/knxdevice.js +++ b/accessories/knxdevice.js @@ -159,7 +159,7 @@ KNXDevice.prototype = { 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); + 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)); @@ -167,7 +167,7 @@ KNXDevice.prototype = { 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); + 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)); @@ -176,52 +176,70 @@ KNXDevice.prototype = { 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); + 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()) { +// 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 +// } 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 } }.bind(this)); }, // float knxregister_float: function(addresses, characteristic) { - this.log("knx registering FLOAT " + addresses); + // 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){ - 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) { + 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); + this.log("["+ this.name +"]:[" + characteristic.displayName+ "]:knx registering INT " + 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)) { + 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(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 +279,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)); }, @@ -278,7 +296,7 @@ KNXDevice.prototype = { */ setBooleanState: 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(); } @@ -287,14 +305,14 @@ KNXDevice.prototype = { if (value) { numericValue = 1; // need 0 or 1, not true or something } - this.log("Setting "+gaddress+" Boolean to %s", numericValue); + this.log("["+ this.name +"]:Setting "+gaddress+" Boolean to %s", numericValue); this.knxwrite(callback, gaddress,'DPT1',numericValue); } }, setBooleanReverseState: 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(); } @@ -303,14 +321,14 @@ KNXDevice.prototype = { if (!value) { numericValue = 1; // need 0 or 1, not true or something } - this.log("Setting "+gaddress+" Boolean to %s", numericValue); + this.log("["+ this.name +"]: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(); } @@ -319,13 +337,13 @@ KNXDevice.prototype = { if (value) { numericValue = Math.round(255*value/100); // convert 1..100 to 1..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(); } @@ -334,13 +352,13 @@ KNXDevice.prototype = { if (value && value>=0 && value<=255) { numericValue = value; // assure 1..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 +367,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 +396,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,7 +405,7 @@ KNXDevice.prototype = { * */ identify: function(callback) { - this.log("Identify requested!"); + this.log("["+ this.name +"]:Identify requested!"); callback(); // success }, /** bindCharacteristic @@ -461,10 +479,10 @@ KNXDevice.prototype = { this.knxregister_HVAC([config.Set].concat(config.Listen || []), myCharacteristic); break; default: - this.log("[ERROR] unknown type passed"); + this.log("[ERROR] unknown type passed: ["+valueType+"]"); 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 +512,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.log("["+ this.name +"]:ContactSensor ContactSensorStateContact1 characteristic enabled"); this.bindCharacteristic(myService, Characteristic.ContactSensorState, "BoolReverse", config.ContactSensorStateContact1); } //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 +573,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 +614,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 +641,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,19 +666,19 @@ 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.log("["+ this.name +"]:LockMechanism LockCurrentState characteristic enabled"); this.bindCharacteristic(myService, Characteristic.LockCurrentState, "BoolReverse", config.LockCurrentStateSecured0); } // 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.log("["+ this.name +"]:LockMechanism LockTargetState characteristic enabled"); this.bindCharacteristic(myService, Characteristic.LockTargetState, "BoolReverse", config.LockTargetStateSecured0); } @@ -683,27 +701,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 +744,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 +766,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 +793,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 +839,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,15 +878,15 @@ 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.log("["+ this.name +"]:Window PositionState characteristic enabled"); this.bindCharacteristic(myService, Characteristic.PositionState, "Float", config.PositionState); } return myService; @@ -880,15 +913,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 +943,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 +998,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) diff --git a/platforms/KNX-sample-config.json b/platforms/KNX-sample-config.json index 2c29736..86e070b 100644 --- a/platforms/KNX-sample-config.json +++ b/platforms/KNX-sample-config.json @@ -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 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": [ + + ] } \ No newline at end of file diff --git a/platforms/KNX.md b/platforms/KNX.md index c3b4fe3..0b4d4e9 100644 --- a/platforms/KNX.md +++ b/platforms/KNX.md @@ -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,6 +68,35 @@ 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:` +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 + } + } +```` + + # Supported Services and their characteristics ## ContactSensor @@ -139,7 +168,7 @@ Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group addres - CurrentTemperature: DPT9.001 in °C [listen only] ## Thermostat -- CurrentTemperature: DPT9.001 in °C [listen only] +- 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 +181,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