@bitpoolos/edge-bacnet 1.6.0 → 1.6.2

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.
@@ -0,0 +1,368 @@
1
+ [
2
+ {
3
+ "id": "1617c14c07ac6e16",
4
+ "type": "Bacnet-Gateway",
5
+ "z": "f1fc21f44027188c",
6
+ "name": "",
7
+ "local_device_address": "",
8
+ "local_interface_name": "",
9
+ "apduTimeout": 6000,
10
+ "roundDecimal": 2,
11
+ "local_device_port": 47808,
12
+ "apduSize": "5",
13
+ "maxSegments": "0x50",
14
+ "retries": "5",
15
+ "broadCastAddr": "255.255.255.255",
16
+ "toLogIam": false,
17
+ "discover_polling_schedule": "900",
18
+ "discover_polling_schedule_value": "15",
19
+ "discover_polling_schedule_options": "Minutes",
20
+ "deviceId": 817001,
21
+ "logErrorToConsole": false,
22
+ "serverEnabled": true,
23
+ "device_read_schedule": "900",
24
+ "device_read_schedule_value": "15",
25
+ "device_read_schedule_options": "Minutes",
26
+ "deviceRangeRegisters": [
27
+ {
28
+ "enabled": true,
29
+ "start": "0",
30
+ "end": "4194303"
31
+ }
32
+ ],
33
+ "portRangeRegisters": [
34
+ {
35
+ "enabled": true,
36
+ "start": "47808",
37
+ "end": "47808"
38
+ }
39
+ ],
40
+ "cacheFileEnabled": true,
41
+ "sanitise_device_schedule": "3600",
42
+ "sanitise_device_schedule_value": "1",
43
+ "sanitise_device_schedule_options": "Hours",
44
+ "x": 840,
45
+ "y": 440,
46
+ "wires": [
47
+ [
48
+ "8db122ce13172090",
49
+ "df826da5f464306c"
50
+ ]
51
+ ]
52
+ },
53
+ {
54
+ "id": "3dbfbb72574a201c",
55
+ "type": "Bacnet-Discovery",
56
+ "z": "f1fc21f44027188c",
57
+ "name": "",
58
+ "events": true,
59
+ "json": true,
60
+ "mqtt": false,
61
+ "pointJson": false,
62
+ "hiddenDeployToggle": false,
63
+ "prevHiddenToggleState": false,
64
+ "roundDecimal": 2,
65
+ "pointsToRead": {},
66
+ "readDevices": [],
67
+ "object_property_simplePayload": false,
68
+ "object_property_simpleWithStatus": false,
69
+ "object_property_fullObject": true,
70
+ "useDeviceName": true,
71
+ "x": 670,
72
+ "y": 360,
73
+ "wires": [
74
+ [
75
+ "1617c14c07ac6e16",
76
+ "df826da5f464306c"
77
+ ]
78
+ ]
79
+ },
80
+ {
81
+ "id": "ae5c90c50e252352",
82
+ "type": "Bacnet-Write",
83
+ "z": "f1fc21f44027188c",
84
+ "name": "",
85
+ "applicationTag": "4",
86
+ "priority": "16",
87
+ "pointsToWrite": [],
88
+ "writeDevices": [],
89
+ "hiddenDeployToggle": false,
90
+ "prevHiddenToggleState": false,
91
+ "x": 670,
92
+ "y": 520,
93
+ "wires": [
94
+ [
95
+ "1617c14c07ac6e16"
96
+ ]
97
+ ]
98
+ },
99
+ {
100
+ "id": "e4837a22dc540343",
101
+ "type": "Bitpool-Inject",
102
+ "z": "f1fc21f44027188c",
103
+ "name": "Discover",
104
+ "props": [
105
+ {
106
+ "p": "payload"
107
+ },
108
+ {
109
+ "p": "topic",
110
+ "vt": "str"
111
+ }
112
+ ],
113
+ "repeat": "",
114
+ "crontab": "",
115
+ "once": false,
116
+ "onceDelay": 0.1,
117
+ "topic": "",
118
+ "payload": "",
119
+ "payloadType": "date",
120
+ "doPoll": false,
121
+ "doDiscover": true,
122
+ "json": false,
123
+ "mqtt": false,
124
+ "pointJson": true,
125
+ "object_property_simplePayload": false,
126
+ "object_property_simpleWithStatus": false,
127
+ "object_property_fullObject": true,
128
+ "useDeviceName": true,
129
+ "x": 660,
130
+ "y": 440,
131
+ "wires": [
132
+ [
133
+ "1617c14c07ac6e16"
134
+ ]
135
+ ]
136
+ },
137
+ {
138
+ "id": "67bd88188ddd1166",
139
+ "type": "Bitpool-Inject",
140
+ "z": "f1fc21f44027188c",
141
+ "name": "Poll",
142
+ "props": [
143
+ {
144
+ "p": "payload"
145
+ },
146
+ {
147
+ "p": "topic",
148
+ "vt": "str"
149
+ }
150
+ ],
151
+ "repeat": "",
152
+ "crontab": "",
153
+ "once": false,
154
+ "onceDelay": 0.1,
155
+ "topic": "",
156
+ "payload": "",
157
+ "payloadType": "date",
158
+ "doPoll": true,
159
+ "doDiscover": false,
160
+ "json": false,
161
+ "mqtt": false,
162
+ "pointJson": true,
163
+ "object_property_simplePayload": false,
164
+ "object_property_simpleWithStatus": false,
165
+ "object_property_fullObject": true,
166
+ "useDeviceName": true,
167
+ "x": 490,
168
+ "y": 520,
169
+ "wires": [
170
+ [
171
+ "ae5c90c50e252352"
172
+ ]
173
+ ]
174
+ },
175
+ {
176
+ "id": "6d1719920e0c3838",
177
+ "type": "Bitpool-Inject",
178
+ "z": "f1fc21f44027188c",
179
+ "name": "Poll",
180
+ "props": [
181
+ {
182
+ "p": "payload"
183
+ },
184
+ {
185
+ "p": "topic",
186
+ "vt": "str"
187
+ }
188
+ ],
189
+ "repeat": "",
190
+ "crontab": "",
191
+ "once": false,
192
+ "onceDelay": 0.1,
193
+ "topic": "",
194
+ "payload": "",
195
+ "payloadType": "date",
196
+ "doPoll": true,
197
+ "doDiscover": false,
198
+ "json": false,
199
+ "mqtt": false,
200
+ "pointJson": true,
201
+ "object_property_simplePayload": false,
202
+ "object_property_simpleWithStatus": false,
203
+ "object_property_fullObject": true,
204
+ "useDeviceName": true,
205
+ "x": 490,
206
+ "y": 360,
207
+ "wires": [
208
+ [
209
+ "3dbfbb72574a201c"
210
+ ]
211
+ ]
212
+ },
213
+ {
214
+ "id": "8db122ce13172090",
215
+ "type": "debug",
216
+ "z": "f1fc21f44027188c",
217
+ "name": "debug 1",
218
+ "active": true,
219
+ "tosidebar": true,
220
+ "console": false,
221
+ "tostatus": false,
222
+ "complete": "true",
223
+ "targetType": "full",
224
+ "statusVal": "",
225
+ "statusType": "auto",
226
+ "x": 1040,
227
+ "y": 440,
228
+ "wires": []
229
+ },
230
+ {
231
+ "id": "df826da5f464306c",
232
+ "type": "Bacnet-Inspector",
233
+ "z": "f1fc21f44027188c",
234
+ "name": "",
235
+ "siteName": "INSPECTOR_SITE_NAME",
236
+ "totalUniqueReadCount": 0,
237
+ "x": 1070,
238
+ "y": 360,
239
+ "wires": [
240
+ [
241
+ "6eeed73a4976730b"
242
+ ]
243
+ ]
244
+ },
245
+ {
246
+ "id": "6eeed73a4976730b",
247
+ "type": "debug",
248
+ "z": "f1fc21f44027188c",
249
+ "name": "debug 2",
250
+ "active": true,
251
+ "tosidebar": true,
252
+ "console": false,
253
+ "tostatus": false,
254
+ "complete": "true",
255
+ "targetType": "full",
256
+ "statusVal": "",
257
+ "statusType": "auto",
258
+ "x": 1300,
259
+ "y": 360,
260
+ "wires": []
261
+ },
262
+ {
263
+ "id": "70b41e715ed44733",
264
+ "type": "Bitpool-Inject",
265
+ "z": "f1fc21f44027188c",
266
+ "name": "sendMqttStats",
267
+ "props": [
268
+ {
269
+ "p": "type",
270
+ "v": "sendMqttStats",
271
+ "vt": "str"
272
+ }
273
+ ],
274
+ "repeat": "",
275
+ "crontab": "",
276
+ "once": false,
277
+ "onceDelay": 0.1,
278
+ "topic": "",
279
+ "doPoll": true,
280
+ "doDiscover": false,
281
+ "json": false,
282
+ "mqtt": false,
283
+ "pointJson": true,
284
+ "object_property_simplePayload": false,
285
+ "object_property_simpleWithStatus": false,
286
+ "object_property_fullObject": true,
287
+ "useDeviceName": true,
288
+ "x": 870,
289
+ "y": 240,
290
+ "wires": [
291
+ [
292
+ "df826da5f464306c"
293
+ ]
294
+ ]
295
+ },
296
+ {
297
+ "id": "031ec232c48e17de",
298
+ "type": "Bitpool-Inject",
299
+ "z": "f1fc21f44027188c",
300
+ "name": "getBacnetStats",
301
+ "props": [
302
+ {
303
+ "p": "type",
304
+ "v": "getBacnetStats",
305
+ "vt": "str"
306
+ }
307
+ ],
308
+ "repeat": "",
309
+ "crontab": "",
310
+ "once": false,
311
+ "onceDelay": 0.1,
312
+ "topic": "",
313
+ "doPoll": true,
314
+ "doDiscover": false,
315
+ "json": false,
316
+ "mqtt": false,
317
+ "pointJson": true,
318
+ "object_property_simplePayload": false,
319
+ "object_property_simpleWithStatus": false,
320
+ "object_property_fullObject": true,
321
+ "useDeviceName": true,
322
+ "x": 860,
323
+ "y": 300,
324
+ "wires": [
325
+ [
326
+ "df826da5f464306c"
327
+ ]
328
+ ]
329
+ },
330
+ {
331
+ "id": "74e1dd56bce21e2f",
332
+ "type": "Bitpool-Inject",
333
+ "z": "f1fc21f44027188c",
334
+ "name": "reset",
335
+ "props": [
336
+ {
337
+ "p": "reset",
338
+ "v": "true",
339
+ "vt": "bool"
340
+ },
341
+ {
342
+ "p": "topic",
343
+ "vt": "str"
344
+ }
345
+ ],
346
+ "repeat": "",
347
+ "crontab": "",
348
+ "once": false,
349
+ "onceDelay": 0.1,
350
+ "topic": "",
351
+ "doPoll": true,
352
+ "doDiscover": false,
353
+ "json": false,
354
+ "mqtt": false,
355
+ "pointJson": true,
356
+ "object_property_simplePayload": false,
357
+ "object_property_simpleWithStatus": false,
358
+ "object_property_fullObject": true,
359
+ "useDeviceName": true,
360
+ "x": 890,
361
+ "y": 180,
362
+ "wires": [
363
+ [
364
+ "df826da5f464306c"
365
+ ]
366
+ ]
367
+ }
368
+ ]
package/inspector.html CHANGED
@@ -35,8 +35,8 @@
35
35
  </span>
