mirror of
https://github.com/mtan93/homebridge.git
synced 2026-03-08 05:31:55 +00:00
@@ -115,7 +115,15 @@
|
||||
"username": "your netatmo username",
|
||||
"password": "your netatmo password"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"platform": "HomeMatic",
|
||||
"name": "HomeMatic CCU",
|
||||
"ccu_ip": "192.168.0.100",
|
||||
"filter_device":[],
|
||||
"filter_channel":["BidCos-RF.KEQXXXXXXX:4", "BidCos-RF.LEQXXXXXXX:2"],
|
||||
"outlets":[ "BidCos-RF.KEQXXXXXXX:4","BidCos-RF.IEQXXXXXXX:1"]
|
||||
},
|
||||
],
|
||||
|
||||
"accessories": [
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"hap-nodejs": "^0.0.3",
|
||||
"harmonyhubjs-client": "^1.1.6",
|
||||
"harmonyhubjs-discover": "git+https://github.com/swissmanu/harmonyhubjs-discover.git",
|
||||
"homematic-xmlrpc": "git+https://github.com/hobbyquaker/homematic-xmlrpc",
|
||||
"isy-js": "",
|
||||
"komponist": "0.1.0",
|
||||
"lifx": "git+https://github.com/magicmonkey/lifxjs.git",
|
||||
|
||||
411
platforms/HomeMatic.js
Normal file
411
platforms/HomeMatic.js
Normal file
@@ -0,0 +1,411 @@
|
||||
"use strict";
|
||||
//
|
||||
// Homematic Platform Shim for HomeBridge
|
||||
//
|
||||
// V0.1 - 2015/10/29
|
||||
// - initial version
|
||||
// - reintegrated Homematic Platform fork from https://github.com/thkl/homebridge/tree/xmlrpc
|
||||
|
||||
|
||||
var types = require("hap-nodejs/accessories/types.js");
|
||||
var xmlrpc = require("homematic-xmlrpc");
|
||||
|
||||
var request = require("request");
|
||||
var http = require("http");
|
||||
var path = require("path");
|
||||
|
||||
var HomeMaticGenericChannel = require(path.resolve(__dirname, "HomematicChannel.js"));
|
||||
|
||||
|
||||
|
||||
function RegaRequest(log, ccuip) {
|
||||
this.log = log;
|
||||
this.ccuIP = ccuip;
|
||||
}
|
||||
|
||||
RegaRequest.prototype = {
|
||||
|
||||
script: function(script, callback) {
|
||||
|
||||
var post_options = {
|
||||
host: this.ccuIP,
|
||||
port: "80",
|
||||
path: "/tclrega.exe",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Content-Length": script.length
|
||||
}
|
||||
};
|
||||
|
||||
var post_req = http.request(post_options, function(res) {
|
||||
var data = "";
|
||||
res.setEncoding("binary");
|
||||
res.on("data", function(chunk) {
|
||||
data += chunk.toString();
|
||||
});
|
||||
res.on("end", function() {
|
||||
var pos = data.lastIndexOf("<xml><exec>");
|
||||
var response = (data.substring(0, pos));
|
||||
callback(response);
|
||||
});
|
||||
});
|
||||
|
||||
post_req.on("error", function(e) {
|
||||
callback("{}");
|
||||
});
|
||||
|
||||
post_req.write(script);
|
||||
post_req.end();
|
||||
|
||||
|
||||
},
|
||||
|
||||
getValue: function(channel, datapoint, callback) {
|
||||
var that = this;
|
||||
|
||||
var script = "var d = dom.GetObject(\"" + channel + "." + datapoint + "\");if (d){Write(d.State());}";
|
||||
//that.log("Rega Request " + script);
|
||||
this.script(script, function(data) {
|
||||
that.log("Rega Response" + data);
|
||||
if (data !== undefined) {
|
||||
callback(parseFloat(data));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setValue: function(channel, datapoint, value) {
|
||||
|
||||
var script = "var d = dom.GetObject(\"" + channel + "." + datapoint + "\");if (d){d.State(\"" + value + "\");}";
|
||||
//this.log("Rega Request " + script);
|
||||
this.script(script, function(data) {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function HomematicRPC(log, ccuip, platform) {
|
||||
this.log = log;
|
||||
this.ccuip = ccuip;
|
||||
this.platform = platform;
|
||||
this.server;
|
||||
this.client;
|
||||
this.stopping = false;
|
||||
this.localIP;
|
||||
}
|
||||
|
||||
HomematicRPC.prototype = {
|
||||
|
||||
|
||||
init: function() {
|
||||
var that = this;
|
||||
|
||||
var ip = this.getIPAddress();
|
||||
if (ip == "0.0.0.0") {
|
||||
that.log("Can not fetch IP");
|
||||
return;
|
||||
}
|
||||
|
||||
this.localIP = ip;
|
||||
this.log("Local IP: " + this.localIP);
|
||||
|
||||
this.server = xmlrpc.createServer({
|
||||
host: this.localIP,
|
||||
port: 9090
|
||||
});
|
||||
|
||||
this.server.on("NotFound", function(method, params) {
|
||||
that.log("Method " + method + " does not exist");
|
||||
});
|
||||
|
||||
this.server.on("system.listMethods", function(err, params, callback) {
|
||||
that.log("Method call params for 'system.listMethods': " + params);
|
||||
callback(null, ["system.listMethods", "system.multicall"]);
|
||||
});
|
||||
|
||||
|
||||
this.server.on("system.multicall", function(err, params, callback) {
|
||||
params.map(function(events) {
|
||||
try {
|
||||
events.map(function(event) {
|
||||
if ((event["methodName"] == "event") && (event["params"] !== undefined)) {
|
||||
var params = event["params"];
|
||||
var channel = "BidCos-RF." + params[1];
|
||||
var datapoint = params[2];
|
||||
var value = params[3];
|
||||
that.platform.foundAccessories.map(function(accessory) {
|
||||
if (accessory.adress == channel) {
|
||||
accessory.event(datapoint, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (err) {}
|
||||
});
|
||||
callback(null);
|
||||
});
|
||||
|
||||
this.log("XML-RPC server listening on port 9090");
|
||||
this.connect();
|
||||
|
||||
|
||||
process.on("SIGINT", function() {
|
||||
if (that.stopping) {
|
||||
return;
|
||||
}
|
||||
that.stopping = true;
|
||||
that.stop();
|
||||
});
|
||||
|
||||
process.on("SIGTERM", function() {
|
||||
if (that.stopping) {
|
||||
return;
|
||||
}
|
||||
that.stopping = true;
|
||||
that.stop();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
getIPAddress: function() {
|
||||
var interfaces = require("os").networkInterfaces();
|
||||
for (var devName in interfaces) {
|
||||
var iface = interfaces[devName];
|
||||
for (var i = 0; i < iface.length; i++) {
|
||||
var alias = iface[i];
|
||||
if (alias.family === "IPv4" && alias.address !== "127.0.0.1" && !alias.internal)
|
||||
return alias.address;
|
||||
}
|
||||
}
|
||||
return "0.0.0.0";
|
||||
},
|
||||
|
||||
getValue: function(channel, datapoint, callback) {
|
||||
|
||||
var that = this;
|
||||
if (this.client === undefined) {
|
||||
that.log("Returning cause client is invalid");
|
||||
return;
|
||||
}
|
||||
if (channel.indexOf("BidCos-RF.") > -1) {
|
||||
channel = channel.substr(10);
|
||||
this.client.methodCall("getValue", [channel, datapoint], function(error, value) {
|
||||
callback(value);
|
||||
});
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
setValue: function(channel, datapoint, value) {
|
||||
|
||||
var that = this;
|
||||
|
||||
if (this.client === undefined) return;
|
||||
|
||||
if (channel.indexOf("BidCos-RF.") > -1) {
|
||||
channel = channel.substr(10);
|
||||
}
|
||||
|
||||
this.client.methodCall("setValue", [channel, datapoint, value], function(error, value) {
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
connect: function() {
|
||||
var that = this;
|
||||
this.log("Creating Local HTTP Client for CCU RPC Events");
|
||||
this.client = xmlrpc.createClient({
|
||||
host: this.ccuip,
|
||||
port: 2001,
|
||||
path: "/"
|
||||
});
|
||||
this.log("CCU RPC Init Call on port 2001");
|
||||
this.client.methodCall("init", ["http://" + this.localIP + ":9090", "homebridge"], function(error, value) {
|
||||
that.log("CCU Response ....");
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
stop: function() {
|
||||
this.log("Removing Event Server");
|
||||
this.client.methodCall("init", ["http://" + this.localIP + ":9090"], function(error, value) {
|
||||
|
||||
});
|
||||
setTimeout(process.exit(0), 1000);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
function HomeMaticPlatform(log, config) {
|
||||
this.log = log;
|
||||
this.ccuIP = config["ccu_ip"];
|
||||
this.filter_device = config["filter_device"];
|
||||
this.filter_channel = config["filter_channel"];
|
||||
this.outlets = config["outlets"];
|
||||
|
||||
this.sendQueue = [];
|
||||
this.timer = 0;
|
||||
|
||||
this.foundAccessories = [];
|
||||
this.adressesToQuery = [];
|
||||
|
||||
this.xmlrpc = new HomematicRPC(this.log, this.ccuIP, this);
|
||||
this.xmlrpc.init();
|
||||
}
|
||||
|
||||
HomeMaticPlatform.prototype = {
|
||||
|
||||
|
||||
|
||||
accessories: function(callback) {
|
||||
this.log("Fetching Homematic devices...");
|
||||
var that = this;
|
||||
that.foundAccessories = [];
|
||||
|
||||
var script = "string sDeviceId;string sChannelId;boolean df = true;Write(\'{\"devices\":[\');foreach(sDeviceId, root.Devices().EnumIDs()){object oDevice = dom.GetObject(sDeviceId);if(oDevice){var oInterface = dom.GetObject(oDevice.Interface());if(df) {df = false;} else { Write(\',\');}Write(\'{\');Write(\'\"id\": \"\' # sDeviceId # \'\",\');Write(\'\"name\": \"\' # oDevice.Name() # \'\",\');Write(\'\"address\": \"\' # oDevice.Address() # \'\",\');Write(\'\"channels\": [\');boolean bcf = true;foreach(sChannelId, oDevice.Channels().EnumIDs()){object oChannel = dom.GetObject(sChannelId);if(bcf) {bcf = false;} else {Write(\',\');}Write(\'{\');Write(\'\"cId\": \' # sChannelId # \',\');Write(\'\"name\": \"\' # oChannel.Name() # \'\",\');if(oInterface){Write(\'\"address\": \"\' # oInterface.Name() #\'.'\ # oChannel.Address() # \'\",\');}Write(\'\"type\": \"\' # oChannel.HssType() # \'\"\');Write(\'}\');}Write(\']}\');}}Write(\']}\');";
|
||||
|
||||
var regarequest = new RegaRequest(this.log, this.ccuIP).script(script, function(data) {
|
||||
var json = JSON.parse(data);
|
||||
if (json["devices"] !== undefined) {
|
||||
json["devices"].map(function(device) {
|
||||
var isFiltered = false;
|
||||
|
||||
if ((that.filter_device !== undefined) && (that.filter_device.indexOf(device.address) > -1)) {
|
||||
isFiltered = true;
|
||||
} else {
|
||||
isFiltered = false;
|
||||
}
|
||||
// that.log('device address:', device.address);
|
||||
|
||||
if ((device["channels"] !== undefined) && (!isFiltered)) {
|
||||
|
||||
device["channels"].map(function(ch) {
|
||||
var isChannelFiltered = false;
|
||||
|
||||
if ((that.filter_channel !== undefined) && (that.filter_channel.indexOf(ch.address) > -1)) {
|
||||
isChannelFiltered = true;
|
||||
} else {
|
||||
isChannelFiltered = false;
|
||||
}
|
||||
// that.log('name', ch.name, ' -> address:', ch.address);
|
||||
if ((ch.address !== undefined) && (!isChannelFiltered)) {
|
||||
|
||||
if ((ch.type == "SWITCH") || (ch.type == "BLIND") || (ch.type == "SHUTTER_CONTACT") || (ch.type == "DIMMER") || (ch.type == "CLIMATECONTROL_RT_TRANSCEIVER") || (ch.type == "MOTION_DETECTOR") || (ch.type == "KEYMATIC")) {
|
||||
// Switch found
|
||||
// Check if marked as Outlet
|
||||
var special = (that.outlets.indexOf(ch.address) > -1) ? "OUTLET" : undefined;
|
||||
var accessory = new HomeMaticGenericChannel(that.log, that, ch.id, ch.name, ch.type, ch.address, special);
|
||||
that.foundAccessories.push(accessory);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
that.log(device.name + " has no address");
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
that.log(device.name + " has no channels or is filtered");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
accessory = new HomeMaticGenericChannel(that.log, that, "1234" , "DummyKM" , "KEYMATIC" , "1234");
|
||||
that.foundAccessories.push(accessory);
|
||||
|
||||
accessory = new HomeMaticGenericChannel(that.log, that, "5678" , "DummyBLIND" , "BLIND" , "5678");
|
||||
that.foundAccessories.push(accessory);
|
||||
|
||||
*/
|
||||
callback(that.foundAccessories);
|
||||
} else {
|
||||
callback(that.foundAccessories);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
setValue: function(channel, datapoint, value) {
|
||||
if (channel.indexOf("BidCos-RF.") > -1) {
|
||||
this.xmlrpc.setValue(channel, datapoint, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel.indexOf("VirtualDevices.") > -1) {
|
||||
var rega = new RegaRequest(this.log, this.ccuIP);
|
||||
rega.setValue(channel, datapoint, value);
|
||||
return;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
getValue: function(channel, datapoint, callback) {
|
||||
|
||||
if (channel.indexOf("BidCos-RF.") > -1) {
|
||||
this.xmlrpc.getValue(channel, datapoint, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel.indexOf("VirtualDevices.") > -1) {
|
||||
var rega = new RegaRequest(this.log, this.ccuIP);
|
||||
rega.getValue(channel, datapoint, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
prepareRequest: function(accessory, script) {
|
||||
var that = this;
|
||||
this.sendQueue.push(script);
|
||||
that.delayed(100);
|
||||
},
|
||||
|
||||
sendPreparedRequests: function() {
|
||||
var that = this;
|
||||
var script = "var d;";
|
||||
this.sendQueue.map(function(command) {
|
||||
script = script + command;
|
||||
});
|
||||
this.sendQueue = [];
|
||||
//this.log('RegaSend: ' + script);
|
||||
var regarequest = new RegaRequest(this.log, this.ccuIP).script(script, function(data) {});
|
||||
},
|
||||
|
||||
sendRequest: function(accessory, script, callback) {
|
||||
|
||||
var regarequest = new RegaRequest(this.log, this.ccuIP).script(script, function(data) {
|
||||
if (data !== undefined) {
|
||||
try {
|
||||
var json = JSON.parse(data);
|
||||
callback(json);
|
||||
} catch (err) {
|
||||
callback(undefined);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
delayed: function(delay) {
|
||||
var timer = this.delayed[delay];
|
||||
if (timer) {
|
||||
this.log("removing old command");
|
||||
clearTimeout(timer);
|
||||
}
|
||||
|
||||
var that = this;
|
||||
this.delayed[delay] = setTimeout(function() {
|
||||
clearTimeout(that.delayed[delay]);
|
||||
that.sendPreparedRequests();
|
||||
}, delay ? delay : 100);
|
||||
this.log("New Timer was set");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
module.exports.platform = HomeMaticPlatform;
|
||||
657
platforms/HomematicChannel.js
Normal file
657
platforms/HomematicChannel.js
Normal file
@@ -0,0 +1,657 @@
|
||||
"use strict";
|
||||
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.reverseDP = [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
HomeMaticGenericChannel.prototype = {
|
||||
|
||||
|
||||
// Return current States
|
||||
query: function(dp, callback) {
|
||||
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;
|
||||
},
|
||||
|
||||
reverse: function(value) {
|
||||
if (value == "true") return "false";
|
||||
if (value == "false") return "true";
|
||||
if (value === 0) return 1;
|
||||
if (value === 1) return 0;
|
||||
if (value == "0") return "1";
|
||||
if (value == "1") return "0";
|
||||
return value;
|
||||
},
|
||||
|
||||
cache: function(dp, value) {
|
||||
var that = this;
|
||||
|
||||
if ((that.reverseDP[dp] !== undefined) && (that.reverseDP[dp] === true)) {
|
||||
value = that.reverse(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) {
|
||||
|
||||
var 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.reverseDP["STATE"] = true;
|
||||
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
|
||||
}
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
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"
|
||||
});
|
||||
}
|
||||
|
||||
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"
|
||||
});
|
||||
}
|
||||
|
||||
if (this.type == "CLIMATECONTROL_RT_TRANSCEIVER") {
|
||||
|
||||
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: ["pr", "ev"],
|
||||
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);
|
||||
},
|
||||
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") {
|
||||
return types.THERMOSTAT_STYPE;
|
||||
}
|
||||
|
||||
if (this.type == "SHUTTER_CONTACT") {
|
||||
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;
|
||||
Reference in New Issue
Block a user