Zwischenstand

This commit is contained in:
tobias 2025-02-25 22:03:00 +01:00
parent b80eff98ad
commit c4b8ea7106
10 changed files with 360 additions and 64 deletions

View File

@ -2,6 +2,8 @@ package info.peper.vz.rest;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import info.peper.vz.rest.bo.db.Aggregate;
interface AggregateRepository extends JpaRepository<Aggregate, Aggregate.CompositeKey> { interface AggregateRepository extends JpaRepository<Aggregate, Aggregate.CompositeKey> {
} }

View File

@ -0,0 +1,9 @@
package info.peper.vz.rest;
import org.springframework.data.jpa.repository.JpaRepository;
import info.peper.vz.rest.bo.db.Data;
interface DataRepository extends JpaRepository<Data, Data.CompositeKey> {
}

View File

@ -0,0 +1,104 @@
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;
public class FillAggregateTableMain {
private static final DateTimeFormatter DTF = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.systemDefault());
private static final int[] CHANNELS_TO_USE = new int[] {1, 4, };
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("2022-06-01T00:00:00");
long endTimeStamp = startTimeStamp + (24*60*60*1000);
final long finalEndTimeStamp = getTimestamp("2025-02-24T00:00:00");
while (endTimeStamp < finalEndTimeStamp) {
for (int channelId : CHANNELS_TO_USE) {
final long[] values = getValues(con, startTimeStamp, endTimeStamp, channelId);
saveValues(con, startTimeStamp, endTimeStamp, channelId, values);
System.out.println(DTF.format(Instant.ofEpochMilli(startTimeStamp)) + ": " + channelId);
}
startTimeStamp += 24*60*60*1000;
endTimeStamp += 24*60*60*1000;
}
}
}
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 long[] getValues(final Connection con,
final long startTimestamp,
final long endTimestamp,
final int channelId) throws SQLException {
long currentTimestamp = startTimestamp;
long wattMillisecondsPos = 0;
long wattMillisecondsNeg = 0;
while (currentTimestamp < endTimestamp) {
try (final PreparedStatement stmt = con.prepareStatement("SELECT * FROM volkszaehler.data WHERE channel_id=? AND timestamp>? ORDER BY timestamp;")) {
stmt.setMaxRows(10000);
stmt.setInt(1, channelId);
stmt.setLong(2, currentTimestamp);
try (final ResultSet rs = stmt.executeQuery()) {
while (rs.next() && currentTimestamp <= endTimestamp) {
final long rsTimestamp = rs.getLong("timestamp");
final long rsValue = rs.getLong("value");
final long tsDiff = rsTimestamp - Math.min(endTimestamp, currentTimestamp);
currentTimestamp = rsTimestamp;
if (rsValue > 0) {
wattMillisecondsPos += (rsValue * tsDiff);
} else if (rsValue < 0) {
wattMillisecondsNeg += (-rsValue * tsDiff);
}
}
}
}
}
return new long[] {wattMillisecondsPos/3600, wattMillisecondsNeg/3600};
}
}

View File

