Implementing a UI-Widget

1. Step-by-step guide

This chapter explains the steps required to implement a UI Widget for OpenEMS UI. There are many examples of how ui widgets are created and used in LiveComponent and HistoryComponent.

UI-Modules mainly consist of these components:

Module

Modules should always be used to import and export all of the components, relevant to this Widget. The following components could be part of it:

FlatWidget

directly visible in Live-View.

ModalComponent

Popover, that can be opened when clicking on a FlatWidget, used in Live-View.

Chart

Chart that is shown instead of a modal, used in History-View

1.1. Create a new module [Live-View]

  1. Copy an existing Module e.g. FixActivePower and paste it inside the Live-View.

  2. Change the @Component selector and use it inside LiveComponent.

  3. Rename the Module and import it in LiveModule under imports. To be able to see the module in action, you need to create a new switchCase Statement with your controllers factoryId.

    <ion-col size="12" *ngSwitchCase="'Controller.Ess.FixActivePower'"
    size-lg="6" class="ion-no-padding">
        <Controller_Ess_FixActivePower [componentId]="widget.componentId">
        </Controller_Ess_FixActivePower>
    </ion-col>
The Live and History View are designed to show UI-Widgets dependent on the EdgeConfig, except of widgets listed in Common. If you implemented a controller or component, that is part of an EdgeConfig, you have to use the factoryId as a switchCase statement. If thats not the case, go into widget.ts and add a identifier to the classes array inside parseWidgets().

The FlatWidget should now be visible in the Live-View and could be looking like this.

FlatWidget FixActivePower

1.2. Creating a FlatWidget

Data Visualisation in the Live-View is enabled with the flat and modal-widgets.

The FlatWidget is mandatory for a Modal-Widget. Its purpose is to show only the most important or general data. It also acts as a button, that can open the ModalWidget.

<ng-container *ngIf="isInitialized">
    <oe-flat-widget (click)="presentModal()" [icon]="{name:'swap-vertical-outline'}" [title]="component.alias">
        <oe-flat-widget-line [name]="'General.state' | translate" [value]="propertyMode"
            [converter]="CONVERT_MANUAL_ON_OFF">
        </oe-flat-widget-line>

        <ng-container *ngIf="propertyMode === 'MANUAL_ON'">
            <oe-flat-widget-line [name]="chargeDischargePower.name" [value]="chargeDischargePower.value"
                [converter]="CONVERT_WATT_TO_KILOWATT">
            </oe-flat-widget-line>
        </ng-container>
    </oe-flat-widget>
</ng-container>

If we take another look at the example of FixActivePowers FlatWidget you can see that everything is wrapped up in a ng-container with a statement, that will return true, if the edge and the edgeConfig have been received from Backend or Edge. The Widget will not be shown, till this condition is met.

One step further there is a oe-flat-widget. If you take a look at the corresponding class, you will see multiple @Input() properties. These properties can be passed with the Widget. If you are not familiar with @Input() and @Output(), window="_blank", take a look here.

Inside this @Component-tag, multiple other Components can be used.

<oe-flat-widget-line [name]="chargeDischargePower.name"  [value]="chargeDischargePower.value"
[converter]="CONVERT_WATT_TO_KILOWATT">
</oe-flat-widget-line>

or

 <oe-flat-widget-line [name]="component.alias"
 [channelAddress]="
 component.id + '/ActualPower'"
[converter]="CONVERT_WATT_TO_KILOWATT">
</oe-flat-widget-line>
FlatWidget FixActivePower

Shows a row with a @Input() name left and @Input() value on the right. This value can also be converted with @Input() converter.

<oe-flat-widget-percentagebar [channelAddress]="
component.id + '/Soc'">
</oe-flat-widget-percentagebar>
ui flat widget autarchy
<oe-flat-widget-horizontal-line></oe-flat-widget-horizontal-line>
ui flat widget consumption

Shows a horizontal line, that is used to divide children of AbstractFlatWidgetLine.

Passing data can be done two ways:

  • @Input() channelAddress: provide channel, which will be subscribed in AbstractFlatWidgetLine.

  • @Input() value: subscribe in the ts-file and pass the subscribed value.