diff --git a/index.js b/index.js index e376abc..e68d07d 100644 --- a/index.js +++ b/index.js @@ -9,14 +9,14 @@ module.exports = function (homebridge) { homebridge.registerPlatform("homebridge-broadlink-platform-outlet", "broadlinkPlatformOutlet", broadlinkPlatform); } -function broadlinkPlatform(log, config, api) { - this.log = log; - this.config = config; - if (api) this.api = api; -} - -broadlinkPlatform.prototype = { - accessories: function (callback) { +class broadlinkPlatform { + constructor(log, config, api) { + this.log = log; + this.config = config; + if (api) + this.api = api; + } + accessories(callback) { //For each device in cfg, create an accessory! var accessories = this.config.accessories; var accessoriesList = []; @@ -33,11 +33,11 @@ broadlinkPlatform.prototype = { accessories[i].outletTimer = accessories[i].timer[outlet - 1]; accessories[i].interval = accessories[i].interval || 0; - accessoriesList.push(new BroadlinkAccessory(this.log, accessories[i])); + accessoriesList.push(new broadlinkAccessory(this.log, accessories[i])); } this.log(`${accessories[i].name} - Created`); } else { - accessoriesList.push(new BroadlinkAccessory(this.log, accessories[i])); + accessoriesList.push(new broadlinkAccessory(this.log, accessories[i])); this.log(`${accessories[i].name} - Created`); } } @@ -45,45 +45,46 @@ broadlinkPlatform.prototype = { } } -function BroadlinkAccessory(log, config) { - this.log = log; - this.config = config; - this.type = config.type || MP; // Expected value MP or SP (default) - this.outletName = config.outletName || ""; - this.name = (config.name || this.type) + (this.type == MP ? ": " : "") + this.outletName; - this.index = config.index || 0; - this.mac = config.mac; - this.timer = config.outletTimer; - this.interval = config.interval < 1000 ? 1000 : config.interval; - - // Other value - this.powered = false; - this.firstTime = true; - this.onGetState = false; - this.onSetState = false; - - if (!this.mac) throw new Error("You must provide a config value for 'mac' address."); - - // MAC string to MAC buffer - this.mac_buff = function (mac) { - var mb = new Buffer.alloc(6, 0); - if (mac) { - var values = mac.split(':'); - if (!values || values.length != 6) { - throw new Error('Invalid MAC [' + mac + ']; should follow pattern ##:##:##:##:##:##'); - } - for (var i = 0; i < values.length; ++i) { - var tmpByte = parseInt(values[i], 16); - mb.writeUInt8(tmpByte, i); +class broadlinkAccessory { + constructor(log, config) { + this.log = log; + this.config = config; + this.type = config.type || MP; // Expected value MP or SP (default) + this.outletName = config.outletName || ""; + this.name = (config.name || this.type) + (this.type == MP ? ": " : "") + this.outletName; + this.index = config.index || 0; + this.mac = config.mac; + this.timer = config.outletTimer; + this.interval = config.interval < 1000 ? 1000 : config.interval; + + // Other value + this.powered = false; + this.firstTime = true; + this.onGetState = false; + this.onSetState = false; + this.device = null; + + if (!this.mac) throw new Error("You must provide a config value for 'mac' address."); + + // MAC string to MAC buffer + this.mac_buff = function (mac) { + var mb = new Buffer.alloc(6, 0); + if (mac) { + var values = mac.split(':'); + if (!values || values.length != 6) { + throw new Error('Invalid MAC [' + mac + ']; should follow pattern ##:##:##:##:##:##'); + } + for (var i = 0; i < values.length; ++i) { + var tmpByte = parseInt(values[i], 16); + mb.writeUInt8(tmpByte, i); + } } - } - return mb; + return mb; + }; } -} -BroadlinkAccessory.prototype = { - getServices: function () { + getServices() { var type = this.config.type; var services = []; @@ -107,118 +108,115 @@ BroadlinkAccessory.prototype = { this.updateState(); return services; - }, + } - discover: function (broadlink) { + discover(broadlink) { try { broadlink.discover(); } catch (error) { this.onGetState = false; this.onSetState = false; } - }, - - // Get MP/SP outlets status - getState: function (callback) { - if (this.onGetState || this.onSetState) { - if (callback) callback(null, this.powered); - return; - } + } - var device = new broadlink(); - - this.onGetState = true; - this.discover(device); - device.on("deviceReady", (dev) => { - if (this.mac_buff(this.mac).equals(dev.mac) && !this.onSetState) { - dev.check_power(); - dev.on(this.type == MP ? "mp_power" : "power", (statuses) => { - var status = (this.type == MP ? statuses[this.index - 1] : statuses) ? true : false; - - dev.exit(); - this.onGetState = false; - - if (this.firstTime || this.powered != status) { - this.powered = status ? true : false; - this.firstTime = false; - this.switchService.updateCharacteristic(Characteristic.On, this.powered); - this.logState(); - } - }); - } else { - device = null; - this.onGetState = false; - } + // Get device + async _getDevice() { + return new Promise(async (resolve) => { + var device = new broadlink(); + var checkAgain; - device = null; + // Find device + this.discover(device); + checkAgain = setInterval(() => { + this.discover(device); + }, 1000); + + // Device is ready + device.on("deviceReady", (dev) => { + if (this.mac_buff(this.mac).equals(dev.mac)) { + clearInterval(checkAgain); + device = null; + + // return the device + resolve(dev); + } + }); }); + } - if (callback) callback(null, this.powered); - }, + // Initiialized device + async _initDevice() { + this.device = await this._getDevice(); - // Set MP/SP outlets status - setState: function (state, callback) { - var device = new broadlink(); - var checkAgain; + // When recived power + this.device.on(this.type == MP ? "mp_power" : "power", (statuses) => { + var status = (this.type == MP ? statuses[this.index - 1] : statuses) ? true : false; - this.onSetState = true; - state = state ? true : false; + if (this.firstTime || this.powered != status) { + if (this.firstTime) this.firstTime = false; - this.log(`[${this.name}] 👈`); + this.powered = status ? true : false; + this.switchService.updateCharacteristic(Characteristic.On, this.powered); - this.discover(device); - checkAgain = setInterval(() => { - this.discover(device); - }, 1000); - - device.on("deviceReady", (dev) => { - if (this.mac_buff(this.mac).equals(dev.mac)) { - // Set the power - this.powered = state; - if (this.type == MP) dev.set_power(this.index, this.powered); - else dev.set_power(this.powered); this.logState(); + } - // Check status while making sure state changed - dev.check_power(); - dev.on(this.type == MP ? "mp_power" : "power", (statuses) => { - if (this.mac_buff(this.mac).equals(dev.mac)) { - var status = (this.type == MP ? statuses[this.index - 1] : statuses) ? true : false; + this.onGetState = false; + }); + } - if (status != state) this.switchService.setCharacteristic(Characteristic.On, this.powered); + // Get MP/SP outlets status + async getState(callback) { + callback(null, this.powered); + } - // Stop the set loop - this.onSetState = false; - } - }); + // Set MP/SP outlets status + async setState(state, callback) { + // Initialized device if it get disconnected + if (!this.device) await this._initDevice(); - // Stop the loop - clearInterval(checkAgain); - dev.exit(); - callback(null); - } + // Log state + this.log(`[${this.name}] 👈`); - device = null; - }); - }, + // Set the power + this.powered = state ? true : false; + if (this.type == MP) this.device.set_power(this.index, this.powered); + else this.device.set_power(this.powered); + this.switchService.updateCharacteristic(Characteristic.On, this.powered); + + // Log state + this.logState(); + + // Send check power command + this.device.check_power(); + + // Callback; + callback(null); + } // Update outlets status based on the last status - updateState: function () { + async updateState() { + // Send check power command and loop it if (this.mainInterval) clearInterval(this.mainInterval); + this.mainInterval = setInterval(async () => { + this.onGetState = true; + + // Initialized device if it get disconnected + if (!this.device) await this._initDevice(); - this.mainInterval = setInterval(() => { - this.getState(); + // Send check power command + this.device.check_power(); }, this.interval); - }, + } - logState: function (extra, tail) { + logState(extra, tail) { var message = `${extra ? extra + ": " : ""}${this.bulb(this.powered)} [${this.name}] ${tail ? "-> " + tail : ""}`; if (message != this._message) this.log(message); this._message = message; - }, + } - bulb: function (state) { + bulb(state) { return state ? "🟡" : "⚪️"; } } diff --git a/package-lock.json b/package-lock.json index 6e5608d..1c3d340 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,35 @@ { "name": "homebridge-broadlink-platform-outlet", - "version": "1.0.4", - "lockfileVersion": 1, + "version": "1.0.5", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "homebridge-broadlink-platform-outlet", + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "broadlinkjs-dw": "^0.1.11" + }, + "engines": { + "homebridge": ">=1.3.0", + "node": ">=12.0.0" + } + }, + "node_modules/@types/node": { + "version": "7.10.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-7.10.14.tgz", + "integrity": "sha512-29GS75BE8asnTno3yB6ubOJOO0FboExEqNJy4bpz0GSmW/8wPTNL4h9h63c6s1uTrOopCmJYe/4yJLh5r92ZUA==" + }, + "node_modules/broadlinkjs-dw": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/broadlinkjs-dw/-/broadlinkjs-dw-0.1.11.tgz", + "integrity": "sha512-BVWH3lCBPES9bYjDgS37wETUXPE1N2yiBYHLsoXB/uXIVbHT2Lu2VbpAj7wuWCjXprWKbNeA5vD6dL51Qyxv0A==", + "dependencies": { + "@types/node": "^7.0.5" + } + } + }, "dependencies": { "@types/node": { "version": "7.10.14", diff --git a/package.json b/package.json index 0e30727..0b8ff36 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-broadlink-platform-outlet", - "version": "1.0.5", + "version": "1.1.0", "description": "Homebridge plugin for Broadlink MP1 and SP2/3", "main": "index.js", "scripts": { @@ -31,6 +31,6 @@ }, "homepage": "https://github.com/dwaan/homebridge-broadlink-platform#readme", "dependencies": { - "broadlinkjs-dw": "^0.1.11" + "broadlinkjs-dw": "^0.1.12" } -} +} \ No newline at end of file