mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Initial Commit
This commit is contained in:
105
currentmonitor/lantern-currentmonitor/pom.xml
Normal file
105
currentmonitor/lantern-currentmonitor/pom.xml
Normal file
@@ -0,0 +1,105 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||
<artifactId>lantern-currentmonitor</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0</version>
|
||||
<name>lantern-currentmonitor</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.29</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pi4j</groupId>
|
||||
<artifactId>pi4j-gpio-extension</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.hypfvieh</groupId>
|
||||
<artifactId>bluez-dbus</artifactId>
|
||||
<version>0.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||
<artifactId>lantern-datamodel-currentmonitor</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lanternsoftware.util</groupId>
|
||||
<artifactId>lantern-util-http</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<optimize>true</optimize>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<finalName>lantern-currentmonitor</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<manifestEntries>
|
||||
<Main-Class>com.lanternsoftware.currentmonitor.MonitorApp</Main-Class>
|
||||
<Specification-Title>Lantern Power Monitor</Specification-Title>
|
||||
<Specification-Version>${project.version}</Specification-Version>
|
||||
<Specification-Vendor>Lantern Software, Inc.</Specification-Vendor>
|
||||
</manifestEntries>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
|
||||
|
||||
public interface PowerListener {
|
||||
void onPowerEvent(BreakerPower _power);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
public class PowerSample {
|
||||
public double voltage;
|
||||
public double current;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.lanternsoftware.currentmonitor.bluetooth;
|
||||
|
||||
public interface BleCharacteristicListener {
|
||||
void write(String _name, byte[] _value);
|
||||
byte[] read(String _name);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.bluez;
|
||||
|
||||
import org.freedesktop.dbus.interfaces.DBusInterface;
|
||||
|
||||
public interface GattApplication1 extends DBusInterface {
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.lanternsoftware.currentmonitor.dao.MonitorConfigSerializer
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>/opt/currentmonitor/log/log.txt</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>/opt/currentmonitor/log/log.%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
|
||||
<maxFileSize>20MB</maxFileSize>
|
||||
<maxHistory>20</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.lanternsoftware" level="INFO"/>
|
||||
|
||||
<root level="OFF">
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.ResourceLoader;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
|
||||
public class CreateConfig {
|
||||
public static void main(String[] args) {
|
||||
// MonitorConfig c = new MonitorConfig(0, "https://mark.lanternsoftware.com/currentmonitor");
|
||||
MonitorConfig c = new MonitorConfig(1, "https://mark.lanternsoftware.com/currentmonitor");
|
||||
c.setDebug(true);
|
||||
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "hub1.json", DaoSerializer.toJson(c));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.util.cryptography.AESTool;
|
||||
|
||||
public class CreateSSIDKey {
|
||||
public static void main(String[] args) {
|
||||
AESTool.printRandomSecretKey();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.dao.generator.DaoSerializerGenerator;
|
||||
|
||||
public class CurrentMonitorAppSerializers {
|
||||
public static void main(String[] args) {
|
||||
DaoSerializerGenerator.generateSerializers(LanternFiles.SOURCE_PATH + "currentmonitor", true, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.currentmonitor.util.NetworkMonitor;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.NetworkStatus;
|
||||
|
||||
public class NetworkTest {
|
||||
public static void main(String[] args) {
|
||||
NetworkStatus status = NetworkMonitor.getNetworkStatus();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.lanternsoftware.currentmonitor;
|
||||
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.ResourceLoader;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.util.xml.XmlNode;
|
||||
import com.lanternsoftware.util.xml.XmlParser;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
public class ReleaseCurrentMonitor {
|
||||
public static void main(String[] args) {
|
||||
XmlNode pom = XmlParser.loadXmlFile(LanternFiles.SOURCE_PATH + "currentmonitor" + File.separator + "lantern-currentmonitor" + File.separator + "pom.xml");
|
||||
if (pom == null)
|
||||
return;
|
||||
XmlNode versionNode = pom.getChild(Collections.singletonList("version"));
|
||||
String version = versionNode.getContent();
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
builder.directory(new File(LanternFiles.SOURCE_PATH));
|
||||
builder.command("cmd.exe", "/c", "mvn clean install");
|
||||
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
|
||||
try {
|
||||
Process process = builder.start();
|
||||
int exitCode = process.waitFor();
|
||||
assert exitCode == 0;
|
||||
} catch (Exception _e) {
|
||||
_e.printStackTrace();
|
||||
}
|
||||
byte[] jar = ResourceLoader.loadFile(LanternFiles.SOURCE_PATH + "currentmonitor" + File.separator + "lantern-currentmonitor" + File.separator + "target" + File.separator + "lantern-currentmonitor.jar");
|
||||
DaoEntity meta = new DaoEntity("version", version).and("size", jar.length).and("checksum", DigestUtils.md5Hex(jar));
|
||||
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "release" + File.separator + "lantern-currentmonitor.jar", jar);
|
||||
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "release" + File.separator + "version.json", DaoSerializer.toJson(meta));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user