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>
|
||||
<app-series-history-graph></app-series-history-graph>
|
||||
</div>
|
||||
|
||||
@ -1,23 +1,27 @@
|
||||
import {AfterViewInit, Component, Input} from '@angular/core';
|
||||
import {History} from '../../../series/History';
|
||||
import {Location} from '../../Location';
|
||||
import {Series} from '../../../series/Series';
|
||||
import {Interval, SeriesService} from '../../../series/series-service';
|
||||
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({
|
||||
selector: 'app-series-history',
|
||||
imports: [],
|
||||
imports: [
|
||||
SeriesHistoryGraph
|
||||
],
|
||||
templateUrl: './series-history.html',
|
||||
styleUrl: './series-history.less',
|
||||
})
|
||||
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;
|
||||
|
||||
@ -25,7 +29,7 @@ export class SeriesHistory implements AfterViewInit {
|
||||
heading!: string;
|
||||
|
||||
@Input()
|
||||
date!: Date;
|
||||
offset: number = 0;
|
||||
|
||||
@Input()
|
||||
interval!: Interval;
|
||||
@ -34,7 +38,7 @@ export class SeriesHistory implements AfterViewInit {
|
||||
location!: Location;
|
||||
|
||||
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) {
|
||||
next(null);
|
||||
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) {
|
||||
|
||||
<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="SectionHeading">
|
||||
|
||||
@ -6,10 +6,11 @@ import {Text} from '../../shared/text/text';
|
||||
import {Number} from '../../shared/number/number';
|
||||
import {SeriesSelect} from '../../series/select/series-select';
|
||||
import {Series} from '../../series/Series';
|
||||
import {Interval, SeriesService} from '../../series/series-service';
|
||||
import {SeriesService} from '../../series/series-service';
|
||||
import {SeriesType} from '../../series/SeriesType';
|
||||
import {Subscription, timer} from 'rxjs';
|
||||
import {SeriesHistory} from './history/series-history';
|
||||
import {Interval} from '../../series/Interval';
|
||||
|
||||
function yesterday(now: any) {
|
||||
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 {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 {
|
||||
|
||||
readonly valueString: string;
|
||||
@ -21,7 +17,11 @@ export class Series {
|
||||
readonly unit: string,
|
||||
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 {
|
||||
|
||||
@ -1,18 +1,8 @@
|
||||
import {Inject, Injectable, LOCALE_ID} from '@angular/core';
|
||||
import {ApiService, CrudService, Next, WebsocketService} from '../common';
|
||||
import {Series} from './Series';
|
||||
import {History} from './History';
|
||||
import {DatePipe} from '@angular/common';
|
||||
|
||||
export enum Interval {
|
||||
FIVE = 'FIVE',
|
||||
HOUR = 'HOUR',
|
||||
DAY = 'DAY',
|
||||
WEEK = 'WEEK',
|
||||
MONTH = 'MONTH',
|
||||
YEAR = 'YEAR',
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
@ -33,8 +23,4 @@ export class SeriesService extends CrudService<Series> {
|
||||
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,6 +1,6 @@
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { appConfig } from './app/app.config';
|
||||
import { App } from './app/app';
|
||||
import {bootstrapApplication} from '@angular/platform-browser';
|
||||
import {appConfig} from './app/app.config';
|
||||
import {App} from './app/app';
|
||||
|
||||
bootstrapApplication(App, appConfig)
|
||||
.catch((err) => console.error(err));
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package de.ph87.data;
|
||||
|
||||
import de.ph87.data.topic.TopicDto;
|
||||
import de.ph87.data.topic.TopicType;
|
||||
import de.ph87.data.topic.TopicService;
|
||||
import de.ph87.data.topic.TopicType;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
|
||||
@ -15,8 +15,6 @@ public class PlotDto implements IWebsocketMessage {
|
||||
|
||||
public final long version;
|
||||
|
||||
private final boolean deleted;
|
||||
|
||||
@NonNull
|
||||
public final String name;
|
||||
|
||||
@ -34,10 +32,9 @@ public class PlotDto implements IWebsocketMessage {
|
||||
@NonNull
|
||||
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.version = plot.getVersion();
|
||||
this.deleted = deleted;
|
||||
this.name = plot.getName();
|
||||
this.interval = plot.getInterval();
|
||||
this.offset = plot.getOffset();
|
||||
|
||||
@ -8,7 +8,7 @@ import java.util.Optional;
|
||||
|
||||
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();
|
||||
|
||||
@Query("select max(p.position) from Plot p")
|
||||
|
||||
@ -87,7 +87,7 @@ public class PlotService {
|
||||
} else {
|
||||
log.info("Updated: plot={}", plot);
|
||||
}
|
||||
final PlotDto dto = new PlotDto(plot, deleted);
|
||||
final PlotDto dto = new PlotDto(plot);
|
||||
applicationEventPublisher.publishEvent(dto);
|
||||
return dto;
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ public class GraphDto {
|
||||
|
||||
public final long version;
|
||||
|
||||
@NonNull
|
||||
@Nullable
|
||||
public final SeriesDto series;
|
||||
|
||||
public final double factor;
|
||||
@ -53,10 +53,10 @@ public class GraphDto {
|
||||
public GraphDto(@NonNull final Graph graph) {
|
||||
this.id = graph.getId();
|
||||
this.version = graph.getVersion();
|
||||
this.series = new SeriesDto(graph.getSeries());
|
||||
this.series = map(graph.getSeries(), SeriesDto::new);
|
||||
this.factor = graph.getFactor();
|
||||
this.operation = graph.getOperation();
|
||||
this.series2 = map(graph.getSeries2(), false, SeriesDto::new);
|
||||
this.series2 = map(graph.getSeries2(), SeriesDto::new);
|
||||
this.factor2 = graph.getFactor2();
|
||||
this.name = graph.getName();
|
||||
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;
|
||||
|
||||
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.RequiredArgsConstructor;
|
||||
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.RestController;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@CrossOrigin
|
||||
@ -31,8 +22,6 @@ public class SeriesController {
|
||||
|
||||
private final SeriesService seriesService;
|
||||
|
||||
private final SeriesPointService seriesPointService;
|
||||
|
||||
@GetMapping("create")
|
||||
public SeriesDto create() {
|
||||
return seriesService.create();
|
||||
@ -68,13 +57,6 @@ public class SeriesController {
|
||||
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
|
||||
@GetMapping("{id}")
|
||||
public SeriesDto getById(@PathVariable final long id) {
|
||||
@ -87,16 +69,4 @@ public class SeriesController {
|
||||
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 boolean deleted;
|
||||
|
||||
public final String name;
|
||||
|
||||
@NonNull
|
||||
@ -38,13 +36,8 @@ public class SeriesDto implements IWebsocketMessage {
|
||||
public final SeriesType type;
|
||||
|
||||
public SeriesDto(@NonNull final Series series) {
|
||||
this(series, false);
|
||||
}
|
||||
|
||||
public SeriesDto(@NonNull final Series series, final boolean deleted) {
|
||||
this.id = series.getId();
|
||||
this.version = series.getVersion();
|
||||
this.deleted = deleted;
|
||||
this.name = series.getName();
|
||||
this.unit = series.getUnit();
|
||||
this.decimals = series.getDecimals();
|
||||
|
||||
@ -5,23 +5,17 @@ import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.ListCrudRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface SeriesRepository extends ListCrudRepository<Series, Long> {
|
||||
|
||||
@NonNull
|
||||
Optional<Series> findByName(@NonNull String seriesName);
|
||||
|
||||
@NonNull
|
||||
@Query("select new de.ph87.data.series.SeriesDto(s, false) from Series s where s.id = :id")
|
||||
@Query("select new de.ph87.data.series.SeriesDto(s) from Series s where s.id = :id")
|
||||
SeriesDto getDtoById(long id);
|
||||
|
||||
@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();
|
||||
|
||||
Optional<Series> findFirstByOrderByNameAsc();
|
||||
|
||||
boolean existsByName(@NonNull String name);
|
||||
|
||||
}
|
||||
|
||||
@ -32,15 +32,15 @@ public class Bool {
|
||||
@Setter
|
||||
@NonNull
|
||||
@Column(nullable = false, name = "`end`")
|
||||
private ZonedDateTime end;
|
||||
private ZonedDateTime since;
|
||||
|
||||
@Setter
|
||||
@Column(nullable = false)
|
||||
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.end = end;
|
||||
this.since = since;
|
||||
this.state = state;
|
||||
this.terminated = terminated;
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ public class BoolDto implements IWebsocketMessage {
|
||||
public BoolDto(@NonNull final Bool bool) {
|
||||
this.series = new SeriesDto(bool.getId().getSeries());
|
||||
this.date = bool.getId().getDate();
|
||||
this.end = bool.getEnd();
|
||||
this.end = bool.getSince();
|
||||
this.state = bool.isState();
|
||||
this.terminated = bool.isTerminated();
|
||||
}
|
||||
|
||||
@ -1,65 +1,34 @@
|
||||
package de.ph87.data.series.data.bool;
|
||||
|
||||
import de.ph87.data.plot.axis.graph.GraphDivisionByZero;
|
||||
import de.ph87.data.plot.axis.graph.GraphOperation;
|
||||
import de.ph87.data.series.point.SeriesPoint;
|
||||
import de.ph87.data.series.data.delta.ISeriesPoint;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@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 terminated;
|
||||
|
||||
public BoolPoint(@NonNull final Bool bool) {
|
||||
this.begin = bool.getId().getDate();
|
||||
this.end = bool.getEnd();
|
||||
this.date = bool.getId().getDate();
|
||||
this.since = bool.getSince();
|
||||
this.state = bool.isState();
|
||||
this.terminated = bool.isTerminated();
|
||||
}
|
||||
|
||||
public BoolPoint(final ZonedDateTime begin, final ZonedDateTime end, final boolean state, final boolean terminated) {
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.state = state;
|
||||
this.terminated = terminated;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public void toJson(final JsonGenerator jsonGenerator) {
|
||||
jsonGenerator.writeNumber(begin.toEpochSecond());
|
||||
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);
|
||||
public List<Double> getValues() {
|
||||
return List.of(state ? 1.0 : 0.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ import java.util.List;
|
||||
public interface BoolRepo extends CrudRepository<Bool, DataId> {
|
||||
|
||||
@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")
|
||||
List<BoolPoint> points(@NonNull Series series, @NonNull ZonedDateTime first, @NonNull ZonedDateTime 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 begin, @NonNull ZonedDateTime end);
|
||||
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package de.ph87.data.series.data.bool;
|
||||
|
||||
import de.ph87.data.point.IPointRequest;
|
||||
import de.ph87.data.series.Series;
|
||||
import de.ph87.data.series.SeriesService;
|
||||
import de.ph87.data.series.data.DataId;
|
||||
import de.ph87.data.series.point.ISeriesPointRequest;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -12,6 +12,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@ -42,22 +43,24 @@ public class BoolService {
|
||||
log.error("Differing states: received=(begin={}, end={}, state={}, terminated={}), existing={}", begin, end, state, terminated, existing);
|
||||
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);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
existing.setEnd(end);
|
||||
existing.setSince(end);
|
||||
existing.setTerminated(terminated);
|
||||
}).findFirst().orElseGet(() -> boolRepo.save(new Bool(id, end, state, terminated)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<BoolPoint> points(@NonNull final Series series, @NonNull final ISeriesPointRequest request) {
|
||||
return boolRepo.points(series, request.getFirst(), request.getAfter());
|
||||
@SuppressWarnings("unused")
|
||||
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;
|
||||
|
||||
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.NonNull;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class DeltaPoint implements SeriesPoint<DeltaPoint> {
|
||||
public class DeltaPoint implements ISeriesPoint {
|
||||
|
||||
@NonNull
|
||||
public final ZonedDateTime date;
|
||||
@ -22,25 +19,10 @@ public class DeltaPoint implements SeriesPoint<DeltaPoint> {
|
||||
this.delta = delta;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public void toJson(final JsonGenerator jsonGenerator) {
|
||||
jsonGenerator.writeNumber(date.toEpochSecond());
|
||||
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()));
|
||||
public List<Double> getValues() {
|
||||
return List.of(delta);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import java.util.List;
|
||||
public interface DeltaRepo<T extends Delta> extends CrudRepository<T, DeltaId> {
|
||||
|
||||
@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")
|
||||
List<DeltaPoint> points(@NonNull Series series, @NonNull ZonedDateTime first, @NonNull ZonedDateTime after);
|
||||
@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 begin, @NonNull ZonedDateTime end);
|
||||
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package de.ph87.data.series.data.delta;
|
||||
|
||||
import de.ph87.data.point.IPointRequest;
|
||||
import de.ph87.data.series.Series;
|
||||
import de.ph87.data.series.SeriesService;
|
||||
import de.ph87.data.series.data.Interval;
|
||||
import de.ph87.data.series.data.delta.meter.Meter;
|
||||
import de.ph87.data.series.data.delta.meter.MeterRepository;
|
||||
import de.ph87.data.series.point.ISeriesPointRequest;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -72,14 +72,14 @@ public class DeltaService {
|
||||
}
|
||||
|
||||
@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()) {
|
||||
case FIVE -> five.points(series, request.getFirst(), request.getAfter());
|
||||
case HOUR -> hour.points(series, request.getFirst(), request.getAfter());
|
||||
case DAY -> day.points(series, request.getFirst(), request.getAfter());
|
||||
case WEEK -> week.points(series, request.getFirst(), request.getAfter());
|
||||
case MONTH -> month.points(series, request.getFirst(), request.getAfter());
|
||||
case YEAR -> year.points(series, request.getFirst(), request.getAfter());
|
||||
case FIVE -> five.points(series, request.getBegin(), request.getEnd());
|
||||
case HOUR -> hour.points(series, request.getBegin(), request.getEnd());
|
||||
case DAY -> day.points(series, request.getBegin(), request.getEnd());
|
||||
case WEEK -> week.points(series, request.getBegin(), request.getEnd());
|
||||
case MONTH -> month.points(series, request.getBegin(), request.getEnd());
|
||||
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;
|
||||
|
||||
import de.ph87.data.plot.axis.graph.GraphDivisionByZero;
|
||||
import de.ph87.data.plot.axis.graph.GraphOperation;
|
||||
import de.ph87.data.series.point.SeriesPoint;
|
||||
import de.ph87.data.series.data.delta.ISeriesPoint;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class VaryingPoint implements SeriesPoint<VaryingPoint> {
|
||||
public class VaryingPoint implements ISeriesPoint {
|
||||
|
||||
public final ZonedDateTime date;
|
||||
|
||||
@ -27,37 +25,10 @@ public class VaryingPoint implements SeriesPoint<VaryingPoint> {
|
||||
this.avg = varying.getAvg();
|
||||
}
|
||||
|
||||
private VaryingPoint(final ZonedDateTime date, final double min, final double avg, final double max) {
|
||||
this.date = date;
|
||||
this.min = min;
|
||||
this.avg = avg;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public void toJson(final JsonGenerator jsonGenerator) {
|
||||
jsonGenerator.writeNumber(date.toEpochSecond());
|
||||
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()));
|
||||
public List<Double> getValues() {
|
||||
return List.of(avg, min, max);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ import java.util.List;
|
||||
public interface VaryingRepo<T extends Varying> extends CrudRepository<T, DataId> {
|
||||
|
||||
@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")
|
||||
List<VaryingPoint> points(@NonNull Series series, @NonNull ZonedDateTime first, @NonNull ZonedDateTime 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 begin, @NonNull ZonedDateTime end);
|
||||
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
package de.ph87.data.series.data.varying;
|
||||
|
||||
import de.ph87.data.point.IPointRequest;
|
||||
import de.ph87.data.series.Series;
|
||||
import de.ph87.data.series.SeriesService;
|
||||
import de.ph87.data.series.data.DataId;
|
||||
import de.ph87.data.series.data.Interval;
|
||||
import de.ph87.data.series.point.ISeriesPointRequest;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -56,14 +56,14 @@ public class VaryingService {
|
||||
}
|
||||
|
||||
@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()) {
|
||||
case FIVE -> five.points(series, request.getFirst(), request.getAfter());
|
||||
case HOUR -> hour.points(series, request.getFirst(), request.getAfter());
|
||||
case DAY -> day.points(series, request.getFirst(), request.getAfter());
|
||||
case WEEK -> week.points(series, request.getFirst(), request.getAfter());
|
||||
case MONTH -> month.points(series, request.getFirst(), request.getAfter());
|
||||
case YEAR -> year.points(series, request.getFirst(), request.getAfter());
|
||||
case FIVE -> five.points(series, request.getBegin(), request.getEnd());
|
||||
case HOUR -> hour.points(series, request.getBegin(), request.getEnd());
|
||||
case DAY -> day.points(series, request.getBegin(), request.getEnd());
|
||||
case WEEK -> week.points(series, request.getBegin(), request.getEnd());
|
||||
case MONTH -> month.points(series, request.getBegin(), request.getEnd());
|
||||
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;
|
||||
|
||||
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.ShellyPlus1PM;
|
||||
import de.ph87.data.topic.parser.TasmotaSmartMeter;
|
||||
import lombok.Getter;
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package de.ph87.data.weather;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user