Wiki source code of Demo for Smart Office, Factory

Version 20.1 by Hera Guo on 2024/11/06 10:03

Show last authors
1 **Table of Contents:**
2
3 {{toc/}}
4
5
6
7
8 = 1. About this demo =
9
10 This demo is to show the installation for various sensors in Dragino Office, Dragino Facotry & ThingsEye Office. It covers various types of sensors such as Temperature, Humidity, CO2, Water Flow, Vibration & many many.
11
12 User can check this [[Public Share Link>>https://thingseye.io/dashboard/d17f70f0-6b5f-11ef-a329-6fb88c149adb?publicId=33180810-5c40-11ef-a329-6fb88c149adb ]] and see the dash board for this demo. The dash board keeps updating, while the main structure will keep the same. It has **Three Level DashBoard **as decribe below.
13
14 * **First Level - Overview for all branches**: This dashboard shows all branches overview status and location.
15 * **Second Level - Branch Level**: This dashboard shows all sensors installation and status in the selected branch.
16 * **Third Level - Sensor Level**: This dashboard shows the detail reading for a specify sensor
17
18 [[image:Level1.png||height="133" width="298"]] [[image:Arrow.png||height="27" width="51"]] [[image:Level2.png||height="134" width="264"]][[image:Arrow.png||height="27" width="51"]] [[image:2024-09-26 23-47-06.png||height="130" width="256"]]
19
20
21 The rest of this chapter will provide the introduction for how to set up similiar solution.
22
23
24 = 2.Basic configuration instructions =
25
26 When you start a complex IoT project, you first need to learn some basic configuration methods for ThingsEye.
27
28 Here are some instructions you need to know:
29
30 Dashboard creation and some basic configurations:[[https:~~/~~/wiki.thingseye.io/xwiki/bin/view/Main/How%20to%20import%20and%20use%20the%20dashboard%3F/#H3.2.2.1CreatA0alarm>>https://wiki.thingseye.io/xwiki/bin/view/Main/How%20to%20import%20and%20use%20the%20dashboard%3F/#H3.2.2.1CreatA0alarm]]
31
32 Rule chain creation:[[https:~~/~~/wiki.thingseye.io/xwiki/bin/view/Main/Basic%20configuration%20of%20rule%20chains>>https://wiki.thingseye.io/xwiki/bin/view/Main/Basic%20configuration%20of%20rule%20chains/]]
33
34 Devices connected to thingseye:[[https:~~/~~/wiki.thingseye.io/xwiki/bin/view/Main/How%20to%20connect%20my%20devices%20to%20ThingsEye%3F/>>https://wiki.thingseye.io/xwiki/bin/view/Main/How%20to%20connect%20my%20devices%20to%20ThingsEye%3F/]]
35
36 = 3.overview =
37
38 == 3.1 MHierarchical architectureore features ==
39
40 Before we start a project, we first need to understand the organizational structure of the project. Only with a clear outline can our project construction process be smoother
41
42 **Assets:**Dragino Office  、Dragino Factory
43
44 **Devices:**
45
46 Dragino Factory:temperature and humidity measurement×7、Gateway×1
47
48 Dragino Office:temperature and humidity measurement×2、Air quality measurement×4
49
50 == 3.2 Dashboard architecture ==
51
52 In this demo, the dashboard is divided into three layers, namely: home page, asset, and device.
53
54 **home page:**It includes three parts: map, asset list, and all alarm. From this interface, you can see how many factories, offices, and so on there are
55
56 **asset:**It includes three parts: asset map, device list, and asset alarm. From this interface, you can see how many sensors are deployed in the office or project, where they are located, and their alarm status
57
58 **device:**This section displays the specific information collected by the device, and different types of sensors have different display interfaces
59
60 [[image:屏幕截图 2024-11-04 134645.png]]
61
62 First floor:
63
64 [[image:1730702565889-204.png||height="771" width="1445"]]
65
66 Second floor:
67
68 [[image:1730702622551-808.png||height="756" width="1450"]]
69
70 Third floor:
71
72 [[image:1730702656725-496.png||height="775" width="1455"]]
73
74 [[image:1730702814435-805.png||height="797" width="1458"]]
75
76
77 [[image:1730702688377-367.png||height="770" width="1462"]]
78
79 * How many types of devices do you need, how many layers of third level dashboards you need to create.
80
81 == 3.3 Alarm rules ==
82
83 High Temperature、Low Temperature、High humidity、Low humidity、Low voltage、Device Disconnected
84
85 [[image:1730854677036-426.png]]
86
87
88 = 4.configuration details =
89
90 After understanding the architecture and layering of the complete project, we can start configuring it
91
92 == 4.1 Dashboard configuration details ==
93
94 === 4.1.1.Data source (Entity aliases) ===
95
96 detail:Obtain data based on dashboard status
97
98 [[image:1730709424998-915.png||height="729" width="1436"]]
99
100 Alarm:Obtain alarm information
101
102 [[image:1730709479828-595.png||height="696" width="1435"]]
103
104 Dragino&GXHL,Ltd:Obtain data through asset types
105
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
125 ==== 4.1.2.2、Configure the interface of the second layer asset ====
126
127 ===== 4.1.2.2.1 Equipment distribution diagram: =====
128
129 **Data:**
130
131 [[image:1730770392454-317.png||height="745" width="1439"]]
132
133 **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
134
135 **Tooltip function:**This module displays the current information of the device
136
137 [[image:1730857537965-184.png]]
138
139 {{code language="none"}}
140 var msg = data
141 if(msg.Label=="gateway" && msg.type == "gateway"){
142 var stauts
143 if (msg.gatewaystauts=="true"){
144 stauts = "Connect"
145 }
146 else{
147 stauts = "Disconnected"
148 }
149 var str = "<b>"+msg.entityName+"</b><br/><b>"+stauts+"</b><br/>"
150 return str
151 }
152 else if(msg.type=="gxhl01" && msg.Label!="gateway"){
153 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+"%"
154 return str
155 }
156 else{
157 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/>"+
158 "<b>Co2:"+msg.co2+"</b></br><b>Air_Pressure:"+msg.air_pressure
159
160 return str
161 }
162 {{/code}}
163
164 (% class="wikigeneratedid" id="HMarkerimagefunctionFF1A" %)
165 **Marker image function:**This module can display different icons based on different types of sensors and their status to achieve its functionality
166
167 (% class="wikigeneratedid" %)
168 [[image:1730857750749-240.png]]
169
170 {{code language="none"}}
171 var res
172 var msg = data
173 if(msg.Label=="gateway" && msg.type=="gateway"){
174 if (msg.gatewaystauts == "true"){
175 res = {
176 url: images[3],
177 size: 40
178 }
179 }
180 else{
181 res = {
182 url: images[2],
183 size: 40
184 }
185 }}
186 else if(msg.Label!="gateway" && msg.type=="gxhl01" ){
187 if (msg.active=="false"){
188 res = {
189 url: images[1],
190 size: 40
191 }}
192 else{
193 res = {
194 url: images[0],
195 size: 40
196 }
197 }
198 }
199 else if(msg.type=="LWL02"){
200 if (msg.WATER_LEAK_STATUS=="0"){
201 res = {
202 url: images[6],
203 size: 40
204 }}
205 else{
206 res = {
207 url: images[7],
208 size: 40
209 }
210 }
211 }
212 else if(msg.type=="LDS02"){
213 if (msg.DOOR_OPEN_STATUS=="0"){
214 res = {
215 url: images[5],
216 size: 40
217 }}
218 else{
219 res = {
220 url: images[8],
221 size: 40
222 }
223 }
224 }
225 else if(msg.type=="LDS12"){
226 res = {
227 url: images[10],
228 size: 40
229 }}
230 else if(msg.type=="SE01"){
231 res = {
232 url: images[9],
233 size: 40
234 }}
235 else if(msg.type=="PB01"){
236 res = {
237 url: images[11],
238 size: 40
239 }}
240 else if(msg.type=="S31b"){
241 res = {
242 url: images[12],
243 size: 40
244 }}
245 else if(msg.type=="LHT65N"){
246 res = {
247 url: images[13],
248 size: 40
249 }}
250 else{
251 res = {
252 url: images[4],
253 size: 40
254 }
255 }
256 return res;
257 {{/code}}
258
259 ==== [[image:1730770875793-351.png]] ====
260
261 (% class="wikigeneratedid" id="HActions" %)
262 **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
263
264 {{code language="none"}}
265 var entitySubType;
266 var $injector = widgetContext.$scope.$injector;
267 $injector.get(widgetContext.servicesMap.get('entityService')).getEntity(entityId.entityType, entityId.id)
268 .subscribe(function(data) {
269 entitySubType = data.type;
270 console.log(entitySubType)
271 if (entitySubType == 'gateway') {
272 openDashboardStates('gateway_detail');
273 } else if (entitySubType == 'gxhl01') {
274 openDashboardStates('detail');
275 }
276 else if(entitySubType == 'AQS01-dragino-office'){
277 openDashboardStates("aqs01_detail")
278 }
279 else if (entitySubType == 'LDS12') {
280 openDashboardStates('lds12_detail');
281 }
282 else if (entitySubType == 'LDS02') {
283 openDashboardStates('lds02_detail');
284 }
285 else if (entitySubType == 'SE01') {
286 openDashboardStates('se01_detail');
287 }
288 else if (entitySubType == 'PB01') {
289 openDashboardStates('pb01_detail');
290 }
291 else if (entitySubType == 'LWL02') {
292 openDashboardStates('lwl02_detail');
293 }
294 else if (entitySubType == 'LPS8N') {
295 openDashboardStates('lps8n_detail');
296 }
297 else if (entitySubType == 'LHT65N') {
298 openDashboardStates('lht65n_detail');
299 }
300 else if (entitySubType == 'S31b') {
301 openDashboardStates('s31b_detail');
302 }
303 });
304
305 function openDashboardStates(statedId) {
306 var stateParams = widgetContext.stateController.getStateParams();
307 var params = {
308 entityId: entityId,
309 entityName: entityName
310 };
311
312 if (stateParams.city) {
313 params.city = stateParams.city;
314 }
315
316 widgetContext.stateController.openState(statedId, params, false);
317 }
318
319 {{/code}}
320
321 [[image:1730771103096-522.png]]
322
323 ===== 4.1.2.2.2 Device List =====
324
325 **Data:**
326
327 [[image:1730771199343-553.png]]
328
329 **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:
330
331 [[image:1730771228766-212.png]]
332
333 (% class="wikigeneratedid" id="HEditdeviceFF1A" %)
334 Edit device:Implementation function: Device editing
335
336 [[image:1730771256045-238.png]]
337
338 {{code language="none"}}
339 let $injector = widgetContext.$scope.$injector;
340 let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
341 let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
342 let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
343
344 openEditDeviceDialog();
345
346 function openEditDeviceDialog() {
347 customDialog.customDialog(htmlTemplate, EditDeviceDialogController).subscribe();
348 }
349
350 function EditDeviceDialogController(instance) {
351 let vm = instance;
352
353 vm.device = null;
354 vm.attributes = {};
355
356 vm.editDeviceFormGroup = vm.fb.group({
357 deviceName: ['', [vm.validators.required]],
358 deviceType: ['', [vm.validators.required]],
359 deviceLabel: [''],
360 attributes: vm.fb.group({
361 latitude: [null],
362 longitude: [null]
363 })
364 });
365
366 vm.cancel = function() {
367 vm.dialogRef.close(null);
368 };
369
370 vm.save = function() {
371 vm.editDeviceFormGroup.markAsPristine();
372 if (vm.editDeviceFormGroup.get('deviceType').value !== vm.device.type) {
373 delete vm.device.deviceProfileId;
374 }
375 vm.device.name = vm.editDeviceFormGroup.get('deviceName').value,
376 vm.device.type = vm.editDeviceFormGroup.get('deviceType').value,
377 vm.device.label = vm.editDeviceFormGroup.get('deviceLabel').value
378 deviceService.saveDevice(vm.device).subscribe(
379 function () {
380 saveAttributes().subscribe(
381 function () {
382 widgetContext.updateAliases();
383 vm.dialogRef.close(null);
384 }
385 );
386 }
387 );
388 };
389
390 getEntityInfo();
391
392 function getEntityInfo() {
393 deviceService.getDevice(entityId.id).subscribe(
394 function (device) {
395 attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',
396 ['latitude', 'longitude']).subscribe(
397 function (attributes) {
398 for (let i = 0; i < attributes.length; i++) {
399 vm.attributes[attributes[i].key] = attributes[i].value;
400 }
401 vm.device = device;
402 vm.editDeviceFormGroup.patchValue(
403 {
404 deviceName: vm.device.name,
405 deviceType: vm.device.type,
406 deviceLabel: vm.device.label,
407 attributes: {
408 latitude: vm.attributes.latitude,
409 longitude: vm.attributes.longitude
410 }
411 }, {emitEvent: false}
412 );
413 }
414 );
415 }
416 );
417 }
418
419 function saveAttributes() {
420 let attributes = vm.editDeviceFormGroup.get('attributes').value;
421 let attributesArray = [];
422 for (let key in attributes) {
423 attributesArray.push({key: key, value: attributes[key]});
424 }
425 if (attributesArray.length > 0) {
426 return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);
427 } else {
428 return widgetContext.rxjs.of([]);
429 }
430 }
431 }
432 {{/code}}
433
434 ==== ====
435
436 Delete device:Implementation function: Device deletion
437
438 [[image:1730771318657-502.png]]
439
440 {{code language="none"}}
441 let $injector = widgetContext.$scope.$injector;
442 let dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));
443 let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
444
445 openDeleteDeviceDialog();
446
447 function openDeleteDeviceDialog() {
448 let title = "Are you sure you want to delete the device " + entityName + "?";
449 let content = "Be careful, after the confirmation, the device and all related data will become unrecoverable!";
450 dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(
451 function (result) {
452 if (result) {
453 deleteDevice();
454 }
455 }
456 );
457 }
458
459 function deleteDevice() {
460 deviceService.deleteDevice(entityId.id).subscribe(
461 function () {
462 widgetContext.updateAliases();
463 }
464 );
465 }
466
467 {{/code}}
468
469
470 jump:Implementation function: Jump to the device details page
471
472 [[image:1730771386258-676.png]]
473
474 {{code language="none"}}
475 console.log(entityName)
476 var entitySubType;
477 var $injector = widgetContext.$scope.$injector;
478 //console.log($injector)
479 $injector.get(widgetContext.servicesMap.get('entityService')).getEntity(entityId.entityType, entityId.id)
480 .subscribe(function(data) {
481 console.log(data)
482 entitySubType = data.type;
483 console.log(entitySubType)
484 if (entitySubType == 'AQS01-dragino-office') {
485 openDashboardStates('aqs01_detail');
486 }else if (entitySubType == 'gateway') {
487 openDashboardStates('gateway_detail');
488 } else if (entitySubType == 'gxhl01') {
489 openDashboardStates('detail');
490
491 } else if (entitySubType == 'tank-type1') {
492 openDashboardStates('test1');
493 }
494 else if (entitySubType == 'LDS12') {
495 openDashboardStates('lds12_detail');
496 }
497 else if (entitySubType == 'LDS02') {
498 openDashboardStates('lds02_detail');
499 }
500 else if (entitySubType == 'SE01') {
501 openDashboardStates('se01_detail');
502 }
503 else if (entitySubType == 'PB01') {
504 openDashboardStates('pb01_detail');
505 }
506 else if (entitySubType == 'LWL02') {
507 openDashboardStates('lwl02_detail');
508 }
509 else if (entitySubType == 'LPS8N') {
510 openDashboardStates('lps8n_detail');
511 }
512 else if (entitySubType == 'LHT65N') {
513 openDashboardStates('lht65n_detail');
514 }
515 else if (entitySubType == 'S31b') {
516 openDashboardStates('s31b_detail');
517 }
518 });
519
520 function openDashboardStates(statedId) {
521 var stateParams = widgetContext.stateController.getStateParams();
522 //console.log(stateParams)
523 var params = {
524 entityId: entityId,
525 entityName: entityName
526 };
527 widgetContext.stateController.updateState(statedId, params, false);
528 }
529 {{/code}}
530
531 ==== ====
532
533 Add device:Implementation function: Add device
534
535 [[image:1730771441589-122.png]]
536
537 {{code language="none"}}
538 let $injector = widgetContext.$scope.$injector;
539 let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
540 let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
541 let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
542
543 openAddDeviceDialog();
544
545 function openAddDeviceDialog() {
546 customDialog.customDialog(htmlTemplate, AddDeviceDialogController).subscribe();
547 }
548
549 function AddDeviceDialogController(instance) {
550 let vm = instance;
551
552 vm.addDeviceFormGroup = vm.fb.group({
553 deviceName: ['', [vm.validators.required]],
554 deviceType: ['', [vm.validators.required]],
555 deviceLabel: [''],
556 attributes: vm.fb.group({
557 latitude: [null],
558 longitude: [null]
559 })
560 });
561
562 vm.cancel = function() {
563 vm.dialogRef.close(null);
564 };
565
566 vm.save = function() {
567 vm.addDeviceFormGroup.markAsPristine();
568 let device = {
569 name: vm.addDeviceFormGroup.get('deviceName').value,
570 type: vm.addDeviceFormGroup.get('deviceType').value,
571 label: vm.addDeviceFormGroup.get('deviceLabel').value
572 };
573 deviceService.saveDevice(device).subscribe(
574 function (device) {
575 saveAttributes(device.id).subscribe(
576 function () {
577 widgetContext.updateAliases();
578 vm.dialogRef.close(null);
579 }
580 );
581 }
582 );
583 };
584
585 function saveAttributes(entityId) {
586 let attributes = vm.addDeviceFormGroup.get('attributes').value;
587 let attributesArray = [];
588 for (let key in attributes) {
589 attributesArray.push({key: key, value: attributes[key]});
590 }
591 if (attributesArray.length > 0) {
592 return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray);
593 } else {
594 return widgetContext.rxjs.of([]);
595 }
596 }
597 }
598 {{/code}}
599
600 ==== ====
601
602 ===== **4.1.2.2.2 Asset Alarm:** =====
603
604 **Data:**
605
606 [[image:1730771504586-433.png]]
607
608 ==== 4.1.2.3、Configure the first layer menu interface ====
609
610 ===== 4.1.2.3.1 **Map:** =====
611
612 **Data:**
613
614 [[image:1730710271230-716.png||height="729" width="1427"]]
615
616 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
617
618 [[image:1730710850458-781.png||height="770" width="1429"]]
619
620 Select supermarket:Implementation function: Refresh the side page
621
622 {{code language="none"}}
623 var params = widgetContext.stateController.getStateParams();
624 var selectedSupermarket = params['selectedSupermarket'];
625 if (selectedSupermarket && selectedSupermarket.entityId.id === entityId.id) {
626 params['selectedSupermarket'] = null;
627 } else {
628 params['selectedSupermarket'] = { entityId: entityId, entityName: entityName, entityLabel: entityLabel };
629 }
630 widgetContext.stateController.updateState(null, params);
631 {{/code}}
632
633 [[image:1730710875401-848.png||height="767" width="1429"]]
634
635 Supermarket_detail:Implementation function: Jump to the asset details page
636
637 {{code language="none"}}
638 var params = JSON.parse(JSON.stringify(widgetContext.stateController.getStateParams()));
639 params['selectedSupermarket'] = {
640 entityId: entityId,
641 entityName: entityName,
642 entityLabel: entityLabel,
643 };
644 params['targetEntityParamName'] = 'selectedSupermarket';
645 params['selectedDevice'] = null;
646
647 widgetContext.stateController.openState('svgmap', params);
648 {{/code}}
649
650 [[image:1730710990334-601.png||height="772" width="1433"]]
651
652 * In this demo, exclusive map icons were set as follows:
653
654 {{code language="none"}}
655 var res = {
656 url: images[0],
657 size: 66
658 };
659 return res;
660 {{/code}}
661
662 [[image:1730710395303-672.png||height="771" width="1438"]]
663
664 ===== 4.1.2.3.1 Asset List: =====
665
666 **Data:**
667
668 [[image:1730710693066-349.png||height="772" width="1439"]]
669
670 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
671
672 [[image:1730712335338-750.png||height="751" width="1423"]]
673
674 [[image:1730712473941-913.png||height="781" width="1422"]]
675
676 All Alarms:
677
678 [[image:1730712539209-554.png||height="764" width="1424"]]
679
680 == 4.2 Alarm configuration details ==
681
682 == 4.3 Rule chain configuration details ==
683
684 = 5. =