series-history current/history

This commit is contained in:
Patrick Haßel 2025-10-30 08:36:13 +01:00
parent 320729647e
commit 26baa904dd
19 changed files with 318 additions and 107 deletions

View File

@ -1,13 +1,18 @@
<div class="MainMenu NoUserSelect"> <div class="MainMenu NoUserSelect">
<div class="MainMenuBar"> <div class="MainMenuBar">
<div class="MainMenuButton" (click)="showDrawer = !showDrawer"> <div class="MainMenuItem MainMenuButton" (click)="showDrawer = !showDrawer">
<fa-icon [icon]="faBars"></fa-icon> <fa-icon [icon]="faBars"></fa-icon>
</div> </div>
<div class="MainMenuItem MainMenuTitle">
{{ menuService.title }}
</div>
</div> </div>
</div> </div>
<div class="MainMenuDrawer NoUserSelect" [hidden]="!showDrawer"> <div class="MainMenuDrawer NoUserSelect" [hidden]="!showDrawer">
<div class="MainMenuItem" routerLink="Location" routerLinkActive="MainMenuItemActive">Orte</div> @for (location of locationList; track location.id) {
<div class="MainMenuItem" routerLink="Location/{{ location.id }}" routerLinkActive="MainMenuItemActive" (click)="showDrawer = false">{{ location.name }}</div>
}
</div> </div>
<router-outlet/> <router-outlet/>

View File

@ -7,6 +7,10 @@
display: flex; display: flex;
padding: 0.25em; padding: 0.25em;
.MainMenuItem {
padding: 0.25em;
}
.MainMenuButton { .MainMenuButton {
padding: 0.25em; padding: 0.25em;
border: 1px solid #888; border: 1px solid #888;
@ -16,6 +20,7 @@
.MainMenuButton:hover { .MainMenuButton:hover {
background-color: lightskyblue; background-color: lightskyblue;
} }
} }
} }

View File

@ -1,7 +1,10 @@
import {Component} from '@angular/core'; import {Component, OnDestroy, OnInit} from '@angular/core';
import {RouterLink, RouterLinkActive, RouterOutlet} from '@angular/router'; import {RouterLink, RouterLinkActive, RouterOutlet} from '@angular/router';
import {FaIconComponent} from '@fortawesome/angular-fontawesome'; import {FaIconComponent} from '@fortawesome/angular-fontawesome';
import {faBars, faBurger} from '@fortawesome/free-solid-svg-icons'; import {faBars} from '@fortawesome/free-solid-svg-icons';
import {MenuService} from './menu-service';
import {Location} from './location/Location';
import {LocationService} from './location/location-service';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -9,11 +12,28 @@ import {faBars, faBurger} from '@fortawesome/free-solid-svg-icons';
templateUrl: './app.html', templateUrl: './app.html',
styleUrl: './app.less' styleUrl: './app.less'
}) })
export class App { export class App implements OnInit, OnDestroy {
protected readonly faBurger = faBurger;
protected readonly faBars = faBars; protected readonly faBars = faBars;
protected showDrawer: boolean = false; protected showDrawer: boolean = false;
protected locationList: Location[] = [];
constructor(
readonly locationService: LocationService,
readonly menuService: MenuService,
) {
//
}
ngOnInit(): void {
this.locationService.findAll(list => this.locationList = list);
this.menuService.title = "Orte";
}
ngOnDestroy(): void {
this.menuService.title = "";
}
} }

View File

@ -5,30 +5,47 @@
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">
<div class="Section4"> <div class="Section4">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Bezogen Bezug
</div> </div>
<div class="SectionBody"> <div class="SectionBody purchase">
{{ historyEnergyPurchase?.valueString }} {{ purchase?.toValueString(true, interval ? null : now) }}
</div> </div>
</div> </div>
<div class="Section4"> <div class="Section4">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Eingespeist Solar
</div> </div>
<div class="SectionBody"> <div class="SectionBody produce">
{{ historyEnergyDeliver?.valueString }} {{ produce?.toValueString(true, interval ? null : now) }}
</div> </div>
</div> </div>
<div class="Section4"> <div class="Section4">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Erzeugt Verbrauch
</div> </div>
<div class="SectionBody"> <div class="SectionBody consume">
{{ historyEnergyProduce?.valueString }} {{ consume?.toValueString(true, interval ? null : now) }}
</div> </div>
</div> </div>
<div class="Section4">
<div class="SectionHeadingText">
Einspeisung
</div> </div>
<app-series-history-graph></app-series-history-graph> <div class="SectionBody deliver">
{{ deliver?.toValueString(true, interval ? null : now) }}
</div>
</div>
</div>
@if (interval) {
<!-- <app-series-history-graph></app-series-history-graph>-->
}
</div> </div>