@ -44,29 +44,29 @@ class LoadDatabase {
return args -> { return args -> {
LOG.info("################ jdbcTemplate: " + jdbcTemplate.getClass().getName()); LOG.info("################ jdbcTemplate: " + jdbcTemplate.getClass().getName());
final long startTimestamp = getTimestamp("2022-06-01T00:00:00"); // final long startTimestamp = getTimestamp("2022-06-01T00:00:00");
final long endTimestamp = getTimestamp("2022-06-02T00:00:00"); // final long endTimestamp = getTimestamp("2022-06-02T00:00:00");
final List<Data> data = jdbcTemplate.query( // final List<Data> data = jdbcTemplate.query(
"SELECT * FROM volkszaehler.data WHERE channel_id=? AND timestamp>? AND timestamp<=? ORDER BY timestamp;", // "SELECT * FROM volkszaehler.data WHERE channel_id=? AND timestamp>? AND timestamp<=? ORDER BY timestamp;",
(rs, rowNum) -> new Data(rs.getInt("channel_id"), rs.getLong("timestamp"), rs.getInt("value")), // (rs, rowNum) -> new Data(rs.getInt("channel_id"), rs.getLong("timestamp"), rs.getInt("value")),
1 ,startTimestamp, endTimestamp); // 1 ,startTimestamp, endTimestamp);
//
LOG.info("########## Count: " + data.size()); // LOG.info("########## Count: " + data.size());
long currentTimestamp = startTimestamp; // long currentTimestamp = startTimestamp;
long wattMillisecondsPos = 0; // long wattMillisecondsPos = 0;
long wattMillisecondsNeg = 0; // long wattMillisecondsNeg = 0;
for (Data d : data) { // for (Data d : data) {
final long rsTimestamp = d.timestamp; // final long rsTimestamp = d.timestamp;
final long rsValue = d.value; // final long rsValue = d.value;
final long tsDiff = rsTimestamp - Math.min(endTimestamp, currentTimestamp); // final long tsDiff = rsTimestamp - Math.min(endTimestamp, currentTimestamp);
currentTimestamp = rsTimestamp; // currentTimestamp = rsTimestamp;
if (rsValue > 0) { // if (rsValue > 0) {
wattMillisecondsPos += (rsValue * tsDiff); // wattMillisecondsPos += (rsValue * tsDiff);
} else if (rsValue < 0) { // } else if (rsValue < 0) {
wattMillisecondsNeg += (-rsValue * tsDiff); // wattMillisecondsNeg += (-rsValue * tsDiff);
} // }
} // }
repository.save(new Aggregate(1, startTimestamp, endTimestamp, wattMillisecondsPos, wattMillisecondsNeg)); // repository.save(new Aggregate(1, startTimestamp, endTimestamp, wattMillisecondsPos, wattMillisecondsNeg));
}; };
} }

View File

