diff --git a/src/main/angular/config.less b/src/main/angular/colors.less similarity index 69% rename from src/main/angular/config.less rename to src/main/angular/colors.less index 30e7e29..4c779a2 100644 --- a/src/main/angular/config.less +++ b/src/main/angular/colors.less @@ -25,3 +25,27 @@ @productionBack: #2d4255; @selfBack: #2b4e2b; @deliveryBack: #753475; + +.consumption { + color: @consumption; +} + +.purchase { + color: @purchase; +} + +.production { + color: @production; +} + +.self { + color: @self; +} + +.delivery { + color: @delivery; +} + +.zero { + filter: opacity(20%); +} diff --git a/src/main/angular/numberTable.less b/src/main/angular/numberTable.less new file mode 100644 index 0000000..eb220c2 --- /dev/null +++ b/src/main/angular/numberTable.less @@ -0,0 +1,50 @@ +@import "./colors.less"; + +.numberTable { + margin-bottom: 2em; + + .arrowLeft { + float: left; + } + + .arrowRight { + float: right; + } + + .title { + clear: left; + font-weight: bold; + text-align: center; + } + + .option { + clear: left; + text-align: center; + } + + .content { + + .entry { + clear: left; + + .name { + float: left; + } + + .value { + float: right; + } + + .percent { + float: right; + padding-top: 0.5em; + font-size: 60%; + width: 4.5em; + text-align: right; + } + + } + + } + +} diff --git a/src/main/angular/src/app/app.component.html b/src/main/angular/src/app/app.component.html index a4d25f0..7dd570e 100644 --- a/src/main/angular/src/app/app.component.html +++ b/src/main/angular/src/app/app.component.html @@ -1,89 +1 @@ -
- -
- Leistung -
- -
-
-
Bedarf
-
 
-
{{ powerConsumption?.formatted }}
-
-
-
Bezug
-
{{ powerPurchasePercent?.formatted }}
-
{{ powerPurchase?.formatted }}
-
-
-
Produktion
-
{{ powerProducedPercent?.formatted }}
-
{{ powerProduction?.formatted }}
-
-
-
Eigenbedarf
-
{{ powerSelfPercent?.formatted }}
-
{{ powerSelf?.formatted }}
-
-
-
Einspeisung
-
{{ powerDeliveryPercent?.formatted }}
-
{{ powerDelivery?.formatted }}
-
-
- - - -
- -
- -
- Energie -
- -
- - {{ alignment.display }} {{ offset > 0 ? -offset : '' }} - -
- -
- - {{ alignment.offsetTitle(offset, locale) }} - -
- -
-
-
Bedarf
-
 
