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

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 {
}