From 2daa73c457517dbe2899ce28c69f1df3c877d6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Thu, 31 Oct 2024 09:53:55 +0100 Subject: [PATCH] DashboardAmortisationComponent --- .../angular/src/app/api/series/constants.ts | 12 ++++ src/main/angular/src/app/api/value/Display.ts | 2 +- src/main/angular/src/app/api/value/Value.ts | 4 ++ .../air/dashboard-air-tile.component.ts | 14 ++--- .../dashboard-amortisation.component.html | 1 + .../dashboard-amortisation.component.less | 0 .../dashboard-amortisation.component.ts | 62 +++++++++++++++++++ .../pages/dashboard/dashboard.component.html | 4 ++ .../pages/dashboard/dashboard.component.ts | 2 + .../dashboard-electricity-tile.component.ts | 30 ++++----- 10 files changed, 108 insertions(+), 23 deletions(-) create mode 100644 src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.html create mode 100644 src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.less create mode 100644 src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.ts diff --git a/src/main/angular/src/app/api/series/constants.ts b/src/main/angular/src/app/api/series/constants.ts index 2c53200..797cb1d 100644 --- a/src/main/angular/src/app/api/series/constants.ts +++ b/src/main/angular/src/app/api/series/constants.ts @@ -29,6 +29,8 @@ export const HEATING_LOOP_SUPPLY_TEMPERATURE = 'heating.loop.supply.temperature' export const HEATING_LOOP_RETURN_TEMPERATURE = 'heating.loop.return.temperature'; export const PERCENT = new ValueConstant(100, "%"); +export const MILLIS_PER_MONTH = new ValueConstant(24 * 60 * 60 * 30 * 1000, ''); +export const MILLIS_PER_YEAR = new ValueConstant(24 * 60 * 60 * 365 * 1000, ''); export const ELECTRICITY_GRID_PURCHASED_FEW = 7.7; export const ELECTRICITY_GRID_PURCHASED_MUCH = 9.7; @@ -39,3 +41,13 @@ export const ELECTRICITY_PHOTOVOLTAIC_PRODUCED_MUCH = 2; export const ELECTRICITY_PHOTOVOLTAIC_POWER_FEW = 50; export const ELECTRICITY_PHOTOVOLTAIC_POWER_MUCH = 200; export const ELECTRICITY_PHOTOVOLTAIC_PRODUCED_BEFORE_METER_CHANGE = new ValueConstant(287.995, "kWh"); + +export const GRID_KWH_EURO = new ValueConstant(0.33, "€"); + +export const PV_COST_MONTAGESCHIENE_EURO = 6.19; +export const PV_COST_MONTAGESCHIENE_COUNT = 8; +export const PV_COST_ANLAGE_EURO = 498; +export const PV_COST_ANLAGE_VERSAND_EURO = 29; +export const PV_COST_TOTAL_EURO = new ValueConstant(PV_COST_MONTAGESCHIENE_EURO * PV_COST_MONTAGESCHIENE_COUNT + PV_COST_ANLAGE_EURO + PV_COST_ANLAGE_VERSAND_EURO, "€"); +export const PV_COST_AMORTISATION_KWH = PV_COST_TOTAL_EURO.div(GRID_KWH_EURO); +export const PV_COST_AMORTISATION_BEGIN = new Date(2024, 1, 10, 13, 39, 42, 345); diff --git a/src/main/angular/src/app/api/value/Display.ts b/src/main/angular/src/app/api/value/Display.ts index ef2ff5f..a9087ff 100644 --- a/src/main/angular/src/app/api/value/Display.ts +++ b/src/main/angular/src/app/api/value/Display.ts @@ -5,7 +5,7 @@ export class DisplayValue { constructor( readonly title: string, readonly value: Value, - readonly color: string, + readonly color: string = '', ) { // - } diff --git a/src/main/angular/src/app/api/value/Value.ts b/src/main/angular/src/app/api/value/Value.ts index b46efd1..9666705 100644 --- a/src/main/angular/src/app/api/value/Value.ts +++ b/src/main/angular/src/app/api/value/Value.ts @@ -56,6 +56,10 @@ export class Value { return this.unary(a => a * factor); } + neg() { + return this.unary((v: number) => -v); + } + unary(func: (v: number) => number): Value { if (this.value === null) { return new Value(null, null, ''); diff --git a/src/main/angular/src/app/pages/dashboard/air/dashboard-air-tile.component.ts b/src/main/angular/src/app/pages/dashboard/air/dashboard-air-tile.component.ts index 0e719f9..9ed17e5 100644 --- a/src/main/angular/src/app/pages/dashboard/air/dashboard-air-tile.component.ts +++ b/src/main/angular/src/app/pages/dashboard/air/dashboard-air-tile.component.ts @@ -32,16 +32,16 @@ export class DashboardAirTileComponent { return [ 'Garten', - new DisplayValue('Temperatur', this.seriesCacheService.outdoorTemperature, ''), - new DisplayValue('Luftfeuchte Relativ', this.seriesCacheService.outdoorHumidityRelative, ''), - new DisplayValue('Luftfeuchte Absolut', this.seriesCacheService.outdoorHumidityAbsolute, ''), + new DisplayValue('Temperatur', this.seriesCacheService.outdoorTemperature), + new DisplayValue('Luftfeuchte Relativ', this.seriesCacheService.outdoorHumidityRelative), + new DisplayValue('Luftfeuchte Absolut', this.seriesCacheService.outdoorHumidityAbsolute), 'Schlafzimmer', - new DisplayValue('Temperatur', this.seriesCacheService.schlafzimmerTemperature, ''), - new DisplayValue('Luftfeuchte Relativ', this.seriesCacheService.schlafzimmerHumidityRelative, ''), + new DisplayValue('Temperatur', this.seriesCacheService.schlafzimmerTemperature), + new DisplayValue('Luftfeuchte Relativ', this.seriesCacheService.schlafzimmerHumidityRelative), new DisplayValue('Luftfeuchte Absolut', this.seriesCacheService.schlafzimmerHumidityAbsolute, bedroomVentColor), 'Heizungskeller', - new DisplayValue('Temperatur', this.seriesCacheService.heatingRoomTemperature, ''), - new DisplayValue('Luftfeuchte Relativ', this.seriesCacheService.heatingRoomHumidityRelative, ''), + new DisplayValue('Temperatur', this.seriesCacheService.heatingRoomTemperature), + new DisplayValue('Luftfeuchte Relativ', this.seriesCacheService.heatingRoomHumidityRelative), new DisplayValue('Luftfeuchte Absolut', this.seriesCacheService.heatingRoomHumidityAbsolute, heatingRoomVentColor), ]; } diff --git a/src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.html b/src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.html new file mode 100644 index 0000000..4f97a66 --- /dev/null +++ b/src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.html @@ -0,0 +1 @@ + diff --git a/src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.less b/src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.less new file mode 100644 index 0000000..e69de29 diff --git a/src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.ts b/src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.ts new file mode 100644 index 0000000..ea45f3e --- /dev/null +++ b/src/main/angular/src/app/pages/dashboard/amortisation/dashboard-amortisation.component.ts @@ -0,0 +1,62 @@ +import {Component, Input} from '@angular/core'; +import {SeriesCacheService} from "../../../api/series/series-cache.service"; +import {Display, DisplayValue} from "../../../api/value/Display"; +import {ELECTRICITY_PHOTOVOLTAIC_PRODUCED_BEFORE_METER_CHANGE, GRID_KWH_EURO, MILLIS_PER_YEAR, PERCENT, PV_COST_AMORTISATION_BEGIN, PV_COST_AMORTISATION_KWH, PV_COST_TOTAL_EURO} from "../../../api/series/constants"; +import {ValueListComponent} from "../../../shared/value-list/value-list.component"; +import {ValueConstant} from "../../../api/value/Value"; +import {DatePipe} from "@angular/common"; + +@Component({ + selector: 'app-dashboard-amortisation', + standalone: true, + imports: [ + ValueListComponent, + ], + providers: [ + DatePipe, + ], + templateUrl: './dashboard-amortisation.component.html', + styleUrl: './dashboard-amortisation.component.less' +}) +export class DashboardAmortisationComponent { + + @Input() + now!: Date; + + constructor( + protected readonly seriesCacheService: SeriesCacheService, + protected readonly datePipe: DatePipe, + ) { + // - + } + + getDisplayList(): Display[] { + const producedAfterChange = this.seriesCacheService.photovoltaicProduced.minus(ELECTRICITY_PHOTOVOLTAIC_PRODUCED_BEFORE_METER_CHANGE); + const selfAfterChange = producedAfterChange.minus(this.seriesCacheService.gridDelivered); + const selfRatio = selfAfterChange.div(producedAfterChange); + const selfConsumed = selfRatio.mul(this.seriesCacheService.photovoltaicProduced); + const costsSaved = selfConsumed.mul(GRID_KWH_EURO).withUnit("€") + const amortisationPercent = selfConsumed.div(PV_COST_AMORTISATION_KWH).mul(PERCENT).withUnit('%'); + const amortisationAlreadyMillis = new ValueConstant(this.now.getTime() - PV_COST_AMORTISATION_BEGIN.getTime(), 'ms'); + const amortisationMilliPerKWh = amortisationAlreadyMillis.div(selfConsumed).withUnit('ms/kWh'); + const amortisationRestKWh = PV_COST_AMORTISATION_KWH.minus(selfConsumed); + const amortisationRestMillis = amortisationRestKWh.mul(amortisationMilliPerKWh).withUnit('ms'); + const amortisationRestYears = amortisationRestMillis.div(MILLIS_PER_YEAR).withUnit('Jahre'); + const amortisationTotalMillis = PV_COST_AMORTISATION_KWH.mul(amortisationMilliPerKWh).withUnit('ms'); + const amortisationTotalYears = amortisationTotalMillis.div(MILLIS_PER_YEAR).withUnit('Jahre'); + const amortisationDate = new Date(this.now.getTime() + (amortisationRestMillis.value || 0)); + const constRestEuro = PV_COST_TOTAL_EURO.minus(costsSaved); + const amortisationDateString = 'Erwarte Amortisation am: ' + this.datePipe.transform(amortisationDate, 'dd. MMM yyyy'); + return [ + new DisplayValue('Ausgaben', PV_COST_TOTAL_EURO), + new DisplayValue('Ersparnis', costsSaved), + ' ', + new DisplayValue('Noch offen', constRestEuro), + new DisplayValue('Amortisiert', amortisationPercent), + new DisplayValue('Restdauer', amortisationRestYears), + new DisplayValue('Gesamtdauer', amortisationTotalYears), + amortisationDateString, + ]; + } + +} diff --git a/src/main/angular/src/app/pages/dashboard/dashboard.component.html b/src/main/angular/src/app/pages/dashboard/dashboard.component.html index a6bf3a6..2f0d230 100644 --- a/src/main/angular/src/app/pages/dashboard/dashboard.component.html +++ b/src/main/angular/src/app/pages/dashboard/dashboard.component.html @@ -9,3 +9,7 @@
+ +
+ +
diff --git a/src/main/angular/src/app/pages/dashboard/dashboard.component.ts b/src/main/angular/src/app/pages/dashboard/dashboard.component.ts index a5cb7fe..7634977 100644 --- a/src/main/angular/src/app/pages/dashboard/dashboard.component.ts +++ b/src/main/angular/src/app/pages/dashboard/dashboard.component.ts @@ -5,6 +5,7 @@ import {DashboardElectricityTileComponent} from "./electricity/dashboard-electri import {DashboardAirTileComponent} from "./air/dashboard-air-tile.component"; import {Subscription, timer} from "rxjs"; import {DashboardHeatingTileComponent} from "./heating/dashboard-heating-tile.component"; +import {DashboardAmortisationComponent} from "./amortisation/dashboard-amortisation.component"; const UPDATE_INTERVAL_MILLIS = 1000; const SLOW_UPDATE_INTERVAL_MILLIS = 60 * 1000; @@ -19,6 +20,7 @@ const SLOW_UPDATE_INTERVAL_MILLIS = 60 * 1000; DashboardElectricityTileComponent, DashboardAirTileComponent, DashboardHeatingTileComponent, + DashboardAmortisationComponent, ], templateUrl: './dashboard.component.html', styleUrl: './dashboard.component.less' diff --git a/src/main/angular/src/app/pages/dashboard/electricity/dashboard-electricity-tile.component.ts b/src/main/angular/src/app/pages/dashboard/electricity/dashboard-electricity-tile.component.ts index 5b32a02..3b09183 100644 --- a/src/main/angular/src/app/pages/dashboard/electricity/dashboard-electricity-tile.component.ts +++ b/src/main/angular/src/app/pages/dashboard/electricity/dashboard-electricity-tile.component.ts @@ -73,30 +73,30 @@ export class DashboardElectricityTileComponent { return [ 'Zählerstände', - new DisplayValue('Bezogen', this.seriesCacheService.gridPurchased, ''), - new DisplayValue('Eingespeist', this.seriesCacheService.gridDelivered, ''), - new DisplayValue('Produziert', this.seriesCacheService.photovoltaicProduced, ''), - new DisplayValue('Selbst verbraucht', selfConsumed, ''), + new DisplayValue('Bezogen', this.seriesCacheService.gridPurchased), + new DisplayValue('Eingespeist', this.seriesCacheService.gridDelivered), + new DisplayValue('Produziert', this.seriesCacheService.photovoltaicProduced), + new DisplayValue('Selbst verbraucht', selfConsumed), 'Leistung', new DisplayValue('Produktion', this.seriesCacheService.photovoltaicPower, this.seriesCacheService.photovoltaicPower.color(ELECTRICITY_PHOTOVOLTAIC_POWER_FEW, ELECTRICITY_PHOTOVOLTAIC_POWER_MUCH, 'red', 'orange', 'green')), new DisplayValue('Netz', this.seriesCacheService.gridPower, gridColor), - new DisplayValue('Verbrauch', consumptionPower, ''), + new DisplayValue('Verbrauch', consumptionPower), 'Heute', new DisplayValue('Produziert', this.producedToday, this.producedToday.color(ELECTRICITY_PHOTOVOLTAIC_PRODUCED_FEW, ELECTRICITY_PHOTOVOLTAIC_PRODUCED_MUCH, 'red', 'orange', 'green')), - new DisplayValue('Eingespeist', this.deliveredToday, ''), - new DisplayValue('Eigenverbrauch', selfToday, ''), - new DisplayValue('Eigenverbrauch', selfPercentToday, ''), - new DisplayValue('Autarkie', selfAutarkyPercentToday, ''), + new DisplayValue('Eingespeist', this.deliveredToday), + new DisplayValue('Selbst verbraucht', selfToday), + new DisplayValue('Eigenverbrauch', selfPercentToday), + new DisplayValue('Autarkie', selfAutarkyPercentToday), new DisplayValue('Bezogen', this.purchasedToday, this.purchasedToday.color(ELECTRICITY_GRID_PURCHASED_FEW, ELECTRICITY_GRID_PURCHASED_MUCH, 'green')), - new DisplayValue('Verbraucht', consumedToday, ''), + new DisplayValue('Verbraucht', consumedToday), 'Gestern', new DisplayValue('Produziert', this.producedYesterday, this.producedYesterday.color(ELECTRICITY_PHOTOVOLTAIC_PRODUCED_FEW, ELECTRICITY_PHOTOVOLTAIC_PRODUCED_MUCH, 'red', 'orange', 'green')), - new DisplayValue('Eingespeist', this.deliveredYesterday, ''), - new DisplayValue('Eigenverbrauch', selfYesterday, ''), - new DisplayValue('Eigenverbrauch', selfPercentYesterday, ''), - new DisplayValue('Autarkie', selfAutarkyPercentYesterday, ''), + new DisplayValue('Eingespeist', this.deliveredYesterday), + new DisplayValue('Selbst verbraucht', selfYesterday), + new DisplayValue('Eigenverbrauch', selfPercentYesterday), + new DisplayValue('Autarkie', selfAutarkyPercentYesterday), new DisplayValue('Bezogen', this.purchasedYesterday, this.purchasedYesterday.color(ELECTRICITY_GRID_PURCHASED_FEW, ELECTRICITY_GRID_PURCHASED_MUCH, 'green')), - new DisplayValue('Verbraucht', consumedYesterday, ''), + new DisplayValue('Verbraucht', consumedYesterday), ]; }