REFACTOR: points (request, response)
This commit is contained in:
parent
03ad1615d2
commit
320729647e
@ -0,0 +1,9 @@
|
|||||||
|
<div class="segments">
|
||||||
|
@for (segment of segments; track segment) {
|
||||||
|
<div class="segment">
|
||||||
|
<!-- @for (graph of graphs; track graph) {-->
|
||||||
|
<!-- <div class="" [style.background-color]="graph[0]" [style.height.%]="graph[1][segment] / total(segment) * 100"></div>-->
|
||||||
|
<!-- }-->
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
.segments {
|
||||||
|
display: flex;
|
||||||
|
height: 4em;
|
||||||
|
|
||||||
|
.segment {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
import {AfterViewInit, Component, Input} from '@angular/core';
|
||||||
|
import {Location} from '../../../Location';
|
||||||
|
import {Interval} from '../../../../series/Interval';
|
||||||
|
import {PointService} from '../../../../point/point-service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-series-history-graph',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './simple-plot.component.html',
|
||||||
|
styleUrl: './simple-plot.component.less',
|
||||||
|
})
|
||||||
|
export class SeriesHistoryGraph implements AfterViewInit {
|
||||||
|
|
||||||
|
protected segments = Array.from(Array(288).keys());
|
||||||
|
|
||||||
|
protected totals: number[] = [];
|
||||||
|
|
||||||
|
protected historyEnergyPurchase: number[] | null = null;
|
||||||
|
|
||||||
|
protected historyEnergyDeliver: number[] | null = null;
|
||||||
|
|
||||||
|
protected historyEnergyProduce: number[] | null = null;
|
||||||
|
|
||||||
|
protected readonly Interval = Interval;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
heading!: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
date!: Date;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
interval!: Interval;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
location!: Location;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly pointService: PointService,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
// this.history(this.location?.energyPurchase, history => this.historyEnergyPurchase = history);
|
||||||
|
// this.history(this.location?.energyDeliver, history => this.historyEnergyDeliver = history);
|
||||||
|
// this.history(this.location?.energyProduce, history => this.historyEnergyProduce = history);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public readonly updateSeries = (fresh: Series): void => {
|
||||||
|
// if (fresh.id === this.location?.energyPurchase?.id) {
|
||||||
|
// this.history(this.location?.energyPurchase, history => this.historyEnergyPurchase = 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);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// private history(series: Series | null | undefined, next: Next<number[] | null>) {
|
||||||
|
// if (!series || !this.interval) {
|
||||||
|
// next(null);
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// this.pointService.points(series, this.date, this.interval, next);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
@ -30,4 +30,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<app-series-history-graph></app-series-history-graph>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,23 +1,27 @@
|
|||||||
import {AfterViewInit, Component, Input} from '@angular/core';
|
import {AfterViewInit, Component, Input} from '@angular/core';
|
||||||
import {History} from '../../../series/History';
|
|
||||||
import {Location} from '../../Location';
|
import {Location} from '../../Location';
|
||||||
import {Series} from '../../../series/Series';
|
import {Series} from '../../../series/Series';
|
||||||
import {Interval, SeriesService} from '../../../series/series-service';
|
|
||||||
import {Next} from '../../../common';
|
import {Next} from '../../../common';
|
||||||
|
import {SeriesHistoryGraph} from './graph/simple-plot.component';
|
||||||
|
import {Interval} from '../../../series/Interval';
|
||||||
|
import {PointService} from '../../../point/point-service';
|
||||||
|
import {PointSeries} from '../../../point/PointSeries';
|
||||||
|
|
||||||
@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 AfterViewInit {
|
||||||
|
|
||||||
protected historyEnergyPurchase: History | null = null;
|
protected historyEnergyPurchase: PointSeries | null = null;
|
||||||
|
|
||||||
protected historyEnergyDeliver: History | null = null;
|
protected historyEnergyDeliver: PointSeries | null = null;
|
||||||
|
|
||||||
protected historyEnergyProduce: History | null = null;
|
protected historyEnergyProduce: PointSeries | null = null;
|
||||||
|
|
||||||
protected readonly Interval = Interval;
|
protected readonly Interval = Interval;
|
||||||
|
|
||||||
@ -25,7 +29,7 @@ export class SeriesHistory implements AfterViewInit {
|
|||||||
heading!: string;
|
heading!: string;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
date!: Date;
|
offset: number = 0;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
interval!: Interval;
|
interval!: Interval;
|
||||||
@ -34,7 +38,7 @@ export class SeriesHistory implements AfterViewInit {
|
|||||||
location!: Location;
|
location!: Location;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly seriesService: SeriesService,
|
readonly pointService: PointService,
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
@ -57,12 +61,12 @@ export class SeriesHistory implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private history(series: Series | null | undefined, next: Next<History | null>) {
|
private history(series: Series | null | undefined, next: Next<PointSeries | null>) {
|
||||||
if (!series || !this.interval) {
|
if (!series || !this.interval) {
|
||||||
next(null);
|
next(null);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.seriesService.history(series, this.date, this.interval, next);
|
this.pointService.relative([series], this.interval, this.offset, 1, response => next(response.series[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
@if (location) {
|
@if (location) {
|
||||||
|
|
||||||
<app-series-history [location]="location" [interval]="Interval.DAY" [date]="now" heading="Heute" #today></app-series-history>
|
<app-series-history [location]="location" [interval]="Interval.DAY" [offset]="0" heading="Heute" #today></app-series-history>
|
||||||
|
|
||||||
<app-series-history [location]="location" [interval]="Interval.DAY" [date]="yesterday" heading="Gestern"></app-series-history>
|
<app-series-history [location]="location" [interval]="Interval.DAY" [offset]="1" heading="Gestern"></app-series-history>
|
||||||
|
|
||||||
<div class="Section">
|
<div class="Section">
|
||||||
<div class="SectionHeading">
|
<div class="SectionHeading">
|
||||||
|
|||||||
@ -6,10 +6,11 @@ import {Text} from '../../shared/text/text';
|
|||||||
import {Number} from '../../shared/number/number';
|
import {Number} from '../../shared/number/number';
|
||||||
import {SeriesSelect} from '../../series/select/series-select';
|
import {SeriesSelect} from '../../series/select/series-select';
|
||||||
import {Series} from '../../series/Series';
|
import {Series} from '../../series/Series';
|
||||||
import {Interval, SeriesService} from '../../series/series-service';
|
import {SeriesService} from '../../series/series-service';
|
||||||
import {SeriesType} from '../../series/SeriesType';
|
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';
|
||||||
|
|
||||||
function yesterday(now: any) {
|
function yesterday(now: any) {
|
||||||
const yesterday = new Date(now.getTime());
|
const yesterday = new Date(now.getTime());
|
||||||
|
|||||||
23
src/main/angular/src/app/point/PointResponse.ts
Normal file
23
src/main/angular/src/app/point/PointResponse.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import {validateDate, validateList} from "../common";
|
||||||
|
|
||||||
|
import {PointSeries} from './PointSeries';
|
||||||
|
|
||||||
|
export class PointResponse {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly begin: Date,
|
||||||
|
readonly end: Date,
|
||||||
|
readonly series: PointSeries[],
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): PointResponse {
|
||||||
|
return new PointResponse(
|
||||||
|
validateDate(json.begin),
|
||||||
|
validateDate(json.end),
|
||||||
|
validateList(json.series, PointSeries.fromJson),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
22
src/main/angular/src/app/point/PointSeries.ts
Normal file
22
src/main/angular/src/app/point/PointSeries.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import {Series} from "../series/Series";
|
||||||
|
import {validateList, validateNumber} from "../common";
|
||||||
|
|
||||||
|
export class PointSeries {
|
||||||
|
|
||||||
|
readonly valueString: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly series: Series,
|
||||||
|
readonly points: number[][],
|
||||||
|
) {
|
||||||
|
this.valueString = series.getValueString(points.length === 0 ? null : points[0][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): PointSeries {
|
||||||
|
return new PointSeries(
|
||||||
|
Series.fromJson(json.series),
|
||||||
|
validateList(json.points, list => list.map(validateNumber)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
29
src/main/angular/src/app/point/point-service.ts
Normal file
29
src/main/angular/src/app/point/point-service.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {ApiService, CrudService, Next, WebsocketService} from '../common';
|
||||||
|
import {PointResponse} from './PointResponse';
|
||||||
|
import {Series} from '../series/Series';
|
||||||
|
import {Interval} from '../series/Interval';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class PointService extends CrudService<PointResponse> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
api: ApiService,
|
||||||
|
ws: WebsocketService,
|
||||||
|
) {
|
||||||
|
super(api, ws, ['Point'], PointResponse.fromJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
relative(series: Series[], interval: Interval, offset: number, count: number, next: Next<PointResponse>): void {
|
||||||
|
const request = {
|
||||||
|
ids: series.map(s => s.id),
|
||||||
|
interval: interval,
|
||||||
|
offset: offset,
|
||||||
|
count: count,
|
||||||
|
};
|
||||||
|
this.postSingle(['relative'], request, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import {getValueString, Series} from "./Series";
|
|
||||||
import {or, validateNumber} from "../common";
|
|
||||||
|
|
||||||
export class History {
|
|
||||||
|
|
||||||
readonly valueString: string;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
readonly series: Series,
|
|
||||||
readonly value: number | null,
|
|
||||||
) {
|
|
||||||
this.valueString = getValueString(value, series);
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromJson(json: any): History {
|
|
||||||
return new History(
|
|
||||||
Series.fromJson(json.series),
|
|
||||||
or(json.value, validateNumber, null),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
8
src/main/angular/src/app/series/Interval.ts
Normal file
8
src/main/angular/src/app/series/Interval.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export enum Interval {
|
||||||
|
FIVE = 'FIVE',
|
||||||
|
HOUR = 'HOUR',
|
||||||
|
DAY = 'DAY',
|
||||||
|
WEEK = 'WEEK',
|
||||||
|
MONTH = 'MONTH',
|
||||||
|
YEAR = 'YEAR',
|
||||||
|
}
|
||||||
@ -3,10 +3,6 @@ import {or, validateDate, validateEnum, validateNumber, validateString} from "..
|
|||||||
import {SeriesType} from './SeriesType';
|
import {SeriesType} from './SeriesType';
|
||||||
import {formatNumber} from '@angular/common';
|
import {formatNumber} from '@angular/common';
|
||||||
|
|
||||||
export function getValueString(value: number | null, series: Series): string {
|
|
||||||
return (value === null ? '-' : formatNumber(value, "de-DE", `0.${series.decimals}-${series.decimals}`)) + ' ' + series.unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Series {
|
export class Series {
|
||||||
|
|
||||||
readonly valueString: string;
|
readonly valueString: string;
|
||||||
@ -21,7 +17,11 @@ export class Series {
|
|||||||
readonly unit: string,
|
readonly unit: string,
|
||||||
readonly type: SeriesType,
|
readonly type: SeriesType,
|
||||||
) {
|
) {
|
||||||
this.valueString = getValueString(value, this);
|
this.valueString = this.getValueString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|||||||
@ -1,18 +1,8 @@
|
|||||||
import {Inject, Injectable, LOCALE_ID} from '@angular/core';
|
import {Inject, Injectable, LOCALE_ID} from '@angular/core';
|
||||||
import {ApiService, CrudService, Next, WebsocketService} from '../common';
|
import {ApiService, CrudService, Next, WebsocketService} from '../common';
|
||||||
import {Series} from './Series';
|
import {Series} from './Series';
|
||||||
import {History} from './History';
|
|
||||||
import {DatePipe} from '@angular/common';
|
import {DatePipe} from '@angular/common';
|
||||||
|
|
||||||
export enum Interval {
|
|
||||||
FIVE = 'FIVE',
|
|
||||||
HOUR = 'HOUR',
|
|
||||||
DAY = 'DAY',
|
|
||||||
WEEK = 'WEEK',
|
|
||||||
MONTH = 'MONTH',
|
|
||||||
YEAR = 'YEAR',
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
@ -33,8 +23,4 @@ export class SeriesService extends CrudService<Series> {
|
|||||||
this.getList(['findAll'], next);
|
this.getList(['findAll'], next);
|
||||||
}
|
}
|
||||||
|
|
||||||
history(series: Series, date: Date, interval: Interval, next: Next<History>) {
|
|
||||||
this.api.getSingle([...this.path, series.id, 'history', Math.floor(date.getTime() / 1000), interval], History.fromJson, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
package de.ph87.data;
|
package de.ph87.data;
|
||||||
|
|
||||||
import de.ph87.data.topic.TopicDto;
|
import de.ph87.data.topic.TopicDto;
|
||||||
import de.ph87.data.topic.TopicType;
|
|
||||||
import de.ph87.data.topic.TopicService;
|
import de.ph87.data.topic.TopicService;
|
||||||
|
import de.ph87.data.topic.TopicType;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
|||||||
@ -15,8 +15,6 @@ public class PlotDto implements IWebsocketMessage {
|
|||||||
|
|
||||||
public final long version;
|
public final long version;
|
||||||
|
|
||||||
private final boolean deleted;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
@ -34,10 +32,9 @@ public class PlotDto implements IWebsocketMessage {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public final List<AxisDto> axes;
|
public final List<AxisDto> axes;
|
||||||
|
|
||||||
public PlotDto(@NonNull final Plot plot, final boolean deleted) {
|
public PlotDto(@NonNull final Plot plot) {
|
||||||
this.id = plot.getId();
|
this.id = plot.getId();
|
||||||
this.version = plot.getVersion();
|
this.version = plot.getVersion();
|
||||||
this.deleted = deleted;
|
|
||||||
this.name = plot.getName();
|
this.name = plot.getName();
|
||||||
this.interval = plot.getInterval();
|
this.interval = plot.getInterval();
|
||||||
this.offset = plot.getOffset();
|
this.offset = plot.getOffset();
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
public interface PlotRepository extends ListCrudRepository<Plot, Long> {
|
public interface PlotRepository extends ListCrudRepository<Plot, Long> {
|
||||||
|
|
||||||
@Query("select new de.ph87.data.plot.PlotDto(p, false) from Plot p")
|
@Query("select new de.ph87.data.plot.PlotDto(p) from Plot p")
|
||||||
List<PlotDto> findAllDto();
|
List<PlotDto> findAllDto();
|
||||||
|
|
||||||
@Query("select max(p.position) from Plot p")
|
@Query("select max(p.position) from Plot p")
|
||||||
|
|||||||
@ -87,7 +87,7 @@ public class PlotService {
|
|||||||
} else {
|
} else {
|
||||||
log.info("Updated: plot={}", plot);
|
log.info("Updated: plot={}", plot);
|
||||||
}
|
}
|
||||||
final PlotDto dto = new PlotDto(plot, deleted);
|
final PlotDto dto = new PlotDto(plot);
|
||||||
applicationEventPublisher.publishEvent(dto);
|
applicationEventPublisher.publishEvent(dto);
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ public class GraphDto {
|
|||||||
|
|
||||||
public final long version;
|
public final long version;
|
||||||
|
|
||||||
@NonNull
|
@Nullable
|
||||||
public final SeriesDto series;
|
public final SeriesDto series;
|
||||||
|
|
||||||
public final double factor;
|
public final double factor;
|
||||||
@ -53,10 +53,10 @@ public class GraphDto {
|
|||||||
public GraphDto(@NonNull final Graph graph) {
|
public GraphDto(@NonNull final Graph graph) {
|
||||||
this.id = graph.getId();
|
this.id = graph.getId();
|
||||||
this.version = graph.getVersion();
|
this.version = graph.getVersion();
|
||||||
this.series = new SeriesDto(graph.getSeries());
|
this.series = map(graph.getSeries(), SeriesDto::new);
|
||||||
this.factor = graph.getFactor();
|
this.factor = graph.getFactor();
|
||||||
this.operation = graph.getOperation();
|
this.operation = graph.getOperation();
|
||||||
this.series2 = map(graph.getSeries2(), false, SeriesDto::new);
|
this.series2 = map(graph.getSeries2(), SeriesDto::new);
|
||||||
this.factor2 = graph.getFactor2();
|
this.factor2 = graph.getFactor2();
|
||||||
this.name = graph.getName();
|
this.name = graph.getName();
|
||||||
this.visible = graph.isVisible();
|
this.visible = graph.isVisible();
|
||||||
|
|||||||
27
src/main/java/de/ph87/data/point/IPointRequest.java
Normal file
27
src/main/java/de/ph87/data/point/IPointRequest.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package de.ph87.data.point;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
|
import de.ph87.data.series.data.Interval;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@JsonSubTypes({
|
||||||
|
@JsonSubTypes.Type(PointRequestRelative.class),
|
||||||
|
})
|
||||||
|
public interface IPointRequest {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
List<Long> getIds();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
Interval getInterval();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
ZonedDateTime getBegin();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
ZonedDateTime getEnd();
|
||||||
|
|
||||||
|
}
|
||||||
23
src/main/java/de/ph87/data/point/PointController.java
Normal file
23
src/main/java/de/ph87/data/point/PointController.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package de.ph87.data.point;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@CrossOrigin
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("Point")
|
||||||
|
public class PointController {
|
||||||
|
|
||||||
|
private final PointService pointService;
|
||||||
|
|
||||||
|
@PostMapping("relative")
|
||||||
|
public PointResponse points(@RequestBody final PointRequestRelative request) {
|
||||||
|
return pointService.points(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
38
src/main/java/de/ph87/data/point/PointRequestRelative.java
Normal file
38
src/main/java/de/ph87/data/point/PointRequestRelative.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package de.ph87.data.point;
|
||||||
|
|
||||||
|
import de.ph87.data.series.data.Interval;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PointRequestRelative implements IPointRequest {
|
||||||
|
|
||||||
|
public final List<Long> ids;
|
||||||
|
|
||||||
|
public final Interval interval;
|
||||||
|
|
||||||
|
public final long offset;
|
||||||
|
|
||||||
|
public final long count;
|
||||||
|
|
||||||
|
public final ZonedDateTime begin;
|
||||||
|
|
||||||
|
public final ZonedDateTime end;
|
||||||
|
|
||||||
|
public PointRequestRelative(
|
||||||
|
final List<Long> ids,
|
||||||
|
final Interval interval,
|
||||||
|
final long offset,
|
||||||
|
final long count
|
||||||
|
) {
|
||||||
|
this.ids = ids;
|
||||||
|
this.interval = interval;
|
||||||
|
this.offset = offset;
|
||||||
|
this.count = count;
|
||||||
|
this.end = interval.align.apply(ZonedDateTime.now()).minus(interval.amount * (offset - 1), interval.unit);
|
||||||
|
this.begin = this.end.minus(interval.amount * count, interval.unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
17
src/main/java/de/ph87/data/point/PointResponse.java
Normal file
17
src/main/java/de/ph87/data/point/PointResponse.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package de.ph87.data.point;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PointResponse {
|
||||||
|
|
||||||
|
public final ZonedDateTime begin;
|
||||||
|
|
||||||
|
public final ZonedDateTime end;
|
||||||
|
|
||||||
|
public final List<PointSeries> series;
|
||||||
|
|
||||||
|
}
|
||||||
16
src/main/java/de/ph87/data/point/PointSeries.java
Normal file
16
src/main/java/de/ph87/data/point/PointSeries.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package de.ph87.data.point;
|
||||||
|
|
||||||
|
import de.ph87.data.series.SeriesDto;
|
||||||
|
import de.ph87.data.series.data.delta.ISeriesPoint;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PointSeries {
|
||||||
|
|
||||||
|
public final SeriesDto series;
|
||||||
|
|
||||||
|
public final List<? extends ISeriesPoint> points;
|
||||||
|
|
||||||
|
}
|
||||||
47
src/main/java/de/ph87/data/point/PointService.java
Normal file
47
src/main/java/de/ph87/data/point/PointService.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package de.ph87.data.point;
|
||||||
|
|
||||||
|
import de.ph87.data.series.Series;
|
||||||
|
import de.ph87.data.series.SeriesDto;
|
||||||
|
import de.ph87.data.series.SeriesService;
|
||||||
|
import de.ph87.data.series.data.bool.BoolService;
|
||||||
|
import de.ph87.data.series.data.delta.DeltaService;
|
||||||
|
import de.ph87.data.series.data.delta.ISeriesPoint;
|
||||||
|
import de.ph87.data.series.data.varying.VaryingService;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PointService {
|
||||||
|
|
||||||
|
private final SeriesService seriesService;
|
||||||
|
|
||||||
|
private final BoolService boolService;
|
||||||
|
|
||||||
|
private final DeltaService deltaService;
|
||||||
|
|
||||||
|
private final VaryingService varyingService;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public PointResponse points(@NonNull final IPointRequest request) {
|
||||||
|
final List<PointSeries> series = request.getIds().stream().map(s -> points(s, request)).toList();
|
||||||
|
return new PointResponse(request.getBegin(), request.getEnd(), series);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private PointSeries points(final long id, @NonNull final IPointRequest request) {
|
||||||
|
final Series series = seriesService.getById(id);
|
||||||
|
final List<? extends ISeriesPoint> points = switch (series.getType()) {
|
||||||
|
case BOOL -> boolService.points(series, request);
|
||||||
|
case DELTA -> deltaService.points(series, request);
|
||||||
|
case VARYING -> varyingService.points(series, request);
|
||||||
|
};
|
||||||
|
return new PointSeries(new SeriesDto(series), points);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,22 +0,0 @@
|
|||||||
package de.ph87.data.series;
|
|
||||||
|
|
||||||
import de.ph87.data.series.point.AllSeriesPointResponse;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class HistoryDto {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final SeriesDto series;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public final Double value;
|
|
||||||
|
|
||||||
public HistoryDto(final AllSeriesPointResponse.Entry entry) {
|
|
||||||
this.series = entry.getSeries();
|
|
||||||
this.value = entry.point == null ? null : entry.point.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,11 +1,5 @@
|
|||||||
package de.ph87.data.series;
|
package de.ph87.data.series;
|
||||||
|
|
||||||
import de.ph87.data.series.data.Interval;
|
|
||||||
import de.ph87.data.series.point.AllSeriesPointRequest;
|
|
||||||
import de.ph87.data.series.point.AllSeriesPointResponse;
|
|
||||||
import de.ph87.data.series.point.OneSeriesPointsRequest;
|
|
||||||
import de.ph87.data.series.point.OneSeriesPointsResponse;
|
|
||||||
import de.ph87.data.series.point.SeriesPointService;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
@ -16,9 +10,6 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@CrossOrigin
|
@CrossOrigin
|
||||||
@ -31,8 +22,6 @@ public class SeriesController {
|
|||||||
|
|
||||||
private final SeriesService seriesService;
|
private final SeriesService seriesService;
|
||||||
|
|
||||||
private final SeriesPointService seriesPointService;
|
|
||||||
|
|
||||||
@GetMapping("create")
|
@GetMapping("create")
|
||||||
public SeriesDto create() {
|
public SeriesDto create() {
|
||||||
return seriesService.create();
|
return seriesService.create();
|
||||||
@ -68,13 +57,6 @@ public class SeriesController {
|
|||||||
return seriesService.modify(id, series -> series.setType(type));
|
return seriesService.modify(id, series -> series.setType(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@GetMapping("{id}/history/{epochSeconds}/{intervalName}")
|
|
||||||
public HistoryDto type(@PathVariable final long id, @PathVariable @NonNull final long epochSeconds, @PathVariable @NonNull final String intervalName) {
|
|
||||||
final Interval interval = Interval.valueOf(intervalName);
|
|
||||||
return seriesPointService.history(id, ZonedDateTime.ofInstant(Instant.ofEpochSecond(epochSeconds), ZoneId.systemDefault()), interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@GetMapping("{id}")
|
@GetMapping("{id}")
|
||||||
public SeriesDto getById(@PathVariable final long id) {
|
public SeriesDto getById(@PathVariable final long id) {
|
||||||
@ -87,16 +69,4 @@ public class SeriesController {
|
|||||||
return seriesRepository.findAllDto();
|
return seriesRepository.findAllDto();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@PostMapping("oneSeriesPoints")
|
|
||||||
public OneSeriesPointsResponse oneSeriesPoints(@NonNull @RequestBody final OneSeriesPointsRequest request) {
|
|
||||||
return seriesPointService.oneSeriesPoints(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@PostMapping("allSeriesPoint")
|
|
||||||
public AllSeriesPointResponse allSeriesPoint(@NonNull @RequestBody final AllSeriesPointRequest request) {
|
|
||||||
return seriesPointService.allSeriesPoint(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,8 +14,6 @@ public class SeriesDto implements IWebsocketMessage {
|
|||||||
|
|
||||||
public final long version;
|
public final long version;
|
||||||
|
|
||||||
public final boolean deleted;
|
|
||||||
|
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -38,13 +36,8 @@ public class SeriesDto implements IWebsocketMessage {
|
|||||||
public final SeriesType type;
|
public final SeriesType type;
|
||||||
|
|
||||||
public SeriesDto(@NonNull final Series series) {
|
public SeriesDto(@NonNull final Series series) {
|
||||||
this(series, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SeriesDto(@NonNull final Series series, final boolean deleted) {
|
|
||||||
this.id = series.getId();
|
this.id = series.getId();
|
||||||
this.version = series.getVersion();
|
this.version = series.getVersion();
|
||||||
this.deleted = deleted;
|
|
||||||
this.name = series.getName();
|
this.name = series.getName();
|
||||||
this.unit = series.getUnit();
|
this.unit = series.getUnit();
|
||||||
this.decimals = series.getDecimals();
|
this.decimals = series.getDecimals();
|
||||||
|
|||||||
@ -5,23 +5,17 @@ import org.springframework.data.jpa.repository.Query;
|
|||||||
import org.springframework.data.repository.ListCrudRepository;
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public interface SeriesRepository extends ListCrudRepository<Series, Long> {
|
public interface SeriesRepository extends ListCrudRepository<Series, Long> {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
Optional<Series> findByName(@NonNull String seriesName);
|
@Query("select new de.ph87.data.series.SeriesDto(s) from Series s where s.id = :id")
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Query("select new de.ph87.data.series.SeriesDto(s, false) from Series s where s.id = :id")
|
|
||||||
SeriesDto getDtoById(long id);
|
SeriesDto getDtoById(long id);
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Query("select new de.ph87.data.series.SeriesDto(t, false) from Series t")
|
@Query("select new de.ph87.data.series.SeriesDto(t) from Series t")
|
||||||
List<SeriesDto> findAllDto();
|
List<SeriesDto> findAllDto();
|
||||||
|
|
||||||
Optional<Series> findFirstByOrderByNameAsc();
|
|
||||||
|
|
||||||
boolean existsByName(@NonNull String name);
|
boolean existsByName(@NonNull String name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,15 +32,15 @@ public class Bool {
|
|||||||
@Setter
|
@Setter
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false, name = "`end`")
|
@Column(nullable = false, name = "`end`")
|
||||||
private ZonedDateTime end;
|
private ZonedDateTime since;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private boolean terminated;
|
private boolean terminated;
|
||||||
|
|
||||||
public Bool(@NonNull final DataId id, @NonNull final ZonedDateTime end, final boolean state, final boolean terminated) {
|
public Bool(@NonNull final DataId id, @NonNull final ZonedDateTime since, final boolean state, final boolean terminated) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.end = end;
|
this.since = since;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.terminated = terminated;
|
this.terminated = terminated;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public class BoolDto implements IWebsocketMessage {
|
|||||||
public BoolDto(@NonNull final Bool bool) {
|
public BoolDto(@NonNull final Bool bool) {
|
||||||
this.series = new SeriesDto(bool.getId().getSeries());
|
this.series = new SeriesDto(bool.getId().getSeries());
|
||||||
this.date = bool.getId().getDate();
|
this.date = bool.getId().getDate();
|
||||||
this.end = bool.getEnd();
|
this.end = bool.getSince();
|
||||||
this.state = bool.isState();
|
this.state = bool.isState();
|
||||||
this.terminated = bool.isTerminated();
|
this.terminated = bool.isTerminated();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,65 +1,34 @@
|
|||||||
package de.ph87.data.series.data.bool;
|
package de.ph87.data.series.data.bool;
|
||||||
|
|
||||||
import de.ph87.data.plot.axis.graph.GraphDivisionByZero;
|
import de.ph87.data.series.data.delta.ISeriesPoint;
|
||||||
import de.ph87.data.plot.axis.graph.GraphOperation;
|
|
||||||
import de.ph87.data.series.point.SeriesPoint;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import tools.jackson.core.JsonGenerator;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class BoolPoint implements SeriesPoint<BoolPoint> {
|
public class BoolPoint implements ISeriesPoint {
|
||||||
|
|
||||||
public final ZonedDateTime begin;
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
public final ZonedDateTime end;
|
public final ZonedDateTime since;
|
||||||
|
|
||||||
public final boolean state;
|
public final boolean state;
|
||||||
|
|
||||||
public final boolean terminated;
|
public final boolean terminated;
|
||||||
|
|
||||||
public BoolPoint(@NonNull final Bool bool) {
|
public BoolPoint(@NonNull final Bool bool) {
|
||||||
this.begin = bool.getId().getDate();
|
this.date = bool.getId().getDate();
|
||||||
this.end = bool.getEnd();
|
this.since = bool.getSince();
|
||||||
this.state = bool.isState();
|
this.state = bool.isState();
|
||||||
this.terminated = bool.isTerminated();
|
this.terminated = bool.isTerminated();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoolPoint(final ZonedDateTime begin, final ZonedDateTime end, final boolean state, final boolean terminated) {
|
@NonNull
|
||||||
this.begin = begin;
|
|
||||||
this.end = end;
|
|
||||||
this.state = state;
|
|
||||||
this.terminated = terminated;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toJson(final JsonGenerator jsonGenerator) {
|
public List<Double> getValues() {
|
||||||
jsonGenerator.writeNumber(begin.toEpochSecond());
|
return List.of(state ? 1.0 : 0.0);
|
||||||
jsonGenerator.writeNumber(end.toEpochSecond());
|
|
||||||
jsonGenerator.writeNumber(state ? 1 : 0);
|
|
||||||
jsonGenerator.writeNumber(terminated ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BoolPoint times(final double factor) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ZonedDateTime getDate() {
|
|
||||||
return begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getValue() {
|
|
||||||
return state ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BoolPoint combine(@NonNull final SeriesPoint<?> other, @NonNull final GraphOperation operation) throws GraphDivisionByZero {
|
|
||||||
return new BoolPoint(begin, end, operation.apply(getValue(), other.getValue()) > 0, terminated);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import java.util.List;
|
|||||||
public interface BoolRepo extends CrudRepository<Bool, DataId> {
|
public interface BoolRepo extends CrudRepository<Bool, DataId> {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Query("select new de.ph87.data.series.data.bool.BoolPoint(e) from Bool e where e.id.series = :series and e.end >= :first and e.id.date < :after")
|
@Query("select new de.ph87.data.series.data.bool.BoolPoint(e) from Bool e where e.id.series = :series and e.since >= :begin and e.id.date < :end")
|
||||||
List<BoolPoint> points(@NonNull Series series, @NonNull ZonedDateTime first, @NonNull ZonedDateTime after);
|
List<BoolPoint> points(@NonNull Series series, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package de.ph87.data.series.data.bool;
|
package de.ph87.data.series.data.bool;
|
||||||
|
|
||||||
|
import de.ph87.data.point.IPointRequest;
|
||||||
import de.ph87.data.series.Series;
|
import de.ph87.data.series.Series;
|
||||||
import de.ph87.data.series.SeriesService;
|
import de.ph87.data.series.SeriesService;
|
||||||
import de.ph87.data.series.data.DataId;
|
import de.ph87.data.series.data.DataId;
|
||||||
import de.ph87.data.series.point.ISeriesPointRequest;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -12,6 +12,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -42,22 +43,24 @@ public class BoolService {
|
|||||||
log.error("Differing states: received=(begin={}, end={}, state={}, terminated={}), existing={}", begin, end, state, terminated, existing);
|
log.error("Differing states: received=(begin={}, end={}, state={}, terminated={}), existing={}", begin, end, state, terminated, existing);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (existing.getEnd().isAfter(end)) {
|
if (existing.getSince().isAfter(end)) {
|
||||||
log.error("End ran backwards: received=(begin={}, end={}, state={}, terminated={}), existing={}", begin, end, state, terminated, existing);
|
log.error("End ran backwards: received=(begin={}, end={}, state={}, terminated={}), existing={}", begin, end, state, terminated, existing);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (existing.isTerminated() && (!terminated || !existing.getEnd().equals(end))) {
|
if (existing.isTerminated() && (!terminated || !existing.getSince().equals(end))) {
|
||||||
log.error("Already terminated: received=(begin={}, end={}, state={}, terminated={}), existing={}", begin, end, state, terminated, existing);
|
log.error("Already terminated: received=(begin={}, end={}, state={}, terminated={}), existing={}", begin, end, state, terminated, existing);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
existing.setEnd(end);
|
existing.setSince(end);
|
||||||
existing.setTerminated(terminated);
|
existing.setTerminated(terminated);
|
||||||
}).findFirst().orElseGet(() -> boolRepo.save(new Bool(id, end, state, terminated)));
|
}).findFirst().orElseGet(() -> boolRepo.save(new Bool(id, end, state, terminated)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<BoolPoint> points(@NonNull final Series series, @NonNull final ISeriesPointRequest request) {
|
@SuppressWarnings("unused")
|
||||||
return boolRepo.points(series, request.getFirst(), request.getAfter());
|
public List<BoolPoint> points(@NonNull final Series series, @NonNull final IPointRequest request) {
|
||||||
|
log.warn("BoolService.points(...) Not implemented yet!");
|
||||||
|
return Collections.emptyList(); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
package de.ph87.data.series.data.delta;
|
package de.ph87.data.series.data.delta;
|
||||||
|
|
||||||
import de.ph87.data.plot.axis.graph.GraphDivisionByZero;
|
|
||||||
import de.ph87.data.plot.axis.graph.GraphOperation;
|
|
||||||
import de.ph87.data.series.point.SeriesPoint;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import tools.jackson.core.JsonGenerator;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class DeltaPoint implements SeriesPoint<DeltaPoint> {
|
public class DeltaPoint implements ISeriesPoint {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final ZonedDateTime date;
|
public final ZonedDateTime date;
|
||||||
@ -22,25 +19,10 @@ public class DeltaPoint implements SeriesPoint<DeltaPoint> {
|
|||||||
this.delta = delta;
|
this.delta = delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public void toJson(final JsonGenerator jsonGenerator) {
|
public List<Double> getValues() {
|
||||||
jsonGenerator.writeNumber(date.toEpochSecond());
|
return List.of(delta);
|
||||||
jsonGenerator.writeNumber(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DeltaPoint times(final double factor) {
|
|
||||||
return new DeltaPoint(date, delta * factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getValue() {
|
|
||||||
return delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DeltaPoint combine(@NonNull final SeriesPoint<?> other, @NonNull final GraphOperation operation) throws GraphDivisionByZero {
|
|
||||||
return new DeltaPoint(date, operation.apply(getValue(), other.getValue()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import java.util.List;
|
|||||||
public interface DeltaRepo<T extends Delta> extends CrudRepository<T, DeltaId> {
|
public interface DeltaRepo<T extends Delta> extends CrudRepository<T, DeltaId> {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Query("select new de.ph87.data.series.data.delta.DeltaPoint(e.id.date, sum((e.last - e.first))) from #{#entityName} e where e.id.meter.series = :series and e.id.date >= :first and e.id.date < :after group by e.id.date")
|
@Query("select new de.ph87.data.series.data.delta.DeltaPoint(e.id.date, sum((e.last - e.first))) from #{#entityName} e where e.id.meter.series = :series and e.id.date >= :begin and e.id.date < :end group by e.id.date")
|
||||||
List<DeltaPoint> points(@NonNull Series series, @NonNull ZonedDateTime first, @NonNull ZonedDateTime after);
|
List<DeltaPoint> points(@NonNull Series series, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
package de.ph87.data.series.data.delta;
|
package de.ph87.data.series.data.delta;
|
||||||
|
|
||||||
|
import de.ph87.data.point.IPointRequest;
|
||||||
import de.ph87.data.series.Series;
|
import de.ph87.data.series.Series;
|
||||||
import de.ph87.data.series.SeriesService;
|
import de.ph87.data.series.SeriesService;
|
||||||
import de.ph87.data.series.data.Interval;
|
import de.ph87.data.series.data.Interval;
|
||||||
import de.ph87.data.series.data.delta.meter.Meter;
|
import de.ph87.data.series.data.delta.meter.Meter;
|
||||||
import de.ph87.data.series.data.delta.meter.MeterRepository;
|
import de.ph87.data.series.data.delta.meter.MeterRepository;
|
||||||
import de.ph87.data.series.point.ISeriesPointRequest;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -72,14 +72,14 @@ public class DeltaService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<DeltaPoint> points(@NonNull final Series series, @NonNull final ISeriesPointRequest request) {
|
public List<DeltaPoint> points(@NonNull final Series series, @NonNull final IPointRequest request) {
|
||||||
return switch (request.getInterval()) {
|
return switch (request.getInterval()) {
|
||||||
case FIVE -> five.points(series, request.getFirst(), request.getAfter());
|
case FIVE -> five.points(series, request.getBegin(), request.getEnd());
|
||||||
case HOUR -> hour.points(series, request.getFirst(), request.getAfter());
|
case HOUR -> hour.points(series, request.getBegin(), request.getEnd());
|
||||||
case DAY -> day.points(series, request.getFirst(), request.getAfter());
|
case DAY -> day.points(series, request.getBegin(), request.getEnd());
|
||||||
case WEEK -> week.points(series, request.getFirst(), request.getAfter());
|
case WEEK -> week.points(series, request.getBegin(), request.getEnd());
|
||||||
case MONTH -> month.points(series, request.getFirst(), request.getAfter());
|
case MONTH -> month.points(series, request.getBegin(), request.getEnd());
|
||||||
case YEAR -> year.points(series, request.getFirst(), request.getAfter());
|
case YEAR -> year.points(series, request.getBegin(), request.getEnd());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
package de.ph87.data.series.data.delta;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import tools.jackson.databind.annotation.JsonSerialize;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@JsonSerialize(using = ISeriesPointSerializer.class)
|
||||||
|
public interface ISeriesPoint {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
ZonedDateTime getDate();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
List<Double> getValues();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package de.ph87.data.series.data.delta;
|
||||||
|
|
||||||
|
import tools.jackson.core.JacksonException;
|
||||||
|
import tools.jackson.core.JsonGenerator;
|
||||||
|
import tools.jackson.databind.SerializationContext;
|
||||||
|
import tools.jackson.databind.ValueSerializer;
|
||||||
|
|
||||||
|
public class ISeriesPointSerializer extends ValueSerializer<ISeriesPoint> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(final ISeriesPoint value, final JsonGenerator gen, final SerializationContext ctxt) throws JacksonException {
|
||||||
|
gen.writeStartArray();
|
||||||
|
gen.writeNumber(value.getDate().toEpochSecond());
|
||||||
|
for (double v : value.getValues()) {
|
||||||
|
gen.writeNumber(v);
|
||||||
|
}
|
||||||
|
gen.writeEndArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,16 +1,14 @@
|
|||||||
package de.ph87.data.series.data.varying;
|
package de.ph87.data.series.data.varying;
|
||||||
|
|
||||||
import de.ph87.data.plot.axis.graph.GraphDivisionByZero;
|
import de.ph87.data.series.data.delta.ISeriesPoint;
|
||||||
import de.ph87.data.plot.axis.graph.GraphOperation;
|
|
||||||
import de.ph87.data.series.point.SeriesPoint;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import tools.jackson.core.JsonGenerator;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class VaryingPoint implements SeriesPoint<VaryingPoint> {
|
public class VaryingPoint implements ISeriesPoint {
|
||||||
|
|
||||||
public final ZonedDateTime date;
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
@ -27,37 +25,10 @@ public class VaryingPoint implements SeriesPoint<VaryingPoint> {
|
|||||||
this.avg = varying.getAvg();
|
this.avg = varying.getAvg();
|
||||||
}
|
}
|
||||||
|
|
||||||
private VaryingPoint(final ZonedDateTime date, final double min, final double avg, final double max) {
|
@NonNull
|
||||||
this.date = date;
|
|
||||||
this.min = min;
|
|
||||||
this.avg = avg;
|
|
||||||
this.max = max;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toJson(final JsonGenerator jsonGenerator) {
|
public List<Double> getValues() {
|
||||||
jsonGenerator.writeNumber(date.toEpochSecond());
|
return List.of(avg, min, max);
|
||||||
jsonGenerator.writeNumber(min);
|
|
||||||
jsonGenerator.writeNumber(max);
|
|
||||||
jsonGenerator.writeNumber(avg);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VaryingPoint times(final double factor) {
|
|
||||||
return new VaryingPoint(date, min * factor, avg * factor, max * factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getValue() {
|
|
||||||
return avg;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VaryingPoint combine(@NonNull final SeriesPoint<?> other, @NonNull final GraphOperation operation) throws GraphDivisionByZero {
|
|
||||||
if (other instanceof final VaryingPoint otherVarying) {
|
|
||||||
return new VaryingPoint(date, operation.apply(min, otherVarying.min), operation.apply(avg, otherVarying.avg), operation.apply(max, otherVarying.max));
|
|
||||||
}
|
|
||||||
return new VaryingPoint(date, operation.apply(min, other.getValue()), operation.apply(avg, other.getValue()), operation.apply(max, other.getValue()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import java.util.List;
|
|||||||
public interface VaryingRepo<T extends Varying> extends CrudRepository<T, DataId> {
|
public interface VaryingRepo<T extends Varying> extends CrudRepository<T, DataId> {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Query("select new de.ph87.data.series.data.varying.VaryingPoint(e) from #{#entityName} e where e.id.series = :series and e.id.date >= :first and e.id.date < :after")
|
@Query("select new de.ph87.data.series.data.varying.VaryingPoint(e) from #{#entityName} e where e.id.series = :series and e.id.date >= :begin and e.id.date < :end")
|
||||||
List<VaryingPoint> points(@NonNull Series series, @NonNull ZonedDateTime first, @NonNull ZonedDateTime after);
|
List<VaryingPoint> points(@NonNull Series series, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
package de.ph87.data.series.data.varying;
|
package de.ph87.data.series.data.varying;
|
||||||
|
|
||||||
|
import de.ph87.data.point.IPointRequest;
|
||||||
import de.ph87.data.series.Series;
|
import de.ph87.data.series.Series;
|
||||||
import de.ph87.data.series.SeriesService;
|
import de.ph87.data.series.SeriesService;
|
||||||
import de.ph87.data.series.data.DataId;
|
import de.ph87.data.series.data.DataId;
|
||||||
import de.ph87.data.series.data.Interval;
|
import de.ph87.data.series.data.Interval;
|
||||||
import de.ph87.data.series.point.ISeriesPointRequest;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -56,14 +56,14 @@ public class VaryingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<VaryingPoint> points(@NonNull final Series series, @NonNull final ISeriesPointRequest request) {
|
public List<VaryingPoint> points(@NonNull final Series series, @NonNull final IPointRequest request) {
|
||||||
return switch (request.getInterval()) {
|
return switch (request.getInterval()) {
|
||||||
case FIVE -> five.points(series, request.getFirst(), request.getAfter());
|
case FIVE -> five.points(series, request.getBegin(), request.getEnd());
|
||||||
case HOUR -> hour.points(series, request.getFirst(), request.getAfter());
|
case HOUR -> hour.points(series, request.getBegin(), request.getEnd());
|
||||||
case DAY -> day.points(series, request.getFirst(), request.getAfter());
|
case DAY -> day.points(series, request.getBegin(), request.getEnd());
|
||||||
case WEEK -> week.points(series, request.getFirst(), request.getAfter());
|
case WEEK -> week.points(series, request.getBegin(), request.getEnd());
|
||||||
case MONTH -> month.points(series, request.getFirst(), request.getAfter());
|
case MONTH -> month.points(series, request.getBegin(), request.getEnd());
|
||||||
case YEAR -> year.points(series, request.getFirst(), request.getAfter());
|
case YEAR -> year.points(series, request.getBegin(), request.getEnd());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,34 +0,0 @@
|
|||||||
package de.ph87.data.series.point;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import de.ph87.data.series.data.Interval;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AllSeriesPointRequest implements ISeriesPointRequest {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final Interval interval;
|
|
||||||
|
|
||||||
public final long offset;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final ZonedDateTime first;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final ZonedDateTime after;
|
|
||||||
|
|
||||||
public AllSeriesPointRequest(
|
|
||||||
@JsonProperty("interval") final Interval interval,
|
|
||||||
@JsonProperty("offset") final long offset
|
|
||||||
) {
|
|
||||||
this.interval = interval;
|
|
||||||
this.offset = offset;
|
|
||||||
this.first = interval.align.apply(ZonedDateTime.now()).minus(interval.amount * offset, interval.unit);
|
|
||||||
this.after = this.first.plus(interval.amount, interval.unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package de.ph87.data.series.point;
|
|
||||||
|
|
||||||
import de.ph87.data.series.SeriesDto;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AllSeriesPointResponse {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final AllSeriesPointRequest request;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final List<Entry> seriesPoints;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class Entry {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final SeriesDto series;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public final SeriesPoint<?> point;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
package de.ph87.data.series.point;
|
|
||||||
|
|
||||||
import de.ph87.data.series.data.Interval;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
|
|
||||||
public interface ISeriesPointRequest {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
Interval getInterval();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
ZonedDateTime getFirst();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
ZonedDateTime getAfter();
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
package de.ph87.data.series.point;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import de.ph87.data.plot.axis.graph.GraphOperation;
|
|
||||||
import de.ph87.data.series.data.Interval;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class OneSeriesPointsRequest implements ISeriesPointRequest {
|
|
||||||
|
|
||||||
public final long id;
|
|
||||||
|
|
||||||
public final double factor;
|
|
||||||
|
|
||||||
public final GraphOperation operation;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public final Long id2;
|
|
||||||
|
|
||||||
public final double factor2;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final Interval interval;
|
|
||||||
|
|
||||||
public final long offset;
|
|
||||||
|
|
||||||
public final long duration;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@JsonIgnore
|
|
||||||
public final ZonedDateTime first;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@JsonIgnore
|
|
||||||
public final ZonedDateTime after;
|
|
||||||
|
|
||||||
public OneSeriesPointsRequest(
|
|
||||||
@JsonProperty("id") final long id,
|
|
||||||
@JsonProperty("factor") final double factor,
|
|
||||||
@JsonProperty("operation") final GraphOperation operation,
|
|
||||||
@JsonProperty("id2") @Nullable final Long id2,
|
|
||||||
@JsonProperty("factor2") final double factor2,
|
|
||||||
@JsonProperty("interval") final Interval interval,
|
|
||||||
@JsonProperty("offset") final long offset,
|
|
||||||
@JsonProperty("duration") final long duration
|
|
||||||
) {
|
|
||||||
this.id = id;
|
|
||||||
this.factor = factor;
|
|
||||||
this.operation = operation;
|
|
||||||
this.id2 = id2;
|
|
||||||
this.factor2 = factor2;
|
|
||||||
this.interval = interval;
|
|
||||||
this.offset = offset;
|
|
||||||
this.duration = duration;
|
|
||||||
this.after = interval.align.apply(ZonedDateTime.now()).minus(interval.amount * (offset - 1), interval.unit);
|
|
||||||
this.first = this.after.minus(interval.amount * duration, interval.unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
package de.ph87.data.series.point;
|
|
||||||
|
|
||||||
import tools.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@JsonSerialize(using = OneSeriesPointsResponseSerializer.class)
|
|
||||||
public class OneSeriesPointsResponse {
|
|
||||||
|
|
||||||
public final List<? extends SeriesPoint<?>> points;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package de.ph87.data.series.point;
|
|
||||||
|
|
||||||
import tools.jackson.core.JacksonException;
|
|
||||||
import tools.jackson.core.JsonGenerator;
|
|
||||||
import tools.jackson.databind.SerializationContext;
|
|
||||||
import tools.jackson.databind.ValueSerializer;
|
|
||||||
|
|
||||||
public class OneSeriesPointsResponseSerializer extends ValueSerializer<OneSeriesPointsResponse> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serialize(final OneSeriesPointsResponse value, final JsonGenerator gen, final SerializationContext ctxt) throws JacksonException {
|
|
||||||
gen.writeStartArray();
|
|
||||||
for (final SeriesPoint<?> point : value.points) {
|
|
||||||
gen.writeStartArray();
|
|
||||||
point.toJson(gen);
|
|
||||||
gen.writeEndArray();
|
|
||||||
}
|
|
||||||
gen.writeEndArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
package de.ph87.data.series.point;
|
|
||||||
|
|
||||||
import de.ph87.data.plot.axis.graph.GraphDivisionByZero;
|
|
||||||
import de.ph87.data.plot.axis.graph.GraphOperation;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import tools.jackson.core.JsonGenerator;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface SeriesPoint<T extends SeriesPoint<T>> {
|
|
||||||
|
|
||||||
ZonedDateTime getDate();
|
|
||||||
|
|
||||||
double getValue();
|
|
||||||
|
|
||||||
void toJson(final JsonGenerator jsonGenerator);
|
|
||||||
|
|
||||||
T times(final double factor);
|
|
||||||
|
|
||||||
T combine(@NonNull final SeriesPoint<?> other, @NonNull final GraphOperation operation) throws GraphDivisionByZero;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
static List<SeriesPoint<?>> combine(@NonNull final List<? extends SeriesPoint<?>> points1, @NonNull final List<? extends SeriesPoint<?>> points2, @NonNull final GraphOperation operation) {
|
|
||||||
if (points1.isEmpty() || points2.isEmpty()) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
final List<SeriesPoint<?>> as = new ArrayList<>(points1);
|
|
||||||
final List<SeriesPoint<?>> bs = new ArrayList<>(points2);
|
|
||||||
SeriesPoint<?> a = as.removeFirst();
|
|
||||||
SeriesPoint<?> b = bs.removeFirst();
|
|
||||||
final List<SeriesPoint<?>> result = new ArrayList<>(Math.min(as.size(), bs.size()));
|
|
||||||
while (true) {
|
|
||||||
final int diff = a.getDate().compareTo(b.getDate());
|
|
||||||
if (diff == 0) {
|
|
||||||
try {
|
|
||||||
result.add(a.combine(b, operation));
|
|
||||||
} catch (GraphDivisionByZero e) {
|
|
||||||
// just not add
|
|
||||||
}
|
|
||||||
a = null;
|
|
||||||
b = null;
|
|
||||||
} else if (diff < 0) {
|
|
||||||
a = null;
|
|
||||||
} else {
|
|
||||||
b = null;
|
|
||||||
}
|
|
||||||
if (a == null) {
|
|
||||||
if (as.isEmpty()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
a = as.removeFirst();
|
|
||||||
}
|
|
||||||
if (b == null) {
|
|
||||||
if (bs.isEmpty()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
b = bs.removeFirst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,100 +0,0 @@
|
|||||||
package de.ph87.data.series.point;
|
|
||||||
|
|
||||||
import de.ph87.data.series.HistoryDto;
|
|
||||||
import de.ph87.data.series.Series;
|
|
||||||
import de.ph87.data.series.SeriesDto;
|
|
||||||
import de.ph87.data.series.SeriesService;
|
|
||||||
import de.ph87.data.series.data.Interval;
|
|
||||||
import de.ph87.data.series.data.bool.BoolService;
|
|
||||||
import de.ph87.data.series.data.delta.DeltaService;
|
|
||||||
import de.ph87.data.series.data.varying.VaryingService;
|
|
||||||
import jakarta.annotation.Nullable;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SeriesPointService {
|
|
||||||
|
|
||||||
private final BoolService boolService;
|
|
||||||
|
|
||||||
private final DeltaService deltaService;
|
|
||||||
|
|
||||||
private final VaryingService varyingService;
|
|
||||||
|
|
||||||
private final SeriesService seriesService;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public OneSeriesPointsResponse oneSeriesPoints(@NonNull final OneSeriesPointsRequest request) {
|
|
||||||
final Series series1 = seriesService.getById(request.id);
|
|
||||||
final List<? extends SeriesPoint<?>> points1 = getSeriesPoints(series1, request, request.factor);
|
|
||||||
if (request.id2 != null) {
|
|
||||||
final Series series2 = seriesService.getById(request.id2);
|
|
||||||
final List<? extends SeriesPoint<?>> points2 = getSeriesPoints(series2, request, request.factor2);
|
|
||||||
return new OneSeriesPointsResponse(SeriesPoint.combine(points1, points2, request.operation));
|
|
||||||
}
|
|
||||||
return new OneSeriesPointsResponse(points1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public AllSeriesPointResponse allSeriesPoint(@NonNull final AllSeriesPointRequest request) {
|
|
||||||
final List<AllSeriesPointResponse.Entry> seriesPoints = seriesService.findAll().stream().map(series -> map(series, request)).toList();
|
|
||||||
return new AllSeriesPointResponse(request, seriesPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private AllSeriesPointResponse.Entry map(@NonNull final Series series, @NonNull final ISeriesPointRequest request) {
|
|
||||||
final List<? extends SeriesPoint<?>> points = getSeriesPoints(series, request, null);
|
|
||||||
final SeriesDto seriesDto = new SeriesDto(series);
|
|
||||||
final SeriesPoint<?> point = points.isEmpty() ? null : points.getFirst();
|
|
||||||
return new AllSeriesPointResponse.Entry(seriesDto, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private List<? extends SeriesPoint<?>> getSeriesPoints(@NonNull final Series series, @NonNull final ISeriesPointRequest request, @Nullable final Double factor) {
|
|
||||||
final List<? extends SeriesPoint<?>> points = switch (series.getType()) {
|
|
||||||
case BOOL -> boolService.points(series, request);
|
|
||||||
case DELTA -> deltaService.points(series, request);
|
|
||||||
case VARYING -> varyingService.points(series, request);
|
|
||||||
};
|
|
||||||
if (factor == null || factor == 1) {
|
|
||||||
return points;
|
|
||||||
}
|
|
||||||
return points.stream().map(p -> p.times(factor)).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public HistoryDto history(final long id, @NonNull final ZonedDateTime date, @NonNull final Interval interval) {
|
|
||||||
final Series series = seriesService.getById(id);
|
|
||||||
final AllSeriesPointResponse.Entry entry = map(series, new Request(date, interval));
|
|
||||||
return new HistoryDto(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
private static class Request implements ISeriesPointRequest {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final Interval interval;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final ZonedDateTime first;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final ZonedDateTime after;
|
|
||||||
|
|
||||||
public Request(final @NonNull ZonedDateTime date, final @NonNull Interval interval) {
|
|
||||||
this.interval = interval;
|
|
||||||
this.first = interval.align.apply(date);
|
|
||||||
this.after = this.first.plus(interval.amount, interval.unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package de.ph87.data.topic;
|
package de.ph87.data.topic;
|
||||||
|
|
||||||
import de.ph87.data.topic.parser.PatrixOpenDtu;
|
import de.ph87.data.topic.parser.PatrixOpenDtu;
|
||||||
import de.ph87.data.topic.parser.ShellyPlus1PM;
|
|
||||||
import de.ph87.data.topic.parser.PatrixSmartMeter;
|
import de.ph87.data.topic.parser.PatrixSmartMeter;
|
||||||
|
import de.ph87.data.topic.parser.ShellyPlus1PM;
|
||||||
import de.ph87.data.topic.parser.TasmotaSmartMeter;
|
import de.ph87.data.topic.parser.TasmotaSmartMeter;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package de.ph87.data.weather;
|
package de.ph87.data.weather;
|
||||||
|
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -9,6 +8,7 @@ import org.springframework.context.event.EventListener;
|
|||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user