mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Add billing rates and track cost for all energy readings.
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
package com.lanternsoftware.datamodel.currentmonitor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public enum BillingCurrency {
|
||||
DOLLAR("$"),
|
||||
EURO("€"),
|
||||
POUND_STERLING("£");
|
||||
|
||||
public final String symbol;
|
||||
|
||||
BillingCurrency(String _symbol) {
|
||||
symbol = _symbol;
|
||||
}
|
||||
|
||||
public String format(double _value) {
|
||||
return format(BigDecimal.valueOf(_value));
|
||||
}
|
||||
|
||||
public String format(BigDecimal _value) {
|
||||
if (_value.compareTo(BigDecimal.ZERO) < 0)
|
||||
return "-" + symbol + _value.abs().setScale(2, RoundingMode.HALF_EVEN);
|
||||
return symbol + _value.setScale(2, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.lanternsoftware.datamodel.currentmonitor;
|
||||
|
||||
public enum BillingMode {
|
||||
CONSUMPTION,
|
||||
PRODUCTION;
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package com.lanternsoftware.datamodel.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.util.DateUtils;
|
||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@DBSerializable
|
||||
public class BillingRate {
|
||||
private int meter;
|
||||
private int dayBillingCycleStart;
|
||||
private BillingMode mode;
|
||||
private double rate;
|
||||
private BillingCurrency currency;
|
||||
private int timeOfDayStart;
|
||||
private int timeOfDayEnd;
|
||||
private double monthKWhStart;
|
||||
private double monthKWhEnd;
|
||||
private Date beginEffective;
|
||||
private Date endEffective;
|
||||
boolean recursAnnually;
|
||||
|
||||
public int getMeter() {
|
||||
return meter;
|
||||
}
|
||||
|
||||
public void setMeter(int _meter) {
|
||||
meter = _meter;
|
||||
}
|
||||
|
||||
public int getDayBillingCycleStart() {
|
||||
return dayBillingCycleStart;
|
||||
}
|
||||
|
||||
public void setDayBillingCycleStart(int _dayBillingCycleStart) {
|
||||
dayBillingCycleStart = _dayBillingCycleStart;
|
||||
}
|
||||
|
||||
public BillingMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(BillingMode _mode) {
|
||||
mode = _mode;
|
||||
}
|
||||
|
||||
public double getRate() {
|
||||
return rate;
|
||||
}
|
||||
|
||||
public void setRate(double _rate) {
|
||||
rate = _rate;
|
||||
}
|
||||
|
||||
public BillingCurrency getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
public void setCurrency(BillingCurrency _currency) {
|
||||
currency = _currency;
|
||||
}
|
||||
|
||||
public int getTimeOfDayStart() {
|
||||
return timeOfDayStart;
|
||||
}
|
||||
|
||||
public void setTimeOfDayStart(int _timeOfDayStart) {
|
||||
timeOfDayStart = _timeOfDayStart;
|
||||
}
|
||||
|
||||
public int getTimeOfDayEnd() {
|
||||
return timeOfDayEnd;
|
||||
}
|
||||
|
||||
public void setTimeOfDayEnd(int _timeOfDayEnd) {
|
||||
timeOfDayEnd = _timeOfDayEnd;
|
||||
}
|
||||
|
||||
public double getMonthKWhStart() {
|
||||
return monthKWhStart;
|
||||
}
|
||||
|
||||
public void setMonthKWhStart(double _monthKWhStart) {
|
||||
monthKWhStart = _monthKWhStart;
|
||||
}
|
||||
|
||||
public double getMonthKWhEnd() {
|
||||
return monthKWhEnd;
|
||||
}
|
||||
|
||||
public void setMonthKWhEnd(double _monthKWhEnd) {
|
||||
monthKWhEnd = _monthKWhEnd;
|
||||
}
|
||||
|
||||
public Date getBeginEffective() {
|
||||
return beginEffective;
|
||||
}
|
||||
|
||||
public void setBeginEffective(Date _beginEffective) {
|
||||
beginEffective = _beginEffective;
|
||||
}
|
||||
|
||||
public Date getEndEffective() {
|
||||
return endEffective;
|
||||
}
|
||||
|
||||
public void setEndEffective(Date _endEffective) {
|
||||
endEffective = _endEffective;
|
||||
}
|
||||
|
||||
public boolean isRecursAnnually() {
|
||||
return recursAnnually;
|
||||
}
|
||||
|
||||
public void setRecursAnnually(boolean _recursAnnually) {
|
||||
recursAnnually = _recursAnnually;
|
||||
}
|
||||
|
||||
public boolean isApplicable(BillingMode _mode, int _meter, double _monthKWh, Date _time, TimeZone _tz) {
|
||||
if (mode != _mode)
|
||||
return false;
|
||||
if (_meter != meter)
|
||||
return false;
|
||||
if ((monthKWhStart > 0) && (_monthKWh < monthKWhStart))
|
||||
return false;
|
||||
if ((monthKWhEnd > 0) && (_monthKWh >= monthKWhEnd))
|
||||
return false;
|
||||
if ((beginEffective != null) && (endEffective != null) && recursAnnually) {
|
||||
Date begin = beginEffective;
|
||||
Date end = endEffective;
|
||||
while (_time.before(begin)) {
|
||||
begin = DateUtils.addYears(begin, -1, _tz);
|
||||
end = DateUtils.addYears(end, -1, _tz);
|
||||
}
|
||||
while (_time.after(end)) {
|
||||
begin = DateUtils.addYears(begin, 1, _tz);
|
||||
end = DateUtils.addYears(end, 1, _tz);
|
||||
}
|
||||
if (!DateUtils.isBetween(_time, begin, end))
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if ((beginEffective != null) && _time.before(beginEffective))
|
||||
return false;
|
||||
if ((endEffective != null) && endEffective.before(_time))
|
||||
return false;
|
||||
}
|
||||
if ((timeOfDayStart == 0) && (timeOfDayEnd == 0))
|
||||
return true;
|
||||
Calendar midnight = DateUtils.getMidnightBeforeCal(_time, _tz);
|
||||
int timeOfDay = (int)((_time.getTime() - midnight.getTimeInMillis()) / 1000);
|
||||
if ((timeOfDayStart > 0) && (timeOfDay < timeOfDayStart))
|
||||
return false;
|
||||
return (timeOfDayEnd == 0) || (timeOfDay < timeOfDayEnd);
|
||||
}
|
||||
|
||||
public double apply(double _kWh) {
|
||||
return rate * _kWh;
|
||||
}
|
||||
|
||||
public BillingRate duplicate() {
|
||||
BillingRate r = new BillingRate();
|
||||
r.setMeter(meter);
|
||||
r.setDayBillingCycleStart(dayBillingCycleStart);
|
||||
r.setMode(mode);
|
||||
r.setRate(rate);
|
||||
r.setCurrency(currency);
|
||||
r.setTimeOfDayStart(timeOfDayStart);
|
||||
r.setTimeOfDayEnd(timeOfDayEnd);
|
||||
r.setMonthKWhStart(monthKWhStart);
|
||||
r.setMonthKWhEnd(monthKWhEnd);
|
||||
r.setBeginEffective(beginEffective);
|
||||
r.setEndEffective(endEffective);
|
||||
r.setRecursAnnually(recursAnnually);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ public class BreakerConfig {
|
||||
private List<BreakerPanel> panels;
|
||||
private List<BreakerHub> breakerHubs;
|
||||
private List<BreakerGroup> breakerGroups;
|
||||
private List<BillingRate> billingRates;
|
||||
private int version;
|
||||
|
||||
public BreakerConfig() {
|
||||
@@ -66,6 +67,14 @@ public class BreakerConfig {
|
||||
breakerGroups = _breakerGroups;
|
||||
}
|
||||
|
||||
public List<BillingRate> getBillingRates() {
|
||||
return billingRates;
|
||||
}
|
||||
|
||||
public void setBillingRates(List<BillingRate> _billingRates) {
|
||||
billingRates = _billingRates;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
@@ -169,4 +178,8 @@ public class BreakerConfig {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public BillingCurrency getCurrency() {
|
||||
return CollectionUtils.getFirst(CollectionUtils.transformToSet(billingRates, BillingRate::getCurrency));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,14 @@ import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
@@ -33,36 +35,18 @@ public class BreakerGroupEnergy {
|
||||
public BreakerGroupEnergy() {
|
||||
}
|
||||
|
||||
public BreakerGroupEnergy(BreakerGroup _group, Map<String, List<BreakerPower>> _powerReadings, EnergyBlockViewMode _viewMode, Date _start, TimeZone _timezone) {
|
||||
public BreakerGroupEnergy(BreakerGroup _group, List<HubPowerMinute> _power, EnergyBlockViewMode _viewMode, Date _start, BreakerGroupSummary _month, List<BillingRate> _rates, TimeZone _timezone) {
|
||||
groupId = _group.getId();
|
||||
groupName = _group.getName();
|
||||
viewMode = _viewMode;
|
||||
start = _start;
|
||||
accountId = _group.getAccountId();
|
||||
timezone = _timezone;
|
||||
subGroups = CollectionUtils.transform(_group.getSubGroups(), _g -> new BreakerGroupEnergy(_g, _powerReadings, _viewMode, _start, timezone));
|
||||
energyBlocks = new ArrayList<>();
|
||||
List<String> breakerKeys = CollectionUtils.transform(_group.getBreakers(), Breaker::getKey);
|
||||
if (!breakerKeys.isEmpty()) {
|
||||
for (BreakerPower power : CollectionUtils.aggregate(breakerKeys, _powerReadings::get)) {
|
||||
addEnergy(groupId, power.getReadTime(), power.getPower());
|
||||
}
|
||||
}
|
||||
subGroups = CollectionUtils.transform(_group.getSubGroups(), _g -> new BreakerGroupEnergy(_g, null, _viewMode, _start, _month, _rates, timezone));
|
||||
addEnergy(_group, _power, _month, _rates);
|
||||
}
|
||||
|
||||
public BreakerGroupEnergy(BreakerGroup _group, List<HubPowerMinute> _power, EnergyBlockViewMode _viewMode, Date _start, TimeZone _timezone) {
|
||||
groupId = _group.getId();
|
||||
groupName = _group.getName();
|
||||
viewMode = _viewMode;
|
||||
start = _start;
|
||||
accountId = _group.getAccountId();
|
||||
timezone = _timezone;
|
||||
subGroups = CollectionUtils.transform(_group.getSubGroups(), _g -> new BreakerGroupEnergy(_g, (List<HubPowerMinute>)null, _viewMode, _start, timezone));
|
||||
energyBlocks = new ArrayList<>();
|
||||
addEnergy(_group, _power);
|
||||
}
|
||||
|
||||
public void addEnergy(BreakerGroup _group, List<HubPowerMinute> _hubPower) {
|
||||
public void addEnergy(BreakerGroup _group, List<HubPowerMinute> _hubPower, BreakerGroupSummary _month, List<BillingRate> _rates) {
|
||||
Map<String, Breaker> breakers = CollectionUtils.transformToMap(_group.getAllBreakers(), Breaker::getKey);
|
||||
Map<String, BreakerGroup> breakerKeyToGroup = new HashMap<>();
|
||||
for (BreakerGroup group : _group.getAllBreakerGroups()) {
|
||||
@@ -70,16 +54,20 @@ public class BreakerGroupEnergy {
|
||||
breakerKeyToGroup.put(b.getKey(), group);
|
||||
}
|
||||
}
|
||||
addEnergy(breakers, breakerKeyToGroup, _hubPower);
|
||||
addEnergy(breakers, breakerKeyToGroup, _hubPower, _month, _rates);
|
||||
}
|
||||
|
||||
public void addEnergy(Map<String, Breaker> _breakers, Map<String, BreakerGroup> _breakerKeyToGroup, List<HubPowerMinute> _hubPower) {
|
||||
public void addEnergy(Map<String, Breaker> _breakers, Map<String, BreakerGroup> _breakerKeyToGroup, List<HubPowerMinute> _hubPower, BreakerGroupSummary _month, List<BillingRate> _rates) {
|
||||
if (CollectionUtils.isEmpty(_hubPower) || CollectionUtils.anyQualify(_hubPower, _p->_p.getAccountId() != accountId))
|
||||
return;
|
||||
Date minute = CollectionUtils.getFirst(_hubPower).getMinuteAsDate();
|
||||
resetEnergy(minute);
|
||||
Map<Integer, MeterMinute> meters = new HashMap<>();
|
||||
_hubPower.sort(Comparator.comparing(HubPowerMinute::getMinute));
|
||||
for (Date minute : CollectionUtils.transformToSet(_hubPower, HubPowerMinute::getMinuteAsDate)) {
|
||||
resetEnergy(minute);
|
||||
}
|
||||
int idx;
|
||||
Map<MeterMinute, MeterMinuteValues> meters = new HashMap<>();
|
||||
for (HubPowerMinute hubPower : _hubPower) {
|
||||
Date minute = hubPower.getMinuteAsDate();
|
||||
for (BreakerPowerMinute breaker : CollectionUtils.makeNotNull(hubPower.getBreakers())) {
|
||||
Breaker b = _breakers.get(breaker.breakerKey());
|
||||
if (b == null)
|
||||
@@ -87,26 +75,68 @@ public class BreakerGroupEnergy {
|
||||
BreakerGroup group = _breakerKeyToGroup.get(breaker.breakerKey());
|
||||
if (group == null)
|
||||
continue;
|
||||
MeterMinute meter = meters.computeIfAbsent(b.getMeter(), _p->new MeterMinute());
|
||||
int idx = 0;
|
||||
for (Float power : CollectionUtils.makeNotNull(breaker.getReadings())) {
|
||||
if (power > 0)
|
||||
meter.usage[idx] += power;
|
||||
else
|
||||
meter.solar[idx] += -power;
|
||||
if (power != 0.0)
|
||||
addEnergy(group.getId(), minute, power);
|
||||
idx++;
|
||||
MeterMinuteValues meter = meters.computeIfAbsent(new MeterMinute(b.getMeter(), minute), _p->new MeterMinuteValues());
|
||||
idx = 0;
|
||||
EnergyBlock block = getBlock(group.getId(), minute);
|
||||
if (block != null) {
|
||||
for (Float power : CollectionUtils.makeNotNull(breaker.getReadings())) {
|
||||
if (idx >= 60)
|
||||
break;
|
||||
if (power > 0)
|
||||
meter.usage[idx] += power;
|
||||
else
|
||||
meter.solar[idx] -= power;
|
||||
block.addJoules(power);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (MeterMinute meter : meters.values()) {
|
||||
double monthFromGrid = _month == null ? 0.0 : _month.getFromGrid();
|
||||
double secondFromGrid;
|
||||
for (Map.Entry<MeterMinute, MeterMinuteValues> meter : meters.entrySet()) {
|
||||
double monthkWh = monthFromGrid/3600000;
|
||||
List<BillingRate> consumptionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(BillingMode.CONSUMPTION, meter.getKey().meter, monthkWh, meter.getKey().minute, timezone));
|
||||
List<BillingRate> productionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(BillingMode.PRODUCTION, meter.getKey().meter, monthkWh, meter.getKey().minute, timezone));
|
||||
for (int i = 0; i < 60; i++) {
|
||||
if (meter.usage[i] > meter.solar[i])
|
||||
fromGrid += meter.usage[i] - meter.solar[i];
|
||||
else
|
||||
toGrid += meter.solar[i] - meter.usage[i];
|
||||
secondFromGrid = meter.getValue().usage[i] - meter.getValue().solar[i];
|
||||
monthFromGrid += secondFromGrid;
|
||||
if (secondFromGrid > 0) {
|
||||
fromGrid += secondFromGrid;
|
||||
for (BillingRate rate : consumptionRates) {
|
||||
meter.getValue().charges[i] += rate.apply(secondFromGrid/3600000);
|
||||
}
|
||||
}
|
||||
else {
|
||||
toGrid -= secondFromGrid;
|
||||
for (BillingRate rate : productionRates) {
|
||||
meter.getValue().charges[i] += rate.apply(secondFromGrid/3600000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (HubPowerMinute hubPower : _hubPower) {
|
||||
Date minute = hubPower.getMinuteAsDate();
|
||||
for (BreakerPowerMinute breaker : CollectionUtils.makeNotNull(hubPower.getBreakers())) {
|
||||
Breaker b = _breakers.get(breaker.breakerKey());
|
||||
if (b == null)
|
||||
continue;
|
||||
BreakerGroup group = _breakerKeyToGroup.get(breaker.breakerKey());
|
||||
if (group == null)
|
||||
continue;
|
||||
MeterMinuteValues meter = meters.get(new MeterMinute(b.getMeter(), minute));
|
||||
idx = 0;
|
||||
double charge = 0.0;
|
||||
for (Float power : CollectionUtils.makeNotNull(breaker.getReadings())) {
|
||||
if (b.getPolarity() == BreakerPolarity.SOLAR) {
|
||||
if (meter.charges[idx] < 0.0)
|
||||
charge -= meter.charges[idx] * (power/meter.solar[idx]);
|
||||
}
|
||||
else if (meter.charges[idx] > 0.0)
|
||||
charge += meter.charges[idx] * (power/meter.usage[idx]);
|
||||
idx++;
|
||||
}
|
||||
addCharge(group.getId(), minute, charge);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,16 +150,31 @@ public class BreakerGroupEnergy {
|
||||
}
|
||||
}
|
||||
|
||||
public void addEnergy(String _groupId, Date _readTime, double _joules) {
|
||||
private EnergyBlock getBlock(String _groupId, Date _readTime) {
|
||||
if (NullUtils.isEqual(groupId, _groupId))
|
||||
getBlock(_readTime).addJoules(_joules);
|
||||
return getBlock(_readTime);
|
||||
else {
|
||||
for (BreakerGroupEnergy subGroup : CollectionUtils.makeNotNull(subGroups)) {
|
||||
subGroup.addEnergy(_groupId, _readTime, _joules);
|
||||
EnergyBlock block = subGroup.getBlock(_groupId, _readTime);
|
||||
if (block != null)
|
||||
return block;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addEnergy(String _groupId, Date _readTime, double _joules) {
|
||||
EnergyBlock block = getBlock(_groupId, _readTime);
|
||||
if (block != null)
|
||||
block.addJoules(_joules);
|
||||
}
|
||||
|
||||
private void addCharge(String _groupId, Date _readTime, double _charge) {
|
||||
EnergyBlock block = getBlock(_groupId, _readTime);
|
||||
if (block != null)
|
||||
block.addCharge(_charge);
|
||||
}
|
||||
|
||||
public static BreakerGroupEnergy summary(BreakerGroup _group, Map<String, List<BreakerGroupSummary>> _energies, EnergyBlockViewMode _viewMode, Date _start, TimeZone _tz) {
|
||||
BreakerGroupEnergy energy = new BreakerGroupEnergy();
|
||||
energy.setGroupId(_group.getId());
|
||||
@@ -142,6 +187,7 @@ public class BreakerGroupEnergy {
|
||||
for (BreakerGroupSummary curEnergy : CollectionUtils.makeNotNull(_energies.get(_group.getId()))) {
|
||||
EnergyBlock block = energy.getBlock(curEnergy.getStart());
|
||||
block.addJoules(curEnergy.getJoules());
|
||||
block.addCharge(curEnergy.getCharge());
|
||||
energy.setToGrid(energy.getToGrid()+curEnergy.getToGrid());
|
||||
energy.setFromGrid(energy.getFromGrid()+curEnergy.getFromGrid());
|
||||
}
|
||||
@@ -154,10 +200,10 @@ public class BreakerGroupEnergy {
|
||||
|
||||
private EnergyBlock getBlock(Date _readTime, boolean _add) {
|
||||
int size = CollectionUtils.size(energyBlocks);
|
||||
int idx = viewMode.blockIndex(_readTime, timezone);
|
||||
int idx = viewMode.blockIndex(start, _readTime, timezone);
|
||||
if (_add && (idx >= size)) {
|
||||
if (energyBlocks == null)
|
||||
energyBlocks = new ArrayList<>();
|
||||
energyBlocks = new ArrayList<>(viewMode.initBlockCount());
|
||||
LinkedList<EnergyBlock> newBlocks = new LinkedList<>();
|
||||
Date end = viewMode.toBlockEnd(_readTime, timezone);
|
||||
while (idx >= size) {
|
||||
@@ -297,6 +343,38 @@ public class BreakerGroupEnergy {
|
||||
return joules;
|
||||
}
|
||||
|
||||
public double charge() {
|
||||
return charge(null);
|
||||
}
|
||||
|
||||
public double charge(Set<String> _selectedBreakers) {
|
||||
return charge(_selectedBreakers, true);
|
||||
}
|
||||
|
||||
public double charge(Set<String> _selectedBreakers, BillingMode _mode) {
|
||||
return charge(_selectedBreakers, true, _mode);
|
||||
}
|
||||
|
||||
public double charge(Set<String> _selectedBreakers, boolean _includeSubgroups) {
|
||||
return charge(_selectedBreakers, _includeSubgroups, null);
|
||||
}
|
||||
|
||||
public double charge(Set<String> _selectedBreakers, boolean _includeSubgroups, BillingMode _mode) {
|
||||
double charge = 0.0;
|
||||
if (_includeSubgroups) {
|
||||
for (BreakerGroupEnergy group : CollectionUtils.makeNotNull(subGroups)) {
|
||||
charge += group.charge(_selectedBreakers, true, _mode);
|
||||
}
|
||||
}
|
||||
if ((energyBlocks != null) && ((_selectedBreakers == null) || _selectedBreakers.contains(getGroupId()))) {
|
||||
for (EnergyBlock energy : energyBlocks) {
|
||||
if ((_mode == null) || ((_mode == BillingMode.PRODUCTION) && energy.getCharge() < 0.0) || (_mode == BillingMode.CONSUMPTION && energy.getCharge() > 0.0))
|
||||
charge += energy.getCharge();
|
||||
}
|
||||
}
|
||||
return charge;
|
||||
}
|
||||
|
||||
public List<BreakerGroupEnergy> getAllGroups() {
|
||||
Map<String, BreakerGroupEnergy> groups = new TreeMap<>();
|
||||
getAllGroups(groups);
|
||||
@@ -343,7 +421,31 @@ public class BreakerGroupEnergy {
|
||||
}
|
||||
|
||||
private static class MeterMinute {
|
||||
private final int meter;
|
||||
private final Date minute;
|
||||
|
||||
public MeterMinute(int _meter, Date _minute) {
|
||||
meter = _meter;
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(meter, minute);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MeterMinuteValues {
|
||||
public double[] usage = new double[60];
|
||||
public double[] solar = new double[60];
|
||||
public double[] charges = new double[60];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public class BreakerGroupSummary {
|
||||
private Date start;
|
||||
private List<BreakerGroupSummary> subGroups;
|
||||
private double joules;
|
||||
private double charge;
|
||||
private double toGrid;
|
||||
private double fromGrid;
|
||||
|
||||
@@ -35,6 +36,7 @@ public class BreakerGroupSummary {
|
||||
start = _energy.getStart();
|
||||
subGroups = CollectionUtils.transform(_energy.getSubGroups(), BreakerGroupSummary::new);
|
||||
joules = _energy.joules(null, false);
|
||||
charge = _energy.charge(null, false);
|
||||
toGrid = _energy.getToGrid();
|
||||
fromGrid = _energy.getFromGrid();
|
||||
}
|
||||
@@ -107,6 +109,14 @@ public class BreakerGroupSummary {
|
||||
joules = _joules;
|
||||
}
|
||||
|
||||
public double getCharge() {
|
||||
return charge;
|
||||
}
|
||||
|
||||
public void setCharge(double _charge) {
|
||||
charge = _charge;
|
||||
}
|
||||
|
||||
public double getToGrid() {
|
||||
return toGrid;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ public class EnergyBlock {
|
||||
private Date start;
|
||||
private Date end;
|
||||
private double joules;
|
||||
private double charge;
|
||||
|
||||
public EnergyBlock() {
|
||||
}
|
||||
@@ -48,6 +49,17 @@ public class EnergyBlock {
|
||||
joules = _joules;
|
||||
}
|
||||
|
||||
public double getCharge() {
|
||||
return charge;
|
||||
}
|
||||
|
||||
public void setCharge(double _charge) {
|
||||
charge = _charge;
|
||||
}
|
||||
public void addCharge(double _charge) {
|
||||
charge += _charge;
|
||||
}
|
||||
|
||||
public double wattHours() {
|
||||
return joules / 3600;
|
||||
}
|
||||
|
||||
@@ -109,10 +109,19 @@ public enum EnergyBlockViewMode {
|
||||
return blockCnt;
|
||||
}
|
||||
|
||||
public int blockIndex(Date _readTime, TimeZone _tz) {
|
||||
public int initBlockCount() {
|
||||
if (this == ALL)
|
||||
return 1;
|
||||
if (this == YEAR)
|
||||
return 12;
|
||||
if (this == MONTH)
|
||||
return 31;
|
||||
return 1500;
|
||||
}
|
||||
|
||||
public int blockIndex(Date _dayStart, Date _readTime, TimeZone _tz) {
|
||||
if (this == DAY) {
|
||||
Date start = DateUtils.getMidnightBefore(_readTime, _tz);
|
||||
return (int)((_readTime.getTime() - start.getTime())/60000);
|
||||
return (int)((_readTime.getTime() - _dayStart.getTime())/60000);
|
||||
}
|
||||
else if (this == MONTH) {
|
||||
Calendar read = DateUtils.toCalendar(_readTime, _tz);
|
||||
|
||||
@@ -45,4 +45,12 @@ public enum HubConfigCharacteristic {
|
||||
public boolean isChar(String _char) {
|
||||
return NullUtils.isEqual(name(), _char);
|
||||
}
|
||||
|
||||
public static HubConfigCharacteristic fromUUID(UUID _uuid) {
|
||||
for (HubConfigCharacteristic c : values()) {
|
||||
if (c.uuid.equals(_uuid))
|
||||
return c;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.lanternsoftware.datamodel.currentmonitor.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BillingCurrency;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BillingMode;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BillingRate;
|
||||
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.DaoProxyType;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class BillingRateSerializer extends AbstractDaoSerializer<BillingRate>
|
||||
{
|
||||
@Override
|
||||
public Class<BillingRate> getSupportedClass()
|
||||
{
|
||||
return BillingRate.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DaoProxyType> getSupportedProxies() {
|
||||
return Collections.singletonList(DaoProxyType.MONGO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoEntity toDaoEntity(BillingRate _o)
|
||||
{
|
||||
DaoEntity d = new DaoEntity();
|
||||
d.put("meter", _o.getMeter());
|
||||
d.put("day_billing_cycle_start", _o.getDayBillingCycleStart());
|
||||
d.put("mode", DaoSerializer.toEnumName(_o.getMode()));
|
||||
d.put("rate", _o.getRate());
|
||||
d.put("unit", DaoSerializer.toEnumName(_o.getCurrency()));
|
||||
d.put("time_of_day_start", _o.getTimeOfDayStart());
|
||||
d.put("time_of_day_end", _o.getTimeOfDayEnd());
|
||||
d.put("month_kwh_start", _o.getMonthKWhStart());
|
||||
d.put("month_kwh_end", _o.getMonthKWhEnd());
|
||||
d.put("begin_effective", DaoSerializer.toLong(_o.getBeginEffective()));
|
||||
d.put("end_effective", DaoSerializer.toLong(_o.getEndEffective()));
|
||||
d.put("recurs_annually", _o.isRecursAnnually());
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BillingRate fromDaoEntity(DaoEntity _d)
|
||||
{
|
||||
BillingRate o = new BillingRate();
|
||||
o.setMeter(DaoSerializer.getInteger(_d, "meter"));
|
||||
o.setDayBillingCycleStart(DaoSerializer.getInteger(_d, "day_billing_cycle_start"));
|
||||
o.setMode(DaoSerializer.getEnum(_d, "mode", BillingMode.class));
|
||||
o.setRate(DaoSerializer.getDouble(_d, "rate"));
|
||||
o.setCurrency(DaoSerializer.getEnum(_d, "unit", BillingCurrency.class));
|
||||
o.setTimeOfDayStart(DaoSerializer.getInteger(_d, "time_of_day_start"));
|
||||
o.setTimeOfDayEnd(DaoSerializer.getInteger(_d, "time_of_day_end"));
|
||||
o.setMonthKWhStart(DaoSerializer.getDouble(_d, "month_kwh_start"));
|
||||
o.setMonthKWhEnd(DaoSerializer.getDouble(_d, "month_kwh_end"));
|
||||
o.setBeginEffective(DaoSerializer.getDate(_d, "begin_effective"));
|
||||
o.setEndEffective(DaoSerializer.getDate(_d, "end_effective"));
|
||||
o.setRecursAnnually(DaoSerializer.getBoolean(_d, "recurs_annually"));
|
||||
return o;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.lanternsoftware.datamodel.currentmonitor.dao;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BillingRate;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
|
||||
@@ -35,6 +36,7 @@ public class BreakerConfigSerializer extends AbstractDaoSerializer<BreakerConfig
|
||||
d.put("panels", DaoSerializer.toDaoEntities(_o.getPanels(), DaoProxyType.MONGO));
|
||||
d.put("breaker_hubs", DaoSerializer.toDaoEntities(_o.getBreakerHubs(), DaoProxyType.MONGO));
|
||||
d.put("breaker_groups", DaoSerializer.toDaoEntities(_o.getBreakerGroups(), DaoProxyType.MONGO));
|
||||
d.put("billing_rates", DaoSerializer.toDaoEntities(_o.getBillingRates(), DaoProxyType.MONGO));
|
||||
d.put("version", _o.getVersion());
|
||||
return d;
|
||||
}
|
||||
@@ -48,6 +50,7 @@ public class BreakerConfigSerializer extends AbstractDaoSerializer<BreakerConfig
|
||||
o.setPanels(DaoSerializer.getList(_d, "panels", BreakerPanel.class));
|
||||
o.setBreakerHubs(DaoSerializer.getList(_d, "breaker_hubs", BreakerHub.class));
|
||||
o.setBreakerGroups(DaoSerializer.getList(_d, "breaker_groups", BreakerGroup.class));
|
||||
o.setBillingRates(DaoSerializer.getList(_d, "billing_rates", BillingRate.class));
|
||||
o.setVersion(DaoSerializer.getInteger(_d, "version"));
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ public class BreakerGroupEnergySerializer extends AbstractDaoSerializer<BreakerG
|
||||
Date start = _o.getStart();
|
||||
Date now = new Date();
|
||||
ByteBuffer bb = ByteBuffer.allocate(_o.getViewMode().blockCount(start, tz) * 4);
|
||||
ByteBuffer cb = ByteBuffer.allocate(_o.getViewMode().blockCount(start, tz) * 8);
|
||||
for (EnergyBlock b : _o.getEnergyBlocks()) {
|
||||
if (b.getStart().before(start))
|
||||
continue;
|
||||
@@ -55,15 +56,21 @@ public class BreakerGroupEnergySerializer extends AbstractDaoSerializer<BreakerG
|
||||
break;
|
||||
while (start.before(b.getStart())) {
|
||||
bb.putFloat(0);
|
||||
cb.putDouble(0);
|
||||
start = _o.getViewMode().toBlockEnd(start, tz);
|
||||
}
|
||||
bb.putFloat((float) b.getJoules());
|
||||
cb.putDouble(b.getCharge());
|
||||
start = _o.getViewMode().toBlockEnd(start, tz);
|
||||
}
|
||||
if (bb.position() < bb.limit())
|
||||
if (bb.position() < bb.limit()) {
|
||||
d.put("blocks", Arrays.copyOfRange(bb.array(), 0, bb.position()));
|
||||
else
|
||||
d.put("charges", Arrays.copyOfRange(cb.array(), 0, cb.position()));
|
||||
}
|
||||
else {
|
||||
d.put("blocks", bb.array());
|
||||
d.put("charges", cb.array());
|
||||
}
|
||||
}
|
||||
d.put("to_grid", _o.getToGrid());
|
||||
d.put("from_grid", _o.getFromGrid());
|
||||
@@ -93,6 +100,14 @@ public class BreakerGroupEnergySerializer extends AbstractDaoSerializer<BreakerG
|
||||
}
|
||||
}
|
||||
o.setEnergyBlocks(blocks);
|
||||
byte[] chargeData = DaoSerializer.getByteArray(_d, "charges");
|
||||
int idx = 0;
|
||||
if (CollectionUtils.length(chargeData) > 0) {
|
||||
ByteBuffer bb = ByteBuffer.wrap(chargeData);
|
||||
while (bb.hasRemaining()) {
|
||||
blocks.get(idx++).setCharge(bb.getDouble());
|
||||
}
|
||||
}
|
||||
o.setToGrid(DaoSerializer.getDouble(_d, "to_grid"));
|
||||
o.setFromGrid(DaoSerializer.getDouble(_d, "from_grid"));
|
||||
return o;
|
||||
|
||||
@@ -33,6 +33,7 @@ public class BreakerGroupSummarySerializer extends AbstractDaoSerializer<Breaker
|
||||
d.put("start", DaoSerializer.toLong(_o.getStart()));
|
||||
d.put("sub_groups", DaoSerializer.toDaoEntities(_o.getSubGroups(), DaoProxyType.MONGO));
|
||||
d.put("joules", _o.getJoules());
|
||||
d.put("charge", _o.getCharge());
|
||||
d.put("to_grid", _o.getToGrid());
|
||||
d.put("from_grid", _o.getFromGrid());
|
||||
return d;
|
||||
@@ -48,6 +49,7 @@ public class BreakerGroupSummarySerializer extends AbstractDaoSerializer<Breaker
|
||||
o.setStart(DaoSerializer.getDate(_d, "start"));
|
||||
o.setSubGroups(DaoSerializer.getList(_d, "sub_groups", BreakerGroupSummary.class));
|
||||
o.setJoules(DaoSerializer.getDouble(_d, "joules"));
|
||||
o.setCharge(DaoSerializer.getDouble(_d, "charge"));
|
||||
o.setToGrid(DaoSerializer.getDouble(_d, "to_grid"));
|
||||
o.setFromGrid(DaoSerializer.getDouble(_d, "from_grid"));
|
||||
return o;
|
||||
|
||||
@@ -28,6 +28,7 @@ public class EnergyBlockSerializer extends AbstractDaoSerializer<EnergyBlock>
|
||||
d.put("start", DaoSerializer.toLong(_o.getStart()));
|
||||
d.put("end", DaoSerializer.toLong(_o.getEnd()));
|
||||
d.put("joules", _o.getJoules());
|
||||
d.put("charge", _o.getCharge());
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -38,6 +39,7 @@ public class EnergyBlockSerializer extends AbstractDaoSerializer<EnergyBlock>
|
||||
o.setStart(DaoSerializer.getDate(_d, "start"));
|
||||
o.setEnd(DaoSerializer.getDate(_d, "end"));
|
||||
o.setJoules(DaoSerializer.getDouble(_d, "joules"));
|
||||
o.setCharge(DaoSerializer.getDouble(_d, "charge"));
|
||||
return o;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
com.lanternsoftware.datamodel.currentmonitor.dao.AccountSerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.dao.BillingRateSerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerConfigSerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerGroupEnergySerializer
|
||||
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerGroupSerializer
|
||||
|
||||
Reference in New Issue
Block a user