Initial Commit

This commit is contained in:
Mark Milligan 2021-01-14 16:28:24 -06:00
parent 21c28201c5
commit 1334c110ff
318 changed files with 24160 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
*.iml
*.project
*.classpath
.idea/
.gradle/
*.settings/
*target/
build/
release/

View File

@ -0,0 +1,105 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-currentmonitor</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<name>lantern-currentmonitor</name>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.29</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.pi4j</groupId>
<artifactId>pi4j-gpio-extension</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.github.hypfvieh</groupId>
<artifactId>bluez-dbus</artifactId>
<version>0.1.3</version>
</dependency>
<dependency>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-datamodel-currentmonitor</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-http</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<executions>
<execution>
<goals>
<goal>testCompile</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<optimize>true</optimize>
<showDeprecation>true</showDeprecation>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>lantern-currentmonitor</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>com.lanternsoftware.currentmonitor.MonitorApp</Main-Class>
<Specification-Title>Lantern Power Monitor</Specification-Title>
<Specification-Version>${project.version}</Specification-Version>
<Specification-Vendor>Lantern Software, Inc.</Specification-Vendor>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,39 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.currentmonitor.bluetooth.BleApplication;
import com.lanternsoftware.currentmonitor.bluetooth.BleCharacteristic;
import com.lanternsoftware.currentmonitor.bluetooth.BleCharacteristicListener;
import com.lanternsoftware.currentmonitor.bluetooth.BleHelper;
import com.lanternsoftware.currentmonitor.bluetooth.BleService;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigService;
import com.lanternsoftware.util.CollectionUtils;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class BluetoothConfig implements Runnable {
private final AtomicBoolean running = new AtomicBoolean(true);
private final BleApplication app;
public BluetoothConfig(String _hubName, BleCharacteristicListener _listener) {
BleHelper.getAdapter().setPowered(true);
BleHelper.requestBusName("com.lanternsoftware");
BleHelper.setBasePath("/com/lanternsoftware");
HubConfigService service = new HubConfigService();
List<BleCharacteristic> chars = CollectionUtils.transform(service.getCharacteristics(), _c->new BleCharacteristic("HubConfig", _c.getUUID(), _c.name(), _c.getFlags()));
chars.forEach(_c->_c.setListener(_listener));
app = new BleApplication("Lantern", _hubName, new BleService("HubConfig", service.getServiceUUID(), chars));
}
@Override
public void run() {
app.start();
}
public void stop() {
synchronized (running) {
running.set(false);
}
app.stop();
}
}

View File

@ -0,0 +1,49 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.pi4j.io.gpio.GpioPinAnalogInput;
import java.util.List;
public class BreakerSamples {
private final Breaker breaker;
private final GpioPinAnalogInput voltagePin;
private final GpioPinAnalogInput currentPin;
private final List<PowerSample> samples;
private int sampleCnt;
public BreakerSamples(Breaker _breaker, GpioPinAnalogInput _voltagePin, GpioPinAnalogInput _currentPin, List<PowerSample> _samples) {
breaker = _breaker;
voltagePin = _voltagePin;
currentPin = _currentPin;
samples = _samples;
}
public Breaker getBreaker() {
return breaker;
}
public GpioPinAnalogInput getVoltagePin() {
return voltagePin;
}
public GpioPinAnalogInput getCurrentPin() {
return currentPin;
}
public List<PowerSample> getSamples() {
return samples;
}
public PowerSample getSample(int _sample) {
return samples.get(_sample);
}
public int getSampleCnt() {
return sampleCnt;
}
public void setSampleCnt(int _sampleCnt) {
sampleCnt = _sampleCnt;
}
}

View File

@ -0,0 +1,7 @@
package com.lanternsoftware.currentmonitor;
import java.util.Date;
public interface CurrentListener {
void onCurrentEvent(int _chip, int _pin, double _currentAmps, Date _start);
}

View File

@ -0,0 +1,241 @@
package com.lanternsoftware.currentmonitor;
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.util.CollectionUtils;
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
import com.pi4j.gpio.extension.base.AdcGpioProvider;
import com.pi4j.gpio.extension.mcp.MCP3008GpioProvider;
import com.pi4j.gpio.extension.mcp.MCP3008Pin;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinAnalogInput;
import com.pi4j.io.spi.SpiChannel;
import com.pi4j.io.spi.SpiDevice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CurrentMonitor {
private static final Logger LOG = LoggerFactory.getLogger(CurrentMonitor.class);
private static final int BATCH_CNT = 4;
private GpioController gpio;
private final ExecutorService executor = Executors.newCachedThreadPool();
private final Map<Integer, AdcGpioProvider> chips = new HashMap<>();
private final Map<Integer, GpioPinAnalogInput> pins = new HashMap<>();
private Sampler sampler;
private PowerListener listener;
private boolean debug = false;
public void start() {
try {
gpio = GpioFactory.getInstance();
LOG.info("Current Monitor Started");
}
catch (Throwable t) {
LOG.info("Failed to get gpio factory", t);
}
}
public void stop() {
stopMonitoring();
ConcurrencyUtils.sleep(1000);
executor.shutdownNow();
chips.clear();
pins.clear();
gpio.shutdown();
LOG.info("Current Monitor Stopped");
}
public void setDebug(boolean _debug) {
debug = _debug;
}
public void monitorPower(BreakerHub _hub, List<Breaker> _breakers, int _intervalMs, PowerListener _listener) {
stopMonitoring();
listener = _listener;
sampler = new Sampler(_hub, _breakers, _intervalMs, 2);
LOG.info("Starting to monitor ports {}", CollectionUtils.transformToCommaSeparated(_breakers, _b->String.valueOf(_b.getPort())));
executor.submit(sampler);
}
private GpioPinAnalogInput getPin(int _chip, int _pin) {
GpioPinAnalogInput pin;
synchronized (pins) {
AdcGpioProvider chip = chips.get(_chip);
if (chip == null) {
SpiChannel channel = SpiChannel.getByNumber(_chip);
if (channel == null)
return null;
try {
chip = new MCP3008GpioProvider(channel, 1250000, SpiDevice.DEFAULT_SPI_MODE, false);
chips.put(_chip, chip);
} catch (IOException _e) {
LOG.error("Failed to connect to chip {}", _chip, _e);
return null;
}
}
int pinKey = pinKey(_chip, _pin);
pin = pins.get(pinKey);
if (pin == null) {
pin = gpio.provisionAnalogInputPin(chip, MCP3008Pin.ALL[_pin], String.valueOf(pinKey));
pins.put(pinKey, pin);
}
}
return pin;
}
private Integer pinKey(int _chip, int _pin) {
return (_chip*8)+_pin;
}
public void submit(Runnable _runnable) {
executor.submit(_runnable);
}
public void stopMonitoring() {
if (sampler != null) {
sampler.stop();
sampler = null;
}
}
private class Sampler implements Runnable {
private boolean running = true;
private final BreakerHub hub;
private final List<List<BreakerSamples>> breakers;
private final int intervalNs;
private final int concurrentBreakerCnt;
public Sampler(BreakerHub _hub, List<Breaker> _breakers, int _intervalMs, int _concurrentBreakerCnt) {
hub = _hub;
GpioPinAnalogInput voltagePin = getPin(0, 0);
breakers = CollectionUtils.transform(_breakers, _b->{
LOG.info("Getting Chip {}, Pin {} for port {}", _b.getChip(), _b.getPin(), _b.getPort());
GpioPinAnalogInput currentPin = getPin(_b.getChip(), _b.getPin());
List<BreakerSamples> batches = new ArrayList<>(BATCH_CNT);
for (int i=0; i<BATCH_CNT; i++) {
List<PowerSample> samples = new ArrayList<>(30000/_breakers.size());
for (int j=0; j<30000/_breakers.size(); j++) {
samples.add(new PowerSample());
}
batches.add(new BreakerSamples(_b, voltagePin, currentPin, samples));
}
return batches;
});
intervalNs = _intervalMs*1000000;
concurrentBreakerCnt = Math.min(_breakers.size(), _concurrentBreakerCnt);
}
@Override
public void run() {
long start = System.nanoTime();
long interval = 0;
int cycle;
BreakerSamples[] cycleBreakers = new BreakerSamples[concurrentBreakerCnt];
try {
while (true) {
synchronized (this) {
if (!running)
break;
}
final Date readTime = new Date();
final long intervalStart = (interval * intervalNs) + start;
long intervalEnd = intervalStart + intervalNs;
cycle = 0;
final int batch = (int) (interval % BATCH_CNT);
int curBreaker;
for (curBreaker = 0; curBreaker < breakers.size(); curBreaker++) {
breakers.get(curBreaker).get(batch).setSampleCnt(0);
}
while (System.nanoTime() < intervalEnd) {
for (curBreaker = 0; curBreaker < concurrentBreakerCnt; curBreaker++) {
cycleBreakers[curBreaker] = breakers.get(((cycle * concurrentBreakerCnt) + curBreaker) % breakers.size()).get(batch);
}
cycle++;
long cycleEnd = intervalStart + (cycle * (intervalNs / hub.getFrequency()));
while (System.nanoTime() < cycleEnd) {
for (curBreaker = 0; curBreaker < concurrentBreakerCnt; curBreaker++) {
PowerSample sample = cycleBreakers[curBreaker].getSample(cycleBreakers[curBreaker].getSampleCnt());
sample.voltage = cycleBreakers[curBreaker].getVoltagePin().getValue();
sample.current = cycleBreakers[curBreaker].getCurrentPin().getValue();
cycleBreakers[curBreaker].setSampleCnt(cycleBreakers[curBreaker].getSampleCnt()+1);
}
}
}
interval++;
executor.submit(() -> {
for (List<BreakerSamples> breaker : breakers) {
double vOffset = 0.0;
double iOffset = 0.0;
BreakerSamples samples = breaker.get(batch);
List<PowerSample> validSamples = samples.getSamples().subList(0, samples.getSampleCnt());
for (PowerSample sample : validSamples) {
vOffset += sample.voltage;
iOffset += sample.current;
}
vOffset /= samples.getSampleCnt();
iOffset /= samples.getSampleCnt();
int lowSamples = 0;
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)
lowSamples++;
sample.voltage -= vOffset;
pSum += sample.current * sample.voltage;
vRms += sample.voltage * sample.voltage;
}
vRms /= validSamples.size();
vRms = hub.getVoltageCalibrationFactor() * Math.sqrt(vRms);
int lowSampleRatio = (lowSamples * 100) / samples.getSampleCnt();
double realPower = Math.abs((hub.getVoltageCalibrationFactor() * samples.getBreaker().getFinalCalibrationFactor() * pSum) / samples.getSampleCnt());
if ((lowSampleRatio > 75) && realPower < 13.0)
realPower = 0.0;
if (samples.getBreaker().getPolarity() == BreakerPolarity.SOLAR)
realPower = -realPower;
if (debug) {
synchronized (CurrentMonitor.this) {
LOG.info("===========================Start Port {}", samples.getBreaker().getPort());
LOG.info("Samples: {}", samples.getSampleCnt());
LOG.info("vMin: {}, vMax: {}, vOffset: {}", String.format("%.3f", CollectionUtils.getSmallest(validSamples, Comparator.comparing(_v -> _v.voltage)).voltage), String.format("%.3f", CollectionUtils.getLargest(validSamples, Comparator.comparing(_v -> _v.voltage)).voltage), String.format("%.3f", vOffset));
LOG.info("iMin: {}, iMax: {}, iOffset: {}", String.format("%.3f", CollectionUtils.getSmallest(validSamples, Comparator.comparing(_v -> _v.current)).current), String.format("%.3f", CollectionUtils.getLargest(validSamples, Comparator.comparing(_v -> _v.current)).current), String.format("%.3f", iOffset));
double iRms = samples.getBreaker().getFinalCalibrationFactor() * Math.sqrt(CollectionUtils.mean(CollectionUtils.transform(validSamples, _p -> _p.current * _p.current)));
LOG.info("vRms: {}", String.format("%.3f", vRms));
LOG.info("iRms: {}", String.format("%.3f", iRms));
double apparentPower = vRms * iRms;
LOG.info("Apparent Power: {} watts", String.format("%.3f", apparentPower));
LOG.info("Real Power: {} watts", String.format("%.3f", realPower));
double powerFactor = realPower / apparentPower;
LOG.info("Power Factor: {}", String.format("%.3f", powerFactor));
LOG.info("===========================End Port {}", samples.getBreaker().getPort());
}
}
listener.onPowerEvent(new BreakerPower(samples.getBreaker().getPanel(), samples.getBreaker().getSpace(), readTime, realPower, vRms));
}
});
}
}
catch (Throwable t) {
LOG.error("Exception while monitoring power", t);
}
}
synchronized void stop() {
running = false;
}
}
}

View File

