Changes for page Demo for Smart Office, Factory
Last modified by Hera Guo on 2024/11/11 17:08
Summary
-
Page properties (1 modified, 0 added, 0 removed)
-
Attachments (0 modified, 51 added, 0 removed)
- 1730709382428-730.png
- 1730709409941-536.png
- 1730709424998-915.png
- 1730709442773-502.png
- 1730709461297-207.png
- 1730709479828-595.png
- 1730709511861-439.png
- 1730709527720-418.png
- 1730709542597-321.png
- 1730709555797-383.png
- 1730710271230-716.png
- 1730710395303-672.png
- 1730710693066-349.png
- 1730710850458-781.png
- 1730710875401-848.png
- 1730710949358-671.png
- 1730710990334-601.png
- 1730712335338-750.png
- 1730712473941-913.png
- 1730712539209-554.png
- 1730770392454-317.png
- 1730770636230-829.png
- 1730770875793-351.png
- 1730771103096-522.png
- 1730771199343-553.png
- 1730771228766-212.png
- 1730771256045-238.png
- 1730771318657-502.png
- 1730771386258-676.png
- 1730771441589-122.png
- 1730771504586-433.png
- 1730857191863-514.png
- 1730857537965-184.png
- 1730857750749-240.png
- 1730862483514-101.png
- 1730862584519-902.png
- 1730863708259-750.png
- 1730863750414-979.png
- 1730864045747-876.png
- 1730864077395-395.png
- 1730864117808-484.png
- 1730864159071-895.png
- 1730864207037-477.png
- 1730864250506-111.png
- 1730864293216-991.png
- 1730864331859-740.png
- 1730864460314-611.png
- 1730864617480-221.png
- 1730864676542-406.png
- 1730864784118-474.png
- 1730865053380-293.png
Details
- Page properties
-
- Content
-
... ... @@ -57,7 +57,7 @@ 57 57 58 58 **device:**This section displays the specific information collected by the device, and different types of sensors have different display interfaces 59 59 60 -[[image: 1730699212334-960.png]]60 +[[image:屏幕截图 2024-11-04 134645.png]] 61 61 62 62 First floor: 63 63 ... ... @@ -82,8 +82,9 @@ 82 82 83 83 High Temperature、Low Temperature、High humidity、Low humidity、Low voltage、Device Disconnected 84 84 85 -[[image:1730 699566023-958.png]]85 +[[image:1730854677036-426.png]] 86 86 87 + 87 87 = 4.configuration details = 88 88 89 89 After understanding the architecture and layering of the complete project, we can start configuring it ... ... @@ -90,17 +90,985 @@ 90 90 91 91 == 4.1 Dashboard configuration details == 92 92 93 -1 、Configurethe interface of the third layerDavies.94 +=== 4.1.1.Data source (Entity aliases) === 94 94 96 +detail:Obtain data based on dashboard status 95 95 96 - 2、Configurethenterfaceof the secondlayer asset98 +[[image:1730709424998-915.png||height="729" width="1436"]] 97 97 100 +Alarm:Obtain alarm information 98 98 99 - 3、Configurethefirstlayer menuinterface102 +[[image:1730709479828-595.png||height="696" width="1435"]] 100 100 104 +Dragino&GXHL,Ltd:Obtain data through asset types 101 101 106 +[[image:1730709511861-439.png||height="714" width="1435"]] 107 + 108 +Selected Supermarket:Retrieve devices by device type 109 + 110 +[[image:1730709527720-418.png||height="751" width="1433"]] 111 + 112 +Supermarket Devices:Obtain data through device type 113 + 114 +[[image:1730709555797-383.png||height="726" width="1434"]] 115 + 116 +LHT65N Device:Obtain data based on device type 117 + 118 +[[image:1730857191863-514.png||height="725" width="1433"]] 119 + 120 +=== 4.1.2.Page Configuration === 121 + 122 +==== 4.1.2.1、Configure the interface of the third layer Davies. ==== 123 + 124 +==== 4.1.2.2、Configure the interface of the second layer asset ==== 125 + 126 +===== 4.1.2.2.1 Equipment distribution diagram: ===== 127 + 128 +**Data:** 129 + 130 +[[image:1730770392454-317.png||height="745" width="1439"]] 131 + 132 +**Appearannce:**In this module, we need to arrange our devices in the corresponding positions and use icons to display our devices. Therefore, in the Appearance interface, we need to configure them 133 + 134 +**Tooltip function:**This module displays the current information of the device 135 + 136 +[[image:1730857537965-184.png]] 137 + 138 +{{code language="none"}} 139 +var msg = data 140 +if(msg.Label=="gateway" && msg.type == "gateway"){ 141 + var stauts 142 + if (msg.gatewaystauts=="true"){ 143 + stauts = "Connect" 144 + } 145 + else{ 146 + stauts = "Disconnected" 147 + } 148 + var str = "<b>"+msg.entityName+"</b><br/><b>"+stauts+"</b><br/>" 149 + return str 150 +} 151 +else if(msg.type=="gxhl01" && msg.Label!="gateway"){ 152 + var str = "<b>"+msg.entityName+"</b><br/><b>"+msg.Label+"</b><br/><b>Bat:</b>"+msg.BatV+"V<br/><b>Temperature:</b>"+ msg.TempC_SHT+ "°C<br/><b>Humidity:</b>"+msg.Hum_SHT+"%" 153 + return str 154 +} 155 +else{ 156 + var str = "<b>"+msg.entityName+"</b><br/><b>"+msg.Label+"</b><br/><b>Bat:</b>"+msg.BatV+"V<br/><b>Temperature:</b>"+ msg.temperature+ "°C<br/><b>Humidity:"+msg.humidity+"%"+"</b><br/>"+ 157 + "<b>Co2:"+msg.co2+"</b></br><b>Air_Pressure:"+msg.air_pressure 158 + 159 + return str 160 +} 161 +{{/code}} 162 + 163 +(% class="wikigeneratedid" id="HMarkerimagefunctionFF1A" %) 164 +**Marker image function:**This module can display different icons based on different types of sensors and their status to achieve its functionality 165 + 166 +(% class="wikigeneratedid" %) 167 +[[image:1730857750749-240.png]] 168 + 169 +{{code language="none"}} 170 +var res 171 +var msg = data 172 +if(msg.Label=="gateway" && msg.type=="gateway"){ 173 + if (msg.gatewaystauts == "true"){ 174 + res = { 175 + url: images[3], 176 + size: 40 177 +} 178 +} 179 +else{ 180 + res = { 181 + url: images[2], 182 + size: 40 183 +} 184 +}} 185 +else if(msg.Label!="gateway" && msg.type=="gxhl01" ){ 186 + if (msg.active=="false"){ 187 + res = { 188 + url: images[1], 189 + size: 40 190 +}} 191 +else{ 192 + res = { 193 + url: images[0], 194 + size: 40 195 +} 196 +} 197 +} 198 +else if(msg.type=="LWL02"){ 199 + if (msg.WATER_LEAK_STATUS=="0"){ 200 + res = { 201 + url: images[6], 202 + size: 40 203 +}} 204 +else{ 205 + res = { 206 + url: images[7], 207 + size: 40 208 +} 209 +} 210 +} 211 +else if(msg.type=="LDS02"){ 212 + if (msg.DOOR_OPEN_STATUS=="0"){ 213 + res = { 214 + url: images[5], 215 + size: 40 216 +}} 217 +else{ 218 + res = { 219 + url: images[8], 220 + size: 40 221 +} 222 +} 223 +} 224 +else if(msg.type=="LDS12"){ 225 + res = { 226 + url: images[10], 227 + size: 40 228 +}} 229 +else if(msg.type=="SE01"){ 230 + res = { 231 + url: images[9], 232 + size: 40 233 +}} 234 +else if(msg.type=="PB01"){ 235 + res = { 236 + url: images[11], 237 + size: 40 238 +}} 239 +else if(msg.type=="S31b"){ 240 + res = { 241 + url: images[12], 242 + size: 40 243 +}} 244 +else if(msg.type=="LHT65N"){ 245 + res = { 246 + url: images[13], 247 + size: 40 248 +}} 249 +else{ 250 + res = { 251 + url: images[4], 252 + size: 40 253 +} 254 +} 255 +return res; 256 +{{/code}} 257 + 258 +(% class="wikigeneratedid" id="H" %) 259 +[[image:1730770875793-351.png]]**Actions:**We need to implement the function of entering the details interface through the corresponding device icon, so in this module, we need to add actions to achieve redirection 260 + 261 +{{code language="none"}} 262 +var entitySubType; 263 +var $injector = widgetContext.$scope.$injector; 264 +$injector.get(widgetContext.servicesMap.get('entityService')).getEntity(entityId.entityType, entityId.id) 265 + .subscribe(function(data) { 266 + entitySubType = data.type; 267 + console.log(entitySubType) 268 + if (entitySubType == 'gateway') { 269 + openDashboardStates('gateway_detail'); 270 + } else if (entitySubType == 'gxhl01') { 271 + openDashboardStates('detail'); 272 + } 273 + else if(entitySubType == 'AQS01-dragino-office'){ 274 + openDashboardStates("aqs01_detail") 275 + } 276 + else if (entitySubType == 'LDS12') { 277 + openDashboardStates('lds12_detail'); 278 + } 279 + else if (entitySubType == 'LDS02') { 280 + openDashboardStates('lds02_detail'); 281 + } 282 + else if (entitySubType == 'SE01') { 283 + openDashboardStates('se01_detail'); 284 + } 285 + else if (entitySubType == 'PB01') { 286 + openDashboardStates('pb01_detail'); 287 + } 288 + else if (entitySubType == 'LWL02') { 289 + openDashboardStates('lwl02_detail'); 290 + } 291 + else if (entitySubType == 'LPS8N') { 292 + openDashboardStates('lps8n_detail'); 293 + } 294 + else if (entitySubType == 'LHT65N') { 295 + openDashboardStates('lht65n_detail'); 296 + } 297 + else if (entitySubType == 'S31b') { 298 + openDashboardStates('s31b_detail'); 299 + } 300 + }); 301 + 302 +function openDashboardStates(statedId) { 303 + var stateParams = widgetContext.stateController.getStateParams(); 304 + var params = { 305 + entityId: entityId, 306 + entityName: entityName 307 + }; 308 + 309 + if (stateParams.city) { 310 + params.city = stateParams.city; 311 + } 312 + 313 + widgetContext.stateController.openState(statedId, params, false); 314 +} 315 + 316 +{{/code}} 317 + 318 +[[image:1730771103096-522.png]] 319 + 320 +===== 4.1.2.2.2 Device List ===== 321 + 322 +(% class="wikigeneratedid" id="HDataFF1A" %) 323 +**Data:** 324 + 325 +[[image:1730771199343-553.png]] 326 + 327 +**Actions:**Equipment distribution diagram: In this module, functions need to be implemented such as adding devices, editing devices, deleting devices, and jumping to the device details page. Therefore, the following actions need to be added: 328 + 329 +[[image:1730771228766-212.png]] 330 + 331 +(% class="wikigeneratedid" id="HEditdeviceFF1A" %) 332 +Edit device:Implementation function: Device editing 333 + 334 +[[image:1730771256045-238.png]] 335 + 336 +{{code language="none"}} 337 +let $injector = widgetContext.$scope.$injector; 338 +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); 339 +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); 340 +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); 341 + 342 +openEditDeviceDialog(); 343 + 344 +function openEditDeviceDialog() { 345 + customDialog.customDialog(htmlTemplate, EditDeviceDialogController).subscribe(); 346 +} 347 + 348 +function EditDeviceDialogController(instance) { 349 + let vm = instance; 350 + 351 + vm.device = null; 352 + vm.attributes = {}; 353 + 354 + vm.editDeviceFormGroup = vm.fb.group({ 355 + deviceName: ['', [vm.validators.required]], 356 + deviceType: ['', [vm.validators.required]], 357 + deviceLabel: [''], 358 + attributes: vm.fb.group({ 359 + latitude: [null], 360 + longitude: [null] 361 + }) 362 + }); 363 + 364 + vm.cancel = function() { 365 + vm.dialogRef.close(null); 366 + }; 367 + 368 + vm.save = function() { 369 + vm.editDeviceFormGroup.markAsPristine(); 370 + if (vm.editDeviceFormGroup.get('deviceType').value !== vm.device.type) { 371 + delete vm.device.deviceProfileId; 372 + } 373 + vm.device.name = vm.editDeviceFormGroup.get('deviceName').value, 374 + vm.device.type = vm.editDeviceFormGroup.get('deviceType').value, 375 + vm.device.label = vm.editDeviceFormGroup.get('deviceLabel').value 376 + deviceService.saveDevice(vm.device).subscribe( 377 + function () { 378 + saveAttributes().subscribe( 379 + function () { 380 + widgetContext.updateAliases(); 381 + vm.dialogRef.close(null); 382 + } 383 + ); 384 + } 385 + ); 386 + }; 387 + 388 + getEntityInfo(); 389 + 390 + function getEntityInfo() { 391 + deviceService.getDevice(entityId.id).subscribe( 392 + function (device) { 393 + attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE', 394 + ['latitude', 'longitude']).subscribe( 395 + function (attributes) { 396 + for (let i = 0; i < attributes.length; i++) { 397 + vm.attributes[attributes[i].key] = attributes[i].value; 398 + } 399 + vm.device = device; 400 + vm.editDeviceFormGroup.patchValue( 401 + { 402 + deviceName: vm.device.name, 403 + deviceType: vm.device.type, 404 + deviceLabel: vm.device.label, 405 + attributes: { 406 + latitude: vm.attributes.latitude, 407 + longitude: vm.attributes.longitude 408 + } 409 + }, {emitEvent: false} 410 + ); 411 + } 412 + ); 413 + } 414 + ); 415 + } 416 + 417 + function saveAttributes() { 418 + let attributes = vm.editDeviceFormGroup.get('attributes').value; 419 + let attributesArray = []; 420 + for (let key in attributes) { 421 + attributesArray.push({key: key, value: attributes[key]}); 422 + } 423 + if (attributesArray.length > 0) { 424 + return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray); 425 + } else { 426 + return widgetContext.rxjs.of([]); 427 + } 428 + } 429 +} 430 +{{/code}} 431 + 432 +(% class="wikigeneratedid" id="H" %) 433 +Delete device:Implementation function: Device deletion 434 + 435 +[[image:1730771318657-502.png]] 436 + 437 +{{code language="none"}} 438 +let $injector = widgetContext.$scope.$injector; 439 +let dialogs = $injector.get(widgetContext.servicesMap.get('dialogs')); 440 +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); 441 + 442 +openDeleteDeviceDialog(); 443 + 444 +function openDeleteDeviceDialog() { 445 + let title = "Are you sure you want to delete the device " + entityName + "?"; 446 + let content = "Be careful, after the confirmation, the device and all related data will become unrecoverable!"; 447 + dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe( 448 + function (result) { 449 + if (result) { 450 + deleteDevice(); 451 + } 452 + } 453 + ); 454 +} 455 + 456 +function deleteDevice() { 457 + deviceService.deleteDevice(entityId.id).subscribe( 458 + function () { 459 + widgetContext.updateAliases(); 460 + } 461 + ); 462 +} 463 + 464 +{{/code}} 465 + 466 +jump:Implementation function: Jump to the device details page 467 + 468 +[[image:1730771386258-676.png]] 469 + 470 +{{code language="none"}} 471 +console.log(entityName) 472 +var entitySubType; 473 +var $injector = widgetContext.$scope.$injector; 474 +//console.log($injector) 475 +$injector.get(widgetContext.servicesMap.get('entityService')).getEntity(entityId.entityType, entityId.id) 476 + .subscribe(function(data) { 477 + console.log(data) 478 + entitySubType = data.type; 479 + console.log(entitySubType) 480 + if (entitySubType == 'AQS01-dragino-office') { 481 + openDashboardStates('aqs01_detail'); 482 + }else if (entitySubType == 'gateway') { 483 + openDashboardStates('gateway_detail'); 484 + } else if (entitySubType == 'gxhl01') { 485 + openDashboardStates('detail'); 486 + 487 + } else if (entitySubType == 'tank-type1') { 488 + openDashboardStates('test1'); 489 + } 490 + else if (entitySubType == 'LDS12') { 491 + openDashboardStates('lds12_detail'); 492 + } 493 + else if (entitySubType == 'LDS02') { 494 + openDashboardStates('lds02_detail'); 495 + } 496 + else if (entitySubType == 'SE01') { 497 + openDashboardStates('se01_detail'); 498 + } 499 + else if (entitySubType == 'PB01') { 500 + openDashboardStates('pb01_detail'); 501 + } 502 + else if (entitySubType == 'LWL02') { 503 + openDashboardStates('lwl02_detail'); 504 + } 505 + else if (entitySubType == 'LPS8N') { 506 + openDashboardStates('lps8n_detail'); 507 + } 508 + else if (entitySubType == 'LHT65N') { 509 + openDashboardStates('lht65n_detail'); 510 + } 511 + else if (entitySubType == 'S31b') { 512 + openDashboardStates('s31b_detail'); 513 + } 514 + }); 515 + 516 +function openDashboardStates(statedId) { 517 + var stateParams = widgetContext.stateController.getStateParams(); 518 + //console.log(stateParams) 519 + var params = { 520 + entityId: entityId, 521 + entityName: entityName 522 + }; 523 + widgetContext.stateController.updateState(statedId, params, false); 524 +} 525 +{{/code}} 526 + 527 +(% class="wikigeneratedid" id="H-1" %) 528 +Add device:Implementation function: Add device 529 + 530 +[[image:1730771441589-122.png]] 531 + 532 +{{code language="none"}} 533 +let $injector = widgetContext.$scope.$injector; 534 +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); 535 +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); 536 +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); 537 + 538 +openAddDeviceDialog(); 539 + 540 +function openAddDeviceDialog() { 541 + customDialog.customDialog(htmlTemplate, AddDeviceDialogController).subscribe(); 542 +} 543 + 544 +function AddDeviceDialogController(instance) { 545 + let vm = instance; 546 + 547 + vm.addDeviceFormGroup = vm.fb.group({ 548 + deviceName: ['', [vm.validators.required]], 549 + deviceType: ['', [vm.validators.required]], 550 + deviceLabel: [''], 551 + attributes: vm.fb.group({ 552 + latitude: [null], 553 + longitude: [null] 554 + }) 555 + }); 556 + 557 + vm.cancel = function() { 558 + vm.dialogRef.close(null); 559 + }; 560 + 561 + vm.save = function() { 562 + vm.addDeviceFormGroup.markAsPristine(); 563 + let device = { 564 + name: vm.addDeviceFormGroup.get('deviceName').value, 565 + type: vm.addDeviceFormGroup.get('deviceType').value, 566 + label: vm.addDeviceFormGroup.get('deviceLabel').value 567 + }; 568 + deviceService.saveDevice(device).subscribe( 569 + function (device) { 570 + saveAttributes(device.id).subscribe( 571 + function () { 572 + widgetContext.updateAliases(); 573 + vm.dialogRef.close(null); 574 + } 575 + ); 576 + } 577 + ); 578 + }; 579 + 580 + function saveAttributes(entityId) { 581 + let attributes = vm.addDeviceFormGroup.get('attributes').value; 582 + let attributesArray = []; 583 + for (let key in attributes) { 584 + attributesArray.push({key: key, value: attributes[key]}); 585 + } 586 + if (attributesArray.length > 0) { 587 + return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray); 588 + } else { 589 + return widgetContext.rxjs.of([]); 590 + } 591 + } 592 +} 593 +{{/code}} 594 + 595 +==== ==== 596 + 597 +===== **4.1.2.2.3 Asset Alarm:** ===== 598 + 599 +**Data:** 600 + 601 +[[image:1730771504586-433.png]] 602 + 603 +==== 4.1.2.3、Configure the first layer menu interface ==== 604 + 605 +===== 4.1.2.3.1 **Map:** ===== 606 + 607 +**Data:** 608 + 609 +[[image:1730710271230-716.png||height="729" width="1427"]] 610 + 611 +Actions:The map interface has two actions, among which Select supermarket can refresh the device list and related alarms on the right side to enter the location, and Supermarket_detail can jump to the second level physical interface to view the details of the location based on the selected location 612 + 613 +[[image:1730710850458-781.png||height="770" width="1429"]] 614 + 615 +Select supermarket:Implementation function: Refresh the side page 616 + 617 +{{code language="none"}} 618 +var params = widgetContext.stateController.getStateParams(); 619 +var selectedSupermarket = params['selectedSupermarket']; 620 +if (selectedSupermarket && selectedSupermarket.entityId.id === entityId.id) { 621 + params['selectedSupermarket'] = null; 622 +} else { 623 + params['selectedSupermarket'] = { entityId: entityId, entityName: entityName, entityLabel: entityLabel }; 624 +} 625 +widgetContext.stateController.updateState(null, params); 626 +{{/code}} 627 + 628 +[[image:1730710875401-848.png||height="767" width="1429"]] 629 + 630 +Supermarket_detail:Implementation function: Jump to the asset details page 631 + 632 +{{code language="none"}} 633 +var params = JSON.parse(JSON.stringify(widgetContext.stateController.getStateParams())); 634 +params['selectedSupermarket'] = { 635 + entityId: entityId, 636 + entityName: entityName, 637 + entityLabel: entityLabel, 638 +}; 639 +params['targetEntityParamName'] = 'selectedSupermarket'; 640 +params['selectedDevice'] = null; 641 + 642 +widgetContext.stateController.openState('svgmap', params); 643 +{{/code}} 644 + 645 +[[image:1730710990334-601.png||height="772" width="1433"]] 646 + 647 +* ((( 648 +In this demo, exclusive map icons were set as follows: 649 +))) 650 + 651 +{{code language="none"}} 652 +var res = { 653 + url: images[0], 654 + size: 66 655 +}; 656 +return res; 657 +{{/code}} 658 + 659 +[[image:1730710395303-672.png||height="771" width="1438"]] 660 + 661 +===== 4.1.2.3.1 Asset List: ===== 662 + 663 +**Data:** 664 + 665 +[[image:1730710693066-349.png||height="772" width="1439"]] 666 + 667 +Actions:The Assets List interface has an action, which is the same as the Supermarket_details in the Map. You can jump to the second level entity interface to view the details of the selected location based on its location 668 + 669 +[[image:1730712335338-750.png||height="751" width="1423"]] 670 + 671 +[[image:1730712473941-913.png||height="781" width="1422"]] 672 + 673 +All Alarms: 674 + 675 +[[image:1730712539209-554.png||height="764" width="1424"]] 676 + 102 102 == 4.2 Alarm configuration details == 103 103 679 +=== 4.2.1 High temperature === 680 + 681 +Creat: 682 + 683 +[[image:1730862483514-101.png||height="750" width="1407"]] 684 + 685 +Clear: 686 + 687 +[[image:1730862584519-902.png||height="758" width="1404"]] 688 + 689 +=== 4.2.2 Low Temperature === 690 + 691 +Creat: 692 + 693 +[[image:1730863708259-750.png||height="752" width="1403"]] 694 + 695 +Clear: 696 + 697 +[[image:1730863750414-979.png||height="746" width="1403"]] 698 + 699 +=== 4.2.3 High humidity === 700 + 701 +Creat: 702 + 703 +[[image:1730864045747-876.png||height="752" width="1396"]] 704 + 705 +Clear: 706 + 707 +[[image:1730864077395-395.png||height="735" width="1393"]] 708 + 709 +=== 4.2.4 Low humidity === 710 + 711 +Creat: 712 + 713 +[[image:1730864117808-484.png||height="741" width="1392"]] 714 + 715 +Clear: 716 + 717 +[[image:1730864159071-895.png||height="745" width="1392"]] 718 + 719 +=== 4.2.5 Low voltage === 720 + 721 +Creat: 722 + 723 +[[image:1730864207037-477.png||height="740" width="1388"]] 724 + 725 +Clear: 726 + 727 +[[image:1730864250506-111.png||height="735" width="1389"]] 728 + 729 +=== 4.2.6 Device Disconnected === 730 + 731 +Creat: 732 + 733 +[[image:1730864293216-991.png||height="739" width="1387"]] 734 + 735 +Clear: 736 + 737 +[[image:1730864331859-740.png||height="735" width="1385"]] 738 + 104 104 == 4.3 Rule chain configuration details == 105 105 106 -= 5. = 741 +[[image:1730864784118-474.png]] 742 + 743 +**Script:**Email configuration for sending device alarm information 744 + 745 +[[image:1730864676542-406.png||height="732" width="1384"]] 746 + 747 +{{code language="none"}} 748 +function locatime(timenumber){ 749 + var date = new Date(timenumber) 750 + return date.toLocaleDateString() + ' ' + date.toLocaleTimeString() 751 +} 752 +var name = msg.name 753 +var devicename = msg.originatorName 754 +var label = msg.originatorLabel 755 +var status = msg.status 756 +var detaildata =JSON.parse(msg.details.data) 757 +var tempswitch 758 + 759 +if (name != "Device Disconnected") { 760 + //detaildata=JSON.parse(msg.details.data) 761 + if (detaildata.Temperature_alarm_switch == true) { 762 + tempswitch = "open" 763 + } else { 764 + tempswitch = "close" 765 + } 766 + var humswitch 767 + if (detaildata.Humidity_alarm_switch == true) { 768 + humswitch = "open" 769 + } else { 770 + humswitch = "close" 771 + } 772 + var batswitch 773 + if (detaildata.Voltage_alarm_switch == true) { 774 + batswitch = "open" 775 + } else { 776 + batswitch = "close" 777 + } 778 + var str2 = "<p>-- Temperature alarm switch status: " + 779 + tempswitch + "</p>" + 780 + "<p>-- Humidity alarm switch status: " + humswitch + 781 + "</p>" + 782 + "<p>-- Voltage alarm switch status: " + batswitch 783 +} 784 + 785 +if (name == "High Temperature" && status == 786 + "ACTIVE_UNACK") { 787 + var emailstr = 788 + "<div><p><span style='color: black; font-weight: bold'>" + 789 + "Device " + label + " has alarm:</span></p>" + 790 + "<p><span style='color: red; font-weight: bold'>-- High Temperature Alarm</span></p>" + 791 + "<p>-- Current Temperature : " + detaildata 792 + .TempC_SHT + "</p><br>" + 793 + "<p>Device Configure:</p>" + 794 + "<p>-- Temperature Threshold : min: " + detaildata 795 + .Low_temperature_alarm + ", max: " + detaildata 796 + .High_temperature_alarm + "</p>" + 797 + "<p>-- Humidity Threshold: min: " + detaildata 798 + .Low_humidity_alarm + ", max:" + detaildata 799 + .High_humidity_alarm + "</p>" + 800 + "<p>-- Battery threshold: min: " + detaildata 801 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 802 + return { 803 + msg: { 804 + "data": emailstr 805 + }, 806 + metadata: metadata, 807 + msgType: msgType 808 + }; 809 +} else if (name == "Low Temperature" && status == 810 + "ACTIVE_UNACK") { 811 + var emailstr = 812 + "<div><p><span style='color: black; font-weight: bold'>" + 813 + "Device " + label + " has alarm:</span></p>" + 814 + "<p><span style='color: red; font-weight: bold'>-- Low Temperature Alarm</span></p>" + 815 + "<p>-- Current Temperature : " + detaildata 816 + .TempC_SHT + "</p><br>" + 817 + "<p>Device Configure:</p>" + 818 + "<p>-- Temperature Threshold : min: " + detaildata 819 + .Low_temperature_alarm + ", max: " + detaildata 820 + .High_temperature_alarm + "</p>" + 821 + "<p>-- Humidity Threshold: min: " + detaildata 822 + .Low_humidity_alarm + ", max:" + detaildata 823 + .High_humidity_alarm + "</p>" + 824 + "<p>-- Battery threshold: min: " + detaildata 825 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 826 + 827 + return { 828 + msg: { 829 + "data": emailstr 830 + }, 831 + metadata: metadata, 832 + msgType: msgType 833 + }; 834 + 835 +} else if (name == "Device Disconnected" && status == 836 + "ACTIVE_UNACK") { 837 + var time1 = locatime(Number(detaildata.lastActivityTime)) 838 + //var time1 = detaildata.lastActivityTime 839 + // var chazhi = parseInt((detaildata.inactivityAlarmTime-detaildata.lastActivityTime)/1000/60) 840 + // var emailstr = 841 + // "<div><p><span style='color: red; font-weight: bold'>" + 842 + // "Device " + label + " has Alarm</span></p><p>Last activity time: "+time1+"</p><p>Last Uplink: 21"+"minutes ago</p></div>" 843 + 844 + var emailstr ="Device " + label + " has Alarm##Last activity time: "+time1+"##Last Uplink: 21minutes ago" 845 + var newType = "POST_TELEMETRY_REQUEST" 846 + return { 847 + msg:emailstr, 848 + metadata: metadata, 849 + msgType: newType 850 + } 851 +} else if (name == "High humidity" && status == 852 + "ACTIVE_UNACK") { 853 + var emailstr = 854 + "<div><p><span style='color: black; font-weight: bold'>" + 855 + "Device " + label + " has alarm:</span></p>" + 856 + "<p><span style='color: red; font-weight: bold'>-- High Humidity Alarm</span></p>" + 857 + "<p>-- Current Temperature : " + detaildata 858 + .Hum_SHT + "</p><br>" + 859 + "<p>Device Configure:</p>" + 860 + "<p>-- Temperature Threshold : min: " + detaildata 861 + .Low_temperature_alarm + ", max: " + detaildata 862 + .High_temperature_alarm + "</p>" + 863 + "<p>-- Humidity Threshold: min: " + detaildata 864 + .Low_humidity_alarm + ", max:" + detaildata 865 + .High_humidity_alarm + "</p>" + 866 + "<p>-- Battery threshold: min: " + detaildata 867 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 868 + 869 + return { 870 + msg: { 871 + "data": emailstr 872 + }, 873 + metadata: metadata, 874 + msgType: msgType 875 + }; 876 +} else if (name == "Low humidity" && status == 877 + "ACTIVE_UNACK") { 878 + var emailstr = 879 + "<div><p><span style='color: black; font-weight: bold'>" + 880 + "Device " + label + " has alarm:</span></p>" + 881 + "<p><span style='color: red; font-weight: bold'>-- Low Humidity Alarm</span></p>" + 882 + "<p>-- Current Temperature : " + detaildata 883 + .Hum_SHT + "</p><br>" + 884 + "<p>Device Configure:</p>" + 885 + "<p>-- Temperature Threshold : min: " + detaildata 886 + .Low_temperature_alarm + ", max: " + detaildata 887 + .High_temperature_alarm + "</p>" + 888 + "<p>-- Humidity Threshold: min: " + detaildata 889 + .Low_humidity_alarm + ", max:" + detaildata 890 + .High_humidity_alarm + "</p>" + 891 + "<p>-- Battery threshold: min: " + detaildata 892 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 893 + 894 + return { 895 + msg: { 896 + "data": emailstr 897 + }, 898 + metadata: metadata, 899 + msgType: msgType 900 + }; 901 +} else if (name == "Low voltage" && status == 902 + "ACTIVE_UNACK") { 903 + var emailstr = 904 + "<div><p><span style='color: black; font-weight: bold'>" + 905 + "Device " + label + " has alarm:</span></p>" + 906 + "<p><span style='color: red; font-weight: bold'>-- Low Voltage Alarm</span></p>" + 907 + "<p>-- Current Temperature : " + detaildata.BatV + 908 + "</p><br>" + 909 + "<p>Device Configure:</p>" + 910 + "<p>-- Temperature Threshold : min: " + detaildata 911 + .Low_temperature_alarm + ", max: " + detaildata 912 + .High_temperature_alarm + "</p>" + 913 + "<p>-- Humidity Threshold: min: " + detaildata 914 + .Low_humidity_alarm + ", max:" + detaildata 915 + .High_humidity_alarm + "</p>" + 916 + "<p>-- Battery threshold: min: " + detaildata 917 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 918 + 919 + return { 920 + msg: { 921 + "data": emailstr 922 + }, 923 + metadata: metadata, 924 + msgType: msgType 925 + }; 926 +} else if (name == "High Temperature" && status == 927 + "CLEARED_UNACK") { 928 + var emailstr = 929 + "<div><p><span style='color: green; font-weight: bold'>Device " + 930 + label + 931 + " High Temperature Alarm Cleared</span></p>" + 932 + "<p>-- Current Temperature : " + detaildata 933 + .TempC_SHT + "</p><br>" + 934 + "<p>Device Configure:</p>" + 935 + "<p>-- Temperature Threshold : min: " + detaildata 936 + .Low_temperature_alarm + ", max: " + detaildata 937 + .High_temperature_alarm + "</p>" + 938 + "<p>-- Humidity Threshold: min: " + detaildata 939 + .Low_humidity_alarm + ", max:" + detaildata 940 + .High_humidity_alarm + "</p>" + 941 + "<p>-- Battery threshold: min: " + detaildata 942 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 943 + 944 + return { 945 + msg: { 946 + "data": emailstr 947 + }, 948 + metadata: metadata, 949 + msgType: msgType 950 + }; 951 +} else if (name == "Low Temperature" && status == 952 + "CLEARED_UNACK") { 953 + var emailstr = 954 + "<div><p><span style='color: green; font-weight: bold'>Device " + 955 + label + 956 + " Low Temperature Alarm Cleared</span></p>" + 957 + "<p>-- Current Temperature : " + detaildata 958 + .TempC_SHT + "</p><br>" + 959 + "<p>Device Configure:</p>" + 960 + "<p>-- Temperature Threshold : min: " + detaildata 961 + .Low_temperature_alarm + ", max: " + detaildata 962 + .High_temperature_alarm + "</p>" + 963 + "<p>-- Humidity Threshold: min: " + detaildata 964 + .Low_humidity_alarm + ", max:" + detaildata 965 + .High_humidity_alarm + "</p>" + 966 + "<p>-- Battery threshold: min: " + detaildata 967 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 968 + 969 + return { 970 + msg: { 971 + "data": emailstr 972 + }, 973 + metadata: metadata, 974 + msgType: msgType 975 + }; 976 +} else if (name == "High humidity" && status == 977 + "CLEARED_UNACK") { 978 + var emailstr = 979 + "<div><p><span style='color: green; font-weight: bold'>Device " + 980 + label + " High Humidity Alarm Cleared</span></p>" + 981 + "<p>-- Current Temperature : " + detaildata 982 + .Hum_SHT + "</p><br>" + 983 + "<p>Device Configure:</p>" + 984 + "<p>-- Temperature Threshold : min: " + detaildata 985 + .Low_temperature_alarm + ", max: " + detaildata 986 + .High_temperature_alarm + "</p>" + 987 + "<p>-- Humidity Threshold: min: " + detaildata 988 + .Low_humidity_alarm + ", max:" + detaildata 989 + .High_humidity_alarm + "</p>" + 990 + "<p>-- Battery threshold: min: " + detaildata 991 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 992 + 993 + return { 994 + msg: { 995 + "data": emailstr 996 + }, 997 + metadata: metadata, 998 + msgType: msgType 999 + }; 1000 +} else if (name == "Low humidity" && status == 1001 + "CLEARED_UNACK") { 1002 + var emailstr = 1003 + "<div><p><span style='color: green; font-weight: bold'>Device " + 1004 + label + " Low Humidity Alarm Cleared</span></p>" + 1005 + "<p>-- Current Temperature : " + detaildata 1006 + .Hum_SHT + "</p><br>" + 1007 + "<p>Device Configure:</p>" + 1008 + "<p>-- Temperature Threshold : min: " + detaildata 1009 + .Low_temperature_alarm + ", max: " + detaildata 1010 + .High_temperature_alarm + "</p>" + 1011 + "<p>-- Humidity Threshold: min: " + detaildata 1012 + .Low_humidity_alarm + ", max:" + detaildata 1013 + .High_humidity_alarm + "</p>" + 1014 + "<p>-- Battery threshold: min: " + detaildata 1015 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 1016 + return { 1017 + msg: { 1018 + "data": emailstr 1019 + }, 1020 + metadata: metadata, 1021 + msgType: msgType 1022 + }; 1023 +} else if (name == "Low voltage" && status == 1024 + "CLEARED_UNACK") { 1025 + 1026 + var emailstr = 1027 + "<div><p><span style='color: green; font-weight: bold'>Device " + 1028 + label + " Low Voltage Alarm Cleared</span></p>" + 1029 + "<p>-- Current Temperature : " + detaildata.BatV + 1030 + "</p><br><br>" + 1031 + "<p>Device Configure:</p>" + 1032 + "<p>-- Temperature Threshold : min: " + detaildata 1033 + .Low_temperature_alarm + ", max: " + detaildata 1034 + .High_temperature_alarm + "</p>" + 1035 + "<p>-- Humidity Threshold: min: " + detaildata 1036 + .Low_humidity_alarm + ", max:" + detaildata 1037 + .High_humidity_alarm + "</p>" + 1038 + "<p>-- Battery threshold: min: " + detaildata 1039 + .Low_voltage_alarm + "</p>" + str2 + "</div>" 1040 + 1041 + return { 1042 + msg: { 1043 + "data": emailstr 1044 + }, 1045 + metadata: metadata, 1046 + msgType: msgType 1047 + }; 1048 +} else if (name == "Device Disconnected" && status == 1049 + "CLEARED_UNACK") { 1050 + var time1 = locatime(Number(detaildata.lastActivityTime)) 1051 + //var time1 = detaildata.lastActivityTime 1052 + // var chazhi = parseInt((detaildata.inactivityAlarmTime-detaildata.lastActivityTime)/1000/60) 1053 + // var emailstr = 1054 + // "<div><p><span style='color: green; font-weight: bold'>" + 1055 + // "Device " + label + " has Alarm Cleared</span></p><p>Last activity time: "+time1+"</p></div>" 1056 + var emailstr ="Device " + label + " has Alarm Cleared##Last activity time: "+time1 1057 + var newType = "POST_TELEMETRY_REQUEST" 1058 + return { 1059 + msg: emailstr, 1060 + metadata: metadata, 1061 + msgType: newType 1062 + } 1063 +} 1064 +{{/code}} 1065 + 1066 +(% class="wikigeneratedid" %) 1067 +**Generate Report:** 1068 + 1069 +(% class="wikigeneratedid" %) 1070 +[[image:1730865053380-293.png]] 1071 + 1072 += 5.other = 1073 + 1074 +* If you want to create a similar dashboard, after understanding the case, you can download and import the dashboard, device profiles, rule chains, etc. of the case on GitHub, and make modifications based on them. 1075 +* GitHub address:[[https:~~/~~/github.com/ThingsEye-io/te-platform/tree/main/case/Dragino%20Office%20%26%20Factory>>https://github.com/ThingsEye-io/te-platform/tree/main/case/Dragino%20Office%20%26%20Factory]]
- 1730709382428-730.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +480.8 KB - Content
- 1730709409941-536.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +451.5 KB - Content
- 1730709424998-915.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +443.4 KB - Content
- 1730709442773-502.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +448.3 KB - Content
- 1730709461297-207.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +458.2 KB - Content
- 1730709479828-595.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +450.7 KB - Content
- 1730709511861-439.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +470.0 KB - Content
- 1730709527720-418.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +475.8 KB - Content
- 1730709542597-321.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +474.8 KB - Content
- 1730709555797-383.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +463.2 KB - Content
- 1730710271230-716.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +1.5 MB - Content
- 1730710395303-672.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +1.6 MB - Content
- 1730710693066-349.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +94.4 KB - Content
- 1730710850458-781.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +1.5 MB - Content
- 1730710875401-848.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +1.0 MB - Content
- 1730710949358-671.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +1.0 MB - Content
- 1730710990334-601.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +1.0 MB - Content
- 1730712335338-750.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +77.1 KB - Content
- 1730712473941-913.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +135.9 KB - Content
- 1730712539209-554.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +131.0 KB - Content
- 1730770392454-317.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +195.6 KB - Content
- 1730770636230-829.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +290.6 KB - Content
- 1730770875793-351.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +305.2 KB - Content
- 1730771103096-522.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +197.9 KB - Content
- 1730771199343-553.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +108.5 KB - Content
- 1730771228766-212.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +46.8 KB - Content
- 1730771256045-238.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +69.1 KB - Content
- 1730771318657-502.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +60.4 KB - Content
- 1730771386258-676.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +46.4 KB - Content
- 1730771441589-122.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +57.6 KB - Content
- 1730771504586-433.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +151.2 KB - Content
- 1730857191863-514.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +354.7 KB - Content
- 1730857537965-184.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +455.1 KB - Content
- 1730857750749-240.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +285.9 KB - Content
- 1730862483514-101.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +195.8 KB - Content
- 1730862584519-902.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +191.1 KB - Content
- 1730863708259-750.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +220.1 KB - Content
- 1730863750414-979.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +210.6 KB - Content
- 1730864045747-876.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +208.9 KB - Content
- 1730864077395-395.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +201.4 KB - Content
- 1730864117808-484.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +203.0 KB - Content
- 1730864159071-895.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +226.6 KB - Content
- 1730864207037-477.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +215.3 KB - Content
- 1730864250506-111.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +209.5 KB - Content
- 1730864293216-991.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +138.5 KB - Content
- 1730864331859-740.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +134.4 KB - Content
- 1730864460314-611.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +256.7 KB - Content
- 1730864617480-221.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +260.8 KB - Content
- 1730864676542-406.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +227.7 KB - Content
- 1730864784118-474.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +148.8 KB - Content
- 1730865053380-293.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.hera - Size
-
... ... @@ -1,0 +1,1 @@ 1 +46.7 KB - Content