Merge branch 'nfarina/master' into zway-more-tags

This commit is contained in:
S'pht'Kr
2015-10-09 06:05:44 +02:00
12 changed files with 879 additions and 350 deletions

View File

@@ -152,15 +152,24 @@ HomeAssistantPlatform.prototype = {
entity = data[i]
entity_type = entity.entity_id.split('.')[0]
// ignore devices that are not in the list of supported types
if (that.supportedTypes.indexOf(entity_type) == -1) {
continue;
}
// ignore hidden devices
if (entity.attributes && entity.attributes.hidden) {
continue;
}
var accessory = null
if (entity_type == 'light') {
accessory = new HomeAssistantLight(that.log, entity, that)
}else if (entity_type == 'switch'){
console.log(JSON.stringify(entity))
console.log("");
console.log("");
accessory = new HomeAssistantSwitch(that.log, entity, that)
}else if (entity_type == 'scene'){
accessory = new HomeAssistantSwitch(that.log, entity, that, 'scene')

370
platforms/HomeSeer.js Normal file
View File

@@ -0,0 +1,370 @@
'use strict';
//
// HomeSeer Platform Shim for HomeBridge
// V0.1 - Jean-Michel Joudrier (stipus at stipus dot com) - 2015/10/07 - Initial version
//
//
// Remember to add platform to config.json.
//
// You can get HomeSeer Device References by clicking a HomeSeer device name, then
// choosing the Advanced Tab.
//
// Example:
// "platforms": [
// {
// "platform": "HomeSeer", // required
// "name": "HomeSeer", // required
// "url": "http://192.168.3.4:81", // required
// "accessories":[
// {
// "ref":8, // required - HomeSeer Device Reference (To get it, select the HS Device - then Advanced Tab)
// "type":"Lightbulb", // Optional - Lightbulb is the default
// "name":"My Light", // Optional - HomeSeer device name is the default
// "offValue":"0", // Optional - 0 is the default
// "onValue":"100", // Optional - 100 is the default
// "can_dim":true // Optional - true is the default - false for a non dimmable lightbulb
// },
// {
// "ref":9 // This is a dimmable Lightbulb by default
// },
// {
// "ref":58, // This is an controllable outlet
// "type":"Outlet"
// }
// ]
// }
// ],
//
//
// SUPORTED TYPES:
// - Lightbulb (can_dim, onValue, offValue options)
// - Fan (onValue, offValue options)
// - Switch (onValue, offValue options)
// - Outlet (onValue, offValue options)
// - TemperatureSensor
// - ContactSensor
// - MotionSensor
// - LeakSensor
// - LightSensor
// - OccupancySensor
// - SmokeSensor
// - Door
var Service = require("HAP-NodeJS").Service;
var Characteristic = require("HAP-NodeJS").Characteristic;
var request = require("request");
function httpRequest(url, method, callback) {
request({
url: url,
method: method
},
function (error, response, body) {
callback(error, response, body)
})
}
function HomeSeerPlatform(log, config){
this.log = log;
this.config = config;
}
HomeSeerPlatform.prototype = {
accessories: function(callback) {
this.log("Fetching HomeSeer devices.");
var refList = "";
for( var i=0; i<this.config.accessories.length; i++ ) {
refList = refList + this.config.accessories[i].ref;
if( i < this.config.accessories.length - 1 )
refList = refList + ",";
}
var that = this;
var foundAccessories = [];
var url = this.config["host"] + "/JSON?request=getstatus&ref=" + refList;
httpRequest( url, "GET", function(error, response, body) {
if (error) {
this.log('HomeSeer status function failed: %s', error.message);
callback( foundAccessories );
}
else {
this.log('HomeSeer status function succeeded!');
var response = JSON.parse( body );
for( var i=0; i<response.Devices.length; i++ ) {
var accessory = new HomeSeerAccessory( that.log, that.config, response.Devices[i] );
foundAccessories.push( accessory );
}
callback( foundAccessories );
}
}.bind(this));
}
}
function HomeSeerAccessory(log, platformConfig, status ) {
this.log = log;
this.ref = status.ref;
this.name = status.name
this.model = status.device_type_string;
this.onValue = "100";
this.offValue = "0";
this.control_url = platformConfig["host"] + "/JSON?request=controldevicebyvalue&ref=" + this.ref + "&value=";
this.status_url = platformConfig["host"] + "/JSON?request=getstatus&ref=" + this.ref;
for( var i=0; i<platformConfig.accessories.length; i++ ) {
if( platformConfig.accessories[i].ref == this.ref )
{
this.config = platformConfig.accessories[i];
break;
}
}
if( this.config.name )
this.name = this.config.name;
if( this.config.onValue )
this.onValue = this.config.onValue;
if( this.config.offValue )
this.offValue = this.config.offValue;
}
HomeSeerAccessory.prototype = {
identify: function(callback) {
callback();
},
setPowerState: function(powerOn, callback) {
var url;
if (powerOn) {
url = this.control_url + this.onValue;
this.log("Setting power state to on");
}
else {
url = this.control_url + this.offValue;
this.log("Setting power state to off");
}
httpRequest(url, 'GET', function(error, response, body) {
if (error) {
this.log('HomeSeer power function failed: %s', error.message);
callback(error);
}
else {
this.log('HomeSeer power function succeeded!');
callback();
}
}.bind(this));
},
getPowerState: function(callback) {
var url = this.status_url;
httpRequest(url, 'GET', function(error, response, body) {
if (error) {
this.log('HomeSeer get power function failed: %s', error.message);
callback( error, 0 );
}
else {
var status = JSON.parse( body );
var value = status.Devices[0].value;
this.log('HomeSeer get power function succeeded: value=' + value );
if( value == 0 )
callback( null, 0 );
else
callback( null, 1 );
}
}.bind(this));
},
setValue: function(level, callback) {
var url = this.control_url + level;
this.log("Setting value to %s", level);
httpRequest(url, 'GET', function(error, response, body) {
if (error) {
this.log('HomeSeer set value function failed: %s', error.message);
callback(error);
}
else {
this.log('HomeSeer set value function succeeded!');
callback();
}
}.bind(this));
},
getValue: function(callback) {
var url = this.status_url;
httpRequest(url, 'GET', function(error, response, body) {
if (error) {
this.log('HomeSeer get value function failed: %s', error.message);
callback( error, 0 );
}
else {
var status = JSON.parse( body );
var value = status.Devices[0].value;
this.log('HomeSeer get value function succeeded: value=' + value );
callback( null, value );
}
}.bind(this));
},
getServices: function() {
var services = []
var informationService = new Service.AccessoryInformation();
informationService
.setCharacteristic(Characteristic.Manufacturer, "HomeSeer")
.setCharacteristic(Characteristic.Model, this.model )
.setCharacteristic(Characteristic.SerialNumber, "HS " + this.config.type + " ref " + this.ref);
services.push( informationService );
switch( this.config.type ) {
case "Lightbulb": {
var lightbulbService = new Service.Lightbulb();
lightbulbService
.getCharacteristic(Characteristic.On)
.on('set', this.setPowerState.bind(this))
.on('get', this.getPowerState.bind(this));
if( this.config.can_dim == null || this.config.can_dim == true ) {
lightbulbService
.addCharacteristic(new Characteristic.Brightness())
.on('set', this.setValue.bind(this))
.on('get', this.getValue.bind(this));
}
services.push( lightbulbService );
break;
}
case "Fan": {
var fanService = new Service.Fan();
fanService
.getCharacteristic(Characteristic.On)
.on('set', this.setPowerState.bind(this))
.on('get', this.getPowerState.bind(this));
services.push( fanService );
break;
}
case "Switch": {
var switchService = new Service.Switch();
switchService
.getCharacteristic(Characteristic.On)
.on('set', this.setPowerState.bind(this))
.on('get', this.getPowerState.bind(this));
services.push( switchService );
break;
}
case "Outlet": {
var outletService = new Service.Outlet();
outletService
.getCharacteristic(Characteristic.On)
.on('set', this.setPowerState.bind(this))
.on('get', this.getPowerState.bind(this));
services.push( outletService );
break;
}
case "TemperatureSensor": {
var temperatureSensorService = new Service.TemperatureSensor();
temperatureSensorService
.getCharacteristic(Characteristic.CurrentTemperature)
.on('get', this.getValue.bind(this));
services.push( temperatureSensorService );
break;
}
case "ContactSensor": {
var contactSensorService = new Service.ContactSensor();
contactSensorService
.getCharacteristic(Characteristic.ContactSensorState)
.on('get', this.getPowerState.bind(this));
services.push( contactSensorService );
break;
}
case "MotionSensor": {
var motionSensorService = new Service.MotionSensor();
motionSensorService
.getCharacteristic(Characteristic.MotionDetected)
.on('get', this.getPowerState.bind(this));
services.push( motionSensorService );
break;
}
case "LeakSensor": {
var leakSensorService = new Service.LeakSensor();
leakSensorService
.getCharacteristic(Characteristic.LeakDetected)
.on('get', this.getPowerState.bind(this));
services.push( leakSensorService );
break;
}
case "LightSensor": {
var lightSensorService = new Service.LightSensor();
lightSensorService
.getCharacteristic(Characteristic.CurrentAmbientLightLevel)
.on('get', this.getValue.bind(this));
services.push( lightSensorService );
break;
}
case "OccupancySensor": {
var occupancySensorService = new Service.OccupancySensor();
motionSensorService
.getCharacteristic(Characteristic.OccupancyDetected)
.on('get', this.getPowerState.bind(this));
services.push( occupancySensorService );
break;
}
case "SmokeSensor": {
var smokeSensorService = new Service.SmokeSensor();
smokeSensorService
.getCharacteristic(Characteristic.SmokeDetected)
.on('get', this.getPowerState.bind(this));
services.push( smokeSensorService );
break;
}
case "Door": {
var doorService = new Service.Door();
doorService
.getCharacteristic(Characteristic.CurrentPosition)
.on('get', this.getValue.bind(this));
doorService
.getCharacteristic(Characteristic.TargetPosition)
.on('set', this.setValue.bind(this));
services.push( doorService );
break;
}
default:{
var lightbulbService = new Service.Lightbulb();
lightbulbService
.getCharacteristic(Characteristic.On)
.on('set', this.setPowerState.bind(this))
.on('get', this.getPowerState.bind(this));
lightbulbService
.addCharacteristic(new Characteristic.Brightness())
.on('set', this.setValue.bind(this))
.on('get', this.getValue.bind(this));
services.push( lightbulbService );
break;
}
}
return services;
}
}
module.exports.accessory = HomeSeerAccessory;
module.exports.platform = HomeSeerPlatform;

View File

@@ -1,154 +1,156 @@
{
"bridge": {
"name": "Homebridge",
"username": "CC:22:3D:E3:CE:30",
"port": 51826,
"pin": "031-45-154"
},
"description": "This is an example configuration file for KNX platform shim",
"hint": "Always paste into jsonlint.com validation page before starting your homebridge, saves a lot of frustration",
"hint2": "Replace all group addresses by current addresses of your installation, these are arbitrary examples!",
"hint3": "For valid services and their characteristics have a look at the knxdevice.md file in folder accessories!",
"platforms": [
{
"platform": "KNX",
"name": "KNX",
"knxd_ip": "192.168.178.205",
"knxd_port": 6720,
"accessories": [
{
"accessory_type": "knxdevice",
"description": "Only generic type knxdevice is supported, all previous knx types have been merged into that.",
"name": "Living Room North Lamp",
"services": [
{
"type": "Lightbulb",
"description": "iOS8 Lightbulb type, supports On (Switch) and Brightness",
"name": "Living Room North Lamp",
"On": {
"Set": "1/1/6",
"Listen": [
"1/1/63"
]
},
"Brightness": {
"Set": "1/1/62",
"Listen": [
"1/1/64"
]
}
}
],
"services-description": "Services is an array, you CAN have multiple service types in one accessory, though it is not fully supported in many iOS HK apps, such as EVE and myTouchHome"
},
{
"accessory_type": "knxdevice",
"name": "Office Temperature",
"description": "iOS8.4.1 TemperatureSensor type, supports CurrentTemperature",
"services": [
{
"type": "TemperatureSensor",
"name": "Raumtemperatur",
"CurrentTemperature": {
"Listen": "3/3/44"
}
}
]
},
{
"accessory_type": "knxdevice",
"name": "Office Window Lock",
"services": [
{
"type": "LockMechanism",
"description": "iOS8 Lock mechanism, Supports LockCurrentStateSecured0 OR LockCurrentState, LockTargetStateSecured0 OR LockTargetState, use depending if LOCKED is 0 or 1",
"name": "Office Window Lock",
"LockCurrentStateSecured0": {
"Listen": "5/3/15"
},
"LockTargetStateSecured0": {
"Listen": "5/3/15"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample device with multiple services. Multiple services of different types are widely supported",
"name": "Office",
"services": [
{
"type": "Lightbulb",
"name": "Office Lamp",
"On": {
"Set": "1/3/5"
}
},
{
"type": "Thermostat",
"description": "iOS8 Thermostat type, supports CurrentTemperature, TargetTemperature, CurrentHeatingCoolingState ",
"name": "Raumtemperatur",
"CurrentTemperature": {
"Listen": "3/3/44"
},
"TargetTemperature": {
"Set": "3/3/94"
},
"CurrentHeatingCoolingState": {
"Listen": "3/3/64"
}
},
{
"type": "WindowCovering",
"description": "iOS9 Window covering (blinds etc) type, still WIP",
"name": "Blinds",
"TargetPosition": {
"Set": "1/2/3",
"Listen": "1/2/4"
},
"CurrentPosition": {
"Set": "1/3/1",
"Listen": "1/3/2"
},
"PositionState": {
"Listen": "2/7/1"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample contact sensor device",
"name": "Office Contact",
"services": [
{
"type": "ContactSensor",
"name": "Office Door",
"ContactSensorState": {
"Listen": "5/3/5"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample garage door opener",
"name": "Office Garage",
"services": [
{
"type": "GarageDoorOpener",
"name": "Office Garage Opener",
"CurrentDoorState": {
"Listen": "5/4/5"
},
"TargetDoorState": {
"Listen": "5/4/6"
}
}
]
}
]
}
],
"accessories": []
"bridge": {
"name": "Homebridge",
"username": "CC:22:3D:E3:CE:30",
"port": 51826,
"pin": "031-45-154"
},
"description": "This is an example configuration file for KNX platform shim",
"hint": "Always paste into jsonlint.com validation page before starting your homebridge, saves a lot of frustration",
"hint2": "Replace all group addresses by current addresses of your installation, these are arbitrary examples!",
"hint3": "For valid services and their characteristics have a look at the KNX.md file in folder platforms!",
"platforms": [
{
"platform": "KNX",
"name": "KNX",
"knxd_ip": "192.168.178.205",
"knxd_port": 6720,
"accessories": [
{
"accessory_type": "knxdevice",
"description": "Only generic type knxdevice is supported, all previous knx types have been merged into that.",
"name": "Living Room North Lamp",
"services": [
{
"type": "Lightbulb",
"description": "iOS8 Lightbulb type, supports On (Switch) and Brightness",
"name": "Living Room North Lamp",
"On": {
"Set": "1/1/6",
"Listen": [
"1/1/63"
]
},
"Brightness": {
"Set": "1/1/62",
"Listen": [
"1/1/64"
]
}
}
],
"services-description": "Services is an array, you CAN have multiple service types in one accessory, though it is not fully supported in many iOS HK apps, such as EVE and myTouchHome"
},
{
"accessory_type": "knxdevice",
"name": "Office Temperature",
"description": "iOS8.4.1 TemperatureSensor type, supports CurrentTemperature",
"services": [
{
"type": "TemperatureSensor",
"name": "Raumtemperatur",
"CurrentTemperature": {
"Listen": "3/3/44"
}
}
]
},
{
"accessory_type": "knxdevice",
"name": "Office Window Lock",
"services": [
{
"type": "LockMechanism",
"description": "iOS8 Lock mechanism, Supports LockCurrentState, LockTargetState, append R to the addresses if LOCKED is 1",
"name": "Office Window Lock",
"LockCurrentState": {
"Listen": "5/3/15R"
},
"LockTargetState": {
"Listen": "5/3/16R"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample device with multiple services. Multiple services of different types are widely supported",
"name": "Office",
"services": [
{
"type": "Lightbulb",
"name": "Office Lamp",
"On": {
"Set": "1/3/5"
}
},
{
"type": "Thermostat",
"description": "iOS8 Thermostat type, supports CurrentTemperature, TargetTemperature, CurrentHeatingCoolingState ",
"name": "Raumtemperatur",
"CurrentTemperature": {
"Listen": "3/3/44"
},
"TargetTemperature": {
"Set": "3/3/94"
},
"CurrentHeatingCoolingState": {
"Listen": "3/3/64"
}
},
{
"type": "WindowCovering",
"description": "iOS9 Window covering (blinds etc) type, still WIP",
"name": "Blinds",
"TargetPosition": {
"Set": "1/2/3",
"Listen": "1/2/4"
},
"CurrentPosition": {
"Set": "1/3/1",
"Listen": "1/3/2"
},
"PositionState": {
"Listen": "2/7/1"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample contact sensor device",
"name": "Office Contact",
"services": [
{
"type": "ContactSensor",
"name": "Office Door",
"ContactSensorState": {
"Listen": "5/3/5"
}
}
]
},
{
"accessory_type": "knxdevice",
"description": "sample garage door opener",
"name": "Office Garage",
"services": [
{
"type": "GarageDoorOpener",
"name": "Office Garage Opener",
"CurrentDoorState": {
"Listen": "5/4/5"
},
"TargetDoorState": {
"Listen": "5/4/6"
}
}
]
}
]
}
],
"accessories": [
]
}

View File

@@ -116,8 +116,8 @@ function groupsocketlisten(opts, callback) {
}
var registerSingleGA = function registerSingleGA (groupAddress, callback) {
subscriptions.push({address: groupAddress, callback: callback });
var registerSingleGA = function registerSingleGA (groupAddress, callback, reverse) {
subscriptions.push({address: groupAddress, callback: callback, reverse:reverse });
}
/*
@@ -143,7 +143,7 @@ var startMonitor = function startMonitor(opts) { // using { host: name-ip, port
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);
subscriptions[i].callback(val, src, dest, type, subscriptions[i].reverse);
}
}
});
@@ -156,7 +156,7 @@ var startMonitor = function startMonitor(opts) { // using { host: name-ip, port
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);
subscriptions[i].callback(val, src, dest, type, subscriptions[i].reverse);
}
}
@@ -185,13 +185,16 @@ var registerGA = function (groupAddresses, callback) {
if (groupAddresses.constructor.toString().indexOf("Array") > -1) {
// handle multiple addresses
for (var i = 0; i < groupAddresses.length; i++) {
if (groupAddresses[i]) { // do not bind empty addresses
registerSingleGA (groupAddresses[i], callback);
if (groupAddresses[i] && groupAddresses[i].match(/(\d*\/\d*\/\d*)/)) { // do not bind empty addresses or invalid addresses
// clean the addresses
registerSingleGA (groupAddresses[i].match(/(\d*\/\d*\/\d*)/)[0], callback,groupAddresses[i].match(/\d*\/\d*\/\d*(R)/) ? true:false );
}
}
} else {
// it's only one
registerSingleGA (groupAddresses, callback);
if (groupAddresses.match(/(\d*\/\d*\/\d*)/)) {
registerSingleGA (groupAddresses.match(/(\d*\/\d*\/\d*)/)[0], callback, groupAddresses[i].match(/\d*\/\d*\/\d*(R)/) ? true:false);
}
}
// console.log("listeners now: " + subscriptions.length);
};

View File

@@ -47,7 +47,7 @@ You have to add services in the following syntax:
{
"type": "SERVICENAME",
"description": "This is just for you to remember things",
"name": "We need a name for each service, though it usually shows only if multiple services are present in one accessory",
"name": "beer tap thermostat",
"CHARACTERISTIC1": {
"Set": "1/1/6",
"Listen": [
@@ -68,11 +68,54 @@ Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group addres
`"Listen":["1/2/3","1/2/4","1/2/5"]` is an array of addresses that are listened to additionally. To these addresses never values get written, but the on startup the service will issue *KNX read requests* to ALL addresses listed in `Set:` and in `Listen:`
# Supported Services and their characteristics
For two characteristics there are additional minValue and maxValue attributes. These are CurrentTemperature and TargetTemperature, and are used in TemperatureSensor and Thermostat.
So the charcteristic section may look like:
````json
{
"type": "Thermostat",
"description": "Sample thermostat",
"name": "We need a name for each service, though it usually shows only if multiple services are present in one accessory",
"CurrentTemperature": {
"Set": "1/1/6",
"Listen": [
"1/1/63"
],
"minValue": -18,
"maxValue": 30
},
"TargetTemperature": {
"Set": "1/1/62",
"Listen": [
"1/1/64"
],
"minValue": -4,
"maxValue": 12
}
}
````
## reversal of values for characteristics
In general, all DPT1 types can be reversed. If you need a 1 for "contact" of a contact senser, you can append an "R" to the group address.
Likewise, all percentages of DPT5 can be reversed, if you need a 100% (=255) for window closed, append an "R" to the group address. Do not forget the listening addresses!
````json
{
"type": "ContactSensor",
"description": "Sample ContactSensor with 1 as contact (0 is Apple's default)",
"name": "WindowContact1",
"ContactSensorState": {
"Listen": [
"1/1/100R"
]
}
}
````
# Supported Services and their characteristics
## ContactSensor
- ContactSensorState: DPT 1.002, 0 as contact **OR**
- ContactSensorStateContact1: DPT 1.002, 1 as contact
- ContactSensorState: DPT 1.002, 0 as contact
- ~~ContactSensorStateContact1: DPT 1.002, 1 as contact~~
- StatusActive: DPT 1.011, 1 as true
- StatusFault: DPT 1.011, 1 as true
@@ -113,10 +156,10 @@ Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group addres
- 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
- LockCurrentState: DPT 1, 1 as secured
- ~~LockCurrentStateSecured0: DPT 1, 0 as secured~~
- LockTargetState: DPT 1, 1 as secured
- ~~LockTargetStateSecured0: DPT 1, 0 as secured~~
*ToDo here: correction of mappings, HomeKit reqires lock states UNSECURED=0, SECURED=1, JAMMED = 2, UNKNOWN=3*
@@ -136,11 +179,11 @@ Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group addres
- On: DPT 1.001, 1 as on, 0 as off
## TemperatureSensor
- CurrentTemperature: DPT9.001 in °C [listen only]
- 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
- CurrentTemperature: DPT9.001 in °C [listen only], -40 to 80°C if not overriden as shown above
- TargetTemperature: DPT9.001, values 0..40°C only, all others are ignored
- CurrentHeatingCoolingState: DPT20.102 HVAC, because of the incompatible mapping only off and heating (=auto) are shown, [listen only]
- TargetHeatingCoolingState: DPT20.102 HVAC, as above
@@ -152,7 +195,7 @@ Two kinds of addresses are supported: `"Set":"1/2/3"` is a writable group addres
## WindowCovering
- CurrentPosition: DPT5 percentage
- TargetPosition: DPT5 percentage
- PositionState: DPT5 value [listen only]
- PositionState: DPT5 value [listen only: 0 Closing, 1 Opening, 2 Stopped]
### not yet supported
- HoldPosition

View File

@@ -44,7 +44,11 @@ NestPlatform.prototype = {
function NestThermostatAccessory(log, name, device, deviceId) {
// device info
this.name = name;
if (name) {
this.name = name;
} else {
this.name = "Nest";
}
this.model = device.model_version;
this.serial = device.serial_number;
this.deviceId = deviceId;
@@ -390,4 +394,4 @@ NestThermostatAccessory.prototype = {
}
module.exports.accessory = NestThermostatAccessory;
module.exports.platform = NestPlatform;
module.exports.platform = NestPlatform;

View File

@@ -23,6 +23,7 @@ function YamahaAVRPlatform(log, config){
this.setMainInputTo = config["setMainInputTo"];
this.expectedDevices = config["expected_devices"] || 100;
this.discoveryTimeout = config["discovery_timeout"] || 30;
this.manualAddresses = config["manual_addresses"] || {};
this.browser = mdns.createBrowser(mdns.tcp('http'), {resolverSequence: sequence});
}
@@ -75,25 +76,44 @@ YamahaAVRPlatform.prototype = {
var accessories = [];
var timer, timeElapsed = 0, checkCyclePeriod = 5000;
browser.on('serviceUp', function(service){
// Hmm... seems we need to prevent double-listing via manual and Bonjour...
var sysIds = {};
var setupFromService = function(service){
var name = service.name;
//console.log('Found HTTP service "' + name + '"');
// We can't tell just from mdns if this is an AVR...
if (service.port != 80) return; // yamaha-nodejs assumes this, so finding one on another port wouldn't do any good anyway.
var yamaha = new Yamaha(service.host);
yamaha.getSystemConfig().then(function(sysConfig){
var sysModel = sysConfig.YAMAHA_AV.System[0].Config[0].Model_Name[0];
var sysId = sysConfig.YAMAHA_AV.System[0].Config[0].System_ID[0];
that.log("Found Yamaha " + sysModel + " - " + sysId + ", \"" + name + "\"");
var accessory = new YamahaAVRAccessory(that.log, that.config, service, yamaha, sysConfig);
accessories.push(accessory);
if(accessories.length >= this.expectedDevices)
timeoutFunction(); // We're done, call the timeout function now.
//callback([accessory]);
}, function(err){
return;
yamaha.getSystemConfig().then(
function(sysConfig){
var sysModel = sysConfig.YAMAHA_AV.System[0].Config[0].Model_Name[0];
var sysId = sysConfig.YAMAHA_AV.System[0].Config[0].System_ID[0];
if(sysIds[sysId]){
this.log("WARN: Got multiple systems with ID " + sysId + "! Omitting duplicate!");
return;
}
sysIds[sysId] = true;
this.log("Found Yamaha " + sysModel + " - " + sysId + ", \"" + name + "\"");
var accessory = new YamahaAVRAccessory(this.log, this.config, name, yamaha, sysConfig);
accessories.push(accessory);
if(accessories.length >= this.expectedDevices)
timeoutFunction(); // We're done, call the timeout function now.
}.bind(this)
);
}.bind(this);
// process manually specified devices...
for(var key in this.manualAddresses){
if(!this.manualAddresses.hasOwnProperty(key)) continue;
setupFromService({
name: key,
host: this.manualAddresses[key],
port: 80
});
});
}
browser.on('serviceUp', setupFromService);
browser.start();
// The callback can only be called once...so we'll have to find as many as we can
@@ -119,15 +139,15 @@ YamahaAVRPlatform.prototype = {
}
};
function YamahaAVRAccessory(log, config, mdnsService, yamaha, sysConfig) {
function YamahaAVRAccessory(log, config, name, yamaha, sysConfig) {
this.log = log;
this.config = config;
this.mdnsService = mdnsService;
this.yamaha = yamaha;
this.sysConfig = sysConfig;
this.name = mdnsService.name;
this.serviceName = mdnsService.name + " Speakers";
this.nameSuffix = config["name_suffix"] || " Speakers";
this.name = name;
this.serviceName = name + this.nameSuffix;
this.setMainInputTo = config["setMainInputTo"];
this.playVolume = this.config["play_volume"];
this.minVolume = config["min_volume"] || -50.0;