From 7a0f9787e1ec113124cce4ea956ca2bd429b0ca9 Mon Sep 17 00:00:00 2001 From: biddster Date: Thu, 23 Nov 2017 00:06:44 +0000 Subject: [PATCH 1/7] #3 Start to implement the other hs100 actuations such as getPowerState --- .gitignore | 3 +- index.js | 81 +++++++++++++++++++++++++++++++++++++-------------- package.json | 81 ++++++++++++++++++++++++++++++++------------------- tests/test.js | 76 +++++++++++++++++++++++++++++++++-------------- 4 files changed, 166 insertions(+), 75 deletions(-) diff --git a/.gitignore b/.gitignore index 178c3cf..851c424 100644 --- a/.gitignore +++ b/.gitignore @@ -49,4 +49,5 @@ jspm_packages .yarn-integrity .idea - +.history +.vscode diff --git a/index.js b/index.js index 8f4855e..d65d7bd 100644 --- a/index.js +++ b/index.js @@ -22,34 +22,68 @@ THE SOFTWARE. */ -module.exports = function (RED) { +module.exports = function hs100(RED) { 'use strict'; var Hs100Api = require('fx-hs100-api'); - RED.nodes.registerType('hs100', function (config) { + hs100.supportedActuations = [ + 'Info', + 'SysInfo', + 'CloudInfo', + 'Consumption', + 'PowerState', + 'ScheduleNextAction', + 'ScheduleRules', + 'AwayRules', + 'TimerRules', + 'Time', + 'TimeZone', + 'ScanInfo', + 'Model' + ]; + hs100.newHs100Client = function() { + return new Hs100Api.Client(); + }; + + RED.nodes.registerType('hs100', function(config) { RED.nodes.createNode(this, config); var node = this; - var client = new Hs100Api.Client(); - var plug = client.getPlug({host: config.host}); + var client = hs100.newHs100Client(); + var plug = client.getPlug({ host: config.host }); - node.on('input', function (msg) { - if (msg.payload === 'consumption' || msg.topic === 'consumption') { - plug.getConsumption().then(function (data) { - node.send({payload: data}); - }).catch(errorHandler); - } else if (msg.payload === 'on' || msg.topic === 'on') { + node.on('input', function(msg) { + if (msg.payload === 'on' || msg.topic === 'on') { setPowerState(true); } else if (msg.payload === 'off' || msg.topic === 'off') { setPowerState(false); } else { - errorHandler(new Error('Actuation must be one of [on, off, consumption]')); + var actuation = hs100.supportedActuations.find(function(supportedActuation) { + // Have to do this lowercase as there are prior versions of this node which allow + // lowercase actuations in the incoming mesage. + var sa = supportedActuation.toLowerCase(); + return msg.topic === sa || msg.payload === sa; + }); + if (actuation) { + plug['get' + actuation]() + .then(function(data) { + node.send({ topic: actuation.toLowerCase(), payload: data }); + }) + .catch(errorHandler); + } else { + errorHandler( + new Error( + 'Actuation must be one of [on, off] or ' + + supportedActuations.toString() + ) + ); + } } }); - node.on('close', function () { + node.on('close', function() { client.socket.close(); }); @@ -57,20 +91,23 @@ module.exports = function (RED) { node.status({ fill: 'orange', shape: on ? 'dot' : 'circle', - text: 'Turning ' + ( on ? 'on' : 'off') + text: 'Turning ' + (on ? 'on' : 'off') }); - plug.setPowerState(on).then(function () { - node.status({ - fill: 'green', - shape: on ? 'dot' : 'circle', - text: on ? 'on' : 'off' - }); - }).catch(errorHandler); + plug + .setPowerState(on) + .then(function() { + node.status({ + fill: 'green', + shape: on ? 'dot' : 'circle', + text: on ? 'on' : 'off' + }); + }) + .catch(errorHandler); } function errorHandler(err) { node.error(err); - node.status({fill: 'red', shape: 'dot', text: err.message}); + node.status({ fill: 'red', shape: 'dot', text: err.message }); } }); -}; \ No newline at end of file +}; diff --git a/package.json b/package.json index d5e758b..1802950 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,54 @@ { - "name": "node-red-contrib-hs100", - "version": "0.3.0", - "description": "", - "main": "index.js", - "keywords": ["node-red", "tp-link", "tplink", "hs100"], - "devDependencies": { - "chai": "^3.0.0", - "markdown-to-html": "0.0.13", - "mocha": "^3.1.2", - "node-red-contrib-mock-node": "^0.3.0" - }, - "directories": { - "test": "tests" - }, - "scripts": { - "test": "node_modules/.bin/mocha tests/test.js" - }, - "author": "@biddster", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/biddster/node-red-contrib-hs100.git" - }, - "dependencies": { - "fx-hs100-api": "^0.3.0" - }, - "node-red": { - "nodes": { - "hs100": "index.js" + "name": "node-red-contrib-hs100", + "version": "0.3.0", + "description": "", + "main": "index.js", + "keywords": ["node-red", "tp-link", "tplink", "hs100"], + "devDependencies": { + "chai": "^3.0.0", + "eslint": "^4.11.0", + "eslint-config-biddster": "^0.4.0", + "eslint-config-prettier": "^2.8.0", + "markdown-to-html": "0.0.13", + "mocha": "^3.1.2", + "node-red-contrib-mock-node": "^0.3.0", + "prettier": "^1.8.2" + }, + "directories": { + "test": "tests" + }, + "scripts": { + "test": "node_modules/.bin/mocha tests/test.js" + }, + "author": "@biddster", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/biddster/node-red-contrib-hs100.git" + }, + "dependencies": { + "fx-hs100-api": "^0.3.0" + }, + "node-red": { + "nodes": { + "hs100": "index.js" + } + }, + "eslintConfig": { + "env": { + "es6": true, + "node": true, + "mocha": true + }, + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + "extends": ["eslint-config-biddster/es6-node", "prettier"] + }, + "prettier": { + "singleQuote": true, + "tabWidth": 4, + "printWidth": 96 } - } } diff --git a/tests/test.js b/tests/test.js index d3b209c..6b2d496 100644 --- a/tests/test.js +++ b/tests/test.js @@ -22,31 +22,63 @@ THE SOFTWARE. */ -"use strict"; +('use strict'); var assert = require('chai').assert; var mock = require('node-red-contrib-mock-node'); -var Hs100Api = require('fx-hs100-api'); +var nodeRedModule = require('../index.js'); - -describe('hs100', function () { +describe('hs100', function() { this.timeout(60000); - describe('test', function () { - it('should turn a known socket on and off', function (done) { - var client = new Hs100Api.Client(); - var plug = client.getPlug({host: '192.168.74.82'}); - plug.setPowerState(true); - console.log('Turned it on'); - plug.getInfo().then(function (device) { - console.log(JSON.stringify(device, null, 4)); - setTimeout(function () { - plug.setPowerState(false); - console.log('Turned it off'); - setTimeout(function () { - console.log('Exiting test'); - done(); - }, 10000); - }, 10000); - }); - }); + it('should turn a socket on', function(done) { + var node = newNode(); + node.emit('input', { payload: 'on' }); + setTimeout(function() { + assert.strictEqual(node.status().text, 'on'); + assert.strictEqual(node.status().shape, 'dot'); + done(); + }, 1000); + }); + it('should turn a socket off', function(done) { + var node = newNode(); + node.emit('input', { payload: 'off' }); + setTimeout(function() { + assert.strictEqual(node.status().text, 'off'); + assert.strictEqual(node.status().shape, 'circle'); + done(); + }, 1000); + }); + it('should emit consumption data', function(done) { + var node = newNode(); + node.emit('input', { payload: 'consumption' }); + setTimeout(function() { + assert.deepEqual(node.sent(0).payload, { mocked: 'Consumption' }); + assert.strictEqual(node.sent(0).topic, 'consumption'); + done(); + }, 1000); }); }); + +function newNode() { + return mock(nodeRedModule, {}, null, function(module, node) { + module.newHs100Client = function() { + return { + getPlug: function() { + var plug = {}; + module.supportedActuations.forEach(function(actuation) { + plug['get' + actuation] = function() { + return new Promise(function(resolve, reject) { + resolve({ mocked: actuation }); + }); + }; + }); + plug.setPowerState = function(state) { + return new Promise(function(resolve, reject) { + resolve({ mocked: state }); + }); + }; + return plug; + } + }; + }; + }); +} From 2fc9f6ba1ea3fde4b658eddcdc49345995faebee Mon Sep 17 00:00:00 2001 From: biddster Date: Thu, 23 Nov 2017 00:09:05 +0000 Subject: [PATCH 2/7] #3 add nyc to get code coverage. --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1802950..e55ab0e 100644 --- a/package.json +++ b/package.json @@ -12,13 +12,14 @@ "markdown-to-html": "0.0.13", "mocha": "^3.1.2", "node-red-contrib-mock-node": "^0.3.0", + "nyc": "^11.3.0", "prettier": "^1.8.2" }, "directories": { "test": "tests" }, "scripts": { - "test": "node_modules/.bin/mocha tests/test.js" + "test": "nyc --reporter=html node_modules/.bin/mocha -R spec ./tests/test.js" }, "author": "@biddster", "license": "MIT", From 93cc94edcc2f5db876c16e78ce1c8ccfb3af437d Mon Sep 17 00:00:00 2001 From: biddster Date: Thu, 23 Nov 2017 00:26:30 +0000 Subject: [PATCH 3/7] #3 Further test coverage. --- index.js | 8 ++++++-- tests/test.js | 21 +++++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index d65d7bd..b09f291 100644 --- a/index.js +++ b/index.js @@ -75,8 +75,12 @@ module.exports = function hs100(RED) { } else { errorHandler( new Error( - 'Actuation must be one of [on, off] or ' + - supportedActuations.toString() + 'Actuation must be one of on,off,' + + hs100.supportedActuations + .map(function(actuation) { + return actuation.toLowerCase(); + }) + .toString() ) ); } diff --git a/tests/test.js b/tests/test.js index 6b2d496..c91dbbc 100644 --- a/tests/test.js +++ b/tests/test.js @@ -35,8 +35,9 @@ describe('hs100', function() { setTimeout(function() { assert.strictEqual(node.status().text, 'on'); assert.strictEqual(node.status().shape, 'dot'); + node.emit('close'); done(); - }, 1000); + }, 10); }); it('should turn a socket off', function(done) { var node = newNode(); @@ -44,8 +45,9 @@ describe('hs100', function() { setTimeout(function() { assert.strictEqual(node.status().text, 'off'); assert.strictEqual(node.status().shape, 'circle'); + node.emit('close'); done(); - }, 1000); + }, 10); }); it('should emit consumption data', function(done) { var node = newNode(); @@ -53,8 +55,18 @@ describe('hs100', function() { setTimeout(function() { assert.deepEqual(node.sent(0).payload, { mocked: 'Consumption' }); assert.strictEqual(node.sent(0).topic, 'consumption'); + node.emit('close'); done(); - }, 1000); + }, 10); + }); + it('should handle errors', function(done) { + var node = newNode(); + node.emit('input', { payload: 'wibble' }); + setTimeout(function() { + assert.isNotNull(node.error(0)); + node.emit('close'); + done(); + }, 10); }); }); @@ -77,7 +89,8 @@ function newNode() { }); }; return plug; - } + }, + socket: { close: function() {} } }; }; }); From 569aad4a087d5d7de77aa352d5948bd1741ea423 Mon Sep 17 00:00:00 2001 From: biddster Date: Thu, 23 Nov 2017 21:38:44 +0000 Subject: [PATCH 4/7] #3 Use the mock node. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e55ab0e..27ed799 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "eslint-config-prettier": "^2.8.0", "markdown-to-html": "0.0.13", "mocha": "^3.1.2", - "node-red-contrib-mock-node": "^0.3.0", + "node-red-contrib-mock-node": "^0.4.0", "nyc": "^11.3.0", "prettier": "^1.8.2" }, From aafb326eb99b7cc9a07b07590675c83dc4e6f55c Mon Sep 17 00:00:00 2001 From: biddster Date: Thu, 23 Nov 2017 23:25:21 +0000 Subject: [PATCH 5/7] #3 Support all features of the hs100 library. Get test code coverage up near 100%. --- README.md | 44 ++++++++++++++------ index.js | 57 +++++++++++++------------- package.json | 111 +++++++++++++++++++++++++++----------------------- tests/test.js | 19 +++++++-- 4 files changed, 135 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index 8b48a0f..f228586 100644 --- a/README.md +++ b/README.md @@ -2,34 +2,52 @@ This Node-RED node is for controlling tp-link Wi-Fi Smart Plug - Model HS100. -This node has only been tested with a HS100(UK). The HS100 is also available in US and EU plug versions. We expect they will work too. +This node has only been tested with a HS100(UK). The HS100 is also available in US and EU plug +versions. We expect they will work too. -This node simply wraps the excellent work here https://github.com/czjs2/hs100-api. +This node simply wraps the excellent work here https://github.com/czjs2/hs100-api. # Installation Change directory to your node red installation: $ npm install node-red-contrib-hs100 - + Alternatively, use the Palette Manager in Node-RED. # Configuration -Drag this node on to a worksheet and double click it. Enter the IP address of the plug on your network. Save and deploy. - - -# Actuation +Drag this node on to a worksheet and double click it. Enter the IP address of the plug on your +network. Save and deploy. + +# Actuations + +This node supports a number of actuations that are invoked by sending a msg.topic or msg.payload +to the node's input. + +| Topic/Payload | Description | +| ------------------ | :----------------------------------------------------------------------------------: | +| on | To turn the HS100 on. | +| off | To turn the HS100 off. | +| info | Get all plug info, combination of sysinfo, cloudinfo consumption, schedulenextaction | +| sysinfo | Get general plug information. | +| cloudinfo | Get TP-Link Cloud information. | +| consumption | Get power consumption data | +| powerstate | Returns true if plug is on. | +| schedulenextaction | | +| schedulerules | | +| awayrules | | +| timerrules | | +| time | | +| timezone | | +| scaninfo | | +| model | | ## Turn on -To turn the HS100 on, send a message to this node's input with the topic or payload set to `on`. - ## Turn off -To turn the HS100 off, send a message to this node's input with the topic or payload set to `off`. - ## Obtain power consumption data -To obtain the power consumption, send a message to this node's input with the topic or payload set to `consumption`. -The consumption data will be sent via this node's output in `msg.payload`. +To obtain the power consumption, send a message to this node's input with the topic or payload +set to `consumption`. The consumption data will be sent via this node's output in `msg.payload`. diff --git a/index.js b/index.js index b09f291..75d204e 100644 --- a/index.js +++ b/index.js @@ -27,21 +27,21 @@ module.exports = function hs100(RED) { var Hs100Api = require('fx-hs100-api'); - hs100.supportedActuations = [ - 'Info', - 'SysInfo', - 'CloudInfo', - 'Consumption', - 'PowerState', - 'ScheduleNextAction', - 'ScheduleRules', - 'AwayRules', - 'TimerRules', - 'Time', - 'TimeZone', - 'ScanInfo', - 'Model' - ]; + hs100.supportedActuations = { + info: 'getInfo', + sysinfo: 'getSysInfo', + cloudinfo: 'getCloudInfo', + consumption: 'getConsumption', + powerstate: 'getPowerState', + schedulenextaction: 'getScheduleNextAction', + schedulerules: 'getScheduleRules', + awayrules: 'getAwayRules', + timerrules: 'getTimerRules', + time: 'getTime', + timezone: 'getTimeZone', + scaninfo: 'getScanInfo', + model: 'getModel' + }; hs100.newHs100Client = function() { return new Hs100Api.Client(); @@ -60,27 +60,18 @@ module.exports = function hs100(RED) { } else if (msg.payload === 'off' || msg.topic === 'off') { setPowerState(false); } else { - var actuation = hs100.supportedActuations.find(function(supportedActuation) { - // Have to do this lowercase as there are prior versions of this node which allow - // lowercase actuations in the incoming mesage. - var sa = supportedActuation.toLowerCase(); - return msg.topic === sa || msg.payload === sa; - }); + var actuation = getActuation(msg.payload) || getActuation(msg.topic); if (actuation) { - plug['get' + actuation]() + plug[actuation.method]() .then(function(data) { - node.send({ topic: actuation.toLowerCase(), payload: data }); + node.send({ topic: actuation.name, payload: data }); }) .catch(errorHandler); } else { errorHandler( new Error( 'Actuation must be one of on,off,' + - hs100.supportedActuations - .map(function(actuation) { - return actuation.toLowerCase(); - }) - .toString() + Object.keys(hs100.supportedActuations).toString() ) ); } @@ -109,6 +100,16 @@ module.exports = function hs100(RED) { .catch(errorHandler); } + function getActuation(actuation) { + if (actuation) { + var method = hs100.supportedActuations[actuation.toLowerCase()]; + if (method) { + return { name: actuation, method: method }; + } + } + return null; + } + function errorHandler(err) { node.error(err); node.status({ fill: 'red', shape: 'dot', text: err.message }); diff --git a/package.json b/package.json index 27ed799..40701de 100644 --- a/package.json +++ b/package.json @@ -1,55 +1,64 @@ { - "name": "node-red-contrib-hs100", - "version": "0.3.0", - "description": "", - "main": "index.js", - "keywords": ["node-red", "tp-link", "tplink", "hs100"], - "devDependencies": { - "chai": "^3.0.0", - "eslint": "^4.11.0", - "eslint-config-biddster": "^0.4.0", - "eslint-config-prettier": "^2.8.0", - "markdown-to-html": "0.0.13", - "mocha": "^3.1.2", - "node-red-contrib-mock-node": "^0.4.0", - "nyc": "^11.3.0", - "prettier": "^1.8.2" - }, - "directories": { - "test": "tests" - }, - "scripts": { - "test": "nyc --reporter=html node_modules/.bin/mocha -R spec ./tests/test.js" - }, - "author": "@biddster", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/biddster/node-red-contrib-hs100.git" - }, - "dependencies": { - "fx-hs100-api": "^0.3.0" - }, - "node-red": { - "nodes": { - "hs100": "index.js" - } + "name": "node-red-contrib-hs100", + "version": "0.3.0", + "description": "", + "main": "index.js", + "keywords": [ + "node-red", + "tp-link", + "tplink", + "hs100" + ], + "devDependencies": { + "chai": "^3.0.0", + "eslint": "^4.11.0", + "eslint-config-biddster": "^0.4.0", + "eslint-config-prettier": "^2.8.0", + "lodash": "^4.17.4", + "markdown-to-html": "0.0.13", + "mocha": "^3.1.2", + "node-red-contrib-mock-node": "^0.4.0", + "nyc": "^11.3.0", + "prettier": "^1.8.2" + }, + "directories": { + "test": "tests" + }, + "scripts": { + "test": "nyc --reporter=html node_modules/.bin/mocha -R spec ./tests/test.js" + }, + "author": "@biddster", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/biddster/node-red-contrib-hs100.git" + }, + "dependencies": { + "fx-hs100-api": "^0.3.0" + }, + "node-red": { + "nodes": { + "hs100": "index.js" + } + }, + "eslintConfig": { + "env": { + "es6": true, + "node": true, + "mocha": true }, - "eslintConfig": { - "env": { - "es6": true, - "node": true, - "mocha": true - }, - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module" - }, - "extends": ["eslint-config-biddster/es6-node", "prettier"] + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" }, - "prettier": { - "singleQuote": true, - "tabWidth": 4, - "printWidth": 96 - } + "extends": [ + "eslint-config-biddster/es6-node", + "prettier" + ] + }, + "prettier": { + "singleQuote": true, + "tabWidth": 4, + "printWidth": 96 + } } diff --git a/tests/test.js b/tests/test.js index c91dbbc..6d9866b 100644 --- a/tests/test.js +++ b/tests/test.js @@ -26,6 +26,7 @@ var assert = require('chai').assert; var mock = require('node-red-contrib-mock-node'); var nodeRedModule = require('../index.js'); +var _ = require('lodash'); describe('hs100', function() { this.timeout(60000); @@ -53,12 +54,22 @@ describe('hs100', function() { var node = newNode(); node.emit('input', { payload: 'consumption' }); setTimeout(function() { - assert.deepEqual(node.sent(0).payload, { mocked: 'Consumption' }); + assert.deepEqual(node.sent(0).payload, { mocked: 'getConsumption' }); assert.strictEqual(node.sent(0).topic, 'consumption'); node.emit('close'); done(); }, 10); }); + it('should emit sysinfo data', function(done) { + var node = newNode(); + node.emit('input', { topic: 'SysInfo' }); + setTimeout(function() { + assert.deepEqual(node.sent(0).payload, { mocked: 'getSysInfo' }); + assert.strictEqual(node.sent(0).topic, 'SysInfo'); + node.emit('close'); + done(); + }, 10); + }); it('should handle errors', function(done) { var node = newNode(); node.emit('input', { payload: 'wibble' }); @@ -76,10 +87,10 @@ function newNode() { return { getPlug: function() { var plug = {}; - module.supportedActuations.forEach(function(actuation) { - plug['get' + actuation] = function() { + _.values(module.supportedActuations).forEach(function(method) { + plug[method] = function() { return new Promise(function(resolve, reject) { - resolve({ mocked: actuation }); + resolve({ mocked: method }); }); }; }); From 86ba54fe7c471d53cf7179c52d12a9b3321821bc Mon Sep 17 00:00:00 2001 From: biddster Date: Thu, 23 Nov 2017 23:41:11 +0000 Subject: [PATCH 6/7] #3 add todo --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 75d204e..aff59d4 100644 --- a/index.js +++ b/index.js @@ -27,6 +27,7 @@ module.exports = function hs100(RED) { var Hs100Api = require('fx-hs100-api'); + // TODO address the disparity of not having on and off in here. It bothers me. hs100.supportedActuations = { info: 'getInfo', sysinfo: 'getSysInfo', From 2cc3941e64b15fefde5f4d79eaeef630225021fb Mon Sep 17 00:00:00 2001 From: biddster Date: Thu, 23 Nov 2017 23:41:54 +0000 Subject: [PATCH 7/7] Prep 0.4.0 --- package.json | 112 ++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 40701de..26dc5e0 100644 --- a/package.json +++ b/package.json @@ -1,64 +1,56 @@ { - "name": "node-red-contrib-hs100", - "version": "0.3.0", - "description": "", - "main": "index.js", - "keywords": [ - "node-red", - "tp-link", - "tplink", - "hs100" - ], - "devDependencies": { - "chai": "^3.0.0", - "eslint": "^4.11.0", - "eslint-config-biddster": "^0.4.0", - "eslint-config-prettier": "^2.8.0", - "lodash": "^4.17.4", - "markdown-to-html": "0.0.13", - "mocha": "^3.1.2", - "node-red-contrib-mock-node": "^0.4.0", - "nyc": "^11.3.0", - "prettier": "^1.8.2" - }, - "directories": { - "test": "tests" - }, - "scripts": { - "test": "nyc --reporter=html node_modules/.bin/mocha -R spec ./tests/test.js" - }, - "author": "@biddster", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/biddster/node-red-contrib-hs100.git" - }, - "dependencies": { - "fx-hs100-api": "^0.3.0" - }, - "node-red": { - "nodes": { - "hs100": "index.js" - } - }, - "eslintConfig": { - "env": { - "es6": true, - "node": true, - "mocha": true + "name": "node-red-contrib-hs100", + "version": "0.4.0", + "description": "", + "main": "index.js", + "keywords": ["node-red", "tp-link", "tplink", "hs100"], + "devDependencies": { + "chai": "^3.0.0", + "eslint": "^4.11.0", + "eslint-config-biddster": "^0.4.0", + "eslint-config-prettier": "^2.8.0", + "lodash": "^4.17.4", + "markdown-to-html": "0.0.13", + "mocha": "^3.1.2", + "node-red-contrib-mock-node": "^0.4.0", + "nyc": "^11.3.0", + "prettier": "^1.8.2" + }, + "directories": { + "test": "tests" + }, + "scripts": { + "test": "nyc --reporter=html node_modules/.bin/mocha -R spec ./tests/test.js" + }, + "author": "@biddster", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/biddster/node-red-contrib-hs100.git" }, - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module" + "dependencies": { + "fx-hs100-api": "^0.3.0" }, - "extends": [ - "eslint-config-biddster/es6-node", - "prettier" - ] - }, - "prettier": { - "singleQuote": true, - "tabWidth": 4, - "printWidth": 96 - } + "node-red": { + "nodes": { + "hs100": "index.js" + } + }, + "eslintConfig": { + "env": { + "es6": true, + "node": true, + "mocha": true + }, + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + "extends": ["eslint-config-biddster/es6-node", "prettier"] + }, + "prettier": { + "singleQuote": true, + "tabWidth": 4, + "printWidth": 96 + } }