@ -0,0 +1,409 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.currentmonitor.bluetooth.BleCharacteristicListener;
import com.lanternsoftware.currentmonitor.led.LEDFlasher;
import com.lanternsoftware.currentmonitor.util.NetworkMonitor;
import com.lanternsoftware.currentmonitor.wifi.WifiConfig;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPowerMinute;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigService;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.http.HttpPool;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
public class MonitorApp {
private static final Logger LOG = LoggerFactory.getLogger(MonitorApp.class);
private static final String WORKING_DIR = "/opt/currentmonitor/";
private static String authCode;
private static MonitorConfig config;
private static BreakerConfig breakerConfig;
private static String host;
private static Date lastUpdateCheck = new Date();
private static HttpPool pool;
private static LEDFlasher flasher = null;
private static final AtomicBoolean running = new AtomicBoolean(true);
private static final CurrentMonitor monitor = new CurrentMonitor();
private static final List<BreakerPower> readings = new ArrayList<>();
private static final String version = getVersionNumber();
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()));
};
public static void main(String[] args) {
config = DaoSerializer.parse(ResourceLoader.loadFileAsString(WORKING_DIR + "config.json"), MonitorConfig.class);
if (config == null) {
LOG.error("Failed to load config file from {}", WORKING_DIR + "config.json");
return;
}
pool = new HttpPool(10, 10, config.getSocketTimeout(), config.getConnectTimeout(), config.getSocketTimeout());
host = NullUtils.terminateWith(config.getHost(), "/");
monitor.setDebug(config.isDebug());
monitor.start();
LEDFlasher.setLEDOn(false);
final BluetoothConfig bluetoothConfig = new BluetoothConfig("Lantern Hub", new BleCharacteristicListener() {
@Override
public void write(String _name, byte[] _value) {
HubConfigCharacteristic ch = NullUtils.toEnum(HubConfigCharacteristic.class, _name);
LOG.info("Char Received, Name: {} Value: {}", _name, _value);
monitor.submit(()->{
switch (ch) {
case HubIndex:
if ((_value.length > 0)) {
config.setHub(_value[0]);
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
}
break;
case AuthCode:
String value = NullUtils.toString(_value);
if (NullUtils.isNotEmpty(value)) {
authCode = value;
config.setAuthCode(value);
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
}
break;
case WifiCredentials:
String ssid = HubConfigService.decryptWifiSSID(_value);
String pwd = HubConfigService.decryptWifiPassword(_value);
if (NullUtils.isNotEmpty(ssid) && NullUtils.isNotEmpty(pwd))
WifiConfig.setCredentials(ssid, pwd);
break;
case Flash:
if ((CollectionUtils.length(_value) == 0) || (_value[0] == 0)) {
if (flasher != null) {
flasher.stop();
flasher = null;
}
else
LEDFlasher.setLEDOn(false);
}
else {
if (flasher == null) {
flasher = new LEDFlasher();
monitor.submit(flasher);
}
}
break;
case Restart:
LOG.info("Restarting Current Monitor...");
try {
Runtime.getRuntime().exec("service currentmonitor restart");
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
break;
case Reboot:
LOG.info("Rebooting Pi...");
try {
Runtime.getRuntime().exec("reboot now");
} catch (IOException _e) {
LOG.error("Exception occurred while trying to reboot", _e);
}
break;
}
});
}
@Override
public byte[] read(String _name) {
HubConfigCharacteristic ch = NullUtils.toEnum(HubConfigCharacteristic.class, _name);
if (HubConfigCharacteristic.HubIndex == ch)
return new byte[]{(byte)(config == null?0:config.getHub())};
if (HubConfigCharacteristic.AccountId == ch)
return ByteBuffer.allocate(4).putInt(breakerConfig == null?0:breakerConfig.getAccountId()).array();
if (HubConfigCharacteristic.NetworkState == ch)
return new byte[]{NetworkMonitor.getNetworkStatus().toMask()};
return null;
}
});
monitor.submit(bluetoothConfig);
if (NullUtils.isNotEmpty(config.getAuthCode())) {
authCode = config.getAuthCode();
//TODO: check auth code validity
}
else {
HttpGet auth = new HttpGet(host + "auth");
HttpPool.addBasicAuthHeader(auth, config.getUsername(), config.getPassword());
authCode = DaoSerializer.getString(DaoSerializer.parse(pool.executeToString(auth)), "auth_code");
}
while (true) {
HttpGet get = new HttpGet(host + "config");
get.addHeader("auth_code", authCode);
breakerConfig = DaoSerializer.parse(pool.executeToString(get), BreakerConfig.class);
if (breakerConfig != null)
break;
LOG.error("Failed to load breaker config. Retrying in 5 seconds...");
ConcurrencyUtils.sleep(5000);
}
LOG.info("Breaker Config loaded");
LOG.debug(DaoSerializer.toJson(breakerConfig));
BreakerHub hub = breakerConfig.getHub(config.getHub());
if (hub != null) {
List<Breaker> breakers = breakerConfig.getBreakersForHub(config.getHub());
LOG.info("Monitoring {} breakers for hub {}", CollectionUtils.size(breakers), hub.getHub());
monitor.monitorPower(hub, breakers, 1000, logger);
}
monitor.submit(new PowerPoster());
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
synchronized (running) {
running.set(false);
}
bluetoothConfig.stop();
monitor.stop();
pool.shutdown();
}, "Monitor Shutdown"));
Console c = System.console();
BufferedReader reader = (c == null)?new BufferedReader(new InputStreamReader(System.in)):null;
while (running.get()) {
try {
String command = c != null ? c.readLine() : reader.readLine();
if (NullUtils.isEqual("exit", command))
break;
}
catch (Exception _e) {
LOG.error("Exception while reading from console input", _e);
break;
}
}
}
private static final class PowerPoster implements Runnable {
private final long firstPost;
private long lastPost;
private int lastMinute;
private final Map<Integer, Float[]> breakers = new HashMap<>();
public PowerPoster() {
firstPost = (new Date().getTime()/1000)*1000;
lastPost = new Date().getTime();
lastMinute = (int)(new Date().getTime()/60000);
}
@Override
public void run() {
try {
while (true) {
synchronized (running) {
if (!running.get())
break;
}
DaoEntity post = null;
DaoEntity minutePost = null;
int curMinute = (int) (new Date().getTime() / 60000);
synchronized (readings) {
if (!readings.isEmpty()) {
post = new DaoEntity("readings", DaoSerializer.toDaoEntities(readings));
if (curMinute != lastMinute) {
HubPowerMinute minute = new HubPowerMinute();
minute.setAccountId(breakerConfig.getAccountId());
minute.setHub(config.getHub());
minute.setMinute(lastMinute);
minute.setBreakers(CollectionUtils.transform(breakers.entrySet(), _e -> {
BreakerPowerMinute breaker = new BreakerPowerMinute();
breaker.setPanel(Breaker.toPanel(_e.getKey()));
breaker.setSpace(Breaker.toSpace(_e.getKey()));
breaker.setReadings(CollectionUtils.asArrayList(_e.getValue()));
return breaker;
}));
breakers.clear();
minutePost = DaoSerializer.toDaoEntity(minute);
lastMinute = curMinute;
}
for (BreakerPower power : readings) {
Float[] breakerReadings = breakers.computeIfAbsent(Breaker.toId(power.getPanel(), power.getSpace()), _i -> new Float[60]);
breakerReadings[(int) ((power.getReadTime().getTime() / 1000)%60)] = (float) power.getPower();
}
readings.clear();
}
}
if (minutePost != null) {
byte[] payload = DaoSerializer.toZipBson(minutePost);
if (!post(payload, "power/hub")) {
LOG.info("Failed Posting HubPowerMinute, writing cache");
ResourceLoader.writeFile(WORKING_DIR + "cache/" + UUID.randomUUID().toString() + ".min", payload);
}
}
if (post != null) {
byte[] payload = DaoSerializer.toZipBson(post);
if (post(payload, "power/batch")) {
File[] files = new File(WORKING_DIR + "cache").listFiles();
if (files != null) {
for (File file : files) {
payload = ResourceLoader.loadFile(file.getAbsolutePath());
if (post(payload, file.getName().endsWith("dat") ? "power/batch" : "power/hub"))
file.delete();
else
break;
}
}
}
}
if (DateUtils.diffInSeconds(new Date(), lastUpdateCheck) >= config.getUpdateInterval()) {
lastUpdateCheck = new Date();
monitor.submit(new UpdateChecker());
monitor.submit(new CommandChecker());
}
long now = new Date().getTime();
long duration = (now - firstPost)%1000;
if (now - lastPost < 1000) {
ConcurrencyUtils.sleep(1000 - duration);
}
lastPost = now;
}
}
catch (Throwable t) {
LOG.error("Exception in PowerPoster", t);
}
}
}
private static void uploadLog() {
LOG.info("Commanded to upload log file, preparing...");
String log = ResourceLoader.loadFileAsString(WORKING_DIR + "log/log.txt");
if (NullUtils.isNotEmpty(log)) {
DaoEntity payload = new DaoEntity("command", "log").and("payload", log);
post(DaoSerializer.toZipBson(payload), "command");
}
}
private static boolean post(byte[] _payload, String _path) {
HttpPost post = new HttpPost(host + _path);
post.addHeader("auth_code", authCode);
post.setEntity(new ByteArrayEntity(_payload, ContentType.APPLICATION_OCTET_STREAM));
CloseableHttpResponse resp = pool.execute(post);
try {
return ((resp != null) && (resp.getStatusLine() != null) && (resp.getStatusLine().getStatusCode() == 200));
} finally {
IOUtils.closeQuietly(resp);
}
}
private static final class UpdateChecker implements Runnable {
@Override
public void run() {
DaoEntity meta = DaoSerializer.fromZipBson(pool.executeToByteArray(new HttpGet(host + "update/version")));
String newVersion = DaoSerializer.getString(meta, "version");
if (NullUtils.isNotEqual(newVersion, version)) {
LOG.info("New version found, {}, downloading...", newVersion);
byte[] jar = pool.executeToByteArray(new HttpGet(host + "update"));
if (CollectionUtils.length(jar) == DaoSerializer.getInteger(meta, "size") && NullUtils.isEqual(DigestUtils.md5Hex(jar), DaoSerializer.getString(meta, "checksum"))) {
LOG.info("Update downloaded, writing jar and restarting...");
ResourceLoader.writeFile(WORKING_DIR + "lantern-currentmonitor.jar", jar);
try {
Runtime.getRuntime().exec("service currentmonitor restart");
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
}
}
}
}
private static final class CommandChecker implements Runnable {
@Override
public void run() {
HttpGet get = new HttpGet(host + "command");
get.addHeader("auth_code", authCode);
DaoEntity meta = DaoSerializer.fromZipBson(pool.executeToByteArray(get));
for (String command : DaoSerializer.getList(meta, "commands", String.class)) {
if (NullUtils.isEqual(command, "log")) {
uploadLog();
}
else if (NullUtils.makeNotNull(command).startsWith("timeout")) {
LOG.info("Updating timeouts...");
String[] timeouts = NullUtils.cleanSplit(command, "-");
if (CollectionUtils.size(timeouts) != 3)
continue;
config.setConnectTimeout(DaoSerializer.toInteger(timeouts[1]));
config.setSocketTimeout(DaoSerializer.toInteger(timeouts[2]));
HttpPool old = pool;
pool = new HttpPool(10, 10, config.getSocketTimeout(), config.getConnectTimeout(), config.getSocketTimeout());
old.shutdown();
ResourceLoader.writeFile(WORKING_DIR+"config.json", DaoSerializer.toJson(config));
}
else if (NullUtils.isEqual(command, "extend_filesystem")) {
LOG.info("Extending filesystem and rebooting");
try {
Runtime.getRuntime().exec("raspi-config --expand-rootfs");
ConcurrencyUtils.sleep(3000);
Runtime.getRuntime().exec("reboot");
} catch (IOException _e) {
LOG.error("Exception occurred while trying to extend filesystem", _e);
}
}
else if (NullUtils.isEqual(command, "restart")) {
LOG.info("Restarting...");
try {
Runtime.getRuntime().exec("service currentmonitor restart");
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
}
}
}
}
private static String getVersionNumber() {
InputStream is = null;
try {
is = MonitorApp.class.getResourceAsStream("/META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(is);
Attributes attr = manifest.getMainAttributes();
String version = attr.getValue("Specification-Version");
LOG.info("Current Version: {}", version);
return version;
}
catch (Exception _e) {
LOG.error("Failed to get current version number", _e);
return "";
}
finally {
IOUtils.closeQuietly(is);
}
}
}

View File

@ -0,0 +1,97 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
@DBSerializable
public class MonitorConfig {
private String host;
private String authCode;
private String username;
private String password;
private int hub;
private boolean debug;
private int connectTimeout;
private int socketTimeout;
private int updateInterval;
public MonitorConfig() {
}
public MonitorConfig(int _hub, String _host) {
hub = _hub;
host = _host;
}
public String getHost() {
return host;
}
public void setHost(String _host) {
host = _host;
}
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String _authCode) {
authCode = _authCode;
}
public String getUsername() {
return username;
}
public void setUsername(String _username) {
username = _username;
}
public String getPassword() {
return password;
}
public void setPassword(String _password) {
password = _password;
}
public int getHub() {
return hub;
}
public void setHub(int _hub) {
hub = _hub;
}
public boolean isDebug() {
return debug;
}
public void setDebug(boolean _debug) {
debug = _debug;
}
public int getConnectTimeout() {
return connectTimeout == 0?3000:connectTimeout;
}
public void setConnectTimeout(int _connectTimeout) {
connectTimeout = _connectTimeout;
}
public int getSocketTimeout() {
return socketTimeout == 0?5000:socketTimeout;
}
public void setSocketTimeout(int _socketTimeout) {
socketTimeout = _socketTimeout;
}
public int getUpdateInterval() {
return updateInterval == 0?300:updateInterval;
}
public void setUpdateInterval(int _updateInterval) {
updateInterval = _updateInterval;
}
}

View File

@ -0,0 +1,7 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
public interface PowerListener {
void onPowerEvent(BreakerPower _power);
}

View File

@ -0,0 +1,6 @@
package com.lanternsoftware.currentmonitor;
public class PowerSample {
public double voltage;
public double current;
}

View File

@ -0,0 +1,90 @@
package com.lanternsoftware.currentmonitor.bluetooth;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.interfaces.DBusInterface;
import org.freedesktop.dbus.interfaces.Properties;
import org.freedesktop.dbus.types.Variant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class AbstractProperties implements Properties {
protected final String interfaceName;
protected final Map<String, Variant<?>> properties = new HashMap<>();
public AbstractProperties(Class<? extends DBusInterface> _bleClass) {
interfaceName = _bleClass.getCanonicalName();
}
public String getInterfaceName() {
return interfaceName;
}
public abstract DBusPath getPath();
@SuppressWarnings("unchecked")
@Override
public <A> A Get(String _interface, String _propertyName) {
if (NullUtils.isNotEqual(_interface, interfaceName))
return null;
Variant<?> var = properties.get(_propertyName);
try {
return (A) var.getValue();
}
catch (ClassCastException _e) {
return null;
}
}
@SuppressWarnings("unchecked")
@Override
public <A> void Set(String _interface, String _propertyName, A _value) {
if ((_value == null) || NullUtils.isNotEqual(_interface, interfaceName))
return;
properties.put(_propertyName, new Variant(_value));
}
@Override
public Map<String, Variant<?>> GetAll(String _interfaceName) {
if (NullUtils.isNotEqual(_interfaceName, getInterfaceName()))
return new HashMap<>();
return getProperties();
}
public Map<String, Variant<?>> getProperties() {
return properties;
}
public List<AbstractProperties> getAllObjects() {
List<AbstractProperties> objects = new ArrayList<>();
getAllObjects(objects);
return objects;
}
public void getAllObjects(List<AbstractProperties> _objects) {
_objects.add(this);
for (AbstractProperties o : CollectionUtils.makeNotNull(getChildObjects())) {
o.getAllObjects(_objects);
}
}
public List<? extends AbstractProperties> getChildObjects() {
return null;
}
public Map<DBusPath, Map<String, Map<String, Variant<?>>>> getAllManagedObjects() {
return getAllManagedObjects(getAllObjects());
}
public static Map<DBusPath, Map<String, Map<String, Variant<?>>>> getAllManagedObjects(List<AbstractProperties> _objects) {
Map<DBusPath, Map<String, Map<String, Variant<?>>>> objects = new HashMap<>();
for (AbstractProperties o : _objects) {
objects.put(o.getPath(), CollectionUtils.asHashMap(o.getInterfaceName(), o.getProperties()));
}
return objects;
}
}

View File

@ -0,0 +1,69 @@
package com.lanternsoftware.currentmonitor.bluetooth;
import com.lanternsoftware.util.CollectionUtils;
import org.bluez.LEAdvertisement1;
import org.bluez.LEAdvertisingManager1;
import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.interfaces.Properties;
import org.freedesktop.dbus.types.Variant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
public class BleAdvertisement extends AbstractProperties implements LEAdvertisement1, Properties {
private static final Logger LOG = LoggerFactory.getLogger(BleAdvertisement.class);
private final LEAdvertisingManager1 advertiser;
private final DBusPath advertisementPath;
public BleAdvertisement(String _name, BleApplication _app) {
super(LEAdvertisement1.class);
String[] serviceUUIDs = CollectionUtils.transform(_app.getServices(), _s->_s.getUuid().toString()).toArray(new String[0]);
advertisementPath = new DBusPath(BleHelper.advertismentPath(_app.getName()));
advertiser = BleHelper.getRemoteObject(BleHelper.getAdapter().getDbusPath(), LEAdvertisingManager1.class);
properties.put("Type", new Variant<>("peripheral"));
properties.put("ServiceUUIDs", new Variant<>(serviceUUIDs));
properties.put("LocalName", new Variant<>(_name));
properties.put("Includes", new Variant<>(new String[]{"tx-power"}));
BleHelper.unExportObject(this);
BleHelper.exportObject(this);
}
public void start() {
try {
advertiser.RegisterAdvertisement(advertisementPath, new HashMap<>());
}
catch (Exception _e) {
LOG.error("Failed to register advertisement", _e);
}
}
public void stop() {
try {
advertiser.UnregisterAdvertisement(advertisementPath);
}
catch (Exception _e) {
LOG.error("Failed to unregister advertisement", _e);
}
}
@Override
public boolean isRemote() {
return false;
}
@Override
public String getObjectPath() {
return advertisementPath.getPath();
}
@Override
public DBusPath getPath() {
return advertisementPath;
}
@Override
public void Release() {
}
}

View File

@ -0,0 +1,90 @@
package com.lanternsoftware.currentmonitor.bluetooth;
import com.lanternsoftware.util.CollectionUtils;
import org.bluez.GattApplication1;
import org.bluez.GattManager1;
import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.interfaces.ObjectManager;
import org.freedesktop.dbus.types.Variant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BleApplication implements GattApplication1, ObjectManager {
private static final Logger LOG = LoggerFactory.getLogger(BleApplication.class);
private final String name;
private final DBusPath appPath;
private final GattManager1 appManager;
private final List<BleService> services;
private final BleAdvertisement advertisement;
public BleApplication(String _name, String _advertisedName, BleService... _services) {
this(_name, _advertisedName, CollectionUtils.asArrayList(_services));
}
public BleApplication(String _name, String _advertisedName, List<BleService> _services) {
name = _name;
appPath = new DBusPath(BleHelper.applicationPath(_name));
appManager = BleHelper.getRemoteObject(BleHelper.getAdapter().getDbusPath(), GattManager1.class);
services = _services;
advertisement = new BleAdvertisement(_advertisedName, this);
List<AbstractProperties> objects = getManagedObjects();
BleHelper.unExportObject(this);
objects.forEach(BleHelper::unExportObject);
BleHelper.exportObject(this);
objects.forEach(BleHelper::exportObject);
}
public List<AbstractProperties> getManagedObjects() {
return CollectionUtils.aggregate(services, AbstractProperties::getAllObjects);
}
public String getName() {
return name;
}
public List<BleService> getServices() {
return services;
}
@Override
public Map<DBusPath, Map<String, Map<String, Variant<?>>>> GetManagedObjects() {
return AbstractProperties.getAllManagedObjects(getManagedObjects());
}
public void start() {
try {
appManager.RegisterApplication(appPath, new HashMap<>());
advertisement.start();
}
catch (Exception _e) {
LOG.error("Failed to register application", _e);
_e.printStackTrace();
}
}
public void stop() {
try {
advertisement.stop();
appManager.UnregisterApplication(appPath);
BleHelper.connection.disconnect();
}
catch (Exception _e) {
LOG.error("Failed to unregister application", _e);
}
}
@Override
public boolean isRemote() {
return false;
}
@Override
public String getObjectPath() {
return appPath.getPath();
}
}

View File

@ -0,0 +1,121 @@
package com.lanternsoftware.currentmonitor.bluetooth;
import com.lanternsoftware.datamodel.currentmonitor.CharacteristicFlag;
import com.lanternsoftware.util.CollectionUtils;
import org.bluez.GattCharacteristic1;
import org.bluez.datatypes.TwoTuple;
import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.FileDescriptor;
import org.freedesktop.dbus.types.UInt16;
import org.freedesktop.dbus.types.Variant;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class BleCharacteristic extends AbstractProperties implements GattCharacteristic1 {
private final String charName;
private final DBusPath charPath;
private final UUID uuid;
private final List<BleDescriptor> descriptors;
private BleCharacteristicListener listener;
public BleCharacteristic(String _serviceName, UUID _uuid, String _characteristicName, Collection<CharacteristicFlag> _flags) {
this(_serviceName, _uuid, _characteristicName, _flags, null);
}
public BleCharacteristic(String _serviceName, UUID _uuid, String _characteristicName, Collection<CharacteristicFlag> _flags, List<BleDescriptor> _descriptors) {
super(GattCharacteristic1.class);
charName = _characteristicName;
charPath = new DBusPath(BleHelper.characteristicPath(_serviceName, _characteristicName));
uuid = _uuid;
descriptors = _descriptors;
properties.put("Service", new Variant<>(new DBusPath(BleHelper.servicePath(_serviceName))));
if (uuid != null)
properties.put("UUID", new Variant<>(uuid.toString()));
if (CollectionUtils.isNotEmpty(_flags))
properties.put("Flags", new Variant<>(CharacteristicFlag.toArray(_flags)));
if (CollectionUtils.isNotEmpty(descriptors))
properties.put("Descriptors", new Variant<>(BleHelper.toPaths(descriptors)));
}
public void setListener(BleCharacteristicListener _listener) {
listener = _listener;
}
@Override
public List<? extends AbstractProperties> getChildObjects() {
return descriptors;
}
@Override
public boolean isRemote() {
return false;
}
public DBusPath getPath() {
return charPath;
}
@Override
public String getObjectPath() {
return charPath.getPath();
}
@Override
public byte[] ReadValue(Map<String, Variant<?>> _options) {
if (listener == null)
return null;
int offset = 0;
Variant<?> voffset = _options.get("offset");
if (voffset != null) {
if (voffset.getValue() instanceof UInt16)
offset = ((UInt16)voffset.getValue()).intValue();
}
byte[] ret = listener.read(charName);
if (ret == null)
return null;
return offset > 0?Arrays.copyOfRange(ret, offset, ret.length):ret;
}
@Override
public void WriteValue(byte[] _bytes, Map<String, Variant<?>> _map) {
if (listener != null)
listener.write(charName, _bytes);
}
@Override
public TwoTuple<FileDescriptor, UInt16> AcquireWrite(Map<String, Variant<?>> _map) {
return null;
}
@Override
public TwoTuple<FileDescriptor, UInt16> AcquireNotify(Map<String, Variant<?>> _map) {
return null;
}
@Override
public void StartNotify() {
}
@Override
public void StopNotify() {
}
@Override
public void Confirm() {
}
public UUID getUuid() {
return uuid;
}
public List<BleDescriptor> getDescriptors() {
return descriptors;
}
}

View File

@ -0,0 +1,6 @@
package com.lanternsoftware.currentmonitor.bluetooth;
public interface BleCharacteristicListener {
void write(String _name, byte[] _value);
byte[] read(String _name);
}

View File

@ -0,0 +1,32 @@
package com.lanternsoftware.currentmonitor.bluetooth;
import org.bluez.GattDescriptor1;
import org.freedesktop.dbus.DBusPath;
import java.util.UUID;
public class BleDescriptor extends AbstractProperties {
private final DBusPath charPath;
private final UUID uuid;
public BleDescriptor(String _serviceName, String _characteristicName, String _descriptorName, UUID _uuid) {
super(GattDescriptor1.class);
charPath = new DBusPath(BleHelper.descriptorPath(_serviceName, _characteristicName, _descriptorName));
uuid = _uuid;
}
@Override
public DBusPath getPath() {
return charPath;
}
@Override
public boolean isRemote() {
return false;
}
@Override
public String getObjectPath() {
return charPath.getPath();
}
}

View File

@ -0,0 +1,115 @@
package com.lanternsoftware.currentmonitor.bluetooth;
import com.github.hypfvieh.bluetooth.DeviceManager;
import com.github.hypfvieh.bluetooth.wrapper.BluetoothAdapter;
import com.lanternsoftware.util.CollectionUtils;
import org.freedesktop.dbus.connections.impl.DBusConnection;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.interfaces.DBusInterface;
import org.freedesktop.dbus.interfaces.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
public abstract class BleHelper {
private static final Logger LOG = LoggerFactory.getLogger(BleHelper.class);
private static String basePath;
private static final DeviceManager deviceManager;
public static final DBusConnection connection;
static {
DeviceManager m = null;
DBusConnection c = null;
try {
DeviceManager.createInstance(false);
m = DeviceManager.getInstance();
c = m.getDbusConnection();
}
catch (Exception _e) {
LOG.error("Failed to get dbus connection", _e);
}
deviceManager = m;
connection = c;
}
public static void setBasePath(String _basePath) {
basePath = _basePath;
}
public static String getBasePath() {
return basePath;
}
public static String advertismentPath(String _advertisementName) {
return BleHelper.getBasePath() + "/advertisement/" + _advertisementName;
}
public static String applicationPath(String _appPath) {
return BleHelper.getBasePath() + "/application/" + _appPath;
}
public static String servicePath(String _serviceName) {
return BleHelper.getBasePath() + "/service/" + _serviceName;
}
public static String characteristicPath(String _serviceName, String _characteristicName) {
return servicePath(_serviceName) + "/" + _characteristicName;
}
public static String descriptorPath(String _serviceName, String _characteristicName, String _descriptorPath) {
return servicePath(_serviceName) + "/" + _characteristicName + "/" + _descriptorPath;
}
public static String[] toPaths(List<? extends AbstractProperties> _properties) {
return CollectionUtils.transform(_properties, Properties::getObjectPath).toArray(new String[0]);
}
public static BluetoothAdapter getAdapter() {
return (deviceManager != null)?deviceManager.getAdapter():null;
}
public static void requestBusName(String _name) {
try {
if (connection != null)
connection.requestBusName(_name);
}
catch (Exception _e) {
LOG.error("Failed to request bus name", _e);
}
}
public static <T extends DBusInterface> T getRemoteObject(String _path, Class<T> _objClass) {
try {
return connection.getRemoteObject("org.bluez", _path, _objClass);
} catch (DBusException _e) {
LOG.error("Failed to get remote object", _e);
return null;
}
}
public static void exportObject(DBusInterface _object) {
try {
if (connection != null)
connection.exportObject(_object.getObjectPath(), _object);
}
catch (Exception _e) {
LOG.error("Failed to export object", _e);
}
}
public static void unExportObject(DBusInterface _object) {
if (_object != null)
unExportObject(_object.getObjectPath());
}
public static void unExportObject(String _objectPath) {
try {
if (connection != null)
connection.unExportObject(_objectPath);
}
catch (Exception _e) {
LOG.error("Failed to unexport object", _e);
}
}
}

View File

@ -0,0 +1,55 @@
package com.lanternsoftware.currentmonitor.bluetooth;
import com.lanternsoftware.util.CollectionUtils;
import org.bluez.GattService1;
import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.types.Variant;
import java.util.List;
import java.util.UUID;
public class BleService extends AbstractProperties implements GattService1 {
private final DBusPath servicePath;
private final UUID uuid;
private final List<BleCharacteristic> characteristics;
public BleService(String _serviceName, UUID _uuid, List<BleCharacteristic> _characteristics) {
super(GattService1.class);
servicePath = new DBusPath(BleHelper.servicePath(_serviceName));
uuid = _uuid;
characteristics = _characteristics;
if (uuid != null)
properties.put("UUID", new Variant<>(uuid.toString()));
properties.put("Primary", new Variant<>(Boolean.TRUE));
if (CollectionUtils.isNotEmpty(characteristics))
properties.put("Characteristics", new Variant<>(BleHelper.toPaths(characteristics)));
}
public DBusPath getPath() {
return servicePath;
}
@Override
public boolean isRemote() {
return false;
}
@Override
public String getObjectPath() {
return getPath().getPath();
}
@Override
public List<? extends AbstractProperties> getChildObjects() {
return characteristics;
}
public UUID getUuid() {
return uuid;
}
public List<BleCharacteristic> getCharacteristics() {
return characteristics;
}
}

View File

@ -0,0 +1,56 @@
package com.lanternsoftware.currentmonitor.dao;
import com.lanternsoftware.currentmonitor.MonitorConfig;
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 MonitorConfigSerializer extends AbstractDaoSerializer<MonitorConfig>
{
@Override
public Class<MonitorConfig> getSupportedClass()
{
return MonitorConfig.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(MonitorConfig _o)
{
DaoEntity d = new DaoEntity();
d.put("host", _o.getHost());
d.put("auth_code", _o.getAuthCode());
d.put("username", _o.getUsername());
d.put("password", _o.getPassword());
d.put("hub", _o.getHub());
d.put("debug", _o.isDebug());
d.put("socket_timeout", _o.getSocketTimeout());
d.put("connect_timeout", _o.getConnectTimeout());
d.put("update_interval", _o.getUpdateInterval());
return d;
}
@Override
public MonitorConfig fromDaoEntity(DaoEntity _d)
{
MonitorConfig o = new MonitorConfig();
o.setHost(DaoSerializer.getString(_d, "host"));
o.setAuthCode(DaoSerializer.getString(_d, "auth_code"));
o.setUsername(DaoSerializer.getString(_d, "username"));
o.setPassword(DaoSerializer.getString(_d, "password"));
o.setHub(DaoSerializer.getInteger(_d, "hub"));
o.setDebug(DaoSerializer.getBoolean(_d, "debug"));
o.setSocketTimeout(DaoSerializer.getInteger(_d, "socket_timeout"));
o.setConnectTimeout(DaoSerializer.getInteger(_d, "connect_timeout"));
o.setUpdateInterval(DaoSerializer.getInteger(_d, "update_interval"));
return o;
}
}

View File

@ -0,0 +1,40 @@
package com.lanternsoftware.currentmonitor.led;
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicBoolean;
public class LEDFlasher implements Runnable {
private static final Logger LOG = LoggerFactory.getLogger(LEDFlasher.class);
private final AtomicBoolean running = new AtomicBoolean(true);
private boolean on = false;
@Override
public void run() {
while (running.get()) {
on = !on;
setLEDOn(on);
ConcurrencyUtils.sleep(250);
}
setLEDOn(false);
}
public void stop() {
running.set(false);
}
public static void setLEDOn(boolean _on) {
try {
if (_on)
Runtime.getRuntime().exec(new String[]{"sh", "-c", "echo default-on > /sys/class/leds/led1/trigger"});
else
Runtime.getRuntime().exec(new String[]{"sh", "-c", "echo none > /sys/class/leds/led1/trigger"});
}
catch (Exception _e) {
LOG.error("Failed to change LED state", _e);
}
}
}

View File

@ -0,0 +1,53 @@
package com.lanternsoftware.currentmonitor.util;
import com.lanternsoftware.datamodel.currentmonitor.NetworkStatus;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class NetworkMonitor {
private static final Logger LOG = LoggerFactory.getLogger(NetworkMonitor.class);
private static final Pattern ethernetPattern = Pattern.compile(".*(eth[0-9]):(.*)");
private static final Pattern wifiPattern = Pattern.compile(".*(wlan[0-9]):(.*)");
public static NetworkStatus getNetworkStatus() {
NetworkStatus status = new NetworkStatus();
String[] commands = {"ifconfig", "-a"};
InputStream is = null;
try {
is = Runtime.getRuntime().exec(commands).getInputStream();
String ifconfig = IOUtils.toString(is);
status.setEthernetIPs(getIPs(ifconfig, ethernetPattern));
status.setWifiIPs(getIPs(ifconfig, wifiPattern));
}
catch (Exception _e) {
LOG.error("Failed to check network state", _e);
}
finally {
IOUtils.closeQuietly(is);
}
return status;
}
private static List<String> getIPs(String _ifConfig, Pattern _pattern) {
List<String> ips = new ArrayList<>();
Matcher m = _pattern.matcher(_ifConfig);
while (m.find()) {
int start = m.start(0);
int ipStart = _ifConfig.indexOf("inet ", start) + 5;
if (ipStart > 4) {
int ipEnd = _ifConfig.indexOf(" ", ipStart);
if (ipEnd > -1)
ips.add(_ifConfig.substring(ipStart, ipEnd));
}
}
return ips;
}
}

View File

@ -0,0 +1,44 @@
package com.lanternsoftware.currentmonitor.wifi;
import com.lanternsoftware.util.ResourceLoader;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
public abstract class WifiConfig {
private static final Logger LOG = LoggerFactory.getLogger(WifiConfig.class);
private static final String WIFI_CONFIG_PATH = "/etc/wpa_supplicant/wpa_supplicant.conf";
private static final String CONF_FORMAT = "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\ncountry=US\nnetwork={\n\tssid=\"%s\"\n\t%s\n}\n";
public static void setCredentials(String _ssid, String _password) {
String[] commands = {"wpa_passphrase", _ssid, _password};
InputStream is = null;
try {
is = Runtime.getRuntime().exec(commands).getInputStream();
String newConf = IOUtils.toString(is);
if (newConf == null)
return;
int idx = newConf.indexOf("psk=");
if (idx > 0) {
if (newConf.charAt(idx-1) == '#')
idx = newConf.indexOf("psk=", idx+1);
if (idx > 0) {
int endIdx = newConf.indexOf("\n", idx);
if (endIdx > 0) {
String finalConf = String.format(CONF_FORMAT, _ssid, newConf.substring(idx, endIdx));
ResourceLoader.writeFile(WIFI_CONFIG_PATH, finalConf);
}
}
}
}
catch (Exception _e) {
LOG.error("Failed to write wifi credentials", _e);
}
finally {
IOUtils.closeQuietly(is);
}
}
}

View File

@ -0,0 +1,6 @@
package org.bluez;
import org.freedesktop.dbus.interfaces.DBusInterface;
public interface GattApplication1 extends DBusInterface {
}

View File

@ -0,0 +1 @@
com.lanternsoftware.currentmonitor.dao.MonitorConfigSerializer

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/opt/currentmonitor/log/log.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/opt/currentmonitor/log/log.%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<maxFileSize>20MB</maxFileSize>
<maxHistory>20</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<logger name="com.lanternsoftware" level="INFO"/>
<root level="OFF">
<appender-ref ref="FILE"/>
</root>
</configuration>

View File

@ -0,0 +1,15 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoSerializer;
public class CreateConfig {
public static void main(String[] args) {
// MonitorConfig c = new MonitorConfig(0, "https://mark.lanternsoftware.com/currentmonitor");
MonitorConfig c = new MonitorConfig(1, "https://mark.lanternsoftware.com/currentmonitor");
c.setDebug(true);
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "hub1.json", DaoSerializer.toJson(c));
}
}

View File

@ -0,0 +1,9 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.cryptography.AESTool;
public class CreateSSIDKey {
public static void main(String[] args) {
AESTool.printRandomSecretKey();
}
}

View File

@ -0,0 +1,11 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.dao.generator.DaoSerializerGenerator;
public class CurrentMonitorAppSerializers {
public static void main(String[] args) {
DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_PATH + "currentmonitor", true, null);
}
}

