Wiki source code of Demo for Smart Office, Factory

Version 23.1 by Hera Guo on 2024/11/06 10:50

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 ==== 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]]
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 jump:Implementation function: Jump to the device details page
470
471 [[image:1730771386258-676.png]]
472
473 {{code language="none"}}
474 console.log(entityName)
475 var entitySubType;
476 var $injector = widgetContext.$scope.$injector;
477 //console.log($injector)
478 $injector.get(widgetContext.servicesMap.get('entityService')).getEntity(entityId.entityType, entityId.id)
479 .subscribe(function(data) {
480 console.log(data)
481 entitySubType = data.type;
482 console.log(entitySubType)
483 if (entitySubType == 'AQS01-dragino-office') {
484 openDashboardStates('aqs01_detail');
485 }else if (entitySubType == 'gateway') {
486 openDashboardStates('gateway_detail');
487 } else if (entitySubType == 'gxhl01') {
488 openDashboardStates('detail');
489
490 } else if (entitySubType == 'tank-type1') {
491 openDashboardStates('test1');
492 }
493 else if (entitySubType == 'LDS12') {
494 openDashboardStates('lds12_detail');
495 }
496 else if (entitySubType == 'LDS02') {
497 openDashboardStates('lds02_detail');
498 }
499 else if (entitySubType == 'SE01') {
500 openDashboardStates('se01_detail');
501 }
502 else if (entitySubType == 'PB01') {
503 openDashboardStates('pb01_detail');
504 }
505 else if (entitySubType == 'LWL02') {
506 openDashboardStates('lwl02_detail');
507 }
508 else if (entitySubType == 'LPS8N') {
509 openDashboardStates('lps8n_detail');
510 }
511 else if (entitySubType == 'LHT65N') {
512 openDashboardStates('lht65n_detail');
513 }
514 else if (entitySubType == 'S31b') {
515 openDashboardStates('s31b_detail');
516 }
517 });
518
519 function openDashboardStates(statedId) {
520 var stateParams = widgetContext.stateController.getStateParams();
521 //console.log(stateParams)
522 var params = {
523 entityId: entityId,
524 entityName: entityName
525 };
526 widgetContext.stateController.updateState(statedId, params, false);
527 }
528 {{/code}}
529
530 (% class="wikigeneratedid" id="H-1" %)
531 Add device:Implementation function: Add device
532
533 [[image:1730771441589-122.png]]
534
535 {{code language="none"}}
536 let $injector = widgetContext.$scope.$injector;
537 let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
538 let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
539 let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
540
541 openAddDeviceDialog();
542
543 function openAddDeviceDialog() {
544 customDialog.customDialog(htmlTemplate, AddDeviceDialogController).subscribe();
545 }
546
547 function AddDeviceDialogController(instance) {
548 let vm = instance;
549
550 vm.addDeviceFormGroup = vm.fb.group({
551 deviceName: ['', [vm.validators.required]],
552 deviceType: ['', [vm.validators.required]],
553 deviceLabel: [''],
554 attributes: vm.fb.group({
555 latitude: [null],
556 longitude: [null]
557 })
558 });
559
560 vm.cancel = function() {
561 vm.dialogRef.close(null);
562 };
563
564 vm.save = function() {
565 vm.addDeviceFormGroup.markAsPristine();
566 let device = {
567 name: vm.addDeviceFormGroup.get('deviceName').value,
568 type: vm.addDeviceFormGroup.get('deviceType').value,
569 label: vm.addDeviceFormGroup.get('deviceLabel').value
570 };
571 deviceService.saveDevice(device).subscribe(
572 function (device) {
573 saveAttributes(device.id).subscribe(
574 function () {
575 widgetContext.updateAliases();
576 vm.dialogRef.close(null);
577 }
578 );
579 }
580 );
581 };
582
583 function saveAttributes(entityId) {
584 let attributes = vm.addDeviceFormGroup.get('attributes').value;
585 let attributesArray = [];
586 for (let key in attributes) {
587 attributesArray.push({key: key, value: attributes[key]});
588 }
589 if (attributesArray.length > 0) {
590 return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray);
591 } else {
592 return widgetContext.rxjs.of([]);
593 }
594 }
595 }
596 {{/code}}
597
598 ==== ====
599
600 ===== **4.1.2.2.3 Asset Alarm:** =====
601
602 **Data:**
603
604 [[image:1730771504586-433.png]]
605
606 ==== 4.1.2.3、Configure the first layer menu interface ====
607
608 ===== 4.1.2.3.1 **Map:** =====
609
610 **Data:**
611
612 [[image:1730710271230-716.png||height="729" width="1427"]]
613
614 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
615
616 [[image:1730710850458-781.png||height="770" width="1429"]]
617
618 Select supermarket:Implementation function: Refresh the side page
619
620 {{code language="none"}}
621 var params = widgetContext.stateController.getStateParams();
622 var selectedSupermarket = params['selectedSupermarket'];
623 if (selectedSupermarket && selectedSupermarket.entityId.id === entityId.id) {
624 params['selectedSupermarket'] = null;
625 } else {
626 params['selectedSupermarket'] = { entityId: entityId, entityName: entityName, entityLabel: entityLabel };
627 }
628 widgetContext.stateController.updateState(null, params);
629 {{/code}}
630
631 [[image:1730710875401-848.png||height="767" width="1429"]]
632
633 Supermarket_detail:Implementation function: Jump to the asset details page
634
635 {{code language="none"}}
636 var params = JSON.parse(JSON.stringify(widgetContext.stateController.getStateParams()));
637 params['selectedSupermarket'] = {
638 entityId: entityId,
639 entityName: entityName,
640 entityLabel: entityLabel,
641 };
642 params['targetEntityParamName'] = 'selectedSupermarket';
643 params['selectedDevice'] = null;
644
645 widgetContext.stateController.openState('svgmap', params);
646 {{/code}}
647
648 [[image:1730710990334-601.png||height="772" width="1433"]]
649
650 * In this demo, exclusive map icons were set as follows:
651
652 {{code language="none"}}
653 var res = {
654 url: images[0],
655 size: 66
656 };
657 return res;
658 {{/code}}
659
660 [[image:1730710395303-672.png||height="771" width="1438"]]
661
662 ===== 4.1.2.3.1 Asset List: =====
663
664 **Data:**
665
666 [[image:1730710693066-349.png||height="772" width="1439"]]
667
668 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
669
670 [[image:1730712335338-750.png||height="751" width="1423"]]
671
672 [[image:1730712473941-913.png||height="781" width="1422"]]
673
674 All Alarms:
675
676 [[image:1730712539209-554.png||height="764" width="1424"]]
677
678 == 4.2 Alarm configuration details ==
679
680 == 4.3 Rule chain configuration details ==
681
682 = 5. =