initial test version

This commit is contained in:
Snowdd1
2015-09-04 15:45:19 +02:00
parent dcc224f898
commit bad0ba0c3b
2 changed files with 386 additions and 0 deletions

180
accessories/knxlamp.js Normal file
View File

@@ -0,0 +1,180 @@
/*
* This is a demo KNX lamp accessory shim.
* It can switch a light on and off, and optionally set a brightness if configured to do so
*
*/
var Service = require("HAP-NodeJS").Service;
var Characteristic = require("HAP-NodeJS").Characteristic;
var knxd = require("eibd");
function KNXlampAccessory(log, config) {
this.log = log;
// knx information on object
this.group_address = config.group_address;
this.listen_addresses = config.listen_addresses; // supposed to be undefined, an array of strings, or single string
this.can_dim = config.can_dim; //supposed to be true or false
this.brightness_group_address = config.brightness_group_address;
this.brightness_listen_addresses = config.brightness_listen_addresses;
this.knxd_ip = config.knxd_ip ; // eg 127.0.0.1 if running on localhost
this.knxd_port = config.knxd_port || 6720; // eg 6720 default knxd port
}
module.exports = {
accessory: KNXlampAccessory
};
KNXlampAccessory.prototype = {
knxwrite: function(callback, groupAddress, dpt, value) {
// this.log("DEBUG in knxwrite");
var knxdConnection = new knxd.Connection();
// this.log("DEBUG in knxwrite: created empty connection, trying to connect socket to "+this.knxd_ip+":"+this.knxd_port);
knxdConnection.socketRemote({ host: this.knxd_ip, port: this.knxd_port }, function() {
var dest = knxd.str2addr(groupAddress);
// this.log("DEBUG got dest="+dest);
knxdConnection.openTGroup(dest, 1, function(err) {
if (err) {
this.log("[ERROR] knxwrite:openTGroup: " + err);
callback(err);
} else {
// this.log("DEBUG opened TGroup ");
var msg = knxd.createMessage('write', dpt, parseFloat(value));
knxdConnection.sendAPDU(msg, function(err) {
if (err) {
this.log("[ERROR] knxwrite:sendAPDU: " + err);
callback(err);
} else {
// this.log("knx data sent");
callback();
}
}.bind(this));
}
}.bind(this));
}.bind(this));
},
// issues a 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){
// this.log("DEBUG in knxread");
var knxdConnection = new knxd.Connection();
// this.log("DEBUG in knxread: created empty connection, trying to connect socket to "+this.knxd_ip+":"+this.knxd_port);
knxdConnection.socketRemote({ host: this.knxd_ip, port: this.knxd_port }, function() {
var dest = knxd.str2addr(groupAddress);
// this.log("DEBUG got dest="+dest);
knxdConnection.openTGroup(dest, 1, function(err) {
if (err) {
this.log("[ERROR] knxread:openTGroup: " + err);
} else {
// this.log("DEBUG knxread: opened TGroup ");
var msg = knxd.createMessage('read', 'DPT1', 0);
knxdConnection.sendAPDU(msg, function(err) {
if (err) {
this.log("[ERROR] knxread:sendAPDU: " + err);
} else {
this.log("knx request sent");
}
}.bind(this));
}
}.bind(this));
}.bind(this));
},
knxregister: function(addresses, characteristic) {
console.log("knx registering " + addresses);
knxd.registerGA(addresses, function(value){
// parameters do not match
this.log("Getting value from bus:"+value);
characteristic.setValue(value, undefined, 'fromKNXBus');
}.bind(this));
},
setPowerState: function(value, callback, context) {
if (context === 'fromKNXBus') {
this.log("event ping pong, exit!");
if (callback) {
callback();
}
} else {
console.log("Setting power to %s", value);
var numericValue = 0;
if (value) {
numericValue = 1; // need 0 or 1, not true or something
}
this.knxwrite(callback, this.group_address,'DPT1',numericValue);
}
},
setBrightness: function(value, callback, context) {
if (context === 'fromKNXBus') {
this.log("event ping pong, exit!");
if (callback) {
callback();
}
} else {
this.log("Setting brightness to %s", value);
var numericValue = 0;
if (value) {
numericValue = 255*value/100; // convert 1..100 to 1..255 for KNX bus
}
this.knxwrite(callback, this.brightness_group_address,'DPT5',numericValue);
}
},
identify: function(callback) {
this.log("Identify requested!");
callback(); // success
},
getServices: function() {
// you can OPTIONALLY create an information service if you wish to override
// the default values for things like serial number, model, etc.
var informationService = new Service.AccessoryInformation();
informationService
.setCharacteristic(Characteristic.Manufacturer, "Opensource Community")
.setCharacteristic(Characteristic.Model, "KNX Light Switch with or without dimmer")
.setCharacteristic(Characteristic.SerialNumber, "Version 1");
var lightbulbService = new Service.Lightbulb();
var onCharacteristic = lightbulbService
.getCharacteristic(Characteristic.On)
.on('set', this.setPowerState.bind(this));
onCharacteristic.supportsEventNotification=true;
// register with value update service
this.addresses = [this.group_address];
this.log("DEBUG1 this.addresses = "+this.addresses);
this.log("DEBUG2 this.listen_addresses = "+this.listen_addresses);
this.addresses = this.addresses.concat(this.listen_addresses || []); // do not join anything if empty (do not add undefined)
this.log("DEBUG3 this.addresses = "+this.addresses);
this.knxregister(this.addresses, onCharacteristic);
this.knxread(this.group_address); // issue a read request on the bus, maybe the device answers to that!
if (this.can_dim) {
var brightnessCharacteristic = lightbulbService
.addCharacteristic(new Characteristic.Brightness())
.on('set', this.setBrightness.bind(this));
// register with value update service
this.brightness_addresses = [this.brightness_group_address];
this.brightness_addresses.concat(this.brightness_listen_addresses || []); // do not join anything if empty (do not add undefined)
this.knxregister(this.brightness_addresses, brightnessCharacteristic);
this.knxread(this.brightness_group_address); // issue a read request on the bus, maybe the device answers to that!
}
knxd.startMonitor({ host: this.knxd_ip, port: this.knxd_port });
return [informationService, lightbulbService];
}
};