View File

@ -0,0 +1,10 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.currentmonitor.util.NetworkMonitor;
import com.lanternsoftware.datamodel.currentmonitor.NetworkStatus;
public class NetworkTest {
public static void main(String[] args) {
NetworkStatus status = NetworkMonitor.getNetworkStatus();
}
}

View File

@ -0,0 +1,38 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.xml.XmlNode;
import com.lanternsoftware.util.xml.XmlParser;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
public class ReleaseCurrentMonitor {
public static void main(String[] args) {
XmlNode pom = XmlParser.loadXmlFile(LanternFiles.SOURCE_PATH + "currentmonitor" + File.separator + "lantern-currentmonitor" + File.separator + "pom.xml");
if (pom == null)
return;
XmlNode versionNode = pom.getChild(Collections.singletonList("version"));
String version = versionNode.getContent();
ProcessBuilder builder = new ProcessBuilder();
builder.directory(new File(LanternFiles.SOURCE_PATH));
builder.command("cmd.exe", "/c", "mvn clean install");
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
try {
Process process = builder.start();
int exitCode = process.waitFor();
assert exitCode == 0;
} catch (Exception _e) {
_e.printStackTrace();
}
byte[] jar = ResourceLoader.loadFile(LanternFiles.SOURCE_PATH + "currentmonitor" + File.separator + "lantern-currentmonitor" + File.separator + "target" + File.separator + "lantern-currentmonitor.jar");
DaoEntity meta = new DaoEntity("version", version).and("size", jar.length).and("checksum", DigestUtils.md5Hex(jar));
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "release" + File.separator + "lantern-currentmonitor.jar", jar);
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "release" + File.separator + "version.json", DaoSerializer.toJson(meta));
}
}

View File

@ -0,0 +1,83 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-dataaccess-currentmonitor</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<name>lantern-dataaccess-currentmonitor</name>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-datamodel-currentmonitor</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-dao-mongo</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<executions>
<execution>
<goals>
<goal>testCompile</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<optimize>true</optimize>
<showDeprecation>true</showDeprecation>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<index>true</index>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,45 @@
package com.lanternsoftware.dataaccess.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.datamodel.currentmonitor.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.HubPowerMinute;
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 {
void shutdown();
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);
void putBreakerGroupEnergy(BreakerGroupEnergy _energy);
void putHubPowerMinute(HubPowerMinute _power);
BreakerConfig getConfig(int _accountId);
BreakerConfig getMergedConfig(AuthCode _authCode);
void putConfig(BreakerConfig _config);
void updateSummaries(BreakerGroup _rootGroup, Set<Date> _daysToSummarize, TimeZone _tz);
String authenticateAccount(String _username, String _password);
String getAuthCodeForEmail(String _email);
Account authCodeToAccount(String _authCode);
AuthCode decryptAuthCode(String _authCode);
Account putAccount(Account _account);
Account getAccount(int _accountId);
Account getAccountByUsername(String _username);
MongoProxy getProxy();
}

View File