@ -10,6 +10,7 @@ import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.time.Instant; import java.time.Instant;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -22,6 +23,24 @@ public class ReadDbMain {
private static final int[] CHANNELS_TO_USE = new int[] {1, 4, }; private static final int[] CHANNELS_TO_USE = new int[] {1, 4, };
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
try (final Connection con = DriverManager.getConnection(
"jdbc:mariadb://mariadb.fritz.box/volkszaehler",
"vz",
getPassword());
final Statement stmt = con.createStatement();) {
stmt.setFetchSize(10);
stmt.setMaxRows(24*60*60);
try (final ResultSet rs = stmt.executeQuery("SELECT * FROM data WHERE channel_id=1 AND timestamp>1656021600000");) {
for (int i = 0; i < 50000; i++) {
if (rs.next()) {
rs.getDouble("value");
}
}
}
}
}
public static void oldMain(String[] args) throws Exception {
try (final Connection con = DriverManager.getConnection( try (final Connection con = DriverManager.getConnection(
"jdbc:mariadb://mariadb.fritz.box/volkszaehler", "jdbc:mariadb://mariadb.fritz.box/volkszaehler",
"vz", "vz",
@ -35,24 +54,12 @@ public class ReadDbMain {
saveValues(con, startTimeStamp, endTimeStamp, channelId, values); saveValues(con, startTimeStamp, endTimeStamp, channelId, values);
System.out.println(DTF.format(Instant.ofEpochMilli(startTimeStamp)) + ": " + channelId); System.out.println(DTF.format(Instant.ofEpochMilli(startTimeStamp)) + ": " + channelId);
} }
// final long[] zaehler = getValues(con, startTimeStamp, endTimeStamp, 1);
// final long[] solar = getValues(con, startTimeStamp, endTimeStamp, 4);
// System.out.println(DTF.format(Instant.ofEpochMilli(startTimeStamp)) +
// "\t" +
// DTF.format(Instant.ofEpochMilli(endTimeStamp)) +
// "\t" +
// zaehler[0] +
// "\t" +
// zaehler[1] +
// "\t" +
// solar[0]
// );
startTimeStamp += 24*60*60*1000; startTimeStamp += 24*60*60*1000;
endTimeStamp += 24*60*60*1000; endTimeStamp += 24*60*60*1000;
} }
} }
} }
private static String getPassword() throws IOException { private static String getPassword() throws IOException {
try (final InputStream is = new FileInputStream("db-password.txt")) { try (final InputStream is = new FileInputStream("db-password.txt")) {
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is)); final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
@ -81,33 +88,35 @@ public class ReadDbMain {
} }
} }
private static long[] getValues(final Connection con, private static long[] getValues(final Connection con,
final long startTimestamp, final long startTimestamp,
final long endTimestamp, final long endTimestamp,
final int channelId) throws SQLException { final int channelId) throws SQLException {
try (final PreparedStatement stmt = con.prepareStatement("SELECT * FROM volkszaehler.data WHERE channel_id=? AND timestamp>? AND timestamp<=? ORDER BY timestamp;")) { long currentTimestamp = startTimestamp;
long currentTimestamp = startTimestamp; long wattMillisecondsPos = 0;
long wattMillisecondsPos = 0; long wattMillisecondsNeg = 0;
long wattMillisecondsNeg = 0;
stmt.setInt(1, channelId); while (currentTimestamp < endTimestamp) {
stmt.setLong(2, startTimestamp); try (final PreparedStatement stmt = con.prepareStatement("SELECT * FROM volkszaehler.data WHERE channel_id=? AND timestamp>?ORDER BY timestamp;")) {
stmt.setLong(3, endTimestamp + 24*60*60*1000); stmt.setMaxRows(10000);
try (final ResultSet rs = stmt.executeQuery()) { stmt.setInt(1, channelId);
while (rs.next() && currentTimestamp <= endTimestamp) { stmt.setLong(2, currentTimestamp);
final long rsTimestamp = rs.getLong("timestamp"); try (final ResultSet rs = stmt.executeQuery()) {
final long rsValue = rs.getLong("value"); while (rs.next() && currentTimestamp <= endTimestamp) {
final long tsDiff = rsTimestamp - Math.min(endTimestamp, currentTimestamp); final long rsTimestamp = rs.getLong("timestamp");
currentTimestamp = rsTimestamp; final long rsValue = rs.getLong("value");
if (rsValue > 0) { final long tsDiff = rsTimestamp - Math.min(endTimestamp, currentTimestamp);
wattMillisecondsPos += (rsValue * tsDiff); currentTimestamp = rsTimestamp;
} else if (rsValue < 0) { if (rsValue > 0) {
wattMillisecondsNeg += (-rsValue * tsDiff); wattMillisecondsPos += (rsValue * tsDiff);
} else if (rsValue < 0) {
wattMillisecondsNeg += (-rsValue * tsDiff);
}
} }
} }
} }
return new long[] {wattMillisecondsPos/3600, wattMillisecondsNeg/3600};
} }
return new long[] {wattMillisecondsPos/3600, wattMillisecondsNeg/3600};
} }

View File

