Improve 3A+ case, making it easier to take the pi out. Improve the fit of the Z2 case.

Make it possible for a hub to reload a config automatically when it changes without being restarted.
Prevent the auto-calibration on first install from being stomped by the app.
Allow updating the hub software via the app.
This commit is contained in:
MarkBryanMilligan
2022-01-13 14:33:21 -06:00
parent 88ed044ef7
commit ed75ab1f05
38 changed files with 659 additions and 261 deletions

View File

@@ -3,7 +3,7 @@
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-currentmonitor</artifactId>
<packaging>jar</packaging>
<version>1.0.4</version>
<version>1.0.6</version>
<name>lantern-currentmonitor</name>
<properties>

View File

@@ -97,12 +97,17 @@ public class CurrentMonitor {
}
public void monitorPower(BreakerHub _hub, List<Breaker> _breakers, int _intervalMs, PowerListener _listener) {
stopMonitoring();
listener = _listener;
List<Breaker> validBreakers = CollectionUtils.filter(_breakers, _b->_b.getPort() > 0 && _b.getPort() < 16);
sampler = new Sampler(_hub, validBreakers, _intervalMs, 2);
LOG.info("Starting to monitor ports {}", CollectionUtils.transformToCommaSeparated(validBreakers, _b->String.valueOf(_b.getPort())));
executor.submit(sampler);
try {
stopMonitoring();
listener = _listener;
List<Breaker> validBreakers = CollectionUtils.filter(_breakers, _b -> _b.getPort() > 0 && _b.getPort() < 16);
sampler = new Sampler(_hub, validBreakers, _intervalMs, 2);
LOG.info("Starting to monitor ports {}", CollectionUtils.transformToCommaSeparated(validBreakers, _b -> String.valueOf(_b.getPort())));
executor.submit(sampler);
}
catch (Throwable t) {
LOG.error("throwable", t);
}
}
private GpioPinAnalogInput getPin(int _chip, int _pin) {
@@ -182,8 +187,10 @@ public class CurrentMonitor {
try {
while (true) {
synchronized (this) {
if (!running)
if (!running) {
LOG.error("Power Monitoring Stopped");
break;
}
}
final Date readTime = new Date();
final long intervalStart = (interval * intervalNs) + start;

View File

@@ -10,6 +10,8 @@ import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPowerMinute;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubCommands;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigService;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
@@ -25,6 +27,7 @@ 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.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
@@ -39,10 +42,12 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -64,7 +69,7 @@ public class MonitorApp {
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 String version;
private static final PowerListener logger = _p -> {
if (!config.isDebug()) {
_p.setHubVersion(version);
@@ -76,9 +81,138 @@ public class MonitorApp {
} else
LOG.info("Panel{} - Space{} Power: {}W", _p.getPanel(), Breaker.toSpaceDisplay(_p.getSpace()), String.format("%.3f", _p.getPower()));
};
private static final BleCharacteristicListener bluetoothListener = 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(()->{
synchronized (monitor) {
switch (ch) {
case Host:
if ((_value.length > 0)) {
config.setHost(NullUtils.terminateWith(NullUtils.toString(_value), "/") + "currentmonitor/");
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
}
break;
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(new String[]{"systemctl","restart","currentmonitor"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
break;
case Reboot:
LOG.info("Rebooting Pi...");
try {
Runtime.getRuntime().exec(new String[]{"reboot","now"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to reboot", _e);
}
break;
case Shutdown:
LOG.info("Shutting down Pi...");
try {
Runtime.getRuntime().exec(new String[]{"shutdown","now"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to shutdown", _e);
}
break;
case Update:
monitor.submit(new UpdateChecker(true));
break;
case ReloadConfig:
HttpGet get = new HttpGet(host + "config");
get.addHeader("auth_code", authCode);
BreakerConfig newConfig = DaoSerializer.parse(pool.executeToString(get), BreakerConfig.class);
if (newConfig != null) {
breakerConfig = newConfig;
List<Breaker> breakers = breakerConfig.getBreakersForHub(config.getHub());
BreakerHub hub = breakerConfig.getHub(config.getHub());
if (hub != null) {
LOG.info("Monitoring {} breakers for hub {}", CollectionUtils.size(breakers), hub.getHub());
if (CollectionUtils.size(breakers) > 0)
monitor.monitorPower(hub, breakers, 1000, logger);
}
}
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()};
if (HubConfigCharacteristic.NetworkDetails == ch) {
NetworkStatus status = NetworkMonitor.getNetworkStatus();
DaoEntity meta = (host == null)?null:DaoSerializer.fromZipBson(pool.executeToByteArray(new HttpGet(host + "update/version")));
status.setPingSuccessful(CollectionUtils.isNotEmpty(meta));
return DaoSerializer.toZipBson(status);
}
if (HubConfigCharacteristic.Log == ch) {
String[] log = NullUtils.cleanSplit(ResourceLoader.loadFileAsString(WORKING_DIR + "log/log.txt"), "\n");
if (log.length > 15)
log = Arrays.copyOfRange(log, log.length-15, log.length);
return ZipUtils.zip(NullUtils.toByteArray(CollectionUtils.delimit(Arrays.asList(log), "\n")));
}
if (HubConfigCharacteristic.Version == ch)
return NullUtils.toByteArray(version);
return null;
}
};
private static BluetoothConfig bluetoothConfig;
private static MqttPoster mqttPoster;
public static void main(String[] args) {
try {
Runtime.getRuntime().exec(new String[]{"systemctl","restart","dbus"});
ConcurrencyUtils.sleep(500);
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
version = getVersionNumber();
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");
@@ -90,107 +224,7 @@ public class MonitorApp {
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(()->{
synchronized (monitor) {
switch (ch) {
case Host:
if ((_value.length > 0)) {
config.setHost(NullUtils.terminateWith(NullUtils.toString(_value), "/") + "currentmonitor/");
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
}
break;
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(new String[]{"systemctl","restart","currentmonitor"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
break;
case Reboot:
LOG.info("Rebooting Pi...");
try {
Runtime.getRuntime().exec(new String[]{"reboot","now"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to reboot", _e);
}
break;
case Shutdown:
LOG.info("Shutting down Pi...");
try {
Runtime.getRuntime().exec(new String[]{"shutdown","now"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to shutdown", _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()};
if (HubConfigCharacteristic.NetworkDetails == ch) {
NetworkStatus status = NetworkMonitor.getNetworkStatus();
DaoEntity meta = (host == null)?null:DaoSerializer.fromZipBson(pool.executeToByteArray(new HttpGet(host + "update/version")));
status.setPingSuccessful(CollectionUtils.isNotEmpty(meta));
return DaoSerializer.toZipBson(status);
}
if (HubConfigCharacteristic.Log == ch) {
String[] log = NullUtils.cleanSplit(ResourceLoader.loadFileAsString(WORKING_DIR + "log/log.txt"), "\n");
if (log.length > 15)
log = Arrays.copyOfRange(log, log.length-15, log.length);
return ZipUtils.zip(NullUtils.toByteArray(CollectionUtils.delimit(Arrays.asList(log), "\n")));
}
return null;
}
});
bluetoothConfig = new BluetoothConfig("Lantern Hub", bluetoothListener);
bluetoothConfig.start();
if (NullUtils.isNotEmpty(config.getAuthCode()))
authCode = config.getAuthCode();
@@ -303,6 +337,7 @@ public class MonitorApp {
if (!readings.isEmpty()) {
mqttReadings.addAll(readings);
post = new DaoEntity("readings", DaoSerializer.toDaoEntities(readings));
post.put("hub", config.getHub());
if (curMinute != lastMinute) {
HubPowerMinute minute = new HubPowerMinute();
minute.setAccountId(breakerConfig.getAccountId());
@@ -336,7 +371,8 @@ public class MonitorApp {
}
if (post != null) {
byte[] payload = DaoSerializer.toZipBson(post);
if (post(payload, "power/batch")) {
PostResponse<HubCommands> resp = post(payload, "power/batch", HubCommands.class);
if (resp.success) {
File[] files = new File(WORKING_DIR + "cache").listFiles();
if (files != null) {
for (File file : files) {
@@ -347,6 +383,11 @@ public class MonitorApp {
break;
}
}
if (resp.t != null) {
for (HubCommand command : resp.t.getCommands()) {
bluetoothListener.write(command.getCharacteristic().name(), command.getData());
}
}
}
}
}
@@ -355,7 +396,6 @@ public class MonitorApp {
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;
@@ -371,34 +411,65 @@ public class MonitorApp {
}
}
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) {
return post(_payload, _path, Boolean.class).success;
}
private static boolean post(byte[] _payload, String _path) {
private static <T> PostResponse<T> post(byte[] _payload, String _path, Class<T> _class) {
if (NullUtils.isEmpty(host))
return false;
return new PostResponse<>(false, null);
HttpPost post = new HttpPost(host + _path);
post.addHeader("auth_code", authCode);
post.setEntity(new ByteArrayEntity(_payload, ContentType.APPLICATION_OCTET_STREAM));
InputStream is = null;
CloseableHttpResponse resp = pool.execute(post);
try {
return ((resp != null) && (resp.getStatusLine() != null) && (resp.getStatusLine().getStatusCode() == 200));
} finally {
if ((resp != null) && (resp.getStatusLine() != null) && (resp.getStatusLine().getStatusCode() == 200)) {
T t = null;
HttpEntity entity = resp.getEntity();
if (entity != null) {
is = entity.getContent();
byte[] payload = IOUtils.toByteArray(is);
if (CollectionUtils.length(payload) > 0)
t = DaoSerializer.fromZipBson(payload, _class);
}
return new PostResponse<>(true, t);
}
}
catch (Exception _e) {
LOG.error("Failed to make http request to " + post.getURI().toString(), _e);
}
finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(resp);
}
return new PostResponse<>(false, null);
}
private static class PostResponse<T> {
public final boolean success;
public final T t;
public PostResponse(boolean _success, T _t) {
success = _success;
t = _t;
}
}
private static final class UpdateChecker implements Runnable {
private final boolean force;
public UpdateChecker() {
force = false;
}
public UpdateChecker(boolean _force) {
force = _force;
}
@Override
public void run() {
if (NullUtils.isNotEmpty(host) && config.isAutoUpdate()) {
if (NullUtils.isNotEmpty(host) && (force || config.isAutoUpdate())) {
DaoEntity meta = DaoSerializer.fromZipBson(pool.executeToByteArray(new HttpGet(host + "update/version")));
String newVersion = DaoSerializer.getString(meta, "version");
if (NullUtils.isNotEqual(newVersion, version)) {
@@ -407,9 +478,14 @@ public class MonitorApp {
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);
ConcurrencyUtils.sleep(10000);
synchronized (running) {
running.set(false);
}
monitor.stopMonitoring();
bluetoothConfig.stop();
pool.shutdown();
try {
Runtime.getRuntime().exec(new String[]{"systemctl", "restart", "currentmonitor"});
Runtime.getRuntime().exec(new String[]{"systemctl","restart","currentmonitor"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
@@ -419,65 +495,29 @@ public class MonitorApp {
}
}
private static final class CommandChecker implements Runnable {
@Override
public void run() {
if (NullUtils.isNotEmpty(host)) {
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(new String[]{"sudo", "raspi-config", "--expand-rootfs"});
ConcurrencyUtils.sleep(5000);
Runtime.getRuntime().exec(new String[]{"reboot", "now"});
} 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(new String[]{"systemctl", "restart", "currentmonitor"});
} catch (IOException _e) {
LOG.error("Exception occurred while trying to restart", _e);
}
}
}
}
}
}
private static String getVersionNumber() {
InputStream is = null;
public static String getVersionNumber() {
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;
Enumeration<URL> resources = MonitorApp.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
while (resources.hasMoreElements()) {
InputStream is = null;
try {
is = resources.nextElement().openStream();
Manifest manifest = new Manifest(is);
Attributes attr = manifest.getMainAttributes();
if (NullUtils.isEqual(attr.getValue("Specification-Title"), "Lantern Power Monitor")) {
String version = attr.getValue("Specification-Version");
LOG.info("Current Version: {}", version);
return version;
}
}
finally {
IOUtils.closeQuietly(is);
}
}
}
catch (Exception _e) {
LOG.error("Failed to get current version number", _e);
return "";
}
finally {
IOUtils.closeQuietly(is);
}
return "";
}
}

View File

@@ -2,6 +2,8 @@ package com.lanternsoftware.dataaccess.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.ChargeSummary;
import com.lanternsoftware.datamodel.currentmonitor.ChargeTotal;
import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
import com.lanternsoftware.datamodel.currentmonitor.EnergyTotal;
import com.lanternsoftware.datamodel.currentmonitor.Sequence;
@@ -10,14 +12,15 @@ import com.lanternsoftware.datamodel.rules.FcmDevice;
import com.lanternsoftware.datamodel.rules.Rule;
import com.lanternsoftware.util.DebugTimer;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.dao.DaoQuery;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import java.util.List;
public class Backup {
public static void main(String[] args) {
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_PATH + "mongo.cfg"));
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_SOURCE + "mongo.cfg"));
CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST + "mongo.cfg"));
DebugTimer t1 = new DebugTimer("Query Accounts");
List<Account> accounts = dao.getProxy().queryAll(Account.class);
@@ -34,17 +37,39 @@ public class Backup {
t4.stop();
DebugTimer t5 = new DebugTimer("Query Energy");
List<EnergySummary> energy = dao.getProxy().queryAll(EnergySummary.class);
for (Account a : accounts) {
List<EnergySummary> energy = dao.getProxy().query(EnergySummary.class, new DaoQuery("account_id", a.getId()));
DebugTimer t = new DebugTimer("Save Energy");
backupDao.getProxy().save(energy);
t.stop();
}
t5.stop();
DebugTimer t6 = new DebugTimer("Save Energy");
backupDao.getProxy().save(energy);
DebugTimer t6 = new DebugTimer("Query Energy Totals");
for (Account a : accounts) {
List<EnergyTotal> total = dao.getProxy().query(EnergyTotal.class, new DaoQuery("account_id", a.getId()));
DebugTimer t = new DebugTimer("Save Summary");
backupDao.getProxy().save(total);
t.stop();
}
t6.stop();
DebugTimer t7 = new DebugTimer("Query Summaries");
List<EnergyTotal> summary = dao.getProxy().queryAll(EnergyTotal.class);
DebugTimer t7 = new DebugTimer("Query Charges");
for (Account a : accounts) {
List<ChargeSummary> charges = dao.getProxy().query(ChargeSummary.class, new DaoQuery("account_id", a.getId()));
DebugTimer t = new DebugTimer("Save Charges");
backupDao.getProxy().save(charges);
t.stop();
}
t7.stop();
DebugTimer t8 = new DebugTimer("Save Summaries");
backupDao.getProxy().save(summary);
DebugTimer t8 = new DebugTimer("Query Charge Totals");
for (Account a : accounts) {
List<ChargeTotal> charges = dao.getProxy().query(ChargeTotal.class, new DaoQuery("account_id", a.getId()));
DebugTimer t = new DebugTimer("Save Charge Totals");
backupDao.getProxy().save(charges);
t.stop();
}
t8.stop();
DebugTimer t9 = new DebugTimer("Query Events");

View File

@@ -16,8 +16,8 @@ import java.util.TimeZone;
public class BackupMinutes {
public static void main(String[] args) {
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_PATH + "mongo.cfg"));
CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_SOURCE + "mongo.cfg"));
CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST + "mongo.cfg"));
Date now = new Date();
for (Account a : dao.getProxy().queryAll(Account.class)) {
if (a.getId() == 0)
@@ -30,12 +30,11 @@ public class BackupMinutes {
HubPowerMinute minute = dao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sort("minute"));
if (minute == null)
continue;
Date minStart = DateUtils.addDays(DateUtils.getMidnightBeforeNow(tz), -60, tz);
Date start = DateUtils.getMidnightBefore(minute.getMinuteAsDate(), tz);
if (minStart.after(start))
start = minStart;
HubPowerMinute lastBackup = backupDao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sortDesc("minute"));
Date start = lastBackup == null ? DateUtils.getMidnightBefore(minute.getMinuteAsDate(), tz) : lastBackup.getMinuteAsDate();
// Date start = DateUtils.date(10,16,2021,tz);
Date end = DateUtils.addDays(start, 1, tz);
while (end.before(now)) {
while (start.before(now)) {
DebugTimer t2 = new DebugTimer("Account Id: " + a.getId() + " Query Day " + DateUtils.format("MM/dd/yyyy", tz, start));
List<HubPowerMinute> minutes = dao.getProxy().query(HubPowerMinute.class, new DaoQuery("account_id", a.getId()).andBetweenInclusiveExclusive("minute", (int) (start.getTime() / 60000), (int) (end.getTime() / 60000)));
t2.stop();

View File

@@ -5,6 +5,7 @@ import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
import com.lanternsoftware.datamodel.currentmonitor.EnergyViewMode;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
import com.lanternsoftware.util.dao.auth.AuthCode;
import com.lanternsoftware.util.dao.mongo.MongoProxy;
@@ -48,5 +49,9 @@ public interface CurrentMonitorDao {
TimeZone getTimeZoneForAccount(int _accountId);
String getTimeZoneForAccount(String _authCode);
void putHubCommand(HubCommand _command);
List<HubCommand> getAllHubCommands();
void deleteHubCommand(String _id);
MongoProxy getProxy();
}

View File

@@ -6,12 +6,14 @@ import com.lanternsoftware.datamodel.currentmonitor.BillingRate;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
import com.lanternsoftware.datamodel.currentmonitor.ChargeSummary;
import com.lanternsoftware.datamodel.currentmonitor.ChargeTotal;
import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
import com.lanternsoftware.datamodel.currentmonitor.EnergyTotal;
import com.lanternsoftware.datamodel.currentmonitor.EnergyViewMode;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
import com.lanternsoftware.datamodel.currentmonitor.Sequence;
import com.lanternsoftware.util.CollectionUtils;
@@ -404,6 +406,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
if (config == null) {
config = new BreakerConfig();
config.setAccountId(_authCode.getAccountId());
config.setVersion(config.getVersion());
return config;
}
}
@@ -416,6 +419,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
config.setMeters(CollectionUtils.aggregate(configs, BreakerConfig::getMeters));
config.setBillingPlans(CollectionUtils.aggregate(configs, BreakerConfig::getBillingPlans));
config.setBillingRates(CollectionUtils.aggregate(configs, BreakerConfig::getBillingRates));
config.setVersion(CollectionUtils.getLargest(CollectionUtils.transform(configs, BreakerConfig::getVersion)));
return config;
}
@@ -424,6 +428,16 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
DaoQuery configQuery = new DaoQuery("_id", String.valueOf(_config.getAccountId()));
BreakerConfig oldConfig = proxy.queryOne(BreakerConfig.class, configQuery);
if (oldConfig != null) {
logger.info("old version: {}, new version: {}", oldConfig.getVersion(), _config.getVersion());
if (oldConfig.getVersion() > _config.getVersion()) {
for (BreakerHub hub : CollectionUtils.makeNotNull(_config.getBreakerHubs())) {
BreakerHub oldHub = oldConfig.getHub(hub.getHub());
if (oldHub != null) {
logger.info("Prevent overwrite of voltage calibration");
hub.setVoltageCalibrationFactor(oldHub.getRawVoltageCalibrationFactor());
}
}
}
_config.setVersion(oldConfig.getVersion() + 1);
if (NullUtils.isNotIdentical(_config, oldConfig)) {
DaoEntity oldEntity = DaoSerializer.toDaoEntity(oldConfig);
@@ -441,6 +455,9 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
});
}
}
for (BreakerHub hub : CollectionUtils.makeNotNull(_config.getBreakerHubs())) {
logger.info("voltage calibration hub {}: {}", hub.getHub(), hub.getVoltageCalibrationFactor());
}
proxy.save(_config);
}
@@ -459,7 +476,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
AuthCode code = decryptAuthCode(_authCode);
if (code == null)
return null;
return proxy.queryOne(Account.class, new DaoQuery("_id", code.getAccountId()));
return proxy.queryOne(Account.class, new DaoQuery("_id", String.valueOf(code.getAccountId())));
}
@Override
@@ -572,6 +589,23 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
return true;
}
@Override
public void putHubCommand(HubCommand _command) {
BreakerConfig config = getConfig(_command.getAccountId());
if (config != null)
proxy.save(_command.forAllHubs(config));
}
@Override
public List<HubCommand> getAllHubCommands() {
return proxy.queryAll(HubCommand.class);
}
@Override
public void deleteHubCommand(String _id) {
proxy.delete(HubCommand.class, new DaoQuery("_id", _id));
}
@Override
public MongoProxy getProxy() {
return proxy;

View File

@@ -209,7 +209,7 @@ public class BreakerConfig implements IIdentical<BreakerConfig> {
@Override
public boolean isIdentical(BreakerConfig _o) {
if (this == _o) return true;
return accountId == _o.accountId && CollectionUtils.isIdentical(meters, _o.meters) && CollectionUtils.isIdentical(panels, _o.panels) && CollectionUtils.isIdentical(breakerHubs, _o.breakerHubs) && CollectionUtils.isIdentical(breakerGroups, _o.breakerGroups) && CollectionUtils.isEqual(billingPlans, _o.billingPlans);
return accountId == _o.accountId && CollectionUtils.isIdentical(meters, _o.meters) && CollectionUtils.isIdentical(panels, _o.panels) && CollectionUtils.isIdentical(breakerHubs, _o.breakerHubs) && CollectionUtils.isIdentical(breakerGroups, _o.breakerGroups) && CollectionUtils.isIdentical(billingPlans, _o.billingPlans);
}
@Override

View File

@@ -6,7 +6,7 @@ import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Objects;
@DBSerializable
@DBSerializable(autogen = false)
public class BreakerHub implements IIdentical<BreakerHub> {
private int hub;
private double voltageCalibrationFactor;
@@ -22,16 +22,24 @@ public class BreakerHub implements IIdentical<BreakerHub> {
hub = _hub;
}
public double getRawVoltageCalibrationFactor() {
return voltageCalibrationFactor;
}
public double getVoltageCalibrationFactor() {
return voltageCalibrationFactor == 0.0?1.0:voltageCalibrationFactor;
return voltageCalibrationFactor == 0.0?0.3445:voltageCalibrationFactor;
}
public void setVoltageCalibrationFactor(double _voltageCalibrationFactor) {
voltageCalibrationFactor = _voltageCalibrationFactor;
}
public double getRawPortCalibrationFactor() {
return portCalibrationFactor;
}
public double getPortCalibrationFactor() {
return portCalibrationFactor == 0.0?1.0:portCalibrationFactor;
return portCalibrationFactor == 0.0?1.25:portCalibrationFactor;
}
public void setPortCalibrationFactor(double _portCalibrationFactor) {

View File

@@ -0,0 +1,104 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import com.lanternsoftware.util.dao.annotations.PrimaryKey;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@DBSerializable
public class HubCommand {
@PrimaryKey private String id;
private int accountId;
private int hub;
private Date created;
private HubConfigCharacteristic characteristic;
private byte[] data;
public HubCommand() {
}
public HubCommand(int _accountId, HubConfigCharacteristic _characteristic, byte[] _data) {
accountId = _accountId;
created = new Date();
characteristic = _characteristic;
data = _data;
}
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 int getHub() {
return hub;
}
public void setHub(int _hub) {
hub = _hub;
}
public Date getCreated() {
return created;
}
public void setCreated(Date _created) {
created = _created;
}
public HubConfigCharacteristic getCharacteristic() {
return characteristic;
}
public void setCharacteristic(HubConfigCharacteristic _characteristic) {
characteristic = _characteristic;
}
public byte[] getData() {
return data;
}
public void setData(byte[] _data) {
data = _data;
}
public List<HubCommand> forAllHubs(BreakerConfig _config) {
return CollectionUtils.transform(_config.getBreakerHubs(), _h->forHub(_h.getHub()));
}
public HubCommand forHub(int _hub) {
HubCommand c = new HubCommand();
c.setAccountId(accountId);
c.setHub(_hub);
c.setCreated(created);
c.setCharacteristic(characteristic);
c.setData(data);
return c;
}
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
HubCommand that = (HubCommand) _o;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@@ -0,0 +1,25 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.List;
@DBSerializable
public class HubCommands {
private List<HubCommand> commands;
public HubCommands() {
}
public HubCommands(List<HubCommand> _commands) {
commands = _commands;
}
public List<HubCommand> getCommands() {
return commands;
}
public void setCommands(List<HubCommand> _commands) {
commands = _commands;
}
}

View File

@@ -18,7 +18,10 @@ public enum HubConfigCharacteristic {
Host(10, CharacteristicFlag.WRITE),
Log(11, CharacteristicFlag.READ),
NetworkDetails(12, CharacteristicFlag.READ),
Shutdown(13, CharacteristicFlag.WRITE);
Shutdown(13, CharacteristicFlag.WRITE),
Version(14, CharacteristicFlag.READ),
Update(15, CharacteristicFlag.WRITE),
ReloadConfig(15, CharacteristicFlag.WRITE);
public final int idx;
public final UUID uuid;

View File

@@ -7,7 +7,6 @@ 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;
@@ -31,7 +30,6 @@ public class BillingRateSerializer extends AbstractDaoSerializer<BillingRate>
d.put("meter", _o.getMeter());
d.put("flow", DaoSerializer.toEnumName(_o.getFlow()));
d.put("rate", _o.getRate());
d.put("unit", DaoSerializer.toEnumName(_o.getCurrency())); //TODO: Remove post migration
d.put("currency", DaoSerializer.toEnumName(_o.getCurrency()));
d.put("time_of_day_start", _o.getTimeOfDayStart());
d.put("time_of_day_end", _o.getTimeOfDayEnd());
@@ -51,8 +49,6 @@ public class BillingRateSerializer extends AbstractDaoSerializer<BillingRate>
o.setFlow(DaoSerializer.getEnum(_d, "flow", GridFlow.class));
o.setRate(DaoSerializer.getDouble(_d, "rate"));
o.setCurrency(DaoSerializer.getEnum(_d, "currency", BillingCurrency.class));
if (o.getCurrency() == null)
o.setCurrency(DaoSerializer.getEnum(_d, "unit", BillingCurrency.class));
o.setTimeOfDayStart(DaoSerializer.getInteger(_d, "time_of_day_start"));
o.setTimeOfDayEnd(DaoSerializer.getInteger(_d, "time_of_day_end"));
o.setMonthKWhStart(DaoSerializer.getDouble(_d, "month_kwh_start"));

View File

@@ -26,8 +26,8 @@ public class BreakerHubSerializer extends AbstractDaoSerializer<BreakerHub>
{
DaoEntity d = new DaoEntity();
d.put("hub", _o.getHub());
d.put("voltage_calibration_factor", _o.getVoltageCalibrationFactor());
d.put("port_calibration_factor", _o.getPortCalibrationFactor());
d.put("voltage_calibration_factor", _o.getRawVoltageCalibrationFactor());
d.put("port_calibration_factor", _o.getRawPortCalibrationFactor());
d.put("frequency", _o.getFrequency());
d.put("bluetooth_mac", _o.getBluetoothMac());
return d;

View File

@@ -0,0 +1,51 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic;
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 HubCommandSerializer extends AbstractDaoSerializer<HubCommand>
{
@Override
public Class<HubCommand> getSupportedClass()
{
return HubCommand.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(HubCommand _o)
{
DaoEntity d = new DaoEntity();
if (_o.getId() != null)
d.put("_id", _o.getId());
d.put("account_id", _o.getAccountId());
d.put("hub", _o.getHub());
d.put("created", DaoSerializer.toLong(_o.getCreated()));
d.put("characteristic", DaoSerializer.toEnumName(_o.getCharacteristic()));
d.put("data", _o.getData());
return d;
}
@Override
public HubCommand fromDaoEntity(DaoEntity _d)
{
HubCommand o = new HubCommand();
o.setId(DaoSerializer.getString(_d, "_id"));
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setHub(DaoSerializer.getInteger(_d, "hub"));
o.setCreated(DaoSerializer.getDate(_d, "created"));
o.setCharacteristic(DaoSerializer.getEnum(_d, "characteristic", HubConfigCharacteristic.class));
o.setData(DaoSerializer.getByteArray(_d, "data"));
return o;
}
}

View File

@@ -0,0 +1,40 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubCommands;
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 HubCommandsSerializer extends AbstractDaoSerializer<HubCommands>
{
@Override
public Class<HubCommands> getSupportedClass()
{
return HubCommands.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(HubCommands _o)
{
DaoEntity d = new DaoEntity();
d.put("commands", DaoSerializer.toDaoEntities(_o.getCommands(), DaoProxyType.MONGO));
return d;
}
@Override
public HubCommands fromDaoEntity(DaoEntity _d)
{
HubCommands o = new HubCommands();
o.setCommands(DaoSerializer.getList(_d, "commands", HubCommand.class));
return o;
}
}

View File

@@ -14,6 +14,8 @@ com.lanternsoftware.datamodel.currentmonitor.dao.ChargeTotalSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.EnergyBlockSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.EnergySummarySerializer
com.lanternsoftware.datamodel.currentmonitor.dao.EnergyTotalSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.HubCommandSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.HubCommandsSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.HubPowerMinuteSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.MeterSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.NetworkStatusSerializer

View File

@@ -2,20 +2,31 @@ package com.lanternsoftware.currentmonitor.context;
import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubCommands;
import com.lanternsoftware.rules.RulesEngine;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.LanternFiles;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
public class Globals implements ServletContextListener {
public static CurrentMonitorDao dao;
private static final Map<Integer, Map<Integer, List<HubCommand>>> commands = new HashMap<>();
@Override
public void contextInitialized(ServletContextEvent sce) {
dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
RulesEngine.instance().start();
RulesEngine.instance().schedule(new CommandTask(), 0);
}
@Override
@@ -23,4 +34,38 @@ public class Globals implements ServletContextListener {
dao.shutdown();
RulesEngine.shutdown();
}
public static HubCommands getCommandsForHub(int _accountId, int _hub) {
List<HubCommand> c = null;
synchronized (commands) {
Map<Integer, List<HubCommand>> hubCommands = commands.get(_accountId);
if (hubCommands != null)
c = hubCommands.remove(_hub);
}
if (c != null) {
for (HubCommand command : c) {
dao.deleteHubCommand(command.getId());
}
return new HubCommands(c);
}
return null;
}
private static final class CommandTask extends TimerTask {
@Override
public void run() {
List<HubCommand> c = Globals.dao.getAllHubCommands();
Date stale = DateUtils.addMinutes(new Date(), -5);
synchronized (commands) {
commands.clear();
for (HubCommand command : c) {
if (DateUtils.isBefore(command.getCreated(), stale))
dao.deleteHubCommand(command.getId());
else
commands.computeIfAbsent(command.getAccountId(), _t -> new HashMap<>()).computeIfAbsent(command.getHub(), _h->new ArrayList<>()).add(command);
}
}
RulesEngine.instance().schedule(new CommandTask(), 1000);
}
}
}

View File

@@ -44,11 +44,8 @@ public class AuthServlet extends LanternServlet {
GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(transport, new GsonFactory(), "https://oauth2.googleapis.com/token", googleClientId, googleClientSecret, auth.getPassword(), "").execute();
if (tokenResponse != null) {
GoogleIdToken idToken = tokenResponse.parseIdToken();
if (idToken != null) {
logger.info("Successfully received google id token");
if (idToken != null)
authCode = Globals.dao.getAuthCodeForEmail(idToken.getPayload().getEmail(), DateUtils.fromTimeZoneId(_req.getHeader("timezone")));
logger.info("Auth code for google user is valid: " + (authCode != null));
}
}
} catch (Exception _e) {
logger.error("Failed to validate google auth code", _e);

View File

@@ -1,49 +1,19 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.util.dao.auth.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

@@ -2,6 +2,8 @@ package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic;
import com.lanternsoftware.util.dao.auth.AuthCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,6 +36,10 @@ public class ConfigServlet extends SecureServlet {
return;
}
logger.info("Received config for account {}", config.getAccountId());
BreakerConfig oldConfig = Globals.dao.getConfig(config.getAccountId());
if ((oldConfig == null) || !oldConfig.isIdentical(config))
Globals.dao.putHubCommand(new HubCommand(config.getAccountId(), HubConfigCharacteristic.ReloadConfig, null));
Globals.dao.putConfig(config);
zipBsonResponse(_rep, Globals.dao.getMergedConfig(_authCode));
}
}

View File

@@ -1,12 +1,17 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
import com.lanternsoftware.datamodel.currentmonitor.HubCommands;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.auth.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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
@@ -15,6 +20,8 @@ import java.util.List;
@WebServlet("/power/*")
public class PowerServlet extends SecureServlet {
private static final Logger logger = LoggerFactory.getLogger(MongoCurrentMonitorDao.class);
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
String[] path = path(_req);
@@ -32,19 +39,29 @@ public class PowerServlet extends SecureServlet {
String[] path = path(_req);
if ((path.length > 0) && NullUtils.isEqual(CollectionUtils.get(path, 0), "hub")) {
HubPowerMinute m = getRequestPayload(_req, HubPowerMinute.class);
if (m == null)
return;
logger.info("Hub Power from ip {}, account {}, hub {}", _req.getRemoteAddr(), m.getAccountId(), m.getHub());
m.setAccountId(_authCode.getAccountId());
Globals.dao.putHubPowerMinute(m);
return;
}
if ((path.length > 0) && NullUtils.isEqual(CollectionUtils.get(path, 0), "batch")) {
List<BreakerPower> powers = DaoSerializer.getList(getRequestZipBson(_req), "readings", BreakerPower.class);
DaoEntity payload = getRequestZipBson(_req);
List<BreakerPower> powers = DaoSerializer.getList(payload, "readings", BreakerPower.class);
if (!powers.isEmpty()) {
CollectionUtils.edit(powers, _p->_p.setAccountId(_authCode.getAccountId()));
Globals.dao.getProxy().save(powers);
int hub = DaoSerializer.getInteger(payload, "hub");
HubCommands commands = Globals.getCommandsForHub(_authCode.getAccountId(), hub);
if (commands != null)
zipBsonResponse(_rep, commands);
}
return;
}
BreakerPower power = getRequestPayload(_req, BreakerPower.class);
if (power == null)
return;
power.setAccountId(_authCode.getAccountId());
Globals.dao.putBreakerPower(power);
}

View File

@@ -2,6 +2,8 @@ package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.auth.AuthCode;
@@ -9,15 +11,21 @@ import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/rebuildSummaries")
@WebServlet("/rebuildSummaries/*")
public class RebuildSummariesServlet extends SecureServlet {
@Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
if (_authCode.getAccountId() == 100) {
for (String sId : Globals.dao.getProxy().queryForField(Account.class, null, "_id")) {
int id = DaoSerializer.toInteger(sId);
if (id != 0)
Globals.dao.rebuildSummariesAsync(id);
String[] path = path(_req);
if (path.length > 0) {
Globals.dao.rebuildSummariesAsync(DaoSerializer.toInteger(CollectionUtils.get(path, 0)));
}
else {
for (String sId : Globals.dao.getProxy().queryForField(Account.class, null, "_id")) {
int id = DaoSerializer.toInteger(sId);
if (id != 0)
Globals.dao.rebuildSummariesAsync(id);
}
}
}
else

View File

@@ -2,16 +2,21 @@
<configuration>
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/opt/tomcat/logs/log.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/opt/tomcat/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="DEBUG"/>
<root level="OFF">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>

View File

@@ -2,16 +2,21 @@
<configuration>
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/opt/tomcat/logs/log.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/opt/tomcat/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="DEBUG"/>
<root level="OFF">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>