diff --git a/currentmonitor/lantern-currentmonitor/pom.xml b/currentmonitor/lantern-currentmonitor/pom.xml
index 6e9c4a1..360449b 100644
--- a/currentmonitor/lantern-currentmonitor/pom.xml
+++ b/currentmonitor/lantern-currentmonitor/pom.xml
@@ -2,7 +2,7 @@
4.0.0
lantern-currentmonitor
jar
- 1.1.0
+ 1.1.1
lantern-currentmonitor
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/BreakerSamples.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/BreakerSamples.java
index aa9d46a..dbe77a8 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/BreakerSamples.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/BreakerSamples.java
@@ -2,6 +2,7 @@ package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.currentmonitor.adc.MCP3008Pin;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
+import com.lanternsoftware.datamodel.currentmonitor.hub.PowerSample;
import java.util.List;
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/CurrentMonitor.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/CurrentMonitor.java
index e6915c4..4e04a55 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/CurrentMonitor.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/CurrentMonitor.java
@@ -6,6 +6,9 @@ import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPolarity;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
+import com.lanternsoftware.datamodel.currentmonitor.hub.BreakerSample;
+import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
+import com.lanternsoftware.datamodel.currentmonitor.hub.PowerSample;
import com.lanternsoftware.pigpio.PiGpioFactory;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
@@ -18,6 +21,8 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -29,6 +34,23 @@ public class CurrentMonitor {
private Sampler sampler;
private PowerListener listener;
private boolean debug = false;
+ private boolean postSamples = false;
+
+ public boolean isDebug() {
+ return debug;
+ }
+
+ public void setDebug(boolean _debug) {
+ debug = _debug;
+ }
+
+ public boolean isPostSamples() {
+ return postSamples;
+ }
+
+ public void setPostSamples(boolean _postSamples) {
+ postSamples = _postSamples;
+ }
public void stop() {
stopMonitoring();
@@ -40,10 +62,6 @@ public class CurrentMonitor {
LOG.info("Power Monitor Service Stopped");
}
- public void setDebug(boolean _debug) {
- debug = _debug;
- }
-
public CalibrationResult calibrateVoltage(double _curCalibration) {
LOG.info("Calibrating Voltage");
MCP3008Pin voltagePin = new MCP3008Pin(getChip(0), 0);
@@ -148,10 +166,10 @@ public class CurrentMonitor {
private boolean running = true;
private final BreakerHub hub;
private final List> breakers;
- private final int intervalNs;
+ private final long intervalNs;
private final int concurrentBreakerCnt;
- public Sampler(BreakerHub _hub, List _breakers, int _intervalMs, int _concurrentBreakerCnt) {
+ public Sampler(BreakerHub _hub, List _breakers, long _intervalMs, int _concurrentBreakerCnt) {
hub = _hub;
MCP3008Pin voltagePin = new MCP3008Pin(getChip(0), 0);
breakers = CollectionUtils.transform(_breakers, _b->{
@@ -177,6 +195,10 @@ public class CurrentMonitor {
long interval = 0;
int cycle;
int curBreaker;
+ long intervalStart;
+ long intervalEnd;
+ long cycleEnd;
+ long curTime;
BreakerSamples[] cycleBreakers = new BreakerSamples[concurrentBreakerCnt];
try {
while (true) {
@@ -187,8 +209,8 @@ public class CurrentMonitor {
}
}
final Date readTime = new Date();
- final long intervalStart = (interval * intervalNs) + start;
- long intervalEnd = intervalStart + intervalNs;
+ intervalStart = (interval * intervalNs) + start;
+ intervalEnd = intervalStart + intervalNs;
cycle = 0;
final int batch = (int) (interval % BATCH_CNT);
while (System.nanoTime() < intervalEnd) {
@@ -197,22 +219,73 @@ public class CurrentMonitor {
cycleBreakers[curBreaker].incrementCycleCnt();
}
cycle++;
- long cycleEnd = intervalStart + (cycle * (intervalNs / hub.getFrequency()));
- while (System.nanoTime() < cycleEnd) {
+ cycleEnd = intervalStart + (cycle * (intervalNs / hub.getFrequency()));
+ curTime = System.nanoTime();
+ while (curTime < cycleEnd) {
for (curBreaker = 0; curBreaker < concurrentBreakerCnt; curBreaker++) {
PowerSample sample = cycleBreakers[curBreaker].incrementSample();
+ sample.nanoTime = curTime;
+ sample.cycle = cycle;
sample.voltage = cycleBreakers[curBreaker].getVoltagePin().read();
sample.current = cycleBreakers[curBreaker].getCurrentPin().read();
}
+ curTime = System.nanoTime();
}
}
interval++;
+ final HubSample hubSample = (postSamples && (interval == 10)) ? new HubSample() : null;
executor.submit(() -> {
+ long cycleLength = 1000000000/hub.getFrequency();
+ if (hubSample != null) {
+ hubSample.setSampleDate(new Date());
+ hubSample.setBreakers(new ArrayList<>());
+ }
for (List breaker : breakers) {
- double vOffset = 0.0;
- double iOffset = 0.0;
BreakerSamples samples = breaker.get(batch);
List validSamples = samples.getSamples().subList(0, samples.getSampleCnt());
+ if (hubSample != null) {
+ BreakerSample breakerSample = new BreakerSample();
+ breakerSample.setSamples(validSamples);
+ breakerSample.setPanel(samples.getBreaker().getPanel());
+ breakerSample.setSpace(samples.getBreaker().getSpace());
+ hubSample.getBreakers().add(breakerSample);
+ }
+ int phaseOffsetNs = samples.getBreaker().getPhaseOffsetNs()-hub.getPhaseOffsetNs();
+ if (phaseOffsetNs != 0) {
+ Map> cycles = CollectionUtils.transformToMultiMap(validSamples, _p->_p.cycle);
+ for (List cycleSamples : cycles.values()) {
+ long minNano;
+ long maxNano = minNano = cycleSamples.get(0).nanoTime;
+ for (PowerSample sample : cycleSamples) {
+ if (sample.nanoTime < minNano)
+ minNano = sample.nanoTime;
+ if (sample.nanoTime > maxNano)
+ maxNano = sample.nanoTime;
+ }
+ TreeMap offsetSamples = new TreeMap<>();
+ for (PowerSample sample : cycleSamples) {
+ if (sample.nanoTime + phaseOffsetNs < minNano)
+ offsetSamples.put(sample.nanoTime + phaseOffsetNs + cycleLength, sample.voltage);
+ else if (sample.nanoTime + phaseOffsetNs > maxNano)
+ offsetSamples.put(sample.nanoTime + phaseOffsetNs - cycleLength, sample.voltage);
+ else
+ offsetSamples.put(sample.nanoTime + phaseOffsetNs, sample.voltage);
+ }
+ for (PowerSample sample : cycleSamples) {
+ List voltages = new ArrayList<>();
+ Entry floorEntry = offsetSamples.floorEntry(sample.nanoTime);
+ if (floorEntry != null)
+ voltages.add(floorEntry.getValue());
+ Entry ceilingEntry = offsetSamples.ceilingEntry(sample.nanoTime);
+ if (ceilingEntry != null)
+ voltages.add(ceilingEntry.getValue());
+ sample.voltage = CollectionUtils.mean(voltages);
+ }
+ }
+ }
+
+ double vOffset = 0.0;
+ double iOffset = 0.0;
for (PowerSample sample : validSamples) {
vOffset += sample.voltage;
iOffset += sample.current;
@@ -223,6 +296,7 @@ public class CurrentMonitor {
double pSum = 0.0;
double vRms = 0.0;
double lowPassFilter = samples.getBreaker().getLowPassFilter();
+
for (PowerSample sample : validSamples) {
sample.current -= iOffset;
if (Math.abs(sample.current) < lowPassFilter)
@@ -233,11 +307,15 @@ public class CurrentMonitor {
}
vRms /= validSamples.size();
vRms = hub.getVoltageCalibrationFactor() * Math.sqrt(vRms);
- int lowSampleRatio = (lowSamples * 100) / samples.getSampleCnt();
- double realPower = Math.abs((hub.getVoltageCalibrationFactor() * hub.getPortCalibrationFactor() * samples.getBreaker().getFinalCalibrationFactor() * pSum) / samples.getSampleCnt());
- if ((lowSampleRatio > 75) && realPower < 13.0)
+ int lowSampleRatio = (lowSamples * 100) / validSamples.size();
+ double realPower = (hub.getVoltageCalibrationFactor() * hub.getPortCalibrationFactor() * samples.getBreaker().getFinalCalibrationFactor() * pSum) / validSamples.size();
+ if ((lowSampleRatio > 75) && Math.abs(realPower) < 13.0)
realPower = 0.0;
- if (samples.getBreaker().getPolarity() == BreakerPolarity.SOLAR)
+ if (samples.getBreaker().getPolarity() == BreakerPolarity.NORMAL)
+ realPower = Math.abs(realPower);
+ else if (samples.getBreaker().getPolarity() == BreakerPolarity.SOLAR)
+ realPower = -Math.abs(realPower);
+ else if (samples.getBreaker().getPolarity() == BreakerPolarity.BI_DIRECTIONAL_INVERTED)
realPower = -realPower;
if (samples.getBreaker().isDoublePower())
realPower *= 2.0;
@@ -263,6 +341,8 @@ public class CurrentMonitor {
samples.setCycleCnt(0);
listener.onPowerEvent(new BreakerPower(samples.getBreaker().getPanel(), samples.getBreaker().getSpace(), readTime, realPower, vRms));
}
+ if (hubSample != null)
+ listener.onSampleEvent(hubSample);
});
}
}
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorApp.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorApp.java
index da609ec..5d73f14 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorApp.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorApp.java
@@ -16,6 +16,7 @@ import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigService;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
import com.lanternsoftware.datamodel.currentmonitor.NetworkStatus;
+import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
@@ -65,16 +66,24 @@ public class MonitorApp {
private static final CurrentMonitor monitor = new CurrentMonitor();
private static final List readings = new ArrayList<>();
private static String version;
- private static final PowerListener logger = _p -> {
- if (!config.isDebug()) {
- _p.setHubVersion(version);
- if (breakerConfig != null)
- _p.setAccountId(breakerConfig.getAccountId());
- synchronized (readings) {
- readings.add(_p);
- }
- } else
- LOG.info("Panel{} - Space{} Power: {}W", _p.getPanel(), Breaker.toSpaceDisplay(_p.getSpace()), String.format("%.3f", _p.getPower()));
+ private static final PowerListener logger = new PowerListener() {
+ @Override
+ public void onPowerEvent(BreakerPower _power) {
+ if (!config.isDebug()) {
+ _power.setHubVersion(version);
+ if (breakerConfig != null)
+ _power.setAccountId(breakerConfig.getAccountId());
+ synchronized (readings) {
+ readings.add(_power);
+ }
+ } else
+ LOG.info("Panel{} - Space{} Power: {}W", _power.getPanel(), Breaker.toSpaceDisplay(_power.getSpace()), String.format("%.3f", _power.getPower()));
+ }
+
+ @Override
+ public void onSampleEvent(HubSample _sample) {
+ post(DaoSerializer.toZipBson(_sample), "sample");
+ }
};
private static final BleCharacteristicListener bluetoothListener = new BleCharacteristicListener() {
@Override
@@ -214,6 +223,7 @@ public class MonitorApp {
if (NullUtils.isNotEmpty(config.getHost()))
host = NullUtils.terminateWith(config.getHost(), "/");
monitor.setDebug(config.isDebug());
+ monitor.setPostSamples(config.isPostSamples());
LEDFlasher.setLEDOn(false);
if (NullUtils.isNotEmpty(config.getAuthCode()))
authCode = config.getAuthCode();
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorConfig.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorConfig.java
index 4c040b0..dd971fd 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorConfig.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/MonitorConfig.java
@@ -17,6 +17,7 @@ public class MonitorConfig {
private boolean debug;
private int connectTimeout;
private int socketTimeout;
+ private boolean postSamples = false;
private boolean needsCalibration = true;
private String mqttBrokerUrl;
private String mqttUserName;
@@ -98,6 +99,14 @@ public class MonitorConfig {
socketTimeout = _socketTimeout;
}
+ public boolean isPostSamples() {
+ return postSamples;
+ }
+
+ public void setPostSamples(boolean _postSamples) {
+ postSamples = _postSamples;
+ }
+
public boolean isNeedsCalibration() {
return needsCalibration;
}
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/PowerListener.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/PowerListener.java
index a3a0a5a..2730b3e 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/PowerListener.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/PowerListener.java
@@ -1,7 +1,9 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
+import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
public interface PowerListener {
void onPowerEvent(BreakerPower _power);
+ void onSampleEvent(HubSample _sample);
}
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/PowerSample.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/PowerSample.java
deleted file mode 100644
index 5efb1f4..0000000
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/PowerSample.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.lanternsoftware.currentmonitor;
-
-public class PowerSample {
- public double voltage;
- public double current;
-}
diff --git a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/dao/MonitorConfigSerializer.java b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/dao/MonitorConfigSerializer.java
index ad54fda..a4e3e2b 100644
--- a/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/dao/MonitorConfigSerializer.java
+++ b/currentmonitor/lantern-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/dao/MonitorConfigSerializer.java
@@ -34,6 +34,7 @@ public class MonitorConfigSerializer extends AbstractDaoSerializer getAllHubCommands();
void deleteHubCommand(String _id);
+ void putHubSample(HubSample _sample);
+ List getSamplesForAccount(int _accountId);
+
MongoProxy getProxy();
}
diff --git a/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/MongoCurrentMonitorDao.java b/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/MongoCurrentMonitorDao.java
index cfa1bc3..80f0bd9 100644
--- a/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/MongoCurrentMonitorDao.java
+++ b/currentmonitor/lantern-dataaccess-currentmonitor/src/main/java/com/lanternsoftware/dataaccess/currentmonitor/MongoCurrentMonitorDao.java
@@ -21,6 +21,7 @@ import com.lanternsoftware.datamodel.currentmonitor.archive.ArchiveStatus;
import com.lanternsoftware.datamodel.currentmonitor.archive.BreakerEnergyArchive;
import com.lanternsoftware.datamodel.currentmonitor.archive.DailyEnergyArchive;
import com.lanternsoftware.datamodel.currentmonitor.archive.MonthlyEnergyArchive;
+import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.DateRange;
import com.lanternsoftware.util.DateUtils;
@@ -487,17 +488,13 @@ 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"));
if (firstMinute == null)
return;
- rebuildSummaries(_accountId, firstMinute.getMinuteAsDate(), new Date());
+ HubPowerMinute lastMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sortDesc("minute"));
+ rebuildSummaries(_accountId, firstMinute.getMinuteAsDate(), lastMinute.getMinuteAsDate());
}
@Override
@@ -812,6 +809,16 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
proxy.delete(HubCommand.class, new DaoQuery("_id", _id));
}
+ @Override
+ public void putHubSample(HubSample _sample) {
+ proxy.save(_sample);
+ }
+
+ @Override
+ public List getSamplesForAccount(int _accountId) {
+ return proxy.query(HubSample.class, new DaoQuery("account_id", _accountId));
+ }
+
@Override
public MongoProxy getProxy() {
return proxy;
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/Breaker.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/Breaker.java
index 2306865..6bd5414 100644
--- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/Breaker.java
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/Breaker.java
@@ -21,6 +21,7 @@ public class Breaker implements IIdentical {
private String name;
private String description;
private int sizeAmps;
+ private int phaseOffsetNs;
private double calibrationFactor;
private double lowPassFilter;
private BreakerPolarity polarity;
@@ -140,6 +141,14 @@ public class Breaker implements IIdentical {
sizeAmps = _sizeAmps;
}
+ public int getPhaseOffsetNs() {
+ return phaseOffsetNs;
+ }
+
+ public void setPhaseOffsetNs(int _phaseOffsetNs) {
+ phaseOffsetNs = _phaseOffsetNs;
+ }
+
public double getLowPassFilter() {
return Math.abs(lowPassFilter) < 0.05 ? 1.6 : lowPassFilter;
}
@@ -278,7 +287,7 @@ public class Breaker implements IIdentical {
@Override
public boolean isIdentical(Breaker _o) {
if (this == _o) return true;
- return panel == _o.panel && space == _o.space && meter == _o.meter && hub == _o.hub && port == _o.port && sizeAmps == _o.sizeAmps && Double.compare(_o.calibrationFactor, calibrationFactor) == 0 && Double.compare(_o.lowPassFilter, lowPassFilter) == 0 && doublePower == _o.doublePower && Objects.equals(name, _o.name) && Objects.equals(description, _o.description) && polarity == _o.polarity && type == _o.type;
+ return panel == _o.panel && space == _o.space && meter == _o.meter && hub == _o.hub && port == _o.port && sizeAmps == _o.sizeAmps && phaseOffsetNs == _o.phaseOffsetNs && Double.compare(_o.calibrationFactor, calibrationFactor) == 0 && Double.compare(_o.lowPassFilter, lowPassFilter) == 0 && doublePower == _o.doublePower && Objects.equals(name, _o.name) && Objects.equals(description, _o.description) && polarity == _o.polarity && type == _o.type;
}
@Override
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/BreakerHub.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/BreakerHub.java
index 09b5ab2..be70d19 100644
--- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/BreakerHub.java
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/BreakerHub.java
@@ -11,6 +11,8 @@ public class BreakerHub implements IIdentical {
private int hub;
private double voltageCalibrationFactor;
private double portCalibrationFactor;
+ private int phaseCnt;
+ private int phaseOffsetNs;
private int frequency;
private String bluetoothMac;
@@ -46,8 +48,24 @@ public class BreakerHub implements IIdentical {
portCalibrationFactor = _portCalibrationFactor;
}
+ public int getPhaseCnt() {
+ return phaseCnt == 0 ? 2 : phaseCnt;
+ }
+
+ public void setPhaseCnt(int _phaseCnt) {
+ phaseCnt = _phaseCnt;
+ }
+
+ public int getPhaseOffsetNs() {
+ return phaseOffsetNs;
+ }
+
+ public void setPhaseOffsetNs(int _phaseOffsetNs) {
+ phaseOffsetNs = _phaseOffsetNs;
+ }
+
public int getFrequency() {
- return frequency;
+ return frequency == 0 ? 60 : frequency;
}
public void setFrequency(int _frequency) {
@@ -73,7 +91,7 @@ public class BreakerHub implements IIdentical {
@Override
public boolean isIdentical(BreakerHub _o) {
if (this == _o) return true;
- return hub == _o.hub && Double.compare(_o.voltageCalibrationFactor, voltageCalibrationFactor) == 0 && Double.compare(_o.portCalibrationFactor, portCalibrationFactor) == 0 && frequency == _o.frequency && Objects.equals(bluetoothMac, _o.bluetoothMac);
+ return hub == _o.hub && Double.compare(_o.voltageCalibrationFactor, voltageCalibrationFactor) == 0 && Double.compare(_o.portCalibrationFactor, portCalibrationFactor) == 0 && getPhaseCnt() == _o.getPhaseCnt() && getPhaseOffsetNs() == _o.getPhaseOffsetNs() && getFrequency() == _o.getFrequency() && Objects.equals(bluetoothMac, _o.bluetoothMac);
}
@Override
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/BreakerPolarity.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/BreakerPolarity.java
index 13fe60b..e84b8ed 100644
--- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/BreakerPolarity.java
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/BreakerPolarity.java
@@ -2,5 +2,7 @@ package com.lanternsoftware.datamodel.currentmonitor;
public enum BreakerPolarity {
NORMAL,
- SOLAR;
+ SOLAR,
+ BI_DIRECTIONAL,
+ BI_DIRECTIONAL_INVERTED
}
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/EnergySummary.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/EnergySummary.java
index 0ccaaed..465b4ee 100644
--- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/EnergySummary.java
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/EnergySummary.java
@@ -140,9 +140,9 @@ public class EnergySummary {
idx = 0;
double flow = 0.0;
for (Float power : CollectionUtils.makeNotNull(breaker.getReadings())) {
- if ((b.getPolarity() == BreakerPolarity.SOLAR) && (meter.flow[idx] < 0.0))
+ if (power < 0 && (meter.flow[idx] < 0.0))
flow -= meter.flow[idx] * (power / meter.solar[idx]);
- else if ((b.getPolarity() != BreakerPolarity.SOLAR) && (meter.flow[idx] > 0.0))
+ else if (power > 0 && (meter.flow[idx] > 0.0))
flow += meter.flow[idx] * (power / meter.usage[idx]);
idx++;
}
@@ -152,11 +152,11 @@ public class EnergySummary {
}
public void resetEnergy(Date _readTime) {
- if (energy == null)
- return;
- int idx = viewMode.blockIndex(start, _readTime, timezone);
- if (idx < energy.length)
- energy[idx] = 0f;
+ if (energy != null) {
+ int idx = viewMode.blockIndex(start, _readTime, timezone);
+ if (idx < energy.length)
+ energy[idx] = 0f;
+ }
for (EnergySummary subGroup : CollectionUtils.makeNotNull(subGroups)) {
subGroup.resetEnergy(_readTime);
}
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/BreakerHubSerializer.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/BreakerHubSerializer.java
index 776059b..135559d 100644
--- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/BreakerHubSerializer.java
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/BreakerHubSerializer.java
@@ -28,6 +28,8 @@ public class BreakerHubSerializer extends AbstractDaoSerializer
d.put("hub", _o.getHub());
d.put("voltage_calibration_factor", _o.getRawVoltageCalibrationFactor());
d.put("port_calibration_factor", _o.getRawPortCalibrationFactor());
+ d.put("phase_cnt", _o.getPhaseCnt());
+ d.put("phase_offset_ns", _o.getPhaseOffsetNs());
d.put("frequency", _o.getFrequency());
d.put("bluetooth_mac", _o.getBluetoothMac());
return d;
@@ -40,6 +42,8 @@ public class BreakerHubSerializer extends AbstractDaoSerializer
o.setHub(DaoSerializer.getInteger(_d, "hub"));
o.setVoltageCalibrationFactor(DaoSerializer.getDouble(_d, "voltage_calibration_factor"));
o.setPortCalibrationFactor(DaoSerializer.getDouble(_d, "port_calibration_factor"));
+ o.setPhaseCnt(DaoSerializer.getInteger(_d, "phase_cnt"));
+ o.setPhaseOffsetNs(DaoSerializer.getInteger(_d, "phase_offset_ns"));
o.setFrequency(DaoSerializer.getInteger(_d, "frequency"));
o.setBluetoothMac(DaoSerializer.getString(_d, "bluetooth_mac"));
return o;
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/BreakerSerializer.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/BreakerSerializer.java
index cfb3361..d8654d0 100644
--- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/BreakerSerializer.java
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/dao/BreakerSerializer.java
@@ -35,6 +35,7 @@ public class BreakerSerializer extends AbstractDaoSerializer
d.put("name", _o.getName());
d.put("description", _o.getDescription());
d.put("size_amps", _o.getSizeAmps());
+ d.put("phase_offset_ns", _o.getPhaseOffsetNs());
d.put("calibration_factor", _o.getCalibrationFactor());
d.put("low_pass_filter", _o.getLowPassFilter());
d.put("polarity", DaoSerializer.toEnumName(_o.getPolarity()));
@@ -56,6 +57,7 @@ public class BreakerSerializer extends AbstractDaoSerializer
o.setName(DaoSerializer.getString(_d, "name"));
o.setDescription(DaoSerializer.getString(_d, "description"));
o.setSizeAmps(DaoSerializer.getInteger(_d, "size_amps"));
+ o.setPhaseOffsetNs(DaoSerializer.getInteger(_d, "phase_offset_ns"));
o.setCalibrationFactor(DaoSerializer.getDouble(_d, "calibration_factor"));
o.setLowPassFilter(DaoSerializer.getDouble(_d, "low_pass_filter"));
o.setPolarity(DaoSerializer.getEnum(_d, "polarity", BreakerPolarity.class));
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/BreakerSample.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/BreakerSample.java
new file mode 100644
index 0000000..67f80a4
--- /dev/null
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/BreakerSample.java
@@ -0,0 +1,41 @@
+package com.lanternsoftware.datamodel.currentmonitor.hub;
+
+import com.lanternsoftware.datamodel.currentmonitor.Breaker;
+import com.lanternsoftware.util.dao.annotations.DBSerializable;
+
+import java.util.List;
+
+@DBSerializable
+public class BreakerSample {
+ private int panel;
+ private int space;
+ private List samples;
+
+ public int key() {
+ return Breaker.intKey(panel, space);
+ }
+
+ public int getPanel() {
+ return panel;
+ }
+
+ public void setPanel(int _panel) {
+ panel = _panel;
+ }
+
+ public int getSpace() {
+ return space;
+ }
+
+ public void setSpace(int _space) {
+ space = _space;
+ }
+
+ public List getSamples() {
+ return samples;
+ }
+
+ public void setSamples(List _samples) {
+ samples = _samples;
+ }
+}
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/HubSample.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/HubSample.java
new file mode 100644
index 0000000..0934648
--- /dev/null
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/HubSample.java
@@ -0,0 +1,42 @@
+package com.lanternsoftware.datamodel.currentmonitor.hub;
+
+import com.lanternsoftware.util.DateUtils;
+import com.lanternsoftware.util.dao.annotations.DBSerializable;
+
+import java.util.Date;
+import java.util.List;
+
+@DBSerializable(autogen = false)
+public class HubSample {
+ private int accountId;
+ private Date sampleDate;
+ private List breakers;
+
+ public String getId() {
+ return String.format("%d-%d", accountId, DateUtils.toLong(sampleDate));
+ }
+
+ public int getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(int _accountId) {
+ accountId = _accountId;
+ }
+
+ public Date getSampleDate() {
+ return sampleDate;
+ }
+
+ public void setSampleDate(Date _sampleDate) {
+ sampleDate = _sampleDate;
+ }
+
+ public List getBreakers() {
+ return breakers;
+ }
+
+ public void setBreakers(List _breakers) {
+ breakers = _breakers;
+ }
+}
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/PowerSample.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/PowerSample.java
new file mode 100644
index 0000000..cb7aa93
--- /dev/null
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/PowerSample.java
@@ -0,0 +1,43 @@
+package com.lanternsoftware.datamodel.currentmonitor.hub;
+
+import com.lanternsoftware.util.dao.annotations.DBSerializable;
+
+@DBSerializable
+public class PowerSample {
+ public long nanoTime;
+ public int cycle;
+ public double voltage;
+ public double current;
+
+ public long getNanoTime() {
+ return nanoTime;
+ }
+
+ public void setNanoTime(long _nanoTime) {
+ nanoTime = _nanoTime;
+ }
+
+ public int getCycle() {
+ return cycle;
+ }
+
+ public void setCycle(int _cycle) {
+ cycle = _cycle;
+ }
+
+ public double getVoltage() {
+ return voltage;
+ }
+
+ public void setVoltage(double _voltage) {
+ voltage = _voltage;
+ }
+
+ public double getCurrent() {
+ return current;
+ }
+
+ public void setCurrent(double _current) {
+ current = _current;
+ }
+}
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/dao/BreakerSampleSerializer.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/dao/BreakerSampleSerializer.java
new file mode 100644
index 0000000..21a3c99
--- /dev/null
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/dao/BreakerSampleSerializer.java
@@ -0,0 +1,44 @@
+package com.lanternsoftware.datamodel.currentmonitor.hub.dao;
+
+import com.lanternsoftware.datamodel.currentmonitor.hub.BreakerSample;
+import com.lanternsoftware.datamodel.currentmonitor.hub.PowerSample;
+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 BreakerSampleSerializer extends AbstractDaoSerializer
+{
+ @Override
+ public Class getSupportedClass()
+ {
+ return BreakerSample.class;
+ }
+
+ @Override
+ public List getSupportedProxies() {
+ return Collections.singletonList(DaoProxyType.MONGO);
+ }
+
+ @Override
+ public DaoEntity toDaoEntity(BreakerSample _o)
+ {
+ DaoEntity d = new DaoEntity();
+ d.put("panel", _o.getPanel());
+ d.put("space", _o.getSpace());
+ d.put("samples", DaoSerializer.toDaoEntities(_o.getSamples(), DaoProxyType.MONGO));
+ return d;
+ }
+
+ @Override
+ public BreakerSample fromDaoEntity(DaoEntity _d)
+ {
+ BreakerSample o = new BreakerSample();
+ o.setPanel(DaoSerializer.getInteger(_d, "panel"));
+ o.setSpace(DaoSerializer.getInteger(_d, "space"));
+ o.setSamples(DaoSerializer.getList(_d, "samples", PowerSample.class));
+ return o;
+ }
+}
\ No newline at end of file
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/dao/HubSampleSerializer.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/dao/HubSampleSerializer.java
new file mode 100644
index 0000000..b734e3c
--- /dev/null
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/dao/HubSampleSerializer.java
@@ -0,0 +1,45 @@
+package com.lanternsoftware.datamodel.currentmonitor.hub.dao;
+
+import com.lanternsoftware.datamodel.currentmonitor.hub.BreakerSample;
+import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
+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 HubSampleSerializer extends AbstractDaoSerializer
+{
+ @Override
+ public Class getSupportedClass()
+ {
+ return HubSample.class;
+ }
+
+ @Override
+ public List getSupportedProxies() {
+ return Collections.singletonList(DaoProxyType.MONGO);
+ }
+
+ @Override
+ public DaoEntity toDaoEntity(HubSample _o)
+ {
+ DaoEntity d = new DaoEntity();
+ d.put("_id", _o.getId());
+ d.put("account_id", _o.getAccountId());
+ d.put("sample_date", DaoSerializer.toLong(_o.getSampleDate()));
+ d.put("breakers", DaoSerializer.toDaoEntities(_o.getBreakers(), DaoProxyType.MONGO));
+ return d;
+ }
+
+ @Override
+ public HubSample fromDaoEntity(DaoEntity _d)
+ {
+ HubSample o = new HubSample();
+ o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
+ o.setSampleDate(DaoSerializer.getDate(_d, "sample_date"));
+ o.setBreakers(DaoSerializer.getList(_d, "breakers", BreakerSample.class));
+ return o;
+ }
+}
\ No newline at end of file
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/dao/PowerSampleSerializer.java b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/dao/PowerSampleSerializer.java
new file mode 100644
index 0000000..aaf0b6c
--- /dev/null
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/java/com/lanternsoftware/datamodel/currentmonitor/hub/dao/PowerSampleSerializer.java
@@ -0,0 +1,45 @@
+package com.lanternsoftware.datamodel.currentmonitor.hub.dao;
+
+import com.lanternsoftware.datamodel.currentmonitor.hub.PowerSample;
+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 PowerSampleSerializer extends AbstractDaoSerializer
+{
+ @Override
+ public Class getSupportedClass()
+ {
+ return PowerSample.class;
+ }
+
+ @Override
+ public List getSupportedProxies() {
+ return Collections.singletonList(DaoProxyType.MONGO);
+ }
+
+ @Override
+ public DaoEntity toDaoEntity(PowerSample _o)
+ {
+ DaoEntity d = new DaoEntity();
+ d.put("nano_time", _o.getNanoTime());
+ d.put("cycle", _o.getCycle());
+ d.put("voltage", _o.getVoltage());
+ d.put("current", _o.getCurrent());
+ return d;
+ }
+
+ @Override
+ public PowerSample fromDaoEntity(DaoEntity _d)
+ {
+ PowerSample o = new PowerSample();
+ o.setNanoTime(DaoSerializer.getLong(_d, "nano_time"));
+ o.setCycle(DaoSerializer.getInteger(_d, "cycle"));
+ o.setVoltage(DaoSerializer.getDouble(_d, "voltage"));
+ o.setCurrent(DaoSerializer.getDouble(_d, "current"));
+ return o;
+ }
+}
\ No newline at end of file
diff --git a/currentmonitor/lantern-datamodel-currentmonitor/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer b/currentmonitor/lantern-datamodel-currentmonitor/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer
index 96fc8ac..b512210 100644
--- a/currentmonitor/lantern-datamodel-currentmonitor/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer
+++ b/currentmonitor/lantern-datamodel-currentmonitor/src/main/resources/META-INF/services/com.lanternsoftware.util.dao.IDaoSerializer
@@ -26,3 +26,6 @@ com.lanternsoftware.datamodel.currentmonitor.dao.MeterSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.NetworkStatusSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.SequenceSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.SignupResponseSerializer
+com.lanternsoftware.datamodel.currentmonitor.hub.dao.BreakerSampleSerializer
+com.lanternsoftware.datamodel.currentmonitor.hub.dao.HubSampleSerializer
+com.lanternsoftware.datamodel.currentmonitor.hub.dao.PowerSampleSerializer
diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/context/Globals.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/context/Globals.java
index 95d5b50..9c5c529 100644
--- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/context/Globals.java
+++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/context/Globals.java
@@ -18,9 +18,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
public class Globals implements ServletContextListener {
public static CurrentMonitorDao dao;
+ public static ExecutorService opsExecutor;
private static final Map>> commands = new HashMap<>();
@Override
@@ -28,10 +31,12 @@ public class Globals implements ServletContextListener {
dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
RulesEngine.instance().start();
RulesEngine.instance().schedule(new CommandTask(), 0);
+ opsExecutor = Executors.newFixedThreadPool(7);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
+ opsExecutor.shutdown();
dao.shutdown();
HttpFactory.shutdown();
RulesEngine.shutdown();
diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/ConfigServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/ConfigServlet.java
index b6c7702..ab3e4d6 100644
--- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/ConfigServlet.java
+++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/ConfigServlet.java
@@ -4,6 +4,7 @@ import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic;
+import com.lanternsoftware.rules.RulesEngine;
import com.lanternsoftware.util.dao.auth.AuthCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,6 +41,8 @@ public class ConfigServlet extends SecureServiceServlet {
if ((oldConfig == null) || !oldConfig.isIdentical(config))
Globals.dao.putHubCommand(new HubCommand(config.getAccountId(), HubConfigCharacteristic.ReloadConfig, null));
Globals.dao.putConfig(config);
- zipBsonResponse(_rep, Globals.dao.getMergedConfig(_authCode));
+ config = Globals.dao.getMergedConfig(_authCode);
+ RulesEngine.instance().sendFcmMessage(config.getAccountId(), config);
+ zipBsonResponse(_rep, config);
}
}
diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/RebuildSummariesServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/RebuildSummariesServlet.java
index 9befc30..391ffec 100644
--- a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/RebuildSummariesServlet.java
+++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/RebuildSummariesServlet.java
@@ -17,13 +17,14 @@ public class RebuildSummariesServlet extends SecureServiceServlet {
if (_authCode.getAccountId() == 100) {
String[] path = path(_req);
if (path.length > 0) {
- Globals.dao.rebuildSummariesAsync(DaoSerializer.toInteger(CollectionUtils.get(path, 0)));
+ Globals.opsExecutor.submit(() -> Globals.dao.rebuildSummaries(DaoSerializer.toInteger(CollectionUtils.get(path, 0))));
}
else {
for (String sId : Globals.dao.getProxy().queryForField(Account.class, null, "_id")) {
int id = DaoSerializer.toInteger(sId);
- if (id != 0)
- Globals.dao.rebuildSummariesAsync(id);
+ if (id != 0) {
+ Globals.opsExecutor.submit(() -> Globals.dao.rebuildSummaries(id));
+ }
}
}
}
diff --git a/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SampleServlet.java b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SampleServlet.java
new file mode 100644
index 0000000..c2ed488
--- /dev/null
+++ b/currentmonitor/lantern-service-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/servlet/SampleServlet.java
@@ -0,0 +1,21 @@
+package com.lanternsoftware.currentmonitor.servlet;
+
+import com.lanternsoftware.currentmonitor.context.Globals;
+import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
+import com.lanternsoftware.util.dao.auth.AuthCode;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/sample")
+public class SampleServlet extends SecureServiceServlet {
+ @Override
+ protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
+ HubSample sample = getRequestPayload(_req, HubSample.class);
+ if (sample == null)
+ return;
+ sample.setAccountId(_authCode.getAccountId());
+ Globals.dao.putHubSample(sample);
+ }
+}
diff --git a/pigpio/lantern-pigpio/src/main/java/com/lanternsoftware/pigpio/PIGPIO.java b/pigpio/lantern-pigpio/src/main/java/com/lanternsoftware/pigpio/PIGPIO.java
index c1bc3f6..22dcdf7 100644
--- a/pigpio/lantern-pigpio/src/main/java/com/lanternsoftware/pigpio/PIGPIO.java
+++ b/pigpio/lantern-pigpio/src/main/java/com/lanternsoftware/pigpio/PIGPIO.java
@@ -4,9 +4,6 @@ import com.lanternsoftware.util.ResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.nio.file.Files;
-
public class PIGPIO {
protected static final Logger LOG = LoggerFactory.getLogger(PIGPIO.class);
@@ -20,10 +17,11 @@ public class PIGPIO {
osArch = "armhf";
String path = "/lib/" + osArch + "/lantern-pigpio.so";
byte[] file = ResourceLoader.getByteArrayResource(PIGPIO.class, path);
- String target = Files.createTempFile("lantern-pigpio", "so").toAbsolutePath().toString();
- ResourceLoader.writeFile(target, file);
- System.load(target);
- } catch (IOException _e) {
+ LOG.info("library size: {}", file.length);
+ String libPath = "/opt/currentmonitor/lantern-pigpio.so";
+ ResourceLoader.writeFile(libPath, file);
+ System.load(libPath);
+ } catch (Exception _e) {
LOG.error("Failed to load lantern-pigpio.so from resource", _e);
}
}
diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/RulesEngine.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/RulesEngine.java
index de50191..ea31e33 100644
--- a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/RulesEngine.java
+++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/RulesEngine.java
@@ -11,13 +11,16 @@ import com.lanternsoftware.datamodel.rules.Criteria;
import com.lanternsoftware.datamodel.rules.Event;
import com.lanternsoftware.datamodel.rules.EventId;
import com.lanternsoftware.datamodel.rules.EventType;
+import com.lanternsoftware.datamodel.rules.FcmDevice;
import com.lanternsoftware.datamodel.rules.Rule;
import com.lanternsoftware.rules.actions.ActionImpl;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.DateUtils;
-import com.lanternsoftware.util.external.LanternFiles;
+import com.lanternsoftware.util.cloudservices.google.FirebaseHelper;
+import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
+import com.lanternsoftware.util.external.LanternFiles;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,6 +39,7 @@ import java.util.concurrent.Executors;
public class RulesEngine {
protected static final Logger LOG = LoggerFactory.getLogger(RulesEngine.class);
+ protected static final FirebaseHelper firebaseHelper = new FirebaseHelper(LanternFiles.CONFIG_PATH + "google_account_key.json");
private static RulesEngine INSTANCE;
private final ExecutorService executor = Executors.newCachedThreadPool();
@@ -69,6 +73,15 @@ public class RulesEngine {
return dao;
}
+ public void sendFcmMessage(int _accountId, Object _payload) {
+ List devices = RulesEngine.instance().dao().getFcmDevicesForAccount(_accountId);
+ if (devices.isEmpty())
+ return;
+ for (FcmDevice device : devices) {
+ firebaseHelper.sendMessage(device.getToken(), new DaoEntity("payload", DaoSerializer.toBase64ZipBson(_payload)).and("payloadClass", _payload.getClass().getCanonicalName()));
+ }
+ }
+
public void fireEvent(Event _event) {
if (_event.getType() != EventType.TIME)
dao.putEvent(_event);
@@ -108,6 +121,8 @@ public class RulesEngine {
return;
Collection dates = CollectionUtils.aggregate(rules, _r->CollectionUtils.transform(_r.getAllCriteria(), _c->_c.getNextTriggerDate(tz)));
Date nextDate = CollectionUtils.getSmallest(dates);
+ if (nextDate == null)
+ return;
LOG.info("Scheduling next time event for account {} at {}", _accountId, DateUtils.format("MM/dd/yyyy HH:mm:ss", nextDate));
nextTask = new EventTimeTask(_accountId, nextDate);
timer.schedule(nextTask, nextDate);
diff --git a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/AbstractAlertAction.java b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/AbstractAlertAction.java
index 3247b46..39764a9 100644
--- a/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/AbstractAlertAction.java
+++ b/rules/lantern-service-rules/src/main/java/com/lanternsoftware/rules/actions/AbstractAlertAction.java
@@ -1,28 +1,11 @@
package com.lanternsoftware.rules.actions;
import com.lanternsoftware.datamodel.rules.Alert;
-import com.lanternsoftware.datamodel.rules.FcmDevice;
import com.lanternsoftware.datamodel.rules.Rule;
import com.lanternsoftware.rules.RulesEngine;
-import com.lanternsoftware.util.dao.DaoEntity;
-import com.lanternsoftware.util.dao.DaoSerializer;
-import com.lanternsoftware.util.external.LanternFiles;
-import com.lanternsoftware.util.cloudservices.google.FirebaseHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
public abstract class AbstractAlertAction implements ActionImpl {
- protected static final Logger logger = LoggerFactory.getLogger(AbstractAlertAction.class);
- protected static final FirebaseHelper firebaseHelper = new FirebaseHelper(LanternFiles.CONFIG_PATH + "google_account_key.json");
-
protected void sendAlert(Rule _rule, Alert _alert) {
- List devices = RulesEngine.instance().dao().getFcmDevicesForAccount(_rule.getAccountId());
- if (devices.isEmpty())
- return;
- for (FcmDevice device : devices) {
- firebaseHelper.sendMessage(device.getToken(), new DaoEntity("payload", DaoSerializer.toBase64ZipBson(_alert)).and("payloadClass", Alert.class.getCanonicalName()));
- }
+ RulesEngine.instance().sendFcmMessage(_rule.getAccountId(), _alert);
}
}
diff --git a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java
index 6677daa..7a28df3 100644
--- a/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java
+++ b/zwave/lantern-service-zwave/src/main/java/com/lanternsoftware/zwave/context/ZWaveApp.java
@@ -2,7 +2,6 @@ package com.lanternsoftware.zwave.context;
import com.lanternsoftware.datamodel.rules.Event;
import com.lanternsoftware.datamodel.rules.EventType;
-import com.lanternsoftware.util.dao.auth.AuthCode;
import com.lanternsoftware.datamodel.zwave.Switch;
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
import com.lanternsoftware.datamodel.zwave.SwitchTransition;
@@ -10,13 +9,14 @@ import com.lanternsoftware.datamodel.zwave.ThermostatMode;
import com.lanternsoftware.datamodel.zwave.ZWaveConfig;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.DateUtils;
-import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
import com.lanternsoftware.util.cryptography.AESTool;
import com.lanternsoftware.util.dao.DaoSerializer;
+import com.lanternsoftware.util.dao.auth.AuthCode;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
+import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.http.HttpPool;
import com.lanternsoftware.zwave.controller.Controller;
import com.lanternsoftware.zwave.dao.MongoZWaveDao;
@@ -54,6 +54,8 @@ import java.util.Set;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
public class ZWaveApp {
public static final AESTool aes = AESTool.authTool();
@@ -75,11 +77,13 @@ public class ZWaveApp {
private SwitchScheduleTask nextScheduleTask;
private final Map sensors = new HashMap<>();
private final Object ZWAVE_MUTEX = new Object();
+ private ExecutorService executor = null;
public void start() {
try {
pool = new HttpPool(100, 20, 5000, 5000, 5000);
config = DaoSerializer.parse(ResourceLoader.loadFile(LanternFiles.CONFIG_PATH + "config.json"), ZWaveConfig.class);
+ executor = Executors.newFixedThreadPool(5);
if (config == null) {
dao = new MongoZWaveDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
config = dao.getConfig(1);
@@ -202,6 +206,7 @@ public class ZWaveApp {
@Override
public void onMessage(MultilevelSwitchReportRequest _message) {
+ logger.info("Received MultilevelSwitchReportRequest");
onSwitchLevelChange(_message.getNodeId(), _message.getLevel());
}
});
@@ -214,6 +219,7 @@ public class ZWaveApp {
@Override
public void onMessage(BinarySwitchReportRequest _message) {
+ logger.info("Received BinarySwitchReportRequest");
onSwitchLevelChange(_message.getNodeId(), _message.getLevel());
}
});
@@ -226,10 +232,18 @@ public class ZWaveApp {
@Override
public void onMessage(CRC16EncapRequest _message) {
- onSwitchLevelChange(_message.getNodeId(), _message.isOn()?0xFF:0);
+// logger.info("Received CRC16EncapRequest");
+// onSwitchLevelChange(_message.getNodeId(), _message.isOn()?0xFF:0);
}
});
+// for (Switch sw : config.getSwitches()) {
+// if (sw.getNodeId() < 255) {
+// controller.send(new NodeNeighborUpdateRequest(sw.getNodeId()));
+// ConcurrencyUtils.sleep(5000);
+// }
+// }
+
// controller.send(new MultilevelSwitchSetRequest((byte)2, 0xFF));
// controller.send(new MultilevelSensorGetRequest((byte)11));
@@ -244,27 +258,31 @@ public class ZWaveApp {
// controller.send(new ThermostatModeGetRequest((byte)11));
}
- private void onSwitchLevelChange(int _secondaryNodeId, int _primaryLevel) {
+ private void onSwitchLevelChange(int _nodeId, int _level) {
synchronized (switches) {
- Switch sw = switches.get(_secondaryNodeId);
- if ((sw != null) && !sw.isPrimary()) {
- int newLevel = sw.isMultilevel()?_primaryLevel:((_primaryLevel == 0)?0:99);
+ Switch sw = switches.get(_nodeId);
+ if (sw != null) {
+ logger.info("Received level change for node {} to level {} via z-wave", _nodeId, _level);
+ if (_level == -1)
+ _level = 255;
+ int newLevel = sw.isMultilevel()?NullUtils.bound(_level, 0, 99):((_level == 0)?0:99);
sw.setLevel(newLevel);
fireSwitchLevelEvent(sw);
- for (Switch peer : CollectionUtils.makeNotNull(peers.get(_secondaryNodeId))) {
- if (peer.isPrimary()) {
- logger.info("Mirror Event from node {} to node {}", _secondaryNodeId, peer.getNodeId());
- if (peer.isMultilevel()) {
- peer.setLevel(newLevel);
- controller.send(new MultilevelSwitchSetRequest((byte) peer.getNodeId(), newLevel));
- } else {
- peer.setLevel(newLevel > 0 ? 0xff : 0);
- controller.send(new BinarySwitchSetRequest((byte) peer.getNodeId(), newLevel > 0));
- }
+ for (Switch peer : CollectionUtils.makeNotNull(peers.get(_nodeId))) {
+ logger.info("Mirror Event from {} node {} to {} node {} level {}", sw.isPrimary() ? "primary" : "secondary", _nodeId, peer.isPrimary() ? "primary" : "secondary", peer.getNodeId(), newLevel);
+ if (peer.isMultilevel()) {
+ peer.setLevel(newLevel);
+ controller.send(new MultilevelSwitchSetRequest((byte) peer.getNodeId(), newLevel));
+ } else {
+ peer.setLevel(newLevel != 0 ? 0xff : 0);
+ controller.send(new BinarySwitchSetRequest((byte) peer.getNodeId(), newLevel != 0));
}
}
persistConfig();
}
+ else {
+ logger.info("Received level change for unknown node {}", _nodeId);
+ }
}
}
@@ -294,18 +312,20 @@ public class ZWaveApp {
public void fireSwitchLevelEvent(Switch _sw) {
if (NullUtils.isEmpty(config.getRulesUrl()) || _sw.isSuppressEvents())
return;
- Event event = new Event();
- event.setEventDescription(_sw.getFullDisplay() + " set to " + _sw.getLevel());
- event.setType(EventType.SWITCH_LEVEL);
- event.setTime(new Date());
- event.setValue(_sw.getLevel());
- event.setSourceId(String.valueOf(_sw.getNodeId()));
- event.setAccountId(config.getAccountId());
- logger.info("Sending event to rules server - " + event.getEventDescription());
- HttpPost post = new HttpPost(NullUtils.terminateWith(config.getRulesUrl(), "/") + "event");
- post.setHeader("auth_code", authCode);
- post.setEntity(new ByteArrayEntity(DaoSerializer.toZipBson(event)));
- pool.execute(post);
+ executor.submit(()->{
+ Event event = new Event();
+ event.setEventDescription(_sw.getFullDisplay() + " set to " + _sw.getLevel());
+ event.setType(EventType.SWITCH_LEVEL);
+ event.setTime(new Date());
+ event.setValue(_sw.getLevel());
+ event.setSourceId(String.valueOf(_sw.getNodeId()));
+ event.setAccountId(config.getAccountId());
+ logger.info("Sending event to rules server - " + event.getEventDescription());
+ HttpPost post = new HttpPost(NullUtils.terminateWith(config.getRulesUrl(), "/") + "event");
+ post.setHeader("auth_code", authCode);
+ post.setEntity(new ByteArrayEntity(DaoSerializer.toZipBson(event)));
+ pool.execute(post);
+ });
}
public void setSwitchLevel(int _nodeId, int _level, boolean _updatePeers) {
@@ -401,11 +421,13 @@ public class ZWaveApp {
peers.remove(config.getUrl());
for (String peer : peers) {
for (Switch sw : modified) {
- logger.info("Sending update for switch {} {} level {} to {}", sw.getNodeId(), sw.getFullDisplay(), sw.getLevel(), peer);
- HttpPost post = new HttpPost(peer + "/switch/" + sw.getNodeId());
- post.setHeader("auth_code", authCode);
- post.setEntity(new ByteArrayEntity(DaoSerializer.toZipBson(sw)));
- pool.execute(post);
+ executor.submit(()->{
+ logger.info("Sending update for switch {} {} level {} to {}", sw.getNodeId(), sw.getFullDisplay(), sw.getLevel(), peer);
+ HttpPost post = new HttpPost(peer + "/switch/" + sw.getNodeId());
+ post.setHeader("auth_code", authCode);
+ post.setEntity(new ByteArrayEntity(DaoSerializer.toZipBson(sw)));
+ pool.execute(post);
+ });
}
}
}
@@ -441,6 +463,10 @@ public class ZWaveApp {
pool.shutdown();
pool = null;
}
+ if (executor != null) {
+ executor.shutdown();
+ executor = null;
+ }
if (dao != null) {
dao.shutdown();
dao = null;
@@ -455,7 +481,7 @@ public class ZWaveApp {
for (Switch node : nodes) {
logger.info("Setting {}, Node {} to {}", node.getName(), node.getNodeId(), _level);
byte nid = (byte) (node.getNodeId()%1000);
- controller.send(node.isMultilevel() ? new MultilevelSwitchSetRequest(nid, _level) : new BinarySwitchSetRequest(nid, _level > 0));
+ controller.send(node.isMultilevel() ? new MultilevelSwitchSetRequest(nid, _level) : new BinarySwitchSetRequest(nid, _level != 0));
}
}
diff --git a/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/BinarySwitchReportRequest.java b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/BinarySwitchReportRequest.java
index 9b6feef..3ded94c 100644
--- a/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/BinarySwitchReportRequest.java
+++ b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/BinarySwitchReportRequest.java
@@ -14,7 +14,7 @@ public class BinarySwitchReportRequest extends RequestMessage {
@Override
public void fromPayload(byte[] _payload) {
nodeId = _payload[5];
- level = _payload[9];
+ level = 0xFF & _payload[9];
}
public int getLevel() {
diff --git a/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/NodeNeighborUpdateRequest.java b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/NodeNeighborUpdateRequest.java
new file mode 100644
index 0000000..6b4e320
--- /dev/null
+++ b/zwave/lantern-zwave/src/main/java/com/lanternsoftware/zwave/message/impl/NodeNeighborUpdateRequest.java
@@ -0,0 +1,15 @@
+package com.lanternsoftware.zwave.message.impl;
+
+import com.lanternsoftware.zwave.message.CommandClass;
+import com.lanternsoftware.zwave.message.ControllerMessageType;
+import com.lanternsoftware.zwave.message.RequestMessage;
+
+public class NodeNeighborUpdateRequest extends RequestMessage {
+ public NodeNeighborUpdateRequest() {
+ super(ControllerMessageType.RequestNodeNeighborUpdate, CommandClass.NO_OPERATION, (byte) 0);
+ }
+
+ public NodeNeighborUpdateRequest(int _nodeId) {
+ super((byte) _nodeId, ControllerMessageType.RequestNodeNeighborUpdate, CommandClass.NO_OPERATION, (byte) 0);
+ }
+}
diff --git a/zwave/lantern-zwave/src/main/resources/META-INF/services/com.lanternsoftware.zwave.message.Message b/zwave/lantern-zwave/src/main/resources/META-INF/services/com.lanternsoftware.zwave.message.Message
index 11fb745..3abbeda 100644
--- a/zwave/lantern-zwave/src/main/resources/META-INF/services/com.lanternsoftware.zwave.message.Message
+++ b/zwave/lantern-zwave/src/main/resources/META-INF/services/com.lanternsoftware.zwave.message.Message
@@ -21,6 +21,7 @@ com.lanternsoftware.zwave.message.impl.MultilevelSwitchReportRequest
com.lanternsoftware.zwave.message.impl.MultilevelSwitchSetRequest
com.lanternsoftware.zwave.message.impl.NodeInfoRequest
com.lanternsoftware.zwave.message.impl.NodeInfoResponse
+com.lanternsoftware.zwave.message.impl.NodeNeighborUpdateRequest
com.lanternsoftware.zwave.message.impl.RemoveNodeFromNetworkStartRequest
com.lanternsoftware.zwave.message.impl.RemoveNodeFromNetworkStopRequest
com.lanternsoftware.zwave.message.impl.SendDataRequest