Mit funktionierendem ScheduledTask für Berechnen der neuen Aggregates
This commit is contained in:
parent
05b93e03fb
commit
00153ed90b
@ -4,13 +4,172 @@ import java.sql.Connection;
|
|||||||
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.Types;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
|
||||||
import info.peper.vz.rest.bo.db.Aggregate2;
|
import info.peper.vz.rest.bo.db.Aggregate2;
|
||||||
|
import info.peper.vz.rest.bo.db.Data;
|
||||||
|
|
||||||
public final class Calculator {
|
public final class Calculator {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Calculator.class);
|
||||||
|
public static final long INTERVAL = 60*1000;
|
||||||
|
|
||||||
|
public static void processHouseMulti(final int houseId,
|
||||||
|
final long startTimestamp,
|
||||||
|
final long endTimestamp,
|
||||||
|
final long interval,
|
||||||
|
final int[] channelIdsSolar,
|
||||||
|
final int[] channelIdsMeter,
|
||||||
|
final JdbcTemplate jdbcTemplate) {
|
||||||
|
|
||||||
|
LOG.info("Processing house " + houseId + "...");
|
||||||
|
|
||||||
|
final List<Object[]> paramsForSave = new LinkedList<Object[]>();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Iterator<Data>[] iterSolar = new Iterator[channelIdsSolar.length];
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Iterator<Data>[] iterMeter = new Iterator[channelIdsMeter.length];
|
||||||
|
long[] currentTsSolar = new long[channelIdsSolar.length];
|
||||||
|
long[] currentTsMeter = new long[channelIdsMeter.length];
|
||||||
|
boolean[] noNextRecordSolar = new boolean[channelIdsSolar.length];
|
||||||
|
boolean[] noNextRecordMeter = new boolean[channelIdsMeter.length];
|
||||||
|
Data[] currentDataSolar = new Data[channelIdsSolar.length];
|
||||||
|
Data[] currentDataMeter = new Data[channelIdsMeter.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < channelIdsSolar.length; i++) {
|
||||||
|
|
||||||
|
List<Data> dataSolar = jdbcTemplate.query("SELECT * FROM volkszaehler.data WHERE channel_id=? AND timestamp>? ORDER BY timestamp;",
|
||||||
|
(rs, rowNum) -> new Data(rs.getInt("channel_id"), rs.getLong("timestamp"), rs.getDouble("value")),
|
||||||
|
channelIdsSolar[i], startTimestamp);
|
||||||
|
iterSolar[i] = dataSolar.iterator();
|
||||||
|
currentTsSolar[i] = startTimestamp;
|
||||||
|
noNextRecordSolar[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < channelIdsMeter.length; i++) {
|
||||||
|
List<Data> dataMeter = jdbcTemplate.query("SELECT * FROM volkszaehler.data WHERE channel_id=? AND timestamp>? ORDER BY timestamp;",
|
||||||
|
(rs, rowNum) -> new Data(rs.getInt("channel_id"), rs.getLong("timestamp"), rs.getDouble("value")),
|
||||||
|
channelIdsMeter[i], startTimestamp);
|
||||||
|
iterMeter[i] = dataMeter.iterator();
|
||||||
|
currentTsMeter[i] = startTimestamp;
|
||||||
|
noNextRecordMeter[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long intervalProduced = 0;
|
||||||
|
long intervalObtained = 0;
|
||||||
|
long intervalInjected = 0;
|
||||||
|
|
||||||
|
long intervalStartTimestamp = startTimestamp;
|
||||||
|
long intervalEndTimestamp = startTimestamp + interval;
|
||||||
|
|
||||||
|
// Eigentliche Verarbeitung
|
||||||
|
|
||||||
|
while (getMinOfArray(currentTsSolar) <= endTimestamp || getMinOfArray(currentTsMeter) <= endTimestamp) {
|
||||||
|
LOG.debug(intervalStartTimestamp + "...");
|
||||||
|
|
||||||
|
for (int iSolar = 0; iSolar < channelIdsSolar.length; iSolar++) {
|
||||||
|
currentTsSolar[iSolar] = intervalStartTimestamp;
|
||||||
|
|
||||||
|
while (currentTsSolar[iSolar] < intervalEndTimestamp && (noNextRecordSolar[iSolar] || iterSolar[iSolar].hasNext())) {
|
||||||
|
if (noNextRecordSolar[iSolar]) {
|
||||||
|
noNextRecordSolar[iSolar] = false;
|
||||||
|
} else {
|
||||||
|
currentDataSolar[iSolar] = iterSolar[iSolar].next();
|
||||||
|
}
|
||||||
|
|
||||||
|
final long tsSolar = currentDataSolar[iSolar].getTimestamp();
|
||||||
|
final double value = currentDataSolar[iSolar].getValue() > 1.0 ? currentDataSolar[iSolar].getValue() : 0.0;
|
||||||
|
final long tsDiff = (tsSolar < intervalEndTimestamp) ? tsSolar - currentTsSolar[iSolar] : intervalEndTimestamp - currentTsSolar[iSolar];
|
||||||
|
|
||||||
|
currentTsSolar[iSolar] = tsSolar;
|
||||||
|
|
||||||
|
intervalProduced += Math.round(value * tsDiff);
|
||||||
|
|
||||||
|
if (currentTsSolar[iSolar] >= intervalEndTimestamp) {
|
||||||
|
noNextRecordSolar[iSolar] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double meterValue = 0;
|
||||||
|
for (int iMeter = 0; iMeter < channelIdsMeter.length; iMeter++) {
|
||||||
|
currentTsMeter[iMeter] = intervalStartTimestamp;
|
||||||
|
|
||||||
|
while (currentTsMeter[iMeter] < intervalEndTimestamp && (noNextRecordMeter[iMeter] || iterMeter[iMeter].hasNext())) {
|
||||||
|
if (noNextRecordMeter[iMeter]) {
|
||||||
|
noNextRecordMeter[iMeter] = false;
|
||||||
|
} else {
|
||||||
|
currentDataMeter[iMeter] = iterMeter[iMeter].next();
|
||||||
|
}
|
||||||
|
final long tsMeter = currentDataMeter[iMeter].getTimestamp();
|
||||||
|
final double value = currentDataMeter[iMeter].getValue();
|
||||||
|
final long tsDiff = (tsMeter < intervalEndTimestamp) ? tsMeter - currentTsMeter[iMeter] : intervalEndTimestamp - currentTsMeter[iMeter];
|
||||||
|
|
||||||
|
currentTsMeter[iMeter] = tsMeter;
|
||||||
|
|
||||||
|
meterValue += Math.round(value * tsDiff);
|
||||||
|
|
||||||
|
if (currentTsMeter[iMeter] >= intervalEndTimestamp) {
|
||||||
|
noNextRecordMeter[iMeter] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (meterValue > 0.0) {
|
||||||
|
intervalObtained += Math.round(meterValue);
|
||||||
|
} else {
|
||||||
|
intervalInjected += Math.abs(Math.round(meterValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean readyToSave = true;
|
||||||
|
for (long endTsSolar : currentTsSolar) {
|
||||||
|
if (endTsSolar < intervalEndTimestamp) {
|
||||||
|
readyToSave = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (long endTsMeter : currentTsMeter) {
|
||||||
|
if (endTsMeter < intervalEndTimestamp) {
|
||||||
|
readyToSave = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.debug(" " + intervalProduced + " / " + intervalObtained + " / " + intervalInjected);
|
||||||
|
|
||||||
|
if (readyToSave) {
|
||||||
|
paramsForSave.add(new Object[] {houseId, intervalStartTimestamp, intervalEndTimestamp, intervalProduced, intervalObtained, intervalInjected});
|
||||||
|
} else {
|
||||||
|
LOG.warn("Not enough data at the end");
|
||||||
|
}
|
||||||
|
|
||||||
|
intervalStartTimestamp += interval;
|
||||||
|
intervalEndTimestamp += interval;
|
||||||
|
|
||||||
|
intervalInjected = 0;
|
||||||
|
intervalObtained = 0;
|
||||||
|
intervalProduced = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.info("Saving " + paramsForSave.size() + " new records...");
|
||||||
|
|
||||||
|
final int[] batchUpdateResults = jdbcTemplate.batchUpdate(
|
||||||
|
"INSERT INTO volkszaehler.tobias_aggregate2 (house_id, timestamp_start, timestamp_end, produced_energy, obtained_energy, injected_energy) VALUES (?, ?, ?, ?, ?, ?);",
|
||||||
|
paramsForSave, new int[] {Types.INTEGER, Types.BIGINT, Types.BIGINT, Types.BIGINT, Types.BIGINT, Types.BIGINT});
|
||||||
|
|
||||||
|
for (int batchUpdateResult : batchUpdateResults) {
|
||||||
|
if (batchUpdateResult != 1) {
|
||||||
|
LOG.error("Something went wrong while saving!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static List<Aggregate2> processHouseMulti(final int houseId,
|
public static List<Aggregate2> processHouseMulti(final int houseId,
|
||||||
final long startTimestamp,
|
final long startTimestamp,
|
||||||
final long endTimestamp,
|
final long endTimestamp,
|
||||||
|
|||||||
@ -1,79 +0,0 @@
|
|||||||
package info.peper.vz.rest;
|
|
||||||
|
|
||||||
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.List;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.CommandLineRunner;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
class LoadDatabase {
|
|
||||||
|
|
||||||
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 Logger LOG = LoggerFactory.getLogger(LoadDatabase.class);
|
|
||||||
|
|
||||||
static class Data {
|
|
||||||
final int channelId;
|
|
||||||
final long timestamp;
|
|
||||||
final int value;
|
|
||||||
|
|
||||||
Data(int channelId, long timestamp, int value) {
|
|
||||||
super();
|
|
||||||
this.channelId = channelId;
|
|
||||||
this.timestamp = timestamp;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
JdbcTemplate jdbcTemplate;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
CommandLineRunner initDatabase(AggregateRepository repository) {
|
|
||||||
|
|
||||||
return args -> {
|
|
||||||
LOG.info("################ jdbcTemplate: " + jdbcTemplate.getClass().getName());
|
|
||||||
// final long startTimestamp = getTimestamp("2022-06-01T00:00:00");
|
|
||||||
// final long endTimestamp = getTimestamp("2022-06-02T00:00:00");
|
|
||||||
// final List<Data> data = jdbcTemplate.query(
|
|
||||||
// "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")),
|
|
||||||
// 1 ,startTimestamp, endTimestamp);
|
|
||||||
//
|
|
||||||
// LOG.info("########## Count: " + data.size());
|
|
||||||
// long currentTimestamp = startTimestamp;
|
|
||||||
// long wattMillisecondsPos = 0;
|
|
||||||
// long wattMillisecondsNeg = 0;
|
|
||||||
// for (Data d : data) {
|
|
||||||
// final long rsTimestamp = d.timestamp;
|
|
||||||
// final long rsValue = d.value;
|
|
||||||
// final long tsDiff = rsTimestamp - Math.min(endTimestamp, currentTimestamp);
|
|
||||||
// currentTimestamp = rsTimestamp;
|
|
||||||
// if (rsValue > 0) {
|
|
||||||
// wattMillisecondsPos += (rsValue * tsDiff);
|
|
||||||
// } else if (rsValue < 0) {
|
|
||||||
// wattMillisecondsNeg += (-rsValue * tsDiff);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// repository.save(new Aggregate(1, startTimestamp, endTimestamp, wattMillisecondsPos, wattMillisecondsNeg));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
long getTimestamp(final String dateTime) {
|
|
||||||
final TemporalAccessor tempAccessor = DTF.parse(dateTime);
|
|
||||||
final Instant instant = Instant.from(tempAccessor);
|
|
||||||
return Instant.EPOCH.until(instant, ChronoUnit.MILLIS);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package info.peper.vz.rest;
|
package info.peper.vz.rest;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -17,8 +18,8 @@ public class ScheduledTasks {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private JdbcTemplate jdbcTemplate;
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
@Scheduled(fixedRate = 5000)
|
@Scheduled(fixedDelay = 60000)
|
||||||
public void printSomething() {
|
public void calculateAggregates() {
|
||||||
final List<Integer> houseIds = jdbcTemplate.query("SELECT house_id FROM tobias_house GROUP BY house_id ORDER BY house_id;",
|
final List<Integer> houseIds = jdbcTemplate.query("SELECT house_id FROM tobias_house GROUP BY house_id ORDER BY house_id;",
|
||||||
(rs, rowNum) -> rs.getInt("house_id"));
|
(rs, rowNum) -> rs.getInt("house_id"));
|
||||||
for (int houseId : houseIds) {
|
for (int houseId : houseIds) {
|
||||||
@ -27,11 +28,27 @@ public class ScheduledTasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processHouse(final int houseId) {
|
private void processHouse(final int houseId) {
|
||||||
LOG.info("Processing house " + houseId + "...");
|
|
||||||
final long lastTimestamp = jdbcTemplate.queryForObject("SELECT MAX(timestamp_end) FROM tobias_aggregate2 WHERE house_id=?", Long.class, houseId);
|
final long lastTimestamp = jdbcTemplate.queryForObject("SELECT MAX(timestamp_end) FROM tobias_aggregate2 WHERE house_id=?", Long.class, houseId);
|
||||||
LOG.info("- last timestamp: " + lastTimestamp);
|
|
||||||
long currentTimeRound = (System.currentTimeMillis()/60000)*60000;
|
final List<Integer> channelIdsMeter = jdbcTemplate.query("SELECT channel_id FROM tobias_house WHERE house_id=? AND type=1;", (rs, rowNum) -> rs.getInt("channel_id"), houseId);
|
||||||
// LOG.info(System.currentTimeMillis() + "");
|
final List<Integer> channelIdsSolar = jdbcTemplate.query("SELECT channel_id FROM tobias_house WHERE house_id=? AND type=2;", (rs, rowNum) -> rs.getInt("channel_id"), houseId);
|
||||||
// LOG.info(currentTimeRound + "");
|
|
||||||
|
long currentTimeLastInterval = (System.currentTimeMillis()/Calculator.INTERVAL)*Calculator.INTERVAL;
|
||||||
|
|
||||||
|
if (currentTimeLastInterval > lastTimestamp) {
|
||||||
|
Calculator.processHouseMulti(houseId, lastTimestamp, currentTimeLastInterval, Calculator.INTERVAL, getAsArray(channelIdsSolar), getAsArray(channelIdsMeter), jdbcTemplate);
|
||||||
|
} else {
|
||||||
|
LOG.warn("Nothing to do for house " + houseId + "...");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] getAsArray(final List<Integer> ints) {
|
||||||
|
final int[] result = new int[ints.size()];
|
||||||
|
final Iterator<Integer> iter = ints.iterator();
|
||||||
|
for (int i = 0; iter.hasNext(); i++) {
|
||||||
|
result[i] = iter.next().intValue();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user