View File

@ -0,0 +1 @@
@import "../../../../colors";

View File

@ -1,30 +1,33 @@
import {AfterViewInit, Component, Input} from '@angular/core'; import {AfterViewInit, Component, Input, OnDestroy, OnInit} from '@angular/core';
import {Location} from '../../Location'; import {Location} from '../../Location';
import {Series} from '../../../series/Series'; import {Series} from '../../../series/Series';
import {Next} from '../../../common'; import {Next} from '../../../common';
import {SeriesHistoryGraph} from './graph/simple-plot.component';
import {Interval} from '../../../series/Interval'; import {Interval} from '../../../series/Interval';
import {PointService} from '../../../point/point-service'; import {PointService} from '../../../point/point-service';
import {PointSeries} from '../../../point/PointSeries'; import {SeriesService} from '../../../series/series-service';
import {Subscription} from 'rxjs';
import {Value} from '../../../series/Value';
@Component({ @Component({
selector: 'app-series-history', selector: 'app-series-history',
imports: [ imports: [],
SeriesHistoryGraph
],
templateUrl: './series-history.html', templateUrl: './series-history.html',
styleUrl: './series-history.less', styleUrl: './series-history.less',
}) })
export class SeriesHistory implements AfterViewInit { export class SeriesHistory implements OnInit, AfterViewInit, OnDestroy {
protected historyEnergyPurchase: PointSeries | null = null;
protected historyEnergyDeliver: PointSeries | null = null;
protected historyEnergyProduce: PointSeries | null = null;
protected readonly Interval = Interval; protected readonly Interval = Interval;
private readonly subs: Subscription[] = [];
protected purchase: Value | null = null;
protected deliver: Value | null = null;
protected produce: Value | null = null;
protected consume: Value | null = null;
@Input() @Input()
heading!: string; heading!: string;
@ -32,41 +35,80 @@ export class SeriesHistory implements AfterViewInit {
offset: number = 0; offset: number = 0;
@Input() @Input()
interval!: Interval; interval: Interval | null = null;
@Input() @Input()
location!: Location; location!: Location;
@Input()
now: Date = new Date();
constructor( constructor(
readonly pointService: PointService, readonly pointService: PointService,
readonly serieService: SeriesService,
) { ) {
// //
} }
ngAfterViewInit(): void { ngOnInit(): void {
this.history(this.location?.energyPurchase, history => this.historyEnergyPurchase = history); this.subs.push(this.serieService.subscribe(this.update));
this.history(this.location?.energyDeliver, history => this.historyEnergyDeliver = history);
this.history(this.location?.energyProduce, history => this.historyEnergyProduce = history);
} }
public readonly updateSeries = (fresh: Series): void => { ngAfterViewInit(): void {
if (fresh.id === this.location?.energyPurchase?.id) { if (this.interval) {
this.history(this.location?.energyPurchase, history => this.historyEnergyPurchase = history); this.history(null, this.location?.energyPurchase, history => this.purchase = history);
this.history(null, this.location?.energyDeliver, history => this.deliver = history);
this.history(null, this.location?.energyProduce, history => this.produce = history);
} else {
this.history(null, this.location?.powerPurchase, history => this.purchase = history);
this.history(null, this.location?.powerDeliver, history => this.deliver = history);
this.history(null, this.location?.powerProduce, history => this.produce = history);
} }
if (fresh.id === this.location?.energyDeliver?.id) {
this.history(this.location?.energyDeliver, history => this.historyEnergyDeliver = history);
} }
if (fresh.id === this.location?.energyProduce?.id) {
this.history(this.location?.energyProduce, history => this.historyEnergyProduce = history); ngOnDestroy(): void {
this.subs.forEach(sub => sub.unsubscribe());
}
protected readonly update = (fresh: Series): void => {
if (this.interval) {
if (this.offset > 0) {
return;
}
this.history(fresh, this.location?.energyPurchase, value => this.purchase = value);
this.history(fresh, this.location?.energyDeliver, value => this.deliver = value);
this.history(fresh, this.location?.energyProduce, value => this.produce = value);
} else {
this.history(fresh, this.location?.powerPurchase, value => this.purchase = value);
this.history(fresh, this.location?.powerDeliver, value => this.deliver = value);
this.history(fresh, this.location?.powerProduce, value => this.produce = value);
} }
}; };
private history(series: Series | null | undefined, next: Next<PointSeries | null>) { private history(fresh: Series | null | undefined, series: Series | null | undefined, next: Next<Value | null>) {
if (!series || !this.interval) { const n = (value: Value | null) => {
next(null); next(value);
this.consume = this.purchase?.plus(this.produce)?.minus(this.deliver) || null;
}
if (fresh !== null && fresh !== undefined) {
if (fresh.id !== series?.id) {
return;
}
series = fresh;
}
if (!series) {
n(null);
return return
} }
this.pointService.relative([series], this.interval, this.offset, 1, response => next(response.series[0])); if (this.interval) {
this.pointService.relative([series], this.interval, this.offset, 1, response => n(Value.ofPoint(response, 0, 0, 1)));
} else {
n(series.value);
}
}
protected nullOrZero(value: Value | null | undefined): boolean {
return value === null || value === undefined || value.value === 0;
} }
} }

View File

@ -1,8 +1,10 @@
@if (location) { @if (location) {
<app-series-history [location]="location" [interval]="Interval.DAY" [offset]="0" heading="Heute" #today></app-series-history> <app-series-history [now]="now" [location]="location" [interval]="null" heading="Aktuell"></app-series-history>
<app-series-history [location]="location" [interval]="Interval.DAY" [offset]="1" heading="Gestern"></app-series-history> <app-series-history [now]="now" [location]="location" [interval]="Interval.DAY" heading="Heute"></app-series-history>
<app-series-history [now]="now" [location]="location" [interval]="Interval.DAY" [offset]="1" heading="Gestern"></app-series-history>
<div class="Section"> <div class="Section">
<div class="SectionHeading"> <div class="SectionHeading">
@ -14,7 +16,7 @@
<div class="Section2"> <div class="Section2">
<div class="SectionHeading"> <div class="SectionHeading">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Name: Name
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">
@ -24,7 +26,7 @@
<div class="Section2"> <div class="Section2">
<div class="SectionHeading"> <div class="SectionHeading">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Breitegrad: Breitegrad
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">
@ -34,7 +36,7 @@
<div class="Section2"> <div class="Section2">
<div class="SectionHeading"> <div class="SectionHeading">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Längengrad: Längengrad
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">
@ -54,7 +56,7 @@
<div class="Section2"> <div class="Section2">
<div class="SectionHeading"> <div class="SectionHeading">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Bezug: Bezug
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">
@ -64,7 +66,7 @@
<div class="Section2"> <div class="Section2">
<div class="SectionHeading"> <div class="SectionHeading">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Einspeisung: Einspeisung
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">
@ -74,7 +76,7 @@
<div class="Section2"> <div class="Section2">
<div class="SectionHeading"> <div class="SectionHeading">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Erzeugung: Erzeugung
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">
@ -94,7 +96,7 @@
<div class="Section2"> <div class="Section2">
<div class="SectionHeading"> <div class="SectionHeading">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Bezug: Bezug
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">
@ -104,7 +106,7 @@
<div class="Section2"> <div class="Section2">
<div class="SectionHeading"> <div class="SectionHeading">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Einspeisung: Einspeisung
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">
@ -114,7 +116,7 @@
<div class="Section2"> <div class="Section2">
<div class="SectionHeading"> <div class="SectionHeading">
<div class="SectionHeadingText"> <div class="SectionHeadingText">
Erzeugung: Erzeugung
</div> </div>
</div> </div>
<div class="SectionBody"> <div class="SectionBody">

View File

@ -1,4 +1,4 @@
import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {Component, OnDestroy, OnInit} from '@angular/core';
import {LocationService} from '../location-service'; import {LocationService} from '../location-service';
import {ActivatedRoute} from '@angular/router'; import {ActivatedRoute} from '@angular/router';
import {Location} from '../Location'; import {Location} from '../Location';
@ -11,6 +11,7 @@ import {SeriesType} from '../../series/SeriesType';
import {Subscription, timer} from 'rxjs'; import {Subscription, timer} from 'rxjs';
import {SeriesHistory} from './history/series-history'; import {SeriesHistory} from './history/series-history';
import {Interval} from '../../series/Interval'; import {Interval} from '../../series/Interval';
import {MenuService} from '../../menu-service';
function yesterday(now: any) { function yesterday(now: any) {
const yesterday = new Date(now.getTime()); const yesterday = new Date(now.getTime());
@ -31,9 +32,6 @@ function yesterday(now: any) {
}) })
export class LocationDetail implements OnInit, OnDestroy { export class LocationDetail implements OnInit, OnDestroy {
@ViewChild("today")
protected today!: SeriesHistory;
protected readonly Interval = Interval; protected readonly Interval = Interval;
protected location: Location | null = null; protected location: Location | null = null;
@ -50,13 +48,17 @@ export class LocationDetail implements OnInit, OnDestroy {
readonly locationService: LocationService, readonly locationService: LocationService,
readonly seriesService: SeriesService, readonly seriesService: SeriesService,
readonly activatedRoute: ActivatedRoute, readonly activatedRoute: ActivatedRoute,
readonly menuService: MenuService,
) { ) {
// //
} }
ngOnInit(): void { ngOnInit(): void {
this.activatedRoute.params.subscribe(params => { this.activatedRoute.params.subscribe(params => {
this.locationService.getById(params['id'], location => this.location = location); this.locationService.getById(params['id'], location => {
this.location = location;
this.menuService.title = this.location.name;
});
}); });
this.seriesService.findAll(list => this.series = list); this.seriesService.findAll(list => this.series = list);
this.subs.push(this.seriesService.subscribe(this.updateSeries)); this.subs.push(this.seriesService.subscribe(this.updateSeries));
@ -67,6 +69,7 @@ export class LocationDetail implements OnInit, OnDestroy {
} }
ngOnDestroy(): void { ngOnDestroy(): void {
this.menuService.title = "";
this.subs.forEach(sub => sub.unsubscribe()); this.subs.forEach(sub => sub.unsubscribe());
} }
@ -83,7 +86,6 @@ export class LocationDetail implements OnInit, OnDestroy {
} else { } else {
this.series.push(fresh); this.series.push(fresh);
} }
this.today.updateSeries(fresh);
}; };
protected readonly filterEnergy = (): Series[] => { protected readonly filterEnergy = (): Series[] => {

View File

@ -1,7 +1,8 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnDestroy, OnInit} from '@angular/core';
import {LocationService} from '../location-service'; import {LocationService} from '../location-service';
import {Location} from '../Location'; import {Location} from '../Location';
import {RouterLink} from '@angular/router'; import {RouterLink} from '@angular/router';
import {MenuService} from '../../menu-service';
@Component({ @Component({
selector: 'app-location-list', selector: 'app-location-list',
@ -11,18 +12,24 @@ import {RouterLink} from '@angular/router';
templateUrl: './location-list.html', templateUrl: './location-list.html',
styleUrl: './location-list.less', styleUrl: './location-list.less',
}) })
export class LocationList implements OnInit { export class LocationList implements OnInit, OnDestroy {
protected list: Location[] = []; protected list: Location[] = [];
constructor( constructor(
readonly locationService: LocationService, readonly locationService: LocationService,
readonly menuService: MenuService,
) { ) {
// //
} }
ngOnInit(): void { ngOnInit(): void {
this.locationService.findAll(list => this.list = list); this.locationService.findAll(list => this.list = list);
this.menuService.title = "Orte";
}
ngOnDestroy(): void {
this.menuService.title = "";
} }
} }

View File

@ -0,0 +1,10 @@
import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class MenuService {
title: string = "";
}

View File

@ -3,13 +3,11 @@ import {validateList, validateNumber} from "../common";
export class PointSeries { export class PointSeries {
readonly valueString: string;
constructor( constructor(
readonly series: Series, readonly series: Series,
readonly points: number[][], readonly points: number[][],
) { ) {
this.valueString = series.getValueString(points.length === 0 ? null : points[0][1]); //
} }
static fromJson(json: any): PointSeries { static fromJson(json: any): PointSeries {

View File

@ -1,48 +1,36 @@
import {or, validateDate, validateEnum, validateNumber, validateString} from "../common"; import {or, validateDate, validateEnum, validateNumber, validateString} from "../common";
import {SeriesType} from './SeriesType'; import {SeriesType} from './SeriesType';
import {formatNumber} from '@angular/common'; import {Value} from './Value';
export class Series { export class Series {
readonly valueString: string; readonly value: Value | null = null;
constructor( constructor(
readonly id: number, readonly id: number,
readonly name: string, readonly name: string,
readonly decimals: number, readonly precision: number,
readonly seconds: number, readonly seconds: number,
readonly value: number | null,
readonly last: Date | null,
readonly unit: string,
readonly type: SeriesType, readonly type: SeriesType,
value: number | null,
readonly unit: string,
readonly last: Date | null,
) { ) {
this.valueString = this.getValueString(value); this.value = Value.of(this, value, last);
}
getValueString(value: number | null | undefined): string {
return (value === null || value === undefined ? '-' : formatNumber(value, "de-DE", `0.${this.decimals}-${this.decimals}`)) + ' ' + this.unit;
} }
static fromJson(json: any): Series { static fromJson(json: any): Series {
return new Series( return new Series(
validateNumber(json.id), validateNumber(json.id),
validateString(json.name), validateString(json.name),
validateNumber(json.decimals), validateNumber(json.precision),
validateNumber(json.seconds), validateNumber(json.seconds),
or(json.value, validateNumber, null),
or(json.last, validateDate, null),
validateString(json.unit),
validateEnum(json.type, SeriesType), validateEnum(json.type, SeriesType),
or(json.value, validateNumber, null),
validateString(json.unit),
or(json.last, validateDate, null),
); );
} }
isOld(now: Date): boolean {
if (this.last === null) {
return true;
}
const ageSeconds = (now.getTime() - this.last.getTime()) / 1000;
return ageSeconds > this.seconds * 2.1;
}
} }

View File

@ -0,0 +1,89 @@
import {formatNumber} from '@angular/common';
import {PointResponse} from '../point/PointResponse';
import {Series} from './Series';
export class Value {
constructor(
readonly value: number,
readonly precision: number,
readonly seconds: number,
readonly unit: string,
readonly date: Date,
) {
//
}
toValueString(zeroToDash: boolean, now_ageCheckToDash: Date | null): string {
if (this.value === null || this.value === undefined) {
return "[???]";
}
if (this.value === 0) {
return zeroToDash ? "-" : `0 ${this.unit}`;
}
if (now_ageCheckToDash !== null) {
const ageSeconds = (now_ageCheckToDash.getTime() - this.date.getTime()) / 1000;
if (ageSeconds > this.seconds * 2.1) {
return `--- ${this.unit}`
}
}
const scale = Math.floor(Math.log10(this.value));
const rest = scale - this.precision + 1;
if (isNaN(rest)) {
console.log(this);
}
if (rest >= 0) {
return `${Math.round(this.value)} ${this.unit}`;
}
return formatNumber(this.value, "de-DE", `0.${-rest}-${-rest}`) + ' ' + this.unit;
}
plus(other: Value | null | undefined): Value | null {
return this.operateSameUnit("plus", other, (a, b) => a + b);
}
minus(other: Value | null | undefined): Value | null {
return this.operateSameUnit("minus", other, (a, b) => a - b);
}
operateSameUnit(operationName: string, other: Value | null | undefined, operation: (a: number, b: number) => number): Value | null {
if (!other) {
return null;
}
if (this.unit !== other.unit) {
throw new Error(`Operation '${operationName} needs units to be the same: this=${this}, other=${other}`);
}
const decimals = Math.max(this.precision, other.precision);
const seconds = Math.max(this.seconds, other.seconds);
const date = this.date.getTime() < other.date.getTime() ? this.date : other.date;
return new Value(operation(this.value, other.value), decimals, seconds, this.unit, date);
}
static of(series: Series, value: number | null | undefined, date: Date | null | undefined): Value | null {
if (value === null || value === undefined) {
return null;
}
if (date === null || date === undefined) {
throw new Error("When 'value' is set, 'last' must be set too, but isn't!")
}
return new Value(value, series.precision, series.seconds, series.unit, date);
}
static ofPoint(response: PointResponse, seriesIndex: number, pointIndex: number, valueIndex: number): Value | null {
const series = response.series[seriesIndex];
if (!series) {
return null;
}
const point = series.points[pointIndex];
if (!point) {
return null;
}
const date = new Date(point[0] * 1000);
const value = point[valueIndex];
return Value.of(series.series, value, date);
}
}

View File

@ -8,12 +8,7 @@
<option [ngValue]="null">-</option> <option [ngValue]="null">-</option>
@for (series of series; track series.id) { @for (series of series; track series.id) {
<option [ngValue]="series.id"> <option [ngValue]="series.id">
{{ series.name }}: {{ series.name }}: {{ series.value?.toValueString(false, now) }}
@if (series.isOld(now)) {
--- {{ series.unit }}
} @else {
{{ series.valueString }}
}
</option> </option>
} }
</select> </select>

View File

@ -0,0 +1,25 @@
@empty: gray;
@purchase: red;
@deliver: magenta;
@produce: #0095ff;
@consume: #ff8800;
.purchase {
color: @purchase;
}
.deliver {
color: @deliver;
}
.produce {
color: @produce;
}
.consume {
color: @consume;
}
.empty {
color: @empty !important;
}

View File

@ -32,10 +32,10 @@ div {
> .SectionHeading { > .SectionHeading {
display: flex; display: flex;
color: dimgray;
margin-top: -1.25em; margin-top: -1.25em;
> .SectionHeadingText { > .SectionHeadingText {
font-weight: bold;
background-color: white; background-color: white;
} }
} }
@ -45,7 +45,9 @@ div {
overflow: visible; overflow: visible;
> .SectionHeading { > .SectionHeading {
color: dimgray;
> .SectionHeadingText { > .SectionHeadingText {
font-size: 70%;
font-style: italic; font-style: italic;
} }
} }
@ -65,10 +67,10 @@ div {
> .SectionHeading { > .SectionHeading {
display: flex; display: flex;
color: dimgray;
margin-top: -1.25em; margin-top: -1.25em;
> .SectionHeadingText { > .SectionHeadingText {
font-weight: bold;
background-color: white; background-color: white;
} }
} }
@ -81,14 +83,17 @@ div {
.Section4 { .Section4 {
flex: 1; flex: 1;
text-align: center;
> .SectionHeadingText { > .SectionHeadingText {
font-weight: bold; text-align: right;
font-size: 70%;
color: dimgray;
font-style: italic;
background-color: white; background-color: white;
} }
> .SectionBody { > .SectionBody {
text-align: right;
} }
} }

View File

@ -42,7 +42,7 @@ public class Series {
@Setter @Setter
@Column(nullable = false) @Column(nullable = false)
private int decimals = 1; private int precision = 2;
@Column @Column
@Nullable @Nullable
@ -66,10 +66,10 @@ public class Series {
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
private SeriesType type = SeriesType.VARYING; private SeriesType type = SeriesType.VARYING;
public Series(@NonNull final String name, @NonNull final String unit, final int decimals, final int seconds, @NonNull final SeriesType type) { public Series(@NonNull final String name, @NonNull final String unit, final int precision, final int seconds, @NonNull final SeriesType type) {
this.name = name; this.name = name;
this.unit = unit; this.unit = unit;
this.decimals = decimals; this.precision = precision;
this.seconds = seconds; this.seconds = seconds;
this.type = type; this.type = type;
} }

View File

@ -42,7 +42,7 @@ public class SeriesController {
@NonNull @NonNull
@PostMapping("{id}/decimals") @PostMapping("{id}/decimals")
public SeriesDto decimals(@PathVariable final long id, @RequestBody final int decimals) { public SeriesDto decimals(@PathVariable final long id, @RequestBody final int decimals) {
return seriesService.modify(id, series -> series.setDecimals(decimals)); return seriesService.modify(id, series -> series.setPrecision(decimals));
} }
@NonNull @NonNull

View File

@ -19,7 +19,7 @@ public class SeriesDto implements IWebsocketMessage {
@NonNull @NonNull
public final String unit; public final String unit;
public final int decimals; public final int precision;
@Nullable @Nullable
public final ZonedDateTime first; public final ZonedDateTime first;
@ -40,7 +40,7 @@ public class SeriesDto implements IWebsocketMessage {
this.version = series.getVersion(); this.version = series.getVersion();
this.name = series.getName(); this.name = series.getName();
this.unit = series.getUnit(); this.unit = series.getUnit();
this.decimals = series.getDecimals(); this.precision = series.getPrecision();
this.first = series.getFirst(); this.first = series.getFirst();
this.last = series.getLast(); this.last = series.getLast();
this.value = series.getValue(); this.value = series.getValue();