1 |
cbb91c90
|
hlavja
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
2 |
370c3423
|
hlavja
|
import {ActivatedRoute} from '@angular/router';
|
3 |
|
|
import {AnalyticsService} from '../../shared/api/endpoints/services/analytics.service';
|
4 |
ba41c963
|
hlavja
|
import {map, tap} from 'rxjs/operators';
|
5 |
b5525aef
|
hlavja
|
import {AggregationModel} from '../../shared/models/aggregationModel';
|
6 |
370c3423
|
hlavja
|
import * as moment from 'moment-timezone';
|
7 |
11efc186
|
hlavja
|
import {GraphLoader} from '../../shared/graph-loading/graphloader';
|
8 |
cd2a65f3
|
hlavja
|
import {SensorsService} from '../../shared/api/endpoints/services/sensors.service';
|
9 |
|
|
import {HttpResponse} from '@angular/common/http';
|
10 |
|
|
import {ToastService} from '../../shared/services/toast.service';
|
11 |
|
|
import {Sensor} from '../../shared/api/endpoints/models/sensor';
|
12 |
ba41c963
|
hlavja
|
import {ObservationService} from '../../shared/api/endpoints/services/observation.service';
|
13 |
cbb91c90
|
hlavja
|
import {SensorType} from '../../shared/api/endpoints/models/sensor-type';
|
14 |
|
|
import {Subscription} from 'rxjs';
|
15 |
370c3423
|
hlavja
|
|
16 |
|
|
|
17 |
|
|
@Component({
|
18 |
|
|
selector: 'app-unit',
|
19 |
|
|
templateUrl: './unit.component.html',
|
20 |
|
|
styleUrls: ['./unit.component.scss']
|
21 |
|
|
})
|
22 |
cbb91c90
|
hlavja
|
export class UnitComponent implements OnInit, OnDestroy {
|
23 |
370c3423
|
hlavja
|
|
24 |
|
|
preselectedSensors: string;
|
25 |
|
|
unitId: number;
|
26 |
8b522708
|
Štěpán Červenka
|
viewCount = 0;
|
27 |
cd2a65f3
|
hlavja
|
data = [];
|
28 |
|
|
time = [];
|
29 |
cbb91c90
|
hlavja
|
from: Date = moment().hour(0).minutes(0).subtract(7, 'days').toDate();
|
30 |
|
|
to: Date = moment().toDate();
|
31 |
|
|
today: Date = moment().toDate();
|
32 |
2b0d2514
|
hlavja
|
analyticsData: any[] = [];
|
33 |
|
|
observationsData: any[] = [];
|
34 |
11efc186
|
hlavja
|
sensorGroups = [];
|
35 |
b937b726
|
hlavja
|
selectedSensors: string[] = [];
|
36 |
cd2a65f3
|
hlavja
|
sensors: Sensor[];
|
37 |
|
|
showAggregation = false;
|
38 |
b5525aef
|
hlavja
|
aggregationFunction: AggregationModel[];
|
39 |
ba41c963
|
hlavja
|
selectedAggregationFunction = 'DAY';
|
40 |
|
|
useAnalyticsData = false;
|
41 |
cbb91c90
|
hlavja
|
dateChanged = false;
|
42 |
|
|
sensorTypes: SensorType[];
|
43 |
|
|
unitDescription: string;
|
44 |
|
|
subscription: Subscription[] = [];
|
45 |
370c3423
|
hlavja
|
|
46 |
|
|
constructor(
|
47 |
|
|
private activatedRoute: ActivatedRoute,
|
48 |
cd2a65f3
|
hlavja
|
private analyticsService: AnalyticsService,
|
49 |
|
|
private sensorService: SensorsService,
|
50 |
ba41c963
|
hlavja
|
private toastService: ToastService,
|
51 |
cbb91c90
|
hlavja
|
private observationService: ObservationService,
|
52 |
|
|
private route: ActivatedRoute,
|
53 |
370c3423
|
hlavja
|
) {
|
54 |
cbb91c90
|
hlavja
|
this.getInitData();
|
55 |
|
|
// get unit sensors and prepare them for view
|
56 |
ba41c963
|
hlavja
|
this.sensorService.getUnitSensors({unit_id: this.unitId}).pipe(
|
57 |
|
|
tap(sens => {
|
58 |
|
|
this.sensors = sens;
|
59 |
b937b726
|
hlavja
|
this.sensors.sort((a, b) => a.sensorId - b.sensorId);
|
60 |
ba41c963
|
hlavja
|
}),
|
61 |
|
|
tap(() => {
|
62 |
|
|
if (this.sensors && this.sensors.length > 0) {
|
63 |
|
|
this.sensors.forEach(sensor => {
|
64 |
b5525aef
|
hlavja
|
const sensorType = sensor.sensorId.toString().slice(0, 5);
|
65 |
cbb91c90
|
hlavja
|
if (!this.sensorGroups.some(group => group === sensorType)) { // create sensor groups only for unit sensors
|
66 |
cd2a65f3
|
hlavja
|
this.sensorGroups.push(sensorType);
|
67 |
2b0d2514
|
hlavja
|
setTimeout(() => {
|
68 |
cbb91c90
|
hlavja
|
GraphLoader.getGraph(null, null, null, '#vega_container_' + sensor.sensorId.toString().slice(0, 5),null);
|
69 |
2b0d2514
|
hlavja
|
}, 0);
|
70 |
cd2a65f3
|
hlavja
|
}
|
71 |
a769e543
|
hlavja
|
});
|
72 |
cd2a65f3
|
hlavja
|
}
|
73 |
ba41c963
|
hlavja
|
})
|
74 |
|
|
).toPromise().then();
|
75 |
370c3423
|
hlavja
|
}
|
76 |
|
|
|
77 |
cbb91c90
|
hlavja
|
/**
|
78 |
|
|
* Unsubscribe after leaving
|
79 |
|
|
*/
|
80 |
|
|
ngOnDestroy(): void {
|
81 |
|
|
this.subscription.forEach(subs => subs.unsubscribe());
|
82 |
370c3423
|
hlavja
|
}
|
83 |
|
|
|
84 |
cbb91c90
|
hlavja
|
/**
|
85 |
|
|
* Sets up default data
|
86 |
|
|
*/
|
87 |
|
|
getInitData() {
|
88 |
|
|
this.route.queryParams.subscribe(params => {
|
89 |
|
|
if(params.unitDescription) {
|
90 |
|
|
this.unitDescription = params.unitDescription;
|
91 |
|
|
}
|
92 |
|
|
});
|
93 |
|
|
this.sensorService.getSensorTypes().toPromise().then(types => this.sensorTypes = types);
|
94 |
|
|
this.unitId = parseInt(this.activatedRoute.snapshot.paramMap.get('unitId'), 10);
|
95 |
|
|
this.aggregationFunction = [
|
96 |
|
|
{name: 'Hour', code: 'HOUR'},
|
97 |
|
|
{name: 'Day', code: 'DAY'},
|
98 |
|
|
{name: 'Month', code: 'MONTH'},
|
99 |
|
|
{name: 'Year', code: 'YEAR'}
|
100 |
|
|
];
|
101 |
|
|
}
|
102 |
cd2a65f3
|
hlavja
|
|
103 |
cbb91c90
|
hlavja
|
ngOnInit(): void {
|
104 |
|
|
}
|
105 |
cd2a65f3
|
hlavja
|
|
106 |
cbb91c90
|
hlavja
|
/**
|
107 |
|
|
* Shows aggregation select box and get data button
|
108 |
|
|
*/
|
109 |
|
|
aggregationShow() {
|
110 |
|
|
this.dateChanged = true;
|
111 |
|
|
this.showAggregation = moment(this.to).diff(moment(this.from), 'days') > 7;
|
112 |
|
|
}
|
113 |
370c3423
|
hlavja
|
|
114 |
cbb91c90
|
hlavja
|
/**
|
115 |
|
|
* Gets data based on selected time range
|
116 |
|
|
*/
|
117 |
|
|
showGraph(changedDate: boolean = true, changedSensor: string = null) {
|
118 |
|
|
if (moment(this.to).diff(moment(this.from), 'days') > 7) {
|
119 |
ba41c963
|
hlavja
|
this.useAnalyticsData = true;
|
120 |
cd2a65f3
|
hlavja
|
this.showAggregation = true;
|
121 |
cbb91c90
|
hlavja
|
const range: Date[] = [this.from, this.to];
|
122 |
ba41c963
|
hlavja
|
this.getAnalytics(range, changedDate, changedSensor);
|
123 |
cd2a65f3
|
hlavja
|
} else {
|
124 |
ba41c963
|
hlavja
|
this.useAnalyticsData = false;
|
125 |
cd2a65f3
|
hlavja
|
this.showAggregation = false;
|
126 |
cbb91c90
|
hlavja
|
const range: Date[] = [this.from, this.to];
|
127 |
ba41c963
|
hlavja
|
this.getObservations(range, changedDate, changedSensor);
|
128 |
370c3423
|
hlavja
|
}
|
129 |
cd2a65f3
|
hlavja
|
}
|
130 |
370c3423
|
hlavja
|
|
131 |
cbb91c90
|
hlavja
|
/**
|
132 |
|
|
* Gets data from analytics endpoint
|
133 |
|
|
* @param range from and to interval
|
134 |
|
|
* @param changedDate determines if dates changed so we need refresh all data
|
135 |
|
|
* @param changedSensorId if selecting sensor only fetch data for this server
|
136 |
|
|
*/
|
137 |
|
|
getAnalytics(range: Date[], changedDate: boolean, changedSensorId: string) {
|
138 |
|
|
if (changedDate) { // if changed date we need new data for all sensors
|
139 |
ba41c963
|
hlavja
|
this.selectedSensors.forEach(selectSens => {
|
140 |
6842a0b0
|
Štěpán Červenka
|
this.analyticsData = []; //empty analytics data
|
141 |
cbb91c90
|
hlavja
|
this.analyticsEndpointRequest(selectSens, range);
|
142 |
ba41c963
|
hlavja
|
});
|
143 |
cbb91c90
|
hlavja
|
} else { // add data for selected sensor
|
144 |
|
|
this.analyticsEndpointRequest(changedSensorId, range);
|
145 |
|
|
}
|
146 |
|
|
}
|
147 |
|
|
|
148 |
|
|
/**
|
149 |
|
|
* Endpoint request to get analytics data for sensor
|
150 |
|
|
* @param sensorId sensor id to get data
|
151 |
|
|
* @param range from and to interval
|
152 |
|
|
*/
|
153 |
|
|
analyticsEndpointRequest(sensorId: string, range: Date[]) {
|
154 |
|
|
this.analyticsService.getAnalytics$Response({unit_id: this.unitId, sensor_id: parseInt(sensorId, 10),
|
155 |
|
|
from: moment(range[0]).format('yyyy-MM-DD HH:mm:ssZ').slice(0, -3),
|
156 |
|
|
to: moment(range[1]).format('yyyy-MM-DD HH:mm:ssZ').slice(0, -3), interval: this.selectedAggregationFunction}).pipe(
|
157 |
|
|
map((response: HttpResponse<any>) => {
|
158 |
|
|
if (response.status === 200) {
|
159 |
|
|
return response.body;
|
160 |
|
|
} else if (response.status === 204) {
|
161 |
|
|
this.toastService.showWarningNoData();
|
162 |
|
|
return response.body;
|
163 |
|
|
} else {
|
164 |
|
|
return false;
|
165 |
|
|
}
|
166 |
|
|
})
|
167 |
|
|
).subscribe(data => {
|
168 |
|
|
if (data) {
|
169 |
6842a0b0
|
Štěpán Červenka
|
this.analyticsData.push({sensorId, data: data[sensorId].data, interval: data[sensorId].interval,
|
170 |
|
|
sensor: this.sensors.find(sens => sens.sensorId.toString() === sensorId.toString())});
|
171 |
cbb91c90
|
hlavja
|
if (data[sensorId].data) {
|
172 |
|
|
const groupId = sensorId.slice(0, 5);
|
173 |
|
|
const view = '#vega_container_' + groupId;
|
174 |
|
|
if (this.selectedSensors.some(sens => sens.toString() === sensorId)) {
|
175 |
|
|
// GraphLoader.getAnalyticsGraph(key, data[key].data, data[key].interval, view);
|
176 |
6842a0b0
|
Štěpán Červenka
|
GraphLoader.getGraphWithInterval(this.filteredSelectedSensors(groupId), this.filteredAnalyticsData(groupId), this.filteredAnalyticsData(groupId)[0]['interval'] * 1000, this.filteredSensorsInfos(groupId)[0], view, true);
|
177 |
ba41c963
|
hlavja
|
} else {
|
178 |
cbb91c90
|
hlavja
|
// GraphLoader.getAnalyticsGraph(null, null, null, view);
|
179 |
|
|
GraphLoader.getGraph(null, null, null, view, null);
|
180 |
cd2a65f3
|
hlavja
|
}
|
181 |
|
|
}
|
182 |
cbb91c90
|
hlavja
|
}
|
183 |
|
|
}, err => this.toastService.showError(err.error.message));
|
184 |
2b0d2514
|
hlavja
|
}
|
185 |
|
|
|
186 |
a769e543
|
hlavja
|
/**
|
187 |
|
|
* Check button handler.
|
188 |
|
|
* @param sensorId checked sensorId
|
189 |
|
|
* @param event event for getting if checked or unchecked
|
190 |
|
|
*/
|
191 |
b937b726
|
hlavja
|
addSensorToGraph(sensorId: string, event) {
|
192 |
a769e543
|
hlavja
|
const groupId = sensorId.toString().slice(0, 5);
|
193 |
|
|
const sensorGroupElement = '#vega_container_' + groupId;
|
194 |
|
|
if (!this.selectedSensors.find(sensId => sensId.toString().slice(0, 5) === groupId)) { // if group of sensors is empty show empty graph
|
195 |
05d4a2a9
|
hlavja
|
// GraphLoader.getAnalyticsGraph(null, null, null, sensorGroupElement);
|
196 |
66c042f1
|
Štěpán Červenka
|
GraphLoader.getGraph(null, null, null, sensorGroupElement, null);
|
197 |
ba41c963
|
hlavja
|
} else {
|
198 |
a769e543
|
hlavja
|
if (this.useAnalyticsData) { // use analytics data
|
199 |
|
|
if (event.checked) { // if checked > add to graph
|
200 |
|
|
if (this.analyticsData.some(sens => sens.sensorId === sensorId)) { // if already data for selected sensor in memory
|
201 |
05d4a2a9
|
hlavja
|
// GraphLoader.getAnalyticsGraph(sensorId, this.analyticsData.find(sens => sens.sensorId === sensorId).data,
|
202 |
8cca41c0
|
Štěpán Červenka
|
// this.analyticsData.find((sens => sens.sensorId === sensorId).interval, sensorGroupElement);
|
203 |
6842a0b0
|
Štěpán Červenka
|
//GraphLoader.getGraph(this.selectedSensors, this.analyticsData, this.filteredSensorsInfos(groupId), sensorGroupElement, true);
|
204 |
|
|
GraphLoader.getGraphWithInterval(this.filteredSelectedSensors(groupId), this.filteredAnalyticsData(groupId), this.filteredAnalyticsData(groupId)[0]['interval'] * 1000, this.filteredSensorsInfos(groupId)[0], sensorGroupElement, true);
|
205 |
8cca41c0
|
Štěpán Červenka
|
|
206 |
a769e543
|
hlavja
|
} else { // get data from server for added sensor and show graph for selected sensors
|
207 |
|
|
this.showGraph(false, sensorId);
|
208 |
|
|
}
|
209 |
|
|
} else { // remove sensor from graph
|
210 |
05d4a2a9
|
hlavja
|
// GraphLoader.getAnalyticsGraph(sensorId, this.analyticsData.find(sens => sens.sensorId === sensorId).data,
|
211 |
8cca41c0
|
Štěpán Červenka
|
// this.analyticsData.find(sens => sens.sensorId === sensorId).interval, sensorGroupElement);
|
212 |
6842a0b0
|
Štěpán Červenka
|
GraphLoader.getGraphWithInterval(this.filteredSelectedSensors(groupId), this.filteredAnalyticsData(groupId), this.filteredAnalyticsData(groupId)[0]['interval'] * 1000, this.filteredSensorsInfos(groupId)[0], sensorGroupElement, true);
|
213 |
8cca41c0
|
Štěpán Červenka
|
|
214 |
ba41c963
|
hlavja
|
}
|
215 |
a769e543
|
hlavja
|
} else { // use observations data
|
216 |
|
|
if (event.checked) { // if checked > add to graph
|
217 |
b937b726
|
hlavja
|
if (this.observationsData.some(sens => sens.sensorId.toString() === sensorId)) { // if already data for selected sensor in memory
|
218 |
05d4a2a9
|
hlavja
|
GraphLoader.getGraph(this.filteredSelectedSensors(groupId), this.filteredObservationData(groupId),
|
219 |
|
|
this.filteredSensorsInfos(groupId), sensorGroupElement, false);
|
220 |
a769e543
|
hlavja
|
} else { // get data from server for added sensor and show graph for selected sensors
|
221 |
|
|
this.showGraph(false, sensorId);
|
222 |
|
|
}
|
223 |
|
|
} else { // remove sensor from graph
|
224 |
cbb91c90
|
hlavja
|
GraphLoader.getGraph(this.filteredSelectedSensors(groupId), this.filteredObservationData(groupId),
|
225 |
05d4a2a9
|
hlavja
|
this.filteredSensorsInfos(groupId), sensorGroupElement, false);
|
226 |
2b0d2514
|
hlavja
|
}
|
227 |
|
|
}
|
228 |
|
|
}
|
229 |
8b522708
|
Štěpán Červenka
|
}
|
230 |
ba41c963
|
hlavja
|
|
231 |
a769e543
|
hlavja
|
/**
|
232 |
|
|
* Filter observations data only fro selected sensors.
|
233 |
|
|
* @param sensorGroupId id of changed sensor group
|
234 |
|
|
*/
|
235 |
|
|
filteredObservationData(sensorGroupId: string): any {
|
236 |
|
|
return this.observationsData.filter(sen => this.selectedSensors.includes(sen.sensorId.toString()) &&
|
237 |
|
|
sen.sensorId.toString().slice(0, 5) === sensorGroupId);
|
238 |
|
|
}
|
239 |
|
|
|
240 |
|
|
/**
|
241 |
|
|
* Filter analytics data only fro selected sensors.
|
242 |
|
|
*/
|
243 |
8cca41c0
|
Štěpán Červenka
|
filteredAnalyticsData(sensorGroupId: string): any {
|
244 |
|
|
return this.analyticsData.filter(sen => this.selectedSensors.includes(sen.sensorId.toString()) &&
|
245 |
|
|
sen.sensorId.toString().slice(0, 5) === sensorGroupId);
|
246 |
a769e543
|
hlavja
|
}
|
247 |
|
|
|
248 |
cbb91c90
|
hlavja
|
/**
|
249 |
|
|
* Filter only selected sensors for group of sensors
|
250 |
|
|
* @param sensorGroupId group of sensors
|
251 |
|
|
*/
|
252 |
66c042f1
|
Štěpán Červenka
|
filteredSelectedSensors(sensorGroupId: string): any {
|
253 |
cbb91c90
|
hlavja
|
return this.selectedSensors.filter(sen => sen.toString().slice(0, 5) === sensorGroupId);
|
254 |
66c042f1
|
Štěpán Červenka
|
}
|
255 |
|
|
|
256 |
cbb91c90
|
hlavja
|
/**
|
257 |
|
|
* Get sensors only for group
|
258 |
|
|
* @param sensorGroupId group id
|
259 |
|
|
*/
|
260 |
66c042f1
|
Štěpán Červenka
|
filteredSensorsInfos(sensorGroupId: string): any {
|
261 |
|
|
return this.sensors.filter(sen => this.selectedSensors.includes(sen.sensorId.toString()) &&
|
262 |
05d4a2a9
|
hlavja
|
sen.sensorId.toString().slice(0, 5) === sensorGroupId);
|
263 |
66c042f1
|
Štěpán Červenka
|
}
|
264 |
|
|
|
265 |
cbb91c90
|
hlavja
|
/**
|
266 |
|
|
* Gets data from observation endpoint
|
267 |
|
|
* @param range from and to interval
|
268 |
|
|
* @param changedDate determines if dates changed so we need refresh all data
|
269 |
|
|
* @param changedSensorId if selecting sensor only fetch data for this server
|
270 |
|
|
*/
|
271 |
|
|
getObservations(range: Date[], changedDate: boolean, changedSensorId: string) {
|
272 |
a769e543
|
hlavja
|
if (changedDate) { // if changed date we need new data for all sensors
|
273 |
|
|
this.observationsData = []; // empty observation data
|
274 |
ba41c963
|
hlavja
|
this.selectedSensors.forEach(selectSens => {
|
275 |
cbb91c90
|
hlavja
|
this.observationEndpointRequest(selectSens, range);
|
276 |
ba41c963
|
hlavja
|
});
|
277 |
cbb91c90
|
hlavja
|
} else { // add data for added sensor
|
278 |
|
|
this.observationEndpointRequest(changedSensorId, range);
|
279 |
ba41c963
|
hlavja
|
}
|
280 |
|
|
}
|
281 |
cbb91c90
|
hlavja
|
|
282 |
|
|
/**
|
283 |
|
|
* Endpoint request to get observation data for sensor
|
284 |
|
|
* @param sensorId sensor id to get data
|
285 |
|
|
* @param range from and to interval
|
286 |
|
|
*/
|
287 |
|
|
observationEndpointRequest(sensorId: string, range: Date[]) {
|
288 |
|
|
this.observationService.getObservation$Response({
|
289 |
|
|
unit_id: this.unitId,
|
290 |
|
|
sensor_id: parseInt(sensorId, 10),
|
291 |
|
|
from: moment(range[0]).format('yyyy-MM-DD HH:mm:ssZ').slice(0, -3),
|
292 |
|
|
to: moment(range[1]).format('yyyy-MM-DD HH:mm:ssZ').slice(0, -3)
|
293 |
|
|
}).pipe(
|
294 |
|
|
map((response: HttpResponse<any>) => {
|
295 |
|
|
if (response.status === 200) {
|
296 |
|
|
return response.body;
|
297 |
|
|
} else if (response.status === 204) {
|
298 |
|
|
this.toastService.showWarningNoData();
|
299 |
|
|
return response.body;
|
300 |
|
|
} else {
|
301 |
|
|
return false;
|
302 |
|
|
}
|
303 |
|
|
})
|
304 |
|
|
).subscribe(
|
305 |
|
|
observations => {
|
306 |
|
|
if (observations) {
|
307 |
|
|
const groupId = sensorId.toString().slice(0, 5);
|
308 |
|
|
this.observationsData.push({
|
309 |
|
|
sensorId, sensor:
|
310 |
|
|
this.sensors.find(sens => sens.sensorId.toString() === sensorId.toString()), data: observations
|
311 |
|
|
});
|
312 |
|
|
const view = '#vega_container_' + sensorId.toString().slice(0, 5);
|
313 |
|
|
GraphLoader.getGraph(this.filteredSelectedSensors(groupId), this.filteredObservationData(groupId),
|
314 |
|
|
this.filteredSensorsInfos(groupId), view, false);
|
315 |
|
|
}
|
316 |
|
|
}, err => this.toastService.showError(err.error.message));
|
317 |
|
|
}
|
318 |
370c3423
|
hlavja
|
}
|