Value-operations accept Value|number and Display.value accepts Value|string now
This commit is contained in:
parent
a02b59fd7e
commit
1ee3215c91
@ -28,9 +28,7 @@ export const HEATING_BUFFER_CIRCULATION_TEMPERATURE = 'heating.buffer.circulatio
|
||||
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 MILLIS_PER_YEAR = 24 * 60 * 60 * 365 * 1000;
|
||||
|
||||
export const ELECTRICITY_GRID_PURCHASED_FEW = 7.7;
|
||||
export const ELECTRICITY_GRID_PURCHASED_MUCH = 9.7;
|
||||
|
||||
@ -4,7 +4,7 @@ export class DisplayValue {
|
||||
|
||||
constructor(
|
||||
readonly title: string,
|
||||
readonly value: Value,
|
||||
readonly value: Value | string,
|
||||
readonly color: string = '',
|
||||
) {
|
||||
// -
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
export type V = Value | number;
|
||||
|
||||
export class Value {
|
||||
|
||||
constructor(
|
||||
@ -8,50 +10,12 @@ export class Value {
|
||||
// -
|
||||
}
|
||||
|
||||
/* UNARY ---------------------------------------------------------------------------------------- */
|
||||
|
||||
clampNonNegative(): Value {
|
||||
return this.unary(v => v > 0 ? v : 0);
|
||||
}
|
||||
|
||||
plus(other: Value): Value {
|
||||
return this.binary(other, (a, b) => a + b);
|
||||
}
|
||||
|
||||
minus(other: Value): Value {
|
||||
return this.binary(other, (a, b) => a - b);
|
||||
}
|
||||
|
||||
mul(other: Value): Value {
|
||||
return this.binary(other, (a, b) => a * b);
|
||||
}
|
||||
|
||||
div(other: Value): Value {
|
||||
return this.binary(other, (a, b) => a / b);
|
||||
}
|
||||
|
||||
ne(other: Value): boolean {
|
||||
return this.compare(other) !== 0;
|
||||
}
|
||||
|
||||
eq(other: Value): boolean {
|
||||
return this.compare(other) === 0;
|
||||
}
|
||||
|
||||
gt(other: Value): boolean {
|
||||
return this.compare(other) > 0;
|
||||
}
|
||||
|
||||
gte(other: Value): boolean {
|
||||
return this.compare(other) >= 0;
|
||||
}
|
||||
|
||||
lt(other: Value): boolean {
|
||||
return this.compare(other) < 0;
|
||||
}
|
||||
|
||||
lte(other: Value): boolean {
|
||||
return this.compare(other) <= 0;
|
||||
}
|
||||
|
||||
times(factor: number) {
|
||||
return this.unary(a => a * factor);
|
||||
}
|
||||
@ -68,7 +32,41 @@ export class Value {
|
||||
return new Value(this.date, value, this.unit);
|
||||
}
|
||||
|
||||
binary(other: Value, func: (a: number, b: number) => number): Value {
|
||||
/* BINARY --------------------------------------------------------------------------------------- */
|
||||
|
||||
plus(other: V): Value {
|
||||
return this.binary(other, (a, b) => a + b);
|
||||
}
|
||||
|
||||
minus(other: V): Value {
|
||||
return this.binary(other, (a, b) => a - b);
|
||||
}
|
||||
|
||||
mul(other: V): Value {
|
||||
return this.binary(other, (a, b) => a * b);
|
||||
}
|
||||
|
||||
div(other: V): Value {
|
||||
return this.binary(other, (a, b) => a / b);
|
||||
}
|
||||
|
||||
binary(other: V, func: (a: number, b: number) => number): Value {
|
||||
if (typeof other === 'number') {
|
||||
return this.binaryNumber(other, func);
|
||||
}
|
||||
return this.binaryValue(other, func);
|
||||
}
|
||||
|
||||
private binaryNumber(other: number, func: (a: number, b: number) => number) {
|
||||
if (this.date === null || this.value === null) {
|
||||
return new Value(null, null, '');
|
||||
}
|
||||
const oldestDate = this.getOldestDate(other);
|
||||
const difference = func(this.value, other);
|
||||
return new Value(oldestDate, difference, this.unit);
|
||||
}
|
||||
|
||||
private binaryValue(other: Value, func: (a: number, b: number) => number) {
|
||||
if (this.date === null || this.value === null) {
|
||||
return new Value(null, null, other.unit);
|
||||
}
|
||||
@ -80,7 +78,50 @@ export class Value {
|
||||
return new Value(oldestDate, difference, this.unit);
|
||||
}
|
||||
|
||||
compare(other: Value, comparing?: (a: number, b: number) => number): number {
|
||||
/* COMPARE -------------------------------------------------------------------------------------- */
|
||||
|
||||
ne(other: V): boolean {
|
||||
return this.compare(other) !== 0;
|
||||
}
|
||||
|
||||
eq(other: V): boolean {
|
||||
return this.compare(other) === 0;
|
||||
}
|
||||
|
||||
gt(other: V): boolean {
|
||||
return this.compare(other) > 0;
|
||||
}
|
||||
|
||||
gte(other: V): boolean {
|
||||
return this.compare(other) >= 0;
|
||||
}
|
||||
|
||||
lt(other: V): boolean {
|
||||
return this.compare(other) < 0;
|
||||
}
|
||||
|
||||
lte(other: V): boolean {
|
||||
return this.compare(other) <= 0;
|
||||
}
|
||||
|
||||
compare(other: V, comparing?: (a: number, b: number) => number): number {
|
||||
if (typeof other === 'number') {
|
||||
return this.compareNumber(comparing, other);
|
||||
}
|
||||
return this.compareValue(other, comparing);
|
||||
}
|
||||
|
||||
private compareNumber(comparing: ((a: number, b: number) => number) | undefined, other: number) {
|
||||
if (this.date === null || this.value === null) {
|
||||
return -1;
|
||||
}
|
||||
if (comparing === undefined) {
|
||||
return this.value - other;
|
||||
}
|
||||
return comparing(this.value, other);
|
||||
}
|
||||
|
||||
private compareValue(other: Value, comparing: ((a: number, b: number) => number) | undefined) {
|
||||
if (this.date === null || this.value === null) {
|
||||
return -1;
|
||||
}
|
||||
@ -93,6 +134,8 @@ export class Value {
|
||||
return comparing(this.value, other.value);
|
||||
}
|
||||
|
||||
/* COLOR ---------------------------------------------------------------------------------------- */
|
||||
|
||||
color(middle: number, high: number, smallColor: string = '#23F', middleColor: string = 'orange', highColor: string = 'red'): string {
|
||||
if (this.value === null) {
|
||||
return "";
|
||||
@ -105,7 +148,20 @@ export class Value {
|
||||
return highColor;
|
||||
}
|
||||
|
||||
private getOldestDate(other: Value) {
|
||||
/* OLDEST DATE ---------------------------------------------------------------------------------- */
|
||||
|
||||
private getOldestDate(other: V) {
|
||||
if (typeof other === 'number') {
|
||||
return this.getOldestDateNumber();
|
||||
}
|
||||
return this.getOldestDateValue(other);
|
||||
}
|
||||
|
||||
private getOldestDateNumber() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
private getOldestDateValue(other: Value) {
|
||||
if (this.date === null || other.date === null) {
|
||||
return null;
|
||||
}
|
||||
@ -117,10 +173,17 @@ export class Value {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
/* MAP ------------------------------------------------------------------------------------------ */
|
||||
|
||||
map<T>(map: (v: number) => T): T | null {
|
||||
return this.value === null ? null : map(this.value);
|
||||
}
|
||||
|
||||
/* UNIT ----------------------------------------------------------------------------------------- */
|
||||
|
||||
withUnit(unit: string) {
|
||||
return new Value(this.date, this.value, unit);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ValueConstant extends Value {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
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 {ELECTRICITY_PHOTOVOLTAIC_PRODUCED_BEFORE_METER_CHANGE, GRID_KWH_EURO, MILLIS_PER_YEAR, 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";
|
||||
import {ValueConstant} from "../../../api/value/Value";
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard-amortisation',
|
||||
@ -36,17 +36,17 @@ export class DashboardAmortisationComponent {
|
||||
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 amortisationPercent = selfConsumed.div(PV_COST_AMORTISATION_KWH).mul(100).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 amortisationTotalMillis = amortisationMilliPerKWh.mul(PV_COST_AMORTISATION_KWH).withUnit('ms');
|
||||
const amortisationTotalYears = amortisationTotalMillis.div(MILLIS_PER_YEAR).withUnit('Jahre');
|
||||
const amortisationDate = new Date(this.now.getTime() + (amortisationRestMillis.value || 0));
|
||||
const amortisationDate = amortisationRestMillis.plus(this.now.getTime());
|
||||
const constRestEuro = PV_COST_TOTAL_EURO.minus(costsSaved);
|
||||
const amortisationDateString = 'Erwarte volle Amortisation am: ' + this.datePipe.transform(amortisationDate, 'dd. MMM yyyy');
|
||||
const amortisationDateString = 'Erwarte volle Amortisation am: ' + this.datePipe.transform(amortisationDate.map(v => new Date(v)), 'dd. MMM yyyy');
|
||||
return [
|
||||
new DisplayValue('Ausgaben', PV_COST_TOTAL_EURO),
|
||||
new DisplayValue('Ersparnis', costsSaved),
|
||||
|
||||
@ -5,7 +5,7 @@ import {SeriesCacheService} from "../../../api/series/series-cache.service";
|
||||
import {SliceService} from "../../../api/series/consumption/slice/slice.service";
|
||||
import {Slice} from "../../../api/series/consumption/slice/Slice";
|
||||
import {Interval} from "../../../api/series/consumption/interval/Interval";
|
||||
import {ELECTRICITY_GRID_DELIVERED_ENERGY, ELECTRICITY_GRID_POWER_MUCH, ELECTRICITY_GRID_PURCHASED_ENERGY, ELECTRICITY_GRID_PURCHASED_FEW, ELECTRICITY_GRID_PURCHASED_MUCH, ELECTRICITY_PHOTOVOLTAIC_POWER_FEW, ELECTRICITY_PHOTOVOLTAIC_POWER_MUCH, ELECTRICITY_PHOTOVOLTAIC_PRODUCED, ELECTRICITY_PHOTOVOLTAIC_PRODUCED_BEFORE_METER_CHANGE, ELECTRICITY_PHOTOVOLTAIC_PRODUCED_FEW, ELECTRICITY_PHOTOVOLTAIC_PRODUCED_MUCH, PERCENT} from "../../../api/series/constants";
|
||||
import {ELECTRICITY_GRID_DELIVERED_ENERGY, ELECTRICITY_GRID_POWER_MUCH, ELECTRICITY_GRID_PURCHASED_ENERGY, ELECTRICITY_GRID_PURCHASED_FEW, ELECTRICITY_GRID_PURCHASED_MUCH, ELECTRICITY_PHOTOVOLTAIC_POWER_FEW, ELECTRICITY_PHOTOVOLTAIC_POWER_MUCH, ELECTRICITY_PHOTOVOLTAIC_PRODUCED, ELECTRICITY_PHOTOVOLTAIC_PRODUCED_BEFORE_METER_CHANGE, ELECTRICITY_PHOTOVOLTAIC_PRODUCED_FEW, ELECTRICITY_PHOTOVOLTAIC_PRODUCED_MUCH} from "../../../api/series/constants";
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard-electricity-tile',
|
||||
@ -63,13 +63,13 @@ export class DashboardElectricityTileComponent {
|
||||
|
||||
const selfToday = this.producedToday.minus(this.deliveredToday);
|
||||
const consumedToday = this.purchasedToday.plus(selfToday);
|
||||
const selfPercentToday = selfToday.div(this.producedToday).mul(PERCENT).withUnit('%');
|
||||
const selfAutarkyPercentToday = selfToday.div(consumedToday).mul(PERCENT).withUnit('%');
|
||||
const selfPercentToday = selfToday.div(this.producedToday).mul(100).withUnit('%');
|
||||
const selfAutarkyPercentToday = selfToday.div(consumedToday).mul(100).withUnit('%');
|
||||
|
||||
const selfYesterday = this.producedYesterday.minus(this.deliveredYesterday);
|
||||
const consumedYesterday = this.purchasedYesterday.plus(selfYesterday);
|
||||
const selfPercentYesterday = selfYesterday.div(this.producedYesterday).mul(PERCENT).withUnit('%');
|
||||
const selfAutarkyPercentYesterday = selfYesterday.div(consumedYesterday).mul(PERCENT).withUnit('%');
|
||||
const selfPercentYesterday = selfYesterday.div(this.producedYesterday).mul(100).withUnit('%');
|
||||
const selfAutarkyPercentYesterday = selfYesterday.div(consumedYesterday).mul(100).withUnit('%');
|
||||
|
||||
return [
|
||||
'Zählerstände',
|
||||
|
||||
@ -5,14 +5,24 @@
|
||||
</div>
|
||||
<table class="values">
|
||||
<ng-container *ngFor="let item of displayList">
|
||||
<tr class="rate" *ngIf="asDisplay(item)" [style.color]="asDisplay(item)?.color">
|
||||
<tr class="rate" *ngIf="asDisplay(item) !== null" [style.color]="asDisplay(item)?.color">
|
||||
<th>{{ asDisplay(item)?.title }}</th>
|
||||
|
||||
<ng-container *ngIf="asDisplayNumber(item) !== null">
|
||||
<td class="v">
|
||||
{{ asDisplay(item)?.value?.value | number:'0.1-1' }}
|
||||
{{ asDisplayNumber(item)?.value | number:'0.1-1' }}
|
||||
</td>
|
||||
<td class="u">
|
||||
{{ asDisplay(item)?.value?.unit }}
|
||||
{{ asDisplayNumber(item)?.unit }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="asDisplayString(item) !== null">
|
||||
<td class="v" colspan="2">
|
||||
{{ asDisplayString(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
</tr>
|
||||
<tr *ngIf="asString(item)">
|
||||
<td colspan="3" class="header">
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {DecimalPipe, NgForOf, NgIf} from "@angular/common";
|
||||
import {Display, DisplayValue} from "../../api/value/Display";
|
||||
import {Value} from "../../api/value/Value";
|
||||
|
||||
@Component({
|
||||
selector: 'app-value-list',
|
||||
@ -53,7 +54,7 @@ export class ValueListComponent {
|
||||
private displayUpdate() {
|
||||
this.valid = this.displayList
|
||||
.filter(d => d instanceof DisplayValue)
|
||||
.some(d => !!d && !!d.value && !!d.value.date && (this.now.getTime() - d.value.date.getTime()) <= this.maxAgeSeconds * 1000)
|
||||
.some(d => !!d && !!d.value && (!(typeof d.value === 'object' && 'date' in d.value) || !!d.value.date && (this.now.getTime() - d.value.date.getTime()) <= this.maxAgeSeconds * 1000));
|
||||
}
|
||||
|
||||
asDisplay(item: Display): DisplayValue | null {
|
||||
@ -70,4 +71,22 @@ export class ValueListComponent {
|
||||
return null;
|
||||
}
|
||||
|
||||
asDisplayNumber(value: DisplayValue | string | null): Value | null {
|
||||
if (value instanceof DisplayValue) {
|
||||
if (value.value instanceof Value) {
|
||||
return value.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
asDisplayString(value: DisplayValue | string | null): string | null {
|
||||
if (value instanceof DisplayValue) {
|
||||
if (typeof value.value === 'string') {
|
||||
return value.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user