node-red-contrib-mobius-flow-base 2.5.86-beta.1 → 2.5.86-beta.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nodes/icons/mobius-inject.png +0 -0
- package/dist/nodes/icons/mobius.png +0 -0
- package/dist/nodes/mobius-clear-resource.html +178 -0
- package/dist/nodes/mobius-clear-resource.js +109 -0
- package/dist/nodes/mobius-connection.html +68 -0
- package/dist/nodes/mobius-connection.js +675 -0
- package/dist/nodes/mobius-discover-object-list.html +272 -0
- package/dist/nodes/mobius-discover-object-list.js +263 -0
- package/dist/nodes/mobius-discover.html +139 -0
- package/dist/nodes/mobius-discover.js +100 -0
- package/dist/nodes/mobius-filter-by-rid-value.html +206 -0
- package/dist/nodes/mobius-filter-by-rid-value.js +123 -0
- package/dist/nodes/mobius-flow-inject.html +162 -0
- package/dist/nodes/mobius-flow-inject.js +124 -0
- package/dist/nodes/mobius-get-multi-object.html +176 -0
- package/dist/nodes/mobius-get-multi-object.js +127 -0
- package/dist/nodes/mobius-get-multi-resource.html +195 -0
- package/dist/nodes/mobius-get-multi-resource.js +140 -0
- package/dist/nodes/mobius-get-object.html +168 -0
- package/dist/nodes/mobius-get-object.js +102 -0
- package/dist/nodes/mobius-get-resource.html +169 -0
- package/dist/nodes/mobius-get-resource.js +101 -0
- package/dist/nodes/mobius-object-cov.html +171 -0
- package/dist/nodes/mobius-object-cov.js +83 -0
- package/dist/nodes/mobius-resource-cov.html +155 -0
- package/dist/nodes/mobius-resource-cov.js +77 -0
- package/dist/nodes/mobius-send-bcmd.html +93 -0
- package/dist/nodes/mobius-send-bcmd.js +61 -0
- package/dist/nodes/mobius-send-dcmd.html +130 -0
- package/dist/nodes/mobius-send-dcmd.js +80 -0
- package/dist/nodes/mobius-set-multi-resource.html +150 -0
- package/dist/nodes/mobius-set-multi-resource.js +104 -0
- package/dist/nodes/mobius-set-resource.html +180 -0
- package/dist/nodes/mobius-set-resource.js +145 -0
- package/dist/nodes/mobius-sub-bcmd.html +94 -0
- package/dist/nodes/mobius-sub-bcmd.js +64 -0
- package/dist/nodes/node-red-ui-discover-devices.js +103 -0
- package/dist/nodes/validateURI.js +51 -0
- package/package.json +1 -1
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Copyright (C) 2016, IAConnects Technology Limited
|
|
3
|
+
All Rights Reserved
|
|
4
|
+
|
|
5
|
+
ALL INFORMATION CONTAINED HEREIN IS, AND REMAINS
|
|
6
|
+
THE PROPERTY OF IACONNECTS TECHNOLOGY LIMITED AND ITS SUPPLIERS,
|
|
7
|
+
IF ANY. THE INTELLECTUAL AND TECHNICAL CONCEPTS CONTAINED
|
|
8
|
+
HEREIN ARE PROPRIETARY TO IACONNECTS TECHNOLOGY LIMITED
|
|
9
|
+
AND ITS SUPPLIERS AND ARE PROTECTED BY TRADE SECRET OR COPYRIGHT LAW.
|
|
10
|
+
DISSEMINATION OF THIS INFORMATION OR REPRODUCTION OF THIS MATERIAL
|
|
11
|
+
IS STRICTLY FORBIDDEN UNLESS PRIOR WRITTEN PERMISSION IS OBTAINED
|
|
12
|
+
FROM IACONNECTS TECHNOLOGY LIMITED.
|
|
13
|
+
|
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
15
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
16
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
17
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
|
18
|
+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
19
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
20
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
21
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
22
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
23
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
24
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
25
|
+
-->
|
|
26
|
+
|
|
27
|
+
<script type="text/x-red" data-template-name="mobius discover object list">
|
|
28
|
+
<div class="form-row">
|
|
29
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
30
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
31
|
+
</div>
|
|
32
|
+
<hr>
|
|
33
|
+
<div class="form-row">
|
|
34
|
+
<label for="node-input-connection"><i class="fa fa-globe"></i> MOBiUS</label>
|
|
35
|
+
<input type="text" id="node-input-connection">
|
|
36
|
+
</div>
|
|
37
|
+
<div class="form-row">
|
|
38
|
+
<label for="node-input-hid"><i class="fa fa-tasks"></i> HID</label>
|
|
39
|
+
<input type="text" id="node-input-hid" placeholder="">
|
|
40
|
+
</div>
|
|
41
|
+
<hr>
|
|
42
|
+
<div class="form-row">
|
|
43
|
+
<label for="node-input-output"><i class="fa fa-sign-out"></i> Output</label>
|
|
44
|
+
<select type="text" id="node-input-output" style="display: inline-block; width: auto; vertical-align: center;">
|
|
45
|
+
<option value="objects">MOBiUS Objects</option>
|
|
46
|
+
<option value="uris">MOBiUS Object URIs</option>
|
|
47
|
+
</select>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="form-row">
|
|
50
|
+
<label for="node-input-send"><i class="fa fa-ellipsis-h"></i> Send</label>
|
|
51
|
+
<select type="text" id="node-input-send" style="display: inline-block; width: auto; vertical-align: center;">
|
|
52
|
+
<option value="individual">Individual Items</option>
|
|
53
|
+
<option value="array">Array of Items</option>
|
|
54
|
+
</select>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="form-row node-input-subs-container-row">
|
|
57
|
+
<label for="node-input-subs-container" style="width:105px;float:left;"><i class="fa fa-bars"></i> Discover</label>
|
|
58
|
+
<ol id="node-input-subs-container"></ol>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="form-row">
|
|
61
|
+
<label for="node-input-useRIDValueFiltering" style="width:178px;float:left;"><i class="fa fa-filter"></i> Filter by Resource Value</label>
|
|
62
|
+
<input type="checkbox" id="node-input-useRIDValueFiltering" style="display: inline-block; width: auto; vertical-align: top;">
|
|
63
|
+
</div>
|
|
64
|
+
<div id="use-rid-filter-row" class="form-row hidden">
|
|
65
|
+
<div class="form-row">
|
|
66
|
+
<label for="node-input-rid"><i class="fa fa-tag"></i> RID</label>
|
|
67
|
+
<input type="text" id="node-input-rid" placeholder="Resource to test">
|
|
68
|
+
</div>
|
|
69
|
+
<div class="form-row">
|
|
70
|
+
<label for="node-input-limit"><i class="fa fa-arrow-up"></i> Limit</label>
|
|
71
|
+
<input type="text" id="node-input-limit" placeholder="Maximum number of objects to return">
|
|
72
|
+
</div>
|
|
73
|
+
<div class="form-row">
|
|
74
|
+
<label for="node-input-func-editor" style="width:105px;float:left;"><i class="fa fa-list-alt"></i> Function</label>
|
|
75
|
+
<div style="height: 150px; min-height:80px;" class="node-text-editor" id="node-input-func-editor"></div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<script type="text/javascript">
|
|
81
|
+
RED.nodes.registerType('mobius discover object list', {
|
|
82
|
+
category: 'mobius',
|
|
83
|
+
defaults: {
|
|
84
|
+
name: {value:""},
|
|
85
|
+
useRIDValueFiltering: {value: false},
|
|
86
|
+
func: {value:""},
|
|
87
|
+
limit: {value:100, validate:RED.validators.number()},
|
|
88
|
+
rid: {value: "", validate:function(v) {
|
|
89
|
+
if(v === '') { return true; }
|
|
90
|
+
if(v.length === 2) { return true; }
|
|
91
|
+
return false;
|
|
92
|
+
}},
|
|
93
|
+
output: {value: "objects", required: true},
|
|
94
|
+
send: {value: "individual", required: true},
|
|
95
|
+
subscriptions: {value:[{uri: '', type: 'include'}]},
|
|
96
|
+
hid: {value: "", validate:function(v) {
|
|
97
|
+
if(v === '') { return true; }
|
|
98
|
+
if(v.length === 6) { return true; }
|
|
99
|
+
return false;
|
|
100
|
+
}},
|
|
101
|
+
connection: {type:"mobius connection", required:true}
|
|
102
|
+
},
|
|
103
|
+
color:"#9ee3fa",
|
|
104
|
+
inputs:1,
|
|
105
|
+
outputs:1,
|
|
106
|
+
outputLabels: ["MOBiUS objects or URIs"],
|
|
107
|
+
icon: "mobius.png",
|
|
108
|
+
align: "left",
|
|
109
|
+
paletteLabel: 'discover object list',
|
|
110
|
+
label: function() {
|
|
111
|
+
if(this.name) {
|
|
112
|
+
return this.name;
|
|
113
|
+
} else {
|
|
114
|
+
return "discover object list";
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
labelStyle: function() {
|
|
118
|
+
return this.name ? "node_label_italic":"";
|
|
119
|
+
},
|
|
120
|
+
oneditprepare: function () {
|
|
121
|
+
var node = this;
|
|
122
|
+
|
|
123
|
+
/** Create the subs container and populate it */
|
|
124
|
+
$('#node-input-subs-container').css('min-height', '200px').css('min-width', '345px').editableList ({
|
|
125
|
+
addButton: "add uri",
|
|
126
|
+
removable: true,
|
|
127
|
+
sortable: true,
|
|
128
|
+
addItem: function (container, i, subscription) {
|
|
129
|
+
container.css({
|
|
130
|
+
overflow: 'hidden',
|
|
131
|
+
whiteSpace: 'nowrap'
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Add a default subscription if it does not exist
|
|
135
|
+
if (!subscription.hasOwnProperty("uri")) {
|
|
136
|
+
subscription = {uri: '', type: 'include'};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
var row = $('<div>URI</div>').appendTo(container);
|
|
140
|
+
var uriField = $('<input/>',{class: "node-input-sub-uri", type: "text", style: "width: 170px; margin-left: 5px; text-align: left;"}).appendTo(row);
|
|
141
|
+
var typeField = $('<select/>',{class: "node-input-sub-type", style: "width:auto; margin-left: 5px; text-align: center;"}).appendTo(row);
|
|
142
|
+
typeField.append($("<option></option>").val('include').text('Include'));
|
|
143
|
+
typeField.append($("<option></option>").val('exclude').text('Exclude'));
|
|
144
|
+
|
|
145
|
+
// Populate the new stat
|
|
146
|
+
uriField.val(subscription.uri);
|
|
147
|
+
typeField.val(subscription.type);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
$('.red-ui-editableList-addButton').css('margin-left', '105px')
|
|
152
|
+
|
|
153
|
+
// If no stat exists, create a default one
|
|
154
|
+
if (!node.subscriptions) {
|
|
155
|
+
node.subscriptions = [subscription = {uri: '', type: 'include'}];
|
|
156
|
+
}
|
|
157
|
+
// Populate list with all saved filters
|
|
158
|
+
for (let i = 0; i < node.subscriptions.length; i++) {
|
|
159
|
+
let subscription = node.subscriptions[i];
|
|
160
|
+
$("#node-input-subs-container").editableList('addItem', subscription);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function showRIDFilterInputs() {
|
|
164
|
+
if($("#node-input-useRIDValueFiltering").is(':checked')) {
|
|
165
|
+
$("#use-rid-filter-row").show();
|
|
166
|
+
} else {
|
|
167
|
+
$("#use-rid-filter-row").hide();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
showRIDFilterInputs();
|
|
171
|
+
$("#node-input-useRIDValueFiltering").change(function() {
|
|
172
|
+
showRIDFilterInputs();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
this.editor = RED.editor.createEditor({
|
|
176
|
+
id: 'node-input-func-editor',
|
|
177
|
+
mode: 'ace/mode/javascript',
|
|
178
|
+
value: this.func
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
oneditresize(size) {
|
|
182
|
+
var rows = $("#dialog-form>div:not(.node-input-subs-container-row)");
|
|
183
|
+
var height = size.height;
|
|
184
|
+
for (var i=0; i<rows.size(); i++) {
|
|
185
|
+
height -= $(rows[i]).outerHeight(true);
|
|
186
|
+
}
|
|
187
|
+
var editorRow = $("#dialog-form>div.node-input-subs-container-row");
|
|
188
|
+
height -= 4 * ((parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom"))));
|
|
189
|
+
|
|
190
|
+
$("#node-input-subs-container").editableList('height',height);
|
|
191
|
+
},
|
|
192
|
+
oneditsave: function() {
|
|
193
|
+
let subscriptions = $("#node-input-subs-container").editableList('items');
|
|
194
|
+
let node = this;
|
|
195
|
+
node.subscriptions= [];
|
|
196
|
+
subscriptions.each(function (i) {
|
|
197
|
+
var subscription = $(this);
|
|
198
|
+
let uri = subscription.find(".node-input-sub-uri").val();
|
|
199
|
+
let type = subscription.find(".node-input-sub-type").val();
|
|
200
|
+
node.subscriptions.push({uri: uri, type: type});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
this.func = this.editor.getValue();
|
|
204
|
+
this.editor.destroy();
|
|
205
|
+
delete this.editor;
|
|
206
|
+
},
|
|
207
|
+
oneditcancel: function() {
|
|
208
|
+
this.editor.destroy();
|
|
209
|
+
delete this.editor;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
</script>
|
|
213
|
+
|
|
214
|
+
<script type="text/x-red" data-help-name="mobius discover object list">
|
|
215
|
+
<p>Discover MOBiUS objects and return a filtered list of objects or URIs.</p>
|
|
216
|
+
|
|
217
|
+
<h3>Configuration Page</h3>
|
|
218
|
+
<dl class="message-properties">
|
|
219
|
+
<dt>MOBiUS <span class="property-type">node</span></dt>
|
|
220
|
+
<dd>Shared MOBiUS connection for communication with the MOBiUS Hub.</dd>
|
|
221
|
+
<dt>HID <span class="property-type">string</span></dt>
|
|
222
|
+
<dd>Optional Mobius hub ID to use for discovery. Leave empty to use the local HID.</dd>
|
|
223
|
+
<dt>Output <span class="property-type">option</span></dt>
|
|
224
|
+
<dd>Output full MOBiUS objects or MOBiUS object URIs.</dd>
|
|
225
|
+
<dt>Send <span class="property-type">option</span></dt>
|
|
226
|
+
<dd>Send the outputs individually or as a single array.</dd>
|
|
227
|
+
<dt>Discover <span class="property-type">string</span></dt>
|
|
228
|
+
<dd>The MOBiUS URI of the objects to discover. This may contain MQTT type wildcards.</dd>
|
|
229
|
+
<dt>Filter by Resource Value <span class="property-type">checkbox</span></dt>
|
|
230
|
+
<dd>If checked the returned objects are also filtered by the value of a single resource.</dd>
|
|
231
|
+
<dt>RID <span class="property-type">string</span></dt>
|
|
232
|
+
<dd>The MOBiUS Object Resource ID of the resource to test.</dd>
|
|
233
|
+
<dt class="optional">Limit <span class="property-type">number</span></dt>
|
|
234
|
+
<dd>The maximum number of objects to return. Defaults to 100.</dd>
|
|
235
|
+
<dt>Function <span class="property-type">string</span></dt>
|
|
236
|
+
<dd>JavaScript used to test the resource value.</dd>
|
|
237
|
+
</dl>
|
|
238
|
+
|
|
239
|
+
<h3>Inputs</h3>
|
|
240
|
+
<ol class="node-ports">
|
|
241
|
+
<li>Input message to trigger discovery
|
|
242
|
+
<dl class="message-properties">
|
|
243
|
+
<dt class="optional">topic <span class="property-type">string</span></dt>
|
|
244
|
+
<dd>Topic is passed through to output.</dd>
|
|
245
|
+
</dl>
|
|
246
|
+
</li>
|
|
247
|
+
</ol>
|
|
248
|
+
|
|
249
|
+
<h3>Outputs</h3>
|
|
250
|
+
<ol class="node-ports">
|
|
251
|
+
<li>Array of URIs discovered.
|
|
252
|
+
<dl class="message-properties">
|
|
253
|
+
<dt>topic <span class="property-type">string</span></dt>
|
|
254
|
+
<dd>When outputting individual items the topic will be the object URI and when outputting arrays the topic is passed through from input.</dd>
|
|
255
|
+
<dt>payload <span class="property-type">array</span></dt>
|
|
256
|
+
<dd>Array or individual list of discovered objects or URIs.</dd>
|
|
257
|
+
</dl>
|
|
258
|
+
</li>
|
|
259
|
+
</ol>
|
|
260
|
+
|
|
261
|
+
<h3>Details</h3>
|
|
262
|
+
<p>
|
|
263
|
+
The <code>Function</code> configuration property is string containing the JavaScript expression used to test the resource value. The expression must return <b>true</b> or <b>false</b>.
|
|
264
|
+
The actual value of the resource is represented in the expression by <code>$PV</code>. A few examples are shown below:</br>
|
|
265
|
+
<code>return $PV === 5;</code><br>
|
|
266
|
+
<code>return $PV > 10 && $PV < 100;</code><br>
|
|
267
|
+
<code>return $PV.includes('test-string');</code>
|
|
268
|
+
</p>
|
|
269
|
+
|
|
270
|
+
<br>
|
|
271
|
+
<p align="center" style="color:#000080">iaconnects © 2019</p>
|
|
272
|
+
</script>
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright (C) 2016, IAConnects Technology Limited
|
|
3
|
+
All Rights Reserved
|
|
4
|
+
|
|
5
|
+
ALL INFORMATION CONTAINED HEREIN IS, AND REMAINS
|
|
6
|
+
THE PROPERTY OF IACONNECTS TECHNOLOGY LIMITED AND ITS SUPPLIERS,
|
|
7
|
+
IF ANY. THE INTELLECTUAL AND TECHNICAL CONCEPTS CONTAINED
|
|
8
|
+
HEREIN ARE PROPRIETARY TO IACONNECTS TECHNOLOGY LIMITED
|
|
9
|
+
AND ITS SUPPLIERS AND ARE PROTECTED BY TRADE SECRET OR COPYRIGHT LAW.
|
|
10
|
+
DISSEMINATION OF THIS INFORMATION OR REPRODUCTION OF THIS MATERIAL
|
|
11
|
+
IS STRICTLY FORBIDDEN UNLESS PRIOR WRITTEN PERMISSION IS OBTAINED
|
|
12
|
+
FROM IACONNECTS TECHNOLOGY LIMITED.
|
|
13
|
+
|
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
15
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
16
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
17
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
|
18
|
+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
19
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
20
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
21
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
22
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
23
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
24
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
25
|
+
**/
|
|
26
|
+
|
|
27
|
+
/* jshint elision: true */
|
|
28
|
+
'use strict';
|
|
29
|
+
|
|
30
|
+
module.exports = function (RED) {
|
|
31
|
+
function MobiusFlowNode (n) {
|
|
32
|
+
RED.nodes.createNode(this, n);
|
|
33
|
+
this.subscriptions = n.subscriptions;
|
|
34
|
+
this.sendType = n.send;
|
|
35
|
+
this.outputType = n.output;
|
|
36
|
+
this.hid = n.hid;
|
|
37
|
+
this.useRIDValueFiltering = n.useRIDValueFiltering;
|
|
38
|
+
this.rid = n.rid;
|
|
39
|
+
this.limit = n.limit;
|
|
40
|
+
this.func = n.func;
|
|
41
|
+
this.serviceConn = RED.nodes.getNode(n.connection);
|
|
42
|
+
var node = this;
|
|
43
|
+
|
|
44
|
+
if (node.serviceConn) {
|
|
45
|
+
node.status({
|
|
46
|
+
fill: 'red',
|
|
47
|
+
shape: 'ring',
|
|
48
|
+
text: 'Disconnected'
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
node.serviceConn.register(node);
|
|
52
|
+
|
|
53
|
+
node.on('input', function (msg, done) {
|
|
54
|
+
node.status({
|
|
55
|
+
fill: 'green',
|
|
56
|
+
shape: 'ring',
|
|
57
|
+
text: 'Busy'
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
node.discoverAllObjectURIs(msg).then((objectList) => {
|
|
61
|
+
if (node.sendType === 'individual') {
|
|
62
|
+
objectList.forEach((mobiusObject) => {
|
|
63
|
+
if (node.outputType === 'uris') {
|
|
64
|
+
node.send({
|
|
65
|
+
topic: mobiusObject.uri,
|
|
66
|
+
payload: mobiusObject.uri
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
node.send({
|
|
70
|
+
topic: mobiusObject.uri,
|
|
71
|
+
payload: mobiusObject
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
if (node.outputType === 'uris') {
|
|
77
|
+
const uris = [];
|
|
78
|
+
objectList.forEach((mobiusObject) => {
|
|
79
|
+
uris.push(mobiusObject.uri);
|
|
80
|
+
});
|
|
81
|
+
node.send({
|
|
82
|
+
topic: msg.topic,
|
|
83
|
+
payload: uris
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
node.send({
|
|
87
|
+
topic: msg.topic,
|
|
88
|
+
payload: objectList
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
node.status({
|
|
94
|
+
fill: 'green',
|
|
95
|
+
shape: 'dot',
|
|
96
|
+
text: 'Done'
|
|
97
|
+
});
|
|
98
|
+
}).catch(() => {
|
|
99
|
+
node.status({
|
|
100
|
+
fill: 'yellow',
|
|
101
|
+
shape: 'dot',
|
|
102
|
+
text: 'Failed discovery'
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
if (done) {
|
|
106
|
+
done();
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
node.on('close', function (done) {
|
|
111
|
+
node.serviceConn.deregister(node, done);
|
|
112
|
+
});
|
|
113
|
+
} else {
|
|
114
|
+
node.error(RED._('Mobius service not defined'));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
node.discoverAllObjectURIs = async function (msg) {
|
|
118
|
+
return new Promise(async (resolve, reject) => {
|
|
119
|
+
let objectList = [];
|
|
120
|
+
try {
|
|
121
|
+
const hid = node.hid === '' ? node.serviceConn.service.srvcAPI.status.hubId : node.hid;
|
|
122
|
+
const profiles = await discoverProfiles(node.serviceConn, hid, node.subscriptions);
|
|
123
|
+
|
|
124
|
+
for await (let entry of profiles.entries()) {
|
|
125
|
+
let discoverParams = {};
|
|
126
|
+
const serviceURI = entry[0];
|
|
127
|
+
const pids = entry[1];
|
|
128
|
+
if (node.useRIDValueFiltering) {
|
|
129
|
+
discoverParams = {
|
|
130
|
+
uri: serviceURI,
|
|
131
|
+
pids: pids,
|
|
132
|
+
rid: node.rid,
|
|
133
|
+
func: node.func,
|
|
134
|
+
limit: node.limit
|
|
135
|
+
};
|
|
136
|
+
} else {
|
|
137
|
+
discoverParams = {
|
|
138
|
+
uri: serviceURI,
|
|
139
|
+
pids: pids,
|
|
140
|
+
rid: '00',
|
|
141
|
+
func: 'return true;',
|
|
142
|
+
limit: 512
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
let objects = await discover(node.serviceConn, discoverParams);
|
|
147
|
+
for (let lp = 0; lp < objects.value.length; lp++) {
|
|
148
|
+
objects.value[lp]['uri'] = `${serviceURI}/${objects.value[lp].pid}/${objects.value[lp].ins}`;
|
|
149
|
+
objectList.push(objects.value[lp]);
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
node.warn(`Discover object failed for service (${serviceURI}) - ${err.message}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (objectList.length === 0) {
|
|
157
|
+
throw new Error('No discovery data found');
|
|
158
|
+
}
|
|
159
|
+
} catch (err) {
|
|
160
|
+
node.warn(`Failed discover all objects: ${err.message}`);
|
|
161
|
+
reject(err.message);
|
|
162
|
+
}
|
|
163
|
+
resolve(objectList);
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function discoverProfiles(serviceConn, hid, subscriptions) {
|
|
169
|
+
return new Promise(async (resolve) => {
|
|
170
|
+
let discoveredProfiles = new Map();
|
|
171
|
+
let services = await discover(serviceConn, hid);
|
|
172
|
+
for (const service of services.value) {
|
|
173
|
+
if (service.status === 'online') {
|
|
174
|
+
let sid = service.id.split('/')[1];
|
|
175
|
+
if (isIncluded(`${hid}/${sid}/#`, subscriptions)) {
|
|
176
|
+
let profiles = await discover(serviceConn, `${hid}/${sid}`);
|
|
177
|
+
let pids = [];
|
|
178
|
+
for (const pid of profiles.value) {
|
|
179
|
+
if (isIncluded(`${hid}/${sid}/${pid}/#`, subscriptions) && !isExcluded(`${hid}/${sid}/${pid}/#`, subscriptions)) {
|
|
180
|
+
pids.push(pid);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (pids.length > 0) {
|
|
184
|
+
discoveredProfiles.set(`${hid}/${sid}`, pids);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
RED.log.warn(`Failed to discover objects for service ${service.id.split('/')[1]} as it is offline.`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
resolve(discoveredProfiles);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function discover (serviceConn, params) {
|
|
196
|
+
return new Promise((resolve, reject) => {
|
|
197
|
+
serviceConn.discover(params, (err, response) => {
|
|
198
|
+
if (err) {
|
|
199
|
+
reject(err);
|
|
200
|
+
} else {
|
|
201
|
+
resolve(response);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
function isIncluded(uri, subscriptions) {
|
|
208
|
+
let include = false;
|
|
209
|
+
for (const subscription of subscriptions) {
|
|
210
|
+
if (subscription.type === 'include' && validateSubscription(subscription.uri)) {
|
|
211
|
+
if (matchTopic(subscription.uri, uri)) {
|
|
212
|
+
include = true;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return include;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function isExcluded (uri, subscriptions) {
|
|
220
|
+
let exclude = false;
|
|
221
|
+
for (const subscription of subscriptions) {
|
|
222
|
+
if (subscription.type === 'exclude' && validateSubscription(subscription.uri)) {
|
|
223
|
+
if (matchTopic(subscription.uri, uri)) {
|
|
224
|
+
exclude = true;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return exclude;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function validateSubscription (uri) {
|
|
232
|
+
let parts = uri.split('/');
|
|
233
|
+
for (let lp = 0; lp < parts.length; lp++) {
|
|
234
|
+
if (parts[lp] === null || parts[lp] === '') {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (parts.length === 4) {
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
if (parts.length < 4 && parts[parts.length - 1] === '#') {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function matchTopic (filter, topic) {
|
|
248
|
+
const filterArray = filter.split('/');
|
|
249
|
+
const topicArray = topic.split('/');
|
|
250
|
+
const length = filterArray.length < topicArray.length ? filterArray.length : topicArray.length;
|
|
251
|
+
|
|
252
|
+
for (let i = 0; i < length; ++i) {
|
|
253
|
+
const left = filterArray[i];
|
|
254
|
+
const right = topicArray[i];
|
|
255
|
+
if (!(left === right || left === '+' || left === '#' || right === '+' || right === '#')) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
RED.nodes.registerType('mobius discover object list', MobiusFlowNode);
|
|
263
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Copyright (C) 2016, IAConnects Technology Limited
|
|
3
|
+
All Rights Reserved
|
|
4
|
+
|
|
5
|
+
ALL INFORMATION CONTAINED HEREIN IS, AND REMAINS
|
|
6
|
+
THE PROPERTY OF IACONNECTS TECHNOLOGY LIMITED AND ITS SUPPLIERS,
|
|
7
|
+
IF ANY. THE INTELLECTUAL AND TECHNICAL CONCEPTS CONTAINED
|
|
8
|
+
HEREIN ARE PROPRIETARY TO IACONNECTS TECHNOLOGY LIMITED
|
|
9
|
+
AND ITS SUPPLIERS AND ARE PROTECTED BY TRADE SECRET OR COPYRIGHT LAW.
|
|
10
|
+
DISSEMINATION OF THIS INFORMATION OR REPRODUCTION OF THIS MATERIAL
|
|
11
|
+
IS STRICTLY FORBIDDEN UNLESS PRIOR WRITTEN PERMISSION IS OBTAINED
|
|
12
|
+
FROM IACONNECTS TECHNOLOGY LIMITED.
|
|
13
|
+
|
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
15
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
16
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
17
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
|
18
|
+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
19
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
20
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
21
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
22
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
23
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
24
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
25
|
+
-->
|
|
26
|
+
|
|
27
|
+
<script type="text/x-red" data-template-name="mobius discover">
|
|
28
|
+
<div class="form-row">
|
|
29
|
+
<label for="node-input-connection"><i class="fa fa-globe"></i> MOBiUS</label>
|
|
30
|
+
<input type="text" id="node-input-connection">
|
|
31
|
+
</div>
|
|
32
|
+
<hr>
|
|
33
|
+
<div class="form-row">
|
|
34
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
35
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
36
|
+
</div>
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<script type="text/javascript">
|
|
40
|
+
RED.nodes.registerType('mobius discover',{
|
|
41
|
+
category: 'mobius',
|
|
42
|
+
color: "#8abff5",
|
|
43
|
+
defaults: {
|
|
44
|
+
name: {value: ""},
|
|
45
|
+
connection: {type: "mobius connection", required: true}
|
|
46
|
+
},
|
|
47
|
+
inputs:1,
|
|
48
|
+
outputs:1,
|
|
49
|
+
inputLabels: "Trigger discovery",
|
|
50
|
+
outputLabels: ["Full MOBiUS response"],
|
|
51
|
+
icon: "mobius.png",
|
|
52
|
+
align: "left",
|
|
53
|
+
paletteLabel: "discover",
|
|
54
|
+
label: function() {
|
|
55
|
+
if(this.name) {
|
|
56
|
+
return this.name;
|
|
57
|
+
} else {
|
|
58
|
+
return "discover";
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
labelStyle: function() {
|
|
62
|
+
return this.name ? "node_label_italic":"";
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<script type="text/x-red" data-help-name="mobius discover">
|
|
68
|
+
<p>Discover MOBiUS services, object profiles, and objects</p>
|
|
69
|
+
|
|
70
|
+
<h3>Configuration Page</h3>
|
|
71
|
+
<dl class="message-properties">
|
|
72
|
+
<dt>MOBiUS <span class="property-type">node</span></dt>
|
|
73
|
+
<dd>Shared MOBiUS connection for communication with the MOBiUS Hub.</dd>
|
|
74
|
+
</dl>
|
|
75
|
+
|
|
76
|
+
<h3>Inputs</h3>
|
|
77
|
+
<ol class="node-ports">
|
|
78
|
+
<li>Input message to trigger discovery
|
|
79
|
+
<dl class="message-properties">
|
|
80
|
+
<dt>topic <span class="property-type">string</span></dt>
|
|
81
|
+
<dd>The path (in the form of a partial MOBiUS URI) whose children are to be discovered.</dd>
|
|
82
|
+
<dt class="optional">payload <span class="property-type">object</span></dt>
|
|
83
|
+
<dd>If the following properties are supplied in the payload the discovery will filter the results based on a resource's value.
|
|
84
|
+
See the Details section below for more information.</dd>
|
|
85
|
+
<dt class="optional">payload.pids <span class="property-type">array of strings</span></dt>
|
|
86
|
+
<dd>An array of MOBiUS Object Profile IDs to filter. Defaults to an empty array.</dd>
|
|
87
|
+
<dt>payload.rid <span class="property-type">string</span></dt>
|
|
88
|
+
<dd>The MOBiUS Object Resource ID of the resource to test.</dd>
|
|
89
|
+
<dt class="optional">payload.limit <span class="property-type">number</span></dt>
|
|
90
|
+
<dd>The maximum number of objects to return. Defaults to 100.</dd>
|
|
91
|
+
<dt>payload.func <span class="property-type">string</span></dt>
|
|
92
|
+
<dd>JavaScript used to test the resource value.</dd>
|
|
93
|
+
</dl>
|
|
94
|
+
</li>
|
|
95
|
+
</ol>
|
|
96
|
+
|
|
97
|
+
<h3>Outputs</h3>
|
|
98
|
+
<ol class="node-ports">
|
|
99
|
+
<li>Full MOBiUS response
|
|
100
|
+
<dl class="message-properties">
|
|
101
|
+
<dt>topic <span class="property-type">string</span></dt>
|
|
102
|
+
<dd>The original path used in the disccovery.</dd>
|
|
103
|
+
<dt>error <span class="property-type">boolean</span></dt>
|
|
104
|
+
<dd>True if an error occured, else false.</dd>
|
|
105
|
+
<dt>response <span class="property-type">object</span></dt>
|
|
106
|
+
<dd>The full MOBiUS response message.</dd>
|
|
107
|
+
</dl>
|
|
108
|
+
</li>
|
|
109
|
+
</ol>
|
|
110
|
+
|
|
111
|
+
<h3>Details</h3>
|
|
112
|
+
<p>
|
|
113
|
+
In addition to discovering all MOBiUS services, object profiles, and objects it is possible filter the results based on the value of a resource.
|
|
114
|
+
This is done by passing in additional parameters in the payload. These parameters are detailed below.
|
|
115
|
+
<br><b>Filtering only works when discovering object profiles or objects.</b>
|
|
116
|
+
</p>
|
|
117
|
+
<p>To filter on objects of type 0201 and 0258 and only return the objects with a value of greater than 12 in resource 40 the message would be:<br>
|
|
118
|
+
<code>{ topic: "000001/021", payload: { pids: ["0201", "0258"], rid: "40", func: "return $PV > 12;" }</code>
|
|
119
|
+
<p>
|
|
120
|
+
<code><i>pids</i></code> When discovering object profiles an array of the profiles (as 4 digit hex strings) to be used in the filter can be supplied. If this is an empty array it acts as a
|
|
121
|
+
wild card and all objects belonging to a service will be used regardless of their object profile. If pids is not supplied it will default to an empty array.
|
|
122
|
+
<br>When discovering object instances the pids value will be ignored and only the pid supplied as part of the discovery URI is used.
|
|
123
|
+
</p>
|
|
124
|
+
<p>
|
|
125
|
+
<code>rid</code> The ID of resource whose value will be tested. This is a 2 digit hex string.
|
|
126
|
+
</p>
|
|
127
|
+
<p>
|
|
128
|
+
<code><i>limit</i></code> The maximum number of objects that will be returned. If not supplied it defaults to 100.
|
|
129
|
+
</p>
|
|
130
|
+
<p>
|
|
131
|
+
<code>func</code> A string containing the JavaScript expression used to test the resource value. The expression must return <b>true</b> or <b>false</b>.
|
|
132
|
+
The actual value of the resource is represented in the expression by <code>$PV</code>. A few examples are shown below:</br>
|
|
133
|
+
<code>return $PV === 5;</code><br>
|
|
134
|
+
<code>return $PV > 10 && $PV < 100;</code><br>
|
|
135
|
+
<code>return $PV.includes('test-string');</code>
|
|
136
|
+
</p>
|
|
137
|
+
<br>
|
|
138
|
+
<p align="center" style="color:#000080">iaconnects © 2017</p>
|
|
139
|
+
</script>
|