@ -0,0 +1,57 @@
package com.lanternsoftware.dataaccess.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Date;
@DBSerializable(autogen = false)
public class DirtyMinute {
private int accountId;
private int minute;
private Date posted;
public DirtyMinute() {
}
public DirtyMinute(int _accountId, int _minute, Date _posted) {
accountId = _accountId;
minute = _minute;
posted = _posted;
}
public String getId() {
return accountId + "-" + minute;
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public Date getMinuteAsDate() {
return new Date(((long)minute)*60000);
}
public int getMinute() {
return minute;
}
public void setMinute(int _minute) {
minute = _minute;
}
public void setMinute(Date _minute) {
minute = (int)(_minute.getTime()/60000);
}
public Date getPosted() {
return posted;
}
public void setPosted(Date _posted) {
posted = _posted;
}
}

View File

@ -0,0 +1,273 @@
package com.lanternsoftware.dataaccess.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
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.HubPowerMinute;
import com.lanternsoftware.datamodel.currentmonitor.Sequence;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.DebugTimer;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.cryptography.AESTool;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoQuery;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.DaoSort;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import com.lanternsoftware.util.dao.mongo.MongoProxy;
import org.mindrot.jbcrypt.BCrypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
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 MongoCurrentMonitorDao implements CurrentMonitorDao {
private static final Logger logger = LoggerFactory.getLogger(MongoCurrentMonitorDao.class);
private static final AESTool aes = new AESTool(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "authKey.dat"));
private static final int BCRYPT_ROUNDS = 11;
private final Timer delayTimer = new Timer();
private final ExecutorService executor = Executors.newCachedThreadPool();
private final MongoProxy proxy;
public MongoCurrentMonitorDao(MongoConfig _config) {
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"));
proxy.ensureIndex(DirtyMinute.class, DaoSort.sort("posted"));
for (DirtyMinute minute : proxy.queryAll(DirtyMinute.class)) {
updateSummaries(minute);
}
proxy.delete(DirtyMinute.class, new DaoQuery());
}
public void shutdown() {
delayTimer.cancel();
executor.shutdownNow();
proxy.shutdown();
}
@Override
public void putBreakerPower(BreakerPower _power) {
proxy.save(_power);
}
@Override
public void putHubPowerMinute(HubPowerMinute _power) {
if (_power == null)
return;
proxy.save(_power);
DirtyMinute minute = new DirtyMinute(_power.getAccountId(), _power.getMinute(), new Date());
proxy.save(minute);
delayTimer.schedule(new TimerTask(){
@Override
public void run() {
executor.submit(()->{
if (proxy.queryOneAndDelete(DirtyMinute.class, new DaoQuery("_id", minute.getId())) != null)
updateSummaries(new DirtyMinute(_power.getAccountId(), _power.getMinute(), new Date()));
});
}
}, 10000);
}
private void updateSummaries(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 = TimeZone.getTimeZone("America/Chicago");
BreakerConfig config = getConfig(_minute.getAccountId());
BreakerGroup group = CollectionUtils.getFirst(config.getBreakerGroups());
Date day = DateUtils.getMidnightBefore(_minute.getMinuteAsDate(), tz);
BreakerGroupEnergy summary = getBreakerGroupEnergy(_minute.getAccountId(), group.getId(), EnergyBlockViewMode.DAY, day);
if (summary == null)
summary = new BreakerGroupEnergy(group, minutes, EnergyBlockViewMode.DAY, day, tz);
else
summary.addEnergy(group, minutes, tz);
putBreakerGroupEnergy(summary);
updateSummaries(group, CollectionUtils.asHashSet(day), tz);
timer.stop();
}
@Override
public List<BreakerPower> getBreakerPowerForAccount(int _accountId) {
return proxy.query(BreakerPower.class, new DaoQuery("account_id", _accountId));
}
@Override
public BreakerPower getLatestBreakerPower(int _accountId, int _panel, int _space) {
return proxy.queryOne(BreakerPower.class, new DaoQuery("account_id", _accountId).and("key", Breaker.key(_panel, _space)), DaoSort.sortDesc("read_time"));
}
@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)));
}
@Override
public void updateSummaries(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) {
Calendar calDayStart = DateUtils.toCalendar(month, _tz);
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()));
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);
}
for (Date year : yearsToSummarize) {
Calendar calMonthStart = DateUtils.toCalendar(year, _tz);
Calendar end = DateUtils.getEndOfYearCal(year, _tz);
List<String> groupEnergyIds = new ArrayList<>();
while (calMonthStart.before(end)) {
groupEnergyIds.add(BreakerGroupEnergy.toId(_rootGroup.getAccountId(), _rootGroup.getId(), EnergyBlockViewMode.MONTH, calMonthStart.getTime()));
calMonthStart.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.YEAR, year, _tz);
putBreakerGroupEnergy(summary);
}
List<BreakerGroupSummary> groupEnergies = CollectionUtils.aggregate(proxy.query(BreakerGroupSummary.class, new DaoQuery("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);
}
@Override
public void putBreakerGroupEnergy(BreakerGroupEnergy _energy) {
proxy.save(_energy);
proxy.save(new BreakerGroupSummary(_energy));
}
@Override
public BreakerConfig getConfig(int _accountId) {
return proxy.queryOne(BreakerConfig.class, new DaoQuery("_id", String.valueOf(_accountId)));
}
@Override
public BreakerConfig getMergedConfig(AuthCode _authCode) {
if (_authCode == null)
return null;
List<BreakerConfig> configs = CollectionUtils.transform(_authCode.getAllAccountIds(), this::getConfig, true);
BreakerConfig config = new BreakerConfig();
config.setAccountId(_authCode.getAccountId());
config.setBreakerHubs(CollectionUtils.aggregate(configs, BreakerConfig::getBreakerHubs));
config.setBreakerGroups(CollectionUtils.aggregate(configs, BreakerConfig::getBreakerGroups));
config.setPanels(CollectionUtils.aggregate(configs, BreakerConfig::getPanels));
config.setMeters(CollectionUtils.aggregate(configs, BreakerConfig::getMeters));
return config;
}
@Override
public void putConfig(BreakerConfig _config) {
DaoQuery configQuery = new DaoQuery("_id", String.valueOf(_config.getAccountId()));
BreakerConfig oldConfig = proxy.queryOne(BreakerConfig.class, configQuery);
if (oldConfig != null)
proxy.delete(BreakerGroup.class, DaoQuery.in("_id", oldConfig.getAllBreakerGroupIds()));
proxy.save(_config);
}
@Override
public String authenticateAccount(String _username, String _password) {
Account acct = proxy.queryOne(Account.class, new DaoQuery("username", _username));
if ((acct == null) || !BCrypt.checkpw(_password, acct.getPassword()))
return null;
return aes.encryptToBase64(DaoSerializer.toZipBson(new AuthCode(acct.getId(), acct.getAuxiliaryAccountIds())));
}
@Override
public Account authCodeToAccount(String _authCode) {
AuthCode code = decryptAuthCode(_authCode);
if (code == null)
return null;
return proxy.queryOne(Account.class, new DaoQuery("_id", code.getAccountId()));
}
@Override
public AuthCode decryptAuthCode(String _authCode) {
return DaoSerializer.fromZipBson(aes.decryptFromBase64(_authCode), AuthCode.class);
}
@Override
public String getAuthCodeForEmail(String _email) {
_email = _email.toLowerCase().trim();
Account account = getAccountByUsername(_email);
if (account == null) {
account = new Account();
account.setUsername(_email);
putAccount(account);
}
return aes.encryptToBase64(DaoSerializer.toZipBson(new AuthCode(account.getId(), account.getAuxiliaryAccountIds())));
}
@Override
public Account putAccount(Account _account) {
if (_account == null)
return null;
_account.setUsername(NullUtils.makeNotNull(_account.getUsername()).toLowerCase().trim());
Account account = getAccountByUsername(_account.getUsername());
if (account != null) {
_account.setId(account.getId());
if (NullUtils.isEmpty(_account.getPassword()))
_account.setPassword(account.getPassword());
else
_account.setPassword(BCrypt.hashpw(_account.getPassword(), BCrypt.gensalt(BCRYPT_ROUNDS)));
}
else if (NullUtils.isNotEmpty(_account.getPassword())) {
_account.setPassword(BCrypt.hashpw(_account.getPassword(), BCrypt.gensalt(BCRYPT_ROUNDS)));
}
if (_account.getId() == 0)
_account.setId(proxy.updateOne(Sequence.class, null, new DaoEntity("$inc", new DaoEntity("sequence", 1))).getSequence());
proxy.save(_account);
return clearPassword(_account);
}
@Override
public Account getAccount(int _accountId) {
return clearPassword(proxy.queryOne(Account.class, new DaoQuery("_id", String.valueOf(_accountId))));
}
@Override
public Account getAccountByUsername(String _username) {
return clearPassword(proxy.queryOne(Account.class, new DaoQuery("username", NullUtils.makeNotNull(_username).toLowerCase().trim())));
}
private Account clearPassword(Account _account) {
if (_account == null)
return null;
_account.setPassword(null);
return _account;
}
@Override
public MongoProxy getProxy() {
return proxy;
}
}

View File

@ -0,0 +1,44 @@
package com.lanternsoftware.dataaccess.currentmonitor.dao;
import com.lanternsoftware.dataaccess.currentmonitor.DirtyMinute;
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 DirtyMinuteSerializer extends AbstractDaoSerializer<DirtyMinute>
{
@Override
public Class<DirtyMinute> getSupportedClass()
{
return DirtyMinute.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(DirtyMinute _o)
{
DaoEntity d = new DaoEntity();
d.put("_id", _o.getId());
d.put("account_id", _o.getAccountId());
d.put("minute", _o.getMinute());
d.put("posted", DaoSerializer.toLong(_o.getPosted()));
return d;
}
@Override
public DirtyMinute fromDaoEntity(DaoEntity _d)
{
DirtyMinute o = new DirtyMinute();
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setMinute(DaoSerializer.getInteger(_d, "minute"));
o.setPosted(DaoSerializer.getDate(_d, "posted"));
return o;
}
}

View File

@ -0,0 +1 @@
com.lanternsoftware.dataaccess.currentmonitor.dao.DirtyMinuteSerializer

View File

@ -0,0 +1,73 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-datamodel-currentmonitor</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<name>lantern-datamodel-currentmonitor</name>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-dao</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<executions>
<execution>
<goals>
<goal>testCompile</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<optimize>true</optimize>
<showDeprecation>true</showDeprecation>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<index>true</index>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,46 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import com.lanternsoftware.util.dao.annotations.PrimaryKey;
import java.util.List;
@DBSerializable(autogen = false)
public class Account {
@PrimaryKey private int id;
private String username;
private String password;
private List<Integer> auxiliaryAccountIds;
public int getId() {
return id;
}
public void setId(int _id) {
id = _id;
}
public String getUsername() {
return username;
}
public void setUsername(String _username) {
username = _username;
}
public String getPassword() {
return password;
}
public void setPassword(String _password) {
password = _password;
}
public List<Integer> getAuxiliaryAccountIds() {
return auxiliaryAccountIds;
}
public void setAuxiliaryAccountIds(List<Integer> _auxiliaryAccountIds) {
auxiliaryAccountIds = _auxiliaryAccountIds;
}
}

View File

@ -0,0 +1,49 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.ArrayList;
import java.util.List;
@DBSerializable(autogen = false)
public class AuthCode {
private int accountId;
private List<Integer> auxiliaryAccountIds;
public AuthCode() {
}
public AuthCode(int _accountId, List<Integer> _auxiliaryAccountIds) {
accountId = _accountId;
auxiliaryAccountIds = _auxiliaryAccountIds;
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public List<Integer> getAuxiliaryAccountIds() {
return auxiliaryAccountIds;
}
public void setAuxiliaryAccountIds(List<Integer> _auxiliaryAccountIds) {
auxiliaryAccountIds = _auxiliaryAccountIds;
}
public List<Integer> getAllAccountIds() {
List<Integer> ids = new ArrayList<>();
ids.add(accountId);
if (auxiliaryAccountIds != null)
ids.addAll(auxiliaryAccountIds);
return ids;
}
public boolean isAuthorized(int _accountId) {
return accountId == _accountId || CollectionUtils.contains(auxiliaryAccountIds, _accountId);
}
}

View File

@ -0,0 +1,232 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
@DBSerializable()
public class Breaker {
private static final int TANDEM_BREAKER_MASK = 3072;
private static final int SPACE_MASK = 1023;
private static final int TANDEM_BREAKER_A_MASK = 1024;
private static final int TANDEM_BREAKER_B_MASK = 2048;
private int panel;
private int space;
private int meter;
private int hub;
private int port;
private String name;
private String description;
private int sizeAmps;
private double calibrationFactor;
private double lowPassFilter;
private BreakerPolarity polarity;
private BreakerType type;
private transient String key;
public Breaker() {
}
public Breaker(String _name, int _panel, int _space, int _hub, int _port, int _sizeAmps, double _lowPassFilter) {
name = _name;
panel = _panel;
space = _space;
hub = _hub;
port = _port;
sizeAmps = _sizeAmps;
lowPassFilter = _lowPassFilter;
}
public int getPanel() {
return panel;
}
public void setPanel(int _panel) {
panel = _panel;
key = null;
}
public int getSpace() {
return space;
}
public void setSpace(int _space) {
space = _space;
key = null;
}
public int getMeter() {
return meter;
}
public void setMeter(int _meter) {
meter = _meter;
}
public String getSpaceDisplay() {
return toSpaceDisplay(space);
}
public void setSpaceTandemA(int _space) {
space = TANDEM_BREAKER_A_MASK | _space;
}
public void setSpaceTandemB(int _space) {
space = TANDEM_BREAKER_B_MASK | _space;
}
public boolean isTandemBreaker() {
return (TANDEM_BREAKER_MASK & space) != 0;
}
public boolean isTandemBreakerA() {
return isTandemBreakerA(space);
}
public boolean isTandemBreakerB() {
return isTandemBreakerB(space);
}
public String getName() {
return name;
}
public void setName(String _name) {
name = _name;
}
public String getDescription() {
return description;
}
public void setDescription(String _description) {
description = _description;
}
public int getHub() {
return hub;
}
public void setHub(int _hub) {
hub = _hub;
}
public int getPort() {
return port;
}
public void setPort(int _port) {
port = _port;
}
public int getChip() {
return portToChip(port);
}
public int getPin() {
return portToPin(port);
}
public int getSizeAmps() {
return sizeAmps;
}
public void setSizeAmps(int _sizeAmps) {
sizeAmps = _sizeAmps;
}
public double getLowPassFilter() {
return lowPassFilter;
}
public void setLowPassFilter(double _lowPassFilter) {
lowPassFilter = _lowPassFilter;
}
public BreakerPolarity getPolarity() {
return polarity;
}
public void setPolarity(BreakerPolarity _polarity) {
polarity = _polarity;
}
public double getCalibrationFactor() {
return calibrationFactor == 0.0?1.0:calibrationFactor;
}
public void setCalibrationFactor(double _calibrationFactor) {
calibrationFactor = _calibrationFactor;
}
public BreakerType getType() {
if (type == null) {
if (isTandemBreaker())
return BreakerType.SINGLE_POLE_TANDEM;
return BreakerType.SINGLE_POLE;
}
return type;
}
public void setType(BreakerType _type) {
type = _type;
}
public double getFinalCalibrationFactor() {
return getCalibrationFactor() * getSizeAmps() / 380.0;
}
public String getKey() {
if (key == null)
key = key(panel, space);
return key;
}
public static String key(int _panel, int _space) {
return String.format("%d-%d", _panel, _space);
}
public static int portToChip(int _port) {
return (_port < 9)?1:0;
}
public static int portToPin(int _port) {
return (_port < 9)?_port-1:_port-8;
}
public static int toPort(int _chip, int _pin) {
return (_chip == 0)?_pin+8:_pin+1;
}
public static boolean isTandemBreakerA(int _space) {
return (TANDEM_BREAKER_A_MASK & _space) != 0;
}
public static boolean isTandemBreakerB(int _space) {
return (TANDEM_BREAKER_B_MASK & _space) != 0;
}
public static int toId(int _panel, int _space) {
return (_panel << 12) | _space;
}
public static int toPanel(int _id) {
return _id >> 12;
}
public static int toSpace(int _id) {
return _id & (TANDEM_BREAKER_MASK |SPACE_MASK);
}
public static String toSpaceDisplay(int _space) {
if (isTandemBreakerA(_space))
return String.format("%dA", _space & SPACE_MASK);
if (isTandemBreakerB(_space))
return String.format("%dB", _space & SPACE_MASK);
return String.valueOf(_space);
}
public int getSpaceIndex() {
return space & SPACE_MASK;
}
}

View File

@ -0,0 +1,162 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import com.lanternsoftware.util.dao.annotations.PrimaryKey;
import java.util.ArrayList;
import java.util.List;
@DBSerializable(autogen = false)
public class BreakerConfig {
@PrimaryKey
private int accountId;
private List<Meter> meters;
private List<BreakerPanel> panels;
private List<BreakerHub> breakerHubs;
private List<BreakerGroup> breakerGroups;
public BreakerConfig() {
}
public BreakerConfig(List<BreakerGroup> _breakerGroups) {
breakerGroups = _breakerGroups;
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public List<Meter> getMeters() {
return meters;
}
public void setMeters(List<Meter> _meters) {
meters = _meters;
}
public List<BreakerPanel> getPanels() {
return panels;
}
public void setPanels(List<BreakerPanel> _panels) {
panels = _panels;
}
public List<BreakerHub> getBreakerHubs() {
return breakerHubs;
}
public void setBreakerHubs(List<BreakerHub> _breakerHubs) {
breakerHubs = _breakerHubs;
}
public List<BreakerGroup> getBreakerGroups() {
return breakerGroups;
}
public void setBreakerGroups(List<BreakerGroup> _breakerGroups) {
breakerGroups = _breakerGroups;
}
public List<Breaker> getAllBreakers() {
List<Breaker> allBreakers = new ArrayList<>();
for (BreakerGroup g : CollectionUtils.makeNotNull(breakerGroups)) {
allBreakers.addAll(g.getAllBreakers());
}
return allBreakers;
}
public List<BreakerGroup> getAllBreakerGroups() {
List<BreakerGroup> groups = new ArrayList<>();
for (BreakerGroup g : CollectionUtils.makeNotNull(breakerGroups)) {
groups.addAll(g.getAllBreakerGroups());
}
return groups;
}
public List<String> getAllBreakerGroupIds() {
List<String> ids = new ArrayList<>();
for (BreakerGroup g : CollectionUtils.makeNotNull(breakerGroups)) {
ids.addAll(g.getAllBreakerGroupIds());
}
return ids;
}
public List<Breaker> getBreakersForHub(int _hub) {
return CollectionUtils.filter(getAllBreakers(), _b -> _b.getHub() == _hub);
}
public BreakerHub getHub(int _hub) {
return CollectionUtils.filterOne(breakerHubs, _h->_h.getHub() == _hub);
}
public boolean isSolarConfigured() {
return CollectionUtils.anyQualify(getAllBreakers(), _b->_b.getPolarity() == BreakerPolarity.SOLAR);
}
public String nextGroupId() {
List<Integer> ids = CollectionUtils.transform(getAllBreakerGroupIds(), NullUtils::toInteger);
return String.valueOf(CollectionUtils.getLargest(ids) + 1);
}
public void addGroup(BreakerGroup _group) {
if (NullUtils.isEmpty(_group.getId())) {
_group.setId(nextGroupId());
}
if (breakerGroups == null)
breakerGroups = new ArrayList<>();
breakerGroups.add(_group);
}
public void removeInvalidGroups() {
if (breakerGroups != null)
breakerGroups.removeIf(_g->!_g.removeInvalidGroups());
}
public String getGroupIdForBreaker(Breaker _breaker) {
return getGroupIdForBreaker(_breaker.getKey());
}
public String getGroupIdForBreaker(int _panel, int _space) {
return getGroupIdForBreaker(Breaker.key(_panel, _space));
}
public String getGroupIdForBreaker(String _breakerKey) {
BreakerGroup group = getGroupForBreaker(_breakerKey);
return group != null ? group.getId() : null;
}
public BreakerGroup getGroupForBreaker(Breaker _breaker) {
return getGroupForBreaker(_breaker.getKey());
}
public BreakerGroup getGroupForBreaker(int _panel, int _space) {
return getGroupForBreaker(Breaker.key(_panel, _space));
}
public BreakerGroup getGroupForBreaker(String _breakerKey) {
if (_breakerKey == null)
return null;
for (BreakerGroup subGroup : CollectionUtils.makeNotNull(breakerGroups)) {
BreakerGroup group = subGroup.getGroupForBreaker(_breakerKey);
if (group != null)
return group;
}
return null;
}
public BreakerGroup findParentGroup(BreakerGroup _group) {
for (BreakerGroup group : CollectionUtils.makeNotNull(breakerGroups)) {
BreakerGroup parent = group.findParentGroup(_group);
if (parent != null)
return parent;
}
return null;
}
}

View File

@ -0,0 +1,192 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import com.lanternsoftware.util.dao.annotations.PrimaryKey;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@DBSerializable()
public class BreakerGroup {
@PrimaryKey private String id;
private int accountId;
private String name;
private List<BreakerGroup> subGroups;
private List<Breaker> breakers;
public BreakerGroup() {
}
public BreakerGroup(String _id, String _name, List<Breaker> _breakers) {
id = _id;
name = _name;
breakers = _breakers;
}
public BreakerGroup(String _id, String _name, List<BreakerGroup> _subGroups, List<Breaker> _breakers) {
id = _id;
name = _name;
subGroups = _subGroups;
breakers = _breakers;
}
public String getId() {
return id;
}
public void setId(String _id) {
id = _id;
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public String getName() {
return name;
}
public void setName(String _name) {
name = _name;
}
public List<BreakerGroup> getSubGroups() {
return subGroups;
}
public void setSubGroups(List<BreakerGroup> _subGroups) {
subGroups = _subGroups;
}
public List<Breaker> getBreakers() {
return breakers;
}
public void setBreakers(List<Breaker> _breakers) {
breakers = _breakers;
}
public List<Breaker> getAllBreakers() {
List<Breaker> allBreakers = new ArrayList<>();
getAllBreakers(allBreakers);
return allBreakers;
}
private void getAllBreakers(List<Breaker> _breakers) {
if (breakers != null)
_breakers.addAll(breakers);
for (BreakerGroup group : CollectionUtils.makeNotNull(subGroups)) {
group.getAllBreakers(_breakers);
}
}
public List<String> getAllBreakerKeys() {
return CollectionUtils.transform(getAllBreakers(), Breaker::getKey);
}
public List<BreakerGroup> getAllBreakerGroups() {
List<BreakerGroup> allGroups = new ArrayList<>();
getAllBreakerGroups(allGroups);
return allGroups;
}
private void getAllBreakerGroups(List<BreakerGroup> _groups) {
_groups.add(this);
for (BreakerGroup group : CollectionUtils.makeNotNull(subGroups)) {
group.getAllBreakerGroups(_groups);
}
}
public List<String> getAllBreakerGroupIds() {
return CollectionUtils.transform(getAllBreakerGroups(), BreakerGroup::getId);
}
public Breaker getBreaker(String _breakerKey) {
for (Breaker b : CollectionUtils.makeNotNull(breakers)) {
if (NullUtils.isEqual(b.getKey(), _breakerKey))
return b;
}
for (BreakerGroup group : CollectionUtils.makeNotNull(subGroups)) {
Breaker b = group.getBreaker(_breakerKey);
if (b != null)
return b;
}
return null;
}
public String getGroupIdForBreaker(Breaker _breaker) {
return getGroupIdForBreaker(_breaker.getKey());
}
public String getGroupIdForBreaker(int _panel, int _space) {
return getGroupIdForBreaker(Breaker.key(_panel, _space));
}
public String getGroupIdForBreaker(String _breakerKey) {
BreakerGroup group = getGroupForBreaker(_breakerKey);
return group != null ? group.getId() : null;
}
public BreakerGroup getGroupForBreaker(Breaker _breaker) {
return getGroupForBreaker(_breaker.getKey());
}
public BreakerGroup getGroupForBreaker(int _panel, int _space) {
return getGroupForBreaker(Breaker.key(_panel, _space));
}
public BreakerGroup getGroupForBreaker(String _breakerKey) {
if (_breakerKey == null)
return null;
Breaker b = CollectionUtils.filterOne(breakers, _b->_breakerKey.equals(_b.getKey()));
if (b != null)
return this;
for (BreakerGroup subGroup : CollectionUtils.makeNotNull(subGroups)) {
BreakerGroup group = subGroup.getGroupForBreaker(_breakerKey);
if (group != null)
return group;
}
return null;
}
public BreakerGroup findParentGroup(BreakerGroup _group) {
if (CollectionUtils.contains(subGroups, _group))
return this;
for (BreakerGroup subGroup : CollectionUtils.makeNotNull(subGroups)) {
BreakerGroup parent = subGroup.findParentGroup(_group);
if (parent != null)
return parent;
}
return null;
}
public boolean removeInvalidGroups() {
if (subGroups != null)
subGroups.removeIf(_g->!_g.removeInvalidGroups());
if (breakers != null)
breakers.removeIf(_b->(_b.getType() == null) || (_b.getType() == BreakerType.EMPTY) || (_b.getPort() < 1));
return CollectionUtils.isNotEmpty(subGroups) || CollectionUtils.isNotEmpty(breakers);
}
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
BreakerGroup that = (BreakerGroup) _o;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@ -0,0 +1,337 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.ArrayList;
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.Set;
import java.util.TimeZone;
import java.util.TreeMap;
@DBSerializable(autogen = false)
public class BreakerGroupEnergy {
private int accountId;
private String groupId;
private String groupName;
private EnergyBlockViewMode viewMode;
private Date start;
private List<BreakerGroupEnergy> subGroups;
private List<EnergyBlock> energyBlocks;
private double toGrid;
private double fromGrid;
public BreakerGroupEnergy() {
}
public BreakerGroupEnergy(BreakerGroup _group, Map<String, List<BreakerPower>> _powerReadings, EnergyBlockViewMode _viewMode, Date _start, TimeZone _tz) {
groupId = _group.getId();
groupName = _group.getName();
viewMode = _viewMode;
start = _start;
accountId = _group.getAccountId();
subGroups = CollectionUtils.transform(_group.getSubGroups(), _g -> new BreakerGroupEnergy(_g, _powerReadings, _viewMode, _start, _tz));
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(), _tz);
}
}
}
public BreakerGroupEnergy(BreakerGroup _group, List<HubPowerMinute> _power, EnergyBlockViewMode _viewMode, Date _start, TimeZone _tz) {
groupId = _group.getId();
groupName = _group.getName();
viewMode = _viewMode;
start = _start;
accountId = _group.getAccountId();
subGroups = CollectionUtils.transform(_group.getSubGroups(), _g -> new BreakerGroupEnergy(_g, (List<HubPowerMinute>)null, _viewMode, _start, _tz));
energyBlocks = new ArrayList<>();
addEnergy(_group, _power, _tz);
}
public void addEnergy(BreakerGroup _group, List<HubPowerMinute> _hubPower, TimeZone _tz) {
Map<String, Breaker> breakers = CollectionUtils.transformToMap(_group.getAllBreakers(), Breaker::getKey);
Map<String, BreakerGroup> breakerKeyToGroup = new HashMap<>();
for (BreakerGroup group : _group.getAllBreakerGroups()) {
for (Breaker b : group.getAllBreakers()) {
breakerKeyToGroup.put(b.getKey(), group);
}
}
addEnergy(breakers, breakerKeyToGroup, _hubPower, _tz);
}
public void addEnergy(Map<String, Breaker> _breakers, Map<String, BreakerGroup> _breakerKeyToGroup, List<HubPowerMinute> _hubPower, TimeZone _tz) {
if (CollectionUtils.isEmpty(_hubPower) || CollectionUtils.anyQualify(_hubPower, _p->_p.getAccountId() != accountId))
return;
Date minute = CollectionUtils.getFirst(_hubPower).getMinuteAsDate();
resetEnergy(minute, _tz);
Map<Integer, MeterMinute> meters = new HashMap<>();
for (HubPowerMinute hubPower : _hubPower) {
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;
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, _tz);
idx++;
}
}
}
for (MeterMinute meter : meters.values()) {
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];
}
}
}
public void resetEnergy(Date _readTime, TimeZone _tz) {
EnergyBlock block = getBlock(_readTime, _tz, false);
if (block != null)
block.setJoules(0);
for (BreakerGroupEnergy subGroup : CollectionUtils.makeNotNull(subGroups)) {
subGroup.resetEnergy(_readTime, _tz);
}
}
public void addEnergy(String _groupId, Date _readTime, double _joules, TimeZone _tz) {
if (NullUtils.isEqual(groupId, _groupId))
getBlock(_readTime, _tz).addJoules(_joules);
else {
for (BreakerGroupEnergy subGroup : CollectionUtils.makeNotNull(subGroups)) {
subGroup.addEnergy(_groupId, _readTime, _joules, _tz);
}
}
}
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());
energy.setGroupName(_group.getName());
energy.setAccountId(_group.getAccountId());
energy.setViewMode(_viewMode);
energy.setStart(_start);
energy.setSubGroups(CollectionUtils.transform(_group.getSubGroups(), _g -> BreakerGroupEnergy.summary(_g, _energies, _viewMode, _start, _tz)));
for (BreakerGroupSummary curEnergy : CollectionUtils.makeNotNull(_energies.get(_group.getId()))) {
EnergyBlock block = energy.getBlock(curEnergy.getStart(), _tz);
block.addJoules(curEnergy.getJoules());
energy.setToGrid(energy.getToGrid()+curEnergy.getToGrid());
energy.setFromGrid(energy.getFromGrid()+curEnergy.getFromGrid());
}
return energy;
}
private EnergyBlock getBlock(Date _readTime, TimeZone _tz) {
return getBlock(_readTime, _tz, true);
}
private EnergyBlock getBlock(Date _readTime, TimeZone _tz, boolean _add) {
int size = CollectionUtils.size(energyBlocks);
int idx = viewMode.blockIndex(_readTime, _tz);
if (_add && (idx >= size)) {
if (energyBlocks == null)
energyBlocks = new ArrayList<>();
LinkedList<EnergyBlock> newBlocks = new LinkedList<>();
Date end = viewMode.toBlockEnd(_readTime, _tz);
while (idx >= size) {
Date start = viewMode.decrementBlock(end, _tz);
newBlocks.add(new EnergyBlock(start, end, 0));
end = start;
size++;
}
Iterator<EnergyBlock> iter = newBlocks.descendingIterator();
while (iter.hasNext()) {
energyBlocks.add(iter.next());
}
}
return CollectionUtils.get(energyBlocks, idx);
}
public String getId() {
return toId(accountId, groupId, viewMode, start);
}
public static String toId(int _accountId, String _groupId, EnergyBlockViewMode _viewMode, Date _start) {
return _accountId + "-" + _groupId + "-" + DaoSerializer.toEnumName(_viewMode) + "-" + _start.getTime();
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String _groupId) {
groupId = _groupId;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String _groupName) {
groupName = _groupName;
}
public BreakerGroupEnergy getSubGroup(String _groupId) {
return CollectionUtils.filterOne(subGroups, _g->_groupId.equals(_g.getGroupId()));
}
public List<BreakerGroupEnergy> getSubGroups() {
return subGroups;
}
public EnergyBlockViewMode getViewMode() {
return viewMode;
}
public void setViewMode(EnergyBlockViewMode _viewMode) {
viewMode = _viewMode;
}
public Date getStart() {
return start;
}
public void setStart(Date _start) {
start = _start;
}
public void setSubGroups(List<BreakerGroupEnergy> _subGroups) {
subGroups = _subGroups;
}
public List<EnergyBlock> getEnergyBlocks() {
return energyBlocks;
}
public void setEnergyBlocks(List<EnergyBlock> _energyBlocks) {
energyBlocks = _energyBlocks;
}
public double getToGrid() {
return toGrid;
}
public void setToGrid(double _toGrid) {
toGrid = _toGrid;
}
public double getFromGrid() {
return fromGrid;
}
public void setFromGrid(double _fromGrid) {
fromGrid = _fromGrid;
}
public double wattHours() {
return joules() / 3600;
}
public double wattHours(Set<String> _selectedBreakers) {
return joules(_selectedBreakers) / 3600;
}
public double joules() {
return joules(null);
}
public double joules(Set<String> _selectedBreakers) {
return joules(_selectedBreakers, true);
}
public double joules(Set<String> _selectedBreakers, boolean _includeSubgroups) {
double joules = 0.0;
if (_includeSubgroups) {
for (BreakerGroupEnergy group : CollectionUtils.makeNotNull(subGroups)) {
joules += group.joules(_selectedBreakers);
}
}
if ((energyBlocks != null) && ((_selectedBreakers == null) || _selectedBreakers.contains(getGroupId()))) {
for (EnergyBlock energy : energyBlocks) {
joules += energy.getJoules();
}
}
return joules;
}
public List<BreakerGroupEnergy> getAllGroups() {
Map<String, BreakerGroupEnergy> groups = new TreeMap<>();
getAllGroups(groups);
return new ArrayList<>(groups.values());
}
public void getAllGroups(Map<String, BreakerGroupEnergy> _groups) {
_groups.put(getGroupId(), this);
for (BreakerGroupEnergy group : CollectionUtils.makeNotNull(subGroups)) {
group.getAllGroups(_groups);
}
}
public List<EnergyBlock> getAllEnergyBlocks() {
return getAllEnergyBlocks(null);
}
public List<EnergyBlock> getAllEnergyBlocks(Set<String> _selectedGroups) {
return getAllEnergyBlocks(_selectedGroups, EnergyBlockType.ANY);
}
public List<EnergyBlock> getAllEnergyBlocks(Set<String> _selectedGroups, EnergyBlockType _type) {
Map<Long, EnergyBlock> blocks = new TreeMap<>();
getAllEnergyBlocks(_selectedGroups, blocks, _type);
return new ArrayList<>(blocks.values());
}
private void getAllEnergyBlocks(Set<String> _selectedGroups, Map<Long, EnergyBlock> _energyBlocks, EnergyBlockType _type) {
if ((energyBlocks != null) && ((_selectedGroups == null) || _selectedGroups.contains(getGroupId()))) {
for (EnergyBlock block : energyBlocks) {
if ((_type == EnergyBlockType.ANY) || ((_type == EnergyBlockType.POSITIVE) && block.getJoules() >= 0.0) || ((_type == EnergyBlockType.NEGATIVE) && block.getJoules() <= 0.0)) {
EnergyBlock b = _energyBlocks.get(block.getStart().getTime());
if (b == null) {
b = new EnergyBlock(block.getStart(), block.getEnd(), block.getJoules());
_energyBlocks.put(block.getStart().getTime(), b);
} else
b.addJoules(block.getJoules());
}
}
}
for (BreakerGroupEnergy group : CollectionUtils.makeNotNull(subGroups)) {
group.getAllEnergyBlocks(_selectedGroups, _energyBlocks, _type);
}
}
private static class MeterMinute {
public double[] usage = new double[60];
public double[] solar = new double[60];
}
}

