Series refactor
This commit is contained in:
parent
5ba7f3d4d6
commit
c85fbb12c3
@ -1,38 +0,0 @@
|
|||||||
package de.ph87.data.demo;
|
|
||||||
|
|
||||||
import de.ph87.data.series.Series;
|
|
||||||
import de.ph87.data.series.SeriesMode;
|
|
||||||
import de.ph87.data.series.SeriesRepository;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import static de.ph87.data.electricity.grid.GridReceiver.GRID_DELIVERY_SERIES_NAME;
|
|
||||||
import static de.ph87.data.electricity.grid.GridReceiver.GRID_PURCHASE_SERIES_NAME;
|
|
||||||
import static de.ph87.data.electricity.photovoltaic.PhotovoltaicReceiver.PHOTOVOLTAIC_ENERGY_SERIES_NAME;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@Transactional
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@SuppressWarnings("SameParameterValue")
|
|
||||||
public class DemoService {
|
|
||||||
|
|
||||||
private final SeriesRepository seriesRepository;
|
|
||||||
|
|
||||||
@EventListener(ApplicationStartedEvent.class)
|
|
||||||
public void startup() {
|
|
||||||
series(PHOTOVOLTAIC_ENERGY_SERIES_NAME, SeriesMode.INCREASING);
|
|
||||||
series(GRID_PURCHASE_SERIES_NAME, SeriesMode.INCREASING);
|
|
||||||
series(GRID_DELIVERY_SERIES_NAME, SeriesMode.INCREASING);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void series(@NonNull final String name, @NonNull final SeriesMode mode) {
|
|
||||||
seriesRepository.findByNameOrAliasesContains(name, name).orElseGet(() -> seriesRepository.save(new Series(name, mode)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -41,10 +41,10 @@ public class GridReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final double purchaseKWh = energyToKWh(inbound.purchaseWh, "Wh");
|
final double purchaseKWh = energyToKWh(inbound.purchaseWh, "Wh");
|
||||||
applicationEventPublisher.publishEvent(new ConsumptionEvent(GRID_PURCHASE_SERIES_NAME, inbound.meter, inbound.date, purchaseKWh));
|
applicationEventPublisher.publishEvent(new ConsumptionEvent(GRID_PURCHASE_SERIES_NAME, true, inbound.meter, inbound.date, purchaseKWh));
|
||||||
|
|
||||||
final double deliveryKWh = energyToKWh(inbound.deliveryWh, "Wh");
|
final double deliveryKWh = energyToKWh(inbound.deliveryWh, "Wh");
|
||||||
applicationEventPublisher.publishEvent(new ConsumptionEvent(GRID_DELIVERY_SERIES_NAME, inbound.meter, inbound.date, deliveryKWh));
|
applicationEventPublisher.publishEvent(new ConsumptionEvent(GRID_DELIVERY_SERIES_NAME, true, inbound.meter, inbound.date, deliveryKWh));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ public class PhotovoltaicReceiver {
|
|||||||
|
|
||||||
public static final String PHOTOVOLTAIC_ENERGY_SERIES_NAME = "photovoltaic.energyKWh";
|
public static final String PHOTOVOLTAIC_ENERGY_SERIES_NAME = "photovoltaic.energyKWh";
|
||||||
|
|
||||||
private static final Pattern REGEX = Pattern.compile("^(?<serial>\\S+) (?<epochSeconds>\\d+) (?<power>\\d+(:?\\.\\d+)?)(?<powerUnit>\\S+) (?<energy>\\d+(:?\\.\\d+)?)(?<energyUnit>\\S+)$");
|
private static final Pattern REGEX = Pattern.compile("^(?<serial>\\S+) (?<epochSeconds>\\d+) (?<powerValue>\\d+(:?\\.\\d+)?)(?<powerUnit>\\S+) (?<producedValue>\\d+(:?\\.\\d+)?)(?<producedUnit>\\S+)$");
|
||||||
|
|
||||||
private final ApplicationEventPublisher applicationEventPublisher;
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
@ -40,10 +40,10 @@ public class PhotovoltaicReceiver {
|
|||||||
|
|
||||||
final String serial = matcher.group("serial");
|
final String serial = matcher.group("serial");
|
||||||
final ZonedDateTime date = ZDT(Long.parseLong(matcher.group("epochSeconds")));
|
final ZonedDateTime date = ZDT(Long.parseLong(matcher.group("epochSeconds")));
|
||||||
final double energy = Double.parseDouble(matcher.group("energy"));
|
final double producedValue = Double.parseDouble(matcher.group("producedValue"));
|
||||||
final String energyUnit = matcher.group("energyUnit");
|
final String producedUnit = matcher.group("producedUnit");
|
||||||
final double energyKWh = energyToKWh(energy, energyUnit);
|
final double producedKWh = energyToKWh(producedValue, producedUnit);
|
||||||
applicationEventPublisher.publishEvent(new ConsumptionEvent(PHOTOVOLTAIC_ENERGY_SERIES_NAME, serial, date, energyKWh));
|
applicationEventPublisher.publishEvent(new ConsumptionEvent(PHOTOVOLTAIC_ENERGY_SERIES_NAME, true, serial, date, producedKWh));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/main/java/de/ph87/data/series/SeriesIntervalKey.java
Normal file
37
src/main/java/de/ph87/data/series/SeriesIntervalKey.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package de.ph87.data.series;
|
||||||
|
|
||||||
|
import de.ph87.data.series.consumption.unit.Unit;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@Embeddable
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class SeriesIntervalKey implements Serializable {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
private Series series;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false, updatable = false, columnDefinition = "CHAR(1)")
|
||||||
|
private Unit unit;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
private ZonedDateTime aligned;
|
||||||
|
|
||||||
|
public SeriesIntervalKey(@NonNull final Series series, @NonNull final Unit unit, @NonNull final ZonedDateTime unaligned) {
|
||||||
|
this.series = series;
|
||||||
|
this.unit = unit;
|
||||||
|
this.aligned = unit.align(unaligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,17 +1,11 @@
|
|||||||
package de.ph87.data.series;
|
package de.ph87.data.series;
|
||||||
|
|
||||||
import de.ph87.data.series.consumption.ConsumptionEvent;
|
|
||||||
import de.ph87.data.series.consumption.ConsumptionEventTooOld;
|
|
||||||
import de.ph87.data.series.consumption.period.PeriodService;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
@Transactional
|
||||||
@ -20,24 +14,13 @@ public class SeriesService {
|
|||||||
|
|
||||||
private final SeriesRepository seriesRepository;
|
private final SeriesRepository seriesRepository;
|
||||||
|
|
||||||
private final PeriodService periodService;
|
@NonNull
|
||||||
|
public Series getOrCreateByName(@NonNull final String name, @NonNull final SeriesMode mode) {
|
||||||
@EventListener(ConsumptionEvent.class)
|
final Series series = seriesRepository.findByNameOrAliasesContains(name, name).orElseGet(() -> seriesRepository.save(new Series(name, mode)));
|
||||||
public void onConsumptionEvent(@NonNull final ConsumptionEvent event) {
|
if (series.getMode() != mode) {
|
||||||
log.debug("Handling ConsumptionEvent: {}", event);
|
throw new RuntimeException("'mode' argument for getOrCreateByName does not match 'mode' of existing Series: mode=%s, series=%s".formatted(mode, series));
|
||||||
final Optional<Series> seriesOptional = seriesRepository.findByNameOrAliasesContains(event.getName(), event.getName());
|
|
||||||
if (seriesOptional.isEmpty()) {
|
|
||||||
log.warn("No series found with name or alias: \"{}\"", event.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Series series = seriesOptional.get();
|
|
||||||
log.debug("Series found: {}", series);
|
|
||||||
try {
|
|
||||||
periodService.onConsumptionEvent(series, event);
|
|
||||||
} catch (ConsumptionEventTooOld e) {
|
|
||||||
log.warn(e.toString());
|
|
||||||
}
|
}
|
||||||
|
return series;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,8 @@ public class ConsumptionEvent {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
private final boolean increasing;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final String periodName;
|
private final String periodName;
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
package de.ph87.data.series.consumption;
|
|
||||||
|
|
||||||
import de.ph87.data.series.consumption.period.Period;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
public class ConsumptionEventTooOld extends Exception {
|
|
||||||
|
|
||||||
public ConsumptionEventTooOld(@NonNull final Period period, @NonNull final ConsumptionEvent event) {
|
|
||||||
super("Date of received Event older than last stored one: event=%s, period=%s".formatted(event, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,10 +1,15 @@
|
|||||||
package de.ph87.data.series.consumption;
|
package de.ph87.data.series.consumption;
|
||||||
|
|
||||||
|
import de.ph87.data.series.Series;
|
||||||
|
import de.ph87.data.series.SeriesMode;
|
||||||
|
import de.ph87.data.series.SeriesService;
|
||||||
import de.ph87.data.series.consumption.period.Period;
|
import de.ph87.data.series.consumption.period.Period;
|
||||||
|
import de.ph87.data.series.consumption.period.PeriodService;
|
||||||
import de.ph87.data.series.consumption.unit.Unit;
|
import de.ph87.data.series.consumption.unit.Unit;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@ -19,7 +24,17 @@ public class ConsumptionService {
|
|||||||
|
|
||||||
private final ConsumptionRepository consumptionRepository;
|
private final ConsumptionRepository consumptionRepository;
|
||||||
|
|
||||||
public void onConsumptionEvent(@NonNull final Period period, @NonNull final ConsumptionEvent event) {
|
private final SeriesService seriesService;
|
||||||
|
|
||||||
|
private final PeriodService periodService;
|
||||||
|
|
||||||
|
@EventListener(ConsumptionEvent.class)
|
||||||
|
public void onConsumptionEvent(@NonNull final ConsumptionEvent event) {
|
||||||
|
log.debug("Handling ConsumptionEvent: {}", event);
|
||||||
|
final Series series = seriesService.getOrCreateByName(event.getName(), event.isIncreasing() ? SeriesMode.INCREASING : SeriesMode.DECREASING);
|
||||||
|
final Period period = periodService.getOrCreatePeriod(series, event);
|
||||||
|
period.setLastDate(event.getDate());
|
||||||
|
period.setLastValue(event.getValue());
|
||||||
for (final Unit unit : Unit.values()) {
|
for (final Unit unit : Unit.values()) {
|
||||||
final ZonedDateTime aligned = unit.align(event.getDate());
|
final ZonedDateTime aligned = unit.align(event.getDate());
|
||||||
final Optional<Consumption> existingOptional = consumptionRepository.findByIdPeriodAndIdUnitAndIdAligned(period, unit, aligned);
|
final Optional<Consumption> existingOptional = consumptionRepository.findByIdPeriodAndIdUnitAndIdAligned(period, unit, aligned);
|
||||||
|
|||||||
@ -3,8 +3,6 @@ package de.ph87.data.series.consumption.period;
|
|||||||
import de.ph87.data.series.Series;
|
import de.ph87.data.series.Series;
|
||||||
import de.ph87.data.series.SeriesMode;
|
import de.ph87.data.series.SeriesMode;
|
||||||
import de.ph87.data.series.consumption.ConsumptionEvent;
|
import de.ph87.data.series.consumption.ConsumptionEvent;
|
||||||
import de.ph87.data.series.consumption.ConsumptionEventTooOld;
|
|
||||||
import de.ph87.data.series.consumption.ConsumptionService;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -19,22 +17,10 @@ public class PeriodService {
|
|||||||
|
|
||||||
private final PeriodRepository periodRepository;
|
private final PeriodRepository periodRepository;
|
||||||
|
|
||||||
private final ConsumptionService consumptionService;
|
|
||||||
|
|
||||||
public void onConsumptionEvent(@NonNull final Series series, @NonNull final ConsumptionEvent event) throws ConsumptionEventTooOld {
|
|
||||||
final Period period = getOrCreatePeriod(series, event);
|
|
||||||
period.setLastDate(event.getDate());
|
|
||||||
period.setLastValue(event.getValue());
|
|
||||||
consumptionService.onConsumptionEvent(period, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Period getOrCreatePeriod(@NonNull final Series series, @NonNull final ConsumptionEvent event) throws ConsumptionEventTooOld {
|
public Period getOrCreatePeriod(@NonNull final Series series, @NonNull final ConsumptionEvent event) {
|
||||||
if (series.getPeriod() != null) {
|
if (series.getPeriod() != null) {
|
||||||
log.debug("Last Period exists: {}", series.getPeriod());
|
log.debug("Last Period exists: {}", series.getPeriod());
|
||||||
if (isEventTooOld(series.getPeriod(), event)) {
|
|
||||||
throw new ConsumptionEventTooOld(series.getPeriod(), event);
|
|
||||||
}
|
|
||||||
if (isPeriodValid(series.getPeriod(), event)) {
|
if (isPeriodValid(series.getPeriod(), event)) {
|
||||||
log.debug("Last Period still VALID.");
|
log.debug("Last Period still VALID.");
|
||||||
return series.getPeriod();
|
return series.getPeriod();
|
||||||
@ -49,10 +35,6 @@ public class PeriodService {
|
|||||||
return newPeriod;
|
return newPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isEventTooOld(@NonNull final Period period, @NonNull final ConsumptionEvent event) {
|
|
||||||
return !period.getLastDate().isBefore(event.getDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isPeriodValid(@NonNull final Period period, @NonNull final ConsumptionEvent event) {
|
private boolean isPeriodValid(@NonNull final Period period, @NonNull final ConsumptionEvent event) {
|
||||||
if (!period.getName().equals(event.getPeriodName())) {
|
if (!period.getName().equals(event.getPeriodName())) {
|
||||||
log.debug("Period name changed: old={}, new={}", period.getName(), event.getPeriodName());
|
log.debug("Period name changed: old={}, new={}", period.getName(), event.getPeriodName());
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
package de.ph87.data.series.measure;
|
|
||||||
|
|
||||||
import de.ph87.data.series.period.Period;
|
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
public class MeasureEventTooOld extends Exception {
|
|
||||||
|
|
||||||
public MeasureEventTooOld(@NonNull final Period period, @NonNull final MeasureEvent event) {
|
|
||||||
super("Date of received MeasureEvent older than last stored one: event=%s, period=%s".formatted(event, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user