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),
];
}