@bitpoolos/edge-bacnet 1.2.8 → 1.3.0

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/bacnet_device.js CHANGED
@@ -2,7 +2,7 @@ class BacnetDevice {
2
2
  constructor(fromImport, config) {
3
3
  let that = this;
4
4
 
5
- if(fromImport == true) {
5
+ if (fromImport == true) {
6
6
  that.address = config.address;
7
7
  that.isMstp = config.isMstp;
8
8
  that.deviceId = config.deviceId;
@@ -14,27 +14,30 @@ class BacnetDevice {
14
14
  that.pointsList = config.pointsList;
15
15
  that.pointListUpdateTs = config.pointListUpdateTs;
16
16
  that.manualDiscoveryMode = config.manualDiscoveryMode;
17
- that.mDiscoverInstanceRange = config.mDiscoverInstanceRange;
18
17
  that.pointListRetryCount = config.pointListRetryCount;
19
18
  that.priorityQueueIsActive = config.priorityQueueIsActive;
20
19
  that.priorityQueue = config.priorityQueue;
21
20
  that.lastPriorityQueueTS = config.lastPriorityQueueTS;
22
21
 
23
- if(config.childDevices) {
22
+ if (config.childDevices) {
24
23
  that.childDevices = config.childDevices;
25
24
  } else {
26
25
  that.childDevices = [];
27
26
  }
28
27
 
29
- if(config.parentDeviceId) {
28
+ if (config.parentDeviceId) {
30
29
  that.parentDeviceId = config.parentDeviceId;
31
30
  } else {
32
31
  that.parentDeviceId = null;
33
32
  }
34
33
 
35
- } else if(fromImport == false) {
36
- if(config.net && config.adr) {
37
- that.address = {address: config.address, net: config.net, adr: config.adr};
34
+ that.displayName = config.displayName;
35
+ that.protocolServicesSupported = config.protocolServicesSupported;
36
+ that.isProtocolServicesSet = config.isProtocolServicesSet;
37
+
38
+ } else if (fromImport == false) {
39
+ if (config.net && config.adr) {
40
+ that.address = { address: config.address, net: config.net, adr: config.adr };
38
41
  that.isMstp = true;
39
42
  } else {
40
43
  that.address = config.address;
@@ -49,16 +52,27 @@ class BacnetDevice {
49
52
  that.pointsList = [];
50
53
  that.pointListUpdateTs = null;
51
54
  that.manualDiscoveryMode = false;
52
- that.mDiscoverInstanceRange = {start: 0, end: 100};
53
55
  that.pointListRetryCount = 0;
54
56
  that.priorityQueueIsActive = false;
55
57
  that.priorityQueue = [];
56
58
  that.lastPriorityQueueTS = null;
57
59
  that.childDevices = [];
58
60
  that.parentDeviceId = null;
61
+ that.displayName = null;
62
+ that.protocolServicesSupported = [];
63
+ that.protocolServicesSupported = [];
64
+ that.isProtocolServicesSet = false;
59
65
  }
60
66
  }
61
67
 
68
+ setDisplayName(displayName) {
69
+ this.displayName = displayName;
70
+ }
71
+
72
+ getDisplayName() {
73
+ return this.displayName;
74
+ }
75
+
62
76
  setParentDeviceId(deviceId) {
63
77
  this.parentDeviceId = deviceId;
64
78
  }
@@ -68,9 +82,9 @@ class BacnetDevice {
68
82
  }
69
83
 
70
84
  hasChildDevices() {
71
- if(this.childDevices.length > 0) {
85
+ if (this.childDevices.length > 0) {
72
86
  return true;
73
- } else if(this.childDevices.length == 0) {
87
+ } else if (this.childDevices.length == 0) {
74
88
  return false;
75
89
  }
76
90
  }
@@ -78,7 +92,7 @@ class BacnetDevice {
78
92
  addChildDevice(deviceId) {
79
93
  let foundIndex = this.childDevices.findIndex(ele => ele == deviceId);
80
94
 
81
- if(foundIndex == -1) {
95
+ if (foundIndex == -1) {
82
96
  this.childDevices.push(deviceId);
83
97
  } else {
84
98
  this.childDevices[foundIndex] = deviceId
@@ -88,7 +102,7 @@ class BacnetDevice {
88
102
  getChildDevice(deviceId) {
89
103
  let foundIndex = this.childDevices.findIndex(ele => ele == deviceId);
90
104
 
91
- if(foundIndex !== -1) return this.childDevices[foundIndex];
105
+ if (foundIndex !== -1) return this.childDevices[foundIndex];
92
106
 
93
107
  return null;
94
108
  }
@@ -104,7 +118,7 @@ class BacnetDevice {
104
118
  getLastPriorityQueueTS() {
105
119
  return this.lastPriorityQueueTS;
106
120
  }
107
-
121
+
108
122
  setPriorityQueueIsActive(bool) {
109
123
  this.priorityQueueIsActive = bool;
110
124
  }
@@ -115,14 +129,14 @@ class BacnetDevice {
115
129
 
116
130
  updatePriorityQueue(point) {
117
131
  let foundIndex = this.priorityQueue.findIndex(ele => ele.value.type == point.value.type && ele.value.instance == point.value.instance);
118
- if(foundIndex == -1 ) {
132
+ if (foundIndex == -1) {
119
133
  //not found
120
134
  this.priorityQueue.push(point);
121
135
  }
122
136
 
123
- if(this.priorityQueue.length > 0) {
137
+ if (this.priorityQueue.length > 0) {
124
138
  this.setPriorityQueueIsActive(true);
125
- } else if(this.priorityQueue.length == 0) {
139
+ } else if (this.priorityQueue.length == 0) {
126
140
  this.setPriorityQueueIsActive(false);
127
141
  }
128
142
  }
@@ -130,20 +144,20 @@ class BacnetDevice {
130
144
  setPriorityQueue(points) {
131
145
  let queue = [];
132
146
  let keys = Object.keys(points);
133
- if(keys.length > 0) {
134
- keys.forEach(function(key) {
147
+ if (keys.length > 0) {
148
+ keys.forEach(function (key) {
135
149
  let point = points[key];
136
- let pointRequestObject = {type: 12, value: point.meta.objectId}
150
+ let pointRequestObject = { type: 12, value: point.meta.objectId }
137
151
  queue.push(pointRequestObject);
138
152
  });
139
153
  this.priorityQueue = queue;
140
154
  this.setPriorityQueueIsActive(true);
141
- } else if(keys.length == 0) {
155
+ } else if (keys.length == 0) {
142
156
  this.setPriorityQueueIsActive(false);
143
157
  }
144
158
  }
145
159
 
146
- getPriorityQueue(){
160
+ getPriorityQueue() {
147
161
  return this.priorityQueue;
148
162
  }
149
163
 
@@ -153,17 +167,17 @@ class BacnetDevice {
153
167
  }
154
168
 
155
169
  updateDeviceConfig(config) {
156
- if(config.address !== "" && config.address !== null && config.address !== "undefined") {
157
- if(config.net && config.adr) {
158
- this.address = {address: config.address, net: config.net, adr: config.adr};
170
+ if (config.address !== "" && config.address !== null && config.address !== "undefined") {
171
+ if (config.net && config.adr) {
172
+ this.address = { address: config.address, net: config.net, adr: config.adr };
159
173
  } else {
160
174
  this.address = config.address;
161
175
  }
162
176
  }
163
- if(Number.isInteger(config.deviceId)) this.deviceId = config.deviceId;
164
- if(Number.isInteger(config.maxApdu)) this.maxApdu = config.maxApdu;
165
- if(Number.isInteger(config.segmentation)) this.segmentation = config.segmentation;
166
- if(Number.isInteger(config.vendorId)) this.vendorId = config.vendorId;
177
+ if (Number.isInteger(config.deviceId)) this.deviceId = config.deviceId;
178
+ if (Number.isInteger(config.maxApdu)) this.maxApdu = config.maxApdu;
179
+ if (Number.isInteger(config.segmentation)) this.segmentation = config.segmentation;
180
+ if (Number.isInteger(config.vendorId)) this.vendorId = config.vendorId;
167
181
  }
168
182
 
169
183
  getPointListRetryCount() {
@@ -178,25 +192,6 @@ class BacnetDevice {
178
192
  this.pointListRetryCount = 0;
179
193
  }
180
194
 
181
- getmDiscoverInstanceRange() {
182
- return this.mDiscoverInstanceRange;
183
- }
184
-
185
- setmDiscoverInstanceRange(range) {
186
- this.mDiscoverInstanceRange = range;
187
- }
188
-
189
- updatemDiscoverInstanceRange(position, value) {
190
- this.mDiscoverInstanceRange[position] = value;
191
- }
192
-
193
- shouldBeInManualMode() {
194
- if(this.mDiscoverInstanceRange.start >= 1000000 || this.mDiscoverInstanceRange.end >= 1000000) {
195
- return false;
196
- }
197
- return true;
198
- }
199
-
200
195
  setManualDiscoveryMode(bool) {
201
196
  this.manualDiscoveryMode = bool;
202
197
  }
@@ -218,14 +213,29 @@ class BacnetDevice {
218
213
  }
219
214
 
220
215
  setPointsList(newPoints) {
221
- for(let index = 0; index < newPoints.length; index ++){
216
+ for (let index = 0; index < newPoints.length; index++) {
222
217
  let newPoint = newPoints[index];
223
- let foundIndex = this.pointsList.findIndex(ele => ele.value.type == newPoint.value.type && ele.value.instance == newPoint.value.instance);
224
- if(foundIndex == -1 ) {
225
- //not found
226
- this.pointsList.push(newPoint);
218
+ if (newPoint) {
219
+ let foundIndex = this.pointsList.findIndex(ele => ele.value.type == newPoint.value.type && ele.value.instance == newPoint.value.instance);
220
+ if (foundIndex == -1) {
221
+ //not found
222
+ this.pointsList.push(newPoint);
223
+ }
227
224
  }
228
225
  }
226
+
227
+ this.pointsList = this.pointsList.filter((point) =>
228
+ point.value.type == 8 || //DEVICE
229
+ point.value.type == 0 || //AI
230
+ point.value.type == 1 || //AV
231
+ point.value.type == 2 || //AO
232
+ point.value.type == 3 || //BI
233
+ point.value.type == 4 || //BV
234
+ point.value.type == 5 || //BO
235
+ point.value.type == 13 || //MSI
236
+ point.value.type == 14 || //MSO
237
+ point.value.type == 19 //MSV
238
+ );
229
239
  }
230
240
 
231
241
  getDevicePoints() {
@@ -236,7 +246,7 @@ class BacnetDevice {
236
246
  return this.address;
237
247
  }
238
248
 
239
- setAddress(address){
249
+ setAddress(address) {
240
250
  this.address = address;
241
251
  }
242
252
 
@@ -244,7 +254,7 @@ class BacnetDevice {
244
254
  return this.deviceId;
245
255
  }
246
256
 
247
- setDeviceId(deviceId){
257
+ setDeviceId(deviceId) {
248
258
  this.deviceId = deviceId;
249
259
  }
250
260
 
@@ -252,7 +262,7 @@ class BacnetDevice {
252
262
  return this.maxApdu;
253
263
  }
254
264
 
255
- setMaxApdu(maxApdu){
265
+ setMaxApdu(maxApdu) {
256
266
  this.maxApdu = maxApdu;
257
267
  }
258
268
 
@@ -260,7 +270,7 @@ class BacnetDevice {
260
270
  return this.segmentation;
261
271
  }
262
272
 
263
- setSegmentation(segmentation){
273
+ setSegmentation(segmentation) {
264
274
  this.segmentation = segmentation;
265
275
  }
266
276
 
@@ -268,7 +278,7 @@ class BacnetDevice {
268
278
  return this.vendorId;
269
279
  }
270
280
 
271
- setVendorId(vendorId){
281
+ setVendorId(vendorId) {
272
282
  this.vendorId = vendorId;
273
283
  }
274
284
 
@@ -276,7 +286,7 @@ class BacnetDevice {
276
286
  return this.lastSeen;
277
287
  }
278
288
 
279
- setLastSeen(lastSeen){
289
+ setLastSeen(lastSeen) {
280
290
  this.lastSeen = lastSeen;
281
291
  }
282
292
 
@@ -284,14 +294,66 @@ class BacnetDevice {
284
294
  return this.deviceName;
285
295
  }
286
296
 
287
- setDeviceName(deviceName){
297
+ setDeviceName(deviceName) {
288
298
  this.deviceName = deviceName;
299
+
300
+ if (this.getDisplayName() == null) {
301
+ this.setDisplayName(deviceName);
302
+ }
289
303
  }
290
304
 
291
- getIsMstpDevice(){
305
+ getIsMstpDevice() {
292
306
  return this.isMstp;
293
307
  }
294
308
 
309
+ getIsProtocolServicesSet() {
310
+ return this.isProtocolServicesSet;
311
+ }
312
+
313
+ setIsProtocolServicesSet(boolean) {
314
+ this.isProtocolServicesSet = boolean;
315
+ }
316
+
317
+ getProtocolServicesSupported() {
318
+ return this.protocolServicesSupported;
319
+ }
320
+
321
+ setProtocolServicesSupported(bitArray) {
322
+ let position = 0;
323
+ for (let i = 0; i < bitArray.length; i++) {
324
+ let bitString = bitArray[i];
325
+ for (let x = 0; x < bitString.length; x++) {
326
+ let bit = bitString[x];
327
+ this.protocolServicesSupported[position] = bit;
328
+ position++;
329
+ }
330
+ }
331
+ this.setIsProtocolServicesSet(true);
332
+ }
333
+
334
+ getProtocolServiceSupport(protocol) {
335
+ switch (protocol) {
336
+ case "ReadPropertyMultiple":
337
+ if (this.protocolServicesSupported[14] == '1') {
338
+ return true;
339
+ } else if (this.protocolServicesSupported[14] == '0') {
340
+ return false;
341
+ }
342
+ break;
343
+
344
+ default:
345
+ return false;
346
+ }
347
+ }
348
+
349
+ getMstpNetworkNumber() {
350
+ if (this.isMstp) {
351
+ return this.address.net;
352
+ } else {
353
+ return false;
354
+ }
355
+ }
356
+
295
357
  }
296
358
 
297
359
  module.exports = { BacnetDevice };
@@ -52,7 +52,7 @@
52
52
  // async load as in your code
53
53
  function LoadScriptsAsync(_scripts, scripts) {
54
54
  for (var i = 0; i < _scripts.length; i++) {
55
- loadScript(_scripts[i], scripts[i], function () {});
55
+ loadScript(_scripts[i], scripts[i], function () { });
56
56
  }
57
57
  }
58
58
 
@@ -84,7 +84,57 @@
84
84
  return fetch("/bitpool-bacnet-data/clearBacnetServerPoints").then((res) => res.json());
85
85
  }
86
86
  getBacnetServerPoints() {
87
- return fetch('/bitpool-bacnet-data/getBacnetServerPoints').then(res => res.json());
87
+ return fetch('/bitpool-bacnet-data/getBacnetServerPoints').then(res => res.json());
88
+ }
89
+ purgeDevice(device) {
90
+ return fetch('/bitpool-bacnet-data/purgeDevice', {
91
+ method: 'POST',
92
+ headers: {
93
+ 'Accept': 'application/json',
94
+ 'Content-Type': 'application/json'
95
+ },
96
+ body: JSON.stringify({ d: device })
97
+ }).then(res => res.json());
98
+ }
99
+ updatePointsForDevice(device) {
100
+ return fetch('/bitpool-bacnet-data/updatePointsForDevice', {
101
+ method: 'POST',
102
+ headers: {
103
+ 'Accept': 'application/json',
104
+ 'Content-Type': 'application/json'
105
+ },
106
+ body: JSON.stringify({ d: device })
107
+ }).then(res => res.json());
108
+ }
109
+ setDeviceDisplayName(device, displayName) {
110
+ return fetch('/bitpool-bacnet-data/setDeviceDisplayName', {
111
+ method: 'POST',
112
+ headers: {
113
+ 'Accept': 'application/json',
114
+ 'Content-Type': 'application/json'
115
+ },
116
+ body: JSON.stringify({ d: device, n: displayName })
117
+ }).then(res => res.json());
118
+ }
119
+ setPointDisplayName(deviceKey, pointName, pointDisplayName) {
120
+ return fetch('/bitpool-bacnet-data/setPointDisplayName', {
121
+ method: 'POST',
122
+ headers: {
123
+ 'Accept': 'application/json',
124
+ 'Content-Type': 'application/json'
125
+ },
126
+ body: JSON.stringify({ k: deviceKey, p: pointName, n: pointDisplayName })
127
+ }).then(res => res.json());
128
+ }
129
+ importReadList(payload) {
130
+ return fetch('/bitpool-bacnet-data/importReadList', {
131
+ method: 'POST',
132
+ headers: {
133
+ 'Accept': 'application/json',
134
+ 'Content-Type': 'application/json'
135
+ },
136
+ body: JSON.stringify({ p: payload })
137
+ }).then(res => res.json());
88
138
  }
89
139
  }
90
140
  RED.nodes.registerType("Bacnet-Gateway", {
@@ -101,23 +151,20 @@
101
151
  retries: { value: "5", required: true },
102
152
  broadCastAddr: { value: "255.255.255.255", required: true },
103
153
  toLogIam: { value: false },
104
- discover_polling_schedule: { value: "60" },
105
- discover_polling_schedule_value: { value: "1", required: true },
154
+ discover_polling_schedule: { value: "900" },
155
+ discover_polling_schedule_value: { value: "15", required: true },
106
156
  discover_polling_schedule_options: { value: "Minutes", required: true },
107
157
  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
158
  logErrorToConsole: { value: false },
112
159
  serverEnabled: { value: false },
113
- device_read_schedule: { value: "60" },
114
- device_read_schedule_value: { value: "1", required: true },
160
+ device_read_schedule: { value: "900" },
161
+ device_read_schedule_value: { value: "15", required: true },
115
162
  device_read_schedule_options: { value: "Minutes", required: true },
116
163
  deviceRangeRegisters: { value: [] },
117
- cacheFileEnabled: {value: false, required: true},
118
- sanitise_device_schedule: { value: "60" },
119
- sanitise_device_schedule_value: { value: "1", required: true },
120
- sanitise_device_schedule_options: { value: "Hours", required: true },
164
+ cacheFileEnabled: { value: false, required: true },
165
+ sanitise_device_schedule: { value: "60", required: false },
166
+ sanitise_device_schedule_value: { value: "1", required: false },
167
+ sanitise_device_schedule_options: { value: "Hours", required: false },
121
168
  },
122
169
  networkInterfaces: [],
123
170
  inputs: 1,
@@ -190,29 +237,9 @@
190
237
 
191
238
  queryAdapters();
192
239
 
193
- function setManualInstanceRangeState(state) {
194
- let deviceIdRangeStart = $("#node-input-manual_instance_range_start");
195
- let deviceIdRangeEnd = $("#node-input-manual_instance_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
- setManualInstanceRangeState(node.manual_instance_range_enabled);
206
-
207
- $("#node-input-manual_instance_range_enabled").change(function (e) {
208
- setManualInstanceRangeState(this.checked);
209
- });
210
-
211
240
  if (node.vm1 == undefined) {
212
241
  const confirmDialog = document.createElement("p-confirm-dialog");
213
242
  document.getElementById("serverParent").appendChild(confirmDialog);
214
- //document.getElementById("clearServerContainer").appendChild(confirmDialog);
215
-
216
243
  }
217
244
 
218
245
  const { createApp, ref, onMounted } = Vue;
@@ -230,7 +257,7 @@
230
257
  };
231
258
  },
232
259
  mounted() {
233
- this.getServerObjects();
260
+ this.getServerObjects();
234
261
  },
235
262
  methods: {
236
263
  confirmAll(event) {
@@ -242,7 +269,7 @@
242
269
  acceptClass: "p-button-danger",
243
270
  accept: () => {
244
271
  //handle accept
245
- this.nodeService.clearBacnetServerPoints().then(function() {
272
+ this.nodeService.clearBacnetServerPoints().then(function () {
246
273
  app.getServerObjects();
247
274
  });
248
275
  },
@@ -253,41 +280,41 @@
253
280
  },
254
281
  confirm(json) {
255
282
  this.$confirm.require({
256
- message: 'Do you want to clear this BACnet server point? This action is not reversible',
257
- header: 'Delete Confirmation',
258
- icon: 'pi pi-info-circle',
259
- acceptClass: 'p-button-danger',
260
- accept: () => {
261
- //handle accept
262
- let app = this;
263
- $.ajax({
264
- type: "POST",
265
- url: '/bitpool-bacnet-data/clearBacnetServerPoint',
266
- dataType: 'json',
267
- contentType: 'application/json',
268
- data: JSON.stringify(json),
269
- success: function (result) {
270
- app.getServerObjects();
271
- },
272
- timeout: 10000
273
- });
274
- },
275
- reject: () => {
276
- //handle reject
277
- }
283
+ message: 'Do you want to clear this BACnet server point? This action is not reversible',
284
+ header: 'Delete Confirmation',
285
+ icon: 'pi pi-info-circle',
286
+ acceptClass: 'p-button-danger',
287
+ accept: () => {
288
+ //handle accept
289
+ let app = this;
290
+ $.ajax({
291
+ type: "POST",
292
+ url: '/bitpool-bacnet-data/clearBacnetServerPoint',
293
+ dataType: 'json',
294
+ contentType: 'application/json',
295
+ data: JSON.stringify(json),
296
+ success: function (result) {
297
+ app.getServerObjects();
298
+ },
299
+ timeout: 10000
300
+ });
301
+ },
302
+ reject: () => {
303
+ //handle reject
304
+ }
278
305
  });
279
306
  },
280
307
  getServerObjects() {
281
308
  let app = this;
282
309
  this.nodeService.getBacnetServerPoints().then(function (result) {
283
- app.serverObjects = result;
310
+ app.serverObjects = result;
284
311
  })
285
312
  },
286
313
  formatObjectName(name) {
287
314
  //return shortened point name if longer than 50 characters
288
- if(name.length > 45) {
315
+ if (name.length > 45) {
289
316
  return name.slice(0, 45).concat("...");
290
- }
317
+ }
291
318
  return name;
292
319
  }
293
320
  },
@@ -319,7 +346,7 @@
319
346
  dataType: "json",
320
347
  contentType: "application/json",
321
348
  data: JSON.stringify(jsonPayload),
322
- success: function (result) {},
349
+ success: function (result) { },
323
350
  timeout: 10000,
324
351
  });
325
352
  };
@@ -674,7 +701,7 @@
674
701
  </select>
675
702
  </div>
676
703
 
677
- <div class="form-row">
704
+ <div class="form-row" style="display: none;">
678
705
  <label for="node-input-retries"
679
706
  ><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.retries"></span>Number of Retries</label
680
707
  >
@@ -713,17 +740,6 @@
713
740
  </select>
714
741
  </div>
715
742
 
716
- <div class="form-row deviceIdRange">
717
- <label for="node-input-device_id_range"
718
- ><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.device_id_range"></span>Point Discovery Range
719
- </label>
720
- <input type="checkbox" id="node-input-manual_instance_range_enabled" style="width: auto;" />
721
- <a style="padding-left: 60px;">Start: </a
722
- ><input type="number" id="node-input-manual_instance_range_start" style="width: 125px;" min="0" max="100000" />
723
- <a style="padding-left: 35px;">End: </a
724
- ><input type="number" id="node-input-manual_instance_range_end" style="width: 125px;" min="1" max="100000" />
725
- </div>
726
-
727
743
  <div class="form-row" style="align-items: center; display: flex;">
728
744
  <label for="node-input-device_read_schedule_value"
729
745
  ><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.device_read_schedule"></span>Object Discover
@@ -744,7 +760,7 @@
744
760
  </select>
745
761
  </div>
746
762
 
747
- <div class="form-row" style="align-items: center; display: flex;">
763
+ <div class="form-row" style="align-items: center; display: none;">
748
764
  <label for="node-input-sanitise_device_schedule_value"
749
765
  ><i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.sanitise_device_schedule"></span>Device Sanitisation
750
766
  Frequency</label
@@ -900,4 +916,4 @@
900
916
  <li><a href="https://wiki.bitpool.com/">wiki.bitpool.com</a> - find more documentation.</li>
901
917
  <li><a href="https://bacnet.org/">BACnet</a> - find more about the protocol.</li>
902
918
  </ul>
903
- </script>
919
+ </script>