diff --git a/src/main/java/info/peper/vz/rest/FillAggregateTableMain3.java b/src/main/java/info/peper/vz/rest/FillAggregateTableMain3.java new file mode 100644 index 0000000..b364a89 --- /dev/null +++ b/src/main/java/info/peper/vz/rest/FillAggregateTableMain3.java @@ -0,0 +1,172 @@ +package info.peper.vz.rest; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAccessor; +import java.util.LinkedList; +import java.util.List; + +import info.peper.vz.rest.bo.db.Aggregate2; + +public class FillAggregateTableMain3 { + + private static final DateTimeFormatter DTF = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.systemDefault()); + private static final List SAVELIST = new LinkedList(); + + public static void main(String[] args) throws Exception { + try (final Connection con = DriverManager.getConnection( + "jdbc:mariadb://mariadb.fritz.box/volkszaehler", + "vz", + 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); + } + System.out.println("Saving... " + SAVELIST.size()); + saveValues(con); +// for (AggregateToSave ats : SAVELIST) { +// saveValues(con, ats.startTs, ats.endTs, ats.channelId, new long[] {ats.valuePos, ats.valueNeg}); +// System.out.println("####"); +// } + } + } + + private static void processHouse(final long startTimestamp, + final long endTimestamp, + final long interval, + final int channelIdSolar, + final int channelIdMeter, + final Connection con) throws SQLException { + long currentTimestamp = startTimestamp; + long intervalStartTimestamp = startTimestamp; + long intervalEndTimestamp = startTimestamp + interval; + long intervalPos = 0; + long intervalNeg = 0; + try (final PreparedStatement stmtSolar = con.prepareStatement("SELECT * FROM volkszaehler.data WHERE channel_id=? AND timestamp>? ORDER BY timestamp;"); + final PreparedStatement stmtMeter = con.prepareStatement("SELECT * FROM volkszaehler.data WHERE channel_id=? AND timestamp>? ORDER BY timestamp;");) { + stmtSolar.setInt(1, channelIdSolar); + stmtSolar.setLong(2, startTimestamp); + stmtSolar.setFetchSize(1000); + stmtMeter.setInt(1, channelIdMeter); + stmtMeter.setLong(2, startTimestamp); + stmtMeter.setFetchSize(1000); + + + boolean noNextRecord = false; + + + + try (final ResultSet rs = stmtSolar.executeQuery()) { + long sumDiff = 0; + while (noNextRecord || (currentTimestamp <= endTimestamp && rs.next())) { + noNextRecord = false; + final long timestamp = rs.getLong("timestamp"); + final double value; + if (rs.getDouble("value") >= 0 && rs.getDouble("value") < 1) { + value = 0.0; + } else { + value = rs.getDouble("value"); + } + final long tsDiff; + if (timestamp < intervalEndTimestamp) { + tsDiff = timestamp - currentTimestamp; + } else { + tsDiff = intervalEndTimestamp - currentTimestamp; + } +// final long tsDiff = Math.min(timestamp - currentTimestamp, intervalEndTimestamp - currentTimestamp); + sumDiff += tsDiff; + currentTimestamp = timestamp; + if (value > 0) { + intervalPos += Math.round(value * tsDiff); + } else if (value < 0) { + 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); + } + sumDiff = 0; + if (intervalStartTimestamp % (86400000*10) == 0) { + System.out.println( + DTF.format(Instant.ofEpochMilli(intervalStartTimestamp)) + " - " + + DTF.format(Instant.ofEpochMilli(intervalEndTimestamp)) + " / " + + (intervalPos/3600) + " / " + + (intervalNeg/3600)); + } + SAVELIST.add(new AggregateToSave(intervalStartTimestamp, intervalEndTimestamp, Math.round(intervalPos), Math.round(intervalNeg), channelId)); + intervalStartTimestamp += interval; + intervalEndTimestamp += interval; + currentTimestamp = intervalStartTimestamp; + intervalPos = 0; + intervalNeg = 0; + noNextRecord = true; + } + } + } + } + } + + private static String getPassword() throws IOException { + try (final InputStream is = new FileInputStream("db-password.txt")) { + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is)); + return bufferedReader.readLine(); + } + } + + private static long getTimestamp(final String dateTime) { + final TemporalAccessor tempAccessor = DTF.parse(dateTime); + final Instant instant = Instant.from(tempAccessor); + return Instant.EPOCH.until(instant, ChronoUnit.MILLIS); + } + + private static void saveValues(final Connection con, + final long startTimestamp, + final long endTimestamp, + final int channelId, + final long[] values) throws SQLException { + try (final PreparedStatement stmt = con.prepareStatement("INSERT INTO tobias_aggregate (channel_id, timestamp_start, timestamp_end, sum_positive, sum_negative) VALUES (?, ?, ?, ?, ?)")) { + stmt.setInt(1, channelId); + stmt.setLong(2, startTimestamp); + stmt.setLong(3, endTimestamp); + stmt.setLong(4, values[0]); + stmt.setLong(5, values[1]); + stmt.execute(); + } + } + + private static void saveValues(final Connection con) throws SQLException { + try (final PreparedStatement stmt = con.prepareStatement("INSERT INTO tobias_aggregate (channel_id, timestamp_start, timestamp_end, sum_positive, sum_negative) VALUES (?, ?, ?, ?, ?)")) { + int i = 0; + for (AggregateToSave ats : SAVELIST) { + stmt.setInt(1, ats.channelId); + stmt.setLong(2, ats.startTs); + stmt.setLong(3, ats.endTs); + stmt.setDouble(4, ats.valuePos); + stmt.setDouble(5, ats.valueNeg); + stmt.addBatch(); + i++; + if (i % 100000 == 0) { + System.out.println(i); + stmt.executeBatch(); + } + } + stmt.executeBatch(); + } + } +} diff --git a/src/main/java/info/peper/vz/rest/bo/db/Aggregate2.java b/src/main/java/info/peper/vz/rest/bo/db/Aggregate2.java new file mode 100644 index 0000000..484c9ba --- /dev/null +++ b/src/main/java/info/peper/vz/rest/bo/db/Aggregate2.java @@ -0,0 +1,124 @@ +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_aggregate2") +@IdClass(Aggregate2.CompositeKey.class) +public class Aggregate2 { + public static class CompositeKey implements Serializable { + private static final long serialVersionUID = 3097284483123288289L; + private int houseId; + private long timestampStart; + private long timestampEnd; + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + houseId; + 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 (houseId != other.houseId) + return false; + if (timestampEnd != other.timestampEnd) + return false; + if (timestampStart != other.timestampStart) + return false; + return true; + } + } + + Aggregate2() { + super(); + } + + public Aggregate2(int houseId, long timestampStart, long timestampEnd, long producedEnergy, long obtainedEnergy, long injectedEnergy) { + super(); + this.houseId = houseId; + this.timestampStart = timestampStart; + this.timestampEnd = timestampEnd; + this.producedEnergy = producedEnergy; + this.obtainedEnergy = obtainedEnergy; + this.injectedEnergy = injectedEnergy; + } + @Id + @Column(name="house_id") + private int houseId; + @Id + @Column(name="timestamp_start") + private long timestampStart; + @Id + @Column(name="timestamp_end") + private long timestampEnd; + @Column(name="produced_energy") + private long producedEnergy; + @Column(name="obtained_energy") + private long obtainedEnergy; + @Column(name="injected_energy") + private long injectedEnergy; + + public int getHouseId() { + return houseId; + } + + public void setHouseId(int houseId) { + this.houseId = houseId; + } + + 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 long getProducedEnergy() { + return producedEnergy; + } + + public void setProducedEnergy(long producedEnergy) { + this.producedEnergy = producedEnergy; + } + + public long getObtainedEnergy() { + return obtainedEnergy; + } + + public void setObtainedEnergy(long obtainedEnergy) { + this.obtainedEnergy = obtainedEnergy; + } + + public long getInjectedEnergy() { + return injectedEnergy; + } + + public void setInjectedEnergy(long injectedEnergy) { + this.injectedEnergy = injectedEnergy; + } + +}