@ -1,18 +1,49 @@
package info.peper.vz.rest; package info.peper.vz.rest;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import info.peper.vz.rest.bo.Sums;
import info.peper.vz.rest.bo.db.Aggregate;
@RestController @RestController
class VzRestController { class VzRestController {
private final AggregateRepository repository; private final AggregateRepository aggregateRep;
private final DataRepository dataRep;
@Autowired
private JdbcTemplate jdbcTemplate;
public VzRestController(final AggregateRepository repository) { public VzRestController(final AggregateRepository aggregateRep, final DataRepository dataRep) {
this.repository = repository; 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<Aggregate> aggregates = jdbcTemplate.query(
"SELECT * FROM volkszaehler.tobias_aggregate WHERE channel_id=? AND timestamp_start>=? AND timestamp_end<=? ORDER BY timestamp_start;",
(rs, rowNum) -> new Aggregate(rs.getInt("channel_id"), rs.getLong("timestamp_start"), rs.getLong("timestamp_end"),
rs.getLong("sum_positive"), rs.getLong("sum_negative")),
channelId ,timestampStart, timestampEnd);
long sumPos = 0;
long sumNeg = 0;
for (Aggregate ag : aggregates) {
sumPos += ag.getSumPositive();
sumNeg += ag.getSumNegative();
}
return new Sums(sumPos, sumNeg);
} }
@GetMapping("/test/{name}") @GetMapping("/test/{name}")
@ -22,7 +53,7 @@ class VzRestController {
@PostMapping("/test") @PostMapping("/test")
Aggregate newAggregate(@RequestBody final Aggregate aggregate) { Aggregate newAggregate(@RequestBody final Aggregate aggregate) {
return repository.save(aggregate); return aggregateRep.save(aggregate);
} }

View File

@ -0,0 +1,45 @@
package info.peper.vz.rest.bo;
import java.io.Serializable;
public class Sums implements Serializable {
private static final long serialVersionUID = -1816023197422851264L;
private final long sumPositive;
private final long sumNegative;
public Sums(long sumPositive, long sumNegative) {
super();
this.sumPositive = sumPositive;
this.sumNegative = sumNegative;
}
public long getSumPositive() {
return sumPositive;
}
public long getSumNegative() {
return sumNegative;
}
@Override
public int hashCode() {
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) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Sums other = (Sums) obj;
if (sumNegative != other.sumNegative)
return false;
if (sumPositive != other.sumPositive)
return false;
return true;
}
}

View File

@ -1,4 +1,4 @@
package info.peper.vz.rest; package info.peper.vz.rest.bo.db;
import java.io.Serializable; import java.io.Serializable;
@ -7,10 +7,10 @@ import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.IdClass; import jakarta.persistence.IdClass;
@Entity(name = "tobias_aggregate_spring") @Entity(name = "tobias_aggregate")
@IdClass(Aggregate.CompositeKey.class) @IdClass(Aggregate.CompositeKey.class)
class Aggregate { public class Aggregate {
static class CompositeKey implements Serializable { public static class CompositeKey implements Serializable {
private static final long serialVersionUID = 3097284483123288289L; private static final long serialVersionUID = 3097284483123288289L;
private int channelId; private int channelId;
private long timestampStart; private long timestampStart;
@ -48,7 +48,7 @@ class Aggregate {
super(); super();
} }
Aggregate(int channelId, long timestampStart, long timestampEnd, long sumPositive, long sumNegative) { public Aggregate(int channelId, long timestampStart, long timestampEnd, long sumPositive, long sumNegative) {
super(); super();
this.channelId = channelId; this.channelId = channelId;
this.timestampStart = timestampStart; this.timestampStart = timestampStart;
@ -69,4 +69,43 @@ class Aggregate {
private long sumPositive; private long sumPositive;
@Column(name="sum_negative") @Column(name="sum_negative")
private long sumNegative; private long sumNegative;
public int getChannelId() {
return channelId;
}
public void setChannelId(int channelId) {
this.channelId = channelId;
}
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 getSumPositive() {
return sumPositive;
}
public void setSumPositive(long sumPositive) {
this.sumPositive = sumPositive;
}
public long getSumNegative() {
return sumNegative;
}
public void setSumNegative(long sumNegative) {
this.sumNegative = sumNegative;
}
} }

View File

@ -0,0 +1,52 @@
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 = "data")
@IdClass(Data.CompositeKey.class)
public class Data {
public static class CompositeKey implements Serializable {
private static final long serialVersionUID = -3486278368164696822L;
private int channelId;
private long timestamp;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + channelId;
result = prime * result + (int) (timestamp ^ (timestamp >>> 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 (channelId != other.channelId)
return false;
if (timestamp != other.timestamp)
return false;
return true;
}
}
@Id
@Column(name="channel_id")
private int channelId;
@Id
@Column(name="timestamp")
private long timestamp;
@Column(name="value")
private double value;
}

View File

@ -0,0 +1,5 @@
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mariadb://mariadb.fritz.box:3306/volkszaehler
spring.datasource.username=vz
spring.datasource.password=2pG7GjQajemwY3f9
spring.jpa.show-sql: true