206
platforms/KNX.js Normal file
View File

@@ -0,0 +1,206 @@
/** Sample platform outline
* based on Sonos platform
*/
'use strict';
var types = require("HAP-NodeJS/accessories/types.js");
//var hardware = require('myHardwareSupport'); //require any additional hardware packages
var Connection = require('eibd').connection;
function KNXPlatform(log, config){
this.log = log;
this.config = config;
// this.property1 = config.property1;
// this.property2 = config.property2;
// initiate connection to bus for listening ==> done with first shim
};
MyPlatform.prototype = {
accessories: function(callback) {
this.log("Fetching myPlatform devices.");
var that = this;
// iterate through all devices the platform my offer
// for each device, create an accessory
// read accessories from file !!!!!
var foundAccessories = this.config.accessories;
//create array of accessories
var myAccessories = [];
for (var int = 0; int < foundAccessories.length; int++) {
// instantiate and push to array
if (foundAccessories[i].accessory-type === "knxlamp") {
myAccessories.push(new require('../accessories/knxlamp.js').accessory(this.log,foundAccessories[i]));
} else {
// do something else
this.log("unkown accessory type found")
} //etc.
};
// if done, return the array to callback function
callback(myAccessories);
}
};
// the signature of the constructor has to be adopted to the accessory you need in your platform! These are the first lines from the sonos platform
function myAccessoryType1(log, config, device, description /* add or remove parms as you need*/ ) {
this.log = log;
this.config = config;
this.device = device;
this.description = description;
// more initialization if required
}
myAccessoryType1.prototype = {
// see https shim wiki page for details. Accessory definition is discussed there.
}
// more
/**
* The buscallbacks module is to expose a simple function to listen on the bus and register callbacks for value changes
* of registered addresses.
*
* Usage:
* You can start the monitoring process at any time
startMonitor({host: name-ip, port: port-num });
* You can add addresses to the subscriptions using
registerGA(groupAddress, callback)
* groupAddress has to be an groupAddress in common knx notation string '1/2/3'
* the callback has to be a
* var f = function(value) { handle value update;}
* so you can do a
* registerGA('1/2/3', function(value){
* console.log('1/2/3 got a hit with '+value);
* });
* but of course it is meant to be used programmatically, not literally, otherwise it has no advantage
*
* You can also use arrays of addresses if your callback is supposed to listen to many addresses:
registerGA(groupAddresses[], callback)
* as in
* registerGA(['1/2/3','1/0/0'], function(value){
* console.log('1/2/3 or 1/0/0 got a hit with '+value);
* });
* if you are having central addresses like "all lights off" or additional response objects
*
*
* callbacks can have a signature of
* function(value, src, dest, type) but do not have to support these parameters (order matters)
* src = physical address such as '1.1.20'
* dest = groupAddress hit (you subscribed to that address, remember?), as '1/2/3'
* type = Data point type, as 'DPT1'
*
*
*/
// array of registered addresses and their callbacks
var subscriptions = [];
// check variable to avoid running two listeners
var running;
function groupsocketlisten(opts, callback) {
var conn = Connection();
conn.socketRemote(opts, function() {
conn.openGroupSocket(0, callback);
});
}
var registerSingleGA = function registerSingleGA (groupAddress, callback) {
subscriptions.push({address: groupAddress, callback: callback });
}
/*
* public busMonitor.startMonitor()
* starts listening for telegrams on KNX bus
*
*/
var startMonitor = function startMonitor(opts) { // using { host: name-ip, port: port-num } options object
if (!running) {
running = true;
} else {
return null;
}
groupsocketlisten(opts, function(parser) {
//console.log("knxfunctions.read: in callback parser");
parser.on('write', function(src, dest, type, val){
// search the registered group addresses
for (var i = 0; i < subscriptions.length; i++) {
// iterate through all registered addresses
if (subscriptions[i].address === dest) {
// found one, notify
//console.log('HIT: Write from '+src+' to '+dest+': '+val+' ['+type+']');
subscriptions[i].callback(val, src, dest, type);
}
}
});
parser.on('response', function(src, dest, type, val) {
// search the registered group addresses
for (var i = 0; i < subscriptions.length; i++) {
// iterate through all registered addresses
if (subscriptions[i].address === dest) {
// found one, notify
//console.log('HIT: Response from '+src+' to '+dest+': '+val+' ['+type+']');
subscriptions[i].callback(val, src, dest, type);
}
}
});
//dont care about reads here
// parser.on('read', function(src, dest) {
// console.log('Read from '+src+' to '+dest);
// });
//console.log("knxfunctions.read: in callback parser at end");
}); // groupsocketlisten parser
}; //startMonitor
/*
* public registerGA(groupAdresses[], callback(value))
* parameters
* callback: function(value, src, dest, type) called when a value is sent on the bus
* groupAddresses: (Array of) string(s) for group addresses
*
*
*
*/
var registerGA = function (groupAddresses, callback) {
// check if the groupAddresses is an array
if (groupAddresses.constructor.toString().indexOf("Array") > -1) {
// handle multiple addresses
for (var i = 0; i < groupAddresses.length; i++) {
registerSingleGA (groupAddresses[i], callback);
}
} else {
// it's only one
registerSingleGA (groupAddresses, callback);
}
};
module.exports.platform = myPlatform;
module.exports.registerGA = registerGA;
module.exports.startMonitor = startMonitor;