36
36
  <div class="status-text">
37
37
  <span class="statBlockValue">
38
- {{statCounts?.readCount}}
39
- <span class="stat-percentage">{{statPercentages.readCount}}%</span>
38
+ {{statCounts?.statBlock.ok}}
39
+ <span class="stat-percentage">{{statPercentages.ok}}%</span>
40
40
  </span>
41
41
  <span class="statBlockKey">Points OK</span>
42
42
  </div>
@@ -133,9 +133,9 @@
133
133
  <div class="center">
134
134
  <p class="headertext">{{siteName}} - Point Status Display</p>
135
135
  </div>
136
- <p-datatable :value="displayData" paginator :rows="12" filterDisplay="menu" :filters="filters"
137
- v-model:filters="filters" :sortMode="'multiple'" @filter="onFilter" scrollable scrollHeight="800px"
138
- class="datatable fixed-height-table">
136
+ <p-datatable :value="displayData" paginator scrollable scrollHeight="800px" :rows="12" filterDisplay="menu"
137
+ :filters="filters" v-model:filters="filters" :sortMode="'multiple'" @filter="onFilter"
138
+ class="datatable fixed-height-table" :loading="loading">
139
139
  <template #header>
140
140
  <div class="tableHeaderDiv">
141
141
  <div style="margin-right: 5px">
