287 lines
14 KiB
Java
287 lines
14 KiB
Java
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;
|
|
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.RequestParam;
|
|
import org.springframework.web.bind.annotation.RestController;
|
|
|
|
import info.peper.vz.rest.bo.Sums;
|
|
import info.peper.vz.rest.bo.Sums2;
|
|
import info.peper.vz.rest.bo.db.Aggregate;
|
|
import info.peper.vz.rest.bo.db.Aggregate2;
|
|
import info.peper.vz.rest.bo.db.Data;
|
|
import info.peper.vz.rest.bo.db.EnergyPrice;
|
|
|
|
@RestController
|
|
class VzRestController {
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(VzRestController.class);
|
|
|
|
private final AggregateRepository aggregateRep;
|
|
|
|
@Autowired
|
|
private JdbcTemplate jdbcTemplate;
|
|
@Autowired
|
|
private JdbcTemplate jdbcTemplateWithLimitedRows;
|
|
|
|
public VzRestController(final AggregateRepository aggregateRep) {
|
|
this.aggregateRep = aggregateRep;
|
|
}
|
|
|
|
@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 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/sums2")
|
|
Sums2 getData2(@RequestParam("timestampStart")final long timestampStart,
|
|
@RequestParam("timestampEnd")final long timestampEnd,
|
|
@RequestParam("houseId")final int houseId) {
|
|
final List<Aggregate2> aggregates = jdbcTemplate.query(
|
|
"SELECT MIN(timestamp_start) AS min_ts_start, MAX(timestamp_end) AS max_ts_end, SUM(produced_energy)/3600 AS sum_produced, SUM(obtained_energy)/3600 AS sum_obtained, SUM(injected_energy)/3600 AS sum_injected FROM volkszaehler.tobias_aggregate2 WHERE house_id=? AND timestamp_start>=? AND timestamp_end<=?;",
|
|
(rs, rowNum) -> new Aggregate2(houseId, rs.getLong("min_ts_start"), rs.getLong("max_ts_end"),
|
|
rs.getLong("sum_produced"), rs.getLong("sum_obtained"), rs.getLong("sum_injected")),
|
|
houseId ,timestampStart, timestampEnd);
|
|
if (aggregates.size() != 1) {
|
|
throw new RuntimeException("Interal error in SQL query.");
|
|
}
|
|
final Aggregate2 aggregate = aggregates.iterator().next();
|
|
|
|
log.debug("energyProduced: " + aggregate.getProducedEnergy() + " / energyObtained: " + aggregate.getObtainedEnergy() + " / injectedEnergy: " + aggregate.getInjectedEnergy());
|
|
log.debug("timestampStart: " + timestampStart);
|
|
log.debug("timestampEnd: " + timestampEnd);
|
|
log.debug("firstTimestamp: " + aggregate.getTimestampStart());
|
|
log.debug("lastTimestamp: " + aggregate.getTimestampEnd());
|
|
|
|
return new Sums2(
|
|
Math.round(aggregate.getInjectedEnergy()),
|
|
Math.round(aggregate.getObtainedEnergy()),
|
|
Math.round(aggregate.getProducedEnergy()));
|
|
}
|
|
|
|
@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<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 firstTimestamp = Long.MAX_VALUE;
|
|
long lastTimestamp = Long.MIN_VALUE;
|
|
double sumPos = 0;
|
|
double sumNeg = 0;
|
|
log.debug("Number of aggregates: " + aggregates.size());
|
|
for (Aggregate ag : aggregates) {
|
|
if (ag.getTimestampStart() < firstTimestamp) {
|
|
firstTimestamp = ag.getTimestampStart();
|
|
}
|
|
if (ag.getTimestampEnd() > lastTimestamp) {
|
|
lastTimestamp = ag.getTimestampEnd();
|
|
}
|
|
sumPos += ag.getSumPositive();
|
|
sumNeg += ag.getSumNegative();
|
|
}
|
|
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.debug("Start: " + startSums.toString());
|
|
}
|
|
if (timestampEnd > lastTimestamp) {
|
|
final Sums endSums = getSums(lastTimestamp, 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/sumsWithoutAggregate")
|
|
Sums getDataWithoutAggregate(@RequestParam("timestampStart")final long timestampStart,
|
|
@RequestParam("timestampEnd")final long timestampEnd,
|
|
@RequestParam("channelId")final int channelId) {
|
|
final Sums startSums = getSums(timestampStart, timestampEnd, channelId);
|
|
final Sums returnSums = new Sums(Math.round((double)startSums.getSumPositive()/3600), Math.round((double)startSums.getSumNegative()/3600));
|
|
return returnSums;
|
|
}
|
|
|
|
@GetMapping("/data/prices")
|
|
List<EnergyPrice> getPrices(@RequestParam("timestampStart")final long timestampStart,
|
|
@RequestParam("timestampEnd")final long timestampEnd,
|
|
@RequestParam("houseId")final int houseId) {
|
|
final List<EnergyPrice> prices = jdbcTemplate.query(
|
|
"SELECT * FROM tobias_energy_price WHERE house_id=? AND timestamp_start < ? AND timestamp_end >= ? ORDER BY timestamp_start;",
|
|
(rs, rowNum) -> new EnergyPrice(rs.getInt("house_id"), rs.getLong("timestamp_start"), rs.getLong("timestamp_end"),
|
|
rs.getFloat("price")),
|
|
houseId ,timestampEnd, timestampStart);
|
|
return prices;
|
|
}
|
|
|
|
@GetMapping("/data/summary")
|
|
String getSummary(@RequestParam("timestampStart")final long timestampStart,
|
|
@RequestParam("timestampEnd")final long timestampEnd,
|
|
@RequestParam("houseId")final int houseId,
|
|
@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<EnergyPrice> prices = this.getPrices(timestampStart, timestampEnd, houseId);
|
|
final List<Sums> partsMeter = new LinkedList<Sums>();
|
|
final List<Sums> partsSolar = new LinkedList<Sums>();
|
|
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("/data/summary2")
|
|
String getSummary2(@RequestParam(name = "timestampStart", defaultValue = "-1")long timestampStart,
|
|
@RequestParam(name = "timestampEnd", defaultValue = "-1")long timestampEnd,
|
|
@RequestParam("houseId")final int houseId) {
|
|
|
|
if (timestampStart == -1) {
|
|
timestampStart = jdbcTemplate.queryForObject("SELECT MIN(timestamp_start) AS ts FROM tobias_aggregate2 WHERE house_id=?;", Long.class, houseId);
|
|
}
|
|
if (timestampEnd == -1) {
|
|
timestampEnd = jdbcTemplate.queryForObject("SELECT MAX(timestamp_end) AS ts FROM tobias_aggregate2 WHERE house_id=?;", Long.class, houseId);
|
|
}
|
|
|
|
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<EnergyPrice> prices = this.getPrices(timestampStart, timestampEnd, houseId);
|
|
|
|
float savedMoney = 0;
|
|
long totalProduced = 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 Sums2 sums = getData2(tsStart, tsEnd, houseId);
|
|
savedMoney += (float)(sums.getProduced() - sums.getInjected())/1000000 * price.getPrice();
|
|
totalProduced += sums.getProduced();
|
|
totalObtained += sums.getObtained();
|
|
totalInjected += sums.getInjected();
|
|
}
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append("Erzeugter Strom von der Photovoltaik: " + formatEnergy.format(totalProduced/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((totalProduced-totalInjected)/1000000) + " kWh (=");
|
|
sb.append(formatPercent.format((float)(totalProduced-totalInjected)/(float)totalProduced*100) + " %)\n");
|
|
sb.append("Bezogener Strom: " + formatEnergy.format(totalObtained/1000000) + " kWh\n");
|
|
sb.append("Autakie: " + formatPercent.format((float)(totalProduced-totalInjected)/(float)(totalObtained+totalProduced-totalInjected)*100) + " %\n");
|
|
sb.append("Eingespartes Geld: " + formatCurrency.format(savedMoney) + "€\n");
|
|
return sb.toString();
|
|
}
|
|
|
|
private Sums getSums(final long startTimestamp,
|
|
final long endTimestamp,
|
|
final int channelId) {
|
|
long currentTimestamp = startTimestamp;
|
|
double wattMillisecondsPos = 0;
|
|
double wattMillisecondsNeg = 0;
|
|
|
|
while (currentTimestamp < endTimestamp) {
|
|
final List<Data> datas = jdbcTemplateWithLimitedRows.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")),
|
|
channelId, currentTimestamp);
|
|
for (Data data : datas) {
|
|
if (currentTimestamp <= endTimestamp)
|
|
{
|
|
final long tsDiff = Math.min(data.getTimestamp() - currentTimestamp, endTimestamp - currentTimestamp);
|
|
currentTimestamp = data.getTimestamp();
|
|
if (data.getValue() > 1.0) {
|
|
wattMillisecondsPos += (data.getValue() * tsDiff);
|
|
}
|
|
if (data.getValue() < 0.0) {
|
|
wattMillisecondsNeg += (-data.getValue() * tsDiff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return new Sums(Math.round(wattMillisecondsPos), Math.round(wattMillisecondsNeg));
|
|
|
|
}
|
|
|
|
}
|