-
{{ aggregations.energyConsumed?.formatted }}
-
-
-
Bezug
-
{{ aggregations.energyPurchasedPercent?.formatted }}
-
{{ aggregations.energyPurchased?.delta?.formatted }}
-
-
-
Produktion
-
{{ aggregations.energyProducedPercent?.formatted }}
-
{{ aggregations.energyProduced?.delta?.formatted }}
-
-
-
Eigenbedarf
-
{{ aggregations.energySelfPercent?.formatted }}
-
{{ aggregations.energySelf?.formatted }}
-
-
-
Einspeisung
-
{{ aggregations.energyDeliveredPercent?.formatted }}
-
{{ aggregations.energyDelivered?.delta?.formatted }}
-
-
- - - -
- diff --git a/src/main/angular/src/app/app.component.less b/src/main/angular/src/app/app.component.less index 5df8cd7..e69de29 100644 --- a/src/main/angular/src/app/app.component.less +++ b/src/main/angular/src/app/app.component.less @@ -1,86 +0,0 @@ -@import "../../config.less"; - -.section { - margin-bottom: 2em; - - .back { - float: left; - } - - .next { - float: right; - } - - .title { - clear: left; - font-weight: bold; - text-align: center; - } - - .option { - clear: left; - text-align: center; - } - - .content { - - .entry { - clear: left; - - .name { - float: left; - } - - .value { - float: right; - } - - .percent { - float: right; - padding-top: 0.5em; - font-size: 60%; - width: 4.5em; - text-align: right; - } - - } - - } - -} - -.live { - font-size: 40%; - color: green; - vertical-align: top; -} - -.archive { - font-size: 40%; - color: darkred; - vertical-align: top; -} - -.consumption { - color: @consumption; -} - -.purchase { - color: @purchase; -} - -.production { - color: @production; -} - -.self { - color: @self; -} - -.delivery { - color: @delivery; -} - -.zero { - filter: opacity(20%); -} diff --git a/src/main/angular/src/app/app.component.ts b/src/main/angular/src/app/app.component.ts index e305a6e..ec110d1 100644 --- a/src/main/angular/src/app/app.component.ts +++ b/src/main/angular/src/app/app.component.ts @@ -1,113 +1,12 @@ -import {Component, Inject, LOCALE_ID, OnDestroy, OnInit} from '@angular/core'; +import {Component} from '@angular/core'; import {RouterOutlet} from '@angular/router'; -import {Alignment} from './series/Alignment'; -import {AggregationWrapperDto} from './series/AggregationWrapperDto'; -import {SeriesService} from './series/series.service'; -import {Subscription} from 'rxjs'; -import {Value} from './value/Value'; -import {PercentBarComponent} from './percent-bar/percent-bar.component'; @Component({ selector: 'app-root', - imports: [RouterOutlet, PercentBarComponent], + imports: [RouterOutlet], templateUrl: './app.component.html', styleUrl: './app.component.less' }) -export class AppComponent implements OnInit, OnDestroy { - - protected aggregations: AggregationWrapperDto = AggregationWrapperDto.EMPTY; - - protected alignment: Alignment = Alignment.DAY; - - protected offset: number = 0; - - protected interval: any; - - private readonly subs: Subscription[] = []; - - get powerProduction(): Value | undefined { - return this.seriesService.powerProduced.series?.lastValue; - } - - get powerBalance(): Value | undefined { - return this.seriesService.powerBalance.series?.lastValue; - } - - get powerPurchase(): Value | undefined { - return this.powerBalance?.notNegative(); - } - - get powerDelivery(): Value | undefined { - return this.powerBalance?.negate()?.notNegative(); - } - - get powerSelf(): Value | undefined { - return this.powerProduction?.minus(this.powerDelivery)?.notNegative(); - } - - get powerConsumption(): Value | undefined { - return this.powerPurchase?.plus(this.powerProduction)?.minus(this.powerDelivery); - } - - get powerProducedPercent(): Value | undefined { - return this.powerProduction?.percent(this.powerConsumption); - } - - get powerSelfPercent(): Value | undefined { - return this.powerSelf?.percent(this.powerProduction); - } - - get powerPurchasePercent(): Value | undefined { - return this.powerPurchase?.percent(this.powerConsumption); - } - - get powerDeliveryPercent(): Value | undefined { - return this.powerDelivery?.percent(this.powerProduction); - } - - constructor( - @Inject(LOCALE_ID) public locale: string, - protected readonly seriesService: SeriesService, - ) { - // - } - - ngOnInit(): void { - this.fetch(); - this.subs.push(this.seriesService.subscribeAny()); - } - - ngOnDestroy(): void { - this.intervalStop(); - this.subs.forEach(sub => sub.unsubscribe()); - } - - shiftOffset(delta: number) { - this.offset = Math.max(0, this.offset + delta); - this.fetch(); - } - - shiftAlignment(delta: number) { - this.alignment = this.alignment.plus(delta) - this.fetch(); - } - - private fetch() { - if (this.offset === 0) { - if (!this.interval) { - this.interval = setInterval(() => this.fetch(), 5000); - } - } else { - this.intervalStop(); - } - this.seriesService.aggregations(this.alignment, this.offset, aggregations => this.aggregations = aggregations); - } - - private intervalStop() { - if (this.interval) { - clearInterval(this.interval); - this.interval = null; - } - } +export class AppComponent { } diff --git a/src/main/angular/src/app/app.routes.ts b/src/main/angular/src/app/app.routes.ts index 8b5e5fb..c85a6e2 100644 --- a/src/main/angular/src/app/app.routes.ts +++ b/src/main/angular/src/app/app.routes.ts @@ -1,3 +1,7 @@ import {Routes} from '@angular/router'; +import {DashboardComponent} from './dashboard/dashboard.component'; -export const routes: Routes = []; +export const routes: Routes = [ + {path: 'Dashboard', component: DashboardComponent}, + {path: '**', redirectTo: 'Dashboard'}, +]; diff --git a/src/main/angular/src/app/core/api.service.ts b/src/main/angular/src/app/core/api.service.ts index b6d864a..49ff931 100644 --- a/src/main/angular/src/app/core/api.service.ts +++ b/src/main/angular/src/app/core/api.service.ts @@ -4,7 +4,7 @@ import {map, Subscription} from 'rxjs'; import {StompService} from '@stomp/ng2-stompjs'; import {FromJson, Next} from './types'; -const DEV_TO_PROD = false; +const DEV_TO_PROD = true; @Injectable({ providedIn: 'root' diff --git a/src/main/angular/src/app/dashboard/dashboard.component.html b/src/main/angular/src/app/dashboard/dashboard.component.html new file mode 100644 index 0000000..54e3528 --- /dev/null +++ b/src/main/angular/src/app/dashboard/dashboard.component.html @@ -0,0 +1,3 @@ + + + diff --git a/src/main/angular/src/app/dashboard/dashboard.component.less b/src/main/angular/src/app/dashboard/dashboard.component.less new file mode 100644 index 0000000..e69de29 diff --git a/src/main/angular/src/app/dashboard/dashboard.component.ts b/src/main/angular/src/app/dashboard/dashboard.component.ts new file mode 100644 index 0000000..c449edc --- /dev/null +++ b/src/main/angular/src/app/dashboard/dashboard.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; +import {ElectroEnergyComponent} from "../electro/energy/electro-energy.component"; +import {ElectroPowerComponent} from "../electro/power/electro-power.component"; + +@Component({ + selector: 'app-dashboard', + imports: [ + ElectroEnergyComponent, + ElectroPowerComponent + ], + templateUrl: './dashboard.component.html', + styleUrl: './dashboard.component.less' +}) +export class DashboardComponent { + +} diff --git a/src/main/angular/src/app/electro/energy/electro-energy.component.html b/src/main/angular/src/app/electro/energy/electro-energy.component.html new file mode 100644 index 0000000..c9dfb6a --- /dev/null +++ b/src/main/angular/src/app/electro/energy/electro-energy.component.html @@ -0,0 +1,49 @@ +
+ +
+ Energie +
+ +
+ + {{ alignment.display }} {{ offset > 0 ? -offset : '' }} + +
+ +
+ + {{ alignment.offsetTitle(offset, locale) }} + +
+ +
+
+
Bedarf
+
 
+
{{ aggregations.energyConsumed?.formatted }}
+
+
+
Bezug
+
{{ aggregations.energyPurchasedPercent?.formatted }}
+
{{ aggregations.energyPurchased?.delta?.formatted }}
+
+
+
Produktion
+
{{ aggregations.energyProducedPercent?.formatted }}
+
{{ aggregations.energyProduced?.delta?.formatted }}
+
+
+
Eigenbedarf
+
{{ aggregations.energySelfPercent?.formatted }}
+
{{ aggregations.energySelf?.formatted }}
+
+
+
Einspeisung
+
{{ aggregations.energyDeliveredPercent?.formatted }}
+
{{ aggregations.energyDelivered?.delta?.formatted }}
+
+
+ + + +
diff --git a/src/main/angular/src/app/electro/energy/electro-energy.component.less b/src/main/angular/src/app/electro/energy/electro-energy.component.less new file mode 100644 index 0000000..bb8f9f0 --- /dev/null +++ b/src/main/angular/src/app/electro/energy/electro-energy.component.less @@ -0,0 +1 @@ +@import "../../../../colors.less"; diff --git a/src/main/angular/src/app/electro/energy/electro-energy.component.ts b/src/main/angular/src/app/electro/energy/electro-energy.component.ts new file mode 100644 index 0000000..b24c1e2 --- /dev/null +++ b/src/main/angular/src/app/electro/energy/electro-energy.component.ts @@ -0,0 +1,73 @@ +import {Component, Inject, LOCALE_ID, OnDestroy, OnInit} from '@angular/core'; +import {PercentBarComponent} from '../../shared/percent-bar/percent-bar.component'; +import {AggregationWrapperDto} from '../../series/AggregationWrapperDto'; +import {Alignment} from '../../series/Alignment'; +import {Subscription} from 'rxjs'; +import {SeriesService} from '../../series/series.service'; + +@Component({ + selector: 'app-electro-energy', + imports: [ + PercentBarComponent + ], + templateUrl: './electro-energy.component.html', + styleUrl: './electro-energy.component.less' +}) +export class ElectroEnergyComponent implements OnInit, OnDestroy { + + protected aggregations: AggregationWrapperDto = AggregationWrapperDto.EMPTY; + + protected alignment: Alignment = Alignment.DAY; + + protected offset: number = 0; + + protected interval: any; + + private readonly subs: Subscription[] = []; + + constructor( + @Inject(LOCALE_ID) public locale: string, + protected readonly seriesService: SeriesService, + ) { + // + } + + ngOnInit(): void { + this.fetch(); + this.subs.push(this.seriesService.subscribeAny()); + } + + ngOnDestroy(): void { + this.intervalStop(); + this.subs.forEach(sub => sub.unsubscribe()); + } + + shiftOffset(delta: number) { + this.offset = Math.max(0, this.offset + delta); + this.fetch(); + } + + shiftAlignment(delta: number) { + this.alignment = this.alignment.plus(delta) + this.fetch(); + } + + private fetch() { + if (this.offset === 0) { + if (!this.interval) { + this.interval = setInterval(() => this.fetch(), 5000); + } + } else { + this.intervalStop(); + } + this.seriesService.aggregations(this.alignment, this.offset, aggregations => this.aggregations = aggregations); + } + + private intervalStop() { + if (this.interval) { + clearInterval(this.interval); + this.interval = null; + } + } + +} diff --git a/src/main/angular/src/app/electro/power/electro-power.component.html b/src/main/angular/src/app/electro/power/electro-power.component.html new file mode 100644 index 0000000..d3a0928 --- /dev/null +++ b/src/main/angular/src/app/electro/power/electro-power.component.html @@ -0,0 +1,37 @@ +
+ +
+ Leistung +
+ +
+
+
Bedarf
+
 
+
{{ powerConsumption?.formatted }}
+
+
+
Bezug
+
{{ powerPurchasePercent?.formatted }}
+
{{ powerPurchase?.formatted }}
+
+
+
Produktion
+
{{ powerProducedPercent?.formatted }}
+
{{ powerProduction?.formatted }}
+
+
+
Eigenbedarf
+
{{ powerSelfPercent?.formatted }}
+
{{ powerSelf?.formatted }}
+
+
+
Einspeisung
+
{{ powerDeliveryPercent?.formatted }}
+
{{ powerDelivery?.formatted }}
+
+
+ + + +
diff --git a/src/main/angular/src/app/electro/power/electro-power.component.less b/src/main/angular/src/app/electro/power/electro-power.component.less new file mode 100644 index 0000000..bb8f9f0 --- /dev/null +++ b/src/main/angular/src/app/electro/power/electro-power.component.less @@ -0,0 +1 @@ +@import "../../../../colors.less"; diff --git a/src/main/angular/src/app/electro/power/electro-power.component.ts b/src/main/angular/src/app/electro/power/electro-power.component.ts new file mode 100644 index 0000000..cf3fbc9 --- /dev/null +++ b/src/main/angular/src/app/electro/power/electro-power.component.ts @@ -0,0 +1,61 @@ +import {Component} from '@angular/core'; +import {PercentBarComponent} from "../../shared/percent-bar/percent-bar.component"; +import {Value} from '../../value/Value'; +import {SeriesService} from '../../series/series.service'; + +@Component({ + selector: 'app-electro-power', + imports: [ + PercentBarComponent + ], + templateUrl: './electro-power.component.html', + styleUrl: './electro-power.component.less' +}) +export class ElectroPowerComponent { + + constructor( + readonly seriesService: SeriesService, + ) { + } + + get powerProduction(): Value | undefined { + return this.seriesService.powerProduced.series?.lastValue; + } + + get powerBalance(): Value | undefined { + return this.seriesService.powerBalance.series?.lastValue; + } + + get powerPurchase(): Value | undefined { + return this.powerBalance?.notNegative(); + } + + get powerDelivery(): Value | undefined { + return this.powerBalance?.negate()?.notNegative(); + } + + get powerSelf(): Value | undefined { + return this.powerProduction?.minus(this.powerDelivery)?.notNegative(); + } + + get powerConsumption(): Value | undefined { + return this.powerPurchase?.plus(this.powerProduction)?.minus(this.powerDelivery); + } + + get powerProducedPercent(): Value | undefined { + return this.powerProduction?.percent(this.powerConsumption); + } + + get powerSelfPercent(): Value | undefined { + return this.powerSelf?.percent(this.powerProduction); + } + + get powerPurchasePercent(): Value | undefined { + return this.powerPurchase?.percent(this.powerConsumption); + } + + get powerDeliveryPercent(): Value | undefined { + return this.powerDelivery?.percent(this.powerProduction); + } + +} diff --git a/src/main/angular/src/app/percent-bar/percent-bar.component.html b/src/main/angular/src/app/shared/percent-bar/percent-bar.component.html similarity index 100% rename from src/main/angular/src/app/percent-bar/percent-bar.component.html rename to src/main/angular/src/app/shared/percent-bar/percent-bar.component.html diff --git a/src/main/angular/src/app/percent-bar/percent-bar.component.less b/src/main/angular/src/app/shared/percent-bar/percent-bar.component.less similarity index 91% rename from src/main/angular/src/app/percent-bar/percent-bar.component.less rename to src/main/angular/src/app/shared/percent-bar/percent-bar.component.less index 3733aee..6eaae9e 100644 --- a/src/main/angular/src/app/percent-bar/percent-bar.component.less +++ b/src/main/angular/src/app/shared/percent-bar/percent-bar.component.less @@ -1,4 +1,4 @@ -@import "../../../config.less"; +@import "../../../../colors.less"; .bar { position: relative; diff --git a/src/main/angular/src/app/percent-bar/percent-bar.component.ts b/src/main/angular/src/app/shared/percent-bar/percent-bar.component.ts similarity index 97% rename from src/main/angular/src/app/percent-bar/percent-bar.component.ts rename to src/main/angular/src/app/shared/percent-bar/percent-bar.component.ts index 4897f38..63a11cb 100644 --- a/src/main/angular/src/app/percent-bar/percent-bar.component.ts +++ b/src/main/angular/src/app/shared/percent-bar/percent-bar.component.ts @@ -1,5 +1,5 @@ import {Component, Input} from '@angular/core'; -import {Value} from '../value/Value'; +import {Value} from '../../value/Value'; import {NgIf} from '@angular/common'; @Component({ diff --git a/src/main/angular/src/styles.less b/src/main/angular/src/styles.less index 20bd6c3..2bd6789 100644 --- a/src/main/angular/src/styles.less +++ b/src/main/angular/src/styles.less @@ -1,4 +1,5 @@ -@import "../config.less"; +@import "../colors.less"; +@import "../numberTable.less"; body { font-family: sans-serif;