View File

@ -0,0 +1,139 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@DBSerializable(autogen = false)
public class BreakerGroupSummary {
private int accountId;
private String groupId;
private String groupName;
private EnergyBlockViewMode viewMode;
private Date start;
private List<BreakerGroupSummary> subGroups;
private double joules;
private double toGrid;
private double fromGrid;
public BreakerGroupSummary() {
}
public BreakerGroupSummary(BreakerGroupEnergy _energy) {
accountId = _energy.getAccountId();
groupId = _energy.getGroupId();
groupName = _energy.getGroupName();
viewMode = _energy.getViewMode();
start = _energy.getStart();
subGroups = CollectionUtils.transform(_energy.getSubGroups(), BreakerGroupSummary::new);
joules = _energy.joules(null, false);
toGrid = _energy.getToGrid();
fromGrid = _energy.getFromGrid();
}
public String getId() {
return toId(accountId, groupId, viewMode, start);
}
public static String toId(int _accountId, String _groupId, EnergyBlockViewMode _viewMode, Date _start) {
return _accountId + "-" + _groupId + "-" + DaoSerializer.toEnumName(_viewMode) + "-" + _start.getTime();
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String _groupId) {
groupId = _groupId;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String _groupName) {
groupName = _groupName;
}
public BreakerGroupSummary getSubGroup(String _groupId) {
return CollectionUtils.filterOne(subGroups, _g->_groupId.equals(_g.getGroupId()));
}
public List<BreakerGroupSummary> getSubGroups() {
return subGroups;
}
public EnergyBlockViewMode getViewMode() {
return viewMode;
}
public void setViewMode(EnergyBlockViewMode _viewMode) {
viewMode = _viewMode;
}
public Date getStart() {
return start;
}
public void setStart(Date _start) {
start = _start;
}
public void setSubGroups(List<BreakerGroupSummary> _subGroups) {
subGroups = _subGroups;
}
public double getJoules() {
return joules;
}
public void setJoules(double _joules) {
joules = _joules;
}
public double getToGrid() {
return toGrid;
}
public void setToGrid(double _toGrid) {
toGrid = _toGrid;
}
public double getFromGrid() {
return fromGrid;
}
public void setFromGrid(double _fromGrid) {
fromGrid = _fromGrid;
}
public List<BreakerGroupSummary> getAllGroups() {
Map<String, BreakerGroupSummary> groups = new TreeMap<>();
getAllGroups(groups);
return new ArrayList<>(groups.values());
}
public void getAllGroups(Map<String, BreakerGroupSummary> _groups) {
if (NullUtils.isNotEmpty(getGroupId()))
_groups.put(getGroupId(), this);
for (BreakerGroupSummary group : CollectionUtils.makeNotNull(subGroups)) {
group.getAllGroups(_groups);
}
}
}

View File

@ -0,0 +1,44 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
@DBSerializable
public class BreakerHub {
private int hub;
private double voltageCalibrationFactor;
private int frequency;
private String bluetoothMac;
public int getHub() {
return hub;
}
public void setHub(int _hub) {
hub = _hub;
}
public double getVoltageCalibrationFactor() {
return voltageCalibrationFactor;
}
public void setVoltageCalibrationFactor(double _voltageCalibrationFactor) {
voltageCalibrationFactor = _voltageCalibrationFactor;
}
public int getFrequency() {
return frequency;
}
public void setFrequency(int _frequency) {
frequency = _frequency;
}
public String getBluetoothMac() {
return bluetoothMac;
}
public void setBluetoothMac(String _bluetoothMac) {
bluetoothMac = _bluetoothMac;
}
}

View File

@ -0,0 +1,52 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
@DBSerializable
public class BreakerPanel {
private int accountId;
private String name;
private int index;
private int spaces;
private int meter;
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public String getName() {
return name;
}
public void setName(String _name) {
name = _name;
}
public int getIndex() {
return index;
}
public void setIndex(int _index) {
index = _index;
}
public int getSpaces() {
return spaces;
}
public void setSpaces(int _spaces) {
spaces = _spaces;
}
public int getMeter() {
return meter;
}
public void setMeter(int _meter) {
meter = _meter;
}
}

View File

@ -0,0 +1,6 @@
package com.lanternsoftware.datamodel.currentmonitor;
public enum BreakerPolarity {
NORMAL,
SOLAR;
}

View File

@ -0,0 +1,92 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Date;
@DBSerializable(autogen = false)
public class BreakerPower {
private int accountId;
private int panel;
private int space;
private Date readTime;
private String hubVersion;
private double power;
private double voltage;
public BreakerPower() {
}
public BreakerPower(int _panel, int _space, Date _readTime, double _power, double _voltage) {
panel = _panel;
space = _space;
readTime = _readTime;
power = _power;
voltage = _voltage;
}
public String getId() {
return String.format("%d-%d-%d", accountId, panel, space);
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
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 Date getReadTime() {
return readTime;
}
public void setReadTime(Date _readTime) {
readTime = _readTime;
}
public String getHubVersion() {
return hubVersion;
}
public void setHubVersion(String _hubVersion) {
hubVersion = _hubVersion;
}
public double getPower() {
return power;
}
public void setPower(double _power) {
power = _power;
}
public double getVoltage() {
return voltage;
}
public void setVoltage(double _voltage) {
voltage = _voltage;
}
public String getKey() {
return Breaker.key(panel, space);
}
}

View File

@ -0,0 +1,40 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.List;
@DBSerializable(autogen = false)
public class BreakerPowerMinute {
private int panel;
private int space;
private List<Float> readings;
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 String breakerKey() {
return Breaker.key(panel, space);
}
public List<Float> getReadings() {
return readings;
}
public void setReadings(List<Float> _readings) {
readings = _readings;
}
}

View File

@ -0,0 +1,36 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import java.util.List;
public enum BreakerType {
EMPTY("Empty"),
SINGLE_POLE("Single Pole"),
SINGLE_POLE_TANDEM("Single Pole Tandem (Two Breakers in One)"),
DOUBLE_POLE_TOP("Double Pole (240V)"),
DOUBLE_POLE_BOTTOM("Double Pole (240V)");
private final String display;
BreakerType(String _display) {
display = _display;
}
public String getDisplay() {
return display;
}
public static List<BreakerType> selectable() {
return CollectionUtils.asArrayList(EMPTY, SINGLE_POLE, SINGLE_POLE_TANDEM, DOUBLE_POLE_TOP);
}
public static BreakerType fromDisplay(String _display) {
for (BreakerType type : values()) {
if (NullUtils.isEqual(_display, type.getDisplay()))
return type;
}
return null;
}
}

View File

@ -0,0 +1,31 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import java.util.Collection;
public enum CharacteristicFlag {
BROADCAST("broadcast"),
READ("read"),
WRITE_WITHOUT_RESPONSE("write-without-response"),
WRITE("write"),
NOTIFY("notify"),
INDICATE("indicate"),
AUTHENTICATED_SIGNED_WRITES("authenticated-signed-writes"),
RELIABLE_WRITE("reliable-write"),
WRITABLE_AUXILIARIES("writable-auxiliaries"),
ENCRYPT_READ("encrypt-read"),
ENCRYPT_WRITE("encrypt-write"),
ENCRYPT_AUTHENTICATED_READ("encrypt-authenticated-read"),
ENCRYPT_AUTHENTICATED_WRITE("encrypt-authenticated-write");
CharacteristicFlag(String _value) {
value = _value;
}
public final String value;
public static String[] toArray(Collection<CharacteristicFlag> _flags) {
return CollectionUtils.transform(_flags, _c->_c.value).toArray(new String[0]);
}
}

View File

@ -0,0 +1,60 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Date;
@DBSerializable
public class EnergyBlock {
private Date start;
private Date end;
private double joules;
public EnergyBlock() {
}
public EnergyBlock(Date _start, Date _end, double _joules) {
start = _start;
end = _end;
joules = _joules;
}
public Date getStart() {
return start;
}
public void setStart(Date _start) {
start = _start;
}
public Date getEnd() {
return end;
}
public void setEnd(Date _end) {
end = _end;
}
public double getJoules() {
return joules;
}
public void addJoules(double _joules) {
joules += _joules;
}
public void setJoules(double _joules) {
joules = _joules;
}
public double wattHours() {
return joules / 3600;
}
public double getAveragePower() {
if ((end == null) || (start == null))
return 0;
return 1000*joules/(end.getTime()-start.getTime());
}
}

View File

@ -0,0 +1,7 @@
package com.lanternsoftware.datamodel.currentmonitor;
public enum EnergyBlockType {
ANY,
POSITIVE,
NEGATIVE
}

View File

@ -0,0 +1,144 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.DateUtils;
import javax.management.remote.rmi._RMIConnection_Stub;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public enum EnergyBlockViewMode {
DAY,
MONTH,
YEAR,
ALL;
public Date toStart(Date _dt, TimeZone _tz) {
if (this == DAY)
return DateUtils.getMidnightBefore(_dt, _tz);
if (this == MONTH)
return DateUtils.getStartOfMonth(_dt, _tz);
if (this == YEAR)
return DateUtils.getStartOfYear(_dt, _tz);
return new Date(0);
}
public Date toEnd(Date _dt, TimeZone _tz) {
if (this == DAY)
return DateUtils.getMidnightAfter(_dt, _tz);
if (this == MONTH)
return DateUtils.getEndOfMonth(_dt, _tz);
if (this == YEAR)
return DateUtils.getEndOfYear(_dt, _tz);
return new Date(0);
}
public Date toBlockStart(Date _dt, TimeZone _tz) {
if (this == DAY)
return DateUtils.getStartOfMinute(_dt, _tz);
if (this == MONTH)
return DateUtils.getMidnightBefore(_dt, _tz);
if (this == YEAR)
return DateUtils.getStartOfMonth(_dt, _tz);
return new Date(0);
}
public Date toBlockEnd(Date _dt, TimeZone _tz) {
if (this == DAY)
return DateUtils.getEndOfMinute(_dt, _tz);
if (this == MONTH)
return DateUtils.getMidnightAfter(_dt, _tz);
if (this == YEAR)
return DateUtils.getEndOfMonth(_dt, _tz);
return new Date(0);
}
public Date incrementBlock(Date _dt, TimeZone _tz) {
Calendar cal = DateUtils.toCalendar(_dt, _tz);
if (this == DAY)
cal.add(Calendar.MINUTE, 1);
else if (this == MONTH)
cal.add(Calendar.DAY_OF_YEAR, 1);
if (this == YEAR)
cal.add(Calendar.MONTH, 1);
return cal.getTime();
}
public Date decrementBlock(Date _dt, TimeZone _tz) {
Calendar cal = DateUtils.toCalendar(_dt, _tz);
if (this == DAY)
cal.add(Calendar.MINUTE, -1);
else if (this == MONTH)
cal.add(Calendar.DAY_OF_YEAR, -1);
if (this == YEAR)
cal.add(Calendar.MONTH, -1);
return cal.getTime();
}
public Date incrementView(Date _dt, TimeZone _tz) {
Calendar cal = DateUtils.toCalendar(_dt, _tz);
if (this == DAY)
cal.add(Calendar.DAY_OF_YEAR, 1);
else if (this == MONTH)
cal.add(Calendar.MONTH, 1);
if (this == YEAR)
cal.add(Calendar.YEAR, 1);
return cal.getTime();
}
public Date decrementView(Date _dt, TimeZone _tz) {
Calendar cal = DateUtils.toCalendar(_dt, _tz);
if (this == DAY)
cal.add(Calendar.DAY_OF_YEAR, -1);
else if (this == MONTH)
cal.add(Calendar.MONTH, -1);
if (this == YEAR)
cal.add(Calendar.YEAR, -1);
return cal.getTime();
}
public int blockCount(Date _start, TimeZone _tz) {
if (this == ALL)
return 1;
Date end = toEnd(_start, _tz);
int blockCnt = 0;
while (_start.before(end)) {
blockCnt++;
_start = toBlockEnd(_start, _tz);
}
return blockCnt;
}
public int blockIndex(Date _readTime, TimeZone _tz) {
if (this == DAY) {
Date start = DateUtils.getMidnightBefore(_readTime, _tz);
return (int)((_readTime.getTime() - start.getTime())/60000);
}
else if (this == MONTH) {
Calendar read = DateUtils.toCalendar(_readTime, _tz);
return read.get(Calendar.DAY_OF_MONTH) - 1;
}
if (this == YEAR) {
Calendar read = DateUtils.toCalendar(_readTime, _tz);
return read.get(Calendar.MONTH);
}
return 0;
}
public Date toBlockStart(int _index, Date _start, TimeZone _tz) {
if (this == DAY)
return new Date(_start.getTime() + _index*60000);
else if (this == MONTH) {
Calendar read = DateUtils.toCalendar(_start, _tz);
read.add(Calendar.DAY_OF_MONTH, _index);
return read.getTime();
}
if (this == YEAR) {
Calendar read = DateUtils.toCalendar(_start, _tz);
read.add(Calendar.MONTH, _index);
return read.getTime();
}
return new Date(0);
}
}

View File

@ -0,0 +1,44 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.NullUtils;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.UUID;
public enum HubConfigCharacteristic {
WifiCredentials(2, CharacteristicFlag.WRITE),
AuthCode(3, CharacteristicFlag.WRITE),
HubIndex(4, CharacteristicFlag.READ, CharacteristicFlag.WRITE),
Restart(5, CharacteristicFlag.WRITE),
Reboot(6, CharacteristicFlag.WRITE),
AccountId(7, CharacteristicFlag.READ),
NetworkState(8, CharacteristicFlag.READ),
Flash(9, CharacteristicFlag.WRITE);
public final int idx;
public final UUID uuid;
public final EnumSet<CharacteristicFlag> flags;
HubConfigCharacteristic(int _idx, CharacteristicFlag... _flags) {
idx = _idx;
uuid = HubConfigService.uuidFormat.format(_idx);
flags = EnumSet.copyOf(Arrays.asList(_flags));
}
public int getIdx() {
return idx;
}
public UUID getUUID() {
return uuid;
}
public EnumSet<CharacteristicFlag> getFlags() {
return flags;
}
public boolean isChar(String _char) {
return NullUtils.isEqual(name(), _char);
}
}

View File

@ -0,0 +1,39 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.cryptography.AESTool;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class HubConfigService {
public static final UUIDFormatter uuidFormat = new UUIDFormatter("c5650001-d50f-49af-b906-cada0dc17937");
private static final AESTool aes = new AESTool(37320708309265127L,-8068168662055796771L,-4867793276337148572L,4425609941731230765L);
private static final UUID serviceUUID = uuidFormat.format(1);
public HubConfigService() {
}
public static UUID getServiceUUID() {
return serviceUUID;
}
public List<HubConfigCharacteristic> getCharacteristics() {
return Arrays.asList(HubConfigCharacteristic.values());
}
public static byte[] encryptWifiCreds(String _ssid, String _password) {
DaoEntity creds = new DaoEntity("ssid", _ssid).and("pwd", _password);
return aes.encrypt(DaoSerializer.toZipBson(creds));
}
public static String decryptWifiSSID(byte[] _payload) {
return DaoSerializer.getString(DaoSerializer.fromZipBson(aes.decrypt(_payload)), "ssid");
}
public static String decryptWifiPassword(byte[] _payload) {
return DaoSerializer.getString(DaoSerializer.fromZipBson(aes.decrypt(_payload)), "pwd");
}
}

View File

@ -0,0 +1,58 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Date;
import java.util.List;
@DBSerializable
public class HubPowerMinute {
private int accountId;
private int hub;
private int minute;
private List<BreakerPowerMinute> breakers;
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public int getHub() {
return hub;
}
public void setHub(int _hub) {
hub = _hub;
}
public Date getMinuteAsDate() {
return new Date(((long)minute)*60000);
}
public int getMinute() {
return minute;
}
public void setMinute(int _minute) {
minute = _minute;
}
public void setMinute(Date _minute) {
minute = (int)(_minute.getTime()/60000);
}
public List<BreakerPowerMinute> getBreakers() {
return breakers;
}
public void setBreakers(List<BreakerPowerMinute> _breakers) {
breakers = _breakers;
}
public String getId() {
return String.format("%d-%d-%d", accountId, hub, minute);
}
}

View File

@ -0,0 +1,34 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
@DBSerializable
public class Meter {
private int accountId;
private int index;
private String name;
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public int getIndex() {
return index;
}
public void setIndex(int _index) {
index = _index;
}
public String getName() {
return name;
}
public void setName(String _name) {
name = _name;
}
}

View File

@ -0,0 +1,42 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import java.util.Collection;
import java.util.EnumSet;
public enum NetworkAdapter {
ETHERNET((byte)0x1),
WIFI((byte)0x2);
public final byte bt;
NetworkAdapter(byte _bt) {
bt = _bt;
}
public static NetworkAdapter fromByte(byte _bt) {
for (NetworkAdapter a : values()) {
if (a.bt == _bt)
return a;
}
return null;
}
public static EnumSet<NetworkAdapter> fromMask(byte _bt) {
EnumSet<NetworkAdapter> values = EnumSet.noneOf(NetworkAdapter.class);
for (NetworkAdapter a : values()) {
if ((a.bt & _bt) == a.bt)
values.add(a);
}
return values;
}
public static byte toMask(Collection<NetworkAdapter> _adapters) {
byte mask = 0;
for (NetworkAdapter a : CollectionUtils.makeNotNull(_adapters)) {
mask |= a.bt;
}
return mask;
}
}

View File

@ -0,0 +1,44 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import java.util.EnumSet;
import java.util.List;
public class NetworkStatus {
private List<String> wifiIPs;
private List<String> ethernetIPs;
public List<String> getWifiIPs() {
return wifiIPs;
}
public void setWifiIPs(List<String> _wifiIPs) {
wifiIPs = _wifiIPs;
}
public List<String> getEthernetIPs() {
return ethernetIPs;
}
public void setEthernetIPs(List<String> _ethernetIPs) {
ethernetIPs = _ethernetIPs;
}
public boolean isWifiConnected() {
return CollectionUtils.isNotEmpty(wifiIPs);
}
public boolean isEthernetConnected() {
return CollectionUtils.isNotEmpty(ethernetIPs);
}
public byte toMask() {
EnumSet<NetworkAdapter> adapters = EnumSet.noneOf(NetworkAdapter.class);
if (isWifiConnected())
adapters.add(NetworkAdapter.WIFI);
if (isEthernetConnected())
adapters.add(NetworkAdapter.ETHERNET);
return NetworkAdapter.toMask(adapters);
}
}

View File

@ -0,0 +1,28 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import com.lanternsoftware.util.dao.annotations.PrimaryKey;
@DBSerializable
public class Sequence {
@PrimaryKey
private String id;
private int sequence;
public String getId() {
return id;
}
public void setId(String _id) {
id = _id;
}
public int getSequence() {
return sequence;
}
public void setSequence(int _sequence) {
sequence = _sequence;
}
}

View File

@ -0,0 +1,45 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
@DBSerializable
public class SignupResponse {
private String error;
private String authCode;
public SignupResponse() {
}
public static SignupResponse error(String _error) {
SignupResponse response = new SignupResponse();
response.setError(_error);
return response;
}
public static SignupResponse success(String _authCode) {
SignupResponse response = new SignupResponse();
response.setAuthCode(_authCode);
return response;
}
public String getError() {
return error;
}
public void setError(String _error) {
error = _error;
}
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String _authCode) {
authCode = _authCode;
}
public boolean isSuccess() {
return NullUtils.isEmpty(error) && NullUtils.isNotEmpty(authCode);
}
}

