From 9042d8a4edfb027ec8f460180027ffbf80422b51 Mon Sep 17 00:00:00 2001 From: Elias Karakoulakis Date: Mon, 5 Dec 2016 07:27:49 +0200 Subject: [PATCH] send direct API call results --- .gitignore | 1 + 10-zwave.html | 99 +++++++++++----------- 10-zwave.js | 220 +++++++++++++++++++++++++++++++----------------- LICENSE.md | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 18 ++-- 5 files changed, 431 insertions(+), 133 deletions(-) create mode 100644 .gitignore create mode 100644 LICENSE.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/10-zwave.html b/10-zwave.html index 5fb4893..34e9e39 100644 --- a/10-zwave.html +++ b/10-zwave.html @@ -15,7 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - + --> - + diff --git a/10-zwave.js b/10-zwave.js index b9a64f7..24da4ff 100644 --- a/10-zwave.js +++ b/10-zwave.js @@ -31,7 +31,7 @@ var debug = false; if (debug) console.log("booting up node-red-contrib-openzwave"); module.exports = function(RED) { - console.log('loading '+ require.resolve('openzwave-shared')); + console.log('loading ' + require.resolve('openzwave-shared')); var OpenZWave = require('openzwave-shared'); var ozwConfig = {}; @@ -53,7 +53,8 @@ module.exports = function(RED) { function zwsubscribe(nrNode, event, callback) { if (!(event in nrNodeSubscriptions)) nrNodeSubscriptions[event] = {}; - if (debug) console.log('subscribing %s(%s) to event %s', nrNode.type, nrNode.id, event); + if (debug) console.log('subscribing %s(%s) to event %s', nrNode.type, + nrNode.id, event); nrNodeSubscriptions[event][nrNode.id] = callback; } @@ -61,7 +62,8 @@ module.exports = function(RED) { function zwunsubscribe(nrNode) { for (var event in nrNodeSubscriptions) { if (nrNodeSubscriptions.hasOwnProperty(event)) { - if (debug) console.log('unsubscribing %s(%s) from %s', nrNode.type, nrNode.id, event); + if (debug) console.log('unsubscribing %s(%s) from %s', nrNode.type, + nrNode.id, event); delete nrNodeSubscriptions[event][nrNode.id]; } } @@ -75,9 +77,9 @@ module.exports = function(RED) { if (debug) console.log("zwcallback(event: %s, args: %j)", event, arghash); // Add uuid if (arghash.nodeid !== undefined && HOMENAME !== undefined) - arghash.uuid = UUIDPREFIX+'-' + - HOMENAME + '-' + - arghash.nodeid; + arghash.uuid = UUIDPREFIX + '-' + + HOMENAME + '-' + + arghash.nodeid; if (nrNodeSubscriptions.hasOwnProperty(event)) { var nrNodes = nrNodeSubscriptions[event]; @@ -85,7 +87,8 @@ module.exports = function(RED) { for (var nrnid in nrNodes) { if (nrNodes.hasOwnProperty(nrnid)) { var nrNode = RED.nodes.getNode(nrnid); - if (debug) console.log("zwcallback => %j, %s, args %j", nrNode, event, arghash); + if (debug) console.log("zwcallback => %j, %s, args %j", nrNode, + event, arghash); nrNodes[nrnid].call(nrNode, event, arghash); updateNodeRedStatus(nrNode); } @@ -99,7 +102,7 @@ module.exports = function(RED) { nrNode.status({ fill: driverReadyStatus ? "green" : "red", text: driverReadyStatus ? "connected" : "disconnected", - shape:"ring" + shape: "ring" }); } @@ -107,10 +110,11 @@ module.exports = function(RED) { function driverReady(homeid) { driverReadyStatus = true; ozwConfig.homeid = homeid; - var homeHex = '0x'+ homeid.toString(16); + var homeHex = '0x' + homeid.toString(16); HOMENAME = homeHex; ozwConfig.name = homeHex; - if (debug) console.log('scanning Zwave network with homeid %s...', homeHex); + if (debug) console.log('scanning Zwave network with homeid %s...', + homeHex); zwcallback('driver ready', ozwConfig); } @@ -121,13 +125,20 @@ module.exports = function(RED) { function nodeAdded(nodeid) { zwnodes[nodeid] = { - manufacturer: '', manufacturerid: '', - product: '', producttype: '', productid: '', - type: '', name: '', loc: '', + manufacturer: '', + manufacturerid: '', + product: '', + producttype: '', + productid: '', + type: '', + name: '', + loc: '', classes: {}, ready: false, }; - zwcallback('node added', {"nodeid": nodeid}); + zwcallback('node added', { + "nodeid": nodeid + }); } function valueAdded(nodeid, comclass, valueId) { @@ -136,10 +147,14 @@ module.exports = function(RED) { if (!zwnodes[nodeid]['classes'][comclass][valueId.instance]) zwnodes[nodeid]['classes'][comclass][valueId.instance] = {}; // add to cache - zwnodes[nodeid]['classes'][comclass][valueId.instance][valueId.index] = valueId; + zwnodes[nodeid]['classes'][comclass][valueId.instance][valueId.index] = + valueId; // tell NR zwcallback('value added', { - "nodeid": nodeid, "cmdclass": comclass, "instance": valueId.instance, "cmdidx": valueId.index, + "nodeid": nodeid, + "cmdclass": comclass, + "instance": valueId.instance, + "cmdidx": valueId.index, "currState": valueId['value'], "label": valueId['label'], "units": valueId['units'], @@ -151,33 +166,42 @@ module.exports = function(RED) { // valueId: OpenZWave ValueID (struct) - not just a boolean var oldst; if (zwnodes[nodeid].ready || allowunreadyupdates) { - oldst = zwnodes[nodeid]['classes'][comclass][valueId.instance][valueId.index].value; + oldst = zwnodes[nodeid]['classes'][comclass][valueId.instance][valueId.index] + .value; if (debug) { - console.log('node%d: changed: %d:%s:%s->%s', nodeid, comclass, valueId['label'], oldst, valueId['value']); + console.log('node%d: changed: %d:%s:%s->%s', nodeid, comclass, + valueId['label'], oldst, valueId['value']); console.log('node%d: value=%s', nodeid, JSON.stringify(valueId)); } // tell NR only if the node is marked as ready zwcallback('value changed', { - "nodeid": nodeid, "cmdclass": comclass, "instance": valueId.instance, "cmdidx": valueId.index, - "oldState": oldst, "currState": valueId['value'], + "nodeid": nodeid, + "cmdclass": comclass, + "instance": valueId.instance, + "cmdidx": valueId.index, + "oldState": oldst, + "currState": valueId['value'], "label": valueId['label'], "units": valueId['units'], "value": valueId }); } // update cache - zwnodes[nodeid]['classes'][comclass][valueId.instance][valueId.index] = valueId; + zwnodes[nodeid]['classes'][comclass][valueId.instance][valueId.index] = + valueId; } function valueRemoved(nodeid, comclass, instance, index) { if (zwnodes[nodeid] && zwnodes[nodeid]['classes'] && zwnodes[nodeid]['classes'][comclass] && - zwnodes[nodeid]['classes'][comclass][index]) - { + zwnodes[nodeid]['classes'][comclass][index]) { delete zwnodes[nodeid]['classes'][comclass][index]; zwcallback('value deleted', { - "nodeid": nodeid, "cmdclass": comclass, "cmdidx": index, "instance": instance + "nodeid": nodeid, + "cmdclass": comclass, + "cmdidx": index, + "instance": instance }); } } @@ -192,35 +216,44 @@ module.exports = function(RED) { // for (comclass in zwnodes[nodeid]['classes']) { switch (comclass) { - case 0x25: // COMMAND_CLASS_SWITCH_BINARY - case 0x26: // COMMAND_CLASS_SWITCH_MULTILEVEL - case 0x30: // COMMAND_CLASS_SENSOR_BINARY - case 0x31: // COMMAND_CLASS_SENSOR_MULTILEVEL - case 0x60: // COMMAND_CLASS_MULTI_INSTANCE - ozwDriver.enablePoll(nodeid, comclass); - break; + case 0x25: // COMMAND_CLASS_SWITCH_BINARY + case 0x26: // COMMAND_CLASS_SWITCH_MULTILEVEL + case 0x30: // COMMAND_CLASS_SENSOR_BINARY + case 0x31: // COMMAND_CLASS_SENSOR_MULTILEVEL + case 0x60: // COMMAND_CLASS_MULTI_INSTANCE + ozwDriver.enablePoll(nodeid, comclass); + break; } var values = zwnodes[nodeid]['classes'][comclass]; if (debug) { console.log('node%d: class %d', nodeid, comclass); for (idx in values) - console.log('node%d: %s=%s', nodeid, values[idx]['label'], values[idx]['value']); + console.log('node%d: %s=%s', nodeid, values[idx]['label'], values[ + idx]['value']); } }; // - zwcallback('node ready', {nodeid: nodeid, nodeinfo: nodeinfo}); + zwcallback('node ready', { + nodeid: nodeid, + nodeinfo: nodeinfo + }); } function nodeEvent(nodeid, evtcode) { zwcallback('node event', { - "nodeid": nodeid, "event": evtcode + "nodeid": nodeid, + "event": evtcode }); } function notification(nodeid, notif, help) { if (debug) console.log('node%d: %s', nodeid, help); - zwcallback('notification', {nodeid: nodeid, notification: notif, help: help}); + zwcallback('notification', { + nodeid: nodeid, + notification: notif, + help: help + }); } function scanComplete() { @@ -230,28 +263,33 @@ module.exports = function(RED) { function controllerCommand(nodeid, state, errcode, help) { if (debug) console.log('ZWave controller command feedback received'); - zwcallback('controller command', {nodeid: nodeid, state: state, errcode: errcode, help: help}); + zwcallback('controller command', { + nodeid: nodeid, + state: state, + errcode: errcode, + help: help + }); } // list of events emitted by OpenZWave and redirected to Node flows by the mapped function var ozwEvents = { - 'driver ready' : driverReady, + 'driver ready': driverReady, 'driver failed': driverFailed, - 'node added' : nodeAdded, - 'node ready' : nodeReady, - 'node event' : nodeEvent, - 'value added' : valueAdded, - 'value changed': valueChanged, + 'node added': nodeAdded, + 'node ready': nodeReady, + 'node event': nodeEvent, + 'value added': valueAdded, + 'value changed': valueChanged, 'value removed': valueRemoved, - 'notification' : notification, + 'notification': notification, 'scan complete': scanComplete, 'controller command': controllerCommand } // ========================== function ZWaveController(n) { - // ========================== - RED.nodes.createNode(this,n); + // ========================== + RED.nodes.createNode(this, n); this.name = n.port; this.port = n.port; this.driverattempts = n.driverattempts; @@ -264,15 +302,15 @@ module.exports = function(RED) { // so we only get to initialise one single OZW driver (a lengthy process) if (!ozwDriver) { ozwDriver = new OpenZWave({ - Logging: debug, + Logging: debug, ConsoleOutput: debug, QueueLogLevel: (debug ? 8 : 6), - UserPath: RED.settings.userDir, + UserPath: RED.settings.userDir, DriverMaxAttempts: this.driverattempts }); /* =============== OpenZWave events ================== */ - Object.keys(ozwEvents).forEach(function (evt) { - if (debug) console.log(node.name+' addListener ' + evt); + Object.keys(ozwEvents).forEach(function(evt) { + if (debug) console.log(node.name + ' addListener ' + evt); ozwDriver.on(evt, ozwEvents[evt]); }) } @@ -285,7 +323,9 @@ module.exports = function(RED) { }); zwsubscribe(node, 'driver failed', function(event, data) { - console.log('failed to start ZWave driver, is there a ZWave stick attached to %s ?', n.port); + console.log( + 'failed to start ZWave driver, is there a ZWave stick attached to %s ?', + n.port); }); zwsubscribe(node, 'scan complete', function(event, data) { @@ -306,7 +346,7 @@ module.exports = function(RED) { // ========================= function ZWaveIn(config) { - // ========================= + // ========================= RED.nodes.createNode(this, config); this.name = config.name; // @@ -320,20 +360,30 @@ module.exports = function(RED) { /* =============== Node-Red events ================== */ this.on("close", function() { // set zwave node status as disconnected - node.status({fill:"red",shape:"ring",text:"disconnected"}); + node.status({ + fill: "red", + shape: "ring", + text: "disconnected" + }); // remove all event subscriptions for this node zwunsubscribe(this); if (debug) console.log('zwave-in: close'); }); this.on("error", function() { // what? there are no errors. there never were. - node.status({fill:"yellow",shape:"ring",text:"error"}); + node.status({ + fill: "yellow", + shape: "ring", + text: "error" + }); }); /* =============== OpenZWave events ================== */ - Object.keys(ozwEvents).forEach(function (key) { + Object.keys(ozwEvents).forEach(function(key) { zwsubscribe(node, key, function(event, data) { - var msg = {'topic': 'zwave: '+event}; + var msg = { + 'topic': 'zwave: ' + event + }; if (data) msg.payload = data; if (debug) console.log('===> ZWAVE-IN injecting: %j', msg); node.send(msg); @@ -348,7 +398,7 @@ module.exports = function(RED) { // ========================= function ZWaveOut(config) { - // ========================= + // ========================= RED.nodes.createNode(this, config); this.name = config.name; // @@ -368,11 +418,11 @@ module.exports = function(RED) { try { payload = (typeof(msg.payload) === "string") ? JSON.parse(msg.payload) : msg.payload; - } catch(err) { - node.error(node.name+': illegal msg.payload! ('+err+')'); + } catch (err) { + node.error(node.name + ': illegal msg.payload! (' + err + ')'); return; } - switch(true) { + switch (true) { // switch On/Off: for basic single-instance switches and dimmers case /switchOn/.test(msg.topic): ozwDriver.setValue(payload.nodeid, 37, 1, 0, true); @@ -381,38 +431,46 @@ module.exports = function(RED) { ozwDriver.setValue(payload.nodeid, 37, 1, 0, false); break; - // setLevel: for dimmers + // setLevel: for dimmers case /setLevel/.test(msg.topic): ozwDriver.setValue(payload.nodeid, 38, 1, 0, payload.value); break; - // setValue: for everything else + // setValue: for everything else case /setValue/.test(msg.topic): if (debug) console.log("ZWaveOut.setValue payload: %j", payload); ozwDriver.setValue( - payload.nodeid, - (payload.cmdclass || 37),// default cmdclass: on-off + payload.nodeid, (payload.cmdclass || 37), // default cmdclass: on-off (payload.instance || 1), // default instance - (payload.cmdidx || 0), // default cmd index + (payload.cmdidx || 0), // default cmd index payload.value ); break; - /* EXPERIMENTAL: send basically every available command down - * to OpenZWave, just name the function in the message topic - * and pass in the payload the function's args as an array: - * {"topic": "someOpenZWaveCommand", "payload": [1, 2, 3]} - * */ + /* EXPERIMENTAL: send basically every available command down + * to OpenZWave, just name the function in the message topic + * and pass in the arguments as "payload.args" as an array: + * {"topic": "someOpenZWaveCommand", "payload": {"args": [1, 2, 3]}} + * If the command needs the HomeID as the 1st arg, use "payload.prependHomeId" + * */ default: - if (msg.topic && typeof ozwDriver[msg.topic] === 'function' && payload) { + if (msg.topic && typeof ozwDriver[msg.topic] === 'function' && + payload) { var args = payload.args || []; if (payload.prependHomeId) args.unshift(ozwConfig.homeid); - node.log('OpenZWave API: attempting direct call to '+msg.topic) + node.log('OpenZWave API: attempting direct call to ' + msg.topic) try { var result = ozwDriver[msg.topic].apply(ozwDriver, args); - node.log('OpenZWave API: direct call success, result=' + result); - } catch(err) { - node.warn('OpenZWave API: direct call to '+ msg.topic+' failed: '+err); + node.log('OpenZWave API: direct call success, result=' + + result); + if (typeof result != 'undefined') { + msg.payload.result = result; + // send off the direct API call's result to the output + node.send(msg); + } + } catch (err) { + node.warn('OpenZWave API: direct call to ' + msg.topic + + ' failed: ' + err); } } } @@ -420,7 +478,11 @@ module.exports = function(RED) { this.on("close", function() { // set zwave node status as disconnected - node.status({fill:"red",shape:"ring",text:"disconnecting"}); + node.status({ + fill: "red", + shape: "ring", + text: "disconnecting" + }); // remove all event subscriptions for this node zwunsubscribe(this); node.log('zwave-out: close'); @@ -428,11 +490,15 @@ module.exports = function(RED) { this.on("error", function() { // there are. no. russians. in afghanistan. - node.status({fill:"yellow",shape:"ring",text:"error"}); + node.status({ + fill: "yellow", + shape: "ring", + text: "error" + }); }); /* =============== OpenZWave events ================== */ - Object.keys(ozwEvents).forEach(function (key) { + Object.keys(ozwEvents).forEach(function(key) { zwsubscribe(node, key, function(event, data) { // nuttin ;) we merely subscribe to have the NR node status update :) }); diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..ec99d84 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,226 @@ +## License + +Copyright (c) 2015 Elias Karakoulakis + +This software follows Node-Red's licencing scheme, Apache-2.0, which +is copied verbatim: + +### Apache-2.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +### node-openzwave-shared + +node-openzwave-shared (aka openzwave-shared) is licensed under the ISC license: + + Copyright (c) 2013 Jonathan Perkin + Copyright (c) 2015 Elias Karakoulakis + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +### OpenZWave + + Copyright (c) 2010 Mal Lansell + + SOFTWARE NOTICE AND LICENSE + + OpenZWave is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + OpenZWave is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with OpenZWave. If not, see . + +You can find full copies of the GPL licenses under OpenZWave's +installation directory. diff --git a/README.md b/README.md index 9059257..cabbbfc 100644 --- a/README.md +++ b/README.md @@ -29,22 +29,28 @@ Use this node to send arbitrary commands to the ZWave appliances. For the momen For a full list of ZWave command classes, see -- **(New since version 1.1.0)** Experimental support for the *full OpenZWave API*: +### Support for the **full OpenZWave API**: + You can invoke ANY of the OpenZWave::Manager commands that are accepted by openzwave-shared (see [this source file for a list of supported commands](https://github.com/OpenZWave/node-openzwave-shared/blob/master/src/openzwave.cc#L59)). You should also consult the [official OpenZWave::Manager class documentation.](http://www.openzwave.com/dev/classOpenZWave_1_1Manager.html) The Node-Red message payload should contain an array of the command arguments **in the correct order**. For example: - * to add a new ZWave node to your network, you need to prepend the ZWave Home ID to the call as follows: + * to **add a new ZWave node** to your network, you need to prepend the ZWave Home ID to the `addNode()` management call as follows: `{"topic": "addNode", "payload": {"prependHomeId": true}}` - * to add a new *secure* ZWave node to your network, you'll also need to set the `_doSecurity` parameter to true as follows: + * to **enable polling** for ZWave node #5 for the on-off command class (0x25 == decimal 37). Notice that the [EnablePoll() command](http://www.openzwave.com/dev/classOpenZWave_1_1Manager.html#a50d795cb20a0bea55ecfd4a02c9777f3) does **not** need a HomeId as an argument, hence we don't need to add `prependHomeId` to the message payload: - `{"topic": "addNode", "payload": {"prependHomeId": true, "args": [true]}}` + `{"topic": "enablePoll", "payload": {"args": [5, 37]}}` - * to enable polling for ZWave node #5 for the on-off command class (0x25 == decimal 37). Notice that the [EnablePoll() command](http://www.openzwave.com/dev/classOpenZWave_1_1Manager.html#a50d795cb20a0bea55ecfd4a02c9777f3) does **not** need a HomeId as an argument, hence we don't need to add `prependHomeId` to the message payload: + * to get **a node's statistics** by using the `getNodeStatistics()` call: + + `{"topic": "getNodeStatistics", "payload": {"args": [2]}}` + +Most of the API calls in OpenZWave are *asynchronous*. This means that you don't get an immediate result value from the call itself, but you'll get notifications from their activity on the zwave-in input node. However, there are some direct API calls which *do return a value* (eg the `getNodeStatistics` is returning an object populated with the node's statistics: number of packets sent/received, transmission error counts etc). + +In this case, the result is appended to the message payload and forwarded to the output of the ZWave-out node. This is the *only* message that the output node is emitting. - `{"topic": "enablePoll", "payload": {"args": [5, 37]}}` ##### - *zwave-in*