homebridge-gsh-kazari
Version:
775 lines (713 loc) • 28.8 kB
JavaScript
'use strict';
var request = require('requestretry');
var hapRequest = require('./lib/hapRequest.js');
var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;
var debug = require('debug')('hapNodeJSClient');
var bonjour = require('bonjour-hap')();
var ip = require('ip');
var normalizeUUID = require('./lib/util.js').normalizeUUID;
var discovered = [];
var mdnsCache = {};
var populateCache = false;
var filter = false;
var pins = {};
module.exports = {
HAPNodeJSClient: HAPNodeJSClient
};
/**
* HAPNodeJSClient - Client for Homebridge and HAP-NodeJS in insecure mode.
*
* Events
*
* @class
* @param {type} options description
* @Type {object}
* @property {boolean} debug - Enable debug logging, defaults to false
* @property {string} pin - Homebridge PIN, defaults to '031-45-154'
* @property {number} refresh - Discovery refresh, defaults to 15 minutes
* @property {number} timeout - Discovery timeout, defaults to 20 seconds
* @property {number} reqTimeout - Accessory request timeout, defaults to 7 seconds
* @example
*
*/
function HAPNodeJSClient(options) {
// console.log('Options', options);
this.debug = options.debug || false;
this.refresh = options.refresh || 900;
this.timeout = options.timeout || 20;
this.reqTimeout = options.reqTimeout || 7000;
this.RegisterPin('default', options.pin || '031-45-154');
filter = options.filter || false;
if (this.debug) {
let debugEnable = require('debug');
let namespaces = debugEnable.disable();
// this.log('DEBUG-1', namespaces);
if (namespaces) {
namespaces = namespaces + ',hap*';
} else {
namespaces = 'hap*';
}
// this.log('DEBUG-2', namespaces);
debugEnable.enable(namespaces);
}
this.eventRegistry = {};
_discovery.call(this);
this._eventBus = new EventEmitter();
setInterval(_discovery.bind(this), this.refresh * 1000);
/**
* HomeKit Accessory Characteristic event pass thru
*
* @event HAPNodeJSClient#Disconnected
* @Type {object}
* @property {string} server - IP Address and port of disconnected homebridge
* @example Sample Message
*
* { host: '192.168.1.4', port: 51826, aid: 16, iid: 11, status: false }
*/
this._eventBus.on('Disconnected', _reconnectServer.bind(this));
this._eventBus.on('Event', function(events) {
debug('Events', JSON.stringify(events));
/**
* HomeKit Accessory Characteristic event pass thru
*
* @event HAPNodeJSClient#hapEvent
* @Type {object}
* @property {string} host - IP Address of homebridge instance generating event
* @property {number} port - Port of homebridge instance generating event
* @property {number} deviceID - deviceID of homebridge instance generating event
* @property {number} aid - Accessory ID of accessory generating event
* @property {number} iid - Instance ID of accessory characteristic generating event
* @property {object} value - Updated characteristic value
* @example Sample Message
*
* [{"host":"192.168.1.13","port":43787,"deviceID":"76:59:CE:25:B9:6E","aid":1,"iid":13,"value":true,"status":true}]
*/
this.emit('hapEvent', events);
this.emit(events[0].host + events[0].port + events[0].aid, events);
events.forEach(function(event) {
// debug('hapEvent', event.host + event.port + event.aid + event.iid, event);
this.emit(event.host + event.port + event.aid + event.iid, event);
this.emit(event.deviceID + event.aid + event.iid, event);
}.bind(this));
}.bind(this));
// debug('This', this);
}
inherits(HAPNodeJSClient, EventEmitter);
function _discovery() {
debug('Starting Homebridge instance discovery');
discovered = [];
// debug('this-0', this);
_populateCache(this.timeout, _getAccessories, function() {
debug('Ready');
this.emit('Ready', discovered);
}.bind(this));
}
function _mdnsLookup(deviceID, callback) {
// debug('\nmdnsLookup start', serviceName);
if (mdnsCache[deviceID]) {
// debug('cached', mdnsCache[serviceName].url);
callback(null, mdnsCache[deviceID]);
} else {
_populateCache(4, null, function() {
if (mdnsCache[deviceID]) {
// debug('refreshed', mdnsCache[deviceID]);
callback(null, mdnsCache[deviceID]);
} else {
callback(new Error('ERROR: HB Instance not found', deviceID), null);
}
});
}
}
function _mdnsError(deviceID) {
// debug('\_mdnsError ', deviceID);
mdnsCache[deviceID] = false;
_populateCache(4, null, function() {
if (mdnsCache[deviceID]) {
// debug('refreshed', mdnsCache[deviceID]);
}
});
}
function _populateCache(timeout, discovery, callback) {
// debug('_populateCache', populateCache);
if (!populateCache) {
populateCache = true;
// debug('_populateCache', new Error().stack);
var browser = bonjour.find({
type: 'hap'
}, function(result) {
if (result.txt) {
debug('HAP Device discovered', result.name);
var ipAddress, url;
for (const address of result.addresses) {
if (ip.isV4Format(address) && address.substring(0, 7) !== '169.254') {
ipAddress = address;
url = 'http://' + ipAddress + ':' + result.port;
break;
} else if (ip.isV6Format(address)) {
ipAddress = address;
url = 'http://[' + ipAddress + ']:' + result.port;
}
}
// debug('result', result);
mdnsCache[result.txt.id] = {
host: ipAddress,
port: result.port,
url: url,
deviceID: result.txt.id,
txt: result.txt
};
// debug('HAP Device address %s -> ', result.name, mdnsCache[result.txt.id]);
// debug('discovery', discovery);
if (discovery) {
discovery.call(this, mdnsCache[result.txt.id], function() {});
}
} else {
debug('Unsupported device found, skipping', result.name);
}
});
setTimeout(function() {
// debug('Timeout:');
browser.stop();
populateCache = false;
callback();
}, timeout * 1000);
} else {
callback();
}
}
function _findPinByKey(key) {
if (!key) {
return pins['default'];
}
key = key.toLowerCase();
return pins[key] || pins['default'];
}
/**
* HAPNodeJSClient.prototype.RegisterPin - Register pin numbers ()
*
* @class
* @param {type} key Unique identifier of homebridge instance (ip:port or deviceID)
* @param {type} pin Homebridge PIN
* @return {type} bool updated
*/
HAPNodeJSClient.prototype.RegisterPin = function(key, pin) {
if (!key || (key in pins && pins[key] === pin)) {
return false;
}
key = key.toLowerCase();
pins[key] = pin;
debug('Registered/updated PIN for `%s`: %s', key, pin);
return true;
};
/**
* HAPNodeJSClient.prototype.HAPaccessories - Returns an array of all homebridge instances, and the accessories for each.
*
* @class
* @param {type} callback description
* @return {type} description
*/
HAPNodeJSClient.prototype.HAPaccessories = function(callback) {
// This is a callback as in the future may need to call something
callback(discovered);
};
// curl -X PUT http://127.0.0.1:51826/characteristics --header "Content-Type:Application/json"
// --header "authorization: 031-45-154" --data "{ \"characteristics\": [{ \"aid\": 2, \"iid\": 9, \"value\": 0}] }"
/**
* HAPNodeJSClient.prototype.HAPcontrolByDeviceID - Send a characteristic PUT Message to a particular homebridge instance
*
* @param {type} deviceID deviceID of homebridge instance
* @param {type} body An array of HomeKit characteristic updates, [{ \"aid\": 2, \"iid\": 9, \"value\": 0}]
* @param {type} callback Callback to execute upon completion of characteristic setting, function(err, response)
*/
HAPNodeJSClient.prototype.HAPcontrolByDeviceID = function(deviceID, body, callback) {
_mdnsLookup(deviceID, function(err, instance) {
if (err) {
callback(err);
} else {
HAPNodeJSClient.prototype.HAPcontrol.call(this, instance.host, instance.port, body, function(err, response) {
if (err) {
_mdnsError(deviceID);
}
callback(err, response);
}, instance);
}
}.bind(this));
};
/**
* HAPNodeJSClient.prototype.HAPcontrol - Send a characteristic PUT Message to a particular homebridge instance
*
* @param {type} ipAddress IP Address of homebridge instance
* @param {type} port Port of homebridge instance
* @param {type} body An array of HomeKit characteristic updates, [{ \"aid\": 2, \"iid\": 9, \"value\": 0}]
* @param {type} callback Callback to execute upon completion of characteristic setting, function(err, response)
*/
HAPNodeJSClient.prototype.HAPcontrol = function(ipAddress, port, body, callback, instance) {
var pin = _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port);
request({
eventBus: this._eventBus,
method: 'PUT',
url: 'http://' + ipAddress + ':' + port + '/characteristics',
timeout: this.reqTimeout,
maxAttempts: 5, // (default) try 5 times
headers: {
'Content-Type': 'Application/json',
'authorization': pin,
'connection': 'keep-alive'
},
body: body
}, function(err, response) {
// Response s/b 200 OK
if (err) {
debug('Homebridge Control failed %s:%s', ipAddress, port, body, err.message);
callback(err);
} else if (response.statusCode !== 207 && response.statusCode !== 204) {
if (response.statusCode === 401 || response.statusCode === 470) {
debug('Homebridge auth failed, invalid PIN %s %s:%s', pin, ipAddress, port, body, err, response.body);
callback(new Error('Homebridge auth failed, invalid PIN ' + pin));
} else {
debug('Homebridge Control failed %s:%s Status: %s ', ipAddress, port, response.statusCode, body, err, response.body);
callback(new Error('Homebridge control failed'));
}
} else {
var rsp;
if (response.statusCode !== 204) {
try {
rsp = JSON.parse(response.body);
} catch (ex) {
debug('Homebridge Response Failed %s:%s', ipAddress, port, response.statusCode, response.statusMessage);
debug('Homebridge Response Failed %s:%s', ipAddress, port, response.body, ex);
callback(new Error(ex));
return;
}
}
callback(null, rsp);
}
}.bind(this));
};
/**
* _reconnectServer - Reconnect to event server
*
* @param {type} server IP Address and port of disconnected homebridge server
* @return {type} description
*/
function _reconnectServer(server) {
debug('HAPevent events Reregister', server);
// debug('This', this, server);
var events = [];
this.eventRegistry[server.deviceID].forEach(function(device) {
events.push({
deviceID: server.deviceID,
aid: device.aid,
iid: device.iid,
status: -70402
});
});
this.emit('hapEvent', events);
// this.emit(events[0].host + events[0].port + events[0].aid, events);
events.forEach(function(event) {
// debug('hapEvent', event.host + event.port + event.aid + event.iid, event);
// this.emit(event.host + event.port + event.aid + event.iid, event);
this.emit(event.deviceID + event.aid + event.iid, event);
}.bind(this));
var reconnectTimer;
if (server.deviceID) {
reconnectTimer = setInterval(function() {
this.HAPeventByDeviceID(server.deviceID, JSON.stringify({
characteristics: this.eventRegistry[server.deviceID]
}), clearTimer.bind(this));
}.bind(this), 60000);
} else {
reconnectTimer = setInterval(function() {
this.HAPevent(server.server.split(':')[0], server.server.split(':')[1], JSON.stringify({
characteristics: this.eventRegistry[server.server]
}), clearTimer.bind(this));
}.bind(this), 60000);
}
function clearTimer(err, rsp) {
var events = [];
if (err) {
debug('HAPevent event reregister failed, retry in 60', server);
/*
*
* [{"host":"192.168.1.13","port":43787,"deviceID":"76:59:CE:25:B9:6E","aid":1,"iid":13,"value":true,"status":true}]
*/
debug('clearTimer', server, this.eventRegistry[server.deviceID]);
this.eventRegistry[server.deviceID].forEach(function(device) {
events.push({
deviceID: server.deviceID,
aid: device.aid,
iid: device.iid,
status: -70402
});
});
this.emit('hapEvent', events);
// this.emit(events[0].host + events[0].port + events[0].aid, events);
events.forEach(function(event) {
// debug('hapEvent', event.host + event.port + event.aid + event.iid, event);
// this.emit(event.host + event.port + event.aid + event.iid, event);
this.emit(event.deviceID + event.aid + event.iid, event);
}.bind(this));
} else {
debug('HAPevent event reregister succeeded', server);
this.eventRegistry[server.deviceID].forEach(function(device) {
events.push({
deviceID: server.deviceID,
aid: device.aid,
iid: device.iid,
status: true
});
});
this.emit('hapEvent', events);
// this.emit(events[0].host + events[0].port + events[0].aid, events);
events.forEach(function(event) {
// debug('hapEvent', event.host + event.port + event.aid + event.iid, event);
// this.emit(event.host + event.port + event.aid + event.iid, event);
this.emit(event.deviceID + event.aid + event.iid, event);
}.bind(this));
clearInterval(reconnectTimer);
}
}
}
/**
* HAPNodeJSClient.prototype.HAPeventByDeviceID - Send a characteristic PUT Message to a particular homebridge instance, this maintains a socket connection for use in returning Events
*
* @param {type} deviceID deviceID homebridge instance
* @param {type} body An array of HomeKit characteristic updates, [{ \"aid\": 2, \"iid\": 9, \"value\": 0}]
* @param {type} callback Callback to execute upon completion of characteristic setting, function(err, response)
*/
HAPNodeJSClient.prototype.HAPeventByDeviceID = function(deviceID, body, callback) {
// console.log('This-0', this);
_mdnsLookup(deviceID, function(err, instance) {
// debug('This-1', instance);
if (err) {
callback(err);
} else {
var pin = _findPinByKey(deviceID);
hapRequest({
eventBus: this._eventBus,
method: 'PUT',
deviceID: deviceID,
url: 'http://' + instance.host + ':' + instance.port + '/characteristics',
timeout: this.reqTimeout,
maxAttempts: 5, // (default) try 5 times
headers: {
'Content-Type': 'Application/json',
'authorization': pin,
'connection': 'keep-alive'
},
body: body
}, function(err, response) {
// Response s/b 200 OK
if (err) {
debug('Homebridge event reg failed %s:%s', instance.host, instance.port, body, err.message);
_mdnsError(deviceID);
callback(err);
} else if (response.statusCode !== 207 && response.statusCode !== 204) {
if (response.statusCode === 401 || response.statusCode === 470) {
debug('Homebridge auth failed, invalid PIN %s', pin, deviceID, body, err, response.body);
_mdnsError(deviceID);
callback(new Error('Homebridge auth failed, invalid PIN ' + pin));
} else {
debug('Homebridge event reg failed %s:%s Status: %s ', deviceID, response.statusCode, body, err, response.body);
_mdnsError(deviceID);
callback(new Error('Homebridge event reg failed'));
}
} else {
var rsp;
if (!this.eventRegistry[deviceID]) {
this.eventRegistry[deviceID] = [];
}
// debug('1', JSON.parse(body).characteristics);
this.eventRegistry[deviceID] = this.eventRegistry[deviceID].concat(JSON.parse(body).characteristics);
// debug('2', JSON.stringify(this.eventRegistry[key]));
this.eventRegistry[deviceID].sort((a, b) => (JSON.stringify(a) > JSON.stringify(b)) ? 1 : ((JSON.stringify(b) > JSON.stringify(a)) ? -1 : 0));
// debug('3', JSON.stringify(this.eventRegistry[key]));
this.eventRegistry[deviceID] = Array.from(new Set(this.eventRegistry[deviceID].map(JSON.stringify))).map(JSON.parse);
// debug('4', JSON.stringify(this.eventRegistry[key]));
try {
rsp = JSON.parse(response.body);
} catch (ex) {
debug('Homebridge Response Failed %s:%s', deviceID, response.statusCode, response.statusMessage);
debug('Homebridge Response Failed %s:%s', deviceID, response.body, ex);
callback(new Error(ex));
return;
}
callback(null, rsp);
}
}.bind(this));
}
}.bind(this));
};
/**
* HAPNodeJSClient.prototype.HAPevent - Send a characteristic PUT Message to a particular homebridge instance, this maintains a socket connection for use in returning Events
*
* @param {type} ipAddress IP Address of homebridge instance
* @param {type} port Port of homebridge instance
* @param {type} body An array of HomeKit characteristic updates, [{ \"aid\": 2, \"iid\": 9, \"value\": 0}]
* @param {type} callback Callback to execute upon completion of characteristic setting, function(err, response)
*/
HAPNodeJSClient.prototype.HAPevent = function(ipAddress, port, body, callback, instance) {
var pin = _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port);
hapRequest({
eventBus: this._eventBus,
method: 'PUT',
url: 'http://' + ipAddress + ':' + port + '/characteristics',
timeout: this.reqTimeout,
maxAttempts: 5, // (default) try 5 times
headers: {
'Content-Type': 'Application/json',
'authorization': pin,
'connection': 'keep-alive'
},
body: body
}, function(err, response) {
// Response s/b 200 OK
if (err) {
debug('Homebridge event reg failed %s:%s', ipAddress, port, body, err.message);
callback(err);
} else if (response.statusCode !== 207 && response.statusCode !== 204) {
if (response.statusCode === 401 || response.statusCode === 470) {
debug('Homebridge auth failed, invalid PIN %s %s:%s', pin, ipAddress, port, body, err, response.body);
callback(new Error('Homebridge auth failed, invalid PIN ' + pin));
} else {
debug('Homebridge event reg failed %s:%s Status: %s ', ipAddress, port, response.statusCode, body, err, response.body);
callback(new Error('Homebridge event reg failed'));
}
} else {
var rsp;
var key = ipAddress + ':' + port;
if (!this.eventRegistry[key]) {
this.eventRegistry[key] = [];
}
// debug('1', JSON.parse(body).characteristics);
this.eventRegistry[key] = this.eventRegistry[key].concat(JSON.parse(body).characteristics);
// debug('2', JSON.stringify(this.eventRegistry[key]));
this.eventRegistry[key].sort((a, b) => (JSON.stringify(a) > JSON.stringify(b)) ? 1 : ((JSON.stringify(b) > JSON.stringify(a)) ? -1 : 0));
// debug('3', JSON.stringify(this.eventRegistry[key]));
this.eventRegistry[key] = Array.from(new Set(this.eventRegistry[key].map(JSON.stringify))).map(JSON.parse);
// debug('4', JSON.stringify(this.eventRegistry[key]));
try {
rsp = JSON.parse(response.body);
} catch (ex) {
debug('Homebridge Response Failed %s:%s', ipAddress, port, response.statusCode, response.statusMessage);
debug('Homebridge Response Failed %s:%s', ipAddress, port, response.body, ex);
callback(new Error(ex));
return;
}
callback(null, rsp);
}
}.bind(this));
};
/**
* HAPNodeJSClient.prototype.HAPresourceByDeviceID - Send a characteristic PUT Message to a particular homebridge instance using resource interface, ie camera
*
* @param {type} DeviceID DeviceID of homebridge instance
* @param {type} body An array of HomeKit characteristic updates, [{ \"aid\": 2, \"iid\": 9, \"value\": 0}]
* @param {type} callback Callback to execute upon completion of characteristic setting, function(err, response)
*/
HAPNodeJSClient.prototype.HAPresourceByDeviceID = function(deviceID, body, callback) {
// console.log('This-0', this);
_mdnsLookup(deviceID, function(err, instance) {
// console.log('This-1', this);
if (err) {
callback(err);
} else {
HAPNodeJSClient.prototype.HAPresource.call(this, instance.host, instance.port, body, function(err, response) {
if (err) {
_mdnsError(deviceID);
}
callback(err, response);
}, instance);
}
}.bind(this));
};
/**
* HAPNodeJSClient.prototype.HAPresource - Send a characteristic PUT Message to a particular homebridge instance using resource interface, ie camera
*
* @param {type} ipAddress IP Address of homebridge instance
* @param {type} port Port of homebridge instance
* @param {type} body An array of HomeKit characteristic updates, [{ \"aid\": 2, \"iid\": 9, \"value\": 0}]
* @param {type} callback Callback to execute upon completion of characteristic setting, function(err, response)
*/
HAPNodeJSClient.prototype.HAPresource = function(ipAddress, port, body, callback, instance) {
var pin = _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port);
request({
eventBus: this._eventBus,
method: 'POST',
url: 'http://' + ipAddress + ':' + port + '/resource',
timeout: this.reqTimeout,
maxAttempts: 5, // (default) try 5 times
encoding: null,
headers: {
'Content-Type': 'Application/json',
'authorization': pin,
'connection': 'keep-alive'
},
body: body
}, function(err, response) {
// Response s/b 200 OK
if (err) {
// debug('Homebridge Status failed %s:%s', ipAddress, port, body, err);
callback(err);
} else if (response.statusCode !== 200) {
if (response.statusCode === 401 || response.statusCode === 470) {
debug('Homebridge auth failed, invalid PIN %s %s:%s', pin, ipAddress, port, body, err);
callback(new Error('Homebridge auth failed, invalid PIN ' + pin));
} else {
debug('Homebridge Status failed %s:%s Status: %s ', ipAddress, port, response.statusCode, body, err);
callback(new Error('Homebridge status failed'));
}
} else {
var rsp;
try {
rsp = response.body;
} catch (ex) {
debug('Homebridge Response Failed %s:%s', ipAddress, port, response.statusCode, response.statusMessage);
debug('Homebridge Response Failed %s:%s', ipAddress, port, ex);
callback(new Error(ex));
return;
}
callback(null, rsp);
}
}.bind(this));
};
/**
* HAPNodeJSClient.prototype.HAPstatusByDeviceID - Get current status for characteristics
*
* @param {type} deviceID deviceID of homebridge instance
* @param {type} body description
* @param {type} callback Callback to execute upon completion of characteristic getting, function(err, response)
*/
HAPNodeJSClient.prototype.HAPstatusByDeviceID = function(deviceID, body, callback) {
// console.log('This-0', this);
_mdnsLookup(deviceID, function(err, instance) {
// console.log('This-1', this);
if (err) {
callback(err);
} else {
HAPNodeJSClient.prototype.HAPstatus.call(this, instance.host, instance.port, body, function(err, response) {
if (err) {
_mdnsError(deviceID);
}
callback(err, response);
}, instance);
}
}.bind(this));
};
/**
* HAPNodeJSClient.prototype.HAPstatus - Get current status for characteristics
*
* @param {type} ipAddress IP Address of homebridge instance
* @param {type} port Port of homebridge instance
* @param {type} body description
* @param {type} callback Callback to execute upon completion of characteristic getting, function(err, response)
*/
HAPNodeJSClient.prototype.HAPstatus = function(ipAddress, port, body, callback, instance) {
var pin = _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port);
// debug('HAPstatus', pin);
request({
eventBus: this._eventBus,
method: 'GET',
url: 'http://' + ipAddress + ':' + port + '/characteristics' + body,
timeout: this.reqTimeout,
maxAttempts: 5, // (default) try 5 times
headers: {
'Content-Type': 'Application/json',
'authorization': pin,
'connection': 'keep-alive'
}
}, function(err, response) {
// Response s/b 200 OK
// debug('HAPstatus', 'http://' + ipAddress + ':' + port + '/characteristics' + body);
// debug('HAPstatus-1', pin);
if (err) {
// debug('Homebridge Status failed %s:%s', ipAddress, port, body, err);
callback(err);
} else if (response.statusCode !== 207 && response.statusCode !== 200) {
if (response.statusCode === 401 || response.statusCode === 470) {
debug('Homebridge auth failed, invalid PIN %s %s:%s', pin, ipAddress, port, body, err, response.body);
callback(new Error('Homebridge auth failed, invalid PIN ' + pin));
} else {
debug('Homebridge Status failed %s:%s Status: %s ', ipAddress, port, response.statusCode, body, err, response.body);
callback(new Error('Homebridge status failed'));
}
} else {
var rsp;
try {
rsp = JSON.parse(response.body);
} catch (ex) {
debug('Homebridge Response Failed %s:%s', ipAddress, port, response.statusCode, response.statusMessage);
debug('Homebridge Response Failed %s:%s', ipAddress, port, response.body, ex);
callback(new Error(ex));
return;
}
// debug('HAPStatus callback', rsp);
callback(null, rsp);
}
});
};
function _getAccessories(instance, callback) {
// debug('_getAccessories', filter);
if ((filter && filter === instance.host + ':' + instance.port) || !filter) {
var host = instance.host + ':' + instance.port;
var pin = _findPinByKey(host);
request({
eventBus: this._eventBus,
method: 'GET',
url: instance.url + '/accessories',
timeout: this.reqTimeout,
maxAttempts: 5, // (default) try 5 times
retryDelay: 5000, // (default) wait for 5s before trying again
headers: {
'Content-Type': 'Application/json',
'authorization': pin,
'connection': 'keep-alive'
}
}, function(err, response) {
// Response s/b 200 OK
// debug('_getAccessories', response);
if (err || response.statusCode !== 200) {
if (err) {
debug('HAP Discover failed %s -> %s error %s', instance.txt.md, instance.url, err);
} else {
// Status code = 401/470 = homebridge not running in insecure mode
if (response.statusCode === 401 || response.statusCode === 470) {
debug('HAP Discover failed %s -> %s invalid PIN or homebridge is not running in insecure mode with -I', instance.txt.md, instance.url);
err = new Error('homebridge is not running in insecure mode with -I', response.statusCode);
} else {
debug('HAP Discover failed %s -> %s http status code %s', instance.txt.md, instance.url, response.statusCode);
// debug('Message', response);
err = new Error('Http Err', response.statusCode);
}
}
callback(err);
} else {
// debug('_getAccessories', response.body);
try {
var message = normalizeUUID(JSON.parse(response.body.replace(/\uFFFD/g, '')));
} catch (err) {
debug('HAP Json Msg Parse failed %s %s error code %s', instance.txt.md, instance.url, response.statusCode);
callback(err);
return;
}
if (message && Object.keys(message.accessories).length > 0) {
debug('Homebridge instance discovered %s with %s accessories', instance.txt.md, Object.keys(message.accessories).length);
discovered.push({
ipAddress: instance.host,
instance: instance,
accessories: message,
deviceID: instance.deviceID,
name: instance.txt.md
});
callback(null);
} else {
debug('Short json data received %s -> %s', instance.txt.md, instance.url, JSON.stringify(response));
callback(new Error('Short json data received %s -> %s', instance.txt.md, instance.url));
}
}
});
} else {
debug('Filtered HAP instance address: %s -> %s', instance.txt.md, instance.url);
}
}