mirror of
https://github.com/mtan93/homebridge.git
synced 2026-03-09 13:21:58 +00:00
Merge branch 'nfarina/master'
This commit is contained in:
@@ -52,14 +52,19 @@ You'll also need some patience, as Siri can be very strict about sentence struct
|
||||
|
||||
# Getting Started
|
||||
|
||||
OK, if you're still excited enough about ordering Siri to make your coffee (which, who wouldn't be!) then here's how to set things up. First, clone this repo:
|
||||
OK, if you're still excited enough about ordering Siri to make your coffee (which, who wouldn't be!) then here's how to set things up.
|
||||
|
||||
**Note:** If you're running on Linux, you'll need to make sure you have the `libavahi-compat-libdnssd-dev` package installed.
|
||||
|
||||
First, clone this repo:
|
||||
|
||||
$ git clone https://github.com/nfarina/homebridge.git
|
||||
$ cd homebridge
|
||||
$ npm install
|
||||
|
||||
**Node**: You'll need to have NodeJS version 0.12.x or better installed for required submodule `HAP-NodeJS` to load.
|
||||
**Note**: You'll need to have NodeJS version 0.12.x or better installed for required submodule `HAP-NodeJS` to load.
|
||||
|
||||
|
||||
Now you should be able to run the homebridge server:
|
||||
|
||||
$ cd homebridge
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
/*
|
||||
/**
|
||||
* This is a KNX universal accessory shim.
|
||||
* This is NOT the version for dynamic installation
|
||||
*
|
||||
New 2015-09-16: Welcome iOS9.0
|
||||
new features includ:
|
||||
services:
|
||||
Window
|
||||
WindowCovering
|
||||
ContactSensor
|
||||
new features include:
|
||||
- services:
|
||||
- Window
|
||||
- WindowCovering
|
||||
- ContactSensor
|
||||
New 2015-09-18:
|
||||
- Services Switch and Outlet
|
||||
- Code cleanup
|
||||
New 2015-09-19:
|
||||
- GarageDoorOpener Service
|
||||
- MotionSensor Service
|
||||
*
|
||||
*/
|
||||
var Service = require("HAP-NodeJS").Service;
|
||||
@@ -102,7 +108,6 @@ KNXDevice.prototype = {
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
// issues an all purpose read request on the knx bus
|
||||
// DOES NOT WAIT for an answer. Please register the address with a callback using registerGA() function
|
||||
knxread: function(groupAddress){
|
||||
@@ -132,7 +137,6 @@ KNXDevice.prototype = {
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
// issuing multiple read requests at once
|
||||
knxreadarray: function (groupAddresses) {
|
||||
if (groupAddresses.constructor.toString().indexOf("Array") > -1) {
|
||||
@@ -148,21 +152,9 @@ KNXDevice.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
// special types
|
||||
knxwrite_percent: function(callback, groupAddress, value) {
|
||||
var numericValue = 0;
|
||||
if (value && value>=0 && value <= 100) {
|
||||
numericValue = 255*value/100; // convert 1..100 to 1..255 for KNX bus
|
||||
} else {
|
||||
this.log("[ERROR] Percentage value ot of bounds ");
|
||||
numericValue = 0;
|
||||
}
|
||||
this.knxwrite(callback, groupAddress,'DPT5',numericValue);
|
||||
},
|
||||
|
||||
|
||||
// need to spit registers into types
|
||||
|
||||
/** Registering routines
|
||||
*
|
||||
*/
|
||||
// boolean: get 0 or 1 from the bus, write boolean
|
||||
knxregister_bool: function(addresses, characteristic) {
|
||||
this.log("knx registering BOOLEAN " + addresses);
|
||||
@@ -201,7 +193,6 @@ KNXDevice.prototype = {
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
// float
|
||||
knxregister_float: function(addresses, characteristic) {
|
||||
this.log("knx registering FLOAT " + addresses);
|
||||
@@ -209,15 +200,24 @@ KNXDevice.prototype = {
|
||||
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) {
|
||||
characteristic.setValue(hk_value, undefined, 'fromKNXBus'); // 1 decoimal for HomeKit
|
||||
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);
|
||||
}
|
||||
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
// what about HVAC heating cooling types?
|
||||
//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');
|
||||
} else {
|
||||
this.log("Value %s out of bounds %s...%s ",hk_value, (characteristic.minimumValue || 0), (characteristic.maximumValue || 255));
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
knxregister_HVAC: function(addresses, characteristic) {
|
||||
this.log("knx registering HVAC " + addresses);
|
||||
knxd_registerGA(addresses, function(val, src, dest, type){
|
||||
@@ -245,7 +245,7 @@ KNXDevice.prototype = {
|
||||
characteristic.setValue(HAPvalue, undefined, 'fromKNXBus');
|
||||
}.bind(this));
|
||||
},
|
||||
// to do! KNX: DPT 20.102 = One Byte like DPT5
|
||||
/** KNX HVAC (heating, ventilation, and air conditioning) types do not really match to homekit types:
|
||||
// 0 = Auto
|
||||
// 1 = Comfort
|
||||
// 2 = Standby
|
||||
@@ -257,8 +257,8 @@ KNXDevice.prototype = {
|
||||
// Characteristic.TargetHeatingCoolingState.HEAT = 1;
|
||||
// Characteristic.TargetHeatingCoolingState.COOL = 2;
|
||||
// Characteristic.TargetHeatingCoolingState.AUTO = 3;
|
||||
|
||||
|
||||
AUTO (3) is not allowed as return type from devices!
|
||||
*/
|
||||
// undefined, has to match!
|
||||
knxregister: function(addresses, characteristic) {
|
||||
this.log("knx registering " + addresses);
|
||||
@@ -268,14 +268,14 @@ KNXDevice.prototype = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/*
|
||||
* set methods used for creating callbacks, such as
|
||||
* var Characteristic = myService.addCharacteristic(new Characteristic.Brightness())
|
||||
* .on('set', function(value, callback, context) {
|
||||
* this.setPercentage(value, callback, context, this.config[index].Set)
|
||||
* }.bind(this));
|
||||
*
|
||||
*/
|
||||
/** set methods used for creating callbacks
|
||||
* such as
|
||||
* var Characteristic = myService.addCharacteristic(new Characteristic.Brightness())
|
||||
* .on('set', function(value, callback, context) {
|
||||
* this.setPercentage(value, callback, context, this.config[index].Set)
|
||||
* }.bind(this));
|
||||
*
|
||||
*/
|
||||
setBooleanState: function(value, callback, context, gaddress) {
|
||||
if (context === 'fromKNXBus') {
|
||||
this.log(gaddress + " event ping pong, exit!");
|
||||
@@ -308,7 +308,6 @@ KNXDevice.prototype = {
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
setPercentage: function(value, callback, context, gaddress) {
|
||||
if (context === 'fromKNXBus') {
|
||||
this.log("event ping pong, exit!");
|
||||
@@ -324,7 +323,21 @@ KNXDevice.prototype = {
|
||||
this.knxwrite(callback, gaddress,'DPT5',numericValue);
|
||||
}
|
||||
},
|
||||
|
||||
setInt: function(value, callback, context, gaddress) {
|
||||
if (context === 'fromKNXBus') {
|
||||
this.log("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
|
||||
}
|
||||
this.log("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!");
|
||||
@@ -340,7 +353,6 @@ KNXDevice.prototype = {
|
||||
this.knxwrite(callback, gaddress,'DPT9',numericValue);
|
||||
}
|
||||
},
|
||||
|
||||
setHVACState: function(value, callback, context, gaddress) {
|
||||
if (context === 'fromKNXBus') {
|
||||
this.log(gaddress + " event ping pong, exit!");
|
||||
@@ -371,21 +383,16 @@ KNXDevice.prototype = {
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
/** identify dummy
|
||||
*
|
||||
*/
|
||||
identify: function(callback) {
|
||||
this.log("Identify requested!");
|
||||
callback(); // success
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* function getXXXXXXXService(config)
|
||||
*
|
||||
* returns a configured service object to the caller (accessory/device)
|
||||
*
|
||||
*/
|
||||
|
||||
/** bindCharacteristic
|
||||
* initializes callbacks for 'set' events (from HK) and for KNX bus reads (to HK)
|
||||
*/
|
||||
bindCharacteristic: function(myService, characteristicType, valueType, config) {
|
||||
var myCharacteristic = myService.getCharacteristic(characteristicType);
|
||||
if (myCharacteristic === undefined) {
|
||||
@@ -415,14 +422,20 @@ KNXDevice.prototype = {
|
||||
this.setFloat(value, callback, context, config.Set);
|
||||
}.bind(this));
|
||||
break;
|
||||
case "Int":
|
||||
myCharacteristic.on('set', function(value, callback, context) {
|
||||
this.setInt(value, callback, context, config.Set);
|
||||
}.bind(this));
|
||||
break;
|
||||
case "HVAC":
|
||||
myCharacteristic.on('set', function(value, callback, context) {
|
||||
this.setHVACState(value, callback, context, config.Set);
|
||||
}.bind(this));
|
||||
break;
|
||||
default:
|
||||
default: {
|
||||
this.log("[ERROR] unknown type passed");
|
||||
throw new Error("[ERROR] unknown type passed");
|
||||
throw new Error("[ERROR] unknown type passed");
|
||||
}
|
||||
}
|
||||
}
|
||||
if ([config.Set].concat(config.Listen || []).length>0) {
|
||||
@@ -441,6 +454,9 @@ KNXDevice.prototype = {
|
||||
case "Float":
|
||||
this.knxregister_float([config.Set].concat(config.Listen || []), myCharacteristic);
|
||||
break;
|
||||
case "Int":
|
||||
this.knxregister_int([config.Set].concat(config.Listen || []), myCharacteristic);
|
||||
break;
|
||||
case "HVAC":
|
||||
this.knxregister_HVAC([config.Set].concat(config.Listen || []), myCharacteristic);
|
||||
break;
|
||||
@@ -453,278 +469,19 @@ KNXDevice.prototype = {
|
||||
}
|
||||
return myCharacteristic; // for chaining or whatsoever
|
||||
},
|
||||
|
||||
getLightbulbService: function(config) {
|
||||
// some sanity checks
|
||||
//this.config = config;
|
||||
|
||||
if (config.type !== "Lightbulb") {
|
||||
this.log("[ERROR] Lightbulb Service for non 'Lightbulb' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] Lightbulb Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.Lightbulb(config.name,config.name);
|
||||
// On (and Off)
|
||||
if (config.On) {
|
||||
this.log("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");
|
||||
myService.addCharacteristic(Characteristic.Brightness); // it's an optional
|
||||
this.bindCharacteristic(myService, Characteristic.Brightness, "Percent", config.Brightness);
|
||||
}
|
||||
// Hue and Saturation could be added here if available in KNX lamps
|
||||
//iterate(myService);
|
||||
return myService;
|
||||
},
|
||||
|
||||
getLockMechanismService: function(config) {
|
||||
// some sanity checks
|
||||
//this.config = config;
|
||||
// Characteristic.LockCurrentState.UNSECURED = 0;
|
||||
// Characteristic.LockCurrentState.SECURED = 1;
|
||||
|
||||
if (config.type !== "LockMechanism") {
|
||||
this.log("[ERROR] LockMechanism Service for non 'LockMechanism' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] LockMechanism Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.LockMechanism(config.name,config.name);
|
||||
// LockCurrentState
|
||||
if (config.LockCurrentState) {
|
||||
// for normal contacts: Secured = 1
|
||||
this.log("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);
|
||||
}
|
||||
// LockTargetState
|
||||
if (config.LockTargetState) {
|
||||
this.log("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);
|
||||
}
|
||||
|
||||
//iterate(myService);
|
||||
return myService;
|
||||
},
|
||||
|
||||
|
||||
getThermostatService: function(config) {
|
||||
|
||||
|
||||
// // Required Characteristics
|
||||
// this.addCharacteristic(Characteristic.CurrentHeatingCoolingState);
|
||||
// this.addCharacteristic(Characteristic.TargetHeatingCoolingState);
|
||||
// this.addCharacteristic(Characteristic.CurrentTemperature); //check
|
||||
// this.addCharacteristic(Characteristic.TargetTemperature); //
|
||||
// this.addCharacteristic(Characteristic.TemperatureDisplayUnits);
|
||||
//
|
||||
// // Optional Characteristics
|
||||
// this.addOptionalCharacteristic(Characteristic.CurrentRelativeHumidity);
|
||||
// this.addOptionalCharacteristic(Characteristic.TargetRelativeHumidity);
|
||||
// this.addOptionalCharacteristic(Characteristic.CoolingThresholdTemperature);
|
||||
// this.addOptionalCharacteristic(Characteristic.HeatingThresholdTemperature);
|
||||
|
||||
|
||||
// some sanity checks
|
||||
|
||||
|
||||
if (config.type !== "Thermostat") {
|
||||
this.log("[ERROR] Thermostat Service for non 'Thermostat' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] Thermostat Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.Thermostat(config.name,config.name);
|
||||
// CurrentTemperature)
|
||||
if (config.CurrentTemperature) {
|
||||
this.log("Thermostat CurrentTemperature characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentTemperature, "Float", config.CurrentTemperature);
|
||||
}
|
||||
// TargetTemperature if available
|
||||
if (config.TargetTemperature) {
|
||||
this.log("Thermostat TargetTemperature characteristic enabled");
|
||||
|
||||
// DEBUG
|
||||
console.log("default value: " + myService.getCharacteristic(Characteristic.TargetTemperature).value);
|
||||
// DEBUG
|
||||
|
||||
// default boundary too narrow for thermostats
|
||||
myService.getCharacteristic(Characteristic.TargetTemperature).minimumValue=0; // °C
|
||||
myService.getCharacteristic(Characteristic.TargetTemperature).maximumValue=40; // °C
|
||||
this.bindCharacteristic(myService, Characteristic.TargetTemperature, "Float", config.TargetTemperature);
|
||||
}
|
||||
// HVAC
|
||||
if (config.CurrentHeatingCoolingState) {
|
||||
this.log("Thermostat CurrentHeatingCoolingState characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentHeatingCoolingState, "HVAC", config.CurrentHeatingCoolingState);
|
||||
}
|
||||
// HVAC
|
||||
if (config.TargetHeatingCoolingState) {
|
||||
this.log("Thermostat TargetHeatingCoolingState characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.TargetHeatingCoolingState, "HVAC", config.TargetHeatingCoolingState);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
|
||||
// temperature sensor type (iOS9 assumed)
|
||||
getTemperatureSensorService: function(config) {
|
||||
|
||||
|
||||
|
||||
// some sanity checks
|
||||
|
||||
|
||||
if (config.type !== "TemperatureSensor") {
|
||||
this.log("[ERROR] TemperatureSensor Service for non 'TemperatureSensor' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] TemperatureSensor Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.TemperatureSensor(config.name,config.name);
|
||||
// CurrentTemperature)
|
||||
if (config.CurrentTemperature) {
|
||||
this.log("TemperatureSensor CurrentTemperature characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentTemperature, "Float", config.CurrentTemperature);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
|
||||
|
||||
|
||||
// window type (iOS9 assumed)
|
||||
getWindowService: function(config) {
|
||||
// Service.Window = function(displayName, subtype) {
|
||||
// Service.call(this, displayName, '0000008B-0000-1000-8000-0026BB765291', subtype);
|
||||
//
|
||||
// // Required Characteristics
|
||||
// this.addCharacteristic(Characteristic.CurrentPosition);
|
||||
// this.addCharacteristic(Characteristic.TargetPosition);
|
||||
// this.addCharacteristic(Characteristic.PositionState);
|
||||
//
|
||||
// // Optional Characteristics
|
||||
// this.addOptionalCharacteristic(Characteristic.HoldPosition);
|
||||
// this.addOptionalCharacteristic(Characteristic.ObstructionDetected);
|
||||
// this.addOptionalCharacteristic(Characteristic.Name);
|
||||
|
||||
// Characteristic.PositionState.DECREASING = 0;
|
||||
// Characteristic.PositionState.INCREASING = 1;
|
||||
// Characteristic.PositionState.STOPPED = 2;
|
||||
|
||||
|
||||
// some sanity checks
|
||||
|
||||
|
||||
if (config.type !== "Window") {
|
||||
this.log("[ERROR] Window Service for non 'Window' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] Window Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.Window(config.name,config.name);
|
||||
|
||||
if (config.CurrentPosition) {
|
||||
this.log("Window CurrentPosition characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentPosition, "Percent", config.CurrentPosition);
|
||||
}
|
||||
if (config.TargetPosition) {
|
||||
this.log("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);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
|
||||
|
||||
// /**
|
||||
// * Service "Window Covering"
|
||||
// */
|
||||
//
|
||||
// Service.WindowCovering = function(displayName, subtype) {
|
||||
// Service.call(this, displayName, '0000008C-0000-1000-8000-0026BB765291', subtype);
|
||||
//
|
||||
// // Required Characteristics
|
||||
// this.addCharacteristic(Characteristic.CurrentPosition);
|
||||
// this.addCharacteristic(Characteristic.TargetPosition);
|
||||
// this.addCharacteristic(Characteristic.PositionState);
|
||||
//
|
||||
// // Optional Characteristics
|
||||
// this.addOptionalCharacteristic(Characteristic.HoldPosition);
|
||||
// this.addOptionalCharacteristic(Characteristic.TargetHorizontalTiltAngle);
|
||||
// this.addOptionalCharacteristic(Characteristic.TargetVerticalTiltAngle);
|
||||
// this.addOptionalCharacteristic(Characteristic.CurrentHorizontalTiltAngle);
|
||||
// this.addOptionalCharacteristic(Characteristic.CurrentVerticalTiltAngle);
|
||||
// this.addOptionalCharacteristic(Characteristic.ObstructionDetected);
|
||||
// this.addOptionalCharacteristic(Characteristic.Name);
|
||||
// };
|
||||
getWindowCoveringService: function(config) {
|
||||
|
||||
// some sanity checks
|
||||
|
||||
|
||||
if (config.type !== "WindowCovering") {
|
||||
this.log("[ERROR] WindowCovering Service for non 'WindowCovering' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] WindowCovering Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.WindowCovering(config.name,config.name);
|
||||
|
||||
if (config.CurrentPosition) {
|
||||
this.log("WindowCovering CurrentPosition characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentPosition, "Percent", config.CurrentPosition);
|
||||
}
|
||||
if (config.TargetPosition) {
|
||||
this.log("WindowCovering TargetPosition characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.TargetPosition, "Percent", config.TargetPosition);
|
||||
}
|
||||
if (config.PositionState) {
|
||||
this.log("WindowCovering PositionState characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.PositionState, "Float", config.PositionState);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
|
||||
// Service.ContactSensor = function(displayName, subtype) {
|
||||
// Service.call(this, displayName, '00000080-0000-1000-8000-0026BB765291', subtype);
|
||||
//
|
||||
// // Required Characteristics
|
||||
// this.addCharacteristic(Characteristic.ContactSensorState);
|
||||
//
|
||||
// // Optional Characteristics
|
||||
// this.addOptionalCharacteristic(Characteristic.StatusActive);
|
||||
// this.addOptionalCharacteristic(Characteristic.StatusFault);
|
||||
// this.addOptionalCharacteristic(Characteristic.StatusTampered);
|
||||
// this.addOptionalCharacteristic(Characteristic.StatusLowBattery);
|
||||
// this.addOptionalCharacteristic(Characteristic.Name);
|
||||
// };
|
||||
// Characteristic.ContactSensorState.CONTACT_DETECTED = 0;
|
||||
// Characteristic.ContactSensorState.CONTACT_NOT_DETECTED = 1;
|
||||
/**
|
||||
* function getXXXXXXXService(config)
|
||||
* returns a configured service object to the caller (accessory/device)
|
||||
*
|
||||
* @param config
|
||||
* pass a configuration array parsed from config.json
|
||||
* specifically for this service
|
||||
*
|
||||
*/
|
||||
getContactSenserService: function(config) {
|
||||
// Characteristic.ContactSensorState.CONTACT_DETECTED = 0;
|
||||
// Characteristic.ContactSensorState.CONTACT_NOT_DETECTED = 1;
|
||||
|
||||
// some sanity checks
|
||||
if (config.type !== "ContactSensor") {
|
||||
this.log("[ERROR] ContactSensor Service for non 'ContactSensor' service called");
|
||||
@@ -734,8 +491,8 @@ KNXDevice.prototype = {
|
||||
this.log("[ERROR] ContactSensor Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var myService = new Service.ContactSensor(config.name,config.name);
|
||||
|
||||
if (config.ContactSensorState) {
|
||||
this.log("ContactSensor ContactSensorState characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.ContactSensorState, "Bool", config.ContactSensorState);
|
||||
@@ -766,12 +523,381 @@ KNXDevice.prototype = {
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
getGarageDoorOpenerService: function(config) {
|
||||
// // Required Characteristics
|
||||
// this.addCharacteristic(Characteristic.CurrentDoorState);
|
||||
// this.addCharacteristic(Characteristic.TargetDoorState);
|
||||
// this.addCharacteristic(Characteristic.ObstructionDetected);
|
||||
// Characteristic.CurrentDoorState.OPEN = 0;
|
||||
// Characteristic.CurrentDoorState.CLOSED = 1;
|
||||
// Characteristic.CurrentDoorState.OPENING = 2;
|
||||
// Characteristic.CurrentDoorState.CLOSING = 3;
|
||||
// Characteristic.CurrentDoorState.STOPPED = 4;
|
||||
// //
|
||||
// // Optional Characteristics
|
||||
// this.addOptionalCharacteristic(Characteristic.LockCurrentState);
|
||||
// this.addOptionalCharacteristic(Characteristic.LockTargetState);
|
||||
// The value property of LockCurrentState must be one of the following:
|
||||
// Characteristic.LockCurrentState.UNSECURED = 0;
|
||||
// Characteristic.LockCurrentState.SECURED = 1;
|
||||
// Characteristic.LockCurrentState.JAMMED = 2;
|
||||
// Characteristic.LockCurrentState.UNKNOWN = 3;
|
||||
|
||||
// some sanity checks
|
||||
if (config.type !== "GarageDoorOpener") {
|
||||
this.log("[ERROR] GarageDoorOpener Service for non 'GarageDoorOpener' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] GarageDoorOpener Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var myService = new Service.GarageDoorOpener(config.name,config.name);
|
||||
if (config.CurrentDoorState) {
|
||||
this.log("GarageDoorOpener CurrentDoorState characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentDoorState, "Int", config.CurrentDoorState);
|
||||
}
|
||||
if (config.TargetDoorState) {
|
||||
this.log("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.bindCharacteristic(myService, Characteristic.ObstructionDetected, "Bool", config.ObstructionDetected);
|
||||
}
|
||||
//optionals
|
||||
if (config.LockCurrentState) {
|
||||
this.log("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");
|
||||
myService.addCharacteristic(Characteristic.LockTargetState);
|
||||
this.bindCharacteristic(myService, Characteristic.LockTargetState, "Bool", config.LockTargetState);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
getLightbulbService: function(config) {
|
||||
// some sanity checks
|
||||
//this.config = config;
|
||||
|
||||
if (config.type !== "Lightbulb") {
|
||||
this.log("[ERROR] Lightbulb Service for non 'Lightbulb' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] Lightbulb Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.Lightbulb(config.name,config.name);
|
||||
// On (and Off)
|
||||
if (config.On) {
|
||||
this.log("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");
|
||||
myService.addCharacteristic(Characteristic.Brightness); // it's an optional
|
||||
this.bindCharacteristic(myService, Characteristic.Brightness, "Percent", config.Brightness);
|
||||
}
|
||||
// Hue and Saturation could be added here if available in KNX lamps
|
||||
//iterate(myService);
|
||||
return myService;
|
||||
},
|
||||
getLightSensorService: function(config) {
|
||||
|
||||
// some sanity checks
|
||||
if (config.type !== "LightSensor") {
|
||||
this.log("[ERROR] LightSensor Service for non 'LightSensor' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] LightSensor Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.LightSensor(config.name,config.name);
|
||||
// CurrentTemperature)
|
||||
if (config.CurrentAmbientLightLevel) {
|
||||
this.log("LightSensor CurrentAmbientLightLevel characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentAmbientLightLevel, "Float", config.CurrentAmbientLightLevel);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
getLockMechanismService: function(config) {
|
||||
|
||||
/** //this.config = config;
|
||||
// Characteristic.LockCurrentState.UNSECURED = 0;
|
||||
// Characteristic.LockCurrentState.SECURED = 1;
|
||||
*/
|
||||
// some sanity checks
|
||||
if (config.type !== "LockMechanism") {
|
||||
this.log("[ERROR] LockMechanism Service for non 'LockMechanism' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] LockMechanism Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var myService = new Service.LockMechanism(config.name,config.name);
|
||||
// LockCurrentState
|
||||
if (config.LockCurrentState) {
|
||||
// for normal contacts: Secured = 1
|
||||
this.log("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);
|
||||
}
|
||||
// LockTargetState
|
||||
if (config.LockTargetState) {
|
||||
this.log("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);
|
||||
}
|
||||
|
||||
//iterate(myService);
|
||||
return myService;
|
||||
},
|
||||
getMotionSensorService: function(config) {
|
||||
// Characteristic.ContactSensorState.CONTACT_DETECTED = 0;
|
||||
// Characteristic.ContactSensorState.CONTACT_NOT_DETECTED = 1;
|
||||
|
||||
// some sanity checks
|
||||
if (config.type !== "MotionSensor") {
|
||||
this.log("[ERROR] MotionSensor Service for non 'MotionSensor' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] MotionSensor Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var myService = new Service.MotionSensor(config.name,config.name);
|
||||
if (config.MotionDetected) {
|
||||
this.log("MotionSensor MotionDetected characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.MotionDetected, "Bool", config.MotionDetected);
|
||||
}
|
||||
//optionals
|
||||
if (config.StatusActive) {
|
||||
this.log("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");
|
||||
myService.addCharacteristic(Characteristic.StatusFault);
|
||||
this.bindCharacteristic(myService, Characteristic.StatusFault, "Bool", config.StatusFault);
|
||||
}
|
||||
if (config.StatusTampered) {
|
||||
this.log("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");
|
||||
myService.addCharacteristic(Characteristic.StatusLowBattery);
|
||||
this.bindCharacteristic(myService, Characteristic.StatusLowBattery, "Bool", config.StatusLowBattery);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
getOutletService: function(config) {
|
||||
/**
|
||||
* this.addCharacteristic(Characteristic.On);
|
||||
* this.addCharacteristic(Characteristic.OutletInUse);
|
||||
*/
|
||||
// some sanity checks
|
||||
if (config.type !== "Outlet") {
|
||||
this.log("[ERROR] Outlet Service for non 'Outlet' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] Outlet Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.Outlet(config.name,config.name);
|
||||
// On (and Off)
|
||||
if (config.On) {
|
||||
this.log("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.bindCharacteristic(myService, Characteristic.OutletInUse, "Bool", config.OutletInUse);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
getSwitchService: function(config) {
|
||||
// some sanity checks
|
||||
if (config.type !== "Switch") {
|
||||
this.log("[ERROR] Switch Service for non 'Switch' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] Switch Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.Switch(config.name,config.name);
|
||||
// On (and Off)
|
||||
if (config.On) {
|
||||
this.log("Switch on/off characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.On, "Bool", config.On);
|
||||
} // On characteristic
|
||||
|
||||
return myService;
|
||||
},
|
||||
getThermostatService: function(config) {
|
||||
/**
|
||||
// Optional Characteristics
|
||||
this.addOptionalCharacteristic(Characteristic.CurrentRelativeHumidity);
|
||||
this.addOptionalCharacteristic(Characteristic.TargetRelativeHumidity);
|
||||
this.addOptionalCharacteristic(Characteristic.CoolingThresholdTemperature);
|
||||
this.addOptionalCharacteristic(Characteristic.HeatingThresholdTemperature);
|
||||
*/
|
||||
|
||||
// some sanity checks
|
||||
if (config.type !== "Thermostat") {
|
||||
this.log("[ERROR] Thermostat Service for non 'Thermostat' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] Thermostat Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var myService = new Service.Thermostat(config.name,config.name);
|
||||
// CurrentTemperature)
|
||||
if (config.CurrentTemperature) {
|
||||
this.log("Thermostat CurrentTemperature characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentTemperature, "Float", config.CurrentTemperature);
|
||||
}
|
||||
// TargetTemperature if available
|
||||
if (config.TargetTemperature) {
|
||||
this.log("Thermostat TargetTemperature characteristic enabled");
|
||||
// default boundary too narrow for thermostats
|
||||
myService.getCharacteristic(Characteristic.TargetTemperature).minimumValue=0; // °C
|
||||
myService.getCharacteristic(Characteristic.TargetTemperature).maximumValue=40; // °C
|
||||
this.bindCharacteristic(myService, Characteristic.TargetTemperature, "Float", config.TargetTemperature);
|
||||
}
|
||||
// HVAC
|
||||
if (config.CurrentHeatingCoolingState) {
|
||||
this.log("Thermostat CurrentHeatingCoolingState characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentHeatingCoolingState, "HVAC", config.CurrentHeatingCoolingState);
|
||||
}
|
||||
// HVAC
|
||||
if (config.TargetHeatingCoolingState) {
|
||||
this.log("Thermostat TargetHeatingCoolingState characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.TargetHeatingCoolingState, "HVAC", config.TargetHeatingCoolingState);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
getTemperatureSensorService: function(config) {
|
||||
|
||||
// some sanity checks
|
||||
if (config.type !== "TemperatureSensor") {
|
||||
this.log("[ERROR] TemperatureSensor Service for non 'TemperatureSensor' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] TemperatureSensor Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.TemperatureSensor(config.name,config.name);
|
||||
// CurrentTemperature)
|
||||
if (config.CurrentTemperature) {
|
||||
this.log("TemperatureSensor CurrentTemperature characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentTemperature, "Float", config.CurrentTemperature);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
getWindowService: function(config) {
|
||||
/**
|
||||
Optional Characteristics
|
||||
this.addOptionalCharacteristic(Characteristic.HoldPosition);
|
||||
this.addOptionalCharacteristic(Characteristic.ObstructionDetected);
|
||||
this.addOptionalCharacteristic(Characteristic.Name);
|
||||
|
||||
|
||||
|
||||
/* assemble the device ***************************************************************************************************/
|
||||
PositionState values: The KNX blind actuators I have return only MOVING=1 and STOPPED=0
|
||||
Characteristic.PositionState.DECREASING = 0;
|
||||
Characteristic.PositionState.INCREASING = 1;
|
||||
Characteristic.PositionState.STOPPED = 2;
|
||||
*/
|
||||
|
||||
// some sanity checks
|
||||
|
||||
|
||||
if (config.type !== "Window") {
|
||||
this.log("[ERROR] Window Service for non 'Window' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] Window Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
var myService = new Service.Window(config.name,config.name);
|
||||
|
||||
if (config.CurrentPosition) {
|
||||
this.log("Window CurrentPosition characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentPosition, "Percent", config.CurrentPosition);
|
||||
}
|
||||
if (config.TargetPosition) {
|
||||
this.log("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);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
getWindowCoveringService: function(config) {
|
||||
/**
|
||||
// Optional Characteristics
|
||||
this.addOptionalCharacteristic(Characteristic.HoldPosition);
|
||||
this.addOptionalCharacteristic(Characteristic.TargetHorizontalTiltAngle);
|
||||
this.addOptionalCharacteristic(Characteristic.TargetVerticalTiltAngle);
|
||||
this.addOptionalCharacteristic(Characteristic.CurrentHorizontalTiltAngle);
|
||||
this.addOptionalCharacteristic(Characteristic.CurrentVerticalTiltAngle);
|
||||
this.addOptionalCharacteristic(Characteristic.ObstructionDetected);
|
||||
*/
|
||||
// some sanity checks
|
||||
if (config.type !== "WindowCovering") {
|
||||
this.log("[ERROR] WindowCovering Service for non 'WindowCovering' service called");
|
||||
return undefined;
|
||||
}
|
||||
if (!config.name) {
|
||||
this.log("[ERROR] WindowCovering Service without 'name' property called");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var myService = new Service.WindowCovering(config.name,config.name);
|
||||
if (config.CurrentPosition) {
|
||||
this.log("WindowCovering CurrentPosition characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.CurrentPosition, "Percent", config.CurrentPosition);
|
||||
}
|
||||
if (config.TargetPosition) {
|
||||
this.log("WindowCovering TargetPosition characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.TargetPosition, "Percent", config.TargetPosition);
|
||||
}
|
||||
if (config.PositionState) {
|
||||
this.log("WindowCovering PositionState characteristic enabled");
|
||||
this.bindCharacteristic(myService, Characteristic.PositionState, "Float", config.PositionState);
|
||||
}
|
||||
return myService;
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
/* assemble the device ***************************************************************************************************/
|
||||
getServices: function() {
|
||||
|
||||
// you can OPTIONALLY create an information service if you wish to override
|
||||
@@ -784,12 +910,12 @@ KNXDevice.prototype = {
|
||||
informationService
|
||||
.setCharacteristic(Characteristic.Manufacturer, "Opensource Community")
|
||||
.setCharacteristic(Characteristic.Model, "KNX Universal Device")
|
||||
.setCharacteristic(Characteristic.SerialNumber, "Version 1.1");
|
||||
.setCharacteristic(Characteristic.SerialNumber, "Version 1.1.2");
|
||||
|
||||
accessoryServices.push(informationService);
|
||||
|
||||
iterate(this.config);
|
||||
// throw new Error("STOP");
|
||||
//iterate(this.config);
|
||||
|
||||
if (!this.config.services){
|
||||
this.log("No services found in accessory?!")
|
||||
}
|
||||
@@ -808,12 +934,24 @@ KNXDevice.prototype = {
|
||||
case "ContactSensor":
|
||||
accessoryServices.push(this.getContactSenserService(configService));
|
||||
break;
|
||||
case "GarageDoorOpener":
|
||||
accessoryServices.push(this.getGarageDoorOpenerService(configService));
|
||||
break;
|
||||
case "Lightbulb":
|
||||
accessoryServices.push(this.getLightbulbService(configService));
|
||||
break;
|
||||
case "LightSensor":
|
||||
accessoryServices.push(this.getLightSensorService(configService));
|
||||
break;
|
||||
case "LockMechanism":
|
||||
accessoryServices.push(this.getLockMechanismService(configService));
|
||||
break;
|
||||
case "MotionSensor":
|
||||
accessoryServices.push(this.getMotionSensorService(configService));
|
||||
break;
|
||||
case "Switch":
|
||||
accessoryServices.push(this.getSwitchService(configService));
|
||||
break;
|
||||
case "TemperatureSensor":
|
||||
accessoryServices.push(this.getTemperatureSensorService(configService));
|
||||
break;
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
# Syntax of the config.json
|
||||
In the platforms section, you can insert a KNX type platform.
|
||||
You need to configure all devices directly in the config.json.
|
||||
|
||||
"platforms": [
|
||||
{
|
||||
"platform": "KNX",
|
||||
"name": "KNX",
|
||||
"knxd_ip": "192.168.178.205",
|
||||
"knxd_port": 6720,
|
||||
"accessories": [
|
||||
{
|
||||
"accessory_type": "knxdevice",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
In the accessories section (the array within the brackets [ ]) you can insert as many objects as you like in the following form
|
||||
{
|
||||
"accessory_type": "knxdevice",
|
||||
"name": "Here goes your display name, this will be shown in HomeKit apps",
|
||||
"services": [
|
||||
{
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
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",
|
||||
"CHARACTERISTIC1": {
|
||||
"Set": "1/1/6",
|
||||
"Listen": [
|
||||
"1/1/63"
|
||||
]
|
||||
},
|
||||
"CHARACTERISTIC2": {
|
||||
"Set": "1/1/62",
|
||||
"Listen": [
|
||||
"1/1/64"
|
||||
]
|
||||
}
|
||||
}
|
||||
CHARACTERISTIC are properties that are dependent on the service type, so they are listed below.
|
||||
Two kinds of addresses are supported: "Set":"1/2/3" is a writable group address, to which changes are sent if the service supports changing values. Changes on the bus are listened to, too.
|
||||
"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 read requests to ALL addresses listed in Set: and in Listen:
|
||||
|
||||
|
||||
# Supported Services and their characteristics
|
||||
|
||||
## Lightbulb
|
||||
On: DPT 1, 1 as on, 0 as off
|
||||
Brightness: DPT5 percentage, 100% (=255) the brightest
|
||||
|
||||
|
||||
## LockMechanism
|
||||
LockCurrentState: DPT 1, 1 as secured
|
||||
OR (but not both:)
|
||||
LockCurrentStateSecured0: DPT 1, 0 as secured
|
||||
|
||||
LockTargetState: DPT 1, 1 as secured
|
||||
LockTargetStateSecured0: DPT 1, 0 as secured
|
||||
|
||||
## Thermostat
|
||||
CurrentTemperature: DPT9 in °C [listen only]
|
||||
TargetTemperature: DPT9, values 0..40°C only, all others are ignored
|
||||
CurrentHeatingCoolingState: DPT5 HVAC, because of the incompatible mapping only off and heating (=auto) are shown, [listen only]
|
||||
TargetHeatingCoolingState: as above
|
||||
|
||||
|
||||
## TemperatureSensor
|
||||
CurrentTemperature: DPT9 in °C [listen only]
|
||||
|
||||
## Window
|
||||
CurrentPosition: DPT5 percentage
|
||||
TargetPosition: DPT5 percentage
|
||||
PositionState: DPT5 value [listen only]
|
||||
|
||||
## WindowCovering
|
||||
CurrentPosition: DPT5 percentage
|
||||
TargetPosition: DPT5 percentage
|
||||
PositionState: DPT5 value [listen only]
|
||||
|
||||
### not yet supported
|
||||
HoldPosition
|
||||
TargetHorizontalTiltAngle
|
||||
TargetVerticalTiltAngle
|
||||
CurrentHorizontalTiltAngle
|
||||
CurrentVerticalTiltAngle
|
||||
ObstructionDetected
|
||||
|
||||
## ContactSensor
|
||||
ContactSensorState: DPT 1, 0 as contact
|
||||
OR
|
||||
ContactSensorStateContact1: DPT 1, 1 as contact
|
||||
|
||||
StatusActive: DPT 1, 1 as true
|
||||
StatusFault: DPT 1, 1 as true
|
||||
StatusTampered: DPT 1, 1 as true
|
||||
StatusLowBattery: DPT 1, 1 as true
|
||||
|
||||
|
||||
# DISCLAIMER
|
||||
This is work in progress!
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"color": "0.10.x",
|
||||
"eibd": "^0.3.1",
|
||||
"elkington": "kevinohara80/elkington",
|
||||
"hap-nodejs": "git+https://github.com/KhaosT/HAP-NodeJS#0030b35856e04ee2b42f0d05839feaa5c44cbd1f",
|
||||
"hap-nodejs": "git+https://github.com/KhaosT/HAP-NodeJS#4650e771f356a220868d873d16564a6be6603ff7",
|
||||
"harmonyhubjs-client": "^1.1.4",
|
||||
"harmonyhubjs-discover": "git+https://github.com/swissmanu/harmonyhubjs-discover.git",
|
||||
"lifx-api": "^1.0.1",
|
||||
|
||||
253
platforms/FibaroHC2.js
Normal file
253
platforms/FibaroHC2.js
Normal file
@@ -0,0 +1,253 @@
|
||||
// Fibaro Home Center 2 Platform Shim for HomeBridge
|
||||
//
|
||||
// Remember to add platform to config.json. Example:
|
||||
// "platforms": [
|
||||
// {
|
||||
// "platform": "FibaroHC2",
|
||||
// "name": "FibaroHC2",
|
||||
// "host": "PUT IP ADDRESS OF YOUR HC2 HERE",
|
||||
// "username": "PUT USERNAME OF YOUR HC2 HERE",
|
||||
// "password": "PUT PASSWORD OF YOUR HC2 HERE"
|
||||
// }
|
||||
// ],
|
||||
//
|
||||
// When you attempt to add a device, it will ask for a "PIN code".
|
||||
// The default code for all HomeBridge accessories is 031-45-154.
|
||||
|
||||
var types = require("HAP-NodeJS/accessories/types.js");
|
||||
var Service = require("HAP-NodeJS").Service;
|
||||
var Characteristic = require("HAP-NodeJS").Characteristic;
|
||||
var request = require("request");
|
||||
|
||||
function FibaroHC2Platform(log, config){
|
||||
this.log = log;
|
||||
this.host = config["host"];
|
||||
this.username = config["username"];
|
||||
this.password = config["password"];
|
||||
this.auth = "Basic " + new Buffer(this.username + ":" + this.password).toString("base64");
|
||||
this.url = "http://"+this.host+"/api/devices";
|
||||
|
||||
startPollingUpdate( this );
|
||||
}
|
||||
|
||||
FibaroHC2Platform.prototype = {
|
||||
accessories: function(callback) {
|
||||
this.log("Fetching Fibaro Home Center devices...");
|
||||
|
||||
var that = this;
|
||||
var foundAccessories = [];
|
||||
|
||||
request.get({
|
||||
url: this.url,
|
||||
headers : {
|
||||
"Authorization" : this.auth
|
||||
},
|
||||
json: true
|
||||
}, function(err, response, json) {
|
||||
if (!err && response.statusCode == 200) {
|
||||
if (json != undefined) {
|
||||
json.map(function(s) {
|
||||
that.log("Found: " + s.type);
|
||||
if (s.visible == true) {
|
||||
var accessory = null;
|
||||
if (s.type == "com.fibaro.multilevelSwitch")
|
||||
accessory = new FibaroAccessory(new Service.Lightbulb(s.name), [Characteristic.On, Characteristic.Brightness]);
|
||||
else if (s.type == "com.fibaro.FGRM222" || s.type == "com.fibaro.FGR221")
|
||||
accessory = new FibaroAccessory(new Service.WindowCovering(s.name), [Characteristic.CurrentPosition, Characteristic.TargetPosition, Characteristic.PositionState]);
|
||||
else if (s.type == "com.fibaro.binarySwitch" || s.type == "com.fibaro.developer.bxs.virtualBinarySwitch")
|
||||
accessory = new FibaroAccessory(new Service.Switch(s.name), [Characteristic.On]);
|
||||
else if (s.type == "com.fibaro.FGMS001" || s.type == "com.fibaro.motionSensor")
|
||||
accessory = new FibaroAccessory(new Service.MotionSensor(s.name), [Characteristic.MotionDetected]);
|
||||
else if (s.type == "com.fibaro.temperatureSensor")
|
||||
accessory = new FibaroAccessory(new Service.TemperatureSensor(s.name), [Characteristic.CurrentTemperature]);
|
||||
else if (s.type == "com.fibaro.doorSensor")
|
||||
accessory = new FibaroAccessory(new Service.ContactSensor(s.name), [Characteristic.ContactSensorState]);
|
||||
else if (s.type == "com.fibaro.lightSensor")
|
||||
accessory = new FibaroAccessory(new Service.LightSensor(s.name), [Characteristic.CurrentAmbientLightLevel]);
|
||||
else if (s.type == "com.fibaro.FGWP101")
|
||||
accessory = new FibaroAccessory(new Service.Outlet(s.name), [Characteristic.On, Characteristic.OutletInUse]);
|
||||
if (accessory != null) {
|
||||
accessory.getServices = function() {
|
||||
return that.getServices(accessory);
|
||||
};
|
||||
accessory.platform = that;
|
||||
accessory.remoteAccessory = s;
|
||||
accessory.id = s.id;
|
||||
accessory.name = s.name;
|
||||
accessory.model = s.type;
|
||||
accessory.manufacturer = "Fibaro";
|
||||
accessory.serialNumber = "<unknown>";
|
||||
foundAccessories.push(accessory);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
callback(foundAccessories);
|
||||
} else {
|
||||
that.log("There was a problem connecting with FibaroHC2.");
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
command: function(c,value, that) {
|
||||
var url = "http://"+this.host+"/api/devices/"+that.id+"/action/"+c;
|
||||
var body = value != undefined ? JSON.stringify({
|
||||
"args": [ value ]
|
||||
}) : null;
|
||||
var method = "post";
|
||||
request({
|
||||
url: url,
|
||||
body: body,
|
||||
method: method,
|
||||
headers: {
|
||||
"Authorization" : this.auth
|
||||
},
|
||||
}, function(err, response) {
|
||||
if (err) {
|
||||
that.platform.log("There was a problem sending command " + c + " to" + that.name);
|
||||
that.platform.log(url);
|
||||
} else {
|
||||
that.platform.log(that.name + " sent command " + c);
|
||||
that.platform.log(url);
|
||||
}
|
||||
});
|
||||
},
|
||||
getAccessoryValue: function(callback, returnBoolean, homebridgeAccessory, powerValue) {
|
||||
var url = "http://"+homebridgeAccessory.platform.host+"/api/devices/"+homebridgeAccessory.id+"/properties/";
|
||||
if (powerValue)
|
||||
url = url + "power";
|
||||
else
|
||||
url = url + "value";
|
||||
|
||||
request.get({
|
||||
headers : {
|
||||
"Authorization" : homebridgeAccessory.platform.auth
|
||||
},
|
||||
json: true,
|
||||
url: url
|
||||
}, function(err, response, json) {
|
||||
homebridgeAccessory.platform.log(url);
|
||||
if (!err && response.statusCode == 200) {
|
||||
if (powerValue) {
|
||||
callback(undefined, parseFloat(json.value) > 1.0 ? true : false);
|
||||
} else if (returnBoolean)
|
||||
callback(undefined, json.value == 0 ? 0 : 1);
|
||||
else
|
||||
callback(undefined, json.value);
|
||||
} else {
|
||||
homebridgeAccessory.platform.log("There was a problem getting value from" + homebridgeAccessory.id);
|
||||
}
|
||||
})
|
||||
},
|
||||
getInformationService: function(homebridgeAccessory) {
|
||||
var informationService = new Service.AccessoryInformation();
|
||||
informationService
|
||||
.setCharacteristic(Characteristic.Name, homebridgeAccessory.name)
|
||||
.setCharacteristic(Characteristic.Manufacturer, homebridgeAccessory.manufacturer)
|
||||
.setCharacteristic(Characteristic.Model, homebridgeAccessory.model)
|
||||
.setCharacteristic(Characteristic.SerialNumber, homebridgeAccessory.serialNumber);
|
||||
return informationService;
|
||||
},
|
||||
bindCharacteristicEvents: function(characteristic, homebridgeAccessory) {
|
||||
var onOff = characteristic.props.format == "bool" ? true : false;
|
||||
var readOnly = true;
|
||||
for (var i = 0; i < characteristic.props.perms.length; i++)
|
||||
if (characteristic.props.perms[i] == "pw")
|
||||
readOnly = false;
|
||||
var powerValue = (characteristic.UUID == "00000026-0000-1000-8000-0026BB765291") ? true : false;
|
||||
subscribeUpdate(characteristic, homebridgeAccessory, onOff);
|
||||
if (!readOnly) {
|
||||
characteristic
|
||||
.on('set', function(value, callback, context) {
|
||||
if( context !== 'fromFibaro' ) {
|
||||
if (onOff)
|
||||
homebridgeAccessory.platform.command(value == 0 ? "turnOff": "turnOn", null, homebridgeAccessory);
|
||||
else
|
||||
homebridgeAccessory.platform.command("setValue", value, homebridgeAccessory);
|
||||
}
|
||||
callback();
|
||||
}.bind(this) );
|
||||
}
|
||||
characteristic
|
||||
.on('get', function(callback) {
|
||||
homebridgeAccessory.platform.getAccessoryValue(callback, onOff, homebridgeAccessory, powerValue);
|
||||
}.bind(this) );
|
||||
},
|
||||
getServices: function(homebridgeAccessory) {
|
||||
var informationService = homebridgeAccessory.platform.getInformationService(homebridgeAccessory);
|
||||
for (var i=0; i < homebridgeAccessory.characteristics.length; i++) {
|
||||
var characteristic = homebridgeAccessory.controlService.getCharacteristic(homebridgeAccessory.characteristics[i]);
|
||||
if (characteristic == undefined)
|
||||
characteristic = homebridgeAccessory.controlService.addCharacteristic(homebridgeAccessory.characteristics[i]);
|
||||
homebridgeAccessory.platform.bindCharacteristicEvents(characteristic, homebridgeAccessory);
|
||||
}
|
||||
|
||||
return [informationService, homebridgeAccessory.controlService];
|
||||
}
|
||||
}
|
||||
|
||||
function FibaroAccessory(controlService, characteristics) {
|
||||
this.controlService = controlService;
|
||||
this.characteristics = characteristics;
|
||||
}
|
||||
|
||||
var lastPoll=0;
|
||||
var pollingUpdateRunning = false;
|
||||
|
||||
function startPollingUpdate( platform )
|
||||
{
|
||||
if( pollingUpdateRunning )
|
||||
return;
|
||||
pollingUpdateRunning = true;
|
||||
|
||||
var updateUrl = "http://"+platform.host+"/api/refreshStates?last="+lastPoll;
|
||||
|
||||
request.get({
|
||||
url: updateUrl,
|
||||
headers : {
|
||||
"Authorization" : platform.auth
|
||||
},
|
||||
json: true
|
||||
}, function(err, response, json) {
|
||||
if (!err && response.statusCode == 200) {
|
||||
if (json != undefined) {
|
||||
lastPoll = json.last;
|
||||
if (json.changes != undefined) {
|
||||
json.changes.map(function(s) {
|
||||
if (s.value != undefined) {
|
||||
|
||||
var value=parseInt(s.value);
|
||||
if (isNaN(value))
|
||||
value=(s.value === "true");
|
||||
for (i=0;i<updateSubscriptions.length; i++) {
|
||||
var subscription = updateSubscriptions[i];
|
||||
if (subscription.id == s.id) {
|
||||
if (s.power != undefined && subscription.characteristic.UUID == "00000026-0000-1000-8000-0026BB765291") {
|
||||
subscription.characteristic.setValue(parseFloat(s.power) > 1.0 ? true : false, undefined, 'fromFibaro');
|
||||
} else if ((subscription.onOff && typeof(value) == "boolean") || !subscription.onOff)
|
||||
subscription.characteristic.setValue(value, undefined, 'fromFibaro');
|
||||
else
|
||||
subscription.characteristic.setValue(value == 0 ? false : true, undefined, 'fromFibaro');
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
platform.log("There was a problem connecting with FibaroHC2.");
|
||||
}
|
||||
pollingUpdateRunning = false;
|
||||
setTimeout( function(){startPollingUpdate(platform)}, 2000 );
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
var updateSubscriptions = [];
|
||||
function subscribeUpdate(characteristic, accessory, onOff)
|
||||
{
|
||||
// TODO: optimized management of updateSubscription data structure (no array with sequential access)
|
||||
updateSubscriptions.push({ 'id': accessory.id, 'characteristic': characteristic, 'accessory': accessory, 'onOff': onOff });
|
||||
}
|
||||
|
||||
module.exports.platform = FibaroHC2Platform;
|
||||
@@ -7,8 +7,8 @@
|
||||
},
|
||||
"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!"
|
||||
"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",
|
||||
@@ -74,7 +74,7 @@
|
||||
},
|
||||
{
|
||||
"accessory_type": "knxdevice",
|
||||
"description":"sample device with multiple services. Multiple services of different types are widely supported",
|
||||
"description": "sample device with multiple services. Multiple services of different types are widely supported",
|
||||
"name": "Office",
|
||||
"services": [
|
||||
{
|
||||
@@ -102,11 +102,11 @@
|
||||
"type": "WindowCovering",
|
||||
"description": "iOS9 Window covering (blinds etc) type, still WIP",
|
||||
"name": "Blinds",
|
||||
"Target": {
|
||||
"TargetPosition": {
|
||||
"Set": "1/2/3",
|
||||
"Listen": "1/2/4"
|
||||
},
|
||||
"Current": {
|
||||
"CurrentPosition": {
|
||||
"Set": "1/3/1",
|
||||
"Listen": "1/3/2"
|
||||
},
|
||||
@@ -115,22 +115,40 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},{
|
||||
"accessory_type": "knxdevice",
|
||||
|
||||
"description":"sample contact sensor device",
|
||||
"name": "Office",
|
||||
"services": [
|
||||
{
|
||||
"type": "ContactSensor",
|
||||
"name": "Office Door",
|
||||
"ContactSensorState": {
|
||||
"Listen": "5/3/5"
|
||||
},
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
}
|
||||
170
platforms/KNX.md
Normal file
170
platforms/KNX.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# Syntax of the config.json
|
||||
In the platforms section, you can insert a KNX type platform.
|
||||
You need to configure all devices directly in the config.json.
|
||||
````json
|
||||
"platforms": [
|
||||
{
|
||||
"platform": "KNX",
|
||||
"name": "KNX",
|
||||
"knxd_ip": "192.168.178.205",
|
||||
"knxd_port": 6720,
|
||||
"accessories": [
|
||||
{
|
||||
"accessory_type": "knxdevice",
|
||||
"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"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
````
|
||||
In the accessories section (the array within the brackets [ ]) you can insert as many objects as you like in the following form
|
||||
````json
|
||||
{
|
||||
"accessory_type": "knxdevice",
|
||||
"name": "Here goes your display name, this will be shown in HomeKit apps",
|
||||
"services": [
|
||||
{
|
||||
}
|
||||
]
|
||||
}
|
||||
````
|
||||
You have to add services in the following syntax:
|
||||
````json
|
||||
{
|
||||
"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",
|
||||
"CHARACTERISTIC1": {
|
||||
"Set": "1/1/6",
|
||||
"Listen": [
|
||||
"1/1/63"
|
||||
]
|
||||
},
|
||||
"CHARACTERISTIC2": {
|
||||
"Set": "1/1/62",
|
||||
"Listen": [
|
||||
"1/1/64"
|
||||
]
|
||||
}
|
||||
}
|
||||
````
|
||||
`CHARACTERISTICx` are properties that are dependent on the service type, so they are listed below.
|
||||
|
||||
Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group address, to which changes are sent if the service supports changing values. Changes on the bus are listened to, too.
|
||||
`"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
|
||||
|
||||
## ContactSensor
|
||||
- ContactSensorState: DPT 1.002, 0 as contact **OR**
|
||||
- ContactSensorStateContact1: DPT 1.002, 1 as contact
|
||||
|
||||
- StatusActive: DPT 1.011, 1 as true
|
||||
- StatusFault: DPT 1.011, 1 as true
|
||||
- StatusTampered: DPT 1.011, 1 as true
|
||||
- StatusLowBattery: DPT 1.011, 1 as true
|
||||
|
||||
## GarageDoorOpener
|
||||
- CurrentDoorState: DPT5 integer value in range 0..4
|
||||
// Characteristic.CurrentDoorState.OPEN = 0;
|
||||
// Characteristic.CurrentDoorState.CLOSED = 1;
|
||||
// Characteristic.CurrentDoorState.OPENING = 2;
|
||||
// Characteristic.CurrentDoorState.CLOSING = 3;
|
||||
// Characteristic.CurrentDoorState.STOPPED = 4;
|
||||
|
||||
- TargetDoorState: DPT5 integer value in range 0..1
|
||||
// Characteristic.TargetDoorState.OPEN = 0;
|
||||
// Characteristic.TargetDoorState.CLOSED = 1;
|
||||
|
||||
- ObstructionDetected: DPT1, 1 as true
|
||||
|
||||
- LockCurrentState: DPT5 integer value in range 0..3
|
||||
// Characteristic.LockCurrentState.UNSECURED = 0;
|
||||
// Characteristic.LockCurrentState.SECURED = 1;
|
||||
// Characteristic.LockCurrentState.JAMMED = 2;
|
||||
// Characteristic.LockCurrentState.UNKNOWN = 3;
|
||||
|
||||
- LockTargetState: DPT5 integer value in range 0..1
|
||||
// Characteristic.LockTargetState.UNSECURED = 0;
|
||||
// Characteristic.LockTargetState.SECURED = 1;
|
||||
|
||||
|
||||
|
||||
## Lightbulb
|
||||
- On: DPT 1.001, 1 as on, 0 as off
|
||||
- Brightness: DPT5.001 percentage, 100% (=255) the brightest
|
||||
|
||||
## LightSensor
|
||||
- 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
|
||||
|
||||
*ToDo here: correction of mappings, HomeKit reqires lock states UNSECURED=0, SECURED=1, JAMMED = 2, UNKNOWN=3*
|
||||
|
||||
## MotionSensor
|
||||
- MotionDetected: DPT 1.002, 1 as motion detected
|
||||
|
||||
- StatusActive: DPT 1.011, 1 as true
|
||||
- StatusFault: DPT 1.011, 1 as true
|
||||
- StatusTampered: DPT 1.011, 1 as true
|
||||
- StatusLowBattery: DPT 1.011, 1 as true
|
||||
|
||||
## Outlet
|
||||
- On: DPT 1.001, 1 as on, 0 as off
|
||||
- OutletInUse: DPT 1.011, 1 as on, 0 as off
|
||||
|
||||
## Switch
|
||||
- On: DPT 1.001, 1 as on, 0 as off
|
||||
|
||||
## TemperatureSensor
|
||||
- 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
|
||||
- CurrentHeatingCoolingState: DPT20.102 HVAC, because of the incompatible mapping only off and heating (=auto) are shown, [listen only]
|
||||
- TargetHeatingCoolingState: DPT20.102 HVAC, as above
|
||||
|
||||
## Window
|
||||
- CurrentPosition: DPT5.001 percentage
|
||||
- TargetPosition: DPT5.001 percentage
|
||||
- PositionState: DPT5.005 value [listen only: 0 Increasing, 1 Decreasing, 2 Stopped]
|
||||
|
||||
## WindowCovering
|
||||
- CurrentPosition: DPT5 percentage
|
||||
- TargetPosition: DPT5 percentage
|
||||
- PositionState: DPT5 value [listen only]
|
||||
|
||||
### not yet supported
|
||||
- HoldPosition
|
||||
- TargetHorizontalTiltAngle
|
||||
- TargetVerticalTiltAngle
|
||||
- CurrentHorizontalTiltAngle
|
||||
- CurrentVerticalTiltAngle
|
||||
- ObstructionDetected
|
||||
|
||||
|
||||
|
||||
|
||||
# DISCLAIMER
|
||||
**This is work in progress!**
|
||||
|
||||
@@ -89,11 +89,11 @@ ZWayServerPlatform.prototype = {
|
||||
//TODO: Unify this with getVDevServices, so there's only one place with mapping between service and vDev type.
|
||||
//Note: Order matters!
|
||||
var primaryDeviceClasses = [
|
||||
"switchBinary",
|
||||
"thermostat",
|
||||
"sensorBinary.Door/Window",
|
||||
"sensorMultilevel.Temperature",
|
||||
"switchMultilevel"
|
||||
"switchMultilevel",
|
||||
"switchBinary",
|
||||
"sensorBinary.Door/Window"
|
||||
];
|
||||
|
||||
var that = this;
|
||||
@@ -226,24 +226,24 @@ ZWayServerAccessory.prototype = {
|
||||
var typeKey = ZWayServerPlatform.getVDevTypeKey(vdev);
|
||||
var services = [], service;
|
||||
switch (typeKey) {
|
||||
case "switchBinary":
|
||||
services.push(new Service.Switch(vdev.metrics.title));
|
||||
break;
|
||||
case "switchMultilevel":
|
||||
services.push(new Service.Lightbulb(vdev.metrics.title));
|
||||
break;
|
||||
case "thermostat":
|
||||
case "thermostat":
|
||||
services.push(new Service.Thermostat(vdev.metrics.title));
|
||||
break;
|
||||
case "sensorMultilevel.Temperature":
|
||||
services.push(new Service.TemperatureSensor(vdev.metrics.title));
|
||||
break;
|
||||
case "sensorBinary.Door/Window":
|
||||
services.push(new Service.GarageDoorOpener(vdev.metrics.title));
|
||||
case "switchMultilevel":
|
||||
services.push(new Service.Lightbulb(vdev.metrics.title));
|
||||
break;
|
||||
case "battery.Battery":
|
||||
services.push(new Service.BatteryService(vdev.metrics.title));
|
||||
break;
|
||||
case "switchBinary":
|
||||
services.push(new Service.Switch(vdev.metrics.title));
|
||||
break;
|
||||
case "sensorBinary.Door/Window":
|
||||
services.push(new Service.GarageDoorOpener(vdev.metrics.title));
|
||||
break;
|
||||
case "sensorMultilevel.Luminiscence":
|
||||
services.push(new Service.LightSensor(vdev.metrics.title));
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user