169 lines
9.3 KiB
Java
169 lines
9.3 KiB
Java
package info.peper.vz.rest;
|
|
|
|
import java.text.DecimalFormat;
|
|
import java.text.DecimalFormatSymbols;
|
|
import java.text.NumberFormat;
|
|
import java.time.Duration;
|
|
import java.time.Instant;
|
|
import java.time.ZoneId;
|
|
import java.time.ZonedDateTime;
|
|
import java.time.temporal.ChronoField;
|
|
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.CrossOrigin;
|
|
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.Statistics;
|
|
import info.peper.vz.rest.bo.db.Aggregate;
|
|
import info.peper.vz.rest.bo.db.EnergyPrice;
|
|
|
|
@RestController
|
|
class VzRestController {
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(VzRestController.class);
|
|
|
|
@Autowired
|
|
private JdbcTemplate jdbcTemplate;
|
|
|
|
public VzRestController() {
|
|
}
|
|
|
|
@GetMapping("/rest-vz/latest-data")
|
|
List<Aggregate> getLatestData(
|
|
@RequestParam("houseId")final int houseId,
|
|
@RequestParam("timeWindow")final int timeWindow) {
|
|
return jdbcTemplate.query("SELECT * FROM tobias_aggregate2 WHERE house_id=? ORDER BY timestamp_start DESC LIMIT ?;",
|
|
(rs, rowNum) -> new Aggregate(houseId, rs.getLong("timestamp_start"), rs.getLong("timestamp_end"), rs.getLong("produced_energy"), rs.getLong("obtained_energy"), rs.getLong("injected_energy")),
|
|
houseId, timeWindow);
|
|
}
|
|
|
|
@GetMapping("/rest-vz/sums")
|
|
Aggregate getData(@RequestParam("timestampStart")final long timestampStart,
|
|
@RequestParam("timestampEnd")final long timestampEnd,
|
|
@RequestParam("houseId")final int houseId,
|
|
@RequestParam("solarFactor")final float solarFactor) {
|
|
final List<Aggregate> aggregates;
|
|
if (solarFactor == 1.0f) {
|
|
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 Aggregate(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);
|
|
} else {
|
|
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(GREATEST(obtained_energy + produced_energy - injected_energy - ? * produced_energy, 0))/3600 AS sum_obtained, SUM(ABS(LEAST(obtained_energy + produced_energy - injected_energy - ? * produced_energy, 0)))/3600 AS sum_injected FROM volkszaehler.tobias_aggregate2 WHERE house_id=? AND timestamp_start>=? AND timestamp_end<=?;",
|
|
(rs, rowNum) -> new Aggregate(houseId, rs.getLong("min_ts_start"), rs.getLong("max_ts_end"),
|
|
rs.getLong("sum_produced"), rs.getLong("sum_obtained"), rs.getLong("sum_injected")),
|
|
solarFactor, solarFactor, solarFactor, houseId ,timestampStart, timestampEnd);
|
|
}
|
|
if (aggregates.size() != 1) {
|
|
throw new RuntimeException("Interal error in SQL query.");
|
|
}
|
|
final Aggregate 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 aggregate;
|
|
}
|
|
|
|
@GetMapping("/rest-vz/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;
|
|
}
|
|
|
|
@CrossOrigin(origins = "http://localhost:4200")
|
|
@GetMapping(value="/rest-vz/stats", produces = {"application/json"})
|
|
Statistics getStats(@RequestParam(name = "timestampStart", defaultValue = "-1")long timestampStart,
|
|
@RequestParam(name = "timestampEnd", defaultValue = "-1")long timestampEnd,
|
|
@RequestParam(name = "duration", defaultValue = "")final String duration,
|
|
@RequestParam("houseId")final int houseId,
|
|
@RequestParam(name = "solarFactor", defaultValue = "1.0")final float solarFactor) {
|
|
|
|
if (!"".equals(duration)) {
|
|
final Duration dur = Duration.parse(duration);
|
|
timestampEnd = (Instant.now().toEpochMilli()/Calculator.INTERVAL)*Calculator.INTERVAL;
|
|
timestampStart = ((dur.subtractFrom(Instant.now()).getLong(ChronoField.INSTANT_SECONDS)*1000)/Calculator.INTERVAL)*Calculator.INTERVAL;
|
|
} else {
|
|
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 List<EnergyPrice> prices = this.getPrices(timestampStart, timestampEnd, houseId);
|
|
|
|
float savedMoney = 0;
|
|
float payedMoney = 0;
|
|
long totalProduced = 0;
|
|
long totalObtained = 0;
|
|
long totalInjected = 0;
|
|
long timestampMin = Long.MAX_VALUE;
|
|
long timestampMax = Long.MIN_VALUE;
|
|
for (EnergyPrice price : prices) {
|
|
final long tsStart = Math.max(price.getTimestampStart(), timestampStart);
|
|
final long tsEnd = Math.min(price.getTimestampEnd(), timestampEnd);
|
|
final Aggregate aggregate = getData(tsStart, tsEnd, houseId, solarFactor);
|
|
payedMoney += (float)(aggregate.getObtainedEnergy()/1000000 * price.getPrice());
|
|
savedMoney += (float)(aggregate.getProducedEnergy() - aggregate.getInjectedEnergy())/1000000 * price.getPrice();
|
|
totalProduced += aggregate.getProducedEnergy();
|
|
totalObtained += aggregate.getObtainedEnergy();
|
|
totalInjected += aggregate.getInjectedEnergy();
|
|
if (timestampMin > aggregate.getTimestampStart()) {
|
|
timestampMin = aggregate.getTimestampStart();
|
|
}
|
|
if (timestampMax < aggregate.getTimestampEnd()) {
|
|
timestampMax = aggregate.getTimestampEnd();
|
|
}
|
|
}
|
|
return new Statistics(timestampMin, timestampMax, totalProduced, totalInjected, totalObtained,
|
|
(long)(savedMoney*100), (long)(payedMoney*100));
|
|
}
|
|
|
|
@GetMapping(value="/rest-vz/summary", produces = {"text/plain"})
|
|
String getSummary(@RequestParam(name = "timestampStart", defaultValue = "-1")long timestampStart,
|
|
@RequestParam(name = "timestampEnd", defaultValue = "-1")long timestampEnd,
|
|
@RequestParam(name = "duration", defaultValue = "")final String duration,
|
|
@RequestParam("houseId")final int houseId,
|
|
@RequestParam(name = "solarFactor", defaultValue = "1.0")final float solarFactor) {
|
|
|
|
final Statistics stats = this.getStats(timestampStart, timestampEnd, duration, houseId, solarFactor);
|
|
|
|
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.00", new DecimalFormatSymbols(Locale.GERMAN));
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append("Start: .................................. " + ZonedDateTime.ofInstant(Instant.ofEpochMilli(stats.getTimestampStart()), ZoneId.systemDefault()).toString() + "\n");
|
|
sb.append("Ende: ................................... " + ZonedDateTime.ofInstant(Instant.ofEpochMilli(stats.getTimestampEnd()), ZoneId.systemDefault()).toString() + "\n");
|
|
sb.append("Erzeugter Strom von der Photovoltaik: ... " + formatEnergy.format((float)stats.getProducedEnergy()/1000000) + " kWh\n");
|
|
sb.append("Eingespeister Strom von der Photovoltaik: " + formatEnergy.format((float)stats.getInjectedEnergy()/1000000) + " kWh\n");
|
|
sb.append("Genutzter Strom von der Photovoltaik: ... " + formatEnergy.format((float)(stats.getProducedEnergy()-stats.getInjectedEnergy())/1000000) + " kWh (=");
|
|
sb.append(formatPercent.format((float)(stats.getProducedEnergy()-stats.getInjectedEnergy())/(float)stats.getProducedEnergy()*100) + " %)\n");
|
|
sb.append("Bezogener Strom: ........................ " + formatEnergy.format((float)stats.getObtainedEnergy()/1000000) + " kWh\n");
|
|
sb.append("Autakie: ................................ " + formatPercent.format((float)(stats.getProducedEnergy()-stats.getInjectedEnergy())/(float)(stats.getObtainedEnergy()+stats.getProducedEnergy()-stats.getInjectedEnergy())*100) + " %\n");
|
|
sb.append("Eingespartes Geld: ...................... " + formatCurrency.format(((float)stats.getSavedMoney())/100) + "€\n");
|
|
sb.append("Stromkosten: ............................ " + formatCurrency.format(((float)stats.getPayedMoney())/100) + "€\n");
|
|
return sb.toString();
|
|
}
|
|
|
|
}
|