diff --git a/src/main/java/info/peper/vz/rest/FillAggregateTableMain2.java b/src/main/java/info/peper/vz/rest/FillAggregateTableMain2.java index 40fd274..afb70ec 100644 --- a/src/main/java/info/peper/vz/rest/FillAggregateTableMain2.java +++ b/src/main/java/info/peper/vz/rest/FillAggregateTableMain2.java @@ -21,17 +21,17 @@ import java.util.List; public class FillAggregateTableMain2 { private static final DateTimeFormatter DTF = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.systemDefault()); - private static final int[] CHANNELS_TO_USE = new int[] {1, 4, }; + private static final int[] CHANNELS_TO_USE = new int[] {1,/* 4,*/ }; private static final List SAVELIST = new LinkedList(); private static class AggregateToSave { private final long startTs; private final long endTs; - private final double valuePos; - private final double valueNeg; + private final long valuePos; + private final long valueNeg; private final int channelId; - private AggregateToSave(long startTs, long endTs, double valuePos, double valueNeg, int channelId) { + private AggregateToSave(long startTs, long endTs, long valuePos, long valueNeg, int channelId) { super(); this.startTs = startTs; this.endTs = endTs; @@ -48,11 +48,11 @@ public class FillAggregateTableMain2 { return endTs; } - private double getValuePos() { + private long getValuePos() { return valuePos; } - private double getValueNeg() { + private long getValueNeg() { return valueNeg; } @@ -68,6 +68,7 @@ public class FillAggregateTableMain2 { getPassword())) { // long startTimeStamp = getTimestamp("2025-01-01T09:00:00"); final long startTimeStamp = getTimestamp("2022-05-20T09:00:00"); +// final long finalEndTimeStamp = getTimestamp("2022-05-20T09:02:00"); final long finalEndTimeStamp = getTimestamp("2025-03-01T00:00:00"); for (int channelId : CHANNELS_TO_USE) { processChannel(startTimeStamp, finalEndTimeStamp, 60*1000, channelId, con); @@ -117,10 +118,11 @@ public class FillAggregateTableMain2 { sumDiff += tsDiff; currentTimestamp = timestamp; if (value > 0) { - intervalPos += (value * tsDiff); + intervalPos += Math.round(value * tsDiff); } else if (value < 0) { - intervalNeg += (-value * tsDiff); + intervalNeg += Math.round(-value * tsDiff); } +// System.out.println("ts: " + currentTimestamp + " / diff: " + tsDiff + " / value: " + value + " / intervalPos: " + intervalPos); if (timestamp >= intervalEndTimestamp) { if (sumDiff != interval) { System.err.println("sumDiff: " + sumDiff + " / interval: " + interval); @@ -133,7 +135,7 @@ public class FillAggregateTableMain2 { (intervalPos/3600) + " / " + (intervalNeg/3600)); } - SAVELIST.add(new AggregateToSave(intervalStartTimestamp, intervalEndTimestamp, ((double)intervalPos)/3600, ((double)intervalNeg)/3600, channelId)); + SAVELIST.add(new AggregateToSave(intervalStartTimestamp, intervalEndTimestamp, Math.round(intervalPos), Math.round(intervalNeg), channelId)); intervalStartTimestamp += interval; intervalEndTimestamp += interval; currentTimestamp = intervalStartTimestamp; diff --git a/src/main/java/info/peper/vz/rest/VzRestController.java b/src/main/java/info/peper/vz/rest/VzRestController.java index e76a859..028a4fc 100644 --- a/src/main/java/info/peper/vz/rest/VzRestController.java +++ b/src/main/java/info/peper/vz/rest/VzRestController.java @@ -1,6 +1,11 @@ package info.peper.vz.rest; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.LinkedList; import java.util.List; +import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController; import info.peper.vz.rest.bo.Sums; import info.peper.vz.rest.bo.db.Aggregate; import info.peper.vz.rest.bo.db.Data; +import info.peper.vz.rest.bo.db.EnergyPrice; @RestController class VzRestController { @@ -23,22 +29,60 @@ class VzRestController { private static final Logger log = LoggerFactory.getLogger(VzRestController.class); private final AggregateRepository aggregateRep; - private final DataRepository dataRep; @Autowired private JdbcTemplate jdbcTemplate; @Autowired private JdbcTemplate jdbcTemplateWithLimitedRows; - public VzRestController(final AggregateRepository aggregateRep, final DataRepository dataRep) { + public VzRestController(final AggregateRepository aggregateRep) { this.aggregateRep = aggregateRep; - this.dataRep = dataRep; } @GetMapping("/data/sums") Sums getData(@RequestParam("timestampStart")final long timestampStart, @RequestParam("timestampEnd")final long timestampEnd, @RequestParam("channelId")final int channelId) { + final List aggregates = jdbcTemplate.query( + "SELECT MIN(timestamp_start) AS min_timestamp_start, MAX(timestamp_end) AS max_timestamp_end, SUM(sum_positive) AS sum_positive, SUM(sum_negative) AS sum_negative FROM volkszaehler.tobias_aggregate WHERE channel_id=? AND timestamp_start>=? AND timestamp_end<=?;", + (rs, rowNum) -> new Aggregate(channelId, rs.getLong("min_timestamp_start"), rs.getLong("max_timestamp_end"), + rs.getLong("sum_positive"), rs.getLong("sum_negative")), + channelId ,timestampStart, timestampEnd); + if (aggregates.size() != 1) { + throw new RuntimeException("Interal error in SQL query."); + } + final Aggregate aggregate = aggregates.iterator().next(); + + double sumPos = aggregate.getSumPositive(); + double sumNeg = aggregate.getSumNegative(); + log.debug("sumPos: " + sumPos + " / sumNeg: " + sumNeg); + log.debug("timestampStart: " + timestampStart); + log.debug("timestampEnd: " + timestampEnd); + log.debug("firstTimestamp: " + aggregate.getTimestampStart()); + log.debug("lastTimestamp: " + aggregate.getTimestampEnd()); + + if (timestampStart < aggregate.getTimestampStart() ) { + final Sums startSums = getSums(timestampStart, aggregate.getTimestampStart(), channelId); + sumPos += startSums.getSumPositive(); + sumNeg += startSums.getSumNegative(); + log.debug("Start: " + startSums.toString()); + } + if (timestampEnd > aggregate.getTimestampEnd()) { + final Sums endSums = getSums(aggregate.getTimestampEnd(), timestampEnd, channelId); + sumPos += endSums.getSumPositive(); + sumNeg += endSums.getSumNegative(); + log.debug("End: " + endSums.toString()); + + } + sumPos /= 3600; + sumNeg /= 3600; + return new Sums(Math.round(sumPos), Math.round(sumNeg)); + } + + @GetMapping("/data/sumsWithFactor") + Sums getDataWithFactor(@RequestParam("timestampStart")final long timestampStart, + @RequestParam("timestampEnd")final long timestampEnd, + @RequestParam("channelId")final int channelId) { // this.jdbcTemplateWithLimitedRows.setMaxRows(1000); final List aggregates = jdbcTemplate.query( "SELECT * FROM volkszaehler.tobias_aggregate WHERE channel_id=? AND timestamp_start>=? AND timestamp_end<=? ORDER BY timestamp_start;", @@ -49,7 +93,7 @@ class VzRestController { long lastTimestamp = Long.MIN_VALUE; double sumPos = 0; double sumNeg = 0; - log.info("Number of aggregates: " + aggregates.size()); + log.debug("Number of aggregates: " + aggregates.size()); for (Aggregate ag : aggregates) { if (ag.getTimestampStart() < firstTimestamp) { firstTimestamp = ag.getTimestampStart(); @@ -60,38 +104,92 @@ class VzRestController { sumPos += ag.getSumPositive(); sumNeg += ag.getSumNegative(); } - sumPos /= 3600; - sumNeg /= 3600; - log.info("sumPos: " + sumPos + " / sumNeg: " + sumNeg); - log.info("timestampStart: " + timestampStart); - log.info("timestampEnd: " + timestampEnd); - log.info("firstTimestamp: " + firstTimestamp); - log.info("lastTimestamp: " + lastTimestamp); + log.debug("sumPos: " + sumPos + " / sumNeg: " + sumNeg); + log.debug("timestampStart: " + timestampStart); + log.debug("timestampEnd: " + timestampEnd); + log.debug("firstTimestamp: " + firstTimestamp); + log.debug("lastTimestamp: " + lastTimestamp); if (timestampStart < firstTimestamp ) { final Sums startSums = getSums(timestampStart, firstTimestamp, channelId); sumPos += startSums.getSumPositive(); sumNeg += startSums.getSumNegative(); - log.info("Start: " + startSums.toString()); + log.debug("Start: " + startSums.toString()); } if (timestampEnd > lastTimestamp) { final Sums endSums = getSums(lastTimestamp, timestampEnd, channelId); sumPos += endSums.getSumPositive(); sumNeg += endSums.getSumNegative(); - log.info("End: " + endSums.toString()); + log.debug("End: " + endSums.toString()); } - return new Sums(sumPos, sumNeg); + sumPos /= 3600; + sumNeg /= 3600; + return new Sums(Math.round(sumPos), Math.round(sumNeg)); } + @GetMapping("/data/sums2") Sums getData2(@RequestParam("timestampStart")final long timestampStart, @RequestParam("timestampEnd")final long timestampEnd, @RequestParam("channelId")final int channelId) { final Sums startSums = getSums(timestampStart, timestampEnd, channelId); - return startSums; + final Sums returnSums = new Sums(Math.round((double)startSums.getSumPositive()/3600), Math.round((double)startSums.getSumNegative()/3600)); + return returnSums; } + @GetMapping("/data/prices") + List getPrices(@RequestParam("timestampStart")final long timestampStart, + @RequestParam("timestampEnd")final long timestampEnd, + @RequestParam("contractId")final int contractId) { + final List prices = jdbcTemplate.query( + "SELECT * FROM tobias_energy_price WHERE contract_id=? AND timestamp_start < ? AND timestamp_end >= ? ORDER BY timestamp_start;", + (rs, rowNum) -> new EnergyPrice(rs.getInt("contract_id"), rs.getLong("timestamp_start"), rs.getLong("timestamp_end"), + rs.getFloat("price")), + contractId ,timestampEnd, timestampStart); + return prices; + } + + @GetMapping("/data/summary") + String getSummary(@RequestParam("timestampStart")final long timestampStart, + @RequestParam("timestampEnd")final long timestampEnd, + @RequestParam("contractId")final int contractId, + @RequestParam("channelIdMeter")final int channelIdMeter, + @RequestParam("channelIdSolar")final int channelIdSolar) { + final NumberFormat formatCurrency = new DecimalFormat("#,##0.00", new DecimalFormatSymbols(Locale.GERMAN)); + final NumberFormat formatPercent = new DecimalFormat("#,##0.00", new DecimalFormatSymbols(Locale.GERMAN)); + final NumberFormat formatEnergy = new DecimalFormat("#,##0", new DecimalFormatSymbols(Locale.GERMAN)); + final List prices = this.getPrices(timestampStart, timestampEnd, contractId); + final List partsMeter = new LinkedList(); + final List partsSolar = new LinkedList(); + float savedMoney = 0; + long totalSolar = 0; + long totalObtained = 0; + long totalInjected = 0; + for (EnergyPrice price : prices) { + final long tsStart = Math.max(price.getTimestampStart(), timestampStart); + final long tsEnd = Math.min(price.getTimestampEnd(), timestampEnd); + final Sums sumsMeter = getData(tsStart, tsEnd, channelIdMeter); + final Sums sumsSolar = getData(tsStart, tsEnd, channelIdSolar); + savedMoney += (float)(sumsSolar.getSumPositive() - sumsMeter.getSumNegative())/1000000 * price.getPrice(); + totalSolar += sumsSolar.getSumPositive(); + totalObtained += sumsMeter.getSumPositive(); + totalInjected += sumsMeter.getSumNegative(); + partsMeter.add(sumsMeter); + partsSolar.add(sumsSolar); + } + final StringBuilder sb = new StringBuilder(); + sb.append("Erzeugter Strom von der Photovoltaik: " + formatEnergy.format(totalSolar/1000000) + " kWh\n"); + sb.append("Eingespeister Strom von der Photovoltaik: " + formatEnergy.format(totalInjected/1000000) + " kWh\n"); + sb.append("Genutzter Strom von der Photovoltaik: " + formatEnergy.format((totalSolar-totalInjected)/1000000) + " kWh (="); + sb.append(formatPercent.format((float)(totalSolar-totalInjected)/(float)totalSolar*100) + " %)\n"); + sb.append("Bezogener Strom: " + formatEnergy.format(totalObtained/1000000) + " kWh\n"); + sb.append("Autakie: " + formatPercent.format((float)(totalSolar-totalInjected)/(float)(totalObtained+totalSolar-totalInjected)*100) + " %\n"); + sb.append("Eingespartes Geld: " + formatCurrency.format(savedMoney) + "€\n"); + return sb.toString(); + } + + @GetMapping("/test/{name}") String hello(@PathVariable("name")final String name) { return "Hello " + name + "!"; @@ -127,7 +225,7 @@ class VzRestController { } } } - return new Sums(wattMillisecondsPos/3600, wattMillisecondsNeg/3600); + return new Sums(Math.round(wattMillisecondsPos), Math.round(wattMillisecondsNeg)); } diff --git a/src/main/java/info/peper/vz/rest/bo/Sums.java b/src/main/java/info/peper/vz/rest/bo/Sums.java index 0186dc2..4c20187 100644 --- a/src/main/java/info/peper/vz/rest/bo/Sums.java +++ b/src/main/java/info/peper/vz/rest/bo/Sums.java @@ -5,22 +5,30 @@ import java.util.Objects; public class Sums implements Serializable { private static final long serialVersionUID = -1816023197422851264L; - private final double sumPositive; - private final double sumNegative; - public Sums(double sumPositive, double sumNegative) { + private final long sumPositive; + private final long sumNegative; + public Sums(long sumPositive, long sumNegative) { super(); this.sumPositive = sumPositive; this.sumNegative = sumNegative; } - public double getSumPositive() { + public long getSumPositive() { return sumPositive; } - public double getSumNegative() { + public long getSumNegative() { return sumNegative; } @Override + public String toString() { + return "Sums [sumPositive=" + sumPositive + ", sumNegative=" + sumNegative + "]"; + } + @Override public int hashCode() { - return Objects.hash(sumNegative, sumPositive); + final int prime = 31; + int result = 1; + result = prime * result + (int) (sumNegative ^ (sumNegative >>> 32)); + result = prime * result + (int) (sumPositive ^ (sumPositive >>> 32)); + return result; } @Override public boolean equals(Object obj) { @@ -31,12 +39,11 @@ public class Sums implements Serializable { if (getClass() != obj.getClass()) return false; Sums other = (Sums) obj; - return Double.doubleToLongBits(sumNegative) == Double.doubleToLongBits(other.sumNegative) - && Double.doubleToLongBits(sumPositive) == Double.doubleToLongBits(other.sumPositive); - } - @Override - public String toString() { - return "Sums [sumPositive=" + sumPositive + ", sumNegative=" + sumNegative + "]"; + if (sumNegative != other.sumNegative) + return false; + if (sumPositive != other.sumPositive) + return false; + return true; } diff --git a/src/main/java/info/peper/vz/rest/bo/db/EnergyPrice.java b/src/main/java/info/peper/vz/rest/bo/db/EnergyPrice.java new file mode 100644 index 0000000..cc5dcbb --- /dev/null +++ b/src/main/java/info/peper/vz/rest/bo/db/EnergyPrice.java @@ -0,0 +1,101 @@ +package info.peper.vz.rest.bo.db; + +import java.io.Serializable; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; + +@Entity(name = "tobias_energy_price") +@IdClass(EnergyPrice.CompositeKey.class) +public class EnergyPrice { + public static class CompositeKey implements Serializable { + private static final long serialVersionUID = 3097284483123288289L; + private int contractId; + private long timestampStart; + private long timestampEnd; + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + contractId; + result = prime * result + (int) (timestampEnd ^ (timestampEnd >>> 32)); + result = prime * result + (int) (timestampStart ^ (timestampStart >>> 32)); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CompositeKey other = (CompositeKey) obj; + if (contractId != other.contractId) + return false; + if (timestampEnd != other.timestampEnd) + return false; + if (timestampStart != other.timestampStart) + return false; + return true; + } + + } + + EnergyPrice() { + super(); + } + + public EnergyPrice(int contractId, long timestampStart, long timestampEnd, float price) { + super(); + this.contractId = contractId; + this.timestampStart = timestampStart; + this.timestampEnd = timestampEnd; + this.price = price; + } + @Id + @Column(name="contract_id") + private int contractId; + @Id + @Column(name="timestamp_start") + private long timestampStart; + @Id + @Column(name="timestamp_end") + private long timestampEnd; + @Column(name="price") + private float price; + + public int getContractId() { + return contractId; + } + + public void setContractId(int contractId) { + this.contractId = contractId; + } + + public long getTimestampStart() { + return timestampStart; + } + + public void setTimestampStart(long timestampStart) { + this.timestampStart = timestampStart; + } + + public long getTimestampEnd() { + return timestampEnd; + } + + public void setTimestampEnd(long timestampEnd) { + this.timestampEnd = timestampEnd; + } + + public float getPrice() { + return price; + } + + public void setPrice(float price) { + this.price = price; + } +} diff --git a/testdaten.ods b/testdaten.ods index 9e7a16a..1d81283 100644 Binary files a/testdaten.ods and b/testdaten.ods differ