mirror of
https://github.com/mtan93/homebridge.git
synced 2026-03-08 05:31:55 +00:00
673 lines
18 KiB
JavaScript
673 lines
18 KiB
JavaScript
var types = require("hap-nodejs/accessories/types.js");
|
||
|
||
|
||
function HomeMaticGenericChannel(log,platform, id ,name, type ,adress,special) {
|
||
this.name = name;
|
||
this.type = type;
|
||
this.adress = adress;
|
||
this.log = log;
|
||
this.platform = platform;
|
||
this.state = [];
|
||
this.eventupdate = false;
|
||
this.special = special;
|
||
this.currentStateCharacteristic = [];
|
||
this.datapointMappings = [];
|
||
}
|
||
|
||
|
||
|
||
|
||
HomeMaticGenericChannel.prototype = {
|
||
|
||
|
||
addValueMapping: function(dp,value,mappedvalue) {
|
||
if (this.datapointMappings[dp]==undefined) {
|
||
this.datapointMappings[dp] = [];
|
||
}
|
||
this.datapointMappings[dp][value] = mappedvalue;
|
||
} ,
|
||
|
||
// Return current States
|
||
query: function(dp,callback) {
|
||
var that = this;
|
||
|
||
if (this.state[dp] != undefined) {
|
||
callback(this.state[dp]);
|
||
} else {
|
||
// that.log("No cached Value found start fetching and send temp 0 back");
|
||
this.remoteGetValue(dp);
|
||
callback(0);
|
||
}
|
||
|
||
},
|
||
|
||
dpvalue:function(dp,fallback) {
|
||
if (this.state[dp] != undefined) {
|
||
return(this.state[dp]);
|
||
} else {
|
||
return fallback;
|
||
}
|
||
},
|
||
|
||
remoteGetValue:function(dp) {
|
||
var that = this;
|
||
that.platform.getValue(that.adress,dp,function(newValue) {
|
||
that.log("Remote Value Response for " + that.adress + "." + dp + "->" + newValue);
|
||
that.eventupdate = true;
|
||
that.cache(dp,newValue);
|
||
that.eventupdate = false;
|
||
});
|
||
},
|
||
|
||
|
||
event:function(dp,newValue) {
|
||
|
||
if (dp=="LEVEL") {
|
||
newValue = newValue*100;
|
||
}
|
||
|
||
this.eventupdate = true;
|
||
this.cache(dp,newValue);
|
||
this.eventupdate = false;
|
||
},
|
||
|
||
cache:function(dp,value) {
|
||
var that = this;
|
||
|
||
|
||
// Check custom Mapping from HM to HomeKit
|
||
var map = this.datapointMappings[dp];
|
||
if (map != undefined) {
|
||
this.log("Mapping found for " + dp);
|
||
if (map[value]!=undefined) {
|
||
this.log("Mapping found for " + dp + " " + value);
|
||
value = map[value];
|
||
}
|
||
}
|
||
|
||
if (that.currentStateCharacteristic[dp]!=undefined) {
|
||
that.currentStateCharacteristic[dp].updateValue(value, null);
|
||
}
|
||
this.state[dp] = value;
|
||
},
|
||
|
||
|
||
delayed: function(mode, dp,value,delay) {
|
||
|
||
if (this.eventupdate==true) {
|
||
return;
|
||
}
|
||
|
||
var timer = this.delayed[delay];
|
||
if( timer ) {
|
||
clearTimeout( timer );
|
||
}
|
||
|
||
this.log(this.name + " delaying command "+mode + " " + dp +" with value " + value);
|
||
var that = this;
|
||
this.delayed[delay] = setTimeout( function(){clearTimeout(that.delayed[delay]);that.command(mode,dp,value)}, delay?delay:100 );
|
||
},
|
||
|
||
command: function(mode,dp,value,callback) {
|
||
|
||
if (this.eventupdate==true) {
|
||
return;
|
||
}
|
||
var that = this;
|
||
|
||
if (mode == "set") {
|
||
//this.log("Send " + value + " to Datapoint " + dp + " at " + that.adress);
|
||
that.platform.setValue(that.adress,dp,value);
|
||
}
|
||
},
|
||
|
||
informationCharacteristics: function() {
|
||
return [
|
||
{
|
||
cType: types.NAME_CTYPE,
|
||
onUpdate: null,
|
||
perms: ["pr"],
|
||
format: "string",
|
||
initialValue: this.name,
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Name of the accessory",
|
||
designedMaxLength: 255
|
||
},{
|
||
cType: types.MANUFACTURER_CTYPE,
|
||
onUpdate: null,
|
||
perms: ["pr"],
|
||
format: "string",
|
||
initialValue: "EQ-3",
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Manufacturer",
|
||
designedMaxLength: 255
|
||
},{
|
||
cType: types.MODEL_CTYPE,
|
||
onUpdate: null,
|
||
perms: ["pr"],
|
||
format: "string",
|
||
initialValue: this.type,
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Model",
|
||
designedMaxLength: 255
|
||
},{
|
||
cType: types.SERIAL_NUMBER_CTYPE,
|
||
onUpdate: null,
|
||
perms: ["pr"],
|
||
format: "string",
|
||
initialValue: this.adress ,
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "SN",
|
||
designedMaxLength: 255
|
||
},{
|
||
cType: types.IDENTIFY_CTYPE,
|
||
onUpdate: null,
|
||
perms: ["pw"],
|
||
format: "bool",
|
||
initialValue: false,
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Identify Accessory",
|
||
designedMaxLength: 1
|
||
}
|
||
]
|
||
},
|
||
|
||
controlCharacteristics: function(that) {
|
||
|
||
cTypes = [{
|
||
cType: types.NAME_CTYPE,
|
||
onUpdate: null,
|
||
perms: ["pr"],
|
||
format: "string",
|
||
initialValue: this.name,
|
||
supportEvents: true,
|
||
supportBonjour: false,
|
||
manfDescription: "Name of service",
|
||
designedMaxLength: 255
|
||
}]
|
||
|
||
|
||
if (this.type=="SWITCH") {
|
||
cTypes.push({
|
||
cType: types.POWER_STATE_CTYPE,
|
||
onUpdate: function(value) {
|
||
that.command("set","STATE" , (value==1)?true:false)
|
||
},
|
||
|
||
onRead: function(callback) {
|
||
that.query("STATE",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["STATE"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("STATE");
|
||
},
|
||
|
||
perms: ["pw","pr","ev"],
|
||
format: "bool",
|
||
initialValue: that.dpvalue("STATE",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Change the power state",
|
||
designedMaxLength: 1
|
||
});
|
||
|
||
if (this.special=="OUTLET") {
|
||
cTypes.push({
|
||
cType: types.OUTLET_IN_USE_CTYPE,
|
||
|
||
onRead: function(callback) {
|
||
callback(true);
|
||
},
|
||
perms: ["pr","ev"],
|
||
format: "bool",
|
||
initialValue: true,
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Is Outlet in Use",
|
||
designedMaxLength: 1
|
||
})
|
||
}
|
||
}
|
||
|
||
|
||
if (this.type=="KEYMATIC") {
|
||
cTypes.push(
|
||
{
|
||
cType: types.CURRENT_LOCK_MECHANISM_STATE_CTYPE,
|
||
|
||
onRead: function(callback) {
|
||
that.query("STATE",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["STATE"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("STATE");
|
||
},
|
||
|
||
perms: ["pr","ev"],
|
||
format: "bool",
|
||
initialValue: that.dpvalue("STATE",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Current State of your Lock",
|
||
designedMaxLength: 1
|
||
},
|
||
{
|
||
cType: types.TARGET_LOCK_MECHANISM_STATE_CTYPE,
|
||
|
||
onUpdate: function(value) {
|
||
that.command("set","STATE",(value==1)?"true":"false")
|
||
},
|
||
|
||
onRead: function(callback) {
|
||
that.query("STATE",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.addValueMapping("STATE","1",0);
|
||
that.addValueMapping("STATE","0",1);
|
||
that.currentStateCharacteristic["STATE"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("STATE");
|
||
},
|
||
|
||
|
||
perms: ["pw","pr","ev"],
|
||
format: "bool",
|
||
initialValue: that.dpvalue("STATE",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Target State of your Lock",
|
||
designedMaxLength: 1
|
||
}
|
||
|
||
,
|
||
{
|
||
cType: types.TARGET_DOORSTATE_CTYPE,
|
||
|
||
onUpdate: function(value) {
|
||
that.command("set","OPEN" , "true")
|
||
},
|
||
|
||
onRead: function(callback) {
|
||
callback(1);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["OPEN"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
},
|
||
|
||
perms: ["pw","pr","ev"],
|
||
format: "bool",
|
||
initialValue: 1,
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Open the Lock",
|
||
designedMaxLength: 1
|
||
}
|
||
);
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
if (this.type=="DIMMER") {
|
||
cTypes.push({
|
||
cType: types.POWER_STATE_CTYPE,
|
||
onUpdate: function(value) {
|
||
that.command("set","LEVEL" , (value==true) ? "1" : "0")
|
||
},
|
||
|
||
onRead: function(callback) {
|
||
that.query("LEVEL",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["LEVEL"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("LEVEL");
|
||
},
|
||
|
||
perms: ["pw","pr","ev"],
|
||
format: "bool",
|
||
initialValue: (that.dpvalue("LEVEL")>0,0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Change the power state",
|
||
designedMaxLength: 1
|
||
},
|
||
{
|
||
cType: types.BRIGHTNESS_CTYPE,
|
||
onUpdate: function(value) {
|
||
that.delayed("set","LEVEL" , String(value/100),100);
|
||
},
|
||
|
||
onRead: function(callback) {
|
||
that.query("LEVEL",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["LEVEL"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("LEVEL");
|
||
},
|
||
|
||
|
||
perms: ["pw","pr","ev"],
|
||
format: "int",
|
||
initialValue: that.dpvalue("LEVEL",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Adjust Brightness of Light",
|
||
designedMinValue: 0,
|
||
designedMaxValue: 100,
|
||
designedMinStep: 1,
|
||
unit: "%"
|
||
});
|
||
}
|
||
|
||
|
||
|
||
if (this.type=="BLIND") {
|
||
cTypes.push(
|
||
{
|
||
cType: types.WINDOW_COVERING_CURRENT_POSITION_CTYPE,
|
||
|
||
onRead: function(callback) {
|
||
that.query("LEVEL",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["LEVEL"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("LEVEL");
|
||
},
|
||
|
||
perms: ["pr","ev"],
|
||
format: "int",
|
||
initialValue: that.dpvalue("LEVEL",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Current Blind Position",
|
||
designedMinValue: 0,
|
||
designedMaxValue: 100,
|
||
designedMinStep: 1,
|
||
unit: "%"
|
||
},
|
||
|
||
{
|
||
cType: types.WINDOW_COVERING_TARGET_POSITION_CTYPE,
|
||
|
||
onUpdate: function(value) {
|
||
that.delayed("set","LEVEL" , String(value/100),100);
|
||
},
|
||
|
||
|
||
onRead: function(callback) {
|
||
that.query("LEVEL",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["LEVEL"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("LEVEL");
|
||
},
|
||
|
||
perms: ["pw","pr","ev"],
|
||
format: "int",
|
||
initialValue: that.dpvalue("LEVEL",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Target Blind Position",
|
||
designedMinValue: 0,
|
||
designedMaxValue: 100,
|
||
designedMinStep: 1,
|
||
unit: "%"
|
||
},
|
||
{
|
||
cType: types.WINDOW_COVERING_OPERATION_STATE_CTYPE,
|
||
|
||
onRead: function(callback) {
|
||
that.query("DIRECTION",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["DIRECTION"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("DIRECTION");
|
||
},
|
||
|
||
perms: ["pr","ev"],
|
||
format: "int",
|
||
initialValue: that.dpvalue("DIRECTION",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Operating State ",
|
||
designedMinValue: 0,
|
||
designedMaxValue: 2,
|
||
designedMinStep: 1
|
||
}
|
||
|
||
);
|
||
}
|
||
|
||
// Simple Contact (Magnet)
|
||
|
||
if (this.type=="SHUTTER_CONTACT") {
|
||
cTypes.push(
|
||
{
|
||
cType: types.CONTACT_SENSOR_STATE_CTYPE,
|
||
|
||
onRead: function(callback) {
|
||
that.query("STATE",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["STATE"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("STATE");
|
||
},
|
||
|
||
perms: ["pr","ev"],
|
||
format: "bool",
|
||
initialValue: that.dpvalue("STATE",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Current State"
|
||
});
|
||
}
|
||
|
||
// Rotary Handle
|
||
if (this.type=="ROTARY_HANDLE_SENSOR") {
|
||
cTypes.push(
|
||
{
|
||
cType: types.CONTACT_SENSOR_STATE_CTYPE,
|
||
|
||
onRead: function(callback) {
|
||
that.query("STATE",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.addValueMapping("STATE","2",1);
|
||
that.currentStateCharacteristic["STATE"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("STATE");
|
||
},
|
||
|
||
perms: ["pr","ev"],
|
||
format: "bool",
|
||
initialValue: that.dpvalue("STATE",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Current State"
|
||
});
|
||
}
|
||
|
||
|
||
// Motion Detector
|
||
|
||
if (this.type=="MOTION_DETECTOR") {
|
||
cTypes.push(
|
||
{
|
||
cType: types.MOTION_DETECTED_CTYPE,
|
||
|
||
onRead: function(callback) {
|
||
that.query("MOTION",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["MOTION"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("MOTION");
|
||
},
|
||
|
||
perms: ["pr","ev"],
|
||
format: "bool",
|
||
initialValue: that.dpvalue("MOTION",0),
|
||
supportEvents: false,
|
||
supportBonjour: false,
|
||
manfDescription: "Current Motion State"
|
||
});
|
||
}
|
||
|
||
// Heating Device
|
||
|
||
if ((this.type=="CLIMATECONTROL_RT_TRANSCEIVER") || (this.type=="THERMALCONTROL_TRANSMIT")) {
|
||
|
||
cTypes.push({
|
||
cType: types.NAME_CTYPE,onUpdate: null,perms: ["pr"],format: "string",
|
||
initialValue: this.name,supportEvents: true,supportBonjour: false,manfDescription: "Name of service",designedMaxLength: 255
|
||
},
|
||
|
||
{
|
||
cType: types.CURRENTHEATINGCOOLING_CTYPE,onUpdate: null,
|
||
perms: ["pr"],format: "int",initialValue: 1,supportEvents: false,
|
||
supportBonjour: false,manfDescription: "Current Mode",designedMaxLength: 1,designedMinValue: 1,designedMaxValue: 1,designedMinStep: 1
|
||
},
|
||
|
||
{
|
||
cType: types.TARGETHEATINGCOOLING_CTYPE,onUpdate: null,perms: ["pw","pr"],
|
||
format: "int",initialValue: 1,supportEvents: false,supportBonjour: false,manfDescription: "Target Mode",
|
||
designedMinValue: 1,designedMaxValue: 1,designedMinStep: 1
|
||
},
|
||
|
||
{
|
||
cType: types.CURRENT_TEMPERATURE_CTYPE,
|
||
onUpdate: null,
|
||
|
||
onRead: function(callback) {
|
||
that.query("ACTUAL_TEMPERATURE",callback);
|
||
},
|
||
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["ACTUAL_TEMPERATURE"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("ACTUAL_TEMPERATURE");
|
||
},
|
||
perms: ["pw","pr","ev"], perms: ["pr"],format: "double",
|
||
initialValue: that.dpvalue("ACTUAL_TEMPERATURE",20),
|
||
supportEvents: false,supportBonjour: false,manfDescription: "Current Temperature",unit: "celsius"
|
||
},
|
||
|
||
{
|
||
cType: types.TARGET_TEMPERATURE_CTYPE,
|
||
onUpdate: function(value) {
|
||
//that.delayed("set", "SET_TEMPERATURE", value,500);
|
||
that.delayed("set", "MANU_MODE", value,500);
|
||
},
|
||
onRead: function(callback) {
|
||
that.query("SET_TEMPERATURE",callback);
|
||
|
||
},
|
||
onRegister: function(characteristic) {
|
||
that.currentStateCharacteristic["SET_TEMPERATURE"] = characteristic;
|
||
characteristic.eventEnabled = true;
|
||
that.remoteGetValue("SET_TEMPERATURE");
|
||
},
|
||
perms: ["pw","pr","ev"],format: "double",
|
||
initialValue: that.dpvalue("SET_TEMPERATURE",16),
|
||
supportEvents: false,supportBonjour: false, manfDescription: "Target Temperature",
|
||
designedMinValue: 16,designedMaxValue: 38,designedMinStep: 1,unit: "celsius"
|
||
},
|
||
|
||
{
|
||
cType: types.TEMPERATURE_UNITS_CTYPE,onRead: null,
|
||
perms: ["pr"],format: "int",initialValue: 0,supportEvents: false,
|
||
supportBonjour: false,manfDescription: "Current Temperature Unit",unit: "celsius"
|
||
}
|
||
|
||
);
|
||
}
|
||
|
||
|
||
return cTypes
|
||
},
|
||
|
||
sType: function() {
|
||
|
||
if (this.type=="SWITCH") {
|
||
|
||
if (this.special=="OUTLET") {
|
||
return types.OUTLET_STYPE;
|
||
} else {
|
||
return types.LIGHTBULB_STYPE;
|
||
}
|
||
}
|
||
|
||
if (this.type=="DIMMER") {
|
||
return types.LIGHTBULB_STYPE;
|
||
}
|
||
|
||
if (this.type=="BLIND") {
|
||
return types.WINDOW_COVERING_STYPE;
|
||
}
|
||
|
||
if ((this.type=="CLIMATECONTROL_RT_TRANSCEIVER") || (this.type=="THERMALCONTROL_TRANSMIT")) {
|
||
return types.THERMOSTAT_STYPE;
|
||
}
|
||
|
||
if ((this.type=="SHUTTER_CONTACT") ||(this.type=="ROTARY_HANDLE_SENSOR")) {
|
||
return types.CONTACT_SENSOR_STYPE;
|
||
}
|
||
|
||
if (this.type=="MOTION_DETECTOR") {
|
||
return types.MOTION_SENSOR_STYPE
|
||
}
|
||
|
||
|
||
if (this.type=="KEYMATIC") {
|
||
return types.LOCK_MECHANISM_STYPE
|
||
}
|
||
|
||
|
||
|
||
},
|
||
|
||
getServices: function() {
|
||
var that = this;
|
||
var services = [{
|
||
sType: types.ACCESSORY_INFORMATION_STYPE,
|
||
characteristics: this.informationCharacteristics(),
|
||
},
|
||
{
|
||
sType: this.sType(),
|
||
characteristics: this.controlCharacteristics(that)
|
||
}];
|
||
this.log("Loaded services for " + this.name)
|
||
return services;
|
||
}
|
||
};
|
||
|
||
|
||
module.exports = HomeMaticGenericChannel;
|