@bitpoolos/edge-bacnet 1.2.5 → 1.2.7

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.
@@ -1,641 +1,875 @@
1
1
  <!--
2
- MIT License Copyright 2021, 2022 - Bitpool Pty Ltd
2
+ MIT License Copyright 2021, 2024 - Bitpool Pty Ltd
3
3
  -->
4
4
  <!-- PrimeVue -->
5
5
  <link href="resources/@bitpoolos/edge-bacnet/primevue-saga-blue-theme.css" rel="stylesheet" />
6
6
  <link href="resources/@bitpoolos/edge-bacnet/primevue.min.css" rel="stylesheet" />
7
7
  <link href="resources/@bitpoolos/edge-bacnet/primeflex.min.css" rel="stylesheet" />
8
8
  <link href="resources/@bitpoolos/edge-bacnet/primeicons.css" rel="stylesheet" />
9
+ <link href="resources/@bitpoolos/edge-bacnet/style.css" rel="stylesheet" />
9
10
 
10
11
  <script>
11
- //custom script loader to ensure dependencies load every time
12
- (function () {
13
- LoadScripts();
14
-
15
- function LoadScripts(async) {
16
- if (async === undefined) {
17
- async = false;
18
- }
19
- var scripts = [];
20
- var _scripts = [
21
- 'resources/@bitpoolos/edge-bacnet/vue.global.prod.js',
22
- 'resources/@bitpoolos/edge-bacnet/core.min.js',
23
- 'resources/@bitpoolos/edge-bacnet/confirmdialog.min.js',
24
- 'resources/@bitpoolos/edge-bacnet/confirmationservice.min.js'
25
- ];
26
-
27
- if (async) {
28
- LoadScriptsAsync(_scripts, scripts)
29
- } else {
30
- LoadScriptsSync(_scripts, scripts)
31
- }
32
- }
12
+ //custom script loader to ensure dependencies load every time
13
+ (function () {
14
+ LoadScripts();
15
+
16
+ function LoadScripts(async) {
17
+ if (async === undefined) {
18
+ async = false;
19
+ }
20
+ var scripts = [];
21
+ var _scripts = [
22
+ "resources/@bitpoolos/edge-bacnet/vue.global.prod.js",
23
+ "resources/@bitpoolos/edge-bacnet/core.min.js",
24
+ "resources/@bitpoolos/edge-bacnet/confirmdialog.min.js",
25
+ "resources/@bitpoolos/edge-bacnet/confirmationservice.min.js",
26
+ ];
27
+
28
+ if (async) {
29
+ LoadScriptsAsync(_scripts, scripts);
30
+ } else {
31
+ LoadScriptsSync(_scripts, scripts);
32
+ }
33
+ }
33
34
 
34
- // what you are looking for :
35
- function LoadScriptsSync(_scripts, scripts) {
36
-
37
- var x = 0;
38
- var loopArray = function (_scripts, scripts) {
39
- // call itself
40
- loadScript(_scripts[x], scripts[x], function () {
41
- // set x to next item
42
- x++;
43
- // any more items in array?
44
- if (x < _scripts.length) {
45
- loopArray(_scripts, scripts);
46
- }
47
- });
48
- }
35
+ // what you are looking for :
36
+ function LoadScriptsSync(_scripts, scripts) {
37
+ var x = 0;
38
+ var loopArray = function (_scripts, scripts) {
39
+ // call itself
40
+ loadScript(_scripts[x], scripts[x], function () {
41
+ // set x to next item
42
+ x++;
43
+ // any more items in array?
44
+ if (x < _scripts.length) {
49
45
  loopArray(_scripts, scripts);
50
- }
51
-
52
- // async load as in your code
53
- function LoadScriptsAsync(_scripts, scripts) {
54
- for (var i = 0; i < _scripts.length; i++) {
55
- loadScript(_scripts[i], scripts[i], function () { });
56
- }
57
- }
46
+ }
47
+ });
48
+ };
49
+ loopArray(_scripts, scripts);
50
+ }
58
51
 
59
- // load script function with callback to handle synchronicity
60
- function loadScript(src, script, callback) {
52
+ // async load as in your code
53
+ function LoadScriptsAsync(_scripts, scripts) {
54
+ for (var i = 0; i < _scripts.length; i++) {
55
+ loadScript(_scripts[i], scripts[i], function () {});
56
+ }
57
+ }
61
58
 
62
- script = document.createElement('script');
63
- script.onerror = function () {
64
- // handling error when loading script
65
- console.log('Error - could not load BACnet node HTML dependencies')
66
- }
67
- script.onload = function () {
68
- callback();
69
- }
70
- script.src = src;
71
- document.getElementsByTagName('head')[0].appendChild(script);
72
- }
73
- })();
59
+ // load script function with callback to handle synchronicity
60
+ function loadScript(src, script, callback) {
61
+ script = document.createElement("script");
62
+ script.onerror = function () {
63
+ // handling error when loading script
64
+ console.log("Error - could not load BACnet node HTML dependencies");
65
+ };
66
+ script.onload = function () {
67
+ callback();
68
+ };
69
+ script.src = src;
70
+ document.getElementsByTagName("head")[0].appendChild(script);
71
+ }
72
+ })();
74
73
  </script>
75
74
 
76
75
  <script type="text/javascript">
