From 3bca9f70f55ba8fd37b7f8b561e1c9196bd26ab4 Mon Sep 17 00:00:00 2001 From: Mike Enriquez Date: Thu, 1 Oct 2015 20:39:00 -0400 Subject: [PATCH 1/8] freeze node-xmpp-client version to working version --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 3a3ca74..fdb62a6 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "xmldoc": "0.1.x", "komponist" : "0.1.0", "yamaha-nodejs": "0.4.x", - "debug": "^2.2.0" + "debug": "^2.2.0", + "node-xmpp-client": "1.0.0-alpha23" } } From 98519c84dd642093247e2f40930dcaf92250cefb Mon Sep 17 00:00:00 2001 From: Mike Enriquez Date: Thu, 1 Oct 2015 23:08:36 -0400 Subject: [PATCH 2/8] Fix crash when trying to get/set power state - Call getPowerState on the object instead of passing the function to fix undefined isActivity error - Remove callback param from setPowerState since it is not called with a callback param. - startActivity expects the activity id as a parameter. We can't actually toggle activities off and on. There is a "PowerOff" activity that will turn everything off. --- platforms/LogitechHarmony.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/platforms/LogitechHarmony.js b/platforms/LogitechHarmony.js index a5c5e22..845f7f8 100644 --- a/platforms/LogitechHarmony.js +++ b/platforms/LogitechHarmony.js @@ -163,9 +163,9 @@ LogitechHarmonyAccessory.prototype = { var self = this; if (this.isActivity) { - hub.getCurrentActivity().then(function (currentActivity) { - callback(currentActivity.id === self.id); - }).except(function (err) { + this.hub.getCurrentActivity().then(function (currentActivity) { + callback(currentActivity === self.id); + }).catch(function (err) { self.log('Unable to get current activity with error', err); callback(false); }); @@ -175,28 +175,23 @@ LogitechHarmonyAccessory.prototype = { } }, - setPowerState: function (state, callback) { + setPowerState: function (state) { var self = this; if (this.isActivity) { this.log('Set activity ' + this.name + ' power state to ' + state); - // Activity id -1 is turn off all devices - var id = state ? this.id : -1; - - this.hub.startActivity(id) + this.hub.startActivity(self.id) .then(function () { self.log('Finished setting activity ' + self.name + ' power state to ' + state); - callback(); }) .catch(function (err) { self.log('Failed setting activity ' + self.name + ' power state to ' + state + ' with error ' + err); - callback(err); }); } else { // TODO: Support setting device power this.log('TODO: Support setting device power'); - callback(); + // callback(); } }, @@ -284,7 +279,9 @@ LogitechHarmonyAccessory.prototype = { onUpdate: function (value) { self.setPowerState(value) }, - onRead: self.getPowerState, + onRead: function(callback) { + self.getPowerState(callback) + }, perms: ["pw","pr","ev"], format: "bool", initialValue: 0, @@ -300,6 +297,5 @@ LogitechHarmonyAccessory.prototype = { }; -module.exports.accessory = LogitechHarmonyAccessory; module.exports.platform = LogitechHarmonyPlatform; From 2652f33a0a2de8566df0d346ec19c2bc1ceaff9d Mon Sep 17 00:00:00 2001 From: Mike Enriquez Date: Sat, 3 Oct 2015 22:04:51 -0400 Subject: [PATCH 3/8] send command every 20s to prevent timing out --- platforms/LogitechHarmony.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/platforms/LogitechHarmony.js b/platforms/LogitechHarmony.js index 845f7f8..c4ee5a0 100644 --- a/platforms/LogitechHarmony.js +++ b/platforms/LogitechHarmony.js @@ -53,6 +53,14 @@ LogitechHarmonyPlatform.prototype = { .then(function (client) { self.log("Connected to Logitech Harmony remote hub"); + // prevent connection from closing + setTimeout(function() { + setInterval(function() { + self.log("Sending command to prevent timeout"); + client.getCurrentActivity(); + }, 20000); + }, 5000); + callback(null, client); }); }; From 3c53b319cb256131ff1817cfa2633fd8abb2132c Mon Sep 17 00:00:00 2001 From: Kraig McConaghy Date: Sun, 18 Oct 2015 13:58:10 -0500 Subject: [PATCH 4/8] Updated to fixed harmonyhubjs-client --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8d1521c..bc26177 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "eibd": "^0.3.1", "elkington": "kevinohara80/elkington", "hap-nodejs": "^0.0.2", - "harmonyhubjs-client": "^1.1.4", + "harmonyhubjs-client": "enriquez/harmonyhubjs-client#patch-1", "harmonyhubjs-discover": "git+https://github.com/swissmanu/harmonyhubjs-discover.git", "lifx-api": "^1.0.1", "lifx": "git+https://github.com/magicmonkey/lifxjs.git", From 6008374b9ee22e0c37af9637ff3f496b374e1e03 Mon Sep 17 00:00:00 2001 From: Kraig McConaghy Date: Sun, 18 Oct 2015 14:00:06 -0500 Subject: [PATCH 5/8] Converted LogitechHarmony accessory to be based on new HAP api --- platforms/LogitechHarmony.js | 155 +++++++---------------------------- 1 file changed, 30 insertions(+), 125 deletions(-) diff --git a/platforms/LogitechHarmony.js b/platforms/LogitechHarmony.js index c4ee5a0..a0172a4 100644 --- a/platforms/LogitechHarmony.js +++ b/platforms/LogitechHarmony.js @@ -24,6 +24,12 @@ var harmony = require('harmonyhubjs-client'); var _harmonyHubPort = 61991; +var Service = require("hap-nodejs").Service; +var Characteristic = require("hap-nodejs").Characteristic; +var Accessory = require("hap-nodejs").Accessory; +var uuid = require("hap-nodejs").uuid; +var inherits = require('util').inherits; + function sortByKey (array, key) { return array.sort(function(a, b) { @@ -119,7 +125,7 @@ LogitechHarmonyPlatform.prototype = { var sArray = sortByKey(json['result'],"Name"); sArray.map(function(s) { - accessory = new LogitechHarmonyAccessory(self.log, self.server, self.port, false, s.idx, s.Name, s.HaveDimmer, s.MaxDimLevel, (s.SubType=="RGB")||(s.SubType=="RGBW")); + accessory = new LogitechHarmonyActivityAccessory(self.log, self.server, self.port, false, s.idx, s.Name, s.HaveDimmer, s.MaxDimLevel, (s.SubType=="RGB")||(s.SubType=="RGBW")); foundAccessories.push(accessory); }); @@ -139,7 +145,7 @@ LogitechHarmonyPlatform.prototype = { var sArray = sortByKey(activities, "label"); sArray.map(function(s) { - var accessory = new LogitechHarmonyAccessory(self.log, hub, s, true); + var accessory = new LogitechHarmonyActivityAccessory(self.log, hub, s); // TODO: Update the initial power state foundAccessories.push(accessory); }); @@ -153,40 +159,46 @@ LogitechHarmonyPlatform.prototype = { }; -function LogitechHarmonyAccessory (log, hub, details, isActivity) { +function LogitechHarmonyActivityAccessory (log, hub, details) { this.log = log; this.hub = hub; this.details = details; this.id = details.id; this.name = details.label; - this.isActivity = isActivity; - this.isActivityActive = false; + Accessory.call(this, this.name, uuid.generate(this.id)); + + this.getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.Manufacturer, "Logitech") + .setCharacteristic(Characteristic.Model, "Harmony") + // TODO: Add hub unique id to this for people with multiple hubs so that it is really a guid. + .setCharacteristic(Characteristic.SerialNumber, this.id); + + this.addService(Service.Switch) + .getCharacteristic(Characteristic.On) + .on('get', this.getPowerState) + .on('set', this.setPowerState); +}; +inherits(LogitechHarmonyActivityAccessory, Accessory); +LogitechHarmonyActivityAccessory.prototype.parent = Accessory.prototype; +LogitechHarmonyActivityAccessory.prototype.getServices = function() { + return this.services; }; - -LogitechHarmonyAccessory.prototype = { - // TODO: Somehow make this event driven so that it tells the user what activity is on - getPowerState: function (callback) { + LogitechHarmonyActivityAccessory.prototype.getPowerState = function (callback) { var self = this; - if (this.isActivity) { this.hub.getCurrentActivity().then(function (currentActivity) { callback(currentActivity === self.id); }).catch(function (err) { self.log('Unable to get current activity with error', err); callback(false); }); - } else { - // TODO: Support onRead for devices - this.log('TODO: Support onRead for devices'); - } - }, + }; - setPowerState: function (state) { + LogitechHarmonyActivityAccessory.prototype.setPowerState = function (state) { var self = this; - if (this.isActivity) { this.log('Set activity ' + this.name + ' power state to ' + state); this.hub.startActivity(self.id) @@ -196,114 +208,7 @@ LogitechHarmonyAccessory.prototype = { .catch(function (err) { self.log('Failed setting activity ' + self.name + ' power state to ' + state + ' with error ' + err); }); - } else { - // TODO: Support setting device power - this.log('TODO: Support setting device power'); - // callback(); - } - }, - - getServices: function () { - var self = this; - - return [ - { - sType: types.ACCESSORY_INFORMATION_STYPE, - characteristics: [ - { - cType: types.NAME_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: self.name, - supportEvents: false, - supportBonjour: false, - manfDescription: "Name of the accessory", - designedMaxLength: 255 - }, - { - cType: types.MANUFACTURER_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: "Logitech", - supportEvents: false, - supportBonjour: false, - manfDescription: "Manufacturer", - designedMaxLength: 255 - }, - { - cType: types.MODEL_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: "Harmony", - supportEvents: false, - supportBonjour: false, - manfDescription: "Model", - designedMaxLength: 255 - }, - { - cType: types.SERIAL_NUMBER_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - // TODO: Add hub unique id to this for people with multiple hubs so that it is really a guid. - initialValue: self.id, - supportEvents: false, - supportBonjour: false, - manfDescription: "SN", - designedMaxLength: 255 - }, - { - cType: types.IDENTIFY_CTYPE, - onUpdate: null, - perms: ["pw"], - format: "bool", - initialValue: false, - supportEvents: false, - supportBonjour: false, - manfDescription: "Identify Accessory", - designedMaxLength: 1 - } - ] - }, - { - sType: types.SWITCH_STYPE, - characteristics: [ - { - cType: types.NAME_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: self.name, - supportEvents: true, - supportBonjour: false, - manfDescription: "Name of service", - designedMaxLength: 255 - }, - { - cType: types.POWER_STATE_CTYPE, - onUpdate: function (value) { - self.setPowerState(value) - }, - onRead: function(callback) { - self.getPowerState(callback) - }, - perms: ["pw","pr","ev"], - format: "bool", - initialValue: 0, - supportEvents: true, - supportBonjour: false, - manfDescription: "Change the power state", - designedMaxLength: 1 - } - ] - } - ]; - } - -}; + }; module.exports.platform = LogitechHarmonyPlatform; From e30b504583cab85dd1ea2ee3b38e3e547db89ba1 Mon Sep 17 00:00:00 2001 From: Kraig McConaghy Date: Sun, 18 Oct 2015 16:00:02 -0500 Subject: [PATCH 6/8] Added handling to keep track of activity state --- platforms/LogitechHarmony.js | 90 +++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 36 deletions(-) diff --git a/platforms/LogitechHarmony.js b/platforms/LogitechHarmony.js index a0172a4..2167b1c 100644 --- a/platforms/LogitechHarmony.js +++ b/platforms/LogitechHarmony.js @@ -63,7 +63,7 @@ LogitechHarmonyPlatform.prototype = { setTimeout(function() { setInterval(function() { self.log("Sending command to prevent timeout"); - client.getCurrentActivity(); + client.getCurrentActivity().then(self.updateCurrentActivity.bind(self)); }, 20000); }, 5000); @@ -99,6 +99,13 @@ LogitechHarmonyPlatform.prototype = { discover.start(); }, + updateCurrentActivity: function(currentActivity) { + var actAccessories = this.activityAccessories; + if (actAccessories instanceof Array) { + actAccessories.map(function(a) { a.updateActivityState(currentActivity); }); + } + }, + accessories: function (callback) { var self = this; var foundAccessories = []; @@ -142,30 +149,36 @@ LogitechHarmonyPlatform.prototype = { .then(function (activities) { self.log("Found activities: \n" + activities.map(function (a) { return "\t" + a.label; }).join("\n")); - var sArray = sortByKey(activities, "label"); - - sArray.map(function(s) { - var accessory = new LogitechHarmonyActivityAccessory(self.log, hub, s); - // TODO: Update the initial power state - foundAccessories.push(accessory); + hub.getCurrentActivity().then(function (currentActivity) { + var actAccessories = []; + var sArray = sortByKey(activities, "label"); + sArray.map(function(s) { + var accessory = new LogitechHarmonyActivityAccessory(self.log, hub, s, self.updateCurrentActivity.bind(self)); + accessory.updateActivityState(currentActivity); + actAccessories.push(accessory); + foundAccessories.push(accessory); + }); + self.activityAccessories = actAccessories; + callback(foundAccessories); + }).catch(function (err) { + self.log('Unable to get current activity with error', err); + callback(false); }); - - callback(foundAccessories); }); }; - } - }; - -function LogitechHarmonyActivityAccessory (log, hub, details) { +function LogitechHarmonyActivityAccessory (log, hub, details, updateCurrentActivity) { this.log = log; this.hub = hub; this.details = details; this.id = details.id; this.name = details.label; + this.isOn = false; + this.updateCurrentActivity = updateCurrentActivity; Accessory.call(this, this.name, uuid.generate(this.id)); + var self = this; this.getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.Manufacturer, "Logitech") @@ -175,8 +188,12 @@ function LogitechHarmonyActivityAccessory (log, hub, details) { this.addService(Service.Switch) .getCharacteristic(Characteristic.On) - .on('get', this.getPowerState) - .on('set', this.setPowerState); + .on('get', function(callback) { + // Refreshed automatically by platform + callback(null, self.isOn); + }) + .on('set', this.setPowerState.bind(this)); + }; inherits(LogitechHarmonyActivityAccessory, Accessory); LogitechHarmonyActivityAccessory.prototype.parent = Accessory.prototype; @@ -184,31 +201,32 @@ LogitechHarmonyActivityAccessory.prototype.getServices = function() { return this.services; }; - // TODO: Somehow make this event driven so that it tells the user what activity is on - LogitechHarmonyActivityAccessory.prototype.getPowerState = function (callback) { - var self = this; +LogitechHarmonyActivityAccessory.prototype.updateActivityState = function (currentActivity) { + this.isOn = (currentActivity === this.id); + // Force get to trigger 'change' if needed + this.getService(Service.Switch) + .getCharacteristic(Characteristic.On) + .getValue(); +}; - this.hub.getCurrentActivity().then(function (currentActivity) { - callback(currentActivity === self.id); - }).catch(function (err) { - self.log('Unable to get current activity with error', err); - callback(false); - }); - }; +LogitechHarmonyActivityAccessory.prototype.setPowerState = function (state, callback) { - LogitechHarmonyActivityAccessory.prototype.setPowerState = function (state) { - var self = this; + var self = this; - this.log('Set activity ' + this.name + ' power state to ' + state); + this.log('Set activity ' + this.name + ' power state to ' + state); - this.hub.startActivity(self.id) - .then(function () { - self.log('Finished setting activity ' + self.name + ' power state to ' + state); - }) - .catch(function (err) { - self.log('Failed setting activity ' + self.name + ' power state to ' + state + ' with error ' + err); - }); - }; + var nextActivity = self.id; + this.hub.startActivity(nextActivity) + .then(function () { + self.log('Finished setting activity ' + self.name + ' power state to ' + state); + self.updateCurrentActivity(nextActivity); + if (callback) callback(null, state); + }) + .catch(function (err) { + self.log('Failed setting activity ' + self.name + ' power state to ' + state + ' with error ' + err); + if (callback) callback(err); + }); +}; module.exports.platform = LogitechHarmonyPlatform; From 6604c2b69aff3b4156102e0aaa20487413aa4a0f Mon Sep 17 00:00:00 2001 From: Kraig McConaghy Date: Sun, 18 Oct 2015 19:08:46 -0500 Subject: [PATCH 7/8] Changed structure to handle numerous issues plus add enhancements. No activity off properly calls "Power Off" (and thus "Power Off" has been removed). HomeKit responses are properly set back when activity finishes switching. Some amount of handling has been added for timeouts while switching activities as well as request sync (you don't seem to be able to send multiple requests to the hub simultaneously, and the activity switching sometimes times out the connection, so a reconnect system was added). --- package.json | 3 +- platforms/LogitechHarmony.js | 257 ++++++++++++++++++++--------------- 2 files changed, 148 insertions(+), 112 deletions(-) diff --git a/package.json b/package.json index bc26177..65f1b4a 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "komponist" : "0.1.0", "yamaha-nodejs": "0.4.x", "debug": "^2.2.0", - "node-xmpp-client": "1.0.0-alpha23" + "node-xmpp-client": "1.0.0-alpha23", + "queue": "^3.1.0" } } diff --git a/platforms/LogitechHarmony.js b/platforms/LogitechHarmony.js index 2167b1c..c8249f4 100644 --- a/platforms/LogitechHarmony.js +++ b/platforms/LogitechHarmony.js @@ -29,6 +29,7 @@ var Characteristic = require("hap-nodejs").Characteristic; var Accessory = require("hap-nodejs").Accessory; var uuid = require("hap-nodejs").uuid; var inherits = require('util').inherits; +var queue = require('queue'); function sortByKey (array, key) { @@ -47,136 +48,185 @@ function LogitechHarmonyPlatform (log, config) { LogitechHarmonyPlatform.prototype = { - // Find one Harmony remote hub (only support one for now) - locateHub: function (callback) { - var self = this; - - // Connect to a Harmony hub - var createClient = function (ipAddress) { - self.log("Connecting to Logitech Harmony remote hub..."); - - harmony(ipAddress) - .then(function (client) { - self.log("Connected to Logitech Harmony remote hub"); - - // prevent connection from closing - setTimeout(function() { - setInterval(function() { - self.log("Sending command to prevent timeout"); - client.getCurrentActivity().then(self.updateCurrentActivity.bind(self)); - }, 20000); - }, 5000); - - callback(null, client); - }); - }; - - // Use the ip address in configuration if available - if (this.ip_address) { - console.log("Using Logitech Harmony hub ip address from configuration"); - - return createClient(this.ip_address) - } - - this.log("Searching for Logitech Harmony remote hubs..."); - - // Discover the harmony hub with bonjour - var discover = new harmonyDiscover(_harmonyHubPort); - - // TODO: Support update event with some way to add accessories - // TODO: Have some kind of timeout with an error message. Right now this searches forever until it finds one hub. - discover.on('online', function (hubInfo) { - self.log("Found Logitech Harmony remote hub: " + hubInfo.ip); - - // Stop looking for hubs once we find the first one - // TODO: Support multiple hubs - discover.stop(); - - createClient(hubInfo.ip); - }); - - // Start looking for hubs - discover.start(); - }, - - updateCurrentActivity: function(currentActivity) { - var actAccessories = this.activityAccessories; - if (actAccessories instanceof Array) { - actAccessories.map(function(a) { a.updateActivityState(currentActivity); }); - } - }, - accessories: function (callback) { - var self = this; + var plat = this; var foundAccessories = []; + var activityAccessories = []; + var hub = null; + var hubIP = null; + var hubQueue = queue(); + hubQueue.concurrency = 1; // Get the first hub - this.locateHub(function (err, hub) { + locateHub(function (err, client, clientIP) { if (err) throw err; - self.log("Fetching Logitech Harmony devices and activites..."); + plat.log("Fetching Logitech Harmony devices and activites..."); + hub = client; + hubIP = clientIP; //getDevices(hub); - getActivities(hub); + getActivities(); }); - // Get Harmony Devices - /* - var getDevices = function(hub) { - self.log("Fetching Logitech Harmony devices..."); + // Find one Harmony remote hub (only support one for now) + function locateHub(callback) { + // Use the ip address in configuration if available + if (plat.ip_address) { + console.log("Using Logitech Harmony hub ip address from configuration"); - hub.getDevices() - .then(function (devices) { - self.log("Found devices: ", devices); + return createClient(plat.ip_address, callback) + } - var sArray = sortByKey(json['result'],"Name"); + plat.log("Searching for Logitech Harmony remote hubs..."); - sArray.map(function(s) { - accessory = new LogitechHarmonyActivityAccessory(self.log, self.server, self.port, false, s.idx, s.Name, s.HaveDimmer, s.MaxDimLevel, (s.SubType=="RGB")||(s.SubType=="RGBW")); - foundAccessories.push(accessory); + // Discover the harmony hub with bonjour + var discover = new harmonyDiscover(_harmonyHubPort); + + // TODO: Support update event with some way to add accessories + // TODO: Have some kind of timeout with an error message. Right now this searches forever until it finds one hub. + discover.on('online', function (hubInfo) { + plat.log("Found Logitech Harmony remote hub: " + hubInfo.ip); + + // Stop looking for hubs once we find the first one + // TODO: Support multiple hubs + discover.stop(); + + createClient(hubInfo.ip, callback); + }); + + // Start looking for hubs + discover.start(); + } + + // Connect to a Harmony hub + function createClient(ipAddress, callback) { + plat.log("Connecting to Logitech Harmony remote hub..."); + harmony(ipAddress) + .then(function (client) { + plat.log("Connected to Logitech Harmony remote hub"); + callback(null, client, ipAddress); }); - - callback(foundAccessories); - }); - }; - */ + } // Get Harmony Activities - var getActivities = function(hub) { - self.log("Fetching Logitech Harmony activities..."); + function getActivities() { + plat.log("Fetching Logitech Harmony activities..."); hub.getActivities() .then(function (activities) { - self.log("Found activities: \n" + activities.map(function (a) { return "\t" + a.label; }).join("\n")); + plat.log("Found activities: \n" + activities.map(function (a) { return "\t" + a.label; }).join("\n")); hub.getCurrentActivity().then(function (currentActivity) { var actAccessories = []; var sArray = sortByKey(activities, "label"); sArray.map(function(s) { - var accessory = new LogitechHarmonyActivityAccessory(self.log, hub, s, self.updateCurrentActivity.bind(self)); - accessory.updateActivityState(currentActivity); - actAccessories.push(accessory); - foundAccessories.push(accessory); + var accessory = createActivityAccessory(s); + if (accessory.id > 0) { + accessory.updateActivityState(currentActivity); + actAccessories.push(accessory); + foundAccessories.push(accessory); + } }); - self.activityAccessories = actAccessories; + activityAccessories = actAccessories; + keepAliveRefreshLoop(); callback(foundAccessories); }).catch(function (err) { - self.log('Unable to get current activity with error', err); - callback(false); + plat.log('Unable to get current activity with error', err); + throw err; }); }); - }; + } + + function createActivityAccessory(activity) { + var accessory = new LogitechHarmonyActivityAccessory(plat.log, activity, changeCurrentActivity.bind(plat), -1); + return accessory; + } + + var isChangingActivity = false; + function changeCurrentActivity(nextActivity, callback) { + if (!nextActivity) { + nextActivity = -1; + } + plat.log('Queue activity to ' + nextActivity); + executeOnHub(function(h, cb) { + plat.log('Set activity to ' + nextActivity); + h.startActivity(nextActivity) + .then(function () { + cb(); + isChangingActivity = false; + plat.log('Finished setting activity to ' + nextActivity); + updateCurrentActivity(nextActivity); + if (callback) callback(null, nextActivity); + }) + .catch(function (err) { + cb(); + isChangingActivity = false; + plat.log('Failed setting activity to ' + nextActivity + ' with error ' + err); + if (callback) callback(err); + }); + }, function(){ + callback(Error("Set activity failed too many times")); + }); + } + + function updateCurrentActivity(currentActivity) { + var actAccessories = activityAccessories; + if (actAccessories instanceof Array) { + actAccessories.map(function(a) { a.updateActivityState(currentActivity); }); + } + } + + // prevent connection from closing + function keepAliveRefreshLoop() { + setTimeout(function() { + setInterval(function() { + executeOnHub(function(h, cb) { + plat.log("Refresh Status"); + h.getCurrentActivity() + .then(function(currentActivity){ + cb(); + updateCurrentActivity(currentActivity); + }) + .catch(cb); + }); + }, 20000); + }, 5000); + } + + function executeOnHub(func, funcMaxTimeout) + { + if (!func) return; + hubQueue.push(function(cb) { + var tout = setTimeout(function(){ + plat.log("Reconnecting to Hub " + hubIP); + createClient(hubIP, function(err, newHub){ + if (err) throw err; + hub = newHub; + if (funcMaxTimeout) { + funcMaxTimeout(); + } + cb(); + }); + }, 30000); + func(hub, function(){ + clearTimeout(tout); + cb(); + }); + }); + if (!hubQueue.running){ + hubQueue.start(); + } + } } }; -function LogitechHarmonyActivityAccessory (log, hub, details, updateCurrentActivity) { +function LogitechHarmonyActivityAccessory (log, details, changeCurrentActivity) { this.log = log; - this.hub = hub; - this.details = details; this.id = details.id; this.name = details.label; this.isOn = false; - this.updateCurrentActivity = updateCurrentActivity; + this.changeCurrentActivity = changeCurrentActivity; Accessory.call(this, this.name, uuid.generate(this.id)); var self = this; @@ -194,7 +244,7 @@ function LogitechHarmonyActivityAccessory (log, hub, details, updateCurrentActiv }) .on('set', this.setPowerState.bind(this)); -}; +} inherits(LogitechHarmonyActivityAccessory, Accessory); LogitechHarmonyActivityAccessory.prototype.parent = Accessory.prototype; LogitechHarmonyActivityAccessory.prototype.getServices = function() { @@ -210,22 +260,7 @@ LogitechHarmonyActivityAccessory.prototype.updateActivityState = function (curre }; LogitechHarmonyActivityAccessory.prototype.setPowerState = function (state, callback) { - - var self = this; - - this.log('Set activity ' + this.name + ' power state to ' + state); - - var nextActivity = self.id; - this.hub.startActivity(nextActivity) - .then(function () { - self.log('Finished setting activity ' + self.name + ' power state to ' + state); - self.updateCurrentActivity(nextActivity); - if (callback) callback(null, state); - }) - .catch(function (err) { - self.log('Failed setting activity ' + self.name + ' power state to ' + state + ' with error ' + err); - if (callback) callback(err); - }); + this.changeCurrentActivity(state ? this.id : null, callback); }; module.exports.platform = LogitechHarmonyPlatform; From 626871680c35ee820248e5ef342a19286dea1c7f Mon Sep 17 00:00:00 2001 From: Kraig McConaghy Date: Mon, 19 Oct 2015 13:46:06 -0500 Subject: [PATCH 8/8] Reorganized dependencies to help with merge --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 65f1b4a..0704076 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,9 @@ "node-icontrol": "^0.1.5", "node-milight-promise": "0.0.x", "node-persist": "0.0.x", + "node-xmpp-client": "1.0.0-alpha23", "q": "1.4.x", + "queue": "^3.1.0", "tough-cookie": "^2.0.0", "request": "2.49.x", "sonos": "0.8.x", @@ -39,8 +41,6 @@ "xmldoc": "0.1.x", "komponist" : "0.1.0", "yamaha-nodejs": "0.4.x", - "debug": "^2.2.0", - "node-xmpp-client": "1.0.0-alpha23", - "queue": "^3.1.0" + "debug": "^2.2.0" } }