@@ -177,6 +177,14 @@
177
177
  </div>
178
178
  </div>
179
179
  </template>
180
+ <template #loading>
181
+ <div class="loading-overlay">
182
+ <div class="loading-spinner">
183
+ <i class="pi pi-spin pi-spinner" style="font-size: 2rem"></i>
184
+ <p>Loading data...</p>
185
+ </div>
186
+ </div>
187
+ </template>
180
188
  <p-column v-for="col in visibleColumns" :key="col.field" :field="col.field" :header="col.header" sortable
181
189
  filter></p-column>
182
190
  <template #paginatorstart>
@@ -188,6 +196,7 @@
188
196
  </span>
189
197
  </template>
190
198
  </p-datatable>
199
+
191
200
  </div>
192
201
  </div>
193
202
  </div>
@@ -199,7 +208,7 @@
199
208
  data() {
200
209
  return {
201
210
  tableData: null,
202
- loading: false,
211
+ loading: true,
203
212
  totalRecords: 0,
204
213
  first: 0,
205
214
  lazyParams: {},
@@ -244,6 +253,7 @@
244
253
  selectedColumns: [],
245
254
  statPercentages: {
246
255
  readCount: 0,
256
+ ok: 0,
247
257
  error: 0,
248
258
  missing: 0,
249
259
  warnings: 0,
@@ -262,6 +272,7 @@
262
272
  this.observeHeaderHeight();
263
273
 
264
274
  this.selectedColumns = JSON.parse(JSON.stringify(this.allColumns));
275
+ this.loading = true;
265
276
 
266
277
  fetch("/getModelStats")
267
278
  .then((response) => {
@@ -287,18 +298,22 @@
287
298
  // Calculate percentages
288
299
  const total = tableData.length || 1; // Avoid division by zero
289
300
  app.statPercentages = {
290
- readCount: Math.round((data.statCounts.readCount / total) * 100),
291
- error: Math.round((data.statCounts.statBlock.error / total) * 100),
292
- missing: Math.round((data.statCounts.statBlock.missing / total) * 100),
293
- warnings: Math.round((data.statCounts.statBlock.warnings / total) * 100),
294
- deviceIdChange: Math.round((data.statCounts.statBlock.deviceIdChange / total) * 100),
295
- deviceIdConflict: Math.round((data.statCounts.statBlock.deviceIdConflict / total) * 100),
296
- unmapped: Math.round((data.statCounts.statBlock.unmapped / total) * 100)
301
+ readCount: Math.round((data.statCounts.readCount / total) * 10000) / 100,
302
+ ok: Math.round((data.statCounts.statBlock.ok / total) * 10000) / 100,
303
+ error: Math.round((data.statCounts.statBlock.error / total) * 10000) / 100,
304
+ missing: Math.round((data.statCounts.statBlock.missing / total) * 10000) / 100,
305
+ warnings: Math.round((data.statCounts.statBlock.warnings / total) * 10000) / 100,
306
+ deviceIdChange: Math.round((data.statCounts.statBlock.deviceIdChange / total) * 10000) / 100,
307
+ deviceIdConflict: Math.round((data.statCounts.statBlock.deviceIdConflict / total) * 10000) / 100,
308
+ unmapped: Math.round((data.statCounts.statBlock.unmapped / total) * 10000) / 100
297
309
  };
298
310
  })
299
311
  .catch((error) => {
300
312
  // Handle any errors
301
313
  console.error("Error:", error);
314
+ })
315
+ .finally(() => {
316
+ app.loading = false;
302
317
  });
303
318
  },
304
319
  computed: {
@@ -401,14 +416,6 @@
401
416
  if (!this.selectedColumns) return false;
402
417
  return this.selectedColumns.some((item) => item.field === option.field);
403
418
  },
404
- getRowClass(rowData) {
405
- console.log("rowData", rowData);
406
- if (rowData.dataModelStatus.includes("Point OK")) return "row-ok";
407
- if (rowData.dataModelStatus.includes("Point Error")) return "row-error";
408
- if (rowData.dataModelStatus.includes("Point Warning")) return "row-warning";
409
- if (rowData.dataModelStatus.includes("Point Missing")) return "row-missing";
410
- return ""; // Default, no class
411
- },
412
419
  downloadCSV() {
413
420
  window.location.href = "/getmodelstatscsv";
414
421
  },
@@ -423,6 +430,7 @@
423
430
  filters: this.filters,
424
431
  selectedColumns: this.selectedColumns,
425
432
  allColumns: this.allColumns,
433
+ statPercentages: this.statPercentages // Include the calculated percentages
426
434
  };
427
435
  downloadPrimeVueAppAsHtml(filename, data);
428
436
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitpoolos/edge-bacnet",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "A bacnet gateway for node-red",
5
5
  "dependencies": {
6
6
  "@plus4nodered/ts-node-bacnet": "^1.0.0-beta.2",
@@ -125,6 +125,7 @@ async function processPrimeVueHtml(appData) {
125
125
  selectedColumnValues: CAPTURED_APP_DATA.selectedColumnValues || [],
126
126
  statPercentages: CAPTURED_APP_DATA.statPercentages || {
127
127
  readCount: 0,
128
+ ok: 0,
128
129
  error: 0,
129
130
  missing: 0,
130
131
  warnings: 0,
@@ -145,13 +146,14 @@ async function processPrimeVueHtml(appData) {
145
146
  // Calculate percentages
146
147
  const total = this.tableData.length || 1; // Avoid division by zero
147
148
  this.statPercentages = {
148
- readCount: Math.round((this.statCounts.readCount / total) * 100),
149
- error: Math.round((this.statCounts.statBlock.error / total) * 100),
150
- missing: Math.round((this.statCounts.statBlock.missing / total) * 100),
151
- warnings: Math.round((this.statCounts.statBlock.warnings / total) * 100),
152
- deviceIdChange: Math.round((this.statCounts.statBlock.deviceIdChange / total) * 100),
153
- deviceIdConflict: Math.round((this.statCounts.statBlock.deviceIdConflict / total) * 100 || 0),
154
- unmapped: Math.round((this.statCounts.statBlock.unmapped / total) * 100)
149
+ readCount: Math.round((this.statCounts.readCount / total) * 10000) / 100,
150
+ ok: Math.round((this.statCounts.statBlock.ok / total) * 10000) / 100,
151
+ error: Math.round((this.statCounts.statBlock.error / total) * 10000) / 100,
152
+ missing: Math.round((this.statCounts.statBlock.missing / total) * 10000) / 100,
153
+ warnings: Math.round((this.statCounts.statBlock.warnings / total) * 10000) / 100,
154
+ deviceIdChange: Math.round((this.statCounts.statBlock.deviceIdChange / total) * 10000) / 100,
155
+ deviceIdConflict: Math.round((this.statCounts.statBlock.deviceIdConflict / total) * 10000) / 100,
156
+ unmapped: Math.round((this.statCounts.statBlock.unmapped / total) * 10000) / 100
155
157
  };
156
158
  },
157
159
  computed: {
@@ -285,8 +287,8 @@ async function processPrimeVueHtml(appData) {
285
287
  </span>
286
288
  <div class="status-text">
287
289
  <span class="statBlockValue">
288
- {{statCounts?.readCount}}
289
- <span class="stat-percentage">{{statPercentages.readCount}}%</span>
290
+ {{statCounts?.statBlock.ok}}
291
+ <span class="stat-percentage">{{statPercentages.ok}}%</span>
290
292
  </span>
291
293
  <span class="statBlockKey">Points OK</span>
292
294
  </div>
@@ -183,32 +183,15 @@ body {
183
183
  }
184
184
 
185
185
 
186
- /* changes start */
187
-
188
- /* Add these rules to forcefully control table height */
189
- .fixed-height-table {
190
- height: 800px !important; /* Fixed height matching scrollHeight */
191
- }
192
-
193
- .fixed-height-table .p-datatable-wrapper {
194
- height: calc(800px - 92px) !important; /* Subtract header and paginator height */
195
- min-height: calc(800px - 92px) !important;
196
- }
197
-
198
186
  .fixed-height-table .p-datatable-table {
199
- min-height: 800px !important; /* Force table to maintain minimum height */
187
+ height: 70vh !important;
200
188
  }
201
189
 
202
- /* Make sure the table body expands to fill available space */
203
- .fixed-height-table .p-datatable-tbody {
204
- min-height: 760px !important; /* Approximate calculation for body only */
205
- }
206
-
207
- /* Add an empty row to maintain height when filtered results are few */
208
190
  .p-datatable-emptymessage td {
209
191
  height: 760px !important;
210
192
  }
211
193
 
194
+
212
195
  .row-missing {
213
196
  background-color: #00adef;
214
197
  }
@@ -234,7 +217,7 @@ body {
234
217
  width: -webkit-fill-available;
235
218
  margin: 5px;
236
219
  left: 0px;
237
- height: 1000px !important;
220
+ /* height: 1000px !important; */
238
221
  }
239
222
 
240
223
  .datatable-card {
@@ -242,7 +225,7 @@ body {
242
225
  padding-bottom: 1rem !important;
243
226
  padding-left: 2rem;
244
227
  padding-right: 2rem;
245
- height: 1000px !important;
228
+ /* height: 1000px !important; */
246
229
  }
247
230
 
248
231
  .p-multiselect-overlay {
@@ -475,4 +458,58 @@ body {
475
458
  box-sizing: border-box;
476
459
  max-height: 80vh;
477
460
  overflow-y: auto;
461
+ }
462
+
463
+ .p-datatable-scrollable-body {
464
+ min-height: 576px !important;
465
+ }
466
+
467
+ /* Set consistent row heights */
468
+ .p-datatable .p-datatable-tbody>tr {
469
+ height: 48px !important;
470
+ min-height: 48px !important;
471
+ max-height: 48px !important;
472
+ }
473
+
474
+ /* Make sure content in cells doesn't expand the row */
475
+ .p-datatable .p-datatable-tbody>tr>td {
476
+ height: 48px !important;
477
+ padding: 0.5rem 1rem;
478
+ white-space: nowrap;
479
+ overflow: hidden;
480
+ text-overflow: ellipsis;
481
+ }
482
+
483
+ /* Ensure table takes minimum space when empty */
484
+ .p-datatable-empty-message {
485
+ height: 576px !important;
486
+ }
487
+ .loading-overlay {
488
+ position: absolute;
489
+ top: 0;
490
+ left: 0;
491
+ width: 100%;
492
+ height: 100%;
493
+ display: flex;
494
+ justify-content: center;
495
+ align-items: center;
496
+ background-color: rgba(255, 255, 255, 0.7);
497
+ z-index: 1000;
498
+ }
499
+
500
+ .loading-spinner {
501
+ display: flex;
502
+ flex-direction: column;
503
+ align-items: center;
504
+ gap: 1rem;
505
+ }
506
+
507
+ .loading-spinner p {
508
+ margin: 0;
509
+ color: #495057;
510
+ font-weight: 500;
511
+ }
512
+
513
+ .p-datatable .p-datatable-loading-overlay {
514
+ position: relative;
478
515
  }
@@ -52,8 +52,8 @@ async function generatePrimeVueAppHtmlStatic(appData, filename = "bacnet-inspect
52
52
  </span>
53
53
  <div class="status-text">
54
54
  <span class="statBlockValue">
55
- {{statCounts?.readCount}}
56
- <span class="stat-percentage">{{statPercentages.readCount}}%</span>
55
+ {{statCounts?.statBlock.ok}}
56
+ <span class="stat-percentage">{{statPercentages.ok}}%</span>
57
57
  </span>
58
58
  <span class="statBlockKey">Points OK</span>
59
59
  </div>
@@ -258,6 +258,7 @@ async function generatePrimeVueAppHtmlStatic(appData, filename = "bacnet-inspect
258
258
  selectedColumns: [],
259
259
  statPercentages: {
260
260
  readCount: 0,
261
+ ok: 0,
261
262
  error: 0,
262
263
  missing: 0,
263
264
  warnings: 0,
@@ -277,13 +278,14 @@ async function generatePrimeVueAppHtmlStatic(appData, filename = "bacnet-inspect
277
278
  // Calculate percentages
278
279
  const total = this.tableData.length || 1; // Avoid division by zero
279
280
  this.statPercentages = {
280
- readCount: Math.round((this.statCounts.readCount / total) * 100) || 0,
281
- error: Math.round((this.statCounts.statBlock?.error / total) * 100) || 0,
282
- missing: Math.round((this.statCounts.statBlock?.missing / total) * 100) || 0,
283
- warnings: Math.round((this.statCounts.statBlock?.warnings / total) * 100) || 0,
284
- deviceIdChange: Math.round((this.statCounts.statBlock?.deviceIdChange / total) * 100) || 0,
285
- deviceIdConflict: Math.round((this.statCounts.statBlock?.deviceIdConflict / total) * 100) || 0,
286
- unmapped: Math.round((this.statCounts.statBlock?.unmapped / total) * 100) || 0
281
+ readCount: Math.round((this.statCounts.readCount / total) * 10000) / 100 || 0,
282
+ ok: Math.round((this.statCounts.statBlock.ok / total) * 10000) / 100 || 0,
283
+ error: Math.round((this.statCounts.statBlock.error / total) * 10000) / 100 || 0,
284
+ missing: Math.round((this.statCounts.statBlock.missing / total) * 10000) / 100 || 0,
285
+ warnings: Math.round((this.statCounts.statBlock.warnings / total) * 10000) / 100 || 0,
286
+ deviceIdChange: Math.round((this.statCounts.statBlock.deviceIdChange / total) * 10000) / 100 || 0,
287
+ deviceIdConflict: Math.round((this.statCounts.statBlock.deviceIdConflict / total) * 10000) / 100 || 0,
288
+ unmapped: Math.round((this.statCounts.statBlock.unmapped / total) * 10000) / 100 || 0
287
289
  };
288
290
  },
289
291
  computed: {