mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Add billing plans so different plans can be compared. Performance enhancements to charge calculations.
This commit is contained in:
@@ -2,8 +2,8 @@ package com.lanternsoftware.dataaccess.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Account;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupEnergy;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupSummary;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergyTotal;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Sequence;
|
||||
import com.lanternsoftware.datamodel.rules.Event;
|
||||
import com.lanternsoftware.datamodel.rules.FcmDevice;
|
||||
@@ -34,14 +34,14 @@ public class Backup {
|
||||
t4.stop();
|
||||
|
||||
DebugTimer t5 = new DebugTimer("Query Energy");
|
||||
List<BreakerGroupEnergy> energy = dao.getProxy().queryAll(BreakerGroupEnergy.class);
|
||||
List<EnergySummary> energy = dao.getProxy().queryAll(EnergySummary.class);
|
||||
t5.stop();
|
||||
DebugTimer t6 = new DebugTimer("Save Energy");
|
||||
backupDao.getProxy().save(energy);
|
||||
t6.stop();
|
||||
|
||||
DebugTimer t7 = new DebugTimer("Query Summaries");
|
||||
List<BreakerGroupSummary> summary = dao.getProxy().queryAll(BreakerGroupSummary.class);
|
||||
List<EnergyTotal> summary = dao.getProxy().queryAll(EnergyTotal.class);
|
||||
t7.stop();
|
||||
DebugTimer t8 = new DebugTimer("Save Summaries");
|
||||
backupDao.getProxy().save(summary);
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
package com.lanternsoftware.dataaccess.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Account;
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupEnergy;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergyBlockViewMode;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergyViewMode;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoProxy;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public interface CurrentMonitorDao {
|
||||
@@ -21,9 +19,10 @@ public interface CurrentMonitorDao {
|
||||
void putBreakerPower(BreakerPower _current);
|
||||
List<BreakerPower> getBreakerPowerForAccount(int _accountId);
|
||||
BreakerPower getLatestBreakerPower(int _accountId, int _hub, int _port);
|
||||
BreakerGroupEnergy getBreakerGroupEnergy(int _accountId, String _groupId, EnergyBlockViewMode _viewMode, Date _start);
|
||||
byte[] getBreakerGroupEnergyBinary(int _accountId, String _groupId, EnergyBlockViewMode _viewMode, Date _start);
|
||||
void putBreakerGroupEnergy(BreakerGroupEnergy _energy);
|
||||
EnergySummary getEnergySummary(int _accountId, String _groupId, EnergyViewMode _viewMode, Date _start);
|
||||
byte[] getEnergySummaryBinary(int _accountId, String _groupId, EnergyViewMode _viewMode, Date _start);
|
||||
byte[] getChargeSummaryBinary(int _accountId, int _planId, String _groupId, EnergyViewMode _viewMode, Date _start);
|
||||
void putEnergySummary(EnergySummary _energy);
|
||||
|
||||
void putHubPowerMinute(HubPowerMinute _power);
|
||||
|
||||
@@ -31,7 +30,6 @@ public interface CurrentMonitorDao {
|
||||
BreakerConfig getMergedConfig(AuthCode _authCode);
|
||||
void putConfig(BreakerConfig _config);
|
||||
|
||||
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);
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package com.lanternsoftware.dataaccess.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Account;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BillingPlan;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BillingRate;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupEnergy;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupSummary;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergyBlockViewMode;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.ChargeSummary;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.ChargeTotal;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergyTotal;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.EnergyViewMode;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Sequence;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
@@ -23,6 +26,7 @@ import com.lanternsoftware.util.dao.DaoSort;
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoProxy;
|
||||
import com.lanternsoftware.util.mutable.MutableDouble;
|
||||
import org.mindrot.jbcrypt.BCrypt;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -31,6 +35,7 @@ import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -53,11 +58,13 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
proxy = new MongoProxy(_config);
|
||||
proxy.ensureIndex(BreakerPower.class, DaoSort.sort("account_id").then("key"));
|
||||
proxy.ensureIndex(HubPowerMinute.class, DaoSort.sort("account_id").then("minute"));
|
||||
proxy.ensureIndex(BreakerGroupEnergy.class, DaoSort.sort("account_id").then("group_id").then("view_mode"));
|
||||
proxy.ensureIndex(BreakerGroupSummary.class, DaoSort.sort("account_id").then("group_id").then("view_mode").then("start"));
|
||||
proxy.ensureIndex(EnergySummary.class, DaoSort.sort("account_id").then("group_id").then("view_mode"));
|
||||
proxy.ensureIndex(EnergyTotal.class, DaoSort.sort("account_id").then("group_id").then("view_mode").then("start"));
|
||||
proxy.ensureIndex(ChargeSummary.class, DaoSort.sort("account_id").then("plan_id").then("group_id").then("view_mode"));
|
||||
proxy.ensureIndex(ChargeTotal.class, DaoSort.sort("account_id").then("plan_id").then("group_id").then("view_mode").then("start"));
|
||||
proxy.ensureIndex(DirtyMinute.class, DaoSort.sort("posted"));
|
||||
for (DirtyMinute minute : proxy.queryAll(DirtyMinute.class)) {
|
||||
updateSummaries(minute);
|
||||
updateEnergySummaries(minute);
|
||||
}
|
||||
proxy.delete(DirtyMinute.class, new DaoQuery());
|
||||
}
|
||||
@@ -80,36 +87,49 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
proxy.save(_power);
|
||||
DirtyMinute minute = new DirtyMinute(_power.getAccountId(), _power.getMinute(), new Date());
|
||||
proxy.save(minute);
|
||||
delayTimer.schedule(new TimerTask(){
|
||||
delayTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
executor.submit(()->{
|
||||
executor.submit(() -> {
|
||||
if (proxy.queryOneAndDelete(DirtyMinute.class, new DaoQuery("_id", minute.getId())) != null)
|
||||
updateSummaries(new DirtyMinute(_power.getAccountId(), _power.getMinute(), new Date()));
|
||||
updateEnergySummaries(new DirtyMinute(_power.getAccountId(), _power.getMinute(), new Date()));
|
||||
});
|
||||
}
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
private void updateSummaries(DirtyMinute _minute) {
|
||||
private void updateEnergySummaries(DirtyMinute _minute) {
|
||||
DebugTimer timer = new DebugTimer("Updating summaries", logger);
|
||||
List<HubPowerMinute> minutes = proxy.query(HubPowerMinute.class, new DaoQuery("account_id", _minute.getAccountId()).and("minute", _minute.getMinute()));
|
||||
TimeZone tz = getTimeZoneForAccount(_minute.getAccountId());
|
||||
BreakerConfig config = getConfig(_minute.getAccountId());
|
||||
BreakerGroup group = CollectionUtils.getFirst(config.getBreakerGroups());
|
||||
Date day = DateUtils.getMidnightBefore(_minute.getMinuteAsDate(), tz);
|
||||
BreakerGroupEnergy energy = getBreakerGroupEnergy(_minute.getAccountId(), group.getId(), EnergyBlockViewMode.DAY, day);
|
||||
Date monthStart = DateUtils.getStartOfMonth(day, tz);
|
||||
BreakerGroupSummary month = proxy.queryOne(BreakerGroupSummary.class, new DaoQuery("_id", BreakerGroupEnergy.toId(_minute.getAccountId(), group.getId(), EnergyBlockViewMode.MONTH, monthStart)));
|
||||
DebugTimer t2 = new DebugTimer("Updating energy", logger);
|
||||
EnergySummary energy = getEnergySummary(_minute.getAccountId(), group.getId(), EnergyViewMode.DAY, day);
|
||||
if (energy == null)
|
||||
energy = new BreakerGroupEnergy(group, minutes, EnergyBlockViewMode.DAY, day, month, config.getBillingRates(), tz);
|
||||
energy = new EnergySummary(group, minutes, EnergyViewMode.DAY, day, tz);
|
||||
else
|
||||
energy.addEnergy(group, minutes, month, config.getBillingRates());
|
||||
putBreakerGroupEnergy(energy);
|
||||
updateSummaries(group, CollectionUtils.asHashSet(day), tz);
|
||||
energy.addEnergy(group, minutes);
|
||||
putEnergySummary(energy);
|
||||
updateEnergySummaries(group, CollectionUtils.asHashSet(day), tz);
|
||||
t2.stop();
|
||||
DebugTimer t3 = new DebugTimer("Updating charges", logger);
|
||||
updateChargeSummary(config, energy, tz);
|
||||
updateChargeSummaries(config, CollectionUtils.asHashSet(energy.getStart()), tz);
|
||||
t3.stop();
|
||||
timer.stop();
|
||||
}
|
||||
|
||||
private void putChargeSummary(ChargeSummary _summary) {
|
||||
putChargeSummaries(CollectionUtils.asArrayList(_summary));
|
||||
}
|
||||
|
||||
private void putChargeSummaries(Collection<ChargeSummary> _summaries) {
|
||||
proxy.save(_summaries);
|
||||
proxy.save(CollectionUtils.transform(_summaries, ChargeTotal::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BreakerPower> getBreakerPowerForAccount(int _accountId) {
|
||||
return proxy.query(BreakerPower.class, new DaoQuery("account_id", _accountId).andGt("read_time", DateUtils.minutesFromNow(-1).getTime()));
|
||||
@@ -121,17 +141,21 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BreakerGroupEnergy getBreakerGroupEnergy(int _accountId, String _groupId, EnergyBlockViewMode _viewMode, Date _start) {
|
||||
return proxy.queryOne(BreakerGroupEnergy.class, new DaoQuery("_id", BreakerGroupEnergy.toId(_accountId, _groupId, _viewMode, _start)));
|
||||
public EnergySummary getEnergySummary(int _accountId, String _groupId, EnergyViewMode _viewMode, Date _start) {
|
||||
return proxy.queryOne(EnergySummary.class, new DaoQuery("_id", EnergySummary.toId(_accountId, _groupId, _viewMode, _start)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBreakerGroupEnergyBinary(int _accountId, String _groupId, EnergyBlockViewMode _viewMode, Date _start) {
|
||||
return DaoSerializer.toZipBson(proxy.queryForEntity(BreakerGroupEnergy.class, new DaoQuery("_id", BreakerGroupEnergy.toId(_accountId, _groupId, _viewMode, _start))));
|
||||
public byte[] getEnergySummaryBinary(int _accountId, String _groupId, EnergyViewMode _viewMode, Date _start) {
|
||||
return DaoSerializer.toZipBson(proxy.queryForEntity(EnergySummary.class, new DaoQuery("_id", EnergySummary.toId(_accountId, _groupId, _viewMode, _start))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSummaries(BreakerGroup _rootGroup, Set<Date> _daysToSummarize, TimeZone _tz) {
|
||||
public byte[] getChargeSummaryBinary(int _accountId, int _planId, String _groupId, EnergyViewMode _viewMode, Date _start) {
|
||||
return DaoSerializer.toZipBson(proxy.queryForEntity(ChargeSummary.class, new DaoQuery("_id", ChargeSummary.toId(_accountId, _planId, _groupId, _viewMode, _start))));
|
||||
}
|
||||
|
||||
private void updateEnergySummaries(BreakerGroup _rootGroup, Set<Date> _daysToSummarize, TimeZone _tz) {
|
||||
Set<Date> monthsToSummarize = CollectionUtils.transformToSet(_daysToSummarize, _c -> DateUtils.getStartOfMonth(_c, _tz));
|
||||
Set<Date> yearsToSummarize = CollectionUtils.transformToSet(monthsToSummarize, _c -> DateUtils.getStartOfYear(_c, _tz));
|
||||
for (Date month : monthsToSummarize) {
|
||||
@@ -139,31 +163,101 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
Calendar end = DateUtils.getEndOfMonthCal(month, _tz);
|
||||
List<String> groupEnergyIds = new ArrayList<>();
|
||||
while (calDayStart.before(end)) {
|
||||
groupEnergyIds.add(BreakerGroupEnergy.toId(_rootGroup.getAccountId(), _rootGroup.getId(), EnergyBlockViewMode.DAY, calDayStart.getTime()));
|
||||
groupEnergyIds.add(EnergySummary.toId(_rootGroup.getAccountId(), _rootGroup.getId(), EnergyViewMode.DAY, calDayStart.getTime()));
|
||||
calDayStart.add(Calendar.DAY_OF_YEAR, 1);
|
||||
}
|
||||
List<BreakerGroupSummary> groupEnergies = CollectionUtils.aggregate(proxy.query(BreakerGroupSummary.class, DaoQuery.in("_id", groupEnergyIds)), BreakerGroupSummary::getAllGroups);
|
||||
Map<String, List<BreakerGroupSummary>> energies = CollectionUtils.transformToMultiMap(groupEnergies, BreakerGroupSummary::getGroupId);
|
||||
BreakerGroupEnergy summary = BreakerGroupEnergy.summary(_rootGroup, energies, EnergyBlockViewMode.MONTH, month, _tz);
|
||||
putBreakerGroupEnergy(summary);
|
||||
List<EnergyTotal> groupEnergies = CollectionUtils.aggregate(proxy.query(EnergyTotal.class, DaoQuery.in("_id", groupEnergyIds)), EnergyTotal::flatten);
|
||||
Map<String, List<EnergyTotal>> energies = CollectionUtils.transformToMultiMap(groupEnergies, EnergyTotal::getGroupId);
|
||||
EnergySummary summary = EnergySummary.summary(_rootGroup, energies, EnergyViewMode.MONTH, month, _tz);
|
||||
putEnergySummary(summary);
|
||||
}
|
||||
for (Date year : yearsToSummarize) {
|
||||
Calendar calMonthStart = DateUtils.toCalendar(year, _tz);
|
||||
Calendar end = DateUtils.getEndOfYearCal(year, _tz);
|
||||
List<String> groupEnergyIds = new ArrayList<>();
|
||||
List<String> summaryIds = new ArrayList<>();
|
||||
while (calMonthStart.before(end)) {
|
||||
groupEnergyIds.add(BreakerGroupEnergy.toId(_rootGroup.getAccountId(), _rootGroup.getId(), EnergyBlockViewMode.MONTH, calMonthStart.getTime()));
|
||||
summaryIds.add(EnergySummary.toId(_rootGroup.getAccountId(), _rootGroup.getId(), EnergyViewMode.MONTH, calMonthStart.getTime()));
|
||||
calMonthStart.add(Calendar.MONTH, 1);
|
||||
}
|
||||
List<BreakerGroupSummary> groupEnergies = CollectionUtils.aggregate(proxy.query(BreakerGroupSummary.class, DaoQuery.in("_id", groupEnergyIds)), BreakerGroupSummary::getAllGroups);
|
||||
Map<String, List<BreakerGroupSummary>> energies = CollectionUtils.transformToMultiMap(groupEnergies, BreakerGroupSummary::getGroupId);
|
||||
BreakerGroupEnergy summary = BreakerGroupEnergy.summary(_rootGroup, energies, EnergyBlockViewMode.YEAR, year, _tz);
|
||||
putBreakerGroupEnergy(summary);
|
||||
List<EnergyTotal> groupEnergies = CollectionUtils.aggregate(proxy.query(EnergyTotal.class, DaoQuery.in("_id", summaryIds)), EnergyTotal::flatten);
|
||||
Map<String, List<EnergyTotal>> energies = CollectionUtils.transformToMultiMap(groupEnergies, EnergyTotal::getGroupId);
|
||||
EnergySummary summary = EnergySummary.summary(_rootGroup, energies, EnergyViewMode.YEAR, year, _tz);
|
||||
putEnergySummary(summary);
|
||||
}
|
||||
List<EnergyTotal> groupEnergies = CollectionUtils.aggregate(proxy.query(EnergyTotal.class, new DaoQuery("account_id", _rootGroup.getAccountId()).and("group_id", _rootGroup.getId()).and("view_mode", EnergyViewMode.YEAR.name())), EnergyTotal::flatten);
|
||||
Map<String, List<EnergyTotal>> energies = CollectionUtils.transformToMultiMap(groupEnergies, EnergyTotal::getGroupId);
|
||||
EnergySummary summary = EnergySummary.summary(_rootGroup, energies, EnergyViewMode.ALL, new Date(0), _tz);
|
||||
putEnergySummary(summary);
|
||||
}
|
||||
|
||||
private void updateChargeSummary(BreakerConfig _config, EnergySummary _energySummary, TimeZone _tz) {
|
||||
Date lookback = null;
|
||||
for (BillingPlan p : CollectionUtils.makeNotNull(_config.getBillingPlans())) {
|
||||
Date cycleStart = p.getBillingCycleStart(_energySummary.getStart(), _tz);
|
||||
if (cycleStart.after(_energySummary.getStart()))
|
||||
cycleStart = DateUtils.addMonths(cycleStart, -1, _tz);
|
||||
if ((lookback == null) || cycleStart.before(lookback))
|
||||
lookback = cycleStart;
|
||||
}
|
||||
if (lookback != null) {
|
||||
List<String> groupEnergyIds = new ArrayList<>();
|
||||
while (lookback.before(_energySummary.getStart())) {
|
||||
groupEnergyIds.add(EnergySummary.toId(_config.getAccountId(), _energySummary.getGroupId(), EnergyViewMode.DAY, lookback));
|
||||
lookback = DateUtils.addDays(lookback, 1, _tz);
|
||||
}
|
||||
List<EnergyTotal> totals = proxy.query(EnergyTotal.class, DaoQuery.in("_id", groupEnergyIds));
|
||||
putChargeSummaries(_energySummary.toChargeSummaries(_config, totals));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChargeSummaries(BreakerConfig _config, Set<Date> _daysToSummarize, TimeZone _tz) {
|
||||
if (CollectionUtils.isEmpty(_config.getBillingPlans()))
|
||||
return;
|
||||
Set<Date> yearsToSummarize = CollectionUtils.transformToSet(_daysToSummarize, _c -> DateUtils.getStartOfYear(_c, _tz));
|
||||
BreakerGroup rootGroup = _config.getRootGroup();
|
||||
for (BillingPlan plan : _config.getBillingPlans()) {
|
||||
List<ChargeSummary> summaries = new ArrayList<>();
|
||||
Set<Date> monthsToSummarize = CollectionUtils.transformToSet(_daysToSummarize, _c -> plan.getBillingCycleStart(_c, _tz));
|
||||
for (Date month : monthsToSummarize) {
|
||||
Calendar monthDayStart = DateUtils.toCalendar(month, _tz);
|
||||
Calendar monthEnd = DateUtils.toCalendar(plan.getBillingCycleEnd(month, _tz), _tz);
|
||||
Set<String> monthSummaryIds = new HashSet<>();
|
||||
while (monthDayStart.before(monthEnd)) {
|
||||
monthSummaryIds.add(ChargeSummary.toId(rootGroup.getAccountId(), plan.getPlanId(), rootGroup.getId(), EnergyViewMode.DAY, monthDayStart.getTime()));
|
||||
monthDayStart.add(Calendar.DAY_OF_YEAR, 1);
|
||||
}
|
||||
List<ChargeTotal> monthTotals = CollectionUtils.aggregate(proxy.query(ChargeTotal.class, DaoQuery.in("_id", monthSummaryIds)), ChargeTotal::flatten);
|
||||
Map<String, List<ChargeTotal>> monthCharges = CollectionUtils.transformToMultiMap(monthTotals, ChargeTotal::getGroupId);
|
||||
summaries.add(new ChargeSummary(rootGroup, plan, monthCharges, EnergyViewMode.MONTH, month, _tz));
|
||||
}
|
||||
putChargeSummaries(summaries);
|
||||
}
|
||||
for (BillingPlan plan : _config.getBillingPlans()) {
|
||||
List<ChargeSummary> summaries = new ArrayList<>();
|
||||
for (Date year : yearsToSummarize) {
|
||||
Date yearStart = DateUtils.getStartOfYear(year, _tz);
|
||||
Date yearEnd = DateUtils.addYears(yearStart, 1, _tz);
|
||||
Date yearMonthStart = yearStart;
|
||||
Set<String> monthSummaryIds = new HashSet<>();
|
||||
Date loopEnd = DateUtils.addDays(yearEnd, 1, _tz);
|
||||
while (yearMonthStart.before(loopEnd)) {
|
||||
Date billingStart = plan.getBillingCycleStart(yearMonthStart, _tz);
|
||||
if (DateUtils.isBetween(billingStart, yearStart, yearEnd))
|
||||
monthSummaryIds.add(ChargeSummary.toId(rootGroup.getAccountId(), plan.getPlanId(), rootGroup.getId(), EnergyViewMode.MONTH, billingStart));
|
||||
yearMonthStart = DateUtils.addMonths(yearMonthStart, 1, _tz);
|
||||
}
|
||||
List<ChargeTotal> flatTotals = CollectionUtils.aggregate(proxy.query(ChargeTotal.class, DaoQuery.in("_id", monthSummaryIds)), ChargeTotal::flatten);
|
||||
Map<String, List<ChargeTotal>> yearCharges = CollectionUtils.transformToMultiMap(flatTotals, ChargeTotal::getGroupId);
|
||||
summaries.add(new ChargeSummary(rootGroup, plan, yearCharges, EnergyViewMode.YEAR, yearStart, _tz));
|
||||
}
|
||||
putChargeSummaries(summaries);
|
||||
}
|
||||
for (BillingPlan plan : _config.getBillingPlans()) {
|
||||
List<ChargeTotal> yearTotals = CollectionUtils.aggregate(proxy.query(ChargeTotal.class, new DaoQuery("account_id", rootGroup.getAccountId()).and("plan_id", plan.getPlanId()).and("group_id", rootGroup.getId()).and("view_mode", EnergyViewMode.YEAR.name())), ChargeTotal::flatten);
|
||||
Map<String, List<ChargeTotal>> charges = CollectionUtils.transformToMultiMap(yearTotals, ChargeTotal::getGroupId);
|
||||
ChargeSummary summary = new ChargeSummary(rootGroup, plan, charges, EnergyViewMode.ALL, new Date(0), _tz);
|
||||
putChargeSummary(summary);
|
||||
}
|
||||
List<BreakerGroupSummary> groupEnergies = CollectionUtils.aggregate(proxy.query(BreakerGroupSummary.class, new DaoQuery("account_id", _rootGroup.getAccountId()).and("group_id", _rootGroup.getId()).and("view_mode", EnergyBlockViewMode.YEAR.name())), BreakerGroupSummary::getAllGroups);
|
||||
Map<String, List<BreakerGroupSummary>> energies = CollectionUtils.transformToMultiMap(groupEnergies, BreakerGroupSummary::getGroupId);
|
||||
BreakerGroupEnergy summary = BreakerGroupEnergy.summary(_rootGroup, energies, EnergyBlockViewMode.ALL, new Date(0), _tz);
|
||||
putBreakerGroupEnergy(summary);
|
||||
}
|
||||
|
||||
private void rebuildSummaries(int _accountId, Collection<BillingRate> _rates) {
|
||||
@@ -172,7 +266,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
if (firstMinute == null)
|
||||
return;
|
||||
TimeZone tz = getTimeZoneForAccount(_accountId);
|
||||
Map<String, BillingRate> rates = CollectionUtils.transformToMap(_rates, _r->String.format("%d%d", DaoSerializer.toLong(_r.getBeginEffective()), DaoSerializer.toLong(_r.getEndEffective())));
|
||||
Map<String, BillingRate> rates = CollectionUtils.transformToMap(_rates, _r -> String.format("%d%d", DaoSerializer.toLong(_r.getBeginEffective()), DaoSerializer.toLong(_r.getEndEffective())));
|
||||
for (BillingRate rate : rates.values()) {
|
||||
Date start = rate.getBeginEffective();
|
||||
Date end = rate.getEndEffective();
|
||||
@@ -194,7 +288,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
|
||||
@Override
|
||||
public void rebuildSummariesAsync(int _accountId) {
|
||||
executor.submit(()->rebuildSummaries(_accountId));
|
||||
executor.submit(() -> rebuildSummaries(_accountId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -210,35 +304,88 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
BreakerConfig config = getConfig(_accountId);
|
||||
TimeZone tz = getTimeZoneForAccount(_accountId);
|
||||
Date start = DateUtils.getMidnightBefore(_start, tz);
|
||||
Date monthStart = DateUtils.getStartOfMonth(_start, tz);
|
||||
BreakerGroup root = CollectionUtils.getFirst(config.getBreakerGroups());
|
||||
if (root == null)
|
||||
return;
|
||||
proxy.delete(BreakerGroupSummary.class, new DaoQuery("_id", BreakerGroupEnergy.toId(_accountId, root.getId(), EnergyBlockViewMode.MONTH, monthStart)));
|
||||
Set<Date> dates = new HashSet<>();
|
||||
while (start.before(_end)) {
|
||||
Date dayEnd = DateUtils.getMidnightAfter(start, tz);
|
||||
DebugTimer timer = new DebugTimer("Time to rebuild one day");
|
||||
DebugTimer t1 = new DebugTimer("Loading hub power for day, account: " + _accountId + " day: " + DateUtils.format("MM/dd/yyyy", tz, start));
|
||||
List<HubPowerMinute> minutes = proxy.query(HubPowerMinute.class, new DaoQuery("account_id", _accountId).andBetweenInclusiveExclusive("minute", (int) (start.getTime() / 60000), (int) (dayEnd.getTime() / 60000)));
|
||||
t1.stop();
|
||||
monthStart = DateUtils.getStartOfMonth(start, tz);
|
||||
BreakerGroupSummary month = null;
|
||||
if (monthStart.equals(start))
|
||||
proxy.delete(BreakerGroupSummary.class, new DaoQuery("_id", BreakerGroupEnergy.toId(_accountId, root.getId(), EnergyBlockViewMode.MONTH, monthStart)));
|
||||
else
|
||||
month = proxy.queryOne(BreakerGroupSummary.class, new DaoQuery("_id", BreakerGroupEnergy.toId(_accountId, root.getId(), EnergyBlockViewMode.MONTH, monthStart)));
|
||||
BreakerGroupEnergy energy = new BreakerGroupEnergy(root, minutes, EnergyBlockViewMode.DAY, start, month, config.getBillingRates(), tz);
|
||||
timer.stop();
|
||||
putBreakerGroupEnergy(energy);
|
||||
updateSummaries(root, CollectionUtils.asHashSet(start), tz);
|
||||
DebugTimer timer = new DebugTimer("Time to rebuild one day", logger);
|
||||
DebugTimer t1 = new DebugTimer("Loading hub power for day, account: " + _accountId + " day: " + DateUtils.format("MM/dd/yyyy", tz, start), logger);
|
||||
List<HubPowerMinute> minutes = proxy.query(HubPowerMinute.class, new DaoQuery("account_id", _accountId).andBetweenInclusiveExclusive("minute", (int) (start.getTime() / 60000), (int) (dayEnd.getTime() / 60000)));
|
||||
t1.stop();
|
||||
if (!minutes.isEmpty()) {
|
||||
DebugTimer t2 = new DebugTimer("In memory rebuild", logger);
|
||||
EnergySummary energy = new EnergySummary(root, minutes, EnergyViewMode.DAY, start, tz);
|
||||
t2.stop();
|
||||
timer.stop();
|
||||
putEnergySummary(energy);
|
||||
DebugTimer t3 = new DebugTimer("Updating charges", logger);
|
||||
updateChargeSummary(config, energy, tz);
|
||||
t3.stop();
|
||||
}
|
||||
dates.add(start);
|
||||
start = DateUtils.addDays(start, 1, tz);
|
||||
}
|
||||
DebugTimer t4 = new DebugTimer("Updating month/year/lifetime energy summaries", logger);
|
||||
updateEnergySummaries(root, dates, tz);
|
||||
t4.stop();
|
||||
DebugTimer t5 = new DebugTimer("Updating month/year/lifetime charge summaries", logger);
|
||||
updateChargeSummaries(config, dates, tz);
|
||||
t5.stop();
|
||||
}
|
||||
|
||||
public void rebuildChargeSummaries(BreakerConfig _config, BillingPlan _plan) {
|
||||
TimeZone tz = getTimeZoneForAccount(_config.getAccountId());
|
||||
HubPowerMinute firstMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _config.getAccountId()), DaoSort.sort("minute"));
|
||||
if (firstMinute == null)
|
||||
return;
|
||||
Date start = DateUtils.getMidnightBefore(firstMinute.getMinuteAsDate(), tz);
|
||||
Date end = DateUtils.getMidnightAfter(new Date(), tz);
|
||||
BreakerGroup root = CollectionUtils.getFirst(_config.getBreakerGroups());
|
||||
if (root == null)
|
||||
return;
|
||||
Set<Date> dates = new HashSet<>();
|
||||
Date curDate = start;
|
||||
while (curDate.before(end)) {
|
||||
dates.add(curDate);
|
||||
curDate = DateUtils.addDays(curDate, 1, tz);
|
||||
}
|
||||
List<String> summaryIds = CollectionUtils.transform(dates, _dt->EnergySummary.toId(_config.getAccountId(), root.getId(), EnergyViewMode.DAY, _dt));
|
||||
DebugTimer t1 = new DebugTimer("Load Daily Energy Totals", logger);
|
||||
Map<Date, EnergyTotal> totals = CollectionUtils.transformToMap(proxy.query(EnergyTotal.class, DaoQuery.in("_id", summaryIds)), EnergyTotal::getStart);
|
||||
t1.stop();
|
||||
Map<String, Integer> breakerGroupMeters = _config.getRootGroup().mapToMeters();
|
||||
List<ChargeSummary> chargeSummaries = new ArrayList<>();
|
||||
DebugTimer t2 = new DebugTimer("Load Energy Summaries", logger);
|
||||
List<EnergySummary> energySummaries = proxy.query(EnergySummary.class, DaoQuery.in("_id", summaryIds));
|
||||
t2.stop();
|
||||
DebugTimer t3 = new DebugTimer("Rebuild Charges Summaries", logger);
|
||||
for (EnergySummary energy : energySummaries) {
|
||||
Date cycleStart = _plan.getBillingCycleStart(energy.getStart(), tz);
|
||||
double monthKwh = 0.0;
|
||||
while (cycleStart.before(energy.getStart())) {
|
||||
EnergyTotal total = totals.get(cycleStart);
|
||||
if (total != null)
|
||||
monthKwh += total.totalJoules();
|
||||
cycleStart = DateUtils.addDays(cycleStart, 1, tz);
|
||||
}
|
||||
monthKwh /= 3600000.0;
|
||||
chargeSummaries.add(energy.toChargeSummary(_plan.getPlanId(), _plan.getRates(), breakerGroupMeters, new MutableDouble(monthKwh)));
|
||||
}
|
||||
t3.stop();
|
||||
DebugTimer t4 = new DebugTimer("Persist Charge Summaries", logger);
|
||||
putChargeSummaries(chargeSummaries);
|
||||
t4.stop();
|
||||
DebugTimer t5 = new DebugTimer("Updating month/year/lifetime charge summaries", logger);
|
||||
updateChargeSummaries(_config, dates, tz);
|
||||
t5.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBreakerGroupEnergy(BreakerGroupEnergy _energy) {
|
||||
public void putEnergySummary(EnergySummary _energy) {
|
||||
proxy.save(_energy);
|
||||
proxy.save(new BreakerGroupSummary(_energy));
|
||||
proxy.save(new EnergyTotal(_energy));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -250,6 +397,8 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
public BreakerConfig getMergedConfig(AuthCode _authCode) {
|
||||
if (_authCode == null)
|
||||
return null;
|
||||
if (CollectionUtils.size(_authCode.getAllAccountIds()) == 1)
|
||||
return getConfig(_authCode.getAccountId());
|
||||
List<BreakerConfig> configs = CollectionUtils.transform(_authCode.getAllAccountIds(), this::getConfig, true);
|
||||
BreakerConfig config = new BreakerConfig();
|
||||
config.setAccountId(_authCode.getAccountId());
|
||||
@@ -257,6 +406,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
config.setBreakerGroups(CollectionUtils.aggregate(configs, BreakerConfig::getBreakerGroups));
|
||||
config.setPanels(CollectionUtils.aggregate(configs, BreakerConfig::getPanels));
|
||||
config.setMeters(CollectionUtils.aggregate(configs, BreakerConfig::getMeters));
|
||||
config.setBillingPlans(CollectionUtils.aggregate(configs, BreakerConfig::getBillingPlans));
|
||||
config.setBillingRates(CollectionUtils.aggregate(configs, BreakerConfig::getBillingRates));
|
||||
return config;
|
||||
}
|
||||
@@ -274,10 +424,12 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
oldEntity.put("archive_date", DaoSerializer.toLong(new Date()));
|
||||
proxy.saveEntity("config_archive", oldEntity);
|
||||
executor.submit(() -> {
|
||||
List<BillingRate> changedRates = new ArrayList<>(_config.getBillingRates());
|
||||
changedRates.removeAll(CollectionUtils.makeNotNull(oldConfig.getBillingRates()));
|
||||
if (!changedRates.isEmpty())
|
||||
rebuildSummaries(_config.getAccountId(), changedRates);
|
||||
Map<Integer, BillingPlan> oldPlans = CollectionUtils.transformToMap(oldConfig.getBillingPlans(), BillingPlan::getPlanId);
|
||||
for (BillingPlan plan : CollectionUtils.makeNotNull(_config.getBillingPlans())) {
|
||||
BillingPlan oldPlan = oldPlans.get(plan.getPlanId());
|
||||
if ((oldPlan == null) || !oldPlan.isIdentical(plan))
|
||||
rebuildChargeSummaries(_config, plan);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -336,8 +488,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
_account.setPassword(account.getPassword());
|
||||
else
|
||||
_account.setPassword(BCrypt.hashpw(_account.getPassword(), BCrypt.gensalt(BCRYPT_ROUNDS)));
|
||||
}
|
||||
else if (NullUtils.isNotEmpty(_account.getPassword())) {
|
||||
} else if (NullUtils.isNotEmpty(_account.getPassword())) {
|
||||
_account.setPassword(BCrypt.hashpw(_account.getPassword(), BCrypt.gensalt(BCRYPT_ROUNDS)));
|
||||
}
|
||||
if (_account.getId() == 0)
|
||||
@@ -363,8 +514,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
||||
try {
|
||||
if (NullUtils.isNotEmpty(timezone))
|
||||
tz = TimeZone.getTimeZone(timezone);
|
||||
}
|
||||
catch (Exception _e) {
|
||||
} catch (Exception _e) {
|
||||
logger.error("TimeZone not configured correctly for account {}", _accountId);
|
||||
}
|
||||
return tz == null ? TimeZone.getTimeZone("America/Chicago") : tz;
|
||||
|
||||
Reference in New Issue
Block a user