Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: FlatWidget for Storage #1445

Merged
merged 50 commits into from
May 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
eb7cec3
autarchy
lukasrgr Apr 14, 2021
71767f8
fix import
lukasrgr Apr 14, 2021
e96cd85
reduce code-length
lukasrgr Apr 14, 2021
e0d01b3
revert deleting line this.ouputchannel
lukasrgr Apr 15, 2021
1b8d4d2
no message
lukasrgr Apr 15, 2021
55ec04a
refactored calculateAutarchy
lukasrgr Apr 15, 2021
5462823
refactored calculateAutarchy() 2
lukasrgr Apr 15, 2021
272ae97
refactored caluclateAutarchy() 3
lukasrgr Apr 15, 2021
d09ed37
refactored calculateAutarchy() 4
lukasrgr Apr 15, 2021
ad67b34
> refactored autarchy title
lukasrgr Apr 15, 2021
e46a69b
Review
sfeilmeier Apr 15, 2021
2127973
Generic Widget for Storage
lukasrgr Apr 15, 2021
628fc95
Merge remote-tracking branch 'origin/develop' into feature/flatwidget…
lukasrgr Apr 15, 2021
f10a675
Style text-underline
lukasrgr Apr 15, 2021
65b5531
> move storage in /common
lukasrgr Apr 16, 2021
e730755
> updated imports
lukasrgr Apr 19, 2021
bfeaa33
reverting some imports
lukasrgr Apr 19, 2021
9c28fbf
revert import ng-cookie-service
lukasrgr Apr 20, 2021
c577eb3
> service.ts import changes 2
lukasrgr Apr 20, 2021
7165f8e
update chageWattInKiloWatt
lukasrgr Apr 20, 2021
37f99b1
> refactor changeWattInKiloWatt to convertWattToKiloWatt, update imports
lukasrgr Apr 20, 2021
457bd6d
> implemented convertCharge, convertDischarge
lukasrgr Apr 21, 2021
42c624e
> removed unnecessary logic
lukasrgr Apr 21, 2021
2472c50
> reduced code
lukasrgr Apr 21, 2021
bae1c70
> reduced code 2
lukasrgr Apr 21, 2021
6fd9ae8
no message
lukasrgr Apr 21, 2021
52c1dc5
> refactored converters
lukasrgr Apr 21, 2021
cffff93
Merge branch 'develop' into feature/flatwidget_for_more_complex_widgets
lukasrgr Apr 21, 2021
3f52f97
> refactored converter
lukasrgr Apr 21, 2021
cba83dd
Merge branch 'feature/flatwidget_for_more_complex_widgets' of https:/…
lukasrgr Apr 21, 2021
a23d92e
> show storageSystem only when StateOfCharge not null
lukasrgr Apr 22, 2021
c166f82
> commented converter
lukasrgr Apr 22, 2021
5b5280f
no message
lukasrgr Apr 22, 2021
db2f703
> conflicting files
lukasrgr Apr 22, 2021
f03bdab
Revert "> conflicting files"
lukasrgr Apr 22, 2021
4d6d3fd
> import FlatwidgetHorizontalLine
lukasrgr Apr 23, 2021
9b2ee84
new flat-widget-horizontal-line
lukasrgr Apr 23, 2021
34daaa7
no message
lukasrgr Apr 23, 2021
bb7d683
Merge remote-tracking branch 'origin/develop' into feature/flatwidget…
lukasrgr Apr 23, 2021
caf39b7
> commented
lukasrgr Apr 23, 2021
82f1873
> called boolean-Array instead of calling function for better perform…
lukasrgr Apr 28, 2021
438d5a8
> reduced isHybridEss
lukasrgr Apr 28, 2021
6f31b04
> removed log
lukasrgr Apr 28, 2021
1ef7f0f
Review + add comments
sfeilmeier May 3, 2021
908562b
Merge branch 'develop' into feature/flatwidget_for_more_complex_widgets
sfeilmeier May 3, 2021
15cb69a
Move method to Utils
sfeilmeier May 3, 2021
18a6037
Review
sfeilmeier May 3, 2021
f0d84dd
Remove isInitialized for flat-widget-line
sfeilmeier May 3, 2021
a6a7896
Reset service.ts
sfeilmeier May 3, 2021
b656991
Reset environment to develop
sfeilmeier May 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -9,6 +9,7 @@ import { TranslateService } from '@ngx-translate/core';
})
export class StorageModalComponent {

// TODO after refactoring of Model: subscribe to EssActivePowerL1/L2/L3 here instead of Flat Widget

@Input() edge: Edge;
@Input() config: EdgeConfig;
Expand Down
36 changes: 36 additions & 0 deletions ui/src/app/edge/live/common/storage/storage.component.html
@@ -0,0 +1,36 @@
<oe-flat-widget [img]="storageItem" [title]="'General.storageSystem'| translate" (click)="presentModal()">
<ng-container *ngFor="let component of essComponents, let i = index">
<!-- Show Alias if there are more than one ESS -->
<ng-container *ngIf="essComponents.length > 1">
<oe-flat-widget-line [name]="component.alias">
</oe-flat-widget-line>
</ng-container>

<oe-flat-widget-percentagebar [channelAddress]="component.id + '/Soc'">
</oe-flat-widget-percentagebar>

<ng-container *ngIf="!isHybridEss[component.id], else HybridEss">
<!-- For AC system: show ActivePower channel -->
<oe-flat-widget-line [name]="'General.chargePower' | translate"
[channelAddress]="component.id + '/ActivePower'" [converter]="convertChargePower">
</oe-flat-widget-line>
<oe-flat-widget-line [name]="'General.dischargePower' | translate"
[channelAddress]="component.id + '/ActivePower'" [converter]="convertDischargePower">
</oe-flat-widget-line>
</ng-container>

<ng-template #HybridEss>
<!-- For DC/hybrid system: show DcDischargePower channel -->
<oe-flat-widget-line [name]="'General.chargePower' | translate"
[channelAddress]="component.id + '/DcDischargePower'" [converter]="convertChargePower">
</oe-flat-widget-line>
<oe-flat-widget-line [name]="'General.dischargePower' | translate"
[channelAddress]="component.id + '/DcDischargePower'" [converter]="convertDischargePower">
</oe-flat-widget-line>
</ng-template>

<oe-flat-widget-horizontal-line [components]="essComponents" [index]="i">
</oe-flat-widget-horizontal-line>

</ng-container>
</oe-flat-widget>
132 changes: 132 additions & 0 deletions ui/src/app/edge/live/common/storage/storage.component.ts
@@ -0,0 +1,132 @@
import { formatNumber } from '@angular/common';
import { Component } from '@angular/core';
import { CurrentData } from "src/app/shared/shared";
import { ChannelAddress, EdgeConfig, Utils } from '../../../../shared/shared';
import { AbstractFlatWidget } from '../../flat/abstract-flat-widget';
import { StorageModalComponent } from './modal/modal.component';

@Component({
selector: 'storage',
templateUrl: './storage.component.html'
})
export class StorageComponent extends AbstractFlatWidget {

public essComponents: EdgeConfig.Component[] = [];
public chargerComponents: EdgeConfig.Component[] = [];
lukasrgr marked this conversation as resolved.
Show resolved Hide resolved
public storageItem: string = null;
public isHybridEss: boolean[] = [];

protected getChannelAddresses() {
let channelAddresses: ChannelAddress[] = [
new ChannelAddress('_sum', 'EssSoc')
];

// Get Chargers
// TODO should be moved to Modal
this.chargerComponents = this.config
.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger")
.filter(component => component.isEnabled);
for (let component of this.chargerComponents) {
channelAddresses.push(
new ChannelAddress(component.id, 'ActualPower'),
)
}

// Get ESSs
this.essComponents = this.config
.getComponentsImplementingNature("io.openems.edge.ess.api.SymmetricEss")
.filter(component => component.isEnabled && !this.config
.getNatureIdsByFactoryId(component.factoryId)
.includes("io.openems.edge.ess.api.MetaEss"));

for (let component of this.config
.getComponentsImplementingNature("io.openems.edge.ess.api.SymmetricEss")
.filter(component => component.isEnabled && !this.config
.getNatureIdsByFactoryId(component.factoryId)
.includes("io.openems.edge.ess.api.MetaEss"))) {

// Check if essComponent is HybridEss
this.isHybridEss[component.id] = this.config
.getNatureIdsByFactoryId(component.factoryId)
.includes("io.openems.edge.ess.api.HybridEss");

channelAddresses.push(
new ChannelAddress(component.id, 'Soc'),
new ChannelAddress(component.id, 'Capacity'),
);
if (this.config.factories[component.factoryId].natureIds.includes("io.openems.edge.ess.api.AsymmetricEss")) {
channelAddresses.push(
new ChannelAddress(component.id, 'ActivePowerL1'),
new ChannelAddress(component.id, 'ActivePowerL2'),
new ChannelAddress(component.id, 'ActivePowerL3')
);
}
}
return channelAddresses
}

protected onCurrentData(currentData: CurrentData) {
// Check total State_of_Charge for dynamical icon in widget-header
let soc = currentData.allComponents['_sum/EssSoc'];
this.storageItem = "assets/img/" + Utils.getStorageSocImage(soc);
}

/**
* Use 'convertChargePower' to convert/map a value
*
* @param value takes @Input value or channelAddress for chargePower
* @returns value
*/
public convertChargePower = (value: any): string => {
return this.convertPower(Utils.multiplySafely(value, -1), true);
}

/**
* Use 'convertDischargePower' to convert/map a value
*
* @param value takes @Input value or channelAddress for dischargePower
* @returns value
*/
public convertDischargePower = (value: any): string => {
return this.convertPower(value)
}

/**
* Use 'convertPower' to check whether 'charge/discharge' and to be only showed when not negative
*
* @param value takes passed value when called
* @returns only positive and 0
*/
public convertPower(value: number, isCharge?: boolean) {
if (value == null) {
return '-';
}

let thisValue: number = (value / 1000);

// Round thisValue to Integer when decimal place equals 0
if (thisValue > 0) {
return formatNumber(thisValue, 'de', '1.0-1') + " kW"; // TODO get locale dynamically

} else if (thisValue == 0 && isCharge) {
// if thisValue is 0, then show only when charge and not discharge
return '0 kW';

} else {
return '-'
}
}

async presentModal() {
const modal = await this.modalController.create({
component: StorageModalComponent,
componentProps: {
edge: this.edge,
config: this.config,
essComponents: this.essComponents,
chargerComponents: this.chargerComponents,
}
});
return await modal.present();
}
}
@@ -1,10 +1,10 @@
import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from './abstractsection.component';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { Component, OnDestroy } from '@angular/core';
import { DefaultTypes } from '../../../../../shared/service/defaulttypes';
import { Service, Utils } from '../../../../../shared/shared';
import { TranslateService } from '@ngx-translate/core';
import { trigger, state, style, animate, transition } from '@angular/animations';
import { UnitvaluePipe } from 'src/app/shared/pipe/unitvalue/unitvalue.pipe';
import { DefaultTypes } from '../../../../../shared/service/defaulttypes';
import { Service, Utils } from '../../../../../shared/shared';
import { AbstractSection, EnergyFlow, Ratio, SvgEnergyFlow, SvgSquare, SvgSquarePosition } from './abstractsection.component';

@Component({
selector: '[storagesection]',
Expand Down Expand Up @@ -148,29 +148,7 @@ export class StorageSectionComponent extends AbstractSection implements OnDestro
}

protected getImagePath(): string {
if (this.socValue < 11) {
return "storage_10_monitor.png"
} else if (this.socValue < 21) {
return "storage_20_monitor.png"
} else if (this.socValue < 31) {
return "storage_30_monitor.png"
} else if (this.socValue < 41) {
return "storage_40_monitor.png"
} else if (this.socValue < 51) {
return "storage_50_monitor.png"
} else if (this.socValue < 61) {
return "storage_60_monitor.png"
} else if (this.socValue < 71) {
return "storage_70_monitor.png"
} else if (this.socValue < 81) {
return "storage_80_monitor.png"
} else if (this.socValue < 91) {
return "storage_90_monitor.png"
} else if (this.socValue < 101) {
return "storage_100_monitor.png"
} else {
return "storage_empty_monitor.png"
}
return Utils.getStorageSocImage(this.socValue);
}

protected getValueText(value: number): string {
Expand Down
Expand Up @@ -9,11 +9,6 @@ import { ChannelAddress, Edge, Service, Websocket } from "src/app/shared/shared"
@Directive()
export abstract class AbstractFlatWidgetLine implements OnDestroy {

/**
* True after this.edge, this.config and this.component are set.
*/
public isInitialized: boolean = false;

/**
* Use `converter` to convert/map a CurrentData value to another value, e.g. an Enum number to a text.
*
Expand Down Expand Up @@ -45,12 +40,9 @@ export abstract class AbstractFlatWidgetLine implements OnDestroy {

protected setValue(value: any) {
this.displayValue = this.converter(value);

// announce initialized
this.isInitialized = true;
}

protected subscribe(channelAddress?: ChannelAddress) {
protected subscribe(channelAddress: ChannelAddress) {
this.service.setCurrentComponent('', this.route).then(edge => {
this.edge = edge;

Expand Down
@@ -0,0 +1,3 @@
<div *ngIf="index != (components.length - 1)"
style="border-bottom: 1px solid lightgray; width: 110%; margin-top: 2%; margin-bottom: 2%; margin-left: -5%;">
</div>
@@ -0,0 +1,15 @@
import { Component, Input } from "@angular/core";

/**
* Shows a horizontal line on all but the last entry of a flat widget.
*/
@Component({
selector: 'oe-flat-widget-horizontal-line',
templateUrl: './flat-widget-horizontal-line.html'
})
export class FlatWidgetHorizontalLine {
/** Components-Array to iterate over */
@Input() components: any[];
/** index is an iterator */
@Input() index: number;
}
27 changes: 12 additions & 15 deletions ui/src/app/edge/live/flat/flat-widget-line/flat-widget-line.html
@@ -1,15 +1,12 @@
<ng-container *ngIf="isInitialized">
<table class="full_width">
<tr>
<!-- Name of Parameter on the left side -->
<td style="width:65%">
<ng-container *ngIf="name">{{ name }}</ng-container>
</td>

<!-- Value of Parameter on the right side -->
<td style="width:35%" class="align_right">
<ng-container *ngIf="displayValue">{{ displayValue }}</ng-container>
</td>
</tr>
</table>
</ng-container>
<table class="full_width">
<tr>
<!-- Name of Parameter on the left side -->
<td style="width:65%">
<ng-container *ngIf="name">{{ name }}</ng-container>
</td>
<!-- Value of Parameter on the right side -->
<td style="width:35%" class="align_right">
<ng-container *ngIf="displayValue">{{ displayValue }}</ng-container>
</td>
</tr>
</table>
@@ -1,9 +1,11 @@
<ng-container *ngIf="isInitialized">
<svg width="100%" height="20">
<rect width="100%" rx="5" ry="5" height="20" style="fill:#f4f4f4" />
<rect *ngIf="displayValue" x="1" y="2" rx="5" ry="5" attr.width="{{displayValue}}%" height="16"
style="fill:#2d8fab" />
<text x="50%" y="58%" dominant-baseline="middle" text-anchor="middle" style="font-weight: 500">{{ displayValue |
number:'1.0-0' }}&nbsp;%</text>
</svg>
</ng-container>
<svg width="100%" height="20">
<rect width="100%" rx="5" ry="5" height="20" style="fill:#f4f4f4" />
<rect *ngIf="displayValue" x="1" y="2" rx="5" ry="5" attr.width="{{ displayValue }}%" height="16"
style="fill:#2d8fab" />
<text x="50%" y="58%" dominant-baseline="middle" text-anchor="middle" style="font-weight: 500">
<ng-container *ngIf="displayValue, else noValue">
{{ displayValue | number:'1.0-0' }}&nbsp;%
</ng-container>
<ng-template #noValue>-</ng-template>
</text>
</svg>