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");
|
||||
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");
|
||||
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";
|
||||
|
||||
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;
|
||||
|
||||
@ -40,10 +40,10 @@ public class PhotovoltaicReceiver {
|
||||
|
||||
final String serial = matcher.group("serial");
|
||||
final ZonedDateTime date = ZDT(Long.parseLong(matcher.group("epochSeconds")));
|
||||
final double energy = Double.parseDouble(matcher.group("energy"));
|
||||
final String energyUnit = matcher.group("energyUnit");
|
||||
final double energyKWh = energyToKWh(energy, energyUnit);
|
||||
applicationEventPublisher.publishEvent(new ConsumptionEvent(PHOTOVOLTAIC_ENERGY_SERIES_NAME, serial, date, energyKWh));
|
||||
final double producedValue = Double.parseDouble(matcher.group("producedValue"));
|
||||
final String producedUnit = matcher.group("producedUnit");
|
||||
final double producedKWh = energyToKWh(producedValue, producedUnit);
|
||||
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;
|
||||
|
||||
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.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@ -20,24 +14,13 @@ public class SeriesService {
|
||||
|
||||
private final SeriesRepository seriesRepository;
|
||||
|
||||
private final PeriodService periodService;
|
||||
|
||||
@EventListener(ConsumptionEvent.class)
|
||||
public void onConsumptionEvent(@NonNull final ConsumptionEvent event) {
|
||||
log.debug("Handling ConsumptionEvent: {}", event);
|
||||
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());
|
||||
@NonNull
|
||||
public Series getOrCreateByName(@NonNull final String name, @NonNull final SeriesMode mode) {
|
||||
final Series series = seriesRepository.findByNameOrAliasesContains(name, name).orElseGet(() -> seriesRepository.save(new Series(name, mode)));
|
||||
if (series.getMode() != mode) {
|
||||
throw new RuntimeException("'mode' argument for getOrCreateByName does not match 'mode' of existing Series: mode=%s, series=%s".formatted(mode, series));
|
||||
}
|
||||
return series;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,6 +15,8 @@ public class ConsumptionEvent {
|
||||
@NonNull
|
||||
private final String name;
|
||||
|
||||
private final boolean increasing;
|
||||
|
||||
@NonNull
|
||||
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;
|
||||
|
||||
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.PeriodService;
|
||||
import de.ph87.data.series.consumption.unit.Unit;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@ -19,7 +24,17 @@ public class ConsumptionService {
|
||||
|
||||
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()) {
|
||||
final ZonedDateTime aligned = unit.align(event.getDate());
|
||||
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.SeriesMode;
|
||||
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.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -19,22 +17,10 @@ public class PeriodService {
|
||||
|
||||
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
|
||||
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) {
|
||||
log.debug("Last Period exists: {}", series.getPeriod());
|
||||
if (isEventTooOld(series.getPeriod(), event)) {
|
||||
throw new ConsumptionEventTooOld(series.getPeriod(), event);
|
||||
}
|
||||
if (isPeriodValid(series.getPeriod(), event)) {
|
||||
log.debug("Last Period still VALID.");
|
||||
return series.getPeriod();
|
||||
@ -49,10 +35,6 @@ public class PeriodService {
|
||||
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) {
|
||||
if (!period.getName().equals(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