View File

@ -0,0 +1,17 @@
package com.lanternsoftware.datamodel.currentmonitor;
import java.util.UUID;
public class UUIDFormatter {
private final String uuidPrefix;
private final String uuidSuffix;
public UUIDFormatter(String _uuid) {
uuidPrefix = _uuid.substring(0,4);
uuidSuffix = _uuid.substring(8);
}
public UUID format(int _idx) {
return UUID.fromString(uuidPrefix + String.format("%04X", _idx) + uuidSuffix);
}
}

View File

@ -0,0 +1,50 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.util.CollectionUtils;
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.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AccountSerializer extends AbstractDaoSerializer<Account>
{
@Override
public Class<Account> getSupportedClass()
{
return Account.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(Account _o)
{
DaoEntity d = new DaoEntity();
d.put("_id", String.valueOf(_o.getId()));
d.put("username", _o.getUsername());
d.put("password", _o.getPassword());
if (CollectionUtils.isNotEmpty(_o.getAuxiliaryAccountIds()))
d.put("aux_account_ids", CollectionUtils.toByteArray(_o.getAuxiliaryAccountIds()));
return d;
}
@Override
public Account fromDaoEntity(DaoEntity _d)
{
Account o = new Account();
o.setId(DaoSerializer.getInteger(_d, "_id"));
o.setUsername(DaoSerializer.getString(_d, "username"));
o.setPassword(DaoSerializer.getString(_d, "password"));
o.setAuxiliaryAccountIds(CollectionUtils.fromByteArrayOfIntegers(DaoSerializer.getByteArray(_d, "aux_account_ids")));
return o;
}
}

View File

@ -0,0 +1,46 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
import com.lanternsoftware.util.CollectionUtils;
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.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AuthCodeSerializer extends AbstractDaoSerializer<AuthCode>
{
@Override
public Class<AuthCode> getSupportedClass()
{
return AuthCode.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(AuthCode _o)
{
DaoEntity d = new DaoEntity();
d.put("account_id", _o.getAccountId());
if (CollectionUtils.isNotEmpty(_o.getAuxiliaryAccountIds()))
d.put("aux_account_ids", CollectionUtils.toByteArray(_o.getAuxiliaryAccountIds()));
return d;
}
@Override
public AuthCode fromDaoEntity(DaoEntity _d)
{
AuthCode o = new AuthCode();
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setAuxiliaryAccountIds(CollectionUtils.fromByteArrayOfIntegers(DaoSerializer.getByteArray(_d, "aux_account_ids")));
return o;
}
}

View File

@ -0,0 +1,52 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPanel;
import com.lanternsoftware.datamodel.currentmonitor.Meter;
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 BreakerConfigSerializer extends AbstractDaoSerializer<BreakerConfig>
{
@Override
public Class<BreakerConfig> getSupportedClass()
{
return BreakerConfig.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(BreakerConfig _o)
{
DaoEntity d = new DaoEntity();
d.put("_id", String.valueOf(_o.getAccountId()));
d.put("meters", DaoSerializer.toDaoEntities(_o.getMeters(), DaoProxyType.MONGO));
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));
return d;
}
@Override
public BreakerConfig fromDaoEntity(DaoEntity _d)
{
BreakerConfig o = new BreakerConfig();
o.setAccountId(DaoSerializer.getInteger(_d, "_id"));
o.setMeters(DaoSerializer.getList(_d, "meters", Meter.class));
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));
return o;
}
}

View File

