mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Keep track of peak production, peak consumption, peak from grid, and peak to grid values to aid in solar panel and storage sizing.
This commit is contained in:
parent
d63f6df1fd
commit
0cfdaaa272
|
@ -33,6 +33,7 @@ public interface CurrentMonitorDao {
|
|||
|
||||
void updateSummaries(BreakerGroup _rootGroup, Set<Date> _daysToSummarize, TimeZone _tz);
|
||||
void rebuildSummaries(int _accountId);
|
||||
void rebuildSummariesAsync(int _accountId);
|
||||
void rebuildSummaries(int _accountId, Date _start, Date _end);
|
||||
|
||||
String addPasswordResetKey(String _email);
|
||||
|
|
|
@ -192,6 +192,11 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rebuildSummariesAsync(int _accountId) {
|
||||
executor.submit(()->rebuildSummaries(_accountId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rebuildSummaries(int _accountId) {
|
||||
HubPowerMinute firstMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sort("minute"));
|
||||
|
|
|
@ -14,7 +14,6 @@ import java.util.Iterator;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeMap;
|
||||
|
@ -30,6 +29,10 @@ public class BreakerGroupEnergy {
|
|||
private List<EnergyBlock> energyBlocks;
|
||||
private double toGrid;
|
||||
private double fromGrid;
|
||||
private double peakToGrid;
|
||||
private double peakFromGrid;
|
||||
private double peakConsumption;
|
||||
private double peakProduction;
|
||||
private TimeZone timezone;
|
||||
|
||||
public BreakerGroupEnergy() {
|
||||
|
@ -65,7 +68,7 @@ public class BreakerGroupEnergy {
|
|||
resetEnergy(minute);
|
||||
}
|
||||
int idx;
|
||||
Map<MeterMinute, MeterMinuteValues> meters = new HashMap<>();
|
||||
Map<Integer, Map<Integer, MeterMinute>> minutes = new TreeMap<>();
|
||||
for (HubPowerMinute hubPower : _hubPower) {
|
||||
Date minute = hubPower.getMinuteAsDate();
|
||||
for (BreakerPowerMinute breaker : CollectionUtils.makeNotNull(hubPower.getBreakers())) {
|
||||
|
@ -75,7 +78,7 @@ public class BreakerGroupEnergy {
|
|||
BreakerGroup group = _breakerKeyToGroup.get(breaker.breakerKey());
|
||||
if (group == null)
|
||||
continue;
|
||||
MeterMinuteValues meter = meters.computeIfAbsent(new MeterMinute(b.getMeter(), minute), _p->new MeterMinuteValues());
|
||||
MeterMinute meter = minutes.computeIfAbsent(hubPower.getMinute(), _p->new TreeMap<>()).computeIfAbsent(b.getMeter(), _m->new MeterMinute(b.getMeter(), hubPower.getMinuteAsDate()));
|
||||
idx = 0;
|
||||
EnergyBlock block = getBlock(group.getId(), minute);
|
||||
if (block != null) {
|
||||
|
@ -94,27 +97,64 @@ public class BreakerGroupEnergy {
|
|||
}
|
||||
double monthFromGrid = _month == null ? 0.0 : _month.getFromGrid();
|
||||
double secondFromGrid;
|
||||
for (Map.Entry<MeterMinute, MeterMinuteValues> meter : meters.entrySet()) {
|
||||
for (MeterMinute minute : CollectionUtils.aggregate(minutes.values(), Map::values)) {
|
||||
double monthkWh = monthFromGrid/3600000;
|
||||
List<BillingRate> consumptionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(GridFlow.FROM, meter.getKey().meter, monthkWh, meter.getKey().minute, timezone));
|
||||
List<BillingRate> productionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(GridFlow.TO, meter.getKey().meter, monthkWh, meter.getKey().minute, timezone));
|
||||
List<BillingRate> consumptionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(GridFlow.FROM, minute.getMeter(), monthkWh, minute.getMinute(), timezone));
|
||||
List<BillingRate> productionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(GridFlow.TO, minute.getMeter(), monthkWh, minute.getMinute(), timezone));
|
||||
for (int i = 0; i < 60; i++) {
|
||||
secondFromGrid = meter.getValue().usage[i] - meter.getValue().solar[i];
|
||||
if (minute.usage[i] > peakConsumption)
|
||||
peakConsumption = minute.usage[i];
|
||||
if (minute.solar[i] > peakProduction)
|
||||
peakProduction = minute.solar[i];
|
||||
secondFromGrid = minute.usage[i] - minute.solar[i];
|
||||
monthFromGrid += secondFromGrid;
|
||||
if (secondFromGrid > 0) {
|
||||
fromGrid += secondFromGrid;
|
||||
if (secondFromGrid > peakFromGrid)
|
||||
peakFromGrid = secondFromGrid;
|
||||
for (BillingRate rate : consumptionRates) {
|
||||
meter.getValue().charges[i] += rate.apply(secondFromGrid/3600000);
|
||||
minute.charges[i] += rate.apply(secondFromGrid/3600000);
|
||||
}
|
||||
}
|
||||
else {
|
||||
toGrid -= secondFromGrid;
|
||||
secondFromGrid = -secondFromGrid;
|
||||
toGrid += secondFromGrid;
|
||||
if (secondFromGrid > peakToGrid)
|
||||
peakToGrid = secondFromGrid;
|
||||
for (BillingRate rate : productionRates) {
|
||||
meter.getValue().charges[i] += rate.apply(secondFromGrid/3600000);
|
||||
minute.charges[i] -= rate.apply(secondFromGrid/3600000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
double curConsumption;
|
||||
double curProduction;
|
||||
double curToGrid;
|
||||
double curFromGrid;
|
||||
for (Map<Integer, MeterMinute> meters : minutes.values()) {
|
||||
for (int i=0; i < 60; i++) {
|
||||
curConsumption = 0;
|
||||
curProduction = 0;
|
||||
curToGrid = 0;
|
||||
curFromGrid = 0;
|
||||
for (MeterMinute meterValues : meters.values()) {
|
||||
curConsumption += meterValues.usage[i];
|
||||
curProduction += meterValues.solar[i];
|
||||
if (meterValues.solar[i] > meterValues.usage[i])
|
||||
curToGrid += meterValues.solar[i] - meterValues.usage[i];
|
||||
else
|
||||
curFromGrid += meterValues.usage[i] - meterValues.solar[i];
|
||||
}
|
||||
if (curConsumption > peakConsumption)
|
||||
peakConsumption = curConsumption;
|
||||
if (curProduction > peakProduction)
|
||||
peakProduction = curProduction;
|
||||
if (curToGrid > peakToGrid)
|
||||
peakToGrid = curToGrid;
|
||||
if (curFromGrid > peakFromGrid)
|
||||
peakFromGrid = curFromGrid;
|
||||
}
|
||||
}
|
||||
for (HubPowerMinute hubPower : _hubPower) {
|
||||
Date minute = hubPower.getMinuteAsDate();
|
||||
for (BreakerPowerMinute breaker : CollectionUtils.makeNotNull(hubPower.getBreakers())) {
|
||||
|
@ -124,7 +164,7 @@ public class BreakerGroupEnergy {
|
|||
BreakerGroup group = _breakerKeyToGroup.get(breaker.breakerKey());
|
||||
if (group == null)
|
||||
continue;
|
||||
MeterMinuteValues meter = meters.get(new MeterMinute(b.getMeter(), minute));
|
||||
MeterMinute meter = minutes.get(hubPower.getMinute()).get(b.getMeter());
|
||||
idx = 0;
|
||||
double charge = 0.0;
|
||||
for (Float power : CollectionUtils.makeNotNull(breaker.getReadings())) {
|
||||
|
@ -190,6 +230,14 @@ public class BreakerGroupEnergy {
|
|||
block.addCharge(curEnergy.getCharge());
|
||||
energy.setToGrid(energy.getToGrid()+curEnergy.getToGrid());
|
||||
energy.setFromGrid(energy.getFromGrid()+curEnergy.getFromGrid());
|
||||
if (curEnergy.getPeakFromGrid() > energy.getPeakFromGrid())
|
||||
energy.setPeakFromGrid(curEnergy.getPeakFromGrid());
|
||||
if (curEnergy.getPeakToGrid() > energy.getPeakToGrid())
|
||||
energy.setPeakToGrid(curEnergy.getPeakToGrid());
|
||||
if (curEnergy.getPeakConsumption() > energy.getPeakConsumption())
|
||||
energy.setPeakConsumption(curEnergy.getPeakConsumption());
|
||||
if (curEnergy.getPeakProduction() > energy.getPeakProduction())
|
||||
energy.setPeakProduction(curEnergy.getPeakProduction());
|
||||
}
|
||||
return energy;
|
||||
}
|
||||
|
@ -304,6 +352,38 @@ public class BreakerGroupEnergy {
|
|||
fromGrid = _fromGrid;
|
||||
}
|
||||
|
||||
public double getPeakToGrid() {
|
||||
return peakToGrid;
|
||||
}
|
||||
|
||||
public void setPeakToGrid(double _peakToGrid) {
|
||||
peakToGrid = _peakToGrid;
|
||||
}
|
||||
|
||||
public double getPeakFromGrid() {
|
||||
return peakFromGrid;
|
||||
}
|
||||
|
||||
public void setPeakFromGrid(double _peakFromGrid) {
|
||||
peakFromGrid = _peakFromGrid;
|
||||
}
|
||||
|
||||
public double getPeakConsumption() {
|
||||
return peakConsumption;
|
||||
}
|
||||
|
||||
public void setPeakConsumption(double _peakConsumption) {
|
||||
peakConsumption = _peakConsumption;
|
||||
}
|
||||
|
||||
public double getPeakProduction() {
|
||||
return peakProduction;
|
||||
}
|
||||
|
||||
public void setPeakProduction(double _peakProduction) {
|
||||
peakProduction = _peakProduction;
|
||||
}
|
||||
|
||||
public TimeZone getTimeZone() {
|
||||
return timezone;
|
||||
}
|
||||
|
@ -430,21 +510,14 @@ public class BreakerGroupEnergy {
|
|||
minute = _minute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object _o) {
|
||||
if (this == _o) return true;
|
||||
if (_o == null || getClass() != _o.getClass()) return false;
|
||||
MeterMinute that = (MeterMinute) _o;
|
||||
return meter == that.meter && minute.equals(that.minute);
|
||||
public int getMeter() {
|
||||
return meter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(meter, minute);
|
||||
public Date getMinute() {
|
||||
return minute;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MeterMinuteValues {
|
||||
public double[] usage = new double[60];
|
||||
public double[] solar = new double[60];
|
||||
public double[] charges = new double[60];
|
||||
|
|
|
@ -24,6 +24,10 @@ public class BreakerGroupSummary {
|
|||
private double charge;
|
||||
private double toGrid;
|
||||
private double fromGrid;
|
||||
private double peakToGrid;
|
||||
private double peakFromGrid;
|
||||
private double peakConsumption;
|
||||
private double peakProduction;
|
||||
|
||||
public BreakerGroupSummary() {
|
||||
}
|
||||
|
@ -39,6 +43,10 @@ public class BreakerGroupSummary {
|
|||
charge = _energy.charge(null, false);
|
||||
toGrid = _energy.getToGrid();
|
||||
fromGrid = _energy.getFromGrid();
|
||||
peakToGrid = _energy.getPeakToGrid();
|
||||
peakFromGrid = _energy.getPeakFromGrid();
|
||||
peakConsumption = _energy.getPeakConsumption();
|
||||
peakProduction = _energy.getPeakProduction();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@ -133,6 +141,38 @@ public class BreakerGroupSummary {
|
|||
fromGrid = _fromGrid;
|
||||
}
|
||||
|
||||
public double getPeakConsumption() {
|
||||
return peakConsumption;
|
||||
}
|
||||
|
||||
public void setPeakConsumption(double _peakConsumption) {
|
||||
peakConsumption = _peakConsumption;
|
||||
}
|
||||
|
||||
public double getPeakProduction() {
|
||||
return peakProduction;
|
||||
}
|
||||
|
||||
public void setPeakProduction(double _peakProduction) {
|
||||
peakProduction = _peakProduction;
|
||||
}
|
||||
|
||||
public double getPeakToGrid() {
|
||||
return peakToGrid;
|
||||
}
|
||||
|
||||
public void setPeakToGrid(double _peakToGrid) {
|
||||
peakToGrid = _peakToGrid;
|
||||
}
|
||||
|
||||
public double getPeakFromGrid() {
|
||||
return peakFromGrid;
|
||||
}
|
||||
|
||||
public void setPeakFromGrid(double _peakFromGrid) {
|
||||
peakFromGrid = _peakFromGrid;
|
||||
}
|
||||
|
||||
public List<BreakerGroupSummary> getAllGroups() {
|
||||
Map<String, BreakerGroupSummary> groups = new TreeMap<>();
|
||||
getAllGroups(groups);
|
||||
|
|
|
@ -74,6 +74,10 @@ public class BreakerGroupEnergySerializer extends AbstractDaoSerializer<BreakerG
|
|||
}
|
||||
d.put("to_grid", _o.getToGrid());
|
||||
d.put("from_grid", _o.getFromGrid());
|
||||
d.put("peak_to_grid", _o.getPeakToGrid());
|
||||
d.put("peak_from_grid", _o.getPeakFromGrid());
|
||||
d.put("peak_production", _o.getPeakProduction());
|
||||
d.put("peak_consumption", _o.getPeakConsumption());
|
||||
return d;
|
||||
}
|
||||
|
||||
|
@ -110,6 +114,10 @@ public class BreakerGroupEnergySerializer extends AbstractDaoSerializer<BreakerG
|
|||
}
|
||||
o.setToGrid(DaoSerializer.getDouble(_d, "to_grid"));
|
||||
o.setFromGrid(DaoSerializer.getDouble(_d, "from_grid"));
|
||||
o.setPeakToGrid(DaoSerializer.getDouble(_d, "peak_to_grid"));
|
||||
o.setPeakFromGrid(DaoSerializer.getDouble(_d, "peak_from_grid"));
|
||||
o.setPeakProduction(DaoSerializer.getDouble(_d, "peak_production"));
|
||||
o.setPeakConsumption(DaoSerializer.getDouble(_d, "peak_consumption"));
|
||||
return o;
|
||||
}
|
||||
}
|
|
@ -36,6 +36,10 @@ public class BreakerGroupSummarySerializer extends AbstractDaoSerializer<Breaker
|
|||
d.put("charge", _o.getCharge());
|
||||
d.put("to_grid", _o.getToGrid());
|
||||
d.put("from_grid", _o.getFromGrid());
|
||||
d.put("peak_to_grid", _o.getPeakToGrid());
|
||||
d.put("peak_from_grid", _o.getPeakFromGrid());
|
||||
d.put("peak_production", _o.getPeakProduction());
|
||||
d.put("peak_consumption", _o.getPeakConsumption());
|
||||
return d;
|
||||
}
|
||||
|
||||
|
@ -52,6 +56,10 @@ public class BreakerGroupSummarySerializer extends AbstractDaoSerializer<Breaker
|
|||
o.setCharge(DaoSerializer.getDouble(_d, "charge"));
|
||||
o.setToGrid(DaoSerializer.getDouble(_d, "to_grid"));
|
||||
o.setFromGrid(DaoSerializer.getDouble(_d, "from_grid"));
|
||||
o.setPeakToGrid(DaoSerializer.getDouble(_d, "peak_to_grid"));
|
||||
o.setPeakFromGrid(DaoSerializer.getDouble(_d, "peak_from_grid"));
|
||||
o.setPeakProduction(DaoSerializer.getDouble(_d, "peak_production"));
|
||||
o.setPeakConsumption(DaoSerializer.getDouble(_d, "peak_consumption"));
|
||||
return o;
|
||||
}
|
||||
}
|
|
@ -35,6 +35,12 @@
|
|||
<artifactId>lantern-util-servlet</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.util</groupId>
|
||||
<artifactId>lantern-util-http</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.rules</groupId>
|
||||
<artifactId>lantern-service-rules</artifactId>
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package com.lanternsoftware.currentmonitor.servlet;
|
||||
|
||||
import com.lanternsoftware.currentmonitor.context.Globals;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Account;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@WebServlet("/rebuildSummaries")
|
||||
public class RebuildSummariesServlet extends SecureServlet {
|
||||
@Override
|
||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
if (_authCode.getAccountId() == 100) {
|
||||
for (String sId : Globals.dao.getProxy().queryForField(Account.class, null, "_id")) {
|
||||
int id = DaoSerializer.toInteger(sId);
|
||||
if (id != 0)
|
||||
Globals.dao.rebuildSummariesAsync(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
_rep.setStatus(401);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.ResourceLoader;
|
||||
import com.lanternsoftware.util.cryptography.AESTool;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
|
||||
public class CreateAuthCode {
|
||||
private static final AESTool aes = new AESTool(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "authKey.dat"));
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.util.http.HttpPool;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
|
||||
public class RebuildSummariesRemote {
|
||||
public static void main(String[] args) {
|
||||
HttpPool pool = new HttpPool(10, 10, 10000, 10000, 10000);
|
||||
HttpGet r = new HttpGet("https://lanternpowermonitor.com/currentmonitor/rebuildSummaries");
|
||||
r.addHeader("auth_code", "<redacted>");
|
||||
CloseableHttpResponse resp = pool.execute(r);
|
||||
System.out.println(resp.getStatusLine().getStatusCode());
|
||||
pool.shutdown();
|
||||
}
|
||||
}
|
|
@ -266,7 +266,7 @@ public class CollectionUtils {
|
|||
public static <T, V> List<V> aggregate(Collection<T> _coll, IAggregator<T, V> _aggregator) {
|
||||
List<V> list = new ArrayList<>();
|
||||
for (T t : makeNotNull(_coll)) {
|
||||
List<V> vs = _aggregator.aggregate(t);
|
||||
Collection<V> vs = _aggregator.aggregate(t);
|
||||
if (vs != null)
|
||||
list.addAll(vs);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.lanternsoftware.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
|
||||
public interface IAggregator<T, V> {
|
||||
List<V> aggregate(T _t);
|
||||
Collection<V> aggregate(T _t);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user