77
- class NodeService {
78
- getNetworkData() {
79
- return fetch('/bitpool-bacnet-data/getNetworkTree').then(res => res.json());
80
- };
81
- rebuildDataModel() {
82
- return fetch('/bitpool-bacnet-data/rebuildDataModel').then(res => res.json());
83
- };
84
- clearBacnetServerPoints() {
85
- return fetch('/bitpool-bacnet-data/clearBacnetServerPoints').then(res => res.json());
86
- };
87
- };
88
- RED.nodes.registerType('Bacnet-Gateway', {
89
- category: 'Bitpool BACnet',
90
- color: '#00aeef',
91
- defaults: {
92
- name: {value: ""},
93
- local_device_address: {value: "", required: true},
94
- apduTimeout: {value: 6000},
95
- roundDecimal: {value: 2},
96
- local_device_port: {value: 47808, required: true},
97
- apduSize: {value: "5", required: true},
98
- maxSegments: {value: "0x50", required: true},
99
- retries: {value: "5", required: true},
100
- broadCastAddr: {value: "255.255.255.255", required: true},
101
- toLogIam: {value: true},
102
- discover_polling_schedule: {value: ""},
103
- discover_polling_schedule_value: {value: "1", required: true},
104
- discover_polling_schedule_options: {value: "Minutes", required: true},
105
- device_id_range_enabled: {value: false},
106
- device_id_range_start: {value: 0},
107
- device_id_range_end: {value: 4194303},
108
- deviceId: {value: 817001, required: true},
109
- manual_instance_range_enabled: {value: false},
110
- manual_instance_range_start: {value: 0},
111
- manual_instance_range_end: {value: 10000},
112
- logErrorToConsole: {value: false},
113
- serverEnabled: {value: false},
114
- device_read_schedule: {value: ""},
115
- device_read_schedule_value: {value: "1", required: true},
116
- device_read_schedule_options: {value: "Minutes", required: true}
76
+ class NodeService {
77
+ getNetworkData() {
78
+ return fetch("/bitpool-bacnet-data/getNetworkTree").then((res) => res.json());
79
+ }
80
+ rebuildDataModel() {
81
+ return fetch("/bitpool-bacnet-data/rebuildDataModel").then((res) => res.json());
82
+ }
83
+ clearBacnetServerPoints() {
84
+ return fetch("/bitpool-bacnet-data/clearBacnetServerPoints").then((res) => res.json());
85
+ }
86
+ getBacnetServerPoints() {
87
+ return fetch('/bitpool-bacnet-data/getBacnetServerPoints').then(res => res.json());
88
+ }
89
+ }
90
+ RED.nodes.registerType("Bacnet-Gateway", {
91
+ category: "Bitpool BACnet",
92
+ color: "#00aeef",
93
+ defaults: {
94
+ name: { value: "" },
95
+ local_device_address: { value: "", required: true },
96
+ apduTimeout: { value: 6000 },
97
+ roundDecimal: { value: 2 },
98
+ local_device_port: { value: 47808, required: true },
99
+ apduSize: { value: "5", required: true },
100
+ maxSegments: { value: "0x50", required: true },
101
+ retries: { value: "5", required: true },
102
+ broadCastAddr: { value: "255.255.255.255", required: true },
103
+ toLogIam: { value: false },
104
+ discover_polling_schedule: { value: "60" },
105
+ discover_polling_schedule_value: { value: "1", required: true },
106
+ discover_polling_schedule_options: { value: "Minutes", required: true },
107
+ deviceId: { value: 817001, required: true },
108
+ manual_instance_range_enabled: { value: false },
109
+ manual_instance_range_start: { value: 0 },
110
+ manual_instance_range_end: { value: 10000 },
111
+ logErrorToConsole: { value: false },
112
+ serverEnabled: { value: false },
113
+ device_read_schedule: { value: "60" },
114
+ device_read_schedule_value: { value: "1", required: true },
115
+ device_read_schedule_options: { value: "Minutes", required: true },
116
+ deviceRangeRegisters: { value: [] },
117
+ cacheFileEnabled: {value: false, required: true},
118
+ },
119
+ networkInterfaces: [],
120
+ inputs: 1,
121
+ outputs: 1,
122
+ icon: "bitpool.svg",
123
+ label: function () {
124
+ return this.name || "gateway";
125
+ },
126
+ paletteLabel: function () {
127
+ return "gateway";
128
+ },
129
+ oneditprepare: function () {
130
+ let node = this;
131
+
132
+ let tabs = RED.tabs.create({
133
+ id: "node-input-read-tabs",
134
+ onchange: function (tab) {
135
+ $("#node-input-tabs-content").children().hide();
136
+ $("#" + tab.id).show();
117
137
  },
118
- networkInterfaces: [],
119
- inputs: 1,
120
- outputs: 1,
121
- icon: "bitpool.svg",
122
- label: function () {
123
- return this.name || "gateway";
138
+ });
139
+
140
+ tabs.addTab({
141
+ id: "read-properties-tab",
142
+ label: "Gateway",
143
+ });
144
+
145
+ tabs.addTab({
146
+ id: "read-discover-tab",
147
+ label: "Discovery",
148
+ });
149
+
150
+ tabs.addTab({
151
+ id: "read-server-tab",
152
+ label: "Server",
153
+ });
154
+
155
+ if (node.networkInterfaces && node.networkInterfaces.length > 0) {
156
+ let nicSelector = document.getElementById("node-input-local_device_address");
157
+ node.networkInterfaces.forEach(function (option) {
158
+ nicSelector.options[nicSelector.options.length] = option;
159
+ });
160
+ nicSelector.value = node.local_device_address;
161
+ }
162
+
163
+ function queryAdapters() {
164
+ let nicSelector = document.getElementById("node-input-local_device_address");
165
+ $.ajax({
166
+ url: "/bitpool-bacnet-data/getNetworkInterfaces",
167
+ success: function (data) {
168
+ let keys = Object.keys(data);
169
+
170
+ for (const key in keys) {
171
+ let nicName = keys[key];
172
+ let ipAddr = data[keys[key]][0];
173
+ let text = nicName + " : " + ipAddr;
174
+ if (!node.networkInterfaces) node.networkInterfaces = [];
175
+ let found = node.networkInterfaces.findIndex((ele) => ele.text == text && ele.value == ipAddr);
176
+ if (found == -1) {
177
+ let newOption = new Option(text, ipAddr);
178
+ nicSelector.options[nicSelector.options.length] = newOption;
179
+ node.networkInterfaces.push(newOption);
180
+ }
181
+ }
182
+ nicSelector.value = node.local_device_address;
183
+ },
184
+ timeout: 10000,
185
+ });
186
+ }
187
+
188
+ queryAdapters();
189
+
190
+ function setManualInstanceRangeState(state) {
191
+ let deviceIdRangeStart = $("#node-input-manual_instance_range_start");
192
+ let deviceIdRangeEnd = $("#node-input-manual_instance_range_end");
193
+ if (state == true) {
194
+ deviceIdRangeStart.removeAttr("readonly");
195
+ deviceIdRangeEnd.removeAttr("readonly");
196
+ } else if (state == false) {
197
+ deviceIdRangeStart.attr("readonly", true);
198
+ deviceIdRangeEnd.attr("readonly", true);
199
+ }
200
+ }
201
+
202
+ setManualInstanceRangeState(node.manual_instance_range_enabled);
203
+
204
+ $("#node-input-manual_instance_range_enabled").change(function (e) {
205
+ setManualInstanceRangeState(this.checked);
206
+ });
207
+
208
+ if (node.vm1 == undefined) {
209
+ const confirmDialog = document.createElement("p-confirm-dialog");
210
+ document.getElementById("serverParent").appendChild(confirmDialog);
211
+ //document.getElementById("clearServerContainer").appendChild(confirmDialog);
212
+
213
+ }
214
+
215
+ const { createApp, ref, onMounted } = Vue;
216
+ const ConfirmDialog = primevue.confirmdialog;
217
+ const ConfirmationService = primevue.confirmationservice;
218
+ const ListBox = primevue.listbox;
219
+
220
+ //prime vue app
221
+ const App = {
222
+ data() {
223
+ return {
224
+ nodeService: ref(new NodeService()),
225
+ serverObjects: ref([]),
226
+ selectedServerObject: ref()
227
+ };
124
228
  },
125
- paletteLabel: function () {
126
- return "gateway";
229
+ mounted() {
230
+ this.getServerObjects();
127
231
  },
128
- oneditprepare: function () {
129
- let node = this;
130
-
131
- let tabs = RED.tabs.create(
132
- {
133
- id: "node-input-read-tabs",
134
- onchange: function (tab) {
135
- $("#node-input-tabs-content").children().hide()
136
- $("#" + tab.id).show()
137
- }
232
+ methods: {
233
+ confirmAll(event) {
234
+ let app = this;
235
+ this.$confirm.require({
236
+ message: "Do you want to clear all the BACnet server points? This action is not reversible",
237
+ header: "Delete Confirmation",
238
+ icon: "pi pi-info-circle",
239
+ acceptClass: "p-button-danger",
240
+ accept: () => {
241
+ //handle accept
242
+ this.nodeService.clearBacnetServerPoints().then(function() {
243
+ app.getServerObjects();
138
244
  });
139
-
140
- tabs.addTab(
141
- {
142
- id: "read-properties-tab",
143
- label: "Gateway"
144
- });
145
-
146
- tabs.addTab(
147
- {
148
- id: "read-discover-tab",
149
- label: "Discovery"
150
- });
151
-
152
- tabs.addTab(
153
- {
154
- id: "read-server-tab",
155
- label: "Server"
156
- });
157
-
158
- if (node.networkInterfaces && node.networkInterfaces.length > 0) {
159
- let nicSelector = document.getElementById("node-input-local_device_address");
160
- node.networkInterfaces.forEach(function (option) {
161
- nicSelector.options[nicSelector.options.length] = option;
162
- });
163
- nicSelector.value = node.local_device_address
164
- }
165
-
166
- function queryAdapters() {
167
- let nicSelector = document.getElementById("node-input-local_device_address");
168
- $.ajax({
169
- url: '/bitpool-bacnet-data/getNetworkInterfaces',
170
- success: function (data) {
171
- let keys = Object.keys(data);
172
-
173
- for (const key in keys) {
174
- let nicName = keys[key];
175
- let ipAddr = data[keys[key]][0];
176
- let text = nicName + ' : ' + ipAddr;
177
- if (!node.networkInterfaces) node.networkInterfaces = [];
178
- let found = node.networkInterfaces.findIndex(ele => ele.text == text && ele.value == ipAddr);
179
- if (found == -1) {
180
- let newOption = new Option(text, ipAddr);
181
- nicSelector.options[nicSelector.options.length] = newOption;
182
- node.networkInterfaces.push(newOption);
183
- }
184
- }
185
- nicSelector.value = node.local_device_address;
186
- },
187
- timeout: 10000
188
- });
189
- }
190
-
191
- queryAdapters();
192
-
193
- function setDeviceIdRangeState(state) {
194
- let deviceIdRangeStart = $("#node-input-device_id_range_start");
195
- let deviceIdRangeEnd = $("#node-input-device_id_range_end");
196
- if(state == true) {
197
- deviceIdRangeStart.removeAttr("readonly");
198
- deviceIdRangeEnd.removeAttr("readonly");
199
- } else if(state == false) {
200
- deviceIdRangeStart.attr("readonly", true);
201
- deviceIdRangeEnd.attr("readonly", true);
202
- }
203
- }
204
-
205
- setDeviceIdRangeState(node.device_id_range_enabled);
206
-
207
- $("#node-input-device_id_range_enabled").change(function(e) {
208
- setDeviceIdRangeState(this.checked);
209
- });
210
-
211
- function setManualInstanceRangeState(state) {
212
- let deviceIdRangeStart = $("#node-input-manual_instance_range_start");
213
- let deviceIdRangeEnd = $("#node-input-manual_instance_range_end");
214
- if(state == true) {
215
- deviceIdRangeStart.removeAttr("readonly");
216
- deviceIdRangeEnd.removeAttr("readonly");
217
- } else if(state == false) {
218
- deviceIdRangeStart.attr("readonly", true);
219
- deviceIdRangeEnd.attr("readonly", true);
220
- }
221
- }
222
-
223
- setManualInstanceRangeState(node.manual_instance_range_enabled);
224
-
225
- $("#node-input-manual_instance_range_enabled").change(function(e) {
226
- setManualInstanceRangeState(this.checked);
245
+ },
246
+ reject: () => {
247
+ //handle reject
248
+ },
227
249
  });
228
-
229
- if(node.vm == undefined) {
230
- const confirmDialog = document.createElement('p-confirm-dialog');
231
- document.getElementById("clearServerContainer").appendChild(confirmDialog);
232
- }
233
-
234
- const {createApp, ref, onMounted} = Vue;
235
- const ConfirmDialog = primevue.confirmdialog;
236
- const ConfirmationService = primevue.confirmationservice;
237
-
238
- //prime vue app
239
- const App = {
240
- data() {
241
- return {
242
- nodeService: ref(new NodeService())
243
- }
244
- },
245
- methods: {
246
- confirm(event) {
247
- this.$confirm.require({
248
- message: 'Do you want to clear all the BACnet server points? This action is not reversible',
249
- header: 'Delete Confirmation',
250
- icon: 'pi pi-info-circle',
251
- acceptClass: 'p-button-danger',
252
- accept: () => {
253
- //handle accept
254
- this.nodeService.clearBacnetServerPoints();
255
- },
256
- reject: () => {
257
- //handle reject
258
- }
259
- });
260
- }
261
- },
262
- components: {
263
- "p-button": primevue.button,
264
- "p-confirm-dialog": primevue.confirmdialog,
265
- "p-confirm-popup": primevue.confirmpopup
266
- }
267
- };
268
-
269
- let vueapp = createApp(App);
270
- vueapp.use(primevue.config.default);
271
- vueapp.use(primevue.confirmpopup);
272
- vueapp.use(primevue.confirmationservice);
273
- node.vm1 = vueapp.mount("#clearServerContainer");
274
-
275
- $("#file-upload").on("change", function(event) {
276
- const input = event.target.files[0];
277
- const reader = new FileReader();
278
-
279
- reader.onload = function (e) {
280
- const text = e.target.result;
281
-
282
- let jsonPayload = JSON.parse(text);
283
-
250
+ },
251
+ confirm(json) {
252
+ this.$confirm.require({
253
+ message: 'Do you want to clear this BACnet server point? This action is not reversible',
254
+ header: 'Delete Confirmation',
255
+ icon: 'pi pi-info-circle',
256
+ acceptClass: 'p-button-danger',
257
+ accept: () => {
258
+ //handle accept
259
+ let app = this;
284
260
  $.ajax({
285
261
  type: "POST",
286
- url: '/bitpool-bacnet-data/updateDeviceList',
262
+ url: '/bitpool-bacnet-data/clearBacnetServerPoint',
287
263
  dataType: 'json',
288
264
  contentType: 'application/json',
289
- data: JSON.stringify(jsonPayload),
265
+ data: JSON.stringify(json),
290
266
  success: function (result) {
267
+ app.getServerObjects();
291
268
  },
292
269
  timeout: 10000
293
270
  });
294
-
295
- };
296
-
297
- reader.readAsText(input);
271
+ },
272
+ reject: () => {
273
+ //handle reject
274
+ }
298
275
  });
276
+ },
277
+ getServerObjects() {
278
+ let app = this;
279
+ this.nodeService.getBacnetServerPoints().then(function (result) {
280
+ app.serverObjects = result;
281
+ })
282
+ },
283
+ formatObjectName(name) {
284
+ //return shortened point name if longer than 50 characters
285
+ if(name.length > 45) {
286
+ return name.slice(0, 45).concat("...");
287
+ }
288
+ return name;
289
+ }
290
+ },
291
+ components: {
292
+ "p-button": primevue.button,
293
+ "p-confirm-dialog": primevue.confirmdialog,
294
+ "p-confirm-popup": primevue.confirmpopup,
295
+ },
296
+ };
297
+
298
+ let vueapp = createApp(App);
299
+ vueapp.use(primevue.config.default);
300
+ vueapp.use(primevue.confirmpopup);
301
+ vueapp.use(primevue.confirmationservice);
302
+ node.vm1 = vueapp.mount("#serverParent");
303
+
304
+ $("#file-upload").on("change", function (event) {
305
+ const input = event.target.files[0];
306
+ const reader = new FileReader();
307
+
308
+ reader.onload = function (e) {
309
+ const text = e.target.result;
310
+
311
+ let jsonPayload = JSON.parse(text);
312
+
313
+ $.ajax({
314
+ type: "POST",
315
+ url: "/bitpool-bacnet-data/updateDeviceList",
316
+ dataType: "json",
317
+ contentType: "application/json",
318
+ data: JSON.stringify(jsonPayload),
319
+ success: function (result) {},
320
+ timeout: 10000,
321
+ });
322
+ };
299
323
 
300
- $("#file-export").click(function(params) {
301
- $.ajax({
302
- url: '/bitpool-bacnet-data/getDeviceList',
303
- success: function (deviceList) {
304
- let data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(deviceList));
305
- let aEle = document.getElementById("exportJSON");
306
- aEle.setAttribute("href", "data:" + data);
307
- aEle.setAttribute("download", "bitpool-bacnet-devices.json");
308
- aEle.click();
309
- },
310
- timeout: 10000
324
+ reader.readAsText(input);
325
+ });
326
+
327
+ $("#file-export").click(function (params) {
328
+ $.ajax({
329
+ url: "/bitpool-bacnet-data/getDeviceList",
330
+ success: function (deviceList) {
331
+ let data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(deviceList));
332
+ let aEle = document.getElementById("exportJSON");
333
+ aEle.setAttribute("href", "data:" + data);
334
+ aEle.setAttribute("download", "bitpool-bacnet-devices.json");
335
+ aEle.click();
336
+ },
337
+ timeout: 10000,
338
+ });
339
+ });
340
+
341
+ //device scan range matrix
342
+ $("#node-input-deviceIdRangeMatrix-container")
343
+ .css("min-width", "350px")
344
+ .editableList({
345
+ addItem: function (row, index, data) {
346
+ row.css({ overflow: "none", whiteSpace: "nowrap" });
347
+ let rowData = {};
348
+ if (data && typeof data.enabled == "boolean" && typeof data.start == "string" && typeof data.end == "string") {
349
+ if (data.enabled === true) {
350
+ rowData.enabled = "checked";
351
+ } else if (data.enabled === false) {
352
+ rowData.enabled = "";
353
+ }
354
+ rowData.start = data.start;
355
+ rowData.end = data.end;
356
+ } else {
357
+ rowData.enabled = "";
358
+ rowData.start = "";
359
+ rowData.end = "";
360
+ }
361
+
362
+ let fragment = document.createDocumentFragment();
363
+ let htmlRow = `
364
+ <div class="form-row deviceIdRangeEntry" id="node-input-device_id_range">
365
+ <label for="node-input-device_id_range_entry"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.device_id_range_entry"></span>Enabled</label>
366
+ <input type="checkbox" id="node-input-device_id_range_entry_enabled" style="width: auto;" ${rowData.enabled} />
367
+ <a style="padding-left: 60px;">Start: </a><input type="number" id="node-input-device_id_range_entry_start" style="width: 125px;" min="0" max="4194303" value="${rowData.start}" />
368
+ <a style="padding-left: 35px;">End: </a><input type="number" id="node-input-device_id_range_entry_end" style="width: 125px;" min="1" max="4194303" value="${rowData.end}" />
369
+ </div>`;
370
+
371
+ $(htmlRow).appendTo(fragment);
372
+ row[0].appendChild(fragment);
373
+ document.getElementById("node-input-reg-block-count").innerHTML = $(
374
+ "#node-input-deviceIdRangeMatrix-container"
375
+ ).editableList("length");
376
+ },
377
+ removeItem: function (data) {
378
+ document.getElementById("node-input-reg-block-count").innerHTML = $(
379
+ "#node-input-deviceIdRangeMatrix-container"
380
+ ).editableList("length");
381
+ },
382
+ removable: true,
383
+ scrollOnAdd: false,
384
+ header: $("<div style='display:flex; padding:10px 10px 0px 5px; column-gap: 10px'>").append(
385
+ $.parseHTML(
386
+ "<div><p>Count:</p></div><div style='color: gray'><label id='node-input-reg-block-count'>0</label> <span style='padding-left: 85px;'>Device ID Range(s)</span> </div>"
387
+ )
388
+ ),
389
+ buttons: [
390
+ {
391
+ label: "json",
392
+ icon: "fa fa-share",
393
+ title: "Export tags as JSON to browser",
394
+ click: function (evt) {
395
+ var deviceRangeRegisters = $("#node-input-deviceIdRangeMatrix-container").editableList("items");
396
+ var mapItems = [];
397
+ deviceRangeRegisters.each(function (i) {
398
+ var registerMap = $(this);
399
+ var mapItem = {
400
+ enabled: registerMap.find("#node-input-device_id_range_entry_enabled").val(),
401
+ start: registerMap.find("#node-input-device_id_range_entry_start").val(),
402
+ end: registerMap.find("#node-input-device_id_range_entry_end").val(),
403
+ };
404
+ mapItems.push(mapItem);
311
405
  });
312
- });
313
- },
314
- oneditsave: function (test) {
315
- let node = this;
316
-
317
- document.getElementById("node-input-discover_polling_schedule").value = getTimePeriodInSeconds(
318
- document.getElementById("node-input-discover_polling_schedule_value").value,
319
- document.getElementById("node-input-discover_polling_schedule_options").value
320
- );
321
-
322
- document.getElementById("node-input-device_read_schedule").value = getTimePeriodInSeconds(
323
- document.getElementById("node-input-device_read_schedule_value").value,
324
- document.getElementById("node-input-device_read_schedule_options").value
325
- );
326
- }
327
- });
328
-
329
- function getTimePeriodInSeconds(value, interval) {
330
- switch (interval) {
331
- case "Seconds":
332
- return value;
333
- break;
334
- case "Minutes":
335
- return value * 60;
336
- break;
337
- case "Hours":
338
- return value * 3600;
339
- break;
340
- case "Days":
341
- return value * 86400;
342
- break;
343
- default:
344
- // code block
406
+ var oMyBlob = new Blob(
407
+ [
408
+ JSON.stringify(mapItems, null, 0)
409
+ .replaceAll(/\[{/gi, "[\n{")
410
+ .replaceAll(/}\]/gi, "}\n]")
411
+ .replaceAll(/},/gi, "},\n")
412
+ .replaceAll(/{/gi, " {"),
413
+ ],
414
+ { type: "text/json" }
415
+ );
416
+ window.open(URL.createObjectURL(oMyBlob));
417
+ },
418
+ },
419
+ {
420
+ label: "delete",
421
+ icon: "fa-regular fa-trash-can",
422
+ title: "Delete all registers",
423
+ click: function (evt) {
424
+ $("#node-input-deviceIdRangeMatrix-container").editableList("empty");
425
+ document.getElementById("node-input-reg-block-count").innerHTML = 0;
426
+ },
427
+ },
428
+ ],
429
+ });
430
+
431
+ if (node.deviceRangeRegisters.length > 0) {
432
+ for (var i = 0; i < node.deviceRangeRegisters.length; i++) {
433
+ $("#node-input-deviceIdRangeMatrix-container").editableList("addItem", node.deviceRangeRegisters[i]);
345
434
  }
435
+ } else {
436
+ $("#node-input-deviceIdRangeMatrix-container").editableList("addItem", {
437
+ enabled: true,
438
+ start: "0",
439
+ end: "4194303",
440
+ });
441
+ }
442
+
443
+ document.getElementById("node-input-reg-block-count").innerHTML = node.deviceRangeRegisters.length;
444
+ },
445
+ oneditsave: function () {
446
+ let node = this;
447
+
448
+ document.getElementById("node-input-discover_polling_schedule").value = getTimePeriodInSeconds(
449
+ document.getElementById("node-input-discover_polling_schedule_value").value,
450
+ document.getElementById("node-input-discover_polling_schedule_options").value
451
+ );
452
+
453
+ document.getElementById("node-input-device_read_schedule").value = getTimePeriodInSeconds(
454
+ document.getElementById("node-input-device_read_schedule_value").value,
455
+ document.getElementById("node-input-device_read_schedule_options").value
456
+ );
457
+
458
+ node.deviceRangeRegisters = [];
459
+ let deviceRanges = $("#node-input-deviceIdRangeMatrix-container").editableList("items");
460
+ deviceRanges.each(function (i) {
461
+ let map = $(this);
462
+ let mapItem = {
463
+ enabled: map.find("#node-input-device_id_range_entry_enabled").is(":checked"),
464
+ start: map.find("#node-input-device_id_range_entry_start").val(),
465
+ end: map.find("#node-input-device_id_range_entry_end").val(),
466
+ };
467
+ node.deviceRangeRegisters.push(mapItem);
468
+ });
469
+ },
470
+ });
471
+
472
+ function getTimePeriodInSeconds(value, interval) {
473
+ switch (interval) {
474
+ case "Seconds":
475
+ return value;
476
+ break;
477
+ case "Minutes":
478
+ return value * 60;
479
+ break;
480
+ case "Hours":
481
+ return value * 3600;
482
+ break;
483
+ case "Days":
484
+ return value * 86400;
485
+ break;
486
+ default:
487
+ // code block
346
488
  }
347
-
489
+ }
348
490
  </script>
349
491
 
350
492
  <script type="text/html" data-template-name="Bacnet-Gateway">
351
- <style>
352
- .deviceButton {
353
- width: -webkit-fill-available;
354
- background: space;
355
- background-color: transparent !important;
356
- color: inherit;
357
- border: none;
358
- display: flex;
359
- align-items: center;
360
- padding-top: 20px;
361
- }
362
- .point {
363
- padding-left: 50px
364
- }
365
- .pointButton {
366
- color: inherit;
367
- border: none;
368
- display: flex;
369
- align-items: center;
370
- }
371
- .networkTreeContent {
372
- margin-top: 20px;
373
- margin-left: 50px;
374
- }
375
- .p-confirm-dialog-accept > .p-button-label, .bacnetServerRebuildSchedule_clearButton > .p-button-label {
376
- color: white;
377
- }
378
- .red-ui-editor label {
379
- font-size: 12px;
380
- }
381
- .bacnetServerRebuildSchedule_clearButton {
382
- box-shadow: 0 0 0 0.2rem #edacac !important;
383
- width: 200px;
384
- border-radius: 3px;
385
- margin-left: 140px !important;
386
- }
387
- .clear_server_span {
388
- width: 0px;
389
- }
390
- .read_server_parent_div {
391
- display: flex;
392
- align-items: center;
393
- justify-content: space-around;
394
- }
395
- button {
396
- height: 34px;
397
- border-radius: 5px !important;
398
- }
399
- .inputStyle {
400
- color: var(--red-ui-workspace-button-color-hover) !important;
401
- background: var(--red-ui-workspace-button-background-hover);
402
- border: 1px solid var(--red-ui-secondary-border-color);
403
- border-radius: 5px !important;
404
- }
405
- input[type="file"] {
406
- display: none !important;
407
- }
408
- .custom-file-upload {
409
- border: 1px solid var(--red-ui-secondary-border-color);
410
- border-radius: 5px !important;
411
- padding: 6px 12px;
412
- cursor: pointer;
413
- }
414
- .uploadButton {
415
- margin-bottom: 5px !important;
416
- margin-left: 30px !important;
417
- }
418
-
419
- </style>
420
-
421
- <div class='form-row node-input-read-tabs-row'>
422
- <ul style='min-width:600px;margin-bottom:20px' id='node-input-read-tabs'></ul>
493
+ <style>
494
+ .deviceButton {
495
+ width: -webkit-fill-available;
496
+ background: space;
497
+ background-color: transparent !important;
498
+ color: inherit;
499
+ border: none;
500
+ display: flex;
501
+ align-items: center;
502
+ padding-top: 20px;
503
+ }
504
+ .point {
505
+ padding-left: 50px;
506
+ }
507
+ .pointButton {
508
+ color: inherit;
509
+ border: none;
510
+ display: flex;
511
+ align-items: center;
512
+ }
513
+ .networkTreeContent {
514
+ margin-top: 20px;
515
+ margin-left: 50px;
516
+ }
517
+ .p-confirm-dialog-accept > .p-button-label,
518
+ .bacnetServerRebuildSchedule_clearButton > .p-button-label {
519
+ color: white;
520
+ }
521
+ .red-ui-editor label {
522
+ font-size: 12px;
523
+ }
524
+ .bacnetServerRebuildSchedule_clearButton {
525
+ box-shadow: 0 0 0 0.2rem #edacac !important;
526
+ width: 200px;
527
+ border-radius: 3px;
528
+ margin-left: 140px !important;
529
+ }
530
+ .clearServerContainer {
531
+ position: absolute;
532
+ top: 55px;
533
+ margin-left: 280px;
534
+ }
535
+ .bacnetServerPoint_clearButton {
536
+ box-shadow: 0 0 0 0.2rem #edacac !important;
537
+ width: 200px;
538
+ border-radius: 3px;
539
+ margin-left: 420px !important;
540
+ margin-top: -75px !important;
541
+ }
542
+ .bacnetServerPoint_clearButton > .p-button-label {
543
+ color: white;
544
+ }
545
+ .clear_server_span {
546
+ width: 0px;
547
+ }
548
+ .read_server_parent_div {
549
+ display: flex;
550
+ align-items: flex-start;
551
+ justify-content: space-around;
552
+ flex-direction: column;
553
+ }
554
+ button {
555
+ height: 34px;
556
+ border-radius: 5px !important;
557
+ }
558
+ .inputStyle {
559
+ color: var(--red-ui-workspace-button-color-hover) !important;
560
+ background: var(--red-ui-workspace-button-background-hover);
561
+ border: 1px solid var(--red-ui-secondary-border-color);
562
+ border-radius: 5px !important;
563
+ }
564
+ input[type="file"] {
565
+ display: none !important;
566
+ }
567
+ .custom-file-upload {
568
+ border: 1px solid var(--red-ui-secondary-border-color);
569
+ border-radius: 5px !important;
570
+ padding: 6px 12px;
571
+ cursor: pointer;
572
+ }
573
+ .uploadButton {
574
+ margin-bottom: 5px !important;
575
+ margin-left: 30px !important;
576
+ }
577
+ .point_name {
578
+ font-weight: bold;
579
+ }
580
+ </style>
581
+
582
+ <div class="form-row node-input-read-tabs-row">
583
+ <ul style="min-width:600px;margin-bottom:20px" id="node-input-read-tabs"></ul>
584
+ </div>
585
+
586
+ <div id="node-input-tabs-content">
587
+ <div id="read-properties-tab" style="display:none">
588
+ <div class="form-row">
589
+ <label for="node-input-name"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.name"></span> Name</label>
590
+ <input type="text" id="node-input-name" placeholder="Name" />
591
+ </div>
592
+
593
+ <div class="form-row node-input-read-tabs-row">
594
+ <ul style="min-width:600px;margin-bottom:20px" id="node-input-read-tabs"></ul>
595
+ </div>
596
+
597
+ <div class="form-row" id="networkInterfaceDiv">
598
+ <label for="node-input-local_device_address"
599
+ ><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.local_device_address"></span> Network
600
+ Interface</label
601
+ >
602
+ <select id="node-input-local_device_address" style="width: 70%;"></select>
603
+ </div>
604
+
605
+ <div class="form-row">
606
+ <label for="node-input-broadCastAddr"
607
+ ><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.broadCastAddr"></span> Broadcast Address
608
+ </label>
609
+ <input type="text" id="node-input-broadCastAddr" placeholder="255.255.255.255" />
610
+ </div>
611
+
612
+ <div class="form-row">
613
+ <label for="node-input-local_device_port"
614
+ ><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.local_device_port"></span> Local Device Port</label
615
+ >
616
+ <input type="text" id="node-input-local_device_port" placeholder="47808" />
617
+ </div>
618
+
619
+ <div class="form-row">
620
+ <label for="node-input-deviceId"
621
+ ><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.deviceId"></span> Device ID
622
+ </label>
623
+ <input type="text" id="node-input-deviceId" placeholder="817001" />
624
+ </div>
625
+
626
+ <div class="form-row node-input-deviceIdRangeMatrix-container-row">
627
+ <ol id="node-input-deviceIdRangeMatrix-container" style="width: 600px;"></ol>
628
+ </div>
629
+ </div>
630
+
631
+ <div id="read-discover-tab" style="display:none">
632
+ <div class="form-row">
633
+ <label for="node-input-apduTimeout"
634
+ ><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.apduTimeout"></span>Apdu Timeout</label
635
+ >
636
+ <input type="text" id="node-input-apduTimeout" placeholder="10000" />
637
+ </div>
638
+
639
+ <div class="form-row" style="display: none;">
640
+ <label for="node-input-apduSize"
641
+ ><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.apduSize"></span>Max Apdu Size</label
642
+ >
643
+ <select id="node-input-apduSize">
644
+ <option value="0">0</option>
645
+ <option value="1">1</option>
646
+ <option value="2">2</option>
647
+ <option value="3">3</option>
648
+ <option value="4">4</option>
649
+ <option value="5">5</option>
650
+ </select>
651
+ </div>
652
+
653
+ <div class="form-row" style="display: none;">
654
+ <label for="node-input-maxSegments"
655
+ ><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.maxSegments"></span>Max Segments</label
656
+ >
657
+ <select id="node-input-maxSegments">
658
+ <option value="0">0</option>
659
+ <option value="0x10">0x10</option>
660
+ <option value="0x20">0x20</option>
661
+ <option value="0x30">0x30</option>
662
+ <option value="0x40">0x40</option>
663
+ <option value="0x50">0x50</option>
664
+ <option value="0x60">0x60</option>
665
+ <option value="0x70">0x70</option>
666
+ </select>
667
+ </div>
668
+
669
+ <div class="form-row">
670
+ <label for="node-input-retries"
671
+ ><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.retries"></span>Number of Retries</label
672
+ >
673
+ <select id="node-input-retries">
674
+ <option value="0">0</option>
675
+ <option value="1">1</option>
676
+ <option value="2">2</option>
677
+ <option value="3">3</option>
678
+ <option value="4">4</option>
679
+ <option value="5">5</option>
680
+ <option value="6">6</option>
681
+ <option value="7">7</option>
682
+ <option value="8">8</option>
683
+ <option value="9">9</option>
684
+ <option value="10">10</option>
685
+ </select>
686
+ </div>
687
+
688
+ <div class="form-row" style="align-items: center; display: flex;">
689
+ <label for="node-input-discover_polling_schedule_value"
690
+ ><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.bacnet_polling_schedule"></span>Device Discover
691
+ Frequency</label
692
+ >
693
+ <p style="margin-right: 5px; margin-bottom: 0px; padding-left: 7px;">Every</p>
694
+ <input type="text" id="node-input-discover_polling_schedule" style="display: none;" />
695
+ <input
696
+ type="text"
697
+ id="node-input-discover_polling_schedule_value"
698
+ placeholder="5"
699
+ style="width: 70px; margin-right: 5px;" />
700
+ <select name="timePeriod" id="node-input-discover_polling_schedule_options" style="width: 120px; margin-right: 5px;">
701
+ <option value="Seconds">Seconds</option>
702
+ <option value="Minutes">Minutes</option>
703
+ <option value="Hours">Hours</option>
704
+ <option value="Days">Days</option>
705
+ </select>
706
+ </div>
707
+
708
+ <div class="form-row deviceIdRange">
709
+ <label for="node-input-device_id_range"
710
+ ><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.device_id_range"></span>Point Discovery Range
711
+ </label>
712
+ <input type="checkbox" id="node-input-manual_instance_range_enabled" style="width: auto;" />
713
+ <a style="padding-left: 60px;">Start: </a
714
+ ><input type="number" id="node-input-manual_instance_range_start" style="width: 125px;" min="0" max="100000" />
715
+ <a style="padding-left: 35px;">End: </a
716
+ ><input type="number" id="node-input-manual_instance_range_end" style="width: 125px;" min="1" max="100000" />
717
+ </div>
718
+
719
+ <div class="form-row" style="align-items: center; display: flex;">
720
+ <label for="node-input-device_read_schedule_value"
721
+ ><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.device_read_schedule"></span>Object Discover
722
+ Frequency</label
723
+ >
724
+ <p style="margin-right: 5px; margin-bottom: 0px; padding-left: 7px;">Every</p>
725
+ <input type="text" id="node-input-device_read_schedule" style="display: none;" />
726
+ <input
727
+ type="text"
728
+ id="node-input-device_read_schedule_value"
729
+ placeholder="5"
730
+ style="width: 70px; margin-right: 5px;" />
731
+ <select name="timePeriod" id="node-input-device_read_schedule_options" style="width: 120px; margin-right: 5px;">
732
+ <option value="Seconds">Seconds</option>
733
+ <option value="Minutes">Minutes</option>
734
+ <option value="Hours">Hours</option>
735
+ <option value="Days">Days</option>
736
+ </select>
737
+ </div>
738
+
739
+ <div class="form-row">
740
+ <label for="node-input-cacheFileEnabled"> Cache file enabled: </label>
741
+ <input type="checkbox" id="node-input-cacheFileEnabled" style="width: auto;" />
742
+ </div>
743
+
744
+ <div class="form-row">
745
+ <label for="node-input-toLog"> Log found device: </label>
746
+ <input type="checkbox" id="node-input-toLogIam" style="width: auto;" />
747
+ </div>
748
+
749
+ <div class="form-row">
750
+ <label for="node-input-logErrorToConsole"> Log BACnet errors to console: </label>
751
+ <input type="checkbox" id="node-input-logErrorToConsole" style="width: auto;" />
752
+ </div>
753
+
754
+ <div class="form-row" id="importDeviceList">
755
+ <label> Device List: </label>
756
+ <label for="file-upload" class="custom-file-upload">
757
+ <i class="fa fa-cloud-upload" id="fileLabel"></i> <a id="fileLabelText" style="padding-left: 10px;">Import</a>
758
+ </label>
759
+ <input type="file" id="file-upload" accept="application/JSON" class="inputStyle" style="width: 258px;" />
760
+ <label for="file-export" class="custom-file-upload" style="margin-left: 30px;">
761
+ <i class="fa fa-cloud-download" id="fileLabel"></i> <a id="fileLabelText" style="padding-left: 10px;">Export</a>
762
+ </label>
763
+ <input id="file-export" class="inputStyle" style="width: 258px; display: none;" />
764
+ <a id="exportJSON" style="display: none"></a>
765
+ </div>
766
+ </div>
767
+
768
+ <div id="read-server-tab" style="display:none">
769
+
770
+ <div class="form-row">
771
+ <label for="node-input-serverEnabled"> Enabled: </label>
772
+ <input type="checkbox" id="node-input-serverEnabled" style="width: auto;" />
773
+ </div>
774
+
775
+ <div class="read_server_parent_div" id="serverParent">
776
+
777
+ <div class="form-row clearServerContainer" id="clearServerContainer" style="align-items: center; display: flex;">
778
+ <p-button
779
+ class="bacnetServerRebuildSchedule_clearButton p-button-danger"
780
+ @click="confirmAll($event)"
781
+ label="Reinitialize Server">
782
+ </p-button>
423
783
  </div>
424
784
 
425
- <div id='node-input-tabs-content'>
426
- <div id='read-properties-tab' style='display:none'>
427
- <div class="form-row">
428
- <label for="node-input-name"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.name"></span> Name</label>
429
- <input type="text" id="node-input-name" placeholder="Name">
430
- </div>
431
-
432
- <div class='form-row node-input-read-tabs-row'>
433
- <ul style='min-width:600px;margin-bottom:20px' id='node-input-read-tabs'></ul>
434
- </div>
435
-
436
- <div class="form-row" id="networkInterfaceDiv">
437
- <label for="node-input-local_device_address"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.local_device_address"></span> Network Interface</label>
438
- <select id="node-input-local_device_address" style="width: 70%;" >
439
- </select>
440
- </div>
441
-
442
- <div class="form-row">
443
- <label for="node-input-broadCastAddr"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.broadCastAddr"></span> Broadcast Address </label>
444
- <input type="text" id="node-input-broadCastAddr" placeholder="255.255.255.255">
445
- </div>
446
-
447
- <div class="form-row">
448
- <label for="node-input-local_device_port"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.local_device_port"></span> Local Device Port</label>
449
- <input type="text" id="node-input-local_device_port" placeholder="47808">
450
- </div>
451
-
452
- <div class="form-row">
453
- <label for="node-input-deviceId"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.deviceId"></span> Device ID </label>
454
- <input type="text" id="node-input-deviceId" placeholder="817001">
455
- </div>
456
-
457
- <div class="form-row deviceIdRange">
458
- <label for="node-input-device_id_range"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.device_id_range"></span> Device ID Range </label>
459
- <input type="checkbox" id="node-input-device_id_range_enabled" style="width: auto;"/>
460
- <a style="padding-left: 60px;">Start: </a><input type="number" id="node-input-device_id_range_start" style="width: 125px;" min="0" max="4194303"/>
461
- <a style="padding-left: 35px;">End: </a><input type="number" id="node-input-device_id_range_end" style="width: 125px;" min="1" max="4194303"/>
462
- </div>
463
- </div>
464
-
465
- <div id='read-discover-tab' style='display:none'>
466
- <div class="form-row">
467
- <label for="node-input-apduTimeout"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.apduTimeout"></span>Apdu Timeout</label>
468
- <input type="text" id="node-input-apduTimeout" placeholder="10000">
469
- </div>
470
-
471
- <div class="form-row">
472
- <label for="node-input-apduSize"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.apduSize"></span>Max Apdu Size</label>
473
- <select id="node-input-apduSize">
474
- <option value="0">0</option>
475
- <option value="1">1</option>
476
- <option value="2">2</option>
477
- <option value="3">3</option>
478
- <option value="4">4</option>
479
- <option value="5">5</option>
480
- </select>
481
- </div>
482
-
483
- <div class="form-row">
484
- <label for="node-input-maxSegments"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.maxSegments"></span>Max Segments</label>
485
- <select id="node-input-maxSegments">
486
- <option value="0">0</option>
487
- <option value="0x10">0x10</option>
488
- <option value="0x20">0x20</option>
489
- <option value="0x30">0x30</option>
490
- <option value="0x40">0x40</option>
491
- <option value="0x50">0x50</option>
492
- <option value="0x60">0x60</option>
493
- <option value="0x70">0x70</option>
494
- </select>
495
- </div>
496
-
497
- <div class="form-row">
498
- <label for="node-input-retries"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.retries"></span>Number of Retries</label>
499
- <select id="node-input-retries">
500
- <option value="0">0</option>
501
- <option value="1">1</option>
502
- <option value="2">2</option>
503
- <option value="3">3</option>
504
- <option value="4">4</option>
505
- <option value="5">5</option>
506
- <option value="6">6</option>
507
- <option value="7">7</option>
508
- <option value="8">8</option>
509
- <option value="9">9</option>
510
- <option value="10">10</option>
511
- </select>
512
- </div>
513
-
514
- <div class="form-row" style="align-items: center; display: flex;">
515
- <label for="node-input-discover_polling_schedule_value"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.bacnet_polling_schedule"></span>Device Discover Frequency</label>
516
- <p style="margin-right: 5px; margin-bottom: 0px; padding-left: 7px;">Every</p>
517
- <input type="text" id="node-input-discover_polling_schedule" style="display: none;">
518
- <input type="text" id="node-input-discover_polling_schedule_value" placeholder="5" style="width: 70px; margin-right: 5px;">
519
- <select name="timePeriod" id="node-input-discover_polling_schedule_options" style="width: 120px; margin-right: 5px;">
520
- <option value="Seconds">Seconds</option>
521
- <option value="Minutes">Minutes</option>
522
- <option value="Hours">Hours</option>
523
- <option value="Days">Days</option>
524
- </select>
525
- </div>
526
-
527
- <div class="form-row deviceIdRange">
528
- <label for="node-input-device_id_range"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.device_id_range"></span>Point Discovery Range </label>
529
- <input type="checkbox" id="node-input-manual_instance_range_enabled" style="width: auto;"/>
530
- <a style="padding-left: 60px;">Start: </a><input type="number" id="node-input-manual_instance_range_start" style="width: 125px;" min="0" max="100000"/>
531
- <a style="padding-left: 35px;">End: </a><input type="number" id="node-input-manual_instance_range_end" style="width: 125px;" min="1" max="100000"/>
532
- </div>
533
-
534
- <div class="form-row" style="align-items: center; display: flex;">
535
- <label for="node-input-device_read_schedule_value"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.device_read_schedule"></span>Object Discover Frequency</label>
536
- <p style="margin-right: 5px; margin-bottom: 0px; padding-left: 7px;">Every</p>
537
- <input type="text" id="node-input-device_read_schedule" style="display: none;">
538
- <input type="text" id="node-input-device_read_schedule_value" placeholder="5" style="width: 70px; margin-right: 5px;">
539
- <select name="timePeriod" id="node-input-device_read_schedule_options" style="width: 120px; margin-right: 5px;">
540
- <option value="Seconds">Seconds</option>
541
- <option value="Minutes">Minutes</option>
542
- <option value="Hours">Hours</option>
543
- <option value="Days">Days</option>
544
- </select>
545
- </div>
546
-
547
- <div class="form-row">
548
- <label for="node-input-toLog">
549
- Log found device:
550
- </label>
551
- <input type="checkbox" id="node-input-toLogIam" style="width: auto;"/>
552
- </div>
553
-
554
- <div class="form-row">
555
- <label for="node-input-logErrorToConsole">
556
- Log BACnet errors to console:
557
- </label>
558
- <input type="checkbox" id="node-input-logErrorToConsole" style="width: auto;"/>
559
- </div>
560
-
561
- <div class="form-row" id="importDeviceList">
562
- <label>
563
- Device List:
564
- </label>
565
- <label for="file-upload" class="custom-file-upload">
566
- <i class="fa fa-cloud-upload" id="fileLabel"></i> <a id="fileLabelText" style="padding-left: 10px;">Import</a>
567
- </label>
568
- <input type="file" id="file-upload" accept="application/JSON" class="inputStyle" style="width: 258px;">
569
- <label for="file-export" class="custom-file-upload" style="margin-left: 30px;">
570
- <i class="fa fa-cloud-download" id="fileLabel"></i> <a id="fileLabelText" style="padding-left: 10px;">Export</a>
571
- </label>
572
- <input id="file-export" class="inputStyle" style="width: 258px; display: none;">
573
- <a id="exportJSON" style="display: none"></a>
574
- </div>
575
- </div>
576
-
577
- <div id='read-server-tab' style='display:none'>
578
- <div class="read_server_parent_div">
579
- <div class="form-row">
580
- <label for="node-input-serverEnabled">
581
- Enabled:
582
- </label>
583
- <input type="checkbox" id="node-input-serverEnabled" style="width: auto;"/>
584
- </div>
585
-
586
- <div class="form-row" id="clearServerContainer" style="align-items: center; display: flex;">
587
- <label for="node-input-bacnetServerRebuildSchedule_value" class="clear_server_span"><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.bacnetServerRebuildSchedule"></span> </label>
588
- <p-button class="bacnetServerRebuildSchedule_clearButton p-button-danger" @click="confirm($event)" label="Reinitialize Server" ></p-button>
589
- </div>
590
- </div>
591
- </div>
592
-
593
- </script>
594
- <script type="text/html" data-help-name="Bacnet-Gateway">
595
- <p> This node is the brain of the Bitpool BACnet node collection. It acts are the gateway for all BACnet communications and functionality for the collection. </p>
596
-
597
- <h3><strong>Gateway Tab</strong></h3>
598
- <ul class="node-ports">
599
- <li>Network Interface - the desired interface for the bacstack client to bind to. This interface must not have any other BACnet clients bound to it.</li>
600
- <li>Broadcast Address - the desired subnet for global msgs to be broadcast and recieved on. This should be as strict as possible. Use 255.255.255.255 if unsure.</li>
601
- <li>Local Device Port - the port to be used for BACnet comms. Default is 47808</li>
602
-
603
- </ul>
604
-
605
- <h3><strong>Discovery Tab</strong></h3>
606
- <ul class="node-ports">
607
- <li>APDU Timeout - BACnet msg timeout option</li>
608
- <li>Max APDU Size - BACnet max apdu size</li>
609
- <li>Max Segments - BACnet max segments</li>
610
- <li>Global Discover Frequency - the frequency at which the gateway issues global WhoIs BACnet commands. This should be limited to the least amount possible, as over-loading a network can be a serious issue with BACnet commmunications.</li>
611
- <li>Manual Point Discovery Instance Range - if a BACnet device doesnt have a Object list (BACnet objectType:propertyId - 8:76), the this bacnet client will enter into manual discovery mode, where it iterates through types and instnace ranges. This range can be used to limit this manual scanning </li>
612
- <li>Log Device Found - toggles logging of found devices to the node-red debug tab.</li>
613
- <li>Log BACnet Errors to Console - toggles logging of BACnet related errors to the node-red console</li>
614
- </ul>
615
-
616
- <h3><strong>Server Tab</strong></h3>
617
- <p>This section provides the ability to simulate a BACnet device and BACnet points using node-red. </p>
618
- <p>Injecting a msg.topic and msg.payload into the gateway node will create a virtual point that can be discovered by other devices via BACnet/IP</p>
619
- <p>This node only supports 2 BACnet object types, Analog Value - to show numeric data, and a Character String - to show string data.</p>
620
- <ul class="node-ports">
621
- <li>Enabled - toggles whether or not the local BACnet server is started or not. </li>
622
- <li>Clear Server Points - a schedule for the locally generated BACnet points to get cleared from the node object store</li>
623
- </ul>
624
-
625
- <h3><strong>Examples</strong></h3>
626
- <p>For example flows, please use the examples section for this node. These examples can be found at: Node-red hamburger menu on top right -> Import -> Examples -> @bitpoolos/edge-bacnet</p>
627
- <p>To find captured examples of settings and flows, please go to our wiki <a href="https://wiki.bitpool.com/en/edge/apps/bitpool-edge/nr-bacnet">here</a></p>
628
-
629
-
630
- <h3>Resources:</h3>
631
-
632
- <p><a href="https://youtu.be/4K7mVxfvfbc">Video Walk-through </a></p>
633
-
634
- <h4><strong>Online Docs:</strong></h4>
635
- <ul type="1">
636
- <li><a href="https://www.bitpool.com/">bitpool.com</a> - check us out here.</li>
637
- <li><a href="https://app.bitpool.com/">app.bitpool.com</a> - set up your account.</li>
638
- <li><a href="https://wiki.bitpool.com/">wiki.bitpool.com</a> - find more documentation.</li>
639
- <li><a href="https://bacnet.org/">BACnet</a> - find more about the protocol.</li>
640
- </ul>
641
- </script>
785
+ <div class="form-row" id="clearServerPointContainer">
786
+ <label>Server Objects</label>
787
+ <div v-for="object in serverObjects" :key="object.name">
788
+ <div><p class="point_name">[{{ object.type }}{{ object.instance }}] {{ formatObjectName(object.name) }}</p></div>
789
+ <p-button class="bacnetServerPoint_clearButton p-button-danger" @click="confirm({
790
+ type: object.type,
791
+ instance: object.instance,
792
+ name: object.name
793
+ })" label="Remove Object"></p-button>
794
+ </div>
795
+ </div>
796
+ </div>
797
+ </div>
798
+ </div>
799
+ </script>
800
+ <script type="text/html" data-help-name="Bacnet-Gateway">
801
+ <p>
802
+ This node is the brain of the Bitpool BACnet node collection. It acts are the gateway for all BACnet communications and
803
+ functionality for the collection.
804
+ </p>
805
+
806
+ <h3><strong>Gateway Tab</strong></h3>
807
+ <ul class="node-ports">
808
+ <li>
809
+ Network Interface - the desired interface for the bacstack client to bind to. This interface must not have any other
810
+ BACnet clients bound to it.
811
+ </li>
812
+ <li>
813
+ Broadcast Address - the desired subnet for global msgs to be broadcast and recieved on. This should be as strict as
814
+ possible. Use 255.255.255.255 if unsure.
815
+ </li>
816
+ <li>Local Device Port - the port to be used for BACnet comms. Default is 47808</li>
817
+ </ul>
818
+
819
+ <h3><strong>Discovery Tab</strong></h3>
820
+ <ul class="node-ports">
821
+ <li>APDU Timeout - BACnet msg timeout option</li>
822
+ <li>Max APDU Size - BACnet max apdu size</li>
823
+ <li>Max Segments - BACnet max segments</li>
824
+ <li>
825
+ Global Discover Frequency - the frequency at which the gateway issues global WhoIs BACnet commands. This should be
826
+ limited to the least amount possible, as over-loading a network can be a serious issue with BACnet commmunications.
827
+ </li>
828
+ <li>
829
+ Manual Point Discovery Instance Range - if a BACnet device doesnt have a Object list (BACnet objectType:propertyId -
830
+ 8:76), the this bacnet client will enter into manual discovery mode, where it iterates through types and instnace
831
+ ranges. This range can be used to limit this manual scanning
832
+ </li>
833
+ <li>Log Device Found - toggles logging of found devices to the node-red debug tab.</li>
834
+ <li>Log BACnet Errors to Console - toggles logging of BACnet related errors to the node-red console</li>
835
+ </ul>
836
+
837
+ <h3><strong>Server Tab</strong></h3>
838
+ <p>This section provides the ability to simulate a BACnet device and BACnet points using node-red.</p>
839
+ <p>
840
+ Injecting a msg.topic and msg.payload into the gateway node will create a virtual point that can be discovered by other
841
+ devices via BACnet/IP
842
+ </p>
843
+ <p>
844
+ This node only supports 2 BACnet object types, Analog Value - to show numeric data, and a Character String - to show
845
+ string data.
846
+ </p>
847
+ <ul class="node-ports">
848
+ <li>Enabled - toggles whether or not the local BACnet server is started or not.</li>
849
+ <li>
850
+ Clear Server Points - a schedule for the locally generated BACnet points to get cleared from the node object store
851
+ </li>
852
+ </ul>
853
+
854
+ <h3><strong>Examples</strong></h3>
855
+ <p>
856
+ For example flows, please use the examples section for this node. These examples can be found at: Node-red hamburger menu
857
+ on top right -> Import -> Examples -> @bitpoolos/edge-bacnet
858
+ </p>
859
+ <p>
860
+ To find captured examples of settings and flows, please go to our wiki
861
+ <a href="https://wiki.bitpool.com/en/edge/apps/bitpool-edge/nr-bacnet">here</a>
862
+ </p>
863
+
864
+ <h3>Resources:</h3>
865
+
866
+ <p><a href="https://youtu.be/4K7mVxfvfbc">Video Walk-through </a></p>
867
+
868
+ <h4><strong>Online Docs:</strong></h4>
869
+ <ul type="1">
870
+ <li><a href="https://www.bitpool.com/">bitpool.com</a> - check us out here.</li>
871
+ <li><a href="https://app.bitpool.com/">app.bitpool.com</a> - set up your account.</li>
872
+ <li><a href="https://wiki.bitpool.com/">wiki.bitpool.com</a> - find more documentation.</li>
873
+ <li><a href="https://bacnet.org/">BACnet</a> - find more about the protocol.</li>
874
+ </ul>
875
+ </script>