@ -0,0 +1,98 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupEnergy;
import com.lanternsoftware.datamodel.currentmonitor.EnergyBlock;
import com.lanternsoftware.datamodel.currentmonitor.EnergyBlockViewMode;
import com.lanternsoftware.util.CollectionUtils;
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.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
public class BreakerGroupEnergySerializer extends AbstractDaoSerializer<BreakerGroupEnergy>
{
@Override
public Class<BreakerGroupEnergy> getSupportedClass()
{
return BreakerGroupEnergy.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(BreakerGroupEnergy _o)
{
DaoEntity d = new DaoEntity();
d.put("_id", _o.getId());
d.put("account_id", _o.getAccountId());
d.put("group_id", _o.getGroupId());
d.put("group_name", _o.getGroupName());
d.put("view_mode", DaoSerializer.toEnumName(_o.getViewMode()));
d.put("start", DaoSerializer.toLong(_o.getStart()));
d.put("sub_groups", DaoSerializer.toDaoEntities(_o.getSubGroups(), DaoProxyType.MONGO));
if (CollectionUtils.size(_o.getEnergyBlocks()) > 0) {
Date start = _o.getStart();
Date now = new Date();
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
ByteBuffer bb = ByteBuffer.allocate(_o.getViewMode().blockCount(start, tz) * 4);
for (EnergyBlock b : _o.getEnergyBlocks()) {
if (b.getStart().before(start))
continue;
if (now.before(start))
break;
while (start.before(b.getStart())) {
bb.putFloat(0);
start = _o.getViewMode().toBlockEnd(start, tz);
}
bb.putFloat((float) b.getJoules());
start = _o.getViewMode().toBlockEnd(start, tz);
}
if (bb.position() < bb.limit())
d.put("blocks", Arrays.copyOfRange(bb.array(), 0, bb.position()));
else
d.put("blocks", bb.array());
}
d.put("to_grid", _o.getToGrid());
d.put("from_grid", _o.getFromGrid());
return d;
}
@Override
public BreakerGroupEnergy fromDaoEntity(DaoEntity _d)
{
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
BreakerGroupEnergy o = new BreakerGroupEnergy();
o.setGroupId(DaoSerializer.getString(_d, "group_id"));
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setGroupName(DaoSerializer.getString(_d, "group_name"));
o.setViewMode(DaoSerializer.getEnum(_d, "view_mode", EnergyBlockViewMode.class));
o.setStart(DaoSerializer.getDate(_d, "start"));
o.setSubGroups(DaoSerializer.getList(_d, "sub_groups", BreakerGroupEnergy.class));
List<EnergyBlock> blocks = new ArrayList<>();
byte[] blockData = DaoSerializer.getByteArray(_d, "blocks");
if (CollectionUtils.length(blockData) > 0) {
ByteBuffer bb = ByteBuffer.wrap(blockData);
Date start = o.getStart();
while (bb.hasRemaining()) {
EnergyBlock block = new EnergyBlock(start, o.getViewMode().toBlockEnd(start, tz), bb.getFloat());
blocks.add(block);
start = block.getEnd();
}
}
o.setEnergyBlocks(blocks);
o.setToGrid(DaoSerializer.getDouble(_d, "to_grid"));
o.setFromGrid(DaoSerializer.getDouble(_d, "from_grid"));
return o;
}
}

View File

@ -0,0 +1,49 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
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 BreakerGroupSerializer extends AbstractDaoSerializer<BreakerGroup>
{
@Override
public Class<BreakerGroup> getSupportedClass()
{
return BreakerGroup.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(BreakerGroup _o)
{
DaoEntity d = new DaoEntity();
if (_o.getId() != null)
d.put("_id", _o.getId());
d.put("account_id", _o.getAccountId());
d.put("name", _o.getName());
d.put("sub_groups", DaoSerializer.toDaoEntities(_o.getSubGroups(), DaoProxyType.MONGO));
d.put("breakers", DaoSerializer.toDaoEntities(_o.getBreakers(), DaoProxyType.MONGO));
return d;
}
@Override
public BreakerGroup fromDaoEntity(DaoEntity _d)
{
BreakerGroup o = new BreakerGroup();
o.setId(DaoSerializer.getString(_d, "_id"));
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setName(DaoSerializer.getString(_d, "name"));
o.setSubGroups(DaoSerializer.getList(_d, "sub_groups", BreakerGroup.class));
o.setBreakers(DaoSerializer.getList(_d, "breakers", Breaker.class));
return o;
}
}

View File

@ -0,0 +1,55 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupSummary;
import com.lanternsoftware.datamodel.currentmonitor.EnergyBlockViewMode;
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;
import java.util.TimeZone;
public class BreakerGroupSummarySerializer extends AbstractDaoSerializer<BreakerGroupSummary> {
@Override
public Class<BreakerGroupSummary> getSupportedClass() {
return BreakerGroupSummary.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(BreakerGroupSummary _o) {
DaoEntity d = new DaoEntity();
d.put("_id", _o.getId());
d.put("account_id", _o.getAccountId());
d.put("group_id", _o.getGroupId());
d.put("group_name", _o.getGroupName());
d.put("view_mode", DaoSerializer.toEnumName(_o.getViewMode()));
d.put("start", DaoSerializer.toLong(_o.getStart()));
d.put("sub_groups", DaoSerializer.toDaoEntities(_o.getSubGroups(), DaoProxyType.MONGO));
d.put("joules", _o.getJoules());
d.put("to_grid", _o.getToGrid());
d.put("from_grid", _o.getFromGrid());
return d;
}
@Override
public BreakerGroupSummary fromDaoEntity(DaoEntity _d) {
BreakerGroupSummary o = new BreakerGroupSummary();
o.setGroupId(DaoSerializer.getString(_d, "group_id"));
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setGroupName(DaoSerializer.getString(_d, "group_name"));
o.setViewMode(DaoSerializer.getEnum(_d, "view_mode", EnergyBlockViewMode.class));
o.setStart(DaoSerializer.getDate(_d, "start"));
o.setSubGroups(DaoSerializer.getList(_d, "sub_groups", BreakerGroupSummary.class));
o.setJoules(DaoSerializer.getDouble(_d, "joules"));
o.setToGrid(DaoSerializer.getDouble(_d, "to_grid"));
o.setFromGrid(DaoSerializer.getDouble(_d, "from_grid"));
return o;
}
}

View File

@ -0,0 +1,45 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
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 BreakerHubSerializer extends AbstractDaoSerializer<BreakerHub>
{
@Override
public Class<BreakerHub> getSupportedClass()
{
return BreakerHub.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(BreakerHub _o)
{
DaoEntity d = new DaoEntity();
d.put("hub", _o.getHub());
d.put("voltage_calibration_factor", _o.getVoltageCalibrationFactor());
d.put("frequency", _o.getFrequency());
d.put("bluetooth_mac", _o.getBluetoothMac());
return d;
}
@Override
public BreakerHub fromDaoEntity(DaoEntity _d)
{
BreakerHub o = new BreakerHub();
o.setHub(DaoSerializer.getInteger(_d, "hub"));
o.setVoltageCalibrationFactor(DaoSerializer.getDouble(_d, "voltage_calibration_factor"));
o.setFrequency(DaoSerializer.getInteger(_d, "frequency"));
o.setBluetoothMac(DaoSerializer.getString(_d, "bluetooth_mac"));
return o;
}
}

View File

@ -0,0 +1,47 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPanel;
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 BreakerPanelSerializer extends AbstractDaoSerializer<BreakerPanel>
{
@Override
public Class<BreakerPanel> getSupportedClass()
{
return BreakerPanel.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(BreakerPanel _o)
{
DaoEntity d = new DaoEntity();
d.put("account_id", _o.getAccountId());
d.put("name", _o.getName());
d.put("index", _o.getIndex());
d.put("spaces", _o.getSpaces());
d.put("meter", _o.getMeter());
return d;
}
@Override
public BreakerPanel fromDaoEntity(DaoEntity _d)
{
BreakerPanel o = new BreakerPanel();
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setName(DaoSerializer.getString(_d, "name"));
o.setIndex(DaoSerializer.getInteger(_d, "index"));
o.setSpaces(DaoSerializer.getInteger(_d, "spaces"));
o.setMeter(DaoSerializer.getInteger(_d, "meter"));
return o;
}
}

View File

@ -0,0 +1,48 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPowerMinute;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class BreakerPowerMinuteSerializer extends AbstractDaoSerializer<BreakerPowerMinute> {
@Override
public Class<BreakerPowerMinute> getSupportedClass() {
return BreakerPowerMinute.class;
}
@Override
public DaoEntity toDaoEntity(BreakerPowerMinute _o) {
DaoEntity d = new DaoEntity();
d.put("panel", _o.getPanel());
d.put("space", _o.getSpace());
ByteBuffer bb = ByteBuffer.allocate(240);
for (Float reading : CollectionUtils.makeNotNull(_o.getReadings())) {
bb.putFloat(DaoSerializer.toFloat(reading));
}
d.put("readings", bb.array());
return d;
}
@Override
public BreakerPowerMinute fromDaoEntity(DaoEntity _d) {
BreakerPowerMinute o = new BreakerPowerMinute();
o.setPanel(DaoSerializer.getInteger(_d, "panel"));
o.setSpace(DaoSerializer.getInteger(_d, "space"));
byte[] data = DaoSerializer.getByteArray(_d, "readings");
List<Float> readings = new ArrayList<>();
o.setReadings(readings);
if (CollectionUtils.length(data) > 0) {
ByteBuffer bb = ByteBuffer.wrap(data);
while (bb.hasRemaining()) {
readings.add(bb.getFloat());
}
}
return o;
}
}

View File

@ -0,0 +1,54 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
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 BreakerPowerSerializer extends AbstractDaoSerializer<BreakerPower>
{
@Override
public Class<BreakerPower> getSupportedClass()
{
return BreakerPower.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(BreakerPower _o)
{
DaoEntity d = new DaoEntity();
d.put("_id", _o.getId());
d.put("account_id", _o.getAccountId());
d.put("panel", _o.getPanel());
d.put("space", _o.getSpace());
d.put("key", _o.getKey());
d.put("read_time", DaoSerializer.toLong(_o.getReadTime()));
d.put("hub_version", _o.getHubVersion());
d.put("power", _o.getPower());
d.put("voltage", _o.getVoltage());
return d;
}
@Override
public BreakerPower fromDaoEntity(DaoEntity _d)
{
BreakerPower o = new BreakerPower();
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setPanel(DaoSerializer.getInteger(_d, "panel"));
o.setSpace(DaoSerializer.getInteger(_d, "space"));
o.setReadTime(DaoSerializer.getDate(_d, "read_time"));
o.setHubVersion(DaoSerializer.getString(_d, "hub_version"));
o.setPower(DaoSerializer.getDouble(_d, "power"));
o.setVoltage(DaoSerializer.getDouble(_d, "voltage"));
return o;
}
}

View File

@ -0,0 +1,63 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPolarity;
import com.lanternsoftware.datamodel.currentmonitor.BreakerType;
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 BreakerSerializer extends AbstractDaoSerializer<Breaker>
{
@Override
public Class<Breaker> getSupportedClass()
{
return Breaker.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(Breaker _o)
{
DaoEntity d = new DaoEntity();
d.put("panel", _o.getPanel());
d.put("space", _o.getSpace());
d.put("meter", _o.getMeter());
d.put("hub", _o.getHub());
d.put("port", _o.getPort());
d.put("name", _o.getName());
d.put("description", _o.getDescription());
d.put("size_amps", _o.getSizeAmps());
d.put("calibration_factor", _o.getCalibrationFactor());
d.put("low_pass_filter", _o.getLowPassFilter());
d.put("polarity", DaoSerializer.toEnumName(_o.getPolarity()));
d.put("type", DaoSerializer.toEnumName(_o.getType()));
return d;
}
@Override
public Breaker fromDaoEntity(DaoEntity _d)
{
Breaker o = new Breaker();
o.setPanel(DaoSerializer.getInteger(_d, "panel"));
o.setSpace(DaoSerializer.getInteger(_d, "space"));
o.setMeter(DaoSerializer.getInteger(_d, "meter"));
o.setHub(DaoSerializer.getInteger(_d, "hub"));
o.setPort(DaoSerializer.getInteger(_d, "port"));
o.setName(DaoSerializer.getString(_d, "name"));
o.setDescription(DaoSerializer.getString(_d, "description"));
o.setSizeAmps(DaoSerializer.getInteger(_d, "size_amps"));
o.setCalibrationFactor(DaoSerializer.getDouble(_d, "calibration_factor"));
o.setLowPassFilter(DaoSerializer.getDouble(_d, "low_pass_filter"));
o.setPolarity(DaoSerializer.getEnum(_d, "polarity", BreakerPolarity.class));
o.setType(DaoSerializer.getEnum(_d, "type", BreakerType.class));
return o;
}
}

View File

@ -0,0 +1,43 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.EnergyBlock;
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 EnergyBlockSerializer extends AbstractDaoSerializer<EnergyBlock>
{
@Override
public Class<EnergyBlock> getSupportedClass()
{
return EnergyBlock.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(EnergyBlock _o)
{
DaoEntity d = new DaoEntity();
d.put("start", DaoSerializer.toLong(_o.getStart()));
d.put("end", DaoSerializer.toLong(_o.getEnd()));
d.put("joules", _o.getJoules());
return d;
}
@Override
public EnergyBlock fromDaoEntity(DaoEntity _d)
{
EnergyBlock o = new EnergyBlock();
o.setStart(DaoSerializer.getDate(_d, "start"));
o.setEnd(DaoSerializer.getDate(_d, "end"));
o.setJoules(DaoSerializer.getDouble(_d, "joules"));
return o;
}
}

View File

@ -0,0 +1,46 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPowerMinute;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
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 HubPowerMinuteSerializer extends AbstractDaoSerializer<HubPowerMinute>
{
@Override
public Class<HubPowerMinute> getSupportedClass()
{
return HubPowerMinute.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(HubPowerMinute _o)
{
DaoEntity d = new DaoEntity();
d.put("account_id", _o.getAccountId());
d.put("hub", _o.getHub());
d.put("minute", _o.getMinute());
d.put("breakers", DaoSerializer.toDaoEntities(_o.getBreakers(), DaoProxyType.MONGO));
return d;
}
@Override
public HubPowerMinute fromDaoEntity(DaoEntity _d)
{
HubPowerMinute o = new HubPowerMinute();
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setHub(DaoSerializer.getInteger(_d, "hub"));
o.setMinute(DaoSerializer.getInteger(_d, "minute"));
o.setBreakers(DaoSerializer.getList(_d, "breakers", BreakerPowerMinute.class));
return o;
}
}

View File

@ -0,0 +1,43 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.Meter;
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 MeterSerializer extends AbstractDaoSerializer<Meter>
{
@Override
public Class<Meter> getSupportedClass()
{
return Meter.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(Meter _o)
{
DaoEntity d = new DaoEntity();
d.put("account_id", _o.getAccountId());
d.put("index", _o.getIndex());
d.put("name", _o.getName());
return d;
}
@Override
public Meter fromDaoEntity(DaoEntity _d)
{
Meter o = new Meter();
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setIndex(DaoSerializer.getInteger(_d, "index"));
o.setName(DaoSerializer.getString(_d, "name"));
return o;
}
}

View File

@ -0,0 +1,42 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.Sequence;
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 SequenceSerializer extends AbstractDaoSerializer<Sequence>
{
@Override
public Class<Sequence> getSupportedClass()
{
return Sequence.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(Sequence _o)
{
DaoEntity d = new DaoEntity();
if (_o.getId() != null)
d.put("_id", _o.getId());
d.put("sequence", _o.getSequence());
return d;
}
@Override
public Sequence fromDaoEntity(DaoEntity _d)
{
Sequence o = new Sequence();
o.setId(DaoSerializer.getString(_d, "_id"));
o.setSequence(DaoSerializer.getInteger(_d, "sequence"));
return o;
}
}

View File

@ -0,0 +1,41 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.SignupResponse;
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 SignupResponseSerializer extends AbstractDaoSerializer<SignupResponse>
{
@Override
public Class<SignupResponse> getSupportedClass()
{
return SignupResponse.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(SignupResponse _o)
{
DaoEntity d = new DaoEntity();
d.put("error", _o.getError());
d.put("auth_code", _o.getAuthCode());
return d;
}
@Override
public SignupResponse fromDaoEntity(DaoEntity _d)
{
SignupResponse o = new SignupResponse();
o.setError(DaoSerializer.getString(_d, "error"));
o.setAuthCode(DaoSerializer.getString(_d, "auth_code"));
return o;
}
}

View File

@ -0,0 +1,16 @@
com.lanternsoftware.datamodel.currentmonitor.dao.AccountSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.AuthCodeSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerConfigSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerGroupEnergySerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerGroupSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerGroupSummarySerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerHubSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerPanelSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerPowerMinuteSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerPowerSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.EnergyBlockSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.HubPowerMinuteSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.MeterSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.SequenceSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.SignupResponseSerializer

View File

@ -0,0 +1,89 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-service-currentmonitor</artifactId>
<packaging>war</packaging>
<version>1.0.0</version>
<name>lantern-service-currentmonitor</name>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-dataaccess-currentmonitor</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-servlet</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.30.4</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.29</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<executions>
<execution>
<goals>
<goal>testCompile</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<optimize>true</optimize>
<showDeprecation>true</showDeprecation>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,23 @@
package com.lanternsoftware.currentmonitor.context;
import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class Globals implements ServletContextListener {
public static CurrentMonitorDao dao;
@Override
public void contextInitialized(ServletContextEvent sce) {
dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
dao.shutdown();
}
}

View File

@ -0,0 +1,57 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.servlet.BasicAuth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
@WebServlet("/auth/*")
public class AuthServlet extends CMServlet {
private static final NetHttpTransport transport = new NetHttpTransport();
private static final JacksonFactory jsonFactory = new JacksonFactory();
private static final Logger logger = LoggerFactory.getLogger(AuthServlet.class);
private static final String googleSsoKey = ResourceLoader.loadFileAsString(LanternFiles.OPS_PATH + "google_sso_key.txt");
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
String authCode = _req.getHeader("auth_code");
if (NullUtils.isEmpty(authCode)) {
BasicAuth auth = new BasicAuth(_req);
if (NullUtils.isEqual(auth.getUsername(), "googlesso")) {
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory).setAudience(Collections.singletonList(googleSsoKey)).build();
try {
GoogleIdToken idToken = verifier.verify(auth.getPassword());
if (idToken != null) {
GoogleIdToken.Payload payload = idToken.getPayload();
String email = payload.getEmail();
authCode = Globals.dao.getAuthCodeForEmail(email);
}
}
catch (Exception _e) {
logger.error("Failed to validate google auth token", _e);
}
}
else
authCode = Globals.dao.authenticateAccount(auth.getUsername(), auth.getPassword());
}
DaoEntity rep = new DaoEntity("auth_code", authCode);
if (isPath(_req, 0, "bin"))
zipBsonResponse(_rep, rep);
else
jsonResponse(_rep, rep);
}
}

View File

@ -0,0 +1,101 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import org.apache.commons.io.IOUtils;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import java.io.InputStream;
import java.io.OutputStream;
public abstract class CMServlet extends HttpServlet {
public static void setResponseHtml(HttpServletResponse _response, String _sHtml) {
setResponseEntity(_response, MediaType.TEXT_HTML, _sHtml);
}
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, String _sEntity) {
setResponseEntity(_response, 200, _sContentType, _sEntity);
}
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, byte[] _btData) {
setResponseEntity(_response, 200, _sContentType, _btData);
}
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, String _sEntity) {
setResponseEntity(_response, _iStatus, _sContentType, NullUtils.toByteArray(_sEntity));
}
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, byte[] _btData) {
OutputStream os = null;
try {
_response.setStatus(_iStatus);
_response.setCharacterEncoding("UTF-8");
_response.setContentType(_sContentType);
if ((_btData != null) && (_btData.length > 0)) {
_response.setContentLength(_btData.length);
os = _response.getOutputStream();
os.write(_btData);
} else
_response.setContentLength(0);
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(os);
}
}
protected void zipBsonResponse(HttpServletResponse _response, Object _object)
{
setResponseEntity(_response, 200, MediaType.APPLICATION_OCTET_STREAM, DaoSerializer.toZipBson(_object));
}
protected void jsonResponse(HttpServletResponse _response, Object _object)
{
setResponseEntity(_response, 200, MediaType.APPLICATION_JSON, DaoSerializer.toJson(_object));
}
protected void jsonResponse(HttpServletResponse _response, String _json)
{
setResponseEntity(_response, 200, MediaType.APPLICATION_JSON, _json);
}
protected String getRequestPayloadAsString(HttpServletRequest _req) {
return NullUtils.toString(getRequestPayload(_req));
}
protected byte[] getRequestPayload(HttpServletRequest _req) {
InputStream is = null;
try {
is = _req.getInputStream();
return IOUtils.toByteArray(is);
}
catch (Exception e) {
e.printStackTrace();
return null;
}
finally {
IOUtils.closeQuietly(is);
}
}
protected DaoEntity getRequestZipBson(HttpServletRequest _req) {
return DaoSerializer.fromZipBson(getRequestPayload(_req));
}
protected <T> T getRequestPayload(HttpServletRequest _req, Class<T> _retClass) {
return DaoSerializer.fromZipBson(getRequestPayload(_req), _retClass);
}
protected String[] path(HttpServletRequest _req) {
return NullUtils.cleanSplit(NullUtils.makeNotNull(_req.getPathInfo()), "/");
}
protected boolean isPath(HttpServletRequest _req, int _index, String _path) {
return NullUtils.isEqual(_path, CollectionUtils.get(path(_req), _index));
}
}

View File

@ -0,0 +1,49 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/command")
public class CommandServlet extends SecureServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
File folder = new File(LanternFiles.OPS_PATH + _authCode.getAccountId());
List<String> commands = new ArrayList<>();
if (folder.exists() && folder.isDirectory()) {
for (File command : CollectionUtils.asArrayList(folder.listFiles())) {
if (command.isDirectory())
continue;
String c = command.getName();
String extension = NullUtils.after(c, ".");
if (NullUtils.isNotEmpty(extension))
c = c.replace("." + extension, "");
commands.add(c);
}
}
zipBsonResponse(_rep, new DaoEntity("commands", commands));
}
@Override
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
DaoEntity payload = getRequestZipBson(_req);
if (payload == null)
return;
String command = DaoSerializer.getString(payload, "command");
String path = LanternFiles.OPS_PATH + _authCode.getAccountId() + File.separator + "payload" + File.separator;
new File(path).mkdirs();
ResourceLoader.writeFile(path+ command + ".txt", DaoSerializer.getString(payload, "payload"));
}
}

View File

@ -0,0 +1,34 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/config/*")
public class ConfigServlet extends SecureServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
if (isPath(_req, 0, "bin"))
zipBsonResponse(_rep, Globals.dao.getMergedConfig(_authCode));
else
jsonResponse(_rep, Globals.dao.getMergedConfig(_authCode));
}
@Override
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
BreakerConfig config = getRequestPayload(_req, BreakerConfig.class);
if (config == null) {
_rep.setStatus(400);
return;
}
if (config.getAccountId() != _authCode.getAccountId()) {
_rep.setStatus(401);
return;
}
Globals.dao.putConfig(config);
}
}

View File

@ -0,0 +1,48 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroupEnergy;
import com.lanternsoftware.datamodel.currentmonitor.EnergyBlockViewMode;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
@WebServlet("/energy/group/*")
public class GroupEnergyServlet extends SecureServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
String[] path = path(_req);
if (path.length < 3) {
_rep.setStatus(400);
return;
}
EnergyBlockViewMode viewMode = NullUtils.toEnum(EnergyBlockViewMode.class, path[1], EnergyBlockViewMode.DAY);
Date start = new Date(NullUtils.toLong(path[2]));
List<BreakerGroupEnergy> energies = CollectionUtils.transform(_authCode.getAllAccountIds(), _id->Globals.dao.getBreakerGroupEnergy(_id, path[0], viewMode, start), true);
if (CollectionUtils.isNotEmpty(energies)) {
BreakerGroupEnergy energy;
if (energies.size() > 1) {
energy = new BreakerGroupEnergy();
energy.setAccountId(_authCode.getAccountId());
energy.setGroupId("Sites");
energy.setGroupName("Sites");
energy.setStart(start);
energy.setViewMode(viewMode);
energy.setSubGroups(CollectionUtils.asArrayList(energies));
}
else
energy = CollectionUtils.getFirst(energies);
if (NullUtils.isEqual(CollectionUtils.get(path, 3), "bin"))
zipBsonResponse(_rep, energy);
else
jsonResponse(_rep, energy);
} else
_rep.setStatus(404);
}
}

View File

@ -0,0 +1,26 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import org.bson.Document;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/power/group/*")
public class GroupPowerServlet extends SecureServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
String[] path = path(_req);
if (path.length < 1)
zipBsonResponse(_rep, new DaoEntity("breakers", DaoSerializer.toDaoEntities(Globals.dao.getBreakerPowerForAccount(_authCode.getAccountId()))));
}
}

View File

@ -0,0 +1,49 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoSerializer;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@WebServlet("/power/*")
public class PowerServlet extends SecureServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
String[] path = path(_req);
if (path.length < 2) {
_rep.setStatus(400);
return;
}
int hub = DaoSerializer.toInteger(CollectionUtils.get(path, 0));
int port = DaoSerializer.toInteger(CollectionUtils.get(path, 1));
jsonResponse(_rep, Globals.dao.getLatestBreakerPower(_authCode.getAccountId(), hub, port));
}
@Override
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
String[] path = path(_req);
if ((path.length > 0) && NullUtils.isEqual(CollectionUtils.get(path, 0), "hub")) {
Globals.dao.putHubPowerMinute(getRequestPayload(_req, HubPowerMinute.class));
return;
}
if ((path.length > 0) && NullUtils.isEqual(CollectionUtils.get(path, 0), "batch")) {
List<BreakerPower> powers = DaoSerializer.getList(getRequestZipBson(_req), "readings", BreakerPower.class);
if (!powers.isEmpty()) {
CollectionUtils.edit(powers, _p->_p.setAccountId(_authCode.getAccountId()));
Globals.dao.getProxy().save(powers);
}
return;
}
BreakerPower power = getRequestPayload(_req, BreakerPower.class);
power.setAccountId(_authCode.getAccountId());
Globals.dao.putBreakerPower(power);
}
}

View File

@ -0,0 +1,35 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class SecureServlet extends CMServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
AuthCode authCode = Globals.dao.decryptAuthCode(_req.getHeader("auth_code"));
if (authCode == null) {
_rep.setStatus(401);
return;
}
get(authCode, _req, _rep);
}
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
}
@Override
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
AuthCode authCode = Globals.dao.decryptAuthCode(_req.getHeader("auth_code"));
if (authCode == null) {
_rep.setStatus(401);
return;
}
post(authCode, _req, _rep);
}
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
}
}

View File

@ -0,0 +1,45 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.datamodel.currentmonitor.SignupResponse;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.email.EmailValidator;
import com.lanternsoftware.util.servlet.BasicAuth;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/signup")
public class SignupServlet extends CMServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
BasicAuth auth = new BasicAuth(_req);
Account acct = Globals.dao.getAccountByUsername(auth.getUsername());
if (acct != null) {
jsonResponse(_rep, SignupResponse.error("An account for " + auth.getUsername() + " already exists"));
return;
}
if (!EmailValidator.getInstance().isValid(auth.getUsername())) {
jsonResponse(_rep, SignupResponse.error(auth.getUsername() + " is not a valid email address"));
return;
}
if (NullUtils.length(auth.getPassword()) < 8) {
jsonResponse(_rep, SignupResponse.error("Your password must be at least 8 characters long"));
return;
}
if (NullUtils.isEqual("password", auth.getPassword())) {
jsonResponse(_rep, SignupResponse.error("Seriously? \"password\"? Come on."));
return;
}
acct = new Account();
acct.setUsername(auth.getUsername());
acct.setPassword(auth.getPassword());
Globals.dao.putAccount(acct);
String authCode = Globals.dao.authenticateAccount(auth.getUsername(), auth.getPassword());
jsonResponse(_rep, SignupResponse.success(authCode));
}
}

View File

@ -0,0 +1,22 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoSerializer;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import java.io.File;
@WebServlet("/update/*")
public class UpdateServlet extends CMServlet {
@Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
if (isPath(_req, 0, "version"))
setResponseEntity(_rep, MediaType.APPLICATION_OCTET_STREAM, DaoSerializer.toZipBson(DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.OPS_PATH + "release" + File.separator + "version.json"))));
else
setResponseEntity(_rep, MediaType.APPLICATION_OCTET_STREAM, ResourceLoader.loadFile(LanternFiles.OPS_PATH + "release" + File.separator + "lantern-currentmonitor.jar"));
}
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<logger name="com.lanternsoftware" level="DEBUG"/>
<root level="OFF">
<appender-ref ref="STDOUT"/>
</root>
</configuration>

View File

@ -0,0 +1,9 @@
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<listener>
<listener-class>com.lanternsoftware.currentmonitor.context.Globals</listener-class>
</listener>
</web-app>

View File

@ -0,0 +1,25 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import java.util.Arrays;
public class CreateAccount {
public static void main(String[] args) {
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
Account account = new Account();
account.setId(1);
account.setPassword("*redacted*");
account.setId(2);
account.setUsername("admin@lanternsoftware.com");
account.setPassword("*redacted*");
dao.putAccount(account);
dao.shutdown();
}
}

View File

@ -0,0 +1,15 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.cryptography.AESTool;
import com.lanternsoftware.util.dao.DaoSerializer;
public class CreateAuthCode {
private static final AESTool aes = new AESTool(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "authKey.dat"));
public static void main(String[] args) {
System.out.println(aes.encryptToBase64(DaoSerializer.toZipBson(new AuthCode(100, null))));
}
}

View File

@ -0,0 +1,11 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.cryptography.AESTool;
public class CreateAuthKey {
public static void main(String[] args) {
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "authKey.dat", AESTool.generateRandomSecretKey().getEncoded());
}
}

View File

@ -0,0 +1,241 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPanel;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPolarity;
import com.lanternsoftware.datamodel.currentmonitor.Meter;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class CreateBreakers {
public static void main(String[] args) {
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
/* Breaker bf1 = new Breaker("Solar A", 2, 20, 0, 1, 50, 1.6);
bf1.setPolarity(BreakerPolarity.SOLAR);
Breaker bf2 = new Breaker("Solar B", 2, 18, 0, 2, 50, 1.6);
bf2.setPolarity(BreakerPolarity.SOLAR);
Breaker bf3 = new Breaker("Septic Agitator", 2, 11, 0, 3, 20, 1.6);
Breaker bf4 = new Breaker("Garage/Guest Baths", 2, 5, 0, 4, 20, 1.6);
Breaker bf5 = new Breaker("Office", 2, 2, 0, 5, 20, 1.6);
Breaker bf6 = new Breaker("Upstairs Furnace R-A", 1, 2, 0, 6, 50, 1.6);
Breaker bf7 = new Breaker("Upstairs Furnace R-B", 1, 4, 0, 7, 50, 1.6);
Breaker bf8 = new Breaker("Upstairs Furnace R-C", 1, 6, 0, 8, 30, 1.6);
Breaker bf9 = new Breaker("Upstairs Furnace R-D", 1, 8, 0, 9, 30, 1.6);
Breaker bf10 = new Breaker("Upstairs Furnace HP-A", 1, 1, 0, 10, 30, 1.6);
Breaker bf11 = new Breaker("Upstairs Furnace HP-B", 1, 3, 0, 11, 30, 1.6);
Breaker bf12 = new Breaker("Dryer A", 2, 8, 0, 12, 30, 1.6);
Breaker bf13 = new Breaker("Dryer B", 2, 10, 0, 13, 30, 1.6);
Breaker bf2_1 = new Breaker("Main Furnace R-A", 0, 6, 1, 1, 50, 1.6);
Breaker bf2_2 = new Breaker("Main Furnace R-B", 0, 8, 1, 2, 50, 1.6);
Breaker bf2_3 = new Breaker("Main Furnace R-C", 0, 2, 1, 3, 50, 1.6);
Breaker bf2_4 = new Breaker("Main Furnace R-D", 0, 4, 1, 4, 50, 1.6);
Breaker bf2_5 = new Breaker("Main Furnace HP-A", 0, 1, 1, 5, 30, 1.6);
Breaker bf2_6 = new Breaker("Main Furnace HP-B", 0, 3, 1, 6, 30, 1.6);
Breaker bf2_7 = new Breaker("Hot Water Heater A", 0, 5, 1, 7, 30, 1.6);
Breaker bf2_8 = new Breaker("Hot Water Heater B", 0, 7, 1, 8, 30, 1.6);
Breaker bf2_9 = new Breaker("Basement HP-A", 1, 13, 1, 9, 30, 1.6);
Breaker bf2_10 = new Breaker("Basement HP-B", 1, 15, 1, 10, 30, 1.6);
Breaker bf2_11 = new Breaker("Oven A", 2, 12, 1, 11, 50, 1.6);
Breaker bf2_12 = new Breaker("Oven B", 2, 14, 1, 12, 50, 1.6);
Breaker bf2_13 = new Breaker("Master Bathroom", 3, 9, 2, 5, 20, 1.6);
Breaker bf2_14 = new Breaker("Refrigerator", 2, 6, 1, 14, 20, 1.6);
bf2_14.setSpaceTandemB(6);
Breaker bf2_15 = new Breaker("Master Bedroom", 2, 1, 1, 15, 20, 1.6);
BreakerGroup basementHP = new BreakerGroup("6", "Heat Pump", Arrays.asList(bf2_9, bf2_10));
BreakerGroup basementCC = new BreakerGroup("3", "Basement", Arrays.asList(basementHP), null);
BreakerGroup mainHP = new BreakerGroup("5", "Heat Pump", Arrays.asList(bf2_5, bf2_6));
BreakerGroup mainR = new BreakerGroup("4", "Air Handler/Resistive", Arrays.asList(bf2_1, bf2_2, bf2_3, bf2_4));
BreakerGroup mainCC = new BreakerGroup("2", "Main Floor", Arrays.asList(mainHP, mainR), null);
BreakerGroup upstairsHP = new BreakerGroup("34", "Heat Pump", Arrays.asList(bf10, bf11));
BreakerGroup upstairsR = new BreakerGroup("35", "Air Handler/Resistive", Arrays.asList(bf6, bf7, bf8, bf9));
BreakerGroup upstairsCC = new BreakerGroup("36", "Upstairs", Arrays.asList(upstairsHP, upstairsR), null);
BreakerGroup cc = new BreakerGroup("1", "Climate Control", Arrays.asList(mainCC, upstairsCC, basementCC), null);
BreakerGroup hotWater = new BreakerGroup("7", "Hot Water Heater", Arrays.asList(bf2_7, bf2_8));
BreakerGroup oven = new BreakerGroup("8", "Oven/Cooktop", Arrays.asList(bf2_11, bf2_12));
BreakerGroup masterBR = new BreakerGroup("9", "Master Bedroom", Arrays.asList(bf2_13, bf2_15));
BreakerGroup fridge = new BreakerGroup("10", "Refrigerator", Arrays.asList(bf2_14));
BreakerGroup solar = new BreakerGroup("11", "Solar", Arrays.asList(bf1, bf2));
BreakerGroup septic = new BreakerGroup("13", "Septic Aerator", Arrays.asList(bf3));
BreakerGroup garage = new BreakerGroup("14", "Garage/Guest Baths", Arrays.asList(bf4));
BreakerGroup office = new BreakerGroup("15", "Office", Arrays.asList(bf5));
BreakerGroup dryer = new BreakerGroup("37", "Dryer", Arrays.asList(bf12, bf13));
Breaker bf3_1 = new Breaker("Hub 2 Port 1", 3, 1, 2, 1, 20, 1.6);
Breaker bf3_2 = new Breaker("Hub 2 Port 2", 3, 3, 2, 2, 20, 1.6);
Breaker bf3_3 = new Breaker("Hub 2 Port 3", 3, 5, 2, 3, 20, 1.6);
Breaker bf3_4 = new Breaker("Hub 2 Port 4", 3, 7, 2, 4, 20, 1.6);
Breaker bf3_6 = new Breaker("Hub 2 Port 6", 3, 11, 2, 6, 20, 1.6);
Breaker bf3_7 = new Breaker("Hub 2 Port 7", 3, 13, 2, 7, 20, 1.6);
Breaker bf3_8 = new Breaker("Hub 2 Port 8", 3, 15, 2, 8, 20, 1.6);
Breaker bf3_9 = new Breaker("Hub 2 Port 9", 3, 2, 2, 9, 20, 1.6);
Breaker bf3_10 = new Breaker("Hub 2 Port 10", 3, 4, 2, 10, 20, 1.6);
Breaker bf3_12 = new Breaker("Hub 2 Port 12", 3, 6, 2, 12, 20, 1.6);
Breaker bf3_13 = new Breaker("Hub 2 Port 13", 3, 8, 2, 13, 20, 1.6);
Breaker bf3_14 = new Breaker("Hub 2 Port 14", 3, 10, 2, 14, 20, 1.6);
BreakerGroup g1 = new BreakerGroup("17", "Living Room/Printer/Outdoor Lights", Arrays.asList(bf3_1));
BreakerGroup g2 = new BreakerGroup("18", "Dishwasher/Disposal/Sink Lights", Arrays.asList(bf3_2));
BreakerGroup g3 = new BreakerGroup("19", "Microwave", Arrays.asList(bf3_3));
BreakerGroup g4 = new BreakerGroup("20", "Kitchen Outlets", Arrays.asList(bf3_4));
// BreakerGroup g5 = new BreakerGroup("21", "Hub 2 Port 5", Arrays.asList(bf3_5));
BreakerGroup g6 = new BreakerGroup("22", "Mini Fridge", Arrays.asList(bf3_6));
BreakerGroup g7 = new BreakerGroup("23", "Basement Lights/Outlets", Arrays.asList(bf3_7));
BreakerGroup g8 = new BreakerGroup("24", "Theatre", Arrays.asList(bf3_8));
BreakerGroup g9 = new BreakerGroup("25", "Sunroom Fan/Outside Floods", Arrays.asList(bf3_9));
BreakerGroup g10 = new BreakerGroup("26", "Radon/Deep Freezer", Arrays.asList(bf3_10));
// BreakerGroup g11 = new BreakerGroup("27", "Hub 2 Port 11", Arrays.asList(bf3_11));
BreakerGroup g12 = new BreakerGroup("28", "Kitchen Lights", Arrays.asList(bf3_12));
BreakerGroup g13 = new BreakerGroup("29", "Router/Networking", Arrays.asList(bf3_13));
BreakerGroup g14 = new BreakerGroup("30", "Half Bath/Utility/Garage Lights", Arrays.asList(bf3_14));
// BreakerGroup g15 = new BreakerGroup("31", "Bar Outlets", Arrays.asList(bf3_15));
BreakerGroup kitchen = new BreakerGroup("33", "Kitchen", Arrays.asList(oven, fridge, g2, g3, g4, g12), null);
Breaker b4_1 = new Breaker("Hub 3 Port 1", 4, 1, 3, 1, 20, 1.6);
Breaker b4_2 = new Breaker("Hub 3 Port 2", 4, 2, 3, 2, 30, 1.6);
Breaker b4_3 = new Breaker("Hub 3 Port 3", 4, 3, 3, 3, 50, 1.6);
Breaker b4_4 = new Breaker("Hub 3 Port 4", 4, 4, 3, 4, 20, 1.6);
Breaker b4_5 = new Breaker("Hub 3 Port 5", 4, 5, 3, 5, 20, 1.6);
Breaker b4_6 = new Breaker("Hub 3 Port 6", 4, 6, 3, 6, 20, 1.6);
Breaker b4_7 = new Breaker("Hub 3 Port 7", 4, 7, 3, 7, 20, 1.6);
Breaker b4_8 = new Breaker("Hub 3 Port 8", 4, 8, 3, 8, 20, 1.6);
Breaker b4_9 = new Breaker("Hub 3 Port 9", 4, 9, 3, 9, 20, 1.6);
Breaker b4_10 = new Breaker("Hub 3 Port 10", 4, 10, 3, 10, 20, 1.6);
Breaker b4_11 = new Breaker("Hub 3 Port 11", 4, 11, 3, 11, 20, 1.6);
Breaker b4_12 = new Breaker("Hub 3 Port 12", 4, 12, 3, 12, 20, 1.6);
Breaker b4_13 = new Breaker("Hub 3 Port 13", 4, 13, 3, 13, 20, 1.6);
Breaker b4_14 = new Breaker("Hub 3 Port 14", 4, 14, 3, 14, 20, 1.6);
Breaker b4_15 = new Breaker("Hub 3 Port 15", 4, 15, 3, 15, 20, 1.6);
BreakerGroup g4_1 = new BreakerGroup("41", "Hub 3 Port 1", Arrays.asList(b4_1));
BreakerGroup g4_2 = new BreakerGroup("42", "Hub 3 Port 2", Arrays.asList(b4_2));
BreakerGroup g4_3 = new BreakerGroup("43", "Hub 3 Port 3", Arrays.asList(b4_3));
BreakerGroup g4_4 = new BreakerGroup("44", "Hub 3 Port 4", Arrays.asList(b4_4));
BreakerGroup g4_5 = new BreakerGroup("45", "Hub 3 Port 5", Arrays.asList(b4_5));
BreakerGroup g4_6 = new BreakerGroup("46", "Hub 3 Port 6", Arrays.asList(b4_6));
BreakerGroup g4_7 = new BreakerGroup("47", "Hub 3 Port 7", Arrays.asList(b4_7));
BreakerGroup g4_8 = new BreakerGroup("48", "Hub 3 Port 8", Arrays.asList(b4_8));
BreakerGroup g4_9 = new BreakerGroup("49", "Hub 3 Port 9", Arrays.asList(b4_9));
BreakerGroup g4_10 = new BreakerGroup("50", "Hub 3 Port 10", Arrays.asList(b4_10));
BreakerGroup g4_11 = new BreakerGroup("51", "Hub 3 Port 11", Arrays.asList(b4_11));
BreakerGroup g4_12 = new BreakerGroup("52", "Hub 3 Port 12", Arrays.asList(b4_12));
BreakerGroup g4_13 = new BreakerGroup("53", "Hub 3 Port 13", Arrays.asList(b4_13));
BreakerGroup g4_14 = new BreakerGroup("54", "Hub 3 Port 14", Arrays.asList(b4_14));
BreakerGroup g4_15 = new BreakerGroup("55", "Hub 3 Port 15", Arrays.asList(b4_15));
BreakerGroup debug = new BreakerGroup("40", "Debug Hub 3", Arrays.asList(g4_1, g4_2, g4_3), null);
// BreakerGroup debug = new BreakerGroup("40", "Debug Hub 3", Arrays.asList(g4_1, g4_2, g4_3, g4_4, g4_5, g4_6, g4_7, g4_8, g4_9, g4_10, g4_11, g4_12, g4_13, g4_14, g4_15), null);
// BreakerGroup debug = new BreakerGroup("40", "Debug Hub 3", Arrays.asList(b4_1));
BreakerGroup house = new BreakerGroup("0", "*redacted*", Arrays.asList(solar, cc, hotWater, dryer, septic, masterBR, garage, office, kitchen, g1, g6, g7, g8, g9, g10, g13, g14, debug), null);
BreakerConfig config = new BreakerConfig(Collections.singletonList(house));
CollectionUtils.edit(config.getAllBreakerGroups(), _g->_g.setAccountId(1));
CollectionUtils.edit(config.getAllBreakers(), _b->{
_b.setAccountId(1);
_b.setCalibrationFactor(1.0);
});
b4_1.setCalibrationFactor(1.215);
b4_2.setCalibrationFactor(1.215);
b4_3.setCalibrationFactor(1.215);
config.setAccountId(1);
BreakerHub hub0 = new BreakerHub();
hub0.setHub(0);
hub0.setVoltageCalibrationFactor(0.4587);
hub0.setFrequency(60);
BreakerHub hub1 = new BreakerHub();
hub1.setHub(1);
hub1.setVoltageCalibrationFactor(0.439);
hub1.setFrequency(60);
BreakerHub hub2 = new BreakerHub();
hub2.setHub(2);
hub2.setVoltageCalibrationFactor(0.3535);
hub2.setFrequency(60);
BreakerHub hub3 = new BreakerHub();
hub3.setHub(3);
hub3.setVoltageCalibrationFactor(0.419);
hub3.setFrequency(60);
config.setBreakerHubs(Arrays.asList(hub0, hub1, hub2, hub3));
Meter heatMeter = new Meter();
heatMeter.setAccountId(1);
heatMeter.setIndex(0);
heatMeter.setName("Heat");
Meter mainMeter = new Meter();
mainMeter.setAccountId(1);
mainMeter.setIndex(1);
mainMeter.setName("Main/Solar");
config.setMeters(CollectionUtils.asArrayList(heatMeter, mainMeter));
BreakerPanel heat1 = new BreakerPanel();
heat1.setAccountId(1);
heat1.setIndex(0);
heat1.setMeter(heatMeter.getIndex());
heat1.setName("Heat 1");
heat1.setSpaces(20);
BreakerPanel heat2 = new BreakerPanel();
heat2.setAccountId(1);
heat2.setIndex(1);
heat2.setMeter(heatMeter.getIndex());
heat2.setName("Heat 2");
heat2.setSpaces(20);
BreakerPanel main = new BreakerPanel();
main.setAccountId(1);
main.setIndex(2);
main.setMeter(mainMeter.getIndex());
main.setName("Main");
main.setSpaces(20);
BreakerPanel sub = new BreakerPanel();
sub.setAccountId(1);
sub.setIndex(3);
sub.setMeter(mainMeter.getIndex());
sub.setName("Sub-Panel");
sub.setSpaces(20);
config.setPanels(CollectionUtils.asArrayList(heat1, heat2, main, sub));
Map<Integer, Integer> panelToMeter = CollectionUtils.transformToMap(config.getPanels(), BreakerPanel::getIndex, BreakerPanel::getMeter);
CollectionUtils.edit(config.getAllBreakers(), _b->_b.setMeter(DaoSerializer.toInteger(panelToMeter.get(_b.getPanel()))));*/
BreakerConfig config = dao.getConfig(1);
// BreakerConfig config = DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.OPS_PATH + "breakerconfig_backup_210107.json"), BreakerConfig.class);
// ResourceLoader.writeFile(LanternFiles.OPS_PATH + "breakerconfig_backup_210107.json", DaoSerializer.toJson(config));
// CollectionUtils.edit(config.getAllBreakerGroups(), _g->{
// if (NullUtils.isEmpty(_g.getName())) {
// Breaker b = CollectionUtils.getFirst(_g.getBreakers());
// if (b != null)
// _g.setName(String.format("Panel %d, %s", b.getPanel(), b.getName()));
// }
// });
// for (BreakerGroup group : CollectionUtils.filter(config.getAllBreakerGroups(), _g->NullUtils.isEmpty(_g.getId()))) {
// List<Integer> ids = CollectionUtils.transform(config.getAllBreakerGroupIds(), NullUtils::toInteger);
// group.setId(String.valueOf(CollectionUtils.getLargest(ids) + 1));
// }
// BreakerGroup root = CollectionUtils.getFirst(config.getBreakerGroups());
// root.getSubGroups().removeIf(_g->_g.getName().equals("Debug Hub 3"));
// config.removeInvalidGroups();
// for (BreakerGroup group : config.getAllBreakerGroups()) {
// if (NullUtils.isEmpty(group.getId())) {
// List<Integer> ids = CollectionUtils.transform(config.getAllBreakerGroupIds(), NullUtils::toInteger);
// group.setId(String.valueOf(CollectionUtils.getLargest(ids) + 1));
// }
// }
dao.putConfig(config);
dao.shutdown();
}
}

View File

@ -0,0 +1,10 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
public class CreateMongoConfig {
public static void main(String[] args) {
new MongoConfig("localhost", "*redacted*", "*redacted*", "CURRENT_MONITOR").saveToDisk(LanternFiles.OPS_PATH + "mongo.cfg");
}
}

View File

@ -0,0 +1,13 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.dao.generator.DaoSerializerGenerator;
import com.lanternsoftware.util.dao.generator.SwiftModelGenerator;
public class CurrentMonitorSerializers {
public static void main(String[] args) {
DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_PATH + "currentmonitor", true, null);
SwiftModelGenerator.generateModel(LanternFiles.SOURCE_PATH + "currentmonitor", LanternFiles.SOURCE_PATH + "iOS");
}
}

Some files were not shown because too many files have changed in this diff Show More