Skip to content

Commit

Permalink
added fake widget; fix #SNRGY-3106
Browse files Browse the repository at this point in the history
  • Loading branch information
hahahannes committed Apr 9, 2024
1 parent a721684 commit 06b2148
Show file tree
Hide file tree
Showing 10 changed files with 368 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { WidgetModel } from '../shared/dashboard-widget.model';
import { DashboardTypesEnum } from '../shared/dashboard-types.enum';
import { Observable } from 'rxjs';
import { EnergyPredictionRequirementsService } from '../../../widgets/energy-prediction/shared/energy-prediction-requirements.service';
import { AuthorizationService } from 'src/app/core/services/authorization.service';

export interface Types {
value: string;
Expand Down Expand Up @@ -121,8 +122,13 @@ export class DashboardNewWidgetDialogComponent {
constructor(
private dialogRef: MatDialogRef<DashboardNewWidgetDialogComponent>,
private energyPredictionRequirementsService: EnergyPredictionRequirementsService,
private userService: AuthorizationService
) {
this.types.forEach((t) => this.checkRequirements(t));
const activeUserId = this.userService.getUserId();
if(activeUserId === 'aae7e87b-63a2-477f-afb4-caa0db84e3fa') {
this.types.push({ value: DashboardTypesEnum.FakeAnomalyDetection, viewValue: 'Fake Anomaly Detection', disabled: false, tooltip: '' });
}
}

activateCategory(): void {
Expand Down
4 changes: 2 additions & 2 deletions src/app/modules/dashboard/shared/dashboard-types.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ export enum DashboardTypesEnum {
DataTable = 'data_table',
AcControl = 'ac_control',
AnomalyDetection = 'anomaly_detection',
OpenWindow = 'open_window'

OpenWindow = 'open_window',
FakeAnomalyDetection = 'fake-anomaly'
}
3 changes: 1 addition & 2 deletions src/app/widgets/anomaly/anomaly.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@

<!-- e.g. network problem or 500 from timescale -->
<div *ngIf="error != null" class="text-container">
<h2>There was a problem loading the detection!</h2>
<h3>{{error}}</h3>
<h2>Data could not be loaded!</h2>
</div>

<div *ngIf="error == null">
Expand Down
36 changes: 36 additions & 0 deletions src/app/widgets/anomaly/fake/fake.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.mat-mdc-card {
width: 100%;
height: 100%;
box-sizing: border-box;
}

.mat-mdc-card-content {
height: calc(100% - 72px);
margin: 0;
overflow: hidden;
}

.outer-container {
height: 100%
}

.anomaly-container {
display: flex;
flex-direction: column;
align-items: center;
}

.text-container {
text-align: center;
}

mat-icon {
font-size: 40px;
}

.mat-icon {
height: 100%;
width: 100%;
}


92 changes: 92 additions & 0 deletions src/app/widgets/anomaly/fake/fake.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<!--
~ Copyright 2022 InfAI (CC SES)
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<mat-card appearance="outlined">
<senergy-widget-header [widget]="widget"></senergy-widget-header>
<mat-card-content>
<div id="{{widget.id}}" fxFill fxLayout="row" fxLayoutAlign="center center">
<div *ngIf="style === 'timeline'">
<timeline-chart *ngIf="chartDataReady" [data]="timelineChartData" [hAxisLabel]="'Zeit'" [vAxisLabel]="'c163d155'"
[enableToolbar]="false" [vAxes]="properties.vAxes" [width]="timelineWidth" [height]="timelineHeight">
</timeline-chart>
</div>
<div *ngIf="style === 'single'">
<div *ngIf="type === 'time'" class="anomaly-container">
<div>
<mat-icon>schedule</mat-icon>
</div>
<div>
<h2>Time between inputs was too long!</h2>
</div>
<div class="text-container">
<p><b>At:</b></p>
<p>{{timestamp | date:'medium'}}</p>
<p><b>Waiting time:</b></p>
<p>10 min.</p>
</div>

</div>

<div *ngIf="type === 'schema'" class="anomaly-container">
<div>
<mat-icon>schema</mat-icon>
</div>
<div>
<h2>Input data did not follow the schema!</h2>
</div>
<div class="text-container">
<p>Occured at {{timestamp | date:'medium'}}</p>
<p>Value: {{'{"status": "error"}'}}</p>
</div>
</div>

<div *ngIf="type === 'extreme_value'" class="anomaly-container">
<div>
<mat-icon>error</mat-icon>
</div>
<div>
<h2>Input is too high!</h2>
</div>
<div class="text-container">
<p>Occured at {{timestamp | date:'medium'}}</p>
<p>Value: {{value | number:'1.0-2'}}</p>
</div>
</div>

<div *ngIf="type === 'curve_anomaly'" class="anomaly-container">
<div>
<mat-icon>error</mat-icon>
</div>
<div>
<h2>An anomaly occured!</h2>
</div>
<div class="text-container">
<p><b>From</b></p>
<p>{{fromTimestamp | date:'medium'}}</p>
<p><b>To</b></p>
<p>{{toTimestamp | date:'medium'}}</p>
</div>
</div>
</div>
</div>


</mat-card-content>
<div>
<senergy-widget-footer [userHasDeleteAuthorization]="true" [dashboardId]="dashboardId" [widget]="widget">
</senergy-widget-footer>
</div>
</mat-card>
223 changes: 223 additions & 0 deletions src/app/widgets/anomaly/fake/fake.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import { AfterViewChecked, AfterViewInit, Component, HostListener, Input, OnInit } from '@angular/core';
import { ElementSizeService } from 'src/app/core/services/element-size.service';
import { ErrorHandlerService } from 'src/app/core/services/error-handler.service';
import { WidgetModel } from 'src/app/modules/dashboard/shared/dashboard-widget.model';
import { ChartsExportVAxesModel } from '../../charts/export/shared/charts-export-properties.model';
import { ChartsExportService } from '../../charts/export/shared/charts-export.service';
import { SingleValueService } from '../../single-value/shared/single-value.service';

@Component({
selector: 'fake-senergy-anomaly-detection',
templateUrl: './fake.component.html',
styleUrls: ['./fake.component.css']
})
export class FakeAnomalyComponent implements AfterViewChecked {
type = 'curve_anomaly'; //time, schema, curve_anomaly
style = '';

timestamp = new Date();
fromTimestamp? = '';
toTimestamp? = '';
value = '';
errorMessage = '';
@Input() dashboardId = '';
@Input() widget: WidgetModel = {} as WidgetModel;
timelineChartData: any = [];
chartDataReady = false;
timelineWidth = 500;
timelineHeight = 400;

initialized = false;

properties = {
exports: [{
id: '1ad3994f-c03f-4c7d-9b9c-eec1595fd7f9',
name: 'value',
values: [],
exportDatabaseId: 'urn:infai:ses:export-db:ac535dbb-4600-4b84-8660-2f40de034644'
}, {
id: 'f53512e9-8427-4d27-a55b-799c4ad418d8',
name: 'value',
values: [],
exportDatabaseId: 'urn:infai:ses:export-db:ac535dbb-4600-4b84-8660-2f40de034644'
}],
group: {
time: '5m',
type: 'mean'
},
time: {
last: '1d',
ahead: undefined,
start: undefined,
end: undefined
},
timeRangeType: 'relative',
vAxes: [{
instanceId: '1ad3994f-c03f-4c7d-9b9c-eec1595fd7f9',
exportName: '',
color: '',
math: '',
valueName: 'value',
valueType: '',
conversions: [{
from: '1',
to: '1',
color: '#AA4A44',
alias: 'auffällig'
}, {
from: '0',
to: '0',
color: '#50C878',
alias: 'normal'
}],
valueAlias: 'Temperatur'
}, {
instanceId: 'f53512e9-8427-4d27-a55b-799c4ad418d8',
exportName: '',
color: '',
math: '',
valueName: 'value',
valueType: '',
conversions: [{
from: '1',
to: '1',
color: '#AA4A44',
alias: 'auffällig'
}, {
from: '0',
to: '0',
color: '#50C878',
alias: 'normal'
}],
valueAlias: 'Druck'
}]
};

@HostListener('window:resize')
onResize() {
this.resize();
}

constructor(
private chartsExportService: ChartsExportService,
private errorHandlerService: ErrorHandlerService,
private elementSizeService: ElementSizeService,
) {}

ngAfterViewChecked(): void {
if(!this.initialized) {
//this.lastAnomaly();
this.timelineAnomalies();
this.initialized = true;
}

}

lastAnomaly() {
this.fromTimestamp = undefined;
this.toTimestamp = undefined;

this.chartsExportService.getData(this.properties).subscribe({
next: (resp) => {
const threshold = 100;
if (resp != null && this.errorHandlerService.checkIfErrorExists(resp)) {
this.errorMessage = 'No data';
} else if (resp != null) {
const data = resp[0][0];
data.sort((a,b) => new Date(b[0] as string).getTime() - new Date(a[0] as string).getTime());

let intervalFound = true;
for (let index = 0; index < data.length; index++) {
const row = data[index];
const currentValue = row[1];
const ts = row[0];
let prevTs = new Date().toDateString();
if(index > 0) {
const prevRow = data[index-1];
prevTs = prevRow[0];
}

if(currentValue > threshold && intervalFound) {
this.toTimestamp = ts;
intervalFound = false;
}
if(currentValue < threshold && !intervalFound) {
this.fromTimestamp = prevTs;
intervalFound = true;
}
}
this.style = 'single';
}
},
error: (_) => {
this.errorMessage = 'Error';
}
});
}

resize() {
const element = this.elementSizeService.getHeightAndWidthByElementId(this.widget.id, 5, 10);
this.timelineWidth = element.width;
this.timelineHeight = element.height;
}

parseSingleExportData(data: any, threshold: any) {
const chartData: any[] = [];

data.sort((a: any,b: any) => new Date(b[0] as string).getTime() - new Date(a[0] as string).getTime());

let intervalFound = true;
for (let index = 0; index < data.length; index++) {
const row = data[index];
const currentValue = row[1];
const ts = row[0];
let prevTs = new Date().toDateString();
if(index > 0) {
const prevRow = data[index-1];
prevTs = prevRow[0];
}

if(currentValue > threshold && intervalFound) {
chartData.push([ts, 1]);
intervalFound = false;
} else if(currentValue < threshold && !intervalFound) {
chartData.push([prevTs, 1]);
intervalFound = true;
} else if (intervalFound) {
chartData.push([ts, 0]);
} else if(!intervalFound && index === data.length -1) {
// anomaly at the beggining of the data history
chartData.push([ts, 1]);
}
}

console.log(chartData)

this.timelineChartData.push([chartData]);

}

timelineAnomalies() {
this.chartsExportService.getData(this.properties).subscribe({
next: (resp) => {
const threshold = 100;
if (resp != null && this.errorHandlerService.checkIfErrorExists(resp)) {
this.errorMessage = 'No data';
} else if (resp != null) {
const tempData = resp[0][0];
this.parseSingleExportData(tempData, 100);

const gasData = resp[0][1];
this.parseSingleExportData(gasData, 3);

this.resize();
this.chartDataReady = true;
this.style = 'timeline';
}
},
error: (_) => {
this.errorMessage = 'Error';
}
});
}
}
Loading

0 comments on commit 06b2148

Please sign in to comment.