From 0730a50cdab3e10d6e74f76737123d154830e295 Mon Sep 17 00:00:00 2001 From: Patrik Mayer Date: Fri, 13 Dec 2019 22:11:31 +0100 Subject: [PATCH] using own forked node-lox-ws-api, better connection information, fixed #35 --- loxone/loxone.js | 125 +++++++++++++++++++++++++-------------------- package-lock.json | 127 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 8 +-- 3 files changed, 201 insertions(+), 59 deletions(-) create mode 100644 package-lock.json diff --git a/loxone/loxone.js b/loxone/loxone.js index 4b17a93..dd578b9 100644 --- a/loxone/loxone.js +++ b/loxone/loxone.js @@ -14,8 +14,8 @@ module.exports = function (RED) { return res.json(""); } - var configNode = RED.nodes.getNode(req.query.id); - var result = { + let configNode = RED.nodes.getNode(req.query.id); + let result = { state: 'error', msg: 'miniserver not connected', structure: {} @@ -40,16 +40,16 @@ module.exports = function (RED) { RED.httpAdmin.get('/loxone-miniserver/struct-changed', function (req, res) { - var result = { + let result = { state: 'error', msg: 'miniserver not connected', structure: {} }; - var username = req.query.username; - var password = req.query.password; + let username = req.query.username; + let password = req.query.password; - var configNode = RED.nodes.getNode(req.query.id); + let configNode = RED.nodes.getNode(req.query.id); if (configNode) { if (!username) { @@ -77,7 +77,7 @@ module.exports = function (RED) { return; } - var data = ''; + let data = ''; http_res.on('data', function (chunk) { data += chunk; }); @@ -112,7 +112,7 @@ module.exports = function (RED) { RED.nodes.createNode(this, config); - var node = this; + let node = this; node.connected = false; node.authenticated = false; node.connection = null; @@ -126,6 +126,7 @@ module.exports = function (RED) { node._webserviceNodeQueue = []; //only webservice nodes which are waiting for a return will be here node._otherEvents = []; + // TODO //do nothing if miniserver connection is not active /* if (config.active !== true) { @@ -135,14 +136,14 @@ module.exports = function (RED) { return; }*/ - var text_logger_limit = 100; + let text_logger_limit = 100; node.encMethod = 'Token-Enc'; if (encMethods.hasOwnProperty(config.enctype)) { node.encMethod = encMethods[config.enctype]; } - var client = new node_lox_ws_api( + let client = new node_lox_ws_api( config.host + ':' + config.port, node.credentials.username, node.credentials.password, @@ -154,7 +155,6 @@ module.exports = function (RED) { client.on('connect', function () { node.log('Miniserver connected (' + config.host + ':' + config.port + ') using ' + node.encMethod); - node.connected = true; }); client.on('authorized', function () { @@ -162,22 +162,29 @@ module.exports = function (RED) { node.authenticated = true; node.connection = client; + node.connected = true; node.setConnectionStatusMsg("green", "connected", "dot"); sendOnlineNodeMsg(true, config.id); + }); - client.on('connect_failed', function () { - node.error('Miniserver connect failed'); + client.on('get_structure_file', function (data) { + node.log("got structure file " + data.lastModified); + node.structureData = prepareStructure(data); + }); + + client.on('connect_failed', function (error, reason) { + node.error('Miniserver connect failed: ' + reason, JSON.stringify(error)); node.setConnectionStatusMsg("red", "connection failed", "ring"); }); - client.on('connection_error', function (error) { - node.error('Miniserver connection error: ' + error); + client.on('connection_error', function (error, reason) { + node.error('Miniserver connection error: ' + reason, JSON.stringify(error)); node.setConnectionStatusMsg("red", "connection error", "ring"); }); - client.on('close', function () { - node.log("connection closed"); + client.on('close', function (info, reason) { + node.log("connection closed: " + reason, info); node.connected = false; node.authenticated = false; node.connection = null; @@ -212,13 +219,13 @@ module.exports = function (RED) { break; case 'control': - for (var i in node._webserviceNodeQueue) { + for (let i in node._webserviceNodeQueue) { - var wsNode = node._webserviceNodeQueue[i]; + let wsNode = node._webserviceNodeQueue[i]; if (wsNode.uri === 'j' + message.control) { - var msg = { + let msg = { 'payload': message.value, 'topic': message.control, 'code': parseInt(message.code) @@ -226,7 +233,7 @@ module.exports = function (RED) { //and parse all values to msg.data if (message.hasOwnProperty('data') && message.data.hasOwnProperty('LL')) { - var additionalData = JSON.parse(JSON.stringify(message.data.LL)); + let additionalData = JSON.parse(JSON.stringify(message.data.LL)); delete additionalData.Code; delete additionalData.control; @@ -238,8 +245,15 @@ module.exports = function (RED) { } //add miniserver info - msg.msInfo = node.structureData.msInfo; - msg.lastModified = node.structureData.lastModified; + if(node.structureData) { + msg.msInfo = node.structureData.msInfo; + msg.lastModified = node.structureData.lastModified; + } else { + msg.msInfo = null; + msg.lastModified = null; + + node.log("structure data not ready yet, webservice request processed but without msInfo and lastModified"); + } //send the data out of the requesting node wsNode.send(msg); @@ -268,7 +282,7 @@ module.exports = function (RED) { nodeData.hasOwnProperty('miniserver') && nodeData.miniserver === node.id) { - var keepaliveNode = RED.nodes.getNode(nodeData.id); + let keepaliveNode = RED.nodes.getNode(nodeData.id); if (keepaliveNode) { keepaliveNode.send({ topic: 'keepalive', @@ -295,11 +309,6 @@ module.exports = function (RED) { //node.log('received text messages:' + messages.length); }); - client.on('get_structure_file', function (data) { - node.log("got structure file " + data.lastModified); - node.structureData = prepareStructure(data); - }); - client.on('update_event_value', _updateEvent); client.on('update_event_text', _updateEvent); client.on('update_event_daytimer', _updateEvent); @@ -310,8 +319,6 @@ module.exports = function (RED) { //on (full-)deploys close event shutdown the client if (node.connected) { client.once('close', function () { - - //console.log('We are here!'); done(); }); client.abort(); @@ -408,7 +415,7 @@ module.exports = function (RED) { LoxoneMiniserver.prototype.setConnectionStatusMsg = function (color, text, shape) { shape = shape || 'dot'; - var newState = function (item) { + let newState = function (item) { item.status({ fill: color, shape: shape, @@ -426,12 +433,12 @@ module.exports = function (RED) { LoxoneMiniserver.prototype.findControlByState = function (uuid) { //search in all controls for given state uuid to find the corresponding control - for (var wantedControlUuid in this.structureData.controls) { + for (let wantedControlUuid in this.structureData.controls) { if ( this.structureData.controls.hasOwnProperty(wantedControlUuid) && this.structureData.controls[wantedControlUuid].hasOwnProperty('states') ) { - for (var curState in this.structureData.controls[wantedControlUuid].states) { + for (let curState in this.structureData.controls[wantedControlUuid].states) { if ( this.structureData.controls[wantedControlUuid].states.hasOwnProperty(curState) && @@ -450,7 +457,7 @@ module.exports = function (RED) { LoxoneMiniserver.prototype.buildMsgObject = function (event, uuid, controlStructure) { //get state name - var stateName; + let stateName; for (stateName in controlStructure.states) { if ( controlStructure.states.hasOwnProperty(stateName) && @@ -466,23 +473,22 @@ module.exports = function (RED) { } //evaluate payload - var payload; + let payload; try { payload = JSON.parse(event); - } - catch (err) { + } catch (err) { payload = event; } //check if control has a room - var room = null; + let room = null; if (controlStructure.room && this.structureData.rooms[controlStructure.room].name) { room = this.structureData.rooms[controlStructure.room].name; } //check if control has a category - var category = null; + let category = null; if (controlStructure.cat && this.structureData.cats[controlStructure.cat].name) { category = this.structureData.cats[controlStructure.cat].name; } @@ -507,8 +513,8 @@ module.exports = function (RED) { LoxoneMiniserver.prototype.handleEvent = function (uuid, event) { - var i, curNode, curRoom, curCategory; - var controlStructure = this.findControlByState(uuid); + let i, curNode, curRoom, curCategory; + let controlStructure = this.findControlByState(uuid); //do we have a control for this uuid? could also be weather or global if (controlStructure) { @@ -554,7 +560,7 @@ module.exports = function (RED) { }; function prepareStructure(data) { - var structure = { + let structure = { rooms: data.rooms || {}, cats: data.cats || {}, controls: {}, @@ -562,7 +568,7 @@ module.exports = function (RED) { lastModified: data.lastModified }; - for (var uuid in data.controls) { + for (let uuid in data.controls) { if (!data.controls.hasOwnProperty(uuid)) { continue; } @@ -570,7 +576,7 @@ module.exports = function (RED) { structure.controls[uuid] = data.controls[uuid]; if (data.controls[uuid].hasOwnProperty('subControls')) { - for (var sub_uuid in data.controls[uuid].subControls) { + for (let sub_uuid in data.controls[uuid].subControls) { if (!data.controls[uuid].subControls.hasOwnProperty(sub_uuid)) { continue; } @@ -584,7 +590,7 @@ module.exports = function (RED) { } return structure; - }; + } function sendOnlineNodeMsg(online, configId) { @@ -596,7 +602,7 @@ module.exports = function (RED) { theNode.hasOwnProperty('miniserver') && theNode.miniserver === configId) { - var node = RED.nodes.getNode(theNode.id); + let node = RED.nodes.getNode(theNode.id); if (node) { /* @@ -621,7 +627,7 @@ module.exports = function (RED) { function LoxoneControlInNode(config) { RED.nodes.createNode(this, config); - var node = this; + let node = this; node.state = config.state; node.control = config.control; @@ -649,7 +655,7 @@ module.exports = function (RED) { function LoxoneControlOutNode(config) { RED.nodes.createNode(this, config); - var node = this; + let node = this; node.control = config.control; node.miniserver = RED.nodes.getNode(config.miniserver); @@ -661,6 +667,8 @@ module.exports = function (RED) { this.on('input', function (msg) { if (node.miniserver.connected && node.miniserver.connection) { node.miniserver.connection.send_control_command(node.control, msg.payload); + } else { + node.log(node.id + ' was triggered but miniserver is not connected.'); } }); @@ -679,11 +687,10 @@ module.exports = function (RED) { function LoxoneWebServiceNode(config) { RED.nodes.createNode(this, config); - var node = this; + let node = this; node.miniserver = RED.nodes.getNode(config.miniserver); - if (node.miniserver) { node.miniserver.registerWebserviceNode(node); @@ -697,8 +704,7 @@ module.exports = function (RED) { this.on('input', function (msg) { - node.status({}); - var wantedURI = msg.uri || config.uri; + let wantedURI = msg.uri || config.uri; if (!wantedURI.length) { node.status({ @@ -726,13 +732,20 @@ module.exports = function (RED) { if (node.miniserver.connected && node.miniserver.connection) { node.miniserver.addWebserviceNodeToQueue(node); node.miniserver.connection.send_command(node.uri); + } else { + node.status({ + fill: 'red', + shape: 'dot', + text: 'not connected' + }); + node.log(node.id + " tried to call " + wantedURI + " but miniserver is not connected."); + return null; } }); } - } RED.nodes.registerType('loxone-webservice', LoxoneWebServiceNode); @@ -756,7 +769,7 @@ module.exports = function (RED) { function LoxoneStreamInNode(config) { RED.nodes.createNode(this, config); - var node = this; + let node = this; node.category = config.category; node.room = config.room; @@ -785,7 +798,7 @@ module.exports = function (RED) { function LoxoneStreamAllNode(config) { RED.nodes.createNode(this, config); - var node = this; + let node = this; node.category = config.category; node.room = config.room; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..dd9e18c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,127 @@ +{ + "name": "node-red-contrib-loxone", + "version": "0.10.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "node-lox-ws-api": { + "version": "file:../node-lox-ws-api", + "requires": { + "websocket": "^1.0.28" + }, + "dependencies": { + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" + } + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "websocket": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", + "integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==", + "requires": { + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "nan": "^2.14.0", + "typedarray-to-buffer": "^3.1.5", + "yaeti": "^0.0.6" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" + } + } + } + } +} diff --git a/package.json b/package.json index 6cd4712..27d9085 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,20 @@ { "name": "node-red-contrib-loxone", - "version": "0.10.2", + "version": "0.10.3", "description": "Connecting the Loxone Miniserver to node-red via Websocket API", "license": "MIT", "keywords": [ - "node-red", "loxone" + "node-red", + "loxone" ], "node-red": { "nodes": { "loxone": "loxone/loxone.js" } }, + "author": "Patrik Mayer