hap-node-client
Advanced tools
Comparing version 0.2.8-beta.6 to 0.2.8-beta.7
'use strict'; | ||
// External Libraries | ||
const ip = require('ip'); | ||
const bonjour = require('bonjour-hap')(); | ||
const axios = require('axios').default; | ||
const inherits = require('node:util').inherits; | ||
var hapRequest = require('./lib/hapRequest.js'); | ||
var EventEmitter = require('events').EventEmitter; | ||
const axiosRetry = require('axios-retry').default; | ||
const EventEmitter = require('node: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; | ||
// Internal Libaries | ||
const hapRequest = require('./lib/hapRequest.js'); | ||
const normalizeUUID = require('./lib/util.js').normalizeUUID; | ||
const getAccessoryDump = require('./lib/getAccessoryDump').getAccessoryDump; | ||
const MonitorBridgeUpdates = require('./lib/monitorBridgeUpdates').MonitorBridgeUpdates; | ||
// Debug Monitoring | ||
var debug = require('debug')('HAPNodeJSClient'); | ||
var debugDis = require('debug')('HAPNodeJSClient:Discover'); | ||
var debugDump = require('debug')('HAPNodeJSClient:Dump'); | ||
axiosRetry(axios, { retries: 3 }); | ||
var discovered = []; | ||
// var mdnsCache = {}; | ||
var mdnsCache = {}; | ||
var populateCache = false; | ||
@@ -34,2 +22,6 @@ | ||
module.exports = { | ||
HAPNodeJSClient: HAPNodeJSClient | ||
}; | ||
/** | ||
@@ -48,3 +40,2 @@ * HAPNodeJSClient - Client for Homebridge and HAP-NodeJS in insecure mode. | ||
* @property {number} reqTimeout - Accessory request timeout, defaults to 7 seconds | ||
* @property {number} type - Type of mDNS record to look for, defaults to `hap`, used for testing only. | ||
* @example | ||
@@ -54,556 +45,68 @@ * | ||
var populateCacheTimeout; | ||
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(); | ||
class HAPNodeJSClient { | ||
constructor(options) { | ||
// console.log('Options', options); | ||
this.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.log('DEBUG-1', namespaces); | ||
if (namespaces) { | ||
namespaces = namespaces + ',hap*'; | ||
} else { | ||
namespaces = 'hap*'; | ||
} | ||
// this.log('DEBUG-2', namespaces); | ||
debugEnable.enable(namespaces); | ||
} | ||
this.eventRegistry = {}; | ||
this.eventRegistry = {}; | ||
_discovery.call(this); | ||
this._eventBus = new EventEmitter(); | ||
setInterval(_discovery.bind(this), this.refresh * 1000); | ||
this.monitorBridgeUpdates = new MonitorBridgeUpdates({ type: (options.type ? options.type : 'hap') }); | ||
/** | ||
* 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.monitorBridgeUpdates.on('up', this.bridgeUp.bind(this)); | ||
this.monitorBridgeUpdates.on('update', this.bridgeUpdate.bind(this)); | ||
this.monitorBridgeUpdates.on('Ready', this.bridgeReady.bind(this)); | ||
this._eventBus.on('Disconnected', _reconnectServer.bind(this)); | ||
// _discovery.call(this); // Inital discovery of devices | ||
this._eventBus = new EventEmitter(); | ||
// this.discoveryTimer = setInterval(_discovery.bind(this), this.refresh * 1000); | ||
this._eventBus.on('Event', function (events) { | ||
debug('Events', JSON.stringify(events)); | ||
/** | ||
* HomeKit Accessory Characteristic event pass thru | ||
* | ||
* @event HAPNodeJSClient#Disconnected | ||
* @event HAPNodeJSClient#hapEvent | ||
* @Type {object} | ||
* @property {string} server - IP Address and port of disconnected homebridge | ||
* @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.4', port: 51826, aid: 16, iid: 11, status: false } | ||
* [{"host":"192.168.1.13","port":43787,"deviceID":"76:59:CE:25:B9:6E","aid":1,"iid":13,"value":true,"status":true}] | ||
*/ | ||
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)); | ||
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)); | ||
// debug('This', this); | ||
} | ||
/** | ||
* | ||
* @param {*} callback | ||
*/ | ||
async bridgeUp(service) { | ||
// debugDis('bridgeUp', service); | ||
if (await this.getServiceDump(service)) { | ||
} | ||
} | ||
/** | ||
* | ||
* @param {*} callback | ||
*/ | ||
async bridgeUpdate(service) { | ||
debugDis('bridgeUpdate', service); | ||
if (await this.getServiceDump(service)) { | ||
this.emit('Update', _deassociateArray(discovered)); | ||
} | ||
} | ||
/** | ||
* | ||
* @param {*} callback | ||
*/ | ||
async bridgeReady(service) { | ||
debugDis('bridgeReady %d Homebridge instances', Object.keys(discovered).length); | ||
if (Object.keys(discovered).length > 0) { | ||
this.emit('Ready', _deassociateArray(discovered)); | ||
} | ||
} | ||
/** | ||
* | ||
* @param {*} callback | ||
*/ | ||
async getServiceDump(service) { | ||
// debugDis('getServiceDump', service); | ||
if ((filter && filter === service.host + ':' + service.port) || !filter) { | ||
try { | ||
let serviceDump = await getAccessoryDump(service); | ||
if (serviceDump) { | ||
// debugDis('discovered', service.deviceID, bridge); | ||
discovered[service.deviceID] = serviceDump; | ||
} | ||
return serviceDump; | ||
} catch (err) { | ||
debugDis('ERROR:', err.message, service.name); | ||
} | ||
} else { | ||
debugDump('Filtered HAP instance address: %s -> %s', service.txt.md, service.url); | ||
} | ||
} | ||
/** | ||
* 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 | ||
*/ | ||
RegisterPin(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; | ||
} | ||
/** | ||
* HAPaccessories - Returns an array of all homebridge instances, and the accessories for each. | ||
* | ||
* @class | ||
* @param {type} callback description | ||
* @return {type} description | ||
*/ | ||
HAPaccessories(callback) { | ||
// This is a callback as in the future may need to call something | ||
callback(_deassociateArray(discovered)); | ||
} | ||
/** | ||
* mdnsCache | ||
* | ||
* @returns mdnsCacheObject | ||
*/ | ||
mdnsCache() { | ||
return this.monitorBridgeUpdates.mdnsCache; | ||
} | ||
// 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}] }" | ||
/** | ||
* 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) | ||
*/ | ||
HAPcontrolByDeviceID(deviceID, body, callback) { | ||
this._mdnsLookup(deviceID, function (err, instance) { | ||
if (err) { | ||
callback(err); | ||
} else { | ||
this.HAPcontrol.call(this, instance.host, instance.port, body, function (err, response) { | ||
if (err) { | ||
this._mdnsError(deviceID); | ||
} | ||
callback(err, response); | ||
}, instance); | ||
} | ||
}.bind(this)); | ||
} | ||
/** | ||
* 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) | ||
*/ | ||
HAPcontrol(ipAddress, port, body, callback, instance) { | ||
axios({ | ||
eventBus: this._eventBus, | ||
method: 'PUT', | ||
url: instance.url + '/characteristics', | ||
timeout: this.reqTimeout, | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), | ||
'connection': 'keep-alive' | ||
}, | ||
data: body, | ||
validateStatus: function (status) { | ||
return true; // Resolve only if the status code is less than 500 | ||
} | ||
}).then(function (response) { | ||
// debug('HAPcontrol-then', response.status, response.statusText, response.headers, response.data, response.config); | ||
switch (response.status) { | ||
case 204: | ||
callback(null, null); | ||
break; | ||
case 207: | ||
callback(null, response.data); | ||
break; | ||
case 401: | ||
case 470: | ||
debug('Homebridge auth failed, invalid PIN %s %s:%s', _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), ipAddress, port, body, response.data); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port))); | ||
break; | ||
default: | ||
debug('Homebridge Control failed %s:%s Status: %s ', ipAddress, port, response.status, body, response.data); | ||
callback(new Error('Homebridge control failed')); | ||
} | ||
}).catch(function (err) { | ||
// Response s/b 200 OK | ||
debug('HAPcontrol-catch', err); | ||
debug('Homebridge Control failed %s:%s', ipAddress, port, body, err.message); | ||
callback(err); | ||
}); | ||
} | ||
/** | ||
* 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) | ||
*/ | ||
HAPeventByDeviceID(deviceID, body, callback) { | ||
// console.log('This-0', this); | ||
this._mdnsLookup(deviceID, function (err, instance) { | ||
// debug('This-1', instance); | ||
if (err) { | ||
callback(err); | ||
} else { | ||
hapRequest({ | ||
eventBus: this._eventBus, | ||
method: 'PUT', | ||
deviceID: deviceID, | ||
url: instance.url + '/characteristics', | ||
timeout: this.reqTimeout, | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(deviceID), | ||
'connection': 'keep-alive' | ||
}, | ||
body: body | ||
}, function (err, response) { | ||
// Response s/b 200 OK | ||
// debug('HAPeventByDeviceID %s:%s', instance.host, instance.port, response); | ||
if (err) { | ||
debug('Homebridge event reg failed %s:%s', instance.host, instance.port, body, err.message); | ||
this._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', _findPinByKey(deviceID), deviceID, body, err, response.body); | ||
this._mdnsError(deviceID); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(deviceID))); | ||
} else { | ||
debug('Homebridge event reg failed %s:%s Status: %s ', deviceID, response.statusCode, body, err, response.body); | ||
this._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)); | ||
} | ||
/** | ||
* 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) | ||
*/ | ||
HAPevent(ipAddress, port, body, callback, instance) { | ||
hapRequest({ | ||
eventBus: this._eventBus, | ||
method: 'PUT', | ||
url: instance.url + '/characteristics', | ||
timeout: this.reqTimeout, | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), | ||
'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', _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), ipAddress, port, body, err, response.body); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port))); | ||
} 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)); | ||
} | ||
/** | ||
* 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) | ||
*/ | ||
HAPresourceByDeviceID(deviceID, body, callback) { | ||
// console.log('This-0', this); | ||
this._mdnsLookup(deviceID, function (err, instance) { | ||
// console.log('This-1', this); | ||
if (err) { | ||
callback(err); | ||
} else { | ||
this.HAPresource.call(this, instance.host, instance.port, body, function (err, response) { | ||
if (err) { | ||
this._mdnsError(deviceID); | ||
} | ||
callback(err, response); | ||
}.bind(this), instance); | ||
} | ||
}.bind(this)); | ||
} | ||
/** | ||
* 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) | ||
*/ | ||
HAPresource(ipAddress, port, body, callback, instance) { | ||
axios({ | ||
eventBus: this._eventBus, | ||
method: 'POST', | ||
url: instance.url + '/resource', | ||
timeout: this.reqTimeout, | ||
responseType: 'arraybuffer', | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), | ||
'connection': 'keep-alive' | ||
}, | ||
data: body, | ||
validateStatus: function (status) { | ||
return true; // Resolve only if the status code is less than 500 | ||
} | ||
}).then(function (response) { | ||
// debug('HAPcontrol-then', response.status, response.statusText, response.headers, response.config); | ||
switch (response.status) { | ||
case 200: | ||
callback(null, response.data); | ||
break; | ||
case 401: | ||
case 470: | ||
debug('Homebridge auth failed, invalid PIN %s %s:%s', _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), ipAddress, port, body, response.data); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port))); | ||
break; | ||
default: | ||
debug('Homebridge Resource failed %s:%s Status: %s ', ipAddress, port, response.status, body, response.data); | ||
callback(new Error('Homebridge Resource failed')); | ||
} | ||
}).catch(function (err) { | ||
// Response s/b 200 OK | ||
debug('HAPcontrol-catch', err); | ||
debug('Homebridge Resource failed %s:%s', ipAddress, port, body, err.message); | ||
callback(err); | ||
}); | ||
} | ||
/** | ||
* 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) | ||
*/ | ||
HAPstatusByDeviceID(deviceID, body, callback) { | ||
// console.log('This-0', this); | ||
this._mdnsLookup(deviceID, function (err, instance) { | ||
// console.log('This-1', this); | ||
if (err) { | ||
callback(err); | ||
} else { | ||
this.HAPstatus.call(this, instance.host, instance.port, body, function (err, response) { | ||
if (err) { | ||
this._mdnsError(deviceID); | ||
} | ||
callback(err, response); | ||
}.bind(this), instance); | ||
} | ||
}.bind(this)); | ||
} | ||
/** | ||
* 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) | ||
*/ | ||
HAPstatus(ipAddress, port, body, callback, instance) { | ||
axios({ | ||
eventBus: this._eventBus, | ||
method: 'GET', | ||
url: instance.url + '/characteristics' + body, | ||
timeout: this.reqTimeout, | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), | ||
'connection': 'keep-alive' | ||
}, | ||
validateStatus: function (status) { | ||
return true; // Resolve only if the status code is less than 500 | ||
} | ||
}).then(function (response) { | ||
// debug('HAPstatus-then', response.status, response.statusText, response.headers, response.data, response.config); | ||
switch (response.status) { | ||
case 200: | ||
callback(null, response.data); | ||
break; | ||
case 207: | ||
callback(null, response.data); | ||
break; | ||
case 401: | ||
case 470: | ||
debug('Homebridge auth failed, invalid PIN %s %s:%s', _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), ipAddress, port, body, response.data); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port))); | ||
break; | ||
default: | ||
debug('Homebridge Status failed %s:%s Status: %s ', ipAddress, port, response.status, body, response.data); | ||
callback(new Error('Homebridge Status failed')); | ||
} | ||
}).catch(function (err) { | ||
// Response s/b 200 OK | ||
debug('HAPstatus-catch', err); | ||
debug('Homebridge Status failed %s:%s', ipAddress, port, body, err.message); | ||
callback(err); | ||
}); | ||
} | ||
/** | ||
* When a 'known' bridge is not found, force refresh the cache | ||
* | ||
* @param {*} deviceID | ||
* @param {*} callback | ||
*/ | ||
async _mdnsLookup(deviceID, callback) { | ||
// debug('\nmdnsLookup start', serviceName); | ||
if (this.monitorBridgeUpdates.mdnsCacheGet(deviceID)) { | ||
// debug('cached', this.monitorBridgeUpdates.mdnsCacheGet(serviceName].url); | ||
callback(null, this.monitorBridgeUpdates.mdnsCacheGet(deviceID)); | ||
} else { | ||
debug('_mdnsLookup missing', deviceID); | ||
await this.monitorBridgeUpdates.refreshCache(); | ||
if (this.monitorBridgeUpdates.mdnsCacheGet(deviceID)) { | ||
// debug('cached', this.monitorBridgeUpdates.mdnsCacheGet(serviceName].url); | ||
callback(null, this.monitorBridgeUpdates.mdnsCacheGet(deviceID)); | ||
} else { | ||
callback(new Error('ERROR: HB Instance not found', deviceID), null); | ||
} | ||
}; | ||
} | ||
async _mdnsError(deviceID) { | ||
debug('_mdnsError ', deviceID); | ||
this.monitorBridgeUpdates.mdnsCacheRemove(deviceID); | ||
this.monitorBridgeUpdates.refreshCache(); | ||
} | ||
/** | ||
* Destroy and shutdown HAPNodeJSClient - Used by testing | ||
*/ | ||
async destroy() { | ||
clearInterval(this.discoveryTimer); | ||
clearInterval(populateCacheTimeout); | ||
bonjour.destroy(); | ||
this.monitorBridgeUpdates.destroy(); | ||
} | ||
}.bind(this)); | ||
// debug('This', this); | ||
} | ||
@@ -613,3 +116,2 @@ | ||
/* | ||
function _discovery() { | ||
@@ -624,7 +126,33 @@ debug('Starting Homebridge instance discovery'); | ||
} | ||
*/ | ||
/* | ||
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); | ||
// debug('_populateCache', populateCache); | ||
if (!populateCache) { | ||
@@ -634,3 +162,3 @@ populateCache = true; | ||
var browser = bonjour.find({ | ||
type: 'test' | ||
type: 'hap' | ||
}, function (result) { | ||
@@ -655,3 +183,3 @@ if (result.txt) { | ||
if (url) { | ||
this.monitorBridgeUpdates.mdnsCacheUpdate({ | ||
mdnsCache[result.txt.id] = { | ||
name: result.name, | ||
@@ -663,5 +191,5 @@ host: ipAddress, | ||
txt: result.txt | ||
}); | ||
}; | ||
if (discovery) { | ||
discovery.call(this, this.monitorBridgeUpdates.mdnsCacheGet(result.txt.id), function () { }); | ||
discovery.call(this, mdnsCache[result.txt.id], function () { }); | ||
} | ||
@@ -675,3 +203,3 @@ } else { | ||
}); | ||
populateCacheTimeout = setTimeout(function () { | ||
setTimeout(function () { | ||
// debug('Timeout:'); | ||
@@ -685,3 +213,3 @@ browser.stop(); | ||
} | ||
}*/ | ||
} | ||
@@ -698,2 +226,121 @@ function _findPinByKey(key) { | ||
/** | ||
* 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); | ||
}; | ||
/** | ||
* HAPNodeJSClient.prototype.mdnsCache | ||
* | ||
* @returns mdnsCacheObject | ||
*/ | ||
HAPNodeJSClient.prototype.mdnsCache = function () { | ||
return mdnsCache; | ||
}; | ||
// 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) { | ||
axios({ | ||
eventBus: this._eventBus, | ||
method: 'PUT', | ||
url: instance.url + '/characteristics', | ||
timeout: this.reqTimeout, | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), | ||
'connection': 'keep-alive' | ||
}, | ||
data: body, | ||
validateStatus: function (status) { | ||
return true; // Resolve only if the status code is less than 500 | ||
} | ||
}).then(function (response) { | ||
// debug('HAPcontrol-then', response.status, response.statusText, response.headers, response.data, response.config); | ||
switch (response.status) { | ||
case 204: | ||
callback(null, null); | ||
break; | ||
case 207: | ||
callback(null, response.data); | ||
break; | ||
case 401: | ||
case 470: | ||
debug('Homebridge auth failed, invalid PIN %s %s:%s', _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), ipAddress, port, body, response.data); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port))); | ||
break; | ||
default: | ||
debug('Homebridge Control failed %s:%s Status: %s ', ipAddress, port, response.status, body, response.data); | ||
callback(new Error('Homebridge control failed')); | ||
} | ||
}).catch(function (err) { | ||
// Response s/b 200 OK | ||
debug('HAPcontrol-catch', err); | ||
debug('Homebridge Control failed %s:%s', ipAddress, port, body, err.message); | ||
callback(err); | ||
}); | ||
}; | ||
/** | ||
* _reconnectServer - Reconnect to event server | ||
@@ -706,15 +353,13 @@ * | ||
function _reconnectServer(server) { | ||
debug('HAPevent events Reregister', server, this.eventRegistry); | ||
debug('HAPevent events Reregister', server); | ||
// debug('This', this, server); | ||
var events = []; | ||
if (this.eventRegistry.length) { | ||
this.eventRegistry[server.deviceID].forEach(function (device) { | ||
events.push({ | ||
deviceID: server.deviceID, | ||
aid: device.aid, | ||
iid: device.iid, | ||
status: -70402 | ||
}); | ||
this.eventRegistry[server.deviceID].forEach(function (device) { | ||
events.push({ | ||
deviceID: server.deviceID, | ||
aid: device.aid, | ||
iid: device.iid, | ||
status: -70402 | ||
}); | ||
} | ||
}); | ||
this.emit('hapEvent', events); | ||
@@ -751,12 +396,10 @@ // this.emit(events[0].host + events[0].port + events[0].aid, events); | ||
debug('clearTimer', server, this.eventRegistry[server.deviceID]); | ||
if (this.eventRegistry.length) { | ||
this.eventRegistry[server.deviceID].forEach(function (device) { | ||
events.push({ | ||
deviceID: server.deviceID, | ||
aid: device.aid, | ||
iid: device.iid, | ||
status: -70402 | ||
}); | ||
this.eventRegistry[server.deviceID].forEach(function (device) { | ||
events.push({ | ||
deviceID: server.deviceID, | ||
aid: device.aid, | ||
iid: device.iid, | ||
status: -70402 | ||
}); | ||
} | ||
}); | ||
this.emit('hapEvent', events); | ||
@@ -771,12 +414,10 @@ // this.emit(events[0].host + events[0].port + events[0].aid, events); | ||
debug('HAPevent event reregister succeeded', server); | ||
if (this.eventRegistry.length) { | ||
this.eventRegistry[server.deviceID].forEach(function (device) { | ||
events.push({ | ||
deviceID: server.deviceID, | ||
aid: device.aid, | ||
iid: device.iid, | ||
status: true | ||
}); | ||
this.eventRegistry[server.deviceID].forEach(function (device) { | ||
events.push({ | ||
deviceID: server.deviceID, | ||
aid: device.aid, | ||
iid: device.iid, | ||
status: true | ||
}); | ||
} | ||
}); | ||
this.emit('hapEvent', events); | ||
@@ -794,7 +435,289 @@ // this.emit(events[0].host + events[0].port + events[0].aid, events); | ||
module.exports = { | ||
HAPNodeJSClient: HAPNodeJSClient | ||
/** | ||
* 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 { | ||
hapRequest({ | ||
eventBus: this._eventBus, | ||
method: 'PUT', | ||
deviceID: deviceID, | ||
url: instance.url + '/characteristics', | ||
timeout: this.reqTimeout, | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(deviceID), | ||
'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', _findPinByKey(deviceID), deviceID, body, err, response.body); | ||
_mdnsError(deviceID); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(deviceID))); | ||
} 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) { | ||
hapRequest({ | ||
eventBus: this._eventBus, | ||
method: 'PUT', | ||
url: instance.url + '/characteristics', | ||
timeout: this.reqTimeout, | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), | ||
'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', _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), ipAddress, port, body, err, response.body); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port))); | ||
} 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) { | ||
axios({ | ||
eventBus: this._eventBus, | ||
method: 'POST', | ||
url: instance.url + '/resource', | ||
timeout: this.reqTimeout, | ||
responseType: 'arraybuffer', | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), | ||
'connection': 'keep-alive' | ||
}, | ||
data: body, | ||
validateStatus: function (status) { | ||
return true; // Resolve only if the status code is less than 500 | ||
} | ||
}).then(function (response) { | ||
// debug('HAPcontrol-then', response.status, response.statusText, response.headers, response.config); | ||
switch (response.status) { | ||
case 200: | ||
callback(null, response.data); | ||
break; | ||
case 401: | ||
case 470: | ||
debug('Homebridge auth failed, invalid PIN %s %s:%s', _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), ipAddress, port, body, response.data); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port))); | ||
break; | ||
default: | ||
debug('Homebridge Resource failed %s:%s Status: %s ', ipAddress, port, response.status, body, response.data); | ||
callback(new Error('Homebridge Resource failed')); | ||
} | ||
}).catch(function (err) { | ||
// Response s/b 200 OK | ||
debug('HAPcontrol-catch', err); | ||
debug('Homebridge Resource failed %s:%s', ipAddress, port, body, err.message); | ||
callback(err); | ||
}); | ||
}; | ||
/** | ||
* 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) { | ||
axios({ | ||
eventBus: this._eventBus, | ||
method: 'GET', | ||
url: instance.url + '/characteristics' + body, | ||
timeout: this.reqTimeout, | ||
headers: { | ||
'Content-Type': 'Application/json', | ||
'authorization': _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), | ||
'connection': 'keep-alive' | ||
}, | ||
validateStatus: function (status) { | ||
return true; // Resolve only if the status code is less than 500 | ||
} | ||
}).then(function (response) { | ||
// debug('HAPstatus-then', response.status, response.statusText, response.headers, response.data, response.config); | ||
switch (response.status) { | ||
case 200: | ||
callback(null, response.data); | ||
break; | ||
case 207: | ||
callback(null, response.data); | ||
break; | ||
case 401: | ||
case 470: | ||
debug('Homebridge auth failed, invalid PIN %s %s:%s', _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port), ipAddress, port, body, response.data); | ||
callback(new Error('Homebridge auth failed, invalid PIN ' + _findPinByKey(instance ? instance.deviceID : ipAddress + ':' + port))); | ||
break; | ||
default: | ||
debug('Homebridge Status failed %s:%s Status: %s ', ipAddress, port, response.status, body, response.data); | ||
callback(new Error('Homebridge Status failed')); | ||
} | ||
}).catch(function (err) { | ||
// Response s/b 200 OK | ||
debug('HAPstatus-catch', err); | ||
debug('Homebridge Status failed %s:%s', ipAddress, port, body, err.message); | ||
callback(err); | ||
}); | ||
}; | ||
function _getAccessories(instance, callback) { | ||
@@ -868,15 +791,3 @@ // debug('_getAccessories()', filter, instance.url + '/accessories'); | ||
} | ||
*/ | ||
function _deassociateArray(original) { | ||
var result = []; | ||
for (var item in original) { | ||
result.push(original[item]); | ||
} | ||
// console.log('Result', result); | ||
return (result); | ||
} | ||
/** | ||
@@ -883,0 +794,0 @@ * This checks the instance pin matches |
@@ -108,3 +108,3 @@ const { _responseLineRegex } = require('./lib/httpParser'); | ||
homebridges.HAPstatusByDeviceID(testDeviceID, "{ a: 1 }", function (err, response) { | ||
console.log("HAPstatusByDeviceID", err.message, response); | ||
// console.log("HAPstatusByDeviceID", err.message, response); | ||
expect(err.message).toEqual('Homebridge Status failed'); | ||
@@ -125,5 +125,5 @@ expect(response).toBeUndefined(); | ||
test("valid deviceID, and valid body On", done => { | ||
console.log("HAPcontrolByDeviceID - start"); | ||
homebridges.HAPcontrolByDeviceID(testDeviceID, testAccessoryControlOn, function (err, response) { | ||
console.log("HAPcontrolByDeviceID", err, response); | ||
// console.log("HAPcontrolByDeviceID", err, response); | ||
expect(err).toBeNull(); | ||
@@ -315,10 +315,2 @@ expect(response).toBeNull(); | ||
}); | ||
afterAll(async () => { | ||
await sleep(1000); | ||
await homebridges.destroy(); | ||
}, 30000); | ||
}); | ||
async function sleep(ms) { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
}); |
// Monkey patch before you require http for the first time. | ||
const parser = require('./httpParser.js'); | ||
var once = require('once'); | ||
var URL = require('node:url'); | ||
var debug = require('debug')('HAPNodeJSClient:eventedHttpClient'); | ||
const net = require('node:net'); | ||
var URL = require('url'); | ||
var debug = require('debug')('hapHttpClient'); | ||
const net = require('net'); | ||
var Queue = require('better-queue'); | ||
@@ -37,14 +37,2 @@ | ||
this.client.setTimeout(request.timeout); | ||
this.client.on('timeout', () => { | ||
this.connected = false; | ||
// console.log('Timeout: from server', this.context.host); | ||
if (!this.callback.called) { | ||
this.callback(new Error('Timeout: from server ' + this.context.host)); | ||
} else { | ||
debug('eventedHttpClient: Timeout from server', this.context.host); | ||
} | ||
}); | ||
this.client.on('data', (data) => { | ||
@@ -95,3 +83,3 @@ // If in the middle of a chunked response | ||
if (!this.callback.called) { | ||
this.callback(err); | ||
this.callback(new Error("Error:", err)); | ||
} | ||
@@ -98,0 +86,0 @@ }); |
"use strict"; | ||
var extend = require('extend'); | ||
var URL = require('node:url'); | ||
var URL = require('url'); | ||
var EventedHttpClient = require('./eventedHttpClient'); | ||
@@ -6,0 +6,0 @@ var debug = require('debug')('hapRequest'); |
{ | ||
"name": "hap-node-client", | ||
"version": "0.2.8-beta.6", | ||
"version": "0.2.8-beta.7", | ||
"description": "Client for Hap-NodeJS", | ||
@@ -15,4 +15,2 @@ "main": "HAPNodeJSClient.js", | ||
"devDependencies": { | ||
"@types/jest": "^29.5.10", | ||
"@types/node": "^20.10.0", | ||
"documentation": "^14.0.3", | ||
@@ -28,3 +26,3 @@ "hap-nodejs": "^0.11.2", | ||
"better-queue": "3.8.12", | ||
"bonjour-hap": "3.7.1", | ||
"bonjour-hap": "3.6.5", | ||
"buffer": "6.0.3", | ||
@@ -40,3 +38,3 @@ "debug": "4.3.4", | ||
"ignore": [], | ||
"exec": "DEBUG=HAPNodeJSClient* jest --detectOpenHandles", | ||
"exec": "jest", | ||
"signal": "SIGTERM", | ||
@@ -43,0 +41,0 @@ "env": { |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
5
86750
16
1921
+ Addedbonjour-hap@3.6.5(transitive)
- Removedbonjour-hap@3.7.1(transitive)
Updatedbonjour-hap@3.6.5